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"
66 #include "objects-msw.h"
68 #include "events-mod.h"
69 #ifdef HAVE_MSG_SELECT
71 #include "console-tty.h"
72 #elif defined(__CYGWIN32__)
73 typedef unsigned int SOCKET;
78 #if !(defined(__CYGWIN32__) || defined(__MINGW32__))
79 # include <shlobj.h> /* For IShellLink */
83 #define ADJR_MENUFLAG TRUE
85 #define ADJR_MENUFLAG FALSE
88 /* Fake key modifier which is attached to a quit char event.
89 Removed upon dequeueing an event */
90 #define FAKE_MOD_QUIT 0x80
92 /* Timer ID used for button2 emulation */
93 #define BUTTON_2_TIMER_ID 1
95 static Lisp_Object mswindows_find_frame (HWND hwnd);
96 static Lisp_Object mswindows_find_console (HWND hwnd);
97 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
99 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
100 static void mswindows_set_chord_timer (HWND hwnd);
101 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
102 static int mswindows_current_layout_has_AltGr (void);
103 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
104 int downp, int keyp);
106 static struct event_stream *mswindows_event_stream;
108 #ifdef HAVE_MSG_SELECT
109 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
110 extern SELECT_TYPE process_only_mask, tty_only_mask;
111 SELECT_TYPE zero_mask;
112 extern int signal_event_pipe_initialized;
117 * Two separate queues, for efficiency, one (_u_) for user events, and
118 * another (_s_) for non-user ones. We always return events out of the
119 * first one until it is empty and only then proceed with the second
122 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
123 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
125 /* The number of things we can wait on */
126 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
128 #ifndef HAVE_MSG_SELECT
129 /* List of mswindows waitable handles. */
130 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
132 /* Number of wait handles */
133 static int mswindows_waitable_count=0;
134 #endif /* HAVE_MSG_SELECT */
136 /* Brush for painting widgets */
137 static HBRUSH widget_brush = 0;
138 static LONG last_widget_brushed = 0;
140 /* Count of quit chars currently in the queue */
141 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
142 Decremented in mswindows_dequeue_dispatch_event() */
143 int mswindows_quit_chars_count = 0;
145 /* These are Lisp integers; see DEFVARS in this file for description. */
146 int mswindows_dynamic_frame_resize;
147 int mswindows_alt_by_itself_activates_menu;
148 int mswindows_num_mouse_buttons;
149 int mswindows_mouse_button_max_skew_x;
150 int mswindows_mouse_button_max_skew_y;
151 int mswindows_mouse_button_tolerance;
154 int mswindows_debug_events;
157 /* This is the event signaled by the event pump.
158 See mswindows_pump_outstanding_events for comments */
159 static Lisp_Object mswindows_error_caught_in_modal_loop;
160 static int mswindows_in_modal_loop;
162 /* Count of wound timers */
163 static int mswindows_pending_timers_count;
165 /************************************************************************/
166 /* Pipe instream - reads process output */
167 /************************************************************************/
169 #define PIPE_READ_DELAY 20
171 #define HANDLE_TO_USID(h) ((USID)(h))
173 #define NTPIPE_SLURP_STREAM_DATA(stream) \
174 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
176 /* This structure is allocated by the main thread, and is deallocated
177 in the thread upon exit. There are situations when a thread
178 remains blocked for a long time, much longer than the lstream
179 exists. For example, "start notepad" command is issued from the
180 shell, then the shell is closed by C-c C-d. Although the shell
181 process exits, its output pipe will not get closed until the
182 notepad process exits also, because it inherits the pipe form the
183 shell. In this case, we abandon the thread, and let it live until
184 all such processes exit. While struct ntpipe_slurp_stream is
185 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
187 struct ntpipe_slurp_stream_shared_data
189 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
190 /* This is a manual-reset object. */
191 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
192 /* This is a manual-reset object. */
193 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
194 /* This is a manual-reset object. */
195 HANDLE hpipe; /* Pipe read end handle. */
196 LONG die_p; /* Thread must exit ASAP if non-zero */
197 BOOL eof_p : 1; /* Set when thread saw EOF */
198 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
199 BOOL inuse_p : 1; /* this structure is in use */
200 LONG lock_count; /* Client count of this struct, 0=safe to free */
201 BYTE onebyte; /* One byte buffer read by thread */
204 #define MAX_SLURP_STREAMS 32
205 struct ntpipe_slurp_stream_shared_data
206 shared_data_block[MAX_SLURP_STREAMS]={{0}};
208 struct ntpipe_slurp_stream
210 LPARAM user_data; /* Any user data stored in the stream object */
211 struct ntpipe_slurp_stream_shared_data* thread_data;
214 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
215 sizeof (struct ntpipe_slurp_stream));
217 /* This function is thread-safe, and is called from either thread
218 context. It serializes freeing shared data structure */
220 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
222 if (InterlockedDecrement (&s->lock_count) == 0)
225 CloseHandle (s->hev_thread);
226 CloseHandle (s->hev_caller);
227 CloseHandle (s->hev_unsleep);
232 static struct ntpipe_slurp_stream_shared_data*
233 slurper_allocate_shared_data (void)
236 for (i=0; i<MAX_SLURP_STREAMS; i++)
238 if (!shared_data_block[i].inuse_p)
240 shared_data_block[i].inuse_p=1;
241 return &shared_data_block[i];
244 return (struct ntpipe_slurp_stream_shared_data*)0;
248 slurp_thread (LPVOID vparam)
250 struct ntpipe_slurp_stream_shared_data *s =
251 (struct ntpipe_slurp_stream_shared_data*)vparam;
255 /* Read one byte from the pipe */
257 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
259 DWORD err = GetLastError ();
260 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
265 else if (actually_read == 0)
268 /* We must terminate on an error or eof */
269 if (s->eof_p || s->error_p)
270 InterlockedIncrement (&s->die_p);
272 /* Before we notify caller, we unsignal our event. */
273 ResetEvent (s->hev_thread);
275 /* Now we got something to notify caller, either a byte or an
276 error/eof indication. Before we do, allow internal pipe
277 buffer to accumulate little bit more data.
278 Reader function pulses this event before waiting for
279 a character, to avoid pipe delay, and to get the byte
282 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
284 /* Either make event loop generate a process event, or
286 SetEvent (s->hev_caller);
288 /* Cleanup and exit if we're shot off */
292 /* Block until the client finishes with retrieving the rest of
294 WaitForSingleObject (s->hev_thread, INFINITE);
297 slurper_free_shared_data_maybe (s);
303 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
306 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
307 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
308 DWORD thread_id_unused;
311 /* We deal only with pipes, for we're using PeekNamedPipe api */
312 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
314 s->thread_data = slurper_allocate_shared_data();
316 /* Create reader thread. This could fail, so do not create events
317 until thread is created */
318 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
319 CREATE_SUSPENDED, &thread_id_unused);
322 Lstream_delete (lstr);
323 s->thread_data->inuse_p=0;
327 /* Shared data are initially owned by both main and slurper
329 s->thread_data->lock_count = 2;
330 s->thread_data->die_p = 0;
331 s->thread_data->eof_p = FALSE;
332 s->thread_data->error_p = FALSE;
333 s->thread_data->hpipe = hpipe;
334 s->user_data = param;
336 /* hev_thread is a manual-reset event, initially signaled */
337 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
338 /* hev_caller is a manual-reset event, initially nonsignaled */
339 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
340 /* hev_unsleep is a manual-reset event, initially nonsignaled */
341 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
344 ResumeThread (hthread);
345 CloseHandle (hthread);
347 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
348 XSETLSTREAM (obj, lstr);
353 get_ntpipe_input_stream_param (Lstream *stream)
355 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
360 get_ntpipe_input_stream_waitable (Lstream *stream)
362 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
363 return s->thread_data->hev_caller;
367 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
369 /* This function must be called from the main thread only */
370 struct ntpipe_slurp_stream_shared_data* s =
371 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
376 /* Disallow pipe read delay for the thread: we need a character
378 SetEvent (s->hev_unsleep);
380 /* Check if we have a character ready. Give it a short delay,
381 for the thread to awake from pipe delay, just ion case*/
382 wait_result = WaitForSingleObject (s->hev_caller, 2);
384 /* Revert to the normal sleep behavior. */
385 ResetEvent (s->hev_unsleep);
387 /* If there's no byte buffered yet, give up */
388 if (wait_result == WAIT_TIMEOUT)
395 /* Reset caller unlock event now, as we've handled the pending
396 process output event */
397 ResetEvent (s->hev_caller);
399 /* It is now safe to do anything with contents of S, except for
400 changing s->die_p, which still should be interlocked */
404 if (s->error_p || s->die_p)
407 /* Ok, there were no error neither eof - we've got a byte from the
409 *(data++) = s->onebyte;
413 DWORD bytes_read = 0;
416 DWORD bytes_available;
418 /* If the api call fails, return at least one byte already
419 read. ReadFile in thread will return error */
420 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
423 /* Fetch available bytes. The same consideration applies,
424 so do not check for errors. ReadFile in the thread will
425 fail if the next call fails. */
427 ReadFile (s->hpipe, data, min (bytes_available, size),
431 /* Now we can unblock thread, so it attempts to read more */
432 SetEvent (s->hev_thread);
433 return bytes_read + 1;
440 ntpipe_slurp_closer (Lstream *stream)
442 /* This function must be called from the main thread only */
443 struct ntpipe_slurp_stream_shared_data* s =
444 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
446 /* Force thread to stop */
447 InterlockedIncrement (&s->die_p);
449 /* Set events which could possibly block slurper. Let it finish soon
451 SetEvent (s->hev_unsleep);
452 SetEvent (s->hev_thread);
454 /* Unlock and maybe free shared data */
455 slurper_free_shared_data_maybe (s);
461 init_slurp_stream (void)
463 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
464 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
467 /************************************************************************/
468 /* Pipe outstream - writes process input */
469 /************************************************************************/
471 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
472 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
474 #define MAX_SHOVE_BUFFER_SIZE 128
476 struct ntpipe_shove_stream
478 LPARAM user_data; /* Any user data stored in the stream object */
479 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
480 /* This is an auto-reset object. */
481 HANDLE hpipe; /* Pipe write end handle. */
482 HANDLE hthread; /* Reader thread handle. */
483 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
484 DWORD size; /* Number of bytes to write */
485 LONG die_p; /* Thread must exit ASAP if non-zero */
486 LONG idle_p; /* Non-zero if thread is waiting for job */
487 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
488 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
491 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
492 sizeof (struct ntpipe_shove_stream));
494 #ifndef HAVE_MSG_SELECT
496 shove_thread (LPVOID vparam)
498 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
504 /* Block on event and wait for a job */
505 InterlockedIncrement (&s->idle_p);
506 WaitForSingleObject (s->hev_thread, INFINITE);
511 /* Write passed buffer */
512 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
513 || bytes_written != s->size)
516 InterlockedIncrement (&s->die_p);
527 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
530 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
531 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
532 DWORD thread_id_unused;
537 s->user_data = param;
539 /* Create reader thread. This could fail, so do not
540 create the event until thread is created */
541 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
542 CREATE_SUSPENDED, &thread_id_unused);
543 if (s->hthread == NULL)
545 Lstream_delete (lstr);
549 /* hev_thread is an auto-reset event, initially nonsignaled */
550 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
553 ResumeThread (s->hthread);
555 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
556 XSETLSTREAM (obj, lstr);
561 get_ntpipe_output_stream_param (Lstream *stream)
563 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
569 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
571 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
576 s->blocking_p = !s->idle_p;
580 if (size>MAX_SHOVE_BUFFER_SIZE)
583 memcpy (s->buffer, data, size);
587 InterlockedDecrement (&s->idle_p);
588 SetEvent (s->hev_thread);
593 ntpipe_shove_was_blocked_p (Lstream *stream)
595 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
596 return s->blocking_p;
600 ntpipe_shove_closer (Lstream *stream)
602 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
604 /* Force thread stop */
605 InterlockedIncrement (&s->die_p);
607 /* Close pipe handle, possibly breaking it */
608 CloseHandle (s->hpipe);
610 /* Thread will end upon unblocking */
611 SetEvent (s->hev_thread);
613 /* Wait while thread terminates */
614 WaitForSingleObject (s->hthread, INFINITE);
615 CloseHandle (s->hthread);
617 /* Destroy the event */
618 CloseHandle (s->hev_thread);
624 init_shove_stream (void)
626 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
627 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
628 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
631 /************************************************************************/
632 /* Winsock I/O stream */
633 /************************************************************************/
634 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
636 #define WINSOCK_READ_BUFFER_SIZE 1024
638 struct winsock_stream
640 LPARAM user_data; /* Any user data stored in the stream object */
641 SOCKET s; /* Socket handle (which is a Win32 handle) */
642 OVERLAPPED ov; /* Overlapped I/O structure */
643 void* buffer; /* Buffer. Allocated for input stream only */
644 unsigned long bufsize; /* Number of bytes last read */
645 unsigned long bufpos; /* Position in buffer for next fetch */
646 unsigned int error_p :1; /* I/O Error seen */
647 unsigned int eof_p :1; /* EOF Error seen */
648 unsigned int pending_p :1; /* There is a pending I/O operation */
649 unsigned int blocking_p :1; /* Last write attempt would block */
652 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
654 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
655 sizeof (struct winsock_stream));
658 winsock_initiate_read (struct winsock_stream *str)
660 ResetEvent (str->ov.hEvent);
663 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
664 &str->bufsize, &str->ov))
666 if (GetLastError () == ERROR_IO_PENDING)
668 else if (GetLastError () == ERROR_HANDLE_EOF)
673 else if (str->bufsize == 0)
678 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
680 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
682 /* If the current operation is not yet complete, there's nothing to
686 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
693 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
695 if (GetLastError() == ERROR_HANDLE_EOF)
700 if (str->bufsize == 0)
711 /* Return as much of buffer as we have */
712 size = min (size, (size_t) (str->bufsize - str->bufpos));
713 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
716 /* Read more if buffer is exhausted */
717 if (str->bufsize == str->bufpos)
718 winsock_initiate_read (str);
724 winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
726 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
730 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
738 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
753 ResetEvent (str->ov.hEvent);
755 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
756 * an overlapped operation. This fails on Win95 with winsock 1.x so we
757 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
758 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
759 || GetLastError() == ERROR_IO_PENDING)
765 return str->error_p ? -1 : size;
769 winsock_closer (Lstream *lstr)
771 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
773 if (lstr->flags & LSTREAM_FL_READ)
774 shutdown (str->s, 0);
776 shutdown (str->s, 1);
778 CloseHandle ((HANDLE)str->s);
780 WaitForSingleObject (str->ov.hEvent, INFINITE);
782 if (lstr->flags & LSTREAM_FL_READ)
785 CloseHandle (str->ov.hEvent);
790 winsock_was_blocked_p (Lstream *stream)
792 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
793 return str->blocking_p;
797 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
800 Lstream *lstr = Lstream_new (lstream_winsock, mode);
801 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
808 str->user_data = param;
811 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
813 if (lstr->flags & LSTREAM_FL_READ)
815 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
816 winsock_initiate_read (str);
819 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
820 XSETLSTREAM (obj, lstr);
825 make_winsock_input_stream (SOCKET s, LPARAM param)
827 return make_winsock_stream_1 (s, param, "r");
831 make_winsock_output_stream (SOCKET s, LPARAM param)
833 return make_winsock_stream_1 (s, param, "w");
837 get_winsock_stream_waitable (Lstream *lstr)
839 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
840 return str->ov.hEvent;
844 get_winsock_stream_param (Lstream *lstr)
846 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
847 return str->user_data;
851 init_winsock_stream (void)
853 LSTREAM_HAS_METHOD (winsock, reader);
854 LSTREAM_HAS_METHOD (winsock, writer);
855 LSTREAM_HAS_METHOD (winsock, closer);
856 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
858 #endif /* defined (HAVE_SOCKETS) */
860 /************************************************************************/
861 /* Dispatch queue management */
862 /************************************************************************/
865 mswindows_user_event_p (Lisp_Event* sevt)
867 return (sevt->event_type == key_press_event
868 || sevt->event_type == button_press_event
869 || sevt->event_type == button_release_event
870 || sevt->event_type == misc_user_event);
874 * Add an emacs event to the proper dispatch queue
877 mswindows_enqueue_dispatch_event (Lisp_Object event)
879 int user_p = mswindows_user_event_p (XEVENT(event));
880 enqueue_event (event,
881 user_p ? &mswindows_u_dispatch_event_queue :
882 &mswindows_s_dispatch_event_queue,
883 user_p ? &mswindows_u_dispatch_event_queue_tail :
884 &mswindows_s_dispatch_event_queue_tail);
886 /* Avoid blocking on WaitMessage */
887 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
891 * Add a misc-user event to the dispatch queue.
893 * Stuff it into our own dispatch queue, so we have something
894 * to return from next_event callback.
897 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
900 Lisp_Object event = Fmake_event (Qnil, Qnil);
901 Lisp_Event* e = XEVENT (event);
903 e->event_type = misc_user_event;
904 e->channel = channel;
905 e->timestamp = GetTickCount ();
906 e->event.misc.function = function;
907 e->event.misc.object = object;
909 mswindows_enqueue_dispatch_event (event);
913 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
915 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
916 Lisp_Event* event = XEVENT (emacs_event);
918 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
919 event->timestamp = GetMessageTime();
920 event->event_type = magic_event;
921 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
923 mswindows_enqueue_dispatch_event (emacs_event);
927 mswindows_enqueue_process_event (Lisp_Process* p)
929 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
930 Lisp_Event* event = XEVENT (emacs_event);
932 XSETPROCESS (process, p);
934 event->event_type = process_event;
935 event->timestamp = GetTickCount ();
936 event->event.process.process = process;
938 mswindows_enqueue_dispatch_event (emacs_event);
942 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
945 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
946 msg == WM_RBUTTONDOWN);
948 /* We always use last message time, because mouse button
949 events may get delayed, and XEmacs double click
950 recognition will fail */
952 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
953 Lisp_Event* event = XEVENT (emacs_event);
955 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
956 event->channel = mswindows_find_frame (hwnd);
957 event->timestamp = when;
958 event->event.button.button =
959 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
960 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
961 event->event.button.x = where.x;
962 event->event.button.y = where.y;
963 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
967 event->event_type = button_press_event;
969 /* we need this to make sure the main window regains the focus
970 from control subwindows */
971 if (GetFocus() != hwnd)
974 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
979 event->event_type = button_release_event;
983 mswindows_enqueue_dispatch_event (emacs_event);
987 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
989 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
990 Lisp_Event* event = XEVENT(emacs_event);
992 event->channel = mswindows_find_console(hwnd);
993 event->timestamp = GetMessageTime();
994 event->event_type = key_press_event;
995 event->event.key.keysym = keysym;
996 event->event.key.modifiers = mods;
997 mswindows_enqueue_dispatch_event (emacs_event);
1001 * Remove and return the first emacs event on the dispatch queue.
1002 * Give a preference to user events over non-user ones.
1005 mswindows_dequeue_dispatch_event (void)
1010 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1011 !NILP(mswindows_s_dispatch_event_queue));
1013 event = dequeue_event (
1014 NILP(mswindows_u_dispatch_event_queue) ?
1015 &mswindows_s_dispatch_event_queue :
1016 &mswindows_u_dispatch_event_queue,
1017 NILP(mswindows_u_dispatch_event_queue) ?
1018 &mswindows_s_dispatch_event_queue_tail :
1019 &mswindows_u_dispatch_event_queue_tail);
1021 sevt = XEVENT(event);
1022 if (sevt->event_type == key_press_event
1023 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1025 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1026 --mswindows_quit_chars_count;
1033 * Remove and return the first emacs event on the dispatch queue that matches
1034 * the supplied event.
1035 * Timeout event matches if interval_id is equal to that of the given event.
1036 * Keypress event matches if logical AND between modifiers bitmask of the
1037 * event in the queue and that of the given event is non-zero.
1038 * For all other event types, this function aborts.
1042 mswindows_cancel_dispatch_event (Lisp_Event *match)
1045 Lisp_Object previous_event = Qnil;
1046 int user_p = mswindows_user_event_p (match);
1047 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1048 &mswindows_s_dispatch_event_queue;
1049 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1050 &mswindows_s_dispatch_event_queue_tail;
1052 assert (match->event_type == timeout_event
1053 || match->event_type == key_press_event);
1055 EVENT_CHAIN_LOOP (event, *head)
1057 Lisp_Event *e = XEVENT (event);
1058 if ((e->event_type == match->event_type) &&
1059 ((e->event_type == timeout_event) ?
1060 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1061 /* Must be key_press_event */
1062 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1064 if (NILP (previous_event))
1065 dequeue_event (head, tail);
1068 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1069 if (EQ (*tail, event))
1070 *tail = previous_event;
1075 previous_event = event;
1080 #ifndef HAVE_MSG_SELECT
1081 /************************************************************************/
1082 /* Waitable handles manipulation */
1083 /************************************************************************/
1085 find_waitable_handle (HANDLE h)
1088 for (i = 0; i < mswindows_waitable_count; ++i)
1089 if (mswindows_waitable_handles[i] == h)
1096 add_waitable_handle (HANDLE h)
1098 assert (find_waitable_handle (h) < 0);
1099 if (mswindows_waitable_count == MAX_WAITABLE)
1102 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1107 remove_waitable_handle (HANDLE h)
1109 int ix = find_waitable_handle (h);
1113 mswindows_waitable_handles [ix] =
1114 mswindows_waitable_handles [--mswindows_waitable_count];
1116 #endif /* HAVE_MSG_SELECT */
1119 /************************************************************************/
1121 /************************************************************************/
1124 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1125 Lisp_Object u_n_u_s_e_d)
1127 mswindows_error_caught_in_modal_loop = cons_sig_data;
1132 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1137 ++mswindows_in_modal_loop;
1138 tmp = condition_case_1 (Qt,
1140 mswindows_modal_loop_error_handler, Qnil);
1141 --mswindows_in_modal_loop;
1147 mswindows_unmodalize_signal_maybe (void)
1149 if (!NILP (mswindows_error_caught_in_modal_loop))
1151 /* Got an error while messages were pumped while
1152 in window procedure - have to resignal */
1153 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1154 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1155 mswindows_error_caught_in_modal_loop = Qnil;
1156 Fsignal (sym, data);
1161 * This is an unsafe part of event pump, guarded by
1162 * condition_case. See mswindows_pump_outstanding_events
1165 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1167 /* This function can call lisp */
1168 Lisp_Object event = Fmake_event (Qnil, Qnil);
1169 struct gcpro gcpro1;
1170 int do_redisplay = 0;
1173 while (detect_input_pending ())
1175 Fnext_event (event, Qnil);
1176 Fdispatch_event (event);
1183 Fdeallocate_event (event);
1186 /* Qt becomes return value of mswindows_pump_outstanding_events
1192 * This function pumps emacs events, while available, by using
1193 * next_message/dispatch_message loop. Errors are trapped around
1194 * the loop so the function always returns.
1196 * Windows message queue is not looked into during the call,
1197 * neither are waitable handles checked. The function pumps
1198 * thus only dispatch events already queued, as well as those
1199 * resulted in dispatching thereof. This is done by setting
1200 * module local variable mswindows_in_modal_loop to nonzero.
1202 * Return value is Qt if no errors was trapped, or Qunbound if
1203 * there was an error.
1205 * In case of error, a cons representing the error, in the
1206 * form (SIGNAL . DATA), is stored in the module local variable
1207 * mswindows_error_caught_in_modal_loop. This error is signaled
1208 * again when DispatchMessage returns. Thus, Windows internal
1209 * modal loops are protected against throws, which are proven
1210 * to corrupt internal Windows structures.
1212 * In case of success, mswindows_error_caught_in_modal_loop is
1215 * If the value of mswindows_error_caught_in_modal_loop is not
1216 * nil already upon entry, the function just returns non-nil.
1217 * This situation means that a new event has been queued while
1218 * in cancel mode. The event will be dequeued on the next regular
1219 * call of next-event; the pump is off since error is caught.
1220 * The caller must *unconditionally* cancel modal loop if the
1221 * value returned by this function is nil. Otherwise, everything
1222 * will become frozen until the modal loop exits under normal
1223 * condition (scrollbar drag is released, menu closed etc.)
1226 mswindows_pump_outstanding_events (void)
1228 /* This function can call lisp */
1230 Lisp_Object result = Qt;
1231 struct gcpro gcpro1;
1234 if (NILP(mswindows_error_caught_in_modal_loop))
1235 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1241 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1242 * QUITP, and are interesting in keyboard messages only.
1245 mswindows_drain_windows_queue (void)
1249 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1250 assert (!mswindows_in_modal_loop);
1252 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1254 /* We have to translate messages that are not sent to the main
1255 window. This is so that key presses work ok in things like
1256 edit fields. However, we *musn't* translate message for the
1257 main window as this is handled in the wnd proc.
1258 We also have to avoid generating paint magic events for windows
1259 that aren't XEmacs frames */
1260 if (GetWindowLong (msg.hwnd, GWL_STYLE) & (WS_CHILD|WS_POPUP))
1262 TranslateMessage (&msg);
1264 else if (msg.message == WM_PAINT)
1266 struct mswindows_frame* msframe;
1268 /* hdc will be NULL unless this is a subwindow - in which case we
1269 shouldn't have received a paint message for it here. */
1270 assert (msg.wParam == 0);
1272 /* Queue a magic event for handling when safe */
1273 msframe = FRAME_MSWINDOWS_DATA (
1274 XFRAME (mswindows_find_frame (msg.hwnd)));
1275 if (!msframe->paint_pending)
1277 msframe->paint_pending = 1;
1278 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1280 /* Don't dispatch. WM_PAINT is always the last message in the
1281 queue so it's OK to just return. */
1284 DispatchMessage (&msg);
1285 mswindows_unmodalize_signal_maybe ();
1290 * This is a special flavor of the mswindows_need_event function,
1291 * used while in event pump. Actually, there is only kind of events
1292 * allowed while in event pump: a timer. An attempt to fetch any
1293 * other event leads to a deadlock, as there's no source of user input
1294 * ('cause event pump mirrors windows modal loop, which is a sole
1295 * owner of thread message queue).
1297 * To detect this, we use a counter of active timers, and allow
1298 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1299 * which will never come when there are no pending timers, which leads
1300 * to deadlock, we simply signal an error.
1303 mswindows_need_event_in_modal_loop (int badly_p)
1307 /* Check if already have one */
1308 if (!NILP (mswindows_u_dispatch_event_queue)
1309 || !NILP (mswindows_s_dispatch_event_queue))
1312 /* No event is ok */
1316 /* We do not check the _u_ queue, because timers go to _s_ */
1317 while (NILP (mswindows_s_dispatch_event_queue))
1319 /* We'll deadlock if go waiting */
1320 if (mswindows_pending_timers_count == 0)
1321 error ("Deadlock due to an attempt to call next-event in a wrong context");
1323 /* Fetch and dispatch any pending timers */
1324 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1325 DispatchMessage (&msg);
1330 * This drains the event queue and fills up two internal queues until
1331 * an event of a type specified by USER_P is retrieved.
1334 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1337 mswindows_need_event (int badly_p)
1341 if (mswindows_in_modal_loop)
1343 mswindows_need_event_in_modal_loop (badly_p);
1347 while (NILP (mswindows_u_dispatch_event_queue)
1348 && NILP (mswindows_s_dispatch_event_queue))
1350 #ifdef HAVE_MSG_SELECT
1352 SELECT_TYPE temp_mask = input_wait_mask;
1353 EMACS_TIME sometime;
1354 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1357 pointer_to_this = 0;
1360 EMACS_SET_SECS_USECS (sometime, 0, 0);
1361 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1362 pointer_to_this = &select_time_to_block;
1365 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1370 return; /* timeout */
1372 else if (active > 0)
1374 if (FD_ISSET (windows_fd, &temp_mask))
1376 mswindows_drain_windows_queue ();
1381 /* Look for a TTY event */
1382 for (i = 0; i < MAXDESC-1; i++)
1384 /* To avoid race conditions (among other things, an infinite
1385 loop when called from Fdiscard_input()), we must return
1386 user events ahead of process events. */
1387 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1389 struct console *c = tty_find_console_from_fd (i);
1390 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1391 Lisp_Event* event = XEVENT (emacs_event);
1394 if (read_event_from_tty_or_stream_desc (event, c, i))
1396 mswindows_enqueue_dispatch_event (emacs_event);
1402 /* Look for a process event */
1403 for (i = 0; i < MAXDESC-1; i++)
1405 if (FD_ISSET (i, &temp_mask))
1407 if (FD_ISSET (i, &process_only_mask))
1410 get_process_from_usid (FD_TO_USID(i));
1412 mswindows_enqueue_process_event (p);
1416 /* We might get here when a fake event came
1417 through a signal. Return a dummy event, so
1418 that a cycle of the command loop will
1420 drain_signal_event_pipe ();
1421 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1427 else if (active==-1)
1431 /* something bad happened */
1440 /* Now try getting a message or process event */
1441 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1442 mswindows_waitable_handles,
1443 FALSE, badly_p ? INFINITE : 0,
1446 /* This will assert if handle being waited for becomes abandoned.
1447 Not the case currently tho */
1448 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1449 (active >= WAIT_OBJECT_0 &&
1450 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1452 if (active == WAIT_TIMEOUT)
1454 /* No luck trying - just return what we've already got */
1457 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1459 /* Got your message, thanks */
1460 mswindows_drain_windows_queue ();
1464 int ix = active - WAIT_OBJECT_0;
1465 /* First, try to find which process' output has signaled */
1467 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1470 /* Found a signaled process input handle */
1471 mswindows_enqueue_process_event (p);
1475 /* None. This means that the process handle itself has signaled.
1476 Remove the handle from the wait vector, and make status_notify
1477 note the exited process */
1478 mswindows_waitable_handles [ix] =
1479 mswindows_waitable_handles [--mswindows_waitable_count];
1480 kick_status_notify ();
1481 /* We need to return a process event here so that
1482 (1) accept-process-output will return when called on this
1483 process, and (2) status notifications will happen in
1484 accept-process-output, sleep-for, and sit-for. */
1485 /* #### horrible kludge till my real process fixes go in.
1487 if (!NILP (Vprocess_list))
1489 Lisp_Object vaffanculo = XCAR (Vprocess_list);
1490 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1492 else /* trash me soon. */
1493 /* Have to return something: there may be no accompanying
1495 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1502 /************************************************************************/
1503 /* Event generators */
1504 /************************************************************************/
1507 * Callback procedure for synchronous timer messages
1509 static void CALLBACK
1510 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1512 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1513 Lisp_Event *event = XEVENT (emacs_event);
1515 if (KillTimer (NULL, id_timer))
1516 --mswindows_pending_timers_count;
1518 event->channel = Qnil;
1519 event->timestamp = dwtime;
1520 event->event_type = timeout_event;
1521 event->event.timeout.interval_id = id_timer;
1522 event->event.timeout.function = Qnil;
1523 event->event.timeout.object = Qnil;
1525 mswindows_enqueue_dispatch_event (emacs_event);
1529 * Callback procedure for dde messages
1531 * We execute a dde Open("file") by simulating a file drop, so dde support
1532 * depends on dnd support.
1534 #ifdef HAVE_DRAGNDROP
1536 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1537 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1538 DWORD dwData1, DWORD dwData2)
1543 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1544 return (HDDEDATA)TRUE;
1545 return (HDDEDATA)FALSE;
1547 case XTYP_WILDCONNECT:
1549 /* We only support one {service,topic} pair */
1550 HSZPAIR pairs[2] = {
1551 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1553 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1554 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1555 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1556 sizeof (pairs), 0L, 0, uFmt, 0));
1558 return (HDDEDATA)NULL;
1561 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1563 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1564 LPBYTE cmd = (LPBYTE) alloca (len+1);
1567 struct gcpro gcpro1, gcpro2;
1568 Lisp_Object l_dndlist = Qnil;
1569 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1570 Lisp_Object frmcons, devcons, concons;
1571 Lisp_Event *event = XEVENT (emacs_event);
1573 DdeGetData (hdata, cmd, len, 0);
1575 DdeFreeDataHandle (hdata);
1577 /* Check syntax & that it's an [Open("foo")] command, which we
1578 * treat like a file drop */
1579 /* #### Ought to be generalised and accept some other commands */
1582 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1583 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1584 return DDE_FNOTPROCESSED;
1585 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1588 if (*cmd!='(' || *(cmd+1)!='\"')
1589 return DDE_FNOTPROCESSED;
1591 while (*end && *end!='\"')
1594 return DDE_FNOTPROCESSED;
1597 return DDE_FNOTPROCESSED;
1601 return DDE_FNOTPROCESSED;
1604 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1605 strcpy (filename, "file:");
1606 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1608 dostounix_filename (cmd);
1609 filename = alloca (strlen (cmd)+6);
1610 strcpy (filename, "file:");
1611 strcat (filename, cmd);
1613 GCPRO2 (emacs_event, l_dndlist);
1614 l_dndlist = make_string (filename, strlen (filename));
1616 /* Find a mswindows frame */
1617 event->channel = Qnil;
1618 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1620 Lisp_Object frame = XCAR (frmcons);
1621 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1622 event->channel = frame;
1624 assert (!NILP (event->channel));
1626 event->timestamp = GetTickCount();
1627 event->event_type = misc_user_event;
1628 event->event.misc.button = 1;
1629 event->event.misc.modifiers = 0;
1630 event->event.misc.x = -1;
1631 event->event.misc.y = -1;
1632 event->event.misc.function = Qdragdrop_drop_dispatch;
1633 event->event.misc.object = Fcons (Qdragdrop_URL,
1634 Fcons (l_dndlist, Qnil));
1635 mswindows_enqueue_dispatch_event (emacs_event);
1637 return (HDDEDATA) DDE_FACK;
1639 DdeFreeDataHandle (hdata);
1640 return (HDDEDATA) DDE_FNOTPROCESSED;
1643 return (HDDEDATA) NULL;
1649 * Helper to do repainting - repaints can happen both from the windows
1650 * procedure and from magic events
1653 mswindows_handle_paint (struct frame *frame)
1655 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1657 /* According to the docs we need to check GetUpdateRect() before
1658 actually doing a WM_PAINT */
1659 if (GetUpdateRect (hwnd, NULL, FALSE))
1661 PAINTSTRUCT paintStruct;
1662 int x, y, width, height;
1664 BeginPaint (hwnd, &paintStruct);
1665 x = paintStruct.rcPaint.left;
1666 y = paintStruct.rcPaint.top;
1667 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1668 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1669 /* Normally we want to ignore expose events when child
1670 windows are unmapped, however once we are in the guts of
1671 WM_PAINT we need to make sure that we don't register
1672 unmaps then because they will not actually occur. */
1673 /* #### commenting out the next line seems to fix some problems
1674 but not all. only andy currently understands this stuff and
1675 he needs to review it more carefully. --ben */
1676 if (!check_for_ignored_expose (frame, x, y, width, height))
1678 hold_ignored_expose_registration = 1;
1679 mswindows_redraw_exposed_area (frame, x, y, width, height);
1680 hold_ignored_expose_registration = 0;
1682 EndPaint (hwnd, &paintStruct);
1687 * Returns 1 if a key is a real modifier or special key, which
1688 * is better handled by DefWindowProc
1691 key_needs_default_processing_p (UINT vkey)
1693 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1694 /* if we let ALT activate the menu like this, then sticky ALT-modified
1695 keystrokes become impossible. */
1696 && !modifier_keys_are_sticky)
1702 /* key-handling code is always ugly. It just ends up working out
1705 #### Most of the sticky-modifier code below is copied from similar
1706 code in event-Xt.c. They should somehow or other be merged.
1708 Here are some pointers:
1710 -- DOWN_MASK indicates which modifiers should be treated as "down"
1711 when the corresponding upstroke happens. It gets reset for
1712 a particular modifier when that modifier goes up, and reset
1713 for all modifiers when a non-modifier key is pressed. Example:
1715 I press Control-A-Shift and then release Control-A-Shift.
1716 I want the Shift key to be sticky but not the Control key.
1718 -- If a modifier key is sticky, I can unstick it by pressing
1719 the modifier key again. */
1721 static WPARAM last_downkey;
1722 static int need_to_add_mask, down_mask;
1724 #define XEMSW_LCONTROL (1<<0)
1725 #define XEMSW_RCONTROL (1<<1)
1726 #define XEMSW_LSHIFT (1<<2)
1727 #define XEMSW_RSHIFT (1<<3)
1728 #define XEMSW_LMENU (1<<4)
1729 #define XEMSW_RMENU (1<<5)
1732 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1733 int downp, int keyp)
1737 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1741 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1742 wParam == VK_RCONTROL ||
1743 wParam == VK_MENU || wParam == VK_LMENU ||
1744 wParam == VK_RMENU ||
1745 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1746 wParam == VK_RSHIFT)))
1747 { /* Not a modifier key */
1748 if (downp && keyp && !last_downkey)
1749 last_downkey = wParam;
1750 /* If I hold press-and-release the Control key and then press
1751 and hold down the right arrow, I want it to auto-repeat
1752 Control-Right. On the other hand, if I do the same but
1753 manually press the Right arrow a bunch of times, I want
1754 to see one Control-Right and then a bunch of Rights.
1755 This means that we need to distinguish between an
1756 auto-repeated key and a key pressed and released a bunch
1758 else if (downp && !keyp ||
1759 (downp && keyp && last_downkey &&
1760 (wParam != last_downkey ||
1761 /* the "previous key state" bit indicates autorepeat */
1762 ! (lParam & (1 << 30)))))
1764 need_to_add_mask = 0;
1770 mods = need_to_add_mask;
1772 else /* Modifier key pressed */
1774 /* If a non-modifier key was pressed in the middle of a bunch
1775 of modifiers, then it unsticks all the modifiers that were
1776 previously pressed. We cannot unstick the modifiers until
1777 now because we want to check for auto-repeat of the
1778 non-modifier key. */
1783 need_to_add_mask = 0;
1786 #define FROB(mask) \
1788 if (downp && keyp) \
1790 /* If modifier key is already sticky, \
1791 then unstick it. Note that we do \
1792 not test down_mask to deal with the \
1793 unlikely but possible case that the \
1794 modifier key auto-repeats. */ \
1795 if (need_to_add_mask & mask) \
1797 need_to_add_mask &= ~mask; \
1798 down_mask &= ~mask; \
1801 down_mask |= mask; \
1805 if (down_mask & mask) \
1807 down_mask &= ~mask; \
1808 need_to_add_mask |= mask; \
1813 if (wParam == VK_CONTROL && (lParam & 0x1000000)
1814 || wParam == VK_RCONTROL)
1815 FROB (XEMSW_RCONTROL);
1816 if (wParam == VK_CONTROL && !(lParam & 0x1000000)
1817 || wParam == VK_LCONTROL)
1818 FROB (XEMSW_LCONTROL);
1820 if (wParam == VK_SHIFT && (lParam & 0x1000000)
1821 || wParam == VK_RSHIFT)
1822 FROB (XEMSW_RSHIFT);
1823 if (wParam == VK_SHIFT && !(lParam & 0x1000000)
1824 || wParam == VK_LSHIFT)
1825 FROB (XEMSW_LSHIFT);
1827 if (wParam == VK_MENU && (lParam & 0x1000000)
1828 || wParam == VK_RMENU)
1830 if (wParam == VK_MENU && !(lParam & 0x1000000)
1831 || wParam == VK_LMENU)
1840 GetKeyboardState (keymap);
1842 if (mods & XEMSW_LCONTROL)
1844 keymap [VK_CONTROL] |= 0x80;
1845 keymap [VK_LCONTROL] |= 0x80;
1847 if (mods & XEMSW_RCONTROL)
1849 keymap [VK_CONTROL] |= 0x80;
1850 keymap [VK_RCONTROL] |= 0x80;
1853 if (mods & XEMSW_LSHIFT)
1855 keymap [VK_SHIFT] |= 0x80;
1856 keymap [VK_LSHIFT] |= 0x80;
1858 if (mods & XEMSW_RSHIFT)
1860 keymap [VK_SHIFT] |= 0x80;
1861 keymap [VK_RSHIFT] |= 0x80;
1864 if (mods & XEMSW_LMENU)
1866 keymap [VK_MENU] |= 0x80;
1867 keymap [VK_LMENU] |= 0x80;
1869 if (mods & XEMSW_RMENU)
1871 keymap [VK_MENU] |= 0x80;
1872 keymap [VK_RMENU] |= 0x80;
1875 SetKeyboardState (keymap);
1883 clear_sticky_modifiers (void)
1885 need_to_add_mask = 0;
1893 output_modifier_keyboard_state (void)
1897 GetKeyboardState (keymap);
1899 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1900 keymap[VK_MENU] & 0x80 ? 1 : 0,
1901 keymap[VK_MENU] & 0x1 ? 1 : 0,
1902 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1903 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1904 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1905 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1906 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1907 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1908 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1909 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1910 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1911 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1912 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1913 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1914 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1915 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1916 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1917 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1918 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1919 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
1922 /* try to debug the stuck-alt-key problem.
1924 #### this happens only inconsistently, and may only happen when using
1925 StickyKeys in the Win2000 accessibility section of the control panel,
1926 which is extremely broken for other reasons. */
1929 output_alt_keyboard_state (void)
1933 // SHORT asyncstate[3];
1935 GetKeyboardState (keymap);
1936 keystate[0] = GetKeyState (VK_MENU);
1937 keystate[1] = GetKeyState (VK_LMENU);
1938 keystate[2] = GetKeyState (VK_RMENU);
1939 /* Doing this interferes with key processing. */
1940 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
1941 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
1942 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
1944 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1945 keymap[VK_MENU] & 0x80 ? 1 : 0,
1946 keymap[VK_MENU] & 0x1 ? 1 : 0,
1947 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1948 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1949 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1950 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1951 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1952 keystate[0] & 0x8000 ? 1 : 0,
1953 keystate[0] & 0x1 ? 1 : 0,
1954 keystate[1] & 0x8000 ? 1 : 0,
1955 keystate[1] & 0x1 ? 1 : 0,
1956 keystate[2] & 0x8000 ? 1 : 0,
1957 keystate[2] & 0x1 ? 1 : 0);
1958 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
1959 /* asyncstate[0] & 0x8000 ? 1 : 0, */
1960 /* asyncstate[0] & 0x1 ? 1 : 0, */
1961 /* asyncstate[1] & 0x8000 ? 1 : 0, */
1962 /* asyncstate[1] & 0x1 ? 1 : 0, */
1963 /* asyncstate[2] & 0x8000 ? 1 : 0, */
1964 /* asyncstate[2] & 0x1 ? 1 : 0); */
1967 #endif /* DEBUG_XEMACS */
1971 * The windows procedure for the window class XEMACS_CLASS
1974 mswindows_wnd_proc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1976 /* Note: Remember to initialize emacs_event and event before use.
1977 This code calls code that can GC. You must GCPRO before calling such code. */
1978 Lisp_Object emacs_event = Qnil;
1979 Lisp_Object fobj = Qnil;
1982 struct frame *frame;
1983 struct mswindows_frame* msframe;
1985 assert (!GetWindowLong (hwnd, GWL_USERDATA));
1988 case WM_DESTROYCLIPBOARD:
1989 /* We own the clipboard and someone else wants it. Delete our
1990 cached copy of the clipboard contents so we'll ask for it from
1991 Windows again when someone does a paste. */
1992 handle_selection_clear(QCLIPBOARD);
1996 /* Erase background only during non-dynamic sizing */
1997 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1998 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2003 fobj = mswindows_find_frame (hwnd);
2004 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2010 /* See Win95 comment under WM_KEYDOWN */
2013 int should_set_keymap = 0;
2016 if (mswindows_debug_events)
2018 stderr_out ("%s wparam=%d lparam=%d\n",
2019 message == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
2020 wParam, (int)lParam);
2021 output_alt_keyboard_state ();
2023 #endif /* DEBUG_XEMACS */
2025 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2026 if (wParam == VK_CONTROL)
2028 GetKeyboardState (keymap);
2029 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2030 should_set_keymap = 1;
2032 else if (wParam == VK_MENU)
2034 GetKeyboardState (keymap);
2035 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2036 should_set_keymap = 1;
2039 if (should_set_keymap)
2040 // && (message != WM_SYSKEYUP
2041 // || NILP (Vmenu_accelerator_enabled)))
2042 SetKeyboardState (keymap);
2046 if (key_needs_default_processing_p (wParam))
2054 /* In some locales the right-hand Alt key is labelled AltGr. This key
2055 * should produce alternative charcaters when combined with another key.
2056 * eg on a German keyboard pressing AltGr+q should produce '@'.
2057 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2058 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2059 * it translates as if AltGr were down.
2060 * We get round this by removing all modifiers from the keymap before
2061 * calling TranslateMessage() unless AltGr is *really* down. */
2063 BYTE keymap_trans[256];
2064 BYTE keymap_orig[256];
2065 BYTE keymap_sticky[256];
2066 int has_AltGr = mswindows_current_layout_has_AltGr ();
2068 int extendedp = lParam & 0x1000000;
2073 if (mswindows_debug_events)
2075 stderr_out ("%s wparam=%d lparam=%d\n",
2076 message == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
2077 wParam, (int)lParam);
2078 output_alt_keyboard_state ();
2080 #endif /* DEBUG_XEMACS */
2082 GetKeyboardState (keymap_orig);
2083 frame = XFRAME (mswindows_find_frame (hwnd));
2084 if ((sticky_changed =
2085 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2087 GetKeyboardState (keymap_sticky);
2088 if (keymap_sticky[VK_MENU] & 0x80)
2090 message = WM_SYSKEYDOWN;
2091 /* We have to set the "context bit" so that the
2092 TranslateMessage() call below that generates the
2093 SYSCHAR message does its thing; see the documentation
2099 memcpy (keymap_sticky, keymap_orig, 256);
2101 mods = mswindows_modifier_state (keymap_sticky, has_AltGr);
2103 /* Handle non-printables */
2104 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2107 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2109 SetKeyboardState (keymap_orig);
2111 else /* Normal keys & modifiers */
2114 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2115 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2117 int potential_accelerator = 0;
2118 int got_accelerator = 0;
2121 msg.message = message;
2122 msg.wParam = wParam;
2123 msg.lParam = lParam;
2124 msg.time = GetMessageTime();
2127 /* GetKeyboardState() does not work as documented on Win95. We have
2128 * to loosely track Left and Right modifiers on behalf of the OS,
2129 * without screwing up Windows NT which tracks them properly. */
2130 if (wParam == VK_CONTROL)
2132 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2133 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2135 else if (wParam == VK_MENU)
2137 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2138 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2141 if (!NILP (Vmenu_accelerator_enabled) &&
2142 !(mods & XEMACS_MOD_SHIFT) && message == WM_SYSKEYDOWN)
2143 potential_accelerator = 1;
2145 /* Remove shift modifier from an ascii character */
2146 mods &= ~XEMACS_MOD_SHIFT;
2148 memcpy (keymap_trans, keymap_sticky, 256);
2150 /* Clear control and alt modifiers unless AltGr is pressed */
2151 keymap_trans[VK_RCONTROL] = 0;
2152 keymap_trans[VK_LMENU] = 0;
2153 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2154 || !(keymap_trans[VK_RMENU] & 0x80))
2156 keymap_trans[VK_LCONTROL] = 0;
2157 keymap_trans[VK_CONTROL] = 0;
2158 keymap_trans[VK_RMENU] = 0;
2159 keymap_trans[VK_MENU] = 0;
2161 SetKeyboardState (keymap_trans);
2163 /* Maybe generate some WM_[SYS]CHARs in the queue */
2164 TranslateMessage (&msg);
2166 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2167 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2171 WPARAM ch = tranmsg.wParam;
2173 /* If a quit char with no modifiers other than control and
2174 shift, then mark it with a fake modifier, which is removed
2175 upon dequeueing the event */
2176 /* #### This might also not withstand localization, if
2177 quit character is not a latin-1 symbol */
2178 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2179 && quit_ch + 'a' - 1 == ch)
2180 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2182 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2185 mods1 |= FAKE_MOD_QUIT;
2186 ++mswindows_quit_chars_count;
2188 else if (potential_accelerator && !got_accelerator &&
2189 msw_char_is_accelerator (frame, ch))
2191 got_accelerator = 1;
2194 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
2197 /* This generates WM_SYSCHAR messages, which are interpreted
2198 by DefWindowProc as the menu selections. */
2199 if (got_accelerator)
2201 SetKeyboardState (keymap_sticky);
2202 TranslateMessage (&msg);
2203 SetKeyboardState (keymap_orig);
2207 SetKeyboardState (keymap_orig);
2211 if (key_needs_default_processing_p (wParam))
2216 case WM_MBUTTONDOWN:
2218 /* Real middle mouse button has nothing to do with emulated one:
2219 if one wants to exercise fingers playing chords on the mouse,
2220 he is allowed to do that! */
2221 mswindows_enqueue_mouse_button_event (hwnd, message,
2222 MAKEPOINTS (lParam), GetMessageTime());
2226 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2227 msframe->last_click_time = GetMessageTime();
2229 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2230 msframe->button2_need_lbutton = 0;
2231 if (msframe->ignore_next_lbutton_up)
2233 msframe->ignore_next_lbutton_up = 0;
2235 else if (msframe->button2_is_down)
2237 msframe->button2_is_down = 0;
2238 msframe->ignore_next_rbutton_up = 1;
2239 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2240 MAKEPOINTS (lParam), GetMessageTime());
2244 if (msframe->button2_need_rbutton)
2246 msframe->button2_need_rbutton = 0;
2247 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2248 MAKEPOINTS (lParam), GetMessageTime());
2250 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2251 MAKEPOINTS (lParam), GetMessageTime());
2256 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2257 msframe->last_click_time = GetMessageTime();
2259 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2260 msframe->button2_need_rbutton = 0;
2261 if (msframe->ignore_next_rbutton_up)
2263 msframe->ignore_next_rbutton_up = 0;
2265 else if (msframe->button2_is_down)
2267 msframe->button2_is_down = 0;
2268 msframe->ignore_next_lbutton_up = 1;
2269 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2270 MAKEPOINTS (lParam), GetMessageTime());
2274 if (msframe->button2_need_lbutton)
2276 msframe->button2_need_lbutton = 0;
2277 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2278 MAKEPOINTS (lParam), GetMessageTime());
2280 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2281 MAKEPOINTS (lParam), GetMessageTime());
2285 case WM_LBUTTONDOWN:
2286 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2288 if (msframe->button2_need_lbutton)
2290 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2291 msframe->button2_need_lbutton = 0;
2292 msframe->button2_need_rbutton = 0;
2293 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
2295 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2296 MAKEPOINTS (lParam), GetMessageTime());
2297 msframe->button2_is_down = 1;
2301 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2302 msframe->last_click_point, msframe->last_click_time);
2303 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2304 MAKEPOINTS (lParam), GetMessageTime());
2309 mswindows_set_chord_timer (hwnd);
2310 msframe->button2_need_rbutton = 1;
2311 msframe->last_click_point = MAKEPOINTS (lParam);
2313 msframe->last_click_time = GetMessageTime();
2316 case WM_RBUTTONDOWN:
2317 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2319 if (msframe->button2_need_rbutton)
2321 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2322 msframe->button2_need_lbutton = 0;
2323 msframe->button2_need_rbutton = 0;
2324 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
2326 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2327 MAKEPOINTS (lParam), GetMessageTime());
2328 msframe->button2_is_down = 1;
2332 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2333 msframe->last_click_point, msframe->last_click_time);
2334 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2335 MAKEPOINTS (lParam), GetMessageTime());
2340 mswindows_set_chord_timer (hwnd);
2341 msframe->button2_need_lbutton = 1;
2342 msframe->last_click_point = MAKEPOINTS (lParam);
2344 msframe->last_click_time = GetMessageTime();
2348 if (wParam == BUTTON_2_TIMER_ID)
2350 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2351 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2353 if (msframe->button2_need_lbutton)
2355 msframe->button2_need_lbutton = 0;
2356 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2357 msframe->last_click_point, msframe->last_click_time);
2359 else if (msframe->button2_need_rbutton)
2361 msframe->button2_need_rbutton = 0;
2362 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2363 msframe->last_click_point, msframe->last_click_time);
2367 assert ("Spurious timer fired" == 0);
2371 /* Optimization: don't report mouse movement while size is changing */
2372 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2373 if (!msframe->sizing)
2375 /* When waiting for the second mouse button to finish
2376 button2 emulation, and have moved too far, just pretend
2377 as if timer has expired. This improves drag-select feedback */
2378 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2379 && !mswindows_button2_near_enough (msframe->last_click_point,
2380 MAKEPOINTS (lParam)))
2382 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2383 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2386 emacs_event = Fmake_event (Qnil, Qnil);
2387 event = XEVENT(emacs_event);
2389 event->channel = mswindows_find_frame(hwnd);
2390 event->timestamp = GetMessageTime();
2391 event->event_type = pointer_motion_event;
2392 event->event.motion.x = MAKEPOINTS(lParam).x;
2393 event->event.motion.y = MAKEPOINTS(lParam).y;
2394 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
2396 mswindows_enqueue_dispatch_event (emacs_event);
2402 /* Queue a `cancel-mode-internal' misc user event, so mouse
2403 selection would be canceled if any */
2404 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2405 Qcancel_mode_internal, Qnil);
2410 LPNMHDR nmhdr = (LPNMHDR)lParam;
2412 if (nmhdr->code == TTN_NEEDTEXT)
2414 #ifdef HAVE_TOOLBARS
2415 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2418 /* find out which toolbar */
2419 frame = XFRAME (mswindows_find_frame (hwnd));
2420 btext = mswindows_get_toolbar_button_text ( frame,
2423 tttext->lpszText = NULL;
2424 tttext->hinst = NULL;
2428 /* I think this is safe since the text will only go away
2429 when the toolbar does...*/
2430 TO_EXTERNAL_FORMAT (LISP_STRING, btext,
2431 C_STRING_ALLOCA, tttext->lpszText,
2436 /* handle tree view callbacks */
2437 else if (nmhdr->code == TVN_SELCHANGED)
2439 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2440 frame = XFRAME (mswindows_find_frame (hwnd));
2441 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2443 /* handle tab control callbacks */
2444 else if (nmhdr->code == TCN_SELCHANGE)
2447 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2448 frame = XFRAME (mswindows_find_frame (hwnd));
2450 item.mask = TCIF_PARAM;
2451 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2454 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2460 /* hdc will be NULL unless this is a subwindow - in which case we
2461 shouldn't have received a paint message for it here. */
2462 assert (wParam == 0);
2464 /* Can't queue a magic event because windows goes modal and sends paint
2465 messages directly to the windows procedure when doing solid drags
2466 and the message queue doesn't get processed. */
2467 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2471 /* We only care about this message if our size has really changed */
2472 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2477 fobj = mswindows_find_frame (hwnd);
2478 frame = XFRAME (fobj);
2479 msframe = FRAME_MSWINDOWS_DATA (frame);
2481 /* We cannot handle frame map and unmap hooks right in
2482 this routine, because these may throw. We queue
2483 magic events to run these hooks instead - kkm */
2485 if (wParam==SIZE_MINIMIZED)
2488 FRAME_VISIBLE_P (frame) = 0;
2489 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2493 GetClientRect(hwnd, &rect);
2494 FRAME_PIXWIDTH(frame) = rect.right;
2495 FRAME_PIXHEIGHT(frame) = rect.bottom;
2497 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2498 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2499 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2501 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2502 change_frame_size (frame, rows, columns, 1);
2504 /* If we are inside frame creation, we have to apply geometric
2506 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2508 /* Yes, we have to size again */
2509 mswindows_size_frame_internal ( frame,
2510 FRAME_MSWINDOWS_TARGET_RECT
2512 /* Reset so we do not get here again. The SetWindowPos call in
2513 * mswindows_size_frame_internal can cause recursion here. */
2514 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2516 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2517 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2522 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2523 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2524 FRAME_VISIBLE_P (frame) = 1;
2526 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2533 case WM_DISPLAYCHANGE:
2537 fobj = mswindows_find_frame (hwnd);
2538 frame = XFRAME (fobj);
2539 d = XDEVICE (FRAME_DEVICE (frame));
2541 DEVICE_MSWINDOWS_HORZRES(d) = LOWORD (lParam);
2542 DEVICE_MSWINDOWS_VERTRES(d) = HIWORD (lParam);
2543 DEVICE_MSWINDOWS_BITSPIXEL(d) = wParam;
2547 /* Misc magic events which only require that the frame be identified */
2550 mswindows_enqueue_magic_event (hwnd, message);
2553 case WM_WINDOWPOSCHANGING:
2555 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2556 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2557 GetWindowPlacement(hwnd, &wpl);
2559 /* Only interested if size is changing and we're not being iconified */
2560 if (wpl.showCmd != SW_SHOWMINIMIZED
2561 && wpl.showCmd != SW_SHOWMAXIMIZED
2562 && !(wp->flags & SWP_NOSIZE))
2564 RECT ncsize = { 0, 0, 0, 0 };
2565 int pixwidth, pixheight;
2566 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2567 GetMenu(hwnd) != NULL,
2568 GetWindowLong (hwnd, GWL_EXSTYLE));
2570 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2571 wp->cx - (ncsize.right - ncsize.left),
2572 wp->cy - (ncsize.bottom - ncsize.top),
2573 &pixwidth, &pixheight);
2575 /* Convert client sizes to window sizes */
2576 pixwidth += (ncsize.right - ncsize.left);
2577 pixheight += (ncsize.bottom - ncsize.top);
2579 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2581 /* Adjust so that the bottom or right doesn't move if it's
2582 * the top or left that's being changed */
2584 GetWindowRect (hwnd, &rect);
2586 if (rect.left != wp->x)
2587 wp->x += wp->cx - pixwidth;
2588 if (rect.top != wp->y)
2589 wp->y += wp->cy - pixheight;
2595 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2596 window position if the user tries to track window too small */
2600 case WM_ENTERSIZEMOVE:
2601 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2602 msframe->sizing = 1;
2605 case WM_EXITSIZEMOVE:
2606 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2607 msframe->sizing = 0;
2608 /* Queue noop event */
2609 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2612 #ifdef HAVE_SCROLLBARS
2616 /* Direction of scroll is determined by scrollbar instance. */
2617 int code = (int) LOWORD(wParam);
2618 int pos = (short int) HIWORD(wParam);
2619 HWND hwndScrollBar = (HWND) lParam;
2620 struct gcpro gcpro1, gcpro2;
2622 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2623 GCPRO2 (emacs_event, fobj);
2624 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2626 /* Error during event pumping - cancel scroll */
2627 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2635 int keys = LOWORD (wParam); /* Modifier key flags */
2636 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2637 struct gcpro gcpro1, gcpro2;
2639 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2641 GCPRO2 (emacs_event, fobj);
2642 mswindows_pump_outstanding_events (); /* Can GC */
2651 #ifdef HAVE_MENUBARS
2653 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2655 XFRAME (mswindows_find_frame (hwnd)))))
2656 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2659 case WM_INITMENUPOPUP:
2660 if (!HIWORD(lParam))
2662 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2664 XFRAME (mswindows_find_frame (hwnd)))))
2665 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2669 #endif /* HAVE_MENUBARS */
2673 WORD id = LOWORD (wParam);
2674 WORD nid = HIWORD (wParam);
2675 HWND cid = (HWND)lParam;
2676 frame = XFRAME (mswindows_find_frame (hwnd));
2678 #ifdef HAVE_TOOLBARS
2679 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2682 /* widgets in a buffer only eval a callback for suitable events.*/
2687 case CBN_EDITCHANGE:
2689 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2692 /* menubars always must come last since the hashtables do not
2694 #ifdef HAVE_MENUBARS
2695 if (!NILP (mswindows_handle_wm_command (frame, id)))
2699 return DefWindowProc (hwnd, message, wParam, lParam);
2700 /* Bite me - a spurious command. This used to not be able to
2701 happen but with the introduction of widgets its now
2706 case WM_CTLCOLORBTN:
2707 case WM_CTLCOLORLISTBOX:
2708 case WM_CTLCOLOREDIT:
2709 case WM_CTLCOLORSTATIC:
2710 case WM_CTLCOLORSCROLLBAR:
2712 /* if we get an opportunity to paint a widget then do so if
2713 there is an appropriate face */
2714 HWND crtlwnd = (HWND)lParam;
2715 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2718 Lisp_Object image_instance;
2719 VOID_TO_LISP (image_instance, ii);
2720 if (IMAGE_INSTANCEP (image_instance)
2722 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2724 /* set colors for the buttons */
2725 HDC hdc = (HDC)wParam;
2726 if (last_widget_brushed != ii)
2729 DeleteObject (widget_brush);
2730 widget_brush = CreateSolidBrush
2731 (COLOR_INSTANCE_MSWINDOWS_COLOR
2734 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2735 XIMAGE_INSTANCE_FRAME (image_instance)))));
2737 last_widget_brushed = ii;
2740 COLOR_INSTANCE_MSWINDOWS_COLOR
2743 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2744 XIMAGE_INSTANCE_FRAME (image_instance)))));
2745 SetBkMode (hdc, OPAQUE);
2748 COLOR_INSTANCE_MSWINDOWS_COLOR
2751 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2752 XIMAGE_INSTANCE_FRAME (image_instance)))));
2753 return (LRESULT)widget_brush;
2759 #ifdef HAVE_DRAGNDROP
2760 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2762 UINT filecount, i, len;
2767 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2768 struct gcpro gcpro1, gcpro2, gcpro3;
2770 emacs_event = Fmake_event (Qnil, Qnil);
2771 event = XEVENT(emacs_event);
2773 GCPRO3 (emacs_event, l_dndlist, l_item);
2775 if (!DragQueryPoint ((HDROP) wParam, &point))
2776 point.x = point.y = -1; /* outside client area */
2778 event->event_type = misc_user_event;
2779 event->channel = mswindows_find_frame(hwnd);
2780 event->timestamp = GetMessageTime();
2781 event->event.misc.button = 1; /* #### Should try harder */
2782 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2783 event->event.misc.x = point.x;
2784 event->event.misc.y = point.y;
2785 event->event.misc.function = Qdragdrop_drop_dispatch;
2787 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2788 for (i=0; i<filecount; i++)
2790 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2791 /* The URLs that we make here aren't correct according to section
2792 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2793 * because they may contain reserved characters. But that's OK -
2794 * they just need to be good enough to keep dragdrop.el happy. */
2795 fname = (char *)xmalloc (len+1);
2796 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2798 /* May be a shell link aka "shortcut" - replace fname if so */
2799 #if !(defined(__CYGWIN32__) || defined(__MINGW32__))
2800 /* cygwin doesn't define this COM stuff */
2801 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2805 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2806 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2810 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2814 WIN32_FIND_DATA wfd;
2815 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2817 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2819 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2820 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2825 len = strlen (fname);
2828 ppf->lpVtbl->Release (ppf);
2831 psl->lpVtbl->Release (psl);
2837 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2838 strcpy (filename, "file:");
2839 cygwin32_win32_to_posix_path_list (fname, filename+5);
2841 filename = (char *)xmalloc (len+6);
2842 strcat (strcpy (filename, "file:"), fname);
2843 dostounix_filename (filename+5);
2846 l_item = make_string (filename, strlen (filename));
2847 l_dndlist = Fcons (l_item, l_dndlist);
2850 DragFinish ((HDROP) wParam);
2852 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2853 mswindows_enqueue_dispatch_event (emacs_event);
2861 return DefWindowProc (hwnd, message, wParam, lParam);
2867 /************************************************************************/
2868 /* keyboard, mouse & other helpers for the windows procedure */
2869 /************************************************************************/
2871 mswindows_set_chord_timer (HWND hwnd)
2875 /* We get one third half system double click threshold */
2876 if (mswindows_mouse_button_tolerance <= 0)
2877 interval = GetDoubleClickTime () / 3;
2879 interval = mswindows_mouse_button_tolerance;
2881 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2885 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2888 if (mswindows_mouse_button_max_skew_x <= 0)
2889 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2891 dx = mswindows_mouse_button_max_skew_x;
2893 if (mswindows_mouse_button_max_skew_y <= 0)
2894 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2896 dy = mswindows_mouse_button_max_skew_y;
2898 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2902 mswindows_current_layout_has_AltGr (void)
2904 /* This simple caching mechanism saves 10% of CPU
2905 time when a key typed at autorepeat rate of 30 cps! */
2906 static HKL last_hkl = 0;
2907 static int last_hkl_has_AltGr;
2909 HKL current_hkl = GetKeyboardLayout (0);
2910 if (current_hkl != last_hkl)
2913 last_hkl_has_AltGr = 0;
2914 /* In this loop, we query whether a character requires
2915 AltGr to be down to generate it. If at least such one
2916 found, this means that the layout does regard AltGr */
2917 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2918 if (HIBYTE (VkKeyScan (c)) == 6)
2919 last_hkl_has_AltGr = 1;
2920 last_hkl = current_hkl;
2922 return last_hkl_has_AltGr;
2926 /* Returns the state of the modifier keys in the format expected by the
2927 * Lisp_Event key_data, button_data and motion_data modifiers member */
2929 mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2937 GetKeyboardState (keymap);
2938 has_AltGr = mswindows_current_layout_has_AltGr ();
2941 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2943 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
2944 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
2948 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
2949 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
2952 mods |= (keymap [VK_SHIFT] & 0x80) ? XEMACS_MOD_SHIFT : 0;
2958 * Translate a mswindows virtual key to a keysym.
2959 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2960 * or whose ASCII codes (like space) xemacs doesn't like.
2961 * Virtual key values are defined in winresrc.h
2963 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
2966 if (extendedp) /* Keys not present on a 82 key keyboard */
2968 switch (mswindows_key)
2970 case VK_RETURN: return KEYSYM ("kp-enter");
2971 case VK_PRIOR: return KEYSYM ("prior");
2972 case VK_NEXT: return KEYSYM ("next");
2973 case VK_END: return KEYSYM ("end");
2974 case VK_HOME: return KEYSYM ("home");
2975 case VK_LEFT: return KEYSYM ("left");
2976 case VK_UP: return KEYSYM ("up");
2977 case VK_RIGHT: return KEYSYM ("right");
2978 case VK_DOWN: return KEYSYM ("down");
2979 case VK_INSERT: return KEYSYM ("insert");
2980 case VK_DELETE: return QKdelete;
2985 switch (mswindows_key)
2987 case VK_BACK: return QKbackspace;
2988 case VK_TAB: return QKtab;
2989 case '\n': return QKlinefeed;
2990 case VK_CLEAR: return KEYSYM ("clear");
2991 case VK_RETURN: return QKreturn;
2992 case VK_ESCAPE: return QKescape;
2993 case VK_SPACE: return QKspace;
2994 case VK_PRIOR: return KEYSYM ("kp-prior");
2995 case VK_NEXT: return KEYSYM ("kp-next");
2996 case VK_END: return KEYSYM ("kp-end");
2997 case VK_HOME: return KEYSYM ("kp-home");
2998 case VK_LEFT: return KEYSYM ("kp-left");
2999 case VK_UP: return KEYSYM ("kp-up");
3000 case VK_RIGHT: return KEYSYM ("kp-right");
3001 case VK_DOWN: return KEYSYM ("kp-down");
3002 case VK_SELECT: return KEYSYM ("select");
3003 case VK_PRINT: return KEYSYM ("print");
3004 case VK_EXECUTE: return KEYSYM ("execute");
3005 case VK_SNAPSHOT: return KEYSYM ("print");
3006 case VK_INSERT: return KEYSYM ("kp-insert");
3007 case VK_DELETE: return KEYSYM ("kp-delete");
3008 case VK_HELP: return KEYSYM ("help");
3009 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3010 case VK_LWIN return KEYSYM ("");
3011 case VK_RWIN return KEYSYM ("");
3013 case VK_APPS: return KEYSYM ("menu");
3014 case VK_NUMPAD0: return KEYSYM ("kp-0");
3015 case VK_NUMPAD1: return KEYSYM ("kp-1");
3016 case VK_NUMPAD2: return KEYSYM ("kp-2");
3017 case VK_NUMPAD3: return KEYSYM ("kp-3");
3018 case VK_NUMPAD4: return KEYSYM ("kp-4");
3019 case VK_NUMPAD5: return KEYSYM ("kp-5");
3020 case VK_NUMPAD6: return KEYSYM ("kp-6");
3021 case VK_NUMPAD7: return KEYSYM ("kp-7");
3022 case VK_NUMPAD8: return KEYSYM ("kp-8");
3023 case VK_NUMPAD9: return KEYSYM ("kp-9");
3024 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3025 case VK_ADD: return KEYSYM ("kp-add");
3026 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3027 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3028 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3029 case VK_DIVIDE: return KEYSYM ("kp-divide");
3030 case VK_F1: return KEYSYM ("f1");
3031 case VK_F2: return KEYSYM ("f2");
3032 case VK_F3: return KEYSYM ("f3");
3033 case VK_F4: return KEYSYM ("f4");
3034 case VK_F5: return KEYSYM ("f5");
3035 case VK_F6: return KEYSYM ("f6");
3036 case VK_F7: return KEYSYM ("f7");
3037 case VK_F8: return KEYSYM ("f8");
3038 case VK_F9: return KEYSYM ("f9");
3039 case VK_F10: return KEYSYM ("f10");
3040 case VK_F11: return KEYSYM ("f11");
3041 case VK_F12: return KEYSYM ("f12");
3042 case VK_F13: return KEYSYM ("f13");
3043 case VK_F14: return KEYSYM ("f14");
3044 case VK_F15: return KEYSYM ("f15");
3045 case VK_F16: return KEYSYM ("f16");
3046 case VK_F17: return KEYSYM ("f17");
3047 case VK_F18: return KEYSYM ("f18");
3048 case VK_F19: return KEYSYM ("f19");
3049 case VK_F20: return KEYSYM ("f20");
3050 case VK_F21: return KEYSYM ("f21");
3051 case VK_F22: return KEYSYM ("f22");
3052 case VK_F23: return KEYSYM ("f23");
3053 case VK_F24: return KEYSYM ("f24");
3060 * Find the console that matches the supplied mswindows window handle
3063 mswindows_find_console (HWND hwnd)
3065 /* We only support one console */
3066 return XCAR (Vconsole_list);
3070 * Find the frame that matches the supplied mswindows window handle
3073 mswindows_find_frame (HWND hwnd)
3075 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3079 /* We are in progress of frame creation. Return the frame
3080 being created, as it still not remembered in the window
3082 assert (!NILP (Vmswindows_frame_being_created));
3083 return Vmswindows_frame_being_created;
3085 VOID_TO_LISP (f, l);
3090 /************************************************************************/
3092 /************************************************************************/
3095 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3098 EMACS_TIME current_time;
3099 EMACS_GET_TIME (current_time);
3100 EMACS_SUB_TIME (thyme, thyme, current_time);
3101 milliseconds = EMACS_SECS (thyme) * 1000 +
3102 (EMACS_USECS (thyme) + 500) / 1000;
3103 if (milliseconds < 1)
3105 ++mswindows_pending_timers_count;
3106 return SetTimer (NULL, 0, milliseconds,
3107 (TIMERPROC) mswindows_wm_timer_callback);
3111 emacs_mswindows_remove_timeout (int id)
3113 Lisp_Event match_against;
3114 Lisp_Object emacs_event;
3116 if (KillTimer (NULL, id))
3117 --mswindows_pending_timers_count;
3119 /* If there is a dispatch event generated by this
3120 timeout in the queue, we have to remove it too. */
3121 match_against.event_type = timeout_event;
3122 match_against.event.timeout.interval_id = id;
3123 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3124 if (!NILP (emacs_event))
3125 Fdeallocate_event(emacs_event);
3128 /* If `user_p' is false, then return whether there are any win32, timeout,
3129 * or subprocess events pending (that is, whether
3130 * emacs_mswindows_next_event() would return immediately without blocking).
3132 * if `user_p' is true, then return whether there are any *user generated*
3133 * events available (that is, whether there are keyboard or mouse-click
3134 * events ready to be read). This also implies that
3135 * emacs_mswindows_next_event() would not block.
3138 emacs_mswindows_event_pending_p (int user_p)
3140 mswindows_need_event (0);
3141 return (!NILP (mswindows_u_dispatch_event_queue)
3142 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3146 * Return the next event
3149 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3151 Lisp_Object event, event2;
3153 mswindows_need_event (1);
3155 event = mswindows_dequeue_dispatch_event ();
3156 XSETEVENT (event2, emacs_event);
3157 Fcopy_event (event, event2);
3158 Fdeallocate_event (event);
3162 * Handle a magic event off the dispatch queue.
3165 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3167 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3174 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3175 mswindows_handle_paint (f);
3176 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3183 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3184 struct frame *f = XFRAME (frame);
3185 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3187 struct gcpro gcpro1;
3189 /* On focus change, clear all memory of sticky modifiers
3190 to avoid non-intuitive behavior. */
3191 clear_sticky_modifiers ();
3193 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3195 emacs_handle_focus_change_preliminary (conser);
3196 /* Under X the stuff up to here is done in the X event handler.
3198 emacs_handle_focus_change_final (conser);
3207 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3208 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3210 Qmap_frame_hook : Qunmap_frame_hook,
3215 /* #### What about Enter & Leave */
3217 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3218 Qmouse_leave_frame_hook, 1, frame);
3226 #ifndef HAVE_MSG_SELECT
3228 get_process_input_waitable (Lisp_Process *process)
3230 Lisp_Object instr, outstr, p;
3231 XSETPROCESS (p, process);
3232 get_process_streams (process, &instr, &outstr);
3233 assert (!NILP (instr));
3234 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3235 return (network_connection_p (p)
3236 ? get_winsock_stream_waitable (XLSTREAM (instr))
3237 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3239 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3244 emacs_mswindows_select_process (Lisp_Process *process)
3246 HANDLE hev = get_process_input_waitable (process);
3248 if (!add_waitable_handle (hev))
3249 error ("Too many active processes");
3251 #ifdef HAVE_WIN32_PROCESSES
3254 XSETPROCESS (p, process);
3255 if (!network_connection_p (p))
3257 HANDLE hprocess = get_nt_process_handle (process);
3258 if (!add_waitable_handle (hprocess))
3260 remove_waitable_handle (hev);
3261 error ("Too many active processes");
3269 emacs_mswindows_unselect_process (Lisp_Process *process)
3271 /* Process handle is removed in the event loop as soon
3272 as it is signaled, so don't bother here about it */
3273 HANDLE hev = get_process_input_waitable (process);
3274 remove_waitable_handle (hev);
3276 #endif /* HAVE_MSG_SELECT */
3279 emacs_mswindows_select_console (struct console *con)
3281 #ifdef HAVE_MSG_SELECT
3282 if (CONSOLE_MSWINDOWS_P (con))
3283 return; /* mswindows consoles are automatically selected */
3285 event_stream_unixoid_select_console (con);
3290 emacs_mswindows_unselect_console (struct console *con)
3292 #ifdef HAVE_MSG_SELECT
3293 if (CONSOLE_MSWINDOWS_P (con))
3294 return; /* mswindows consoles are automatically selected */
3296 event_stream_unixoid_unselect_console (con);
3301 emacs_mswindows_quit_p (void)
3303 /* Quit cannot happen in modal loop: all program
3304 input is dedicated to Windows. */
3305 if (mswindows_in_modal_loop)
3308 /* Drain windows queue. This sets up number of quit characters in
3310 mswindows_drain_windows_queue ();
3312 if (mswindows_quit_chars_count > 0)
3314 /* Yes there's a hidden one... Throw it away */
3315 Lisp_Event match_against;
3316 Lisp_Object emacs_event;
3319 match_against.event_type = key_press_event;
3320 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3322 while (mswindows_quit_chars_count-- > 0)
3324 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3325 assert (!NILP (emacs_event));
3327 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
3330 Fdeallocate_event(emacs_event);
3333 Vquit_flag = critical_p ? Qcritical : Qt;
3338 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3339 Lisp_Object* instream,
3340 Lisp_Object* outstream,
3343 /* Handles for streams */
3345 /* fds. These just stored along with the streams, and are closed in
3346 delete stream pair method, because we need to handle fake unices
3350 /* Decode inhandle and outhandle. Their meaning depends on
3351 the process implementation being used. */
3352 #if defined (HAVE_WIN32_PROCESSES)
3353 /* We're passed in Windows handles. That's what we like most... */
3354 hin = (HANDLE) inhandle;
3355 hout = (HANDLE) outhandle;
3357 #elif defined (HAVE_UNIX_PROCESSES)
3358 /* We are passed UNIX fds. This must be Cygwin.
3360 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3361 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3365 #error "So, WHICH kind of processes do you want?"
3368 *instream = (hin == INVALID_HANDLE_VALUE
3370 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3371 : flags & STREAM_NETWORK_CONNECTION
3372 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3374 : make_ntpipe_input_stream (hin, fdi));
3376 #ifdef HAVE_WIN32_PROCESSES
3377 *outstream = (hout == INVALID_HANDLE_VALUE
3379 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3380 : flags & STREAM_NETWORK_CONNECTION
3381 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3383 : make_ntpipe_output_stream (hout, fdo));
3384 #elif defined (HAVE_UNIX_PROCESSES)
3385 *outstream = (fdo >= 0
3386 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3389 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3390 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3391 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3393 Bufbyte eof_char = get_eof_char (fdo);
3394 int pty_max_bytes = get_pty_max_bytes (fdo);
3395 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3400 return (NILP (*instream)
3402 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3403 : flags & STREAM_NETWORK_CONNECTION
3404 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3406 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3410 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3411 Lisp_Object outstream)
3413 /* Oh nothing special here for Win32 at all */
3414 #if defined (HAVE_UNIX_PROCESSES)
3415 int in = (NILP(instream)
3417 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3418 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3419 ? get_winsock_stream_param (XLSTREAM (instream))
3421 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3422 int out = (NILP(outstream) ? -1
3423 : filedesc_stream_fd (XLSTREAM (outstream)));
3427 if (out != in && out >= 0)
3431 return (NILP (instream)
3433 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3434 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3435 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3437 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3440 #ifndef HAVE_X_WINDOWS
3441 /* This is called from GC when a process object is about to be freed.
3442 If we've still got pointers to it in this file, we're gonna lose hard.
3445 debug_process_finalization (Lisp_Process *p)
3448 Lisp_Object instr, outstr;
3450 get_process_streams (p, &instr, &outstr);
3451 /* if it still has fds, then it hasn't been killed yet. */
3452 assert (NILP(instr));
3453 assert (NILP(outstr));
3455 /* #### More checks here */
3460 /************************************************************************/
3461 /* initialization */
3462 /************************************************************************/
3465 reinit_vars_of_event_mswindows (void)
3467 mswindows_in_modal_loop = 0;
3468 mswindows_pending_timers_count = 0;
3470 mswindows_event_stream = xnew (struct event_stream);
3472 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3473 mswindows_event_stream->force_event_pending = 0;
3474 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3475 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3476 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3477 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3478 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3479 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3480 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3481 #ifdef HAVE_MSG_SELECT
3482 mswindows_event_stream->select_process_cb =
3483 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3484 mswindows_event_stream->unselect_process_cb =
3485 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3486 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3487 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3489 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3490 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3491 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3492 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3497 vars_of_event_mswindows (void)
3499 reinit_vars_of_event_mswindows ();
3501 mswindows_u_dispatch_event_queue = Qnil;
3502 staticpro (&mswindows_u_dispatch_event_queue);
3503 mswindows_u_dispatch_event_queue_tail = Qnil;
3504 pdump_wire (&mswindows_u_dispatch_event_queue_tail);
3506 mswindows_s_dispatch_event_queue = Qnil;
3507 staticpro (&mswindows_s_dispatch_event_queue);
3508 mswindows_s_dispatch_event_queue_tail = Qnil;
3509 pdump_wire (&mswindows_s_dispatch_event_queue_tail);
3511 mswindows_error_caught_in_modal_loop = Qnil;
3512 staticpro (&mswindows_error_caught_in_modal_loop);
3516 DEFVAR_INT ("mswindows-debug-events", &mswindows_debug_events /*
3517 If non-zero, display debug information about Windows events that XEmacs sees.
3518 Information is displayed in a console window. Currently defined values are:
3520 1 == non-verbose output
3523 #### Unfortunately, not yet implemented.
3525 mswindows_debug_events = 0;
3528 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3529 &mswindows_alt_by_itself_activates_menu /*
3530 *Controls whether pressing and releasing the Alt key activates the menubar.
3531 This applies only if no intervening key was pressed. See also
3532 `menu-accelerator-enabled', which is probably the behavior you actually want.
3536 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3537 &mswindows_dynamic_frame_resize /*
3538 *Controls redrawing frame contents during mouse-drag or keyboard resize
3539 operation. When non-nil, the frame is redrawn while being resized. When
3540 nil, frame is not redrawn, and exposed areas are filled with default
3541 MDI application background color. Note that this option only has effect
3542 if "Show window contents while dragging" is on in system Display/Plus!
3544 Default is t on fast machines, nil on slow.
3547 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3548 &mswindows_mouse_button_tolerance /*
3549 *Analogue of double click interval for faking middle mouse events.
3550 The value is the minimum time in milliseconds that must elapse between
3551 left/right button down events before they are considered distinct events.
3552 If both mouse buttons are depressed within this interval, a middle mouse
3553 button down event is generated instead.
3554 If negative or zero, currently set system default is used instead.
3557 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3558 Number of physical mouse buttons.
3561 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3562 &mswindows_mouse_button_max_skew_x /*
3563 *Maximum horizontal distance in pixels between points in which left and
3564 right button clicks occurred for them to be translated into single
3565 middle button event. Clicks must occur in time not longer than defined
3566 by the variable `mswindows-mouse-button-tolerance'.
3567 If negative or zero, currently set system default is used instead.
3570 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3571 &mswindows_mouse_button_max_skew_y /*
3572 *Maximum vertical distance in pixels between points in which left and
3573 right button clicks occurred for them to be translated into single
3574 middle button event. Clicks must occur in time not longer than defined
3575 by the variable `mswindows-mouse-button-tolerance'.
3576 If negative or zero, currently set system default is used instead.
3579 mswindows_mouse_button_max_skew_x = 0;
3580 mswindows_mouse_button_max_skew_y = 0;
3581 mswindows_mouse_button_tolerance = 0;
3582 mswindows_alt_by_itself_activates_menu = 1;
3586 syms_of_event_mswindows (void)
3591 lstream_type_create_mswindows_selectable (void)
3593 init_slurp_stream ();
3594 init_shove_stream ();
3595 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3596 init_winsock_stream ();
3601 init_event_mswindows_late (void)
3603 #ifdef HAVE_MSG_SELECT
3604 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3605 assert (windows_fd>=0);
3606 FD_SET (windows_fd, &input_wait_mask);
3607 FD_ZERO(&zero_mask);
3610 event_stream = mswindows_event_stream;
3612 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3613 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);