From 477f1e504482847a3b1209bc0a1dccfded649370 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 6 Oct 2012 20:02:31 +0200 Subject: [PATCH] Initial version of the w32notify code. Adding and removing a watch seems to work: a new thread is launched when a watch is added and exits when the watch is removed. But there are no notifications, so it seems. At least, the Lisp callback function passed to w32notify-add-watch is not called. --- lib-src/makefile.w32-in | 2 +- lisp/subr.el | 11 ++++ src/alloc.c | 2 +- src/emacs.c | 1 + src/keyboard.c | 15 ++++- src/lisp.h | 5 ++ src/makefile.w32-in | 14 ++++- src/termhooks.h | 1 + src/w32term.c | 127 ++++++++++++++++++++++++++++++++++++++++ src/w32term.h | 8 ++- 10 files changed, 181 insertions(+), 5 deletions(-) diff --git a/lib-src/makefile.w32-in b/lib-src/makefile.w32-in index 23ef71de10c..d53f768cfa8 100644 --- a/lib-src/makefile.w32-in +++ b/lib-src/makefile.w32-in @@ -126,7 +126,7 @@ obj = dosfns.o msdos.o \ fontset.o menu.o \ w32.o w32console.o w32fns.o w32heap.o w32inevt.o \ w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ - font.o w32font.o w32uniscribe.o \ + font.o w32font.o w32uniscribe.o w32notify.o \ dispnew.o frame.o scroll.o xdisp.o window.o bidi.o \ charset.o coding.o category.o ccl.o character.o chartab.o \ cm.o term.o terminal.o xfaces.o \ diff --git a/lisp/subr.el b/lisp/subr.el index 72bedc69c3c..9b557dcfd20 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -1167,6 +1167,17 @@ The return value has the form (WIDTH . HEIGHT). POSITION should be a list of the form returned by `event-start' and `event-end'." (nth 9 position)) +(defun w32notify-handle-event (event) + "Handle file system monitoring event. +If EVENT is a file-notification event, then its callback is called. +Otherwise, a `filewatch-error' is signaled." + (interactive "e") + + (if (and (eq (car event) 'file-notify) + (= (length event) 3)) + (funcall (nth 2 event) (nth 1 event)) + (signal 'filewatch-error (cons "Not a valid file-notify event" event)))) + ;;;; Obsolescent names for functions. diff --git a/src/alloc.c b/src/alloc.c index 3ed8cc2d990..dd3a93ae019 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -376,7 +376,7 @@ struct gcpro *gcprolist; /* Addresses of staticpro'd variables. Initialize it to a nonzero value; otherwise some compilers put it into BSS. */ -#define NSTATICS 0x650 +#define NSTATICS 0x660 static Lisp_Object *staticvec[NSTATICS] = {&Vpurify_flag}; /* Index of next unused slot in staticvec. */ diff --git a/src/emacs.c b/src/emacs.c index bc54f56b98a..65ee11fb261 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -1417,6 +1417,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem #ifdef WINDOWSNT syms_of_ntterm (); + syms_of_w32notify (); #endif /* WINDOWSNT */ syms_of_profiler (); diff --git a/src/keyboard.c b/src/keyboard.c index d06b02024c5..6597ebd884b 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -314,7 +314,7 @@ static Lisp_Object Qmouse_fixup_help_message; static Lisp_Object Qfunction_key; Lisp_Object Qmouse_click; #if defined (WINDOWSNT) -Lisp_Object Qlanguage_change; +Lisp_Object Qlanguage_change, Qfile_notify; #endif static Lisp_Object Qdrag_n_drop; static Lisp_Object Qsave_session; @@ -3957,6 +3957,16 @@ kbd_buffer_get_event (KBOARD **kbp, make_number (event->modifiers))); kbd_fetch_ptr = event + 1; } + else if (event->kind == FILE_NOTIFY_EVENT) + { + /* Make an event (file-notify (DESCRIPTOR ACTION FILE) CALLBACK). */ + obj = Fcons (Qfile_notify, + list2 (list3 (event->code, + XCAR (event->arg), + CAR_SAFE (XCDR (event->arg))), + event->frame_or_window)); + kbd_fetch_ptr = event + 1; + } #endif else if (event->kind == SAVE_SESSION_EVENT) { @@ -11396,6 +11406,7 @@ syms_of_keyboard (void) #if defined (WINDOWSNT) DEFSYM (Qlanguage_change, "language-change"); + DEFSYM (Qfile_notify, "file-notify"); #endif #ifdef HAVE_DBUS @@ -12167,6 +12178,8 @@ keys_of_keyboard (void) #if defined (WINDOWSNT) initial_define_lispy_key (Vspecial_event_map, "language-change", "ignore"); + initial_define_lispy_key (Vspecial_event_map, "file-notify", + "w32notify-handlde-event"); #endif } diff --git a/src/lisp.h b/src/lisp.h index 2a647e593a8..7812e58782b 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -3497,6 +3497,11 @@ extern void syms_of_fontset (void); extern Lisp_Object Qfont_param; #endif +#ifdef WINDOWSNT +/* Defined on w32notify.c. */ +extern void syms_of_w32notify (void); +#endif + /* Defined in xfaces.c. */ extern Lisp_Object Qdefault, Qtool_bar, Qfringe; extern Lisp_Object Qheader_line, Qscroll_bar, Qcursor; diff --git a/src/makefile.w32-in b/src/makefile.w32-in index c6fbf59fb5a..f051ed6a8a9 100644 --- a/src/makefile.w32-in +++ b/src/makefile.w32-in @@ -134,6 +134,7 @@ OBJ2 = $(BLD)/sysdep.$(O) \ $(BLD)/w32menu.$(O) \ $(BLD)/w32reg.$(O) \ $(BLD)/w32font.$(O) \ + $(BLD)/w32notify.$(O) \ $(BLD)/w32uniscribe.$(O) LIBS = $(TLIB0) \ @@ -209,7 +210,7 @@ GLOBAL_SOURCES = dosfns.c msdos.c \ fontset.c menu.c dbusbind.c \ w32.c w32console.c w32fns.c w32heap.c w32inevt.c \ w32menu.c w32proc.c w32reg.c w32select.c w32term.c w32xfns.c \ - font.c w32font.c w32uniscribe.c \ + font.c w32font.c w32uniscribe.c w32notify.c \ dispnew.c frame.c scroll.c xdisp.c window.c bidi.c \ charset.c coding.c category.c ccl.c character.c chartab.c \ cm.c term.c terminal.c xfaces.c \ @@ -1673,6 +1674,17 @@ $(BLD)/w32uniscribe.$(O) : \ $(W32FONT_H) \ $(W32TERM_H) +$(BLD)/w32notify.$(O) : \ + $(SRC)/w32notify.c \ + $(SRC)/w32heap.h \ + $(CODING_H) \ + $(CONFIG_H) \ + $(FRAME_H) \ + $(KEYBOARD_H) \ + $(LISP_H) \ + $(TERMHOOKS_H) \ + $(W32TERM_H) + # Each object file depends on stamp_BLD, because in parallel builds we must # make sure $(BLD) exists before starting compilations. # diff --git a/src/termhooks.h b/src/termhooks.h index f35bd929af1..0afd7d97e7b 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -201,6 +201,7 @@ enum event_kind On X, the window manager seems to grab the keys it wants first, so this is not a problem there. */ , MULTIMEDIA_KEY_EVENT + , FILE_NOTIFY_EVENT #endif #ifdef HAVE_NS diff --git a/src/w32term.c b/src/w32term.c index 1cc8bd2adef..951ce9ef2df 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -235,6 +235,8 @@ static void x_check_font (struct frame *, struct font *); #endif static Lisp_Object Qvendor_specific_keysyms; +static Lisp_Object Qadded, Qremoved, Qmodified; +static Lisp_Object Qrenamed_from, Qrenamed_to; /*********************************************************************** @@ -3202,6 +3204,119 @@ construct_drag_n_drop (struct input_event *result, W32Msg *msg, struct frame *f) return Qnil; } +static Lisp_Object +lispy_file_action (DWORD action) +{ + static char unknown_fmt[] = "unknown-action(%d)"; + Lisp_Object retval; + + switch (action) + { + case FILE_ACTION_ADDED: + retval = Qadded; + break; + case FILE_ACTION_REMOVED: + retval = Qremoved; + break; + case FILE_ACTION_MODIFIED: + retval = Qmodified; + break; + case FILE_ACTION_RENAMED_OLD_NAME: + retval = Qrenamed_from; + break; + case FILE_ACTION_RENAMED_NEW_NAME: + retval = Qrenamed_to; + break; + default: + { + char buf[sizeof(unknown_fmt) - 1 + INT_STRLEN_BOUND (DWORD)]; + + sprintf (buf, unknown_fmt, action); + retval = intern (buf); + } + break; + } + + return retval; +} + +/* Put file notifications into the Emacs input event queue. This + function runs when the WM_EMACS_FILENOTIFY message arrives from a + watcher thread. */ +static void +queue_notifications (struct input_event *event, W32Msg *msg, struct frame *f, + int *evcount) +{ + BYTE *p = file_notifications; + FILE_NOTIFY_INFORMATION *fni = (PFILE_NOTIFY_INFORMATION)p; + const DWORD min_size + = offsetof (FILE_NOTIFY_INFORMATION, FileName) + sizeof(wchar_t); + Lisp_Object frame; + + /* We cannot process notification before Emacs is fully initialized, + since we need the UTF-16LE coding-system to be set up. */ + if (!initialized) + { + notification_buffer_in_use = 0; + return; + } + + XSETFRAME (frame, f); + + enter_crit (); + if (notification_buffer_in_use) + { + DWORD info_size = notifications_size; + + /* notifications_size could be zero when the buffer of + notifications overflowed on the OS level, or when the + directory being watched was itself deleted. Do nothing in + that case. */ + if (info_size) + { + while (info_size >= min_size) + { + Lisp_Object utf_16_fn + = make_unibyte_string ((char *)fni->FileName, + fni->FileNameLength); + /* Note: mule-conf is preloaded, so utf-16le must + already be defined at this point. */ + Lisp_Object fname + = code_convert_string_norecord (utf_16_fn, + intern ("utf-16le"), 0); + Lisp_Object action = lispy_file_action (fni->Action); + Lisp_Object obj; + + obj = get_watch_object (make_number (notifications_desc)); + if (!NILP (obj) && CONSP (obj)) + { + event->kind = FILE_NOTIFY_EVENT; + event->code = (ptrdiff_t)notifications_desc; + event->timestamp = msg->msg.time; + event->modifiers = 0; + event->frame_or_window = XCDR (obj); + event->arg = Fcons (action, fname); + kbd_buffer_store_event (event); + (*evcount)++; + } + + if (!fni->NextEntryOffset) + break; + p += fni->NextEntryOffset; + fni = (PFILE_NOTIFY_INFORMATION)p; + info_size -= fni->NextEntryOffset; + } + } + notification_buffer_in_use = 0; + } + else + DebPrint (("We were promised notifications, but in-use flag is zero!\n")); + leave_crit (); + + /* We've stuffed all the events ourselves, so w32_read_socket shouldn't. */ + event->kind = NO_EVENT; +} + /* Function to report a mouse movement to the mainstream Emacs code. The input handler calls this. @@ -4829,6 +4944,12 @@ w32_read_socket (struct terminal *terminal, check_visibility = 1; break; + case WM_EMACS_FILENOTIFY: + f = x_window_to_frame (dpyinfo, msg.msg.hwnd); + if (f) + queue_notifications (&inev, &msg, f, &count); + break; + default: /* Check for messages registered at runtime. */ if (msg.msg.message == msh_mousewheel) @@ -6494,6 +6615,12 @@ syms_of_w32term (void) DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms"); + DEFSYM (Qadded, "added"); + DEFSYM (Qremoved, "removed"); + DEFSYM (Qmodified, "modified"); + DEFSYM (Qrenamed_from, "renamed-from"); + DEFSYM (Qrenamed_to, "renamed-to"); + DEFVAR_INT ("w32-num-mouse-buttons", w32_num_mouse_buttons, doc: /* Number of physical mouse buttons. */); diff --git a/src/w32term.h b/src/w32term.h index fcaccc4d624..75537458981 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -584,7 +584,8 @@ do { \ #define WM_EMACS_SETCURSOR (WM_EMACS_START + 19) #define WM_EMACS_PAINT (WM_EMACS_START + 20) #define WM_EMACS_BRINGTOTOP (WM_EMACS_START + 21) -#define WM_EMACS_END (WM_EMACS_START + 22) +#define WM_EMACS_FILENOTIFY (WM_EMACS_START + 22) +#define WM_EMACS_END (WM_EMACS_START + 23) #define WND_FONTWIDTH_INDEX (0) #define WND_LINEHEIGHT_INDEX (4) @@ -642,6 +643,11 @@ extern BOOL parse_button (int, int, int *, int *); extern void w32_sys_ring_bell (struct frame *f); extern void x_delete_display (struct w32_display_info *dpyinfo); +extern int notification_buffer_in_use; +extern BYTE file_notifications[16384]; +extern DWORD notifications_size; +extern HANDLE notifications_desc; +extern Lisp_Object get_watch_object (Lisp_Object); /* Keypad command key support. W32 doesn't have virtual keys defined for the function keys on the keypad (they are mapped to the standard -- 2.39.5