aboutsummaryrefslogtreecommitdiffstats
path: root/src/frame.c
diff options
context:
space:
mode:
authorStéphane Marks2026-01-13 09:29:44 +0100
committerMartin Rudalics2026-01-13 09:29:44 +0100
commit785059a1f7ab0ab272b2463d7a7958746ca8fe80 (patch)
tree77f662954cdc35bd7f9d11087ec8594bee160b72 /src/frame.c
parent52875b51bf11646fa5f7d5bf6320407b37c767c6 (diff)
downloademacs-master.tar.gz
emacs-master.zip
Add frame identifiers (bug#80138)HEADmaster
A unique frame id is assigned to a new or cloned frame, and reused on an undeleted frame. The id facilitates unambiguous identification among frames that share identical names or titles, deleted frames where a live frame object no longer exists that we can resurrect by id, for example via 'tab-bar-undo-close-tab'. It also aids debugging at the C level using the frame struct member id. Rewrite 'clone-frame' and 'undelete-frame' to not let bind variables that 'make-frame' uses to avoid conflicts with nested 'make-frame' calls, for example via 'after-make-frame-functions'. * lisp/frame.el (clone-frame, undelete-frame): Use 'frame--purify-parameters' to supply parameters explicitly. (undelete-frame--save-deleted-frame): Save frame id for restoration. (undelete-frame): Restore frame id. (frame--purify-parameters): New defun. (make-frame): Assign a new id for a new or cloned frame, reuse for undeleted frame. * src/frame.h (struct frame): Add id member. (frame_next_id): New extern. * src/frame.c (frame_next_id): New global counter. (frame_set_id, frame_set_id_from_params): New function. (Fframe_id): New DEFUN. (syms_of_frame <Sframe_id>): New defsubr. (syms_of_frame <Qinternal_id>): New DEFSYM. (syms_of_frame <frame_internal_parameters>): Add 'Qinternal_id'. * src/androidfns.c (Fx_create_frame): * src/haikufns.c (Fx_create_frame): * src/nsfns.m (Fx_create_frame): * src/pgtkfns.c (Fx_create_frame): * src/w32fns.c (Fx_create_frame): * src/xfns.c (Fx_create_frame): Call 'frame_set_id_from_params'. * doc/lispref/frames.texi: Add documentation. * etc/NEWS: Announce frame id.
Diffstat (limited to 'src/frame.c')
-rw-r--r--src/frame.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/src/frame.c b/src/frame.c
index 5d38f015130..033215a76ec 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -337,6 +337,83 @@ return values. */)
337 : Qnil); 337 : Qnil);
338} 338}
339 339
340
341/* Frame id. */
342
343EMACS_UINT frame_next_id = 1; /* 0 indicates no id (yet) set. */
344
345DEFUN ("frame-id", Fframe_id, Sframe_id, 0, 1, 0,
346 doc: /* Return FRAME's id.
347If FRAME is nil, use the selected frame.
348Return nil if the id has not been set. */)
349 (Lisp_Object frame)
350{
351 if (NILP (frame))
352 frame = selected_frame;
353 struct frame *f = decode_live_frame (frame);
354 if (f->id == 0)
355 return Qnil;
356 else
357 return make_fixnum (f->id);
358}
359
360/** frame_set_id: Set frame F's id to ID.
361
362 If ID is 0 and F's ID is 0, use frame_next_id and increment it,
363 otherwise, use ID.
364
365 Signal an error if ID >= frame_next_id.
366 Signal an error if ID is in use on another live frame.
367
368 Return ID if it was used, 0 otherwise. */
369EMACS_UINT
370frame_set_id (struct frame *f, EMACS_UINT id)
371{
372 if (id >= frame_next_id)
373 error ("Specified frame ID unassigned");
374
375 if (id > 0)
376 {
377 eassume (CONSP (Vframe_list));
378 Lisp_Object frame, tail = Qnil;
379 FOR_EACH_FRAME (tail, frame)
380 {
381 if (id == XFRAME (frame)->id)
382 error ("Specified frame ID already in use");
383 }
384 }
385
386 if (id == 0)
387 if (f->id != 0)
388 return 0;
389 else
390 f->id = frame_next_id++;
391 else
392 f->id = id;
393 return f->id;
394}
395
396/** frame_set_id_from_params: Set frame F's id from params, if present.
397
398 Call frame_set_id to using the frame parameter 'frame-id, if present
399 and a valid positive integer greater than 0, otherwise use 0.
400
401 Return frame_set_id's return value. */
402EMACS_UINT
403frame_set_id_from_params (struct frame *f, Lisp_Object params)
404{
405 EMACS_UINT id = 0;
406 Lisp_Object param_id = Fcdr (Fassq (Qframe_id, params));
407 if (TYPE_RANGED_FIXNUMP (int, param_id))
408 {
409 EMACS_INT id_1 = XFIXNUM (param_id);
410 if (id_1 > 0)
411 id = (EMACS_UINT) id_1;
412 }
413 return frame_set_id (f, id);
414}
415
416
340DEFUN ("window-system", Fwindow_system, Swindow_system, 0, 1, 0, 417DEFUN ("window-system", Fwindow_system, Swindow_system, 0, 1, 0,
341 doc: /* The name of the window system that FRAME is displaying through. 418 doc: /* The name of the window system that FRAME is displaying through.
342The value is a symbol: 419The value is a symbol:
@@ -1358,6 +1435,7 @@ make_initial_frame (void)
1358 1435
1359 f = make_frame (true); 1436 f = make_frame (true);
1360 XSETFRAME (frame, f); 1437 XSETFRAME (frame, f);
1438 frame_set_id (f, 0);
1361 1439
1362 Vframe_list = Fcons (frame, Vframe_list); 1440 Vframe_list = Fcons (frame, Vframe_list);
1363 1441
@@ -1742,6 +1820,7 @@ affects all frames on the same terminal device. */)
1742 frames don't obscure other frames. */ 1820 frames don't obscure other frames. */
1743 Lisp_Object parent = Fcdr (Fassq (Qparent_frame, parms)); 1821 Lisp_Object parent = Fcdr (Fassq (Qparent_frame, parms));
1744 struct frame *f = make_terminal_frame (t, parent, parms); 1822 struct frame *f = make_terminal_frame (t, parent, parms);
1823 frame_set_id_from_params (f, parms);
1745 1824
1746 if (!noninteractive) 1825 if (!noninteractive)
1747 init_frame_faces (f); 1826 init_frame_faces (f);
@@ -7195,6 +7274,7 @@ syms_of_frame (void)
7195 DEFSYM (Qfont_parameter, "font-parameter"); 7274 DEFSYM (Qfont_parameter, "font-parameter");
7196 DEFSYM (Qforce, "force"); 7275 DEFSYM (Qforce, "force");
7197 DEFSYM (Qinhibit, "inhibit"); 7276 DEFSYM (Qinhibit, "inhibit");
7277 DEFSYM (Qframe_id, "frame-id");
7198 DEFSYM (Qcloned_from, "cloned-from"); 7278 DEFSYM (Qcloned_from, "cloned-from");
7199 DEFSYM (Qundeleted, "undeleted"); 7279 DEFSYM (Qundeleted, "undeleted");
7200 7280
@@ -7581,6 +7661,7 @@ allow `make-frame' to show the current buffer even if its hidden. */);
7581#else 7661#else
7582 frame_internal_parameters = list3 (Qname, Qparent_id, Qwindow_id); 7662 frame_internal_parameters = list3 (Qname, Qparent_id, Qwindow_id);
7583#endif 7663#endif
7664 frame_internal_parameters = Fcons (Qframe_id, frame_internal_parameters);
7584 frame_internal_parameters = Fcons (Qcloned_from, frame_internal_parameters); 7665 frame_internal_parameters = Fcons (Qcloned_from, frame_internal_parameters);
7585 frame_internal_parameters = Fcons (Qundeleted, frame_internal_parameters); 7666 frame_internal_parameters = Fcons (Qundeleted, frame_internal_parameters);
7586 7667
@@ -7607,6 +7688,7 @@ The default is \\+`inhibit' in NS builds and nil everywhere else. */);
7607 alter_fullscreen_frames = Qnil; 7688 alter_fullscreen_frames = Qnil;
7608#endif 7689#endif
7609 7690
7691 defsubr (&Sframe_id);
7610 defsubr (&Sframep); 7692 defsubr (&Sframep);
7611 defsubr (&Sframe_live_p); 7693 defsubr (&Sframe_live_p);
7612 defsubr (&Swindow_system); 7694 defsubr (&Swindow_system);