diff options
| author | Stéphane Marks | 2026-01-13 09:29:44 +0100 |
|---|---|---|
| committer | Martin Rudalics | 2026-01-13 09:29:44 +0100 |
| commit | 785059a1f7ab0ab272b2463d7a7958746ca8fe80 (patch) | |
| tree | 77f662954cdc35bd7f9d11087ec8594bee160b72 /src/frame.c | |
| parent | 52875b51bf11646fa5f7d5bf6320407b37c767c6 (diff) | |
| download | emacs-master.tar.gz emacs-master.zip | |
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.c | 82 |
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 | |||
| 343 | EMACS_UINT frame_next_id = 1; /* 0 indicates no id (yet) set. */ | ||
| 344 | |||
| 345 | DEFUN ("frame-id", Fframe_id, Sframe_id, 0, 1, 0, | ||
| 346 | doc: /* Return FRAME's id. | ||
| 347 | If FRAME is nil, use the selected frame. | ||
| 348 | Return 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. */ | ||
| 369 | EMACS_UINT | ||
| 370 | frame_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. */ | ||
| 402 | EMACS_UINT | ||
| 403 | frame_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 | |||
| 340 | DEFUN ("window-system", Fwindow_system, Swindow_system, 0, 1, 0, | 417 | DEFUN ("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. |
| 342 | The value is a symbol: | 419 | The 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); |