From 977c647927a5ac5916f4c737e32885f15a1a5b00 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Fri, 12 Oct 2012 11:47:00 +0200 Subject: [PATCH] The TTY case is resolved: notifications now work even if Emacs doesn't have focus. --- src/w32console.c | 3 +++ src/w32notify.c | 58 +++++++++++++++++++++++++++++++----------------- src/w32proc.c | 19 +++++++++++++++- src/w32term.h | 2 +- src/w32xfns.c | 10 +++++++-- 5 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/w32console.c b/src/w32console.c index f0574689bf1..f201ff190c2 100644 --- a/src/w32console.c +++ b/src/w32console.c @@ -746,6 +746,9 @@ initialize_w32_display (struct terminal *term) else w32_console_unicode_input = 0; + /* This is needed by w32notify.c:send_notifications. */ + dwMainThreadId = GetCurrentThreadId (); + /* Setup w32_display_info structure for this frame. */ w32_initialize_display_info (build_string ("Console")); diff --git a/src/w32notify.c b/src/w32notify.c index 59547635636..bdfdf3472a0 100644 --- a/src/w32notify.c +++ b/src/w32notify.c @@ -36,21 +36,32 @@ along with GNU Emacs. If not, see . */ return, and watch_worker then issues another call to ReadDirectoryChangesW. (Except when it does not, see below.) - The WM_EMACS_FILENOTIFY message, posted to the message queue gets - dispatched to the main Emacs window procedure, which queues it for - processing by w32_read_socket. When w32_read_socket sees this - message, it accesses the buffer with file notifications (using a - critical section), extracts the information, converts it to a - series of FILE_NOTIFY_EVENT events, and stuffs them into the input - event queue to be processed by keyboard.c input machinery - (read_char via a call to kbd_buffer_get_event). When the - FILE_NOTIFY_EVENT event is processed by kbd_buffer_get_event, it is - converted to a Lispy event that can be bound to a command. The - default binding is w32notify-handle-event, defined on subr.el. - - After w32_read_socket is done processing the notifications, it - resets a flag signaling to all watch worker threads that the - notifications buffer is available for more input. + In a GUI session, The WM_EMACS_FILENOTIFY message, posted to the + message queue gets dispatched to the main Emacs window procedure, + which queues it for processing by w32_read_socket. When + w32_read_socket sees this message, it accesses the buffer with file + notifications (using a critical section), extracts the information, + converts it to a series of FILE_NOTIFY_EVENT events, and stuffs + them into the input event queue to be processed by keyboard.c input + machinery (read_char via a call to kbd_buffer_get_event). + + In a non-GUI session, we send the WM_EMACS_FILENOTIFY message to + the main (a.k.a. "Lisp") thread instead, since there are no window + procedures in console programs. That message wakes up + MsgWaitForMultipleObjects inside sys_select, which then signals to + its caller that some keyboard input is available. This causes + w32_console_read_socket to be called, which accesses the buffer + with file notifications and stuffs them into the input event queue + for keyboard.c to process. + + When the FILE_NOTIFY_EVENT event is processed by keyboard.c's + kbd_buffer_get_event, it is converted to a Lispy event that can be + bound to a command. The default binding is w32notify-handle-event, + defined on subr.el. + + After w32_read_socket or w32_console_read_socket is done processing + the notifications, it resets a flag signaling to all watch worker + threads that the notifications buffer is available for more input. When the watch is removed by a call to w32notify-rm-watch, the main thread requests that the worker thread terminates by queuing an APC @@ -134,12 +145,19 @@ send_notifications (BYTE *info, DWORD info_size, HANDLE hdir, int *terminate) memcpy (file_notifications, info, info_size); notifications_size = info_size; notifications_desc = hdir; - if (FRAME_TERMCAP_P (f) + /* If PostMessage fails, the message queue is full. If that + happens, the last thing they will worry about is file + notifications. So we effectively discard the + notification in that case. */ + if ((FRAME_TERMCAP_P (f) + /* We send the message to the main (a.k.a. "Lisp") + thread, where it will wake up MsgWaitForMultipleObjects + inside sys_select, causing it to report that there's + some keyboard input available. This will in turn cause + w32_console_read_socket to be called, which will pick + up the file notifications. */ + && PostThreadMessage (dwMainThreadId, WM_EMACS_FILENOTIFY, 0, 0)) || (FRAME_W32_P (f) - /* If PostMessage fails, the message queue is full. - If that happens, the last thing they will worry - about is file notifications. So we effectively - discard the notification in that case. */ && PostMessage (FRAME_W32_WINDOW (f), WM_EMACS_FILENOTIFY, 0, 0))) notification_buffer_in_use = 1; diff --git a/src/w32proc.c b/src/w32proc.c index 7e8183b0e82..d8d32e78d5c 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -1867,7 +1867,24 @@ count_children: (*) Note that MsgWaitForMultipleObjects above is an internal dispatch point for messages that are sent to windows created by this thread. */ - drain_message_queue (); + if (drain_message_queue () + /* If drain_message_queue returns non-zero, that means + we received a WM_EMACS_FILENOTIFY message. If this + is a TTY frame, we must signal the caller that keyboard + input is available, so that w32_console_read_socket + will be called to pick up the notifications. If we + don't do that, file notifications will only work when + the Emacs TTY frame has focus. */ + && FRAME_TERMCAP_P (SELECTED_FRAME ()) + /* they asked for stdin reads */ + && FD_ISSET (0, &orfds) + /* the stdin handle is valid */ + && keyboard_handle) + { + FD_SET (0, rfds); + if (nr == 0) + nr = 1; + } } else if (active >= nh) { diff --git a/src/w32term.h b/src/w32term.h index 6540d0f4d3d..a3579c8ff60 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -672,7 +672,7 @@ extern void deselect_palette (struct frame * f, HDC hdc); extern HDC get_frame_dc (struct frame * f); extern int release_frame_dc (struct frame * f, HDC hDC); -extern void drain_message_queue (void); +extern int drain_message_queue (void); extern BOOL get_next_msg (W32Msg *, BOOL); extern BOOL post_msg (W32Msg *); diff --git a/src/w32xfns.c b/src/w32xfns.c index cb452571665..8820edda6c2 100644 --- a/src/w32xfns.c +++ b/src/w32xfns.c @@ -315,16 +315,22 @@ prepend_msg (W32Msg *lpmsg) return (TRUE); } -/* Process all messages in the current thread's queue. */ -void +/* Process all messages in the current thread's queue. Value is 1 if + one of these messages was WM_EMACS_FILENOTIFY, zero otherwise. */ +int drain_message_queue (void) { MSG msg; + int retval = 0; + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_EMACS_FILENOTIFY) + retval = 1; TranslateMessage (&msg); DispatchMessage (&msg); } + return retval; } /* x_sync is a no-op on W32. */ -- 2.39.5