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.
36 #include "console-msw.h"
38 #ifdef HAVE_SCROLLBARS
39 # include "scrollbar-msw.h"
43 # include "menubar-msw.h"
47 # include "dragdrop.h"
55 #include "redisplay.h"
61 #include "events-mod.h"
62 #ifdef HAVE_MSG_SELECT
64 #elif defined(__CYGWIN32__)
65 typedef unsigned int SOCKET;
71 #define ADJR_MENUFLAG TRUE
73 #define ADJR_MENUFLAG FALSE
76 /* Fake key modifier which is attached to a quit char event.
77 Removed upon dequeueing an event */
78 #define FAKE_MOD_QUIT 0x80
80 /* Timer ID used for button2 emulation */
81 #define BUTTON_2_TIMER_ID 1
84 mswindows_get_toolbar_button_text (struct frame* f, int command_id);
86 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id);
88 static Lisp_Object mswindows_find_frame (HWND hwnd);
89 static Lisp_Object mswindows_find_console (HWND hwnd);
90 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods);
91 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
92 static void mswindows_set_chord_timer (HWND hwnd);
93 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
94 static int mswindows_current_layout_has_AltGr (void);
96 static struct event_stream *mswindows_event_stream;
98 #ifdef HAVE_MSG_SELECT
99 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
100 extern SELECT_TYPE process_only_mask, tty_only_mask;
101 SELECT_TYPE zero_mask;
102 extern int signal_event_pipe_initialized;
107 * Two separate queues, for efficiency, one (_u_) for user events, and
108 * another (_s_) for non-user ones. We always return events out of the
109 * first one until it is empty and only then proceed with the second
112 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
113 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
115 /* The number of things we can wait on */
116 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
118 /* List of mswindows waitable handles. */
119 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
121 /* Number of wait handles */
122 static int mswindows_waitable_count=0;
124 /* Count of quit chars currently in the queue */
125 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
126 Decremented in mswindows_dequeue_dispatch_event() */
127 int mswindows_quit_chars_count = 0;
129 /* These are Lisp integers; see DEFVARS in this file for description. */
130 int mswindows_dynamic_frame_resize;
131 int mswindows_num_mouse_buttons;
132 int mswindows_mouse_button_max_skew_x;
133 int mswindows_mouse_button_max_skew_y;
134 int mswindows_mouse_button_tolerance;
136 /* This is the event signaled by the event pump.
137 See mswindows_pump_outstanding_events for comments */
138 static Lisp_Object mswindows_error_caught_in_modal_loop;
139 static int mswindows_in_modal_loop;
141 /* Count of wound timers */
142 static int mswindows_pending_timers_count;
144 /************************************************************************/
145 /* Pipe instream - reads process output */
146 /************************************************************************/
148 #define PIPE_READ_DELAY 20
150 #define HANDLE_TO_USID(h) ((USID)(h))
152 #define NTPIPE_SLURP_STREAM_DATA(stream) \
153 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
155 /* This structure is allocated by the main thread, and is deallocated
156 in the thread upon exit. There are situations when a thread
157 remains blocked for a long time, much longer than the lstream
158 exists. For example, "start notepad" command is issued from the
159 shell, then the shell is closed by C-c C-d. Although the shell
160 process exits, its output pipe will not get closed until the
161 notepad process exits also, because it inherits the pipe form the
162 shell. In this case, we abandon the thread, and let it live until
163 all such processes exit. While struct ntpipe_slurp_stream is
164 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
166 struct ntpipe_slurp_stream_shared_data
168 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
169 /* This is a manual-reset object. */
170 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
171 /* This is a manual-reset object. */
172 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
173 /* This is a manual-reset object. */
174 HANDLE hpipe; /* Pipe read end handle. */
175 LONG die_p; /* Thread must exit ASAP if non-zero */
176 BOOL eof_p : 1; /* Set when thread saw EOF */
177 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
178 BOOL inuse_p : 1; /* this structure is in use */
179 LONG lock_count; /* Client count of this struct, 0=safe to free */
180 BYTE onebyte; /* One byte buffer read by thread */
183 #define MAX_SLURP_STREAMS 32
184 struct ntpipe_slurp_stream_shared_data
185 shared_data_block[MAX_SLURP_STREAMS]={{0}};
187 struct ntpipe_slurp_stream
189 LPARAM user_data; /* Any user data stored in the stream object */
190 struct ntpipe_slurp_stream_shared_data* thread_data;
193 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
194 sizeof (struct ntpipe_slurp_stream));
196 /* This function is thread-safe, and is called from either thread
197 context. It serializes freeing shared data structure */
199 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
201 if (InterlockedDecrement (&s->lock_count) == 0)
204 CloseHandle (s->hev_thread);
205 CloseHandle (s->hev_caller);
206 CloseHandle (s->hev_unsleep);
211 static struct ntpipe_slurp_stream_shared_data*
212 slurper_allocate_shared_data()
215 for (i=0; i<MAX_SLURP_STREAMS; i++)
217 if (!shared_data_block[i].inuse_p)
219 shared_data_block[i].inuse_p=1;
220 return &shared_data_block[i];
223 return (struct ntpipe_slurp_stream_shared_data*)0;
227 slurp_thread (LPVOID vparam)
229 struct ntpipe_slurp_stream_shared_data *s =
230 (struct ntpipe_slurp_stream_shared_data*)vparam;
234 /* Read one byte from the pipe */
236 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
238 DWORD err = GetLastError ();
239 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
244 else if (actually_read == 0)
247 /* We must terminate on an error or eof */
248 if (s->eof_p || s->error_p)
249 InterlockedIncrement (&s->die_p);
251 /* Before we notify caller, we unsignal our event. */
252 ResetEvent (s->hev_thread);
254 /* Now we got something to notify caller, either a byte or an
255 error/eof indication. Before we do, allow internal pipe
256 buffer to accumulate little bit more data.
257 Reader function pulses this event before waiting for
258 a character, to avoid pipe delay, and to get the byte
261 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
263 /* Either make event loop generate a process event, or
265 SetEvent (s->hev_caller);
267 /* Cleanup and exit if we're shot off */
271 /* Block until the client finishes with retrieving the rest of
273 WaitForSingleObject (s->hev_thread, INFINITE);
276 slurper_free_shared_data_maybe (s);
282 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
285 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
286 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
287 DWORD thread_id_unused;
290 /* We deal only with pipes, for we're using PeekNamedPipe api */
291 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
293 s->thread_data = slurper_allocate_shared_data();
295 /* Create reader thread. This could fail, so do not create events
296 until thread is created */
297 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
298 CREATE_SUSPENDED, &thread_id_unused);
301 Lstream_delete (lstr);
302 s->thread_data->inuse_p=0;
306 /* Shared data are initially owned by both main and slurper
308 s->thread_data->lock_count = 2;
309 s->thread_data->die_p = 0;
310 s->thread_data->eof_p = FALSE;
311 s->thread_data->error_p = FALSE;
312 s->thread_data->hpipe = hpipe;
313 s->user_data = param;
315 /* hev_thread is a manual-reset event, initially signaled */
316 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
317 /* hev_caller is a manual-reset event, initially nonsignaled */
318 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
319 /* hev_unsleep is a manual-reset event, initially nonsignaled */
320 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
323 ResumeThread (hthread);
324 CloseHandle (hthread);
326 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
327 XSETLSTREAM (obj, lstr);
332 get_ntpipe_input_stream_param (Lstream *stream)
334 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
339 get_ntpipe_input_stream_waitable (Lstream *stream)
341 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
342 return s->thread_data->hev_caller;
346 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
348 /* This function must be called from the main thread only */
349 struct ntpipe_slurp_stream_shared_data* s =
350 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
355 /* Disallow pipe read delay for the thread: we need a character
357 SetEvent (s->hev_unsleep);
359 /* Check if we have a character ready. Give it a short delay,
360 for the thread to awake from pipe delay, just ion case*/
361 wait_result = WaitForSingleObject (s->hev_caller, 2);
363 /* Revert to the normal sleep behavior. */
364 ResetEvent (s->hev_unsleep);
366 /* If there's no byte buffered yet, give up */
367 if (wait_result == WAIT_TIMEOUT)
374 /* Reset caller unlock event now, as we've handled the pending
375 process output event */
376 ResetEvent (s->hev_caller);
378 /* It is now safe to do anything with contents of S, except for
379 changing s->die_p, which still should be interlocked */
383 if (s->error_p || s->die_p)
386 /* Ok, there were no error neither eof - we've got a byte from the
388 *(data++) = s->onebyte;
392 DWORD bytes_read = 0;
395 DWORD bytes_available;
397 /* If the api call fails, return at least one byte already
398 read. ReadFile in thread will return error */
399 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
402 /* Fetch available bytes. The same consideration applies,
403 so do not check for errors. ReadFile in the thread will
404 fail if the next call fails. */
406 ReadFile (s->hpipe, data, min (bytes_available, size),
410 /* Now we can unblock thread, so it attempts to read more */
411 SetEvent (s->hev_thread);
412 return bytes_read + 1;
419 ntpipe_slurp_closer (Lstream *stream)
421 /* This function must be called from the main thread only */
422 struct ntpipe_slurp_stream_shared_data* s =
423 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
425 /* Force thread to stop */
426 InterlockedIncrement (&s->die_p);
428 /* Set events which could possibly block slurper. Let it finish soon
430 SetEvent (s->hev_unsleep);
431 SetEvent (s->hev_thread);
433 /* Unlock and maybe free shared data */
434 slurper_free_shared_data_maybe (s);
440 init_slurp_stream (void)
442 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
443 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
446 /************************************************************************/
447 /* Pipe outstream - writes process input */
448 /************************************************************************/
450 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
451 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
453 #define MAX_SHOVE_BUFFER_SIZE 128
455 struct ntpipe_shove_stream
457 LPARAM user_data; /* Any user data stored in the stream object */
458 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
459 /* This is an auto-reset object. */
460 HANDLE hpipe; /* Pipe write end handle. */
461 HANDLE hthread; /* Reader thread handle. */
462 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
463 DWORD size; /* Number of bytes to write */
464 LONG die_p; /* Thread must exit ASAP if non-zero */
465 LONG idle_p; /* Non-zero if thread is waiting for job */
466 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
467 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
470 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
471 sizeof (struct ntpipe_shove_stream));
474 shove_thread (LPVOID vparam)
476 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
482 /* Block on event and wait for a job */
483 InterlockedIncrement (&s->idle_p);
484 WaitForSingleObject (s->hev_thread, INFINITE);
489 /* Write passed buffer */
490 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
491 || bytes_written != s->size)
494 InterlockedIncrement (&s->die_p);
505 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
508 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
509 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
510 DWORD thread_id_unused;
515 s->user_data = param;
517 /* Create reader thread. This could fail, so do not
518 create the event until thread is created */
519 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
520 CREATE_SUSPENDED, &thread_id_unused);
521 if (s->hthread == NULL)
523 Lstream_delete (lstr);
527 /* hev_thread is an auto-reset event, initially nonsignaled */
528 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
531 ResumeThread (s->hthread);
533 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
534 XSETLSTREAM (obj, lstr);
539 get_ntpipe_output_stream_param (Lstream *stream)
541 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
546 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
548 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
553 s->blocking_p = !s->idle_p;
557 if (size>MAX_SHOVE_BUFFER_SIZE)
560 memcpy (s->buffer, data, size);
564 InterlockedDecrement (&s->idle_p);
565 SetEvent (s->hev_thread);
570 ntpipe_shove_was_blocked_p (Lstream *stream)
572 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
573 return s->blocking_p;
577 ntpipe_shove_closer (Lstream *stream)
579 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
581 /* Force thread stop */
582 InterlockedIncrement (&s->die_p);
584 /* Close pipe handle, possibly breaking it */
585 CloseHandle (s->hpipe);
587 /* Thread will end upon unblocking */
588 SetEvent (s->hev_thread);
590 /* Wait while thread terminates */
591 WaitForSingleObject (s->hthread, INFINITE);
592 CloseHandle (s->hthread);
594 /* Destroy the event */
595 CloseHandle (s->hev_thread);
601 init_shove_stream (void)
603 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
604 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
605 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
608 /************************************************************************/
609 /* Winsock I/O stream */
610 /************************************************************************/
611 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
613 #define WINSOCK_READ_BUFFER_SIZE 1024
615 struct winsock_stream
617 LPARAM user_data; /* Any user data stored in the stream object */
618 SOCKET s; /* Socket handle (which is a Win32 handle) */
619 OVERLAPPED ov; /* Overlapped I/O structure */
620 void* buffer; /* Buffer. Allocated for input stream only */
621 unsigned int bufsize; /* Number of bytes last read */
622 unsigned int bufpos; /* Position in buffer for next fetch */
623 unsigned int error_p :1; /* I/O Error seen */
624 unsigned int eof_p :1; /* EOF Error seen */
625 unsigned int pending_p :1; /* There is a pending I/O operation */
626 unsigned int blocking_p :1; /* Last write attempt would block */
629 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
631 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
632 sizeof (struct winsock_stream));
635 winsock_initiate_read (struct winsock_stream *str)
637 ResetEvent (str->ov.hEvent);
640 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
641 &str->bufsize, &str->ov))
643 if (GetLastError () == ERROR_IO_PENDING)
645 else if (GetLastError () == ERROR_HANDLE_EOF)
650 else if (str->bufsize == 0)
655 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
657 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
659 /* If the current operation is not yet complete, there's nothing to
663 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
670 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
672 if (GetLastError() == ERROR_HANDLE_EOF)
677 if (str->bufsize == 0)
688 /* Return as much of buffer as we have */
689 size = min (size, (size_t) (str->bufsize - str->bufpos));
690 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
693 /* Read more if buffer is exhausted */
694 if (str->bufsize == str->bufpos)
695 winsock_initiate_read (str);
701 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
703 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
707 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
715 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
730 ResetEvent (str->ov.hEvent);
732 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
733 * an overlapped operation. This fails on Win95 with winsock 1.x so we
734 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
735 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
736 || GetLastError() == ERROR_IO_PENDING)
742 return str->error_p ? -1 : size;
746 winsock_closer (Lstream *lstr)
748 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
750 if (lstr->flags & LSTREAM_FL_READ)
751 shutdown (str->s, 0);
753 shutdown (str->s, 1);
755 CloseHandle ((HANDLE)str->s);
757 WaitForSingleObject (str->ov.hEvent, INFINITE);
759 if (lstr->flags & LSTREAM_FL_READ)
762 CloseHandle (str->ov.hEvent);
767 winsock_was_blocked_p (Lstream *stream)
769 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
770 return str->blocking_p;
774 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
777 Lstream *lstr = Lstream_new (lstream_winsock, mode);
778 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
785 str->user_data = param;
788 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
790 if (lstr->flags & LSTREAM_FL_READ)
792 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
793 winsock_initiate_read (str);
796 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
797 XSETLSTREAM (obj, lstr);
802 make_winsock_input_stream (SOCKET s, LPARAM param)
804 return make_winsock_stream_1 (s, param, "r");
808 make_winsock_output_stream (SOCKET s, LPARAM param)
810 return make_winsock_stream_1 (s, param, "w");
814 get_winsock_stream_waitable (Lstream *lstr)
816 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
817 return str->ov.hEvent;
821 get_winsock_stream_param (Lstream *lstr)
823 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
824 return str->user_data;
828 init_winsock_stream (void)
830 LSTREAM_HAS_METHOD (winsock, reader);
831 LSTREAM_HAS_METHOD (winsock, writer);
832 LSTREAM_HAS_METHOD (winsock, closer);
833 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
835 #endif /* defined (HAVE_SOCKETS) */
837 /************************************************************************/
838 /* Dispatch queue management */
839 /************************************************************************/
842 mswindows_user_event_p (struct Lisp_Event* sevt)
844 return (sevt->event_type == key_press_event
845 || sevt->event_type == button_press_event
846 || sevt->event_type == button_release_event
847 || sevt->event_type == misc_user_event);
851 * Add an emacs event to the proper dispatch queue
854 mswindows_enqueue_dispatch_event (Lisp_Object event)
856 int user_p = mswindows_user_event_p (XEVENT(event));
857 enqueue_event (event,
858 user_p ? &mswindows_u_dispatch_event_queue :
859 &mswindows_s_dispatch_event_queue,
860 user_p ? &mswindows_u_dispatch_event_queue_tail :
861 &mswindows_s_dispatch_event_queue_tail);
863 /* Avoid blocking on WaitMessage */
864 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
868 * Add a misc-user event to the dispatch queue.
870 * Stuff it into our own dispatch queue, so we have something
871 * to return from next_event callback.
874 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
877 Lisp_Object event = Fmake_event (Qnil, Qnil);
878 struct Lisp_Event* e = XEVENT (event);
880 e->event_type = misc_user_event;
881 e->channel = channel;
882 e->event.misc.function = function;
883 e->event.misc.object = object;
885 mswindows_enqueue_dispatch_event (event);
889 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
891 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
892 struct Lisp_Event* event = XEVENT (emacs_event);
894 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
895 event->timestamp = GetMessageTime();
896 event->event_type = magic_event;
897 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
899 mswindows_enqueue_dispatch_event (emacs_event);
903 mswindows_enqueue_process_event (struct Lisp_Process* p)
905 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
906 struct Lisp_Event* event = XEVENT (emacs_event);
908 XSETPROCESS (process, p);
910 event->event_type = process_event;
911 event->timestamp = GetTickCount ();
912 event->event.process.process = process;
914 mswindows_enqueue_dispatch_event (emacs_event);
918 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
921 /* We always use last message time, because mouse button
922 events may get delayed, and XEmacs double click
923 recognition will fail */
925 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
926 struct Lisp_Event* event = XEVENT(emacs_event);
928 event->channel = mswindows_find_frame(hwnd);
929 event->timestamp = when;
930 event->event.button.button =
931 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
932 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
933 event->event.button.x = where.x;
934 event->event.button.y = where.y;
935 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
937 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
938 message==WM_RBUTTONDOWN)
940 event->event_type = button_press_event;
945 event->event_type = button_release_event;
949 mswindows_enqueue_dispatch_event (emacs_event);
953 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
955 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
956 struct Lisp_Event* event = XEVENT(emacs_event);
958 event->channel = mswindows_find_console(hwnd);
959 event->timestamp = GetMessageTime();
960 event->event_type = key_press_event;
961 event->event.key.keysym = keysym;
962 event->event.key.modifiers = mods;
963 mswindows_enqueue_dispatch_event (emacs_event);
967 * Remove and return the first emacs event on the dispatch queue.
968 * Give a preference to user events over non-user ones.
971 mswindows_dequeue_dispatch_event ()
974 struct Lisp_Event* sevt;
976 assert (!NILP(mswindows_u_dispatch_event_queue) ||
977 !NILP(mswindows_s_dispatch_event_queue));
979 event = dequeue_event (
980 NILP(mswindows_u_dispatch_event_queue) ?
981 &mswindows_s_dispatch_event_queue :
982 &mswindows_u_dispatch_event_queue,
983 NILP(mswindows_u_dispatch_event_queue) ?
984 &mswindows_s_dispatch_event_queue_tail :
985 &mswindows_u_dispatch_event_queue_tail);
987 sevt = XEVENT(event);
988 if (sevt->event_type == key_press_event
989 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
991 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
992 --mswindows_quit_chars_count;
999 * Remove and return the first emacs event on the dispatch queue that matches
1000 * the supplied event
1001 * Timeout event matches if interval_id equals to that of the given event.
1002 * Keypress event matches if logical AND between modifiers bitmask of the
1003 * event in the queue and that of the given event is non-zero
1004 * For all other event types, this function asserts.
1008 mswindows_cancel_dispatch_event (struct Lisp_Event* match)
1011 Lisp_Object previous_event=Qnil;
1012 int user_p = mswindows_user_event_p (match);
1013 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1014 &mswindows_s_dispatch_event_queue;
1015 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1016 &mswindows_s_dispatch_event_queue_tail;
1018 assert (match->event_type == timeout_event
1019 || match->event_type == key_press_event);
1021 EVENT_CHAIN_LOOP (event, *head)
1024 if (XEVENT_TYPE (event) != match->event_type)
1026 if (found && match->event_type == timeout_event
1027 && (XEVENT(event)->event.timeout.interval_id !=
1028 match->event.timeout.interval_id))
1030 if (found && match->event_type == key_press_event
1031 && ((XEVENT(event)->event.key.modifiers &
1032 match->event.key.modifiers) == 0))
1037 if (NILP (previous_event))
1038 dequeue_event (head, tail);
1041 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1042 if (EQ (*tail, event))
1043 *tail = previous_event;
1048 previous_event = event;
1053 /************************************************************************/
1054 /* Waitable handles manipulation */
1055 /************************************************************************/
1057 find_waitable_handle (HANDLE h)
1060 for (i = 0; i < mswindows_waitable_count; ++i)
1061 if (mswindows_waitable_handles[i] == h)
1068 add_waitable_handle (HANDLE h)
1070 assert (find_waitable_handle (h) < 0);
1071 if (mswindows_waitable_count == MAX_WAITABLE)
1074 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1079 remove_waitable_handle (HANDLE h)
1081 int ix = find_waitable_handle (h);
1085 mswindows_waitable_handles [ix] =
1086 mswindows_waitable_handles [--mswindows_waitable_count];
1090 /************************************************************************/
1092 /************************************************************************/
1095 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1096 Lisp_Object u_n_u_s_e_d)
1098 mswindows_error_caught_in_modal_loop = cons_sig_data;
1103 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1108 ++mswindows_in_modal_loop;
1109 tmp = condition_case_1 (Qt,
1111 mswindows_modal_loop_error_handler, Qnil);
1112 --mswindows_in_modal_loop;
1118 mswindows_unmodalize_signal_maybe (void)
1120 if (!NILP (mswindows_error_caught_in_modal_loop))
1122 /* Got an error while messages were pumped while
1123 in window procedure - have to resignal */
1124 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1125 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1126 mswindows_error_caught_in_modal_loop = Qnil;
1127 Fsignal (sym, data);
1132 * This is an unsafe part of event pump, guarded by
1133 * condition_case. See mswindows_pump_outstanding_events
1136 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1138 /* This function can call lisp */
1139 Lisp_Object event = Fmake_event (Qnil, Qnil);
1140 struct gcpro gcpro1;
1141 int do_redisplay = 0;
1144 while (detect_input_pending ())
1146 Fnext_event (event, Qnil);
1147 Fdispatch_event (event);
1154 Fdeallocate_event (event);
1157 /* Qt becomes return value of mswindows_pump_outstanding_events
1163 * This function pumps emacs events, while available, by using
1164 * next_message/dispatch_message loop. Errors are trapped around
1165 * the loop so the function always returns.
1167 * Windows message queue is not looked into during the call,
1168 * neither are waitable handles checked. The function pumps
1169 * thus only dispatch events already queued, as well as those
1170 * resulted in dispatching thereof. This is done by setting
1171 * module local variable mswindows_in_modal_loop to nonzero.
1173 * Return value is Qt if no errors was trapped, or Qunbound if
1174 * there was an error.
1176 * In case of error, a cons representing the error, in the
1177 * form (SIGNAL . DATA), is stored in the module local variable
1178 * mswindows_error_caught_in_modal_loop. This error is signaled
1179 * again when DispatchMessage returns. Thus, Windows internal
1180 * modal loops are protected against throws, which are proven
1181 * to corrupt internal Windows structures.
1183 * In case of success, mswindows_error_caught_in_modal_loop is
1186 * If the value of mswindows_error_caught_in_modal_loop is not
1187 * nil already upon entry, the function just returns non-nil.
1188 * This situation means that a new event has been queued while
1189 * in cancel mode. The event will be dequeued on the next regular
1190 * call of next-event; the pump is off since error is caught.
1191 * The caller must *unconditionally* cancel modal loop if the
1192 * value returned by this function is nil. Otherwise, everything
1193 * will become frozen until the modal loop exits under normal
1194 * condition (scrollbar drag is released, menu closed etc.)
1197 mswindows_pump_outstanding_events (void)
1199 /* This function can call lisp */
1201 Lisp_Object result = Qt;
1202 struct gcpro gcpro1;
1205 if (NILP(mswindows_error_caught_in_modal_loop))
1206 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1212 mswindows_drain_windows_queue ()
1215 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1217 DispatchMessage (&msg);
1218 mswindows_unmodalize_signal_maybe ();
1223 * This is a special flavor of the mswindows_need_event function,
1224 * used while in event pump. Actually, there is only kind of events
1225 * allowed while in event pump: a timer. An attempt to fetch any
1226 * other event leads to a deadlock, as there's no source of user input
1227 * ('cause event pump mirrors windows modal loop, which is a sole
1228 * owner of thread message queue).
1230 * To detect this, we use a counter of active timers, and allow
1231 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1232 * which will never come when there are no pending timers, which leads
1233 * to deadlock, we simply signal an error.
1236 mswindows_need_event_in_modal_loop (int badly_p)
1240 /* Check if already have one */
1241 if (!NILP (mswindows_u_dispatch_event_queue)
1242 || !NILP (mswindows_s_dispatch_event_queue))
1245 /* No event is ok */
1249 /* We do not check the _u_ queue, because timers go to _s_ */
1250 while (NILP (mswindows_s_dispatch_event_queue))
1252 /* We'll deadlock if go waiting */
1253 if (mswindows_pending_timers_count == 0)
1254 error ("Deadlock due to an attempt to call next-event in a wrong context");
1256 /* Fetch and dispatch any pending timers */
1257 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1258 DispatchMessage (&msg);
1263 * This drains the event queue and fills up two internal queues until
1264 * an event of a type specified by USER_P is retrieved.
1267 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1270 mswindows_need_event (int badly_p)
1274 if (mswindows_in_modal_loop)
1276 mswindows_need_event_in_modal_loop (badly_p);
1280 /* Have to drain Windows message queue first, otherwise, we may miss
1281 quit char when called from quit_p */
1282 mswindows_drain_windows_queue ();
1284 while (NILP (mswindows_u_dispatch_event_queue)
1285 && NILP (mswindows_s_dispatch_event_queue))
1287 #ifdef HAVE_MSG_SELECT
1289 SELECT_TYPE temp_mask = input_wait_mask;
1290 EMACS_TIME sometime;
1291 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1294 pointer_to_this = 0;
1297 EMACS_SET_SECS_USECS (sometime, 0, 0);
1298 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1299 pointer_to_this = &select_time_to_block;
1302 /* select() is slow and buggy so if we don't have any processes
1303 just wait as normal */
1304 if (memcmp (&process_only_mask, &zero_mask, sizeof(SELECT_TYPE))==0)
1306 /* Now try getting a message or process event */
1307 active = MsgWaitForMultipleObjects (0, mswindows_waitable_handles,
1308 FALSE, badly_p ? INFINITE : 0,
1311 if (active == WAIT_TIMEOUT)
1313 /* No luck trying - just return what we've already got */
1316 else if (active == WAIT_OBJECT_0)
1318 /* Got your message, thanks */
1319 mswindows_drain_windows_queue ();
1324 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1328 return; /* timeout */
1330 else if (active > 0)
1332 if (FD_ISSET (windows_fd, &temp_mask))
1334 mswindows_drain_windows_queue ();
1337 /* Look for a process event */
1338 for (i = 0; i < MAXDESC-1; i++)
1340 if (FD_ISSET (i, &temp_mask))
1342 if (FD_ISSET (i, &process_only_mask))
1344 struct Lisp_Process *p =
1345 get_process_from_usid (FD_TO_USID(i));
1347 mswindows_enqueue_process_event (p);
1349 else if (FD_ISSET (i, &tty_only_mask))
1351 /* do we care about tty events? Do we
1352 ever get tty events? */
1356 /* We might get here when a fake event came
1357 through a signal. Return a dummy event, so
1358 that a cycle of the command loop will
1360 drain_signal_event_pipe ();
1361 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1366 else if (active==-1)
1370 /* something bad happened */
1379 /* Now try getting a message or process event */
1380 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1381 mswindows_waitable_handles,
1382 FALSE, badly_p ? INFINITE : 0,
1385 /* This will assert if handle being waited for becomes abandoned.
1386 Not the case currently tho */
1387 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1388 (active >= WAIT_OBJECT_0 &&
1389 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1391 if (active == WAIT_TIMEOUT)
1393 /* No luck trying - just return what we've already got */
1396 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1398 /* Got your message, thanks */
1399 mswindows_drain_windows_queue ();
1403 int ix = active - WAIT_OBJECT_0;
1404 /* First, try to find which process' output has signaled */
1405 struct Lisp_Process *p =
1406 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1409 /* Found a signaled process input handle */
1410 mswindows_enqueue_process_event (p);
1414 /* None. This means that the process handle itself has signaled.
1415 Remove the handle from the wait vector, and make status_notify
1416 note the exited process */
1417 mswindows_waitable_handles [ix] =
1418 mswindows_waitable_handles [--mswindows_waitable_count];
1419 kick_status_notify ();
1420 /* Have to return something: there may be no accompanying
1422 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1429 /************************************************************************/
1430 /* Event generators */
1431 /************************************************************************/
1434 * Callback procedure for synchronous timer messages
1436 static void CALLBACK
1437 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1439 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1440 struct Lisp_Event *event = XEVENT (emacs_event);
1442 if (KillTimer (NULL, id_timer))
1443 --mswindows_pending_timers_count;
1445 event->channel = Qnil;
1446 event->timestamp = dwtime;
1447 event->event_type = timeout_event;
1448 event->event.timeout.interval_id = id_timer;
1449 event->event.timeout.function = Qnil;
1450 event->event.timeout.object = Qnil;
1452 mswindows_enqueue_dispatch_event (emacs_event);
1456 * Callback procedure for dde messages
1458 * We execute a dde Open("file") by simulating a file drop, so dde support
1459 * depends on dnd support.
1461 #ifdef HAVE_DRAGNDROP
1463 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1464 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1465 DWORD dwData1, DWORD dwData2)
1470 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1471 return (HDDEDATA)TRUE;
1472 return (HDDEDATA)FALSE;
1474 case XTYP_WILDCONNECT:
1476 /* We only support one {service,topic} pair */
1477 HSZPAIR pairs[2] = {
1478 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1480 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1481 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1482 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1483 sizeof (pairs), 0L, 0, uFmt, 0));
1485 return (HDDEDATA)NULL;
1488 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1490 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1491 char *cmd = alloca (len+1);
1494 struct gcpro gcpro1, gcpro2;
1495 Lisp_Object l_dndlist = Qnil;
1496 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1497 Lisp_Object frmcons, devcons, concons;
1498 struct Lisp_Event *event = XEVENT (emacs_event);
1500 DdeGetData (hdata, cmd, len, 0);
1502 DdeFreeDataHandle (hdata);
1504 /* Check syntax & that it's an [Open("foo")] command, which we
1505 * treat like a file drop */
1506 /* #### Ought to be generalised and accept some other commands */
1509 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1510 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1511 return DDE_FNOTPROCESSED;
1512 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1515 if (*cmd!='(' || *(cmd+1)!='\"')
1516 return DDE_FNOTPROCESSED;
1518 while (*end && *end!='\"')
1521 return DDE_FNOTPROCESSED;
1524 return DDE_FNOTPROCESSED;
1528 return DDE_FNOTPROCESSED;
1531 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1532 strcpy (filename, "file:");
1533 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1535 dostounix_filename (cmd);
1536 filename = alloca (strlen (cmd)+6);
1537 strcpy (filename, "file:");
1538 strcat (filename, cmd);
1540 GCPRO2 (emacs_event, l_dndlist);
1541 l_dndlist = make_string (filename, strlen (filename));
1543 /* Find a mswindows frame */
1544 event->channel = Qnil;
1545 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1547 Lisp_Object frame = XCAR (frmcons);
1548 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1549 event->channel = frame;
1551 assert (!NILP (event->channel));
1553 event->timestamp = GetTickCount();
1554 event->event_type = misc_user_event;
1555 event->event.misc.button = 1;
1556 event->event.misc.modifiers = 0;
1557 event->event.misc.x = -1;
1558 event->event.misc.y = -1;
1559 event->event.misc.function = Qdragdrop_drop_dispatch;
1560 event->event.misc.object = Fcons (Qdragdrop_URL,
1561 Fcons (l_dndlist, Qnil));
1562 mswindows_enqueue_dispatch_event (emacs_event);
1564 return (HDDEDATA) DDE_FACK;
1566 DdeFreeDataHandle (hdata);
1567 return (HDDEDATA) DDE_FNOTPROCESSED;
1570 return (HDDEDATA) NULL;
1576 * The windows procedure for the window class XEMACS_CLASS
1579 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1581 /* Note: Remember to initialize emacs_event and event before use.
1582 This code calls code that can GC. You must GCPRO before calling such code. */
1583 Lisp_Object emacs_event = Qnil;
1584 Lisp_Object fobj = Qnil;
1586 struct Lisp_Event *event;
1587 struct frame *frame;
1588 struct mswindows_frame* msframe;
1593 /* Erase background only during non-dynamic sizing */
1594 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1595 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1600 fobj = mswindows_find_frame (hwnd);
1601 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1606 /* See Win95 comment under WM_KEYDOWN */
1610 if (wParam == VK_CONTROL)
1612 GetKeyboardState (keymap);
1613 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1614 SetKeyboardState (keymap);
1616 else if (wParam == VK_MENU)
1618 GetKeyboardState (keymap);
1619 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1620 SetKeyboardState (keymap);
1627 /* In some locales the right-hand Alt key is labelled AltGr. This key
1628 * should produce alternative charcaters when combined with another key.
1629 * eg on a German keyboard pressing AltGr+q should produce '@'.
1630 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1631 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1632 * it translates as if AltGr were down.
1633 * We get round this by removing all modifiers from the keymap before
1634 * calling TranslateMessage() unless AltGr is *really* down. */
1637 int has_AltGr = mswindows_current_layout_has_AltGr ();
1641 GetKeyboardState (keymap);
1642 mods = mswindows_modifier_state (keymap, has_AltGr);
1644 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1645 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1646 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1649 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1650 BYTE keymap_orig[256];
1651 MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
1653 /* GetKeyboardState() does not work as documented on Win95. We have
1654 * to loosely track Left and Right modifiers on behalf of the OS,
1655 * without screwing up Windows NT which tracks them properly. */
1656 if (wParam == VK_CONTROL)
1657 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1658 else if (wParam == VK_MENU)
1659 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1661 memcpy (keymap_orig, keymap, 256);
1663 /* Remove shift modifier from an ascii character */
1666 /* Clear control and alt modifiers unless AltGr is pressed */
1667 keymap [VK_RCONTROL] = 0;
1668 keymap [VK_LMENU] = 0;
1669 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1671 keymap [VK_LCONTROL] = 0;
1672 keymap [VK_CONTROL] = 0;
1673 keymap [VK_RMENU] = 0;
1674 keymap [VK_MENU] = 0;
1676 SetKeyboardState (keymap);
1678 /* Maybe generate some WM_[SYS]CHARs in the queue */
1679 TranslateMessage (&msg);
1681 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1682 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1685 WPARAM ch = msg.wParam;
1687 /* If a quit char with no modifiers other than control and
1688 shift, then mark it with a fake modifier, which is removed
1689 upon dequeueing the event */
1690 /* #### This might also not withstand localization, if
1691 quit character is not a latin-1 symbol */
1692 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1693 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1694 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1696 mods1 |= FAKE_MOD_QUIT;
1697 ++mswindows_quit_chars_count;
1700 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1702 SetKeyboardState (keymap_orig);
1705 /* F10 causes menu activation by default. We do not want this */
1706 if (wParam != VK_F10)
1710 case WM_MBUTTONDOWN:
1712 /* Real middle mouse button has nothing to do with emulated one:
1713 if one wants to exercise fingers playing chords on the mouse,
1714 he is allowed to do that! */
1715 mswindows_enqueue_mouse_button_event (hwnd, message,
1716 MAKEPOINTS (lParam), GetMessageTime());
1720 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1721 msframe->last_click_time = GetMessageTime();
1723 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1724 msframe->button2_need_lbutton = 0;
1725 if (msframe->ignore_next_lbutton_up)
1727 msframe->ignore_next_lbutton_up = 0;
1729 else if (msframe->button2_is_down)
1731 msframe->button2_is_down = 0;
1732 msframe->ignore_next_rbutton_up = 1;
1733 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1734 MAKEPOINTS (lParam), GetMessageTime());
1738 if (msframe->button2_need_rbutton)
1740 msframe->button2_need_rbutton = 0;
1741 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1742 MAKEPOINTS (lParam), GetMessageTime());
1744 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1745 MAKEPOINTS (lParam), GetMessageTime());
1750 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1751 msframe->last_click_time = GetMessageTime();
1753 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1754 msframe->button2_need_rbutton = 0;
1755 if (msframe->ignore_next_rbutton_up)
1757 msframe->ignore_next_rbutton_up = 0;
1759 else if (msframe->button2_is_down)
1761 msframe->button2_is_down = 0;
1762 msframe->ignore_next_lbutton_up = 1;
1763 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1764 MAKEPOINTS (lParam), GetMessageTime());
1768 if (msframe->button2_need_lbutton)
1770 msframe->button2_need_lbutton = 0;
1771 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1772 MAKEPOINTS (lParam), GetMessageTime());
1774 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1775 MAKEPOINTS (lParam), GetMessageTime());
1779 case WM_LBUTTONDOWN:
1780 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1782 if (msframe->button2_need_lbutton)
1784 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1785 msframe->button2_need_lbutton = 0;
1786 msframe->button2_need_rbutton = 0;
1787 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1789 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1790 MAKEPOINTS (lParam), GetMessageTime());
1791 msframe->button2_is_down = 1;
1795 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1796 msframe->last_click_point, msframe->last_click_time);
1797 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1798 MAKEPOINTS (lParam), GetMessageTime());
1803 mswindows_set_chord_timer (hwnd);
1804 msframe->button2_need_rbutton = 1;
1805 msframe->last_click_point = MAKEPOINTS (lParam);
1807 msframe->last_click_time = GetMessageTime();
1810 case WM_RBUTTONDOWN:
1811 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1813 if (msframe->button2_need_rbutton)
1815 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1816 msframe->button2_need_lbutton = 0;
1817 msframe->button2_need_rbutton = 0;
1818 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1820 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1821 MAKEPOINTS (lParam), GetMessageTime());
1822 msframe->button2_is_down = 1;
1826 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1827 msframe->last_click_point, msframe->last_click_time);
1828 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1829 MAKEPOINTS (lParam), GetMessageTime());
1834 mswindows_set_chord_timer (hwnd);
1835 msframe->button2_need_lbutton = 1;
1836 msframe->last_click_point = MAKEPOINTS (lParam);
1838 msframe->last_click_time = GetMessageTime();
1842 if (wParam == BUTTON_2_TIMER_ID)
1844 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1845 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1847 if (msframe->button2_need_lbutton)
1849 msframe->button2_need_lbutton = 0;
1850 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1851 msframe->last_click_point, msframe->last_click_time);
1853 else if (msframe->button2_need_rbutton)
1855 msframe->button2_need_rbutton = 0;
1856 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1857 msframe->last_click_point, msframe->last_click_time);
1861 assert ("Spurious timer fired" == 0);
1865 /* Optimization: don't report mouse movement while size is changing */
1866 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1867 if (!msframe->sizing)
1869 /* When waiting for the second mouse button to finish
1870 button2 emulation, and have moved too far, just pretend
1871 as if timer has expired. This improves drag-select feedback */
1872 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1873 && !mswindows_button2_near_enough (msframe->last_click_point,
1874 MAKEPOINTS (lParam)))
1876 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1877 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1880 emacs_event = Fmake_event (Qnil, Qnil);
1881 event = XEVENT(emacs_event);
1883 event->channel = mswindows_find_frame(hwnd);
1884 event->timestamp = GetMessageTime();
1885 event->event_type = pointer_motion_event;
1886 event->event.motion.x = MAKEPOINTS(lParam).x;
1887 event->event.motion.y = MAKEPOINTS(lParam).y;
1888 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1890 mswindows_enqueue_dispatch_event (emacs_event);
1896 /* Queue a `cancel-mode-internal' misc user event, so mouse
1897 selection would be canceled if any */
1898 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1899 Qcancel_mode_internal, Qnil);
1902 #ifdef HAVE_TOOLBARS
1905 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1907 if (tttext->hdr.code == TTN_NEEDTEXT)
1909 /* find out which toolbar */
1910 frame = XFRAME (mswindows_find_frame (hwnd));
1911 btext = mswindows_get_toolbar_button_text ( frame,
1912 tttext->hdr.idFrom );
1914 tttext->lpszText = NULL;
1915 tttext->hinst = NULL;
1919 /* I think this is safe since the text will only go away
1920 when the toolbar does...*/
1921 tttext->lpszText=XSTRING_DATA (btext);
1924 tttext->uFlags |= TTF_DI_SETITEM;
1933 PAINTSTRUCT paintStruct;
1935 frame = XFRAME (mswindows_find_frame (hwnd));
1937 BeginPaint (hwnd, &paintStruct);
1938 mswindows_redraw_exposed_area (frame,
1939 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1940 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1941 EndPaint (hwnd, &paintStruct);
1946 /* We only care about this message if our size has really changed */
1947 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1952 fobj = mswindows_find_frame (hwnd);
1953 frame = XFRAME (fobj);
1954 msframe = FRAME_MSWINDOWS_DATA (frame);
1956 /* We cannot handle frame map and unmap hooks right in
1957 this routine, because these may throw. We queue
1958 magic events to run these hooks instead - kkm */
1960 if (wParam==SIZE_MINIMIZED)
1963 FRAME_VISIBLE_P (frame) = 0;
1964 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
1968 GetClientRect(hwnd, &rect);
1969 FRAME_PIXWIDTH(frame) = rect.right;
1970 FRAME_PIXHEIGHT(frame) = rect.bottom;
1972 pixel_to_real_char_size (frame, rect.right, rect.bottom,
1973 &FRAME_MSWINDOWS_CHARWIDTH (frame),
1974 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
1976 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
1977 change_frame_size (frame, rows, columns, 1);
1979 /* If we are inside frame creation, we have to apply geometric
1981 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1983 /* Yes, we have to size again */
1984 mswindows_size_frame_internal ( frame,
1985 FRAME_MSWINDOWS_TARGET_RECT
1987 /* Reset so we do not get here again. The SetWindowPos call in
1988 * mswindows_size_frame_internal can cause recursion here. */
1989 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1991 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
1992 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
1997 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
1998 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
1999 FRAME_VISIBLE_P (frame) = 1;
2001 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2008 /* Misc magic events which only require that the frame be identified */
2011 mswindows_enqueue_magic_event (hwnd, message);
2014 case WM_WINDOWPOSCHANGING:
2016 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2017 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2018 GetWindowPlacement(hwnd, &wpl);
2020 /* Only interested if size is changing and we're not being iconified */
2021 if (wpl.showCmd != SW_SHOWMINIMIZED
2022 && wpl.showCmd != SW_SHOWMAXIMIZED
2023 && !(wp->flags & SWP_NOSIZE))
2025 RECT ncsize = { 0, 0, 0, 0 };
2026 int pixwidth, pixheight;
2027 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2028 GetMenu(hwnd) != NULL,
2029 GetWindowLong (hwnd, GWL_EXSTYLE));
2031 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2032 wp->cx - (ncsize.right - ncsize.left),
2033 wp->cy - (ncsize.bottom - ncsize.top),
2034 &pixwidth, &pixheight);
2036 /* Convert client sizes to window sizes */
2037 pixwidth += (ncsize.right - ncsize.left);
2038 pixheight += (ncsize.bottom - ncsize.top);
2040 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2042 /* Adjust so that the bottom or right doesn't move if it's
2043 * the top or left that's being changed */
2045 GetWindowRect (hwnd, &rect);
2047 if (rect.left != wp->x)
2048 wp->x += wp->cx - pixwidth;
2049 if (rect.top != wp->y)
2050 wp->y += wp->cy - pixheight;
2056 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2057 window position if the user tries to track window too small */
2061 case WM_ENTERSIZEMOVE:
2062 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2063 msframe->sizing = 1;
2066 case WM_EXITSIZEMOVE:
2067 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2068 msframe->sizing = 0;
2069 /* Queue noop event */
2070 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2073 #ifdef HAVE_SCROLLBARS
2077 /* Direction of scroll is determined by scrollbar instance. */
2078 int code = (int) LOWORD(wParam);
2079 int pos = (short int) HIWORD(wParam);
2080 HWND hwndScrollBar = (HWND) lParam;
2081 struct gcpro gcpro1, gcpro2;
2083 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2084 GCPRO2 (emacs_event, fobj);
2085 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2087 /* Error during event pumping - cancel scroll */
2088 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2095 #ifdef HAVE_MENUBARS
2097 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2099 XFRAME (mswindows_find_frame (hwnd)))))
2100 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2103 case WM_INITMENUPOPUP:
2104 if (!HIWORD(lParam))
2106 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2108 XFRAME (mswindows_find_frame (hwnd)))))
2109 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2113 #endif /* HAVE_MENUBARS */
2117 WORD id = LOWORD (wParam);
2118 HWND cid = (HWND)lParam;
2119 frame = XFRAME (mswindows_find_frame (hwnd));
2121 #ifdef HAVE_TOOLBARS
2122 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2126 #ifdef HAVE_MENUBARS
2127 if (!NILP (mswindows_handle_wm_command (frame, id)))
2131 /* Bite me - a spurious command. This cannot happen. */
2132 error ("XEMACS BUG: Cannot decode command message");
2136 #ifdef HAVE_DRAGNDROP
2137 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2139 UINT filecount, i, len;
2145 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2146 struct gcpro gcpro1, gcpro2, gcpro3;
2148 emacs_event = Fmake_event (Qnil, Qnil);
2149 event = XEVENT(emacs_event);
2151 GCPRO3 (emacs_event, l_dndlist, l_item);
2153 if (!DragQueryPoint ((HANDLE) wParam, &point))
2154 point.x = point.y = -1; /* outside client area */
2156 event->event_type = misc_user_event;
2157 event->channel = mswindows_find_frame(hwnd);
2158 event->timestamp = GetMessageTime();
2159 event->event.misc.button = 1; /* #### Should try harder */
2160 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2161 event->event.misc.x = point.x;
2162 event->event.misc.y = point.y;
2163 event->event.misc.function = Qdragdrop_drop_dispatch;
2165 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2166 for (i=0; i<filecount; i++)
2168 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2169 /* The URLs that we make here aren't correct according to section
2170 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2171 * because they may contain reserved characters. But that's OK. */
2173 fname = (char *)xmalloc (len+1);
2174 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2175 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2176 strcpy (filename, "file:");
2177 cygwin32_win32_to_posix_path_list (fname, filename+5);
2180 filename = (char *)xmalloc (len+6);
2181 strcpy (filename, "file:");
2182 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2183 dostounix_filename (filename+5);
2185 l_item = make_string (filename, strlen (filename));
2186 l_dndlist = Fcons (l_item, l_dndlist);
2189 DragFinish ((HANDLE) wParam);
2191 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2192 mswindows_enqueue_dispatch_event (emacs_event);
2200 return DefWindowProc (hwnd, message, wParam, lParam);
2206 /************************************************************************/
2207 /* keyboard, mouse & other helpers for the windows procedure */
2208 /************************************************************************/
2210 mswindows_set_chord_timer (HWND hwnd)
2214 /* We get one third half system double click threshold */
2215 if (mswindows_mouse_button_tolerance <= 0)
2216 interval = GetDoubleClickTime () / 3;
2218 interval = mswindows_mouse_button_tolerance;
2220 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2224 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2227 if (mswindows_mouse_button_max_skew_x <= 0)
2228 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2230 dx = mswindows_mouse_button_max_skew_x;
2232 if (mswindows_mouse_button_max_skew_y <= 0)
2233 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2235 dy = mswindows_mouse_button_max_skew_y;
2237 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2241 mswindows_current_layout_has_AltGr (void)
2243 /* This simple caching mechanism saves 10% of CPU
2244 time when a key typed at autorepeat rate of 30 cps! */
2245 static HKL last_hkl = 0;
2246 static int last_hkl_has_AltGr;
2248 HKL current_hkl = GetKeyboardLayout (0);
2249 if (current_hkl != last_hkl)
2252 last_hkl_has_AltGr = 0;
2253 /* In this loop, we query whether a character requires
2254 AltGr to be down to generate it. If at least such one
2255 found, this means that the layout does regard AltGr */
2256 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2257 if (HIBYTE (VkKeyScan (c)) == 6)
2258 last_hkl_has_AltGr = 1;
2259 last_hkl = current_hkl;
2261 return last_hkl_has_AltGr;
2265 /* Returns the state of the modifier keys in the format expected by the
2266 * Lisp_Event key_data, button_data and motion_data modifiers member */
2267 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2273 keymap = (BYTE*) alloca(256);
2274 GetKeyboardState (keymap);
2275 has_AltGr = mswindows_current_layout_has_AltGr ();
2278 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2280 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2281 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2285 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2286 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2289 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2295 * Translate a mswindows virtual key to a keysym.
2296 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2297 * or whose ASCII codes (like space) xemacs doesn't like.
2298 * Virtual key values are defined in winresrc.h
2299 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2301 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2303 switch (mswindows_key)
2305 /* First the predefined ones */
2306 case VK_BACK: return QKbackspace;
2307 case VK_TAB: return QKtab;
2308 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2309 case VK_RETURN: return QKreturn;
2310 case VK_ESCAPE: return QKescape;
2311 case VK_SPACE: return QKspace;
2312 case VK_DELETE: return QKdelete;
2315 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2316 case VK_PRIOR: return KEYSYM ("prior");
2317 case VK_NEXT: return KEYSYM ("next");
2318 case VK_END: return KEYSYM ("end");
2319 case VK_HOME: return KEYSYM ("home");
2320 case VK_LEFT: return KEYSYM ("left");
2321 case VK_UP: return KEYSYM ("up");
2322 case VK_RIGHT: return KEYSYM ("right");
2323 case VK_DOWN: return KEYSYM ("down");
2324 case VK_SELECT: return KEYSYM ("select");
2325 case VK_PRINT: return KEYSYM ("print");
2326 case VK_EXECUTE: return KEYSYM ("execute");
2327 case VK_SNAPSHOT: return KEYSYM ("print");
2328 case VK_INSERT: return KEYSYM ("insert");
2329 case VK_HELP: return KEYSYM ("help");
2330 #if 0 /* XXX What are these supposed to do? */
2331 case VK_LWIN return KEYSYM ("");
2332 case VK_RWIN return KEYSYM ("");
2334 case VK_APPS: return KEYSYM ("menu");
2335 case VK_F1: return KEYSYM ("f1");
2336 case VK_F2: return KEYSYM ("f2");
2337 case VK_F3: return KEYSYM ("f3");
2338 case VK_F4: return KEYSYM ("f4");
2339 case VK_F5: return KEYSYM ("f5");
2340 case VK_F6: return KEYSYM ("f6");
2341 case VK_F7: return KEYSYM ("f7");
2342 case VK_F8: return KEYSYM ("f8");
2343 case VK_F9: return KEYSYM ("f9");
2344 case VK_F10: return KEYSYM ("f10");
2345 case VK_F11: return KEYSYM ("f11");
2346 case VK_F12: return KEYSYM ("f12");
2347 case VK_F13: return KEYSYM ("f13");
2348 case VK_F14: return KEYSYM ("f14");
2349 case VK_F15: return KEYSYM ("f15");
2350 case VK_F16: return KEYSYM ("f16");
2351 case VK_F17: return KEYSYM ("f17");
2352 case VK_F18: return KEYSYM ("f18");
2353 case VK_F19: return KEYSYM ("f19");
2354 case VK_F20: return KEYSYM ("f20");
2355 case VK_F21: return KEYSYM ("f21");
2356 case VK_F22: return KEYSYM ("f22");
2357 case VK_F23: return KEYSYM ("f23");
2358 case VK_F24: return KEYSYM ("f24");
2364 * Find the console that matches the supplied mswindows window handle
2367 mswindows_find_console (HWND hwnd)
2369 /* We only support one console */
2370 return XCAR (Vconsole_list);
2374 * Find the frame that matches the supplied mswindows window handle
2377 mswindows_find_frame (HWND hwnd)
2379 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2383 /* We are in progress of frame creation. Return the frame
2384 being created, as it still not remembered in the window
2386 assert (!NILP (Vmswindows_frame_being_created));
2387 return Vmswindows_frame_being_created;
2389 VOID_TO_LISP (f, l);
2394 /************************************************************************/
2396 /************************************************************************/
2399 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2402 EMACS_TIME current_time;
2403 EMACS_GET_TIME (current_time);
2404 EMACS_SUB_TIME (thyme, thyme, current_time);
2405 milliseconds = EMACS_SECS (thyme) * 1000 +
2406 (EMACS_USECS (thyme) + 500) / 1000;
2407 if (milliseconds < 1)
2409 ++mswindows_pending_timers_count;
2410 return SetTimer (NULL, 0, milliseconds,
2411 (TIMERPROC) mswindows_wm_timer_callback);
2415 emacs_mswindows_remove_timeout (int id)
2417 struct Lisp_Event match_against;
2418 Lisp_Object emacs_event;
2420 if (KillTimer (NULL, id))
2421 --mswindows_pending_timers_count;
2423 /* If there is a dispatch event generated by this
2424 timeout in the queue, we have to remove it too. */
2425 match_against.event_type = timeout_event;
2426 match_against.event.timeout.interval_id = id;
2427 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2428 if (!NILP (emacs_event))
2429 Fdeallocate_event(emacs_event);
2432 /* If `user_p' is false, then return whether there are any win32, timeout,
2433 * or subprocess events pending (that is, whether
2434 * emacs_mswindows_next_event() would return immediately without blocking).
2436 * if `user_p' is true, then return whether there are any *user generated*
2437 * events available (that is, whether there are keyboard or mouse-click
2438 * events ready to be read). This also implies that
2439 * emacs_mswindows_next_event() would not block.
2442 emacs_mswindows_event_pending_p (int user_p)
2444 mswindows_need_event (0);
2445 return (!NILP (mswindows_u_dispatch_event_queue)
2446 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2450 * Return the next event
2453 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2455 Lisp_Object event, event2;
2457 mswindows_need_event (1);
2459 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
2460 XSETEVENT (event2, emacs_event);
2461 Fcopy_event (event, event2);
2462 Fdeallocate_event (event);
2466 * Handle a magic event off the dispatch queue.
2469 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2471 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2479 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2480 struct frame *f = XFRAME (frame);
2481 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2484 /* struct gcpro gcpro1; */
2486 /* Clear sticky modifiers here (if we had any) */
2488 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2489 /* GCPRO1 (conser); XXX Not necessary? */
2490 emacs_handle_focus_change_preliminary (conser);
2491 /* Under X the stuff up to here is done in the X event handler.
2493 emacs_handle_focus_change_final (conser);
2502 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2503 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2505 Qmap_frame_hook : Qunmap_frame_hook,
2510 /* #### What about Enter & Leave */
2512 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2513 Qmouse_leave_frame_hook, 1, frame);
2522 get_process_input_waitable (struct Lisp_Process *process)
2524 Lisp_Object instr, outstr, p;
2525 XSETPROCESS (p, process);
2526 get_process_streams (process, &instr, &outstr);
2527 assert (!NILP (instr));
2528 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2529 return (network_connection_p (p)
2530 ? get_winsock_stream_waitable (XLSTREAM (instr))
2531 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2533 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2538 emacs_mswindows_select_process (struct Lisp_Process *process)
2540 HANDLE hev = get_process_input_waitable (process);
2542 if (!add_waitable_handle (hev))
2543 error ("Too many active processes");
2545 #ifdef HAVE_WIN32_PROCESSES
2548 XSETPROCESS (p, process);
2549 if (!network_connection_p (p))
2551 HANDLE hprocess = get_nt_process_handle (process);
2552 if (!add_waitable_handle (hprocess))
2554 remove_waitable_handle (hev);
2555 error ("Too many active processes");
2563 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2565 /* Process handle is removed in the event loop as soon
2566 as it is signaled, so don't bother here about it */
2567 HANDLE hev = get_process_input_waitable (process);
2568 remove_waitable_handle (hev);
2572 emacs_mswindows_select_console (struct console *con)
2577 emacs_mswindows_unselect_console (struct console *con)
2582 emacs_mswindows_quit_p (void)
2584 /* Quit cannot happen in modal loop: all program
2585 input is dedicated to Windows. */
2586 if (mswindows_in_modal_loop)
2589 /* Drain windows queue. This sets up number of quit
2590 characters in in the queue */
2591 mswindows_drain_windows_queue ();
2593 if (mswindows_quit_chars_count > 0)
2595 /* Yes there's a hidden one... Throw it away */
2596 struct Lisp_Event match_against;
2597 Lisp_Object emacs_event;
2599 match_against.event_type = key_press_event;
2600 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2602 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2603 assert (!NILP (emacs_event));
2605 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2608 Fdeallocate_event(emacs_event);
2609 --mswindows_quit_chars_count;
2614 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2615 Lisp_Object* instream,
2616 Lisp_Object* outstream,
2619 /* Handles for streams */
2621 /* fds. These just stored along with the streams, and are closed in
2622 delete stream pair method, because we need to handle fake unices
2626 /* Decode inhandle and outhandle. Their meaning depends on
2627 the process implementation being used. */
2628 #if defined (HAVE_WIN32_PROCESSES)
2629 /* We're passed in Windows handles. That's what we like most... */
2630 hin = (HANDLE) inhandle;
2631 hout = (HANDLE) outhandle;
2633 #elif defined (HAVE_UNIX_PROCESSES)
2634 /* We are passed UNIX fds. This must be Cygwin.
2636 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2637 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2641 #error "So, WHICH kind of processes do you want?"
2644 *instream = (hin == INVALID_HANDLE_VALUE
2646 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2647 : flags & STREAM_NETWORK_CONNECTION
2648 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2650 : make_ntpipe_input_stream (hin, fdi));
2652 #ifdef HAVE_WIN32_PROCESSES
2653 *outstream = (hout == INVALID_HANDLE_VALUE
2655 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2656 : flags & STREAM_NETWORK_CONNECTION
2657 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2659 : make_ntpipe_output_stream (hout, fdo));
2660 #elif defined (HAVE_UNIX_PROCESSES)
2661 *outstream = (fdo >= 0
2662 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2665 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2666 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2667 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2669 Bufbyte eof_char = get_eof_char (fdo);
2670 int pty_max_bytes = get_pty_max_bytes (fdo);
2671 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2676 return (NILP (*instream)
2678 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2679 : flags & STREAM_NETWORK_CONNECTION
2680 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2682 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2686 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2687 Lisp_Object outstream)
2689 /* Oh nothing special here for Win32 at all */
2690 #if defined (HAVE_UNIX_PROCESSES)
2691 int in = (NILP(instream)
2693 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2694 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2695 ? get_winsock_stream_param (XLSTREAM (instream))
2697 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2698 int out = (NILP(outstream) ? -1
2699 : filedesc_stream_fd (XLSTREAM (outstream)));
2703 if (out != in && out >= 0)
2707 return (NILP (instream)
2709 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2710 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2711 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2713 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2716 #ifndef HAVE_X_WINDOWS
2717 /* This is called from GC when a process object is about to be freed.
2718 If we've still got pointers to it in this file, we're gonna lose hard.
2721 debug_process_finalization (struct Lisp_Process *p)
2724 Lisp_Object instr, outstr;
2726 get_process_streams (p, &instr, &outstr);
2727 /* if it still has fds, then it hasn't been killed yet. */
2728 assert (NILP(instr));
2729 assert (NILP(outstr));
2731 /* #### More checks here */
2736 /************************************************************************/
2737 /* initialization */
2738 /************************************************************************/
2741 vars_of_event_mswindows (void)
2743 mswindows_u_dispatch_event_queue = Qnil;
2744 staticpro (&mswindows_u_dispatch_event_queue);
2745 mswindows_u_dispatch_event_queue_tail = Qnil;
2747 mswindows_s_dispatch_event_queue = Qnil;
2748 staticpro (&mswindows_s_dispatch_event_queue);
2749 mswindows_s_dispatch_event_queue_tail = Qnil;
2751 mswindows_error_caught_in_modal_loop = Qnil;
2752 staticpro (&mswindows_error_caught_in_modal_loop);
2753 mswindows_in_modal_loop = 0;
2754 mswindows_pending_timers_count = 0;
2756 mswindows_event_stream = xnew (struct event_stream);
2758 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2759 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2760 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2761 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2762 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2763 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2764 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2765 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2766 #ifdef HAVE_MSG_SELECT
2767 mswindows_event_stream->select_process_cb =
2768 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2769 mswindows_event_stream->unselect_process_cb =
2770 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2771 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2772 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2774 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2775 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2776 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2777 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2780 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2781 *Controls redrawing frame contents during mouse-drag or keyboard resize
2782 operation. When non-nil, the frame is redrawn while being resized. When
2783 nil, frame is not redrawn, and exposed areas are filled with default
2784 MDI application background color. Note that this option only has effect
2785 if "Show window contents while dragging" is on in system Display/Plus!
2787 Default is t on fast machines, nil on slow.
2790 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2791 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2792 *Analogue of double click interval for faking middle mouse events.
2793 The value is the minimum time in milliseconds that must elapse between
2794 left/right button down events before they are considered distinct events.
2795 If both mouse buttons are depressed within this interval, a middle mouse
2796 button down event is generated instead.
2797 If negative or zero, currently set system default is used instead.
2800 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2801 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2802 Number of physical mouse buttons.
2805 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2806 *Maximum horizontal distance in pixels between points in which left and
2807 right button clicks occurred for them to be translated into single
2808 middle button event. Clicks must occur in time not longer than defined
2809 by the variable `mswindows-mouse-button-tolerance'.
2810 If negative or zero, currently set system default is used instead.
2813 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2814 *Maximum vertical distance in pixels between points in which left and
2815 right button clicks occurred for them to be translated into single
2816 middle button event. Clicks must occur in time not longer than defined
2817 by the variable `mswindows-mouse-button-tolerance'.
2818 If negative or zero, currently set system default is used instead.
2821 mswindows_mouse_button_max_skew_x = 0;
2822 mswindows_mouse_button_max_skew_y = 0;
2823 mswindows_mouse_button_tolerance = 0;
2827 syms_of_event_mswindows (void)
2832 lstream_type_create_mswindows_selectable (void)
2834 init_slurp_stream ();
2835 init_shove_stream ();
2836 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2837 init_winsock_stream ();
2842 init_event_mswindows_late (void)
2844 #ifdef HAVE_MSG_SELECT
2845 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2846 assert (windows_fd>=0);
2847 FD_SET (windows_fd, &input_wait_mask);
2848 FD_ZERO(&zero_mask);
2851 event_stream = mswindows_event_stream;
2853 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2854 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);