X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=src%2Fevent-msw.c;h=45e77ee71115aa44e276272840f6e037e3c243aa;hp=e6e87d151643a86dff71b27967f1a07d7d92db9e;hb=1e7fd761ecf5fd2208bde8e30fc6f7cbf789b7db;hpb=77dcef404dc78635f6ffa8f71a803d2bc7cc8921 diff --git a/src/event-msw.c b/src/event-msw.c index e6e87d1..45e77ee 100644 --- a/src/event-msw.c +++ b/src/event-msw.c @@ -28,6 +28,7 @@ Boston, MA 02111-1307, USA. */ Ultimately based on FSF. Rewritten by Ben Wing. Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0. + Subprocess and modal loop support by Kirill M. Katsnelson. */ #include @@ -50,6 +51,8 @@ Boston, MA 02111-1307, USA. */ #include "device.h" #include "events.h" #include "frame.h" +#include "buffer.h" +#include "faces.h" #include "lstream.h" #include "process.h" #include "redisplay.h" @@ -57,16 +60,22 @@ Boston, MA 02111-1307, USA. */ #include "syswait.h" #include "systime.h" #include "sysdep.h" +#include "objects-msw.h" #include "events-mod.h" #ifdef HAVE_MSG_SELECT #include "sysfile.h" +#include "console-tty.h" #elif defined(__CYGWIN32__) typedef unsigned int SOCKET; #endif #include #include +#if defined (__CYGWIN32__) && !defined (CYGWIN_VERSION_DLL_MAJOR) +typedef NMHDR *LPNMHDR; +#endif + #ifdef HAVE_MENUBARS #define ADJR_MENUFLAG TRUE #else @@ -84,6 +93,8 @@ extern Lisp_Object mswindows_get_toolbar_button_text (struct frame* f, int command_id); extern Lisp_Object mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id); +extern Lisp_Object +mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id); static Lisp_Object mswindows_find_frame (HWND hwnd); static Lisp_Object mswindows_find_console (HWND hwnd); @@ -115,11 +126,16 @@ static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_ /* The number of things we can wait on */ #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1) +#ifndef HAVE_MSG_SELECT /* List of mswindows waitable handles. */ static HANDLE mswindows_waitable_handles[MAX_WAITABLE]; /* Number of wait handles */ static int mswindows_waitable_count=0; +#endif /* HAVE_MSG_SELECT */ +/* Brush for painting widgets */ +static HBRUSH widget_brush = 0; +static LONG last_widget_brushed = 0; /* Count of quit chars currently in the queue */ /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc() @@ -470,6 +486,7 @@ struct ntpipe_shove_stream DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove, sizeof (struct ntpipe_shove_stream)); +#ifndef HAVE_MSG_SELECT static DWORD WINAPI shove_thread (LPVOID vparam) { @@ -541,6 +558,7 @@ get_ntpipe_output_stream_param (Lstream *stream) struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); return s->user_data; } +#endif static int ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size) @@ -939,6 +957,13 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWO { event->event_type = button_press_event; SetCapture (hwnd); + /* we need this to make sure the main window regains the focus + from control subwindows */ + if (GetFocus() != hwnd) + { + SetFocus (hwnd); + mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS); + } } else { @@ -997,18 +1022,18 @@ mswindows_dequeue_dispatch_event () /* * Remove and return the first emacs event on the dispatch queue that matches - * the supplied event - * Timeout event matches if interval_id equals to that of the given event. + * the supplied event. + * Timeout event matches if interval_id is equal to that of the given event. * Keypress event matches if logical AND between modifiers bitmask of the - * event in the queue and that of the given event is non-zero - * For all other event types, this function asserts. + * event in the queue and that of the given event is non-zero. + * For all other event types, this function aborts. */ Lisp_Object -mswindows_cancel_dispatch_event (struct Lisp_Event* match) +mswindows_cancel_dispatch_event (struct Lisp_Event *match) { Lisp_Object event; - Lisp_Object previous_event=Qnil; + Lisp_Object previous_event = Qnil; int user_p = mswindows_user_event_p (match); Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : &mswindows_s_dispatch_event_queue; @@ -1020,19 +1045,12 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match) EVENT_CHAIN_LOOP (event, *head) { - int found = 1; - if (XEVENT_TYPE (event) != match->event_type) - found = 0; - if (found && match->event_type == timeout_event - && (XEVENT(event)->event.timeout.interval_id != - match->event.timeout.interval_id)) - found = 0; - if (found && match->event_type == key_press_event - && ((XEVENT(event)->event.key.modifiers & - match->event.key.modifiers) == 0)) - found = 0; - - if (found) + struct Lisp_Event *e = XEVENT (event); + if ((e->event_type == match->event_type) && + ((e->event_type == timeout_event) ? + (e->event.timeout.interval_id == match->event.timeout.interval_id) : + /* Must be key_press_event */ + ((e->event.key.modifiers & match->event.key.modifiers) != 0))) { if (NILP (previous_event)) dequeue_event (head, tail); @@ -1050,6 +1068,7 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match) return Qnil; } +#ifndef HAVE_MSG_SELECT /************************************************************************/ /* Waitable handles manipulation */ /************************************************************************/ @@ -1085,6 +1104,7 @@ remove_waitable_handle (HANDLE h) mswindows_waitable_handles [ix] = mswindows_waitable_handles [--mswindows_waitable_count]; } +#endif /* HAVE_MSG_SELECT */ /************************************************************************/ @@ -1214,6 +1234,14 @@ mswindows_drain_windows_queue () MSG msg; while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { + /* we have to translate messages that are not sent to the main + window. this is so that key presses work ok in things like + edit fields. however, we *musn't* translate message for the + main window as this is handled in the wnd proc. */ + if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD ) + { + TranslateMessage (&msg); + } DispatchMessage (&msg); mswindows_unmodalize_signal_maybe (); } @@ -1299,32 +1327,11 @@ mswindows_need_event (int badly_p) pointer_to_this = &select_time_to_block; } - /* select() is slow and buggy so if we don't have any processes - just wait as normal */ - if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0) - { - /* Now try getting a message or process event */ - active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles, - FALSE, badly_p ? INFINITE : 0, - QS_ALLINPUT); - - if (active == WAIT_TIMEOUT) - { - /* No luck trying - just return what we've already got */ - return; - } - else if (active == WAIT_OBJECT_0) - { - /* Got your message, thanks */ - mswindows_drain_windows_queue (); - continue; - } - } - active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this); if (active == 0) { + assert (!badly_p); return; /* timeout */ } else if (active > 0) @@ -1333,7 +1340,28 @@ mswindows_need_event (int badly_p) { mswindows_drain_windows_queue (); } - +#ifdef HAVE_TTY + /* Look for a TTY event */ + for (i = 0; i < MAXDESC-1; i++) + { + /* To avoid race conditions (among other things, an infinite + loop when called from Fdiscard_input()), we must return + user events ahead of process events. */ + if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) + { + struct console *c = tty_find_console_from_fd (i); + Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); + struct Lisp_Event* event = XEVENT (emacs_event); + + assert (c); + if (read_event_from_tty_or_stream_desc (event, c, i)) + { + mswindows_enqueue_dispatch_event (emacs_event); + return; + } + } + } +#endif /* Look for a process event */ for (i = 0; i < MAXDESC-1; i++) { @@ -1346,11 +1374,6 @@ mswindows_need_event (int badly_p) mswindows_enqueue_process_event (p); } - else if (FD_ISSET (i, &tty_only_mask)) - { - /* do we care about tty events? Do we - ever get tty events? */ - } else { /* We might get here when a fake event came @@ -1446,6 +1469,8 @@ mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime) event->timestamp = dwtime; event->event_type = timeout_event; event->event.timeout.interval_id = id_timer; + event->event.timeout.function = Qnil; + event->event.timeout.object = Qnil; mswindows_enqueue_dispatch_event (emacs_event); } @@ -1646,7 +1671,15 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); BYTE keymap_orig[256]; - MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) }; + POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; + MSG msg; + + msg.hwnd = hwnd; + msg.message = message; + msg.wParam = wParam; + msg.lParam = lParam; + msg.time = GetMessageTime(); + msg.pt = pnt; /* GetKeyboardState() does not work as documented on Win95. We have * to loosely track Left and Right modifiers on behalf of the OS, @@ -1897,17 +1930,20 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) Qcancel_mode_internal, Qnil); break; -#ifdef HAVE_TOOLBARS case WM_NOTIFY: { - LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; - Lisp_Object btext; - if (tttext->hdr.code == TTN_NEEDTEXT) + LPNMHDR nmhdr = (LPNMHDR)lParam; + + if (nmhdr->code == TTN_NEEDTEXT) { +#ifdef HAVE_TOOLBARS + LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; + Lisp_Object btext; + /* find out which toolbar */ frame = XFRAME (mswindows_find_frame (hwnd)); btext = mswindows_get_toolbar_button_text ( frame, - tttext->hdr.idFrom ); + nmhdr->idFrom ); tttext->lpszText = NULL; tttext->hinst = NULL; @@ -1916,15 +1952,33 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { /* I think this is safe since the text will only go away when the toolbar does...*/ - tttext->lpszText=XSTRING_DATA (btext); + GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS, + tttext->lpszText); } -#if 0 - tttext->uFlags |= TTF_DI_SETITEM; #endif - } + } + /* handle tree view callbacks */ + else if (nmhdr->code == TVN_SELCHANGED) + { + NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam; + frame = XFRAME (mswindows_find_frame (hwnd)); + mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); + } + /* handle tab control callbacks */ + else if (nmhdr->code == TCN_SELCHANGE) + { + TC_ITEM item; + int index = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); + frame = XFRAME (mswindows_find_frame (hwnd)); + + item.mask = TCIF_PARAM; + SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index, + (LPARAM)&item); + + mswindows_handle_gui_wm_command (frame, 0, item.lParam); + } } break; -#endif case WM_PAINT: { @@ -2113,6 +2167,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_COMMAND: { WORD id = LOWORD (wParam); + WORD nid = HIWORD (wParam); HWND cid = (HWND)lParam; frame = XFRAME (mswindows_find_frame (hwnd)); @@ -2120,17 +2175,85 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) break; #endif - + /* widgets in a buffer only eval a callback for suitable events.*/ + switch (nid) + { + case BN_CLICKED: + case EN_CHANGE: + case CBN_EDITCHANGE: + case CBN_SELCHANGE: + if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) + return 0; + } + /* menubars always must come last since the hashtables do not + always exist*/ #ifdef HAVE_MENUBARS if (!NILP (mswindows_handle_wm_command (frame, id))) break; #endif - /* Bite me - a spurious command. This cannot happen. */ - error ("XEMACS BUG: Cannot decode command message"); + return DefWindowProc (hwnd, message, wParam, lParam); + /* Bite me - a spurious command. This used to not be able to + happen but with the introduction of widgets its now + possible. */ } break; + case WM_CTLCOLORBTN: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + case WM_CTLCOLORSCROLLBAR: + { + /* if we get an opportunity to paint a widget then do so if + there is an appropriate face */ + HWND crtlwnd = (HWND)lParam; + LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA); + if (ii) + { + Lisp_Object image_instance; + VOID_TO_LISP (image_instance, ii); + if (IMAGE_INSTANCEP (image_instance) + && + IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET) + && + !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance))) + { + /* set colors for the buttons */ + HDC hdc = (HDC)wParam; + if (last_widget_brushed != ii) + { + if (widget_brush) + DeleteObject (widget_brush); + widget_brush = CreateSolidBrush + (COLOR_INSTANCE_MSWINDOWS_COLOR + (XCOLOR_INSTANCE + (FACE_BACKGROUND + (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), + XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + } + last_widget_brushed = ii; + SetTextColor + (hdc, + COLOR_INSTANCE_MSWINDOWS_COLOR + (XCOLOR_INSTANCE + (FACE_FOREGROUND + (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), + XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + SetBkMode (hdc, OPAQUE); + SetBkColor + (hdc, + COLOR_INSTANCE_MSWINDOWS_COLOR + (XCOLOR_INSTANCE + (FACE_BACKGROUND + (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), + XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + return (LRESULT)widget_brush; + } + } + } + goto defproc; + #ifdef HAVE_DRAGNDROP case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ { @@ -2454,7 +2577,7 @@ emacs_mswindows_next_event (struct Lisp_Event *emacs_event) mswindows_need_event (1); - event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue)); + event = mswindows_dequeue_dispatch_event (); XSETEVENT (event2, emacs_event); Fcopy_event (event, event2); Fdeallocate_event (event); @@ -2516,6 +2639,7 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) } } +#ifndef HAVE_MSG_SELECT static HANDLE get_process_input_waitable (struct Lisp_Process *process) { @@ -2565,28 +2689,47 @@ emacs_mswindows_unselect_process (struct Lisp_Process *process) HANDLE hev = get_process_input_waitable (process); remove_waitable_handle (hev); } +#endif /* HAVE_MSG_SELECT */ static void emacs_mswindows_select_console (struct console *con) { +#ifdef HAVE_MSG_SELECT + if (CONSOLE_MSWINDOWS_P (con)) + return; /* mswindows consoles are automatically selected */ + + event_stream_unixoid_select_console (con); +#endif } static void emacs_mswindows_unselect_console (struct console *con) { +#ifdef HAVE_MSG_SELECT + if (CONSOLE_MSWINDOWS_P (con)) + return; /* mswindows consoles are automatically selected */ + + event_stream_unixoid_unselect_console (con); +#endif } static void emacs_mswindows_quit_p (void) { + MSG msg; + /* Quit cannot happen in modal loop: all program input is dedicated to Windows. */ if (mswindows_in_modal_loop) return; - /* Drain windows queue. This sets up number of quit - characters in in the queue */ - mswindows_drain_windows_queue (); + /* Drain windows queue. This sets up number of quit characters in the queue + * (and also processes wm focus change, move, resize, etc messages). + * We don't want to process WM_PAINT messages because this function can be + * called from almost anywhere and the windows' states may be changing. */ + while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) || + PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE)) + DispatchMessage (&msg); if (mswindows_quit_chars_count > 0) {