diff options
| author | Sean Whitton | 2026-02-28 15:34:16 +0000 |
|---|---|---|
| committer | Sean Whitton | 2026-02-28 15:34:16 +0000 |
| commit | 342e002c879329e89bdec3a9d82c28ab06e6fce9 (patch) | |
| tree | 51bbf420cffecdc0176991f9efe1cc67bfd8fb29 /src | |
| parent | fe2fdf7c82e5efc3350061233d3f0aed54915876 (diff) | |
| download | emacs-342e002c879329e89bdec3a9d82c28ab06e6fce9.tar.gz emacs-342e002c879329e89bdec3a9d82c28ab06e6fce9.zip | |
Show a message in locked frames in single-kboard mode
* src/keyboard.c (kbd_buffer_get_event): Pass the event's frame
up to the caller by means of a new 'struct frame **' argument.
(read_event_from_main_queue): Show a message in locked frames in
single-kboard mode (bug#79892).
* src/xdisp.c (log_message): Factor out of message3.
(message3): Call it.
(message3_nolog): Rename to ...
(message3_frame_nolog): ... this. New 'struct frame *' argument
which causes temporarily switching to another frame when
displaying the message.
(message3_frame, message3_nolog): New functions.
* src/lisp.h: Declare message3_frame and message3_frame_nolog.
* admin/notes/multi-tty: Remove notes on showing a message.
Diffstat (limited to 'src')
| -rw-r--r-- | src/keyboard.c | 40 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/xdisp.c | 100 |
3 files changed, 110 insertions, 32 deletions
diff --git a/src/keyboard.c b/src/keyboard.c index ffe47460528..648dd81660a 100644 --- a/src/keyboard.c +++ b/src/keyboard.c | |||
| @@ -2297,6 +2297,7 @@ show_help_echo (Lisp_Object help, Lisp_Object window, Lisp_Object object, | |||
| 2297 | /* Input of single characters from keyboard. */ | 2297 | /* Input of single characters from keyboard. */ |
| 2298 | 2298 | ||
| 2299 | static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu, | 2299 | static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu, |
| 2300 | struct frame **event_frame, | ||
| 2300 | struct timespec *end_time); | 2301 | struct timespec *end_time); |
| 2301 | static void record_char (Lisp_Object c); | 2302 | static void record_char (Lisp_Object c); |
| 2302 | 2303 | ||
| @@ -2342,7 +2343,8 @@ read_event_from_main_queue (struct timespec *end_time, | |||
| 2342 | restore_getcjmp (local_getcjmp); | 2343 | restore_getcjmp (local_getcjmp); |
| 2343 | if (!end_time) | 2344 | if (!end_time) |
| 2344 | timer_start_idle (); | 2345 | timer_start_idle (); |
| 2345 | c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time); | 2346 | struct frame *frame; |
| 2347 | c = kbd_buffer_get_event (&kb, used_mouse_menu, &frame, end_time); | ||
| 2346 | unbind_to (count, Qnil); | 2348 | unbind_to (count, Qnil); |
| 2347 | 2349 | ||
| 2348 | if (! NILP (c) && (kb != current_kboard)) | 2350 | if (! NILP (c) && (kb != current_kboard)) |
| @@ -2360,9 +2362,26 @@ read_event_from_main_queue (struct timespec *end_time, | |||
| 2360 | else | 2362 | else |
| 2361 | XSETCDR (last, list1 (c)); | 2363 | XSETCDR (last, list1 (c)); |
| 2362 | kb->kbd_queue_has_data = true; | 2364 | kb->kbd_queue_has_data = true; |
| 2363 | c = Qnil; | ||
| 2364 | if (single_kboard) | 2365 | if (single_kboard) |
| 2365 | goto start; | 2366 | { |
| 2367 | /* Typing and clicking in a locked frame is confusing because | ||
| 2368 | it seems like Emacs has completely locked up (bug#79892). | ||
| 2369 | Show a message about what's happening. */ | ||
| 2370 | /* FIXME: We also display the message in the unlocked frame. | ||
| 2371 | Can we avoid that? */ | ||
| 2372 | if (frame | ||
| 2373 | && (FIXNUMP (c) || (EVENT_HAS_PARAMETERS (c) | ||
| 2374 | && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), | ||
| 2375 | Qmouse_click)))) | ||
| 2376 | { | ||
| 2377 | AUTO_STRING (locked, "Frame is locked while another" | ||
| 2378 | " waits for input" | ||
| 2379 | " or is otherwise in a recursive edit"); | ||
| 2380 | message3_frame (locked, frame); | ||
| 2381 | } | ||
| 2382 | c = Qnil; | ||
| 2383 | goto start; | ||
| 2384 | } | ||
| 2366 | current_kboard = kb; | 2385 | current_kboard = kb; |
| 2367 | return make_fixnum (-2); | 2386 | return make_fixnum (-2); |
| 2368 | } | 2387 | } |
| @@ -4005,6 +4024,7 @@ kbd_buffer_get_event_2 (Lisp_Object val) | |||
| 4005 | static Lisp_Object | 4024 | static Lisp_Object |
| 4006 | kbd_buffer_get_event (KBOARD **kbp, | 4025 | kbd_buffer_get_event (KBOARD **kbp, |
| 4007 | bool *used_mouse_menu, | 4026 | bool *used_mouse_menu, |
| 4027 | struct frame **event_frame, | ||
| 4008 | struct timespec *end_time) | 4028 | struct timespec *end_time) |
| 4009 | { | 4029 | { |
| 4010 | Lisp_Object obj, str; | 4030 | Lisp_Object obj, str; |
| @@ -4019,6 +4039,8 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4019 | had_pending_conversion_events = false; | 4039 | had_pending_conversion_events = false; |
| 4020 | #endif | 4040 | #endif |
| 4021 | 4041 | ||
| 4042 | *event_frame = NULL; | ||
| 4043 | |||
| 4022 | #ifdef subprocesses | 4044 | #ifdef subprocesses |
| 4023 | if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4) | 4045 | if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4) |
| 4024 | { | 4046 | { |
| @@ -4179,6 +4201,9 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4179 | if (*kbp == 0) | 4201 | if (*kbp == 0) |
| 4180 | *kbp = current_kboard; /* Better than returning null ptr? */ | 4202 | *kbp = current_kboard; /* Better than returning null ptr? */ |
| 4181 | 4203 | ||
| 4204 | if (FRAMEP (event->ie.frame_or_window)) | ||
| 4205 | *event_frame = XFRAME (event->ie.frame_or_window); | ||
| 4206 | |||
| 4182 | obj = Qnil; | 4207 | obj = Qnil; |
| 4183 | 4208 | ||
| 4184 | /* These two kinds of events get special handling | 4209 | /* These two kinds of events get special handling |
| @@ -4492,13 +4517,14 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4492 | /* Try generating a mouse motion event. */ | 4517 | /* Try generating a mouse motion event. */ |
| 4493 | else if (some_mouse_moved ()) | 4518 | else if (some_mouse_moved ()) |
| 4494 | { | 4519 | { |
| 4495 | struct frame *f, *movement_frame = some_mouse_moved (); | 4520 | struct frame *f; |
| 4496 | Lisp_Object bar_window; | 4521 | Lisp_Object bar_window; |
| 4497 | enum scroll_bar_part part; | 4522 | enum scroll_bar_part part; |
| 4498 | Lisp_Object x, y; | 4523 | Lisp_Object x, y; |
| 4499 | Time t; | 4524 | Time t; |
| 4500 | 4525 | ||
| 4501 | f = movement_frame; | 4526 | *event_frame = some_mouse_moved (); |
| 4527 | f = *event_frame; | ||
| 4502 | *kbp = current_kboard; | 4528 | *kbp = current_kboard; |
| 4503 | /* Note that this uses F to determine which terminal to look at. | 4529 | /* Note that this uses F to determine which terminal to look at. |
| 4504 | If there is no valid info, it does not store anything | 4530 | If there is no valid info, it does not store anything |
| @@ -4535,8 +4561,8 @@ kbd_buffer_get_event (KBOARD **kbp, | |||
| 4535 | obj = make_lispy_movement (f, bar_window, part, x, y, t); | 4561 | obj = make_lispy_movement (f, bar_window, part, x, y, t); |
| 4536 | 4562 | ||
| 4537 | if (!NILP (obj)) | 4563 | if (!NILP (obj)) |
| 4538 | Vlast_event_device = (STRINGP (movement_frame->last_mouse_device) | 4564 | Vlast_event_device = (STRINGP ((*event_frame)->last_mouse_device) |
| 4539 | ? movement_frame->last_mouse_device | 4565 | ? (*event_frame)->last_mouse_device |
| 4540 | : virtual_core_pointer_name); | 4566 | : virtual_core_pointer_name); |
| 4541 | } | 4567 | } |
| 4542 | #ifdef HAVE_X_WINDOWS | 4568 | #ifdef HAVE_X_WINDOWS |
diff --git a/src/lisp.h b/src/lisp.h index c7afb07576b..cefca3d6fbb 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4390,6 +4390,8 @@ extern void message1 (const char *); | |||
| 4390 | extern void message1_nolog (const char *); | 4390 | extern void message1_nolog (const char *); |
| 4391 | extern void message3 (Lisp_Object); | 4391 | extern void message3 (Lisp_Object); |
| 4392 | extern void message3_nolog (Lisp_Object); | 4392 | extern void message3_nolog (Lisp_Object); |
| 4393 | extern void message3_frame (Lisp_Object, struct frame *); | ||
| 4394 | extern void message3_frame_nolog (Lisp_Object, struct frame *); | ||
| 4393 | extern void message_dolog (const char *, ptrdiff_t, bool, bool); | 4395 | extern void message_dolog (const char *, ptrdiff_t, bool, bool); |
| 4394 | extern void message_with_string (const char *, Lisp_Object, bool); | 4396 | extern void message_with_string (const char *, Lisp_Object, bool); |
| 4395 | extern void message_log_maybe_newline (void); | 4397 | extern void message_log_maybe_newline (void); |
diff --git a/src/xdisp.c b/src/xdisp.c index f5e2b6e2d24..c8e4bf0cf10 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -510,6 +510,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 510 | /* Holds the list (error). */ | 510 | /* Holds the list (error). */ |
| 511 | static Lisp_Object list_of_error; | 511 | static Lisp_Object list_of_error; |
| 512 | 512 | ||
| 513 | /* Forward declarations. */ | ||
| 514 | static void restore_selected_window (Lisp_Object); | ||
| 515 | static void restore_frame_selected_window (Lisp_Object); | ||
| 516 | |||
| 513 | #ifdef HAVE_WINDOW_SYSTEM | 517 | #ifdef HAVE_WINDOW_SYSTEM |
| 514 | 518 | ||
| 515 | /* Test if overflow newline into fringe. Called with iterator IT | 519 | /* Test if overflow newline into fringe. Called with iterator IT |
| @@ -12481,15 +12485,8 @@ message_log_check_duplicate (ptrdiff_t prev_bol_byte, ptrdiff_t this_bol_byte) | |||
| 12481 | } | 12485 | } |
| 12482 | 12486 | ||
| 12483 | 12487 | ||
| 12484 | /* Display an echo area message M with a specified length of NBYTES | 12488 | static void |
| 12485 | bytes. The string may include null characters. If M is not a | 12489 | log_message (Lisp_Object m) |
| 12486 | string, clear out any existing message, and let the mini-buffer | ||
| 12487 | text show through. | ||
| 12488 | |||
| 12489 | This function cancels echoing. */ | ||
| 12490 | |||
| 12491 | void | ||
| 12492 | message3 (Lisp_Object m) | ||
| 12493 | { | 12490 | { |
| 12494 | clear_message (true, true); | 12491 | clear_message (true, true); |
| 12495 | cancel_echoing (); | 12492 | cancel_echoing (); |
| @@ -12506,10 +12503,34 @@ message3 (Lisp_Object m) | |||
| 12506 | message_dolog (buffer, nbytes, true, multibyte); | 12503 | message_dolog (buffer, nbytes, true, multibyte); |
| 12507 | SAFE_FREE (); | 12504 | SAFE_FREE (); |
| 12508 | } | 12505 | } |
| 12506 | } | ||
| 12507 | |||
| 12508 | /* Display an echo area message M with a specified length of NBYTES | ||
| 12509 | bytes. The string may include null characters. If M is not a | ||
| 12510 | string, clear out any existing message, and let the mini-buffer | ||
| 12511 | text show through. | ||
| 12512 | |||
| 12513 | This function cancels echoing. */ | ||
| 12514 | |||
| 12515 | void | ||
| 12516 | message3 (Lisp_Object m) | ||
| 12517 | { | ||
| 12518 | log_message (m); | ||
| 12509 | if (! inhibit_message) | 12519 | if (! inhibit_message) |
| 12510 | message3_nolog (m); | 12520 | message3_nolog (m); |
| 12511 | } | 12521 | } |
| 12512 | 12522 | ||
| 12523 | /* Display an echo area message M on frame F, which may not be the | ||
| 12524 | selected frame. */ | ||
| 12525 | |||
| 12526 | void | ||
| 12527 | message3_frame (Lisp_Object m, struct frame *f) | ||
| 12528 | { | ||
| 12529 | log_message (m); | ||
| 12530 | if (! inhibit_message) | ||
| 12531 | message3_frame_nolog (m, f); | ||
| 12532 | } | ||
| 12533 | |||
| 12513 | /* Log the message M to stderr. Log an empty line if M is not a string. */ | 12534 | /* Log the message M to stderr. Log an empty line if M is not a string. */ |
| 12514 | 12535 | ||
| 12515 | static void | 12536 | static void |
| @@ -12538,7 +12559,7 @@ message_to_stderr (Lisp_Object m) | |||
| 12538 | errputc ('\n'); | 12559 | errputc ('\n'); |
| 12539 | } | 12560 | } |
| 12540 | 12561 | ||
| 12541 | /* The non-logging version of message3. | 12562 | /* The non-logging versions of message3 & message3_frame. |
| 12542 | This does not cancel echoing, because it is used for echoing. | 12563 | This does not cancel echoing, because it is used for echoing. |
| 12543 | Perhaps we need to make a separate function for echoing | 12564 | Perhaps we need to make a separate function for echoing |
| 12544 | and make this cancel echoing. */ | 12565 | and make this cancel echoing. */ |
| @@ -12546,28 +12567,55 @@ message_to_stderr (Lisp_Object m) | |||
| 12546 | void | 12567 | void |
| 12547 | message3_nolog (Lisp_Object m) | 12568 | message3_nolog (Lisp_Object m) |
| 12548 | { | 12569 | { |
| 12570 | message3_frame_nolog (m, NULL); | ||
| 12571 | } | ||
| 12572 | |||
| 12573 | void | ||
| 12574 | message3_frame_nolog (Lisp_Object m, struct frame *f) | ||
| 12575 | { | ||
| 12549 | struct frame *sf = SELECTED_FRAME (); | 12576 | struct frame *sf = SELECTED_FRAME (); |
| 12577 | if (!f) f = sf; | ||
| 12550 | 12578 | ||
| 12551 | if (FRAME_INITIAL_P (sf)) | 12579 | if (FRAME_INITIAL_P (f)) |
| 12552 | message_to_stderr (m); | 12580 | message_to_stderr (m); |
| 12553 | /* Error messages get reported properly by cmd_error, so this must be just an | 12581 | /* Error messages get reported properly by cmd_error, so this must be |
| 12554 | informative message; if the frame hasn't really been initialized yet, just | 12582 | just an informative message; therefore if the frame hasn't really |
| 12555 | toss it. */ | 12583 | been initialized yet, just toss it. */ |
| 12556 | else if (INTERACTIVE && sf->glyphs_initialized_p) | 12584 | else if (INTERACTIVE && f->glyphs_initialized_p) |
| 12557 | { | 12585 | { |
| 12558 | /* Get the frame containing the mini-buffer | 12586 | Lisp_Object frame = Qnil; |
| 12559 | that the selected frame is using. */ | 12587 | struct frame *mbf = NULL; |
| 12560 | Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf); | 12588 | specpdl_ref count = SPECPDL_INDEX (); |
| 12561 | Lisp_Object frame = XWINDOW (mini_window)->frame; | 12589 | |
| 12562 | struct frame *f = XFRAME (frame); | 12590 | if (f == sf) |
| 12591 | { | ||
| 12592 | /* Get the frame containing the mini-buffer that the selected | ||
| 12593 | frame is using. */ | ||
| 12594 | Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (f); | ||
| 12595 | frame = XWINDOW (mini_window)->frame; | ||
| 12596 | mbf = XFRAME (frame); | ||
| 12563 | 12597 | ||
| 12564 | if (FRAME_VISIBLE_P (sf) && !FRAME_VISIBLE_P (f)) | 12598 | if (FRAME_VISIBLE_P (f) && !FRAME_VISIBLE_P (mbf)) |
| 12565 | Fmake_frame_visible (frame); | 12599 | Fmake_frame_visible (frame); |
| 12600 | } | ||
| 12601 | else | ||
| 12602 | { | ||
| 12603 | /* We temporarily switch frame, show the message, and then | ||
| 12604 | when we unwind the message will normally still be visible | ||
| 12605 | in the other frame, at least for a few seconds. */ | ||
| 12606 | record_unwind_protect | ||
| 12607 | (restore_selected_window, selected_window); | ||
| 12608 | record_unwind_protect | ||
| 12609 | (restore_frame_selected_window, f->selected_window); | ||
| 12610 | XSETFRAME (frame, f); | ||
| 12611 | selected_frame = frame; | ||
| 12612 | selected_window = FRAME_SELECTED_WINDOW (f); | ||
| 12613 | } | ||
| 12566 | 12614 | ||
| 12567 | if (STRINGP (m) && SCHARS (m) > 0) | 12615 | if (STRINGP (m) && SCHARS (m) > 0) |
| 12568 | { | 12616 | { |
| 12569 | set_message (m); | 12617 | set_message (m); |
| 12570 | if (minibuffer_auto_raise) | 12618 | if (minibuffer_auto_raise && !NILP (frame)) |
| 12571 | Fraise_frame (frame); | 12619 | Fraise_frame (frame); |
| 12572 | /* Assume we are not echoing. | 12620 | /* Assume we are not echoing. |
| 12573 | (If we are, echo_now will override this.) */ | 12621 | (If we are, echo_now will override this.) */ |
| @@ -12579,8 +12627,10 @@ message3_nolog (Lisp_Object m) | |||
| 12579 | do_pending_window_change (false); | 12627 | do_pending_window_change (false); |
| 12580 | echo_area_display (true); | 12628 | echo_area_display (true); |
| 12581 | do_pending_window_change (false); | 12629 | do_pending_window_change (false); |
| 12582 | if (FRAME_TERMINAL (f)->frame_up_to_date_hook) | 12630 | if (mbf && FRAME_TERMINAL (mbf)->frame_up_to_date_hook) |
| 12583 | (*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f); | 12631 | (*FRAME_TERMINAL (mbf)->frame_up_to_date_hook) (mbf); |
| 12632 | |||
| 12633 | unbind_to (count, Qnil); | ||
| 12584 | } | 12634 | } |
| 12585 | } | 12635 | } |
| 12586 | 12636 | ||