diff options
| author | Eli Zaretskii | 2012-10-07 15:41:15 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2012-10-07 15:41:15 +0200 |
| commit | c5c91b847a41ec7e09dee582816d702c8a9adcdd (patch) | |
| tree | c96da676a40396ee6e0aaaa969fd01f984791559 | |
| parent | 25d99a950debf417295e68a7a7d519b4ddf3e546 (diff) | |
| download | emacs-c5c91b847a41ec7e09dee582816d702c8a9adcdd.tar.gz emacs-c5c91b847a41ec7e09dee582816d702c8a9adcdd.zip | |
Final version that supports only one watch at a time.
| -rw-r--r-- | lib-src/ChangeLog | 4 | ||||
| -rw-r--r-- | lisp/ChangeLog | 4 | ||||
| -rw-r--r-- | src/ChangeLog | 34 | ||||
| -rw-r--r-- | src/w32fns.c | 3 | ||||
| -rw-r--r-- | src/w32notify.c | 102 | ||||
| -rw-r--r-- | src/w32term.c | 4 |
6 files changed, 94 insertions, 57 deletions
diff --git a/lib-src/ChangeLog b/lib-src/ChangeLog index 2a8ac9b8131..a9031d74758 100644 --- a/lib-src/ChangeLog +++ b/lib-src/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2012-10-07 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * makefile.w32-in (obj): Add w32notify.o. | ||
| 4 | |||
| 1 | 2012-10-01 Fabrice Popineau <fabrice.popineau@gmail.com> | 5 | 2012-10-01 Fabrice Popineau <fabrice.popineau@gmail.com> |
| 2 | 6 | ||
| 3 | * make-docfile.c (write_globals): Special-case | 7 | * make-docfile.c (write_globals): Special-case |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e54e82233a2..7d40007f435 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2012-10-07 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * subr.el (w32notify-handle-event): New function. | ||
| 4 | |||
| 1 | 2012-10-07 Glenn Morris <rgm@gnu.org> | 5 | 2012-10-07 Glenn Morris <rgm@gnu.org> |
| 2 | 6 | ||
| 3 | * mail/rmailmm.el (rmail-mime-process-multipart): | 7 | * mail/rmailmm.el (rmail-mime-process-multipart): |
diff --git a/src/ChangeLog b/src/ChangeLog index 492b966a256..cb2aab2166c 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,37 @@ | |||
| 1 | 2012-10-07 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * w32term.h (WM_EMACS_FILENOTIFY): New custom message. | ||
| 4 | (WM_EMACS_END): Bump value by 1. | ||
| 5 | |||
| 6 | * w32term.c (lispy_file_action, queue_notifications): New functions. | ||
| 7 | (syms_of_w32term) <Qadded, Qremoved, Qmodified, Qrenamed_from> | ||
| 8 | <Qrenamed_to>: New symbols. | ||
| 9 | |||
| 10 | * w32notify.c: New file, implement file event notifications for | ||
| 11 | MS-Windows. | ||
| 12 | |||
| 13 | * w32fns.c (w32_wnd_proc): Handle the WM_EMACS_FILENOTIFY message | ||
| 14 | by posting it to the w32_read_socket queue. | ||
| 15 | |||
| 16 | * termhooks.h (enum event_kind) [WINDOWSNT]: New event kind | ||
| 17 | FILE_NOTIFY_EVENT. | ||
| 18 | |||
| 19 | * makefile.w32-in (OBJ2): Add $(BLD)/w32notify.$(O). | ||
| 20 | (GLOBAL_SOURCES): Add w32notify.c | ||
| 21 | ($(BLD)/w32notify.$(O)): New set of dependencies. | ||
| 22 | |||
| 23 | * lisp.h (syms_of_w32notify) [WINDOWSNT]: Add prototype. | ||
| 24 | |||
| 25 | * keyboard.c (kbd_buffer_get_event) [WINDOWSNT]: Handle | ||
| 26 | FILE_NOTIFY_EVENT. | ||
| 27 | (syms_of_keyboard) [WINDOWSNT] <Qfile_notify>: New symbol. | ||
| 28 | (keys_of_keyboard) [WINDOWSNT]: Bind file-notify to | ||
| 29 | w32notify-handle-event by default. | ||
| 30 | |||
| 31 | * emacs.c (main) [WINDOWSNT]: Call syms_of_w32notify. | ||
| 32 | |||
| 33 | * alloc.c (NSTATICS): Enlarge to 0x660. | ||
| 34 | |||
| 1 | 2012-10-07 Jan Djärv <jan.h.d@swipnet.se> | 35 | 2012-10-07 Jan Djärv <jan.h.d@swipnet.se> |
| 2 | 36 | ||
| 3 | * nsterm.m (ns_dumpglyphs_image): Only draw slize of image (Bug#12506). | 37 | * nsterm.m (ns_dumpglyphs_image): Only draw slize of image (Bug#12506). |
diff --git a/src/w32fns.c b/src/w32fns.c index 2d36da3b56b..fac6030b9b5 100644 --- a/src/w32fns.c +++ b/src/w32fns.c | |||
| @@ -2259,8 +2259,6 @@ w32_msg_pump (deferred_msg * msg_buf) | |||
| 2259 | 2259 | ||
| 2260 | while ((w32_unicode_gui ? GetMessageW : GetMessageA) (&msg, NULL, 0, 0)) | 2260 | while ((w32_unicode_gui ? GetMessageW : GetMessageA) (&msg, NULL, 0, 0)) |
| 2261 | { | 2261 | { |
| 2262 | if (msg.message == WM_EMACS_FILENOTIFY) | ||
| 2263 | DebPrint (("w32_msg_pump: File notification, hwnd = 0x%p\n", msg.hwnd)); | ||
| 2264 | if (msg.hwnd == NULL) | 2262 | if (msg.hwnd == NULL) |
| 2265 | { | 2263 | { |
| 2266 | switch (msg.message) | 2264 | switch (msg.message) |
| @@ -3810,7 +3808,6 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | |||
| 3810 | return retval; | 3808 | return retval; |
| 3811 | } | 3809 | } |
| 3812 | case WM_EMACS_FILENOTIFY: | 3810 | case WM_EMACS_FILENOTIFY: |
| 3813 | DebPrint (("w32_wnd_proc: File notification arrived, posting\n")); | ||
| 3814 | my_post_msg (&wmsg, hwnd, msg, wParam, lParam); | 3811 | my_post_msg (&wmsg, hwnd, msg, wParam, lParam); |
| 3815 | return 1; | 3812 | return 1; |
| 3816 | 3813 | ||
diff --git a/src/w32notify.c b/src/w32notify.c index 0dc4d27d33f..81199b2a0a1 100644 --- a/src/w32notify.c +++ b/src/w32notify.c | |||
| @@ -16,6 +16,54 @@ GNU General Public License for more details. | |||
| 16 | You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
| 17 | along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | 17 | along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ |
| 18 | 18 | ||
| 19 | /* Design overview: | ||
| 20 | |||
| 21 | For each watch request, we launch a separate worker thread. The | ||
| 22 | worker thread runs the watch_worker function, which issues an | ||
| 23 | asynchronous call to ReadDirectoryChangesW, and then waits for that | ||
| 24 | call to complete in SleepEx. Waiting in SleepEx puts the thread in | ||
| 25 | an alertable state, so it wakes up when either (a) the call to | ||
| 26 | ReadDirectoryChangesW completes, or (b) the main thread instructs | ||
| 27 | the worker thread to terminate by sending it an APC, see below. | ||
| 28 | |||
| 29 | When the ReadDirectoryChangesW call completes, its completion | ||
| 30 | routine watch_completion is automatically called. watch_completion | ||
| 31 | stashes the received file events in a buffer used to communicate | ||
| 32 | them to the main thread (using a critical section, so that several | ||
| 33 | threads could use the same buffer), posts a special message, | ||
| 34 | WM_EMACS_FILENOTIFY, to the Emacs's message queue, and returns. | ||
| 35 | That causes the SleepEx function call inside watch_worker to | ||
| 36 | return, and watch_worker then issues another call to | ||
| 37 | ReadDirectoryChangesW. (Except when it does not, see below.) | ||
| 38 | |||
| 39 | The WM_EMACS_FILENOTIFY message, posted to the message queue gets | ||
| 40 | dispatched to the main Emacs window procedure, which queues it for | ||
| 41 | processing by w32_read_socket. When w32_read_socket sees this | ||
| 42 | message, it accesses the buffer with file notifications (using a | ||
| 43 | critical section), extracts the information, converts it to a | ||
| 44 | series of FILE_NOTIFY_EVENT events, and stuffs them into the input | ||
| 45 | event queue to be processed by keyboard.c input machinery | ||
| 46 | (read_char via a call to kbd_buffer_get_event). When the | ||
| 47 | FILE_NOTIFY_EVENT event is processed by kbd_buffer_get_event, it is | ||
| 48 | converted to a Lispy event that can be bound to a command. The | ||
| 49 | default binding is w32notify-handle-event, defined on subr.el. | ||
| 50 | |||
| 51 | After w32_read_socket is done processing the notifications, it | ||
| 52 | resets a flag signaling to all watch worker threads that the | ||
| 53 | notifications buffer is available for more input. | ||
| 54 | |||
| 55 | When the watch is removed by a call to w32notify-rm-watch, the main | ||
| 56 | thread requests that the worker thread terminates by queuing an APC | ||
| 57 | for the worker thread. The APC specifies the watch_end function to | ||
| 58 | be called. watch_end calls CancelIo on the outstanding | ||
| 59 | ReadDirectoryChangesW call and closes the handle on which the | ||
| 60 | watched directory was open. When watch_end returns, the | ||
| 61 | watch_completion function is called one last time with the | ||
| 62 | ERROR_OPERATION_ABORTED status, which causes it to clean up and set | ||
| 63 | a flag telling watch_worker to exit without issuing another | ||
| 64 | ReadDirectoryChangesW call. The main thread waits for the worker | ||
| 65 | thread to exit, and if it doesn't, terminate it forcibly. */ | ||
| 66 | |||
| 19 | #include <stddef.h> | 67 | #include <stddef.h> |
| 20 | #include <errno.h> | 68 | #include <errno.h> |
| 21 | 69 | ||
| @@ -58,51 +106,6 @@ static Lisp_Object Qfile_name, Qdirectory_name, Qattributes, Qsize; | |||
| 58 | static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time; | 106 | static Lisp_Object Qlast_write_time, Qlast_access_time, Qcreation_time; |
| 59 | static Lisp_Object Qsecurity_desc, Qsubtree, watch_list; | 107 | static Lisp_Object Qsecurity_desc, Qsubtree, watch_list; |
| 60 | 108 | ||
| 61 | #if 0 | ||
| 62 | /* FIXME: Debugging code, should be removed eventually. */ | ||
| 63 | const wchar_t * | ||
| 64 | format_file_action (DWORD action) | ||
| 65 | { | ||
| 66 | static const wchar_t *action_str[] = | ||
| 67 | { L"???", L"Added", L"Removed", L"Modified", L"Renamed from", L"Renamed to" }; | ||
| 68 | |||
| 69 | if (action >= sizeof(action_str)/sizeof(action_str[0])) | ||
| 70 | action = 0; | ||
| 71 | return action_str[action]; | ||
| 72 | } | ||
| 73 | |||
| 74 | void | ||
| 75 | parse_notifications (BYTE *info, DWORD info_size) | ||
| 76 | { | ||
| 77 | BYTE *p = info; | ||
| 78 | FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p; | ||
| 79 | const DWORD min_size | ||
| 80 | = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t); | ||
| 81 | |||
| 82 | if (!info_size) | ||
| 83 | { | ||
| 84 | printf ("No info in notifications!\n"); | ||
| 85 | return; | ||
| 86 | } | ||
| 87 | |||
| 88 | while (info_size >= min_size) | ||
| 89 | { | ||
| 90 | wchar_t *fn = alloca (fni->FileNameLength + sizeof(wchar_t)); | ||
| 91 | const wchar_t *action_str; | ||
| 92 | |||
| 93 | memcpy (fn, fni->FileName, fni->FileNameLength); | ||
| 94 | fn[fni->FileNameLength/sizeof(wchar_t)] = 0; | ||
| 95 | action_str = format_file_action (fni->Action); | ||
| 96 | wprintf (L"%s: %s\n", action_str, fn); | ||
| 97 | if (!fni->NextEntryOffset) | ||
| 98 | break; | ||
| 99 | p += fni->NextEntryOffset; | ||
| 100 | fni = (PFILE_NOTIFY_INFORMATION)p; | ||
| 101 | info_size -= fni->NextEntryOffset; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | #endif /* debugging code */ | ||
| 105 | |||
| 106 | /* Signal to the main thread that we have file notifications for it to | 109 | /* Signal to the main thread that we have file notifications for it to |
| 107 | process. */ | 110 | process. */ |
| 108 | static void | 111 | static void |
| @@ -141,7 +144,6 @@ send_notifications (BYTE *info, DWORD info_size, HANDLE hdir, int *terminate) | |||
| 141 | if (PostMessage (FRAME_W32_WINDOW (f), WM_EMACS_FILENOTIFY, 0, 0)) | 144 | if (PostMessage (FRAME_W32_WINDOW (f), WM_EMACS_FILENOTIFY, 0, 0)) |
| 142 | notification_buffer_in_use = 1; | 145 | notification_buffer_in_use = 1; |
| 143 | done = 1; | 146 | done = 1; |
| 144 | DebPrint (("Announced notifications of %lu bytes\n", info_size)); | ||
| 145 | } | 147 | } |
| 146 | leave_crit (); | 148 | leave_crit (); |
| 147 | if (!done) | 149 | if (!done) |
| @@ -205,9 +207,6 @@ watch_completion (DWORD status, DWORD bytes_ret, OVERLAPPED *io_info) | |||
| 205 | } | 207 | } |
| 206 | else | 208 | else |
| 207 | { | 209 | { |
| 208 | #if 0 /* debugging code */ | ||
| 209 | parse_notifications (dirwatch->buf, bytes_ret); | ||
| 210 | #endif | ||
| 211 | /* Tell the main thread we have notifications for it. */ | 210 | /* Tell the main thread we have notifications for it. */ |
| 212 | send_notifications (dirwatch->buf, bytes_ret, dirwatch->dir, | 211 | send_notifications (dirwatch->buf, bytes_ret, dirwatch->dir, |
| 213 | &dirwatch->terminate); | 212 | &dirwatch->terminate); |
| @@ -233,7 +232,7 @@ watch_worker (LPVOID arg) | |||
| 233 | dirwatch->io_info, watch_completion); | 232 | dirwatch->io_info, watch_completion); |
| 234 | if (!status) | 233 | if (!status) |
| 235 | { | 234 | { |
| 236 | DebPrint (("watch_worker(1): %lu\n", GetLastError ())); | 235 | DebPrint (("watch_worker, abnormal exit: %lu\n", GetLastError ())); |
| 237 | xfree (dirwatch->buf); | 236 | xfree (dirwatch->buf); |
| 238 | dirwatch->buf = NULL; | 237 | dirwatch->buf = NULL; |
| 239 | xfree (dirwatch->io_info); | 238 | xfree (dirwatch->io_info); |
| @@ -249,11 +248,8 @@ watch_worker (LPVOID arg) | |||
| 249 | could be either a change notification or a cancellation of the | 248 | could be either a change notification or a cancellation of the |
| 250 | watch. */ | 249 | watch. */ |
| 251 | sleep_result = SleepEx (INFINITE, TRUE); | 250 | sleep_result = SleepEx (INFINITE, TRUE); |
| 252 | if (dirwatch->terminate) | ||
| 253 | DebPrint (("watch_worker: exiting by request\n")); | ||
| 254 | } while (!dirwatch->terminate); | 251 | } while (!dirwatch->terminate); |
| 255 | 252 | ||
| 256 | DebPrint (("watch_worker(2): %lu\n", GetLastError ())); | ||
| 257 | return 0; | 253 | return 0; |
| 258 | } | 254 | } |
| 259 | 255 | ||
diff --git a/src/w32term.c b/src/w32term.c index 1c32383098f..71e6c7235a1 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -3204,6 +3204,9 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f) | |||
| 3204 | return Qnil; | 3204 | return Qnil; |
| 3205 | } | 3205 | } |
| 3206 | 3206 | ||
| 3207 | |||
| 3208 | /* File event notifications (see w32notify.c). */ | ||
| 3209 | |||
| 3207 | static Lisp_Object | 3210 | static Lisp_Object |
| 3208 | lispy_file_action (DWORD action) | 3211 | lispy_file_action (DWORD action) |
| 3209 | { | 3212 | { |
| @@ -4945,7 +4948,6 @@ w32_read_socket (struct terminal *terminal, | |||
| 4945 | break; | 4948 | break; |
| 4946 | 4949 | ||
| 4947 | case WM_EMACS_FILENOTIFY: | 4950 | case WM_EMACS_FILENOTIFY: |
| 4948 | DebPrint (("w32_read_socket: File notification arrived\n")); | ||
| 4949 | f = x_window_to_frame (dpyinfo, msg.msg.hwnd); | 4951 | f = x_window_to_frame (dpyinfo, msg.msg.hwnd); |
| 4950 | if (f) | 4952 | if (f) |
| 4951 | queue_notifications (&inev, &msg, f, &count); | 4953 | queue_notifications (&inev, &msg, f, &count); |