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 #include "console-tty.h"
69 #elif defined(__CYGWIN32__)
70 typedef unsigned int SOCKET;
76 #define ADJR_MENUFLAG TRUE
78 #define ADJR_MENUFLAG FALSE
81 /* Fake key modifier which is attached to a quit char event.
82 Removed upon dequeueing an event */
83 #define FAKE_MOD_QUIT 0x80
85 /* Timer ID used for button2 emulation */
86 #define BUTTON_2_TIMER_ID 1
89 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
91 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
93 mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
95 static Lisp_Object mswindows_find_frame (HWND hwnd);
96 static Lisp_Object mswindows_find_console (HWND hwnd);
97 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
98 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
99 static void mswindows_set_chord_timer (HWND hwnd);
100 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
101 static int mswindows_current_layout_has_AltGr (void);
103 static struct event_stream *mswindows_event_stream;
105 #ifdef HAVE_MSG_SELECT
106 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
107 extern SELECT_TYPE process_only_mask, tty_only_mask;
108 SELECT_TYPE zero_mask;
109 extern int signal_event_pipe_initialized;
114 * Two separate queues, for efficiency, one (_u_) for user events, and
115 * another (_s_) for non-user ones. We always return events out of the
116 * first one until it is empty and only then proceed with the second
119 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
120 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
122 /* The number of things we can wait on */
123 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
125 #ifndef HAVE_MSG_SELECT
126 /* List of mswindows waitable handles. */
127 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
129 /* Number of wait handles */
130 static int mswindows_waitable_count=0;
131 #endif /* HAVE_MSG_SELECT */
132 /* Brush for painting widgets */
133 static HBRUSH widget_brush = 0;
134 static LONG last_widget_brushed = 0;
136 /* Count of quit chars currently in the queue */
137 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
138 Decremented in mswindows_dequeue_dispatch_event() */
139 int mswindows_quit_chars_count = 0;
141 /* These are Lisp integers; see DEFVARS in this file for description. */
142 int mswindows_dynamic_frame_resize;
143 int mswindows_num_mouse_buttons;
144 int mswindows_mouse_button_max_skew_x;
145 int mswindows_mouse_button_max_skew_y;
146 int mswindows_mouse_button_tolerance;
148 /* This is the event signaled by the event pump.
149 See mswindows_pump_outstanding_events for comments */
150 static Lisp_Object mswindows_error_caught_in_modal_loop;
151 static int mswindows_in_modal_loop;
153 /* Count of wound timers */
154 static int mswindows_pending_timers_count;
156 /************************************************************************/
157 /* Pipe instream - reads process output */
158 /************************************************************************/
160 #define PIPE_READ_DELAY 20
162 #define HANDLE_TO_USID(h) ((USID)(h))
164 #define NTPIPE_SLURP_STREAM_DATA(stream) \
165 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
167 /* This structure is allocated by the main thread, and is deallocated
168 in the thread upon exit. There are situations when a thread
169 remains blocked for a long time, much longer than the lstream
170 exists. For example, "start notepad" command is issued from the
171 shell, then the shell is closed by C-c C-d. Although the shell
172 process exits, its output pipe will not get closed until the
173 notepad process exits also, because it inherits the pipe form the
174 shell. In this case, we abandon the thread, and let it live until
175 all such processes exit. While struct ntpipe_slurp_stream is
176 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
178 struct ntpipe_slurp_stream_shared_data
180 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
181 /* This is a manual-reset object. */
182 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
183 /* This is a manual-reset object. */
184 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
185 /* This is a manual-reset object. */
186 HANDLE hpipe; /* Pipe read end handle. */
187 LONG die_p; /* Thread must exit ASAP if non-zero */
188 BOOL eof_p : 1; /* Set when thread saw EOF */
189 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
190 BOOL inuse_p : 1; /* this structure is in use */
191 LONG lock_count; /* Client count of this struct, 0=safe to free */
192 BYTE onebyte; /* One byte buffer read by thread */
195 #define MAX_SLURP_STREAMS 32
196 struct ntpipe_slurp_stream_shared_data
197 shared_data_block[MAX_SLURP_STREAMS]={{0}};
199 struct ntpipe_slurp_stream
201 LPARAM user_data; /* Any user data stored in the stream object */
202 struct ntpipe_slurp_stream_shared_data* thread_data;
205 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
206 sizeof (struct ntpipe_slurp_stream));
208 /* This function is thread-safe, and is called from either thread
209 context. It serializes freeing shared data structure */
211 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
213 if (InterlockedDecrement (&s->lock_count) == 0)
216 CloseHandle (s->hev_thread);
217 CloseHandle (s->hev_caller);
218 CloseHandle (s->hev_unsleep);
223 static struct ntpipe_slurp_stream_shared_data*
224 slurper_allocate_shared_data()
227 for (i=0; i<MAX_SLURP_STREAMS; i++)
229 if (!shared_data_block[i].inuse_p)
231 shared_data_block[i].inuse_p=1;
232 return &shared_data_block[i];
235 return (struct ntpipe_slurp_stream_shared_data*)0;
239 slurp_thread (LPVOID vparam)
241 struct ntpipe_slurp_stream_shared_data *s =
242 (struct ntpipe_slurp_stream_shared_data*)vparam;
246 /* Read one byte from the pipe */
248 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
250 DWORD err = GetLastError ();
251 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
256 else if (actually_read == 0)
259 /* We must terminate on an error or eof */
260 if (s->eof_p || s->error_p)
261 InterlockedIncrement (&s->die_p);
263 /* Before we notify caller, we unsignal our event. */
264 ResetEvent (s->hev_thread);
266 /* Now we got something to notify caller, either a byte or an
267 error/eof indication. Before we do, allow internal pipe
268 buffer to accumulate little bit more data.
269 Reader function pulses this event before waiting for
270 a character, to avoid pipe delay, and to get the byte
273 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
275 /* Either make event loop generate a process event, or
277 SetEvent (s->hev_caller);
279 /* Cleanup and exit if we're shot off */
283 /* Block until the client finishes with retrieving the rest of
285 WaitForSingleObject (s->hev_thread, INFINITE);
288 slurper_free_shared_data_maybe (s);
294 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
297 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
298 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
299 DWORD thread_id_unused;
302 /* We deal only with pipes, for we're using PeekNamedPipe api */
303 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
305 s->thread_data = slurper_allocate_shared_data();
307 /* Create reader thread. This could fail, so do not create events
308 until thread is created */
309 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
310 CREATE_SUSPENDED, &thread_id_unused);
313 Lstream_delete (lstr);
314 s->thread_data->inuse_p=0;
318 /* Shared data are initially owned by both main and slurper
320 s->thread_data->lock_count = 2;
321 s->thread_data->die_p = 0;
322 s->thread_data->eof_p = FALSE;
323 s->thread_data->error_p = FALSE;
324 s->thread_data->hpipe = hpipe;
325 s->user_data = param;
327 /* hev_thread is a manual-reset event, initially signaled */
328 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
329 /* hev_caller is a manual-reset event, initially nonsignaled */
330 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
331 /* hev_unsleep is a manual-reset event, initially nonsignaled */
332 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
335 ResumeThread (hthread);
336 CloseHandle (hthread);
338 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
339 XSETLSTREAM (obj, lstr);
344 get_ntpipe_input_stream_param (Lstream *stream)
346 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
351 get_ntpipe_input_stream_waitable (Lstream *stream)
353 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
354 return s->thread_data->hev_caller;
358 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
360 /* This function must be called from the main thread only */
361 struct ntpipe_slurp_stream_shared_data* s =
362 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
367 /* Disallow pipe read delay for the thread: we need a character
369 SetEvent (s->hev_unsleep);
371 /* Check if we have a character ready. Give it a short delay,
372 for the thread to awake from pipe delay, just ion case*/
373 wait_result = WaitForSingleObject (s->hev_caller, 2);
375 /* Revert to the normal sleep behavior. */
376 ResetEvent (s->hev_unsleep);
378 /* If there's no byte buffered yet, give up */
379 if (wait_result == WAIT_TIMEOUT)
386 /* Reset caller unlock event now, as we've handled the pending
387 process output event */
388 ResetEvent (s->hev_caller);
390 /* It is now safe to do anything with contents of S, except for
391 changing s->die_p, which still should be interlocked */
395 if (s->error_p || s->die_p)
398 /* Ok, there were no error neither eof - we've got a byte from the
400 *(data++) = s->onebyte;
404 DWORD bytes_read = 0;
407 DWORD bytes_available;
409 /* If the api call fails, return at least one byte already
410 read. ReadFile in thread will return error */
411 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
414 /* Fetch available bytes. The same consideration applies,
415 so do not check for errors. ReadFile in the thread will
416 fail if the next call fails. */
418 ReadFile (s->hpipe, data, min (bytes_available, size),
422 /* Now we can unblock thread, so it attempts to read more */
423 SetEvent (s->hev_thread);
424 return bytes_read + 1;
431 ntpipe_slurp_closer (Lstream *stream)
433 /* This function must be called from the main thread only */
434 struct ntpipe_slurp_stream_shared_data* s =
435 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
437 /* Force thread to stop */
438 InterlockedIncrement (&s->die_p);
440 /* Set events which could possibly block slurper. Let it finish soon
442 SetEvent (s->hev_unsleep);
443 SetEvent (s->hev_thread);
445 /* Unlock and maybe free shared data */
446 slurper_free_shared_data_maybe (s);
452 init_slurp_stream (void)
454 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
455 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
458 /************************************************************************/
459 /* Pipe outstream - writes process input */
460 /************************************************************************/
462 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
463 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
465 #define MAX_SHOVE_BUFFER_SIZE 128
467 struct ntpipe_shove_stream
469 LPARAM user_data; /* Any user data stored in the stream object */
470 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
471 /* This is an auto-reset object. */
472 HANDLE hpipe; /* Pipe write end handle. */
473 HANDLE hthread; /* Reader thread handle. */
474 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
475 DWORD size; /* Number of bytes to write */
476 LONG die_p; /* Thread must exit ASAP if non-zero */
477 LONG idle_p; /* Non-zero if thread is waiting for job */
478 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
479 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
482 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
483 sizeof (struct ntpipe_shove_stream));
485 #ifndef HAVE_MSG_SELECT
487 shove_thread (LPVOID vparam)
489 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
495 /* Block on event and wait for a job */
496 InterlockedIncrement (&s->idle_p);
497 WaitForSingleObject (s->hev_thread, INFINITE);
502 /* Write passed buffer */
503 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
504 || bytes_written != s->size)
507 InterlockedIncrement (&s->die_p);
518 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
521 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
522 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
523 DWORD thread_id_unused;
528 s->user_data = param;
530 /* Create reader thread. This could fail, so do not
531 create the event until thread is created */
532 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
533 CREATE_SUSPENDED, &thread_id_unused);
534 if (s->hthread == NULL)
536 Lstream_delete (lstr);
540 /* hev_thread is an auto-reset event, initially nonsignaled */
541 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
544 ResumeThread (s->hthread);
546 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
547 XSETLSTREAM (obj, lstr);
552 get_ntpipe_output_stream_param (Lstream *stream)
554 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
560 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
562 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
567 s->blocking_p = !s->idle_p;
571 if (size>MAX_SHOVE_BUFFER_SIZE)
574 memcpy (s->buffer, data, size);
578 InterlockedDecrement (&s->idle_p);
579 SetEvent (s->hev_thread);
584 ntpipe_shove_was_blocked_p (Lstream *stream)
586 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
587 return s->blocking_p;
591 ntpipe_shove_closer (Lstream *stream)
593 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
595 /* Force thread stop */
596 InterlockedIncrement (&s->die_p);
598 /* Close pipe handle, possibly breaking it */
599 CloseHandle (s->hpipe);
601 /* Thread will end upon unblocking */
602 SetEvent (s->hev_thread);
604 /* Wait while thread terminates */
605 WaitForSingleObject (s->hthread, INFINITE);
606 CloseHandle (s->hthread);
608 /* Destroy the event */
609 CloseHandle (s->hev_thread);
615 init_shove_stream (void)
617 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
618 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
619 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
622 /************************************************************************/
623 /* Winsock I/O stream */
624 /************************************************************************/
625 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
627 #define WINSOCK_READ_BUFFER_SIZE 1024
629 struct winsock_stream
631 LPARAM user_data; /* Any user data stored in the stream object */
632 SOCKET s; /* Socket handle (which is a Win32 handle) */
633 OVERLAPPED ov; /* Overlapped I/O structure */
634 void* buffer; /* Buffer. Allocated for input stream only */
635 unsigned int bufsize; /* Number of bytes last read */
636 unsigned int bufpos; /* Position in buffer for next fetch */
637 unsigned int error_p :1; /* I/O Error seen */
638 unsigned int eof_p :1; /* EOF Error seen */
639 unsigned int pending_p :1; /* There is a pending I/O operation */
640 unsigned int blocking_p :1; /* Last write attempt would block */
643 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
645 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
646 sizeof (struct winsock_stream));
649 winsock_initiate_read (struct winsock_stream *str)
651 ResetEvent (str->ov.hEvent);
654 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
655 &str->bufsize, &str->ov))
657 if (GetLastError () == ERROR_IO_PENDING)
659 else if (GetLastError () == ERROR_HANDLE_EOF)
664 else if (str->bufsize == 0)
669 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
671 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
673 /* If the current operation is not yet complete, there's nothing to
677 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
684 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
686 if (GetLastError() == ERROR_HANDLE_EOF)
691 if (str->bufsize == 0)
702 /* Return as much of buffer as we have */
703 size = min (size, (size_t) (str->bufsize - str->bufpos));
704 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
707 /* Read more if buffer is exhausted */
708 if (str->bufsize == str->bufpos)
709 winsock_initiate_read (str);
715 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
717 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
721 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
729 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
744 ResetEvent (str->ov.hEvent);
746 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
747 * an overlapped operation. This fails on Win95 with winsock 1.x so we
748 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
749 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
750 || GetLastError() == ERROR_IO_PENDING)
756 return str->error_p ? -1 : size;
760 winsock_closer (Lstream *lstr)
762 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
764 if (lstr->flags & LSTREAM_FL_READ)
765 shutdown (str->s, 0);
767 shutdown (str->s, 1);
769 CloseHandle ((HANDLE)str->s);
771 WaitForSingleObject (str->ov.hEvent, INFINITE);
773 if (lstr->flags & LSTREAM_FL_READ)
776 CloseHandle (str->ov.hEvent);
781 winsock_was_blocked_p (Lstream *stream)
783 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
784 return str->blocking_p;
788 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
791 Lstream *lstr = Lstream_new (lstream_winsock, mode);
792 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
799 str->user_data = param;
802 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
804 if (lstr->flags & LSTREAM_FL_READ)
806 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
807 winsock_initiate_read (str);
810 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
811 XSETLSTREAM (obj, lstr);
816 make_winsock_input_stream (SOCKET s, LPARAM param)
818 return make_winsock_stream_1 (s, param, "r");
822 make_winsock_output_stream (SOCKET s, LPARAM param)
824 return make_winsock_stream_1 (s, param, "w");
828 get_winsock_stream_waitable (Lstream *lstr)
830 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
831 return str->ov.hEvent;
835 get_winsock_stream_param (Lstream *lstr)
837 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
838 return str->user_data;
842 init_winsock_stream (void)
844 LSTREAM_HAS_METHOD (winsock, reader);
845 LSTREAM_HAS_METHOD (winsock, writer);
846 LSTREAM_HAS_METHOD (winsock, closer);
847 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
849 #endif /* defined (HAVE_SOCKETS) */
851 /************************************************************************/
852 /* Dispatch queue management */
853 /************************************************************************/
856 mswindows_user_event_p (struct Lisp_Event* sevt)
858 return (sevt->event_type == key_press_event
859 || sevt->event_type == button_press_event
860 || sevt->event_type == button_release_event
861 || sevt->event_type == misc_user_event);
865 * Add an emacs event to the proper dispatch queue
868 mswindows_enqueue_dispatch_event (Lisp_Object event)
870 int user_p = mswindows_user_event_p (XEVENT(event));
871 enqueue_event (event,
872 user_p ? &mswindows_u_dispatch_event_queue :
873 &mswindows_s_dispatch_event_queue,
874 user_p ? &mswindows_u_dispatch_event_queue_tail :
875 &mswindows_s_dispatch_event_queue_tail);
877 /* Avoid blocking on WaitMessage */
878 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
882 * Add a misc-user event to the dispatch queue.
884 * Stuff it into our own dispatch queue, so we have something
885 * to return from next_event callback.
888 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
891 Lisp_Object event = Fmake_event (Qnil, Qnil);
892 struct Lisp_Event* e = XEVENT (event);
894 e->event_type = misc_user_event;
895 e->channel = channel;
896 e->event.misc.function = function;
897 e->event.misc.object = object;
899 mswindows_enqueue_dispatch_event (event);
903 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
905 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
906 struct Lisp_Event* event = XEVENT (emacs_event);
908 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
909 event->timestamp = GetMessageTime();
910 event->event_type = magic_event;
911 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
913 mswindows_enqueue_dispatch_event (emacs_event);
917 mswindows_enqueue_process_event (struct Lisp_Process* p)
919 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
920 struct Lisp_Event* event = XEVENT (emacs_event);
922 XSETPROCESS (process, p);
924 event->event_type = process_event;
925 event->timestamp = GetTickCount ();
926 event->event.process.process = process;
928 mswindows_enqueue_dispatch_event (emacs_event);
932 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
935 /* We always use last message time, because mouse button
936 events may get delayed, and XEmacs double click
937 recognition will fail */
939 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
940 struct Lisp_Event* event = XEVENT(emacs_event);
942 event->channel = mswindows_find_frame(hwnd);
943 event->timestamp = when;
944 event->event.button.button =
945 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
946 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
947 event->event.button.x = where.x;
948 event->event.button.y = where.y;
949 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
951 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
952 message==WM_RBUTTONDOWN)
954 event->event_type = button_press_event;
956 /* we need this to make sure the main window regains the focus
957 from control subwindows */
958 if (GetFocus() != hwnd)
961 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
966 event->event_type = button_release_event;
970 mswindows_enqueue_dispatch_event (emacs_event);
974 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
976 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
977 struct Lisp_Event* event = XEVENT(emacs_event);
979 event->channel = mswindows_find_console(hwnd);
980 event->timestamp = GetMessageTime();
981 event->event_type = key_press_event;
982 event->event.key.keysym = keysym;
983 event->event.key.modifiers = mods;
984 mswindows_enqueue_dispatch_event (emacs_event);
988 * Remove and return the first emacs event on the dispatch queue.
989 * Give a preference to user events over non-user ones.
992 mswindows_dequeue_dispatch_event ()
995 struct Lisp_Event* sevt;
997 assert (!NILP(mswindows_u_dispatch_event_queue) ||
998 !NILP(mswindows_s_dispatch_event_queue));
1000 event = dequeue_event (
1001 NILP(mswindows_u_dispatch_event_queue) ?
1002 &mswindows_s_dispatch_event_queue :
1003 &mswindows_u_dispatch_event_queue,
1004 NILP(mswindows_u_dispatch_event_queue) ?
1005 &mswindows_s_dispatch_event_queue_tail :
1006 &mswindows_u_dispatch_event_queue_tail);
1008 sevt = XEVENT(event);
1009 if (sevt->event_type == key_press_event
1010 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1012 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1013 --mswindows_quit_chars_count;
1020 * Remove and return the first emacs event on the dispatch queue that matches
1021 * the supplied event.
1022 * Timeout event matches if interval_id is equal to that of the given event.
1023 * Keypress event matches if logical AND between modifiers bitmask of the
1024 * event in the queue and that of the given event is non-zero.
1025 * For all other event types, this function aborts.
1029 mswindows_cancel_dispatch_event (struct Lisp_Event *match)
1032 Lisp_Object previous_event = Qnil;
1033 int user_p = mswindows_user_event_p (match);
1034 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1035 &mswindows_s_dispatch_event_queue;
1036 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1037 &mswindows_s_dispatch_event_queue_tail;
1039 assert (match->event_type == timeout_event
1040 || match->event_type == key_press_event);
1042 EVENT_CHAIN_LOOP (event, *head)
1044 struct Lisp_Event *e = XEVENT (event);
1045 if ((e->event_type == match->event_type) &&
1046 ((e->event_type == timeout_event) ?
1047 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1048 /* Must be key_press_event */
1049 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1051 if (NILP (previous_event))
1052 dequeue_event (head, tail);
1055 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1056 if (EQ (*tail, event))
1057 *tail = previous_event;
1062 previous_event = event;
1067 #ifndef HAVE_MSG_SELECT
1068 /************************************************************************/
1069 /* Waitable handles manipulation */
1070 /************************************************************************/
1072 find_waitable_handle (HANDLE h)
1075 for (i = 0; i < mswindows_waitable_count; ++i)
1076 if (mswindows_waitable_handles[i] == h)
1083 add_waitable_handle (HANDLE h)
1085 assert (find_waitable_handle (h) < 0);
1086 if (mswindows_waitable_count == MAX_WAITABLE)
1089 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1094 remove_waitable_handle (HANDLE h)
1096 int ix = find_waitable_handle (h);
1100 mswindows_waitable_handles [ix] =
1101 mswindows_waitable_handles [--mswindows_waitable_count];
1103 #endif /* HAVE_MSG_SELECT */
1106 /************************************************************************/
1108 /************************************************************************/
1111 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1112 Lisp_Object u_n_u_s_e_d)
1114 mswindows_error_caught_in_modal_loop = cons_sig_data;
1119 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1124 ++mswindows_in_modal_loop;
1125 tmp = condition_case_1 (Qt,
1127 mswindows_modal_loop_error_handler, Qnil);
1128 --mswindows_in_modal_loop;
1134 mswindows_unmodalize_signal_maybe (void)
1136 if (!NILP (mswindows_error_caught_in_modal_loop))
1138 /* Got an error while messages were pumped while
1139 in window procedure - have to resignal */
1140 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1141 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1142 mswindows_error_caught_in_modal_loop = Qnil;
1143 Fsignal (sym, data);
1148 * This is an unsafe part of event pump, guarded by
1149 * condition_case. See mswindows_pump_outstanding_events
1152 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1154 /* This function can call lisp */
1155 Lisp_Object event = Fmake_event (Qnil, Qnil);
1156 struct gcpro gcpro1;
1157 int do_redisplay = 0;
1160 while (detect_input_pending ())
1162 Fnext_event (event, Qnil);
1163 Fdispatch_event (event);
1170 Fdeallocate_event (event);
1173 /* Qt becomes return value of mswindows_pump_outstanding_events
1179 * This function pumps emacs events, while available, by using
1180 * next_message/dispatch_message loop. Errors are trapped around
1181 * the loop so the function always returns.
1183 * Windows message queue is not looked into during the call,
1184 * neither are waitable handles checked. The function pumps
1185 * thus only dispatch events already queued, as well as those
1186 * resulted in dispatching thereof. This is done by setting
1187 * module local variable mswindows_in_modal_loop to nonzero.
1189 * Return value is Qt if no errors was trapped, or Qunbound if
1190 * there was an error.
1192 * In case of error, a cons representing the error, in the
1193 * form (SIGNAL . DATA), is stored in the module local variable
1194 * mswindows_error_caught_in_modal_loop. This error is signaled
1195 * again when DispatchMessage returns. Thus, Windows internal
1196 * modal loops are protected against throws, which are proven
1197 * to corrupt internal Windows structures.
1199 * In case of success, mswindows_error_caught_in_modal_loop is
1202 * If the value of mswindows_error_caught_in_modal_loop is not
1203 * nil already upon entry, the function just returns non-nil.
1204 * This situation means that a new event has been queued while
1205 * in cancel mode. The event will be dequeued on the next regular
1206 * call of next-event; the pump is off since error is caught.
1207 * The caller must *unconditionally* cancel modal loop if the
1208 * value returned by this function is nil. Otherwise, everything
1209 * will become frozen until the modal loop exits under normal
1210 * condition (scrollbar drag is released, menu closed etc.)
1213 mswindows_pump_outstanding_events (void)
1215 /* This function can call lisp */
1217 Lisp_Object result = Qt;
1218 struct gcpro gcpro1;
1221 if (NILP(mswindows_error_caught_in_modal_loop))
1222 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1228 mswindows_drain_windows_queue ()
1231 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1233 /* we have to translate messages that are not sent to the main
1234 window. this is so that key presses work ok in things like
1235 edit fields. however, we *musn't* translate message for the
1236 main window as this is handled in the wnd proc. */
1237 if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
1239 TranslateMessage (&msg);
1241 DispatchMessage (&msg);
1242 mswindows_unmodalize_signal_maybe ();
1247 * This is a special flavor of the mswindows_need_event function,
1248 * used while in event pump. Actually, there is only kind of events
1249 * allowed while in event pump: a timer. An attempt to fetch any
1250 * other event leads to a deadlock, as there's no source of user input
1251 * ('cause event pump mirrors windows modal loop, which is a sole
1252 * owner of thread message queue).
1254 * To detect this, we use a counter of active timers, and allow
1255 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1256 * which will never come when there are no pending timers, which leads
1257 * to deadlock, we simply signal an error.
1260 mswindows_need_event_in_modal_loop (int badly_p)
1264 /* Check if already have one */
1265 if (!NILP (mswindows_u_dispatch_event_queue)
1266 || !NILP (mswindows_s_dispatch_event_queue))
1269 /* No event is ok */
1273 /* We do not check the _u_ queue, because timers go to _s_ */
1274 while (NILP (mswindows_s_dispatch_event_queue))
1276 /* We'll deadlock if go waiting */
1277 if (mswindows_pending_timers_count == 0)
1278 error ("Deadlock due to an attempt to call next-event in a wrong context");
1280 /* Fetch and dispatch any pending timers */
1281 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1282 DispatchMessage (&msg);
1287 * This drains the event queue and fills up two internal queues until
1288 * an event of a type specified by USER_P is retrieved.
1291 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1294 mswindows_need_event (int badly_p)
1298 if (mswindows_in_modal_loop)
1300 mswindows_need_event_in_modal_loop (badly_p);
1304 /* Have to drain Windows message queue first, otherwise, we may miss
1305 quit char when called from quit_p */
1306 mswindows_drain_windows_queue ();
1308 while (NILP (mswindows_u_dispatch_event_queue)
1309 && NILP (mswindows_s_dispatch_event_queue))
1311 #ifdef HAVE_MSG_SELECT
1313 SELECT_TYPE temp_mask = input_wait_mask;
1314 EMACS_TIME sometime;
1315 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1318 pointer_to_this = 0;
1321 EMACS_SET_SECS_USECS (sometime, 0, 0);
1322 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1323 pointer_to_this = &select_time_to_block;
1326 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1330 return; /* timeout */
1332 else if (active > 0)
1334 if (FD_ISSET (windows_fd, &temp_mask))
1336 mswindows_drain_windows_queue ();
1339 /* Look for a TTY event */
1340 for (i = 0; i < MAXDESC-1; i++)
1342 /* To avoid race conditions (among other things, an infinite
1343 loop when called from Fdiscard_input()), we must return
1344 user events ahead of process events. */
1345 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1347 struct console *c = tty_find_console_from_fd (i);
1348 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1349 struct Lisp_Event* event = XEVENT (emacs_event);
1352 if (read_event_from_tty_or_stream_desc (event, c, i))
1354 mswindows_enqueue_dispatch_event (emacs_event);
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);
1374 /* We might get here when a fake event came
1375 through a signal. Return a dummy event, so
1376 that a cycle of the command loop will
1378 drain_signal_event_pipe ();
1379 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1384 else if (active==-1)
1388 /* something bad happened */
1397 /* Now try getting a message or process event */
1398 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1399 mswindows_waitable_handles,
1400 FALSE, badly_p ? INFINITE : 0,
1403 /* This will assert if handle being waited for becomes abandoned.
1404 Not the case currently tho */
1405 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1406 (active >= WAIT_OBJECT_0 &&
1407 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1409 if (active == WAIT_TIMEOUT)
1411 /* No luck trying - just return what we've already got */
1414 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1416 /* Got your message, thanks */
1417 mswindows_drain_windows_queue ();
1421 int ix = active - WAIT_OBJECT_0;
1422 /* First, try to find which process' output has signaled */
1423 struct Lisp_Process *p =
1424 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1427 /* Found a signaled process input handle */
1428 mswindows_enqueue_process_event (p);
1432 /* None. This means that the process handle itself has signaled.
1433 Remove the handle from the wait vector, and make status_notify
1434 note the exited process */
1435 mswindows_waitable_handles [ix] =
1436 mswindows_waitable_handles [--mswindows_waitable_count];
1437 kick_status_notify ();
1438 /* Have to return something: there may be no accompanying
1440 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1447 /************************************************************************/
1448 /* Event generators */
1449 /************************************************************************/
1452 * Callback procedure for synchronous timer messages
1454 static void CALLBACK
1455 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1457 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1458 struct Lisp_Event *event = XEVENT (emacs_event);
1460 if (KillTimer (NULL, id_timer))
1461 --mswindows_pending_timers_count;
1463 event->channel = Qnil;
1464 event->timestamp = dwtime;
1465 event->event_type = timeout_event;
1466 event->event.timeout.interval_id = id_timer;
1467 event->event.timeout.function = Qnil;
1468 event->event.timeout.object = Qnil;
1470 mswindows_enqueue_dispatch_event (emacs_event);
1474 * Callback procedure for dde messages
1476 * We execute a dde Open("file") by simulating a file drop, so dde support
1477 * depends on dnd support.
1479 #ifdef HAVE_DRAGNDROP
1481 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1482 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1483 DWORD dwData1, DWORD dwData2)
1488 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1489 return (HDDEDATA)TRUE;
1490 return (HDDEDATA)FALSE;
1492 case XTYP_WILDCONNECT:
1494 /* We only support one {service,topic} pair */
1495 HSZPAIR pairs[2] = {
1496 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1498 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1499 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1500 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1501 sizeof (pairs), 0L, 0, uFmt, 0));
1503 return (HDDEDATA)NULL;
1506 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1508 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1509 char *cmd = alloca (len+1);
1512 struct gcpro gcpro1, gcpro2;
1513 Lisp_Object l_dndlist = Qnil;
1514 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1515 Lisp_Object frmcons, devcons, concons;
1516 struct Lisp_Event *event = XEVENT (emacs_event);
1518 DdeGetData (hdata, cmd, len, 0);
1520 DdeFreeDataHandle (hdata);
1522 /* Check syntax & that it's an [Open("foo")] command, which we
1523 * treat like a file drop */
1524 /* #### Ought to be generalised and accept some other commands */
1527 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1528 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1529 return DDE_FNOTPROCESSED;
1530 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1533 if (*cmd!='(' || *(cmd+1)!='\"')
1534 return DDE_FNOTPROCESSED;
1536 while (*end && *end!='\"')
1539 return DDE_FNOTPROCESSED;
1542 return DDE_FNOTPROCESSED;
1546 return DDE_FNOTPROCESSED;
1549 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1550 strcpy (filename, "file:");
1551 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1553 dostounix_filename (cmd);
1554 filename = alloca (strlen (cmd)+6);
1555 strcpy (filename, "file:");
1556 strcat (filename, cmd);
1558 GCPRO2 (emacs_event, l_dndlist);
1559 l_dndlist = make_string (filename, strlen (filename));
1561 /* Find a mswindows frame */
1562 event->channel = Qnil;
1563 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1565 Lisp_Object frame = XCAR (frmcons);
1566 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1567 event->channel = frame;
1569 assert (!NILP (event->channel));
1571 event->timestamp = GetTickCount();
1572 event->event_type = misc_user_event;
1573 event->event.misc.button = 1;
1574 event->event.misc.modifiers = 0;
1575 event->event.misc.x = -1;
1576 event->event.misc.y = -1;
1577 event->event.misc.function = Qdragdrop_drop_dispatch;
1578 event->event.misc.object = Fcons (Qdragdrop_URL,
1579 Fcons (l_dndlist, Qnil));
1580 mswindows_enqueue_dispatch_event (emacs_event);
1582 return (HDDEDATA) DDE_FACK;
1584 DdeFreeDataHandle (hdata);
1585 return (HDDEDATA) DDE_FNOTPROCESSED;
1588 return (HDDEDATA) NULL;
1594 * The windows procedure for the window class XEMACS_CLASS
1597 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1599 /* Note: Remember to initialize emacs_event and event before use.
1600 This code calls code that can GC. You must GCPRO before calling such code. */
1601 Lisp_Object emacs_event = Qnil;
1602 Lisp_Object fobj = Qnil;
1604 struct Lisp_Event *event;
1605 struct frame *frame;
1606 struct mswindows_frame* msframe;
1611 /* Erase background only during non-dynamic sizing */
1612 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1613 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1618 fobj = mswindows_find_frame (hwnd);
1619 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1624 /* See Win95 comment under WM_KEYDOWN */
1628 if (wParam == VK_CONTROL)
1630 GetKeyboardState (keymap);
1631 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1632 SetKeyboardState (keymap);
1634 else if (wParam == VK_MENU)
1636 GetKeyboardState (keymap);
1637 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1638 SetKeyboardState (keymap);
1645 /* In some locales the right-hand Alt key is labelled AltGr. This key
1646 * should produce alternative charcaters when combined with another key.
1647 * eg on a German keyboard pressing AltGr+q should produce '@'.
1648 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1649 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1650 * it translates as if AltGr were down.
1651 * We get round this by removing all modifiers from the keymap before
1652 * calling TranslateMessage() unless AltGr is *really* down. */
1655 int has_AltGr = mswindows_current_layout_has_AltGr ();
1659 GetKeyboardState (keymap);
1660 mods = mswindows_modifier_state (keymap, has_AltGr);
1662 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1663 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1664 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1667 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1668 BYTE keymap_orig[256];
1669 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1673 msg.message = message;
1674 msg.wParam = wParam;
1675 msg.lParam = lParam;
1676 msg.time = GetMessageTime();
1679 /* GetKeyboardState() does not work as documented on Win95. We have
1680 * to loosely track Left and Right modifiers on behalf of the OS,
1681 * without screwing up Windows NT which tracks them properly. */
1682 if (wParam == VK_CONTROL)
1683 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1684 else if (wParam == VK_MENU)
1685 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1687 memcpy (keymap_orig, keymap, 256);
1689 /* Remove shift modifier from an ascii character */
1692 /* Clear control and alt modifiers unless AltGr is pressed */
1693 keymap [VK_RCONTROL] = 0;
1694 keymap [VK_LMENU] = 0;
1695 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1697 keymap [VK_LCONTROL] = 0;
1698 keymap [VK_CONTROL] = 0;
1699 keymap [VK_RMENU] = 0;
1700 keymap [VK_MENU] = 0;
1702 SetKeyboardState (keymap);
1704 /* Maybe generate some WM_[SYS]CHARs in the queue */
1705 TranslateMessage (&msg);
1707 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1708 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1711 WPARAM ch = msg.wParam;
1713 /* If a quit char with no modifiers other than control and
1714 shift, then mark it with a fake modifier, which is removed
1715 upon dequeueing the event */
1716 /* #### This might also not withstand localization, if
1717 quit character is not a latin-1 symbol */
1718 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1719 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1720 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1722 mods1 |= FAKE_MOD_QUIT;
1723 ++mswindows_quit_chars_count;
1726 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1728 SetKeyboardState (keymap_orig);
1731 /* F10 causes menu activation by default. We do not want this */
1732 if (wParam != VK_F10)
1736 case WM_MBUTTONDOWN:
1738 /* Real middle mouse button has nothing to do with emulated one:
1739 if one wants to exercise fingers playing chords on the mouse,
1740 he is allowed to do that! */
1741 mswindows_enqueue_mouse_button_event (hwnd, message,
1742 MAKEPOINTS (lParam), GetMessageTime());
1746 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1747 msframe->last_click_time = GetMessageTime();
1749 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1750 msframe->button2_need_lbutton = 0;
1751 if (msframe->ignore_next_lbutton_up)
1753 msframe->ignore_next_lbutton_up = 0;
1755 else if (msframe->button2_is_down)
1757 msframe->button2_is_down = 0;
1758 msframe->ignore_next_rbutton_up = 1;
1759 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1760 MAKEPOINTS (lParam), GetMessageTime());
1764 if (msframe->button2_need_rbutton)
1766 msframe->button2_need_rbutton = 0;
1767 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1768 MAKEPOINTS (lParam), GetMessageTime());
1770 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1771 MAKEPOINTS (lParam), GetMessageTime());
1776 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1777 msframe->last_click_time = GetMessageTime();
1779 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1780 msframe->button2_need_rbutton = 0;
1781 if (msframe->ignore_next_rbutton_up)
1783 msframe->ignore_next_rbutton_up = 0;
1785 else if (msframe->button2_is_down)
1787 msframe->button2_is_down = 0;
1788 msframe->ignore_next_lbutton_up = 1;
1789 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1790 MAKEPOINTS (lParam), GetMessageTime());
1794 if (msframe->button2_need_lbutton)
1796 msframe->button2_need_lbutton = 0;
1797 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1798 MAKEPOINTS (lParam), GetMessageTime());
1800 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1801 MAKEPOINTS (lParam), GetMessageTime());
1805 case WM_LBUTTONDOWN:
1806 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1808 if (msframe->button2_need_lbutton)
1810 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1811 msframe->button2_need_lbutton = 0;
1812 msframe->button2_need_rbutton = 0;
1813 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1815 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1816 MAKEPOINTS (lParam), GetMessageTime());
1817 msframe->button2_is_down = 1;
1821 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1822 msframe->last_click_point, msframe->last_click_time);
1823 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1824 MAKEPOINTS (lParam), GetMessageTime());
1829 mswindows_set_chord_timer (hwnd);
1830 msframe->button2_need_rbutton = 1;
1831 msframe->last_click_point = MAKEPOINTS (lParam);
1833 msframe->last_click_time = GetMessageTime();
1836 case WM_RBUTTONDOWN:
1837 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1839 if (msframe->button2_need_rbutton)
1841 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1842 msframe->button2_need_lbutton = 0;
1843 msframe->button2_need_rbutton = 0;
1844 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1846 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1847 MAKEPOINTS (lParam), GetMessageTime());
1848 msframe->button2_is_down = 1;
1852 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1853 msframe->last_click_point, msframe->last_click_time);
1854 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1855 MAKEPOINTS (lParam), GetMessageTime());
1860 mswindows_set_chord_timer (hwnd);
1861 msframe->button2_need_lbutton = 1;
1862 msframe->last_click_point = MAKEPOINTS (lParam);
1864 msframe->last_click_time = GetMessageTime();
1868 if (wParam == BUTTON_2_TIMER_ID)
1870 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1871 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1873 if (msframe->button2_need_lbutton)
1875 msframe->button2_need_lbutton = 0;
1876 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1877 msframe->last_click_point, msframe->last_click_time);
1879 else if (msframe->button2_need_rbutton)
1881 msframe->button2_need_rbutton = 0;
1882 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1883 msframe->last_click_point, msframe->last_click_time);
1887 assert ("Spurious timer fired" == 0);
1891 /* Optimization: don't report mouse movement while size is changing */
1892 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1893 if (!msframe->sizing)
1895 /* When waiting for the second mouse button to finish
1896 button2 emulation, and have moved too far, just pretend
1897 as if timer has expired. This improves drag-select feedback */
1898 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1899 && !mswindows_button2_near_enough (msframe->last_click_point,
1900 MAKEPOINTS (lParam)))
1902 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1903 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1906 emacs_event = Fmake_event (Qnil, Qnil);
1907 event = XEVENT(emacs_event);
1909 event->channel = mswindows_find_frame(hwnd);
1910 event->timestamp = GetMessageTime();
1911 event->event_type = pointer_motion_event;
1912 event->event.motion.x = MAKEPOINTS(lParam).x;
1913 event->event.motion.y = MAKEPOINTS(lParam).y;
1914 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1916 mswindows_enqueue_dispatch_event (emacs_event);
1922 /* Queue a `cancel-mode-internal' misc user event, so mouse
1923 selection would be canceled if any */
1924 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1925 Qcancel_mode_internal, Qnil);
1928 #ifdef HAVE_TOOLBARS
1931 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1933 if (tttext->hdr.code == TTN_NEEDTEXT)
1935 /* find out which toolbar */
1936 frame = XFRAME (mswindows_find_frame (hwnd));
1937 btext = mswindows_get_toolbar_button_text ( frame,
1938 tttext->hdr.idFrom );
1940 tttext->lpszText = NULL;
1941 tttext->hinst = NULL;
1945 /* I think this is safe since the text will only go away
1946 when the toolbar does...*/
1947 GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS,
1951 tttext->uFlags |= TTF_DI_SETITEM;
1960 PAINTSTRUCT paintStruct;
1962 frame = XFRAME (mswindows_find_frame (hwnd));
1964 BeginPaint (hwnd, &paintStruct);
1965 mswindows_redraw_exposed_area (frame,
1966 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1967 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1968 EndPaint (hwnd, &paintStruct);
1973 /* We only care about this message if our size has really changed */
1974 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1979 fobj = mswindows_find_frame (hwnd);
1980 frame = XFRAME (fobj);
1981 msframe = FRAME_MSWINDOWS_DATA (frame);
1983 /* We cannot handle frame map and unmap hooks right in
1984 this routine, because these may throw. We queue
1985 magic events to run these hooks instead - kkm */
1987 if (wParam==SIZE_MINIMIZED)
1990 FRAME_VISIBLE_P (frame) = 0;
1991 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
1995 GetClientRect(hwnd, &rect);
1996 FRAME_PIXWIDTH(frame) = rect.right;
1997 FRAME_PIXHEIGHT(frame) = rect.bottom;
1999 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2000 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2001 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2003 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2004 change_frame_size (frame, rows, columns, 1);
2006 /* If we are inside frame creation, we have to apply geometric
2008 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2010 /* Yes, we have to size again */
2011 mswindows_size_frame_internal ( frame,
2012 FRAME_MSWINDOWS_TARGET_RECT
2014 /* Reset so we do not get here again. The SetWindowPos call in
2015 * mswindows_size_frame_internal can cause recursion here. */
2016 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2018 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2019 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2024 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2025 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2026 FRAME_VISIBLE_P (frame) = 1;
2028 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2035 /* Misc magic events which only require that the frame be identified */
2038 mswindows_enqueue_magic_event (hwnd, message);
2041 case WM_WINDOWPOSCHANGING:
2043 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2044 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2045 GetWindowPlacement(hwnd, &wpl);
2047 /* Only interested if size is changing and we're not being iconified */
2048 if (wpl.showCmd != SW_SHOWMINIMIZED
2049 && wpl.showCmd != SW_SHOWMAXIMIZED
2050 && !(wp->flags & SWP_NOSIZE))
2052 RECT ncsize = { 0, 0, 0, 0 };
2053 int pixwidth, pixheight;
2054 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2055 GetMenu(hwnd) != NULL,
2056 GetWindowLong (hwnd, GWL_EXSTYLE));
2058 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2059 wp->cx - (ncsize.right - ncsize.left),
2060 wp->cy - (ncsize.bottom - ncsize.top),
2061 &pixwidth, &pixheight);
2063 /* Convert client sizes to window sizes */
2064 pixwidth += (ncsize.right - ncsize.left);
2065 pixheight += (ncsize.bottom - ncsize.top);
2067 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2069 /* Adjust so that the bottom or right doesn't move if it's
2070 * the top or left that's being changed */
2072 GetWindowRect (hwnd, &rect);
2074 if (rect.left != wp->x)
2075 wp->x += wp->cx - pixwidth;
2076 if (rect.top != wp->y)
2077 wp->y += wp->cy - pixheight;
2083 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2084 window position if the user tries to track window too small */
2088 case WM_ENTERSIZEMOVE:
2089 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2090 msframe->sizing = 1;
2093 case WM_EXITSIZEMOVE:
2094 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2095 msframe->sizing = 0;
2096 /* Queue noop event */
2097 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2100 #ifdef HAVE_SCROLLBARS
2104 /* Direction of scroll is determined by scrollbar instance. */
2105 int code = (int) LOWORD(wParam);
2106 int pos = (short int) HIWORD(wParam);
2107 HWND hwndScrollBar = (HWND) lParam;
2108 struct gcpro gcpro1, gcpro2;
2110 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2111 GCPRO2 (emacs_event, fobj);
2112 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2114 /* Error during event pumping - cancel scroll */
2115 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2122 #ifdef HAVE_MENUBARS
2124 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2126 XFRAME (mswindows_find_frame (hwnd)))))
2127 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2130 case WM_INITMENUPOPUP:
2131 if (!HIWORD(lParam))
2133 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2135 XFRAME (mswindows_find_frame (hwnd)))))
2136 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2140 #endif /* HAVE_MENUBARS */
2144 WORD id = LOWORD (wParam);
2145 WORD nid = HIWORD (wParam);
2146 HWND cid = (HWND)lParam;
2147 frame = XFRAME (mswindows_find_frame (hwnd));
2149 #ifdef HAVE_TOOLBARS
2150 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2153 /* widgets in a buffer only eval a callback for suitable events.*/
2158 case CBN_EDITCHANGE:
2160 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2163 /* menubars always must come last since the hashtables do not
2165 #ifdef HAVE_MENUBARS
2166 if (!NILP (mswindows_handle_wm_command (frame, id)))
2170 return DefWindowProc (hwnd, message, wParam, lParam);
2171 /* Bite me - a spurious command. This used to not be able to
2172 happen but with the introduction of widgets its now
2177 case WM_CTLCOLORBTN:
2178 case WM_CTLCOLORLISTBOX:
2179 case WM_CTLCOLOREDIT:
2180 case WM_CTLCOLORSTATIC:
2181 case WM_CTLCOLORSCROLLBAR:
2183 /* if we get an opportunity to paint a widget then do so if
2184 there is an appropriate face */
2185 HWND crtlwnd = (HWND)lParam;
2186 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2189 Lisp_Object image_instance;
2190 VOID_TO_LISP (image_instance, ii);
2191 if (IMAGE_INSTANCEP (image_instance)
2193 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
2195 !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
2197 /* set colors for the buttons */
2198 HDC hdc = (HDC)wParam;
2199 if (last_widget_brushed != ii)
2202 DeleteObject (widget_brush);
2203 widget_brush = CreateSolidBrush
2204 (COLOR_INSTANCE_MSWINDOWS_COLOR
2207 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2208 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2210 last_widget_brushed = ii;
2213 COLOR_INSTANCE_MSWINDOWS_COLOR
2216 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2217 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2218 SetBkMode (hdc, OPAQUE);
2221 COLOR_INSTANCE_MSWINDOWS_COLOR
2224 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2225 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2226 return (LRESULT)widget_brush;
2232 #ifdef HAVE_DRAGNDROP
2233 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2235 UINT filecount, i, len;
2241 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2242 struct gcpro gcpro1, gcpro2, gcpro3;
2244 emacs_event = Fmake_event (Qnil, Qnil);
2245 event = XEVENT(emacs_event);
2247 GCPRO3 (emacs_event, l_dndlist, l_item);
2249 if (!DragQueryPoint ((HANDLE) wParam, &point))
2250 point.x = point.y = -1; /* outside client area */
2252 event->event_type = misc_user_event;
2253 event->channel = mswindows_find_frame(hwnd);
2254 event->timestamp = GetMessageTime();
2255 event->event.misc.button = 1; /* #### Should try harder */
2256 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2257 event->event.misc.x = point.x;
2258 event->event.misc.y = point.y;
2259 event->event.misc.function = Qdragdrop_drop_dispatch;
2261 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2262 for (i=0; i<filecount; i++)
2264 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2265 /* The URLs that we make here aren't correct according to section
2266 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2267 * because they may contain reserved characters. But that's OK. */
2269 fname = (char *)xmalloc (len+1);
2270 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2271 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2272 strcpy (filename, "file:");
2273 cygwin32_win32_to_posix_path_list (fname, filename+5);
2276 filename = (char *)xmalloc (len+6);
2277 strcpy (filename, "file:");
2278 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2279 dostounix_filename (filename+5);
2281 l_item = make_string (filename, strlen (filename));
2282 l_dndlist = Fcons (l_item, l_dndlist);
2285 DragFinish ((HANDLE) wParam);
2287 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2288 mswindows_enqueue_dispatch_event (emacs_event);
2296 return DefWindowProc (hwnd, message, wParam, lParam);
2302 /************************************************************************/
2303 /* keyboard, mouse & other helpers for the windows procedure */
2304 /************************************************************************/
2306 mswindows_set_chord_timer (HWND hwnd)
2310 /* We get one third half system double click threshold */
2311 if (mswindows_mouse_button_tolerance <= 0)
2312 interval = GetDoubleClickTime () / 3;
2314 interval = mswindows_mouse_button_tolerance;
2316 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2320 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2323 if (mswindows_mouse_button_max_skew_x <= 0)
2324 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2326 dx = mswindows_mouse_button_max_skew_x;
2328 if (mswindows_mouse_button_max_skew_y <= 0)
2329 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2331 dy = mswindows_mouse_button_max_skew_y;
2333 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2337 mswindows_current_layout_has_AltGr (void)
2339 /* This simple caching mechanism saves 10% of CPU
2340 time when a key typed at autorepeat rate of 30 cps! */
2341 static HKL last_hkl = 0;
2342 static int last_hkl_has_AltGr;
2344 HKL current_hkl = GetKeyboardLayout (0);
2345 if (current_hkl != last_hkl)
2348 last_hkl_has_AltGr = 0;
2349 /* In this loop, we query whether a character requires
2350 AltGr to be down to generate it. If at least such one
2351 found, this means that the layout does regard AltGr */
2352 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2353 if (HIBYTE (VkKeyScan (c)) == 6)
2354 last_hkl_has_AltGr = 1;
2355 last_hkl = current_hkl;
2357 return last_hkl_has_AltGr;
2361 /* Returns the state of the modifier keys in the format expected by the
2362 * Lisp_Event key_data, button_data and motion_data modifiers member */
2363 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2369 keymap = (BYTE*) alloca(256);
2370 GetKeyboardState (keymap);
2371 has_AltGr = mswindows_current_layout_has_AltGr ();
2374 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2376 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2377 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2381 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2382 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2385 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2391 * Translate a mswindows virtual key to a keysym.
2392 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2393 * or whose ASCII codes (like space) xemacs doesn't like.
2394 * Virtual key values are defined in winresrc.h
2395 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2397 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2399 switch (mswindows_key)
2401 /* First the predefined ones */
2402 case VK_BACK: return QKbackspace;
2403 case VK_TAB: return QKtab;
2404 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2405 case VK_RETURN: return QKreturn;
2406 case VK_ESCAPE: return QKescape;
2407 case VK_SPACE: return QKspace;
2408 case VK_DELETE: return QKdelete;
2411 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2412 case VK_PRIOR: return KEYSYM ("prior");
2413 case VK_NEXT: return KEYSYM ("next");
2414 case VK_END: return KEYSYM ("end");
2415 case VK_HOME: return KEYSYM ("home");
2416 case VK_LEFT: return KEYSYM ("left");
2417 case VK_UP: return KEYSYM ("up");
2418 case VK_RIGHT: return KEYSYM ("right");
2419 case VK_DOWN: return KEYSYM ("down");
2420 case VK_SELECT: return KEYSYM ("select");
2421 case VK_PRINT: return KEYSYM ("print");
2422 case VK_EXECUTE: return KEYSYM ("execute");
2423 case VK_SNAPSHOT: return KEYSYM ("print");
2424 case VK_INSERT: return KEYSYM ("insert");
2425 case VK_HELP: return KEYSYM ("help");
2426 #if 0 /* XXX What are these supposed to do? */
2427 case VK_LWIN return KEYSYM ("");
2428 case VK_RWIN return KEYSYM ("");
2430 case VK_APPS: return KEYSYM ("menu");
2431 case VK_F1: return KEYSYM ("f1");
2432 case VK_F2: return KEYSYM ("f2");
2433 case VK_F3: return KEYSYM ("f3");
2434 case VK_F4: return KEYSYM ("f4");
2435 case VK_F5: return KEYSYM ("f5");
2436 case VK_F6: return KEYSYM ("f6");
2437 case VK_F7: return KEYSYM ("f7");
2438 case VK_F8: return KEYSYM ("f8");
2439 case VK_F9: return KEYSYM ("f9");
2440 case VK_F10: return KEYSYM ("f10");
2441 case VK_F11: return KEYSYM ("f11");
2442 case VK_F12: return KEYSYM ("f12");
2443 case VK_F13: return KEYSYM ("f13");
2444 case VK_F14: return KEYSYM ("f14");
2445 case VK_F15: return KEYSYM ("f15");
2446 case VK_F16: return KEYSYM ("f16");
2447 case VK_F17: return KEYSYM ("f17");
2448 case VK_F18: return KEYSYM ("f18");
2449 case VK_F19: return KEYSYM ("f19");
2450 case VK_F20: return KEYSYM ("f20");
2451 case VK_F21: return KEYSYM ("f21");
2452 case VK_F22: return KEYSYM ("f22");
2453 case VK_F23: return KEYSYM ("f23");
2454 case VK_F24: return KEYSYM ("f24");
2460 * Find the console that matches the supplied mswindows window handle
2463 mswindows_find_console (HWND hwnd)
2465 /* We only support one console */
2466 return XCAR (Vconsole_list);
2470 * Find the frame that matches the supplied mswindows window handle
2473 mswindows_find_frame (HWND hwnd)
2475 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2479 /* We are in progress of frame creation. Return the frame
2480 being created, as it still not remembered in the window
2482 assert (!NILP (Vmswindows_frame_being_created));
2483 return Vmswindows_frame_being_created;
2485 VOID_TO_LISP (f, l);
2490 /************************************************************************/
2492 /************************************************************************/
2495 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2498 EMACS_TIME current_time;
2499 EMACS_GET_TIME (current_time);
2500 EMACS_SUB_TIME (thyme, thyme, current_time);
2501 milliseconds = EMACS_SECS (thyme) * 1000 +
2502 (EMACS_USECS (thyme) + 500) / 1000;
2503 if (milliseconds < 1)
2505 ++mswindows_pending_timers_count;
2506 return SetTimer (NULL, 0, milliseconds,
2507 (TIMERPROC) mswindows_wm_timer_callback);
2511 emacs_mswindows_remove_timeout (int id)
2513 struct Lisp_Event match_against;
2514 Lisp_Object emacs_event;
2516 if (KillTimer (NULL, id))
2517 --mswindows_pending_timers_count;
2519 /* If there is a dispatch event generated by this
2520 timeout in the queue, we have to remove it too. */
2521 match_against.event_type = timeout_event;
2522 match_against.event.timeout.interval_id = id;
2523 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2524 if (!NILP (emacs_event))
2525 Fdeallocate_event(emacs_event);
2528 /* If `user_p' is false, then return whether there are any win32, timeout,
2529 * or subprocess events pending (that is, whether
2530 * emacs_mswindows_next_event() would return immediately without blocking).
2532 * if `user_p' is true, then return whether there are any *user generated*
2533 * events available (that is, whether there are keyboard or mouse-click
2534 * events ready to be read). This also implies that
2535 * emacs_mswindows_next_event() would not block.
2538 emacs_mswindows_event_pending_p (int user_p)
2540 mswindows_need_event (0);
2541 return (!NILP (mswindows_u_dispatch_event_queue)
2542 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2546 * Return the next event
2549 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2551 Lisp_Object event, event2;
2553 mswindows_need_event (1);
2555 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
2556 XSETEVENT (event2, emacs_event);
2557 Fcopy_event (event, event2);
2558 Fdeallocate_event (event);
2562 * Handle a magic event off the dispatch queue.
2565 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2567 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2575 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2576 struct frame *f = XFRAME (frame);
2577 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2580 /* struct gcpro gcpro1; */
2582 /* Clear sticky modifiers here (if we had any) */
2584 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2585 /* GCPRO1 (conser); XXX Not necessary? */
2586 emacs_handle_focus_change_preliminary (conser);
2587 /* Under X the stuff up to here is done in the X event handler.
2589 emacs_handle_focus_change_final (conser);
2598 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2599 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2601 Qmap_frame_hook : Qunmap_frame_hook,
2606 /* #### What about Enter & Leave */
2608 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2609 Qmouse_leave_frame_hook, 1, frame);
2617 #ifndef HAVE_MSG_SELECT
2619 get_process_input_waitable (struct Lisp_Process *process)
2621 Lisp_Object instr, outstr, p;
2622 XSETPROCESS (p, process);
2623 get_process_streams (process, &instr, &outstr);
2624 assert (!NILP (instr));
2625 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2626 return (network_connection_p (p)
2627 ? get_winsock_stream_waitable (XLSTREAM (instr))
2628 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2630 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2635 emacs_mswindows_select_process (struct Lisp_Process *process)
2637 HANDLE hev = get_process_input_waitable (process);
2639 if (!add_waitable_handle (hev))
2640 error ("Too many active processes");
2642 #ifdef HAVE_WIN32_PROCESSES
2645 XSETPROCESS (p, process);
2646 if (!network_connection_p (p))
2648 HANDLE hprocess = get_nt_process_handle (process);
2649 if (!add_waitable_handle (hprocess))
2651 remove_waitable_handle (hev);
2652 error ("Too many active processes");
2660 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2662 /* Process handle is removed in the event loop as soon
2663 as it is signaled, so don't bother here about it */
2664 HANDLE hev = get_process_input_waitable (process);
2665 remove_waitable_handle (hev);
2667 #endif /* HAVE_MSG_SELECT */
2670 emacs_mswindows_select_console (struct console *con)
2672 #ifdef HAVE_MSG_SELECT
2673 if (CONSOLE_MSWINDOWS_P (con))
2674 return; /* mswindows consoles are automatically selected */
2676 event_stream_unixoid_select_console (con);
2681 emacs_mswindows_unselect_console (struct console *con)
2683 #ifdef HAVE_MSG_SELECT
2684 if (CONSOLE_MSWINDOWS_P (con))
2685 return; /* mswindows consoles are automatically selected */
2687 event_stream_unixoid_unselect_console (con);
2692 emacs_mswindows_quit_p (void)
2696 /* Quit cannot happen in modal loop: all program
2697 input is dedicated to Windows. */
2698 if (mswindows_in_modal_loop)
2701 /* Drain windows queue. This sets up number of quit characters in the queue
2702 * (and also processes wm focus change, move, resize, etc messages).
2703 * We don't want to process WM_PAINT messages because this function can be
2704 * called from almost anywhere and the windows' states may be changing. */
2705 while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
2706 PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
2707 DispatchMessage (&msg);
2709 if (mswindows_quit_chars_count > 0)
2711 /* Yes there's a hidden one... Throw it away */
2712 struct Lisp_Event match_against;
2713 Lisp_Object emacs_event;
2715 match_against.event_type = key_press_event;
2716 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2718 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2719 assert (!NILP (emacs_event));
2721 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2724 Fdeallocate_event(emacs_event);
2725 --mswindows_quit_chars_count;
2730 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2731 Lisp_Object* instream,
2732 Lisp_Object* outstream,
2735 /* Handles for streams */
2737 /* fds. These just stored along with the streams, and are closed in
2738 delete stream pair method, because we need to handle fake unices
2742 /* Decode inhandle and outhandle. Their meaning depends on
2743 the process implementation being used. */
2744 #if defined (HAVE_WIN32_PROCESSES)
2745 /* We're passed in Windows handles. That's what we like most... */
2746 hin = (HANDLE) inhandle;
2747 hout = (HANDLE) outhandle;
2749 #elif defined (HAVE_UNIX_PROCESSES)
2750 /* We are passed UNIX fds. This must be Cygwin.
2752 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2753 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2757 #error "So, WHICH kind of processes do you want?"
2760 *instream = (hin == INVALID_HANDLE_VALUE
2762 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2763 : flags & STREAM_NETWORK_CONNECTION
2764 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2766 : make_ntpipe_input_stream (hin, fdi));
2768 #ifdef HAVE_WIN32_PROCESSES
2769 *outstream = (hout == INVALID_HANDLE_VALUE
2771 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2772 : flags & STREAM_NETWORK_CONNECTION
2773 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2775 : make_ntpipe_output_stream (hout, fdo));
2776 #elif defined (HAVE_UNIX_PROCESSES)
2777 *outstream = (fdo >= 0
2778 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2781 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2782 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2783 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2785 Bufbyte eof_char = get_eof_char (fdo);
2786 int pty_max_bytes = get_pty_max_bytes (fdo);
2787 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2792 return (NILP (*instream)
2794 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2795 : flags & STREAM_NETWORK_CONNECTION
2796 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2798 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2802 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2803 Lisp_Object outstream)
2805 /* Oh nothing special here for Win32 at all */
2806 #if defined (HAVE_UNIX_PROCESSES)
2807 int in = (NILP(instream)
2809 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2810 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2811 ? get_winsock_stream_param (XLSTREAM (instream))
2813 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2814 int out = (NILP(outstream) ? -1
2815 : filedesc_stream_fd (XLSTREAM (outstream)));
2819 if (out != in && out >= 0)
2823 return (NILP (instream)
2825 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2826 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2827 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2829 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2832 #ifndef HAVE_X_WINDOWS
2833 /* This is called from GC when a process object is about to be freed.
2834 If we've still got pointers to it in this file, we're gonna lose hard.
2837 debug_process_finalization (struct Lisp_Process *p)
2840 Lisp_Object instr, outstr;
2842 get_process_streams (p, &instr, &outstr);
2843 /* if it still has fds, then it hasn't been killed yet. */
2844 assert (NILP(instr));
2845 assert (NILP(outstr));
2847 /* #### More checks here */
2852 /************************************************************************/
2853 /* initialization */
2854 /************************************************************************/
2857 vars_of_event_mswindows (void)
2859 mswindows_u_dispatch_event_queue = Qnil;
2860 staticpro (&mswindows_u_dispatch_event_queue);
2861 mswindows_u_dispatch_event_queue_tail = Qnil;
2863 mswindows_s_dispatch_event_queue = Qnil;
2864 staticpro (&mswindows_s_dispatch_event_queue);
2865 mswindows_s_dispatch_event_queue_tail = Qnil;
2867 mswindows_error_caught_in_modal_loop = Qnil;
2868 staticpro (&mswindows_error_caught_in_modal_loop);
2869 mswindows_in_modal_loop = 0;
2870 mswindows_pending_timers_count = 0;
2872 mswindows_event_stream = xnew (struct event_stream);
2874 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2875 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2876 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2877 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2878 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2879 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2880 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2881 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2882 #ifdef HAVE_MSG_SELECT
2883 mswindows_event_stream->select_process_cb =
2884 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2885 mswindows_event_stream->unselect_process_cb =
2886 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2887 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2888 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2890 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2891 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2892 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2893 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2896 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2897 *Controls redrawing frame contents during mouse-drag or keyboard resize
2898 operation. When non-nil, the frame is redrawn while being resized. When
2899 nil, frame is not redrawn, and exposed areas are filled with default
2900 MDI application background color. Note that this option only has effect
2901 if "Show window contents while dragging" is on in system Display/Plus!
2903 Default is t on fast machines, nil on slow.
2906 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2907 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2908 *Analogue of double click interval for faking middle mouse events.
2909 The value is the minimum time in milliseconds that must elapse between
2910 left/right button down events before they are considered distinct events.
2911 If both mouse buttons are depressed within this interval, a middle mouse
2912 button down event is generated instead.
2913 If negative or zero, currently set system default is used instead.
2916 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2917 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2918 Number of physical mouse buttons.
2921 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2922 *Maximum horizontal distance in pixels between points in which left and
2923 right button clicks occurred for them to be translated into single
2924 middle button event. Clicks must occur in time not longer than defined
2925 by the variable `mswindows-mouse-button-tolerance'.
2926 If negative or zero, currently set system default is used instead.
2929 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2930 *Maximum vertical distance in pixels between points in which left and
2931 right button clicks occurred for them to be translated into single
2932 middle button event. Clicks must occur in time not longer than defined
2933 by the variable `mswindows-mouse-button-tolerance'.
2934 If negative or zero, currently set system default is used instead.
2937 mswindows_mouse_button_max_skew_x = 0;
2938 mswindows_mouse_button_max_skew_y = 0;
2939 mswindows_mouse_button_tolerance = 0;
2943 syms_of_event_mswindows (void)
2948 lstream_type_create_mswindows_selectable (void)
2950 init_slurp_stream ();
2951 init_shove_stream ();
2952 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2953 init_winsock_stream ();
2958 init_event_mswindows_late (void)
2960 #ifdef HAVE_MSG_SELECT
2961 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2962 assert (windows_fd>=0);
2963 FD_SET (windows_fd, &input_wait_mask);
2964 FD_ZERO(&zero_mask);
2967 event_stream = mswindows_event_stream;
2969 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2970 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);