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;
75 #if defined (__CYGWIN32__) && !defined (CYGWIN_VERSION_DLL_MAJOR)
76 typedef struct tagNMHDR {
80 } NMHDR, *PNMHDR, *LPNMHDR;
84 #define ADJR_MENUFLAG TRUE
86 #define ADJR_MENUFLAG FALSE
89 /* Fake key modifier which is attached to a quit char event.
90 Removed upon dequeueing an event */
91 #define FAKE_MOD_QUIT 0x80
93 /* Timer ID used for button2 emulation */
94 #define BUTTON_2_TIMER_ID 1
97 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
99 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
101 mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id);
103 static Lisp_Object mswindows_find_frame (HWND hwnd);
104 static Lisp_Object mswindows_find_console (HWND hwnd);
105 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
106 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
107 static void mswindows_set_chord_timer (HWND hwnd);
108 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
109 static int mswindows_current_layout_has_AltGr (void);
111 static struct event_stream *mswindows_event_stream;
113 #ifdef HAVE_MSG_SELECT
114 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
115 extern SELECT_TYPE process_only_mask, tty_only_mask;
116 SELECT_TYPE zero_mask;
117 extern int signal_event_pipe_initialized;
122 * Two separate queues, for efficiency, one (_u_) for user events, and
123 * another (_s_) for non-user ones. We always return events out of the
124 * first one until it is empty and only then proceed with the second
127 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
128 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
130 /* The number of things we can wait on */
131 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
133 #ifndef HAVE_MSG_SELECT
134 /* List of mswindows waitable handles. */
135 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
137 /* Number of wait handles */
138 static int mswindows_waitable_count=0;
139 #endif /* HAVE_MSG_SELECT */
140 /* Brush for painting widgets */
141 static HBRUSH widget_brush = 0;
142 static LONG last_widget_brushed = 0;
144 /* Count of quit chars currently in the queue */
145 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
146 Decremented in mswindows_dequeue_dispatch_event() */
147 int mswindows_quit_chars_count = 0;
149 /* These are Lisp integers; see DEFVARS in this file for description. */
150 int mswindows_dynamic_frame_resize;
151 int mswindows_num_mouse_buttons;
152 int mswindows_mouse_button_max_skew_x;
153 int mswindows_mouse_button_max_skew_y;
154 int mswindows_mouse_button_tolerance;
156 /* This is the event signaled by the event pump.
157 See mswindows_pump_outstanding_events for comments */
158 static Lisp_Object mswindows_error_caught_in_modal_loop;
159 static int mswindows_in_modal_loop;
161 /* Count of wound timers */
162 static int mswindows_pending_timers_count;
164 /************************************************************************/
165 /* Pipe instream - reads process output */
166 /************************************************************************/
168 #define PIPE_READ_DELAY 20
170 #define HANDLE_TO_USID(h) ((USID)(h))
172 #define NTPIPE_SLURP_STREAM_DATA(stream) \
173 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
175 /* This structure is allocated by the main thread, and is deallocated
176 in the thread upon exit. There are situations when a thread
177 remains blocked for a long time, much longer than the lstream
178 exists. For example, "start notepad" command is issued from the
179 shell, then the shell is closed by C-c C-d. Although the shell
180 process exits, its output pipe will not get closed until the
181 notepad process exits also, because it inherits the pipe form the
182 shell. In this case, we abandon the thread, and let it live until
183 all such processes exit. While struct ntpipe_slurp_stream is
184 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
186 struct ntpipe_slurp_stream_shared_data
188 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
189 /* This is a manual-reset object. */
190 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
191 /* This is a manual-reset object. */
192 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
193 /* This is a manual-reset object. */
194 HANDLE hpipe; /* Pipe read end handle. */
195 LONG die_p; /* Thread must exit ASAP if non-zero */
196 BOOL eof_p : 1; /* Set when thread saw EOF */
197 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
198 BOOL inuse_p : 1; /* this structure is in use */
199 LONG lock_count; /* Client count of this struct, 0=safe to free */
200 BYTE onebyte; /* One byte buffer read by thread */
203 #define MAX_SLURP_STREAMS 32
204 struct ntpipe_slurp_stream_shared_data
205 shared_data_block[MAX_SLURP_STREAMS]={{0}};
207 struct ntpipe_slurp_stream
209 LPARAM user_data; /* Any user data stored in the stream object */
210 struct ntpipe_slurp_stream_shared_data* thread_data;
213 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
214 sizeof (struct ntpipe_slurp_stream));
216 /* This function is thread-safe, and is called from either thread
217 context. It serializes freeing shared data structure */
219 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
221 if (InterlockedDecrement (&s->lock_count) == 0)
224 CloseHandle (s->hev_thread);
225 CloseHandle (s->hev_caller);
226 CloseHandle (s->hev_unsleep);
231 static struct ntpipe_slurp_stream_shared_data*
232 slurper_allocate_shared_data()
235 for (i=0; i<MAX_SLURP_STREAMS; i++)
237 if (!shared_data_block[i].inuse_p)
239 shared_data_block[i].inuse_p=1;
240 return &shared_data_block[i];
243 return (struct ntpipe_slurp_stream_shared_data*)0;
247 slurp_thread (LPVOID vparam)
249 struct ntpipe_slurp_stream_shared_data *s =
250 (struct ntpipe_slurp_stream_shared_data*)vparam;
254 /* Read one byte from the pipe */
256 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
258 DWORD err = GetLastError ();
259 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
264 else if (actually_read == 0)
267 /* We must terminate on an error or eof */
268 if (s->eof_p || s->error_p)
269 InterlockedIncrement (&s->die_p);
271 /* Before we notify caller, we unsignal our event. */
272 ResetEvent (s->hev_thread);
274 /* Now we got something to notify caller, either a byte or an
275 error/eof indication. Before we do, allow internal pipe
276 buffer to accumulate little bit more data.
277 Reader function pulses this event before waiting for
278 a character, to avoid pipe delay, and to get the byte
281 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
283 /* Either make event loop generate a process event, or
285 SetEvent (s->hev_caller);
287 /* Cleanup and exit if we're shot off */
291 /* Block until the client finishes with retrieving the rest of
293 WaitForSingleObject (s->hev_thread, INFINITE);
296 slurper_free_shared_data_maybe (s);
302 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
305 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
306 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
307 DWORD thread_id_unused;
310 /* We deal only with pipes, for we're using PeekNamedPipe api */
311 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
313 s->thread_data = slurper_allocate_shared_data();
315 /* Create reader thread. This could fail, so do not create events
316 until thread is created */
317 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
318 CREATE_SUSPENDED, &thread_id_unused);
321 Lstream_delete (lstr);
322 s->thread_data->inuse_p=0;
326 /* Shared data are initially owned by both main and slurper
328 s->thread_data->lock_count = 2;
329 s->thread_data->die_p = 0;
330 s->thread_data->eof_p = FALSE;
331 s->thread_data->error_p = FALSE;
332 s->thread_data->hpipe = hpipe;
333 s->user_data = param;
335 /* hev_thread is a manual-reset event, initially signaled */
336 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
337 /* hev_caller is a manual-reset event, initially nonsignaled */
338 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
339 /* hev_unsleep is a manual-reset event, initially nonsignaled */
340 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
343 ResumeThread (hthread);
344 CloseHandle (hthread);
346 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
347 XSETLSTREAM (obj, lstr);
352 get_ntpipe_input_stream_param (Lstream *stream)
354 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
359 get_ntpipe_input_stream_waitable (Lstream *stream)
361 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
362 return s->thread_data->hev_caller;
366 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
368 /* This function must be called from the main thread only */
369 struct ntpipe_slurp_stream_shared_data* s =
370 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
375 /* Disallow pipe read delay for the thread: we need a character
377 SetEvent (s->hev_unsleep);
379 /* Check if we have a character ready. Give it a short delay,
380 for the thread to awake from pipe delay, just ion case*/
381 wait_result = WaitForSingleObject (s->hev_caller, 2);
383 /* Revert to the normal sleep behavior. */
384 ResetEvent (s->hev_unsleep);
386 /* If there's no byte buffered yet, give up */
387 if (wait_result == WAIT_TIMEOUT)
394 /* Reset caller unlock event now, as we've handled the pending
395 process output event */
396 ResetEvent (s->hev_caller);
398 /* It is now safe to do anything with contents of S, except for
399 changing s->die_p, which still should be interlocked */
403 if (s->error_p || s->die_p)
406 /* Ok, there were no error neither eof - we've got a byte from the
408 *(data++) = s->onebyte;
412 DWORD bytes_read = 0;
415 DWORD bytes_available;
417 /* If the api call fails, return at least one byte already
418 read. ReadFile in thread will return error */
419 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
422 /* Fetch available bytes. The same consideration applies,
423 so do not check for errors. ReadFile in the thread will
424 fail if the next call fails. */
426 ReadFile (s->hpipe, data, min (bytes_available, size),
430 /* Now we can unblock thread, so it attempts to read more */
431 SetEvent (s->hev_thread);
432 return bytes_read + 1;
439 ntpipe_slurp_closer (Lstream *stream)
441 /* This function must be called from the main thread only */
442 struct ntpipe_slurp_stream_shared_data* s =
443 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
445 /* Force thread to stop */
446 InterlockedIncrement (&s->die_p);
448 /* Set events which could possibly block slurper. Let it finish soon
450 SetEvent (s->hev_unsleep);
451 SetEvent (s->hev_thread);
453 /* Unlock and maybe free shared data */
454 slurper_free_shared_data_maybe (s);
460 init_slurp_stream (void)
462 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
463 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
466 /************************************************************************/
467 /* Pipe outstream - writes process input */
468 /************************************************************************/
470 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
471 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
473 #define MAX_SHOVE_BUFFER_SIZE 128
475 struct ntpipe_shove_stream
477 LPARAM user_data; /* Any user data stored in the stream object */
478 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
479 /* This is an auto-reset object. */
480 HANDLE hpipe; /* Pipe write end handle. */
481 HANDLE hthread; /* Reader thread handle. */
482 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
483 DWORD size; /* Number of bytes to write */
484 LONG die_p; /* Thread must exit ASAP if non-zero */
485 LONG idle_p; /* Non-zero if thread is waiting for job */
486 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
487 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
490 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
491 sizeof (struct ntpipe_shove_stream));
493 #ifndef HAVE_MSG_SELECT
495 shove_thread (LPVOID vparam)
497 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
503 /* Block on event and wait for a job */
504 InterlockedIncrement (&s->idle_p);
505 WaitForSingleObject (s->hev_thread, INFINITE);
510 /* Write passed buffer */
511 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
512 || bytes_written != s->size)
515 InterlockedIncrement (&s->die_p);
526 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
529 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
530 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
531 DWORD thread_id_unused;
536 s->user_data = param;
538 /* Create reader thread. This could fail, so do not
539 create the event until thread is created */
540 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
541 CREATE_SUSPENDED, &thread_id_unused);
542 if (s->hthread == NULL)
544 Lstream_delete (lstr);
548 /* hev_thread is an auto-reset event, initially nonsignaled */
549 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
552 ResumeThread (s->hthread);
554 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
555 XSETLSTREAM (obj, lstr);
560 get_ntpipe_output_stream_param (Lstream *stream)
562 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
568 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
570 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
575 s->blocking_p = !s->idle_p;
579 if (size>MAX_SHOVE_BUFFER_SIZE)
582 memcpy (s->buffer, data, size);
586 InterlockedDecrement (&s->idle_p);
587 SetEvent (s->hev_thread);
592 ntpipe_shove_was_blocked_p (Lstream *stream)
594 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
595 return s->blocking_p;
599 ntpipe_shove_closer (Lstream *stream)
601 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
603 /* Force thread stop */
604 InterlockedIncrement (&s->die_p);
606 /* Close pipe handle, possibly breaking it */
607 CloseHandle (s->hpipe);
609 /* Thread will end upon unblocking */
610 SetEvent (s->hev_thread);
612 /* Wait while thread terminates */
613 WaitForSingleObject (s->hthread, INFINITE);
614 CloseHandle (s->hthread);
616 /* Destroy the event */
617 CloseHandle (s->hev_thread);
623 init_shove_stream (void)
625 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
626 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
627 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
630 /************************************************************************/
631 /* Winsock I/O stream */
632 /************************************************************************/
633 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
635 #define WINSOCK_READ_BUFFER_SIZE 1024
637 struct winsock_stream
639 LPARAM user_data; /* Any user data stored in the stream object */
640 SOCKET s; /* Socket handle (which is a Win32 handle) */
641 OVERLAPPED ov; /* Overlapped I/O structure */
642 void* buffer; /* Buffer. Allocated for input stream only */
643 unsigned int bufsize; /* Number of bytes last read */
644 unsigned int bufpos; /* Position in buffer for next fetch */
645 unsigned int error_p :1; /* I/O Error seen */
646 unsigned int eof_p :1; /* EOF Error seen */
647 unsigned int pending_p :1; /* There is a pending I/O operation */
648 unsigned int blocking_p :1; /* Last write attempt would block */
651 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
653 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
654 sizeof (struct winsock_stream));
657 winsock_initiate_read (struct winsock_stream *str)
659 ResetEvent (str->ov.hEvent);
662 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
663 &str->bufsize, &str->ov))
665 if (GetLastError () == ERROR_IO_PENDING)
667 else if (GetLastError () == ERROR_HANDLE_EOF)
672 else if (str->bufsize == 0)
677 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
679 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
681 /* If the current operation is not yet complete, there's nothing to
685 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
692 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
694 if (GetLastError() == ERROR_HANDLE_EOF)
699 if (str->bufsize == 0)
710 /* Return as much of buffer as we have */
711 size = min (size, (size_t) (str->bufsize - str->bufpos));
712 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
715 /* Read more if buffer is exhausted */
716 if (str->bufsize == str->bufpos)
717 winsock_initiate_read (str);
723 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
725 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
729 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
737 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
752 ResetEvent (str->ov.hEvent);
754 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
755 * an overlapped operation. This fails on Win95 with winsock 1.x so we
756 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
757 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
758 || GetLastError() == ERROR_IO_PENDING)
764 return str->error_p ? -1 : size;
768 winsock_closer (Lstream *lstr)
770 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
772 if (lstr->flags & LSTREAM_FL_READ)
773 shutdown (str->s, 0);
775 shutdown (str->s, 1);
777 CloseHandle ((HANDLE)str->s);
779 WaitForSingleObject (str->ov.hEvent, INFINITE);
781 if (lstr->flags & LSTREAM_FL_READ)
784 CloseHandle (str->ov.hEvent);
789 winsock_was_blocked_p (Lstream *stream)
791 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
792 return str->blocking_p;
796 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
799 Lstream *lstr = Lstream_new (lstream_winsock, mode);
800 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
807 str->user_data = param;
810 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
812 if (lstr->flags & LSTREAM_FL_READ)
814 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
815 winsock_initiate_read (str);
818 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
819 XSETLSTREAM (obj, lstr);
824 make_winsock_input_stream (SOCKET s, LPARAM param)
826 return make_winsock_stream_1 (s, param, "r");
830 make_winsock_output_stream (SOCKET s, LPARAM param)
832 return make_winsock_stream_1 (s, param, "w");
836 get_winsock_stream_waitable (Lstream *lstr)
838 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
839 return str->ov.hEvent;
843 get_winsock_stream_param (Lstream *lstr)
845 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
846 return str->user_data;
850 init_winsock_stream (void)
852 LSTREAM_HAS_METHOD (winsock, reader);
853 LSTREAM_HAS_METHOD (winsock, writer);
854 LSTREAM_HAS_METHOD (winsock, closer);
855 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
857 #endif /* defined (HAVE_SOCKETS) */
859 /************************************************************************/
860 /* Dispatch queue management */
861 /************************************************************************/
864 mswindows_user_event_p (struct Lisp_Event* sevt)
866 return (sevt->event_type == key_press_event
867 || sevt->event_type == button_press_event
868 || sevt->event_type == button_release_event
869 || sevt->event_type == misc_user_event);
873 * Add an emacs event to the proper dispatch queue
876 mswindows_enqueue_dispatch_event (Lisp_Object event)
878 int user_p = mswindows_user_event_p (XEVENT(event));
879 enqueue_event (event,
880 user_p ? &mswindows_u_dispatch_event_queue :
881 &mswindows_s_dispatch_event_queue,
882 user_p ? &mswindows_u_dispatch_event_queue_tail :
883 &mswindows_s_dispatch_event_queue_tail);
885 /* Avoid blocking on WaitMessage */
886 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
890 * Add a misc-user event to the dispatch queue.
892 * Stuff it into our own dispatch queue, so we have something
893 * to return from next_event callback.
896 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
899 Lisp_Object event = Fmake_event (Qnil, Qnil);
900 struct Lisp_Event* e = XEVENT (event);
902 e->event_type = misc_user_event;
903 e->channel = channel;
904 e->event.misc.function = function;
905 e->event.misc.object = object;
907 mswindows_enqueue_dispatch_event (event);
911 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
913 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
914 struct Lisp_Event* event = XEVENT (emacs_event);
916 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
917 event->timestamp = GetMessageTime();
918 event->event_type = magic_event;
919 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
921 mswindows_enqueue_dispatch_event (emacs_event);
925 mswindows_enqueue_process_event (struct Lisp_Process* p)
927 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
928 struct Lisp_Event* event = XEVENT (emacs_event);
930 XSETPROCESS (process, p);
932 event->event_type = process_event;
933 event->timestamp = GetTickCount ();
934 event->event.process.process = process;
936 mswindows_enqueue_dispatch_event (emacs_event);
940 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
943 /* We always use last message time, because mouse button
944 events may get delayed, and XEmacs double click
945 recognition will fail */
947 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
948 struct Lisp_Event* event = XEVENT(emacs_event);
950 event->channel = mswindows_find_frame(hwnd);
951 event->timestamp = when;
952 event->event.button.button =
953 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
954 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
955 event->event.button.x = where.x;
956 event->event.button.y = where.y;
957 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
959 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
960 message==WM_RBUTTONDOWN)
962 event->event_type = button_press_event;
964 /* we need this to make sure the main window regains the focus
965 from control subwindows */
966 if (GetFocus() != hwnd)
969 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
974 event->event_type = button_release_event;
978 mswindows_enqueue_dispatch_event (emacs_event);
982 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
984 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
985 struct Lisp_Event* event = XEVENT(emacs_event);
987 event->channel = mswindows_find_console(hwnd);
988 event->timestamp = GetMessageTime();
989 event->event_type = key_press_event;
990 event->event.key.keysym = keysym;
991 event->event.key.modifiers = mods;
992 mswindows_enqueue_dispatch_event (emacs_event);
996 * Remove and return the first emacs event on the dispatch queue.
997 * Give a preference to user events over non-user ones.
1000 mswindows_dequeue_dispatch_event ()
1003 struct Lisp_Event* sevt;
1005 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1006 !NILP(mswindows_s_dispatch_event_queue));
1008 event = dequeue_event (
1009 NILP(mswindows_u_dispatch_event_queue) ?
1010 &mswindows_s_dispatch_event_queue :
1011 &mswindows_u_dispatch_event_queue,
1012 NILP(mswindows_u_dispatch_event_queue) ?
1013 &mswindows_s_dispatch_event_queue_tail :
1014 &mswindows_u_dispatch_event_queue_tail);
1016 sevt = XEVENT(event);
1017 if (sevt->event_type == key_press_event
1018 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1020 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1021 --mswindows_quit_chars_count;
1028 * Remove and return the first emacs event on the dispatch queue that matches
1029 * the supplied event.
1030 * Timeout event matches if interval_id is equal to that of the given event.
1031 * Keypress event matches if logical AND between modifiers bitmask of the
1032 * event in the queue and that of the given event is non-zero.
1033 * For all other event types, this function aborts.
1037 mswindows_cancel_dispatch_event (struct Lisp_Event *match)
1040 Lisp_Object previous_event = Qnil;
1041 int user_p = mswindows_user_event_p (match);
1042 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1043 &mswindows_s_dispatch_event_queue;
1044 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1045 &mswindows_s_dispatch_event_queue_tail;
1047 assert (match->event_type == timeout_event
1048 || match->event_type == key_press_event);
1050 EVENT_CHAIN_LOOP (event, *head)
1052 struct Lisp_Event *e = XEVENT (event);
1053 if ((e->event_type == match->event_type) &&
1054 ((e->event_type == timeout_event) ?
1055 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1056 /* Must be key_press_event */
1057 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1059 if (NILP (previous_event))
1060 dequeue_event (head, tail);
1063 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1064 if (EQ (*tail, event))
1065 *tail = previous_event;
1070 previous_event = event;
1075 #ifndef HAVE_MSG_SELECT
1076 /************************************************************************/
1077 /* Waitable handles manipulation */
1078 /************************************************************************/
1080 find_waitable_handle (HANDLE h)
1083 for (i = 0; i < mswindows_waitable_count; ++i)
1084 if (mswindows_waitable_handles[i] == h)
1091 add_waitable_handle (HANDLE h)
1093 assert (find_waitable_handle (h) < 0);
1094 if (mswindows_waitable_count == MAX_WAITABLE)
1097 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1102 remove_waitable_handle (HANDLE h)
1104 int ix = find_waitable_handle (h);
1108 mswindows_waitable_handles [ix] =
1109 mswindows_waitable_handles [--mswindows_waitable_count];
1111 #endif /* HAVE_MSG_SELECT */
1114 /************************************************************************/
1116 /************************************************************************/
1119 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1120 Lisp_Object u_n_u_s_e_d)
1122 mswindows_error_caught_in_modal_loop = cons_sig_data;
1127 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1132 ++mswindows_in_modal_loop;
1133 tmp = condition_case_1 (Qt,
1135 mswindows_modal_loop_error_handler, Qnil);
1136 --mswindows_in_modal_loop;
1142 mswindows_unmodalize_signal_maybe (void)
1144 if (!NILP (mswindows_error_caught_in_modal_loop))
1146 /* Got an error while messages were pumped while
1147 in window procedure - have to resignal */
1148 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1149 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1150 mswindows_error_caught_in_modal_loop = Qnil;
1151 Fsignal (sym, data);
1156 * This is an unsafe part of event pump, guarded by
1157 * condition_case. See mswindows_pump_outstanding_events
1160 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1162 /* This function can call lisp */
1163 Lisp_Object event = Fmake_event (Qnil, Qnil);
1164 struct gcpro gcpro1;
1165 int do_redisplay = 0;
1168 while (detect_input_pending ())
1170 Fnext_event (event, Qnil);
1171 Fdispatch_event (event);
1178 Fdeallocate_event (event);
1181 /* Qt becomes return value of mswindows_pump_outstanding_events
1187 * This function pumps emacs events, while available, by using
1188 * next_message/dispatch_message loop. Errors are trapped around
1189 * the loop so the function always returns.
1191 * Windows message queue is not looked into during the call,
1192 * neither are waitable handles checked. The function pumps
1193 * thus only dispatch events already queued, as well as those
1194 * resulted in dispatching thereof. This is done by setting
1195 * module local variable mswindows_in_modal_loop to nonzero.
1197 * Return value is Qt if no errors was trapped, or Qunbound if
1198 * there was an error.
1200 * In case of error, a cons representing the error, in the
1201 * form (SIGNAL . DATA), is stored in the module local variable
1202 * mswindows_error_caught_in_modal_loop. This error is signaled
1203 * again when DispatchMessage returns. Thus, Windows internal
1204 * modal loops are protected against throws, which are proven
1205 * to corrupt internal Windows structures.
1207 * In case of success, mswindows_error_caught_in_modal_loop is
1210 * If the value of mswindows_error_caught_in_modal_loop is not
1211 * nil already upon entry, the function just returns non-nil.
1212 * This situation means that a new event has been queued while
1213 * in cancel mode. The event will be dequeued on the next regular
1214 * call of next-event; the pump is off since error is caught.
1215 * The caller must *unconditionally* cancel modal loop if the
1216 * value returned by this function is nil. Otherwise, everything
1217 * will become frozen until the modal loop exits under normal
1218 * condition (scrollbar drag is released, menu closed etc.)
1221 mswindows_pump_outstanding_events (void)
1223 /* This function can call lisp */
1225 Lisp_Object result = Qt;
1226 struct gcpro gcpro1;
1229 if (NILP(mswindows_error_caught_in_modal_loop))
1230 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1236 mswindows_drain_windows_queue ()
1239 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1241 /* we have to translate messages that are not sent to the main
1242 window. this is so that key presses work ok in things like
1243 edit fields. however, we *musn't* translate message for the
1244 main window as this is handled in the wnd proc. */
1245 if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD )
1247 TranslateMessage (&msg);
1249 DispatchMessage (&msg);
1250 mswindows_unmodalize_signal_maybe ();
1255 * This is a special flavor of the mswindows_need_event function,
1256 * used while in event pump. Actually, there is only kind of events
1257 * allowed while in event pump: a timer. An attempt to fetch any
1258 * other event leads to a deadlock, as there's no source of user input
1259 * ('cause event pump mirrors windows modal loop, which is a sole
1260 * owner of thread message queue).
1262 * To detect this, we use a counter of active timers, and allow
1263 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1264 * which will never come when there are no pending timers, which leads
1265 * to deadlock, we simply signal an error.
1268 mswindows_need_event_in_modal_loop (int badly_p)
1272 /* Check if already have one */
1273 if (!NILP (mswindows_u_dispatch_event_queue)
1274 || !NILP (mswindows_s_dispatch_event_queue))
1277 /* No event is ok */
1281 /* We do not check the _u_ queue, because timers go to _s_ */
1282 while (NILP (mswindows_s_dispatch_event_queue))
1284 /* We'll deadlock if go waiting */
1285 if (mswindows_pending_timers_count == 0)
1286 error ("Deadlock due to an attempt to call next-event in a wrong context");
1288 /* Fetch and dispatch any pending timers */
1289 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1290 DispatchMessage (&msg);
1295 * This drains the event queue and fills up two internal queues until
1296 * an event of a type specified by USER_P is retrieved.
1299 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1302 mswindows_need_event (int badly_p)
1306 if (mswindows_in_modal_loop)
1308 mswindows_need_event_in_modal_loop (badly_p);
1312 /* Have to drain Windows message queue first, otherwise, we may miss
1313 quit char when called from quit_p */
1314 mswindows_drain_windows_queue ();
1316 while (NILP (mswindows_u_dispatch_event_queue)
1317 && NILP (mswindows_s_dispatch_event_queue))
1319 #ifdef HAVE_MSG_SELECT
1321 SELECT_TYPE temp_mask = input_wait_mask;
1322 EMACS_TIME sometime;
1323 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1326 pointer_to_this = 0;
1329 EMACS_SET_SECS_USECS (sometime, 0, 0);
1330 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1331 pointer_to_this = &select_time_to_block;
1334 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1339 return; /* timeout */
1341 else if (active > 0)
1343 if (FD_ISSET (windows_fd, &temp_mask))
1345 mswindows_drain_windows_queue ();
1348 /* Look for a TTY event */
1349 for (i = 0; i < MAXDESC-1; i++)
1351 /* To avoid race conditions (among other things, an infinite
1352 loop when called from Fdiscard_input()), we must return
1353 user events ahead of process events. */
1354 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1356 struct console *c = tty_find_console_from_fd (i);
1357 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1358 struct Lisp_Event* event = XEVENT (emacs_event);
1361 if (read_event_from_tty_or_stream_desc (event, c, i))
1363 mswindows_enqueue_dispatch_event (emacs_event);
1369 /* Look for a process event */
1370 for (i = 0; i < MAXDESC-1; i++)
1372 if (FD_ISSET (i, &temp_mask))
1374 if (FD_ISSET (i, &process_only_mask))
1376 struct Lisp_Process *p =
1377 get_process_from_usid (FD_TO_USID(i));
1379 mswindows_enqueue_process_event (p);
1383 /* We might get here when a fake event came
1384 through a signal. Return a dummy event, so
1385 that a cycle of the command loop will
1387 drain_signal_event_pipe ();
1388 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1393 else if (active==-1)
1397 /* something bad happened */
1406 /* Now try getting a message or process event */
1407 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1408 mswindows_waitable_handles,
1409 FALSE, badly_p ? INFINITE : 0,
1412 /* This will assert if handle being waited for becomes abandoned.
1413 Not the case currently tho */
1414 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1415 (active >= WAIT_OBJECT_0 &&
1416 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1418 if (active == WAIT_TIMEOUT)
1420 /* No luck trying - just return what we've already got */
1423 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1425 /* Got your message, thanks */
1426 mswindows_drain_windows_queue ();
1430 int ix = active - WAIT_OBJECT_0;
1431 /* First, try to find which process' output has signaled */
1432 struct Lisp_Process *p =
1433 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1436 /* Found a signaled process input handle */
1437 mswindows_enqueue_process_event (p);
1441 /* None. This means that the process handle itself has signaled.
1442 Remove the handle from the wait vector, and make status_notify
1443 note the exited process */
1444 mswindows_waitable_handles [ix] =
1445 mswindows_waitable_handles [--mswindows_waitable_count];
1446 kick_status_notify ();
1447 /* Have to return something: there may be no accompanying
1449 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1456 /************************************************************************/
1457 /* Event generators */
1458 /************************************************************************/
1461 * Callback procedure for synchronous timer messages
1463 static void CALLBACK
1464 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1466 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1467 struct Lisp_Event *event = XEVENT (emacs_event);
1469 if (KillTimer (NULL, id_timer))
1470 --mswindows_pending_timers_count;
1472 event->channel = Qnil;
1473 event->timestamp = dwtime;
1474 event->event_type = timeout_event;
1475 event->event.timeout.interval_id = id_timer;
1476 event->event.timeout.function = Qnil;
1477 event->event.timeout.object = Qnil;
1479 mswindows_enqueue_dispatch_event (emacs_event);
1483 * Callback procedure for dde messages
1485 * We execute a dde Open("file") by simulating a file drop, so dde support
1486 * depends on dnd support.
1488 #ifdef HAVE_DRAGNDROP
1490 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1491 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1492 DWORD dwData1, DWORD dwData2)
1497 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1498 return (HDDEDATA)TRUE;
1499 return (HDDEDATA)FALSE;
1501 case XTYP_WILDCONNECT:
1503 /* We only support one {service,topic} pair */
1504 HSZPAIR pairs[2] = {
1505 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1507 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1508 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1509 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1510 sizeof (pairs), 0L, 0, uFmt, 0));
1512 return (HDDEDATA)NULL;
1515 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1517 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1518 char *cmd = alloca (len+1);
1521 struct gcpro gcpro1, gcpro2;
1522 Lisp_Object l_dndlist = Qnil;
1523 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1524 Lisp_Object frmcons, devcons, concons;
1525 struct Lisp_Event *event = XEVENT (emacs_event);
1527 DdeGetData (hdata, cmd, len, 0);
1529 DdeFreeDataHandle (hdata);
1531 /* Check syntax & that it's an [Open("foo")] command, which we
1532 * treat like a file drop */
1533 /* #### Ought to be generalised and accept some other commands */
1536 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1537 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1538 return DDE_FNOTPROCESSED;
1539 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1542 if (*cmd!='(' || *(cmd+1)!='\"')
1543 return DDE_FNOTPROCESSED;
1545 while (*end && *end!='\"')
1548 return DDE_FNOTPROCESSED;
1551 return DDE_FNOTPROCESSED;
1555 return DDE_FNOTPROCESSED;
1558 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1559 strcpy (filename, "file:");
1560 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1562 dostounix_filename (cmd);
1563 filename = alloca (strlen (cmd)+6);
1564 strcpy (filename, "file:");
1565 strcat (filename, cmd);
1567 GCPRO2 (emacs_event, l_dndlist);
1568 l_dndlist = make_string (filename, strlen (filename));
1570 /* Find a mswindows frame */
1571 event->channel = Qnil;
1572 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1574 Lisp_Object frame = XCAR (frmcons);
1575 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1576 event->channel = frame;
1578 assert (!NILP (event->channel));
1580 event->timestamp = GetTickCount();
1581 event->event_type = misc_user_event;
1582 event->event.misc.button = 1;
1583 event->event.misc.modifiers = 0;
1584 event->event.misc.x = -1;
1585 event->event.misc.y = -1;
1586 event->event.misc.function = Qdragdrop_drop_dispatch;
1587 event->event.misc.object = Fcons (Qdragdrop_URL,
1588 Fcons (l_dndlist, Qnil));
1589 mswindows_enqueue_dispatch_event (emacs_event);
1591 return (HDDEDATA) DDE_FACK;
1593 DdeFreeDataHandle (hdata);
1594 return (HDDEDATA) DDE_FNOTPROCESSED;
1597 return (HDDEDATA) NULL;
1603 * The windows procedure for the window class XEMACS_CLASS
1606 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1608 /* Note: Remember to initialize emacs_event and event before use.
1609 This code calls code that can GC. You must GCPRO before calling such code. */
1610 Lisp_Object emacs_event = Qnil;
1611 Lisp_Object fobj = Qnil;
1613 struct Lisp_Event *event;
1614 struct frame *frame;
1615 struct mswindows_frame* msframe;
1620 /* Erase background only during non-dynamic sizing */
1621 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1622 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1627 fobj = mswindows_find_frame (hwnd);
1628 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1633 /* See Win95 comment under WM_KEYDOWN */
1637 if (wParam == VK_CONTROL)
1639 GetKeyboardState (keymap);
1640 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1641 SetKeyboardState (keymap);
1643 else if (wParam == VK_MENU)
1645 GetKeyboardState (keymap);
1646 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1647 SetKeyboardState (keymap);
1654 /* In some locales the right-hand Alt key is labelled AltGr. This key
1655 * should produce alternative charcaters when combined with another key.
1656 * eg on a German keyboard pressing AltGr+q should produce '@'.
1657 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1658 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1659 * it translates as if AltGr were down.
1660 * We get round this by removing all modifiers from the keymap before
1661 * calling TranslateMessage() unless AltGr is *really* down. */
1664 int has_AltGr = mswindows_current_layout_has_AltGr ();
1668 GetKeyboardState (keymap);
1669 mods = mswindows_modifier_state (keymap, has_AltGr);
1671 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1672 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1673 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1676 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1677 BYTE keymap_orig[256];
1678 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
1682 msg.message = message;
1683 msg.wParam = wParam;
1684 msg.lParam = lParam;
1685 msg.time = GetMessageTime();
1688 /* GetKeyboardState() does not work as documented on Win95. We have
1689 * to loosely track Left and Right modifiers on behalf of the OS,
1690 * without screwing up Windows NT which tracks them properly. */
1691 if (wParam == VK_CONTROL)
1692 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1693 else if (wParam == VK_MENU)
1694 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1696 memcpy (keymap_orig, keymap, 256);
1698 /* Remove shift modifier from an ascii character */
1701 /* Clear control and alt modifiers unless AltGr is pressed */
1702 keymap [VK_RCONTROL] = 0;
1703 keymap [VK_LMENU] = 0;
1704 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1706 keymap [VK_LCONTROL] = 0;
1707 keymap [VK_CONTROL] = 0;
1708 keymap [VK_RMENU] = 0;
1709 keymap [VK_MENU] = 0;
1711 SetKeyboardState (keymap);
1713 /* Maybe generate some WM_[SYS]CHARs in the queue */
1714 TranslateMessage (&msg);
1716 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1717 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1720 WPARAM ch = msg.wParam;
1722 /* If a quit char with no modifiers other than control and
1723 shift, then mark it with a fake modifier, which is removed
1724 upon dequeueing the event */
1725 /* #### This might also not withstand localization, if
1726 quit character is not a latin-1 symbol */
1727 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1728 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1729 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1731 mods1 |= FAKE_MOD_QUIT;
1732 ++mswindows_quit_chars_count;
1735 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1737 SetKeyboardState (keymap_orig);
1740 /* F10 causes menu activation by default. We do not want this */
1741 if (wParam != VK_F10)
1745 case WM_MBUTTONDOWN:
1747 /* Real middle mouse button has nothing to do with emulated one:
1748 if one wants to exercise fingers playing chords on the mouse,
1749 he is allowed to do that! */
1750 mswindows_enqueue_mouse_button_event (hwnd, message,
1751 MAKEPOINTS (lParam), GetMessageTime());
1755 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1756 msframe->last_click_time = GetMessageTime();
1758 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1759 msframe->button2_need_lbutton = 0;
1760 if (msframe->ignore_next_lbutton_up)
1762 msframe->ignore_next_lbutton_up = 0;
1764 else if (msframe->button2_is_down)
1766 msframe->button2_is_down = 0;
1767 msframe->ignore_next_rbutton_up = 1;
1768 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1769 MAKEPOINTS (lParam), GetMessageTime());
1773 if (msframe->button2_need_rbutton)
1775 msframe->button2_need_rbutton = 0;
1776 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1777 MAKEPOINTS (lParam), GetMessageTime());
1779 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1780 MAKEPOINTS (lParam), GetMessageTime());
1785 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1786 msframe->last_click_time = GetMessageTime();
1788 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1789 msframe->button2_need_rbutton = 0;
1790 if (msframe->ignore_next_rbutton_up)
1792 msframe->ignore_next_rbutton_up = 0;
1794 else if (msframe->button2_is_down)
1796 msframe->button2_is_down = 0;
1797 msframe->ignore_next_lbutton_up = 1;
1798 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1799 MAKEPOINTS (lParam), GetMessageTime());
1803 if (msframe->button2_need_lbutton)
1805 msframe->button2_need_lbutton = 0;
1806 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1807 MAKEPOINTS (lParam), GetMessageTime());
1809 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1810 MAKEPOINTS (lParam), GetMessageTime());
1814 case WM_LBUTTONDOWN:
1815 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1817 if (msframe->button2_need_lbutton)
1819 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1820 msframe->button2_need_lbutton = 0;
1821 msframe->button2_need_rbutton = 0;
1822 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1824 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1825 MAKEPOINTS (lParam), GetMessageTime());
1826 msframe->button2_is_down = 1;
1830 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1831 msframe->last_click_point, msframe->last_click_time);
1832 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1833 MAKEPOINTS (lParam), GetMessageTime());
1838 mswindows_set_chord_timer (hwnd);
1839 msframe->button2_need_rbutton = 1;
1840 msframe->last_click_point = MAKEPOINTS (lParam);
1842 msframe->last_click_time = GetMessageTime();
1845 case WM_RBUTTONDOWN:
1846 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1848 if (msframe->button2_need_rbutton)
1850 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1851 msframe->button2_need_lbutton = 0;
1852 msframe->button2_need_rbutton = 0;
1853 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1855 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1856 MAKEPOINTS (lParam), GetMessageTime());
1857 msframe->button2_is_down = 1;
1861 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1862 msframe->last_click_point, msframe->last_click_time);
1863 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1864 MAKEPOINTS (lParam), GetMessageTime());
1869 mswindows_set_chord_timer (hwnd);
1870 msframe->button2_need_lbutton = 1;
1871 msframe->last_click_point = MAKEPOINTS (lParam);
1873 msframe->last_click_time = GetMessageTime();
1877 if (wParam == BUTTON_2_TIMER_ID)
1879 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1880 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1882 if (msframe->button2_need_lbutton)
1884 msframe->button2_need_lbutton = 0;
1885 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1886 msframe->last_click_point, msframe->last_click_time);
1888 else if (msframe->button2_need_rbutton)
1890 msframe->button2_need_rbutton = 0;
1891 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1892 msframe->last_click_point, msframe->last_click_time);
1896 assert ("Spurious timer fired" == 0);
1900 /* Optimization: don't report mouse movement while size is changing */
1901 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1902 if (!msframe->sizing)
1904 /* When waiting for the second mouse button to finish
1905 button2 emulation, and have moved too far, just pretend
1906 as if timer has expired. This improves drag-select feedback */
1907 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1908 && !mswindows_button2_near_enough (msframe->last_click_point,
1909 MAKEPOINTS (lParam)))
1911 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1912 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1915 emacs_event = Fmake_event (Qnil, Qnil);
1916 event = XEVENT(emacs_event);
1918 event->channel = mswindows_find_frame(hwnd);
1919 event->timestamp = GetMessageTime();
1920 event->event_type = pointer_motion_event;
1921 event->event.motion.x = MAKEPOINTS(lParam).x;
1922 event->event.motion.y = MAKEPOINTS(lParam).y;
1923 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1925 mswindows_enqueue_dispatch_event (emacs_event);
1931 /* Queue a `cancel-mode-internal' misc user event, so mouse
1932 selection would be canceled if any */
1933 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1934 Qcancel_mode_internal, Qnil);
1939 LPNMHDR nmhdr = (LPNMHDR)lParam;
1941 if (nmhdr->code == TTN_NEEDTEXT)
1943 #ifdef HAVE_TOOLBARS
1944 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1947 /* find out which toolbar */
1948 frame = XFRAME (mswindows_find_frame (hwnd));
1949 btext = mswindows_get_toolbar_button_text ( frame,
1952 tttext->lpszText = NULL;
1953 tttext->hinst = NULL;
1957 /* I think this is safe since the text will only go away
1958 when the toolbar does...*/
1959 GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS,
1964 /* handle tree view callbacks */
1965 else if (nmhdr->code == TVN_SELCHANGED)
1967 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
1968 frame = XFRAME (mswindows_find_frame (hwnd));
1969 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
1971 /* handle tab control callbacks */
1972 else if (nmhdr->code == TCN_SELCHANGE)
1975 int index = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
1976 frame = XFRAME (mswindows_find_frame (hwnd));
1977 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index,
1980 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
1987 PAINTSTRUCT paintStruct;
1989 frame = XFRAME (mswindows_find_frame (hwnd));
1991 BeginPaint (hwnd, &paintStruct);
1992 mswindows_redraw_exposed_area (frame,
1993 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1994 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1995 EndPaint (hwnd, &paintStruct);
2000 /* We only care about this message if our size has really changed */
2001 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2006 fobj = mswindows_find_frame (hwnd);
2007 frame = XFRAME (fobj);
2008 msframe = FRAME_MSWINDOWS_DATA (frame);
2010 /* We cannot handle frame map and unmap hooks right in
2011 this routine, because these may throw. We queue
2012 magic events to run these hooks instead - kkm */
2014 if (wParam==SIZE_MINIMIZED)
2017 FRAME_VISIBLE_P (frame) = 0;
2018 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2022 GetClientRect(hwnd, &rect);
2023 FRAME_PIXWIDTH(frame) = rect.right;
2024 FRAME_PIXHEIGHT(frame) = rect.bottom;
2026 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2027 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2028 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2030 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2031 change_frame_size (frame, rows, columns, 1);
2033 /* If we are inside frame creation, we have to apply geometric
2035 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2037 /* Yes, we have to size again */
2038 mswindows_size_frame_internal ( frame,
2039 FRAME_MSWINDOWS_TARGET_RECT
2041 /* Reset so we do not get here again. The SetWindowPos call in
2042 * mswindows_size_frame_internal can cause recursion here. */
2043 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2045 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2046 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2051 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2052 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2053 FRAME_VISIBLE_P (frame) = 1;
2055 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2062 /* Misc magic events which only require that the frame be identified */
2065 mswindows_enqueue_magic_event (hwnd, message);
2068 case WM_WINDOWPOSCHANGING:
2070 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2071 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2072 GetWindowPlacement(hwnd, &wpl);
2074 /* Only interested if size is changing and we're not being iconified */
2075 if (wpl.showCmd != SW_SHOWMINIMIZED
2076 && wpl.showCmd != SW_SHOWMAXIMIZED
2077 && !(wp->flags & SWP_NOSIZE))
2079 RECT ncsize = { 0, 0, 0, 0 };
2080 int pixwidth, pixheight;
2081 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2082 GetMenu(hwnd) != NULL,
2083 GetWindowLong (hwnd, GWL_EXSTYLE));
2085 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2086 wp->cx - (ncsize.right - ncsize.left),
2087 wp->cy - (ncsize.bottom - ncsize.top),
2088 &pixwidth, &pixheight);
2090 /* Convert client sizes to window sizes */
2091 pixwidth += (ncsize.right - ncsize.left);
2092 pixheight += (ncsize.bottom - ncsize.top);
2094 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2096 /* Adjust so that the bottom or right doesn't move if it's
2097 * the top or left that's being changed */
2099 GetWindowRect (hwnd, &rect);
2101 if (rect.left != wp->x)
2102 wp->x += wp->cx - pixwidth;
2103 if (rect.top != wp->y)
2104 wp->y += wp->cy - pixheight;
2110 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2111 window position if the user tries to track window too small */
2115 case WM_ENTERSIZEMOVE:
2116 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2117 msframe->sizing = 1;
2120 case WM_EXITSIZEMOVE:
2121 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2122 msframe->sizing = 0;
2123 /* Queue noop event */
2124 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2127 #ifdef HAVE_SCROLLBARS
2131 /* Direction of scroll is determined by scrollbar instance. */
2132 int code = (int) LOWORD(wParam);
2133 int pos = (short int) HIWORD(wParam);
2134 HWND hwndScrollBar = (HWND) lParam;
2135 struct gcpro gcpro1, gcpro2;
2137 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2138 GCPRO2 (emacs_event, fobj);
2139 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2141 /* Error during event pumping - cancel scroll */
2142 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2149 #ifdef HAVE_MENUBARS
2151 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2153 XFRAME (mswindows_find_frame (hwnd)))))
2154 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2157 case WM_INITMENUPOPUP:
2158 if (!HIWORD(lParam))
2160 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2162 XFRAME (mswindows_find_frame (hwnd)))))
2163 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2167 #endif /* HAVE_MENUBARS */
2171 WORD id = LOWORD (wParam);
2172 WORD nid = HIWORD (wParam);
2173 HWND cid = (HWND)lParam;
2174 frame = XFRAME (mswindows_find_frame (hwnd));
2176 #ifdef HAVE_TOOLBARS
2177 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2180 /* widgets in a buffer only eval a callback for suitable events.*/
2185 case CBN_EDITCHANGE:
2187 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2190 /* menubars always must come last since the hashtables do not
2192 #ifdef HAVE_MENUBARS
2193 if (!NILP (mswindows_handle_wm_command (frame, id)))
2197 return DefWindowProc (hwnd, message, wParam, lParam);
2198 /* Bite me - a spurious command. This used to not be able to
2199 happen but with the introduction of widgets its now
2204 case WM_CTLCOLORBTN:
2205 case WM_CTLCOLORLISTBOX:
2206 case WM_CTLCOLOREDIT:
2207 case WM_CTLCOLORSTATIC:
2208 case WM_CTLCOLORSCROLLBAR:
2210 /* if we get an opportunity to paint a widget then do so if
2211 there is an appropriate face */
2212 HWND crtlwnd = (HWND)lParam;
2213 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2216 Lisp_Object image_instance;
2217 VOID_TO_LISP (image_instance, ii);
2218 if (IMAGE_INSTANCEP (image_instance)
2220 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
2222 !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
2224 /* set colors for the buttons */
2225 HDC hdc = (HDC)wParam;
2226 if (last_widget_brushed != ii)
2229 DeleteObject (widget_brush);
2230 widget_brush = CreateSolidBrush
2231 (COLOR_INSTANCE_MSWINDOWS_COLOR
2234 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2235 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2237 last_widget_brushed = ii;
2240 COLOR_INSTANCE_MSWINDOWS_COLOR
2243 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2244 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2245 SetBkMode (hdc, OPAQUE);
2248 COLOR_INSTANCE_MSWINDOWS_COLOR
2251 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2252 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2253 return (LRESULT)widget_brush;
2259 #ifdef HAVE_DRAGNDROP
2260 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2262 UINT filecount, i, len;
2268 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2269 struct gcpro gcpro1, gcpro2, gcpro3;
2271 emacs_event = Fmake_event (Qnil, Qnil);
2272 event = XEVENT(emacs_event);
2274 GCPRO3 (emacs_event, l_dndlist, l_item);
2276 if (!DragQueryPoint ((HANDLE) wParam, &point))
2277 point.x = point.y = -1; /* outside client area */
2279 event->event_type = misc_user_event;
2280 event->channel = mswindows_find_frame(hwnd);
2281 event->timestamp = GetMessageTime();
2282 event->event.misc.button = 1; /* #### Should try harder */
2283 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2284 event->event.misc.x = point.x;
2285 event->event.misc.y = point.y;
2286 event->event.misc.function = Qdragdrop_drop_dispatch;
2288 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2289 for (i=0; i<filecount; i++)
2291 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2292 /* The URLs that we make here aren't correct according to section
2293 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2294 * because they may contain reserved characters. But that's OK. */
2296 fname = (char *)xmalloc (len+1);
2297 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2298 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2299 strcpy (filename, "file:");
2300 cygwin32_win32_to_posix_path_list (fname, filename+5);
2303 filename = (char *)xmalloc (len+6);
2304 strcpy (filename, "file:");
2305 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2306 dostounix_filename (filename+5);
2308 l_item = make_string (filename, strlen (filename));
2309 l_dndlist = Fcons (l_item, l_dndlist);
2312 DragFinish ((HANDLE) wParam);
2314 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2315 mswindows_enqueue_dispatch_event (emacs_event);
2323 return DefWindowProc (hwnd, message, wParam, lParam);
2329 /************************************************************************/
2330 /* keyboard, mouse & other helpers for the windows procedure */
2331 /************************************************************************/
2333 mswindows_set_chord_timer (HWND hwnd)
2337 /* We get one third half system double click threshold */
2338 if (mswindows_mouse_button_tolerance <= 0)
2339 interval = GetDoubleClickTime () / 3;
2341 interval = mswindows_mouse_button_tolerance;
2343 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2347 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2350 if (mswindows_mouse_button_max_skew_x <= 0)
2351 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2353 dx = mswindows_mouse_button_max_skew_x;
2355 if (mswindows_mouse_button_max_skew_y <= 0)
2356 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2358 dy = mswindows_mouse_button_max_skew_y;
2360 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2364 mswindows_current_layout_has_AltGr (void)
2366 /* This simple caching mechanism saves 10% of CPU
2367 time when a key typed at autorepeat rate of 30 cps! */
2368 static HKL last_hkl = 0;
2369 static int last_hkl_has_AltGr;
2371 HKL current_hkl = GetKeyboardLayout (0);
2372 if (current_hkl != last_hkl)
2375 last_hkl_has_AltGr = 0;
2376 /* In this loop, we query whether a character requires
2377 AltGr to be down to generate it. If at least such one
2378 found, this means that the layout does regard AltGr */
2379 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2380 if (HIBYTE (VkKeyScan (c)) == 6)
2381 last_hkl_has_AltGr = 1;
2382 last_hkl = current_hkl;
2384 return last_hkl_has_AltGr;
2388 /* Returns the state of the modifier keys in the format expected by the
2389 * Lisp_Event key_data, button_data and motion_data modifiers member */
2390 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2396 keymap = (BYTE*) alloca(256);
2397 GetKeyboardState (keymap);
2398 has_AltGr = mswindows_current_layout_has_AltGr ();
2401 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2403 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2404 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2408 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2409 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2412 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2418 * Translate a mswindows virtual key to a keysym.
2419 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2420 * or whose ASCII codes (like space) xemacs doesn't like.
2421 * Virtual key values are defined in winresrc.h
2422 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2424 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2426 switch (mswindows_key)
2428 /* First the predefined ones */
2429 case VK_BACK: return QKbackspace;
2430 case VK_TAB: return QKtab;
2431 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2432 case VK_RETURN: return QKreturn;
2433 case VK_ESCAPE: return QKescape;
2434 case VK_SPACE: return QKspace;
2435 case VK_DELETE: return QKdelete;
2438 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2439 case VK_PRIOR: return KEYSYM ("prior");
2440 case VK_NEXT: return KEYSYM ("next");
2441 case VK_END: return KEYSYM ("end");
2442 case VK_HOME: return KEYSYM ("home");
2443 case VK_LEFT: return KEYSYM ("left");
2444 case VK_UP: return KEYSYM ("up");
2445 case VK_RIGHT: return KEYSYM ("right");
2446 case VK_DOWN: return KEYSYM ("down");
2447 case VK_SELECT: return KEYSYM ("select");
2448 case VK_PRINT: return KEYSYM ("print");
2449 case VK_EXECUTE: return KEYSYM ("execute");
2450 case VK_SNAPSHOT: return KEYSYM ("print");
2451 case VK_INSERT: return KEYSYM ("insert");
2452 case VK_HELP: return KEYSYM ("help");
2453 #if 0 /* XXX What are these supposed to do? */
2454 case VK_LWIN return KEYSYM ("");
2455 case VK_RWIN return KEYSYM ("");
2457 case VK_APPS: return KEYSYM ("menu");
2458 case VK_F1: return KEYSYM ("f1");
2459 case VK_F2: return KEYSYM ("f2");
2460 case VK_F3: return KEYSYM ("f3");
2461 case VK_F4: return KEYSYM ("f4");
2462 case VK_F5: return KEYSYM ("f5");
2463 case VK_F6: return KEYSYM ("f6");
2464 case VK_F7: return KEYSYM ("f7");
2465 case VK_F8: return KEYSYM ("f8");
2466 case VK_F9: return KEYSYM ("f9");
2467 case VK_F10: return KEYSYM ("f10");
2468 case VK_F11: return KEYSYM ("f11");
2469 case VK_F12: return KEYSYM ("f12");
2470 case VK_F13: return KEYSYM ("f13");
2471 case VK_F14: return KEYSYM ("f14");
2472 case VK_F15: return KEYSYM ("f15");
2473 case VK_F16: return KEYSYM ("f16");
2474 case VK_F17: return KEYSYM ("f17");
2475 case VK_F18: return KEYSYM ("f18");
2476 case VK_F19: return KEYSYM ("f19");
2477 case VK_F20: return KEYSYM ("f20");
2478 case VK_F21: return KEYSYM ("f21");
2479 case VK_F22: return KEYSYM ("f22");
2480 case VK_F23: return KEYSYM ("f23");
2481 case VK_F24: return KEYSYM ("f24");
2487 * Find the console that matches the supplied mswindows window handle
2490 mswindows_find_console (HWND hwnd)
2492 /* We only support one console */
2493 return XCAR (Vconsole_list);
2497 * Find the frame that matches the supplied mswindows window handle
2500 mswindows_find_frame (HWND hwnd)
2502 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2506 /* We are in progress of frame creation. Return the frame
2507 being created, as it still not remembered in the window
2509 assert (!NILP (Vmswindows_frame_being_created));
2510 return Vmswindows_frame_being_created;
2512 VOID_TO_LISP (f, l);
2517 /************************************************************************/
2519 /************************************************************************/
2522 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2525 EMACS_TIME current_time;
2526 EMACS_GET_TIME (current_time);
2527 EMACS_SUB_TIME (thyme, thyme, current_time);
2528 milliseconds = EMACS_SECS (thyme) * 1000 +
2529 (EMACS_USECS (thyme) + 500) / 1000;
2530 if (milliseconds < 1)
2532 ++mswindows_pending_timers_count;
2533 return SetTimer (NULL, 0, milliseconds,
2534 (TIMERPROC) mswindows_wm_timer_callback);
2538 emacs_mswindows_remove_timeout (int id)
2540 struct Lisp_Event match_against;
2541 Lisp_Object emacs_event;
2543 if (KillTimer (NULL, id))
2544 --mswindows_pending_timers_count;
2546 /* If there is a dispatch event generated by this
2547 timeout in the queue, we have to remove it too. */
2548 match_against.event_type = timeout_event;
2549 match_against.event.timeout.interval_id = id;
2550 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2551 if (!NILP (emacs_event))
2552 Fdeallocate_event(emacs_event);
2555 /* If `user_p' is false, then return whether there are any win32, timeout,
2556 * or subprocess events pending (that is, whether
2557 * emacs_mswindows_next_event() would return immediately without blocking).
2559 * if `user_p' is true, then return whether there are any *user generated*
2560 * events available (that is, whether there are keyboard or mouse-click
2561 * events ready to be read). This also implies that
2562 * emacs_mswindows_next_event() would not block.
2565 emacs_mswindows_event_pending_p (int user_p)
2567 mswindows_need_event (0);
2568 return (!NILP (mswindows_u_dispatch_event_queue)
2569 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2573 * Return the next event
2576 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2578 Lisp_Object event, event2;
2580 mswindows_need_event (1);
2582 event = mswindows_dequeue_dispatch_event ();
2583 XSETEVENT (event2, emacs_event);
2584 Fcopy_event (event, event2);
2585 Fdeallocate_event (event);
2589 * Handle a magic event off the dispatch queue.
2592 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2594 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2602 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2603 struct frame *f = XFRAME (frame);
2604 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2607 /* struct gcpro gcpro1; */
2609 /* Clear sticky modifiers here (if we had any) */
2611 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2612 /* GCPRO1 (conser); XXX Not necessary? */
2613 emacs_handle_focus_change_preliminary (conser);
2614 /* Under X the stuff up to here is done in the X event handler.
2616 emacs_handle_focus_change_final (conser);
2625 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2626 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2628 Qmap_frame_hook : Qunmap_frame_hook,
2633 /* #### What about Enter & Leave */
2635 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2636 Qmouse_leave_frame_hook, 1, frame);
2644 #ifndef HAVE_MSG_SELECT
2646 get_process_input_waitable (struct Lisp_Process *process)
2648 Lisp_Object instr, outstr, p;
2649 XSETPROCESS (p, process);
2650 get_process_streams (process, &instr, &outstr);
2651 assert (!NILP (instr));
2652 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2653 return (network_connection_p (p)
2654 ? get_winsock_stream_waitable (XLSTREAM (instr))
2655 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2657 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2662 emacs_mswindows_select_process (struct Lisp_Process *process)
2664 HANDLE hev = get_process_input_waitable (process);
2666 if (!add_waitable_handle (hev))
2667 error ("Too many active processes");
2669 #ifdef HAVE_WIN32_PROCESSES
2672 XSETPROCESS (p, process);
2673 if (!network_connection_p (p))
2675 HANDLE hprocess = get_nt_process_handle (process);
2676 if (!add_waitable_handle (hprocess))
2678 remove_waitable_handle (hev);
2679 error ("Too many active processes");
2687 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2689 /* Process handle is removed in the event loop as soon
2690 as it is signaled, so don't bother here about it */
2691 HANDLE hev = get_process_input_waitable (process);
2692 remove_waitable_handle (hev);
2694 #endif /* HAVE_MSG_SELECT */
2697 emacs_mswindows_select_console (struct console *con)
2699 #ifdef HAVE_MSG_SELECT
2700 if (CONSOLE_MSWINDOWS_P (con))
2701 return; /* mswindows consoles are automatically selected */
2703 event_stream_unixoid_select_console (con);
2708 emacs_mswindows_unselect_console (struct console *con)
2710 #ifdef HAVE_MSG_SELECT
2711 if (CONSOLE_MSWINDOWS_P (con))
2712 return; /* mswindows consoles are automatically selected */
2714 event_stream_unixoid_unselect_console (con);
2719 emacs_mswindows_quit_p (void)
2723 /* Quit cannot happen in modal loop: all program
2724 input is dedicated to Windows. */
2725 if (mswindows_in_modal_loop)
2728 /* Drain windows queue. This sets up number of quit characters in the queue
2729 * (and also processes wm focus change, move, resize, etc messages).
2730 * We don't want to process WM_PAINT messages because this function can be
2731 * called from almost anywhere and the windows' states may be changing. */
2732 while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
2733 PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
2734 DispatchMessage (&msg);
2736 if (mswindows_quit_chars_count > 0)
2738 /* Yes there's a hidden one... Throw it away */
2739 struct Lisp_Event match_against;
2740 Lisp_Object emacs_event;
2742 match_against.event_type = key_press_event;
2743 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2745 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2746 assert (!NILP (emacs_event));
2748 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2751 Fdeallocate_event(emacs_event);
2752 --mswindows_quit_chars_count;
2757 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2758 Lisp_Object* instream,
2759 Lisp_Object* outstream,
2762 /* Handles for streams */
2764 /* fds. These just stored along with the streams, and are closed in
2765 delete stream pair method, because we need to handle fake unices
2769 /* Decode inhandle and outhandle. Their meaning depends on
2770 the process implementation being used. */
2771 #if defined (HAVE_WIN32_PROCESSES)
2772 /* We're passed in Windows handles. That's what we like most... */
2773 hin = (HANDLE) inhandle;
2774 hout = (HANDLE) outhandle;
2776 #elif defined (HAVE_UNIX_PROCESSES)
2777 /* We are passed UNIX fds. This must be Cygwin.
2779 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2780 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2784 #error "So, WHICH kind of processes do you want?"
2787 *instream = (hin == INVALID_HANDLE_VALUE
2789 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2790 : flags & STREAM_NETWORK_CONNECTION
2791 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2793 : make_ntpipe_input_stream (hin, fdi));
2795 #ifdef HAVE_WIN32_PROCESSES
2796 *outstream = (hout == INVALID_HANDLE_VALUE
2798 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2799 : flags & STREAM_NETWORK_CONNECTION
2800 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2802 : make_ntpipe_output_stream (hout, fdo));
2803 #elif defined (HAVE_UNIX_PROCESSES)
2804 *outstream = (fdo >= 0
2805 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2808 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2809 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2810 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2812 Bufbyte eof_char = get_eof_char (fdo);
2813 int pty_max_bytes = get_pty_max_bytes (fdo);
2814 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2819 return (NILP (*instream)
2821 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2822 : flags & STREAM_NETWORK_CONNECTION
2823 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2825 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2829 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2830 Lisp_Object outstream)
2832 /* Oh nothing special here for Win32 at all */
2833 #if defined (HAVE_UNIX_PROCESSES)
2834 int in = (NILP(instream)
2836 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2837 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2838 ? get_winsock_stream_param (XLSTREAM (instream))
2840 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2841 int out = (NILP(outstream) ? -1
2842 : filedesc_stream_fd (XLSTREAM (outstream)));
2846 if (out != in && out >= 0)
2850 return (NILP (instream)
2852 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2853 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2854 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2856 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2859 #ifndef HAVE_X_WINDOWS
2860 /* This is called from GC when a process object is about to be freed.
2861 If we've still got pointers to it in this file, we're gonna lose hard.
2864 debug_process_finalization (struct Lisp_Process *p)
2867 Lisp_Object instr, outstr;
2869 get_process_streams (p, &instr, &outstr);
2870 /* if it still has fds, then it hasn't been killed yet. */
2871 assert (NILP(instr));
2872 assert (NILP(outstr));
2874 /* #### More checks here */
2879 /************************************************************************/
2880 /* initialization */
2881 /************************************************************************/
2884 vars_of_event_mswindows (void)
2886 mswindows_u_dispatch_event_queue = Qnil;
2887 staticpro (&mswindows_u_dispatch_event_queue);
2888 mswindows_u_dispatch_event_queue_tail = Qnil;
2890 mswindows_s_dispatch_event_queue = Qnil;
2891 staticpro (&mswindows_s_dispatch_event_queue);
2892 mswindows_s_dispatch_event_queue_tail = Qnil;
2894 mswindows_error_caught_in_modal_loop = Qnil;
2895 staticpro (&mswindows_error_caught_in_modal_loop);
2896 mswindows_in_modal_loop = 0;
2897 mswindows_pending_timers_count = 0;
2899 mswindows_event_stream = xnew (struct event_stream);
2901 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2902 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2903 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2904 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2905 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2906 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2907 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2908 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2909 #ifdef HAVE_MSG_SELECT
2910 mswindows_event_stream->select_process_cb =
2911 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2912 mswindows_event_stream->unselect_process_cb =
2913 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2914 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2915 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2917 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2918 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2919 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2920 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2923 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2924 *Controls redrawing frame contents during mouse-drag or keyboard resize
2925 operation. When non-nil, the frame is redrawn while being resized. When
2926 nil, frame is not redrawn, and exposed areas are filled with default
2927 MDI application background color. Note that this option only has effect
2928 if "Show window contents while dragging" is on in system Display/Plus!
2930 Default is t on fast machines, nil on slow.
2933 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2934 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2935 *Analogue of double click interval for faking middle mouse events.
2936 The value is the minimum time in milliseconds that must elapse between
2937 left/right button down events before they are considered distinct events.
2938 If both mouse buttons are depressed within this interval, a middle mouse
2939 button down event is generated instead.
2940 If negative or zero, currently set system default is used instead.
2943 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2944 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2945 Number of physical mouse buttons.
2948 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2949 *Maximum horizontal distance in pixels between points in which left and
2950 right button clicks occurred for them to be translated into single
2951 middle button event. Clicks must occur in time not longer than defined
2952 by the variable `mswindows-mouse-button-tolerance'.
2953 If negative or zero, currently set system default is used instead.
2956 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2957 *Maximum vertical distance in pixels between points in which left and
2958 right button clicks occurred for them to be translated into single
2959 middle button event. Clicks must occur in time not longer than defined
2960 by the variable `mswindows-mouse-button-tolerance'.
2961 If negative or zero, currently set system default is used instead.
2964 mswindows_mouse_button_max_skew_x = 0;
2965 mswindows_mouse_button_max_skew_y = 0;
2966 mswindows_mouse_button_tolerance = 0;
2970 syms_of_event_mswindows (void)
2975 lstream_type_create_mswindows_selectable (void)
2977 init_slurp_stream ();
2978 init_shove_stream ();
2979 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2980 init_winsock_stream ();
2985 init_event_mswindows_late (void)
2987 #ifdef HAVE_MSG_SELECT
2988 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2989 assert (windows_fd>=0);
2990 FD_SET (windows_fd, &input_wait_mask);
2991 FD_ZERO(&zero_mask);
2994 event_stream = mswindows_event_stream;
2996 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2997 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);