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;
75 #if defined (__CYGWIN32__) && !defined (CYGWIN_VERSION_DLL_MAJOR)
76 typedef NMHDR *LPNMHDR;
80 #define ADJR_MENUFLAG TRUE
82 #define ADJR_MENUFLAG FALSE
85 /* Fake key modifier which is attached to a quit char event.
86 Removed upon dequeueing an event */
87 #define FAKE_MOD_QUIT 0x80
89 /* Timer ID used for button2 emulation */
90 #define BUTTON_2_TIMER_ID 1
93 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
95 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
97 mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
99 static Lisp_Object mswindows_find_frame (HWND hwnd);
100 static Lisp_Object mswindows_find_console (HWND hwnd);
101 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
102 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
103 static void mswindows_set_chord_timer (HWND hwnd);
104 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
105 static int mswindows_current_layout_has_AltGr (void);
107 static struct event_stream *mswindows_event_stream;
109 #ifdef HAVE_MSG_SELECT
110 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
111 extern SELECT_TYPE process_only_mask, tty_only_mask;
112 SELECT_TYPE zero_mask;
113 extern int signal_event_pipe_initialized;
118 * Two separate queues, for efficiency, one (_u_) for user events, and
119 * another (_s_) for non-user ones. We always return events out of the
120 * first one until it is empty and only then proceed with the second
123 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
124 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
126 /* The number of things we can wait on */
127 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
129 #ifndef HAVE_MSG_SELECT
130 /* List of mswindows waitable handles. */
131 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
133 /* Number of wait handles */
134 static int mswindows_waitable_count=0;
135 #endif /* HAVE_MSG_SELECT */
136 /* Brush for painting widgets */
137 static HBRUSH widget_brush = 0;
138 static LONG last_widget_brushed = 0;
140 /* Count of quit chars currently in the queue */
141 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
142 Decremented in mswindows_dequeue_dispatch_event() */
143 int mswindows_quit_chars_count = 0;
145 /* These are Lisp integers; see DEFVARS in this file for description. */
146 int mswindows_dynamic_frame_resize;
147 int mswindows_num_mouse_buttons;
148 int mswindows_mouse_button_max_skew_x;
149 int mswindows_mouse_button_max_skew_y;
150 int mswindows_mouse_button_tolerance;
152 /* This is the event signaled by the event pump.
153 See mswindows_pump_outstanding_events for comments */
154 static Lisp_Object mswindows_error_caught_in_modal_loop;
155 static int mswindows_in_modal_loop;
157 /* Count of wound timers */
158 static int mswindows_pending_timers_count;
160 /************************************************************************/
161 /* Pipe instream - reads process output */
162 /************************************************************************/
164 #define PIPE_READ_DELAY 20
166 #define HANDLE_TO_USID(h) ((USID)(h))
168 #define NTPIPE_SLURP_STREAM_DATA(stream) \
169 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
171 /* This structure is allocated by the main thread, and is deallocated
172 in the thread upon exit. There are situations when a thread
173 remains blocked for a long time, much longer than the lstream
174 exists. For example, "start notepad" command is issued from the
175 shell, then the shell is closed by C-c C-d. Although the shell
176 process exits, its output pipe will not get closed until the
177 notepad process exits also, because it inherits the pipe form the
178 shell. In this case, we abandon the thread, and let it live until
179 all such processes exit. While struct ntpipe_slurp_stream is
180 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
182 struct ntpipe_slurp_stream_shared_data
184 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
185 /* This is a manual-reset object. */
186 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
187 /* This is a manual-reset object. */
188 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
189 /* This is a manual-reset object. */
190 HANDLE hpipe; /* Pipe read end handle. */
191 LONG die_p; /* Thread must exit ASAP if non-zero */
192 BOOL eof_p : 1; /* Set when thread saw EOF */
193 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
194 BOOL inuse_p : 1; /* this structure is in use */
195 LONG lock_count; /* Client count of this struct, 0=safe to free */
196 BYTE onebyte; /* One byte buffer read by thread */
199 #define MAX_SLURP_STREAMS 32
200 struct ntpipe_slurp_stream_shared_data
201 shared_data_block[MAX_SLURP_STREAMS]={{0}};
203 struct ntpipe_slurp_stream
205 LPARAM user_data; /* Any user data stored in the stream object */
206 struct ntpipe_slurp_stream_shared_data* thread_data;
209 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
210 sizeof (struct ntpipe_slurp_stream));
212 /* This function is thread-safe, and is called from either thread
213 context. It serializes freeing shared data structure */
215 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
217 if (InterlockedDecrement (&s->lock_count) == 0)
220 CloseHandle (s->hev_thread);
221 CloseHandle (s->hev_caller);
222 CloseHandle (s->hev_unsleep);
227 static struct ntpipe_slurp_stream_shared_data*
228 slurper_allocate_shared_data()
231 for (i=0; i<MAX_SLURP_STREAMS; i++)
233 if (!shared_data_block[i].inuse_p)
235 shared_data_block[i].inuse_p=1;
236 return &shared_data_block[i];
239 return (struct ntpipe_slurp_stream_shared_data*)0;
243 slurp_thread (LPVOID vparam)
245 struct ntpipe_slurp_stream_shared_data *s =
246 (struct ntpipe_slurp_stream_shared_data*)vparam;
250 /* Read one byte from the pipe */
252 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
254 DWORD err = GetLastError ();
255 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
260 else if (actually_read == 0)
263 /* We must terminate on an error or eof */
264 if (s->eof_p || s->error_p)
265 InterlockedIncrement (&s->die_p);
267 /* Before we notify caller, we unsignal our event. */
268 ResetEvent (s->hev_thread);
270 /* Now we got something to notify caller, either a byte or an
271 error/eof indication. Before we do, allow internal pipe
272 buffer to accumulate little bit more data.
273 Reader function pulses this event before waiting for
274 a character, to avoid pipe delay, and to get the byte
277 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
279 /* Either make event loop generate a process event, or
281 SetEvent (s->hev_caller);
283 /* Cleanup and exit if we're shot off */
287 /* Block until the client finishes with retrieving the rest of
289 WaitForSingleObject (s->hev_thread, INFINITE);
292 slurper_free_shared_data_maybe (s);
298 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
301 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
302 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
303 DWORD thread_id_unused;
306 /* We deal only with pipes, for we're using PeekNamedPipe api */
307 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
309 s->thread_data = slurper_allocate_shared_data();
311 /* Create reader thread. This could fail, so do not create events
312 until thread is created */
313 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
314 CREATE_SUSPENDED, &thread_id_unused);
317 Lstream_delete (lstr);
318 s->thread_data->inuse_p=0;
322 /* Shared data are initially owned by both main and slurper
324 s->thread_data->lock_count = 2;
325 s->thread_data->die_p = 0;
326 s->thread_data->eof_p = FALSE;
327 s->thread_data->error_p = FALSE;
328 s->thread_data->hpipe = hpipe;
329 s->user_data = param;
331 /* hev_thread is a manual-reset event, initially signaled */
332 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
333 /* hev_caller is a manual-reset event, initially nonsignaled */
334 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
335 /* hev_unsleep is a manual-reset event, initially nonsignaled */
336 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
339 ResumeThread (hthread);
340 CloseHandle (hthread);
342 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
343 XSETLSTREAM (obj, lstr);
348 get_ntpipe_input_stream_param (Lstream *stream)
350 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
355 get_ntpipe_input_stream_waitable (Lstream *stream)
357 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
358 return s->thread_data->hev_caller;
362 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
364 /* This function must be called from the main thread only */
365 struct ntpipe_slurp_stream_shared_data* s =
366 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
371 /* Disallow pipe read delay for the thread: we need a character
373 SetEvent (s->hev_unsleep);
375 /* Check if we have a character ready. Give it a short delay,
376 for the thread to awake from pipe delay, just ion case*/
377 wait_result = WaitForSingleObject (s->hev_caller, 2);
379 /* Revert to the normal sleep behavior. */
380 ResetEvent (s->hev_unsleep);
382 /* If there's no byte buffered yet, give up */
383 if (wait_result == WAIT_TIMEOUT)
390 /* Reset caller unlock event now, as we've handled the pending
391 process output event */
392 ResetEvent (s->hev_caller);
394 /* It is now safe to do anything with contents of S, except for
395 changing s->die_p, which still should be interlocked */
399 if (s->error_p || s->die_p)
402 /* Ok, there were no error neither eof - we've got a byte from the
404 *(data++) = s->onebyte;
408 DWORD bytes_read = 0;
411 DWORD bytes_available;
413 /* If the api call fails, return at least one byte already
414 read. ReadFile in thread will return error */
415 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
418 /* Fetch available bytes. The same consideration applies,
419 so do not check for errors. ReadFile in the thread will
420 fail if the next call fails. */
422 ReadFile (s->hpipe, data, min (bytes_available, size),
426 /* Now we can unblock thread, so it attempts to read more */
427 SetEvent (s->hev_thread);
428 return bytes_read + 1;
435 ntpipe_slurp_closer (Lstream *stream)
437 /* This function must be called from the main thread only */
438 struct ntpipe_slurp_stream_shared_data* s =
439 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
441 /* Force thread to stop */
442 InterlockedIncrement (&s->die_p);
444 /* Set events which could possibly block slurper. Let it finish soon
446 SetEvent (s->hev_unsleep);
447 SetEvent (s->hev_thread);
449 /* Unlock and maybe free shared data */
450 slurper_free_shared_data_maybe (s);
456 init_slurp_stream (void)
458 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
459 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
462 /************************************************************************/
463 /* Pipe outstream - writes process input */
464 /************************************************************************/
466 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
467 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
469 #define MAX_SHOVE_BUFFER_SIZE 128
471 struct ntpipe_shove_stream
473 LPARAM user_data; /* Any user data stored in the stream object */
474 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
475 /* This is an auto-reset object. */
476 HANDLE hpipe; /* Pipe write end handle. */
477 HANDLE hthread; /* Reader thread handle. */
478 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
479 DWORD size; /* Number of bytes to write */
480 LONG die_p; /* Thread must exit ASAP if non-zero */
481 LONG idle_p; /* Non-zero if thread is waiting for job */
482 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
483 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
486 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
487 sizeof (struct ntpipe_shove_stream));
489 #ifndef HAVE_MSG_SELECT
491 shove_thread (LPVOID vparam)
493 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
499 /* Block on event and wait for a job */
500 InterlockedIncrement (&s->idle_p);
501 WaitForSingleObject (s->hev_thread, INFINITE);
506 /* Write passed buffer */
507 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
508 || bytes_written != s->size)
511 InterlockedIncrement (&s->die_p);
522 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
525 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
526 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
527 DWORD thread_id_unused;
532 s->user_data = param;
534 /* Create reader thread. This could fail, so do not
535 create the event until thread is created */
536 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
537 CREATE_SUSPENDED, &thread_id_unused);
538 if (s->hthread == NULL)
540 Lstream_delete (lstr);
544 /* hev_thread is an auto-reset event, initially nonsignaled */
545 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
548 ResumeThread (s->hthread);
550 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
551 XSETLSTREAM (obj, lstr);
556 get_ntpipe_output_stream_param (Lstream *stream)
558 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
564 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
566 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
571 s->blocking_p = !s->idle_p;
575 if (size>MAX_SHOVE_BUFFER_SIZE)
578 memcpy (s->buffer, data, size);
582 InterlockedDecrement (&s->idle_p);
583 SetEvent (s->hev_thread);
588 ntpipe_shove_was_blocked_p (Lstream *stream)
590 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
591 return s->blocking_p;
595 ntpipe_shove_closer (Lstream *stream)
597 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
599 /* Force thread stop */
600 InterlockedIncrement (&s->die_p);
602 /* Close pipe handle, possibly breaking it */
603 CloseHandle (s->hpipe);
605 /* Thread will end upon unblocking */
606 SetEvent (s->hev_thread);
608 /* Wait while thread terminates */
609 WaitForSingleObject (s->hthread, INFINITE);
610 CloseHandle (s->hthread);
612 /* Destroy the event */
613 CloseHandle (s->hev_thread);
619 init_shove_stream (void)
621 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
622 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
623 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
626 /************************************************************************/
627 /* Winsock I/O stream */
628 /************************************************************************/
629 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
631 #define WINSOCK_READ_BUFFER_SIZE 1024
633 struct winsock_stream
635 LPARAM user_data; /* Any user data stored in the stream object */
636 SOCKET s; /* Socket handle (which is a Win32 handle) */
637 OVERLAPPED ov; /* Overlapped I/O structure */
638 void* buffer; /* Buffer. Allocated for input stream only */
639 unsigned int bufsize; /* Number of bytes last read */
640 unsigned int bufpos; /* Position in buffer for next fetch */
641 unsigned int error_p :1; /* I/O Error seen */
642 unsigned int eof_p :1; /* EOF Error seen */
643 unsigned int pending_p :1; /* There is a pending I/O operation */
644 unsigned int blocking_p :1; /* Last write attempt would block */
647 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
649 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
650 sizeof (struct winsock_stream));
653 winsock_initiate_read (struct winsock_stream *str)
655 ResetEvent (str->ov.hEvent);
658 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
659 &str->bufsize, &str->ov))
661 if (GetLastError () == ERROR_IO_PENDING)
663 else if (GetLastError () == ERROR_HANDLE_EOF)
668 else if (str->bufsize == 0)
673 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
675 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
677 /* If the current operation is not yet complete, there's nothing to
681 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
688 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
690 if (GetLastError() == ERROR_HANDLE_EOF)
695 if (str->bufsize == 0)
706 /* Return as much of buffer as we have */
707 size = min (size, (size_t) (str->bufsize - str->bufpos));
708 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
711 /* Read more if buffer is exhausted */
712 if (str->bufsize == str->bufpos)
713 winsock_initiate_read (str);
719 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
721 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
725 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
733 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
748 ResetEvent (str->ov.hEvent);
750 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
751 * an overlapped operation. This fails on Win95 with winsock 1.x so we
752 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
753 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
754 || GetLastError() == ERROR_IO_PENDING)
760 return str->error_p ? -1 : size;
764 winsock_closer (Lstream *lstr)
766 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
768 if (lstr->flags & LSTREAM_FL_READ)
769 shutdown (str->s, 0);
771 shutdown (str->s, 1);
773 CloseHandle ((HANDLE)str->s);
775 WaitForSingleObject (str->ov.hEvent, INFINITE);
777 if (lstr->flags & LSTREAM_FL_READ)
780 CloseHandle (str->ov.hEvent);
785 winsock_was_blocked_p (Lstream *stream)
787 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
788 return str->blocking_p;
792 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
795 Lstream *lstr = Lstream_new (lstream_winsock, mode);
796 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
803 str->user_data = param;
806 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
808 if (lstr->flags & LSTREAM_FL_READ)
810 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
811 winsock_initiate_read (str);
814 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
815 XSETLSTREAM (obj, lstr);
820 make_winsock_input_stream (SOCKET s, LPARAM param)
822 return make_winsock_stream_1 (s, param, "r");
826 make_winsock_output_stream (SOCKET s, LPARAM param)
828 return make_winsock_stream_1 (s, param, "w");
832 get_winsock_stream_waitable (Lstream *lstr)
834 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
835 return str->ov.hEvent;
839 get_winsock_stream_param (Lstream *lstr)
841 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
842 return str->user_data;
846 init_winsock_stream (void)
848 LSTREAM_HAS_METHOD (winsock, reader);
849 LSTREAM_HAS_METHOD (winsock, writer);
850 LSTREAM_HAS_METHOD (winsock, closer);
851 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
853 #endif /* defined (HAVE_SOCKETS) */
855 /************************************************************************/
856 /* Dispatch queue management */
857 /************************************************************************/
860 mswindows_user_event_p (struct Lisp_Event* sevt)
862 return (sevt->event_type == key_press_event
863 || sevt->event_type == button_press_event
864 || sevt->event_type == button_release_event
865 || sevt->event_type == misc_user_event);
869 * Add an emacs event to the proper dispatch queue
872 mswindows_enqueue_dispatch_event (Lisp_Object event)
874 int user_p = mswindows_user_event_p (XEVENT(event));
875 enqueue_event (event,
876 user_p ? &mswindows_u_dispatch_event_queue :
877 &mswindows_s_dispatch_event_queue,
878 user_p ? &mswindows_u_dispatch_event_queue_tail :
879 &mswindows_s_dispatch_event_queue_tail);
881 /* Avoid blocking on WaitMessage */
882 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
886 * Add a misc-user event to the dispatch queue.
888 * Stuff it into our own dispatch queue, so we have something
889 * to return from next_event callback.
892 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
895 Lisp_Object event = Fmake_event (Qnil, Qnil);
896 struct Lisp_Event* e = XEVENT (event);
898 e->event_type = misc_user_event;
899 e->channel = channel;
900 e->event.misc.function = function;
901 e->event.misc.object = object;
903 mswindows_enqueue_dispatch_event (event);
907 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
909 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
910 struct Lisp_Event* event = XEVENT (emacs_event);
912 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
913 event->timestamp = GetMessageTime();
914 event->event_type = magic_event;
915 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
917 mswindows_enqueue_dispatch_event (emacs_event);
921 mswindows_enqueue_process_event (struct Lisp_Process* p)
923 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
924 struct Lisp_Event* event = XEVENT (emacs_event);
926 XSETPROCESS (process, p);
928 event->event_type = process_event;
929 event->timestamp = GetTickCount ();
930 event->event.process.process = process;
932 mswindows_enqueue_dispatch_event (emacs_event);
936 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
939 /* We always use last message time, because mouse button
940 events may get delayed, and XEmacs double click
941 recognition will fail */
943 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
944 struct Lisp_Event* event = XEVENT(emacs_event);
946 event->channel = mswindows_find_frame(hwnd);
947 event->timestamp = when;
948 event->event.button.button =
949 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
950 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
951 event->event.button.x = where.x;
952 event->event.button.y = where.y;
953 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
955 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
956 message==WM_RBUTTONDOWN)
958 event->event_type = button_press_event;
960 /* we need this to make sure the main window regains the focus
961 from control subwindows */
962 if (GetFocus() != hwnd)
965 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
970 event->event_type = button_release_event;
974 mswindows_enqueue_dispatch_event (emacs_event);
978 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
980 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
981 struct Lisp_Event* event = XEVENT(emacs_event);
983 event->channel = mswindows_find_console(hwnd);
984 event->timestamp = GetMessageTime();
985 event->event_type = key_press_event;
986 event->event.key.keysym = keysym;
987 event->event.key.modifiers = mods;
988 mswindows_enqueue_dispatch_event (emacs_event);
992 * Remove and return the first emacs event on the dispatch queue.
993 * Give a preference to user events over non-user ones.
996 mswindows_dequeue_dispatch_event ()
999 struct Lisp_Event* sevt;
1001 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1002 !NILP(mswindows_s_dispatch_event_queue));
1004 event = dequeue_event (
1005 NILP(mswindows_u_dispatch_event_queue) ?
1006 &mswindows_s_dispatch_event_queue :
1007 &mswindows_u_dispatch_event_queue,
1008 NILP(mswindows_u_dispatch_event_queue) ?
1009 &mswindows_s_dispatch_event_queue_tail :
1010 &mswindows_u_dispatch_event_queue_tail);
1012 sevt = XEVENT(event);
1013 if (sevt->event_type == key_press_event
1014 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1016 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1017 --mswindows_quit_chars_count;
1024 * Remove and return the first emacs event on the dispatch queue that matches
1025 * the supplied event.
1026 * Timeout event matches if interval_id is equal to that of the given event.
1027 * Keypress event matches if logical AND between modifiers bitmask of the
1028 * event in the queue and that of the given event is non-zero.
1029 * For all other event types, this function aborts.
1033 mswindows_cancel_dispatch_event (struct Lisp_Event *match)
1036 Lisp_Object previous_event = Qnil;
1037 int user_p = mswindows_user_event_p (match);
1038 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1039 &mswindows_s_dispatch_event_queue;
1040 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1041 &mswindows_s_dispatch_event_queue_tail;
1043 assert (match->event_type == timeout_event
1044 || match->event_type == key_press_event);
1046 EVENT_CHAIN_LOOP (event, *head)
1048 struct Lisp_Event *e = XEVENT (event);
1049 if ((e->event_type == match->event_type) &&
1050 ((e->event_type == timeout_event) ?
1051 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1052 /* Must be key_press_event */
1053 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1055 if (NILP (previous_event))
1056 dequeue_event (head, tail);
1059 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1060 if (EQ (*tail, event))
1061 *tail = previous_event;
1066 previous_event = event;
1071 #ifndef HAVE_MSG_SELECT
1072 /************************************************************************/
1073 /* Waitable handles manipulation */
1074 /************************************************************************/
1076 find_waitable_handle (HANDLE h)
1079 for (i = 0; i < mswindows_waitable_count; ++i)
1080 if (mswindows_waitable_handles[i] == h)
1087 add_waitable_handle (HANDLE h)
1089 assert (find_waitable_handle (h) < 0);
1090 if (mswindows_waitable_count == MAX_WAITABLE)
1093 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1098 remove_waitable_handle (HANDLE h)
1100 int ix = find_waitable_handle (h);
1104 mswindows_waitable_handles [ix] =
1105 mswindows_waitable_handles [--mswindows_waitable_count];
1107 #endif /* HAVE_MSG_SELECT */
1110 /************************************************************************/
1112 /************************************************************************/
1115 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1116 Lisp_Object u_n_u_s_e_d)
1118 mswindows_error_caught_in_modal_loop = cons_sig_data;
1123 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1128 ++mswindows_in_modal_loop;
1129 tmp = condition_case_1 (Qt,
1131 mswindows_modal_loop_error_handler, Qnil);
1132 --mswindows_in_modal_loop;
1138 mswindows_unmodalize_signal_maybe (void)
1140 if (!NILP (mswindows_error_caught_in_modal_loop))
1142 /* Got an error while messages were pumped while
1143 in window procedure - have to resignal */
1144 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1145 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1146 mswindows_error_caught_in_modal_loop = Qnil;
1147 Fsignal (sym, data);
1152 * This is an unsafe part of event pump, guarded by
1153 * condition_case. See mswindows_pump_outstanding_events
1156 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1158 /* This function can call lisp */
1159 Lisp_Object event = Fmake_event (Qnil, Qnil);
1160 struct gcpro gcpro1;
1161 int do_redisplay = 0;
1164 while (detect_input_pending ())
1166 Fnext_event (event, Qnil);
1167 Fdispatch_event (event);
1174 Fdeallocate_event (event);
1177 /* Qt becomes return value of mswindows_pump_outstanding_events
1183 * This function pumps emacs events, while available, by using
1184 * next_message/dispatch_message loop. Errors are trapped around
1185 * the loop so the function always returns.
1187 * Windows message queue is not looked into during the call,
1188 * neither are waitable handles checked. The function pumps
1189 * thus only dispatch events already queued, as well as those
1190 * resulted in dispatching thereof. This is done by setting
1191 * module local variable mswindows_in_modal_loop to nonzero.
1193 * Return value is Qt if no errors was trapped, or Qunbound if
1194 * there was an error.
1196 * In case of error, a cons representing the error, in the
1197 * form (SIGNAL . DATA), is stored in the module local variable
1198 * mswindows_error_caught_in_modal_loop. This error is signaled
1199 * again when DispatchMessage returns. Thus, Windows internal
1200 * modal loops are protected against throws, which are proven
1201 * to corrupt internal Windows structures.
1203 * In case of success, mswindows_error_caught_in_modal_loop is
1206 * If the value of mswindows_error_caught_in_modal_loop is not
1207 * nil already upon entry, the function just returns non-nil.
1208 * This situation means that a new event has been queued while
1209 * in cancel mode. The event will be dequeued on the next regular
1210 * call of next-event; the pump is off since error is caught.
1211 * The caller must *unconditionally* cancel modal loop if the
1212 * value returned by this function is nil. Otherwise, everything
1213 * will become frozen until the modal loop exits under normal
1214 * condition (scrollbar drag is released, menu closed etc.)
1217 mswindows_pump_outstanding_events (void)
1219 /* This function can call lisp */
1221 Lisp_Object result = Qt;
1222 struct gcpro gcpro1;
1225 if (NILP(mswindows_error_caught_in_modal_loop))
1226 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1232 mswindows_drain_windows_queue ()
1235 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1237 /* we have to translate messages that are not sent to the main
1238 window. this is so that key presses work ok in things like
1239 edit fields. however, we *musn't* translate message for the
1240 main window as this is handled in the wnd proc. */
1241 if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
1243 TranslateMessage (&msg);
1245 DispatchMessage (&msg);
1246 mswindows_unmodalize_signal_maybe ();
1251 * This is a special flavor of the mswindows_need_event function,
1252 * used while in event pump. Actually, there is only kind of events
1253 * allowed while in event pump: a timer. An attempt to fetch any
1254 * other event leads to a deadlock, as there's no source of user input
1255 * ('cause event pump mirrors windows modal loop, which is a sole
1256 * owner of thread message queue).
1258 * To detect this, we use a counter of active timers, and allow
1259 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1260 * which will never come when there are no pending timers, which leads
1261 * to deadlock, we simply signal an error.
1264 mswindows_need_event_in_modal_loop (int badly_p)
1268 /* Check if already have one */
1269 if (!NILP (mswindows_u_dispatch_event_queue)
1270 || !NILP (mswindows_s_dispatch_event_queue))
1273 /* No event is ok */
1277 /* We do not check the _u_ queue, because timers go to _s_ */
1278 while (NILP (mswindows_s_dispatch_event_queue))
1280 /* We'll deadlock if go waiting */
1281 if (mswindows_pending_timers_count == 0)
1282 error ("Deadlock due to an attempt to call next-event in a wrong context");
1284 /* Fetch and dispatch any pending timers */
1285 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1286 DispatchMessage (&msg);
1291 * This drains the event queue and fills up two internal queues until
1292 * an event of a type specified by USER_P is retrieved.
1295 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1298 mswindows_need_event (int badly_p)
1302 if (mswindows_in_modal_loop)
1304 mswindows_need_event_in_modal_loop (badly_p);
1308 /* Have to drain Windows message queue first, otherwise, we may miss
1309 quit char when called from quit_p */
1310 mswindows_drain_windows_queue ();
1312 while (NILP (mswindows_u_dispatch_event_queue)
1313 && NILP (mswindows_s_dispatch_event_queue))
1315 #ifdef HAVE_MSG_SELECT
1317 SELECT_TYPE temp_mask = input_wait_mask;
1318 EMACS_TIME sometime;
1319 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1322 pointer_to_this = 0;
1325 EMACS_SET_SECS_USECS (sometime, 0, 0);
1326 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1327 pointer_to_this = &select_time_to_block;
1330 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1335 return; /* timeout */
1337 else if (active > 0)
1339 if (FD_ISSET (windows_fd, &temp_mask))
1341 mswindows_drain_windows_queue ();
1344 /* Look for a TTY event */
1345 for (i = 0; i < MAXDESC-1; i++)
1347 /* To avoid race conditions (among other things, an infinite
1348 loop when called from Fdiscard_input()), we must return
1349 user events ahead of process events. */
1350 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1352 struct console *c = tty_find_console_from_fd (i);
1353 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1354 struct Lisp_Event* event = XEVENT (emacs_event);
1357 if (read_event_from_tty_or_stream_desc (event, c, i))
1359 mswindows_enqueue_dispatch_event (emacs_event);
1365 /* Look for a process event */
1366 for (i = 0; i < MAXDESC-1; i++)
1368 if (FD_ISSET (i, &temp_mask))
1370 if (FD_ISSET (i, &process_only_mask))
1372 struct Lisp_Process *p =
1373 get_process_from_usid (FD_TO_USID(i));
1375 mswindows_enqueue_process_event (p);
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()) };
1678 msg.message = message;
1679 msg.wParam = wParam;
1680 msg.lParam = lParam;
1681 msg.time = GetMessageTime();
1684 /* GetKeyboardState() does not work as documented on Win95. We have
1685 * to loosely track Left and Right modifiers on behalf of the OS,
1686 * without screwing up Windows NT which tracks them properly. */
1687 if (wParam == VK_CONTROL)
1688 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1689 else if (wParam == VK_MENU)
1690 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1692 memcpy (keymap_orig, keymap, 256);
1694 /* Remove shift modifier from an ascii character */
1697 /* Clear control and alt modifiers unless AltGr is pressed */
1698 keymap [VK_RCONTROL] = 0;
1699 keymap [VK_LMENU] = 0;
1700 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1702 keymap [VK_LCONTROL] = 0;
1703 keymap [VK_CONTROL] = 0;
1704 keymap [VK_RMENU] = 0;
1705 keymap [VK_MENU] = 0;
1707 SetKeyboardState (keymap);
1709 /* Maybe generate some WM_[SYS]CHARs in the queue */
1710 TranslateMessage (&msg);
1712 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1713 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1716 WPARAM ch = msg.wParam;
1718 /* If a quit char with no modifiers other than control and
1719 shift, then mark it with a fake modifier, which is removed
1720 upon dequeueing the event */
1721 /* #### This might also not withstand localization, if
1722 quit character is not a latin-1 symbol */
1723 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1724 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1725 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1727 mods1 |= FAKE_MOD_QUIT;
1728 ++mswindows_quit_chars_count;
1731 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1733 SetKeyboardState (keymap_orig);
1736 /* F10 causes menu activation by default. We do not want this */
1737 if (wParam != VK_F10)
1741 case WM_MBUTTONDOWN:
1743 /* Real middle mouse button has nothing to do with emulated one:
1744 if one wants to exercise fingers playing chords on the mouse,
1745 he is allowed to do that! */
1746 mswindows_enqueue_mouse_button_event (hwnd, message,
1747 MAKEPOINTS (lParam), GetMessageTime());
1751 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1752 msframe->last_click_time = GetMessageTime();
1754 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1755 msframe->button2_need_lbutton = 0;
1756 if (msframe->ignore_next_lbutton_up)
1758 msframe->ignore_next_lbutton_up = 0;
1760 else if (msframe->button2_is_down)
1762 msframe->button2_is_down = 0;
1763 msframe->ignore_next_rbutton_up = 1;
1764 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1765 MAKEPOINTS (lParam), GetMessageTime());
1769 if (msframe->button2_need_rbutton)
1771 msframe->button2_need_rbutton = 0;
1772 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1773 MAKEPOINTS (lParam), GetMessageTime());
1775 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1776 MAKEPOINTS (lParam), GetMessageTime());
1781 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1782 msframe->last_click_time = GetMessageTime();
1784 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1785 msframe->button2_need_rbutton = 0;
1786 if (msframe->ignore_next_rbutton_up)
1788 msframe->ignore_next_rbutton_up = 0;
1790 else if (msframe->button2_is_down)
1792 msframe->button2_is_down = 0;
1793 msframe->ignore_next_lbutton_up = 1;
1794 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1795 MAKEPOINTS (lParam), GetMessageTime());
1799 if (msframe->button2_need_lbutton)
1801 msframe->button2_need_lbutton = 0;
1802 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1803 MAKEPOINTS (lParam), GetMessageTime());
1805 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1806 MAKEPOINTS (lParam), GetMessageTime());
1810 case WM_LBUTTONDOWN:
1811 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1813 if (msframe->button2_need_lbutton)
1815 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1816 msframe->button2_need_lbutton = 0;
1817 msframe->button2_need_rbutton = 0;
1818 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1820 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1821 MAKEPOINTS (lParam), GetMessageTime());
1822 msframe->button2_is_down = 1;
1826 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1827 msframe->last_click_point, msframe->last_click_time);
1828 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1829 MAKEPOINTS (lParam), GetMessageTime());
1834 mswindows_set_chord_timer (hwnd);
1835 msframe->button2_need_rbutton = 1;
1836 msframe->last_click_point = MAKEPOINTS (lParam);
1838 msframe->last_click_time = GetMessageTime();
1841 case WM_RBUTTONDOWN:
1842 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1844 if (msframe->button2_need_rbutton)
1846 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1847 msframe->button2_need_lbutton = 0;
1848 msframe->button2_need_rbutton = 0;
1849 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1851 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1852 MAKEPOINTS (lParam), GetMessageTime());
1853 msframe->button2_is_down = 1;
1857 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1858 msframe->last_click_point, msframe->last_click_time);
1859 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1860 MAKEPOINTS (lParam), GetMessageTime());
1865 mswindows_set_chord_timer (hwnd);
1866 msframe->button2_need_lbutton = 1;
1867 msframe->last_click_point = MAKEPOINTS (lParam);
1869 msframe->last_click_time = GetMessageTime();
1873 if (wParam == BUTTON_2_TIMER_ID)
1875 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1876 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1878 if (msframe->button2_need_lbutton)
1880 msframe->button2_need_lbutton = 0;
1881 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1882 msframe->last_click_point, msframe->last_click_time);
1884 else if (msframe->button2_need_rbutton)
1886 msframe->button2_need_rbutton = 0;
1887 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1888 msframe->last_click_point, msframe->last_click_time);
1892 assert ("Spurious timer fired" == 0);
1896 /* Optimization: don't report mouse movement while size is changing */
1897 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1898 if (!msframe->sizing)
1900 /* When waiting for the second mouse button to finish
1901 button2 emulation, and have moved too far, just pretend
1902 as if timer has expired. This improves drag-select feedback */
1903 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1904 && !mswindows_button2_near_enough (msframe->last_click_point,
1905 MAKEPOINTS (lParam)))
1907 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1908 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1911 emacs_event = Fmake_event (Qnil, Qnil);
1912 event = XEVENT(emacs_event);
1914 event->channel = mswindows_find_frame(hwnd);
1915 event->timestamp = GetMessageTime();
1916 event->event_type = pointer_motion_event;
1917 event->event.motion.x = MAKEPOINTS(lParam).x;
1918 event->event.motion.y = MAKEPOINTS(lParam).y;
1919 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1921 mswindows_enqueue_dispatch_event (emacs_event);
1927 /* Queue a `cancel-mode-internal' misc user event, so mouse
1928 selection would be canceled if any */
1929 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1930 Qcancel_mode_internal, Qnil);
1935 LPNMHDR nmhdr = (LPNMHDR)lParam;
1937 if (nmhdr->code == TTN_NEEDTEXT)
1939 #ifdef HAVE_TOOLBARS
1940 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1943 /* find out which toolbar */
1944 frame = XFRAME (mswindows_find_frame (hwnd));
1945 btext = mswindows_get_toolbar_button_text ( frame,
1948 tttext->lpszText = NULL;
1949 tttext->hinst = NULL;
1953 /* I think this is safe since the text will only go away
1954 when the toolbar does...*/
1955 GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS,
1960 /* handle tree view callbacks */
1961 else if (nmhdr->code == TVN_SELCHANGED)
1963 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
1964 frame = XFRAME (mswindows_find_frame (hwnd));
1965 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
1967 /* handle tab control callbacks */
1968 else if (nmhdr->code == TCN_SELCHANGE)
1971 int index = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
1972 frame = XFRAME (mswindows_find_frame (hwnd));
1974 item.mask = TCIF_PARAM;
1975 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index,
1978 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
1985 PAINTSTRUCT paintStruct;
1987 frame = XFRAME (mswindows_find_frame (hwnd));
1989 BeginPaint (hwnd, &paintStruct);
1990 mswindows_redraw_exposed_area (frame,
1991 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1992 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1993 EndPaint (hwnd, &paintStruct);
1998 /* We only care about this message if our size has really changed */
1999 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2004 fobj = mswindows_find_frame (hwnd);
2005 frame = XFRAME (fobj);
2006 msframe = FRAME_MSWINDOWS_DATA (frame);
2008 /* We cannot handle frame map and unmap hooks right in
2009 this routine, because these may throw. We queue
2010 magic events to run these hooks instead - kkm */
2012 if (wParam==SIZE_MINIMIZED)
2015 FRAME_VISIBLE_P (frame) = 0;
2016 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2020 GetClientRect(hwnd, &rect);
2021 FRAME_PIXWIDTH(frame) = rect.right;
2022 FRAME_PIXHEIGHT(frame) = rect.bottom;
2024 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2025 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2026 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2028 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2029 change_frame_size (frame, rows, columns, 1);
2031 /* If we are inside frame creation, we have to apply geometric
2033 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2035 /* Yes, we have to size again */
2036 mswindows_size_frame_internal ( frame,
2037 FRAME_MSWINDOWS_TARGET_RECT
2039 /* Reset so we do not get here again. The SetWindowPos call in
2040 * mswindows_size_frame_internal can cause recursion here. */
2041 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2043 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2044 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2049 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2050 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2051 FRAME_VISIBLE_P (frame) = 1;
2053 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2060 /* Misc magic events which only require that the frame be identified */
2063 mswindows_enqueue_magic_event (hwnd, message);
2066 case WM_WINDOWPOSCHANGING:
2068 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2069 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2070 GetWindowPlacement(hwnd, &wpl);
2072 /* Only interested if size is changing and we're not being iconified */
2073 if (wpl.showCmd != SW_SHOWMINIMIZED
2074 && wpl.showCmd != SW_SHOWMAXIMIZED
2075 && !(wp->flags & SWP_NOSIZE))
2077 RECT ncsize = { 0, 0, 0, 0 };
2078 int pixwidth, pixheight;
2079 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2080 GetMenu(hwnd) != NULL,
2081 GetWindowLong (hwnd, GWL_EXSTYLE));
2083 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2084 wp->cx - (ncsize.right - ncsize.left),
2085 wp->cy - (ncsize.bottom - ncsize.top),
2086 &pixwidth, &pixheight);
2088 /* Convert client sizes to window sizes */
2089 pixwidth += (ncsize.right - ncsize.left);
2090 pixheight += (ncsize.bottom - ncsize.top);
2092 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2094 /* Adjust so that the bottom or right doesn't move if it's
2095 * the top or left that's being changed */
2097 GetWindowRect (hwnd, &rect);
2099 if (rect.left != wp->x)
2100 wp->x += wp->cx - pixwidth;
2101 if (rect.top != wp->y)
2102 wp->y += wp->cy - pixheight;
2108 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2109 window position if the user tries to track window too small */
2113 case WM_ENTERSIZEMOVE:
2114 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2115 msframe->sizing = 1;
2118 case WM_EXITSIZEMOVE:
2119 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2120 msframe->sizing = 0;
2121 /* Queue noop event */
2122 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2125 #ifdef HAVE_SCROLLBARS
2129 /* Direction of scroll is determined by scrollbar instance. */
2130 int code = (int) LOWORD(wParam);
2131 int pos = (short int) HIWORD(wParam);
2132 HWND hwndScrollBar = (HWND) lParam;
2133 struct gcpro gcpro1, gcpro2;
2135 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2136 GCPRO2 (emacs_event, fobj);
2137 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2139 /* Error during event pumping - cancel scroll */
2140 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2147 #ifdef HAVE_MENUBARS
2149 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2151 XFRAME (mswindows_find_frame (hwnd)))))
2152 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2155 case WM_INITMENUPOPUP:
2156 if (!HIWORD(lParam))
2158 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2160 XFRAME (mswindows_find_frame (hwnd)))))
2161 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2165 #endif /* HAVE_MENUBARS */
2169 WORD id = LOWORD (wParam);
2170 WORD nid = HIWORD (wParam);
2171 HWND cid = (HWND)lParam;
2172 frame = XFRAME (mswindows_find_frame (hwnd));
2174 #ifdef HAVE_TOOLBARS
2175 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2178 /* widgets in a buffer only eval a callback for suitable events.*/
2183 case CBN_EDITCHANGE:
2185 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2188 /* menubars always must come last since the hashtables do not
2190 #ifdef HAVE_MENUBARS
2191 if (!NILP (mswindows_handle_wm_command (frame, id)))
2195 return DefWindowProc (hwnd, message, wParam, lParam);
2196 /* Bite me - a spurious command. This used to not be able to
2197 happen but with the introduction of widgets its now
2202 case WM_CTLCOLORBTN:
2203 case WM_CTLCOLORLISTBOX:
2204 case WM_CTLCOLOREDIT:
2205 case WM_CTLCOLORSTATIC:
2206 case WM_CTLCOLORSCROLLBAR:
2208 /* if we get an opportunity to paint a widget then do so if
2209 there is an appropriate face */
2210 HWND crtlwnd = (HWND)lParam;
2211 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2214 Lisp_Object image_instance;
2215 VOID_TO_LISP (image_instance, ii);
2216 if (IMAGE_INSTANCEP (image_instance)
2218 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
2220 !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
2222 /* set colors for the buttons */
2223 HDC hdc = (HDC)wParam;
2224 if (last_widget_brushed != ii)
2227 DeleteObject (widget_brush);
2228 widget_brush = CreateSolidBrush
2229 (COLOR_INSTANCE_MSWINDOWS_COLOR
2232 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2233 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2235 last_widget_brushed = ii;
2238 COLOR_INSTANCE_MSWINDOWS_COLOR
2241 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2242 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2243 SetBkMode (hdc, OPAQUE);
2246 COLOR_INSTANCE_MSWINDOWS_COLOR
2249 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2250 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2251 return (LRESULT)widget_brush;
2257 #ifdef HAVE_DRAGNDROP
2258 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2260 UINT filecount, i, len;
2266 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2267 struct gcpro gcpro1, gcpro2, gcpro3;
2269 emacs_event = Fmake_event (Qnil, Qnil);
2270 event = XEVENT(emacs_event);
2272 GCPRO3 (emacs_event, l_dndlist, l_item);
2274 if (!DragQueryPoint ((HANDLE) wParam, &point))
2275 point.x = point.y = -1; /* outside client area */
2277 event->event_type = misc_user_event;
2278 event->channel = mswindows_find_frame(hwnd);
2279 event->timestamp = GetMessageTime();
2280 event->event.misc.button = 1; /* #### Should try harder */
2281 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2282 event->event.misc.x = point.x;
2283 event->event.misc.y = point.y;
2284 event->event.misc.function = Qdragdrop_drop_dispatch;
2286 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2287 for (i=0; i<filecount; i++)
2289 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2290 /* The URLs that we make here aren't correct according to section
2291 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2292 * because they may contain reserved characters. But that's OK. */
2294 fname = (char *)xmalloc (len+1);
2295 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2296 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2297 strcpy (filename, "file:");
2298 cygwin32_win32_to_posix_path_list (fname, filename+5);
2301 filename = (char *)xmalloc (len+6);
2302 strcpy (filename, "file:");
2303 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2304 dostounix_filename (filename+5);
2306 l_item = make_string (filename, strlen (filename));
2307 l_dndlist = Fcons (l_item, l_dndlist);
2310 DragFinish ((HANDLE) wParam);
2312 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2313 mswindows_enqueue_dispatch_event (emacs_event);
2321 return DefWindowProc (hwnd, message, wParam, lParam);
2327 /************************************************************************/
2328 /* keyboard, mouse & other helpers for the windows procedure */
2329 /************************************************************************/
2331 mswindows_set_chord_timer (HWND hwnd)
2335 /* We get one third half system double click threshold */
2336 if (mswindows_mouse_button_tolerance <= 0)
2337 interval = GetDoubleClickTime () / 3;
2339 interval = mswindows_mouse_button_tolerance;
2341 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2345 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2348 if (mswindows_mouse_button_max_skew_x <= 0)
2349 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2351 dx = mswindows_mouse_button_max_skew_x;
2353 if (mswindows_mouse_button_max_skew_y <= 0)
2354 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2356 dy = mswindows_mouse_button_max_skew_y;
2358 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2362 mswindows_current_layout_has_AltGr (void)
2364 /* This simple caching mechanism saves 10% of CPU
2365 time when a key typed at autorepeat rate of 30 cps! */
2366 static HKL last_hkl = 0;
2367 static int last_hkl_has_AltGr;
2369 HKL current_hkl = GetKeyboardLayout (0);
2370 if (current_hkl != last_hkl)
2373 last_hkl_has_AltGr = 0;
2374 /* In this loop, we query whether a character requires
2375 AltGr to be down to generate it. If at least such one
2376 found, this means that the layout does regard AltGr */
2377 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2378 if (HIBYTE (VkKeyScan (c)) == 6)
2379 last_hkl_has_AltGr = 1;
2380 last_hkl = current_hkl;
2382 return last_hkl_has_AltGr;
2386 /* Returns the state of the modifier keys in the format expected by the
2387 * Lisp_Event key_data, button_data and motion_data modifiers member */
2388 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2394 keymap = (BYTE*) alloca(256);
2395 GetKeyboardState (keymap);
2396 has_AltGr = mswindows_current_layout_has_AltGr ();
2399 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2401 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2402 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2406 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2407 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2410 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2416 * Translate a mswindows virtual key to a keysym.
2417 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2418 * or whose ASCII codes (like space) xemacs doesn't like.
2419 * Virtual key values are defined in winresrc.h
2420 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2422 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2424 switch (mswindows_key)
2426 /* First the predefined ones */
2427 case VK_BACK: return QKbackspace;
2428 case VK_TAB: return QKtab;
2429 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2430 case VK_RETURN: return QKreturn;
2431 case VK_ESCAPE: return QKescape;
2432 case VK_SPACE: return QKspace;
2433 case VK_DELETE: return QKdelete;
2436 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2437 case VK_PRIOR: return KEYSYM ("prior");
2438 case VK_NEXT: return KEYSYM ("next");
2439 case VK_END: return KEYSYM ("end");
2440 case VK_HOME: return KEYSYM ("home");
2441 case VK_LEFT: return KEYSYM ("left");
2442 case VK_UP: return KEYSYM ("up");
2443 case VK_RIGHT: return KEYSYM ("right");
2444 case VK_DOWN: return KEYSYM ("down");
2445 case VK_SELECT: return KEYSYM ("select");
2446 case VK_PRINT: return KEYSYM ("print");
2447 case VK_EXECUTE: return KEYSYM ("execute");
2448 case VK_SNAPSHOT: return KEYSYM ("print");
2449 case VK_INSERT: return KEYSYM ("insert");
2450 case VK_HELP: return KEYSYM ("help");
2451 #if 0 /* XXX What are these supposed to do? */
2452 case VK_LWIN return KEYSYM ("");
2453 case VK_RWIN return KEYSYM ("");
2455 case VK_APPS: return KEYSYM ("menu");
2456 case VK_F1: return KEYSYM ("f1");
2457 case VK_F2: return KEYSYM ("f2");
2458 case VK_F3: return KEYSYM ("f3");
2459 case VK_F4: return KEYSYM ("f4");
2460 case VK_F5: return KEYSYM ("f5");
2461 case VK_F6: return KEYSYM ("f6");
2462 case VK_F7: return KEYSYM ("f7");
2463 case VK_F8: return KEYSYM ("f8");
2464 case VK_F9: return KEYSYM ("f9");
2465 case VK_F10: return KEYSYM ("f10");
2466 case VK_F11: return KEYSYM ("f11");
2467 case VK_F12: return KEYSYM ("f12");
2468 case VK_F13: return KEYSYM ("f13");
2469 case VK_F14: return KEYSYM ("f14");
2470 case VK_F15: return KEYSYM ("f15");
2471 case VK_F16: return KEYSYM ("f16");
2472 case VK_F17: return KEYSYM ("f17");
2473 case VK_F18: return KEYSYM ("f18");
2474 case VK_F19: return KEYSYM ("f19");
2475 case VK_F20: return KEYSYM ("f20");
2476 case VK_F21: return KEYSYM ("f21");
2477 case VK_F22: return KEYSYM ("f22");
2478 case VK_F23: return KEYSYM ("f23");
2479 case VK_F24: return KEYSYM ("f24");
2485 * Find the console that matches the supplied mswindows window handle
2488 mswindows_find_console (HWND hwnd)
2490 /* We only support one console */
2491 return XCAR (Vconsole_list);
2495 * Find the frame that matches the supplied mswindows window handle
2498 mswindows_find_frame (HWND hwnd)
2500 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2504 /* We are in progress of frame creation. Return the frame
2505 being created, as it still not remembered in the window
2507 assert (!NILP (Vmswindows_frame_being_created));
2508 return Vmswindows_frame_being_created;
2510 VOID_TO_LISP (f, l);
2515 /************************************************************************/
2517 /************************************************************************/
2520 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2523 EMACS_TIME current_time;
2524 EMACS_GET_TIME (current_time);
2525 EMACS_SUB_TIME (thyme, thyme, current_time);
2526 milliseconds = EMACS_SECS (thyme) * 1000 +
2527 (EMACS_USECS (thyme) + 500) / 1000;
2528 if (milliseconds < 1)
2530 ++mswindows_pending_timers_count;
2531 return SetTimer (NULL, 0, milliseconds,
2532 (TIMERPROC) mswindows_wm_timer_callback);
2536 emacs_mswindows_remove_timeout (int id)
2538 struct Lisp_Event match_against;
2539 Lisp_Object emacs_event;
2541 if (KillTimer (NULL, id))
2542 --mswindows_pending_timers_count;
2544 /* If there is a dispatch event generated by this
2545 timeout in the queue, we have to remove it too. */
2546 match_against.event_type = timeout_event;
2547 match_against.event.timeout.interval_id = id;
2548 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2549 if (!NILP (emacs_event))
2550 Fdeallocate_event(emacs_event);
2553 /* If `user_p' is false, then return whether there are any win32, timeout,
2554 * or subprocess events pending (that is, whether
2555 * emacs_mswindows_next_event() would return immediately without blocking).
2557 * if `user_p' is true, then return whether there are any *user generated*
2558 * events available (that is, whether there are keyboard or mouse-click
2559 * events ready to be read). This also implies that
2560 * emacs_mswindows_next_event() would not block.
2563 emacs_mswindows_event_pending_p (int user_p)
2565 mswindows_need_event (0);
2566 return (!NILP (mswindows_u_dispatch_event_queue)
2567 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2571 * Return the next event
2574 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2576 Lisp_Object event, event2;
2578 mswindows_need_event (1);
2580 event = mswindows_dequeue_dispatch_event ();
2581 XSETEVENT (event2, emacs_event);
2582 Fcopy_event (event, event2);
2583 Fdeallocate_event (event);
2587 * Handle a magic event off the dispatch queue.
2590 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2592 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2600 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2601 struct frame *f = XFRAME (frame);
2602 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2605 /* struct gcpro gcpro1; */
2607 /* Clear sticky modifiers here (if we had any) */
2609 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2610 /* GCPRO1 (conser); XXX Not necessary? */
2611 emacs_handle_focus_change_preliminary (conser);
2612 /* Under X the stuff up to here is done in the X event handler.
2614 emacs_handle_focus_change_final (conser);
2623 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2624 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2626 Qmap_frame_hook : Qunmap_frame_hook,
2631 /* #### What about Enter & Leave */
2633 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2634 Qmouse_leave_frame_hook, 1, frame);
2642 #ifndef HAVE_MSG_SELECT
2644 get_process_input_waitable (struct Lisp_Process *process)
2646 Lisp_Object instr, outstr, p;
2647 XSETPROCESS (p, process);
2648 get_process_streams (process, &instr, &outstr);
2649 assert (!NILP (instr));
2650 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2651 return (network_connection_p (p)
2652 ? get_winsock_stream_waitable (XLSTREAM (instr))
2653 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2655 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2660 emacs_mswindows_select_process (struct Lisp_Process *process)
2662 HANDLE hev = get_process_input_waitable (process);
2664 if (!add_waitable_handle (hev))
2665 error ("Too many active processes");
2667 #ifdef HAVE_WIN32_PROCESSES
2670 XSETPROCESS (p, process);
2671 if (!network_connection_p (p))
2673 HANDLE hprocess = get_nt_process_handle (process);
2674 if (!add_waitable_handle (hprocess))
2676 remove_waitable_handle (hev);
2677 error ("Too many active processes");
2685 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2687 /* Process handle is removed in the event loop as soon
2688 as it is signaled, so don't bother here about it */
2689 HANDLE hev = get_process_input_waitable (process);
2690 remove_waitable_handle (hev);
2692 #endif /* HAVE_MSG_SELECT */
2695 emacs_mswindows_select_console (struct console *con)
2697 #ifdef HAVE_MSG_SELECT
2698 if (CONSOLE_MSWINDOWS_P (con))
2699 return; /* mswindows consoles are automatically selected */
2701 event_stream_unixoid_select_console (con);
2706 emacs_mswindows_unselect_console (struct console *con)
2708 #ifdef HAVE_MSG_SELECT
2709 if (CONSOLE_MSWINDOWS_P (con))
2710 return; /* mswindows consoles are automatically selected */
2712 event_stream_unixoid_unselect_console (con);
2717 emacs_mswindows_quit_p (void)
2721 /* Quit cannot happen in modal loop: all program
2722 input is dedicated to Windows. */
2723 if (mswindows_in_modal_loop)
2726 /* Drain windows queue. This sets up number of quit characters in the queue
2727 * (and also processes wm focus change, move, resize, etc messages).
2728 * We don't want to process WM_PAINT messages because this function can be
2729 * called from almost anywhere and the windows' states may be changing. */
2730 while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
2731 PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
2732 DispatchMessage (&msg);
2734 if (mswindows_quit_chars_count > 0)
2736 /* Yes there's a hidden one... Throw it away */
2737 struct Lisp_Event match_against;
2738 Lisp_Object emacs_event;
2740 match_against.event_type = key_press_event;
2741 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2743 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2744 assert (!NILP (emacs_event));
2746 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2749 Fdeallocate_event(emacs_event);
2750 --mswindows_quit_chars_count;
2755 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2756 Lisp_Object* instream,
2757 Lisp_Object* outstream,
2760 /* Handles for streams */
2762 /* fds. These just stored along with the streams, and are closed in
2763 delete stream pair method, because we need to handle fake unices
2767 /* Decode inhandle and outhandle. Their meaning depends on
2768 the process implementation being used. */
2769 #if defined (HAVE_WIN32_PROCESSES)
2770 /* We're passed in Windows handles. That's what we like most... */
2771 hin = (HANDLE) inhandle;
2772 hout = (HANDLE) outhandle;
2774 #elif defined (HAVE_UNIX_PROCESSES)
2775 /* We are passed UNIX fds. This must be Cygwin.
2777 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2778 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2782 #error "So, WHICH kind of processes do you want?"
2785 *instream = (hin == INVALID_HANDLE_VALUE
2787 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2788 : flags & STREAM_NETWORK_CONNECTION
2789 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2791 : make_ntpipe_input_stream (hin, fdi));
2793 #ifdef HAVE_WIN32_PROCESSES
2794 *outstream = (hout == INVALID_HANDLE_VALUE
2796 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2797 : flags & STREAM_NETWORK_CONNECTION
2798 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2800 : make_ntpipe_output_stream (hout, fdo));
2801 #elif defined (HAVE_UNIX_PROCESSES)
2802 *outstream = (fdo >= 0
2803 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2806 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2807 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2808 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2810 Bufbyte eof_char = get_eof_char (fdo);
2811 int pty_max_bytes = get_pty_max_bytes (fdo);
2812 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2817 return (NILP (*instream)
2819 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2820 : flags & STREAM_NETWORK_CONNECTION
2821 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2823 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2827 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2828 Lisp_Object outstream)
2830 /* Oh nothing special here for Win32 at all */
2831 #if defined (HAVE_UNIX_PROCESSES)
2832 int in = (NILP(instream)
2834 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2835 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2836 ? get_winsock_stream_param (XLSTREAM (instream))
2838 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2839 int out = (NILP(outstream) ? -1
2840 : filedesc_stream_fd (XLSTREAM (outstream)));
2844 if (out != in && out >= 0)
2848 return (NILP (instream)
2850 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2851 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2852 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2854 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2857 #ifndef HAVE_X_WINDOWS
2858 /* This is called from GC when a process object is about to be freed.
2859 If we've still got pointers to it in this file, we're gonna lose hard.
2862 debug_process_finalization (struct Lisp_Process *p)
2865 Lisp_Object instr, outstr;
2867 get_process_streams (p, &instr, &outstr);
2868 /* if it still has fds, then it hasn't been killed yet. */
2869 assert (NILP(instr));
2870 assert (NILP(outstr));
2872 /* #### More checks here */
2877 /************************************************************************/
2878 /* initialization */
2879 /************************************************************************/
2882 vars_of_event_mswindows (void)
2884 mswindows_u_dispatch_event_queue = Qnil;
2885 staticpro (&mswindows_u_dispatch_event_queue);
2886 mswindows_u_dispatch_event_queue_tail = Qnil;
2888 mswindows_s_dispatch_event_queue = Qnil;
2889 staticpro (&mswindows_s_dispatch_event_queue);
2890 mswindows_s_dispatch_event_queue_tail = Qnil;
2892 mswindows_error_caught_in_modal_loop = Qnil;
2893 staticpro (&mswindows_error_caught_in_modal_loop);
2894 mswindows_in_modal_loop = 0;
2895 mswindows_pending_timers_count = 0;
2897 mswindows_event_stream = xnew (struct event_stream);
2899 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2900 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2901 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2902 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2903 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2904 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2905 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2906 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2907 #ifdef HAVE_MSG_SELECT
2908 mswindows_event_stream->select_process_cb =
2909 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2910 mswindows_event_stream->unselect_process_cb =
2911 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2912 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2913 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2915 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2916 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2917 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2918 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2921 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2922 *Controls redrawing frame contents during mouse-drag or keyboard resize
2923 operation. When non-nil, the frame is redrawn while being resized. When
2924 nil, frame is not redrawn, and exposed areas are filled with default
2925 MDI application background color. Note that this option only has effect
2926 if "Show window contents while dragging" is on in system Display/Plus!
2928 Default is t on fast machines, nil on slow.
2931 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2932 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2933 *Analogue of double click interval for faking middle mouse events.
2934 The value is the minimum time in milliseconds that must elapse between
2935 left/right button down events before they are considered distinct events.
2936 If both mouse buttons are depressed within this interval, a middle mouse
2937 button down event is generated instead.
2938 If negative or zero, currently set system default is used instead.
2941 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2942 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2943 Number of physical mouse buttons.
2946 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2947 *Maximum horizontal distance in pixels between points in which left and
2948 right button clicks occurred for them to be translated into single
2949 middle button event. Clicks must occur in time not longer than defined
2950 by the variable `mswindows-mouse-button-tolerance'.
2951 If negative or zero, currently set system default is used instead.
2954 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2955 *Maximum vertical distance in pixels between points in which left and
2956 right button clicks occurred for them to be translated into single
2957 middle button event. Clicks must occur in time not longer than defined
2958 by the variable `mswindows-mouse-button-tolerance'.
2959 If negative or zero, currently set system default is used instead.
2962 mswindows_mouse_button_max_skew_x = 0;
2963 mswindows_mouse_button_max_skew_y = 0;
2964 mswindows_mouse_button_tolerance = 0;
2968 syms_of_event_mswindows (void)
2973 lstream_type_create_mswindows_selectable (void)
2975 init_slurp_stream ();
2976 init_shove_stream ();
2977 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2978 init_winsock_stream ();
2983 init_event_mswindows_late (void)
2985 #ifdef HAVE_MSG_SELECT
2986 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2987 assert (windows_fd>=0);
2988 FD_SET (windows_fd, &input_wait_mask);
2989 FD_ZERO(&zero_mask);
2992 event_stream = mswindows_event_stream;
2994 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2995 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);