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, 2000 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"
45 # include "menubar-msw.h"
49 # include "dragdrop.h"
59 #include "redisplay.h"
65 #include "objects-msw.h"
67 #include "events-mod.h"
68 #ifdef HAVE_MSG_SELECT
70 #include "console-tty.h"
71 #elif defined(__CYGWIN32__)
72 typedef unsigned int SOCKET;
77 #if !(defined(__CYGWIN32__) || defined(__MINGW32__))
78 # include <shlobj.h> /* For IShellLink */
81 #if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20)
82 typedef NMHDR *LPNMHDR;
86 #define ADJR_MENUFLAG TRUE
88 #define ADJR_MENUFLAG FALSE
91 /* Fake key modifier which is attached to a quit char event.
92 Removed upon dequeueing an event */
93 #define FAKE_MOD_QUIT 0x80
95 /* Timer ID used for button2 emulation */
96 #define BUTTON_2_TIMER_ID 1
98 static Lisp_Object mswindows_find_frame (HWND hwnd);
99 static Lisp_Object mswindows_find_console (HWND hwnd);
100 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
102 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
103 static void mswindows_set_chord_timer (HWND hwnd);
104 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
105 static int mswindows_current_layout_has_AltGr (void);
107 static struct event_stream *mswindows_event_stream;
109 #ifdef HAVE_MSG_SELECT
110 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
111 extern SELECT_TYPE process_only_mask, tty_only_mask;
112 SELECT_TYPE zero_mask;
113 extern int signal_event_pipe_initialized;
118 * Two separate queues, for efficiency, one (_u_) for user events, and
119 * another (_s_) for non-user ones. We always return events out of the
120 * first one until it is empty and only then proceed with the second
123 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
124 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
126 /* The number of things we can wait on */
127 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
129 #ifndef HAVE_MSG_SELECT
130 /* List of mswindows waitable handles. */
131 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
133 /* Number of wait handles */
134 static int mswindows_waitable_count=0;
135 #endif /* HAVE_MSG_SELECT */
137 /* Brush for painting widgets */
138 static HBRUSH widget_brush = 0;
139 static LONG last_widget_brushed = 0;
141 /* Count of quit chars currently in the queue */
142 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
143 Decremented in mswindows_dequeue_dispatch_event() */
144 int mswindows_quit_chars_count = 0;
146 /* These are Lisp integers; see DEFVARS in this file for description. */
147 int mswindows_dynamic_frame_resize;
148 int mswindows_alt_by_itself_activates_menu;
149 int mswindows_num_mouse_buttons;
150 int mswindows_mouse_button_max_skew_x;
151 int mswindows_mouse_button_max_skew_y;
152 int mswindows_mouse_button_tolerance;
154 /* This is the event signaled by the event pump.
155 See mswindows_pump_outstanding_events for comments */
156 static Lisp_Object mswindows_error_caught_in_modal_loop;
157 static int mswindows_in_modal_loop;
159 /* Count of wound timers */
160 static int mswindows_pending_timers_count;
162 /************************************************************************/
163 /* Pipe instream - reads process output */
164 /************************************************************************/
166 #define PIPE_READ_DELAY 20
168 #define HANDLE_TO_USID(h) ((USID)(h))
170 #define NTPIPE_SLURP_STREAM_DATA(stream) \
171 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
173 /* This structure is allocated by the main thread, and is deallocated
174 in the thread upon exit. There are situations when a thread
175 remains blocked for a long time, much longer than the lstream
176 exists. For example, "start notepad" command is issued from the
177 shell, then the shell is closed by C-c C-d. Although the shell
178 process exits, its output pipe will not get closed until the
179 notepad process exits also, because it inherits the pipe form the
180 shell. In this case, we abandon the thread, and let it live until
181 all such processes exit. While struct ntpipe_slurp_stream is
182 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
184 struct ntpipe_slurp_stream_shared_data
186 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
187 /* This is a manual-reset object. */
188 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
189 /* This is a manual-reset object. */
190 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
191 /* This is a manual-reset object. */
192 HANDLE hpipe; /* Pipe read end handle. */
193 LONG die_p; /* Thread must exit ASAP if non-zero */
194 BOOL eof_p : 1; /* Set when thread saw EOF */
195 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
196 BOOL inuse_p : 1; /* this structure is in use */
197 LONG lock_count; /* Client count of this struct, 0=safe to free */
198 BYTE onebyte; /* One byte buffer read by thread */
201 #define MAX_SLURP_STREAMS 32
202 struct ntpipe_slurp_stream_shared_data
203 shared_data_block[MAX_SLURP_STREAMS]={{0}};
205 struct ntpipe_slurp_stream
207 LPARAM user_data; /* Any user data stored in the stream object */
208 struct ntpipe_slurp_stream_shared_data* thread_data;
211 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
212 sizeof (struct ntpipe_slurp_stream));
214 /* This function is thread-safe, and is called from either thread
215 context. It serializes freeing shared data structure */
217 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
219 if (InterlockedDecrement (&s->lock_count) == 0)
222 CloseHandle (s->hev_thread);
223 CloseHandle (s->hev_caller);
224 CloseHandle (s->hev_unsleep);
229 static struct ntpipe_slurp_stream_shared_data*
230 slurper_allocate_shared_data (void)
233 for (i=0; i<MAX_SLURP_STREAMS; i++)
235 if (!shared_data_block[i].inuse_p)
237 shared_data_block[i].inuse_p=1;
238 return &shared_data_block[i];
241 return (struct ntpipe_slurp_stream_shared_data*)0;
245 slurp_thread (LPVOID vparam)
247 struct ntpipe_slurp_stream_shared_data *s =
248 (struct ntpipe_slurp_stream_shared_data*)vparam;
252 /* Read one byte from the pipe */
254 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
256 DWORD err = GetLastError ();
257 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
262 else if (actually_read == 0)
265 /* We must terminate on an error or eof */
266 if (s->eof_p || s->error_p)
267 InterlockedIncrement (&s->die_p);
269 /* Before we notify caller, we unsignal our event. */
270 ResetEvent (s->hev_thread);
272 /* Now we got something to notify caller, either a byte or an
273 error/eof indication. Before we do, allow internal pipe
274 buffer to accumulate little bit more data.
275 Reader function pulses this event before waiting for
276 a character, to avoid pipe delay, and to get the byte
279 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
281 /* Either make event loop generate a process event, or
283 SetEvent (s->hev_caller);
285 /* Cleanup and exit if we're shot off */
289 /* Block until the client finishes with retrieving the rest of
291 WaitForSingleObject (s->hev_thread, INFINITE);
294 slurper_free_shared_data_maybe (s);
300 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
303 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
304 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
305 DWORD thread_id_unused;
308 /* We deal only with pipes, for we're using PeekNamedPipe api */
309 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
311 s->thread_data = slurper_allocate_shared_data();
313 /* Create reader thread. This could fail, so do not create events
314 until thread is created */
315 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
316 CREATE_SUSPENDED, &thread_id_unused);
319 Lstream_delete (lstr);
320 s->thread_data->inuse_p=0;
324 /* Shared data are initially owned by both main and slurper
326 s->thread_data->lock_count = 2;
327 s->thread_data->die_p = 0;
328 s->thread_data->eof_p = FALSE;
329 s->thread_data->error_p = FALSE;
330 s->thread_data->hpipe = hpipe;
331 s->user_data = param;
333 /* hev_thread is a manual-reset event, initially signaled */
334 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
335 /* hev_caller is a manual-reset event, initially nonsignaled */
336 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
337 /* hev_unsleep is a manual-reset event, initially nonsignaled */
338 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
341 ResumeThread (hthread);
342 CloseHandle (hthread);
344 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
345 XSETLSTREAM (obj, lstr);
350 get_ntpipe_input_stream_param (Lstream *stream)
352 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
357 get_ntpipe_input_stream_waitable (Lstream *stream)
359 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
360 return s->thread_data->hev_caller;
364 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
366 /* This function must be called from the main thread only */
367 struct ntpipe_slurp_stream_shared_data* s =
368 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
373 /* Disallow pipe read delay for the thread: we need a character
375 SetEvent (s->hev_unsleep);
377 /* Check if we have a character ready. Give it a short delay,
378 for the thread to awake from pipe delay, just ion case*/
379 wait_result = WaitForSingleObject (s->hev_caller, 2);
381 /* Revert to the normal sleep behavior. */
382 ResetEvent (s->hev_unsleep);
384 /* If there's no byte buffered yet, give up */
385 if (wait_result == WAIT_TIMEOUT)
392 /* Reset caller unlock event now, as we've handled the pending
393 process output event */
394 ResetEvent (s->hev_caller);
396 /* It is now safe to do anything with contents of S, except for
397 changing s->die_p, which still should be interlocked */
401 if (s->error_p || s->die_p)
404 /* Ok, there were no error neither eof - we've got a byte from the
406 *(data++) = s->onebyte;
410 DWORD bytes_read = 0;
413 DWORD bytes_available;
415 /* If the api call fails, return at least one byte already
416 read. ReadFile in thread will return error */
417 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
420 /* Fetch available bytes. The same consideration applies,
421 so do not check for errors. ReadFile in the thread will
422 fail if the next call fails. */
424 ReadFile (s->hpipe, data, min (bytes_available, size),
428 /* Now we can unblock thread, so it attempts to read more */
429 SetEvent (s->hev_thread);
430 return bytes_read + 1;
437 ntpipe_slurp_closer (Lstream *stream)
439 /* This function must be called from the main thread only */
440 struct ntpipe_slurp_stream_shared_data* s =
441 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
443 /* Force thread to stop */
444 InterlockedIncrement (&s->die_p);
446 /* Set events which could possibly block slurper. Let it finish soon
448 SetEvent (s->hev_unsleep);
449 SetEvent (s->hev_thread);
451 /* Unlock and maybe free shared data */
452 slurper_free_shared_data_maybe (s);
458 init_slurp_stream (void)
460 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
461 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
464 /************************************************************************/
465 /* Pipe outstream - writes process input */
466 /************************************************************************/
468 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
469 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
471 #define MAX_SHOVE_BUFFER_SIZE 128
473 struct ntpipe_shove_stream
475 LPARAM user_data; /* Any user data stored in the stream object */
476 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
477 /* This is an auto-reset object. */
478 HANDLE hpipe; /* Pipe write end handle. */
479 HANDLE hthread; /* Reader thread handle. */
480 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
481 DWORD size; /* Number of bytes to write */
482 LONG die_p; /* Thread must exit ASAP if non-zero */
483 LONG idle_p; /* Non-zero if thread is waiting for job */
484 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
485 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
488 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
489 sizeof (struct ntpipe_shove_stream));
491 #ifndef HAVE_MSG_SELECT
493 shove_thread (LPVOID vparam)
495 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
501 /* Block on event and wait for a job */
502 InterlockedIncrement (&s->idle_p);
503 WaitForSingleObject (s->hev_thread, INFINITE);
508 /* Write passed buffer */
509 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
510 || bytes_written != s->size)
513 InterlockedIncrement (&s->die_p);
524 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
527 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
528 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
529 DWORD thread_id_unused;
534 s->user_data = param;
536 /* Create reader thread. This could fail, so do not
537 create the event until thread is created */
538 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
539 CREATE_SUSPENDED, &thread_id_unused);
540 if (s->hthread == NULL)
542 Lstream_delete (lstr);
546 /* hev_thread is an auto-reset event, initially nonsignaled */
547 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
550 ResumeThread (s->hthread);
552 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
553 XSETLSTREAM (obj, lstr);
558 get_ntpipe_output_stream_param (Lstream *stream)
560 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
566 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
568 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
573 s->blocking_p = !s->idle_p;
577 if (size>MAX_SHOVE_BUFFER_SIZE)
580 memcpy (s->buffer, data, size);
584 InterlockedDecrement (&s->idle_p);
585 SetEvent (s->hev_thread);
590 ntpipe_shove_was_blocked_p (Lstream *stream)
592 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
593 return s->blocking_p;
597 ntpipe_shove_closer (Lstream *stream)
599 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
601 /* Force thread stop */
602 InterlockedIncrement (&s->die_p);
604 /* Close pipe handle, possibly breaking it */
605 CloseHandle (s->hpipe);
607 /* Thread will end upon unblocking */
608 SetEvent (s->hev_thread);
610 /* Wait while thread terminates */
611 WaitForSingleObject (s->hthread, INFINITE);
612 CloseHandle (s->hthread);
614 /* Destroy the event */
615 CloseHandle (s->hev_thread);
621 init_shove_stream (void)
623 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
624 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
625 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
628 /************************************************************************/
629 /* Winsock I/O stream */
630 /************************************************************************/
631 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
633 #define WINSOCK_READ_BUFFER_SIZE 1024
635 struct winsock_stream
637 LPARAM user_data; /* Any user data stored in the stream object */
638 SOCKET s; /* Socket handle (which is a Win32 handle) */
639 OVERLAPPED ov; /* Overlapped I/O structure */
640 void* buffer; /* Buffer. Allocated for input stream only */
641 unsigned long bufsize; /* Number of bytes last read */
642 unsigned long bufpos; /* Position in buffer for next fetch */
643 unsigned int error_p :1; /* I/O Error seen */
644 unsigned int eof_p :1; /* EOF Error seen */
645 unsigned int pending_p :1; /* There is a pending I/O operation */
646 unsigned int blocking_p :1; /* Last write attempt would block */
649 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
651 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
652 sizeof (struct winsock_stream));
655 winsock_initiate_read (struct winsock_stream *str)
657 ResetEvent (str->ov.hEvent);
660 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
661 &str->bufsize, &str->ov))
663 if (GetLastError () == ERROR_IO_PENDING)
665 else if (GetLastError () == ERROR_HANDLE_EOF)
670 else if (str->bufsize == 0)
675 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
677 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
679 /* If the current operation is not yet complete, there's nothing to
683 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
690 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
692 if (GetLastError() == ERROR_HANDLE_EOF)
697 if (str->bufsize == 0)
708 /* Return as much of buffer as we have */
709 size = min (size, (size_t) (str->bufsize - str->bufpos));
710 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
713 /* Read more if buffer is exhausted */
714 if (str->bufsize == str->bufpos)
715 winsock_initiate_read (str);
721 winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
723 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
727 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
735 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
750 ResetEvent (str->ov.hEvent);
752 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
753 * an overlapped operation. This fails on Win95 with winsock 1.x so we
754 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
755 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
756 || GetLastError() == ERROR_IO_PENDING)
762 return str->error_p ? -1 : size;
766 winsock_closer (Lstream *lstr)
768 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
770 if (lstr->flags & LSTREAM_FL_READ)
771 shutdown (str->s, 0);
773 shutdown (str->s, 1);
775 CloseHandle ((HANDLE)str->s);
777 WaitForSingleObject (str->ov.hEvent, INFINITE);
779 if (lstr->flags & LSTREAM_FL_READ)
782 CloseHandle (str->ov.hEvent);
787 winsock_was_blocked_p (Lstream *stream)
789 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
790 return str->blocking_p;
794 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
797 Lstream *lstr = Lstream_new (lstream_winsock, mode);
798 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
805 str->user_data = param;
808 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
810 if (lstr->flags & LSTREAM_FL_READ)
812 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
813 winsock_initiate_read (str);
816 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
817 XSETLSTREAM (obj, lstr);
822 make_winsock_input_stream (SOCKET s, LPARAM param)
824 return make_winsock_stream_1 (s, param, "r");
828 make_winsock_output_stream (SOCKET s, LPARAM param)
830 return make_winsock_stream_1 (s, param, "w");
834 get_winsock_stream_waitable (Lstream *lstr)
836 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
837 return str->ov.hEvent;
841 get_winsock_stream_param (Lstream *lstr)
843 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
844 return str->user_data;
848 init_winsock_stream (void)
850 LSTREAM_HAS_METHOD (winsock, reader);
851 LSTREAM_HAS_METHOD (winsock, writer);
852 LSTREAM_HAS_METHOD (winsock, closer);
853 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
855 #endif /* defined (HAVE_SOCKETS) */
857 /************************************************************************/
858 /* Dispatch queue management */
859 /************************************************************************/
862 mswindows_user_event_p (Lisp_Event* sevt)
864 return (sevt->event_type == key_press_event
865 || sevt->event_type == button_press_event
866 || sevt->event_type == button_release_event
867 || sevt->event_type == misc_user_event);
871 * Add an emacs event to the proper dispatch queue
874 mswindows_enqueue_dispatch_event (Lisp_Object event)
876 int user_p = mswindows_user_event_p (XEVENT(event));
877 enqueue_event (event,
878 user_p ? &mswindows_u_dispatch_event_queue :
879 &mswindows_s_dispatch_event_queue,
880 user_p ? &mswindows_u_dispatch_event_queue_tail :
881 &mswindows_s_dispatch_event_queue_tail);
883 /* Avoid blocking on WaitMessage */
884 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
888 * Add a misc-user event to the dispatch queue.
890 * Stuff it into our own dispatch queue, so we have something
891 * to return from next_event callback.
894 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
897 Lisp_Object event = Fmake_event (Qnil, Qnil);
898 Lisp_Event* e = XEVENT (event);
900 e->event_type = misc_user_event;
901 e->channel = channel;
902 e->timestamp = GetTickCount ();
903 e->event.misc.function = function;
904 e->event.misc.object = object;
906 mswindows_enqueue_dispatch_event (event);
910 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
912 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
913 Lisp_Event* event = XEVENT (emacs_event);
915 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
916 event->timestamp = GetMessageTime();
917 event->event_type = magic_event;
918 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
920 mswindows_enqueue_dispatch_event (emacs_event);
924 mswindows_enqueue_process_event (Lisp_Process* p)
926 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
927 Lisp_Event* event = XEVENT (emacs_event);
929 XSETPROCESS (process, p);
931 event->event_type = process_event;
932 event->timestamp = GetTickCount ();
933 event->event.process.process = process;
935 mswindows_enqueue_dispatch_event (emacs_event);
939 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when)
942 /* We always use last message time, because mouse button
943 events may get delayed, and XEmacs double click
944 recognition will fail */
946 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
947 Lisp_Event* event = XEVENT(emacs_event);
949 event->channel = mswindows_find_frame(hwnd);
950 event->timestamp = when;
951 event->event.button.button =
952 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
953 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
954 event->event.button.x = where.x;
955 event->event.button.y = where.y;
956 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
958 if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN ||
961 event->event_type = button_press_event;
963 /* we need this to make sure the main window regains the focus
964 from control subwindows */
965 if (GetFocus() != hwnd)
968 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
973 event->event_type = button_release_event;
977 mswindows_enqueue_dispatch_event (emacs_event);
981 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
983 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
984 Lisp_Event* event = XEVENT(emacs_event);
986 event->channel = mswindows_find_console(hwnd);
987 event->timestamp = GetMessageTime();
988 event->event_type = key_press_event;
989 event->event.key.keysym = keysym;
990 event->event.key.modifiers = mods;
991 mswindows_enqueue_dispatch_event (emacs_event);
995 * Remove and return the first emacs event on the dispatch queue.
996 * Give a preference to user events over non-user ones.
999 mswindows_dequeue_dispatch_event (void)
1004 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1005 !NILP(mswindows_s_dispatch_event_queue));
1007 event = dequeue_event (
1008 NILP(mswindows_u_dispatch_event_queue) ?
1009 &mswindows_s_dispatch_event_queue :
1010 &mswindows_u_dispatch_event_queue,
1011 NILP(mswindows_u_dispatch_event_queue) ?
1012 &mswindows_s_dispatch_event_queue_tail :
1013 &mswindows_u_dispatch_event_queue_tail);
1015 sevt = XEVENT(event);
1016 if (sevt->event_type == key_press_event
1017 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1019 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1020 --mswindows_quit_chars_count;
1027 * Remove and return the first emacs event on the dispatch queue that matches
1028 * the supplied event.
1029 * Timeout event matches if interval_id is equal to that of the given event.
1030 * Keypress event matches if logical AND between modifiers bitmask of the
1031 * event in the queue and that of the given event is non-zero.
1032 * For all other event types, this function aborts.
1036 mswindows_cancel_dispatch_event (Lisp_Event *match)
1039 Lisp_Object previous_event = Qnil;
1040 int user_p = mswindows_user_event_p (match);
1041 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1042 &mswindows_s_dispatch_event_queue;
1043 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1044 &mswindows_s_dispatch_event_queue_tail;
1046 assert (match->event_type == timeout_event
1047 || match->event_type == key_press_event);
1049 EVENT_CHAIN_LOOP (event, *head)
1051 Lisp_Event *e = XEVENT (event);
1052 if ((e->event_type == match->event_type) &&
1053 ((e->event_type == timeout_event) ?
1054 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1055 /* Must be key_press_event */
1056 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1058 if (NILP (previous_event))
1059 dequeue_event (head, tail);
1062 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1063 if (EQ (*tail, event))
1064 *tail = previous_event;
1069 previous_event = event;
1074 #ifndef HAVE_MSG_SELECT
1075 /************************************************************************/
1076 /* Waitable handles manipulation */
1077 /************************************************************************/
1079 find_waitable_handle (HANDLE h)
1082 for (i = 0; i < mswindows_waitable_count; ++i)
1083 if (mswindows_waitable_handles[i] == h)
1090 add_waitable_handle (HANDLE h)
1092 assert (find_waitable_handle (h) < 0);
1093 if (mswindows_waitable_count == MAX_WAITABLE)
1096 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1101 remove_waitable_handle (HANDLE h)
1103 int ix = find_waitable_handle (h);
1107 mswindows_waitable_handles [ix] =
1108 mswindows_waitable_handles [--mswindows_waitable_count];
1110 #endif /* HAVE_MSG_SELECT */
1113 /************************************************************************/
1115 /************************************************************************/
1118 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1119 Lisp_Object u_n_u_s_e_d)
1121 mswindows_error_caught_in_modal_loop = cons_sig_data;
1126 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1131 ++mswindows_in_modal_loop;
1132 tmp = condition_case_1 (Qt,
1134 mswindows_modal_loop_error_handler, Qnil);
1135 --mswindows_in_modal_loop;
1141 mswindows_unmodalize_signal_maybe (void)
1143 if (!NILP (mswindows_error_caught_in_modal_loop))
1145 /* Got an error while messages were pumped while
1146 in window procedure - have to resignal */
1147 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1148 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1149 mswindows_error_caught_in_modal_loop = Qnil;
1150 Fsignal (sym, data);
1155 * This is an unsafe part of event pump, guarded by
1156 * condition_case. See mswindows_pump_outstanding_events
1159 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1161 /* This function can call lisp */
1162 Lisp_Object event = Fmake_event (Qnil, Qnil);
1163 struct gcpro gcpro1;
1164 int do_redisplay = 0;
1167 while (detect_input_pending ())
1169 Fnext_event (event, Qnil);
1170 Fdispatch_event (event);
1177 Fdeallocate_event (event);
1180 /* Qt becomes return value of mswindows_pump_outstanding_events
1186 * This function pumps emacs events, while available, by using
1187 * next_message/dispatch_message loop. Errors are trapped around
1188 * the loop so the function always returns.
1190 * Windows message queue is not looked into during the call,
1191 * neither are waitable handles checked. The function pumps
1192 * thus only dispatch events already queued, as well as those
1193 * resulted in dispatching thereof. This is done by setting
1194 * module local variable mswindows_in_modal_loop to nonzero.
1196 * Return value is Qt if no errors was trapped, or Qunbound if
1197 * there was an error.
1199 * In case of error, a cons representing the error, in the
1200 * form (SIGNAL . DATA), is stored in the module local variable
1201 * mswindows_error_caught_in_modal_loop. This error is signaled
1202 * again when DispatchMessage returns. Thus, Windows internal
1203 * modal loops are protected against throws, which are proven
1204 * to corrupt internal Windows structures.
1206 * In case of success, mswindows_error_caught_in_modal_loop is
1209 * If the value of mswindows_error_caught_in_modal_loop is not
1210 * nil already upon entry, the function just returns non-nil.
1211 * This situation means that a new event has been queued while
1212 * in cancel mode. The event will be dequeued on the next regular
1213 * call of next-event; the pump is off since error is caught.
1214 * The caller must *unconditionally* cancel modal loop if the
1215 * value returned by this function is nil. Otherwise, everything
1216 * will become frozen until the modal loop exits under normal
1217 * condition (scrollbar drag is released, menu closed etc.)
1220 mswindows_pump_outstanding_events (void)
1222 /* This function can call lisp */
1224 Lisp_Object result = Qt;
1225 struct gcpro gcpro1;
1228 if (NILP(mswindows_error_caught_in_modal_loop))
1229 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1235 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1236 * QUITP, and are interesting in keyboard messages only.
1239 mswindows_drain_windows_queue (void)
1243 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1244 assert (!mswindows_in_modal_loop);
1246 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1248 /* We have to translate messages that are not sent to the main
1249 window. This is so that key presses work ok in things like
1250 edit fields. However, we *musn't* translate message for the
1251 main window as this is handled in the wnd proc.
1252 We also have to avoid generating paint magic events for windows
1253 that aren't XEmacs frames */
1254 if (GetWindowLong (msg.hwnd, GWL_STYLE) & (WS_CHILD|WS_POPUP))
1256 TranslateMessage (&msg);
1258 else if (msg.message == WM_PAINT)
1260 struct mswindows_frame* msframe;
1262 /* hdc will be NULL unless this is a subwindow - in which case we
1263 shouldn't have received a paint message for it here. */
1264 assert (msg.wParam == 0);
1266 /* Queue a magic event for handling when safe */
1267 msframe = FRAME_MSWINDOWS_DATA (
1268 XFRAME (mswindows_find_frame (msg.hwnd)));
1269 if (!msframe->paint_pending)
1271 msframe->paint_pending = 1;
1272 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1274 /* Don't dispatch. WM_PAINT is always the last message in the
1275 queue so it's OK to just return. */
1278 DispatchMessage (&msg);
1279 mswindows_unmodalize_signal_maybe ();
1284 * This is a special flavor of the mswindows_need_event function,
1285 * used while in event pump. Actually, there is only kind of events
1286 * allowed while in event pump: a timer. An attempt to fetch any
1287 * other event leads to a deadlock, as there's no source of user input
1288 * ('cause event pump mirrors windows modal loop, which is a sole
1289 * owner of thread message queue).
1291 * To detect this, we use a counter of active timers, and allow
1292 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1293 * which will never come when there are no pending timers, which leads
1294 * to deadlock, we simply signal an error.
1297 mswindows_need_event_in_modal_loop (int badly_p)
1301 /* Check if already have one */
1302 if (!NILP (mswindows_u_dispatch_event_queue)
1303 || !NILP (mswindows_s_dispatch_event_queue))
1306 /* No event is ok */
1310 /* We do not check the _u_ queue, because timers go to _s_ */
1311 while (NILP (mswindows_s_dispatch_event_queue))
1313 /* We'll deadlock if go waiting */
1314 if (mswindows_pending_timers_count == 0)
1315 error ("Deadlock due to an attempt to call next-event in a wrong context");
1317 /* Fetch and dispatch any pending timers */
1318 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1319 DispatchMessage (&msg);
1324 * This drains the event queue and fills up two internal queues until
1325 * an event of a type specified by USER_P is retrieved.
1328 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1331 mswindows_need_event (int badly_p)
1335 if (mswindows_in_modal_loop)
1337 mswindows_need_event_in_modal_loop (badly_p);
1341 while (NILP (mswindows_u_dispatch_event_queue)
1342 && NILP (mswindows_s_dispatch_event_queue))
1344 #ifdef HAVE_MSG_SELECT
1346 SELECT_TYPE temp_mask = input_wait_mask;
1347 EMACS_TIME sometime;
1348 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1351 pointer_to_this = 0;
1354 EMACS_SET_SECS_USECS (sometime, 0, 0);
1355 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1356 pointer_to_this = &select_time_to_block;
1359 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1364 return; /* timeout */
1366 else if (active > 0)
1368 if (FD_ISSET (windows_fd, &temp_mask))
1370 mswindows_drain_windows_queue ();
1375 /* Look for a TTY event */
1376 for (i = 0; i < MAXDESC-1; i++)
1378 /* To avoid race conditions (among other things, an infinite
1379 loop when called from Fdiscard_input()), we must return
1380 user events ahead of process events. */
1381 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1383 struct console *c = tty_find_console_from_fd (i);
1384 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1385 Lisp_Event* event = XEVENT (emacs_event);
1388 if (read_event_from_tty_or_stream_desc (event, c, i))
1390 mswindows_enqueue_dispatch_event (emacs_event);
1396 /* Look for a process event */
1397 for (i = 0; i < MAXDESC-1; i++)
1399 if (FD_ISSET (i, &temp_mask))
1401 if (FD_ISSET (i, &process_only_mask))
1404 get_process_from_usid (FD_TO_USID(i));
1406 mswindows_enqueue_process_event (p);
1410 /* We might get here when a fake event came
1411 through a signal. Return a dummy event, so
1412 that a cycle of the command loop will
1414 drain_signal_event_pipe ();
1415 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1421 else if (active==-1)
1425 /* something bad happened */
1434 /* Now try getting a message or process event */
1435 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1436 mswindows_waitable_handles,
1437 FALSE, badly_p ? INFINITE : 0,
1440 /* This will assert if handle being waited for becomes abandoned.
1441 Not the case currently tho */
1442 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1443 (active >= WAIT_OBJECT_0 &&
1444 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1446 if (active == WAIT_TIMEOUT)
1448 /* No luck trying - just return what we've already got */
1451 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1453 /* Got your message, thanks */
1454 mswindows_drain_windows_queue ();
1458 int ix = active - WAIT_OBJECT_0;
1459 /* First, try to find which process' output has signaled */
1461 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1464 /* Found a signaled process input handle */
1465 mswindows_enqueue_process_event (p);
1469 /* None. This means that the process handle itself has signaled.
1470 Remove the handle from the wait vector, and make status_notify
1471 note the exited process */
1472 mswindows_waitable_handles [ix] =
1473 mswindows_waitable_handles [--mswindows_waitable_count];
1474 kick_status_notify ();
1475 /* We need to return a process event here so that
1476 (1) accept-process-output will return when called on this
1477 process, and (2) status notifications will happen in
1478 accept-process-output, sleep-for, and sit-for. */
1479 /* #### horrible kludge till my real process fixes go in.
1481 if (!NILP (Vprocess_list))
1483 Lisp_Object vaffanculo = XCAR (Vprocess_list);
1484 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1486 else /* trash me soon. */
1487 /* Have to return something: there may be no accompanying
1489 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1496 /************************************************************************/
1497 /* Event generators */
1498 /************************************************************************/
1501 * Callback procedure for synchronous timer messages
1503 static void CALLBACK
1504 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1506 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1507 Lisp_Event *event = XEVENT (emacs_event);
1509 if (KillTimer (NULL, id_timer))
1510 --mswindows_pending_timers_count;
1512 event->channel = Qnil;
1513 event->timestamp = dwtime;
1514 event->event_type = timeout_event;
1515 event->event.timeout.interval_id = id_timer;
1516 event->event.timeout.function = Qnil;
1517 event->event.timeout.object = Qnil;
1519 mswindows_enqueue_dispatch_event (emacs_event);
1523 * Callback procedure for dde messages
1525 * We execute a dde Open("file") by simulating a file drop, so dde support
1526 * depends on dnd support.
1528 #ifdef HAVE_DRAGNDROP
1530 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1531 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1532 DWORD dwData1, DWORD dwData2)
1537 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1538 return (HDDEDATA)TRUE;
1539 return (HDDEDATA)FALSE;
1541 case XTYP_WILDCONNECT:
1543 /* We only support one {service,topic} pair */
1544 HSZPAIR pairs[2] = {
1545 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1547 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1548 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1549 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1550 sizeof (pairs), 0L, 0, uFmt, 0));
1552 return (HDDEDATA)NULL;
1555 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1557 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1558 LPBYTE cmd = (LPBYTE) alloca (len+1);
1561 struct gcpro gcpro1, gcpro2;
1562 Lisp_Object l_dndlist = Qnil;
1563 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1564 Lisp_Object frmcons, devcons, concons;
1565 Lisp_Event *event = XEVENT (emacs_event);
1567 DdeGetData (hdata, cmd, len, 0);
1569 DdeFreeDataHandle (hdata);
1571 /* Check syntax & that it's an [Open("foo")] command, which we
1572 * treat like a file drop */
1573 /* #### Ought to be generalised and accept some other commands */
1576 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1577 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1578 return DDE_FNOTPROCESSED;
1579 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1582 if (*cmd!='(' || *(cmd+1)!='\"')
1583 return DDE_FNOTPROCESSED;
1585 while (*end && *end!='\"')
1588 return DDE_FNOTPROCESSED;
1591 return DDE_FNOTPROCESSED;
1595 return DDE_FNOTPROCESSED;
1598 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1599 strcpy (filename, "file:");
1600 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1602 dostounix_filename (cmd);
1603 filename = alloca (strlen (cmd)+6);
1604 strcpy (filename, "file:");
1605 strcat (filename, cmd);
1607 GCPRO2 (emacs_event, l_dndlist);
1608 l_dndlist = make_string (filename, strlen (filename));
1610 /* Find a mswindows frame */
1611 event->channel = Qnil;
1612 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1614 Lisp_Object frame = XCAR (frmcons);
1615 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1616 event->channel = frame;
1618 assert (!NILP (event->channel));
1620 event->timestamp = GetTickCount();
1621 event->event_type = misc_user_event;
1622 event->event.misc.button = 1;
1623 event->event.misc.modifiers = 0;
1624 event->event.misc.x = -1;
1625 event->event.misc.y = -1;
1626 event->event.misc.function = Qdragdrop_drop_dispatch;
1627 event->event.misc.object = Fcons (Qdragdrop_URL,
1628 Fcons (l_dndlist, Qnil));
1629 mswindows_enqueue_dispatch_event (emacs_event);
1631 return (HDDEDATA) DDE_FACK;
1633 DdeFreeDataHandle (hdata);
1634 return (HDDEDATA) DDE_FNOTPROCESSED;
1637 return (HDDEDATA) NULL;
1643 * Helper to do repainting - repaints can happen both from the windows
1644 * procedure and from magic events
1647 mswindows_handle_paint (struct frame *frame)
1649 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1651 /* According to the docs we need to check GetUpdateRect() before
1652 actually doing a WM_PAINT */
1653 if (GetUpdateRect (hwnd, NULL, FALSE))
1655 PAINTSTRUCT paintStruct;
1656 int x, y, width, height;
1658 BeginPaint (hwnd, &paintStruct);
1659 x = paintStruct.rcPaint.left;
1660 y = paintStruct.rcPaint.top;
1661 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1662 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1663 /* Normally we want to ignore expose events when child
1664 windows are unmapped, however once we are in the guts of
1665 WM_PAINT we need to make sure that we don't register
1666 unmaps then because they will not actually occur. */
1667 if (!check_for_ignored_expose (frame, x, y, width, height))
1669 hold_ignored_expose_registration = 1;
1670 mswindows_redraw_exposed_area (frame, x, y, width, height);
1671 hold_ignored_expose_registration = 0;
1673 EndPaint (hwnd, &paintStruct);
1678 * Returns 1 if a key is a real modifier or special key, which
1679 * is better handled by DefWindowProc
1682 key_needs_default_processing_p (UINT vkey)
1684 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU)
1691 * The windows procedure for the window class XEMACS_CLASS
1694 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1696 /* Note: Remember to initialize emacs_event and event before use.
1697 This code calls code that can GC. You must GCPRO before calling such code. */
1698 Lisp_Object emacs_event = Qnil;
1699 Lisp_Object fobj = Qnil;
1702 struct frame *frame;
1703 struct mswindows_frame* msframe;
1705 assert (!GetWindowLong (hwnd, GWL_USERDATA));
1708 case WM_DESTROYCLIPBOARD:
1709 /* We own the clipboard and someone else wants it. Delete our
1710 cached copy of the clipboard contents so we'll ask for it from
1711 Windows again when someone does a paste. */
1712 handle_selection_clear(QCLIPBOARD);
1716 /* Erase background only during non-dynamic sizing */
1717 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1718 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1723 fobj = mswindows_find_frame (hwnd);
1724 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1729 /* See Win95 comment under WM_KEYDOWN */
1732 int should_set_keymap = 0;
1734 if (wParam == VK_CONTROL)
1736 GetKeyboardState (keymap);
1737 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1738 should_set_keymap = 1;
1740 else if (wParam == VK_MENU)
1742 GetKeyboardState (keymap);
1743 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1744 should_set_keymap = 1;
1747 if (should_set_keymap
1748 && (message != WM_SYSKEYUP
1749 || NILP (Vmenu_accelerator_enabled)))
1750 SetKeyboardState (keymap);
1753 if (key_needs_default_processing_p (wParam))
1760 /* In some locales the right-hand Alt key is labelled AltGr. This key
1761 * should produce alternative charcaters when combined with another key.
1762 * eg on a German keyboard pressing AltGr+q should produce '@'.
1763 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1764 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1765 * it translates as if AltGr were down.
1766 * We get round this by removing all modifiers from the keymap before
1767 * calling TranslateMessage() unless AltGr is *really* down. */
1770 int has_AltGr = mswindows_current_layout_has_AltGr ();
1772 int extendedp = lParam & 0x1000000;
1775 frame = XFRAME (mswindows_find_frame (hwnd));
1776 GetKeyboardState (keymap);
1777 mods = mswindows_modifier_state (keymap, has_AltGr);
1779 /* Handle non-printables */
1780 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
1782 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1783 else /* Normal keys & modifiers */
1785 Emchar quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1786 BYTE keymap_orig[256];
1787 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1789 int potential_accelerator = 0;
1790 int got_accelerator = 0;
1793 msg.message = message;
1794 msg.wParam = wParam;
1795 msg.lParam = lParam;
1796 msg.time = GetMessageTime();
1799 /* GetKeyboardState() does not work as documented on Win95. We have
1800 * to loosely track Left and Right modifiers on behalf of the OS,
1801 * without screwing up Windows NT which tracks them properly. */
1802 if (wParam == VK_CONTROL)
1803 keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1804 else if (wParam == VK_MENU)
1805 keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
1807 memcpy (keymap_orig, keymap, 256);
1809 if (!NILP (Vmenu_accelerator_enabled) &&
1810 !(mods & XEMACS_MOD_SHIFT) && message == WM_SYSKEYDOWN)
1811 potential_accelerator = 1;
1813 /* Remove shift modifier from an ascii character */
1814 mods &= ~XEMACS_MOD_SHIFT;
1816 /* Clear control and alt modifiers unless AltGr is pressed */
1817 keymap [VK_RCONTROL] = 0;
1818 keymap [VK_LMENU] = 0;
1819 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80)
1820 || !(keymap [VK_RMENU] & 0x80))
1822 keymap [VK_LCONTROL] = 0;
1823 keymap [VK_CONTROL] = 0;
1824 keymap [VK_RMENU] = 0;
1825 keymap [VK_MENU] = 0;
1827 SetKeyboardState (keymap);
1829 /* Maybe generate some WM_[SYS]CHARs in the queue */
1830 TranslateMessage (&msg);
1832 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1833 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1836 WPARAM ch = tranmsg.wParam;
1838 /* If a quit char with no modifiers other than control and
1839 shift, then mark it with a fake modifier, which is removed
1840 upon dequeueing the event */
1841 /* #### This might also not withstand localization, if
1842 quit character is not a latin-1 symbol */
1843 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1844 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) && quit_ch == ch))
1845 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) == 0))
1847 mods1 |= FAKE_MOD_QUIT;
1848 ++mswindows_quit_chars_count;
1850 else if (potential_accelerator && !got_accelerator &&
1851 msw_char_is_accelerator (frame, ch))
1853 got_accelerator = 1;
1856 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
1858 SetKeyboardState (keymap_orig);
1859 /* This generates WM_SYSCHAR messages, which are interpreted
1860 by DefWindowProc as the menu selections. */
1861 if (got_accelerator)
1863 TranslateMessage (&msg);
1868 if (key_needs_default_processing_p (wParam))
1873 case WM_MBUTTONDOWN:
1875 /* Real middle mouse button has nothing to do with emulated one:
1876 if one wants to exercise fingers playing chords on the mouse,
1877 he is allowed to do that! */
1878 mswindows_enqueue_mouse_button_event (hwnd, message,
1879 MAKEPOINTS (lParam), GetMessageTime());
1883 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1884 msframe->last_click_time = GetMessageTime();
1886 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1887 msframe->button2_need_lbutton = 0;
1888 if (msframe->ignore_next_lbutton_up)
1890 msframe->ignore_next_lbutton_up = 0;
1892 else if (msframe->button2_is_down)
1894 msframe->button2_is_down = 0;
1895 msframe->ignore_next_rbutton_up = 1;
1896 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1897 MAKEPOINTS (lParam), GetMessageTime());
1901 if (msframe->button2_need_rbutton)
1903 msframe->button2_need_rbutton = 0;
1904 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1905 MAKEPOINTS (lParam), GetMessageTime());
1907 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1908 MAKEPOINTS (lParam), GetMessageTime());
1913 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1914 msframe->last_click_time = GetMessageTime();
1916 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1917 msframe->button2_need_rbutton = 0;
1918 if (msframe->ignore_next_rbutton_up)
1920 msframe->ignore_next_rbutton_up = 0;
1922 else if (msframe->button2_is_down)
1924 msframe->button2_is_down = 0;
1925 msframe->ignore_next_lbutton_up = 1;
1926 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1927 MAKEPOINTS (lParam), GetMessageTime());
1931 if (msframe->button2_need_lbutton)
1933 msframe->button2_need_lbutton = 0;
1934 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1935 MAKEPOINTS (lParam), GetMessageTime());
1937 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1938 MAKEPOINTS (lParam), GetMessageTime());
1942 case WM_LBUTTONDOWN:
1943 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1945 if (msframe->button2_need_lbutton)
1947 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1948 msframe->button2_need_lbutton = 0;
1949 msframe->button2_need_rbutton = 0;
1950 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1952 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1953 MAKEPOINTS (lParam), GetMessageTime());
1954 msframe->button2_is_down = 1;
1958 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1959 msframe->last_click_point, msframe->last_click_time);
1960 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1961 MAKEPOINTS (lParam), GetMessageTime());
1966 mswindows_set_chord_timer (hwnd);
1967 msframe->button2_need_rbutton = 1;
1968 msframe->last_click_point = MAKEPOINTS (lParam);
1970 msframe->last_click_time = GetMessageTime();
1973 case WM_RBUTTONDOWN:
1974 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1976 if (msframe->button2_need_rbutton)
1978 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1979 msframe->button2_need_lbutton = 0;
1980 msframe->button2_need_rbutton = 0;
1981 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1983 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1984 MAKEPOINTS (lParam), GetMessageTime());
1985 msframe->button2_is_down = 1;
1989 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1990 msframe->last_click_point, msframe->last_click_time);
1991 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1992 MAKEPOINTS (lParam), GetMessageTime());
1997 mswindows_set_chord_timer (hwnd);
1998 msframe->button2_need_lbutton = 1;
1999 msframe->last_click_point = MAKEPOINTS (lParam);
2001 msframe->last_click_time = GetMessageTime();
2005 if (wParam == BUTTON_2_TIMER_ID)
2007 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2008 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2010 if (msframe->button2_need_lbutton)
2012 msframe->button2_need_lbutton = 0;
2013 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2014 msframe->last_click_point, msframe->last_click_time);
2016 else if (msframe->button2_need_rbutton)
2018 msframe->button2_need_rbutton = 0;
2019 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2020 msframe->last_click_point, msframe->last_click_time);
2024 assert ("Spurious timer fired" == 0);
2028 /* Optimization: don't report mouse movement while size is changing */
2029 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2030 if (!msframe->sizing)
2032 /* When waiting for the second mouse button to finish
2033 button2 emulation, and have moved too far, just pretend
2034 as if timer has expired. This improves drag-select feedback */
2035 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2036 && !mswindows_button2_near_enough (msframe->last_click_point,
2037 MAKEPOINTS (lParam)))
2039 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2040 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2043 emacs_event = Fmake_event (Qnil, Qnil);
2044 event = XEVENT(emacs_event);
2046 event->channel = mswindows_find_frame(hwnd);
2047 event->timestamp = GetMessageTime();
2048 event->event_type = pointer_motion_event;
2049 event->event.motion.x = MAKEPOINTS(lParam).x;
2050 event->event.motion.y = MAKEPOINTS(lParam).y;
2051 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
2053 mswindows_enqueue_dispatch_event (emacs_event);
2059 /* Queue a `cancel-mode-internal' misc user event, so mouse
2060 selection would be canceled if any */
2061 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2062 Qcancel_mode_internal, Qnil);
2067 LPNMHDR nmhdr = (LPNMHDR)lParam;
2069 if (nmhdr->code == TTN_NEEDTEXT)
2071 #ifdef HAVE_TOOLBARS
2072 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2075 /* find out which toolbar */
2076 frame = XFRAME (mswindows_find_frame (hwnd));
2077 btext = mswindows_get_toolbar_button_text ( frame,
2080 tttext->lpszText = NULL;
2081 tttext->hinst = NULL;
2085 /* I think this is safe since the text will only go away
2086 when the toolbar does...*/
2087 TO_EXTERNAL_FORMAT (LISP_STRING, btext,
2088 C_STRING_ALLOCA, tttext->lpszText,
2093 /* handle tree view callbacks */
2094 else if (nmhdr->code == TVN_SELCHANGED)
2096 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2097 frame = XFRAME (mswindows_find_frame (hwnd));
2098 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2100 /* handle tab control callbacks */
2101 else if (nmhdr->code == TCN_SELCHANGE)
2104 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2105 frame = XFRAME (mswindows_find_frame (hwnd));
2107 item.mask = TCIF_PARAM;
2108 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2111 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2117 /* hdc will be NULL unless this is a subwindow - in which case we
2118 shouldn't have received a paint message for it here. */
2119 assert (wParam == 0);
2121 /* Can't queue a magic event because windows goes modal and sends paint
2122 messages directly to the windows procedure when doing solid drags
2123 and the message queue doesn't get processed. */
2124 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2128 /* We only care about this message if our size has really changed */
2129 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2134 fobj = mswindows_find_frame (hwnd);
2135 frame = XFRAME (fobj);
2136 msframe = FRAME_MSWINDOWS_DATA (frame);
2138 /* We cannot handle frame map and unmap hooks right in
2139 this routine, because these may throw. We queue
2140 magic events to run these hooks instead - kkm */
2142 if (wParam==SIZE_MINIMIZED)
2145 FRAME_VISIBLE_P (frame) = 0;
2146 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2150 GetClientRect(hwnd, &rect);
2151 FRAME_PIXWIDTH(frame) = rect.right;
2152 FRAME_PIXHEIGHT(frame) = rect.bottom;
2154 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2155 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2156 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2158 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2159 change_frame_size (frame, rows, columns, 1);
2161 /* If we are inside frame creation, we have to apply geometric
2163 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2165 /* Yes, we have to size again */
2166 mswindows_size_frame_internal ( frame,
2167 FRAME_MSWINDOWS_TARGET_RECT
2169 /* Reset so we do not get here again. The SetWindowPos call in
2170 * mswindows_size_frame_internal can cause recursion here. */
2171 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2173 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2174 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2179 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2180 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2181 FRAME_VISIBLE_P (frame) = 1;
2183 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2190 case WM_DISPLAYCHANGE:
2194 fobj = mswindows_find_frame (hwnd);
2195 frame = XFRAME (fobj);
2196 d = XDEVICE (FRAME_DEVICE (frame));
2198 DEVICE_MSWINDOWS_HORZRES(d) = LOWORD (lParam);
2199 DEVICE_MSWINDOWS_VERTRES(d) = HIWORD (lParam);
2200 DEVICE_MSWINDOWS_BITSPIXEL(d) = wParam;
2204 /* Misc magic events which only require that the frame be identified */
2207 mswindows_enqueue_magic_event (hwnd, message);
2210 case WM_WINDOWPOSCHANGING:
2212 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2213 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2214 GetWindowPlacement(hwnd, &wpl);
2216 /* Only interested if size is changing and we're not being iconified */
2217 if (wpl.showCmd != SW_SHOWMINIMIZED
2218 && wpl.showCmd != SW_SHOWMAXIMIZED
2219 && !(wp->flags & SWP_NOSIZE))
2221 RECT ncsize = { 0, 0, 0, 0 };
2222 int pixwidth, pixheight;
2223 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2224 GetMenu(hwnd) != NULL,
2225 GetWindowLong (hwnd, GWL_EXSTYLE));
2227 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2228 wp->cx - (ncsize.right - ncsize.left),
2229 wp->cy - (ncsize.bottom - ncsize.top),
2230 &pixwidth, &pixheight);
2232 /* Convert client sizes to window sizes */
2233 pixwidth += (ncsize.right - ncsize.left);
2234 pixheight += (ncsize.bottom - ncsize.top);
2236 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2238 /* Adjust so that the bottom or right doesn't move if it's
2239 * the top or left that's being changed */
2241 GetWindowRect (hwnd, &rect);
2243 if (rect.left != wp->x)
2244 wp->x += wp->cx - pixwidth;
2245 if (rect.top != wp->y)
2246 wp->y += wp->cy - pixheight;
2252 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2253 window position if the user tries to track window too small */
2257 case WM_ENTERSIZEMOVE:
2258 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2259 msframe->sizing = 1;
2262 case WM_EXITSIZEMOVE:
2263 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2264 msframe->sizing = 0;
2265 /* Queue noop event */
2266 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2269 #ifdef HAVE_SCROLLBARS
2273 /* Direction of scroll is determined by scrollbar instance. */
2274 int code = (int) LOWORD(wParam);
2275 int pos = (short int) HIWORD(wParam);
2276 HWND hwndScrollBar = (HWND) lParam;
2277 struct gcpro gcpro1, gcpro2;
2279 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2280 GCPRO2 (emacs_event, fobj);
2281 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2283 /* Error during event pumping - cancel scroll */
2284 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2292 int keys = LOWORD (wParam); /* Modifier key flags */
2293 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2294 struct gcpro gcpro1, gcpro2;
2296 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2298 GCPRO2 (emacs_event, fobj);
2299 mswindows_pump_outstanding_events (); /* Can GC */
2308 #ifdef HAVE_MENUBARS
2310 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2312 XFRAME (mswindows_find_frame (hwnd)))))
2313 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2316 case WM_INITMENUPOPUP:
2317 if (!HIWORD(lParam))
2319 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2321 XFRAME (mswindows_find_frame (hwnd)))))
2322 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2326 #endif /* HAVE_MENUBARS */
2330 WORD id = LOWORD (wParam);
2331 WORD nid = HIWORD (wParam);
2332 HWND cid = (HWND)lParam;
2333 frame = XFRAME (mswindows_find_frame (hwnd));
2335 #ifdef HAVE_TOOLBARS
2336 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2339 /* widgets in a buffer only eval a callback for suitable events.*/
2344 case CBN_EDITCHANGE:
2346 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2349 /* menubars always must come last since the hashtables do not
2351 #ifdef HAVE_MENUBARS
2352 if (!NILP (mswindows_handle_wm_command (frame, id)))
2356 return DefWindowProc (hwnd, message, wParam, lParam);
2357 /* Bite me - a spurious command. This used to not be able to
2358 happen but with the introduction of widgets its now
2363 case WM_CTLCOLORBTN:
2364 case WM_CTLCOLORLISTBOX:
2365 case WM_CTLCOLOREDIT:
2366 case WM_CTLCOLORSTATIC:
2367 case WM_CTLCOLORSCROLLBAR:
2369 /* if we get an opportunity to paint a widget then do so if
2370 there is an appropriate face */
2371 HWND crtlwnd = (HWND)lParam;
2372 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2375 Lisp_Object image_instance;
2376 VOID_TO_LISP (image_instance, ii);
2377 if (IMAGE_INSTANCEP (image_instance)
2379 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2381 /* set colors for the buttons */
2382 HDC hdc = (HDC)wParam;
2383 if (last_widget_brushed != ii)
2386 DeleteObject (widget_brush);
2387 widget_brush = CreateSolidBrush
2388 (COLOR_INSTANCE_MSWINDOWS_COLOR
2391 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2392 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2394 last_widget_brushed = ii;
2397 COLOR_INSTANCE_MSWINDOWS_COLOR
2400 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2401 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2402 SetBkMode (hdc, OPAQUE);
2405 COLOR_INSTANCE_MSWINDOWS_COLOR
2408 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2409 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2410 return (LRESULT)widget_brush;
2416 #ifdef HAVE_DRAGNDROP
2417 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2419 UINT filecount, i, len;
2424 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2425 struct gcpro gcpro1, gcpro2, gcpro3;
2427 emacs_event = Fmake_event (Qnil, Qnil);
2428 event = XEVENT(emacs_event);
2430 GCPRO3 (emacs_event, l_dndlist, l_item);
2432 if (!DragQueryPoint ((HDROP) wParam, &point))
2433 point.x = point.y = -1; /* outside client area */
2435 event->event_type = misc_user_event;
2436 event->channel = mswindows_find_frame(hwnd);
2437 event->timestamp = GetMessageTime();
2438 event->event.misc.button = 1; /* #### Should try harder */
2439 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2440 event->event.misc.x = point.x;
2441 event->event.misc.y = point.y;
2442 event->event.misc.function = Qdragdrop_drop_dispatch;
2444 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2445 for (i=0; i<filecount; i++)
2447 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2448 /* The URLs that we make here aren't correct according to section
2449 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2450 * because they may contain reserved characters. But that's OK -
2451 * they just need to be good enough to keep dragdrop.el happy. */
2452 fname = (char *)xmalloc (len+1);
2453 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2455 /* May be a shell link aka "shortcut" - replace fname if so */
2456 #if !(defined(__CYGWIN32__) || defined(__MINGW32__))
2457 /* cygwin doesn't define this COM stuff */
2458 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2462 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2463 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2467 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2471 WIN32_FIND_DATA wfd;
2472 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2474 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2476 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2477 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2482 len = strlen (fname);
2485 ppf->lpVtbl->Release (ppf);
2488 psl->lpVtbl->Release (psl);
2494 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2495 strcpy (filename, "file:");
2496 cygwin32_win32_to_posix_path_list (fname, filename+5);
2498 filename = (char *)xmalloc (len+6);
2499 strcat (strcpy (filename, "file:"), fname);
2500 dostounix_filename (filename+5);
2503 l_item = make_string (filename, strlen (filename));
2504 l_dndlist = Fcons (l_item, l_dndlist);
2507 DragFinish ((HDROP) wParam);
2509 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2510 mswindows_enqueue_dispatch_event (emacs_event);
2518 return DefWindowProc (hwnd, message, wParam, lParam);
2524 /************************************************************************/
2525 /* keyboard, mouse & other helpers for the windows procedure */
2526 /************************************************************************/
2528 mswindows_set_chord_timer (HWND hwnd)
2532 /* We get one third half system double click threshold */
2533 if (mswindows_mouse_button_tolerance <= 0)
2534 interval = GetDoubleClickTime () / 3;
2536 interval = mswindows_mouse_button_tolerance;
2538 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2542 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2545 if (mswindows_mouse_button_max_skew_x <= 0)
2546 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2548 dx = mswindows_mouse_button_max_skew_x;
2550 if (mswindows_mouse_button_max_skew_y <= 0)
2551 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2553 dy = mswindows_mouse_button_max_skew_y;
2555 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2559 mswindows_current_layout_has_AltGr (void)
2561 /* This simple caching mechanism saves 10% of CPU
2562 time when a key typed at autorepeat rate of 30 cps! */
2563 static HKL last_hkl = 0;
2564 static int last_hkl_has_AltGr;
2566 HKL current_hkl = GetKeyboardLayout (0);
2567 if (current_hkl != last_hkl)
2570 last_hkl_has_AltGr = 0;
2571 /* In this loop, we query whether a character requires
2572 AltGr to be down to generate it. If at least such one
2573 found, this means that the layout does regard AltGr */
2574 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2575 if (HIBYTE (VkKeyScan (c)) == 6)
2576 last_hkl_has_AltGr = 1;
2577 last_hkl = current_hkl;
2579 return last_hkl_has_AltGr;
2583 /* Returns the state of the modifier keys in the format expected by the
2584 * Lisp_Event key_data, button_data and motion_data modifiers member */
2585 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2591 keymap = (BYTE*) alloca(256);
2592 GetKeyboardState (keymap);
2593 has_AltGr = mswindows_current_layout_has_AltGr ();
2596 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2598 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
2599 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
2603 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
2604 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
2607 mods |= (keymap [VK_SHIFT] & 0x80) ? XEMACS_MOD_SHIFT : 0;
2613 * Translate a mswindows virtual key to a keysym.
2614 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2615 * or whose ASCII codes (like space) xemacs doesn't like.
2616 * Virtual key values are defined in winresrc.h
2618 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
2621 if (extendedp) /* Keys not present on a 82 key keyboard */
2623 switch (mswindows_key)
2625 case VK_RETURN: return KEYSYM ("kp-enter");
2626 case VK_PRIOR: return KEYSYM ("prior");
2627 case VK_NEXT: return KEYSYM ("next");
2628 case VK_END: return KEYSYM ("end");
2629 case VK_HOME: return KEYSYM ("home");
2630 case VK_LEFT: return KEYSYM ("left");
2631 case VK_UP: return KEYSYM ("up");
2632 case VK_RIGHT: return KEYSYM ("right");
2633 case VK_DOWN: return KEYSYM ("down");
2634 case VK_INSERT: return KEYSYM ("insert");
2635 case VK_DELETE: return QKdelete;
2640 switch (mswindows_key)
2642 case VK_BACK: return QKbackspace;
2643 case VK_TAB: return QKtab;
2644 case '\n': return QKlinefeed;
2645 case VK_CLEAR: return KEYSYM ("clear");
2646 case VK_RETURN: return QKreturn;
2647 case VK_ESCAPE: return QKescape;
2648 case VK_SPACE: return QKspace;
2649 case VK_PRIOR: return KEYSYM ("kp-prior");
2650 case VK_NEXT: return KEYSYM ("kp-next");
2651 case VK_END: return KEYSYM ("kp-end");
2652 case VK_HOME: return KEYSYM ("kp-home");
2653 case VK_LEFT: return KEYSYM ("kp-left");
2654 case VK_UP: return KEYSYM ("kp-up");
2655 case VK_RIGHT: return KEYSYM ("kp-right");
2656 case VK_DOWN: return KEYSYM ("kp-down");
2657 case VK_SELECT: return KEYSYM ("select");
2658 case VK_PRINT: return KEYSYM ("print");
2659 case VK_EXECUTE: return KEYSYM ("execute");
2660 case VK_SNAPSHOT: return KEYSYM ("print");
2661 case VK_INSERT: return KEYSYM ("kp-insert");
2662 case VK_DELETE: return KEYSYM ("kp-delete");
2663 case VK_HELP: return KEYSYM ("help");
2664 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
2665 case VK_LWIN return KEYSYM ("");
2666 case VK_RWIN return KEYSYM ("");
2668 case VK_APPS: return KEYSYM ("menu");
2669 case VK_NUMPAD0: return KEYSYM ("kp-0");
2670 case VK_NUMPAD1: return KEYSYM ("kp-1");
2671 case VK_NUMPAD2: return KEYSYM ("kp-2");
2672 case VK_NUMPAD3: return KEYSYM ("kp-3");
2673 case VK_NUMPAD4: return KEYSYM ("kp-4");
2674 case VK_NUMPAD5: return KEYSYM ("kp-5");
2675 case VK_NUMPAD6: return KEYSYM ("kp-6");
2676 case VK_NUMPAD7: return KEYSYM ("kp-7");
2677 case VK_NUMPAD8: return KEYSYM ("kp-8");
2678 case VK_NUMPAD9: return KEYSYM ("kp-9");
2679 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
2680 case VK_ADD: return KEYSYM ("kp-add");
2681 case VK_SEPARATOR: return KEYSYM ("kp-separator");
2682 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
2683 case VK_DECIMAL: return KEYSYM ("kp-decimal");
2684 case VK_DIVIDE: return KEYSYM ("kp-divide");
2685 case VK_F1: return KEYSYM ("f1");
2686 case VK_F2: return KEYSYM ("f2");
2687 case VK_F3: return KEYSYM ("f3");
2688 case VK_F4: return KEYSYM ("f4");
2689 case VK_F5: return KEYSYM ("f5");
2690 case VK_F6: return KEYSYM ("f6");
2691 case VK_F7: return KEYSYM ("f7");
2692 case VK_F8: return KEYSYM ("f8");
2693 case VK_F9: return KEYSYM ("f9");
2694 case VK_F10: return KEYSYM ("f10");
2695 case VK_F11: return KEYSYM ("f11");
2696 case VK_F12: return KEYSYM ("f12");
2697 case VK_F13: return KEYSYM ("f13");
2698 case VK_F14: return KEYSYM ("f14");
2699 case VK_F15: return KEYSYM ("f15");
2700 case VK_F16: return KEYSYM ("f16");
2701 case VK_F17: return KEYSYM ("f17");
2702 case VK_F18: return KEYSYM ("f18");
2703 case VK_F19: return KEYSYM ("f19");
2704 case VK_F20: return KEYSYM ("f20");
2705 case VK_F21: return KEYSYM ("f21");
2706 case VK_F22: return KEYSYM ("f22");
2707 case VK_F23: return KEYSYM ("f23");
2708 case VK_F24: return KEYSYM ("f24");
2715 * Find the console that matches the supplied mswindows window handle
2718 mswindows_find_console (HWND hwnd)
2720 /* We only support one console */
2721 return XCAR (Vconsole_list);
2725 * Find the frame that matches the supplied mswindows window handle
2728 mswindows_find_frame (HWND hwnd)
2730 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2734 /* We are in progress of frame creation. Return the frame
2735 being created, as it still not remembered in the window
2737 assert (!NILP (Vmswindows_frame_being_created));
2738 return Vmswindows_frame_being_created;
2740 VOID_TO_LISP (f, l);
2745 /************************************************************************/
2747 /************************************************************************/
2750 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2753 EMACS_TIME current_time;
2754 EMACS_GET_TIME (current_time);
2755 EMACS_SUB_TIME (thyme, thyme, current_time);
2756 milliseconds = EMACS_SECS (thyme) * 1000 +
2757 (EMACS_USECS (thyme) + 500) / 1000;
2758 if (milliseconds < 1)
2760 ++mswindows_pending_timers_count;
2761 return SetTimer (NULL, 0, milliseconds,
2762 (TIMERPROC) mswindows_wm_timer_callback);
2766 emacs_mswindows_remove_timeout (int id)
2768 Lisp_Event match_against;
2769 Lisp_Object emacs_event;
2771 if (KillTimer (NULL, id))
2772 --mswindows_pending_timers_count;
2774 /* If there is a dispatch event generated by this
2775 timeout in the queue, we have to remove it too. */
2776 match_against.event_type = timeout_event;
2777 match_against.event.timeout.interval_id = id;
2778 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2779 if (!NILP (emacs_event))
2780 Fdeallocate_event(emacs_event);
2783 /* If `user_p' is false, then return whether there are any win32, timeout,
2784 * or subprocess events pending (that is, whether
2785 * emacs_mswindows_next_event() would return immediately without blocking).
2787 * if `user_p' is true, then return whether there are any *user generated*
2788 * events available (that is, whether there are keyboard or mouse-click
2789 * events ready to be read). This also implies that
2790 * emacs_mswindows_next_event() would not block.
2793 emacs_mswindows_event_pending_p (int user_p)
2795 mswindows_need_event (0);
2796 return (!NILP (mswindows_u_dispatch_event_queue)
2797 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2801 * Return the next event
2804 emacs_mswindows_next_event (Lisp_Event *emacs_event)
2806 Lisp_Object event, event2;
2808 mswindows_need_event (1);
2810 event = mswindows_dequeue_dispatch_event ();
2811 XSETEVENT (event2, emacs_event);
2812 Fcopy_event (event, event2);
2813 Fdeallocate_event (event);
2817 * Handle a magic event off the dispatch queue.
2820 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
2822 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2829 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
2830 mswindows_handle_paint (f);
2831 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
2838 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2839 struct frame *f = XFRAME (frame);
2840 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2843 /* struct gcpro gcpro1; */
2845 /* Clear sticky modifiers here (if we had any) */
2847 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2848 /* GCPRO1 (conser); XXX Not necessary? */
2849 emacs_handle_focus_change_preliminary (conser);
2850 /* Under X the stuff up to here is done in the X event handler.
2852 emacs_handle_focus_change_final (conser);
2861 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2862 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2864 Qmap_frame_hook : Qunmap_frame_hook,
2869 /* #### What about Enter & Leave */
2871 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2872 Qmouse_leave_frame_hook, 1, frame);
2880 #ifndef HAVE_MSG_SELECT
2882 get_process_input_waitable (Lisp_Process *process)
2884 Lisp_Object instr, outstr, p;
2885 XSETPROCESS (p, process);
2886 get_process_streams (process, &instr, &outstr);
2887 assert (!NILP (instr));
2888 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2889 return (network_connection_p (p)
2890 ? get_winsock_stream_waitable (XLSTREAM (instr))
2891 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2893 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2898 emacs_mswindows_select_process (Lisp_Process *process)
2900 HANDLE hev = get_process_input_waitable (process);
2902 if (!add_waitable_handle (hev))
2903 error ("Too many active processes");
2905 #ifdef HAVE_WIN32_PROCESSES
2908 XSETPROCESS (p, process);
2909 if (!network_connection_p (p))
2911 HANDLE hprocess = get_nt_process_handle (process);
2912 if (!add_waitable_handle (hprocess))
2914 remove_waitable_handle (hev);
2915 error ("Too many active processes");
2923 emacs_mswindows_unselect_process (Lisp_Process *process)
2925 /* Process handle is removed in the event loop as soon
2926 as it is signaled, so don't bother here about it */
2927 HANDLE hev = get_process_input_waitable (process);
2928 remove_waitable_handle (hev);
2930 #endif /* HAVE_MSG_SELECT */
2933 emacs_mswindows_select_console (struct console *con)
2935 #ifdef HAVE_MSG_SELECT
2936 if (CONSOLE_MSWINDOWS_P (con))
2937 return; /* mswindows consoles are automatically selected */
2939 event_stream_unixoid_select_console (con);
2944 emacs_mswindows_unselect_console (struct console *con)
2946 #ifdef HAVE_MSG_SELECT
2947 if (CONSOLE_MSWINDOWS_P (con))
2948 return; /* mswindows consoles are automatically selected */
2950 event_stream_unixoid_unselect_console (con);
2955 emacs_mswindows_quit_p (void)
2957 /* Quit cannot happen in modal loop: all program
2958 input is dedicated to Windows. */
2959 if (mswindows_in_modal_loop)
2962 /* Drain windows queue. This sets up number of quit characters in
2964 mswindows_drain_windows_queue ();
2966 if (mswindows_quit_chars_count > 0)
2968 /* Yes there's a hidden one... Throw it away */
2969 Lisp_Event match_against;
2970 Lisp_Object emacs_event;
2973 match_against.event_type = key_press_event;
2974 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2976 while (mswindows_quit_chars_count-- > 0)
2978 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2979 assert (!NILP (emacs_event));
2981 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
2984 Fdeallocate_event(emacs_event);
2987 Vquit_flag = critical_p ? Qcritical : Qt;
2992 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2993 Lisp_Object* instream,
2994 Lisp_Object* outstream,
2997 /* Handles for streams */
2999 /* fds. These just stored along with the streams, and are closed in
3000 delete stream pair method, because we need to handle fake unices
3004 /* Decode inhandle and outhandle. Their meaning depends on
3005 the process implementation being used. */
3006 #if defined (HAVE_WIN32_PROCESSES)
3007 /* We're passed in Windows handles. That's what we like most... */
3008 hin = (HANDLE) inhandle;
3009 hout = (HANDLE) outhandle;
3011 #elif defined (HAVE_UNIX_PROCESSES)
3012 /* We are passed UNIX fds. This must be Cygwin.
3014 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3015 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3019 #error "So, WHICH kind of processes do you want?"
3022 *instream = (hin == INVALID_HANDLE_VALUE
3024 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3025 : flags & STREAM_NETWORK_CONNECTION
3026 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3028 : make_ntpipe_input_stream (hin, fdi));
3030 #ifdef HAVE_WIN32_PROCESSES
3031 *outstream = (hout == INVALID_HANDLE_VALUE
3033 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3034 : flags & STREAM_NETWORK_CONNECTION
3035 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3037 : make_ntpipe_output_stream (hout, fdo));
3038 #elif defined (HAVE_UNIX_PROCESSES)
3039 *outstream = (fdo >= 0
3040 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3043 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3044 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3045 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3047 Bufbyte eof_char = get_eof_char (fdo);
3048 int pty_max_bytes = get_pty_max_bytes (fdo);
3049 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3054 return (NILP (*instream)
3056 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3057 : flags & STREAM_NETWORK_CONNECTION
3058 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3060 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3064 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3065 Lisp_Object outstream)
3067 /* Oh nothing special here for Win32 at all */
3068 #if defined (HAVE_UNIX_PROCESSES)
3069 int in = (NILP(instream)
3071 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3072 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3073 ? get_winsock_stream_param (XLSTREAM (instream))
3075 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3076 int out = (NILP(outstream) ? -1
3077 : filedesc_stream_fd (XLSTREAM (outstream)));
3081 if (out != in && out >= 0)
3085 return (NILP (instream)
3087 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3088 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3089 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3091 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3094 #ifndef HAVE_X_WINDOWS
3095 /* This is called from GC when a process object is about to be freed.
3096 If we've still got pointers to it in this file, we're gonna lose hard.
3099 debug_process_finalization (Lisp_Process *p)
3102 Lisp_Object instr, outstr;
3104 get_process_streams (p, &instr, &outstr);
3105 /* if it still has fds, then it hasn't been killed yet. */
3106 assert (NILP(instr));
3107 assert (NILP(outstr));
3109 /* #### More checks here */
3114 /************************************************************************/
3115 /* initialization */
3116 /************************************************************************/
3119 reinit_vars_of_event_mswindows (void)
3121 mswindows_in_modal_loop = 0;
3122 mswindows_pending_timers_count = 0;
3124 mswindows_event_stream = xnew (struct event_stream);
3126 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3127 mswindows_event_stream->force_event_pending = 0;
3128 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3129 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3130 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3131 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3132 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3133 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3134 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3135 #ifdef HAVE_MSG_SELECT
3136 mswindows_event_stream->select_process_cb =
3137 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3138 mswindows_event_stream->unselect_process_cb =
3139 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3140 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3141 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3143 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3144 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3145 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3146 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3151 vars_of_event_mswindows (void)
3153 reinit_vars_of_event_mswindows ();
3155 mswindows_u_dispatch_event_queue = Qnil;
3156 staticpro (&mswindows_u_dispatch_event_queue);
3157 mswindows_u_dispatch_event_queue_tail = Qnil;
3158 pdump_wire (&mswindows_u_dispatch_event_queue_tail);
3160 mswindows_s_dispatch_event_queue = Qnil;
3161 staticpro (&mswindows_s_dispatch_event_queue);
3162 mswindows_s_dispatch_event_queue_tail = Qnil;
3163 pdump_wire (&mswindows_s_dispatch_event_queue_tail);
3165 mswindows_error_caught_in_modal_loop = Qnil;
3166 staticpro (&mswindows_error_caught_in_modal_loop);
3168 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3169 &mswindows_alt_by_itself_activates_menu /*
3170 *Controls whether pressing and releasing the Alt key activates the menubar.
3171 This applies only if no intervening key was pressed. See also
3172 `menu-accelerator-enabled', which is probably the behavior you actually want.
3176 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3177 &mswindows_dynamic_frame_resize /*
3178 *Controls redrawing frame contents during mouse-drag or keyboard resize
3179 operation. When non-nil, the frame is redrawn while being resized. When
3180 nil, frame is not redrawn, and exposed areas are filled with default
3181 MDI application background color. Note that this option only has effect
3182 if "Show window contents while dragging" is on in system Display/Plus!
3184 Default is t on fast machines, nil on slow.
3187 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3188 &mswindows_mouse_button_tolerance /*
3189 *Analogue of double click interval for faking middle mouse events.
3190 The value is the minimum time in milliseconds that must elapse between
3191 left/right button down events before they are considered distinct events.
3192 If both mouse buttons are depressed within this interval, a middle mouse
3193 button down event is generated instead.
3194 If negative or zero, currently set system default is used instead.
3197 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3198 Number of physical mouse buttons.
3201 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3202 &mswindows_mouse_button_max_skew_x /*
3203 *Maximum horizontal distance in pixels between points in which left and
3204 right button clicks occurred for them to be translated into single
3205 middle button event. Clicks must occur in time not longer than defined
3206 by the variable `mswindows-mouse-button-tolerance'.
3207 If negative or zero, currently set system default is used instead.
3210 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3211 &mswindows_mouse_button_max_skew_y /*
3212 *Maximum vertical distance in pixels between points in which left and
3213 right button clicks occurred for them to be translated into single
3214 middle button event. Clicks must occur in time not longer than defined
3215 by the variable `mswindows-mouse-button-tolerance'.
3216 If negative or zero, currently set system default is used instead.
3219 mswindows_mouse_button_max_skew_x = 0;
3220 mswindows_mouse_button_max_skew_y = 0;
3221 mswindows_mouse_button_tolerance = 0;
3222 mswindows_alt_by_itself_activates_menu = 1;
3226 syms_of_event_mswindows (void)
3231 lstream_type_create_mswindows_selectable (void)
3233 init_slurp_stream ();
3234 init_shove_stream ();
3235 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3236 init_winsock_stream ();
3241 init_event_mswindows_late (void)
3243 #ifdef HAVE_MSG_SELECT
3244 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3245 assert (windows_fd>=0);
3246 FD_SET (windows_fd, &input_wait_mask);
3247 FD_ZERO(&zero_mask);
3250 event_stream = mswindows_event_stream;
3252 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3253 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);