1 /* The mswindows event_stream interface.
2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1996 Ben Wing.
5 Copyright (C) 1997 Jonathan Harris.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
28 Ultimately based on FSF.
29 Rewritten by Ben Wing.
30 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
31 Subprocess and modal loop support by Kirill M. Katsnelson.
37 #include "console-msw.h"
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
44 # include "menubar-msw.h"
48 # include "dragdrop.h"
58 #include "redisplay.h"
63 #include "objects-msw.h"
65 #include "events-mod.h"
66 #ifdef HAVE_MSG_SELECT
68 #elif defined(__CYGWIN32__)
69 typedef unsigned int SOCKET;
75 #define ADJR_MENUFLAG TRUE
77 #define ADJR_MENUFLAG FALSE
80 /* Fake key modifier which is attached to a quit char event.
81 Removed upon dequeueing an event */
82 #define FAKE_MOD_QUIT 0x80
84 /* Timer ID used for button2 emulation */
85 #define BUTTON_2_TIMER_ID 1
88 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
90 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
92 mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
94 static Lisp_Object mswindows_find_frame (HWND hwnd);
95 static Lisp_Object mswindows_find_console (HWND hwnd);
96 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
97 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
98 static void mswindows_set_chord_timer (HWND hwnd);
99 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
100 static int mswindows_current_layout_has_AltGr (void);
102 static struct event_stream *mswindows_event_stream;
104 #ifdef HAVE_MSG_SELECT
105 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
106 extern SELECT_TYPE process_only_mask, tty_only_mask;
107 SELECT_TYPE zero_mask;
108 extern int signal_event_pipe_initialized;
113 * Two separate queues, for efficiency, one (_u_) for user events, and
114 * another (_s_) for non-user ones. We always return events out of the
115 * first one until it is empty and only then proceed with the second
118 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
119 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
121 /* The number of things we can wait on */
122 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
124 /* List of mswindows waitable handles. */
125 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
127 #ifndef HAVE_MSG_SELECT
128 /* Number of wait handles */
129 static int mswindows_waitable_count=0;
130 #endif /* HAVE_MSG_SELECT */
131 /* Brush for painting widgets */
132 static HBRUSH widget_brush = 0;
133 static LONG last_widget_brushed = 0;
135 /* Count of quit chars currently in the queue */
136 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
137 Decremented in mswindows_dequeue_dispatch_event() */
138 int mswindows_quit_chars_count = 0;
140 /* These are Lisp integers; see DEFVARS in this file for description. */
141 int mswindows_dynamic_frame_resize;
142 int mswindows_num_mouse_buttons;
143 int mswindows_mouse_button_max_skew_x;
144 int mswindows_mouse_button_max_skew_y;
145 int mswindows_mouse_button_tolerance;
147 /* This is the event signaled by the event pump.
148 See mswindows_pump_outstanding_events for comments */
149 static Lisp_Object mswindows_error_caught_in_modal_loop;
150 static int mswindows_in_modal_loop;
152 /* Count of wound timers */
153 static int mswindows_pending_timers_count;
155 /************************************************************************/
156 /* Pipe instream - reads process output */
157 /************************************************************************/
159 #define PIPE_READ_DELAY 20
161 #define HANDLE_TO_USID(h) ((USID)(h))
163 #define NTPIPE_SLURP_STREAM_DATA(stream) \
164 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
166 /* This structure is allocated by the main thread, and is deallocated
167 in the thread upon exit. There are situations when a thread
168 remains blocked for a long time, much longer than the lstream
169 exists. For example, "start notepad" command is issued from the
170 shell, then the shell is closed by C-c C-d. Although the shell
171 process exits, its output pipe will not get closed until the
172 notepad process exits also, because it inherits the pipe form the
173 shell. In this case, we abandon the thread, and let it live until
174 all such processes exit. While struct ntpipe_slurp_stream is
175 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
177 struct ntpipe_slurp_stream_shared_data
179 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
180 /* This is a manual-reset object. */
181 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
182 /* This is a manual-reset object. */
183 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
184 /* This is a manual-reset object. */
185 HANDLE hpipe; /* Pipe read end handle. */
186 LONG die_p; /* Thread must exit ASAP if non-zero */
187 BOOL eof_p : 1; /* Set when thread saw EOF */
188 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
189 BOOL inuse_p : 1; /* this structure is in use */
190 LONG lock_count; /* Client count of this struct, 0=safe to free */
191 BYTE onebyte; /* One byte buffer read by thread */
194 #define MAX_SLURP_STREAMS 32
195 struct ntpipe_slurp_stream_shared_data
196 shared_data_block[MAX_SLURP_STREAMS]={{0}};
198 struct ntpipe_slurp_stream
200 LPARAM user_data; /* Any user data stored in the stream object */
201 struct ntpipe_slurp_stream_shared_data* thread_data;
204 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
205 sizeof (struct ntpipe_slurp_stream));
207 /* This function is thread-safe, and is called from either thread
208 context. It serializes freeing shared data structure */
210 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
212 if (InterlockedDecrement (&s->lock_count) == 0)
215 CloseHandle (s->hev_thread);
216 CloseHandle (s->hev_caller);
217 CloseHandle (s->hev_unsleep);
222 static struct ntpipe_slurp_stream_shared_data*
223 slurper_allocate_shared_data()
226 for (i=0; i<MAX_SLURP_STREAMS; i++)
228 if (!shared_data_block[i].inuse_p)
230 shared_data_block[i].inuse_p=1;
231 return &shared_data_block[i];
234 return (struct ntpipe_slurp_stream_shared_data*)0;
238 slurp_thread (LPVOID vparam)
240 struct ntpipe_slurp_stream_shared_data *s =
241 (struct ntpipe_slurp_stream_shared_data*)vparam;
245 /* Read one byte from the pipe */
247 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
249 DWORD err = GetLastError ();
250 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
255 else if (actually_read == 0)
258 /* We must terminate on an error or eof */
259 if (s->eof_p || s->error_p)
260 InterlockedIncrement (&s->die_p);
262 /* Before we notify caller, we unsignal our event. */
263 ResetEvent (s->hev_thread);
265 /* Now we got something to notify caller, either a byte or an
266 error/eof indication. Before we do, allow internal pipe
267 buffer to accumulate little bit more data.
268 Reader function pulses this event before waiting for
269 a character, to avoid pipe delay, and to get the byte
272 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
274 /* Either make event loop generate a process event, or
276 SetEvent (s->hev_caller);
278 /* Cleanup and exit if we're shot off */
282 /* Block until the client finishes with retrieving the rest of
284 WaitForSingleObject (s->hev_thread, INFINITE);
287 slurper_free_shared_data_maybe (s);
293 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
296 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
297 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
298 DWORD thread_id_unused;
301 /* We deal only with pipes, for we're using PeekNamedPipe api */
302 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
304 s->thread_data = slurper_allocate_shared_data();
306 /* Create reader thread. This could fail, so do not create events
307 until thread is created */
308 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
309 CREATE_SUSPENDED, &thread_id_unused);
312 Lstream_delete (lstr);
313 s->thread_data->inuse_p=0;
317 /* Shared data are initially owned by both main and slurper
319 s->thread_data->lock_count = 2;
320 s->thread_data->die_p = 0;
321 s->thread_data->eof_p = FALSE;
322 s->thread_data->error_p = FALSE;
323 s->thread_data->hpipe = hpipe;
324 s->user_data = param;
326 /* hev_thread is a manual-reset event, initially signaled */
327 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
328 /* hev_caller is a manual-reset event, initially nonsignaled */
329 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
330 /* hev_unsleep is a manual-reset event, initially nonsignaled */
331 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
334 ResumeThread (hthread);
335 CloseHandle (hthread);
337 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
338 XSETLSTREAM (obj, lstr);
343 get_ntpipe_input_stream_param (Lstream *stream)
345 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
350 get_ntpipe_input_stream_waitable (Lstream *stream)
352 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
353 return s->thread_data->hev_caller;
357 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
359 /* This function must be called from the main thread only */
360 struct ntpipe_slurp_stream_shared_data* s =
361 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
366 /* Disallow pipe read delay for the thread: we need a character
368 SetEvent (s->hev_unsleep);
370 /* Check if we have a character ready. Give it a short delay,
371 for the thread to awake from pipe delay, just ion case*/
372 wait_result = WaitForSingleObject (s->hev_caller, 2);
374 /* Revert to the normal sleep behavior. */
375 ResetEvent (s->hev_unsleep);
377 /* If there's no byte buffered yet, give up */
378 if (wait_result == WAIT_TIMEOUT)
385 /* Reset caller unlock event now, as we've handled the pending
386 process output event */
387 ResetEvent (s->hev_caller);
389 /* It is now safe to do anything with contents of S, except for
390 changing s->die_p, which still should be interlocked */
394 if (s->error_p || s->die_p)
397 /* Ok, there were no error neither eof - we've got a byte from the
399 *(data++) = s->onebyte;
403 DWORD bytes_read = 0;
406 DWORD bytes_available;
408 /* If the api call fails, return at least one byte already
409 read. ReadFile in thread will return error */
410 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
413 /* Fetch available bytes. The same consideration applies,
414 so do not check for errors. ReadFile in the thread will
415 fail if the next call fails. */
417 ReadFile (s->hpipe, data, min (bytes_available, size),
421 /* Now we can unblock thread, so it attempts to read more */
422 SetEvent (s->hev_thread);
423 return bytes_read + 1;
430 ntpipe_slurp_closer (Lstream *stream)
432 /* This function must be called from the main thread only */
433 struct ntpipe_slurp_stream_shared_data* s =
434 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
436 /* Force thread to stop */
437 InterlockedIncrement (&s->die_p);
439 /* Set events which could possibly block slurper. Let it finish soon
441 SetEvent (s->hev_unsleep);
442 SetEvent (s->hev_thread);
444 /* Unlock and maybe free shared data */
445 slurper_free_shared_data_maybe (s);
451 init_slurp_stream (void)
453 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
454 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
457 /************************************************************************/
458 /* Pipe outstream - writes process input */
459 /************************************************************************/
461 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
462 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
464 #define MAX_SHOVE_BUFFER_SIZE 128
466 struct ntpipe_shove_stream
468 LPARAM user_data; /* Any user data stored in the stream object */
469 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
470 /* This is an auto-reset object. */
471 HANDLE hpipe; /* Pipe write end handle. */
472 HANDLE hthread; /* Reader thread handle. */
473 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
474 DWORD size; /* Number of bytes to write */
475 LONG die_p; /* Thread must exit ASAP if non-zero */
476 LONG idle_p; /* Non-zero if thread is waiting for job */
477 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
478 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
481 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
482 sizeof (struct ntpipe_shove_stream));
484 #ifndef HAVE_MSG_SELECT
486 shove_thread (LPVOID vparam)
488 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
494 /* Block on event and wait for a job */
495 InterlockedIncrement (&s->idle_p);
496 WaitForSingleObject (s->hev_thread, INFINITE);
501 /* Write passed buffer */
502 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
503 || bytes_written != s->size)
506 InterlockedIncrement (&s->die_p);
517 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
520 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
521 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
522 DWORD thread_id_unused;
527 s->user_data = param;
529 /* Create reader thread. This could fail, so do not
530 create the event until thread is created */
531 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
532 CREATE_SUSPENDED, &thread_id_unused);
533 if (s->hthread == NULL)
535 Lstream_delete (lstr);
539 /* hev_thread is an auto-reset event, initially nonsignaled */
540 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
543 ResumeThread (s->hthread);
545 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
546 XSETLSTREAM (obj, lstr);
551 get_ntpipe_output_stream_param (Lstream *stream)
553 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
559 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
561 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
566 s->blocking_p = !s->idle_p;
570 if (size>MAX_SHOVE_BUFFER_SIZE)
573 memcpy (s->buffer, data, size);
577 InterlockedDecrement (&s->idle_p);
578 SetEvent (s->hev_thread);
583 ntpipe_shove_was_blocked_p (Lstream *stream)
585 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
586 return s->blocking_p;
590 ntpipe_shove_closer (Lstream *stream)
592 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
594 /* Force thread stop */
595 InterlockedIncrement (&s->die_p);
597 /* Close pipe handle, possibly breaking it */
598 CloseHandle (s->hpipe);
600 /* Thread will end upon unblocking */
601 SetEvent (s->hev_thread);
603 /* Wait while thread terminates */
604 WaitForSingleObject (s->hthread, INFINITE);
605 CloseHandle (s->hthread);
607 /* Destroy the event */
608 CloseHandle (s->hev_thread);
614 init_shove_stream (void)
616 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
617 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
618 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
621 /************************************************************************/
622 /* Winsock I/O stream */
623 /************************************************************************/
624 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
626 #define WINSOCK_READ_BUFFER_SIZE 1024
628 struct winsock_stream
630 LPARAM user_data; /* Any user data stored in the stream object */
631 SOCKET s; /* Socket handle (which is a Win32 handle) */
632 OVERLAPPED ov; /* Overlapped I/O structure */
633 void* buffer; /* Buffer. Allocated for input stream only */
634 unsigned int bufsize; /* Number of bytes last read */
635 unsigned int bufpos; /* Position in buffer for next fetch */
636 unsigned int error_p :1; /* I/O Error seen */
637 unsigned int eof_p :1; /* EOF Error seen */
638 unsigned int pending_p :1; /* There is a pending I/O operation */
639 unsigned int blocking_p :1; /* Last write attempt would block */
642 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
644 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
645 sizeof (struct winsock_stream));
648 winsock_initiate_read (struct winsock_stream *str)
650 ResetEvent (str->ov.hEvent);
653 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
654 &str->bufsize, &str->ov))
656 if (GetLastError () == ERROR_IO_PENDING)
658 else if (GetLastError () == ERROR_HANDLE_EOF)
663 else if (str->bufsize == 0)
668 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
670 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
672 /* If the current operation is not yet complete, there's nothing to
676 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
683 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
685 if (GetLastError() == ERROR_HANDLE_EOF)
690 if (str->bufsize == 0)
701 /* Return as much of buffer as we have */
702 size = min (size, (size_t) (str->bufsize - str->bufpos));
703 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
706 /* Read more if buffer is exhausted */
707 if (str->bufsize == str->bufpos)
708 winsock_initiate_read (str);
714 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
716 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
720 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
728 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
743 ResetEvent (str->ov.hEvent);
745 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
746 * an overlapped operation. This fails on Win95 with winsock 1.x so we
747 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
748 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
749 || GetLastError() == ERROR_IO_PENDING)
755 return str->error_p ? -1 : size;
759 winsock_closer (Lstream *lstr)
761 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
763 if (lstr->flags & LSTREAM_FL_READ)
764 shutdown (str->s, 0);
766 shutdown (str->s, 1);
768 CloseHandle ((HANDLE)str->s);
770 WaitForSingleObject (str->ov.hEvent, INFINITE);
772 if (lstr->flags & LSTREAM_FL_READ)
775 CloseHandle (str->ov.hEvent);
780 winsock_was_blocked_p (Lstream *stream)
782 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
783 return str->blocking_p;
787 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
790 Lstream *lstr = Lstream_new (lstream_winsock, mode);
791 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
798 str->user_data = param;
801 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
803 if (lstr->flags & LSTREAM_FL_READ)
805 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
806 winsock_initiate_read (str);
809 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
810 XSETLSTREAM (obj, lstr);
815 make_winsock_input_stream (SOCKET s, LPARAM param)
817 return make_winsock_stream_1 (s, param, "r");
821 make_winsock_output_stream (SOCKET s, LPARAM param)
823 return make_winsock_stream_1 (s, param, "w");
827 get_winsock_stream_waitable (Lstream *lstr)
829 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
830 return str->ov.hEvent;
834 get_winsock_stream_param (Lstream *lstr)
836 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
837 return str->user_data;
841 init_winsock_stream (void)
843 LSTREAM_HAS_METHOD (winsock, reader);
844 LSTREAM_HAS_METHOD (winsock, writer);
845 LSTREAM_HAS_METHOD (winsock, closer);
846 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
848 #endif /* defined (HAVE_SOCKETS) */
850 /************************************************************************/
851 /* Dispatch queue management */
852 /************************************************************************/
855 mswindows_user_event_p (struct Lisp_Event* sevt)
857 return (sevt->event_type == key_press_event
858 || sevt->event_type == button_press_event
859 || sevt->event_type == button_release_event
860 || sevt->event_type == misc_user_event);
864 * Add an emacs event to the proper dispatch queue
867 mswindows_enqueue_dispatch_event (Lisp_Object event)
869 int user_p = mswindows_user_event_p (XEVENT(event));
870 enqueue_event (event,
871 user_p ? &mswindows_u_dispatch_event_queue :
872 &mswindows_s_dispatch_event_queue,
873 user_p ? &mswindows_u_dispatch_event_queue_tail :
874 &mswindows_s_dispatch_event_queue_tail);
876 /* Avoid blocking on WaitMessage */
877 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
881 * Add a misc-user event to the dispatch queue.
883 * Stuff it into our own dispatch queue, so we have something
884 * to return from next_event callback.
887 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
890 Lisp_Object event = Fmake_event (Qnil, Qnil);
891 struct Lisp_Event* e = XEVENT (event);
893 e->event_type = misc_user_event;
894 e->channel = channel;
895 e->event.misc.function = function;
896 e->event.misc.object = object;
898 mswindows_enqueue_dispatch_event (event);
902 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
904 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
905 struct Lisp_Event* event = XEVENT (emacs_event);
907 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
908 event->timestamp = GetMessageTime();
909 event->event_type = magic_event;
910 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
912 mswindows_enqueue_dispatch_event (emacs_event);
916 mswindows_enqueue_process_event (struct Lisp_Process* p)
918 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
919 struct Lisp_Event* event = XEVENT (emacs_event);
921 XSETPROCESS (process, p);
923 event->event_type = process_event;
924 event->timestamp = GetTickCount ();
925 event->event.process.process = process;
927 mswindows_enqueue_dispatch_event (emacs_event);
931 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
934 /* We always use last message time, because mouse button
935 events may get delayed, and XEmacs double click
936 recognition will fail */
938 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
939 struct Lisp_Event* event = XEVENT(emacs_event);
941 event->channel = mswindows_find_frame(hwnd);
942 event->timestamp = when;
943 event->event.button.button =
944 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
945 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
946 event->event.button.x = where.x;
947 event->event.button.y = where.y;
948 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
950 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
951 message==WM_RBUTTONDOWN)
953 event->event_type = button_press_event;
955 /* we need this to make sure the main window regains the focus
956 from control subwindows */
957 if (GetFocus() != hwnd)
960 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
965 event->event_type = button_release_event;
969 mswindows_enqueue_dispatch_event (emacs_event);
973 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
975 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
976 struct Lisp_Event* event = XEVENT(emacs_event);
978 event->channel = mswindows_find_console(hwnd);
979 event->timestamp = GetMessageTime();
980 event->event_type = key_press_event;
981 event->event.key.keysym = keysym;
982 event->event.key.modifiers = mods;
983 mswindows_enqueue_dispatch_event (emacs_event);
987 * Remove and return the first emacs event on the dispatch queue.
988 * Give a preference to user events over non-user ones.
991 mswindows_dequeue_dispatch_event ()
994 struct Lisp_Event* sevt;
996 assert (!NILP(mswindows_u_dispatch_event_queue) ||
997 !NILP(mswindows_s_dispatch_event_queue));
999 event = dequeue_event (
1000 NILP(mswindows_u_dispatch_event_queue) ?
1001 &mswindows_s_dispatch_event_queue :
1002 &mswindows_u_dispatch_event_queue,
1003 NILP(mswindows_u_dispatch_event_queue) ?
1004 &mswindows_s_dispatch_event_queue_tail :
1005 &mswindows_u_dispatch_event_queue_tail);
1007 sevt = XEVENT(event);
1008 if (sevt->event_type == key_press_event
1009 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1011 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1012 --mswindows_quit_chars_count;
1019 * Remove and return the first emacs event on the dispatch queue that matches
1020 * the supplied event.
1021 * Timeout event matches if interval_id is equal to that of the given event.
1022 * Keypress event matches if logical AND between modifiers bitmask of the
1023 * event in the queue and that of the given event is non-zero.
1024 * For all other event types, this function aborts.
1028 mswindows_cancel_dispatch_event (struct Lisp_Event *match)
1031 Lisp_Object previous_event = Qnil;
1032 int user_p = mswindows_user_event_p (match);
1033 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1034 &mswindows_s_dispatch_event_queue;
1035 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1036 &mswindows_s_dispatch_event_queue_tail;
1038 assert (match->event_type == timeout_event
1039 || match->event_type == key_press_event);
1041 EVENT_CHAIN_LOOP (event, *head)
1043 struct Lisp_Event *e = XEVENT (event);
1044 if ((e->event_type == match->event_type) &&
1045 ((e->event_type == timeout_event) ?
1046 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1047 /* Must be key_press_event */
1048 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1050 if (NILP (previous_event))
1051 dequeue_event (head, tail);
1054 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1055 if (EQ (*tail, event))
1056 *tail = previous_event;
1061 previous_event = event;
1066 #ifndef HAVE_MSG_SELECT
1067 /************************************************************************/
1068 /* Waitable handles manipulation */
1069 /************************************************************************/
1071 find_waitable_handle (HANDLE h)
1074 for (i = 0; i < mswindows_waitable_count; ++i)
1075 if (mswindows_waitable_handles[i] == h)
1082 add_waitable_handle (HANDLE h)
1084 assert (find_waitable_handle (h) < 0);
1085 if (mswindows_waitable_count == MAX_WAITABLE)
1088 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1093 remove_waitable_handle (HANDLE h)
1095 int ix = find_waitable_handle (h);
1099 mswindows_waitable_handles [ix] =
1100 mswindows_waitable_handles [--mswindows_waitable_count];
1102 #endif /* HAVE_MSG_SELECT */
1105 /************************************************************************/
1107 /************************************************************************/
1110 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1111 Lisp_Object u_n_u_s_e_d)
1113 mswindows_error_caught_in_modal_loop = cons_sig_data;
1118 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1123 ++mswindows_in_modal_loop;
1124 tmp = condition_case_1 (Qt,
1126 mswindows_modal_loop_error_handler, Qnil);
1127 --mswindows_in_modal_loop;
1133 mswindows_unmodalize_signal_maybe (void)
1135 if (!NILP (mswindows_error_caught_in_modal_loop))
1137 /* Got an error while messages were pumped while
1138 in window procedure - have to resignal */
1139 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1140 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1141 mswindows_error_caught_in_modal_loop = Qnil;
1142 Fsignal (sym, data);
1147 * This is an unsafe part of event pump, guarded by
1148 * condition_case. See mswindows_pump_outstanding_events
1151 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1153 /* This function can call lisp */
1154 Lisp_Object event = Fmake_event (Qnil, Qnil);
1155 struct gcpro gcpro1;
1156 int do_redisplay = 0;
1159 while (detect_input_pending ())
1161 Fnext_event (event, Qnil);
1162 Fdispatch_event (event);
1169 Fdeallocate_event (event);
1172 /* Qt becomes return value of mswindows_pump_outstanding_events
1178 * This function pumps emacs events, while available, by using
1179 * next_message/dispatch_message loop. Errors are trapped around
1180 * the loop so the function always returns.
1182 * Windows message queue is not looked into during the call,
1183 * neither are waitable handles checked. The function pumps
1184 * thus only dispatch events already queued, as well as those
1185 * resulted in dispatching thereof. This is done by setting
1186 * module local variable mswindows_in_modal_loop to nonzero.
1188 * Return value is Qt if no errors was trapped, or Qunbound if
1189 * there was an error.
1191 * In case of error, a cons representing the error, in the
1192 * form (SIGNAL . DATA), is stored in the module local variable
1193 * mswindows_error_caught_in_modal_loop. This error is signaled
1194 * again when DispatchMessage returns. Thus, Windows internal
1195 * modal loops are protected against throws, which are proven
1196 * to corrupt internal Windows structures.
1198 * In case of success, mswindows_error_caught_in_modal_loop is
1201 * If the value of mswindows_error_caught_in_modal_loop is not
1202 * nil already upon entry, the function just returns non-nil.
1203 * This situation means that a new event has been queued while
1204 * in cancel mode. The event will be dequeued on the next regular
1205 * call of next-event; the pump is off since error is caught.
1206 * The caller must *unconditionally* cancel modal loop if the
1207 * value returned by this function is nil. Otherwise, everything
1208 * will become frozen until the modal loop exits under normal
1209 * condition (scrollbar drag is released, menu closed etc.)
1212 mswindows_pump_outstanding_events (void)
1214 /* This function can call lisp */
1216 Lisp_Object result = Qt;
1217 struct gcpro gcpro1;
1220 if (NILP(mswindows_error_caught_in_modal_loop))
1221 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1227 mswindows_drain_windows_queue ()
1230 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1232 /* we have to translate messages that are not sent to the main
1233 window. this is so that key presses work ok in things like
1234 edit fields. however, we *musn't* translate message for the
1235 main window as this is handled in the wnd proc. */
1236 if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
1238 TranslateMessage (&msg);
1240 DispatchMessage (&msg);
1241 mswindows_unmodalize_signal_maybe ();
1246 * This is a special flavor of the mswindows_need_event function,
1247 * used while in event pump. Actually, there is only kind of events
1248 * allowed while in event pump: a timer. An attempt to fetch any
1249 * other event leads to a deadlock, as there's no source of user input
1250 * ('cause event pump mirrors windows modal loop, which is a sole
1251 * owner of thread message queue).
1253 * To detect this, we use a counter of active timers, and allow
1254 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1255 * which will never come when there are no pending timers, which leads
1256 * to deadlock, we simply signal an error.
1259 mswindows_need_event_in_modal_loop (int badly_p)
1263 /* Check if already have one */
1264 if (!NILP (mswindows_u_dispatch_event_queue)
1265 || !NILP (mswindows_s_dispatch_event_queue))
1268 /* No event is ok */
1272 /* We do not check the _u_ queue, because timers go to _s_ */
1273 while (NILP (mswindows_s_dispatch_event_queue))
1275 /* We'll deadlock if go waiting */
1276 if (mswindows_pending_timers_count == 0)
1277 error ("Deadlock due to an attempt to call next-event in a wrong context");
1279 /* Fetch and dispatch any pending timers */
1280 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1281 DispatchMessage (&msg);
1286 * This drains the event queue and fills up two internal queues until
1287 * an event of a type specified by USER_P is retrieved.
1290 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1293 mswindows_need_event (int badly_p)
1297 if (mswindows_in_modal_loop)
1299 mswindows_need_event_in_modal_loop (badly_p);
1303 /* Have to drain Windows message queue first, otherwise, we may miss
1304 quit char when called from quit_p */
1305 mswindows_drain_windows_queue ();
1307 while (NILP (mswindows_u_dispatch_event_queue)
1308 && NILP (mswindows_s_dispatch_event_queue))
1310 #ifdef HAVE_MSG_SELECT
1312 SELECT_TYPE temp_mask = input_wait_mask;
1313 EMACS_TIME sometime;
1314 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1317 pointer_to_this = 0;
1320 EMACS_SET_SECS_USECS (sometime, 0, 0);
1321 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1322 pointer_to_this = &select_time_to_block;
1325 /* select() is slow and buggy so if we don't have any processes
1326 just wait as normal */
1327 if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0)
1329 /* Now try getting a message or process event */
1330 active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles,
1331 FALSE, badly_p ? INFINITE : 0,
1334 if (active == WAIT_TIMEOUT)
1336 /* No luck trying - just return what we've already got */
1339 else if (active == WAIT_OBJECT_0)
1341 /* Got your message, thanks */
1342 mswindows_drain_windows_queue ();
1347 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1351 return; /* timeout */
1353 else if (active > 0)
1355 if (FD_ISSET (windows_fd, &temp_mask))
1357 mswindows_drain_windows_queue ();
1360 /* Look for a process event */
1361 for (i = 0; i < MAXDESC-1; i++)
1363 if (FD_ISSET (i, &temp_mask))
1365 if (FD_ISSET (i, &process_only_mask))
1367 struct Lisp_Process *p =
1368 get_process_from_usid (FD_TO_USID(i));
1370 mswindows_enqueue_process_event (p);
1372 else if (FD_ISSET (i, &tty_only_mask))
1374 /* do we care about tty events? Do we
1375 ever get tty events? */
1379 /* We might get here when a fake event came
1380 through a signal. Return a dummy event, so
1381 that a cycle of the command loop will
1383 drain_signal_event_pipe ();
1384 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1389 else if (active==-1)
1393 /* something bad happened */
1402 /* Now try getting a message or process event */
1403 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1404 mswindows_waitable_handles,
1405 FALSE, badly_p ? INFINITE : 0,
1408 /* This will assert if handle being waited for becomes abandoned.
1409 Not the case currently tho */
1410 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1411 (active >= WAIT_OBJECT_0 &&
1412 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1414 if (active == WAIT_TIMEOUT)
1416 /* No luck trying - just return what we've already got */
1419 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1421 /* Got your message, thanks */
1422 mswindows_drain_windows_queue ();
1426 int ix = active - WAIT_OBJECT_0;
1427 /* First, try to find which process' output has signaled */
1428 struct Lisp_Process *p =
1429 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1432 /* Found a signaled process input handle */
1433 mswindows_enqueue_process_event (p);
1437 /* None. This means that the process handle itself has signaled.
1438 Remove the handle from the wait vector, and make status_notify
1439 note the exited process */
1440 mswindows_waitable_handles [ix] =
1441 mswindows_waitable_handles [--mswindows_waitable_count];
1442 kick_status_notify ();
1443 /* Have to return something: there may be no accompanying
1445 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1452 /************************************************************************/
1453 /* Event generators */
1454 /************************************************************************/
1457 * Callback procedure for synchronous timer messages
1459 static void CALLBACK
1460 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1462 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1463 struct Lisp_Event *event = XEVENT (emacs_event);
1465 if (KillTimer (NULL, id_timer))
1466 --mswindows_pending_timers_count;
1468 event->channel = Qnil;
1469 event->timestamp = dwtime;
1470 event->event_type = timeout_event;
1471 event->event.timeout.interval_id = id_timer;
1472 event->event.timeout.function = Qnil;
1473 event->event.timeout.object = Qnil;
1475 mswindows_enqueue_dispatch_event (emacs_event);
1479 * Callback procedure for dde messages
1481 * We execute a dde Open("file") by simulating a file drop, so dde support
1482 * depends on dnd support.
1484 #ifdef HAVE_DRAGNDROP
1486 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1487 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1488 DWORD dwData1, DWORD dwData2)
1493 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1494 return (HDDEDATA)TRUE;
1495 return (HDDEDATA)FALSE;
1497 case XTYP_WILDCONNECT:
1499 /* We only support one {service,topic} pair */
1500 HSZPAIR pairs[2] = {
1501 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1503 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1504 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1505 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1506 sizeof (pairs), 0L, 0, uFmt, 0));
1508 return (HDDEDATA)NULL;
1511 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1513 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1514 char *cmd = alloca (len+1);
1517 struct gcpro gcpro1, gcpro2;
1518 Lisp_Object l_dndlist = Qnil;
1519 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1520 Lisp_Object frmcons, devcons, concons;
1521 struct Lisp_Event *event = XEVENT (emacs_event);
1523 DdeGetData (hdata, cmd, len, 0);
1525 DdeFreeDataHandle (hdata);
1527 /* Check syntax & that it's an [Open("foo")] command, which we
1528 * treat like a file drop */
1529 /* #### Ought to be generalised and accept some other commands */
1532 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1533 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1534 return DDE_FNOTPROCESSED;
1535 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1538 if (*cmd!='(' || *(cmd+1)!='\"')
1539 return DDE_FNOTPROCESSED;
1541 while (*end && *end!='\"')
1544 return DDE_FNOTPROCESSED;
1547 return DDE_FNOTPROCESSED;
1551 return DDE_FNOTPROCESSED;
1554 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1555 strcpy (filename, "file:");
1556 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1558 dostounix_filename (cmd);
1559 filename = alloca (strlen (cmd)+6);
1560 strcpy (filename, "file:");
1561 strcat (filename, cmd);
1563 GCPRO2 (emacs_event, l_dndlist);
1564 l_dndlist = make_string (filename, strlen (filename));
1566 /* Find a mswindows frame */
1567 event->channel = Qnil;
1568 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1570 Lisp_Object frame = XCAR (frmcons);
1571 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1572 event->channel = frame;
1574 assert (!NILP (event->channel));
1576 event->timestamp = GetTickCount();
1577 event->event_type = misc_user_event;
1578 event->event.misc.button = 1;
1579 event->event.misc.modifiers = 0;
1580 event->event.misc.x = -1;
1581 event->event.misc.y = -1;
1582 event->event.misc.function = Qdragdrop_drop_dispatch;
1583 event->event.misc.object = Fcons (Qdragdrop_URL,
1584 Fcons (l_dndlist, Qnil));
1585 mswindows_enqueue_dispatch_event (emacs_event);
1587 return (HDDEDATA) DDE_FACK;
1589 DdeFreeDataHandle (hdata);
1590 return (HDDEDATA) DDE_FNOTPROCESSED;
1593 return (HDDEDATA) NULL;
1599 * The windows procedure for the window class XEMACS_CLASS
1602 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1604 /* Note: Remember to initialize emacs_event and event before use.
1605 This code calls code that can GC. You must GCPRO before calling such code. */
1606 Lisp_Object emacs_event = Qnil;
1607 Lisp_Object fobj = Qnil;
1609 struct Lisp_Event *event;
1610 struct frame *frame;
1611 struct mswindows_frame* msframe;
1616 /* Erase background only during non-dynamic sizing */
1617 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1618 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1623 fobj = mswindows_find_frame (hwnd);
1624 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1629 /* See Win95 comment under WM_KEYDOWN */
1633 if (wParam == VK_CONTROL)
1635 GetKeyboardState (keymap);
1636 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1637 SetKeyboardState (keymap);
1639 else if (wParam == VK_MENU)
1641 GetKeyboardState (keymap);
1642 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1643 SetKeyboardState (keymap);
1650 /* In some locales the right-hand Alt key is labelled AltGr. This key
1651 * should produce alternative charcaters when combined with another key.
1652 * eg on a German keyboard pressing AltGr+q should produce '@'.
1653 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1654 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1655 * it translates as if AltGr were down.
1656 * We get round this by removing all modifiers from the keymap before
1657 * calling TranslateMessage() unless AltGr is *really* down. */
1660 int has_AltGr = mswindows_current_layout_has_AltGr ();
1664 GetKeyboardState (keymap);
1665 mods = mswindows_modifier_state (keymap, has_AltGr);
1667 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1668 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1669 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1672 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1673 BYTE keymap_orig[256];
1674 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1678 msg.message = message;
1679 msg.wParam = wParam;
1680 msg.lParam = lParam;
1681 msg.time = GetMessageTime();
1684 /* GetKeyboardState() does not work as documented on Win95. We have
1685 * to loosely track Left and Right modifiers on behalf of the OS,
1686 * without screwing up Windows NT which tracks them properly. */
1687 if (wParam == VK_CONTROL)
1688 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1689 else if (wParam == VK_MENU)
1690 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1692 memcpy (keymap_orig, keymap, 256);
1694 /* Remove shift modifier from an ascii character */
1697 /* Clear control and alt modifiers unless AltGr is pressed */
1698 keymap [VK_RCONTROL] = 0;
1699 keymap [VK_LMENU] = 0;
1700 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1702 keymap [VK_LCONTROL] = 0;
1703 keymap [VK_CONTROL] = 0;
1704 keymap [VK_RMENU] = 0;
1705 keymap [VK_MENU] = 0;
1707 SetKeyboardState (keymap);
1709 /* Maybe generate some WM_[SYS]CHARs in the queue */
1710 TranslateMessage (&msg);
1712 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1713 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1716 WPARAM ch = msg.wParam;
1718 /* If a quit char with no modifiers other than control and
1719 shift, then mark it with a fake modifier, which is removed
1720 upon dequeueing the event */
1721 /* #### This might also not withstand localization, if
1722 quit character is not a latin-1 symbol */
1723 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1724 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1725 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1727 mods1 |= FAKE_MOD_QUIT;
1728 ++mswindows_quit_chars_count;
1731 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1733 SetKeyboardState (keymap_orig);
1736 /* F10 causes menu activation by default. We do not want this */
1737 if (wParam != VK_F10)
1741 case WM_MBUTTONDOWN:
1743 /* Real middle mouse button has nothing to do with emulated one:
1744 if one wants to exercise fingers playing chords on the mouse,
1745 he is allowed to do that! */
1746 mswindows_enqueue_mouse_button_event (hwnd, message,
1747 MAKEPOINTS (lParam), GetMessageTime());
1751 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1752 msframe->last_click_time = GetMessageTime();
1754 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1755 msframe->button2_need_lbutton = 0;
1756 if (msframe->ignore_next_lbutton_up)
1758 msframe->ignore_next_lbutton_up = 0;
1760 else if (msframe->button2_is_down)
1762 msframe->button2_is_down = 0;
1763 msframe->ignore_next_rbutton_up = 1;
1764 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1765 MAKEPOINTS (lParam), GetMessageTime());
1769 if (msframe->button2_need_rbutton)
1771 msframe->button2_need_rbutton = 0;
1772 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1773 MAKEPOINTS (lParam), GetMessageTime());
1775 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1776 MAKEPOINTS (lParam), GetMessageTime());
1781 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1782 msframe->last_click_time = GetMessageTime();
1784 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1785 msframe->button2_need_rbutton = 0;
1786 if (msframe->ignore_next_rbutton_up)
1788 msframe->ignore_next_rbutton_up = 0;
1790 else if (msframe->button2_is_down)
1792 msframe->button2_is_down = 0;
1793 msframe->ignore_next_lbutton_up = 1;
1794 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1795 MAKEPOINTS (lParam), GetMessageTime());
1799 if (msframe->button2_need_lbutton)
1801 msframe->button2_need_lbutton = 0;
1802 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1803 MAKEPOINTS (lParam), GetMessageTime());
1805 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1806 MAKEPOINTS (lParam), GetMessageTime());
1810 case WM_LBUTTONDOWN:
1811 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1813 if (msframe->button2_need_lbutton)
1815 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1816 msframe->button2_need_lbutton = 0;
1817 msframe->button2_need_rbutton = 0;
1818 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1820 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1821 MAKEPOINTS (lParam), GetMessageTime());
1822 msframe->button2_is_down = 1;
1826 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1827 msframe->last_click_point, msframe->last_click_time);
1828 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1829 MAKEPOINTS (lParam), GetMessageTime());
1834 mswindows_set_chord_timer (hwnd);
1835 msframe->button2_need_rbutton = 1;
1836 msframe->last_click_point = MAKEPOINTS (lParam);
1838 msframe->last_click_time = GetMessageTime();
1841 case WM_RBUTTONDOWN:
1842 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1844 if (msframe->button2_need_rbutton)
1846 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1847 msframe->button2_need_lbutton = 0;
1848 msframe->button2_need_rbutton = 0;
1849 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1851 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1852 MAKEPOINTS (lParam), GetMessageTime());
1853 msframe->button2_is_down = 1;
1857 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1858 msframe->last_click_point, msframe->last_click_time);
1859 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1860 MAKEPOINTS (lParam), GetMessageTime());
1865 mswindows_set_chord_timer (hwnd);
1866 msframe->button2_need_lbutton = 1;
1867 msframe->last_click_point = MAKEPOINTS (lParam);
1869 msframe->last_click_time = GetMessageTime();
1873 if (wParam == BUTTON_2_TIMER_ID)
1875 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1876 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1878 if (msframe->button2_need_lbutton)
1880 msframe->button2_need_lbutton = 0;
1881 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1882 msframe->last_click_point, msframe->last_click_time);
1884 else if (msframe->button2_need_rbutton)
1886 msframe->button2_need_rbutton = 0;
1887 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1888 msframe->last_click_point, msframe->last_click_time);
1892 assert ("Spurious timer fired" == 0);
1896 /* Optimization: don't report mouse movement while size is changing */
1897 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1898 if (!msframe->sizing)
1900 /* When waiting for the second mouse button to finish
1901 button2 emulation, and have moved too far, just pretend
1902 as if timer has expired. This improves drag-select feedback */
1903 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1904 && !mswindows_button2_near_enough (msframe->last_click_point,
1905 MAKEPOINTS (lParam)))
1907 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1908 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1911 emacs_event = Fmake_event (Qnil, Qnil);
1912 event = XEVENT(emacs_event);
1914 event->channel = mswindows_find_frame(hwnd);
1915 event->timestamp = GetMessageTime();
1916 event->event_type = pointer_motion_event;
1917 event->event.motion.x = MAKEPOINTS(lParam).x;
1918 event->event.motion.y = MAKEPOINTS(lParam).y;
1919 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1921 mswindows_enqueue_dispatch_event (emacs_event);
1927 /* Queue a `cancel-mode-internal' misc user event, so mouse
1928 selection would be canceled if any */
1929 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1930 Qcancel_mode_internal, Qnil);
1933 #ifdef HAVE_TOOLBARS
1936 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1938 if (tttext->hdr.code == TTN_NEEDTEXT)
1940 /* find out which toolbar */
1941 frame = XFRAME (mswindows_find_frame (hwnd));
1942 btext = mswindows_get_toolbar_button_text ( frame,
1943 tttext->hdr.idFrom );
1945 tttext->lpszText = NULL;
1946 tttext->hinst = NULL;
1950 /* I think this is safe since the text will only go away
1951 when the toolbar does...*/
1952 GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS,
1956 tttext->uFlags |= TTF_DI_SETITEM;
1965 PAINTSTRUCT paintStruct;
1967 frame = XFRAME (mswindows_find_frame (hwnd));
1969 BeginPaint (hwnd, &paintStruct);
1970 mswindows_redraw_exposed_area (frame,
1971 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1972 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1973 EndPaint (hwnd, &paintStruct);
1978 /* We only care about this message if our size has really changed */
1979 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1984 fobj = mswindows_find_frame (hwnd);
1985 frame = XFRAME (fobj);
1986 msframe = FRAME_MSWINDOWS_DATA (frame);
1988 /* We cannot handle frame map and unmap hooks right in
1989 this routine, because these may throw. We queue
1990 magic events to run these hooks instead - kkm */
1992 if (wParam==SIZE_MINIMIZED)
1995 FRAME_VISIBLE_P (frame) = 0;
1996 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2000 GetClientRect(hwnd, &rect);
2001 FRAME_PIXWIDTH(frame) = rect.right;
2002 FRAME_PIXHEIGHT(frame) = rect.bottom;
2004 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2005 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2006 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2008 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2009 change_frame_size (frame, rows, columns, 1);
2011 /* If we are inside frame creation, we have to apply geometric
2013 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2015 /* Yes, we have to size again */
2016 mswindows_size_frame_internal ( frame,
2017 FRAME_MSWINDOWS_TARGET_RECT
2019 /* Reset so we do not get here again. The SetWindowPos call in
2020 * mswindows_size_frame_internal can cause recursion here. */
2021 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2023 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2024 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2029 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2030 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2031 FRAME_VISIBLE_P (frame) = 1;
2033 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2040 /* Misc magic events which only require that the frame be identified */
2043 mswindows_enqueue_magic_event (hwnd, message);
2046 case WM_WINDOWPOSCHANGING:
2048 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2049 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2050 GetWindowPlacement(hwnd, &wpl);
2052 /* Only interested if size is changing and we're not being iconified */
2053 if (wpl.showCmd != SW_SHOWMINIMIZED
2054 && wpl.showCmd != SW_SHOWMAXIMIZED
2055 && !(wp->flags & SWP_NOSIZE))
2057 RECT ncsize = { 0, 0, 0, 0 };
2058 int pixwidth, pixheight;
2059 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2060 GetMenu(hwnd) != NULL,
2061 GetWindowLong (hwnd, GWL_EXSTYLE));
2063 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2064 wp->cx - (ncsize.right - ncsize.left),
2065 wp->cy - (ncsize.bottom - ncsize.top),
2066 &pixwidth, &pixheight);
2068 /* Convert client sizes to window sizes */
2069 pixwidth += (ncsize.right - ncsize.left);
2070 pixheight += (ncsize.bottom - ncsize.top);
2072 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2074 /* Adjust so that the bottom or right doesn't move if it's
2075 * the top or left that's being changed */
2077 GetWindowRect (hwnd, &rect);
2079 if (rect.left != wp->x)
2080 wp->x += wp->cx - pixwidth;
2081 if (rect.top != wp->y)
2082 wp->y += wp->cy - pixheight;
2088 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2089 window position if the user tries to track window too small */
2093 case WM_ENTERSIZEMOVE:
2094 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2095 msframe->sizing = 1;
2098 case WM_EXITSIZEMOVE:
2099 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2100 msframe->sizing = 0;
2101 /* Queue noop event */
2102 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2105 #ifdef HAVE_SCROLLBARS
2109 /* Direction of scroll is determined by scrollbar instance. */
2110 int code = (int) LOWORD(wParam);
2111 int pos = (short int) HIWORD(wParam);
2112 HWND hwndScrollBar = (HWND) lParam;
2113 struct gcpro gcpro1, gcpro2;
2115 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2116 GCPRO2 (emacs_event, fobj);
2117 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2119 /* Error during event pumping - cancel scroll */
2120 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2127 #ifdef HAVE_MENUBARS
2129 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2131 XFRAME (mswindows_find_frame (hwnd)))))
2132 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2135 case WM_INITMENUPOPUP:
2136 if (!HIWORD(lParam))
2138 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2140 XFRAME (mswindows_find_frame (hwnd)))))
2141 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2145 #endif /* HAVE_MENUBARS */
2149 WORD id = LOWORD (wParam);
2150 WORD nid = HIWORD (wParam);
2151 HWND cid = (HWND)lParam;
2152 frame = XFRAME (mswindows_find_frame (hwnd));
2154 #ifdef HAVE_TOOLBARS
2155 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2158 /* widgets in a buffer only eval a callback for suitable events.*/
2163 case CBN_EDITCHANGE:
2165 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2168 /* menubars always must come last since the hashtables do not
2170 #ifdef HAVE_MENUBARS
2171 if (!NILP (mswindows_handle_wm_command (frame, id)))
2175 return DefWindowProc (hwnd, message, wParam, lParam);
2176 /* Bite me - a spurious command. This used to not be able to
2177 happen but with the introduction of widgets its now
2182 case WM_CTLCOLORBTN:
2183 case WM_CTLCOLORLISTBOX:
2184 case WM_CTLCOLOREDIT:
2185 case WM_CTLCOLORSTATIC:
2186 case WM_CTLCOLORSCROLLBAR:
2188 /* if we get an opportunity to paint a widget then do so if
2189 there is an appropriate face */
2190 HWND crtlwnd = (HWND)lParam;
2191 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2194 Lisp_Object image_instance;
2195 VOID_TO_LISP (image_instance, ii);
2196 if (IMAGE_INSTANCEP (image_instance)
2198 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
2200 !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
2202 /* set colors for the buttons */
2203 HDC hdc = (HDC)wParam;
2204 if (last_widget_brushed != ii)
2207 DeleteObject (widget_brush);
2208 widget_brush = CreateSolidBrush
2209 (COLOR_INSTANCE_MSWINDOWS_COLOR
2212 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2213 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2215 last_widget_brushed = ii;
2218 COLOR_INSTANCE_MSWINDOWS_COLOR
2221 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2222 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2223 SetBkMode (hdc, OPAQUE);
2226 COLOR_INSTANCE_MSWINDOWS_COLOR
2229 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2230 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2231 return (LRESULT)widget_brush;
2237 #ifdef HAVE_DRAGNDROP
2238 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2240 UINT filecount, i, len;
2246 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2247 struct gcpro gcpro1, gcpro2, gcpro3;
2249 emacs_event = Fmake_event (Qnil, Qnil);
2250 event = XEVENT(emacs_event);
2252 GCPRO3 (emacs_event, l_dndlist, l_item);
2254 if (!DragQueryPoint ((HANDLE) wParam, &point))
2255 point.x = point.y = -1; /* outside client area */
2257 event->event_type = misc_user_event;
2258 event->channel = mswindows_find_frame(hwnd);
2259 event->timestamp = GetMessageTime();
2260 event->event.misc.button = 1; /* #### Should try harder */
2261 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2262 event->event.misc.x = point.x;
2263 event->event.misc.y = point.y;
2264 event->event.misc.function = Qdragdrop_drop_dispatch;
2266 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2267 for (i=0; i<filecount; i++)
2269 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2270 /* The URLs that we make here aren't correct according to section
2271 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2272 * because they may contain reserved characters. But that's OK. */
2274 fname = (char *)xmalloc (len+1);
2275 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2276 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2277 strcpy (filename, "file:");
2278 cygwin32_win32_to_posix_path_list (fname, filename+5);
2281 filename = (char *)xmalloc (len+6);
2282 strcpy (filename, "file:");
2283 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2284 dostounix_filename (filename+5);
2286 l_item = make_string (filename, strlen (filename));
2287 l_dndlist = Fcons (l_item, l_dndlist);
2290 DragFinish ((HANDLE) wParam);
2292 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2293 mswindows_enqueue_dispatch_event (emacs_event);
2301 return DefWindowProc (hwnd, message, wParam, lParam);
2307 /************************************************************************/
2308 /* keyboard, mouse & other helpers for the windows procedure */
2309 /************************************************************************/
2311 mswindows_set_chord_timer (HWND hwnd)
2315 /* We get one third half system double click threshold */
2316 if (mswindows_mouse_button_tolerance <= 0)
2317 interval = GetDoubleClickTime () / 3;
2319 interval = mswindows_mouse_button_tolerance;
2321 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2325 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2328 if (mswindows_mouse_button_max_skew_x <= 0)
2329 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2331 dx = mswindows_mouse_button_max_skew_x;
2333 if (mswindows_mouse_button_max_skew_y <= 0)
2334 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2336 dy = mswindows_mouse_button_max_skew_y;
2338 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2342 mswindows_current_layout_has_AltGr (void)
2344 /* This simple caching mechanism saves 10% of CPU
2345 time when a key typed at autorepeat rate of 30 cps! */
2346 static HKL last_hkl = 0;
2347 static int last_hkl_has_AltGr;
2349 HKL current_hkl = GetKeyboardLayout (0);
2350 if (current_hkl != last_hkl)
2353 last_hkl_has_AltGr = 0;
2354 /* In this loop, we query whether a character requires
2355 AltGr to be down to generate it. If at least such one
2356 found, this means that the layout does regard AltGr */
2357 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2358 if (HIBYTE (VkKeyScan (c)) == 6)
2359 last_hkl_has_AltGr = 1;
2360 last_hkl = current_hkl;
2362 return last_hkl_has_AltGr;
2366 /* Returns the state of the modifier keys in the format expected by the
2367 * Lisp_Event key_data, button_data and motion_data modifiers member */
2368 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2374 keymap = (BYTE*) alloca(256);
2375 GetKeyboardState (keymap);
2376 has_AltGr = mswindows_current_layout_has_AltGr ();
2379 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2381 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2382 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2386 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2387 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2390 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2396 * Translate a mswindows virtual key to a keysym.
2397 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2398 * or whose ASCII codes (like space) xemacs doesn't like.
2399 * Virtual key values are defined in winresrc.h
2400 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2402 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2404 switch (mswindows_key)
2406 /* First the predefined ones */
2407 case VK_BACK: return QKbackspace;
2408 case VK_TAB: return QKtab;
2409 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2410 case VK_RETURN: return QKreturn;
2411 case VK_ESCAPE: return QKescape;
2412 case VK_SPACE: return QKspace;
2413 case VK_DELETE: return QKdelete;
2416 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2417 case VK_PRIOR: return KEYSYM ("prior");
2418 case VK_NEXT: return KEYSYM ("next");
2419 case VK_END: return KEYSYM ("end");
2420 case VK_HOME: return KEYSYM ("home");
2421 case VK_LEFT: return KEYSYM ("left");
2422 case VK_UP: return KEYSYM ("up");
2423 case VK_RIGHT: return KEYSYM ("right");
2424 case VK_DOWN: return KEYSYM ("down");
2425 case VK_SELECT: return KEYSYM ("select");
2426 case VK_PRINT: return KEYSYM ("print");
2427 case VK_EXECUTE: return KEYSYM ("execute");
2428 case VK_SNAPSHOT: return KEYSYM ("print");
2429 case VK_INSERT: return KEYSYM ("insert");
2430 case VK_HELP: return KEYSYM ("help");
2431 #if 0 /* XXX What are these supposed to do? */
2432 case VK_LWIN return KEYSYM ("");
2433 case VK_RWIN return KEYSYM ("");
2435 case VK_APPS: return KEYSYM ("menu");
2436 case VK_F1: return KEYSYM ("f1");
2437 case VK_F2: return KEYSYM ("f2");
2438 case VK_F3: return KEYSYM ("f3");
2439 case VK_F4: return KEYSYM ("f4");
2440 case VK_F5: return KEYSYM ("f5");
2441 case VK_F6: return KEYSYM ("f6");
2442 case VK_F7: return KEYSYM ("f7");
2443 case VK_F8: return KEYSYM ("f8");
2444 case VK_F9: return KEYSYM ("f9");
2445 case VK_F10: return KEYSYM ("f10");
2446 case VK_F11: return KEYSYM ("f11");
2447 case VK_F12: return KEYSYM ("f12");
2448 case VK_F13: return KEYSYM ("f13");
2449 case VK_F14: return KEYSYM ("f14");
2450 case VK_F15: return KEYSYM ("f15");
2451 case VK_F16: return KEYSYM ("f16");
2452 case VK_F17: return KEYSYM ("f17");
2453 case VK_F18: return KEYSYM ("f18");
2454 case VK_F19: return KEYSYM ("f19");
2455 case VK_F20: return KEYSYM ("f20");
2456 case VK_F21: return KEYSYM ("f21");
2457 case VK_F22: return KEYSYM ("f22");
2458 case VK_F23: return KEYSYM ("f23");
2459 case VK_F24: return KEYSYM ("f24");
2465 * Find the console that matches the supplied mswindows window handle
2468 mswindows_find_console (HWND hwnd)
2470 /* We only support one console */
2471 return XCAR (Vconsole_list);
2475 * Find the frame that matches the supplied mswindows window handle
2478 mswindows_find_frame (HWND hwnd)
2480 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2484 /* We are in progress of frame creation. Return the frame
2485 being created, as it still not remembered in the window
2487 assert (!NILP (Vmswindows_frame_being_created));
2488 return Vmswindows_frame_being_created;
2490 VOID_TO_LISP (f, l);
2495 /************************************************************************/
2497 /************************************************************************/
2500 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2503 EMACS_TIME current_time;
2504 EMACS_GET_TIME (current_time);
2505 EMACS_SUB_TIME (thyme, thyme, current_time);
2506 milliseconds = EMACS_SECS (thyme) * 1000 +
2507 (EMACS_USECS (thyme) + 500) / 1000;
2508 if (milliseconds < 1)
2510 ++mswindows_pending_timers_count;
2511 return SetTimer (NULL, 0, milliseconds,
2512 (TIMERPROC) mswindows_wm_timer_callback);
2516 emacs_mswindows_remove_timeout (int id)
2518 struct Lisp_Event match_against;
2519 Lisp_Object emacs_event;
2521 if (KillTimer (NULL, id))
2522 --mswindows_pending_timers_count;
2524 /* If there is a dispatch event generated by this
2525 timeout in the queue, we have to remove it too. */
2526 match_against.event_type = timeout_event;
2527 match_against.event.timeout.interval_id = id;
2528 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2529 if (!NILP (emacs_event))
2530 Fdeallocate_event(emacs_event);
2533 /* If `user_p' is false, then return whether there are any win32, timeout,
2534 * or subprocess events pending (that is, whether
2535 * emacs_mswindows_next_event() would return immediately without blocking).
2537 * if `user_p' is true, then return whether there are any *user generated*
2538 * events available (that is, whether there are keyboard or mouse-click
2539 * events ready to be read). This also implies that
2540 * emacs_mswindows_next_event() would not block.
2543 emacs_mswindows_event_pending_p (int user_p)
2545 mswindows_need_event (0);
2546 return (!NILP (mswindows_u_dispatch_event_queue)
2547 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2551 * Return the next event
2554 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2556 Lisp_Object event, event2;
2558 mswindows_need_event (1);
2560 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
2561 XSETEVENT (event2, emacs_event);
2562 Fcopy_event (event, event2);
2563 Fdeallocate_event (event);
2567 * Handle a magic event off the dispatch queue.
2570 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2572 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2580 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2581 struct frame *f = XFRAME (frame);
2582 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2585 /* struct gcpro gcpro1; */
2587 /* Clear sticky modifiers here (if we had any) */
2589 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2590 /* GCPRO1 (conser); XXX Not necessary? */
2591 emacs_handle_focus_change_preliminary (conser);
2592 /* Under X the stuff up to here is done in the X event handler.
2594 emacs_handle_focus_change_final (conser);
2603 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2604 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2606 Qmap_frame_hook : Qunmap_frame_hook,
2611 /* #### What about Enter & Leave */
2613 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2614 Qmouse_leave_frame_hook, 1, frame);
2622 #ifndef HAVE_MSG_SELECT
2624 get_process_input_waitable (struct Lisp_Process *process)
2626 Lisp_Object instr, outstr, p;
2627 XSETPROCESS (p, process);
2628 get_process_streams (process, &instr, &outstr);
2629 assert (!NILP (instr));
2630 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2631 return (network_connection_p (p)
2632 ? get_winsock_stream_waitable (XLSTREAM (instr))
2633 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2635 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2640 emacs_mswindows_select_process (struct Lisp_Process *process)
2642 HANDLE hev = get_process_input_waitable (process);
2644 if (!add_waitable_handle (hev))
2645 error ("Too many active processes");
2647 #ifdef HAVE_WIN32_PROCESSES
2650 XSETPROCESS (p, process);
2651 if (!network_connection_p (p))
2653 HANDLE hprocess = get_nt_process_handle (process);
2654 if (!add_waitable_handle (hprocess))
2656 remove_waitable_handle (hev);
2657 error ("Too many active processes");
2665 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2667 /* Process handle is removed in the event loop as soon
2668 as it is signaled, so don't bother here about it */
2669 HANDLE hev = get_process_input_waitable (process);
2670 remove_waitable_handle (hev);
2672 #endif /* HAVE_MSG_SELECT */
2675 emacs_mswindows_select_console (struct console *con)
2680 emacs_mswindows_unselect_console (struct console *con)
2685 emacs_mswindows_quit_p (void)
2689 /* Quit cannot happen in modal loop: all program
2690 input is dedicated to Windows. */
2691 if (mswindows_in_modal_loop)
2694 /* Drain windows queue. This sets up number of quit characters in the queue
2695 * (and also processes wm focus change, move, resize, etc messages).
2696 * We don't want to process WM_PAINT messages because this function can be
2697 * called from almost anywhere and the windows' states may be changing. */
2698 while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
2699 PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
2700 DispatchMessage (&msg);
2702 if (mswindows_quit_chars_count > 0)
2704 /* Yes there's a hidden one... Throw it away */
2705 struct Lisp_Event match_against;
2706 Lisp_Object emacs_event;
2708 match_against.event_type = key_press_event;
2709 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2711 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2712 assert (!NILP (emacs_event));
2714 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2717 Fdeallocate_event(emacs_event);
2718 --mswindows_quit_chars_count;
2723 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2724 Lisp_Object* instream,
2725 Lisp_Object* outstream,
2728 /* Handles for streams */
2730 /* fds. These just stored along with the streams, and are closed in
2731 delete stream pair method, because we need to handle fake unices
2735 /* Decode inhandle and outhandle. Their meaning depends on
2736 the process implementation being used. */
2737 #if defined (HAVE_WIN32_PROCESSES)
2738 /* We're passed in Windows handles. That's what we like most... */
2739 hin = (HANDLE) inhandle;
2740 hout = (HANDLE) outhandle;
2742 #elif defined (HAVE_UNIX_PROCESSES)
2743 /* We are passed UNIX fds. This must be Cygwin.
2745 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2746 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2750 #error "So, WHICH kind of processes do you want?"
2753 *instream = (hin == INVALID_HANDLE_VALUE
2755 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2756 : flags & STREAM_NETWORK_CONNECTION
2757 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2759 : make_ntpipe_input_stream (hin, fdi));
2761 #ifdef HAVE_WIN32_PROCESSES
2762 *outstream = (hout == INVALID_HANDLE_VALUE
2764 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2765 : flags & STREAM_NETWORK_CONNECTION
2766 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2768 : make_ntpipe_output_stream (hout, fdo));
2769 #elif defined (HAVE_UNIX_PROCESSES)
2770 *outstream = (fdo >= 0
2771 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2774 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2775 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2776 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2778 Bufbyte eof_char = get_eof_char (fdo);
2779 int pty_max_bytes = get_pty_max_bytes (fdo);
2780 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2785 return (NILP (*instream)
2787 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2788 : flags & STREAM_NETWORK_CONNECTION
2789 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2791 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2795 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2796 Lisp_Object outstream)
2798 /* Oh nothing special here for Win32 at all */
2799 #if defined (HAVE_UNIX_PROCESSES)
2800 int in = (NILP(instream)
2802 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2803 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2804 ? get_winsock_stream_param (XLSTREAM (instream))
2806 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2807 int out = (NILP(outstream) ? -1
2808 : filedesc_stream_fd (XLSTREAM (outstream)));
2812 if (out != in && out >= 0)
2816 return (NILP (instream)
2818 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2819 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2820 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2822 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2825 #ifndef HAVE_X_WINDOWS
2826 /* This is called from GC when a process object is about to be freed.
2827 If we've still got pointers to it in this file, we're gonna lose hard.
2830 debug_process_finalization (struct Lisp_Process *p)
2833 Lisp_Object instr, outstr;
2835 get_process_streams (p, &instr, &outstr);
2836 /* if it still has fds, then it hasn't been killed yet. */
2837 assert (NILP(instr));
2838 assert (NILP(outstr));
2840 /* #### More checks here */
2845 /************************************************************************/
2846 /* initialization */
2847 /************************************************************************/
2850 vars_of_event_mswindows (void)
2852 mswindows_u_dispatch_event_queue = Qnil;
2853 staticpro (&mswindows_u_dispatch_event_queue);
2854 mswindows_u_dispatch_event_queue_tail = Qnil;
2856 mswindows_s_dispatch_event_queue = Qnil;
2857 staticpro (&mswindows_s_dispatch_event_queue);
2858 mswindows_s_dispatch_event_queue_tail = Qnil;
2860 mswindows_error_caught_in_modal_loop = Qnil;
2861 staticpro (&mswindows_error_caught_in_modal_loop);
2862 mswindows_in_modal_loop = 0;
2863 mswindows_pending_timers_count = 0;
2865 mswindows_event_stream = xnew (struct event_stream);
2867 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2868 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2869 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2870 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2871 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2872 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2873 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2874 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2875 #ifdef HAVE_MSG_SELECT
2876 mswindows_event_stream->select_process_cb =
2877 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2878 mswindows_event_stream->unselect_process_cb =
2879 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2880 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2881 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2883 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2884 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2885 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2886 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2889 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2890 *Controls redrawing frame contents during mouse-drag or keyboard resize
2891 operation. When non-nil, the frame is redrawn while being resized. When
2892 nil, frame is not redrawn, and exposed areas are filled with default
2893 MDI application background color. Note that this option only has effect
2894 if "Show window contents while dragging" is on in system Display/Plus!
2896 Default is t on fast machines, nil on slow.
2899 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2900 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2901 *Analogue of double click interval for faking middle mouse events.
2902 The value is the minimum time in milliseconds that must elapse between
2903 left/right button down events before they are considered distinct events.
2904 If both mouse buttons are depressed within this interval, a middle mouse
2905 button down event is generated instead.
2906 If negative or zero, currently set system default is used instead.
2909 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2910 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2911 Number of physical mouse buttons.
2914 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2915 *Maximum horizontal distance in pixels between points in which left and
2916 right button clicks occurred for them to be translated into single
2917 middle button event. Clicks must occur in time not longer than defined
2918 by the variable `mswindows-mouse-button-tolerance'.
2919 If negative or zero, currently set system default is used instead.
2922 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2923 *Maximum vertical distance in pixels between points in which left and
2924 right button clicks occurred for them to be translated into single
2925 middle button event. Clicks must occur in time not longer than defined
2926 by the variable `mswindows-mouse-button-tolerance'.
2927 If negative or zero, currently set system default is used instead.
2930 mswindows_mouse_button_max_skew_x = 0;
2931 mswindows_mouse_button_max_skew_y = 0;
2932 mswindows_mouse_button_tolerance = 0;
2936 syms_of_event_mswindows (void)
2941 lstream_type_create_mswindows_selectable (void)
2943 init_slurp_stream ();
2944 init_shove_stream ();
2945 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2946 init_winsock_stream ();
2951 init_event_mswindows_late (void)
2953 #ifdef HAVE_MSG_SELECT
2954 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2955 assert (windows_fd>=0);
2956 FD_SET (windows_fd, &input_wait_mask);
2957 FD_ZERO(&zero_mask);
2960 event_stream = mswindows_event_stream;
2962 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2963 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);