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 /* The number of things we can wait on */
122 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
124 #ifndef HAVE_MSG_SELECT
125 /* List of mswindows waitable handles. */
126 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
128 /* Number of wait handles */
129 static int mswindows_waitable_count=0;
130 #endif /* HAVE_MSG_SELECT */
132 /* Brush for painting widgets */
133 static HBRUSH widget_brush = 0;
134 static LONG last_widget_brushed = 0;
136 /* Count of quit chars currently in the queue */
137 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
138 Decremented in mswindows_dequeue_dispatch_event() */
139 int mswindows_quit_chars_count = 0;
141 /* These are Lisp integers; see DEFVARS in this file for description. */
142 int mswindows_dynamic_frame_resize;
143 int mswindows_meta_activates_menu;
144 int mswindows_num_mouse_buttons;
145 int mswindows_mouse_button_max_skew_x;
146 int mswindows_mouse_button_max_skew_y;
147 int mswindows_mouse_button_tolerance;
149 /* This is the event signaled by the event pump.
150 See mswindows_pump_outstanding_events for comments */
151 static Lisp_Object mswindows_error_caught_in_modal_loop;
152 static int mswindows_in_modal_loop;
154 /* Count of wound timers */
155 static int mswindows_pending_timers_count;
157 /************************************************************************/
158 /* Pipe instream - reads process output */
159 /************************************************************************/
161 #define PIPE_READ_DELAY 20
163 #define HANDLE_TO_USID(h) ((USID)(h))
165 #define NTPIPE_SLURP_STREAM_DATA(stream) \
166 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
168 /* This structure is allocated by the main thread, and is deallocated
169 in the thread upon exit. There are situations when a thread
170 remains blocked for a long time, much longer than the lstream
171 exists. For example, "start notepad" command is issued from the
172 shell, then the shell is closed by C-c C-d. Although the shell
173 process exits, its output pipe will not get closed until the
174 notepad process exits also, because it inherits the pipe form the
175 shell. In this case, we abandon the thread, and let it live until
176 all such processes exit. While struct ntpipe_slurp_stream is
177 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
179 struct ntpipe_slurp_stream_shared_data
181 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
182 /* This is a manual-reset object. */
183 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
184 /* This is a manual-reset object. */
185 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
186 /* This is a manual-reset object. */
187 HANDLE hpipe; /* Pipe read end handle. */
188 LONG die_p; /* Thread must exit ASAP if non-zero */
189 BOOL eof_p : 1; /* Set when thread saw EOF */
190 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
191 BOOL inuse_p : 1; /* this structure is in use */
192 LONG lock_count; /* Client count of this struct, 0=safe to free */
193 BYTE onebyte; /* One byte buffer read by thread */
196 #define MAX_SLURP_STREAMS 32
197 struct ntpipe_slurp_stream_shared_data
198 shared_data_block[MAX_SLURP_STREAMS]={{0}};
200 struct ntpipe_slurp_stream
202 LPARAM user_data; /* Any user data stored in the stream object */
203 struct ntpipe_slurp_stream_shared_data* thread_data;
206 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
207 sizeof (struct ntpipe_slurp_stream));
209 /* This function is thread-safe, and is called from either thread
210 context. It serializes freeing shared data structure */
212 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
214 if (InterlockedDecrement (&s->lock_count) == 0)
217 CloseHandle (s->hev_thread);
218 CloseHandle (s->hev_caller);
219 CloseHandle (s->hev_unsleep);
224 static struct ntpipe_slurp_stream_shared_data*
225 slurper_allocate_shared_data()
228 for (i=0; i<MAX_SLURP_STREAMS; i++)
230 if (!shared_data_block[i].inuse_p)
232 shared_data_block[i].inuse_p=1;
233 return &shared_data_block[i];
236 return (struct ntpipe_slurp_stream_shared_data*)0;
240 slurp_thread (LPVOID vparam)
242 struct ntpipe_slurp_stream_shared_data *s =
243 (struct ntpipe_slurp_stream_shared_data*)vparam;
247 /* Read one byte from the pipe */
249 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
251 DWORD err = GetLastError ();
252 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
257 else if (actually_read == 0)
260 /* We must terminate on an error or eof */
261 if (s->eof_p || s->error_p)
262 InterlockedIncrement (&s->die_p);
264 /* Before we notify caller, we unsignal our event. */
265 ResetEvent (s->hev_thread);
267 /* Now we got something to notify caller, either a byte or an
268 error/eof indication. Before we do, allow internal pipe
269 buffer to accumulate little bit more data.
270 Reader function pulses this event before waiting for
271 a character, to avoid pipe delay, and to get the byte
274 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
276 /* Either make event loop generate a process event, or
278 SetEvent (s->hev_caller);
280 /* Cleanup and exit if we're shot off */
284 /* Block until the client finishes with retrieving the rest of
286 WaitForSingleObject (s->hev_thread, INFINITE);
289 slurper_free_shared_data_maybe (s);
295 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
298 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
299 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
300 DWORD thread_id_unused;
303 /* We deal only with pipes, for we're using PeekNamedPipe api */
304 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
306 s->thread_data = slurper_allocate_shared_data();
308 /* Create reader thread. This could fail, so do not create events
309 until thread is created */
310 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
311 CREATE_SUSPENDED, &thread_id_unused);
314 Lstream_delete (lstr);
315 s->thread_data->inuse_p=0;
319 /* Shared data are initially owned by both main and slurper
321 s->thread_data->lock_count = 2;
322 s->thread_data->die_p = 0;
323 s->thread_data->eof_p = FALSE;
324 s->thread_data->error_p = FALSE;
325 s->thread_data->hpipe = hpipe;
326 s->user_data = param;
328 /* hev_thread is a manual-reset event, initially signaled */
329 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
330 /* hev_caller is a manual-reset event, initially nonsignaled */
331 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
332 /* hev_unsleep is a manual-reset event, initially nonsignaled */
333 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
336 ResumeThread (hthread);
337 CloseHandle (hthread);
339 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
340 XSETLSTREAM (obj, lstr);
345 get_ntpipe_input_stream_param (Lstream *stream)
347 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
352 get_ntpipe_input_stream_waitable (Lstream *stream)
354 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
355 return s->thread_data->hev_caller;
359 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
361 /* This function must be called from the main thread only */
362 struct ntpipe_slurp_stream_shared_data* s =
363 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
368 /* Disallow pipe read delay for the thread: we need a character
370 SetEvent (s->hev_unsleep);
372 /* Check if we have a character ready. Give it a short delay,
373 for the thread to awake from pipe delay, just ion case*/
374 wait_result = WaitForSingleObject (s->hev_caller, 2);
376 /* Revert to the normal sleep behavior. */
377 ResetEvent (s->hev_unsleep);
379 /* If there's no byte buffered yet, give up */
380 if (wait_result == WAIT_TIMEOUT)
387 /* Reset caller unlock event now, as we've handled the pending
388 process output event */
389 ResetEvent (s->hev_caller);
391 /* It is now safe to do anything with contents of S, except for
392 changing s->die_p, which still should be interlocked */
396 if (s->error_p || s->die_p)
399 /* Ok, there were no error neither eof - we've got a byte from the
401 *(data++) = s->onebyte;
405 DWORD bytes_read = 0;
408 DWORD bytes_available;
410 /* If the api call fails, return at least one byte already
411 read. ReadFile in thread will return error */
412 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
415 /* Fetch available bytes. The same consideration applies,
416 so do not check for errors. ReadFile in the thread will
417 fail if the next call fails. */
419 ReadFile (s->hpipe, data, min (bytes_available, size),
423 /* Now we can unblock thread, so it attempts to read more */
424 SetEvent (s->hev_thread);
425 return bytes_read + 1;
432 ntpipe_slurp_closer (Lstream *stream)
434 /* This function must be called from the main thread only */
435 struct ntpipe_slurp_stream_shared_data* s =
436 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
438 /* Force thread to stop */
439 InterlockedIncrement (&s->die_p);
441 /* Set events which could possibly block slurper. Let it finish soon
443 SetEvent (s->hev_unsleep);
444 SetEvent (s->hev_thread);
446 /* Unlock and maybe free shared data */
447 slurper_free_shared_data_maybe (s);
453 init_slurp_stream (void)
455 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
456 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
459 /************************************************************************/
460 /* Pipe outstream - writes process input */
461 /************************************************************************/
463 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
464 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
466 #define MAX_SHOVE_BUFFER_SIZE 128
468 struct ntpipe_shove_stream
470 LPARAM user_data; /* Any user data stored in the stream object */
471 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
472 /* This is an auto-reset object. */
473 HANDLE hpipe; /* Pipe write end handle. */
474 HANDLE hthread; /* Reader thread handle. */
475 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
476 DWORD size; /* Number of bytes to write */
477 LONG die_p; /* Thread must exit ASAP if non-zero */
478 LONG idle_p; /* Non-zero if thread is waiting for job */
479 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
480 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
483 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
484 sizeof (struct ntpipe_shove_stream));
486 #ifndef HAVE_MSG_SELECT
488 shove_thread (LPVOID vparam)
490 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
496 /* Block on event and wait for a job */
497 InterlockedIncrement (&s->idle_p);
498 WaitForSingleObject (s->hev_thread, INFINITE);
503 /* Write passed buffer */
504 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
505 || bytes_written != s->size)
508 InterlockedIncrement (&s->die_p);
519 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
522 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
523 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
524 DWORD thread_id_unused;
529 s->user_data = param;
531 /* Create reader thread. This could fail, so do not
532 create the event until thread is created */
533 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
534 CREATE_SUSPENDED, &thread_id_unused);
535 if (s->hthread == NULL)
537 Lstream_delete (lstr);
541 /* hev_thread is an auto-reset event, initially nonsignaled */
542 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
545 ResumeThread (s->hthread);
547 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
548 XSETLSTREAM (obj, lstr);
553 get_ntpipe_output_stream_param (Lstream *stream)
555 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
561 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
563 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
568 s->blocking_p = !s->idle_p;
572 if (size>MAX_SHOVE_BUFFER_SIZE)
575 memcpy (s->buffer, data, size);
579 InterlockedDecrement (&s->idle_p);
580 SetEvent (s->hev_thread);
585 ntpipe_shove_was_blocked_p (Lstream *stream)
587 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
588 return s->blocking_p;
592 ntpipe_shove_closer (Lstream *stream)
594 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
596 /* Force thread stop */
597 InterlockedIncrement (&s->die_p);
599 /* Close pipe handle, possibly breaking it */
600 CloseHandle (s->hpipe);
602 /* Thread will end upon unblocking */
603 SetEvent (s->hev_thread);
605 /* Wait while thread terminates */
606 WaitForSingleObject (s->hthread, INFINITE);
607 CloseHandle (s->hthread);
609 /* Destroy the event */
610 CloseHandle (s->hev_thread);
616 init_shove_stream (void)
618 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
619 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
620 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
623 /************************************************************************/
624 /* Winsock I/O stream */
625 /************************************************************************/
626 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
628 #define WINSOCK_READ_BUFFER_SIZE 1024
630 struct winsock_stream
632 LPARAM user_data; /* Any user data stored in the stream object */
633 SOCKET s; /* Socket handle (which is a Win32 handle) */
634 OVERLAPPED ov; /* Overlapped I/O structure */
635 void* buffer; /* Buffer. Allocated for input stream only */
636 unsigned long bufsize; /* Number of bytes last read */
637 unsigned long bufpos; /* Position in buffer for next fetch */
638 unsigned int error_p :1; /* I/O Error seen */
639 unsigned int eof_p :1; /* EOF Error seen */
640 unsigned int pending_p :1; /* There is a pending I/O operation */
641 unsigned int blocking_p :1; /* Last write attempt would block */
644 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
646 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
647 sizeof (struct winsock_stream));
650 winsock_initiate_read (struct winsock_stream *str)
652 ResetEvent (str->ov.hEvent);
655 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
656 &str->bufsize, &str->ov))
658 if (GetLastError () == ERROR_IO_PENDING)
660 else if (GetLastError () == ERROR_HANDLE_EOF)
665 else if (str->bufsize == 0)
670 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
672 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
674 /* If the current operation is not yet complete, there's nothing to
678 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
685 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
687 if (GetLastError() == ERROR_HANDLE_EOF)
692 if (str->bufsize == 0)
703 /* Return as much of buffer as we have */
704 size = min (size, (size_t) (str->bufsize - str->bufpos));
705 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
708 /* Read more if buffer is exhausted */
709 if (str->bufsize == str->bufpos)
710 winsock_initiate_read (str);
716 winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
718 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
722 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
730 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
745 ResetEvent (str->ov.hEvent);
747 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
748 * an overlapped operation. This fails on Win95 with winsock 1.x so we
749 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
750 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
751 || GetLastError() == ERROR_IO_PENDING)
757 return str->error_p ? -1 : size;
761 winsock_closer (Lstream *lstr)
763 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
765 if (lstr->flags & LSTREAM_FL_READ)
766 shutdown (str->s, 0);
768 shutdown (str->s, 1);
770 CloseHandle ((HANDLE)str->s);
772 WaitForSingleObject (str->ov.hEvent, INFINITE);
774 if (lstr->flags & LSTREAM_FL_READ)
777 CloseHandle (str->ov.hEvent);
782 winsock_was_blocked_p (Lstream *stream)
784 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
785 return str->blocking_p;
789 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
792 Lstream *lstr = Lstream_new (lstream_winsock, mode);
793 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
800 str->user_data = param;
803 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
805 if (lstr->flags & LSTREAM_FL_READ)
807 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
808 winsock_initiate_read (str);
811 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
812 XSETLSTREAM (obj, lstr);
817 make_winsock_input_stream (SOCKET s, LPARAM param)
819 return make_winsock_stream_1 (s, param, "r");
823 make_winsock_output_stream (SOCKET s, LPARAM param)
825 return make_winsock_stream_1 (s, param, "w");
829 get_winsock_stream_waitable (Lstream *lstr)
831 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
832 return str->ov.hEvent;
836 get_winsock_stream_param (Lstream *lstr)
838 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
839 return str->user_data;
843 init_winsock_stream (void)
845 LSTREAM_HAS_METHOD (winsock, reader);
846 LSTREAM_HAS_METHOD (winsock, writer);
847 LSTREAM_HAS_METHOD (winsock, closer);
848 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
850 #endif /* defined (HAVE_SOCKETS) */
852 /************************************************************************/
853 /* Dispatch queue management */
854 /************************************************************************/
857 mswindows_user_event_p (Lisp_Event* sevt)
859 return (sevt->event_type == key_press_event
860 || sevt->event_type == button_press_event
861 || sevt->event_type == button_release_event
862 || sevt->event_type == misc_user_event);
866 * Add an emacs event to the proper dispatch queue
869 mswindows_enqueue_dispatch_event (Lisp_Object event)
871 int user_p = mswindows_user_event_p (XEVENT(event));
872 enqueue_event (event,
873 user_p ? &mswindows_u_dispatch_event_queue :
874 &mswindows_s_dispatch_event_queue,
875 user_p ? &mswindows_u_dispatch_event_queue_tail :
876 &mswindows_s_dispatch_event_queue_tail);
878 /* Avoid blocking on WaitMessage */
879 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
883 * Add a misc-user event to the dispatch queue.
885 * Stuff it into our own dispatch queue, so we have something
886 * to return from next_event callback.
889 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
892 Lisp_Object event = Fmake_event (Qnil, Qnil);
893 Lisp_Event* e = XEVENT (event);
895 e->event_type = misc_user_event;
896 e->channel = channel;
897 e->timestamp = GetTickCount ();
898 e->event.misc.function = function;
899 e->event.misc.object = object;
901 mswindows_enqueue_dispatch_event (event);
905 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
907 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
908 Lisp_Event* event = XEVENT (emacs_event);
910 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
911 event->timestamp = GetMessageTime();
912 event->event_type = magic_event;
913 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
915 mswindows_enqueue_dispatch_event (emacs_event);
919 mswindows_enqueue_process_event (Lisp_Process* p)
921 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
922 Lisp_Event* event = XEVENT (emacs_event);
924 XSETPROCESS (process, p);
926 event->event_type = process_event;
927 event->timestamp = GetTickCount ();
928 event->event.process.process = process;
930 mswindows_enqueue_dispatch_event (emacs_event);
934 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when)
937 /* We always use last message time, because mouse button
938 events may get delayed, and XEmacs double click
939 recognition will fail */
941 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
942 Lisp_Event* event = XEVENT(emacs_event);
944 event->channel = mswindows_find_frame(hwnd);
945 event->timestamp = when;
946 event->event.button.button =
947 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
948 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
949 event->event.button.x = where.x;
950 event->event.button.y = where.y;
951 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
953 if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN ||
956 event->event_type = button_press_event;
958 /* we need this to make sure the main window regains the focus
959 from control subwindows */
960 if (GetFocus() != hwnd)
963 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
968 event->event_type = button_release_event;
972 mswindows_enqueue_dispatch_event (emacs_event);
976 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
978 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
979 Lisp_Event* event = XEVENT(emacs_event);
981 event->channel = mswindows_find_console(hwnd);
982 event->timestamp = GetMessageTime();
983 event->event_type = key_press_event;
984 event->event.key.keysym = keysym;
985 event->event.key.modifiers = mods;
986 mswindows_enqueue_dispatch_event (emacs_event);
990 * Remove and return the first emacs event on the dispatch queue.
991 * Give a preference to user events over non-user ones.
994 mswindows_dequeue_dispatch_event ()
999 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1000 !NILP(mswindows_s_dispatch_event_queue));
1002 event = dequeue_event (
1003 NILP(mswindows_u_dispatch_event_queue) ?
1004 &mswindows_s_dispatch_event_queue :
1005 &mswindows_u_dispatch_event_queue,
1006 NILP(mswindows_u_dispatch_event_queue) ?
1007 &mswindows_s_dispatch_event_queue_tail :
1008 &mswindows_u_dispatch_event_queue_tail);
1010 sevt = XEVENT(event);
1011 if (sevt->event_type == key_press_event
1012 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1014 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1015 --mswindows_quit_chars_count;
1022 * Remove and return the first emacs event on the dispatch queue that matches
1023 * the supplied event.
1024 * Timeout event matches if interval_id is equal to that of the given event.
1025 * Keypress event matches if logical AND between modifiers bitmask of the
1026 * event in the queue and that of the given event is non-zero.
1027 * For all other event types, this function aborts.
1031 mswindows_cancel_dispatch_event (Lisp_Event *match)
1034 Lisp_Object previous_event = Qnil;
1035 int user_p = mswindows_user_event_p (match);
1036 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1037 &mswindows_s_dispatch_event_queue;
1038 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1039 &mswindows_s_dispatch_event_queue_tail;
1041 assert (match->event_type == timeout_event
1042 || match->event_type == key_press_event);
1044 EVENT_CHAIN_LOOP (event, *head)
1046 Lisp_Event *e = XEVENT (event);
1047 if ((e->event_type == match->event_type) &&
1048 ((e->event_type == timeout_event) ?
1049 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1050 /* Must be key_press_event */
1051 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1053 if (NILP (previous_event))
1054 dequeue_event (head, tail);
1057 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1058 if (EQ (*tail, event))
1059 *tail = previous_event;
1064 previous_event = event;
1069 #ifndef HAVE_MSG_SELECT
1070 /************************************************************************/
1071 /* Waitable handles manipulation */
1072 /************************************************************************/
1074 find_waitable_handle (HANDLE h)
1077 for (i = 0; i < mswindows_waitable_count; ++i)
1078 if (mswindows_waitable_handles[i] == h)
1085 add_waitable_handle (HANDLE h)
1087 assert (find_waitable_handle (h) < 0);
1088 if (mswindows_waitable_count == MAX_WAITABLE)
1091 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1096 remove_waitable_handle (HANDLE h)
1098 int ix = find_waitable_handle (h);
1102 mswindows_waitable_handles [ix] =
1103 mswindows_waitable_handles [--mswindows_waitable_count];
1105 #endif /* HAVE_MSG_SELECT */
1108 /************************************************************************/
1110 /************************************************************************/
1113 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1114 Lisp_Object u_n_u_s_e_d)
1116 mswindows_error_caught_in_modal_loop = cons_sig_data;
1121 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1126 ++mswindows_in_modal_loop;
1127 tmp = condition_case_1 (Qt,
1129 mswindows_modal_loop_error_handler, Qnil);
1130 --mswindows_in_modal_loop;
1136 mswindows_unmodalize_signal_maybe (void)
1138 if (!NILP (mswindows_error_caught_in_modal_loop))
1140 /* Got an error while messages were pumped while
1141 in window procedure - have to resignal */
1142 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1143 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1144 mswindows_error_caught_in_modal_loop = Qnil;
1145 Fsignal (sym, data);
1150 * This is an unsafe part of event pump, guarded by
1151 * condition_case. See mswindows_pump_outstanding_events
1154 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1156 /* This function can call lisp */
1157 Lisp_Object event = Fmake_event (Qnil, Qnil);
1158 struct gcpro gcpro1;
1159 int do_redisplay = 0;
1162 while (detect_input_pending ())
1164 Fnext_event (event, Qnil);
1165 Fdispatch_event (event);
1172 Fdeallocate_event (event);
1175 /* Qt becomes return value of mswindows_pump_outstanding_events
1181 * This function pumps emacs events, while available, by using
1182 * next_message/dispatch_message loop. Errors are trapped around
1183 * the loop so the function always returns.
1185 * Windows message queue is not looked into during the call,
1186 * neither are waitable handles checked. The function pumps
1187 * thus only dispatch events already queued, as well as those
1188 * resulted in dispatching thereof. This is done by setting
1189 * module local variable mswindows_in_modal_loop to nonzero.
1191 * Return value is Qt if no errors was trapped, or Qunbound if
1192 * there was an error.
1194 * In case of error, a cons representing the error, in the
1195 * form (SIGNAL . DATA), is stored in the module local variable
1196 * mswindows_error_caught_in_modal_loop. This error is signaled
1197 * again when DispatchMessage returns. Thus, Windows internal
1198 * modal loops are protected against throws, which are proven
1199 * to corrupt internal Windows structures.
1201 * In case of success, mswindows_error_caught_in_modal_loop is
1204 * If the value of mswindows_error_caught_in_modal_loop is not
1205 * nil already upon entry, the function just returns non-nil.
1206 * This situation means that a new event has been queued while
1207 * in cancel mode. The event will be dequeued on the next regular
1208 * call of next-event; the pump is off since error is caught.
1209 * The caller must *unconditionally* cancel modal loop if the
1210 * value returned by this function is nil. Otherwise, everything
1211 * will become frozen until the modal loop exits under normal
1212 * condition (scrollbar drag is released, menu closed etc.)
1215 mswindows_pump_outstanding_events (void)
1217 /* This function can call lisp */
1219 Lisp_Object result = Qt;
1220 struct gcpro gcpro1;
1223 if (NILP(mswindows_error_caught_in_modal_loop))
1224 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1230 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1231 * QUITP, and are interesting in keyboard messages only.
1234 mswindows_drain_windows_queue ()
1238 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1239 assert (!mswindows_in_modal_loop);
1241 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1243 /* We have to translate messages that are not sent to the main
1244 window. This is so that key presses work ok in things like
1245 edit fields. However, we *musn't* translate message for the
1246 main window as this is handled in the wnd proc. */
1247 if (GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD)
1249 TranslateMessage (&msg);
1251 else if (msg.message == WM_PAINT)
1253 /* hdc will be NULL unless this is a subwindow - in which case we
1254 shouldn't have received a paint message for it here. */
1255 assert (msg.wParam == 0);
1257 /* Queue a magic event for handling when safe */
1258 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1260 /* Don't dispatch. WM_PAINT is always the last message in the
1261 queue so it's OK to just return. */
1264 DispatchMessage (&msg);
1265 mswindows_unmodalize_signal_maybe ();
1270 * This is a special flavor of the mswindows_need_event function,
1271 * used while in event pump. Actually, there is only kind of events
1272 * allowed while in event pump: a timer. An attempt to fetch any
1273 * other event leads to a deadlock, as there's no source of user input
1274 * ('cause event pump mirrors windows modal loop, which is a sole
1275 * owner of thread message queue).
1277 * To detect this, we use a counter of active timers, and allow
1278 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1279 * which will never come when there are no pending timers, which leads
1280 * to deadlock, we simply signal an error.
1283 mswindows_need_event_in_modal_loop (int badly_p)
1287 /* Check if already have one */
1288 if (!NILP (mswindows_u_dispatch_event_queue)
1289 || !NILP (mswindows_s_dispatch_event_queue))
1292 /* No event is ok */
1296 /* We do not check the _u_ queue, because timers go to _s_ */
1297 while (NILP (mswindows_s_dispatch_event_queue))
1299 /* We'll deadlock if go waiting */
1300 if (mswindows_pending_timers_count == 0)
1301 error ("Deadlock due to an attempt to call next-event in a wrong context");
1303 /* Fetch and dispatch any pending timers */
1304 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1305 DispatchMessage (&msg);
1310 * This drains the event queue and fills up two internal queues until
1311 * an event of a type specified by USER_P is retrieved.
1314 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1317 mswindows_need_event (int badly_p)
1321 if (mswindows_in_modal_loop)
1323 mswindows_need_event_in_modal_loop (badly_p);
1327 while (NILP (mswindows_u_dispatch_event_queue)
1328 && NILP (mswindows_s_dispatch_event_queue))
1330 #ifdef HAVE_MSG_SELECT
1332 SELECT_TYPE temp_mask = input_wait_mask;
1333 EMACS_TIME sometime;
1334 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1337 pointer_to_this = 0;
1340 EMACS_SET_SECS_USECS (sometime, 0, 0);
1341 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1342 pointer_to_this = &select_time_to_block;
1345 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1350 return; /* timeout */
1352 else if (active > 0)
1354 if (FD_ISSET (windows_fd, &temp_mask))
1356 mswindows_drain_windows_queue ();
1359 /* Look for a TTY event */
1360 for (i = 0; i < MAXDESC-1; i++)
1362 /* To avoid race conditions (among other things, an infinite
1363 loop when called from Fdiscard_input()), we must return
1364 user events ahead of process events. */
1365 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1367 struct console *c = tty_find_console_from_fd (i);
1368 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1369 Lisp_Event* event = XEVENT (emacs_event);
1372 if (read_event_from_tty_or_stream_desc (event, c, i))
1374 mswindows_enqueue_dispatch_event (emacs_event);
1380 /* Look for a process event */
1381 for (i = 0; i < MAXDESC-1; i++)
1383 if (FD_ISSET (i, &temp_mask))
1385 if (FD_ISSET (i, &process_only_mask))
1388 get_process_from_usid (FD_TO_USID(i));
1390 mswindows_enqueue_process_event (p);
1394 /* We might get here when a fake event came
1395 through a signal. Return a dummy event, so
1396 that a cycle of the command loop will
1398 drain_signal_event_pipe ();
1399 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1404 else if (active==-1)
1408 /* something bad happened */
1417 /* Now try getting a message or process event */
1418 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1419 mswindows_waitable_handles,
1420 FALSE, badly_p ? INFINITE : 0,
1423 /* This will assert if handle being waited for becomes abandoned.
1424 Not the case currently tho */
1425 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1426 (active >= WAIT_OBJECT_0 &&
1427 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1429 if (active == WAIT_TIMEOUT)
1431 /* No luck trying - just return what we've already got */
1434 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1436 /* Got your message, thanks */
1437 mswindows_drain_windows_queue ();
1441 int ix = active - WAIT_OBJECT_0;
1442 /* First, try to find which process' output has signaled */
1444 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1447 /* Found a signaled process input handle */
1448 mswindows_enqueue_process_event (p);
1452 /* None. This means that the process handle itself has signaled.
1453 Remove the handle from the wait vector, and make status_notify
1454 note the exited process */
1455 mswindows_waitable_handles [ix] =
1456 mswindows_waitable_handles [--mswindows_waitable_count];
1457 kick_status_notify ();
1458 /* Have to return something: there may be no accompanying
1460 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1467 /************************************************************************/
1468 /* Event generators */
1469 /************************************************************************/
1472 * Callback procedure for synchronous timer messages
1474 static void CALLBACK
1475 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1477 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1478 Lisp_Event *event = XEVENT (emacs_event);
1480 if (KillTimer (NULL, id_timer))
1481 --mswindows_pending_timers_count;
1483 event->channel = Qnil;
1484 event->timestamp = dwtime;
1485 event->event_type = timeout_event;
1486 event->event.timeout.interval_id = id_timer;
1487 event->event.timeout.function = Qnil;
1488 event->event.timeout.object = Qnil;
1490 mswindows_enqueue_dispatch_event (emacs_event);
1494 * Callback procedure for dde messages
1496 * We execute a dde Open("file") by simulating a file drop, so dde support
1497 * depends on dnd support.
1499 #ifdef HAVE_DRAGNDROP
1501 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1502 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1503 DWORD dwData1, DWORD dwData2)
1508 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1509 return (HDDEDATA)TRUE;
1510 return (HDDEDATA)FALSE;
1512 case XTYP_WILDCONNECT:
1514 /* We only support one {service,topic} pair */
1515 HSZPAIR pairs[2] = {
1516 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1518 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1519 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1520 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1521 sizeof (pairs), 0L, 0, uFmt, 0));
1523 return (HDDEDATA)NULL;
1526 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1528 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1529 LPBYTE cmd = (LPBYTE) alloca (len+1);
1532 struct gcpro gcpro1, gcpro2;
1533 Lisp_Object l_dndlist = Qnil;
1534 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1535 Lisp_Object frmcons, devcons, concons;
1536 Lisp_Event *event = XEVENT (emacs_event);
1538 DdeGetData (hdata, cmd, len, 0);
1540 DdeFreeDataHandle (hdata);
1542 /* Check syntax & that it's an [Open("foo")] command, which we
1543 * treat like a file drop */
1544 /* #### Ought to be generalised and accept some other commands */
1547 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1548 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1549 return DDE_FNOTPROCESSED;
1550 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1553 if (*cmd!='(' || *(cmd+1)!='\"')
1554 return DDE_FNOTPROCESSED;
1556 while (*end && *end!='\"')
1559 return DDE_FNOTPROCESSED;
1562 return DDE_FNOTPROCESSED;
1566 return DDE_FNOTPROCESSED;
1569 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1570 strcpy (filename, "file:");
1571 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1573 dostounix_filename (cmd);
1574 filename = alloca (strlen (cmd)+6);
1575 strcpy (filename, "file:");
1576 strcat (filename, cmd);
1578 GCPRO2 (emacs_event, l_dndlist);
1579 l_dndlist = make_string (filename, strlen (filename));
1581 /* Find a mswindows frame */
1582 event->channel = Qnil;
1583 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1585 Lisp_Object frame = XCAR (frmcons);
1586 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1587 event->channel = frame;
1589 assert (!NILP (event->channel));
1591 event->timestamp = GetTickCount();
1592 event->event_type = misc_user_event;
1593 event->event.misc.button = 1;
1594 event->event.misc.modifiers = 0;
1595 event->event.misc.x = -1;
1596 event->event.misc.y = -1;
1597 event->event.misc.function = Qdragdrop_drop_dispatch;
1598 event->event.misc.object = Fcons (Qdragdrop_URL,
1599 Fcons (l_dndlist, Qnil));
1600 mswindows_enqueue_dispatch_event (emacs_event);
1602 return (HDDEDATA) DDE_FACK;
1604 DdeFreeDataHandle (hdata);
1605 return (HDDEDATA) DDE_FNOTPROCESSED;
1608 return (HDDEDATA) NULL;
1614 * Helper to do repainting - repaints can happen both from the windows
1615 * procedure and from magic events
1618 mswindows_handle_paint (struct frame *frame)
1620 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1622 /* According to the docs we need to check GetUpdateRect() before
1623 actually doing a WM_PAINT */
1624 if (GetUpdateRect (hwnd, NULL, FALSE))
1626 PAINTSTRUCT paintStruct;
1627 int x, y, width, height;
1629 BeginPaint (hwnd, &paintStruct);
1630 x = paintStruct.rcPaint.left;
1631 y = paintStruct.rcPaint.top;
1632 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1633 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1634 /* Normally we want to ignore expose events when child
1635 windows are unmapped, however once we are in the guts of
1636 WM_PAINT we need to make sure that we don't register
1637 unmaps then because they will not actually occur. */
1638 if (!check_for_ignored_expose (frame, x, y, width, height))
1640 hold_ignored_expose_registration = 1;
1641 mswindows_redraw_exposed_area (frame, x, y, width, height);
1642 hold_ignored_expose_registration = 0;
1644 EndPaint (hwnd, &paintStruct);
1649 * Returns 1 if a key is a real modifier or special key, which
1650 * is better handled by DefWindowProc
1653 key_needs_default_processing_p (UINT vkey)
1655 if (mswindows_meta_activates_menu && vkey == VK_MENU)
1662 * The windows procedure for the window class XEMACS_CLASS
1665 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1667 /* Note: Remember to initialize emacs_event and event before use.
1668 This code calls code that can GC. You must GCPRO before calling such code. */
1669 Lisp_Object emacs_event = Qnil;
1670 Lisp_Object fobj = Qnil;
1673 struct frame *frame;
1674 struct mswindows_frame* msframe;
1678 case WM_DESTROYCLIPBOARD:
1679 /* We own the clipboard and someone else wants it. Delete our
1680 cached copy of the clipboard contents so we'll ask for it from
1681 Windows again when someone does a paste. */
1682 handle_selection_clear(QCLIPBOARD);
1686 /* Erase background only during non-dynamic sizing */
1687 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1688 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1693 fobj = mswindows_find_frame (hwnd);
1694 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1699 /* See Win95 comment under WM_KEYDOWN */
1703 if (wParam == VK_CONTROL)
1705 GetKeyboardState (keymap);
1706 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1707 SetKeyboardState (keymap);
1709 else if (wParam == VK_MENU)
1711 GetKeyboardState (keymap);
1712 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1713 SetKeyboardState (keymap);
1716 if (key_needs_default_processing_p (wParam))
1723 /* In some locales the right-hand Alt key is labelled AltGr. This key
1724 * should produce alternative charcaters when combined with another key.
1725 * eg on a German keyboard pressing AltGr+q should produce '@'.
1726 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1727 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1728 * it translates as if AltGr were down.
1729 * We get round this by removing all modifiers from the keymap before
1730 * calling TranslateMessage() unless AltGr is *really* down. */
1733 int has_AltGr = mswindows_current_layout_has_AltGr ();
1735 int extendedp = lParam & 0x1000000;
1738 GetKeyboardState (keymap);
1739 mods = mswindows_modifier_state (keymap, has_AltGr);
1741 /* Handle non-printables */
1742 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
1744 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1745 else /* Normal keys & modifiers */
1747 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1748 BYTE keymap_orig[256];
1749 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1753 msg.message = message;
1754 msg.wParam = wParam;
1755 msg.lParam = lParam;
1756 msg.time = GetMessageTime();
1759 /* GetKeyboardState() does not work as documented on Win95. We have
1760 * to loosely track Left and Right modifiers on behalf of the OS,
1761 * without screwing up Windows NT which tracks them properly. */
1762 if (wParam == VK_CONTROL)
1763 keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1764 else if (wParam == VK_MENU)
1765 keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
1767 memcpy (keymap_orig, keymap, 256);
1769 /* Remove shift modifier from an ascii character */
1772 /* Clear control and alt modifiers unless AltGr is pressed */
1773 keymap [VK_RCONTROL] = 0;
1774 keymap [VK_LMENU] = 0;
1775 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80)
1776 || !(keymap [VK_RMENU] & 0x80))
1778 keymap [VK_LCONTROL] = 0;
1779 keymap [VK_CONTROL] = 0;
1780 keymap [VK_RMENU] = 0;
1781 keymap [VK_MENU] = 0;
1783 SetKeyboardState (keymap);
1785 /* Maybe generate some WM_[SYS]CHARs in the queue */
1786 TranslateMessage (&msg);
1788 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1789 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1792 WPARAM ch = msg.wParam;
1794 /* If a quit char with no modifiers other than control and
1795 shift, then mark it with a fake modifier, which is removed
1796 upon dequeueing the event */
1797 /* #### This might also not withstand localization, if
1798 quit character is not a latin-1 symbol */
1799 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1800 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1801 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1803 mods1 |= FAKE_MOD_QUIT;
1804 ++mswindows_quit_chars_count;
1807 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1809 SetKeyboardState (keymap_orig);
1812 if (key_needs_default_processing_p (wParam))
1817 case WM_MBUTTONDOWN:
1819 /* Real middle mouse button has nothing to do with emulated one:
1820 if one wants to exercise fingers playing chords on the mouse,
1821 he is allowed to do that! */
1822 mswindows_enqueue_mouse_button_event (hwnd, message,
1823 MAKEPOINTS (lParam), GetMessageTime());
1827 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1828 msframe->last_click_time = GetMessageTime();
1830 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1831 msframe->button2_need_lbutton = 0;
1832 if (msframe->ignore_next_lbutton_up)
1834 msframe->ignore_next_lbutton_up = 0;
1836 else if (msframe->button2_is_down)
1838 msframe->button2_is_down = 0;
1839 msframe->ignore_next_rbutton_up = 1;
1840 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1841 MAKEPOINTS (lParam), GetMessageTime());
1845 if (msframe->button2_need_rbutton)
1847 msframe->button2_need_rbutton = 0;
1848 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1849 MAKEPOINTS (lParam), GetMessageTime());
1851 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1852 MAKEPOINTS (lParam), GetMessageTime());
1857 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1858 msframe->last_click_time = GetMessageTime();
1860 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1861 msframe->button2_need_rbutton = 0;
1862 if (msframe->ignore_next_rbutton_up)
1864 msframe->ignore_next_rbutton_up = 0;
1866 else if (msframe->button2_is_down)
1868 msframe->button2_is_down = 0;
1869 msframe->ignore_next_lbutton_up = 1;
1870 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1871 MAKEPOINTS (lParam), GetMessageTime());
1875 if (msframe->button2_need_lbutton)
1877 msframe->button2_need_lbutton = 0;
1878 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1879 MAKEPOINTS (lParam), GetMessageTime());
1881 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1882 MAKEPOINTS (lParam), GetMessageTime());
1886 case WM_LBUTTONDOWN:
1887 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1889 if (msframe->button2_need_lbutton)
1891 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1892 msframe->button2_need_lbutton = 0;
1893 msframe->button2_need_rbutton = 0;
1894 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1896 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1897 MAKEPOINTS (lParam), GetMessageTime());
1898 msframe->button2_is_down = 1;
1902 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1903 msframe->last_click_point, msframe->last_click_time);
1904 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1905 MAKEPOINTS (lParam), GetMessageTime());
1910 mswindows_set_chord_timer (hwnd);
1911 msframe->button2_need_rbutton = 1;
1912 msframe->last_click_point = MAKEPOINTS (lParam);
1914 msframe->last_click_time = GetMessageTime();
1917 case WM_RBUTTONDOWN:
1918 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1920 if (msframe->button2_need_rbutton)
1922 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1923 msframe->button2_need_lbutton = 0;
1924 msframe->button2_need_rbutton = 0;
1925 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1927 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1928 MAKEPOINTS (lParam), GetMessageTime());
1929 msframe->button2_is_down = 1;
1933 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1934 msframe->last_click_point, msframe->last_click_time);
1935 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1936 MAKEPOINTS (lParam), GetMessageTime());
1941 mswindows_set_chord_timer (hwnd);
1942 msframe->button2_need_lbutton = 1;
1943 msframe->last_click_point = MAKEPOINTS (lParam);
1945 msframe->last_click_time = GetMessageTime();
1949 if (wParam == BUTTON_2_TIMER_ID)
1951 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1952 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1954 if (msframe->button2_need_lbutton)
1956 msframe->button2_need_lbutton = 0;
1957 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1958 msframe->last_click_point, msframe->last_click_time);
1960 else if (msframe->button2_need_rbutton)
1962 msframe->button2_need_rbutton = 0;
1963 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1964 msframe->last_click_point, msframe->last_click_time);
1968 assert ("Spurious timer fired" == 0);
1972 /* Optimization: don't report mouse movement while size is changing */
1973 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1974 if (!msframe->sizing)
1976 /* When waiting for the second mouse button to finish
1977 button2 emulation, and have moved too far, just pretend
1978 as if timer has expired. This improves drag-select feedback */
1979 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1980 && !mswindows_button2_near_enough (msframe->last_click_point,
1981 MAKEPOINTS (lParam)))
1983 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1984 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1987 emacs_event = Fmake_event (Qnil, Qnil);
1988 event = XEVENT(emacs_event);
1990 event->channel = mswindows_find_frame(hwnd);
1991 event->timestamp = GetMessageTime();
1992 event->event_type = pointer_motion_event;
1993 event->event.motion.x = MAKEPOINTS(lParam).x;
1994 event->event.motion.y = MAKEPOINTS(lParam).y;
1995 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1997 mswindows_enqueue_dispatch_event (emacs_event);
2003 /* Queue a `cancel-mode-internal' misc user event, so mouse
2004 selection would be canceled if any */
2005 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2006 Qcancel_mode_internal, Qnil);
2011 LPNMHDR nmhdr = (LPNMHDR)lParam;
2013 if (nmhdr->code == TTN_NEEDTEXT)
2015 #ifdef HAVE_TOOLBARS
2016 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2019 /* find out which toolbar */
2020 frame = XFRAME (mswindows_find_frame (hwnd));
2021 btext = mswindows_get_toolbar_button_text ( frame,
2024 tttext->lpszText = NULL;
2025 tttext->hinst = NULL;
2029 /* I think this is safe since the text will only go away
2030 when the toolbar does...*/
2031 TO_EXTERNAL_FORMAT (LISP_STRING, btext,
2032 C_STRING_ALLOCA, tttext->lpszText,
2037 /* handle tree view callbacks */
2038 else if (nmhdr->code == TVN_SELCHANGED)
2040 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2041 frame = XFRAME (mswindows_find_frame (hwnd));
2042 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2044 /* handle tab control callbacks */
2045 else if (nmhdr->code == TCN_SELCHANGE)
2048 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2049 frame = XFRAME (mswindows_find_frame (hwnd));
2051 item.mask = TCIF_PARAM;
2052 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2055 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2061 /* hdc will be NULL unless this is a subwindow - in which case we
2062 shouldn't have received a paint message for it here. */
2063 assert (wParam == 0);
2065 /* Can't queue a magic event because windows goes modal and sends paint
2066 messages directly to the windows procedure when doing solid drags
2067 and the message queue doesn't get processed. */
2068 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2072 /* We only care about this message if our size has really changed */
2073 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2078 fobj = mswindows_find_frame (hwnd);
2079 frame = XFRAME (fobj);
2080 msframe = FRAME_MSWINDOWS_DATA (frame);
2082 /* We cannot handle frame map and unmap hooks right in
2083 this routine, because these may throw. We queue
2084 magic events to run these hooks instead - kkm */
2086 if (wParam==SIZE_MINIMIZED)
2089 FRAME_VISIBLE_P (frame) = 0;
2090 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2094 GetClientRect(hwnd, &rect);
2095 FRAME_PIXWIDTH(frame) = rect.right;
2096 FRAME_PIXHEIGHT(frame) = rect.bottom;
2098 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2099 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2100 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2102 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2103 change_frame_size (frame, rows, columns, 1);
2105 /* If we are inside frame creation, we have to apply geometric
2107 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2109 /* Yes, we have to size again */
2110 mswindows_size_frame_internal ( frame,
2111 FRAME_MSWINDOWS_TARGET_RECT
2113 /* Reset so we do not get here again. The SetWindowPos call in
2114 * mswindows_size_frame_internal can cause recursion here. */
2115 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2117 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2118 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2123 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2124 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2125 FRAME_VISIBLE_P (frame) = 1;
2127 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2134 /* Misc magic events which only require that the frame be identified */
2137 mswindows_enqueue_magic_event (hwnd, message);
2140 case WM_WINDOWPOSCHANGING:
2142 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2143 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2144 GetWindowPlacement(hwnd, &wpl);
2146 /* Only interested if size is changing and we're not being iconified */
2147 if (wpl.showCmd != SW_SHOWMINIMIZED
2148 && wpl.showCmd != SW_SHOWMAXIMIZED
2149 && !(wp->flags & SWP_NOSIZE))
2151 RECT ncsize = { 0, 0, 0, 0 };
2152 int pixwidth, pixheight;
2153 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2154 GetMenu(hwnd) != NULL,
2155 GetWindowLong (hwnd, GWL_EXSTYLE));
2157 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2158 wp->cx - (ncsize.right - ncsize.left),
2159 wp->cy - (ncsize.bottom - ncsize.top),
2160 &pixwidth, &pixheight);
2162 /* Convert client sizes to window sizes */
2163 pixwidth += (ncsize.right - ncsize.left);
2164 pixheight += (ncsize.bottom - ncsize.top);
2166 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2168 /* Adjust so that the bottom or right doesn't move if it's
2169 * the top or left that's being changed */
2171 GetWindowRect (hwnd, &rect);
2173 if (rect.left != wp->x)
2174 wp->x += wp->cx - pixwidth;
2175 if (rect.top != wp->y)
2176 wp->y += wp->cy - pixheight;
2182 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2183 window position if the user tries to track window too small */
2187 case WM_ENTERSIZEMOVE:
2188 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2189 msframe->sizing = 1;
2192 case WM_EXITSIZEMOVE:
2193 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2194 msframe->sizing = 0;
2195 /* Queue noop event */
2196 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2199 #ifdef HAVE_SCROLLBARS
2203 /* Direction of scroll is determined by scrollbar instance. */
2204 int code = (int) LOWORD(wParam);
2205 int pos = (short int) HIWORD(wParam);
2206 HWND hwndScrollBar = (HWND) lParam;
2207 struct gcpro gcpro1, gcpro2;
2209 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2210 GCPRO2 (emacs_event, fobj);
2211 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2213 /* Error during event pumping - cancel scroll */
2214 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2222 int keys = LOWORD (wParam); /* Modifier key flags */
2223 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2224 struct gcpro gcpro1, gcpro2;
2226 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2228 GCPRO2 (emacs_event, fobj);
2229 mswindows_pump_outstanding_events (); /* Can GC */
2238 #ifdef HAVE_MENUBARS
2240 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2242 XFRAME (mswindows_find_frame (hwnd)))))
2243 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2246 case WM_INITMENUPOPUP:
2247 if (!HIWORD(lParam))
2249 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2251 XFRAME (mswindows_find_frame (hwnd)))))
2252 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2256 #endif /* HAVE_MENUBARS */
2260 WORD id = LOWORD (wParam);
2261 WORD nid = HIWORD (wParam);
2262 HWND cid = (HWND)lParam;
2263 frame = XFRAME (mswindows_find_frame (hwnd));
2265 #ifdef HAVE_TOOLBARS
2266 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2269 /* widgets in a buffer only eval a callback for suitable events.*/
2274 case CBN_EDITCHANGE:
2276 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2279 /* menubars always must come last since the hashtables do not
2281 #ifdef HAVE_MENUBARS
2282 if (!NILP (mswindows_handle_wm_command (frame, id)))
2286 return DefWindowProc (hwnd, message, wParam, lParam);
2287 /* Bite me - a spurious command. This used to not be able to
2288 happen but with the introduction of widgets its now
2293 case WM_CTLCOLORBTN:
2294 case WM_CTLCOLORLISTBOX:
2295 case WM_CTLCOLOREDIT:
2296 case WM_CTLCOLORSTATIC:
2297 case WM_CTLCOLORSCROLLBAR:
2299 /* if we get an opportunity to paint a widget then do so if
2300 there is an appropriate face */
2301 HWND crtlwnd = (HWND)lParam;
2302 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2305 Lisp_Object image_instance;
2306 VOID_TO_LISP (image_instance, ii);
2307 if (IMAGE_INSTANCEP (image_instance)
2309 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2311 /* set colors for the buttons */
2312 HDC hdc = (HDC)wParam;
2313 if (last_widget_brushed != ii)
2316 DeleteObject (widget_brush);
2317 widget_brush = CreateSolidBrush
2318 (COLOR_INSTANCE_MSWINDOWS_COLOR
2321 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2322 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2324 last_widget_brushed = ii;
2327 COLOR_INSTANCE_MSWINDOWS_COLOR
2330 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2331 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2332 SetBkMode (hdc, OPAQUE);
2335 COLOR_INSTANCE_MSWINDOWS_COLOR
2338 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2339 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2340 return (LRESULT)widget_brush;
2346 #ifdef HAVE_DRAGNDROP
2347 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2349 UINT filecount, i, len;
2355 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2356 struct gcpro gcpro1, gcpro2, gcpro3;
2358 emacs_event = Fmake_event (Qnil, Qnil);
2359 event = XEVENT(emacs_event);
2361 GCPRO3 (emacs_event, l_dndlist, l_item);
2363 if (!DragQueryPoint ((HDROP) wParam, &point))
2364 point.x = point.y = -1; /* outside client area */
2366 event->event_type = misc_user_event;
2367 event->channel = mswindows_find_frame(hwnd);
2368 event->timestamp = GetMessageTime();
2369 event->event.misc.button = 1; /* #### Should try harder */
2370 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2371 event->event.misc.x = point.x;
2372 event->event.misc.y = point.y;
2373 event->event.misc.function = Qdragdrop_drop_dispatch;
2375 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2376 for (i=0; i<filecount; i++)
2378 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2379 /* The URLs that we make here aren't correct according to section
2380 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2381 * because they may contain reserved characters. But that's OK. */
2383 fname = (char *)xmalloc (len+1);
2384 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2385 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2386 strcpy (filename, "file:");
2387 cygwin32_win32_to_posix_path_list (fname, filename+5);
2390 filename = (char *)xmalloc (len+6);
2391 strcpy (filename, "file:");
2392 DragQueryFile ((HDROP) wParam, i, filename+5, len+1);
2393 dostounix_filename (filename+5);
2395 l_item = make_string (filename, strlen (filename));
2396 l_dndlist = Fcons (l_item, l_dndlist);
2399 DragFinish ((HDROP) wParam);
2401 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2402 mswindows_enqueue_dispatch_event (emacs_event);
2410 return DefWindowProc (hwnd, message, wParam, lParam);
2416 /************************************************************************/
2417 /* keyboard, mouse & other helpers for the windows procedure */
2418 /************************************************************************/
2420 mswindows_set_chord_timer (HWND hwnd)
2424 /* We get one third half system double click threshold */
2425 if (mswindows_mouse_button_tolerance <= 0)
2426 interval = GetDoubleClickTime () / 3;
2428 interval = mswindows_mouse_button_tolerance;
2430 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2434 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2437 if (mswindows_mouse_button_max_skew_x <= 0)
2438 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2440 dx = mswindows_mouse_button_max_skew_x;
2442 if (mswindows_mouse_button_max_skew_y <= 0)
2443 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2445 dy = mswindows_mouse_button_max_skew_y;
2447 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2451 mswindows_current_layout_has_AltGr (void)
2453 /* This simple caching mechanism saves 10% of CPU
2454 time when a key typed at autorepeat rate of 30 cps! */
2455 static HKL last_hkl = 0;
2456 static int last_hkl_has_AltGr;
2458 HKL current_hkl = GetKeyboardLayout (0);
2459 if (current_hkl != last_hkl)
2462 last_hkl_has_AltGr = 0;
2463 /* In this loop, we query whether a character requires
2464 AltGr to be down to generate it. If at least such one
2465 found, this means that the layout does regard AltGr */
2466 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2467 if (HIBYTE (VkKeyScan (c)) == 6)
2468 last_hkl_has_AltGr = 1;
2469 last_hkl = current_hkl;
2471 return last_hkl_has_AltGr;
2475 /* Returns the state of the modifier keys in the format expected by the
2476 * Lisp_Event key_data, button_data and motion_data modifiers member */
2477 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2483 keymap = (BYTE*) alloca(256);
2484 GetKeyboardState (keymap);
2485 has_AltGr = mswindows_current_layout_has_AltGr ();
2488 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2490 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2491 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2495 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2496 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2499 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2505 * Translate a mswindows virtual key to a keysym.
2506 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2507 * or whose ASCII codes (like space) xemacs doesn't like.
2508 * Virtual key values are defined in winresrc.h
2510 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
2513 if (extendedp) /* Keys not present on a 82 key keyboard */
2515 switch (mswindows_key)
2517 case VK_RETURN: return KEYSYM ("kp-enter");
2518 case VK_PRIOR: return KEYSYM ("prior");
2519 case VK_NEXT: return KEYSYM ("next");
2520 case VK_END: return KEYSYM ("end");
2521 case VK_HOME: return KEYSYM ("home");
2522 case VK_LEFT: return KEYSYM ("left");
2523 case VK_UP: return KEYSYM ("up");
2524 case VK_RIGHT: return KEYSYM ("right");
2525 case VK_DOWN: return KEYSYM ("down");
2526 case VK_INSERT: return KEYSYM ("insert");
2527 case VK_DELETE: return QKdelete;
2532 switch (mswindows_key)
2534 case VK_BACK: return QKbackspace;
2535 case VK_TAB: return QKtab;
2536 case '\n': return QKlinefeed;
2537 case VK_CLEAR: return KEYSYM ("clear");
2538 case VK_RETURN: return QKreturn;
2539 case VK_ESCAPE: return QKescape;
2540 case VK_SPACE: return QKspace;
2541 case VK_PRIOR: return KEYSYM ("kp-prior");
2542 case VK_NEXT: return KEYSYM ("kp-next");
2543 case VK_END: return KEYSYM ("kp-end");
2544 case VK_HOME: return KEYSYM ("kp-home");
2545 case VK_LEFT: return KEYSYM ("kp-left");
2546 case VK_UP: return KEYSYM ("kp-up");
2547 case VK_RIGHT: return KEYSYM ("kp-right");
2548 case VK_DOWN: return KEYSYM ("kp-down");
2549 case VK_SELECT: return KEYSYM ("select");
2550 case VK_PRINT: return KEYSYM ("print");
2551 case VK_EXECUTE: return KEYSYM ("execute");
2552 case VK_SNAPSHOT: return KEYSYM ("print");
2553 case VK_INSERT: return KEYSYM ("kp-insert");
2554 case VK_DELETE: return KEYSYM ("kp-delete");
2555 case VK_HELP: return KEYSYM ("help");
2556 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
2557 case VK_LWIN return KEYSYM ("");
2558 case VK_RWIN return KEYSYM ("");
2560 case VK_APPS: return KEYSYM ("menu");
2561 case VK_NUMPAD0: return KEYSYM ("kp-0");
2562 case VK_NUMPAD1: return KEYSYM ("kp-1");
2563 case VK_NUMPAD2: return KEYSYM ("kp-2");
2564 case VK_NUMPAD3: return KEYSYM ("kp-3");
2565 case VK_NUMPAD4: return KEYSYM ("kp-4");
2566 case VK_NUMPAD5: return KEYSYM ("kp-5");
2567 case VK_NUMPAD6: return KEYSYM ("kp-6");
2568 case VK_NUMPAD7: return KEYSYM ("kp-7");
2569 case VK_NUMPAD8: return KEYSYM ("kp-8");
2570 case VK_NUMPAD9: return KEYSYM ("kp-9");
2571 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
2572 case VK_ADD: return KEYSYM ("kp-add");
2573 case VK_SEPARATOR: return KEYSYM ("kp-separator");
2574 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
2575 case VK_DECIMAL: return KEYSYM ("kp-decimal");
2576 case VK_DIVIDE: return KEYSYM ("kp-divide");
2577 case VK_F1: return KEYSYM ("f1");
2578 case VK_F2: return KEYSYM ("f2");
2579 case VK_F3: return KEYSYM ("f3");
2580 case VK_F4: return KEYSYM ("f4");
2581 case VK_F5: return KEYSYM ("f5");
2582 case VK_F6: return KEYSYM ("f6");
2583 case VK_F7: return KEYSYM ("f7");
2584 case VK_F8: return KEYSYM ("f8");
2585 case VK_F9: return KEYSYM ("f9");
2586 case VK_F10: return KEYSYM ("f10");
2587 case VK_F11: return KEYSYM ("f11");
2588 case VK_F12: return KEYSYM ("f12");
2589 case VK_F13: return KEYSYM ("f13");
2590 case VK_F14: return KEYSYM ("f14");
2591 case VK_F15: return KEYSYM ("f15");
2592 case VK_F16: return KEYSYM ("f16");
2593 case VK_F17: return KEYSYM ("f17");
2594 case VK_F18: return KEYSYM ("f18");
2595 case VK_F19: return KEYSYM ("f19");
2596 case VK_F20: return KEYSYM ("f20");
2597 case VK_F21: return KEYSYM ("f21");
2598 case VK_F22: return KEYSYM ("f22");
2599 case VK_F23: return KEYSYM ("f23");
2600 case VK_F24: return KEYSYM ("f24");
2607 * Find the console that matches the supplied mswindows window handle
2610 mswindows_find_console (HWND hwnd)
2612 /* We only support one console */
2613 return XCAR (Vconsole_list);
2617 * Find the frame that matches the supplied mswindows window handle
2620 mswindows_find_frame (HWND hwnd)
2622 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2626 /* We are in progress of frame creation. Return the frame
2627 being created, as it still not remembered in the window
2629 assert (!NILP (Vmswindows_frame_being_created));
2630 return Vmswindows_frame_being_created;
2632 VOID_TO_LISP (f, l);
2637 /************************************************************************/
2639 /************************************************************************/
2642 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2645 EMACS_TIME current_time;
2646 EMACS_GET_TIME (current_time);
2647 EMACS_SUB_TIME (thyme, thyme, current_time);
2648 milliseconds = EMACS_SECS (thyme) * 1000 +
2649 (EMACS_USECS (thyme) + 500) / 1000;
2650 if (milliseconds < 1)
2652 ++mswindows_pending_timers_count;
2653 return SetTimer (NULL, 0, milliseconds,
2654 (TIMERPROC) mswindows_wm_timer_callback);
2658 emacs_mswindows_remove_timeout (int id)
2660 Lisp_Event match_against;
2661 Lisp_Object emacs_event;
2663 if (KillTimer (NULL, id))
2664 --mswindows_pending_timers_count;
2666 /* If there is a dispatch event generated by this
2667 timeout in the queue, we have to remove it too. */
2668 match_against.event_type = timeout_event;
2669 match_against.event.timeout.interval_id = id;
2670 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2671 if (!NILP (emacs_event))
2672 Fdeallocate_event(emacs_event);
2675 /* If `user_p' is false, then return whether there are any win32, timeout,
2676 * or subprocess events pending (that is, whether
2677 * emacs_mswindows_next_event() would return immediately without blocking).
2679 * if `user_p' is true, then return whether there are any *user generated*
2680 * events available (that is, whether there are keyboard or mouse-click
2681 * events ready to be read). This also implies that
2682 * emacs_mswindows_next_event() would not block.
2685 emacs_mswindows_event_pending_p (int user_p)
2687 mswindows_need_event (0);
2688 return (!NILP (mswindows_u_dispatch_event_queue)
2689 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2693 * Return the next event
2696 emacs_mswindows_next_event (Lisp_Event *emacs_event)
2698 Lisp_Object event, event2;
2700 mswindows_need_event (1);
2702 event = mswindows_dequeue_dispatch_event ();
2703 XSETEVENT (event2, emacs_event);
2704 Fcopy_event (event, event2);
2705 Fdeallocate_event (event);
2709 * Handle a magic event off the dispatch queue.
2712 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
2714 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2720 mswindows_handle_paint (XFRAME (EVENT_CHANNEL (emacs_event)));
2726 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2727 struct frame *f = XFRAME (frame);
2728 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2731 /* struct gcpro gcpro1; */
2733 /* Clear sticky modifiers here (if we had any) */
2735 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2736 /* GCPRO1 (conser); XXX Not necessary? */
2737 emacs_handle_focus_change_preliminary (conser);
2738 /* Under X the stuff up to here is done in the X event handler.
2740 emacs_handle_focus_change_final (conser);
2749 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2750 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2752 Qmap_frame_hook : Qunmap_frame_hook,
2757 /* #### What about Enter & Leave */
2759 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2760 Qmouse_leave_frame_hook, 1, frame);
2768 #ifndef HAVE_MSG_SELECT
2770 get_process_input_waitable (Lisp_Process *process)
2772 Lisp_Object instr, outstr, p;
2773 XSETPROCESS (p, process);
2774 get_process_streams (process, &instr, &outstr);
2775 assert (!NILP (instr));
2776 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2777 return (network_connection_p (p)
2778 ? get_winsock_stream_waitable (XLSTREAM (instr))
2779 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2781 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2786 emacs_mswindows_select_process (Lisp_Process *process)
2788 HANDLE hev = get_process_input_waitable (process);
2790 if (!add_waitable_handle (hev))
2791 error ("Too many active processes");
2793 #ifdef HAVE_WIN32_PROCESSES
2796 XSETPROCESS (p, process);
2797 if (!network_connection_p (p))
2799 HANDLE hprocess = get_nt_process_handle (process);
2800 if (!add_waitable_handle (hprocess))
2802 remove_waitable_handle (hev);
2803 error ("Too many active processes");
2811 emacs_mswindows_unselect_process (Lisp_Process *process)
2813 /* Process handle is removed in the event loop as soon
2814 as it is signaled, so don't bother here about it */
2815 HANDLE hev = get_process_input_waitable (process);
2816 remove_waitable_handle (hev);
2818 #endif /* HAVE_MSG_SELECT */
2821 emacs_mswindows_select_console (struct console *con)
2823 #ifdef HAVE_MSG_SELECT
2824 if (CONSOLE_MSWINDOWS_P (con))
2825 return; /* mswindows consoles are automatically selected */
2827 event_stream_unixoid_select_console (con);
2832 emacs_mswindows_unselect_console (struct console *con)
2834 #ifdef HAVE_MSG_SELECT
2835 if (CONSOLE_MSWINDOWS_P (con))
2836 return; /* mswindows consoles are automatically selected */
2838 event_stream_unixoid_unselect_console (con);
2843 emacs_mswindows_quit_p (void)
2845 /* Quit cannot happen in modal loop: all program
2846 input is dedicated to Windows. */
2847 if (mswindows_in_modal_loop)
2850 /* Drain windows queue. This sets up number of quit characters in
2852 mswindows_drain_windows_queue ();
2854 if (mswindows_quit_chars_count > 0)
2856 /* Yes there's a hidden one... Throw it away */
2857 Lisp_Event match_against;
2858 Lisp_Object emacs_event;
2861 match_against.event_type = key_press_event;
2862 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2864 while (mswindows_quit_chars_count-- > 0)
2866 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2867 assert (!NILP (emacs_event));
2869 if (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT)
2872 Fdeallocate_event(emacs_event);
2875 Vquit_flag = critical_p ? Qcritical : Qt;
2880 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2881 Lisp_Object* instream,
2882 Lisp_Object* outstream,
2885 /* Handles for streams */
2887 /* fds. These just stored along with the streams, and are closed in
2888 delete stream pair method, because we need to handle fake unices
2892 /* Decode inhandle and outhandle. Their meaning depends on
2893 the process implementation being used. */
2894 #if defined (HAVE_WIN32_PROCESSES)
2895 /* We're passed in Windows handles. That's what we like most... */
2896 hin = (HANDLE) inhandle;
2897 hout = (HANDLE) outhandle;
2899 #elif defined (HAVE_UNIX_PROCESSES)
2900 /* We are passed UNIX fds. This must be Cygwin.
2902 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2903 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2907 #error "So, WHICH kind of processes do you want?"
2910 *instream = (hin == INVALID_HANDLE_VALUE
2912 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2913 : flags & STREAM_NETWORK_CONNECTION
2914 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2916 : make_ntpipe_input_stream (hin, fdi));
2918 #ifdef HAVE_WIN32_PROCESSES
2919 *outstream = (hout == INVALID_HANDLE_VALUE
2921 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2922 : flags & STREAM_NETWORK_CONNECTION
2923 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2925 : make_ntpipe_output_stream (hout, fdo));
2926 #elif defined (HAVE_UNIX_PROCESSES)
2927 *outstream = (fdo >= 0
2928 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2931 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2932 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2933 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2935 Bufbyte eof_char = get_eof_char (fdo);
2936 int pty_max_bytes = get_pty_max_bytes (fdo);
2937 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2942 return (NILP (*instream)
2944 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2945 : flags & STREAM_NETWORK_CONNECTION
2946 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2948 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2952 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2953 Lisp_Object outstream)
2955 /* Oh nothing special here for Win32 at all */
2956 #if defined (HAVE_UNIX_PROCESSES)
2957 int in = (NILP(instream)
2959 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2960 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2961 ? get_winsock_stream_param (XLSTREAM (instream))
2963 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2964 int out = (NILP(outstream) ? -1
2965 : filedesc_stream_fd (XLSTREAM (outstream)));
2969 if (out != in && out >= 0)
2973 return (NILP (instream)
2975 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2976 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2977 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2979 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2982 #ifndef HAVE_X_WINDOWS
2983 /* This is called from GC when a process object is about to be freed.
2984 If we've still got pointers to it in this file, we're gonna lose hard.
2987 debug_process_finalization (Lisp_Process *p)
2990 Lisp_Object instr, outstr;
2992 get_process_streams (p, &instr, &outstr);
2993 /* if it still has fds, then it hasn't been killed yet. */
2994 assert (NILP(instr));
2995 assert (NILP(outstr));
2997 /* #### More checks here */
3002 /************************************************************************/
3003 /* initialization */
3004 /************************************************************************/
3007 reinit_vars_of_event_mswindows (void)
3009 mswindows_in_modal_loop = 0;
3010 mswindows_pending_timers_count = 0;
3012 mswindows_event_stream = xnew (struct event_stream);
3014 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3015 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3016 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3017 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3018 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3019 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3020 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3021 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3022 #ifdef HAVE_MSG_SELECT
3023 mswindows_event_stream->select_process_cb =
3024 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3025 mswindows_event_stream->unselect_process_cb =
3026 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3027 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3028 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3030 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3031 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3032 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3033 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3038 vars_of_event_mswindows (void)
3040 reinit_vars_of_event_mswindows ();
3042 mswindows_u_dispatch_event_queue = Qnil;
3043 staticpro (&mswindows_u_dispatch_event_queue);
3044 mswindows_u_dispatch_event_queue_tail = Qnil;
3045 pdump_wire (&mswindows_u_dispatch_event_queue_tail);
3047 mswindows_s_dispatch_event_queue = Qnil;
3048 staticpro (&mswindows_s_dispatch_event_queue);
3049 mswindows_s_dispatch_event_queue_tail = Qnil;
3050 pdump_wire (&mswindows_s_dispatch_event_queue_tail);
3052 mswindows_error_caught_in_modal_loop = Qnil;
3053 staticpro (&mswindows_error_caught_in_modal_loop);
3055 DEFVAR_BOOL ("mswindows-meta-activates-menu", &mswindows_meta_activates_menu /*
3056 *Controls whether pressing and releasing the Meta (Alt) key should
3057 activate the menubar.
3061 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
3062 *Controls redrawing frame contents during mouse-drag or keyboard resize
3063 operation. When non-nil, the frame is redrawn while being resized. When
3064 nil, frame is not redrawn, and exposed areas are filled with default
3065 MDI application background color. Note that this option only has effect
3066 if "Show window contents while dragging" is on in system Display/Plus!
3068 Default is t on fast machines, nil on slow.
3071 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
3072 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
3073 *Analogue of double click interval for faking middle mouse events.
3074 The value is the minimum time in milliseconds that must elapse between
3075 left/right button down events before they are considered distinct events.
3076 If both mouse buttons are depressed within this interval, a middle mouse
3077 button down event is generated instead.
3078 If negative or zero, currently set system default is used instead.
3081 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
3082 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3083 Number of physical mouse buttons.
3086 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
3087 *Maximum horizontal distance in pixels between points in which left and
3088 right button clicks occurred for them to be translated into single
3089 middle button event. Clicks must occur in time not longer than defined
3090 by the variable `mswindows-mouse-button-tolerance'.
3091 If negative or zero, currently set system default is used instead.
3094 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
3095 *Maximum vertical 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 mswindows_mouse_button_max_skew_x = 0;
3103 mswindows_mouse_button_max_skew_y = 0;
3104 mswindows_mouse_button_tolerance = 0;
3105 mswindows_meta_activates_menu = 1;
3109 syms_of_event_mswindows (void)
3114 lstream_type_create_mswindows_selectable (void)
3116 init_slurp_stream ();
3117 init_shove_stream ();
3118 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3119 init_winsock_stream ();
3124 init_event_mswindows_late (void)
3126 #ifdef HAVE_MSG_SELECT
3127 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3128 assert (windows_fd>=0);
3129 FD_SET (windows_fd, &input_wait_mask);
3130 FD_ZERO(&zero_mask);
3133 event_stream = mswindows_event_stream;
3135 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3136 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);