X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=src%2Fevent-msw.c;h=4745a6653a151f9857b547b05d459ae346a6ebda;hp=681743edf440b258859af33b41e82adf3204484d;hb=02f4d2761a98c5cb9d5b423d2361160a5d8c9ee4;hpb=2fd9701a4f902054649dde9143a3f77809afee8f diff --git a/src/event-msw.c b/src/event-msw.c index 681743e..4745a66 100644 --- a/src/event-msw.c +++ b/src/event-msw.c @@ -1,4 +1,4 @@ -/* The mswindows event_stream interface. +/* The mswindows event_stream interface. Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. Copyright (C) 1995 Sun Microsystems, Inc. Copyright (C) 1996, 2000 Ben Wing. @@ -49,39 +49,36 @@ Boston, MA 02111-1307, USA. */ # include "dragdrop.h" #endif +#include "buffer.h" #include "device.h" #include "events.h" -#include "frame.h" -#include "buffer.h" #include "faces.h" +#include "frame.h" #include "lstream.h" +#include "objects-msw.h" #include "process.h" #include "redisplay.h" #include "select.h" +#include "sysdep.h" +#include "window.h" + +#include "sysfile.h" #include "sysproc.h" -#include "syswait.h" #include "systime.h" -#include "sysdep.h" -#include "objects-msw.h" +#include "syswait.h" #include "events-mod.h" + #ifdef HAVE_MSG_SELECT -#include "sysfile.h" #include "console-tty.h" -#elif defined(__CYGWIN32__) +#elif defined(CYGWIN) typedef unsigned int SOCKET; #endif -#include -#include -#if !(defined(__CYGWIN32__) || defined(__MINGW32__)) +#if !(defined(CYGWIN) || defined(MINGW)) # include /* For IShellLink */ #endif -#if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20) -typedef NMHDR *LPNMHDR; -#endif - #ifdef HAVE_MENUBARS #define ADJR_MENUFLAG TRUE #else @@ -90,7 +87,8 @@ typedef NMHDR *LPNMHDR; /* Fake key modifier which is attached to a quit char event. Removed upon dequeueing an event */ -#define FAKE_MOD_QUIT 0x80 +#define FAKE_MOD_QUIT (1 << 20) +#define FAKE_MOD_QUIT_CRITICAL (1 << 21) /* Timer ID used for button2 emulation */ #define BUTTON_2_TIMER_ID 1 @@ -99,10 +97,13 @@ static Lisp_Object mswindows_find_frame (HWND hwnd); static Lisp_Object mswindows_find_console (HWND hwnd); static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, int extendedp); -static int mswindows_modifier_state (BYTE* keymap, int has_AltGr); +static int mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, + int has_AltGr); static void mswindows_set_chord_timer (HWND hwnd); static int mswindows_button2_near_enough (POINTS p1, POINTS p2); static int mswindows_current_layout_has_AltGr (void); +static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, + int downp, int keyp); static struct event_stream *mswindows_event_stream; @@ -146,10 +147,17 @@ int mswindows_quit_chars_count = 0; /* These are Lisp integers; see DEFVARS in this file for description. */ int mswindows_dynamic_frame_resize; int mswindows_alt_by_itself_activates_menu; -int mswindows_num_mouse_buttons; -int mswindows_mouse_button_max_skew_x; -int mswindows_mouse_button_max_skew_y; -int mswindows_mouse_button_tolerance; +Fixnum mswindows_num_mouse_buttons; +Fixnum mswindows_mouse_button_max_skew_x; +Fixnum mswindows_mouse_button_max_skew_y; +Fixnum mswindows_mouse_button_tolerance; + +#ifdef DEBUG_XEMACS +Fixnum debug_mswindows_events; + +static void debug_output_mswin_message (HWND hwnd, UINT message_, + WPARAM wParam, LPARAM lParam); +#endif /* This is the event signaled by the event pump. See mswindows_pump_outstanding_events for comments */ @@ -158,6 +166,8 @@ static int mswindows_in_modal_loop; /* Count of wound timers */ static int mswindows_pending_timers_count; + +static DWORD mswindows_last_mouse_button_state; /************************************************************************/ /* Pipe instream - reads process output */ @@ -360,8 +370,9 @@ get_ntpipe_input_stream_waitable (Lstream *stream) return s->thread_data->hev_caller; } -static ssize_t -ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) +static Lstream_data_count +ntpipe_slurp_reader (Lstream *stream, unsigned char *data, + Lstream_data_count size) { /* This function must be called from the main thread only */ struct ntpipe_slurp_stream_shared_data* s = @@ -468,7 +479,7 @@ init_slurp_stream (void) #define NTPIPE_SHOVE_STREAM_DATA(stream) \ LSTREAM_TYPE_DATA (stream, ntpipe_shove) -#define MAX_SHOVE_BUFFER_SIZE 128 +#define MAX_SHOVE_BUFFER_SIZE 512 struct ntpipe_shove_stream { @@ -502,15 +513,18 @@ shove_thread (LPVOID vparam) InterlockedIncrement (&s->idle_p); WaitForSingleObject (s->hev_thread, INFINITE); - if (s->die_p) - break; - - /* Write passed buffer */ - if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) - || bytes_written != s->size) + /* Write passed buffer if any */ + if (s->size > 0) { - s->error_p = TRUE; - InterlockedIncrement (&s->die_p); + if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) + || bytes_written != s->size) + { + s->error_p = TRUE; + InterlockedIncrement (&s->die_p); + } + /* Set size to zero so we won't write it again if the closer sets + die_p and kicks us */ + s->size = 0; } if (s->die_p) @@ -543,6 +557,15 @@ make_ntpipe_output_stream (HANDLE hpipe, LPARAM param) return Qnil; } + /* Set the priority of the thread higher so we don't end up waiting + on it to send things. */ + if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST)) + { + CloseHandle (s->hthread); + Lstream_delete (lstr); + return Qnil; + } + /* hev_thread is an auto-reset event, initially nonsignaled */ s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL); @@ -562,8 +585,9 @@ get_ntpipe_output_stream_param (Lstream *stream) } #endif -static ssize_t -ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size) +static Lstream_data_count +ntpipe_shove_writer (Lstream *stream, const unsigned char *data, + Lstream_data_count size) { struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); @@ -583,6 +607,10 @@ ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size) /* Start output */ InterlockedDecrement (&s->idle_p); SetEvent (s->hev_thread); + /* Give it a chance to run -- this dramatically improves performance + of things like crypt. */ + if (xSwitchToThread) /* not in Win9x or NT 3.51 */ + (void) xSwitchToThread (); return size; } @@ -601,14 +629,18 @@ ntpipe_shove_closer (Lstream *stream) /* Force thread stop */ InterlockedIncrement (&s->die_p); - /* Close pipe handle, possibly breaking it */ - CloseHandle (s->hpipe); - - /* Thread will end upon unblocking */ + /* Thread will end upon unblocking. If it's already unblocked this will + do nothing, but the thread won't look at die_p until it's written any + pending output. */ SetEvent (s->hev_thread); /* Wait while thread terminates */ WaitForSingleObject (s->hthread, INFINITE); + + /* Close pipe handle, possibly breaking it */ + CloseHandle (s->hpipe); + + /* Close the thread handle */ CloseHandle (s->hthread); /* Destroy the event */ @@ -637,7 +669,7 @@ struct winsock_stream LPARAM user_data; /* Any user data stored in the stream object */ SOCKET s; /* Socket handle (which is a Win32 handle) */ OVERLAPPED ov; /* Overlapped I/O structure */ - void* buffer; /* Buffer. Allocated for input stream only */ + void* buffer; /* Buffer. */ unsigned long bufsize; /* Number of bytes last read */ unsigned long bufpos; /* Position in buffer for next fetch */ unsigned int error_p :1; /* I/O Error seen */ @@ -671,8 +703,8 @@ winsock_initiate_read (struct winsock_stream *str) str->eof_p = 1; } -static ssize_t -winsock_reader (Lstream *stream, unsigned char *data, size_t size) +static Lstream_data_count +winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size) { struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); @@ -706,7 +738,7 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size) return -1; /* Return as much of buffer as we have */ - size = min (size, (size_t) (str->bufsize - str->bufpos)); + size = min (size, (Lstream_data_count) (str->bufsize - str->bufpos)); memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size); str->bufpos += size; @@ -717,8 +749,9 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size) return size; } -static ssize_t -winsock_writer (Lstream *stream, const unsigned char *data, size_t size) +static Lstream_data_count +winsock_writer (Lstream *stream, const unsigned char *data, + Lstream_data_count size) { struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); @@ -746,18 +779,24 @@ winsock_writer (Lstream *stream, const unsigned char *data, size_t size) if (size == 0) return 0; - { - ResetEvent (str->ov.hEvent); - - /* Docs indicate that 4th parameter to WriteFile can be NULL since this is - * an overlapped operation. This fails on Win95 with winsock 1.x so we - * supply a spare address which is ignored by Win95 anyway. Sheesh. */ - if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov) - || GetLastError() == ERROR_IO_PENDING) - str->pending_p = 1; - else - str->error_p = 1; - } + ResetEvent (str->ov.hEvent); + + /* According to WriteFile docs, we must hold onto the data we pass to it + and not make any changes until it finishes -- which may not be until + the next time we get here, since we use asynchronous I/O. We have + in fact seen data loss as a result of not doing this. */ + str->buffer = xrealloc (str->buffer, size); + memcpy (str->buffer, data, size); + + /* According to MSDN WriteFile docs, the fourth parameter cannot be NULL + on Win95 even when doing an overlapped operation, as we are, where + the return value through that parameter is not meaningful. */ + if (WriteFile ((HANDLE)str->s, str->buffer, size, &str->bufsize, + &str->ov) + || GetLastError() == ERROR_IO_PENDING) + str->pending_p = 1; + else + str->error_p = 1; return str->error_p ? -1 : size; } @@ -776,8 +815,11 @@ winsock_closer (Lstream *lstr) if (str->pending_p) WaitForSingleObject (str->ov.hEvent, INFINITE); - if (lstr->flags & LSTREAM_FL_READ) - xfree (str->buffer); + if (str->buffer) + { + xfree (str->buffer); + str->buffer = 0; + } CloseHandle (str->ov.hEvent); return 0; @@ -797,14 +839,10 @@ make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode) Lstream *lstr = Lstream_new (lstream_winsock, mode); struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); + xzero (*str); str->s = s; - str->blocking_p = 0; - str->error_p = 0; - str->eof_p = 0; - str->pending_p = 0; str->user_data = param; - xzero (str->ov); str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if (lstr->flags & LSTREAM_FL_READ) @@ -870,7 +908,7 @@ mswindows_user_event_p (Lisp_Event* sevt) /* * Add an emacs event to the proper dispatch queue */ -static void +void mswindows_enqueue_dispatch_event (Lisp_Object event) { int user_p = mswindows_user_event_p (XEVENT(event)); @@ -936,27 +974,30 @@ mswindows_enqueue_process_event (Lisp_Process* p) } static void -mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when) +mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, + int mods, DWORD when) { + int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || + msg == WM_RBUTTONDOWN); /* We always use last message time, because mouse button events may get delayed, and XEmacs double click recognition will fail */ Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - Lisp_Event* event = XEVENT(emacs_event); + Lisp_Event* event = XEVENT (emacs_event); - event->channel = mswindows_find_frame(hwnd); + mswindows_handle_sticky_modifiers (0, 0, downp, 0); + event->channel = mswindows_find_frame (hwnd); event->timestamp = when; event->event.button.button = (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 : ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2); event->event.button.x = where.x; event->event.button.y = where.y; - event->event.button.modifiers = mswindows_modifier_state (NULL, 0); + event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0); - if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN || - msg==WM_RBUTTONDOWN) + if (downp) { event->event_type = button_press_event; SetCapture (hwnd); @@ -1012,13 +1053,11 @@ mswindows_dequeue_dispatch_event (void) &mswindows_s_dispatch_event_queue_tail : &mswindows_u_dispatch_event_queue_tail); - sevt = XEVENT(event); + sevt = XEVENT (event); if (sevt->event_type == key_press_event && (sevt->event.key.modifiers & FAKE_MOD_QUIT)) - { - sevt->event.key.modifiers &= ~FAKE_MOD_QUIT; - --mswindows_quit_chars_count; - } + sevt->event.key.modifiers &= + ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL); return event; } @@ -1245,27 +1284,43 @@ mswindows_drain_windows_queue (void) 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. + char class_name_buf [sizeof (XEMACS_CLASS) + 2] = ""; + + /* Don't translate messages destined for a dialog box, this + makes keyboard traversal work. I think?? */ + if (mswindows_is_dialog_msg (&msg)) + { + mswindows_unmodalize_signal_maybe (); + continue; + } + + /* We have to translate messages that are not sent to an XEmacs + frame. This is so that key presses work ok in things like + edit fields. However, we *musn't* translate message for XEmacs + frames as this is handled in the wnd proc. We also have to avoid generating paint magic events for windows that aren't XEmacs frames */ - if (GetWindowLong (msg.hwnd, GWL_STYLE) & (WS_CHILD|WS_POPUP)) + /* GetClassName will truncate a longer class name. By adding one + extra character, we are forcing textual comparison to fail + if the name is longer than XEMACS_CLASS */ + + GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1); + if (stricmp (class_name_buf, XEMACS_CLASS) != 0) { + /* Not an XEmacs frame */ TranslateMessage (&msg); } else if (msg.message == WM_PAINT) { struct mswindows_frame* msframe; - + /* hdc will be NULL unless this is a subwindow - in which case we shouldn't have received a paint message for it here. */ assert (msg.wParam == 0); /* Queue a magic event for handling when safe */ - msframe = FRAME_MSWINDOWS_DATA ( - XFRAME (mswindows_find_frame (msg.hwnd))); + msframe = + FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd))); if (!msframe->paint_pending) { msframe->paint_pending = 1; @@ -1292,6 +1347,10 @@ mswindows_drain_windows_queue (void) * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER * which will never come when there are no pending timers, which leads * to deadlock, we simply signal an error. + * + * It might be possible to combine this with mswindows_drain_windows_queue + * which fetches events when not in a modal loop. It's not clear + * whether the result would be more complex than is justified. */ static void mswindows_need_event_in_modal_loop (int badly_p) @@ -1315,8 +1374,8 @@ mswindows_need_event_in_modal_loop (int badly_p) error ("Deadlock due to an attempt to call next-event in a wrong context"); /* Fetch and dispatch any pending timers */ - GetMessage (&msg, NULL, WM_TIMER, WM_TIMER); - DispatchMessage (&msg); + if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0) + DispatchMessage (&msg); } } @@ -1332,12 +1391,6 @@ mswindows_need_event (int badly_p) { int active; - if (mswindows_in_modal_loop) - { - mswindows_need_event_in_modal_loop (badly_p); - return; - } - while (NILP (mswindows_u_dispatch_event_queue) && NILP (mswindows_s_dispatch_event_queue)) { @@ -1354,6 +1407,10 @@ mswindows_need_event (int badly_p) EMACS_SET_SECS_USECS (sometime, 0, 0); EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block); pointer_to_this = &select_time_to_block; + if (mswindows_in_modal_loop) + /* In modal loop with badly_p false, don't care about + Windows events. */ + FD_CLR (windows_fd, &temp_mask); } active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this); @@ -1367,9 +1424,12 @@ mswindows_need_event (int badly_p) { if (FD_ISSET (windows_fd, &temp_mask)) { - mswindows_drain_windows_queue (); + if (mswindows_in_modal_loop) + mswindows_need_event_in_modal_loop (badly_p); + else + mswindows_drain_windows_queue (); } - else + else { #ifdef HAVE_TTY /* Look for a TTY event */ @@ -1383,7 +1443,7 @@ mswindows_need_event (int badly_p) struct console *c = tty_find_console_from_fd (i); Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); Lisp_Event* event = XEVENT (emacs_event); - + assert (c); if (read_event_from_tty_or_stream_desc (event, c, i)) { @@ -1402,7 +1462,7 @@ mswindows_need_event (int badly_p) { Lisp_Process *p = get_process_from_usid (FD_TO_USID(i)); - + mswindows_enqueue_process_event (p); } else @@ -1432,10 +1492,24 @@ mswindows_need_event (int badly_p) } #else /* Now try getting a message or process event */ + DWORD what_events; + if (mswindows_in_modal_loop) + /* In a modal loop, only look for timer events, and only if + we really need one. */ + { + if (badly_p) + what_events = QS_TIMER; + else + what_events = 0; + } + else + /* Look for any event */ + what_events = QS_ALLINPUT; + active = MsgWaitForMultipleObjects (mswindows_waitable_count, mswindows_waitable_handles, FALSE, badly_p ? INFINITE : 0, - QS_ALLINPUT); + what_events); /* This will assert if handle being waited for becomes abandoned. Not the case currently tho */ @@ -1451,7 +1525,10 @@ mswindows_need_event (int badly_p) else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) { /* Got your message, thanks */ - mswindows_drain_windows_queue (); + if (mswindows_in_modal_loop) + mswindows_need_event_in_modal_loop (badly_p); + else + mswindows_drain_windows_queue (); } else { @@ -1468,13 +1545,32 @@ mswindows_need_event (int badly_p) { /* None. This means that the process handle itself has signaled. Remove the handle from the wait vector, and make status_notify - note the exited process */ + note the exited process. First find the process object if + possible. */ + LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail) + if (get_nt_process_handle (XPROCESS (vaffanculo)) == + mswindows_waitable_handles [ix]) + break; mswindows_waitable_handles [ix] = mswindows_waitable_handles [--mswindows_waitable_count]; kick_status_notify (); - /* Have to return something: there may be no accompanying - process event */ - mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); + /* We need to return a process event here so that + (1) accept-process-output will return when called on this + process, and (2) status notifications will happen in + accept-process-output, sleep-for, and sit-for. */ + /* #### horrible kludge till my real process fixes go in. + #### Replaced with a slightly less horrible kluge that + at least finds the right process instead of axing the + first one on the list. + */ + if (!NILP (vproctail)) + { + mswindows_enqueue_process_event (XPROCESS (vaffanculo)); + } + else /* trash me soon. */ + /* Have to return something: there may be no accompanying + process event */ + mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); } } #endif @@ -1582,10 +1678,10 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, if (*end) return DDE_FNOTPROCESSED; -#ifdef __CYGWIN32__ - filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5); +#ifdef CYGWIN + filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5); strcpy (filename, "file:"); - cygwin32_win32_to_posix_path_list (cmd, filename+5); + cygwin_win32_to_posix_path_list (cmd, filename+5); #else dostounix_filename (cmd); filename = alloca (strlen (cmd)+6); @@ -1652,6 +1748,9 @@ mswindows_handle_paint (struct frame *frame) windows are unmapped, however once we are in the guts of WM_PAINT we need to make sure that we don't register unmaps then because they will not actually occur. */ + /* #### commenting out the next line seems to fix some problems + but not all. only andy currently understands this stuff and + he needs to review it more carefully. --ben */ if (!check_for_ignored_expose (frame, x, y, width, height)) { hold_ignored_expose_registration = 1; @@ -1663,23 +1762,298 @@ mswindows_handle_paint (struct frame *frame) } /* - * Returns 1 if a key is a real modifier or special key, which + * Returns 1 if a key is a real modifier or special key, which * is better handled by DefWindowProc */ static int key_needs_default_processing_p (UINT vkey) { - if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU) + if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU + /* if we let ALT activate the menu like this, then sticky ALT-modified + keystrokes become impossible. */ + && !modifier_keys_are_sticky) return 1; return 0; } +/* key-handling code is always ugly. It just ends up working out + that way. + + #### Most of the sticky-modifier code below is copied from similar + code in event-Xt.c. They should somehow or other be merged. + + Here are some pointers: + + -- DOWN_MASK indicates which modifiers should be treated as "down" + when the corresponding upstroke happens. It gets reset for + a particular modifier when that modifier goes up, and reset + for all modifiers when a non-modifier key is pressed. Example: + + I press Control-A-Shift and then release Control-A-Shift. + I want the Shift key to be sticky but not the Control key. + + -- If a modifier key is sticky, I can unstick it by pressing + the modifier key again. */ + +static WPARAM last_downkey; +static int need_to_add_mask, down_mask; + +#define XEMSW_LCONTROL (1<<0) +#define XEMSW_RCONTROL (1<<1) +#define XEMSW_LSHIFT (1<<2) +#define XEMSW_RSHIFT (1<<3) +#define XEMSW_LMENU (1<<4) +#define XEMSW_RMENU (1<<5) + +static int +mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, + int downp, int keyp) +{ + int mods = 0; + + if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */ + return 0; + + if (! (keyp && + (wParam == VK_CONTROL || wParam == VK_LCONTROL || + wParam == VK_RCONTROL || + wParam == VK_MENU || wParam == VK_LMENU || + wParam == VK_RMENU || + wParam == VK_SHIFT || wParam == VK_LSHIFT || + wParam == VK_RSHIFT))) + { /* Not a modifier key */ + if (downp && keyp && !last_downkey) + last_downkey = wParam; + /* If I hold press-and-release the Control key and then press + and hold down the right arrow, I want it to auto-repeat + Control-Right. On the other hand, if I do the same but + manually press the Right arrow a bunch of times, I want + to see one Control-Right and then a bunch of Rights. + This means that we need to distinguish between an + auto-repeated key and a key pressed and released a bunch + of times. */ + else if ((downp && !keyp) || + (downp && keyp && last_downkey && + (wParam != last_downkey || + /* the "previous key state" bit indicates autorepeat */ + ! (lParam & (1 << 30))))) + { + need_to_add_mask = 0; + last_downkey = 0; + } + if (downp) + down_mask = 0; + + mods = need_to_add_mask; + } + else /* Modifier key pressed */ + { + /* If a non-modifier key was pressed in the middle of a bunch + of modifiers, then it unsticks all the modifiers that were + previously pressed. We cannot unstick the modifiers until + now because we want to check for auto-repeat of the + non-modifier key. */ + + if (last_downkey) + { + last_downkey = 0; + need_to_add_mask = 0; + } + +#define FROB(mask) \ +do { \ + if (downp && keyp) \ + { \ + /* If modifier key is already sticky, \ + then unstick it. Note that we do \ + not test down_mask to deal with the \ + unlikely but possible case that the \ + modifier key auto-repeats. */ \ + if (need_to_add_mask & mask) \ + { \ + need_to_add_mask &= ~mask; \ + down_mask &= ~mask; \ + } \ + else \ + down_mask |= mask; \ + } \ + else \ + { \ + if (down_mask & mask) \ + { \ + down_mask &= ~mask; \ + need_to_add_mask |= mask; \ + } \ + } \ +} while (0) + + if ((wParam == VK_CONTROL && (lParam & 0x1000000)) + || wParam == VK_RCONTROL) + FROB (XEMSW_RCONTROL); + if ((wParam == VK_CONTROL && !(lParam & 0x1000000)) + || wParam == VK_LCONTROL) + FROB (XEMSW_LCONTROL); + + if ((wParam == VK_SHIFT && (lParam & 0x1000000)) + || wParam == VK_RSHIFT) + FROB (XEMSW_RSHIFT); + if ((wParam == VK_SHIFT && !(lParam & 0x1000000)) + || wParam == VK_LSHIFT) + FROB (XEMSW_LSHIFT); + + if ((wParam == VK_MENU && (lParam & 0x1000000)) + || wParam == VK_RMENU) + FROB (XEMSW_RMENU); + if ((wParam == VK_MENU && !(lParam & 0x1000000)) + || wParam == VK_LMENU) + FROB (XEMSW_LMENU); + } +#undef FROB + + if (mods && downp) + { + BYTE keymap[256]; + + GetKeyboardState (keymap); + + if (mods & XEMSW_LCONTROL) + { + keymap [VK_CONTROL] |= 0x80; + keymap [VK_LCONTROL] |= 0x80; + } + if (mods & XEMSW_RCONTROL) + { + keymap [VK_CONTROL] |= 0x80; + keymap [VK_RCONTROL] |= 0x80; + } + + if (mods & XEMSW_LSHIFT) + { + keymap [VK_SHIFT] |= 0x80; + keymap [VK_LSHIFT] |= 0x80; + } + if (mods & XEMSW_RSHIFT) + { + keymap [VK_SHIFT] |= 0x80; + keymap [VK_RSHIFT] |= 0x80; + } + + if (mods & XEMSW_LMENU) + { + keymap [VK_MENU] |= 0x80; + keymap [VK_LMENU] |= 0x80; + } + if (mods & XEMSW_RMENU) + { + keymap [VK_MENU] |= 0x80; + keymap [VK_RMENU] |= 0x80; + } + + SetKeyboardState (keymap); + return 1; + } + + return 0; +} + +static void +clear_sticky_modifiers (void) +{ + need_to_add_mask = 0; + last_downkey = 0; + down_mask = 0; +} + +#ifdef DEBUG_XEMACS + +#if 0 + +static void +output_modifier_keyboard_state (void) +{ + BYTE keymap[256]; + + GetKeyboardState (keymap); + + stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", + keymap[VK_MENU] & 0x80 ? 1 : 0, + keymap[VK_MENU] & 0x1 ? 1 : 0, + keymap[VK_LMENU] & 0x80 ? 1 : 0, + keymap[VK_LMENU] & 0x1 ? 1 : 0, + keymap[VK_RMENU] & 0x80 ? 1 : 0, + keymap[VK_RMENU] & 0x1 ? 1 : 0); + stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n", + keymap[VK_CONTROL] & 0x80 ? 1 : 0, + keymap[VK_CONTROL] & 0x1 ? 1 : 0, + keymap[VK_LCONTROL] & 0x80 ? 1 : 0, + keymap[VK_LCONTROL] & 0x1 ? 1 : 0, + keymap[VK_RCONTROL] & 0x80 ? 1 : 0, + keymap[VK_RCONTROL] & 0x1 ? 1 : 0); + stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n", + keymap[VK_SHIFT] & 0x80 ? 1 : 0, + keymap[VK_SHIFT] & 0x1 ? 1 : 0, + keymap[VK_LSHIFT] & 0x80 ? 1 : 0, + keymap[VK_LSHIFT] & 0x1 ? 1 : 0, + keymap[VK_RSHIFT] & 0x80 ? 1 : 0, + keymap[VK_RSHIFT] & 0x1 ? 1 : 0); +} + +#endif + +/* try to debug the stuck-alt-key problem. + + #### this happens only inconsistently, and may only happen when using + StickyKeys in the Win2000 accessibility section of the control panel, + which is extremely broken for other reasons. */ + +static void +output_alt_keyboard_state (void) +{ + BYTE keymap[256]; + SHORT keystate[3]; + // SHORT asyncstate[3]; + + GetKeyboardState (keymap); + keystate[0] = GetKeyState (VK_MENU); + keystate[1] = GetKeyState (VK_LMENU); + keystate[2] = GetKeyState (VK_RMENU); + /* Doing this interferes with key processing. */ +/* asyncstate[0] = GetAsyncKeyState (VK_MENU); */ +/* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */ +/* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */ + + stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", + keymap[VK_MENU] & 0x80 ? 1 : 0, + keymap[VK_MENU] & 0x1 ? 1 : 0, + keymap[VK_LMENU] & 0x80 ? 1 : 0, + keymap[VK_LMENU] & 0x1 ? 1 : 0, + keymap[VK_RMENU] & 0x80 ? 1 : 0, + keymap[VK_RMENU] & 0x1 ? 1 : 0); + stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", + keystate[0] & 0x8000 ? 1 : 0, + keystate[0] & 0x1 ? 1 : 0, + keystate[1] & 0x8000 ? 1 : 0, + keystate[1] & 0x1 ? 1 : 0, + keystate[2] & 0x8000 ? 1 : 0, + keystate[2] & 0x1 ? 1 : 0); +/* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */ +/* asyncstate[0] & 0x8000 ? 1 : 0, */ +/* asyncstate[0] & 0x1 ? 1 : 0, */ +/* asyncstate[1] & 0x8000 ? 1 : 0, */ +/* asyncstate[1] & 0x1 ? 1 : 0, */ +/* asyncstate[2] & 0x8000 ? 1 : 0, */ +/* asyncstate[2] & 0x1 ? 1 : 0); */ +} + +#endif /* DEBUG_XEMACS */ + + /* * The windows procedure for the window class XEMACS_CLASS */ LRESULT WINAPI -mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam) { /* Note: Remember to initialize emacs_event and event before use. This code calls code that can GC. You must GCPRO before calling such code. */ @@ -1690,14 +2064,34 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) struct frame *frame; struct mswindows_frame* msframe; + /* Not perfect but avoids crashes. There is potential for wierd + behavior here. */ + if (gc_in_progress) + { + mswindows_output_console_string ("Window procedure called during GC???????\n", 41); + /* Yes, this assert always triggers in a --debug XEmacs. But + --debug=no is default in the stable branches. + #### How about patch in <200106081225.IAA31075@gwyn.tux.org>? */ + assert (!gc_in_progress); + goto defproc; + } + +#ifdef DEBUG_XEMACS + if (debug_mswindows_events) + debug_output_mswin_message (hwnd, message_, wParam, lParam); +#endif /* DEBUG_XEMACS */ + assert (!GetWindowLong (hwnd, GWL_USERDATA)); - switch (message) + switch (message_) { case WM_DESTROYCLIPBOARD: /* We own the clipboard and someone else wants it. Delete our cached copy of the clipboard contents so we'll ask for it from - Windows again when someone does a paste. */ - handle_selection_clear(QCLIPBOARD); + Windows again when someone does a paste, and destroy any memory + objects we hold on the clipboard that are not in the list of types + that Windows will delete itself. */ + mswindows_destroy_selection (QCLIPBOARD); + handle_selection_clear (QCLIPBOARD); break; case WM_ERASEBKGND: @@ -1714,11 +2108,18 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_KEYUP: case WM_SYSKEYUP: + /* See Win95 comment under WM_KEYDOWN */ { BYTE keymap[256]; int should_set_keymap = 0; +#ifdef DEBUG_XEMACS + if (debug_mswindows_events > 2) + output_alt_keyboard_state (); +#endif /* DEBUG_XEMACS */ + + mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1); if (wParam == VK_CONTROL) { GetKeyboardState (keymap); @@ -1732,12 +2133,13 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) should_set_keymap = 1; } - if (should_set_keymap - && (message != WM_SYSKEYUP - || NILP (Vmenu_accelerator_enabled))) + if (should_set_keymap) + // && (message_ != WM_SYSKEYUP + // || NILP (Vmenu_accelerator_enabled))) SetKeyboardState (keymap); } + if (key_needs_default_processing_p (wParam)) goto defproc; else @@ -1745,8 +2147,9 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_KEYDOWN: case WM_SYSKEYDOWN: + /* In some locales the right-hand Alt key is labelled AltGr. This key - * should produce alternative charcaters when combined with another key. + * should produce alternative characters when combined with another key. * eg on a German keyboard pressing AltGr+q should produce '@'. * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if * TranslateMessage() is called with *any* combination of Ctrl+Alt down, @@ -1754,31 +2157,61 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) * We get round this by removing all modifiers from the keymap before * calling TranslateMessage() unless AltGr is *really* down. */ { - BYTE keymap[256]; + BYTE keymap_trans[256]; + BYTE keymap_orig[256]; + BYTE keymap_sticky[256]; int has_AltGr = mswindows_current_layout_has_AltGr (); - int mods; + int mods = 0, mods_with_shift = 0; int extendedp = lParam & 0x1000000; Lisp_Object keysym; + int sticky_changed; + +#ifdef DEBUG_XEMACS + if (debug_mswindows_events > 2) + output_alt_keyboard_state (); +#endif /* DEBUG_XEMACS */ + GetKeyboardState (keymap_orig); frame = XFRAME (mswindows_find_frame (hwnd)); - GetKeyboardState (keymap); - mods = mswindows_modifier_state (keymap, has_AltGr); + if ((sticky_changed = + mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1))) + { + GetKeyboardState (keymap_sticky); + if (keymap_sticky[VK_MENU] & 0x80) + { + message_ = WM_SYSKEYDOWN; + /* We have to set the "context bit" so that the + TranslateMessage() call below that generates the + SYSCHAR message does its thing; see the documentation + on WM_SYSKEYDOWN */ + lParam |= 1 << 29; + } + } + else + memcpy (keymap_sticky, keymap_orig, 256); + + mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr); + mods_with_shift = mods; /* Handle non-printables */ if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, extendedp))) - mswindows_enqueue_keypress_event (hwnd, keysym, mods); + { + mswindows_enqueue_keypress_event (hwnd, keysym, mods); + if (sticky_changed) + SetKeyboardState (keymap_orig); + } else /* Normal keys & modifiers */ { - Emchar quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); - BYTE keymap_orig[256]; + Emchar quit_ch = + CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; MSG msg, tranmsg; int potential_accelerator = 0; int got_accelerator = 0; - + msg.hwnd = hwnd; - msg.message = message; + msg.message = message_; msg.wParam = wParam; msg.lParam = lParam; msg.time = GetMessageTime(); @@ -1788,71 +2221,102 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) * to loosely track Left and Right modifiers on behalf of the OS, * without screwing up Windows NT which tracks them properly. */ if (wParam == VK_CONTROL) - keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + { + keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + } else if (wParam == VK_MENU) - keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80; - - memcpy (keymap_orig, keymap, 256); + { + keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; + keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; + } if (!NILP (Vmenu_accelerator_enabled) && - !(mods & XEMACS_MOD_SHIFT) && message == WM_SYSKEYDOWN) + !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN) potential_accelerator = 1; /* Remove shift modifier from an ascii character */ mods &= ~XEMACS_MOD_SHIFT; + memcpy (keymap_trans, keymap_sticky, 256); + /* Clear control and alt modifiers unless AltGr is pressed */ - keymap [VK_RCONTROL] = 0; - keymap [VK_LMENU] = 0; - if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) - || !(keymap [VK_RMENU] & 0x80)) + keymap_trans[VK_RCONTROL] = 0; + keymap_trans[VK_LMENU] = 0; + if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80) + || !(keymap_trans[VK_RMENU] & 0x80)) { - keymap [VK_LCONTROL] = 0; - keymap [VK_CONTROL] = 0; - keymap [VK_RMENU] = 0; - keymap [VK_MENU] = 0; + keymap_trans[VK_LCONTROL] = 0; + keymap_trans[VK_CONTROL] = 0; + keymap_trans[VK_RMENU] = 0; + keymap_trans[VK_MENU] = 0; } - SetKeyboardState (keymap); + SetKeyboardState (keymap_trans); /* Maybe generate some WM_[SYS]CHARs in the queue */ TranslateMessage (&msg); while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) - || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) + || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, + PM_REMOVE)) { - int mods1 = mods; + int mods_with_quit = mods; WPARAM ch = tranmsg.wParam; +#ifdef DEBUG_XEMACS + if (debug_mswindows_events) + { + stderr_out ("-> "); + debug_output_mswin_message (tranmsg.hwnd, tranmsg.message, + tranmsg.wParam, + tranmsg.lParam); + } +#endif /* DEBUG_XEMACS */ + /* If a quit char with no modifiers other than control and shift, then mark it with a fake modifier, which is removed upon dequeueing the event */ - /* #### This might also not withstand localization, if - quit character is not a latin-1 symbol */ - if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) && quit_ch + 'a' - 1 == ch) - || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) && quit_ch == ch)) - && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) == 0)) + /* !!#### Fix this in my mule ws -- replace current_buffer + with 0 */ + if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) + && DOWNCASE (current_buffer, quit_ch + 'a' - 1) == + DOWNCASE (current_buffer, ch)) + || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) + && DOWNCASE (current_buffer, quit_ch) == + DOWNCASE (current_buffer, ch))) + && ((mods_with_shift & + ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) + == 0)) { - mods1 |= FAKE_MOD_QUIT; - ++mswindows_quit_chars_count; + mods_with_quit |= FAKE_MOD_QUIT; + if (mods_with_shift & XEMACS_MOD_SHIFT) + mods_with_quit |= FAKE_MOD_QUIT_CRITICAL; + mswindows_quit_chars_count++; } else if (potential_accelerator && !got_accelerator && - msw_char_is_accelerator (frame, ch)) + mswindows_char_is_accelerator (frame, ch)) { got_accelerator = 1; break; } - mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1); + mswindows_enqueue_keypress_event (hwnd, make_char (ch), + mods_with_quit); } /* while */ - SetKeyboardState (keymap_orig); + /* This generates WM_SYSCHAR messages, which are interpreted by DefWindowProc as the menu selections. */ if (got_accelerator) - { + { + SetKeyboardState (keymap_sticky); TranslateMessage (&msg); + SetKeyboardState (keymap_orig); goto defproc; } + + SetKeyboardState (keymap_orig); } /* else */ } + if (key_needs_default_processing_p (wParam)) goto defproc; else @@ -1863,8 +2327,10 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Real middle mouse button has nothing to do with emulated one: if one wants to exercise fingers playing chords on the mouse, he is allowed to do that! */ - mswindows_enqueue_mouse_button_event (hwnd, message, - MAKEPOINTS (lParam), GetMessageTime()); + mswindows_enqueue_mouse_button_event (hwnd, message_, + MAKEPOINTS (lParam), + wParam &~ MK_MBUTTON, + GetMessageTime()); break; case WM_LBUTTONUP: @@ -1882,7 +2348,11 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) msframe->button2_is_down = 0; msframe->ignore_next_rbutton_up = 1; mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam + &~ (MK_LBUTTON | MK_MBUTTON + | MK_RBUTTON), + GetMessageTime()); } else { @@ -1890,10 +2360,14 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { msframe->button2_need_rbutton = 0; mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam &~ MK_LBUTTON, + GetMessageTime()); } mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam &~ MK_LBUTTON, + GetMessageTime()); } break; @@ -1912,7 +2386,11 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) msframe->button2_is_down = 0; msframe->ignore_next_lbutton_up = 1; mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam + &~ (MK_LBUTTON | MK_MBUTTON + | MK_RBUTTON), + GetMessageTime()); } else { @@ -1920,10 +2398,14 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { msframe->button2_need_lbutton = 0; mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam &~ MK_RBUTTON, + GetMessageTime()); } mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam &~ MK_RBUTTON, + GetMessageTime()); } break; @@ -1935,18 +2417,28 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) KillTimer (hwnd, BUTTON_2_TIMER_ID); msframe->button2_need_lbutton = 0; msframe->button2_need_rbutton = 0; - if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) + if (mswindows_button2_near_enough (msframe->last_click_point, + MAKEPOINTS (lParam))) { mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam + &~ (MK_LBUTTON | MK_MBUTTON + | MK_RBUTTON), + GetMessageTime()); msframe->button2_is_down = 1; } else { mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); + msframe->last_click_point, + msframe->last_click_mods + &~ MK_RBUTTON, + msframe->last_click_time); mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam &~ MK_LBUTTON, + GetMessageTime()); } } else @@ -1954,6 +2446,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) mswindows_set_chord_timer (hwnd); msframe->button2_need_rbutton = 1; msframe->last_click_point = MAKEPOINTS (lParam); + msframe->last_click_mods = wParam; } msframe->last_click_time = GetMessageTime(); break; @@ -1966,18 +2459,28 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) KillTimer (hwnd, BUTTON_2_TIMER_ID); msframe->button2_need_lbutton = 0; msframe->button2_need_rbutton = 0; - if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) + if (mswindows_button2_near_enough (msframe->last_click_point, + MAKEPOINTS (lParam))) { mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam + &~ (MK_LBUTTON | MK_MBUTTON + | MK_RBUTTON), + GetMessageTime()); msframe->button2_is_down = 1; } else { mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); + msframe->last_click_point, + msframe->last_click_mods + &~ MK_LBUTTON, + msframe->last_click_time); mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - MAKEPOINTS (lParam), GetMessageTime()); + MAKEPOINTS (lParam), + wParam &~ MK_RBUTTON, + GetMessageTime()); } } else @@ -1985,6 +2488,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) mswindows_set_chord_timer (hwnd); msframe->button2_need_lbutton = 1; msframe->last_click_point = MAKEPOINTS (lParam); + msframe->last_click_mods = wParam; } msframe->last_click_time = GetMessageTime(); break; @@ -1999,13 +2503,19 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { msframe->button2_need_lbutton = 0; mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); + msframe->last_click_point, + msframe->last_click_mods + &~ MK_RBUTTON, + msframe->last_click_time); } else if (msframe->button2_need_rbutton) { msframe->button2_need_rbutton = 0; mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, - msframe->last_click_point, msframe->last_click_time); + msframe->last_click_point, + msframe->last_click_mods + &~ MK_LBUTTON, + msframe->last_click_time); } } else @@ -2036,7 +2546,8 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) event->event_type = pointer_motion_event; event->event.motion.x = MAKEPOINTS(lParam).x; event->event.motion.y = MAKEPOINTS(lParam).y; - event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); + event->event.motion.modifiers = + mswindows_modifier_state (NULL, wParam, 0); mswindows_enqueue_dispatch_event (emacs_event); } @@ -2072,9 +2583,7 @@ 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...*/ - TO_EXTERNAL_FORMAT (LISP_STRING, btext, - C_STRING_ALLOCA, tttext->lpszText, - Qnative); + LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative); } #endif } @@ -2106,12 +2615,39 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) shouldn't have received a paint message for it here. */ assert (wParam == 0); - /* Can't queue a magic event because windows goes modal and sends paint + /* Can't queue a magic event because windows goes modal and sends paint messages directly to the windows procedure when doing solid drags and the message queue doesn't get processed. */ mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd))); break; + case WM_WINDOWPOSCHANGED: + /* This is sent before WM_SIZE; in fact, the processing of this + by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when + a window is hidden (make-frame-invisible), so we need to process + this and update the state flags. */ + { + fobj = mswindows_find_frame (hwnd); + frame = XFRAME (fobj); + if (IsIconic (hwnd)) + { + FRAME_VISIBLE_P (frame) = 0; + FRAME_ICONIFIED_P (frame) = 1; + } + else if (IsWindowVisible (hwnd)) + { + FRAME_VISIBLE_P (frame) = 1; + FRAME_ICONIFIED_P (frame) = 0; + } + else + { + FRAME_VISIBLE_P (frame) = 0; + FRAME_ICONIFIED_P (frame) = 0; + } + + return DefWindowProc (hwnd, message_, wParam, lParam); + } + case WM_SIZE: /* We only care about this message if our size has really changed */ if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) @@ -2130,7 +2666,6 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (wParam==SIZE_MINIMIZED) { /* Iconified */ - FRAME_VISIBLE_P (frame) = 0; mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); } else @@ -2166,7 +2701,6 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); - FRAME_VISIBLE_P (frame) = 1; if (!msframe->sizing || mswindows_dynamic_frame_resize) redisplay (); @@ -2178,21 +2712,31 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DISPLAYCHANGE: { struct device *d; + DWORD message_tick = GetMessageTime (); fobj = mswindows_find_frame (hwnd); frame = XFRAME (fobj); d = XDEVICE (FRAME_DEVICE (frame)); - DEVICE_MSWINDOWS_HORZRES(d) = LOWORD (lParam); - DEVICE_MSWINDOWS_VERTRES(d) = HIWORD (lParam); - DEVICE_MSWINDOWS_BITSPIXEL(d) = wParam; - break; + /* Do this only once per message. XEmacs can receive this message + through as many frames as it currently has open. Message time + will be the same for all these messages. Despite extreme + efficiency, the code below has about one in 4 billion + probability that the HDC is not recreated, provided that + XEmacs is running sufficiently longer than 52 days. */ + if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick) + { + DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick; + DeleteDC (DEVICE_MSWINDOWS_HCDC(d)); + DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL); + } } + break; /* Misc magic events which only require that the frame be identified */ case WM_SETFOCUS: case WM_KILLFOCUS: - mswindows_enqueue_magic_event (hwnd, message); + mswindows_enqueue_magic_event (hwnd, message_); break; case WM_WINDOWPOSCHANGING: @@ -2281,7 +2825,9 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ struct gcpro gcpro1, gcpro2; - if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta)) + if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), + keys, delta, + MAKEPOINTS (lParam))) { GCPRO2 (emacs_event, fobj); mswindows_pump_outstanding_events (); /* Can GC */ @@ -2341,7 +2887,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; #endif - return DefWindowProc (hwnd, message, wParam, lParam); + 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. */ @@ -2377,7 +2923,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (XCOLOR_INSTANCE (FACE_BACKGROUND (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + XIMAGE_INSTANCE_FRAME (image_instance))))); } last_widget_brushed = ii; SetTextColor @@ -2386,7 +2932,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (XCOLOR_INSTANCE (FACE_FOREGROUND (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + XIMAGE_INSTANCE_FRAME (image_instance))))); SetBkMode (hdc, OPAQUE); SetBkColor (hdc, @@ -2394,7 +2940,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) (XCOLOR_INSTANCE (FACE_BACKGROUND (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), - XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); + XIMAGE_INSTANCE_FRAME (image_instance))))); return (LRESULT)widget_brush; } } @@ -2424,7 +2970,8 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) event->channel = mswindows_find_frame(hwnd); event->timestamp = GetMessageTime(); event->event.misc.button = 1; /* #### Should try harder */ - event->event.misc.modifiers = mswindows_modifier_state (NULL, 0); + event->event.misc.modifiers = mswindows_modifier_state (NULL, + (DWORD) -1, 0); event->event.misc.x = point.x; event->event.misc.y = point.y; event->event.misc.function = Qdragdrop_drop_dispatch; @@ -2441,7 +2988,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) DragQueryFile ((HANDLE) wParam, i, fname, len+1); /* May be a shell link aka "shortcut" - replace fname if so */ -#if !(defined(__CYGWIN32__) || defined(__MINGW32__)) +#if !(defined(CYGWIN) || defined(MINGW)) /* cygwin doesn't define this COM stuff */ if (!stricmp (fname + strlen (fname) - 4, ".LNK")) { @@ -2449,20 +2996,20 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (CoCreateInstance (&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK) - { + { IPersistFile* ppf; if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, &ppf) == S_OK) { - WORD wsz[MAX_PATH]; + OLECHAR wsz[PATH_MAX]; WIN32_FIND_DATA wfd; - LPSTR resolved = (char *) xmalloc (MAX_PATH+1); + LPSTR resolved = (char *) xmalloc (PATH_MAX+1); - MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH); + MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX); if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) && - (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH, + (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX, &wfd, 0)==S_OK)) { xfree (fname); @@ -2478,10 +3025,10 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } #endif -#ifdef __CYGWIN32__ - filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); +#ifdef CYGWIN + filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5); strcpy (filename, "file:"); - cygwin32_win32_to_posix_path_list (fname, filename+5); + cygwin_win32_to_posix_path_list (fname, filename+5); #else filename = (char *)xmalloc (len+6); strcat (strcpy (filename, "file:"), fname); @@ -2503,7 +3050,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) defproc: default: - return DefWindowProc (hwnd, message, wParam, lParam); + return DefWindowProc (hwnd, message_, wParam, lParam); } return (0); } @@ -2550,8 +3097,10 @@ mswindows_current_layout_has_AltGr (void) time when a key typed at autorepeat rate of 30 cps! */ static HKL last_hkl = 0; static int last_hkl_has_AltGr; + HKL current_hkl = (HKL) -1; - HKL current_hkl = GetKeyboardLayout (0); + if (xGetKeyboardLayout) /* not in NT 3.5 */ + current_hkl = xGetKeyboardLayout (0); if (current_hkl != last_hkl) { TCHAR c; @@ -2570,17 +3119,30 @@ mswindows_current_layout_has_AltGr (void) /* Returns the state of the modifier keys in the format expected by the * Lisp_Event key_data, button_data and motion_data modifiers member */ -int mswindows_modifier_state (BYTE* keymap, int has_AltGr) +static int +mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr) { int mods = 0; + int keys_is_real = 0; + BYTE keymap2[256]; + + if (fwKeys == (DWORD) -1) + fwKeys = mswindows_last_mouse_button_state; + else + { + keys_is_real = 1; + mswindows_last_mouse_button_state = fwKeys; + } if (keymap == NULL) { - keymap = (BYTE*) alloca(256); + keymap = keymap2; GetKeyboardState (keymap); has_AltGr = mswindows_current_layout_has_AltGr (); } + /* #### should look at fwKeys for MK_CONTROL. I don't understand how + AltGr works. */ if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) { mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0; @@ -2592,7 +3154,11 @@ int mswindows_modifier_state (BYTE* keymap, int has_AltGr) mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; } - mods |= (keymap [VK_SHIFT] & 0x80) ? XEMACS_MOD_SHIFT : 0; + mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80)) + ? XEMACS_MOD_SHIFT : 0; + mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0; + mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0; + mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0; return mods; } @@ -2601,7 +3167,6 @@ int mswindows_modifier_state (BYTE* keymap, int has_AltGr) * Translate a mswindows virtual key to a keysym. * Only returns non-Qnil for keys that don't generate WM_CHAR messages * or whose ASCII codes (like space) xemacs doesn't like. - * Virtual key values are defined in winresrc.h */ Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, int extendedp) @@ -2610,6 +3175,7 @@ Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, { switch (mswindows_key) { + case VK_CANCEL: return KEYSYM ("pause"); case VK_RETURN: return KEYSYM ("kp-enter"); case VK_PRIOR: return KEYSYM ("prior"); case VK_NEXT: return KEYSYM ("next"); @@ -2621,6 +3187,11 @@ Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, case VK_DOWN: return KEYSYM ("down"); case VK_INSERT: return KEYSYM ("insert"); case VK_DELETE: return QKdelete; +#if 0 /* FSF Emacs allows these to return configurable syms/mods */ + case VK_LWIN return KEYSYM (""); + case VK_RWIN return KEYSYM (""); +#endif + case VK_APPS: return KEYSYM ("menu"); } } else @@ -2632,6 +3203,7 @@ Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, case '\n': return QKlinefeed; case VK_CLEAR: return KEYSYM ("clear"); case VK_RETURN: return QKreturn; + case VK_PAUSE: return KEYSYM ("pause"); case VK_ESCAPE: return QKescape; case VK_SPACE: return QKspace; case VK_PRIOR: return KEYSYM ("kp-prior"); @@ -2649,11 +3221,6 @@ Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, case VK_INSERT: return KEYSYM ("kp-insert"); case VK_DELETE: return KEYSYM ("kp-delete"); case VK_HELP: return KEYSYM ("help"); -#if 0 /* FSF Emacs allows these to return configurable syms/mods */ - case VK_LWIN return KEYSYM (""); - case VK_RWIN return KEYSYM (""); -#endif - case VK_APPS: return KEYSYM ("menu"); case VK_NUMPAD0: return KEYSYM ("kp-0"); case VK_NUMPAD1: return KEYSYM ("kp-1"); case VK_NUMPAD2: return KEYSYM ("kp-2"); @@ -2827,18 +3394,19 @@ emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event) struct frame *f = XFRAME (frame); int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); Lisp_Object conser; + struct gcpro gcpro1; - /* struct gcpro gcpro1; */ - - /* Clear sticky modifiers here (if we had any) */ + /* On focus change, clear all memory of sticky modifiers + to avoid non-intuitive behavior. */ + clear_sticky_modifiers (); conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); - /* GCPRO1 (conser); XXX Not necessary? */ + GCPRO1 (conser); emacs_handle_focus_change_preliminary (conser); /* Under X the stuff up to here is done in the X event handler. I Don't know why */ emacs_handle_focus_change_final (conser); - /* UNGCPRO; */ + UNGCPRO; } break; @@ -2947,8 +3515,9 @@ emacs_mswindows_quit_p (void) if (mswindows_in_modal_loop) return; - /* Drain windows queue. This sets up number of quit characters in - the queue */ + mswindows_quit_chars_count = 0; + /* Drain windows queue. This sets up number of quit characters in + the queue. */ mswindows_drain_windows_queue (); if (mswindows_quit_chars_count > 0) @@ -2961,15 +3530,17 @@ emacs_mswindows_quit_p (void) match_against.event_type = key_press_event; match_against.event.key.modifiers = FAKE_MOD_QUIT; - while (mswindows_quit_chars_count-- > 0) + while (mswindows_quit_chars_count > 0) { emacs_event = mswindows_cancel_dispatch_event (&match_against); assert (!NILP (emacs_event)); - - if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT) + + if (XEVENT (emacs_event)->event.key.modifiers & + FAKE_MOD_QUIT_CRITICAL) critical_p = 1; - Fdeallocate_event(emacs_event); + Fdeallocate_event (emacs_event); + mswindows_quit_chars_count--; } Vquit_flag = critical_p ? Qcritical : Qt; @@ -3079,6 +3650,12 @@ emacs_mswindows_delete_stream_pair (Lisp_Object instream, : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream)))); } +static int +emacs_mswindows_current_event_timestamp (struct console *c) +{ + return GetTickCount (); +} + #ifndef HAVE_X_WINDOWS /* This is called from GC when a process object is about to be freed. If we've still got pointers to it in this file, we're gonna lose hard. @@ -3099,6 +3676,318 @@ debug_process_finalization (Lisp_Process *p) } #endif +#ifdef DEBUG_XEMACS + +struct mswin_message_debug +{ + int mess; + char *string; +}; + +#define FROB(val) { val, #val, }, + +struct mswin_message_debug debug_mswin_messages[] = +{ +FROB (WM_NULL) +FROB (WM_CREATE) +FROB (WM_DESTROY) +FROB (WM_MOVE) +FROB (WM_SIZE) + +FROB (WM_ACTIVATE) + +FROB (WM_SETFOCUS) +FROB (WM_KILLFOCUS) +FROB (WM_ENABLE) +FROB (WM_SETREDRAW) +FROB (WM_SETTEXT) +FROB (WM_GETTEXT) +FROB (WM_GETTEXTLENGTH) +FROB (WM_PAINT) +FROB (WM_CLOSE) +FROB (WM_QUERYENDSESSION) +FROB (WM_QUIT) +FROB (WM_QUERYOPEN) +FROB (WM_ERASEBKGND) +FROB (WM_SYSCOLORCHANGE) +FROB (WM_ENDSESSION) +FROB (WM_SHOWWINDOW) +FROB (WM_WININICHANGE) +#if(WINVER >= 0x0400) +FROB (WM_SETTINGCHANGE) +#endif /* WINVER >= 0x0400 */ + +FROB (WM_DEVMODECHANGE) +FROB (WM_ACTIVATEAPP) +FROB (WM_FONTCHANGE) +FROB (WM_TIMECHANGE) +FROB (WM_CANCELMODE) +FROB (WM_SETCURSOR) +FROB (WM_MOUSEACTIVATE) +FROB (WM_CHILDACTIVATE) +FROB (WM_QUEUESYNC) + +FROB (WM_GETMINMAXINFO) + +FROB (WM_PAINTICON) +FROB (WM_ICONERASEBKGND) +FROB (WM_NEXTDLGCTL) +FROB (WM_SPOOLERSTATUS) +FROB (WM_DRAWITEM) +FROB (WM_MEASUREITEM) +FROB (WM_DELETEITEM) +FROB (WM_VKEYTOITEM) +FROB (WM_CHARTOITEM) +FROB (WM_SETFONT) +FROB (WM_GETFONT) +FROB (WM_SETHOTKEY) +FROB (WM_GETHOTKEY) +FROB (WM_QUERYDRAGICON) +FROB (WM_COMPAREITEM) +#if(WINVER >= 0x0500) +FROB (WM_GETOBJECT) +#endif /* WINVER >= 0x0500 */ +FROB (WM_COMPACTING) +FROB (WM_COMMNOTIFY) +FROB (WM_WINDOWPOSCHANGING) +FROB (WM_WINDOWPOSCHANGED) + +FROB (WM_POWER) + +FROB (WM_COPYDATA) +FROB (WM_CANCELJOURNAL) + +#if(WINVER >= 0x0400) +FROB (WM_NOTIFY) +FROB (WM_INPUTLANGCHANGEREQUEST) +FROB (WM_INPUTLANGCHANGE) +FROB (WM_TCARD) +FROB (WM_HELP) +FROB (WM_USERCHANGED) +FROB (WM_NOTIFYFORMAT) + +FROB (WM_CONTEXTMENU) +FROB (WM_STYLECHANGING) +FROB (WM_STYLECHANGED) +FROB (WM_DISPLAYCHANGE) +FROB (WM_GETICON) +FROB (WM_SETICON) +#endif /* WINVER >= 0x0400 */ + +FROB (WM_NCCREATE) +FROB (WM_NCDESTROY) +FROB (WM_NCCALCSIZE) +FROB (WM_NCHITTEST) +FROB (WM_NCPAINT) +FROB (WM_NCACTIVATE) +FROB (WM_GETDLGCODE) +FROB (WM_SYNCPAINT) +FROB (WM_NCMOUSEMOVE) +FROB (WM_NCLBUTTONDOWN) +FROB (WM_NCLBUTTONUP) +FROB (WM_NCLBUTTONDBLCLK) +FROB (WM_NCRBUTTONDOWN) +FROB (WM_NCRBUTTONUP) +FROB (WM_NCRBUTTONDBLCLK) +FROB (WM_NCMBUTTONDOWN) +FROB (WM_NCMBUTTONUP) +FROB (WM_NCMBUTTONDBLCLK) + +/* FROB (WM_KEYFIRST) */ +FROB (WM_KEYDOWN) +FROB (WM_KEYUP) +FROB (WM_CHAR) +FROB (WM_DEADCHAR) +FROB (WM_SYSKEYDOWN) +FROB (WM_SYSKEYUP) +FROB (WM_SYSCHAR) +FROB (WM_SYSDEADCHAR) +FROB (WM_KEYLAST) + +#if(WINVER >= 0x0400) && !defined(CYGWIN) +FROB (WM_IME_STARTCOMPOSITION) +FROB (WM_IME_ENDCOMPOSITION) +FROB (WM_IME_COMPOSITION) +FROB (WM_IME_KEYLAST) +#endif /* WINVER >= 0x0400 */ + +FROB (WM_INITDIALOG) +FROB (WM_COMMAND) +FROB (WM_SYSCOMMAND) +FROB (WM_TIMER) +FROB (WM_HSCROLL) +FROB (WM_VSCROLL) +FROB (WM_INITMENU) +FROB (WM_INITMENUPOPUP) +FROB (WM_MENUSELECT) +FROB (WM_MENUCHAR) +FROB (WM_ENTERIDLE) +#if(WINVER >= 0x0500) +FROB (WM_MENURBUTTONUP) +FROB (WM_MENUDRAG) +FROB (WM_MENUGETOBJECT) +FROB (WM_UNINITMENUPOPUP) +FROB (WM_MENUCOMMAND) +#endif /* WINVER >= 0x0500 */ + + +FROB (WM_CTLCOLORMSGBOX) +FROB (WM_CTLCOLOREDIT) +FROB (WM_CTLCOLORLISTBOX) +FROB (WM_CTLCOLORBTN) +FROB (WM_CTLCOLORDLG) +FROB (WM_CTLCOLORSCROLLBAR) +FROB (WM_CTLCOLORSTATIC) + + +/* FROB (WM_MOUSEFIRST) */ +FROB (WM_MOUSEMOVE) +FROB (WM_LBUTTONDOWN) +FROB (WM_LBUTTONUP) +FROB (WM_LBUTTONDBLCLK) +FROB (WM_RBUTTONDOWN) +FROB (WM_RBUTTONUP) +FROB (WM_RBUTTONDBLCLK) +FROB (WM_MBUTTONDOWN) +FROB (WM_MBUTTONUP) +FROB (WM_MBUTTONDBLCLK) + +#if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) +FROB (WM_MOUSEWHEEL) +FROB (WM_MOUSELAST) +#else +FROB (WM_MOUSELAST) +#endif /* if (_WIN32_WINNT < 0x0400) */ + +FROB (WM_PARENTNOTIFY) +FROB (WM_ENTERMENULOOP) +FROB (WM_EXITMENULOOP) + +#if(WINVER >= 0x0400) +FROB (WM_NEXTMENU) + +FROB (WM_SIZING) +FROB (WM_CAPTURECHANGED) +FROB (WM_MOVING) +FROB (WM_POWERBROADCAST) + +FROB (WM_DEVICECHANGE) + +#endif /* WINVER >= 0x0400 */ + +FROB (WM_MDICREATE) +FROB (WM_MDIDESTROY) +FROB (WM_MDIACTIVATE) +FROB (WM_MDIRESTORE) +FROB (WM_MDINEXT) +FROB (WM_MDIMAXIMIZE) +FROB (WM_MDITILE) +FROB (WM_MDICASCADE) +FROB (WM_MDIICONARRANGE) +FROB (WM_MDIGETACTIVE) + + +FROB (WM_MDISETMENU) +FROB (WM_ENTERSIZEMOVE) +FROB (WM_EXITSIZEMOVE) +FROB (WM_DROPFILES) +FROB (WM_MDIREFRESHMENU) + + +#if(WINVER >= 0x0400) && !defined(CYGWIN) +FROB (WM_IME_SETCONTEXT) +FROB (WM_IME_NOTIFY) +FROB (WM_IME_CONTROL) +FROB (WM_IME_COMPOSITIONFULL) +FROB (WM_IME_SELECT) +FROB (WM_IME_CHAR) +#endif /* WINVER >= 0x0400 */ +#if(WINVER >= 0x0500) +FROB (WM_IME_REQUEST) +#endif /* WINVER >= 0x0500 */ +#if(WINVER >= 0x0400) && !defined(CYGWIN) +FROB (WM_IME_KEYDOWN) +FROB (WM_IME_KEYUP) +#endif /* WINVER >= 0x0400 */ + + +#if(_WIN32_WINNT >= 0x0400) +FROB (WM_MOUSEHOVER) +FROB (WM_MOUSELEAVE) +#endif /* _WIN32_WINNT >= 0x0400 */ + +FROB (WM_CUT) +FROB (WM_COPY) +FROB (WM_PASTE) +FROB (WM_CLEAR) +FROB (WM_UNDO) +FROB (WM_RENDERFORMAT) +FROB (WM_RENDERALLFORMATS) +FROB (WM_DESTROYCLIPBOARD) +FROB (WM_DRAWCLIPBOARD) +FROB (WM_PAINTCLIPBOARD) +FROB (WM_VSCROLLCLIPBOARD) +FROB (WM_SIZECLIPBOARD) +FROB (WM_ASKCBFORMATNAME) +FROB (WM_CHANGECBCHAIN) +FROB (WM_HSCROLLCLIPBOARD) +FROB (WM_QUERYNEWPALETTE) +FROB (WM_PALETTEISCHANGING) +FROB (WM_PALETTECHANGED) +FROB (WM_HOTKEY) + +#if(WINVER >= 0x0400) +FROB (WM_PRINT) +FROB (WM_PRINTCLIENT) + +FROB (WM_HANDHELDFIRST) +FROB (WM_HANDHELDLAST) + +FROB (WM_AFXFIRST) +FROB (WM_AFXLAST) +#endif /* WINVER >= 0x0400 */ + +FROB (WM_PENWINFIRST) +FROB (WM_PENWINLAST) +}; + +#undef FROB + +static void +debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam, + LPARAM lParam) +{ + Lisp_Object frame = mswindows_find_frame (hwnd); + int i; + char *str = 0; + /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */ + + for (i = 0; i < countof (debug_mswin_messages); i++) + { + if (debug_mswin_messages[i].mess == message_) + { + str = debug_mswin_messages[i].string; + break; + } + } + + if (str) + stderr_out ("%s", str); + else + stderr_out ("%x", message_); + + if (debug_mswindows_events > 1) + { + stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ", + wParam, (int) lParam, (unsigned int) hwnd); + debug_print (frame); + } + else + stderr_out ("\n"); +} + +#endif /* DEBUG_XEMACS */ + /************************************************************************/ /* initialization */ /************************************************************************/ @@ -3133,6 +4022,8 @@ reinit_vars_of_event_mswindows (void) mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair; mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair; #endif + mswindows_event_stream->current_event_timestamp_cb = + emacs_mswindows_current_event_timestamp; } void @@ -3143,16 +4034,29 @@ vars_of_event_mswindows (void) mswindows_u_dispatch_event_queue = Qnil; staticpro (&mswindows_u_dispatch_event_queue); mswindows_u_dispatch_event_queue_tail = Qnil; - pdump_wire (&mswindows_u_dispatch_event_queue_tail); + dump_add_root_object (&mswindows_u_dispatch_event_queue_tail); mswindows_s_dispatch_event_queue = Qnil; staticpro (&mswindows_s_dispatch_event_queue); mswindows_s_dispatch_event_queue_tail = Qnil; - pdump_wire (&mswindows_s_dispatch_event_queue_tail); + dump_add_root_object (&mswindows_s_dispatch_event_queue_tail); mswindows_error_caught_in_modal_loop = Qnil; staticpro (&mswindows_error_caught_in_modal_loop); + +#ifdef DEBUG_XEMACS + DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /* +If non-zero, display debug information about Windows messages that XEmacs sees. +Information is displayed in a console window. Currently defined values are: + +1 == non-verbose output (just the message name) +2 == verbose output (all parameters) +3 == even more verbose output (extra debugging info) +*/ ); + debug_mswindows_events = 0; +#endif + DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu", &mswindows_alt_by_itself_activates_menu /* *Controls whether pressing and releasing the Alt key activates the menubar. @@ -3220,7 +4124,7 @@ lstream_type_create_mswindows_selectable (void) { init_slurp_stream (); init_shove_stream (); -#if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT) +#if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT) init_winsock_stream (); #endif }