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"
64 #include "objects-msw.h"
66 #include "events-mod.h"
67 #ifdef HAVE_MSG_SELECT
69 #include "console-tty.h"
70 #elif defined(__CYGWIN32__)
71 typedef unsigned int SOCKET;
76 #if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20)
77 typedef NMHDR *LPNMHDR;
81 #define ADJR_MENUFLAG TRUE
83 #define ADJR_MENUFLAG FALSE
86 /* Fake key modifier which is attached to a quit char event.
87 Removed upon dequeueing an event */
88 #define FAKE_MOD_QUIT 0x80
90 /* Timer ID used for button2 emulation */
91 #define BUTTON_2_TIMER_ID 1
93 static Lisp_Object mswindows_find_frame (HWND hwnd);
94 static Lisp_Object mswindows_find_console (HWND hwnd);
95 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
97 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
98 static void mswindows_set_chord_timer (HWND hwnd);
99 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
100 static int mswindows_current_layout_has_AltGr (void);
102 static struct event_stream *mswindows_event_stream;
104 #ifdef HAVE_MSG_SELECT
105 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
106 extern SELECT_TYPE process_only_mask, tty_only_mask;
107 SELECT_TYPE zero_mask;
108 extern int signal_event_pipe_initialized;
113 * Two separate queues, for efficiency, one (_u_) for user events, and
114 * another (_s_) for non-user ones. We always return events out of the
115 * first one until it is empty and only then proceed with the second
118 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
119 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
121 /* For speed: whether there is a WM_PAINT magic message in the system queue */
122 static int mswindows_paint_pending = 0;
124 /* The number of things we can wait on */
125 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
127 #ifndef HAVE_MSG_SELECT
128 /* List of mswindows waitable handles. */
129 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
131 /* Number of wait handles */
132 static int mswindows_waitable_count=0;
133 #endif /* HAVE_MSG_SELECT */
135 /* Brush for painting widgets */
136 static HBRUSH widget_brush = 0;
137 static LONG last_widget_brushed = 0;
139 /* Count of quit chars currently in the queue */
140 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
141 Decremented in mswindows_dequeue_dispatch_event() */
142 int mswindows_quit_chars_count = 0;
144 /* These are Lisp integers; see DEFVARS in this file for description. */
145 int mswindows_dynamic_frame_resize;
146 int mswindows_meta_activates_menu;
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 (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 Lisp_Event* e = XEVENT (event);
898 e->event_type = misc_user_event;
899 e->channel = channel;
900 e->timestamp = GetTickCount ();
901 e->event.misc.function = function;
902 e->event.misc.object = object;
904 mswindows_enqueue_dispatch_event (event);
908 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
910 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
911 Lisp_Event* event = XEVENT (emacs_event);
913 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
914 event->timestamp = GetMessageTime();
915 event->event_type = magic_event;
916 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
918 mswindows_enqueue_dispatch_event (emacs_event);
922 mswindows_enqueue_process_event (Lisp_Process* p)
924 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
925 Lisp_Event* event = XEVENT (emacs_event);
927 XSETPROCESS (process, p);
929 event->event_type = process_event;
930 event->timestamp = GetTickCount ();
931 event->event.process.process = process;
933 mswindows_enqueue_dispatch_event (emacs_event);
937 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when)
940 /* We always use last message time, because mouse button
941 events may get delayed, and XEmacs double click
942 recognition will fail */
944 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
945 Lisp_Event* event = XEVENT(emacs_event);
947 event->channel = mswindows_find_frame(hwnd);
948 event->timestamp = when;
949 event->event.button.button =
950 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
951 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
952 event->event.button.x = where.x;
953 event->event.button.y = where.y;
954 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
956 if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN ||
959 event->event_type = button_press_event;
961 /* we need this to make sure the main window regains the focus
962 from control subwindows */
963 if (GetFocus() != hwnd)
966 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
971 event->event_type = button_release_event;
975 mswindows_enqueue_dispatch_event (emacs_event);
979 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
981 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
982 Lisp_Event* event = XEVENT(emacs_event);
984 event->channel = mswindows_find_console(hwnd);
985 event->timestamp = GetMessageTime();
986 event->event_type = key_press_event;
987 event->event.key.keysym = keysym;
988 event->event.key.modifiers = mods;
989 mswindows_enqueue_dispatch_event (emacs_event);
993 * Remove and return the first emacs event on the dispatch queue.
994 * Give a preference to user events over non-user ones.
997 mswindows_dequeue_dispatch_event ()
1002 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1003 !NILP(mswindows_s_dispatch_event_queue));
1005 event = dequeue_event (
1006 NILP(mswindows_u_dispatch_event_queue) ?
1007 &mswindows_s_dispatch_event_queue :
1008 &mswindows_u_dispatch_event_queue,
1009 NILP(mswindows_u_dispatch_event_queue) ?
1010 &mswindows_s_dispatch_event_queue_tail :
1011 &mswindows_u_dispatch_event_queue_tail);
1013 sevt = XEVENT(event);
1014 if (sevt->event_type == key_press_event
1015 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1017 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1018 --mswindows_quit_chars_count;
1025 * Remove and return the first emacs event on the dispatch queue that matches
1026 * the supplied event.
1027 * Timeout event matches if interval_id is equal to that of the given event.
1028 * Keypress event matches if logical AND between modifiers bitmask of the
1029 * event in the queue and that of the given event is non-zero.
1030 * For all other event types, this function aborts.
1034 mswindows_cancel_dispatch_event (Lisp_Event *match)
1037 Lisp_Object previous_event = Qnil;
1038 int user_p = mswindows_user_event_p (match);
1039 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1040 &mswindows_s_dispatch_event_queue;
1041 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1042 &mswindows_s_dispatch_event_queue_tail;
1044 assert (match->event_type == timeout_event
1045 || match->event_type == key_press_event);
1047 EVENT_CHAIN_LOOP (event, *head)
1049 Lisp_Event *e = XEVENT (event);
1050 if ((e->event_type == match->event_type) &&
1051 ((e->event_type == timeout_event) ?
1052 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1053 /* Must be key_press_event */
1054 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1056 if (NILP (previous_event))
1057 dequeue_event (head, tail);
1060 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1061 if (EQ (*tail, event))
1062 *tail = previous_event;
1067 previous_event = event;
1072 #ifndef HAVE_MSG_SELECT
1073 /************************************************************************/
1074 /* Waitable handles manipulation */
1075 /************************************************************************/
1077 find_waitable_handle (HANDLE h)
1080 for (i = 0; i < mswindows_waitable_count; ++i)
1081 if (mswindows_waitable_handles[i] == h)
1088 add_waitable_handle (HANDLE h)
1090 assert (find_waitable_handle (h) < 0);
1091 if (mswindows_waitable_count == MAX_WAITABLE)
1094 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1099 remove_waitable_handle (HANDLE h)
1101 int ix = find_waitable_handle (h);
1105 mswindows_waitable_handles [ix] =
1106 mswindows_waitable_handles [--mswindows_waitable_count];
1108 #endif /* HAVE_MSG_SELECT */
1111 /************************************************************************/
1113 /************************************************************************/
1116 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1117 Lisp_Object u_n_u_s_e_d)
1119 mswindows_error_caught_in_modal_loop = cons_sig_data;
1124 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1129 ++mswindows_in_modal_loop;
1130 tmp = condition_case_1 (Qt,
1132 mswindows_modal_loop_error_handler, Qnil);
1133 --mswindows_in_modal_loop;
1139 mswindows_unmodalize_signal_maybe (void)
1141 if (!NILP (mswindows_error_caught_in_modal_loop))
1143 /* Got an error while messages were pumped while
1144 in window procedure - have to resignal */
1145 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1146 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1147 mswindows_error_caught_in_modal_loop = Qnil;
1148 Fsignal (sym, data);
1153 * This is an unsafe part of event pump, guarded by
1154 * condition_case. See mswindows_pump_outstanding_events
1157 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1159 /* This function can call lisp */
1160 Lisp_Object event = Fmake_event (Qnil, Qnil);
1161 struct gcpro gcpro1;
1162 int do_redisplay = 0;
1165 while (detect_input_pending ())
1167 Fnext_event (event, Qnil);
1168 Fdispatch_event (event);
1175 Fdeallocate_event (event);
1178 /* Qt becomes return value of mswindows_pump_outstanding_events
1184 * This function pumps emacs events, while available, by using
1185 * next_message/dispatch_message loop. Errors are trapped around
1186 * the loop so the function always returns.
1188 * Windows message queue is not looked into during the call,
1189 * neither are waitable handles checked. The function pumps
1190 * thus only dispatch events already queued, as well as those
1191 * resulted in dispatching thereof. This is done by setting
1192 * module local variable mswindows_in_modal_loop to nonzero.
1194 * Return value is Qt if no errors was trapped, or Qunbound if
1195 * there was an error.
1197 * In case of error, a cons representing the error, in the
1198 * form (SIGNAL . DATA), is stored in the module local variable
1199 * mswindows_error_caught_in_modal_loop. This error is signaled
1200 * again when DispatchMessage returns. Thus, Windows internal
1201 * modal loops are protected against throws, which are proven
1202 * to corrupt internal Windows structures.
1204 * In case of success, mswindows_error_caught_in_modal_loop is
1207 * If the value of mswindows_error_caught_in_modal_loop is not
1208 * nil already upon entry, the function just returns non-nil.
1209 * This situation means that a new event has been queued while
1210 * in cancel mode. The event will be dequeued on the next regular
1211 * call of next-event; the pump is off since error is caught.
1212 * The caller must *unconditionally* cancel modal loop if the
1213 * value returned by this function is nil. Otherwise, everything
1214 * will become frozen until the modal loop exits under normal
1215 * condition (scrollbar drag is released, menu closed etc.)
1218 mswindows_pump_outstanding_events (void)
1220 /* This function can call lisp */
1222 Lisp_Object result = Qt;
1223 struct gcpro gcpro1;
1226 if (NILP(mswindows_error_caught_in_modal_loop))
1227 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1233 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1234 * QUITP, and are interesting in keyboard messages only.
1237 mswindows_drain_windows_queue ()
1241 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1242 assert (!mswindows_in_modal_loop);
1244 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1246 /* We have to translate messages that are not sent to the main
1247 window. This is so that key presses work ok in things like
1248 edit fields. However, we *musn't* translate message for the
1249 main window as this is handled in the wnd proc. */
1250 if (GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD)
1252 TranslateMessage (&msg);
1254 else if (msg.message == WM_PAINT)
1256 /* hdc will be NULL unless this is a subwindow - in which case we
1257 shouldn't have received a paint message for it here. */
1258 assert (msg.wParam == 0);
1260 if (!mswindows_paint_pending)
1262 /* Queue a magic event for handling when safe */
1263 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1264 mswindows_paint_pending = 1;
1267 /* Don't dispatch. WM_PAINT is always the last message in the
1268 queue so it's OK to just return. */
1271 DispatchMessage (&msg);
1272 mswindows_unmodalize_signal_maybe ();
1277 * This is a special flavor of the mswindows_need_event function,
1278 * used while in event pump. Actually, there is only kind of events
1279 * allowed while in event pump: a timer. An attempt to fetch any
1280 * other event leads to a deadlock, as there's no source of user input
1281 * ('cause event pump mirrors windows modal loop, which is a sole
1282 * owner of thread message queue).
1284 * To detect this, we use a counter of active timers, and allow
1285 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1286 * which will never come when there are no pending timers, which leads
1287 * to deadlock, we simply signal an error.
1290 mswindows_need_event_in_modal_loop (int badly_p)
1294 /* Check if already have one */
1295 if (!NILP (mswindows_u_dispatch_event_queue)
1296 || !NILP (mswindows_s_dispatch_event_queue))
1299 /* No event is ok */
1303 /* We do not check the _u_ queue, because timers go to _s_ */
1304 while (NILP (mswindows_s_dispatch_event_queue))
1306 /* We'll deadlock if go waiting */
1307 if (mswindows_pending_timers_count == 0)
1308 error ("Deadlock due to an attempt to call next-event in a wrong context");
1310 /* Fetch and dispatch any pending timers */
1311 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1312 DispatchMessage (&msg);
1317 * This drains the event queue and fills up two internal queues until
1318 * an event of a type specified by USER_P is retrieved.
1321 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1324 mswindows_need_event (int badly_p)
1328 if (mswindows_in_modal_loop)
1330 mswindows_need_event_in_modal_loop (badly_p);
1334 while (NILP (mswindows_u_dispatch_event_queue)
1335 && NILP (mswindows_s_dispatch_event_queue))
1337 #ifdef HAVE_MSG_SELECT
1339 SELECT_TYPE temp_mask = input_wait_mask;
1340 EMACS_TIME sometime;
1341 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1344 pointer_to_this = 0;
1347 EMACS_SET_SECS_USECS (sometime, 0, 0);
1348 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1349 pointer_to_this = &select_time_to_block;
1352 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1357 return; /* timeout */
1359 else if (active > 0)
1361 if (FD_ISSET (windows_fd, &temp_mask))
1363 mswindows_drain_windows_queue ();
1366 /* Look for a TTY event */
1367 for (i = 0; i < MAXDESC-1; i++)
1369 /* To avoid race conditions (among other things, an infinite
1370 loop when called from Fdiscard_input()), we must return
1371 user events ahead of process events. */
1372 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1374 struct console *c = tty_find_console_from_fd (i);
1375 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1376 Lisp_Event* event = XEVENT (emacs_event);
1379 if (read_event_from_tty_or_stream_desc (event, c, i))
1381 mswindows_enqueue_dispatch_event (emacs_event);
1387 /* Look for a process event */
1388 for (i = 0; i < MAXDESC-1; i++)
1390 if (FD_ISSET (i, &temp_mask))
1392 if (FD_ISSET (i, &process_only_mask))
1395 get_process_from_usid (FD_TO_USID(i));
1397 mswindows_enqueue_process_event (p);
1401 /* We might get here when a fake event came
1402 through a signal. Return a dummy event, so
1403 that a cycle of the command loop will
1405 drain_signal_event_pipe ();
1406 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1411 else if (active==-1)
1415 /* something bad happened */
1424 /* Now try getting a message or process event */
1425 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1426 mswindows_waitable_handles,
1427 FALSE, badly_p ? INFINITE : 0,
1430 /* This will assert if handle being waited for becomes abandoned.
1431 Not the case currently tho */
1432 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1433 (active >= WAIT_OBJECT_0 &&
1434 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1436 if (active == WAIT_TIMEOUT)
1438 /* No luck trying - just return what we've already got */
1441 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1443 /* Got your message, thanks */
1444 mswindows_drain_windows_queue ();
1448 int ix = active - WAIT_OBJECT_0;
1449 /* First, try to find which process' output has signaled */
1451 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1454 /* Found a signaled process input handle */
1455 mswindows_enqueue_process_event (p);
1459 /* None. This means that the process handle itself has signaled.
1460 Remove the handle from the wait vector, and make status_notify
1461 note the exited process */
1462 mswindows_waitable_handles [ix] =
1463 mswindows_waitable_handles [--mswindows_waitable_count];
1464 kick_status_notify ();
1465 /* Have to return something: there may be no accompanying
1467 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1474 /************************************************************************/
1475 /* Event generators */
1476 /************************************************************************/
1479 * Callback procedure for synchronous timer messages
1481 static void CALLBACK
1482 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1484 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1485 Lisp_Event *event = XEVENT (emacs_event);
1487 if (KillTimer (NULL, id_timer))
1488 --mswindows_pending_timers_count;
1490 event->channel = Qnil;
1491 event->timestamp = dwtime;
1492 event->event_type = timeout_event;
1493 event->event.timeout.interval_id = id_timer;
1494 event->event.timeout.function = Qnil;
1495 event->event.timeout.object = Qnil;
1497 mswindows_enqueue_dispatch_event (emacs_event);
1501 * Callback procedure for dde messages
1503 * We execute a dde Open("file") by simulating a file drop, so dde support
1504 * depends on dnd support.
1506 #ifdef HAVE_DRAGNDROP
1508 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1509 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1510 DWORD dwData1, DWORD dwData2)
1515 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1516 return (HDDEDATA)TRUE;
1517 return (HDDEDATA)FALSE;
1519 case XTYP_WILDCONNECT:
1521 /* We only support one {service,topic} pair */
1522 HSZPAIR pairs[2] = {
1523 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1525 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1526 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1527 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1528 sizeof (pairs), 0L, 0, uFmt, 0));
1530 return (HDDEDATA)NULL;
1533 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1535 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1536 char *cmd = alloca (len+1);
1539 struct gcpro gcpro1, gcpro2;
1540 Lisp_Object l_dndlist = Qnil;
1541 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1542 Lisp_Object frmcons, devcons, concons;
1543 Lisp_Event *event = XEVENT (emacs_event);
1545 DdeGetData (hdata, cmd, len, 0);
1547 DdeFreeDataHandle (hdata);
1549 /* Check syntax & that it's an [Open("foo")] command, which we
1550 * treat like a file drop */
1551 /* #### Ought to be generalised and accept some other commands */
1554 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1555 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1556 return DDE_FNOTPROCESSED;
1557 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1560 if (*cmd!='(' || *(cmd+1)!='\"')
1561 return DDE_FNOTPROCESSED;
1563 while (*end && *end!='\"')
1566 return DDE_FNOTPROCESSED;
1569 return DDE_FNOTPROCESSED;
1573 return DDE_FNOTPROCESSED;
1576 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1577 strcpy (filename, "file:");
1578 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1580 dostounix_filename (cmd);
1581 filename = alloca (strlen (cmd)+6);
1582 strcpy (filename, "file:");
1583 strcat (filename, cmd);
1585 GCPRO2 (emacs_event, l_dndlist);
1586 l_dndlist = make_string (filename, strlen (filename));
1588 /* Find a mswindows frame */
1589 event->channel = Qnil;
1590 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1592 Lisp_Object frame = XCAR (frmcons);
1593 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1594 event->channel = frame;
1596 assert (!NILP (event->channel));
1598 event->timestamp = GetTickCount();
1599 event->event_type = misc_user_event;
1600 event->event.misc.button = 1;
1601 event->event.misc.modifiers = 0;
1602 event->event.misc.x = -1;
1603 event->event.misc.y = -1;
1604 event->event.misc.function = Qdragdrop_drop_dispatch;
1605 event->event.misc.object = Fcons (Qdragdrop_URL,
1606 Fcons (l_dndlist, Qnil));
1607 mswindows_enqueue_dispatch_event (emacs_event);
1609 return (HDDEDATA) DDE_FACK;
1611 DdeFreeDataHandle (hdata);
1612 return (HDDEDATA) DDE_FNOTPROCESSED;
1615 return (HDDEDATA) NULL;
1621 * Helper to do repainting - repaints can happen both from the windows
1622 * procedure and from magic events
1625 mswindows_handle_paint (struct frame *frame)
1627 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1629 /* According to the docs we need to check GetUpdateRect() before
1630 actually doing a WM_PAINT */
1631 if (GetUpdateRect (hwnd, NULL, FALSE))
1633 PAINTSTRUCT paintStruct;
1634 int x, y, width, height;
1636 BeginPaint (hwnd, &paintStruct);
1637 x = paintStruct.rcPaint.left;
1638 y = paintStruct.rcPaint.top;
1639 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1640 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1641 /* Normally we want to ignore expose events when child
1642 windows are unmapped, however once we are in the guts of
1643 WM_PAINT we need to make sure that we don't register
1644 unmaps then because they will not actually occur. */
1645 if (!check_for_ignored_expose (frame, x, y, width, height))
1647 hold_ignored_expose_registration = 1;
1648 mswindows_redraw_exposed_area (frame, x, y, width, height);
1649 hold_ignored_expose_registration = 0;
1651 EndPaint (hwnd, &paintStruct);
1656 * Returns 1 if a key is a real modifier or special key, which
1657 * is better handled by DefWindowProc
1660 key_needs_default_processing_p (UINT vkey)
1662 if (mswindows_meta_activates_menu && vkey == VK_MENU)
1669 * The windows procedure for the window class XEMACS_CLASS
1672 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1674 /* Note: Remember to initialize emacs_event and event before use.
1675 This code calls code that can GC. You must GCPRO before calling such code. */
1676 Lisp_Object emacs_event = Qnil;
1677 Lisp_Object fobj = Qnil;
1680 struct frame *frame;
1681 struct mswindows_frame* msframe;
1685 case WM_DESTROYCLIPBOARD:
1686 /* We own the clipboard and someone else wants it. Delete our
1687 cached copy of the clipboard contents so we'll ask for it from
1688 Windows again when someone does a paste. */
1689 handle_selection_clear(QCLIPBOARD);
1693 /* Erase background only during non-dynamic sizing */
1694 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1695 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1700 fobj = mswindows_find_frame (hwnd);
1701 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1706 /* See Win95 comment under WM_KEYDOWN */
1710 if (wParam == VK_CONTROL)
1712 GetKeyboardState (keymap);
1713 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1714 SetKeyboardState (keymap);
1716 else if (wParam == VK_MENU)
1718 GetKeyboardState (keymap);
1719 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1720 SetKeyboardState (keymap);
1723 if (key_needs_default_processing_p (wParam))
1730 /* In some locales the right-hand Alt key is labelled AltGr. This key
1731 * should produce alternative charcaters when combined with another key.
1732 * eg on a German keyboard pressing AltGr+q should produce '@'.
1733 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1734 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1735 * it translates as if AltGr were down.
1736 * We get round this by removing all modifiers from the keymap before
1737 * calling TranslateMessage() unless AltGr is *really* down. */
1740 int has_AltGr = mswindows_current_layout_has_AltGr ();
1742 int extendedp = lParam & 0x1000000;
1745 GetKeyboardState (keymap);
1746 mods = mswindows_modifier_state (keymap, has_AltGr);
1748 /* Handle non-printables */
1749 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
1751 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1752 else /* Normal keys & modifiers */
1754 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1755 BYTE keymap_orig[256];
1756 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1760 msg.message = message;
1761 msg.wParam = wParam;
1762 msg.lParam = lParam;
1763 msg.time = GetMessageTime();
1766 /* GetKeyboardState() does not work as documented on Win95. We have
1767 * to loosely track Left and Right modifiers on behalf of the OS,
1768 * without screwing up Windows NT which tracks them properly. */
1769 if (wParam == VK_CONTROL)
1770 keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1771 else if (wParam == VK_MENU)
1772 keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
1774 memcpy (keymap_orig, keymap, 256);
1776 /* Remove shift modifier from an ascii character */
1779 /* Clear control and alt modifiers unless AltGr is pressed */
1780 keymap [VK_RCONTROL] = 0;
1781 keymap [VK_LMENU] = 0;
1782 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80)
1783 || !(keymap [VK_RMENU] & 0x80))
1785 keymap [VK_LCONTROL] = 0;
1786 keymap [VK_CONTROL] = 0;
1787 keymap [VK_RMENU] = 0;
1788 keymap [VK_MENU] = 0;
1790 SetKeyboardState (keymap);
1792 /* Maybe generate some WM_[SYS]CHARs in the queue */
1793 TranslateMessage (&msg);
1795 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1796 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1799 WPARAM ch = msg.wParam;
1801 /* If a quit char with no modifiers other than control and
1802 shift, then mark it with a fake modifier, which is removed
1803 upon dequeueing the event */
1804 /* #### This might also not withstand localization, if
1805 quit character is not a latin-1 symbol */
1806 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1807 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1808 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1810 mods1 |= FAKE_MOD_QUIT;
1811 ++mswindows_quit_chars_count;
1814 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1816 SetKeyboardState (keymap_orig);
1819 if (key_needs_default_processing_p (wParam))
1824 case WM_MBUTTONDOWN:
1826 /* Real middle mouse button has nothing to do with emulated one:
1827 if one wants to exercise fingers playing chords on the mouse,
1828 he is allowed to do that! */
1829 mswindows_enqueue_mouse_button_event (hwnd, message,
1830 MAKEPOINTS (lParam), GetMessageTime());
1834 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1835 msframe->last_click_time = GetMessageTime();
1837 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1838 msframe->button2_need_lbutton = 0;
1839 if (msframe->ignore_next_lbutton_up)
1841 msframe->ignore_next_lbutton_up = 0;
1843 else if (msframe->button2_is_down)
1845 msframe->button2_is_down = 0;
1846 msframe->ignore_next_rbutton_up = 1;
1847 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1848 MAKEPOINTS (lParam), GetMessageTime());
1852 if (msframe->button2_need_rbutton)
1854 msframe->button2_need_rbutton = 0;
1855 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1856 MAKEPOINTS (lParam), GetMessageTime());
1858 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1859 MAKEPOINTS (lParam), GetMessageTime());
1864 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1865 msframe->last_click_time = GetMessageTime();
1867 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1868 msframe->button2_need_rbutton = 0;
1869 if (msframe->ignore_next_rbutton_up)
1871 msframe->ignore_next_rbutton_up = 0;
1873 else if (msframe->button2_is_down)
1875 msframe->button2_is_down = 0;
1876 msframe->ignore_next_lbutton_up = 1;
1877 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1878 MAKEPOINTS (lParam), GetMessageTime());
1882 if (msframe->button2_need_lbutton)
1884 msframe->button2_need_lbutton = 0;
1885 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1886 MAKEPOINTS (lParam), GetMessageTime());
1888 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1889 MAKEPOINTS (lParam), GetMessageTime());
1893 case WM_LBUTTONDOWN:
1894 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1896 if (msframe->button2_need_lbutton)
1898 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1899 msframe->button2_need_lbutton = 0;
1900 msframe->button2_need_rbutton = 0;
1901 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1903 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1904 MAKEPOINTS (lParam), GetMessageTime());
1905 msframe->button2_is_down = 1;
1909 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1910 msframe->last_click_point, msframe->last_click_time);
1911 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1912 MAKEPOINTS (lParam), GetMessageTime());
1917 mswindows_set_chord_timer (hwnd);
1918 msframe->button2_need_rbutton = 1;
1919 msframe->last_click_point = MAKEPOINTS (lParam);
1921 msframe->last_click_time = GetMessageTime();
1924 case WM_RBUTTONDOWN:
1925 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1927 if (msframe->button2_need_rbutton)
1929 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1930 msframe->button2_need_lbutton = 0;
1931 msframe->button2_need_rbutton = 0;
1932 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1934 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1935 MAKEPOINTS (lParam), GetMessageTime());
1936 msframe->button2_is_down = 1;
1940 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1941 msframe->last_click_point, msframe->last_click_time);
1942 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1943 MAKEPOINTS (lParam), GetMessageTime());
1948 mswindows_set_chord_timer (hwnd);
1949 msframe->button2_need_lbutton = 1;
1950 msframe->last_click_point = MAKEPOINTS (lParam);
1952 msframe->last_click_time = GetMessageTime();
1956 if (wParam == BUTTON_2_TIMER_ID)
1958 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1959 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1961 if (msframe->button2_need_lbutton)
1963 msframe->button2_need_lbutton = 0;
1964 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1965 msframe->last_click_point, msframe->last_click_time);
1967 else if (msframe->button2_need_rbutton)
1969 msframe->button2_need_rbutton = 0;
1970 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1971 msframe->last_click_point, msframe->last_click_time);
1975 assert ("Spurious timer fired" == 0);
1979 /* Optimization: don't report mouse movement while size is changing */
1980 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1981 if (!msframe->sizing)
1983 /* When waiting for the second mouse button to finish
1984 button2 emulation, and have moved too far, just pretend
1985 as if timer has expired. This improves drag-select feedback */
1986 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1987 && !mswindows_button2_near_enough (msframe->last_click_point,
1988 MAKEPOINTS (lParam)))
1990 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1991 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1994 emacs_event = Fmake_event (Qnil, Qnil);
1995 event = XEVENT(emacs_event);
1997 event->channel = mswindows_find_frame(hwnd);
1998 event->timestamp = GetMessageTime();
1999 event->event_type = pointer_motion_event;
2000 event->event.motion.x = MAKEPOINTS(lParam).x;
2001 event->event.motion.y = MAKEPOINTS(lParam).y;
2002 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
2004 mswindows_enqueue_dispatch_event (emacs_event);
2010 /* Queue a `cancel-mode-internal' misc user event, so mouse
2011 selection would be canceled if any */
2012 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2013 Qcancel_mode_internal, Qnil);
2018 LPNMHDR nmhdr = (LPNMHDR)lParam;
2020 if (nmhdr->code == TTN_NEEDTEXT)
2022 #ifdef HAVE_TOOLBARS
2023 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2026 /* find out which toolbar */
2027 frame = XFRAME (mswindows_find_frame (hwnd));
2028 btext = mswindows_get_toolbar_button_text ( frame,
2031 tttext->lpszText = NULL;
2032 tttext->hinst = NULL;
2036 /* I think this is safe since the text will only go away
2037 when the toolbar does...*/
2038 TO_EXTERNAL_FORMAT (LISP_STRING, btext,
2039 C_STRING_ALLOCA, tttext->lpszText,
2044 /* handle tree view callbacks */
2045 else if (nmhdr->code == TVN_SELCHANGED)
2047 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2048 frame = XFRAME (mswindows_find_frame (hwnd));
2049 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2051 /* handle tab control callbacks */
2052 else if (nmhdr->code == TCN_SELCHANGE)
2055 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2056 frame = XFRAME (mswindows_find_frame (hwnd));
2058 item.mask = TCIF_PARAM;
2059 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2062 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2068 /* hdc will be NULL unless this is a subwindow - in which case we
2069 shouldn't have received a paint message for it here. */
2070 assert (wParam == 0);
2072 /* Can't queue a magic event because windows goes modal and sends paint
2073 messages directly to the windows procedure when doing solid drags
2074 and the message queue doesn't get processed. */
2075 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2079 /* We only care about this message if our size has really changed */
2080 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2085 fobj = mswindows_find_frame (hwnd);
2086 frame = XFRAME (fobj);
2087 msframe = FRAME_MSWINDOWS_DATA (frame);
2089 /* We cannot handle frame map and unmap hooks right in
2090 this routine, because these may throw. We queue
2091 magic events to run these hooks instead - kkm */
2093 if (wParam==SIZE_MINIMIZED)
2096 FRAME_VISIBLE_P (frame) = 0;
2097 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2101 GetClientRect(hwnd, &rect);
2102 FRAME_PIXWIDTH(frame) = rect.right;
2103 FRAME_PIXHEIGHT(frame) = rect.bottom;
2105 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2106 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2107 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2109 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2110 change_frame_size (frame, rows, columns, 1);
2112 /* If we are inside frame creation, we have to apply geometric
2114 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2116 /* Yes, we have to size again */
2117 mswindows_size_frame_internal ( frame,
2118 FRAME_MSWINDOWS_TARGET_RECT
2120 /* Reset so we do not get here again. The SetWindowPos call in
2121 * mswindows_size_frame_internal can cause recursion here. */
2122 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2124 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2125 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2130 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2131 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2132 FRAME_VISIBLE_P (frame) = 1;
2134 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2141 /* Misc magic events which only require that the frame be identified */
2144 mswindows_enqueue_magic_event (hwnd, message);
2147 case WM_WINDOWPOSCHANGING:
2149 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2150 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2151 GetWindowPlacement(hwnd, &wpl);
2153 /* Only interested if size is changing and we're not being iconified */
2154 if (wpl.showCmd != SW_SHOWMINIMIZED
2155 && wpl.showCmd != SW_SHOWMAXIMIZED
2156 && !(wp->flags & SWP_NOSIZE))
2158 RECT ncsize = { 0, 0, 0, 0 };
2159 int pixwidth, pixheight;
2160 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2161 GetMenu(hwnd) != NULL,
2162 GetWindowLong (hwnd, GWL_EXSTYLE));
2164 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2165 wp->cx - (ncsize.right - ncsize.left),
2166 wp->cy - (ncsize.bottom - ncsize.top),
2167 &pixwidth, &pixheight);
2169 /* Convert client sizes to window sizes */
2170 pixwidth += (ncsize.right - ncsize.left);
2171 pixheight += (ncsize.bottom - ncsize.top);
2173 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2175 /* Adjust so that the bottom or right doesn't move if it's
2176 * the top or left that's being changed */
2178 GetWindowRect (hwnd, &rect);
2180 if (rect.left != wp->x)
2181 wp->x += wp->cx - pixwidth;
2182 if (rect.top != wp->y)
2183 wp->y += wp->cy - pixheight;
2189 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2190 window position if the user tries to track window too small */
2194 case WM_ENTERSIZEMOVE:
2195 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2196 msframe->sizing = 1;
2199 case WM_EXITSIZEMOVE:
2200 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2201 msframe->sizing = 0;
2202 /* Queue noop event */
2203 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2206 #ifdef HAVE_SCROLLBARS
2210 /* Direction of scroll is determined by scrollbar instance. */
2211 int code = (int) LOWORD(wParam);
2212 int pos = (short int) HIWORD(wParam);
2213 HWND hwndScrollBar = (HWND) lParam;
2214 struct gcpro gcpro1, gcpro2;
2216 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2217 GCPRO2 (emacs_event, fobj);
2218 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2220 /* Error during event pumping - cancel scroll */
2221 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2229 int keys = LOWORD (wParam); /* Modifier key flags */
2230 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2231 struct gcpro gcpro1, gcpro2;
2233 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2235 GCPRO2 (emacs_event, fobj);
2236 mswindows_pump_outstanding_events (); /* Can GC */
2245 #ifdef HAVE_MENUBARS
2247 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2249 XFRAME (mswindows_find_frame (hwnd)))))
2250 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2253 case WM_INITMENUPOPUP:
2254 if (!HIWORD(lParam))
2256 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2258 XFRAME (mswindows_find_frame (hwnd)))))
2259 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2263 #endif /* HAVE_MENUBARS */
2267 WORD id = LOWORD (wParam);
2268 WORD nid = HIWORD (wParam);
2269 HWND cid = (HWND)lParam;
2270 frame = XFRAME (mswindows_find_frame (hwnd));
2272 #ifdef HAVE_TOOLBARS
2273 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2276 /* widgets in a buffer only eval a callback for suitable events.*/
2281 case CBN_EDITCHANGE:
2283 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2286 /* menubars always must come last since the hashtables do not
2288 #ifdef HAVE_MENUBARS
2289 if (!NILP (mswindows_handle_wm_command (frame, id)))
2293 return DefWindowProc (hwnd, message, wParam, lParam);
2294 /* Bite me - a spurious command. This used to not be able to
2295 happen but with the introduction of widgets its now
2300 case WM_CTLCOLORBTN:
2301 case WM_CTLCOLORLISTBOX:
2302 case WM_CTLCOLOREDIT:
2303 case WM_CTLCOLORSTATIC:
2304 case WM_CTLCOLORSCROLLBAR:
2306 /* if we get an opportunity to paint a widget then do so if
2307 there is an appropriate face */
2308 HWND crtlwnd = (HWND)lParam;
2309 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2312 Lisp_Object image_instance;
2313 VOID_TO_LISP (image_instance, ii);
2314 if (IMAGE_INSTANCEP (image_instance)
2316 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2318 /* set colors for the buttons */
2319 HDC hdc = (HDC)wParam;
2320 if (last_widget_brushed != ii)
2323 DeleteObject (widget_brush);
2324 widget_brush = CreateSolidBrush
2325 (COLOR_INSTANCE_MSWINDOWS_COLOR
2328 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2329 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2331 last_widget_brushed = ii;
2334 COLOR_INSTANCE_MSWINDOWS_COLOR
2337 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2338 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2339 SetBkMode (hdc, OPAQUE);
2342 COLOR_INSTANCE_MSWINDOWS_COLOR
2345 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2346 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2347 return (LRESULT)widget_brush;
2353 #ifdef HAVE_DRAGNDROP
2354 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2356 UINT filecount, i, len;
2362 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2363 struct gcpro gcpro1, gcpro2, gcpro3;
2365 emacs_event = Fmake_event (Qnil, Qnil);
2366 event = XEVENT(emacs_event);
2368 GCPRO3 (emacs_event, l_dndlist, l_item);
2370 if (!DragQueryPoint ((HANDLE) wParam, &point))
2371 point.x = point.y = -1; /* outside client area */
2373 event->event_type = misc_user_event;
2374 event->channel = mswindows_find_frame(hwnd);
2375 event->timestamp = GetMessageTime();
2376 event->event.misc.button = 1; /* #### Should try harder */
2377 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2378 event->event.misc.x = point.x;
2379 event->event.misc.y = point.y;
2380 event->event.misc.function = Qdragdrop_drop_dispatch;
2382 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2383 for (i=0; i<filecount; i++)
2385 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2386 /* The URLs that we make here aren't correct according to section
2387 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2388 * because they may contain reserved characters. But that's OK. */
2390 fname = (char *)xmalloc (len+1);
2391 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2392 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2393 strcpy (filename, "file:");
2394 cygwin32_win32_to_posix_path_list (fname, filename+5);
2397 filename = (char *)xmalloc (len+6);
2398 strcpy (filename, "file:");
2399 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2400 dostounix_filename (filename+5);
2402 l_item = make_string (filename, strlen (filename));
2403 l_dndlist = Fcons (l_item, l_dndlist);
2406 DragFinish ((HANDLE) wParam);
2408 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2409 mswindows_enqueue_dispatch_event (emacs_event);
2417 return DefWindowProc (hwnd, message, wParam, lParam);
2423 /************************************************************************/
2424 /* keyboard, mouse & other helpers for the windows procedure */
2425 /************************************************************************/
2427 mswindows_set_chord_timer (HWND hwnd)
2431 /* We get one third half system double click threshold */
2432 if (mswindows_mouse_button_tolerance <= 0)
2433 interval = GetDoubleClickTime () / 3;
2435 interval = mswindows_mouse_button_tolerance;
2437 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2441 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2444 if (mswindows_mouse_button_max_skew_x <= 0)
2445 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2447 dx = mswindows_mouse_button_max_skew_x;
2449 if (mswindows_mouse_button_max_skew_y <= 0)
2450 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2452 dy = mswindows_mouse_button_max_skew_y;
2454 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2458 mswindows_current_layout_has_AltGr (void)
2460 /* This simple caching mechanism saves 10% of CPU
2461 time when a key typed at autorepeat rate of 30 cps! */
2462 static HKL last_hkl = 0;
2463 static int last_hkl_has_AltGr;
2465 HKL current_hkl = GetKeyboardLayout (0);
2466 if (current_hkl != last_hkl)
2469 last_hkl_has_AltGr = 0;
2470 /* In this loop, we query whether a character requires
2471 AltGr to be down to generate it. If at least such one
2472 found, this means that the layout does regard AltGr */
2473 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2474 if (HIBYTE (VkKeyScan (c)) == 6)
2475 last_hkl_has_AltGr = 1;
2476 last_hkl = current_hkl;
2478 return last_hkl_has_AltGr;
2482 /* Returns the state of the modifier keys in the format expected by the
2483 * Lisp_Event key_data, button_data and motion_data modifiers member */
2484 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2490 keymap = (BYTE*) alloca(256);
2491 GetKeyboardState (keymap);
2492 has_AltGr = mswindows_current_layout_has_AltGr ();
2495 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2497 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2498 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2502 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2503 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2506 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2512 * Translate a mswindows virtual key to a keysym.
2513 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2514 * or whose ASCII codes (like space) xemacs doesn't like.
2515 * Virtual key values are defined in winresrc.h
2517 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
2520 if (extendedp) /* Keys not present on a 82 key keyboard */
2522 switch (mswindows_key)
2524 case VK_RETURN: return KEYSYM ("kp-enter");
2525 case VK_PRIOR: return KEYSYM ("prior");
2526 case VK_NEXT: return KEYSYM ("next");
2527 case VK_END: return KEYSYM ("end");
2528 case VK_HOME: return KEYSYM ("home");
2529 case VK_LEFT: return KEYSYM ("left");
2530 case VK_UP: return KEYSYM ("up");
2531 case VK_RIGHT: return KEYSYM ("right");
2532 case VK_DOWN: return KEYSYM ("down");
2533 case VK_INSERT: return KEYSYM ("insert");
2534 case VK_DELETE: return QKdelete;
2539 switch (mswindows_key)
2541 case VK_BACK: return QKbackspace;
2542 case VK_TAB: return QKtab;
2543 case '\n': return QKlinefeed;
2544 case VK_CLEAR: return KEYSYM ("clear");
2545 case VK_RETURN: return QKreturn;
2546 case VK_ESCAPE: return QKescape;
2547 case VK_SPACE: return QKspace;
2548 case VK_PRIOR: return KEYSYM ("kp-prior");
2549 case VK_NEXT: return KEYSYM ("kp-next");
2550 case VK_END: return KEYSYM ("kp-end");
2551 case VK_HOME: return KEYSYM ("kp-home");
2552 case VK_LEFT: return KEYSYM ("kp-left");
2553 case VK_UP: return KEYSYM ("kp-up");
2554 case VK_RIGHT: return KEYSYM ("kp-right");
2555 case VK_DOWN: return KEYSYM ("kp-down");
2556 case VK_SELECT: return KEYSYM ("select");
2557 case VK_PRINT: return KEYSYM ("print");
2558 case VK_EXECUTE: return KEYSYM ("execute");
2559 case VK_SNAPSHOT: return KEYSYM ("print");
2560 case VK_INSERT: return KEYSYM ("kp-insert");
2561 case VK_DELETE: return KEYSYM ("kp-delete");
2562 case VK_HELP: return KEYSYM ("help");
2563 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
2564 case VK_LWIN return KEYSYM ("");
2565 case VK_RWIN return KEYSYM ("");
2567 case VK_APPS: return KEYSYM ("menu");
2568 case VK_NUMPAD0: return KEYSYM ("kp-0");
2569 case VK_NUMPAD1: return KEYSYM ("kp-1");
2570 case VK_NUMPAD2: return KEYSYM ("kp-2");
2571 case VK_NUMPAD3: return KEYSYM ("kp-3");
2572 case VK_NUMPAD4: return KEYSYM ("kp-4");
2573 case VK_NUMPAD5: return KEYSYM ("kp-5");
2574 case VK_NUMPAD6: return KEYSYM ("kp-6");
2575 case VK_NUMPAD7: return KEYSYM ("kp-7");
2576 case VK_NUMPAD8: return KEYSYM ("kp-8");
2577 case VK_NUMPAD9: return KEYSYM ("kp-9");
2578 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
2579 case VK_ADD: return KEYSYM ("kp-add");
2580 case VK_SEPARATOR: return KEYSYM ("kp-separator");
2581 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
2582 case VK_DECIMAL: return KEYSYM ("kp-decimal");
2583 case VK_DIVIDE: return KEYSYM ("kp-divide");
2584 case VK_F1: return KEYSYM ("f1");
2585 case VK_F2: return KEYSYM ("f2");
2586 case VK_F3: return KEYSYM ("f3");
2587 case VK_F4: return KEYSYM ("f4");
2588 case VK_F5: return KEYSYM ("f5");
2589 case VK_F6: return KEYSYM ("f6");
2590 case VK_F7: return KEYSYM ("f7");
2591 case VK_F8: return KEYSYM ("f8");
2592 case VK_F9: return KEYSYM ("f9");
2593 case VK_F10: return KEYSYM ("f10");
2594 case VK_F11: return KEYSYM ("f11");
2595 case VK_F12: return KEYSYM ("f12");
2596 case VK_F13: return KEYSYM ("f13");
2597 case VK_F14: return KEYSYM ("f14");
2598 case VK_F15: return KEYSYM ("f15");
2599 case VK_F16: return KEYSYM ("f16");
2600 case VK_F17: return KEYSYM ("f17");
2601 case VK_F18: return KEYSYM ("f18");
2602 case VK_F19: return KEYSYM ("f19");
2603 case VK_F20: return KEYSYM ("f20");
2604 case VK_F21: return KEYSYM ("f21");
2605 case VK_F22: return KEYSYM ("f22");
2606 case VK_F23: return KEYSYM ("f23");
2607 case VK_F24: return KEYSYM ("f24");
2614 * Find the console that matches the supplied mswindows window handle
2617 mswindows_find_console (HWND hwnd)
2619 /* We only support one console */
2620 return XCAR (Vconsole_list);
2624 * Find the frame that matches the supplied mswindows window handle
2627 mswindows_find_frame (HWND hwnd)
2629 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2633 /* We are in progress of frame creation. Return the frame
2634 being created, as it still not remembered in the window
2636 assert (!NILP (Vmswindows_frame_being_created));
2637 return Vmswindows_frame_being_created;
2639 VOID_TO_LISP (f, l);
2644 /************************************************************************/
2646 /************************************************************************/
2649 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2652 EMACS_TIME current_time;
2653 EMACS_GET_TIME (current_time);
2654 EMACS_SUB_TIME (thyme, thyme, current_time);
2655 milliseconds = EMACS_SECS (thyme) * 1000 +
2656 (EMACS_USECS (thyme) + 500) / 1000;
2657 if (milliseconds < 1)
2659 ++mswindows_pending_timers_count;
2660 return SetTimer (NULL, 0, milliseconds,
2661 (TIMERPROC) mswindows_wm_timer_callback);
2665 emacs_mswindows_remove_timeout (int id)
2667 Lisp_Event match_against;
2668 Lisp_Object emacs_event;
2670 if (KillTimer (NULL, id))
2671 --mswindows_pending_timers_count;
2673 /* If there is a dispatch event generated by this
2674 timeout in the queue, we have to remove it too. */
2675 match_against.event_type = timeout_event;
2676 match_against.event.timeout.interval_id = id;
2677 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2678 if (!NILP (emacs_event))
2679 Fdeallocate_event(emacs_event);
2682 /* If `user_p' is false, then return whether there are any win32, timeout,
2683 * or subprocess events pending (that is, whether
2684 * emacs_mswindows_next_event() would return immediately without blocking).
2686 * if `user_p' is true, then return whether there are any *user generated*
2687 * events available (that is, whether there are keyboard or mouse-click
2688 * events ready to be read). This also implies that
2689 * emacs_mswindows_next_event() would not block.
2692 emacs_mswindows_event_pending_p (int user_p)
2694 mswindows_need_event (0);
2695 return (!NILP (mswindows_u_dispatch_event_queue)
2696 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2700 * Return the next event
2703 emacs_mswindows_next_event (Lisp_Event *emacs_event)
2705 Lisp_Object event, event2;
2707 mswindows_need_event (1);
2709 event = mswindows_dequeue_dispatch_event ();
2710 XSETEVENT (event2, emacs_event);
2711 Fcopy_event (event, event2);
2712 Fdeallocate_event (event);
2716 * Handle a magic event off the dispatch queue.
2719 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
2721 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2727 mswindows_handle_paint (XFRAME (EVENT_CHANNEL (emacs_event)));
2728 mswindows_paint_pending = 0;
2734 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2735 struct frame *f = XFRAME (frame);
2736 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2739 /* struct gcpro gcpro1; */
2741 /* Clear sticky modifiers here (if we had any) */
2743 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2744 /* GCPRO1 (conser); XXX Not necessary? */
2745 emacs_handle_focus_change_preliminary (conser);
2746 /* Under X the stuff up to here is done in the X event handler.
2748 emacs_handle_focus_change_final (conser);
2757 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2758 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2760 Qmap_frame_hook : Qunmap_frame_hook,
2765 /* #### What about Enter & Leave */
2767 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2768 Qmouse_leave_frame_hook, 1, frame);
2776 #ifndef HAVE_MSG_SELECT
2778 get_process_input_waitable (Lisp_Process *process)
2780 Lisp_Object instr, outstr, p;
2781 XSETPROCESS (p, process);
2782 get_process_streams (process, &instr, &outstr);
2783 assert (!NILP (instr));
2784 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2785 return (network_connection_p (p)
2786 ? get_winsock_stream_waitable (XLSTREAM (instr))
2787 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2789 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2794 emacs_mswindows_select_process (Lisp_Process *process)
2796 HANDLE hev = get_process_input_waitable (process);
2798 if (!add_waitable_handle (hev))
2799 error ("Too many active processes");
2801 #ifdef HAVE_WIN32_PROCESSES
2804 XSETPROCESS (p, process);
2805 if (!network_connection_p (p))
2807 HANDLE hprocess = get_nt_process_handle (process);
2808 if (!add_waitable_handle (hprocess))
2810 remove_waitable_handle (hev);
2811 error ("Too many active processes");
2819 emacs_mswindows_unselect_process (Lisp_Process *process)
2821 /* Process handle is removed in the event loop as soon
2822 as it is signaled, so don't bother here about it */
2823 HANDLE hev = get_process_input_waitable (process);
2824 remove_waitable_handle (hev);
2826 #endif /* HAVE_MSG_SELECT */
2829 emacs_mswindows_select_console (struct console *con)
2831 #ifdef HAVE_MSG_SELECT
2832 if (CONSOLE_MSWINDOWS_P (con))
2833 return; /* mswindows consoles are automatically selected */
2835 event_stream_unixoid_select_console (con);
2840 emacs_mswindows_unselect_console (struct console *con)
2842 #ifdef HAVE_MSG_SELECT
2843 if (CONSOLE_MSWINDOWS_P (con))
2844 return; /* mswindows consoles are automatically selected */
2846 event_stream_unixoid_unselect_console (con);
2851 emacs_mswindows_quit_p (void)
2853 /* Quit cannot happen in modal loop: all program
2854 input is dedicated to Windows. */
2855 if (mswindows_in_modal_loop)
2858 /* Drain windows queue. This sets up number of quit characters in
2860 mswindows_drain_windows_queue ();
2862 if (mswindows_quit_chars_count > 0)
2864 /* Yes there's a hidden one... Throw it away */
2865 Lisp_Event match_against;
2866 Lisp_Object emacs_event;
2869 match_against.event_type = key_press_event;
2870 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2872 while (mswindows_quit_chars_count-- > 0)
2874 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2875 assert (!NILP (emacs_event));
2877 if (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT)
2880 Fdeallocate_event(emacs_event);
2883 Vquit_flag = critical_p ? Qcritical : Qt;
2888 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2889 Lisp_Object* instream,
2890 Lisp_Object* outstream,
2893 /* Handles for streams */
2895 /* fds. These just stored along with the streams, and are closed in
2896 delete stream pair method, because we need to handle fake unices
2900 /* Decode inhandle and outhandle. Their meaning depends on
2901 the process implementation being used. */
2902 #if defined (HAVE_WIN32_PROCESSES)
2903 /* We're passed in Windows handles. That's what we like most... */
2904 hin = (HANDLE) inhandle;
2905 hout = (HANDLE) outhandle;
2907 #elif defined (HAVE_UNIX_PROCESSES)
2908 /* We are passed UNIX fds. This must be Cygwin.
2910 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2911 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2915 #error "So, WHICH kind of processes do you want?"
2918 *instream = (hin == INVALID_HANDLE_VALUE
2920 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2921 : flags & STREAM_NETWORK_CONNECTION
2922 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2924 : make_ntpipe_input_stream (hin, fdi));
2926 #ifdef HAVE_WIN32_PROCESSES
2927 *outstream = (hout == INVALID_HANDLE_VALUE
2929 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2930 : flags & STREAM_NETWORK_CONNECTION
2931 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2933 : make_ntpipe_output_stream (hout, fdo));
2934 #elif defined (HAVE_UNIX_PROCESSES)
2935 *outstream = (fdo >= 0
2936 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2939 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2940 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2941 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2943 Bufbyte eof_char = get_eof_char (fdo);
2944 int pty_max_bytes = get_pty_max_bytes (fdo);
2945 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2950 return (NILP (*instream)
2952 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2953 : flags & STREAM_NETWORK_CONNECTION
2954 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2956 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2960 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2961 Lisp_Object outstream)
2963 /* Oh nothing special here for Win32 at all */
2964 #if defined (HAVE_UNIX_PROCESSES)
2965 int in = (NILP(instream)
2967 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2968 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2969 ? get_winsock_stream_param (XLSTREAM (instream))
2971 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2972 int out = (NILP(outstream) ? -1
2973 : filedesc_stream_fd (XLSTREAM (outstream)));
2977 if (out != in && out >= 0)
2981 return (NILP (instream)
2983 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2984 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2985 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2987 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2990 #ifndef HAVE_X_WINDOWS
2991 /* This is called from GC when a process object is about to be freed.
2992 If we've still got pointers to it in this file, we're gonna lose hard.
2995 debug_process_finalization (Lisp_Process *p)
2998 Lisp_Object instr, outstr;
3000 get_process_streams (p, &instr, &outstr);
3001 /* if it still has fds, then it hasn't been killed yet. */
3002 assert (NILP(instr));
3003 assert (NILP(outstr));
3005 /* #### More checks here */
3010 /************************************************************************/
3011 /* initialization */
3012 /************************************************************************/
3015 reinit_vars_of_event_mswindows (void)
3017 mswindows_in_modal_loop = 0;
3018 mswindows_pending_timers_count = 0;
3020 mswindows_event_stream = xnew (struct event_stream);
3022 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3023 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3024 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3025 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3026 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3027 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3028 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3029 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3030 #ifdef HAVE_MSG_SELECT
3031 mswindows_event_stream->select_process_cb =
3032 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3033 mswindows_event_stream->unselect_process_cb =
3034 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3035 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3036 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3038 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3039 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3040 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3041 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3046 vars_of_event_mswindows (void)
3048 reinit_vars_of_event_mswindows ();
3050 mswindows_u_dispatch_event_queue = Qnil;
3051 staticpro (&mswindows_u_dispatch_event_queue);
3052 mswindows_u_dispatch_event_queue_tail = Qnil;
3053 pdump_wire (&mswindows_u_dispatch_event_queue_tail);
3055 mswindows_s_dispatch_event_queue = Qnil;
3056 staticpro (&mswindows_s_dispatch_event_queue);
3057 mswindows_s_dispatch_event_queue_tail = Qnil;
3058 pdump_wire (&mswindows_s_dispatch_event_queue_tail);
3060 mswindows_error_caught_in_modal_loop = Qnil;
3061 staticpro (&mswindows_error_caught_in_modal_loop);
3063 DEFVAR_BOOL ("mswindows-meta-activates-menu", &mswindows_meta_activates_menu /*
3064 *Controls whether pressing and releasing the Meta (Alt) key should
3065 activate the menubar.
3069 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
3070 *Controls redrawing frame contents during mouse-drag or keyboard resize
3071 operation. When non-nil, the frame is redrawn while being resized. When
3072 nil, frame is not redrawn, and exposed areas are filled with default
3073 MDI application background color. Note that this option only has effect
3074 if "Show window contents while dragging" is on in system Display/Plus!
3076 Default is t on fast machines, nil on slow.
3079 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
3080 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
3081 *Analogue of double click interval for faking middle mouse events.
3082 The value is the minimum time in milliseconds that must elapse between
3083 left/right button down events before they are considered distinct events.
3084 If both mouse buttons are depressed within this interval, a middle mouse
3085 button down event is generated instead.
3086 If negative or zero, currently set system default is used instead.
3089 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
3090 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3091 Number of physical mouse buttons.
3094 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
3095 *Maximum horizontal distance in pixels between points in which left and
3096 right button clicks occurred for them to be translated into single
3097 middle button event. Clicks must occur in time not longer than defined
3098 by the variable `mswindows-mouse-button-tolerance'.
3099 If negative or zero, currently set system default is used instead.
3102 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
3103 *Maximum vertical distance in pixels between points in which left and
3104 right button clicks occurred for them to be translated into single
3105 middle button event. Clicks must occur in time not longer than defined
3106 by the variable `mswindows-mouse-button-tolerance'.
3107 If negative or zero, currently set system default is used instead.
3110 mswindows_mouse_button_max_skew_x = 0;
3111 mswindows_mouse_button_max_skew_y = 0;
3112 mswindows_mouse_button_tolerance = 0;
3113 mswindows_meta_activates_menu = 1;
3117 syms_of_event_mswindows (void)
3122 lstream_type_create_mswindows_selectable (void)
3124 init_slurp_stream ();
3125 init_shove_stream ();
3126 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3127 init_winsock_stream ();
3132 init_event_mswindows_late (void)
3134 #ifdef HAVE_MSG_SELECT
3135 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3136 assert (windows_fd>=0);
3137 FD_SET (windows_fd, &input_wait_mask);
3138 FD_ZERO(&zero_mask);
3141 event_stream = mswindows_event_stream;
3143 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3144 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);