1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-11 09:21:23 -07:00

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.
This commit is contained in:
Sean Whitton 2026-02-28 15:34:16 +00:00
parent fe2fdf7c82
commit 342e002c87
4 changed files with 112 additions and 48 deletions

View file

@ -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:

View file

@ -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

View file

@ -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);

View file

@ -510,6 +510,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* 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);
}
}