X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=src%2Fevent-msw.c;h=c5c3d2fef1d228652bcb335571b8de6d0ce78519;hp=09054fd94eb8add05f4f382b333496ea91da472e;hb=716cfba952c1dc0d2cf5c968971f3780ba728a89;hpb=6883ee56ec887c2c48abe5b06b5e66aa74031910 diff --git a/src/event-msw.c b/src/event-msw.c index 09054fd..c5c3d2f 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,23 +51,32 @@ 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" +#include "select.h" #include "sysproc.h" #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__) && (CYGWIN_VERSION_DLL_MAJOR < 20) +typedef NMHDR *LPNMHDR; +#endif + #ifdef HAVE_MENUBARS #define ADJR_MENUFLAG TRUE #else @@ -80,14 +90,10 @@ typedef unsigned int SOCKET; /* Timer ID used for button2 emulation */ #define BUTTON_2_TIMER_ID 1 -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); - 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); +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 void mswindows_set_chord_timer (HWND hwnd); static int mswindows_button2_near_enough (POINTS p1, POINTS p2); @@ -98,6 +104,7 @@ static struct event_stream *mswindows_event_stream; #ifdef HAVE_MSG_SELECT extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; extern SELECT_TYPE process_only_mask, tty_only_mask; +SELECT_TYPE zero_mask; extern int signal_event_pipe_initialized; int windows_fd; #endif @@ -114,11 +121,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() @@ -127,6 +139,7 @@ int mswindows_quit_chars_count = 0; /* These are Lisp integers; see DEFVARS in this file for description. */ int mswindows_dynamic_frame_resize; +int mswindows_meta_activates_menu; int mswindows_num_mouse_buttons; int mswindows_mouse_button_max_skew_x; int mswindows_mouse_button_max_skew_y; @@ -154,7 +167,7 @@ static int mswindows_pending_timers_count; /* This structure is allocated by the main thread, and is deallocated in the thread upon exit. There are situations when a thread remains blocked for a long time, much longer than the lstream - exists. For exmaple, "start notepad" command is issued from the + exists. For example, "start notepad" command is issued from the shell, then the shell is closed by C-c C-d. Although the shell process exits, its output pipe will not get closed until the notepad process exits also, because it inherits the pipe form the @@ -180,7 +193,7 @@ struct ntpipe_slurp_stream_shared_data }; #define MAX_SLURP_STREAMS 32 -struct ntpipe_slurp_stream_shared_data +struct ntpipe_slurp_stream_shared_data shared_data_block[MAX_SLURP_STREAMS]={{0}}; struct ntpipe_slurp_stream @@ -193,7 +206,7 @@ DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp, sizeof (struct ntpipe_slurp_stream)); /* This function is thread-safe, and is called from either thread - context. It serializes freeing shared dtata structure */ + context. It serializes freeing shared data structure */ static void slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s) { @@ -252,7 +265,7 @@ slurp_thread (LPVOID vparam) /* Now we got something to notify caller, either a byte or an error/eof indication. Before we do, allow internal pipe - buffer to accumulate little bit more data. + buffer to accumulate little bit more data. Reader function pulses this event before waiting for a character, to avoid pipe delay, and to get the byte immediately. */ @@ -267,7 +280,7 @@ slurp_thread (LPVOID vparam) if (s->die_p) break; - /* Block until the client finishes with retireving the rest of + /* Block until the client finishes with retrieving the rest of pipe data */ WaitForSingleObject (s->hev_thread, INFINITE); } @@ -341,11 +354,11 @@ get_ntpipe_input_stream_waitable (Lstream *stream) return s->thread_data->hev_caller; } -static int +static ssize_t ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) { /* This function must be called from the main thread only */ - struct ntpipe_slurp_stream_shared_data* s = + struct ntpipe_slurp_stream_shared_data* s = NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; if (!s->die_p) @@ -354,7 +367,7 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) /* Disallow pipe read delay for the thread: we need a character ASAP */ SetEvent (s->hev_unsleep); - + /* Check if we have a character ready. Give it a short delay, for the thread to awake from pipe delay, just ion case*/ wait_result = WaitForSingleObject (s->hev_caller, 2); @@ -405,7 +418,7 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) ReadFile (s->hpipe, data, min (bytes_available, size), &bytes_read, NULL); } - + /* Now we can unblock thread, so it attempts to read more */ SetEvent (s->hev_thread); return bytes_read + 1; @@ -414,11 +427,11 @@ ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) return 0; } -static int +static int ntpipe_slurp_closer (Lstream *stream) { /* This function must be called from the main thread only */ - struct ntpipe_slurp_stream_shared_data* s = + struct ntpipe_slurp_stream_shared_data* s = NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; /* Force thread to stop */ @@ -450,7 +463,7 @@ init_slurp_stream (void) LSTREAM_TYPE_DATA (stream, ntpipe_shove) #define MAX_SHOVE_BUFFER_SIZE 128 - + struct ntpipe_shove_stream { LPARAM user_data; /* Any user data stored in the stream object */ @@ -469,6 +482,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) { @@ -476,7 +490,7 @@ shove_thread (LPVOID vparam) for (;;) { - DWORD bytes_written; + DWORD bytes_written; /* Block on event and wait for a job */ InterlockedIncrement (&s->idle_p); @@ -513,7 +527,7 @@ make_ntpipe_output_stream (HANDLE hpipe, LPARAM param) s->hpipe = hpipe; s->user_data = param; - /* Create reader thread. This could fail, so do not + /* Create reader thread. This could fail, so do not create the event until thread is created */ s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s, CREATE_SUSPENDED, &thread_id_unused); @@ -540,8 +554,9 @@ get_ntpipe_output_stream_param (Lstream *stream) struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); return s->user_data; } +#endif -static int +static ssize_t ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size) { struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); @@ -618,7 +633,7 @@ struct winsock_stream OVERLAPPED ov; /* Overlapped I/O structure */ void* buffer; /* Buffer. Allocated for input stream only */ unsigned int bufsize; /* Number of bytes last read */ - unsigned int bufpos; /* Psition in buffer for next fetch */ + unsigned int bufpos; /* Position in buffer for next fetch */ unsigned int error_p :1; /* I/O Error seen */ unsigned int eof_p :1; /* EOF Error seen */ unsigned int pending_p :1; /* There is a pending I/O operation */ @@ -650,7 +665,7 @@ winsock_initiate_read (struct winsock_stream *str) str->eof_p = 1; } -static int +static ssize_t winsock_reader (Lstream *stream, unsigned char *data, size_t size) { struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); @@ -683,7 +698,7 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size) return 0; if (str->error_p) return -1; - + /* Return as much of buffer as we have */ size = min (size, (size_t) (str->bufsize - str->bufpos)); memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size); @@ -696,7 +711,7 @@ winsock_reader (Lstream *stream, unsigned char *data, size_t size) return size; } -static int +static ssize_t winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size) { struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); @@ -724,11 +739,14 @@ winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size) if (size == 0) return 0; - + { ResetEvent (str->ov.hEvent); - - if (WriteFile ((HANDLE)str->s, data, size, NULL, &str->ov) + + /* 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 @@ -835,7 +853,7 @@ init_winsock_stream (void) /************************************************************************/ static int -mswindows_user_event_p (struct Lisp_Event* sevt) +mswindows_user_event_p (Lisp_Event* sevt) { return (sevt->event_type == key_press_event || sevt->event_type == button_press_event @@ -843,7 +861,7 @@ mswindows_user_event_p (struct Lisp_Event* sevt) || sevt->event_type == misc_user_event); } -/* +/* * Add an emacs event to the proper dispatch queue */ static void @@ -851,7 +869,7 @@ mswindows_enqueue_dispatch_event (Lisp_Object event) { int user_p = mswindows_user_event_p (XEVENT(event)); enqueue_event (event, - user_p ? &mswindows_u_dispatch_event_queue : + user_p ? &mswindows_u_dispatch_event_queue : &mswindows_s_dispatch_event_queue, user_p ? &mswindows_u_dispatch_event_queue_tail : &mswindows_s_dispatch_event_queue_tail); @@ -871,10 +889,11 @@ mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function, Lisp_Object object) { Lisp_Object event = Fmake_event (Qnil, Qnil); - struct Lisp_Event* e = XEVENT (event); + Lisp_Event* e = XEVENT (event); e->event_type = misc_user_event; e->channel = channel; + e->timestamp = GetTickCount (); e->event.misc.function = function; e->event.misc.object = object; @@ -882,24 +901,24 @@ mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function, } void -mswindows_enqueue_magic_event (HWND hwnd, UINT message) +mswindows_enqueue_magic_event (HWND hwnd, UINT msg) { Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - struct Lisp_Event* event = XEVENT (emacs_event); + Lisp_Event* event = XEVENT (emacs_event); event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil; event->timestamp = GetMessageTime(); event->event_type = magic_event; - EVENT_MSWINDOWS_MAGIC_TYPE (event) = message; + EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg; mswindows_enqueue_dispatch_event (emacs_event); } static void -mswindows_enqueue_process_event (struct Lisp_Process* p) +mswindows_enqueue_process_event (Lisp_Process* p) { Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - struct Lisp_Event* event = XEVENT (emacs_event); + Lisp_Event* event = XEVENT (emacs_event); Lisp_Object process; XSETPROCESS (process, p); @@ -911,7 +930,7 @@ mswindows_enqueue_process_event (struct Lisp_Process* p) } static void -mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when) +mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when) { /* We always use last message time, because mouse button @@ -919,29 +938,36 @@ mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWO recognition will fail */ Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - struct Lisp_Event* event = XEVENT(emacs_event); + Lisp_Event* event = XEVENT(emacs_event); event->channel = mswindows_find_frame(hwnd); event->timestamp = when; event->event.button.button = - (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 : - ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2); + (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); - - if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN || - message==WM_RBUTTONDOWN) + + if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN || + msg==WM_RBUTTONDOWN) { 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 { event->event_type = button_release_event; ReleaseCapture (); } - + mswindows_enqueue_dispatch_event (emacs_event); } @@ -949,7 +975,7 @@ static void mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods) { Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - struct Lisp_Event* event = XEVENT(emacs_event); + Lisp_Event* event = XEVENT(emacs_event); event->channel = mswindows_find_console(hwnd); event->timestamp = GetMessageTime(); @@ -967,16 +993,16 @@ static Lisp_Object mswindows_dequeue_dispatch_event () { Lisp_Object event; - struct Lisp_Event* sevt; + Lisp_Event* sevt; assert (!NILP(mswindows_u_dispatch_event_queue) || !NILP(mswindows_s_dispatch_event_queue)); event = dequeue_event ( - NILP(mswindows_u_dispatch_event_queue) ? - &mswindows_s_dispatch_event_queue : + NILP(mswindows_u_dispatch_event_queue) ? + &mswindows_s_dispatch_event_queue : &mswindows_u_dispatch_event_queue, - NILP(mswindows_u_dispatch_event_queue) ? + NILP(mswindows_u_dispatch_event_queue) ? &mswindows_s_dispatch_event_queue_tail : &mswindows_u_dispatch_event_queue_tail); @@ -993,22 +1019,22 @@ 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 (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 : + Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : &mswindows_s_dispatch_event_queue; - Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : + Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : &mswindows_s_dispatch_event_queue_tail; assert (match->event_type == timeout_event @@ -1016,19 +1042,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) + 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); @@ -1038,7 +1057,7 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match) if (EQ (*tail, event)) *tail = previous_event; } - + return event; } previous_event = event; @@ -1046,6 +1065,7 @@ mswindows_cancel_dispatch_event (struct Lisp_Event* match) return Qnil; } +#ifndef HAVE_MSG_SELECT /************************************************************************/ /* Waitable handles manipulation */ /************************************************************************/ @@ -1078,9 +1098,10 @@ remove_waitable_handle (HANDLE h) if (ix < 0) return; - mswindows_waitable_handles [ix] = + mswindows_waitable_handles [ix] = mswindows_waitable_handles [--mswindows_waitable_count]; } +#endif /* HAVE_MSG_SELECT */ /************************************************************************/ @@ -1101,7 +1122,7 @@ mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg), { Lisp_Object tmp; - ++mswindows_in_modal_loop; + ++mswindows_in_modal_loop; tmp = condition_case_1 (Qt, bfun, barg, mswindows_modal_loop_error_handler, Qnil); @@ -1125,7 +1146,7 @@ mswindows_unmodalize_signal_maybe (void) } /* - * This is an unsafe part of event pump, guarded by + * This is an unsafe part of event pump, guarded by * condition_case. See mswindows_pump_outstanding_events */ static Lisp_Object @@ -1149,7 +1170,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d) Fdeallocate_event (event); UNGCPRO; - + /* Qt becomes return value of mswindows_pump_outstanding_events once we get here */ return Qt; @@ -1164,7 +1185,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d) * neither are waitable handles checked. The function pumps * thus only dispatch events already queued, as well as those * resulted in dispatching thereof. This is done by setting - * module local variable mswidows_in_modal_loop to nonzero. + * module local variable mswindows_in_modal_loop to nonzero. * * Return value is Qt if no errors was trapped, or Qunbound if * there was an error. @@ -1182,7 +1203,7 @@ mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d) * If the value of mswindows_error_caught_in_modal_loop is not * nil already upon entry, the function just returns non-nil. * This situation means that a new event has been queued while - * cancleng mode. The event will be dequeued on the next regular + * in cancel mode. The event will be dequeued on the next regular * call of next-event; the pump is off since error is caught. * The caller must *unconditionally* cancel modal loop if the * value returned by this function is nil. Otherwise, everything @@ -1197,29 +1218,49 @@ mswindows_pump_outstanding_events (void) Lisp_Object result = Qt; struct gcpro gcpro1; GCPRO1 (result); - + if (NILP(mswindows_error_caught_in_modal_loop)) result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); UNGCPRO; return result; } -static void -mswindows_drain_windows_queue () +/* + * KEYBOARD_ONLY_P is set to non-zero when we are called from + * QUITP, and are interesting in keyboard messages only. + */ +static void +mswindows_drain_windows_queue (int keyboard_only_till_quit_char_p) { MSG msg; - while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + + /* Minimize the hassle of misordered events by not fetching + past quit char if called from QUITP; */ + while (!(keyboard_only_till_quit_char_p && + mswindows_quit_chars_count > 0) && + PeekMessage (&msg, NULL, + keyboard_only_till_quit_char_p ? WM_KEYFIRST : 0, + keyboard_only_till_quit_char_p ? WM_KEYLAST : 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 (); } } -/* - * This is a special flavour of the mswindows_need_event function, +/* + * This is a special flavor of the mswindows_need_event function, * used while in event pump. Actually, there is only kind of events * allowed while in event pump: a timer. An attempt to fetch any - * other event leads to a dealock, as there's no source of user input + * other event leads to a deadlock, as there's no source of user input * ('cause event pump mirrors windows modal loop, which is a sole * owner of thread message queue). * @@ -1248,7 +1289,7 @@ mswindows_need_event_in_modal_loop (int badly_p) /* We'll deadlock if go waiting */ if (mswindows_pending_timers_count == 0) 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); @@ -1273,9 +1314,13 @@ mswindows_need_event (int badly_p) return; } +#if 0 /* Have to drain Windows message queue first, otherwise, we may miss quit char when called from quit_p */ + /* #### This is, ehm, not quite true -- this function is not + called from quit_p. --kkm */ mswindows_drain_windows_queue (); +#endif while (NILP (mswindows_u_dispatch_event_queue) && NILP (mswindows_s_dispatch_event_queue)) @@ -1285,7 +1330,7 @@ mswindows_need_event (int badly_p) SELECT_TYPE temp_mask = input_wait_mask; EMACS_TIME sometime; EMACS_SELECT_TIME select_time_to_block, *pointer_to_this; - + if (badly_p) pointer_to_this = 0; else @@ -1294,19 +1339,42 @@ mswindows_need_event (int badly_p) EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block); pointer_to_this = &select_time_to_block; } + active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this); - + if (active == 0) { + assert (!badly_p); return; /* timeout */ } else if (active > 0) { if (FD_ISSET (windows_fd, &temp_mask)) { - mswindows_drain_windows_queue (); + mswindows_drain_windows_queue (0); } - +#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); + 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++) { @@ -1314,16 +1382,11 @@ mswindows_need_event (int badly_p) { if (FD_ISSET (i, &process_only_mask)) { - struct Lisp_Process *p = + Lisp_Process *p = get_process_from_usid (FD_TO_USID(i)); - + 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 @@ -1340,7 +1403,7 @@ mswindows_need_event (int badly_p) { if (errno != EINTR) { - /* something bad happended */ + /* something bad happened */ assert(0); } } @@ -1360,7 +1423,7 @@ mswindows_need_event (int badly_p) assert ((!badly_p && active == WAIT_TIMEOUT) || (active >= WAIT_OBJECT_0 && active <= WAIT_OBJECT_0 + mswindows_waitable_count)); - + if (active == WAIT_TIMEOUT) { /* No luck trying - just return what we've already got */ @@ -1369,13 +1432,13 @@ mswindows_need_event (int badly_p) else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) { /* Got your message, thanks */ - mswindows_drain_windows_queue (); + mswindows_drain_windows_queue (0); } else { int ix = active - WAIT_OBJECT_0; - /* First, try to find which process' ouptut has signaled */ - struct Lisp_Process *p = + /* First, try to find which process' output has signaled */ + Lisp_Process *p = get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix])); if (p != NULL) { @@ -1385,7 +1448,7 @@ mswindows_need_event (int badly_p) else { /* None. This means that the process handle itself has signaled. - Remove the handle from the wait vector, and make status_ntoify + Remove the handle from the wait vector, and make status_notify note the exited process */ mswindows_waitable_handles [ix] = mswindows_waitable_handles [--mswindows_waitable_count]; @@ -1403,14 +1466,14 @@ mswindows_need_event (int badly_p) /* Event generators */ /************************************************************************/ -/* +/* * Callback procedure for synchronous timer messages */ static void CALLBACK mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime) { Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); - struct Lisp_Event *event = XEVENT (emacs_event); + Lisp_Event *event = XEVENT (emacs_event); if (KillTimer (NULL, id_timer)) --mswindows_pending_timers_count; @@ -1419,11 +1482,13 @@ 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); } -/* +/* * Callback procedure for dde messages * * We execute a dde Open("file") by simulating a file drop, so dde support @@ -1434,9 +1499,9 @@ HDDEDATA CALLBACK mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, HSZ hszTopic, HSZ hszItem, HDDEDATA hdata, DWORD dwData1, DWORD dwData2) -{ +{ switch (uType) - { + { case XTYP_CONNECT: if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) return (HDDEDATA)TRUE; @@ -1453,7 +1518,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs, sizeof (pairs), 0L, 0, uFmt, 0)); } - return (HDDEDATA)NULL; + return (HDDEDATA)NULL; case XTYP_EXECUTE: if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) @@ -1466,7 +1531,7 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, Lisp_Object l_dndlist = Qnil; Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); Lisp_Object frmcons, devcons, concons; - struct Lisp_Event *event = XEVENT (emacs_event); + Lisp_Event *event = XEVENT (emacs_event); DdeGetData (hdata, cmd, len, 0); cmd[len] = '\0'; @@ -1534,32 +1599,52 @@ mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, UNGCPRO; return (HDDEDATA) DDE_FACK; } - DdeFreeDataHandle (hdata); + DdeFreeDataHandle (hdata); return (HDDEDATA) DDE_FNOTPROCESSED; - default: - return (HDDEDATA) NULL; - } + default: + return (HDDEDATA) NULL; + } } #endif /* + * 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_meta_activates_menu && vkey == VK_MENU) + return 1; + + return 0; +} + +/* * The windows procedure for the window class XEMACS_CLASS */ LRESULT WINAPI mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - /* Note: Remember to initialise emacs_event and event before use. + /* Note: Remember to initialize emacs_event and event before use. This code calls code that can GC. You must GCPRO before calling such code. */ Lisp_Object emacs_event = Qnil; Lisp_Object fobj = Qnil; - struct Lisp_Event *event; + Lisp_Event *event; struct frame *frame; struct mswindows_frame* msframe; 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); + break; + case WM_ERASEBKGND: /* Erase background only during non-dynamic sizing */ msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); @@ -1572,34 +1657,86 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); break; + case WM_KEYUP: + case WM_SYSKEYUP: + /* See Win95 comment under WM_KEYDOWN */ + { + BYTE keymap[256]; + + if (wParam == VK_CONTROL) + { + GetKeyboardState (keymap); + keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; + SetKeyboardState (keymap); + } + else if (wParam == VK_MENU) + { + GetKeyboardState (keymap); + keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; + SetKeyboardState (keymap); + } + }; + if (key_needs_default_processing_p (wParam)) + goto defproc; + else + break; + 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. + * 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, + * it translates as if AltGr were down. + * We get round this by removing all modifiers from the keymap before + * calling TranslateMessage() unless AltGr is *really* down. */ { BYTE keymap[256]; int has_AltGr = mswindows_current_layout_has_AltGr (); int mods; + int extendedp = lParam & 0x1000000; Lisp_Object keysym; GetKeyboardState (keymap); mods = mswindows_modifier_state (keymap, has_AltGr); - /* Handle those keys that TranslateMessage won't generate a WM_CHAR for */ - if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods))) + /* Handle non-printables */ + if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, + extendedp))) mswindows_enqueue_keypress_event (hwnd, keysym, mods); - else + else /* Normal keys & modifiers */ { 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, + * without screwing up Windows NT which tracks them properly. */ + if (wParam == VK_CONTROL) + keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; + else if (wParam == VK_MENU) + keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80; + memcpy (keymap_orig, keymap, 256); /* Remove shift modifier from an ascii character */ mods &= ~MOD_SHIFT; - /* Clear control and alt modifiers out of the keymap */ + /* 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)) + if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) + || !(keymap [VK_RMENU] & 0x80)) { keymap [VK_LCONTROL] = 0; keymap [VK_CONTROL] = 0; @@ -1608,7 +1745,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } SetKeyboardState (keymap); - /* Have some WM_[SYS]CHARS in the queue */ + /* Maybe generate some WM_[SYS]CHARs in the queue */ TranslateMessage (&msg); while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) @@ -1635,10 +1772,10 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) SetKeyboardState (keymap_orig); } /* else */ } - /* F10 causes menu activation by default. We do not want this */ - if (wParam != VK_F10) + if (key_needs_default_processing_p (wParam)) goto defproc; - break; + else + break; case WM_MBUTTONDOWN: case WM_MBUTTONUP: @@ -1648,7 +1785,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) mswindows_enqueue_mouse_button_event (hwnd, message, MAKEPOINTS (lParam), GetMessageTime()); break; - + case WM_LBUTTONUP: msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); msframe->last_click_time = GetMessageTime(); @@ -1770,7 +1907,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } msframe->last_click_time = GetMessageTime(); break; - + case WM_TIMER: if (wParam == BUTTON_2_TIMER_ID) { @@ -1795,13 +1932,13 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_MOUSEMOVE: - /* Optimization: don't report mouse movement while size is changind */ + /* Optimization: don't report mouse movement while size is changing */ msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); if (!msframe->sizing) { /* When waiting for the second mouse button to finish button2 emulation, and have moved too far, just pretend - as if timer has expired. This impoves drag-select feedback */ + as if timer has expired. This improves drag-select feedback */ if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) && !mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) @@ -1819,7 +1956,7 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) event->event.motion.x = MAKEPOINTS(lParam).x; event->event.motion.y = MAKEPOINTS(lParam).y; event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); - + mswindows_enqueue_dispatch_event (emacs_event); } break; @@ -1832,18 +1969,21 @@ 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 ); - + btext = mswindows_get_toolbar_button_text ( frame, + nmhdr->idFrom ); + tttext->lpszText = NULL; tttext->hinst = NULL; @@ -1851,27 +1991,66 @@ 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); + TO_EXTERNAL_FORMAT (LISP_STRING, btext, + C_STRING_ALLOCA, tttext->lpszText, + Qnative); } -#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 idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); + frame = XFRAME (mswindows_find_frame (hwnd)); + + item.mask = TCIF_PARAM; + SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx, + (LPARAM)&item); + + mswindows_handle_gui_wm_command (frame, 0, item.lParam); + } } break; -#endif - + case WM_PAINT: { - PAINTSTRUCT paintStruct; - - frame = XFRAME (mswindows_find_frame (hwnd)); + /* According to the docs we need to check GetUpdateRect() before + actually doing a WM_PAINT */ + if (GetUpdateRect (hwnd, NULL, FALSE)) + { + PAINTSTRUCT paintStruct; + int x, y, width, height; - BeginPaint (hwnd, &paintStruct); - mswindows_redraw_exposed_area (frame, - paintStruct.rcPaint.left, paintStruct.rcPaint.top, - paintStruct.rcPaint.right, paintStruct.rcPaint.bottom); - EndPaint (hwnd, &paintStruct); + frame = XFRAME (mswindows_find_frame (hwnd)); + + BeginPaint (hwnd, &paintStruct); + x = paintStruct.rcPaint.left; + y = paintStruct.rcPaint.top; + width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; + height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; + /* Normally we want to ignore expose events when child + 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. */ + if (!check_for_ignored_expose (frame, x, y, width, height)) + { + hold_ignored_expose_registration = 1; + mswindows_redraw_exposed_area (frame, x, y, width, height); + hold_ignored_expose_registration = 0; + } + + EndPaint (hwnd, &paintStruct); + } + else + goto defproc; } break; @@ -1914,8 +2093,8 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (FRAME_MSWINDOWS_TARGET_RECT (frame)) { /* Yes, we have to size again */ - mswindows_size_frame_internal ( frame, - FRAME_MSWINDOWS_TARGET_RECT + mswindows_size_frame_internal ( frame, + FRAME_MSWINDOWS_TARGET_RECT (frame)); /* Reset so we do not get here again. The SetWindowPos call in * mswindows_size_frame_internal can cause recursion here. */ @@ -1930,7 +2109,7 @@ 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 (); } @@ -2021,7 +2200,24 @@ mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); } UNGCPRO; - break; + break; + } + + case WM_MOUSEWHEEL: + { + int keys = LOWORD (wParam); /* Modifier key flags */ + int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ + struct gcpro gcpro1, gcpro2; + + if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta)) + { + GCPRO2 (emacs_event, fobj); + mswindows_pump_outstanding_events (); /* Can GC */ + UNGCPRO; + } + else + goto defproc; + break; } #endif @@ -2048,6 +2244,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)); @@ -2055,17 +2252,83 @@ 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)) + { + /* 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 */ { @@ -2229,67 +2492,100 @@ int mswindows_modifier_state (BYTE* keymap, int has_AltGr) * 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 - * XXX I'm not sure that KEYSYM("name") is the best thing to use here. */ -Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods) +Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, + int extendedp) { - switch (mswindows_key) - { - /* First the predefined ones */ - case VK_BACK: return QKbackspace; - case VK_TAB: return QKtab; - case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */ - case VK_RETURN: return QKreturn; - case VK_ESCAPE: return QKescape; - case VK_SPACE: return QKspace; - case VK_DELETE: return QKdelete; - - /* The rest */ - case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */ - case VK_PRIOR: return KEYSYM ("prior"); - case VK_NEXT: return KEYSYM ("next"); - case VK_END: return KEYSYM ("end"); - case VK_HOME: return KEYSYM ("home"); - case VK_LEFT: return KEYSYM ("left"); - case VK_UP: return KEYSYM ("up"); - case VK_RIGHT: return KEYSYM ("right"); - case VK_DOWN: return KEYSYM ("down"); - case VK_SELECT: return KEYSYM ("select"); - case VK_PRINT: return KEYSYM ("print"); - case VK_EXECUTE: return KEYSYM ("execute"); - case VK_SNAPSHOT: return KEYSYM ("print"); - case VK_INSERT: return KEYSYM ("insert"); - case VK_HELP: return KEYSYM ("help"); -#if 0 /* XXX What are these supposed to do? */ - case VK_LWIN return KEYSYM (""); - case VK_RWIN return KEYSYM (""); + if (extendedp) /* Keys not present on a 82 key keyboard */ + { + switch (mswindows_key) + { + case VK_RETURN: return KEYSYM ("kp-enter"); + case VK_PRIOR: return KEYSYM ("prior"); + case VK_NEXT: return KEYSYM ("next"); + case VK_END: return KEYSYM ("end"); + case VK_HOME: return KEYSYM ("home"); + case VK_LEFT: return KEYSYM ("left"); + case VK_UP: return KEYSYM ("up"); + case VK_RIGHT: return KEYSYM ("right"); + case VK_DOWN: return KEYSYM ("down"); + case VK_INSERT: return KEYSYM ("insert"); + case VK_DELETE: return QKdelete; + } + } + else + { + switch (mswindows_key) + { + case VK_BACK: return QKbackspace; + case VK_TAB: return QKtab; + case '\n': return QKlinefeed; + case VK_CLEAR: return KEYSYM ("clear"); + case VK_RETURN: return QKreturn; + case VK_ESCAPE: return QKescape; + case VK_SPACE: return QKspace; + case VK_PRIOR: return KEYSYM ("kp-prior"); + case VK_NEXT: return KEYSYM ("kp-next"); + case VK_END: return KEYSYM ("kp-end"); + case VK_HOME: return KEYSYM ("kp-home"); + case VK_LEFT: return KEYSYM ("kp-left"); + case VK_UP: return KEYSYM ("kp-up"); + case VK_RIGHT: return KEYSYM ("kp-right"); + case VK_DOWN: return KEYSYM ("kp-down"); + case VK_SELECT: return KEYSYM ("select"); + case VK_PRINT: return KEYSYM ("print"); + case VK_EXECUTE: return KEYSYM ("execute"); + case VK_SNAPSHOT: return KEYSYM ("print"); + 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_F1: return KEYSYM ("f1"); - case VK_F2: return KEYSYM ("f2"); - case VK_F3: return KEYSYM ("f3"); - case VK_F4: return KEYSYM ("f4"); - case VK_F5: return KEYSYM ("f5"); - case VK_F6: return KEYSYM ("f6"); - case VK_F7: return KEYSYM ("f7"); - case VK_F8: return KEYSYM ("f8"); - case VK_F9: return KEYSYM ("f9"); - case VK_F10: return KEYSYM ("f10"); - case VK_F11: return KEYSYM ("f11"); - case VK_F12: return KEYSYM ("f12"); - case VK_F13: return KEYSYM ("f13"); - case VK_F14: return KEYSYM ("f14"); - case VK_F15: return KEYSYM ("f15"); - case VK_F16: return KEYSYM ("f16"); - case VK_F17: return KEYSYM ("f17"); - case VK_F18: return KEYSYM ("f18"); - case VK_F19: return KEYSYM ("f19"); - case VK_F20: return KEYSYM ("f20"); - case VK_F21: return KEYSYM ("f21"); - case VK_F22: return KEYSYM ("f22"); - case VK_F23: return KEYSYM ("f23"); - case VK_F24: return KEYSYM ("f24"); - } + 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"); + case VK_NUMPAD3: return KEYSYM ("kp-3"); + case VK_NUMPAD4: return KEYSYM ("kp-4"); + case VK_NUMPAD5: return KEYSYM ("kp-5"); + case VK_NUMPAD6: return KEYSYM ("kp-6"); + case VK_NUMPAD7: return KEYSYM ("kp-7"); + case VK_NUMPAD8: return KEYSYM ("kp-8"); + case VK_NUMPAD9: return KEYSYM ("kp-9"); + case VK_MULTIPLY: return KEYSYM ("kp-multiply"); + case VK_ADD: return KEYSYM ("kp-add"); + case VK_SEPARATOR: return KEYSYM ("kp-separator"); + case VK_SUBTRACT: return KEYSYM ("kp-subtract"); + case VK_DECIMAL: return KEYSYM ("kp-decimal"); + case VK_DIVIDE: return KEYSYM ("kp-divide"); + case VK_F1: return KEYSYM ("f1"); + case VK_F2: return KEYSYM ("f2"); + case VK_F3: return KEYSYM ("f3"); + case VK_F4: return KEYSYM ("f4"); + case VK_F5: return KEYSYM ("f5"); + case VK_F6: return KEYSYM ("f6"); + case VK_F7: return KEYSYM ("f7"); + case VK_F8: return KEYSYM ("f8"); + case VK_F9: return KEYSYM ("f9"); + case VK_F10: return KEYSYM ("f10"); + case VK_F11: return KEYSYM ("f11"); + case VK_F12: return KEYSYM ("f12"); + case VK_F13: return KEYSYM ("f13"); + case VK_F14: return KEYSYM ("f14"); + case VK_F15: return KEYSYM ("f15"); + case VK_F16: return KEYSYM ("f16"); + case VK_F17: return KEYSYM ("f17"); + case VK_F18: return KEYSYM ("f18"); + case VK_F19: return KEYSYM ("f19"); + case VK_F20: return KEYSYM ("f20"); + case VK_F21: return KEYSYM ("f21"); + case VK_F22: return KEYSYM ("f22"); + case VK_F23: return KEYSYM ("f23"); + case VK_F24: return KEYSYM ("f24"); + } + } return Qnil; } @@ -2347,7 +2643,7 @@ emacs_mswindows_add_timeout (EMACS_TIME thyme) static void emacs_mswindows_remove_timeout (int id) { - struct Lisp_Event match_against; + Lisp_Event match_against; Lisp_Object emacs_event; if (KillTimer (NULL, id)) @@ -2383,13 +2679,13 @@ emacs_mswindows_event_pending_p (int user_p) * Return the next event */ static void -emacs_mswindows_next_event (struct Lisp_Event *emacs_event) +emacs_mswindows_next_event (Lisp_Event *emacs_event) { Lisp_Object event, event2; 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); @@ -2399,13 +2695,13 @@ emacs_mswindows_next_event (struct Lisp_Event *emacs_event) * Handle a magic event off the dispatch queue. */ static void -emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) +emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event) { switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) { case XM_BUMPQUEUE: break; - + case WM_SETFOCUS: case WM_KILLFOCUS: { @@ -2433,13 +2729,13 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) case XM_UNMAPFRAME: { Lisp_Object frame = EVENT_CHANNEL (emacs_event); - va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) + va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == XM_MAPFRAME ? - Qmap_frame_hook : Qunmap_frame_hook, + Qmap_frame_hook : Qunmap_frame_hook, 1, frame); } break; - + /* #### What about Enter & Leave */ #if 0 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : @@ -2451,8 +2747,9 @@ emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) } } +#ifndef HAVE_MSG_SELECT static HANDLE -get_process_input_waitable (struct Lisp_Process *process) +get_process_input_waitable (Lisp_Process *process) { Lisp_Object instr, outstr, p; XSETPROCESS (p, process); @@ -2468,7 +2765,7 @@ get_process_input_waitable (struct Lisp_Process *process) } static void -emacs_mswindows_select_process (struct Lisp_Process *process) +emacs_mswindows_select_process (Lisp_Process *process) { HANDLE hev = get_process_input_waitable (process); @@ -2493,22 +2790,35 @@ emacs_mswindows_select_process (struct Lisp_Process *process) } static void -emacs_mswindows_unselect_process (struct Lisp_Process *process) +emacs_mswindows_unselect_process (Lisp_Process *process) { /* Process handle is removed in the event loop as soon as it is signaled, so don't bother here about it */ 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 @@ -2519,27 +2829,32 @@ emacs_mswindows_quit_p (void) 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 */ + mswindows_drain_windows_queue (1); if (mswindows_quit_chars_count > 0) { /* Yes there's a hidden one... Throw it away */ - struct Lisp_Event match_against; + Lisp_Event match_against; Lisp_Object emacs_event; + int critical_p = 0; match_against.event_type = key_press_event; match_against.event.key.modifiers = FAKE_MOD_QUIT; - emacs_event = mswindows_cancel_dispatch_event (&match_against); - assert (!NILP (emacs_event)); + 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 & MOD_SHIFT) + critical_p = 1; - Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT - ? Qcritical : Qt); + Fdeallocate_event(emacs_event); + } - Fdeallocate_event(emacs_event); - --mswindows_quit_chars_count; + Vquit_flag = critical_p ? Qcritical : Qt; } } @@ -2651,7 +2966,7 @@ emacs_mswindows_delete_stream_pair (Lisp_Object instream, If we've still got pointers to it in this file, we're gonna lose hard. */ void -debug_process_finalization (struct Lisp_Process *p) +debug_process_finalization (Lisp_Process *p) { #if 0 /* #### */ Lisp_Object instr, outstr; @@ -2669,20 +2984,10 @@ debug_process_finalization (struct Lisp_Process *p) /************************************************************************/ /* initialization */ /************************************************************************/ - + void -vars_of_event_mswindows (void) +reinit_vars_of_event_mswindows (void) { - mswindows_u_dispatch_event_queue = Qnil; - staticpro (&mswindows_u_dispatch_event_queue); - mswindows_u_dispatch_event_queue_tail = Qnil; - - mswindows_s_dispatch_event_queue = Qnil; - staticpro (&mswindows_s_dispatch_event_queue); - mswindows_s_dispatch_event_queue_tail = Qnil; - - mswindows_error_caught_in_modal_loop = Qnil; - staticpro (&mswindows_error_caught_in_modal_loop); mswindows_in_modal_loop = 0; mswindows_pending_timers_count = 0; @@ -2697,10 +3002,10 @@ vars_of_event_mswindows (void) mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; #ifdef HAVE_MSG_SELECT - mswindows_event_stream->select_process_cb = - (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process; - mswindows_event_stream->unselect_process_cb = - (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process; + mswindows_event_stream->select_process_cb = + (void (*)(Lisp_Process*))event_stream_unixoid_select_process; + mswindows_event_stream->unselect_process_cb = + (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process; mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair; mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair; #else @@ -2709,6 +3014,31 @@ 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 +} + +void +vars_of_event_mswindows (void) +{ + reinit_vars_of_event_mswindows (); + + 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); + + 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); + + mswindows_error_caught_in_modal_loop = Qnil; + staticpro (&mswindows_error_caught_in_modal_loop); + + DEFVAR_BOOL ("mswindows-meta-activates-menu", &mswindows_meta_activates_menu /* +*Controls whether pressing and releasing the Meta (Alt) key should +activate the menubar. +Default is t. +*/ ); DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /* *Controls redrawing frame contents during mouse-drag or keyboard resize @@ -2737,7 +3067,7 @@ Number of physical mouse buttons. DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /* *Maximum horizontal distance in pixels between points in which left and -right button clicks occured for them to be translated into single +right button clicks occurred for them to be translated into single middle button event. Clicks must occur in time not longer than defined by the variable `mswindows-mouse-button-tolerance'. If negative or zero, currently set system default is used instead. @@ -2745,7 +3075,7 @@ If negative or zero, currently set system default is used instead. DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /* *Maximum vertical distance in pixels between points in which left and -right button clicks occured for them to be translated into single +right button clicks occurred for them to be translated into single middle button event. Clicks must occur in time not longer than defined by the variable `mswindows-mouse-button-tolerance'. If negative or zero, currently set system default is used instead. @@ -2754,6 +3084,7 @@ If negative or zero, currently set system default is used instead. mswindows_mouse_button_max_skew_x = 0; mswindows_mouse_button_max_skew_y = 0; mswindows_mouse_button_tolerance = 0; + mswindows_meta_activates_menu = 1; } void @@ -2778,9 +3109,7 @@ init_event_mswindows_late (void) windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0); assert (windows_fd>=0); FD_SET (windows_fd, &input_wait_mask); - /* for some reason I get blocks on the signal event pipe, which is - bad... - signal_event_pipe_initialized = 0; */ + FD_ZERO(&zero_mask); #endif event_stream = mswindows_event_stream;