diff --git a/admin/notes/multi-tty b/admin/notes/multi-tty index 7783eb395e7..fff20a1769b 100644 --- a/admin/notes/multi-tty +++ b/admin/notes/multi-tty @@ -402,29 +402,15 @@ THINGS TO DO ** The single-keyboard mode of MULTI_KBOARD is extremely confusing sometimes; Emacs does not respond to stimuli from other keyboards. - At least a beep or a message would be important, if the single-mode - is still required to prevent interference. (Reported by Dan - Nicolaescu.) + (Reported by Dan Nicolaescu.) Update: selecting a region with the mouse enables single_kboard under X. This is very confusing. Update: After discussions with Richard Stallman, this will be - resolved by having locked displays warn the user to wait, and - introducing a complex protocol to remotely bail out of + resolved introducing a complex protocol to remotely bail out of single-kboard mode by pressing C-g. - Update: Warning the user is not trivial to implement, as Emacs has - only one echo area, shared by all frames. Ideally the warning - should not be displayed on the display that is locking the others. - Perhaps the high probability of user confusion caused by - single_kboard mode deserves a special case in the display code. - Alternatively, it might be good enough to signal single_kboard mode - by changing the modelines or some other frame-local display element - on the locked out displays. - - Update: In fact struct kboard does have an echo_string slot. - ** The session management module is prone to crashes when the X connection is closed and then later I try to connect to a new X session: 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, /* Input of single characters from keyboard. */ static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu, + struct frame **event_frame, struct timespec *end_time); static void record_char (Lisp_Object c); @@ -2342,7 +2343,8 @@ read_event_from_main_queue (struct timespec *end_time, restore_getcjmp (local_getcjmp); if (!end_time) timer_start_idle (); - c = kbd_buffer_get_event (&kb, used_mouse_menu, end_time); + struct frame *frame; + c = kbd_buffer_get_event (&kb, used_mouse_menu, &frame, end_time); unbind_to (count, Qnil); if (! NILP (c) && (kb != current_kboard)) @@ -2360,9 +2362,26 @@ read_event_from_main_queue (struct timespec *end_time, else XSETCDR (last, list1 (c)); kb->kbd_queue_has_data = true; - c = Qnil; if (single_kboard) - goto start; + { + /* Typing and clicking in a locked frame is confusing because + it seems like Emacs has completely locked up (bug#79892). + Show a message about what's happening. */ + /* FIXME: We also display the message in the unlocked frame. + Can we avoid that? */ + if (frame + && (FIXNUMP (c) || (EVENT_HAS_PARAMETERS (c) + && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), + Qmouse_click)))) + { + AUTO_STRING (locked, "Frame is locked while another" + " waits for input" + " or is otherwise in a recursive edit"); + message3_frame (locked, frame); + } + c = Qnil; + goto start; + } current_kboard = kb; return make_fixnum (-2); } @@ -4005,6 +4024,7 @@ kbd_buffer_get_event_2 (Lisp_Object val) static Lisp_Object kbd_buffer_get_event (KBOARD **kbp, bool *used_mouse_menu, + struct frame **event_frame, struct timespec *end_time) { Lisp_Object obj, str; @@ -4019,6 +4039,8 @@ kbd_buffer_get_event (KBOARD **kbp, had_pending_conversion_events = false; #endif + *event_frame = NULL; + #ifdef subprocesses if (kbd_on_hold_p () && kbd_buffer_nr_stored () < KBD_BUFFER_SIZE / 4) { @@ -4179,6 +4201,9 @@ kbd_buffer_get_event (KBOARD **kbp, if (*kbp == 0) *kbp = current_kboard; /* Better than returning null ptr? */ + if (FRAMEP (event->ie.frame_or_window)) + *event_frame = XFRAME (event->ie.frame_or_window); + obj = Qnil; /* These two kinds of events get special handling @@ -4492,13 +4517,14 @@ kbd_buffer_get_event (KBOARD **kbp, /* Try generating a mouse motion event. */ else if (some_mouse_moved ()) { - struct frame *f, *movement_frame = some_mouse_moved (); + struct frame *f; Lisp_Object bar_window; enum scroll_bar_part part; Lisp_Object x, y; Time t; - f = movement_frame; + *event_frame = some_mouse_moved (); + f = *event_frame; *kbp = current_kboard; /* Note that this uses F to determine which terminal to look at. If there is no valid info, it does not store anything @@ -4535,8 +4561,8 @@ kbd_buffer_get_event (KBOARD **kbp, obj = make_lispy_movement (f, bar_window, part, x, y, t); if (!NILP (obj)) - Vlast_event_device = (STRINGP (movement_frame->last_mouse_device) - ? movement_frame->last_mouse_device + Vlast_event_device = (STRINGP ((*event_frame)->last_mouse_device) + ? (*event_frame)->last_mouse_device : virtual_core_pointer_name); } #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 *); extern void message1_nolog (const char *); extern void message3 (Lisp_Object); extern void message3_nolog (Lisp_Object); +extern void message3_frame (Lisp_Object, struct frame *); +extern void message3_frame_nolog (Lisp_Object, struct frame *); extern void message_dolog (const char *, ptrdiff_t, bool, bool); extern void message_with_string (const char *, Lisp_Object, bool); 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 . */ /* Holds the list (error). */ static Lisp_Object list_of_error; +/* Forward declarations. */ +static void restore_selected_window (Lisp_Object); +static void restore_frame_selected_window (Lisp_Object); + #ifdef HAVE_WINDOW_SYSTEM /* 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) } -/* Display an echo area message M with a specified length of NBYTES - bytes. The string may include null characters. If M is not a - string, clear out any existing message, and let the mini-buffer - text show through. - - This function cancels echoing. */ - -void -message3 (Lisp_Object m) +static void +log_message (Lisp_Object m) { clear_message (true, true); cancel_echoing (); @@ -12506,10 +12503,34 @@ message3 (Lisp_Object m) message_dolog (buffer, nbytes, true, multibyte); SAFE_FREE (); } +} + +/* Display an echo area message M with a specified length of NBYTES + bytes. The string may include null characters. If M is not a + string, clear out any existing message, and let the mini-buffer + text show through. + + This function cancels echoing. */ + +void +message3 (Lisp_Object m) +{ + log_message (m); if (! inhibit_message) message3_nolog (m); } +/* Display an echo area message M on frame F, which may not be the + selected frame. */ + +void +message3_frame (Lisp_Object m, struct frame *f) +{ + log_message (m); + if (! inhibit_message) + message3_frame_nolog (m, f); +} + /* Log the message M to stderr. Log an empty line if M is not a string. */ static void @@ -12538,36 +12559,63 @@ message_to_stderr (Lisp_Object m) errputc ('\n'); } -/* The non-logging version of message3. +/* The non-logging versions of message3 & message3_frame. This does not cancel echoing, because it is used for echoing. Perhaps we need to make a separate function for echoing and make this cancel echoing. */ void message3_nolog (Lisp_Object m) +{ + message3_frame_nolog (m, NULL); +} + +void +message3_frame_nolog (Lisp_Object m, struct frame *f) { struct frame *sf = SELECTED_FRAME (); + if (!f) f = sf; - if (FRAME_INITIAL_P (sf)) + if (FRAME_INITIAL_P (f)) message_to_stderr (m); - /* Error messages get reported properly by cmd_error, so this must be just an - informative message; if the frame hasn't really been initialized yet, just - toss it. */ - else if (INTERACTIVE && sf->glyphs_initialized_p) + /* Error messages get reported properly by cmd_error, so this must be + just an informative message; therefore if the frame hasn't really + been initialized yet, just toss it. */ + else if (INTERACTIVE && f->glyphs_initialized_p) { - /* Get the frame containing the mini-buffer - that the selected frame is using. */ - Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (sf); - Lisp_Object frame = XWINDOW (mini_window)->frame; - struct frame *f = XFRAME (frame); + Lisp_Object frame = Qnil; + struct frame *mbf = NULL; + specpdl_ref count = SPECPDL_INDEX (); - if (FRAME_VISIBLE_P (sf) && !FRAME_VISIBLE_P (f)) - Fmake_frame_visible (frame); + if (f == sf) + { + /* Get the frame containing the mini-buffer that the selected + frame is using. */ + Lisp_Object mini_window = FRAME_MINIBUF_WINDOW (f); + frame = XWINDOW (mini_window)->frame; + mbf = XFRAME (frame); + + if (FRAME_VISIBLE_P (f) && !FRAME_VISIBLE_P (mbf)) + Fmake_frame_visible (frame); + } + else + { + /* We temporarily switch frame, show the message, and then + when we unwind the message will normally still be visible + in the other frame, at least for a few seconds. */ + record_unwind_protect + (restore_selected_window, selected_window); + record_unwind_protect + (restore_frame_selected_window, f->selected_window); + XSETFRAME (frame, f); + selected_frame = frame; + selected_window = FRAME_SELECTED_WINDOW (f); + } if (STRINGP (m) && SCHARS (m) > 0) { set_message (m); - if (minibuffer_auto_raise) + if (minibuffer_auto_raise && !NILP (frame)) Fraise_frame (frame); /* Assume we are not echoing. (If we are, echo_now will override this.) */ @@ -12579,8 +12627,10 @@ message3_nolog (Lisp_Object m) do_pending_window_change (false); echo_area_display (true); do_pending_window_change (false); - if (FRAME_TERMINAL (f)->frame_up_to_date_hook) - (*FRAME_TERMINAL (f)->frame_up_to_date_hook) (f); + if (mbf && FRAME_TERMINAL (mbf)->frame_up_to_date_hook) + (*FRAME_TERMINAL (mbf)->frame_up_to_date_hook) (mbf); + + unbind_to (count, Qnil); } }