1 /* The mswindows event_stream interface.
2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1996 Ben Wing.
5 Copyright (C) 1997 Jonathan Harris.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
28 Ultimately based on FSF.
29 Rewritten by Ben Wing.
30 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
31 Subprocess and modal loop support by Kirill M. Katsnelson.
37 #include "console-msw.h"
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
44 # include "menubar-msw.h"
48 # include "dragdrop.h"
58 #include "redisplay.h"
63 #include "objects-msw.h"
65 #include "events-mod.h"
66 #ifdef HAVE_MSG_SELECT
68 #elif defined(__CYGWIN32__)
69 typedef unsigned int SOCKET;
75 #define ADJR_MENUFLAG TRUE
77 #define ADJR_MENUFLAG FALSE
80 /* Fake key modifier which is attached to a quit char event.
81 Removed upon dequeueing an event */
82 #define FAKE_MOD_QUIT 0x80
84 /* Timer ID used for button2 emulation */
85 #define BUTTON_2_TIMER_ID 1
88 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
90 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
92 mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
94 static Lisp_Object mswindows_find_frame (HWND hwnd);
95 static Lisp_Object mswindows_find_console (HWND hwnd);
96 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
97 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
98 static void mswindows_set_chord_timer (HWND hwnd);
99 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
100 static int mswindows_current_layout_has_AltGr (void);
102 static struct event_stream *mswindows_event_stream;
104 #ifdef HAVE_MSG_SELECT
105 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
106 extern SELECT_TYPE process_only_mask, tty_only_mask;
107 SELECT_TYPE zero_mask;
108 extern int signal_event_pipe_initialized;
113 * Two separate queues, for efficiency, one (_u_) for user events, and
114 * another (_s_) for non-user ones. We always return events out of the
115 * first one until it is empty and only then proceed with the second
118 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
119 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
121 /* The number of things we can wait on */
122 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
124 /* List of mswindows waitable handles. */
125 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
127 #ifndef HAVE_MSG_SELECT
128 /* Number of wait handles */
129 static int mswindows_waitable_count=0;
130 #endif /* HAVE_MSG_SELECT */
131 /* Brush for painting widgets */
132 static HBRUSH widget_brush = 0;
133 static LONG last_widget_brushed = 0;
135 /* Count of quit chars currently in the queue */
136 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
137 Decremented in mswindows_dequeue_dispatch_event() */
138 int mswindows_quit_chars_count = 0;
140 /* These are Lisp integers; see DEFVARS in this file for description. */
141 int mswindows_dynamic_frame_resize;
142 int mswindows_num_mouse_buttons;
143 int mswindows_mouse_button_max_skew_x;
144 int mswindows_mouse_button_max_skew_y;
145 int mswindows_mouse_button_tolerance;
147 /* This is the event signaled by the event pump.
148 See mswindows_pump_outstanding_events for comments */
149 static Lisp_Object mswindows_error_caught_in_modal_loop;
150 static int mswindows_in_modal_loop;
152 /* Count of wound timers */
153 static int mswindows_pending_timers_count;
155 /************************************************************************/
156 /* Pipe instream - reads process output */
157 /************************************************************************/
159 #define PIPE_READ_DELAY 20
161 #define HANDLE_TO_USID(h) ((USID)(h))
163 #define NTPIPE_SLURP_STREAM_DATA(stream) \
164 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
166 /* This structure is allocated by the main thread, and is deallocated
167 in the thread upon exit. There are situations when a thread
168 remains blocked for a long time, much longer than the lstream
169 exists. For example, "start notepad" command is issued from the
170 shell, then the shell is closed by C-c C-d. Although the shell
171 process exits, its output pipe will not get closed until the
172 notepad process exits also, because it inherits the pipe form the
173 shell. In this case, we abandon the thread, and let it live until
174 all such processes exit. While struct ntpipe_slurp_stream is
175 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
177 struct ntpipe_slurp_stream_shared_data
179 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
180 /* This is a manual-reset object. */
181 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
182 /* This is a manual-reset object. */
183 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
184 /* This is a manual-reset object. */
185 HANDLE hpipe; /* Pipe read end handle. */
186 LONG die_p; /* Thread must exit ASAP if non-zero */
187 BOOL eof_p : 1; /* Set when thread saw EOF */
188 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
189 BOOL inuse_p : 1; /* this structure is in use */
190 LONG lock_count; /* Client count of this struct, 0=safe to free */
191 BYTE onebyte; /* One byte buffer read by thread */
194 #define MAX_SLURP_STREAMS 32
195 struct ntpipe_slurp_stream_shared_data
196 shared_data_block[MAX_SLURP_STREAMS]={{0}};
198 struct ntpipe_slurp_stream
200 LPARAM user_data; /* Any user data stored in the stream object */
201 struct ntpipe_slurp_stream_shared_data* thread_data;
204 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
205 sizeof (struct ntpipe_slurp_stream));
207 /* This function is thread-safe, and is called from either thread
208 context. It serializes freeing shared data structure */
210 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
212 if (InterlockedDecrement (&s->lock_count) == 0)
215 CloseHandle (s->hev_thread);
216 CloseHandle (s->hev_caller);
217 CloseHandle (s->hev_unsleep);
222 static struct ntpipe_slurp_stream_shared_data*
223 slurper_allocate_shared_data()
226 for (i=0; i<MAX_SLURP_STREAMS; i++)
228 if (!shared_data_block[i].inuse_p)
230 shared_data_block[i].inuse_p=1;
231 return &shared_data_block[i];
234 return (struct ntpipe_slurp_stream_shared_data*)0;
238 slurp_thread (LPVOID vparam)
240 struct ntpipe_slurp_stream_shared_data *s =
241 (struct ntpipe_slurp_stream_shared_data*)vparam;
245 /* Read one byte from the pipe */
247 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
249 DWORD err = GetLastError ();
250 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
255 else if (actually_read == 0)
258 /* We must terminate on an error or eof */
259 if (s->eof_p || s->error_p)
260 InterlockedIncrement (&s->die_p);
262 /* Before we notify caller, we unsignal our event. */
263 ResetEvent (s->hev_thread);
265 /* Now we got something to notify caller, either a byte or an
266 error/eof indication. Before we do, allow internal pipe
267 buffer to accumulate little bit more data.
268 Reader function pulses this event before waiting for
269 a character, to avoid pipe delay, and to get the byte
272 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
274 /* Either make event loop generate a process event, or
276 SetEvent (s->hev_caller);
278 /* Cleanup and exit if we're shot off */
282 /* Block until the client finishes with retrieving the rest of
284 WaitForSingleObject (s->hev_thread, INFINITE);
287 slurper_free_shared_data_maybe (s);
293 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
296 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
297 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
298 DWORD thread_id_unused;
301 /* We deal only with pipes, for we're using PeekNamedPipe api */
302 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
304 s->thread_data = slurper_allocate_shared_data();
306 /* Create reader thread. This could fail, so do not create events
307 until thread is created */
308 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
309 CREATE_SUSPENDED, &thread_id_unused);
312 Lstream_delete (lstr);
313 s->thread_data->inuse_p=0;
317 /* Shared data are initially owned by both main and slurper
319 s->thread_data->lock_count = 2;
320 s->thread_data->die_p = 0;
321 s->thread_data->eof_p = FALSE;
322 s->thread_data->error_p = FALSE;
323 s->thread_data->hpipe = hpipe;
324 s->user_data = param;
326 /* hev_thread is a manual-reset event, initially signaled */
327 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
328 /* hev_caller is a manual-reset event, initially nonsignaled */
329 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
330 /* hev_unsleep is a manual-reset event, initially nonsignaled */
331 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
334 ResumeThread (hthread);
335 CloseHandle (hthread);
337 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
338 XSETLSTREAM (obj, lstr);
343 get_ntpipe_input_stream_param (Lstream *stream)
345 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
350 get_ntpipe_input_stream_waitable (Lstream *stream)
352 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
353 return s->thread_data->hev_caller;
357 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
359 /* This function must be called from the main thread only */
360 struct ntpipe_slurp_stream_shared_data* s =
361 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
366 /* Disallow pipe read delay for the thread: we need a character
368 SetEvent (s->hev_unsleep);
370 /* Check if we have a character ready. Give it a short delay,
371 for the thread to awake from pipe delay, just ion case*/
372 wait_result = WaitForSingleObject (s->hev_caller, 2);
374 /* Revert to the normal sleep behavior. */
375 ResetEvent (s->hev_unsleep);
377 /* If there's no byte buffered yet, give up */
378 if (wait_result == WAIT_TIMEOUT)
385 /* Reset caller unlock event now, as we've handled the pending
386 process output event */
387 ResetEvent (s->hev_caller);
389 /* It is now safe to do anything with contents of S, except for
390 changing s->die_p, which still should be interlocked */
394 if (s->error_p || s->die_p)
397 /* Ok, there were no error neither eof - we've got a byte from the
399 *(data++) = s->onebyte;
403 DWORD bytes_read = 0;
406 DWORD bytes_available;
408 /* If the api call fails, return at least one byte already
409 read. ReadFile in thread will return error */
410 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
413 /* Fetch available bytes. The same consideration applies,
414 so do not check for errors. ReadFile in the thread will
415 fail if the next call fails. */
417 ReadFile (s->hpipe, data, min (bytes_available, size),
421 /* Now we can unblock thread, so it attempts to read more */
422 SetEvent (s->hev_thread);
423 return bytes_read + 1;
430 ntpipe_slurp_closer (Lstream *stream)
432 /* This function must be called from the main thread only */
433 struct ntpipe_slurp_stream_shared_data* s =
434 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
436 /* Force thread to stop */
437 InterlockedIncrement (&s->die_p);
439 /* Set events which could possibly block slurper. Let it finish soon
441 SetEvent (s->hev_unsleep);
442 SetEvent (s->hev_thread);
444 /* Unlock and maybe free shared data */
445 slurper_free_shared_data_maybe (s);
451 init_slurp_stream (void)
453 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
454 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
457 /************************************************************************/
458 /* Pipe outstream - writes process input */
459 /************************************************************************/
461 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
462 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
464 #define MAX_SHOVE_BUFFER_SIZE 128
466 struct ntpipe_shove_stream
468 LPARAM user_data; /* Any user data stored in the stream object */
469 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
470 /* This is an auto-reset object. */
471 HANDLE hpipe; /* Pipe write end handle. */
472 HANDLE hthread; /* Reader thread handle. */
473 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
474 DWORD size; /* Number of bytes to write */
475 LONG die_p; /* Thread must exit ASAP if non-zero */
476 LONG idle_p; /* Non-zero if thread is waiting for job */
477 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
478 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
481 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
482 sizeof (struct ntpipe_shove_stream));
484 #ifndef HAVE_MSG_SELECT
486 shove_thread (LPVOID vparam)
488 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
494 /* Block on event and wait for a job */
495 InterlockedIncrement (&s->idle_p);
496 WaitForSingleObject (s->hev_thread, INFINITE);
501 /* Write passed buffer */
502 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
503 || bytes_written != s->size)
506 InterlockedIncrement (&s->die_p);
517 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
520 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
521 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
522 DWORD thread_id_unused;
527 s->user_data = param;
529 /* Create reader thread. This could fail, so do not
530 create the event until thread is created */
531 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
532 CREATE_SUSPENDED, &thread_id_unused);
533 if (s->hthread == NULL)
535 Lstream_delete (lstr);
539 /* hev_thread is an auto-reset event, initially nonsignaled */
540 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
543 ResumeThread (s->hthread);
545 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
546 XSETLSTREAM (obj, lstr);
551 get_ntpipe_output_stream_param (Lstream *stream)
553 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
559 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
561 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
566 s->blocking_p = !s->idle_p;
570 if (size>MAX_SHOVE_BUFFER_SIZE)
573 memcpy (s->buffer, data, size);
577 InterlockedDecrement (&s->idle_p);
578 SetEvent (s->hev_thread);
583 ntpipe_shove_was_blocked_p (Lstream *stream)
585 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
586 return s->blocking_p;
590 ntpipe_shove_closer (Lstream *stream)
592 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
594 /* Force thread stop */
595 InterlockedIncrement (&s->die_p);
597 /* Close pipe handle, possibly breaking it */
598 CloseHandle (s->hpipe);
600 /* Thread will end upon unblocking */
601 SetEvent (s->hev_thread);
603 /* Wait while thread terminates */
604 WaitForSingleObject (s->hthread, INFINITE);
605 CloseHandle (s->hthread);
607 /* Destroy the event */
608 CloseHandle (s->hev_thread);
614 init_shove_stream (void)
616 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
617 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
618 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
621 /************************************************************************/
622 /* Winsock I/O stream */
623 /************************************************************************/
624 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
626 #define WINSOCK_READ_BUFFER_SIZE 1024
628 struct winsock_stream
630 LPARAM user_data; /* Any user data stored in the stream object */
631 SOCKET s; /* Socket handle (which is a Win32 handle) */
632 OVERLAPPED ov; /* Overlapped I/O structure */
633 void* buffer; /* Buffer. Allocated for input stream only */
634 unsigned int bufsize; /* Number of bytes last read */
635 unsigned int bufpos; /* Position in buffer for next fetch */
636 unsigned int error_p :1; /* I/O Error seen */
637 unsigned int eof_p :1; /* EOF Error seen */
638 unsigned int pending_p :1; /* There is a pending I/O operation */
639 unsigned int blocking_p :1; /* Last write attempt would block */
642 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
644 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
645 sizeof (struct winsock_stream));
648 winsock_initiate_read (struct winsock_stream *str)
650 ResetEvent (str->ov.hEvent);
653 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
654 &str->bufsize, &str->ov))
656 if (GetLastError () == ERROR_IO_PENDING)
658 else if (GetLastError () == ERROR_HANDLE_EOF)
663 else if (str->bufsize == 0)
668 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
670 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
672 /* If the current operation is not yet complete, there's nothing to
676 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
683 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
685 if (GetLastError() == ERROR_HANDLE_EOF)
690 if (str->bufsize == 0)
701 /* Return as much of buffer as we have */
702 size = min (size, (size_t) (str->bufsize - str->bufpos));
703 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
706 /* Read more if buffer is exhausted */
707 if (str->bufsize == str->bufpos)
708 winsock_initiate_read (str);
714 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
716 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
720 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
728 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
743 ResetEvent (str->ov.hEvent);
745 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
746 * an overlapped operation. This fails on Win95 with winsock 1.x so we
747 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
748 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
749 || GetLastError() == ERROR_IO_PENDING)
755 return str->error_p ? -1 : size;
759 winsock_closer (Lstream *lstr)
761 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
763 if (lstr->flags & LSTREAM_FL_READ)
764 shutdown (str->s, 0);
766 shutdown (str->s, 1);
768 CloseHandle ((HANDLE)str->s);
770 WaitForSingleObject (str->ov.hEvent, INFINITE);
772 if (lstr->flags & LSTREAM_FL_READ)
775 CloseHandle (str->ov.hEvent);
780 winsock_was_blocked_p (Lstream *stream)
782 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
783 return str->blocking_p;
787 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
790 Lstream *lstr = Lstream_new (lstream_winsock, mode);
791 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
798 str->user_data = param;
801 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
803 if (lstr->flags & LSTREAM_FL_READ)
805 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
806 winsock_initiate_read (str);
809 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
810 XSETLSTREAM (obj, lstr);
815 make_winsock_input_stream (SOCKET s, LPARAM param)
817 return make_winsock_stream_1 (s, param, "r");
821 make_winsock_output_stream (SOCKET s, LPARAM param)
823 return make_winsock_stream_1 (s, param, "w");
827 get_winsock_stream_waitable (Lstream *lstr)
829 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
830 return str->ov.hEvent;
834 get_winsock_stream_param (Lstream *lstr)
836 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
837 return str->user_data;
841 init_winsock_stream (void)
843 LSTREAM_HAS_METHOD (winsock, reader);
844 LSTREAM_HAS_METHOD (winsock, writer);
845 LSTREAM_HAS_METHOD (winsock, closer);
846 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
848 #endif /* defined (HAVE_SOCKETS) */
850 /************************************************************************/
851 /* Dispatch queue management */
852 /************************************************************************/
855 mswindows_user_event_p (struct Lisp_Event* sevt)
857 return (sevt->event_type == key_press_event
858 || sevt->event_type == button_press_event
859 || sevt->event_type == button_release_event
860 || sevt->event_type == misc_user_event);
864 * Add an emacs event to the proper dispatch queue
867 mswindows_enqueue_dispatch_event (Lisp_Object event)
869 int user_p = mswindows_user_event_p (XEVENT(event));
870 enqueue_event (event,
871 user_p ? &mswindows_u_dispatch_event_queue :
872 &mswindows_s_dispatch_event_queue,
873 user_p ? &mswindows_u_dispatch_event_queue_tail :
874 &mswindows_s_dispatch_event_queue_tail);
876 /* Avoid blocking on WaitMessage */
877 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
881 * Add a misc-user event to the dispatch queue.
883 * Stuff it into our own dispatch queue, so we have something
884 * to return from next_event callback.
887 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
890 Lisp_Object event = Fmake_event (Qnil, Qnil);
891 struct Lisp_Event* e = XEVENT (event);
893 e->event_type = misc_user_event;
894 e->channel = channel;
895 e->event.misc.function = function;
896 e->event.misc.object = object;
898 mswindows_enqueue_dispatch_event (event);
902 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
904 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
905 struct Lisp_Event* event = XEVENT (emacs_event);
907 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
908 event->timestamp = GetMessageTime();
909 event->event_type = magic_event;
910 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
912 mswindows_enqueue_dispatch_event (emacs_event);
916 mswindows_enqueue_process_event (struct Lisp_Process* p)
918 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
919 struct Lisp_Event* event = XEVENT (emacs_event);
921 XSETPROCESS (process, p);
923 event->event_type = process_event;
924 event->timestamp = GetTickCount ();
925 event->event.process.process = process;
927 mswindows_enqueue_dispatch_event (emacs_event);
931 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
934 /* We always use last message time, because mouse button
935 events may get delayed, and XEmacs double click
936 recognition will fail */
938 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
939 struct Lisp_Event* event = XEVENT(emacs_event);
941 event->channel = mswindows_find_frame(hwnd);
942 event->timestamp = when;
943 event->event.button.button =
944 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
945 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
946 event->event.button.x = where.x;
947 event->event.button.y = where.y;
948 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
950 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
951 message==WM_RBUTTONDOWN)
953 event->event_type = button_press_event;
955 /* we need this to make sure the main window regains the focus
956 from control subwindows */
957 if (GetFocus() != hwnd)
960 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
965 event->event_type = button_release_event;
969 mswindows_enqueue_dispatch_event (emacs_event);
973 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
975 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
976 struct Lisp_Event* event = XEVENT(emacs_event);
978 event->channel = mswindows_find_console(hwnd);
979 event->timestamp = GetMessageTime();
980 event->event_type = key_press_event;
981 event->event.key.keysym = keysym;
982 event->event.key.modifiers = mods;
983 mswindows_enqueue_dispatch_event (emacs_event);
987 * Remove and return the first emacs event on the dispatch queue.
988 * Give a preference to user events over non-user ones.
991 mswindows_dequeue_dispatch_event ()
994 struct Lisp_Event* sevt;
996 assert (!NILP(mswindows_u_dispatch_event_queue) ||
997 !NILP(mswindows_s_dispatch_event_queue));
999 event = dequeue_event (
1000 NILP(mswindows_u_dispatch_event_queue) ?
1001 &mswindows_s_dispatch_event_queue :
1002 &mswindows_u_dispatch_event_queue,
1003 NILP(mswindows_u_dispatch_event_queue) ?
1004 &mswindows_s_dispatch_event_queue_tail :
1005 &mswindows_u_dispatch_event_queue_tail);
1007 sevt = XEVENT(event);
1008 if (sevt->event_type == key_press_event
1009 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1011 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1012 --mswindows_quit_chars_count;
1019 * Remove and return the first emacs event on the dispatch queue that matches
1020 * the supplied event.
1021 * Timeout event matches if interval_id is equal to that of the given event.
1022 * Keypress event matches if logical AND between modifiers bitmask of the
1023 * event in the queue and that of the given event is non-zero.
1024 * For all other event types, this function aborts.
1028 mswindows_cancel_dispatch_event (struct Lisp_Event *match)
1031 Lisp_Object previous_event = Qnil;
1032 int user_p = mswindows_user_event_p (match);
1033 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1034 &mswindows_s_dispatch_event_queue;
1035 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1036 &mswindows_s_dispatch_event_queue_tail;
1038 assert (match->event_type == timeout_event
1039 || match->event_type == key_press_event);
1041 EVENT_CHAIN_LOOP (event, *head)
1043 struct Lisp_Event *e = XEVENT (event);
1044 if ((e->event_type == match->event_type) &&
1045 ((e->event_type == timeout_event) ?
1046 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1047 /* Must be key_press_event */
1048 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1050 if (NILP (previous_event))
1051 dequeue_event (head, tail);
1054 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1055 if (EQ (*tail, event))
1056 *tail = previous_event;
1061 previous_event = event;
1066 #ifndef HAVE_MSG_SELECT
1067 /************************************************************************/
1068 /* Waitable handles manipulation */
1069 /************************************************************************/
1071 find_waitable_handle (HANDLE h)
1074 for (i = 0; i < mswindows_waitable_count; ++i)
1075 if (mswindows_waitable_handles[i] == h)
1082 add_waitable_handle (HANDLE h)
1084 assert (find_waitable_handle (h) < 0);
1085 if (mswindows_waitable_count == MAX_WAITABLE)
1088 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1093 remove_waitable_handle (HANDLE h)
1095 int ix = find_waitable_handle (h);
1099 mswindows_waitable_handles [ix] =
1100 mswindows_waitable_handles [--mswindows_waitable_count];
1102 #endif /* HAVE_MSG_SELECT */
1105 /************************************************************************/
1107 /************************************************************************/
1110 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1111 Lisp_Object u_n_u_s_e_d)
1113 mswindows_error_caught_in_modal_loop = cons_sig_data;
1118 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1123 ++mswindows_in_modal_loop;
1124 tmp = condition_case_1 (Qt,
1126 mswindows_modal_loop_error_handler, Qnil);
1127 --mswindows_in_modal_loop;
1133 mswindows_unmodalize_signal_maybe (void)
1135 if (!NILP (mswindows_error_caught_in_modal_loop))
1137 /* Got an error while messages were pumped while
1138 in window procedure - have to resignal */
1139 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1140 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1141 mswindows_error_caught_in_modal_loop = Qnil;
1142 Fsignal (sym, data);
1147 * This is an unsafe part of event pump, guarded by
1148 * condition_case. See mswindows_pump_outstanding_events
1151 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1153 /* This function can call lisp */
1154 Lisp_Object event = Fmake_event (Qnil, Qnil);
1155 struct gcpro gcpro1;
1156 int do_redisplay = 0;
1159 while (detect_input_pending ())
1161 Fnext_event (event, Qnil);
1162 Fdispatch_event (event);
1169 Fdeallocate_event (event);
1172 /* Qt becomes return value of mswindows_pump_outstanding_events
1178 * This function pumps emacs events, while available, by using
1179 * next_message/dispatch_message loop. Errors are trapped around
1180 * the loop so the function always returns.
1182 * Windows message queue is not looked into during the call,
1183 * neither are waitable handles checked. The function pumps
1184 * thus only dispatch events already queued, as well as those
1185 * resulted in dispatching thereof. This is done by setting
1186 * module local variable mswindows_in_modal_loop to nonzero.
1188 * Return value is Qt if no errors was trapped, or Qunbound if
1189 * there was an error.
1191 * In case of error, a cons representing the error, in the
1192 * form (SIGNAL . DATA), is stored in the module local variable
1193 * mswindows_error_caught_in_modal_loop. This error is signaled
1194 * again when DispatchMessage returns. Thus, Windows internal
1195 * modal loops are protected against throws, which are proven
1196 * to corrupt internal Windows structures.
1198 * In case of success, mswindows_error_caught_in_modal_loop is
1201 * If the value of mswindows_error_caught_in_modal_loop is not
1202 * nil already upon entry, the function just returns non-nil.
1203 * This situation means that a new event has been queued while
1204 * in cancel mode. The event will be dequeued on the next regular
1205 * call of next-event; the pump is off since error is caught.
1206 * The caller must *unconditionally* cancel modal loop if the
1207 * value returned by this function is nil. Otherwise, everything
1208 * will become frozen until the modal loop exits under normal
1209 * condition (scrollbar drag is released, menu closed etc.)
1212 mswindows_pump_outstanding_events (void)
1214 /* This function can call lisp */
1216 Lisp_Object result = Qt;
1217 struct gcpro gcpro1;
1220 if (NILP(mswindows_error_caught_in_modal_loop))
1221 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1227 mswindows_drain_windows_queue ()
1230 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1232 /* we have to translate messages that are not sent to the main
1233 window. this is so that key presses work ok in things like
1234 edit fields. however, we *musn't* translate message for the
1235 main window as this is handled in the wnd proc. */
1236 if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
1238 TranslateMessage (&msg);
1240 DispatchMessage (&msg);
1241 mswindows_unmodalize_signal_maybe ();
1246 * This is a special flavor of the mswindows_need_event function,
1247 * used while in event pump. Actually, there is only kind of events
1248 * allowed while in event pump: a timer. An attempt to fetch any
1249 * other event leads to a deadlock, as there's no source of user input
1250 * ('cause event pump mirrors windows modal loop, which is a sole
1251 * owner of thread message queue).
1253 * To detect this, we use a counter of active timers, and allow
1254 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1255 * which will never come when there are no pending timers, which leads
1256 * to deadlock, we simply signal an error.
1259 mswindows_need_event_in_modal_loop (int badly_p)
1263 /* Check if already have one */
1264 if (!NILP (mswindows_u_dispatch_event_queue)
1265 || !NILP (mswindows_s_dispatch_event_queue))
1268 /* No event is ok */
1272 /* We do not check the _u_ queue, because timers go to _s_ */
1273 while (NILP (mswindows_s_dispatch_event_queue))
1275 /* We'll deadlock if go waiting */
1276 if (mswindows_pending_timers_count == 0)
1277 error ("Deadlock due to an attempt to call next-event in a wrong context");
1279 /* Fetch and dispatch any pending timers */
1280 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1281 DispatchMessage (&msg);
1286 * This drains the event queue and fills up two internal queues until
1287 * an event of a type specified by USER_P is retrieved.
1290 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1293 mswindows_need_event (int badly_p)
1297 if (mswindows_in_modal_loop)
1299 mswindows_need_event_in_modal_loop (badly_p);
1303 /* Have to drain Windows message queue first, otherwise, we may miss
1304 quit char when called from quit_p */
1305 mswindows_drain_windows_queue ();
1307 while (NILP (mswindows_u_dispatch_event_queue)
1308 && NILP (mswindows_s_dispatch_event_queue))
1310 #ifdef HAVE_MSG_SELECT
1312 SELECT_TYPE temp_mask = input_wait_mask;
1313 EMACS_TIME sometime;
1314 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1317 pointer_to_this = 0;
1320 EMACS_SET_SECS_USECS (sometime, 0, 0);
1321 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1322 pointer_to_this = &select_time_to_block;
1325 /* select() is slow and buggy so if we don't have any processes
1326 just wait as normal */
1327 if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0)
1329 /* Now try getting a message or process event */
1330 active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles,
1331 FALSE, badly_p ? INFINITE : 0,
1334 if (active == WAIT_TIMEOUT)
1336 /* No luck trying - just return what we've already got */
1339 else if (active == WAIT_OBJECT_0)
1341 /* Got your message, thanks */
1342 mswindows_drain_windows_queue ();
1347 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1351 return; /* timeout */
1353 else if (active > 0)
1355 if (FD_ISSET (windows_fd, &temp_mask))
1357 mswindows_drain_windows_queue ();
1360 /* Look for a process event */
1361 for (i = 0; i < MAXDESC-1; i++)
1363 if (FD_ISSET (i, &temp_mask))
1365 if (FD_ISSET (i, &process_only_mask))
1367 struct Lisp_Process *p =
1368 get_process_from_usid (FD_TO_USID(i));
1370 mswindows_enqueue_process_event (p);
1372 else if (FD_ISSET (i, &tty_only_mask))
1374 /* do we care about tty events? Do we
1375 ever get tty events? */
1379 /* We might get here when a fake event came
1380 through a signal. Return a dummy event, so
1381 that a cycle of the command loop will
1383 drain_signal_event_pipe ();
1384 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1389 else if (active==-1)
1393 /* something bad happened */
1402 /* Now try getting a message or process event */
1403 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1404 mswindows_waitable_handles,
1405 FALSE, badly_p ? INFINITE : 0,
1408 /* This will assert if handle being waited for becomes abandoned.
1409 Not the case currently tho */
1410 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1411 (active >= WAIT_OBJECT_0 &&
1412 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1414 if (active == WAIT_TIMEOUT)
1416 /* No luck trying - just return what we've already got */
1419 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1421 /* Got your message, thanks */
1422 mswindows_drain_windows_queue ();
1426 int ix = active - WAIT_OBJECT_0;
1427 /* First, try to find which process' output has signaled */
1428 struct Lisp_Process *p =
1429 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1432 /* Found a signaled process input handle */
1433 mswindows_enqueue_process_event (p);
1437 /* None. This means that the process handle itself has signaled.
1438 Remove the handle from the wait vector, and make status_notify
1439 note the exited process */
1440 mswindows_waitable_handles [ix] =
1441 mswindows_waitable_handles [--mswindows_waitable_count];
1442 kick_status_notify ();
1443 /* Have to return something: there may be no accompanying
1445 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1452 /************************************************************************/
1453 /* Event generators */
1454 /************************************************************************/
1457 * Callback procedure for synchronous timer messages
1459 static void CALLBACK
1460 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1462 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1463 struct Lisp_Event *event = XEVENT (emacs_event);
1465 if (KillTimer (NULL, id_timer))
1466 --mswindows_pending_timers_count;
1468 event->channel = Qnil;
1469 event->timestamp = dwtime;
1470 event->event_type = timeout_event;
1471 event->event.timeout.interval_id = id_timer;
1472 event->event.timeout.function = Qnil;
1473 event->event.timeout.object = Qnil;
1475 mswindows_enqueue_dispatch_event (emacs_event);
1479 * Callback procedure for dde messages
1481 * We execute a dde Open("file") by simulating a file drop, so dde support
1482 * depends on dnd support.
1484 #ifdef HAVE_DRAGNDROP
1486 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1487 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1488 DWORD dwData1, DWORD dwData2)
1493 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1494 return (HDDEDATA)TRUE;
1495 return (HDDEDATA)FALSE;
1497 case XTYP_WILDCONNECT:
1499 /* We only support one {service,topic} pair */
1500 HSZPAIR pairs[2] = {
1501 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1503 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1504 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1505 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1506 sizeof (pairs), 0L, 0, uFmt, 0));
1508 return (HDDEDATA)NULL;
1511 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1513 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1514 char *cmd = alloca (len+1);
1517 struct gcpro gcpro1, gcpro2;
1518 Lisp_Object l_dndlist = Qnil;
1519 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1520 Lisp_Object frmcons, devcons, concons;
1521 struct Lisp_Event *event = XEVENT (emacs_event);
1523 DdeGetData (hdata, cmd, len, 0);
1525 DdeFreeDataHandle (hdata);
1527 /* Check syntax & that it's an [Open("foo")] command, which we
1528 * treat like a file drop */
1529 /* #### Ought to be generalised and accept some other commands */
1532 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1533 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1534 return DDE_FNOTPROCESSED;
1535 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1538 if (*cmd!='(' || *(cmd+1)!='\"')
1539 return DDE_FNOTPROCESSED;
1541 while (*end && *end!='\"')
1544 return DDE_FNOTPROCESSED;
1547 return DDE_FNOTPROCESSED;
1551 return DDE_FNOTPROCESSED;
1554 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1555 strcpy (filename, "file:");
1556 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1558 dostounix_filename (cmd);
1559 filename = alloca (strlen (cmd)+6);
1560 strcpy (filename, "file:");
1561 strcat (filename, cmd);
1563 GCPRO2 (emacs_event, l_dndlist);
1564 l_dndlist = make_string (filename, strlen (filename));
1566 /* Find a mswindows frame */
1567 event->channel = Qnil;
1568 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1570 Lisp_Object frame = XCAR (frmcons);
1571 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1572 event->channel = frame;
1574 assert (!NILP (event->channel));
1576 event->timestamp = GetTickCount();
1577 event->event_type = misc_user_event;
1578 event->event.misc.button = 1;
1579 event->event.misc.modifiers = 0;
1580 event->event.misc.x = -1;
1581 event->event.misc.y = -1;
1582 event->event.misc.function = Qdragdrop_drop_dispatch;
1583 event->event.misc.object = Fcons (Qdragdrop_URL,
1584 Fcons (l_dndlist, Qnil));
1585 mswindows_enqueue_dispatch_event (emacs_event);
1587 return (HDDEDATA) DDE_FACK;
1589 DdeFreeDataHandle (hdata);
1590 return (HDDEDATA) DDE_FNOTPROCESSED;
1593 return (HDDEDATA) NULL;
1599 * The windows procedure for the window class XEMACS_CLASS
1602 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1604 /* Note: Remember to initialize emacs_event and event before use.
1605 This code calls code that can GC. You must GCPRO before calling such code. */
1606 Lisp_Object emacs_event = Qnil;
1607 Lisp_Object fobj = Qnil;
1609 struct Lisp_Event *event;
1610 struct frame *frame;
1611 struct mswindows_frame* msframe;
1616 /* Erase background only during non-dynamic sizing */
1617 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1618 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1623 fobj = mswindows_find_frame (hwnd);
1624 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1629 /* See Win95 comment under WM_KEYDOWN */
1633 if (wParam == VK_CONTROL)
1635 GetKeyboardState (keymap);
1636 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1637 SetKeyboardState (keymap);
1639 else if (wParam == VK_MENU)
1641 GetKeyboardState (keymap);
1642 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1643 SetKeyboardState (keymap);
1650 /* In some locales the right-hand Alt key is labelled AltGr. This key
1651 * should produce alternative charcaters when combined with another key.
1652 * eg on a German keyboard pressing AltGr+q should produce '@'.
1653 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1654 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1655 * it translates as if AltGr were down.
1656 * We get round this by removing all modifiers from the keymap before
1657 * calling TranslateMessage() unless AltGr is *really* down. */
1660 int has_AltGr = mswindows_current_layout_has_AltGr ();
1664 GetKeyboardState (keymap);
1665 mods = mswindows_modifier_state (keymap, has_AltGr);
1667 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1668 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1669 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1672 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1673 BYTE keymap_orig[256];
1674 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1675 MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), pnt };
1677 /* GetKeyboardState() does not work as documented on Win95. We have
1678 * to loosely track Left and Right modifiers on behalf of the OS,
1679 * without screwing up Windows NT which tracks them properly. */
1680 if (wParam == VK_CONTROL)
1681 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1682 else if (wParam == VK_MENU)
1683 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1685 memcpy (keymap_orig, keymap, 256);
1687 /* Remove shift modifier from an ascii character */
1690 /* Clear control and alt modifiers unless AltGr is pressed */
1691 keymap [VK_RCONTROL] = 0;
1692 keymap [VK_LMENU] = 0;
1693 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1695 keymap [VK_LCONTROL] = 0;
1696 keymap [VK_CONTROL] = 0;
1697 keymap [VK_RMENU] = 0;
1698 keymap [VK_MENU] = 0;
1700 SetKeyboardState (keymap);
1702 /* Maybe generate some WM_[SYS]CHARs in the queue */
1703 TranslateMessage (&msg);
1705 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1706 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1709 WPARAM ch = msg.wParam;
1711 /* If a quit char with no modifiers other than control and
1712 shift, then mark it with a fake modifier, which is removed
1713 upon dequeueing the event */
1714 /* #### This might also not withstand localization, if
1715 quit character is not a latin-1 symbol */
1716 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1717 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1718 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1720 mods1 |= FAKE_MOD_QUIT;
1721 ++mswindows_quit_chars_count;
1724 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1726 SetKeyboardState (keymap_orig);
1729 /* F10 causes menu activation by default. We do not want this */
1730 if (wParam != VK_F10)
1734 case WM_MBUTTONDOWN:
1736 /* Real middle mouse button has nothing to do with emulated one:
1737 if one wants to exercise fingers playing chords on the mouse,
1738 he is allowed to do that! */
1739 mswindows_enqueue_mouse_button_event (hwnd, message,
1740 MAKEPOINTS (lParam), GetMessageTime());
1744 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1745 msframe->last_click_time = GetMessageTime();
1747 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1748 msframe->button2_need_lbutton = 0;
1749 if (msframe->ignore_next_lbutton_up)
1751 msframe->ignore_next_lbutton_up = 0;
1753 else if (msframe->button2_is_down)
1755 msframe->button2_is_down = 0;
1756 msframe->ignore_next_rbutton_up = 1;
1757 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1758 MAKEPOINTS (lParam), GetMessageTime());
1762 if (msframe->button2_need_rbutton)
1764 msframe->button2_need_rbutton = 0;
1765 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1766 MAKEPOINTS (lParam), GetMessageTime());
1768 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1769 MAKEPOINTS (lParam), GetMessageTime());
1774 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1775 msframe->last_click_time = GetMessageTime();
1777 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1778 msframe->button2_need_rbutton = 0;
1779 if (msframe->ignore_next_rbutton_up)
1781 msframe->ignore_next_rbutton_up = 0;
1783 else if (msframe->button2_is_down)
1785 msframe->button2_is_down = 0;
1786 msframe->ignore_next_lbutton_up = 1;
1787 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1788 MAKEPOINTS (lParam), GetMessageTime());
1792 if (msframe->button2_need_lbutton)
1794 msframe->button2_need_lbutton = 0;
1795 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1796 MAKEPOINTS (lParam), GetMessageTime());
1798 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1799 MAKEPOINTS (lParam), GetMessageTime());
1803 case WM_LBUTTONDOWN:
1804 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1806 if (msframe->button2_need_lbutton)
1808 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1809 msframe->button2_need_lbutton = 0;
1810 msframe->button2_need_rbutton = 0;
1811 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1813 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1814 MAKEPOINTS (lParam), GetMessageTime());
1815 msframe->button2_is_down = 1;
1819 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1820 msframe->last_click_point, msframe->last_click_time);
1821 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1822 MAKEPOINTS (lParam), GetMessageTime());
1827 mswindows_set_chord_timer (hwnd);
1828 msframe->button2_need_rbutton = 1;
1829 msframe->last_click_point = MAKEPOINTS (lParam);
1831 msframe->last_click_time = GetMessageTime();
1834 case WM_RBUTTONDOWN:
1835 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1837 if (msframe->button2_need_rbutton)
1839 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1840 msframe->button2_need_lbutton = 0;
1841 msframe->button2_need_rbutton = 0;
1842 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1844 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1845 MAKEPOINTS (lParam), GetMessageTime());
1846 msframe->button2_is_down = 1;
1850 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1851 msframe->last_click_point, msframe->last_click_time);
1852 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1853 MAKEPOINTS (lParam), GetMessageTime());
1858 mswindows_set_chord_timer (hwnd);
1859 msframe->button2_need_lbutton = 1;
1860 msframe->last_click_point = MAKEPOINTS (lParam);
1862 msframe->last_click_time = GetMessageTime();
1866 if (wParam == BUTTON_2_TIMER_ID)
1868 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1869 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1871 if (msframe->button2_need_lbutton)
1873 msframe->button2_need_lbutton = 0;
1874 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1875 msframe->last_click_point, msframe->last_click_time);
1877 else if (msframe->button2_need_rbutton)
1879 msframe->button2_need_rbutton = 0;
1880 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1881 msframe->last_click_point, msframe->last_click_time);
1885 assert ("Spurious timer fired" == 0);
1889 /* Optimization: don't report mouse movement while size is changing */
1890 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1891 if (!msframe->sizing)
1893 /* When waiting for the second mouse button to finish
1894 button2 emulation, and have moved too far, just pretend
1895 as if timer has expired. This improves drag-select feedback */
1896 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1897 && !mswindows_button2_near_enough (msframe->last_click_point,
1898 MAKEPOINTS (lParam)))
1900 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1901 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1904 emacs_event = Fmake_event (Qnil, Qnil);
1905 event = XEVENT(emacs_event);
1907 event->channel = mswindows_find_frame(hwnd);
1908 event->timestamp = GetMessageTime();
1909 event->event_type = pointer_motion_event;
1910 event->event.motion.x = MAKEPOINTS(lParam).x;
1911 event->event.motion.y = MAKEPOINTS(lParam).y;
1912 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1914 mswindows_enqueue_dispatch_event (emacs_event);
1920 /* Queue a `cancel-mode-internal' misc user event, so mouse
1921 selection would be canceled if any */
1922 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1923 Qcancel_mode_internal, Qnil);
1926 #ifdef HAVE_TOOLBARS
1929 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1931 if (tttext->hdr.code == TTN_NEEDTEXT)
1933 /* find out which toolbar */
1934 frame = XFRAME (mswindows_find_frame (hwnd));
1935 btext = mswindows_get_toolbar_button_text ( frame,
1936 tttext->hdr.idFrom );
1938 tttext->lpszText = NULL;
1939 tttext->hinst = NULL;
1943 /* I think this is safe since the text will only go away
1944 when the toolbar does...*/
1945 GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS,
1949 tttext->uFlags |= TTF_DI_SETITEM;
1958 PAINTSTRUCT paintStruct;
1960 frame = XFRAME (mswindows_find_frame (hwnd));
1962 BeginPaint (hwnd, &paintStruct);
1963 mswindows_redraw_exposed_area (frame,
1964 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1965 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1966 EndPaint (hwnd, &paintStruct);
1971 /* We only care about this message if our size has really changed */
1972 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1977 fobj = mswindows_find_frame (hwnd);
1978 frame = XFRAME (fobj);
1979 msframe = FRAME_MSWINDOWS_DATA (frame);
1981 /* We cannot handle frame map and unmap hooks right in
1982 this routine, because these may throw. We queue
1983 magic events to run these hooks instead - kkm */
1985 if (wParam==SIZE_MINIMIZED)
1988 FRAME_VISIBLE_P (frame) = 0;
1989 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
1993 GetClientRect(hwnd, &rect);
1994 FRAME_PIXWIDTH(frame) = rect.right;
1995 FRAME_PIXHEIGHT(frame) = rect.bottom;
1997 pixel_to_real_char_size (frame, rect.right, rect.bottom,
1998 &FRAME_MSWINDOWS_CHARWIDTH (frame),
1999 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2001 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2002 change_frame_size (frame, rows, columns, 1);
2004 /* If we are inside frame creation, we have to apply geometric
2006 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2008 /* Yes, we have to size again */
2009 mswindows_size_frame_internal ( frame,
2010 FRAME_MSWINDOWS_TARGET_RECT
2012 /* Reset so we do not get here again. The SetWindowPos call in
2013 * mswindows_size_frame_internal can cause recursion here. */
2014 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2016 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2017 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2022 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2023 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2024 FRAME_VISIBLE_P (frame) = 1;
2026 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2033 /* Misc magic events which only require that the frame be identified */
2036 mswindows_enqueue_magic_event (hwnd, message);
2039 case WM_WINDOWPOSCHANGING:
2041 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2042 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2043 GetWindowPlacement(hwnd, &wpl);
2045 /* Only interested if size is changing and we're not being iconified */
2046 if (wpl.showCmd != SW_SHOWMINIMIZED
2047 && wpl.showCmd != SW_SHOWMAXIMIZED
2048 && !(wp->flags & SWP_NOSIZE))
2050 RECT ncsize = { 0, 0, 0, 0 };
2051 int pixwidth, pixheight;
2052 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2053 GetMenu(hwnd) != NULL,
2054 GetWindowLong (hwnd, GWL_EXSTYLE));
2056 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2057 wp->cx - (ncsize.right - ncsize.left),
2058 wp->cy - (ncsize.bottom - ncsize.top),
2059 &pixwidth, &pixheight);
2061 /* Convert client sizes to window sizes */
2062 pixwidth += (ncsize.right - ncsize.left);
2063 pixheight += (ncsize.bottom - ncsize.top);
2065 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2067 /* Adjust so that the bottom or right doesn't move if it's
2068 * the top or left that's being changed */
2070 GetWindowRect (hwnd, &rect);
2072 if (rect.left != wp->x)
2073 wp->x += wp->cx - pixwidth;
2074 if (rect.top != wp->y)
2075 wp->y += wp->cy - pixheight;
2081 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2082 window position if the user tries to track window too small */
2086 case WM_ENTERSIZEMOVE:
2087 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2088 msframe->sizing = 1;
2091 case WM_EXITSIZEMOVE:
2092 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2093 msframe->sizing = 0;
2094 /* Queue noop event */
2095 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2098 #ifdef HAVE_SCROLLBARS
2102 /* Direction of scroll is determined by scrollbar instance. */
2103 int code = (int) LOWORD(wParam);
2104 int pos = (short int) HIWORD(wParam);
2105 HWND hwndScrollBar = (HWND) lParam;
2106 struct gcpro gcpro1, gcpro2;
2108 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2109 GCPRO2 (emacs_event, fobj);
2110 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2112 /* Error during event pumping - cancel scroll */
2113 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2120 #ifdef HAVE_MENUBARS
2122 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2124 XFRAME (mswindows_find_frame (hwnd)))))
2125 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2128 case WM_INITMENUPOPUP:
2129 if (!HIWORD(lParam))
2131 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2133 XFRAME (mswindows_find_frame (hwnd)))))
2134 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2138 #endif /* HAVE_MENUBARS */
2142 WORD id = LOWORD (wParam);
2143 WORD nid = HIWORD (wParam);
2144 HWND cid = (HWND)lParam;
2145 frame = XFRAME (mswindows_find_frame (hwnd));
2147 #ifdef HAVE_TOOLBARS
2148 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2151 /* widgets in a buffer only eval a callback for suitable events.*/
2156 case CBN_EDITCHANGE:
2158 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2160 default: /* do nothing */
2162 /* menubars always must come last since the hashtables do not
2164 #ifdef HAVE_MENUBARS
2165 if (!NILP (mswindows_handle_wm_command (frame, id)))
2169 return DefWindowProc (hwnd, message, wParam, lParam);
2170 /* Bite me - a spurious command. This used to not be able to
2171 happen but with the introduction of widgets its now
2176 case WM_CTLCOLORBTN:
2177 case WM_CTLCOLORLISTBOX:
2178 case WM_CTLCOLOREDIT:
2179 case WM_CTLCOLORSTATIC:
2180 case WM_CTLCOLORSCROLLBAR:
2182 /* if we get an opportunity to paint a widget then do so if
2183 there is an appropriate face */
2184 HWND crtlwnd = (HWND)lParam;
2185 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2188 Lisp_Object image_instance;
2189 VOID_TO_LISP (image_instance, ii);
2190 if (IMAGE_INSTANCEP (image_instance)
2192 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
2194 !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
2196 /* set colors for the buttons */
2197 HDC hdc = (HDC)wParam;
2198 if (last_widget_brushed != ii)
2201 DeleteObject (widget_brush);
2202 widget_brush = CreateSolidBrush
2203 (COLOR_INSTANCE_MSWINDOWS_COLOR
2206 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2207 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2209 last_widget_brushed = ii;
2212 COLOR_INSTANCE_MSWINDOWS_COLOR
2215 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2216 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2217 SetBkMode (hdc, OPAQUE);
2220 COLOR_INSTANCE_MSWINDOWS_COLOR
2223 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2224 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2225 return (LRESULT)widget_brush;
2231 #ifdef HAVE_DRAGNDROP
2232 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2234 UINT filecount, i, len;
2240 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2241 struct gcpro gcpro1, gcpro2, gcpro3;
2243 emacs_event = Fmake_event (Qnil, Qnil);
2244 event = XEVENT(emacs_event);
2246 GCPRO3 (emacs_event, l_dndlist, l_item);
2248 if (!DragQueryPoint ((HANDLE) wParam, &point))
2249 point.x = point.y = -1; /* outside client area */
2251 event->event_type = misc_user_event;
2252 event->channel = mswindows_find_frame(hwnd);
2253 event->timestamp = GetMessageTime();
2254 event->event.misc.button = 1; /* #### Should try harder */
2255 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2256 event->event.misc.x = point.x;
2257 event->event.misc.y = point.y;
2258 event->event.misc.function = Qdragdrop_drop_dispatch;
2260 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2261 for (i=0; i<filecount; i++)
2263 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2264 /* The URLs that we make here aren't correct according to section
2265 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2266 * because they may contain reserved characters. But that's OK. */
2268 fname = (char *)xmalloc (len+1);
2269 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2270 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2271 strcpy (filename, "file:");
2272 cygwin32_win32_to_posix_path_list (fname, filename+5);
2275 filename = (char *)xmalloc (len+6);
2276 strcpy (filename, "file:");
2277 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2278 dostounix_filename (filename+5);
2280 l_item = make_string (filename, strlen (filename));
2281 l_dndlist = Fcons (l_item, l_dndlist);
2284 DragFinish ((HANDLE) wParam);
2286 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2287 mswindows_enqueue_dispatch_event (emacs_event);
2295 return DefWindowProc (hwnd, message, wParam, lParam);
2301 /************************************************************************/
2302 /* keyboard, mouse & other helpers for the windows procedure */
2303 /************************************************************************/
2305 mswindows_set_chord_timer (HWND hwnd)
2309 /* We get one third half system double click threshold */
2310 if (mswindows_mouse_button_tolerance <= 0)
2311 interval = GetDoubleClickTime () / 3;
2313 interval = mswindows_mouse_button_tolerance;
2315 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2319 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2322 if (mswindows_mouse_button_max_skew_x <= 0)
2323 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2325 dx = mswindows_mouse_button_max_skew_x;
2327 if (mswindows_mouse_button_max_skew_y <= 0)
2328 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2330 dy = mswindows_mouse_button_max_skew_y;
2332 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2336 mswindows_current_layout_has_AltGr (void)
2338 /* This simple caching mechanism saves 10% of CPU
2339 time when a key typed at autorepeat rate of 30 cps! */
2340 static HKL last_hkl = 0;
2341 static int last_hkl_has_AltGr;
2343 HKL current_hkl = GetKeyboardLayout (0);
2344 if (current_hkl != last_hkl)
2347 last_hkl_has_AltGr = 0;
2348 /* In this loop, we query whether a character requires
2349 AltGr to be down to generate it. If at least such one
2350 found, this means that the layout does regard AltGr */
2351 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2352 if (HIBYTE (VkKeyScan (c)) == 6)
2353 last_hkl_has_AltGr = 1;
2354 last_hkl = current_hkl;
2356 return last_hkl_has_AltGr;
2360 /* Returns the state of the modifier keys in the format expected by the
2361 * Lisp_Event key_data, button_data and motion_data modifiers member */
2362 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2368 keymap = (BYTE*) alloca(256);
2369 GetKeyboardState (keymap);
2370 has_AltGr = mswindows_current_layout_has_AltGr ();
2373 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2375 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2376 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2380 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2381 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2384 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2390 * Translate a mswindows virtual key to a keysym.
2391 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2392 * or whose ASCII codes (like space) xemacs doesn't like.
2393 * Virtual key values are defined in winresrc.h
2394 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2396 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2398 switch (mswindows_key)
2400 /* First the predefined ones */
2401 case VK_BACK: return QKbackspace;
2402 case VK_TAB: return QKtab;
2403 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2404 case VK_RETURN: return QKreturn;
2405 case VK_ESCAPE: return QKescape;
2406 case VK_SPACE: return QKspace;
2407 case VK_DELETE: return QKdelete;
2410 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2411 case VK_PRIOR: return KEYSYM ("prior");
2412 case VK_NEXT: return KEYSYM ("next");
2413 case VK_END: return KEYSYM ("end");
2414 case VK_HOME: return KEYSYM ("home");
2415 case VK_LEFT: return KEYSYM ("left");
2416 case VK_UP: return KEYSYM ("up");
2417 case VK_RIGHT: return KEYSYM ("right");
2418 case VK_DOWN: return KEYSYM ("down");
2419 case VK_SELECT: return KEYSYM ("select");
2420 case VK_PRINT: return KEYSYM ("print");
2421 case VK_EXECUTE: return KEYSYM ("execute");
2422 case VK_SNAPSHOT: return KEYSYM ("print");
2423 case VK_INSERT: return KEYSYM ("insert");
2424 case VK_HELP: return KEYSYM ("help");
2425 #if 0 /* XXX What are these supposed to do? */
2426 case VK_LWIN return KEYSYM ("");
2427 case VK_RWIN return KEYSYM ("");
2429 case VK_APPS: return KEYSYM ("menu");
2430 case VK_F1: return KEYSYM ("f1");
2431 case VK_F2: return KEYSYM ("f2");
2432 case VK_F3: return KEYSYM ("f3");
2433 case VK_F4: return KEYSYM ("f4");
2434 case VK_F5: return KEYSYM ("f5");
2435 case VK_F6: return KEYSYM ("f6");
2436 case VK_F7: return KEYSYM ("f7");
2437 case VK_F8: return KEYSYM ("f8");
2438 case VK_F9: return KEYSYM ("f9");
2439 case VK_F10: return KEYSYM ("f10");
2440 case VK_F11: return KEYSYM ("f11");
2441 case VK_F12: return KEYSYM ("f12");
2442 case VK_F13: return KEYSYM ("f13");
2443 case VK_F14: return KEYSYM ("f14");
2444 case VK_F15: return KEYSYM ("f15");
2445 case VK_F16: return KEYSYM ("f16");
2446 case VK_F17: return KEYSYM ("f17");
2447 case VK_F18: return KEYSYM ("f18");
2448 case VK_F19: return KEYSYM ("f19");
2449 case VK_F20: return KEYSYM ("f20");
2450 case VK_F21: return KEYSYM ("f21");
2451 case VK_F22: return KEYSYM ("f22");
2452 case VK_F23: return KEYSYM ("f23");
2453 case VK_F24: return KEYSYM ("f24");
2459 * Find the console that matches the supplied mswindows window handle
2462 mswindows_find_console (HWND hwnd)
2464 /* We only support one console */
2465 return XCAR (Vconsole_list);
2469 * Find the frame that matches the supplied mswindows window handle
2472 mswindows_find_frame (HWND hwnd)
2474 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2478 /* We are in progress of frame creation. Return the frame
2479 being created, as it still not remembered in the window
2481 assert (!NILP (Vmswindows_frame_being_created));
2482 return Vmswindows_frame_being_created;
2484 VOID_TO_LISP (f, l);
2489 /************************************************************************/
2491 /************************************************************************/
2494 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2497 EMACS_TIME current_time;
2498 EMACS_GET_TIME (current_time);
2499 EMACS_SUB_TIME (thyme, thyme, current_time);
2500 milliseconds = EMACS_SECS (thyme) * 1000 +
2501 (EMACS_USECS (thyme) + 500) / 1000;
2502 if (milliseconds < 1)
2504 ++mswindows_pending_timers_count;
2505 return SetTimer (NULL, 0, milliseconds,
2506 (TIMERPROC) mswindows_wm_timer_callback);
2510 emacs_mswindows_remove_timeout (int id)
2512 struct Lisp_Event match_against;
2513 Lisp_Object emacs_event;
2515 if (KillTimer (NULL, id))
2516 --mswindows_pending_timers_count;
2518 /* If there is a dispatch event generated by this
2519 timeout in the queue, we have to remove it too. */
2520 match_against.event_type = timeout_event;
2521 match_against.event.timeout.interval_id = id;
2522 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2523 if (!NILP (emacs_event))
2524 Fdeallocate_event(emacs_event);
2527 /* If `user_p' is false, then return whether there are any win32, timeout,
2528 * or subprocess events pending (that is, whether
2529 * emacs_mswindows_next_event() would return immediately without blocking).
2531 * if `user_p' is true, then return whether there are any *user generated*
2532 * events available (that is, whether there are keyboard or mouse-click
2533 * events ready to be read). This also implies that
2534 * emacs_mswindows_next_event() would not block.
2537 emacs_mswindows_event_pending_p (int user_p)
2539 mswindows_need_event (0);
2540 return (!NILP (mswindows_u_dispatch_event_queue)
2541 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2545 * Return the next event
2548 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2550 Lisp_Object event, event2;
2552 mswindows_need_event (1);
2554 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
2555 XSETEVENT (event2, emacs_event);
2556 Fcopy_event (event, event2);
2557 Fdeallocate_event (event);
2561 * Handle a magic event off the dispatch queue.
2564 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2566 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2574 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2575 struct frame *f = XFRAME (frame);
2576 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2579 /* struct gcpro gcpro1; */
2581 /* Clear sticky modifiers here (if we had any) */
2583 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2584 /* GCPRO1 (conser); XXX Not necessary? */
2585 emacs_handle_focus_change_preliminary (conser);
2586 /* Under X the stuff up to here is done in the X event handler.
2588 emacs_handle_focus_change_final (conser);
2597 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2598 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2600 Qmap_frame_hook : Qunmap_frame_hook,
2605 /* #### What about Enter & Leave */
2607 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2608 Qmouse_leave_frame_hook, 1, frame);
2616 #ifndef HAVE_MSG_SELECT
2618 get_process_input_waitable (struct Lisp_Process *process)
2620 Lisp_Object instr, outstr, p;
2621 XSETPROCESS (p, process);
2622 get_process_streams (process, &instr, &outstr);
2623 assert (!NILP (instr));
2624 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2625 return (network_connection_p (p)
2626 ? get_winsock_stream_waitable (XLSTREAM (instr))
2627 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2629 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2634 emacs_mswindows_select_process (struct Lisp_Process *process)
2636 HANDLE hev = get_process_input_waitable (process);
2638 if (!add_waitable_handle (hev))
2639 error ("Too many active processes");
2641 #ifdef HAVE_WIN32_PROCESSES
2644 XSETPROCESS (p, process);
2645 if (!network_connection_p (p))
2647 HANDLE hprocess = get_nt_process_handle (process);
2648 if (!add_waitable_handle (hprocess))
2650 remove_waitable_handle (hev);
2651 error ("Too many active processes");
2659 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2661 /* Process handle is removed in the event loop as soon
2662 as it is signaled, so don't bother here about it */
2663 HANDLE hev = get_process_input_waitable (process);
2664 remove_waitable_handle (hev);
2666 #endif /* HAVE_MSG_SELECT */
2669 emacs_mswindows_select_console (struct console *con)
2674 emacs_mswindows_unselect_console (struct console *con)
2679 emacs_mswindows_quit_p (void)
2683 /* Quit cannot happen in modal loop: all program
2684 input is dedicated to Windows. */
2685 if (mswindows_in_modal_loop)
2688 /* Drain windows queue. This sets up number of quit characters in the queue
2689 * (and also processes wm focus change, move, resize, etc messages).
2690 * We don't want to process WM_PAINT messages because this function can be
2691 * called from almost anywhere and the windows' states may be changing. */
2692 while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
2693 PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
2694 DispatchMessage (&msg);
2696 if (mswindows_quit_chars_count > 0)
2698 /* Yes there's a hidden one... Throw it away */
2699 struct Lisp_Event match_against;
2700 Lisp_Object emacs_event;
2702 match_against.event_type = key_press_event;
2703 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2705 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2706 assert (!NILP (emacs_event));
2708 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2711 Fdeallocate_event(emacs_event);
2712 --mswindows_quit_chars_count;
2717 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2718 Lisp_Object* instream,
2719 Lisp_Object* outstream,
2722 /* Handles for streams */
2724 /* fds. These just stored along with the streams, and are closed in
2725 delete stream pair method, because we need to handle fake unices
2729 /* Decode inhandle and outhandle. Their meaning depends on
2730 the process implementation being used. */
2731 #if defined (HAVE_WIN32_PROCESSES)
2732 /* We're passed in Windows handles. That's what we like most... */
2733 hin = (HANDLE) inhandle;
2734 hout = (HANDLE) outhandle;
2736 #elif defined (HAVE_UNIX_PROCESSES)
2737 /* We are passed UNIX fds. This must be Cygwin.
2739 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2740 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2744 #error "So, WHICH kind of processes do you want?"
2747 *instream = (hin == INVALID_HANDLE_VALUE
2749 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2750 : flags & STREAM_NETWORK_CONNECTION
2751 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2753 : make_ntpipe_input_stream (hin, fdi));
2755 #ifdef HAVE_WIN32_PROCESSES
2756 *outstream = (hout == INVALID_HANDLE_VALUE
2758 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2759 : flags & STREAM_NETWORK_CONNECTION
2760 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2762 : make_ntpipe_output_stream (hout, fdo));
2763 #elif defined (HAVE_UNIX_PROCESSES)
2764 *outstream = (fdo >= 0
2765 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2768 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2769 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2770 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2772 Bufbyte eof_char = get_eof_char (fdo);
2773 int pty_max_bytes = get_pty_max_bytes (fdo);
2774 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2779 return (NILP (*instream)
2781 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2782 : flags & STREAM_NETWORK_CONNECTION
2783 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2785 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2789 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2790 Lisp_Object outstream)
2792 /* Oh nothing special here for Win32 at all */
2793 #if defined (HAVE_UNIX_PROCESSES)
2794 int in = (NILP(instream)
2796 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2797 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2798 ? get_winsock_stream_param (XLSTREAM (instream))
2800 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2801 int out = (NILP(outstream) ? -1
2802 : filedesc_stream_fd (XLSTREAM (outstream)));
2806 if (out != in && out >= 0)
2810 return (NILP (instream)
2812 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2813 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2814 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2816 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2819 #ifndef HAVE_X_WINDOWS
2820 /* This is called from GC when a process object is about to be freed.
2821 If we've still got pointers to it in this file, we're gonna lose hard.
2824 debug_process_finalization (struct Lisp_Process *p)
2827 Lisp_Object instr, outstr;
2829 get_process_streams (p, &instr, &outstr);
2830 /* if it still has fds, then it hasn't been killed yet. */
2831 assert (NILP(instr));
2832 assert (NILP(outstr));
2834 /* #### More checks here */
2839 /************************************************************************/
2840 /* initialization */
2841 /************************************************************************/
2844 vars_of_event_mswindows (void)
2846 mswindows_u_dispatch_event_queue = Qnil;
2847 staticpro (&mswindows_u_dispatch_event_queue);
2848 mswindows_u_dispatch_event_queue_tail = Qnil;
2850 mswindows_s_dispatch_event_queue = Qnil;
2851 staticpro (&mswindows_s_dispatch_event_queue);
2852 mswindows_s_dispatch_event_queue_tail = Qnil;
2854 mswindows_error_caught_in_modal_loop = Qnil;
2855 staticpro (&mswindows_error_caught_in_modal_loop);
2856 mswindows_in_modal_loop = 0;
2857 mswindows_pending_timers_count = 0;
2859 mswindows_event_stream = xnew (struct event_stream);
2861 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2862 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2863 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2864 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2865 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2866 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2867 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2868 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2869 #ifdef HAVE_MSG_SELECT
2870 mswindows_event_stream->select_process_cb =
2871 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2872 mswindows_event_stream->unselect_process_cb =
2873 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2874 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2875 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2877 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2878 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2879 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2880 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2883 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2884 *Controls redrawing frame contents during mouse-drag or keyboard resize
2885 operation. When non-nil, the frame is redrawn while being resized. When
2886 nil, frame is not redrawn, and exposed areas are filled with default
2887 MDI application background color. Note that this option only has effect
2888 if "Show window contents while dragging" is on in system Display/Plus!
2890 Default is t on fast machines, nil on slow.
2893 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2894 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2895 *Analogue of double click interval for faking middle mouse events.
2896 The value is the minimum time in milliseconds that must elapse between
2897 left/right button down events before they are considered distinct events.
2898 If both mouse buttons are depressed within this interval, a middle mouse
2899 button down event is generated instead.
2900 If negative or zero, currently set system default is used instead.
2903 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2904 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2905 Number of physical mouse buttons.
2908 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2909 *Maximum horizontal distance in pixels between points in which left and
2910 right button clicks occurred for them to be translated into single
2911 middle button event. Clicks must occur in time not longer than defined
2912 by the variable `mswindows-mouse-button-tolerance'.
2913 If negative or zero, currently set system default is used instead.
2916 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2917 *Maximum vertical distance in pixels between points in which left and
2918 right button clicks occurred for them to be translated into single
2919 middle button event. Clicks must occur in time not longer than defined
2920 by the variable `mswindows-mouse-button-tolerance'.
2921 If negative or zero, currently set system default is used instead.
2924 mswindows_mouse_button_max_skew_x = 0;
2925 mswindows_mouse_button_max_skew_y = 0;
2926 mswindows_mouse_button_tolerance = 0;
2930 syms_of_event_mswindows (void)
2935 lstream_type_create_mswindows_selectable (void)
2937 init_slurp_stream ();
2938 init_shove_stream ();
2939 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2940 init_winsock_stream ();
2945 init_event_mswindows_late (void)
2947 #ifdef HAVE_MSG_SELECT
2948 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2949 assert (windows_fd>=0);
2950 FD_SET (windows_fd, &input_wait_mask);
2951 FD_ZERO(&zero_mask);
2954 event_stream = mswindows_event_stream;
2956 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2957 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);