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 #include "console-tty.h"
69 #elif defined(__CYGWIN32__)
70 typedef unsigned int SOCKET;
76 #define ADJR_MENUFLAG TRUE
78 #define ADJR_MENUFLAG FALSE
81 /* Fake key modifier which is attached to a quit char event.
82 Removed upon dequeueing an event */
83 #define FAKE_MOD_QUIT 0x80
85 /* Timer ID used for button2 emulation */
86 #define BUTTON_2_TIMER_ID 1
89 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
91 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
93 mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
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);
98 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
99 static void mswindows_set_chord_timer (HWND hwnd);
100 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
101 static int mswindows_current_layout_has_AltGr (void);
103 static struct event_stream *mswindows_event_stream;
105 #ifdef HAVE_MSG_SELECT
106 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
107 extern SELECT_TYPE process_only_mask, tty_only_mask;
108 SELECT_TYPE zero_mask;
109 extern int signal_event_pipe_initialized;
114 * Two separate queues, for efficiency, one (_u_) for user events, and
115 * another (_s_) for non-user ones. We always return events out of the
116 * first one until it is empty and only then proceed with the second
119 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
120 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
122 /* The number of things we can wait on */
123 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
125 #ifndef HAVE_MSG_SELECT
126 /* List of mswindows waitable handles. */
127 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
129 /* Number of wait handles */
130 static int mswindows_waitable_count=0;
131 #endif /* HAVE_MSG_SELECT */
132 /* Brush for painting widgets */
133 static HBRUSH widget_brush = 0;
134 static LONG last_widget_brushed = 0;
136 /* Count of quit chars currently in the queue */
137 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
138 Decremented in mswindows_dequeue_dispatch_event() */
139 int mswindows_quit_chars_count = 0;
141 /* These are Lisp integers; see DEFVARS in this file for description. */
142 int mswindows_dynamic_frame_resize;
143 int mswindows_num_mouse_buttons;
144 int mswindows_mouse_button_max_skew_x;
145 int mswindows_mouse_button_max_skew_y;
146 int mswindows_mouse_button_tolerance;
148 /* This is the event signaled by the event pump.
149 See mswindows_pump_outstanding_events for comments */
150 static Lisp_Object mswindows_error_caught_in_modal_loop;
151 static int mswindows_in_modal_loop;
153 /* Count of wound timers */
154 static int mswindows_pending_timers_count;
156 /************************************************************************/
157 /* Pipe instream - reads process output */
158 /************************************************************************/
160 #define PIPE_READ_DELAY 20
162 #define HANDLE_TO_USID(h) ((USID)(h))
164 #define NTPIPE_SLURP_STREAM_DATA(stream) \
165 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
167 /* This structure is allocated by the main thread, and is deallocated
168 in the thread upon exit. There are situations when a thread
169 remains blocked for a long time, much longer than the lstream
170 exists. For example, "start notepad" command is issued from the
171 shell, then the shell is closed by C-c C-d. Although the shell
172 process exits, its output pipe will not get closed until the
173 notepad process exits also, because it inherits the pipe form the
174 shell. In this case, we abandon the thread, and let it live until
175 all such processes exit. While struct ntpipe_slurp_stream is
176 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
178 struct ntpipe_slurp_stream_shared_data
180 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
181 /* This is a manual-reset object. */
182 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
183 /* This is a manual-reset object. */
184 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
185 /* This is a manual-reset object. */
186 HANDLE hpipe; /* Pipe read end handle. */
187 LONG die_p; /* Thread must exit ASAP if non-zero */
188 BOOL eof_p : 1; /* Set when thread saw EOF */
189 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
190 BOOL inuse_p : 1; /* this structure is in use */
191 LONG lock_count; /* Client count of this struct, 0=safe to free */
192 BYTE onebyte; /* One byte buffer read by thread */
195 #define MAX_SLURP_STREAMS 32
196 struct ntpipe_slurp_stream_shared_data
197 shared_data_block[MAX_SLURP_STREAMS]={{0}};
199 struct ntpipe_slurp_stream
201 LPARAM user_data; /* Any user data stored in the stream object */
202 struct ntpipe_slurp_stream_shared_data* thread_data;
205 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
206 sizeof (struct ntpipe_slurp_stream));
208 /* This function is thread-safe, and is called from either thread
209 context. It serializes freeing shared data structure */
211 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
213 if (InterlockedDecrement (&s->lock_count) == 0)
216 CloseHandle (s->hev_thread);
217 CloseHandle (s->hev_caller);
218 CloseHandle (s->hev_unsleep);
223 static struct ntpipe_slurp_stream_shared_data*
224 slurper_allocate_shared_data()
227 for (i=0; i<MAX_SLURP_STREAMS; i++)
229 if (!shared_data_block[i].inuse_p)
231 shared_data_block[i].inuse_p=1;
232 return &shared_data_block[i];
235 return (struct ntpipe_slurp_stream_shared_data*)0;
239 slurp_thread (LPVOID vparam)
241 struct ntpipe_slurp_stream_shared_data *s =
242 (struct ntpipe_slurp_stream_shared_data*)vparam;
246 /* Read one byte from the pipe */
248 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
250 DWORD err = GetLastError ();
251 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
256 else if (actually_read == 0)
259 /* We must terminate on an error or eof */
260 if (s->eof_p || s->error_p)
261 InterlockedIncrement (&s->die_p);
263 /* Before we notify caller, we unsignal our event. */
264 ResetEvent (s->hev_thread);
266 /* Now we got something to notify caller, either a byte or an
267 error/eof indication. Before we do, allow internal pipe
268 buffer to accumulate little bit more data.
269 Reader function pulses this event before waiting for
270 a character, to avoid pipe delay, and to get the byte
273 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
275 /* Either make event loop generate a process event, or
277 SetEvent (s->hev_caller);
279 /* Cleanup and exit if we're shot off */
283 /* Block until the client finishes with retrieving the rest of
285 WaitForSingleObject (s->hev_thread, INFINITE);
288 slurper_free_shared_data_maybe (s);
294 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
297 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
298 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
299 DWORD thread_id_unused;
302 /* We deal only with pipes, for we're using PeekNamedPipe api */
303 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
305 s->thread_data = slurper_allocate_shared_data();
307 /* Create reader thread. This could fail, so do not create events
308 until thread is created */
309 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
310 CREATE_SUSPENDED, &thread_id_unused);
313 Lstream_delete (lstr);
314 s->thread_data->inuse_p=0;
318 /* Shared data are initially owned by both main and slurper
320 s->thread_data->lock_count = 2;
321 s->thread_data->die_p = 0;
322 s->thread_data->eof_p = FALSE;
323 s->thread_data->error_p = FALSE;
324 s->thread_data->hpipe = hpipe;
325 s->user_data = param;
327 /* hev_thread is a manual-reset event, initially signaled */
328 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
329 /* hev_caller is a manual-reset event, initially nonsignaled */
330 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
331 /* hev_unsleep is a manual-reset event, initially nonsignaled */
332 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
335 ResumeThread (hthread);
336 CloseHandle (hthread);
338 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
339 XSETLSTREAM (obj, lstr);
344 get_ntpipe_input_stream_param (Lstream *stream)
346 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
351 get_ntpipe_input_stream_waitable (Lstream *stream)
353 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
354 return s->thread_data->hev_caller;
358 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
360 /* This function must be called from the main thread only */
361 struct ntpipe_slurp_stream_shared_data* s =
362 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
367 /* Disallow pipe read delay for the thread: we need a character
369 SetEvent (s->hev_unsleep);
371 /* Check if we have a character ready. Give it a short delay,
372 for the thread to awake from pipe delay, just ion case*/
373 wait_result = WaitForSingleObject (s->hev_caller, 2);
375 /* Revert to the normal sleep behavior. */
376 ResetEvent (s->hev_unsleep);
378 /* If there's no byte buffered yet, give up */
379 if (wait_result == WAIT_TIMEOUT)
386 /* Reset caller unlock event now, as we've handled the pending
387 process output event */
388 ResetEvent (s->hev_caller);
390 /* It is now safe to do anything with contents of S, except for
391 changing s->die_p, which still should be interlocked */
395 if (s->error_p || s->die_p)
398 /* Ok, there were no error neither eof - we've got a byte from the
400 *(data++) = s->onebyte;
404 DWORD bytes_read = 0;
407 DWORD bytes_available;
409 /* If the api call fails, return at least one byte already
410 read. ReadFile in thread will return error */
411 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
414 /* Fetch available bytes. The same consideration applies,
415 so do not check for errors. ReadFile in the thread will
416 fail if the next call fails. */
418 ReadFile (s->hpipe, data, min (bytes_available, size),
422 /* Now we can unblock thread, so it attempts to read more */
423 SetEvent (s->hev_thread);
424 return bytes_read + 1;
431 ntpipe_slurp_closer (Lstream *stream)
433 /* This function must be called from the main thread only */
434 struct ntpipe_slurp_stream_shared_data* s =
435 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
437 /* Force thread to stop */
438 InterlockedIncrement (&s->die_p);
440 /* Set events which could possibly block slurper. Let it finish soon
442 SetEvent (s->hev_unsleep);
443 SetEvent (s->hev_thread);
445 /* Unlock and maybe free shared data */
446 slurper_free_shared_data_maybe (s);
452 init_slurp_stream (void)
454 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
455 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
458 /************************************************************************/
459 /* Pipe outstream - writes process input */
460 /************************************************************************/
462 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
463 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
465 #define MAX_SHOVE_BUFFER_SIZE 128
467 struct ntpipe_shove_stream
469 LPARAM user_data; /* Any user data stored in the stream object */
470 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
471 /* This is an auto-reset object. */
472 HANDLE hpipe; /* Pipe write end handle. */
473 HANDLE hthread; /* Reader thread handle. */
474 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
475 DWORD size; /* Number of bytes to write */
476 LONG die_p; /* Thread must exit ASAP if non-zero */
477 LONG idle_p; /* Non-zero if thread is waiting for job */
478 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
479 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
482 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
483 sizeof (struct ntpipe_shove_stream));
485 #ifndef HAVE_MSG_SELECT
487 shove_thread (LPVOID vparam)
489 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
495 /* Block on event and wait for a job */
496 InterlockedIncrement (&s->idle_p);
497 WaitForSingleObject (s->hev_thread, INFINITE);
502 /* Write passed buffer */
503 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
504 || bytes_written != s->size)
507 InterlockedIncrement (&s->die_p);
518 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
521 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
522 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
523 DWORD thread_id_unused;
528 s->user_data = param;
530 /* Create reader thread. This could fail, so do not
531 create the event until thread is created */
532 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
533 CREATE_SUSPENDED, &thread_id_unused);
534 if (s->hthread == NULL)
536 Lstream_delete (lstr);
540 /* hev_thread is an auto-reset event, initially nonsignaled */
541 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
544 ResumeThread (s->hthread);
546 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
547 XSETLSTREAM (obj, lstr);
552 get_ntpipe_output_stream_param (Lstream *stream)
554 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
560 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
562 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
567 s->blocking_p = !s->idle_p;
571 if (size>MAX_SHOVE_BUFFER_SIZE)
574 memcpy (s->buffer, data, size);
578 InterlockedDecrement (&s->idle_p);
579 SetEvent (s->hev_thread);
584 ntpipe_shove_was_blocked_p (Lstream *stream)
586 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
587 return s->blocking_p;
591 ntpipe_shove_closer (Lstream *stream)
593 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
595 /* Force thread stop */
596 InterlockedIncrement (&s->die_p);
598 /* Close pipe handle, possibly breaking it */
599 CloseHandle (s->hpipe);
601 /* Thread will end upon unblocking */
602 SetEvent (s->hev_thread);
604 /* Wait while thread terminates */
605 WaitForSingleObject (s->hthread, INFINITE);
606 CloseHandle (s->hthread);
608 /* Destroy the event */
609 CloseHandle (s->hev_thread);
615 init_shove_stream (void)
617 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
618 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
619 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
622 /************************************************************************/
623 /* Winsock I/O stream */
624 /************************************************************************/
625 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
627 #define WINSOCK_READ_BUFFER_SIZE 1024
629 struct winsock_stream
631 LPARAM user_data; /* Any user data stored in the stream object */
632 SOCKET s; /* Socket handle (which is a Win32 handle) */
633 OVERLAPPED ov; /* Overlapped I/O structure */
634 void* buffer; /* Buffer. Allocated for input stream only */
635 unsigned int bufsize; /* Number of bytes last read */
636 unsigned int bufpos; /* Position in buffer for next fetch */
637 unsigned int error_p :1; /* I/O Error seen */
638 unsigned int eof_p :1; /* EOF Error seen */
639 unsigned int pending_p :1; /* There is a pending I/O operation */
640 unsigned int blocking_p :1; /* Last write attempt would block */
643 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
645 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
646 sizeof (struct winsock_stream));
649 winsock_initiate_read (struct winsock_stream *str)
651 ResetEvent (str->ov.hEvent);
654 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
655 &str->bufsize, &str->ov))
657 if (GetLastError () == ERROR_IO_PENDING)
659 else if (GetLastError () == ERROR_HANDLE_EOF)
664 else if (str->bufsize == 0)
669 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
671 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
673 /* If the current operation is not yet complete, there's nothing to
677 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
684 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
686 if (GetLastError() == ERROR_HANDLE_EOF)
691 if (str->bufsize == 0)
702 /* Return as much of buffer as we have */
703 size = min (size, (size_t) (str->bufsize - str->bufpos));
704 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
707 /* Read more if buffer is exhausted */
708 if (str->bufsize == str->bufpos)
709 winsock_initiate_read (str);
715 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
717 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
721 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
729 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
744 ResetEvent (str->ov.hEvent);
746 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
747 * an overlapped operation. This fails on Win95 with winsock 1.x so we
748 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
749 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
750 || GetLastError() == ERROR_IO_PENDING)
756 return str->error_p ? -1 : size;
760 winsock_closer (Lstream *lstr)
762 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
764 if (lstr->flags & LSTREAM_FL_READ)
765 shutdown (str->s, 0);
767 shutdown (str->s, 1);
769 CloseHandle ((HANDLE)str->s);
771 WaitForSingleObject (str->ov.hEvent, INFINITE);
773 if (lstr->flags & LSTREAM_FL_READ)
776 CloseHandle (str->ov.hEvent);
781 winsock_was_blocked_p (Lstream *stream)
783 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
784 return str->blocking_p;
788 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
791 Lstream *lstr = Lstream_new (lstream_winsock, mode);
792 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
799 str->user_data = param;
802 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
804 if (lstr->flags & LSTREAM_FL_READ)
806 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
807 winsock_initiate_read (str);
810 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
811 XSETLSTREAM (obj, lstr);
816 make_winsock_input_stream (SOCKET s, LPARAM param)
818 return make_winsock_stream_1 (s, param, "r");
822 make_winsock_output_stream (SOCKET s, LPARAM param)
824 return make_winsock_stream_1 (s, param, "w");
828 get_winsock_stream_waitable (Lstream *lstr)
830 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
831 return str->ov.hEvent;
835 get_winsock_stream_param (Lstream *lstr)
837 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
838 return str->user_data;
842 init_winsock_stream (void)
844 LSTREAM_HAS_METHOD (winsock, reader);
845 LSTREAM_HAS_METHOD (winsock, writer);
846 LSTREAM_HAS_METHOD (winsock, closer);
847 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
849 #endif /* defined (HAVE_SOCKETS) */
851 /************************************************************************/
852 /* Dispatch queue management */
853 /************************************************************************/
856 mswindows_user_event_p (struct Lisp_Event* sevt)
858 return (sevt->event_type == key_press_event
859 || sevt->event_type == button_press_event
860 || sevt->event_type == button_release_event
861 || sevt->event_type == misc_user_event);
865 * Add an emacs event to the proper dispatch queue
868 mswindows_enqueue_dispatch_event (Lisp_Object event)
870 int user_p = mswindows_user_event_p (XEVENT(event));
871 enqueue_event (event,
872 user_p ? &mswindows_u_dispatch_event_queue :
873 &mswindows_s_dispatch_event_queue,
874 user_p ? &mswindows_u_dispatch_event_queue_tail :
875 &mswindows_s_dispatch_event_queue_tail);
877 /* Avoid blocking on WaitMessage */
878 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
882 * Add a misc-user event to the dispatch queue.
884 * Stuff it into our own dispatch queue, so we have something
885 * to return from next_event callback.
888 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
891 Lisp_Object event = Fmake_event (Qnil, Qnil);
892 struct Lisp_Event* e = XEVENT (event);
894 e->event_type = misc_user_event;
895 e->channel = channel;
896 e->event.misc.function = function;
897 e->event.misc.object = object;
899 mswindows_enqueue_dispatch_event (event);
903 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
905 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
906 struct Lisp_Event* event = XEVENT (emacs_event);
908 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
909 event->timestamp = GetMessageTime();
910 event->event_type = magic_event;
911 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
913 mswindows_enqueue_dispatch_event (emacs_event);
917 mswindows_enqueue_process_event (struct Lisp_Process* p)
919 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
920 struct Lisp_Event* event = XEVENT (emacs_event);
922 XSETPROCESS (process, p);
924 event->event_type = process_event;
925 event->timestamp = GetTickCount ();
926 event->event.process.process = process;
928 mswindows_enqueue_dispatch_event (emacs_event);
932 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
935 /* We always use last message time, because mouse button
936 events may get delayed, and XEmacs double click
937 recognition will fail */
939 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
940 struct Lisp_Event* event = XEVENT(emacs_event);
942 event->channel = mswindows_find_frame(hwnd);
943 event->timestamp = when;
944 event->event.button.button =
945 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
946 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
947 event->event.button.x = where.x;
948 event->event.button.y = where.y;
949 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
951 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
952 message==WM_RBUTTONDOWN)
954 event->event_type = button_press_event;
956 /* we need this to make sure the main window regains the focus
957 from control subwindows */
958 if (GetFocus() != hwnd)
961 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
966 event->event_type = button_release_event;
970 mswindows_enqueue_dispatch_event (emacs_event);
974 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
976 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
977 struct Lisp_Event* event = XEVENT(emacs_event);
979 event->channel = mswindows_find_console(hwnd);
980 event->timestamp = GetMessageTime();
981 event->event_type = key_press_event;
982 event->event.key.keysym = keysym;
983 event->event.key.modifiers = mods;
984 mswindows_enqueue_dispatch_event (emacs_event);
988 * Remove and return the first emacs event on the dispatch queue.
989 * Give a preference to user events over non-user ones.
992 mswindows_dequeue_dispatch_event ()
995 struct Lisp_Event* sevt;
997 assert (!NILP(mswindows_u_dispatch_event_queue) ||
998 !NILP(mswindows_s_dispatch_event_queue));
1000 event = dequeue_event (
1001 NILP(mswindows_u_dispatch_event_queue) ?
1002 &mswindows_s_dispatch_event_queue :
1003 &mswindows_u_dispatch_event_queue,
1004 NILP(mswindows_u_dispatch_event_queue) ?
1005 &mswindows_s_dispatch_event_queue_tail :
1006 &mswindows_u_dispatch_event_queue_tail);
1008 sevt = XEVENT(event);
1009 if (sevt->event_type == key_press_event
1010 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1012 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1013 --mswindows_quit_chars_count;
1020 * Remove and return the first emacs event on the dispatch queue that matches
1021 * the supplied event.
1022 * Timeout event matches if interval_id is equal to that of the given event.
1023 * Keypress event matches if logical AND between modifiers bitmask of the
1024 * event in the queue and that of the given event is non-zero.
1025 * For all other event types, this function aborts.
1029 mswindows_cancel_dispatch_event (struct Lisp_Event *match)
1032 Lisp_Object previous_event = Qnil;
1033 int user_p = mswindows_user_event_p (match);
1034 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1035 &mswindows_s_dispatch_event_queue;
1036 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1037 &mswindows_s_dispatch_event_queue_tail;
1039 assert (match->event_type == timeout_event
1040 || match->event_type == key_press_event);
1042 EVENT_CHAIN_LOOP (event, *head)
1044 struct Lisp_Event *e = XEVENT (event);
1045 if ((e->event_type == match->event_type) &&
1046 ((e->event_type == timeout_event) ?
1047 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1048 /* Must be key_press_event */
1049 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1051 if (NILP (previous_event))
1052 dequeue_event (head, tail);
1055 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1056 if (EQ (*tail, event))
1057 *tail = previous_event;
1062 previous_event = event;
1067 #ifndef HAVE_MSG_SELECT
1068 /************************************************************************/
1069 /* Waitable handles manipulation */
1070 /************************************************************************/
1072 find_waitable_handle (HANDLE h)
1075 for (i = 0; i < mswindows_waitable_count; ++i)
1076 if (mswindows_waitable_handles[i] == h)
1083 add_waitable_handle (HANDLE h)
1085 assert (find_waitable_handle (h) < 0);
1086 if (mswindows_waitable_count == MAX_WAITABLE)
1089 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1094 remove_waitable_handle (HANDLE h)
1096 int ix = find_waitable_handle (h);
1100 mswindows_waitable_handles [ix] =
1101 mswindows_waitable_handles [--mswindows_waitable_count];
1103 #endif /* HAVE_MSG_SELECT */
1106 /************************************************************************/
1108 /************************************************************************/
1111 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1112 Lisp_Object u_n_u_s_e_d)
1114 mswindows_error_caught_in_modal_loop = cons_sig_data;
1119 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1124 ++mswindows_in_modal_loop;
1125 tmp = condition_case_1 (Qt,
1127 mswindows_modal_loop_error_handler, Qnil);
1128 --mswindows_in_modal_loop;
1134 mswindows_unmodalize_signal_maybe (void)
1136 if (!NILP (mswindows_error_caught_in_modal_loop))
1138 /* Got an error while messages were pumped while
1139 in window procedure - have to resignal */
1140 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1141 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1142 mswindows_error_caught_in_modal_loop = Qnil;
1143 Fsignal (sym, data);
1148 * This is an unsafe part of event pump, guarded by
1149 * condition_case. See mswindows_pump_outstanding_events
1152 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1154 /* This function can call lisp */
1155 Lisp_Object event = Fmake_event (Qnil, Qnil);
1156 struct gcpro gcpro1;
1157 int do_redisplay = 0;
1160 while (detect_input_pending ())
1162 Fnext_event (event, Qnil);
1163 Fdispatch_event (event);
1170 Fdeallocate_event (event);
1173 /* Qt becomes return value of mswindows_pump_outstanding_events
1179 * This function pumps emacs events, while available, by using
1180 * next_message/dispatch_message loop. Errors are trapped around
1181 * the loop so the function always returns.
1183 * Windows message queue is not looked into during the call,
1184 * neither are waitable handles checked. The function pumps
1185 * thus only dispatch events already queued, as well as those
1186 * resulted in dispatching thereof. This is done by setting
1187 * module local variable mswindows_in_modal_loop to nonzero.
1189 * Return value is Qt if no errors was trapped, or Qunbound if
1190 * there was an error.
1192 * In case of error, a cons representing the error, in the
1193 * form (SIGNAL . DATA), is stored in the module local variable
1194 * mswindows_error_caught_in_modal_loop. This error is signaled
1195 * again when DispatchMessage returns. Thus, Windows internal
1196 * modal loops are protected against throws, which are proven
1197 * to corrupt internal Windows structures.
1199 * In case of success, mswindows_error_caught_in_modal_loop is
1202 * If the value of mswindows_error_caught_in_modal_loop is not
1203 * nil already upon entry, the function just returns non-nil.
1204 * This situation means that a new event has been queued while
1205 * in cancel mode. The event will be dequeued on the next regular
1206 * call of next-event; the pump is off since error is caught.
1207 * The caller must *unconditionally* cancel modal loop if the
1208 * value returned by this function is nil. Otherwise, everything
1209 * will become frozen until the modal loop exits under normal
1210 * condition (scrollbar drag is released, menu closed etc.)
1213 mswindows_pump_outstanding_events (void)
1215 /* This function can call lisp */
1217 Lisp_Object result = Qt;
1218 struct gcpro gcpro1;
1221 if (NILP(mswindows_error_caught_in_modal_loop))
1222 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1228 mswindows_drain_windows_queue ()
1231 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1233 /* we have to translate messages that are not sent to the main
1234 window. this is so that key presses work ok in things like
1235 edit fields. however, we *musn't* translate message for the
1236 main window as this is handled in the wnd proc. */
1237 if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
1239 TranslateMessage (&msg);
1241 DispatchMessage (&msg);
1242 mswindows_unmodalize_signal_maybe ();
1247 * This is a special flavor of the mswindows_need_event function,
1248 * used while in event pump. Actually, there is only kind of events
1249 * allowed while in event pump: a timer. An attempt to fetch any
1250 * other event leads to a deadlock, as there's no source of user input
1251 * ('cause event pump mirrors windows modal loop, which is a sole
1252 * owner of thread message queue).
1254 * To detect this, we use a counter of active timers, and allow
1255 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1256 * which will never come when there are no pending timers, which leads
1257 * to deadlock, we simply signal an error.
1260 mswindows_need_event_in_modal_loop (int badly_p)
1264 /* Check if already have one */
1265 if (!NILP (mswindows_u_dispatch_event_queue)
1266 || !NILP (mswindows_s_dispatch_event_queue))
1269 /* No event is ok */
1273 /* We do not check the _u_ queue, because timers go to _s_ */
1274 while (NILP (mswindows_s_dispatch_event_queue))
1276 /* We'll deadlock if go waiting */
1277 if (mswindows_pending_timers_count == 0)
1278 error ("Deadlock due to an attempt to call next-event in a wrong context");
1280 /* Fetch and dispatch any pending timers */
1281 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1282 DispatchMessage (&msg);
1287 * This drains the event queue and fills up two internal queues until
1288 * an event of a type specified by USER_P is retrieved.
1291 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1294 mswindows_need_event (int badly_p)
1298 if (mswindows_in_modal_loop)
1300 mswindows_need_event_in_modal_loop (badly_p);
1304 /* Have to drain Windows message queue first, otherwise, we may miss
1305 quit char when called from quit_p */
1306 mswindows_drain_windows_queue ();
1308 while (NILP (mswindows_u_dispatch_event_queue)
1309 && NILP (mswindows_s_dispatch_event_queue))
1311 #ifdef HAVE_MSG_SELECT
1313 SELECT_TYPE temp_mask = input_wait_mask;
1314 EMACS_TIME sometime;
1315 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1318 pointer_to_this = 0;
1321 EMACS_SET_SECS_USECS (sometime, 0, 0);
1322 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1323 pointer_to_this = &select_time_to_block;
1326 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1331 return; /* timeout */
1333 else if (active > 0)
1335 if (FD_ISSET (windows_fd, &temp_mask))
1337 mswindows_drain_windows_queue ();
1340 /* Look for a TTY event */
1341 for (i = 0; i < MAXDESC-1; i++)
1343 /* To avoid race conditions (among other things, an infinite
1344 loop when called from Fdiscard_input()), we must return
1345 user events ahead of process events. */
1346 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1348 struct console *c = tty_find_console_from_fd (i);
1349 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1350 struct Lisp_Event* event = XEVENT (emacs_event);
1353 if (read_event_from_tty_or_stream_desc (event, c, i))
1355 mswindows_enqueue_dispatch_event (emacs_event);
1361 /* Look for a process event */
1362 for (i = 0; i < MAXDESC-1; i++)
1364 if (FD_ISSET (i, &temp_mask))
1366 if (FD_ISSET (i, &process_only_mask))
1368 struct Lisp_Process *p =
1369 get_process_from_usid (FD_TO_USID(i));
1371 mswindows_enqueue_process_event (p);
1375 /* We might get here when a fake event came
1376 through a signal. Return a dummy event, so
1377 that a cycle of the command loop will
1379 drain_signal_event_pipe ();
1380 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1385 else if (active==-1)
1389 /* something bad happened */
1398 /* Now try getting a message or process event */
1399 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1400 mswindows_waitable_handles,
1401 FALSE, badly_p ? INFINITE : 0,
1404 /* This will assert if handle being waited for becomes abandoned.
1405 Not the case currently tho */
1406 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1407 (active >= WAIT_OBJECT_0 &&
1408 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1410 if (active == WAIT_TIMEOUT)
1412 /* No luck trying - just return what we've already got */
1415 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1417 /* Got your message, thanks */
1418 mswindows_drain_windows_queue ();
1422 int ix = active - WAIT_OBJECT_0;
1423 /* First, try to find which process' output has signaled */
1424 struct Lisp_Process *p =
1425 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1428 /* Found a signaled process input handle */
1429 mswindows_enqueue_process_event (p);
1433 /* None. This means that the process handle itself has signaled.
1434 Remove the handle from the wait vector, and make status_notify
1435 note the exited process */
1436 mswindows_waitable_handles [ix] =
1437 mswindows_waitable_handles [--mswindows_waitable_count];
1438 kick_status_notify ();
1439 /* Have to return something: there may be no accompanying
1441 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1448 /************************************************************************/
1449 /* Event generators */
1450 /************************************************************************/
1453 * Callback procedure for synchronous timer messages
1455 static void CALLBACK
1456 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1458 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1459 struct Lisp_Event *event = XEVENT (emacs_event);
1461 if (KillTimer (NULL, id_timer))
1462 --mswindows_pending_timers_count;
1464 event->channel = Qnil;
1465 event->timestamp = dwtime;
1466 event->event_type = timeout_event;
1467 event->event.timeout.interval_id = id_timer;
1468 event->event.timeout.function = Qnil;
1469 event->event.timeout.object = Qnil;
1471 mswindows_enqueue_dispatch_event (emacs_event);
1475 * Callback procedure for dde messages
1477 * We execute a dde Open("file") by simulating a file drop, so dde support
1478 * depends on dnd support.
1480 #ifdef HAVE_DRAGNDROP
1482 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1483 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1484 DWORD dwData1, DWORD dwData2)
1489 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1490 return (HDDEDATA)TRUE;
1491 return (HDDEDATA)FALSE;
1493 case XTYP_WILDCONNECT:
1495 /* We only support one {service,topic} pair */
1496 HSZPAIR pairs[2] = {
1497 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1499 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1500 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1501 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1502 sizeof (pairs), 0L, 0, uFmt, 0));
1504 return (HDDEDATA)NULL;
1507 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1509 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1510 char *cmd = alloca (len+1);
1513 struct gcpro gcpro1, gcpro2;
1514 Lisp_Object l_dndlist = Qnil;
1515 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1516 Lisp_Object frmcons, devcons, concons;
1517 struct Lisp_Event *event = XEVENT (emacs_event);
1519 DdeGetData (hdata, cmd, len, 0);
1521 DdeFreeDataHandle (hdata);
1523 /* Check syntax & that it's an [Open("foo")] command, which we
1524 * treat like a file drop */
1525 /* #### Ought to be generalised and accept some other commands */
1528 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1529 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1530 return DDE_FNOTPROCESSED;
1531 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1534 if (*cmd!='(' || *(cmd+1)!='\"')
1535 return DDE_FNOTPROCESSED;
1537 while (*end && *end!='\"')
1540 return DDE_FNOTPROCESSED;
1543 return DDE_FNOTPROCESSED;
1547 return DDE_FNOTPROCESSED;
1550 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1551 strcpy (filename, "file:");
1552 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1554 dostounix_filename (cmd);
1555 filename = alloca (strlen (cmd)+6);
1556 strcpy (filename, "file:");
1557 strcat (filename, cmd);
1559 GCPRO2 (emacs_event, l_dndlist);
1560 l_dndlist = make_string (filename, strlen (filename));
1562 /* Find a mswindows frame */
1563 event->channel = Qnil;
1564 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1566 Lisp_Object frame = XCAR (frmcons);
1567 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1568 event->channel = frame;
1570 assert (!NILP (event->channel));
1572 event->timestamp = GetTickCount();
1573 event->event_type = misc_user_event;
1574 event->event.misc.button = 1;
1575 event->event.misc.modifiers = 0;
1576 event->event.misc.x = -1;
1577 event->event.misc.y = -1;
1578 event->event.misc.function = Qdragdrop_drop_dispatch;
1579 event->event.misc.object = Fcons (Qdragdrop_URL,
1580 Fcons (l_dndlist, Qnil));
1581 mswindows_enqueue_dispatch_event (emacs_event);
1583 return (HDDEDATA) DDE_FACK;
1585 DdeFreeDataHandle (hdata);
1586 return (HDDEDATA) DDE_FNOTPROCESSED;
1589 return (HDDEDATA) NULL;
1595 * The windows procedure for the window class XEMACS_CLASS
1598 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1600 /* Note: Remember to initialize emacs_event and event before use.
1601 This code calls code that can GC. You must GCPRO before calling such code. */
1602 Lisp_Object emacs_event = Qnil;
1603 Lisp_Object fobj = Qnil;
1605 struct Lisp_Event *event;
1606 struct frame *frame;
1607 struct mswindows_frame* msframe;
1612 /* Erase background only during non-dynamic sizing */
1613 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1614 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1619 fobj = mswindows_find_frame (hwnd);
1620 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1625 /* See Win95 comment under WM_KEYDOWN */
1629 if (wParam == VK_CONTROL)
1631 GetKeyboardState (keymap);
1632 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1633 SetKeyboardState (keymap);
1635 else if (wParam == VK_MENU)
1637 GetKeyboardState (keymap);
1638 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1639 SetKeyboardState (keymap);
1646 /* In some locales the right-hand Alt key is labelled AltGr. This key
1647 * should produce alternative charcaters when combined with another key.
1648 * eg on a German keyboard pressing AltGr+q should produce '@'.
1649 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1650 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1651 * it translates as if AltGr were down.
1652 * We get round this by removing all modifiers from the keymap before
1653 * calling TranslateMessage() unless AltGr is *really* down. */
1656 int has_AltGr = mswindows_current_layout_has_AltGr ();
1660 GetKeyboardState (keymap);
1661 mods = mswindows_modifier_state (keymap, has_AltGr);
1663 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1664 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1665 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1668 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1669 BYTE keymap_orig[256];
1670 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1674 msg.message = message;
1675 msg.wParam = wParam;
1676 msg.lParam = lParam;
1677 msg.time = GetMessageTime();
1680 /* GetKeyboardState() does not work as documented on Win95. We have
1681 * to loosely track Left and Right modifiers on behalf of the OS,
1682 * without screwing up Windows NT which tracks them properly. */
1683 if (wParam == VK_CONTROL)
1684 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1685 else if (wParam == VK_MENU)
1686 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1688 memcpy (keymap_orig, keymap, 256);
1690 /* Remove shift modifier from an ascii character */
1693 /* Clear control and alt modifiers unless AltGr is pressed */
1694 keymap [VK_RCONTROL] = 0;
1695 keymap [VK_LMENU] = 0;
1696 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1698 keymap [VK_LCONTROL] = 0;
1699 keymap [VK_CONTROL] = 0;
1700 keymap [VK_RMENU] = 0;
1701 keymap [VK_MENU] = 0;
1703 SetKeyboardState (keymap);
1705 /* Maybe generate some WM_[SYS]CHARs in the queue */
1706 TranslateMessage (&msg);
1708 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1709 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1712 WPARAM ch = msg.wParam;
1714 /* If a quit char with no modifiers other than control and
1715 shift, then mark it with a fake modifier, which is removed
1716 upon dequeueing the event */
1717 /* #### This might also not withstand localization, if
1718 quit character is not a latin-1 symbol */
1719 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1720 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1721 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1723 mods1 |= FAKE_MOD_QUIT;
1724 ++mswindows_quit_chars_count;
1727 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1729 SetKeyboardState (keymap_orig);
1732 /* F10 causes menu activation by default. We do not want this */
1733 if (wParam != VK_F10)
1737 case WM_MBUTTONDOWN:
1739 /* Real middle mouse button has nothing to do with emulated one:
1740 if one wants to exercise fingers playing chords on the mouse,
1741 he is allowed to do that! */
1742 mswindows_enqueue_mouse_button_event (hwnd, message,
1743 MAKEPOINTS (lParam), GetMessageTime());
1747 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1748 msframe->last_click_time = GetMessageTime();
1750 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1751 msframe->button2_need_lbutton = 0;
1752 if (msframe->ignore_next_lbutton_up)
1754 msframe->ignore_next_lbutton_up = 0;
1756 else if (msframe->button2_is_down)
1758 msframe->button2_is_down = 0;
1759 msframe->ignore_next_rbutton_up = 1;
1760 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1761 MAKEPOINTS (lParam), GetMessageTime());
1765 if (msframe->button2_need_rbutton)
1767 msframe->button2_need_rbutton = 0;
1768 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1769 MAKEPOINTS (lParam), GetMessageTime());
1771 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1772 MAKEPOINTS (lParam), GetMessageTime());
1777 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1778 msframe->last_click_time = GetMessageTime();
1780 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1781 msframe->button2_need_rbutton = 0;
1782 if (msframe->ignore_next_rbutton_up)
1784 msframe->ignore_next_rbutton_up = 0;
1786 else if (msframe->button2_is_down)
1788 msframe->button2_is_down = 0;
1789 msframe->ignore_next_lbutton_up = 1;
1790 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1791 MAKEPOINTS (lParam), GetMessageTime());
1795 if (msframe->button2_need_lbutton)
1797 msframe->button2_need_lbutton = 0;
1798 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1799 MAKEPOINTS (lParam), GetMessageTime());
1801 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1802 MAKEPOINTS (lParam), GetMessageTime());
1806 case WM_LBUTTONDOWN:
1807 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1809 if (msframe->button2_need_lbutton)
1811 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1812 msframe->button2_need_lbutton = 0;
1813 msframe->button2_need_rbutton = 0;
1814 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1816 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1817 MAKEPOINTS (lParam), GetMessageTime());
1818 msframe->button2_is_down = 1;
1822 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1823 msframe->last_click_point, msframe->last_click_time);
1824 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1825 MAKEPOINTS (lParam), GetMessageTime());
1830 mswindows_set_chord_timer (hwnd);
1831 msframe->button2_need_rbutton = 1;
1832 msframe->last_click_point = MAKEPOINTS (lParam);
1834 msframe->last_click_time = GetMessageTime();
1837 case WM_RBUTTONDOWN:
1838 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1840 if (msframe->button2_need_rbutton)
1842 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1843 msframe->button2_need_lbutton = 0;
1844 msframe->button2_need_rbutton = 0;
1845 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1847 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1848 MAKEPOINTS (lParam), GetMessageTime());
1849 msframe->button2_is_down = 1;
1853 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1854 msframe->last_click_point, msframe->last_click_time);
1855 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1856 MAKEPOINTS (lParam), GetMessageTime());
1861 mswindows_set_chord_timer (hwnd);
1862 msframe->button2_need_lbutton = 1;
1863 msframe->last_click_point = MAKEPOINTS (lParam);
1865 msframe->last_click_time = GetMessageTime();
1869 if (wParam == BUTTON_2_TIMER_ID)
1871 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1872 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1874 if (msframe->button2_need_lbutton)
1876 msframe->button2_need_lbutton = 0;
1877 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1878 msframe->last_click_point, msframe->last_click_time);
1880 else if (msframe->button2_need_rbutton)
1882 msframe->button2_need_rbutton = 0;
1883 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1884 msframe->last_click_point, msframe->last_click_time);
1888 assert ("Spurious timer fired" == 0);
1892 /* Optimization: don't report mouse movement while size is changing */
1893 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1894 if (!msframe->sizing)
1896 /* When waiting for the second mouse button to finish
1897 button2 emulation, and have moved too far, just pretend
1898 as if timer has expired. This improves drag-select feedback */
1899 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1900 && !mswindows_button2_near_enough (msframe->last_click_point,
1901 MAKEPOINTS (lParam)))
1903 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1904 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1907 emacs_event = Fmake_event (Qnil, Qnil);
1908 event = XEVENT(emacs_event);
1910 event->channel = mswindows_find_frame(hwnd);
1911 event->timestamp = GetMessageTime();
1912 event->event_type = pointer_motion_event;
1913 event->event.motion.x = MAKEPOINTS(lParam).x;
1914 event->event.motion.y = MAKEPOINTS(lParam).y;
1915 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1917 mswindows_enqueue_dispatch_event (emacs_event);
1923 /* Queue a `cancel-mode-internal' misc user event, so mouse
1924 selection would be canceled if any */
1925 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1926 Qcancel_mode_internal, Qnil);
1931 LPNMHDR nmhdr = (LPNMHDR)lParam;
1932 int idCtrl = (int)wParam;
1934 if (nmhdr->code == TTN_NEEDTEXT)
1936 #ifdef HAVE_TOOLBARS
1937 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1940 /* find out which toolbar */
1941 frame = XFRAME (mswindows_find_frame (hwnd));
1942 btext = mswindows_get_toolbar_button_text ( frame,
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,
1957 /* handle tree view callbacks */
1958 else if (nmhdr->code == TVN_SELCHANGED)
1960 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
1961 frame = XFRAME (mswindows_find_frame (hwnd));
1962 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
1964 /* handle tab control callbacks */
1965 else if (nmhdr->code == TCN_SELCHANGE)
1968 int index = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
1969 frame = XFRAME (mswindows_find_frame (hwnd));
1970 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index,
1973 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
1980 PAINTSTRUCT paintStruct;
1982 frame = XFRAME (mswindows_find_frame (hwnd));
1984 BeginPaint (hwnd, &paintStruct);
1985 mswindows_redraw_exposed_area (frame,
1986 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1987 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1988 EndPaint (hwnd, &paintStruct);
1993 /* We only care about this message if our size has really changed */
1994 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1999 fobj = mswindows_find_frame (hwnd);
2000 frame = XFRAME (fobj);
2001 msframe = FRAME_MSWINDOWS_DATA (frame);
2003 /* We cannot handle frame map and unmap hooks right in
2004 this routine, because these may throw. We queue
2005 magic events to run these hooks instead - kkm */
2007 if (wParam==SIZE_MINIMIZED)
2010 FRAME_VISIBLE_P (frame) = 0;
2011 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2015 GetClientRect(hwnd, &rect);
2016 FRAME_PIXWIDTH(frame) = rect.right;
2017 FRAME_PIXHEIGHT(frame) = rect.bottom;
2019 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2020 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2021 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2023 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2024 change_frame_size (frame, rows, columns, 1);
2026 /* If we are inside frame creation, we have to apply geometric
2028 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2030 /* Yes, we have to size again */
2031 mswindows_size_frame_internal ( frame,
2032 FRAME_MSWINDOWS_TARGET_RECT
2034 /* Reset so we do not get here again. The SetWindowPos call in
2035 * mswindows_size_frame_internal can cause recursion here. */
2036 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2038 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2039 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2044 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2045 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2046 FRAME_VISIBLE_P (frame) = 1;
2048 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2055 /* Misc magic events which only require that the frame be identified */
2058 mswindows_enqueue_magic_event (hwnd, message);
2061 case WM_WINDOWPOSCHANGING:
2063 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2064 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2065 GetWindowPlacement(hwnd, &wpl);
2067 /* Only interested if size is changing and we're not being iconified */
2068 if (wpl.showCmd != SW_SHOWMINIMIZED
2069 && wpl.showCmd != SW_SHOWMAXIMIZED
2070 && !(wp->flags & SWP_NOSIZE))
2072 RECT ncsize = { 0, 0, 0, 0 };
2073 int pixwidth, pixheight;
2074 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2075 GetMenu(hwnd) != NULL,
2076 GetWindowLong (hwnd, GWL_EXSTYLE));
2078 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2079 wp->cx - (ncsize.right - ncsize.left),
2080 wp->cy - (ncsize.bottom - ncsize.top),
2081 &pixwidth, &pixheight);
2083 /* Convert client sizes to window sizes */
2084 pixwidth += (ncsize.right - ncsize.left);
2085 pixheight += (ncsize.bottom - ncsize.top);
2087 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2089 /* Adjust so that the bottom or right doesn't move if it's
2090 * the top or left that's being changed */
2092 GetWindowRect (hwnd, &rect);
2094 if (rect.left != wp->x)
2095 wp->x += wp->cx - pixwidth;
2096 if (rect.top != wp->y)
2097 wp->y += wp->cy - pixheight;
2103 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2104 window position if the user tries to track window too small */
2108 case WM_ENTERSIZEMOVE:
2109 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2110 msframe->sizing = 1;
2113 case WM_EXITSIZEMOVE:
2114 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2115 msframe->sizing = 0;
2116 /* Queue noop event */
2117 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2120 #ifdef HAVE_SCROLLBARS
2124 /* Direction of scroll is determined by scrollbar instance. */
2125 int code = (int) LOWORD(wParam);
2126 int pos = (short int) HIWORD(wParam);
2127 HWND hwndScrollBar = (HWND) lParam;
2128 struct gcpro gcpro1, gcpro2;
2130 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2131 GCPRO2 (emacs_event, fobj);
2132 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2134 /* Error during event pumping - cancel scroll */
2135 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2142 #ifdef HAVE_MENUBARS
2144 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2146 XFRAME (mswindows_find_frame (hwnd)))))
2147 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2150 case WM_INITMENUPOPUP:
2151 if (!HIWORD(lParam))
2153 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2155 XFRAME (mswindows_find_frame (hwnd)))))
2156 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2160 #endif /* HAVE_MENUBARS */
2164 WORD id = LOWORD (wParam);
2165 WORD nid = HIWORD (wParam);
2166 HWND cid = (HWND)lParam;
2167 frame = XFRAME (mswindows_find_frame (hwnd));
2169 #ifdef HAVE_TOOLBARS
2170 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2173 /* widgets in a buffer only eval a callback for suitable events.*/
2178 case CBN_EDITCHANGE:
2180 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2183 /* menubars always must come last since the hashtables do not
2185 #ifdef HAVE_MENUBARS
2186 if (!NILP (mswindows_handle_wm_command (frame, id)))
2190 return DefWindowProc (hwnd, message, wParam, lParam);
2191 /* Bite me - a spurious command. This used to not be able to
2192 happen but with the introduction of widgets its now
2197 case WM_CTLCOLORBTN:
2198 case WM_CTLCOLORLISTBOX:
2199 case WM_CTLCOLOREDIT:
2200 case WM_CTLCOLORSTATIC:
2201 case WM_CTLCOLORSCROLLBAR:
2203 /* if we get an opportunity to paint a widget then do so if
2204 there is an appropriate face */
2205 HWND crtlwnd = (HWND)lParam;
2206 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2209 Lisp_Object image_instance;
2210 VOID_TO_LISP (image_instance, ii);
2211 if (IMAGE_INSTANCEP (image_instance)
2213 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
2215 !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
2217 /* set colors for the buttons */
2218 HDC hdc = (HDC)wParam;
2219 if (last_widget_brushed != ii)
2222 DeleteObject (widget_brush);
2223 widget_brush = CreateSolidBrush
2224 (COLOR_INSTANCE_MSWINDOWS_COLOR
2227 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2228 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2230 last_widget_brushed = ii;
2233 COLOR_INSTANCE_MSWINDOWS_COLOR
2236 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2237 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2238 SetBkMode (hdc, OPAQUE);
2241 COLOR_INSTANCE_MSWINDOWS_COLOR
2244 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2245 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2246 return (LRESULT)widget_brush;
2252 #ifdef HAVE_DRAGNDROP
2253 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2255 UINT filecount, i, len;
2261 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2262 struct gcpro gcpro1, gcpro2, gcpro3;
2264 emacs_event = Fmake_event (Qnil, Qnil);
2265 event = XEVENT(emacs_event);
2267 GCPRO3 (emacs_event, l_dndlist, l_item);
2269 if (!DragQueryPoint ((HANDLE) wParam, &point))
2270 point.x = point.y = -1; /* outside client area */
2272 event->event_type = misc_user_event;
2273 event->channel = mswindows_find_frame(hwnd);
2274 event->timestamp = GetMessageTime();
2275 event->event.misc.button = 1; /* #### Should try harder */
2276 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2277 event->event.misc.x = point.x;
2278 event->event.misc.y = point.y;
2279 event->event.misc.function = Qdragdrop_drop_dispatch;
2281 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2282 for (i=0; i<filecount; i++)
2284 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2285 /* The URLs that we make here aren't correct according to section
2286 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2287 * because they may contain reserved characters. But that's OK. */
2289 fname = (char *)xmalloc (len+1);
2290 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2291 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2292 strcpy (filename, "file:");
2293 cygwin32_win32_to_posix_path_list (fname, filename+5);
2296 filename = (char *)xmalloc (len+6);
2297 strcpy (filename, "file:");
2298 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2299 dostounix_filename (filename+5);
2301 l_item = make_string (filename, strlen (filename));
2302 l_dndlist = Fcons (l_item, l_dndlist);
2305 DragFinish ((HANDLE) wParam);
2307 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2308 mswindows_enqueue_dispatch_event (emacs_event);
2316 return DefWindowProc (hwnd, message, wParam, lParam);
2322 /************************************************************************/
2323 /* keyboard, mouse & other helpers for the windows procedure */
2324 /************************************************************************/
2326 mswindows_set_chord_timer (HWND hwnd)
2330 /* We get one third half system double click threshold */
2331 if (mswindows_mouse_button_tolerance <= 0)
2332 interval = GetDoubleClickTime () / 3;
2334 interval = mswindows_mouse_button_tolerance;
2336 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2340 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2343 if (mswindows_mouse_button_max_skew_x <= 0)
2344 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2346 dx = mswindows_mouse_button_max_skew_x;
2348 if (mswindows_mouse_button_max_skew_y <= 0)
2349 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2351 dy = mswindows_mouse_button_max_skew_y;
2353 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2357 mswindows_current_layout_has_AltGr (void)
2359 /* This simple caching mechanism saves 10% of CPU
2360 time when a key typed at autorepeat rate of 30 cps! */
2361 static HKL last_hkl = 0;
2362 static int last_hkl_has_AltGr;
2364 HKL current_hkl = GetKeyboardLayout (0);
2365 if (current_hkl != last_hkl)
2368 last_hkl_has_AltGr = 0;
2369 /* In this loop, we query whether a character requires
2370 AltGr to be down to generate it. If at least such one
2371 found, this means that the layout does regard AltGr */
2372 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2373 if (HIBYTE (VkKeyScan (c)) == 6)
2374 last_hkl_has_AltGr = 1;
2375 last_hkl = current_hkl;
2377 return last_hkl_has_AltGr;
2381 /* Returns the state of the modifier keys in the format expected by the
2382 * Lisp_Event key_data, button_data and motion_data modifiers member */
2383 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2389 keymap = (BYTE*) alloca(256);
2390 GetKeyboardState (keymap);
2391 has_AltGr = mswindows_current_layout_has_AltGr ();
2394 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2396 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2397 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2401 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2402 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2405 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2411 * Translate a mswindows virtual key to a keysym.
2412 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2413 * or whose ASCII codes (like space) xemacs doesn't like.
2414 * Virtual key values are defined in winresrc.h
2415 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2417 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2419 switch (mswindows_key)
2421 /* First the predefined ones */
2422 case VK_BACK: return QKbackspace;
2423 case VK_TAB: return QKtab;
2424 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2425 case VK_RETURN: return QKreturn;
2426 case VK_ESCAPE: return QKescape;
2427 case VK_SPACE: return QKspace;
2428 case VK_DELETE: return QKdelete;
2431 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2432 case VK_PRIOR: return KEYSYM ("prior");
2433 case VK_NEXT: return KEYSYM ("next");
2434 case VK_END: return KEYSYM ("end");
2435 case VK_HOME: return KEYSYM ("home");
2436 case VK_LEFT: return KEYSYM ("left");
2437 case VK_UP: return KEYSYM ("up");
2438 case VK_RIGHT: return KEYSYM ("right");
2439 case VK_DOWN: return KEYSYM ("down");
2440 case VK_SELECT: return KEYSYM ("select");
2441 case VK_PRINT: return KEYSYM ("print");
2442 case VK_EXECUTE: return KEYSYM ("execute");
2443 case VK_SNAPSHOT: return KEYSYM ("print");
2444 case VK_INSERT: return KEYSYM ("insert");
2445 case VK_HELP: return KEYSYM ("help");
2446 #if 0 /* XXX What are these supposed to do? */
2447 case VK_LWIN return KEYSYM ("");
2448 case VK_RWIN return KEYSYM ("");
2450 case VK_APPS: return KEYSYM ("menu");
2451 case VK_F1: return KEYSYM ("f1");
2452 case VK_F2: return KEYSYM ("f2");
2453 case VK_F3: return KEYSYM ("f3");
2454 case VK_F4: return KEYSYM ("f4");
2455 case VK_F5: return KEYSYM ("f5");
2456 case VK_F6: return KEYSYM ("f6");
2457 case VK_F7: return KEYSYM ("f7");
2458 case VK_F8: return KEYSYM ("f8");
2459 case VK_F9: return KEYSYM ("f9");
2460 case VK_F10: return KEYSYM ("f10");
2461 case VK_F11: return KEYSYM ("f11");
2462 case VK_F12: return KEYSYM ("f12");
2463 case VK_F13: return KEYSYM ("f13");
2464 case VK_F14: return KEYSYM ("f14");
2465 case VK_F15: return KEYSYM ("f15");
2466 case VK_F16: return KEYSYM ("f16");
2467 case VK_F17: return KEYSYM ("f17");
2468 case VK_F18: return KEYSYM ("f18");
2469 case VK_F19: return KEYSYM ("f19");
2470 case VK_F20: return KEYSYM ("f20");
2471 case VK_F21: return KEYSYM ("f21");
2472 case VK_F22: return KEYSYM ("f22");
2473 case VK_F23: return KEYSYM ("f23");
2474 case VK_F24: return KEYSYM ("f24");
2480 * Find the console that matches the supplied mswindows window handle
2483 mswindows_find_console (HWND hwnd)
2485 /* We only support one console */
2486 return XCAR (Vconsole_list);
2490 * Find the frame that matches the supplied mswindows window handle
2493 mswindows_find_frame (HWND hwnd)
2495 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2499 /* We are in progress of frame creation. Return the frame
2500 being created, as it still not remembered in the window
2502 assert (!NILP (Vmswindows_frame_being_created));
2503 return Vmswindows_frame_being_created;
2505 VOID_TO_LISP (f, l);
2510 /************************************************************************/
2512 /************************************************************************/
2515 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2518 EMACS_TIME current_time;
2519 EMACS_GET_TIME (current_time);
2520 EMACS_SUB_TIME (thyme, thyme, current_time);
2521 milliseconds = EMACS_SECS (thyme) * 1000 +
2522 (EMACS_USECS (thyme) + 500) / 1000;
2523 if (milliseconds < 1)
2525 ++mswindows_pending_timers_count;
2526 return SetTimer (NULL, 0, milliseconds,
2527 (TIMERPROC) mswindows_wm_timer_callback);
2531 emacs_mswindows_remove_timeout (int id)
2533 struct Lisp_Event match_against;
2534 Lisp_Object emacs_event;
2536 if (KillTimer (NULL, id))
2537 --mswindows_pending_timers_count;
2539 /* If there is a dispatch event generated by this
2540 timeout in the queue, we have to remove it too. */
2541 match_against.event_type = timeout_event;
2542 match_against.event.timeout.interval_id = id;
2543 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2544 if (!NILP (emacs_event))
2545 Fdeallocate_event(emacs_event);
2548 /* If `user_p' is false, then return whether there are any win32, timeout,
2549 * or subprocess events pending (that is, whether
2550 * emacs_mswindows_next_event() would return immediately without blocking).
2552 * if `user_p' is true, then return whether there are any *user generated*
2553 * events available (that is, whether there are keyboard or mouse-click
2554 * events ready to be read). This also implies that
2555 * emacs_mswindows_next_event() would not block.
2558 emacs_mswindows_event_pending_p (int user_p)
2560 mswindows_need_event (0);
2561 return (!NILP (mswindows_u_dispatch_event_queue)
2562 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2566 * Return the next event
2569 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2571 Lisp_Object event, event2;
2573 mswindows_need_event (1);
2575 event = mswindows_dequeue_dispatch_event ();
2576 XSETEVENT (event2, emacs_event);
2577 Fcopy_event (event, event2);
2578 Fdeallocate_event (event);
2582 * Handle a magic event off the dispatch queue.
2585 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2587 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2595 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2596 struct frame *f = XFRAME (frame);
2597 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2600 /* struct gcpro gcpro1; */
2602 /* Clear sticky modifiers here (if we had any) */
2604 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2605 /* GCPRO1 (conser); XXX Not necessary? */
2606 emacs_handle_focus_change_preliminary (conser);
2607 /* Under X the stuff up to here is done in the X event handler.
2609 emacs_handle_focus_change_final (conser);
2618 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2619 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2621 Qmap_frame_hook : Qunmap_frame_hook,
2626 /* #### What about Enter & Leave */
2628 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2629 Qmouse_leave_frame_hook, 1, frame);
2637 #ifndef HAVE_MSG_SELECT
2639 get_process_input_waitable (struct Lisp_Process *process)
2641 Lisp_Object instr, outstr, p;
2642 XSETPROCESS (p, process);
2643 get_process_streams (process, &instr, &outstr);
2644 assert (!NILP (instr));
2645 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2646 return (network_connection_p (p)
2647 ? get_winsock_stream_waitable (XLSTREAM (instr))
2648 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2650 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2655 emacs_mswindows_select_process (struct Lisp_Process *process)
2657 HANDLE hev = get_process_input_waitable (process);
2659 if (!add_waitable_handle (hev))
2660 error ("Too many active processes");
2662 #ifdef HAVE_WIN32_PROCESSES
2665 XSETPROCESS (p, process);
2666 if (!network_connection_p (p))
2668 HANDLE hprocess = get_nt_process_handle (process);
2669 if (!add_waitable_handle (hprocess))
2671 remove_waitable_handle (hev);
2672 error ("Too many active processes");
2680 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2682 /* Process handle is removed in the event loop as soon
2683 as it is signaled, so don't bother here about it */
2684 HANDLE hev = get_process_input_waitable (process);
2685 remove_waitable_handle (hev);
2687 #endif /* HAVE_MSG_SELECT */
2690 emacs_mswindows_select_console (struct console *con)
2692 #ifdef HAVE_MSG_SELECT
2693 if (CONSOLE_MSWINDOWS_P (con))
2694 return; /* mswindows consoles are automatically selected */
2696 event_stream_unixoid_select_console (con);
2701 emacs_mswindows_unselect_console (struct console *con)
2703 #ifdef HAVE_MSG_SELECT
2704 if (CONSOLE_MSWINDOWS_P (con))
2705 return; /* mswindows consoles are automatically selected */
2707 event_stream_unixoid_unselect_console (con);
2712 emacs_mswindows_quit_p (void)
2716 /* Quit cannot happen in modal loop: all program
2717 input is dedicated to Windows. */
2718 if (mswindows_in_modal_loop)
2721 /* Drain windows queue. This sets up number of quit characters in the queue
2722 * (and also processes wm focus change, move, resize, etc messages).
2723 * We don't want to process WM_PAINT messages because this function can be
2724 * called from almost anywhere and the windows' states may be changing. */
2725 while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
2726 PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
2727 DispatchMessage (&msg);
2729 if (mswindows_quit_chars_count > 0)
2731 /* Yes there's a hidden one... Throw it away */
2732 struct Lisp_Event match_against;
2733 Lisp_Object emacs_event;
2735 match_against.event_type = key_press_event;
2736 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2738 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2739 assert (!NILP (emacs_event));
2741 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2744 Fdeallocate_event(emacs_event);
2745 --mswindows_quit_chars_count;
2750 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2751 Lisp_Object* instream,
2752 Lisp_Object* outstream,
2755 /* Handles for streams */
2757 /* fds. These just stored along with the streams, and are closed in
2758 delete stream pair method, because we need to handle fake unices
2762 /* Decode inhandle and outhandle. Their meaning depends on
2763 the process implementation being used. */
2764 #if defined (HAVE_WIN32_PROCESSES)
2765 /* We're passed in Windows handles. That's what we like most... */
2766 hin = (HANDLE) inhandle;
2767 hout = (HANDLE) outhandle;
2769 #elif defined (HAVE_UNIX_PROCESSES)
2770 /* We are passed UNIX fds. This must be Cygwin.
2772 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2773 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2777 #error "So, WHICH kind of processes do you want?"
2780 *instream = (hin == INVALID_HANDLE_VALUE
2782 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2783 : flags & STREAM_NETWORK_CONNECTION
2784 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2786 : make_ntpipe_input_stream (hin, fdi));
2788 #ifdef HAVE_WIN32_PROCESSES
2789 *outstream = (hout == INVALID_HANDLE_VALUE
2791 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2792 : flags & STREAM_NETWORK_CONNECTION
2793 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2795 : make_ntpipe_output_stream (hout, fdo));
2796 #elif defined (HAVE_UNIX_PROCESSES)
2797 *outstream = (fdo >= 0
2798 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2801 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2802 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2803 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2805 Bufbyte eof_char = get_eof_char (fdo);
2806 int pty_max_bytes = get_pty_max_bytes (fdo);
2807 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2812 return (NILP (*instream)
2814 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2815 : flags & STREAM_NETWORK_CONNECTION
2816 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2818 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2822 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2823 Lisp_Object outstream)
2825 /* Oh nothing special here for Win32 at all */
2826 #if defined (HAVE_UNIX_PROCESSES)
2827 int in = (NILP(instream)
2829 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2830 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2831 ? get_winsock_stream_param (XLSTREAM (instream))
2833 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2834 int out = (NILP(outstream) ? -1
2835 : filedesc_stream_fd (XLSTREAM (outstream)));
2839 if (out != in && out >= 0)
2843 return (NILP (instream)
2845 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2846 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2847 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2849 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2852 #ifndef HAVE_X_WINDOWS
2853 /* This is called from GC when a process object is about to be freed.
2854 If we've still got pointers to it in this file, we're gonna lose hard.
2857 debug_process_finalization (struct Lisp_Process *p)
2860 Lisp_Object instr, outstr;
2862 get_process_streams (p, &instr, &outstr);
2863 /* if it still has fds, then it hasn't been killed yet. */
2864 assert (NILP(instr));
2865 assert (NILP(outstr));
2867 /* #### More checks here */
2872 /************************************************************************/
2873 /* initialization */
2874 /************************************************************************/
2877 vars_of_event_mswindows (void)
2879 mswindows_u_dispatch_event_queue = Qnil;
2880 staticpro (&mswindows_u_dispatch_event_queue);
2881 mswindows_u_dispatch_event_queue_tail = Qnil;
2883 mswindows_s_dispatch_event_queue = Qnil;
2884 staticpro (&mswindows_s_dispatch_event_queue);
2885 mswindows_s_dispatch_event_queue_tail = Qnil;
2887 mswindows_error_caught_in_modal_loop = Qnil;
2888 staticpro (&mswindows_error_caught_in_modal_loop);
2889 mswindows_in_modal_loop = 0;
2890 mswindows_pending_timers_count = 0;
2892 mswindows_event_stream = xnew (struct event_stream);
2894 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2895 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2896 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2897 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2898 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2899 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2900 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2901 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2902 #ifdef HAVE_MSG_SELECT
2903 mswindows_event_stream->select_process_cb =
2904 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2905 mswindows_event_stream->unselect_process_cb =
2906 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2907 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2908 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2910 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2911 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2912 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2913 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2916 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2917 *Controls redrawing frame contents during mouse-drag or keyboard resize
2918 operation. When non-nil, the frame is redrawn while being resized. When
2919 nil, frame is not redrawn, and exposed areas are filled with default
2920 MDI application background color. Note that this option only has effect
2921 if "Show window contents while dragging" is on in system Display/Plus!
2923 Default is t on fast machines, nil on slow.
2926 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2927 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2928 *Analogue of double click interval for faking middle mouse events.
2929 The value is the minimum time in milliseconds that must elapse between
2930 left/right button down events before they are considered distinct events.
2931 If both mouse buttons are depressed within this interval, a middle mouse
2932 button down event is generated instead.
2933 If negative or zero, currently set system default is used instead.
2936 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2937 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2938 Number of physical mouse buttons.
2941 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2942 *Maximum horizontal distance in pixels between points in which left and
2943 right button clicks occurred for them to be translated into single
2944 middle button event. Clicks must occur in time not longer than defined
2945 by the variable `mswindows-mouse-button-tolerance'.
2946 If negative or zero, currently set system default is used instead.
2949 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2950 *Maximum vertical distance in pixels between points in which left and
2951 right button clicks occurred for them to be translated into single
2952 middle button event. Clicks must occur in time not longer than defined
2953 by the variable `mswindows-mouse-button-tolerance'.
2954 If negative or zero, currently set system default is used instead.
2957 mswindows_mouse_button_max_skew_x = 0;
2958 mswindows_mouse_button_max_skew_y = 0;
2959 mswindows_mouse_button_tolerance = 0;
2963 syms_of_event_mswindows (void)
2968 lstream_type_create_mswindows_selectable (void)
2970 init_slurp_stream ();
2971 init_shove_stream ();
2972 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2973 init_winsock_stream ();
2978 init_event_mswindows_late (void)
2980 #ifdef HAVE_MSG_SELECT
2981 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2982 assert (windows_fd>=0);
2983 FD_SET (windows_fd, &input_wait_mask);
2984 FD_ZERO(&zero_mask);
2987 event_stream = mswindows_event_stream;
2989 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2990 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);