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;
1450 mswindows_enqueue_dispatch_event (emacs_event);
1454 * Callback procedure for dde messages
1456 * We execute a dde Open("file") by simulating a file drop, so dde support
1457 * depends on dnd support.
1459 #ifdef HAVE_DRAGNDROP
1461 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1462 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1463 DWORD dwData1, DWORD dwData2)
1468 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1469 return (HDDEDATA)TRUE;
1470 return (HDDEDATA)FALSE;
1472 case XTYP_WILDCONNECT:
1474 /* We only support one {service,topic} pair */
1475 HSZPAIR pairs[2] = {
1476 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1478 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1479 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1480 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1481 sizeof (pairs), 0L, 0, uFmt, 0));
1483 return (HDDEDATA)NULL;
1486 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1488 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1489 char *cmd = alloca (len+1);
1492 struct gcpro gcpro1, gcpro2;
1493 Lisp_Object l_dndlist = Qnil;
1494 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1495 Lisp_Object frmcons, devcons, concons;
1496 struct Lisp_Event *event = XEVENT (emacs_event);
1498 DdeGetData (hdata, cmd, len, 0);
1500 DdeFreeDataHandle (hdata);
1502 /* Check syntax & that it's an [Open("foo")] command, which we
1503 * treat like a file drop */
1504 /* #### Ought to be generalised and accept some other commands */
1507 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1508 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1509 return DDE_FNOTPROCESSED;
1510 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1513 if (*cmd!='(' || *(cmd+1)!='\"')
1514 return DDE_FNOTPROCESSED;
1516 while (*end && *end!='\"')
1519 return DDE_FNOTPROCESSED;
1522 return DDE_FNOTPROCESSED;
1526 return DDE_FNOTPROCESSED;
1529 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1530 strcpy (filename, "file:");
1531 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1533 dostounix_filename (cmd);
1534 filename = alloca (strlen (cmd)+6);
1535 strcpy (filename, "file:");
1536 strcat (filename, cmd);
1538 GCPRO2 (emacs_event, l_dndlist);
1539 l_dndlist = make_string (filename, strlen (filename));
1541 /* Find a mswindows frame */
1542 event->channel = Qnil;
1543 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1545 Lisp_Object frame = XCAR (frmcons);
1546 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1547 event->channel = frame;
1549 assert (!NILP (event->channel));
1551 event->timestamp = GetTickCount();
1552 event->event_type = misc_user_event;
1553 event->event.misc.button = 1;
1554 event->event.misc.modifiers = 0;
1555 event->event.misc.x = -1;
1556 event->event.misc.y = -1;
1557 event->event.misc.function = Qdragdrop_drop_dispatch;
1558 event->event.misc.object = Fcons (Qdragdrop_URL,
1559 Fcons (l_dndlist, Qnil));
1560 mswindows_enqueue_dispatch_event (emacs_event);
1562 return (HDDEDATA) DDE_FACK;
1564 DdeFreeDataHandle (hdata);
1565 return (HDDEDATA) DDE_FNOTPROCESSED;
1568 return (HDDEDATA) NULL;
1574 * The windows procedure for the window class XEMACS_CLASS
1577 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1579 /* Note: Remember to initialize emacs_event and event before use.
1580 This code calls code that can GC. You must GCPRO before calling such code. */
1581 Lisp_Object emacs_event = Qnil;
1582 Lisp_Object fobj = Qnil;
1584 struct Lisp_Event *event;
1585 struct frame *frame;
1586 struct mswindows_frame* msframe;
1591 /* Erase background only during non-dynamic sizing */
1592 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1593 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1598 fobj = mswindows_find_frame (hwnd);
1599 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1604 /* See Win95 comment under WM_KEYDOWN */
1608 if (wParam == VK_CONTROL)
1610 GetKeyboardState (keymap);
1611 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1612 SetKeyboardState (keymap);
1614 else if (wParam == VK_MENU)
1616 GetKeyboardState (keymap);
1617 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1618 SetKeyboardState (keymap);
1625 /* In some locales the right-hand Alt key is labelled AltGr. This key
1626 * should produce alternative charcaters when combined with another key.
1627 * eg on a German keyboard pressing AltGr+q should produce '@'.
1628 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1629 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1630 * it translates as if AltGr were down.
1631 * We get round this by removing all modifiers from the keymap before
1632 * calling TranslateMessage() unless AltGr is *really* down. */
1635 int has_AltGr = mswindows_current_layout_has_AltGr ();
1639 GetKeyboardState (keymap);
1640 mods = mswindows_modifier_state (keymap, has_AltGr);
1642 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1643 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1644 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1647 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1648 BYTE keymap_orig[256];
1649 MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
1651 /* GetKeyboardState() does not work as documented on Win95. We have
1652 * to loosely track Left and Right modifiers on behalf of the OS,
1653 * without screwing up Windows NT which tracks them properly. */
1654 if (wParam == VK_CONTROL)
1655 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1656 else if (wParam == VK_MENU)
1657 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1659 memcpy (keymap_orig, keymap, 256);
1661 /* Remove shift modifier from an ascii character */
1664 /* Clear control and alt modifiers unless AltGr is pressed */
1665 keymap [VK_RCONTROL] = 0;
1666 keymap [VK_LMENU] = 0;
1667 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1669 keymap [VK_LCONTROL] = 0;
1670 keymap [VK_CONTROL] = 0;
1671 keymap [VK_RMENU] = 0;
1672 keymap [VK_MENU] = 0;
1674 SetKeyboardState (keymap);
1676 /* Maybe generate some WM_[SYS]CHARs in the queue */
1677 TranslateMessage (&msg);
1679 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1680 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1683 WPARAM ch = msg.wParam;
1685 /* If a quit char with no modifiers other than control and
1686 shift, then mark it with a fake modifier, which is removed
1687 upon dequeueing the event */
1688 /* #### This might also not withstand localization, if
1689 quit character is not a latin-1 symbol */
1690 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1691 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1692 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1694 mods1 |= FAKE_MOD_QUIT;
1695 ++mswindows_quit_chars_count;
1698 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1700 SetKeyboardState (keymap_orig);
1703 /* F10 causes menu activation by default. We do not want this */
1704 if (wParam != VK_F10)
1708 case WM_MBUTTONDOWN:
1710 /* Real middle mouse button has nothing to do with emulated one:
1711 if one wants to exercise fingers playing chords on the mouse,
1712 he is allowed to do that! */
1713 mswindows_enqueue_mouse_button_event (hwnd, message,
1714 MAKEPOINTS (lParam), GetMessageTime());
1718 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1719 msframe->last_click_time = GetMessageTime();
1721 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1722 msframe->button2_need_lbutton = 0;
1723 if (msframe->ignore_next_lbutton_up)
1725 msframe->ignore_next_lbutton_up = 0;
1727 else if (msframe->button2_is_down)
1729 msframe->button2_is_down = 0;
1730 msframe->ignore_next_rbutton_up = 1;
1731 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1732 MAKEPOINTS (lParam), GetMessageTime());
1736 if (msframe->button2_need_rbutton)
1738 msframe->button2_need_rbutton = 0;
1739 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1740 MAKEPOINTS (lParam), GetMessageTime());
1742 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1743 MAKEPOINTS (lParam), GetMessageTime());
1748 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1749 msframe->last_click_time = GetMessageTime();
1751 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1752 msframe->button2_need_rbutton = 0;
1753 if (msframe->ignore_next_rbutton_up)
1755 msframe->ignore_next_rbutton_up = 0;
1757 else if (msframe->button2_is_down)
1759 msframe->button2_is_down = 0;
1760 msframe->ignore_next_lbutton_up = 1;
1761 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1762 MAKEPOINTS (lParam), GetMessageTime());
1766 if (msframe->button2_need_lbutton)
1768 msframe->button2_need_lbutton = 0;
1769 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1770 MAKEPOINTS (lParam), GetMessageTime());
1772 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1773 MAKEPOINTS (lParam), GetMessageTime());
1777 case WM_LBUTTONDOWN:
1778 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1780 if (msframe->button2_need_lbutton)
1782 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1783 msframe->button2_need_lbutton = 0;
1784 msframe->button2_need_rbutton = 0;
1785 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1787 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1788 MAKEPOINTS (lParam), GetMessageTime());
1789 msframe->button2_is_down = 1;
1793 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1794 msframe->last_click_point, msframe->last_click_time);
1795 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1796 MAKEPOINTS (lParam), GetMessageTime());
1801 mswindows_set_chord_timer (hwnd);
1802 msframe->button2_need_rbutton = 1;
1803 msframe->last_click_point = MAKEPOINTS (lParam);
1805 msframe->last_click_time = GetMessageTime();
1808 case WM_RBUTTONDOWN:
1809 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1811 if (msframe->button2_need_rbutton)
1813 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1814 msframe->button2_need_lbutton = 0;
1815 msframe->button2_need_rbutton = 0;
1816 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1818 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1819 MAKEPOINTS (lParam), GetMessageTime());
1820 msframe->button2_is_down = 1;
1824 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1825 msframe->last_click_point, msframe->last_click_time);
1826 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1827 MAKEPOINTS (lParam), GetMessageTime());
1832 mswindows_set_chord_timer (hwnd);
1833 msframe->button2_need_lbutton = 1;
1834 msframe->last_click_point = MAKEPOINTS (lParam);
1836 msframe->last_click_time = GetMessageTime();
1840 if (wParam == BUTTON_2_TIMER_ID)
1842 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1843 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1845 if (msframe->button2_need_lbutton)
1847 msframe->button2_need_lbutton = 0;
1848 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1849 msframe->last_click_point, msframe->last_click_time);
1851 else if (msframe->button2_need_rbutton)
1853 msframe->button2_need_rbutton = 0;
1854 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1855 msframe->last_click_point, msframe->last_click_time);
1859 assert ("Spurious timer fired" == 0);
1863 /* Optimization: don't report mouse movement while size is changing */
1864 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1865 if (!msframe->sizing)
1867 /* When waiting for the second mouse button to finish
1868 button2 emulation, and have moved too far, just pretend
1869 as if timer has expired. This improves drag-select feedback */
1870 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1871 && !mswindows_button2_near_enough (msframe->last_click_point,
1872 MAKEPOINTS (lParam)))
1874 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1875 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1878 emacs_event = Fmake_event (Qnil, Qnil);
1879 event = XEVENT(emacs_event);
1881 event->channel = mswindows_find_frame(hwnd);
1882 event->timestamp = GetMessageTime();
1883 event->event_type = pointer_motion_event;
1884 event->event.motion.x = MAKEPOINTS(lParam).x;
1885 event->event.motion.y = MAKEPOINTS(lParam).y;
1886 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1888 mswindows_enqueue_dispatch_event (emacs_event);
1894 /* Queue a `cancel-mode-internal' misc user event, so mouse
1895 selection would be canceled if any */
1896 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1897 Qcancel_mode_internal, Qnil);
1900 #ifdef HAVE_TOOLBARS
1903 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1905 if (tttext->hdr.code == TTN_NEEDTEXT)
1907 /* find out which toolbar */
1908 frame = XFRAME (mswindows_find_frame (hwnd));
1909 btext = mswindows_get_toolbar_button_text ( frame,
1910 tttext->hdr.idFrom );
1912 tttext->lpszText = NULL;
1913 tttext->hinst = NULL;
1917 /* I think this is safe since the text will only go away
1918 when the toolbar does...*/
1919 tttext->lpszText=XSTRING_DATA (btext);
1922 tttext->uFlags |= TTF_DI_SETITEM;
1931 PAINTSTRUCT paintStruct;
1933 frame = XFRAME (mswindows_find_frame (hwnd));
1935 BeginPaint (hwnd, &paintStruct);
1936 mswindows_redraw_exposed_area (frame,
1937 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1938 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1939 EndPaint (hwnd, &paintStruct);
1944 /* We only care about this message if our size has really changed */
1945 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1950 fobj = mswindows_find_frame (hwnd);
1951 frame = XFRAME (fobj);
1952 msframe = FRAME_MSWINDOWS_DATA (frame);
1954 /* We cannot handle frame map and unmap hooks right in
1955 this routine, because these may throw. We queue
1956 magic events to run these hooks instead - kkm */
1958 if (wParam==SIZE_MINIMIZED)
1961 FRAME_VISIBLE_P (frame) = 0;
1962 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
1966 GetClientRect(hwnd, &rect);
1967 FRAME_PIXWIDTH(frame) = rect.right;
1968 FRAME_PIXHEIGHT(frame) = rect.bottom;
1970 pixel_to_real_char_size (frame, rect.right, rect.bottom,
1971 &FRAME_MSWINDOWS_CHARWIDTH (frame),
1972 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
1974 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
1975 change_frame_size (frame, rows, columns, 1);
1977 /* If we are inside frame creation, we have to apply geometric
1979 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1981 /* Yes, we have to size again */
1982 mswindows_size_frame_internal ( frame,
1983 FRAME_MSWINDOWS_TARGET_RECT
1985 /* Reset so we do not get here again. The SetWindowPos call in
1986 * mswindows_size_frame_internal can cause recursion here. */
1987 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1989 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
1990 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
1995 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
1996 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
1997 FRAME_VISIBLE_P (frame) = 1;
1999 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2006 /* Misc magic events which only require that the frame be identified */
2009 mswindows_enqueue_magic_event (hwnd, message);
2012 case WM_WINDOWPOSCHANGING:
2014 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2015 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2016 GetWindowPlacement(hwnd, &wpl);
2018 /* Only interested if size is changing and we're not being iconified */
2019 if (wpl.showCmd != SW_SHOWMINIMIZED
2020 && wpl.showCmd != SW_SHOWMAXIMIZED
2021 && !(wp->flags & SWP_NOSIZE))
2023 RECT ncsize = { 0, 0, 0, 0 };
2024 int pixwidth, pixheight;
2025 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2026 GetMenu(hwnd) != NULL,
2027 GetWindowLong (hwnd, GWL_EXSTYLE));
2029 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2030 wp->cx - (ncsize.right - ncsize.left),
2031 wp->cy - (ncsize.bottom - ncsize.top),
2032 &pixwidth, &pixheight);
2034 /* Convert client sizes to window sizes */
2035 pixwidth += (ncsize.right - ncsize.left);
2036 pixheight += (ncsize.bottom - ncsize.top);
2038 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2040 /* Adjust so that the bottom or right doesn't move if it's
2041 * the top or left that's being changed */
2043 GetWindowRect (hwnd, &rect);
2045 if (rect.left != wp->x)
2046 wp->x += wp->cx - pixwidth;
2047 if (rect.top != wp->y)
2048 wp->y += wp->cy - pixheight;
2054 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2055 window position if the user tries to track window too small */
2059 case WM_ENTERSIZEMOVE:
2060 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2061 msframe->sizing = 1;
2064 case WM_EXITSIZEMOVE:
2065 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2066 msframe->sizing = 0;
2067 /* Queue noop event */
2068 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2071 #ifdef HAVE_SCROLLBARS
2075 /* Direction of scroll is determined by scrollbar instance. */
2076 int code = (int) LOWORD(wParam);
2077 int pos = (short int) HIWORD(wParam);
2078 HWND hwndScrollBar = (HWND) lParam;
2079 struct gcpro gcpro1, gcpro2;
2081 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2082 GCPRO2 (emacs_event, fobj);
2083 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2085 /* Error during event pumping - cancel scroll */
2086 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2093 #ifdef HAVE_MENUBARS
2095 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2097 XFRAME (mswindows_find_frame (hwnd)))))
2098 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2101 case WM_INITMENUPOPUP:
2102 if (!HIWORD(lParam))
2104 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2106 XFRAME (mswindows_find_frame (hwnd)))))
2107 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2111 #endif /* HAVE_MENUBARS */
2115 WORD id = LOWORD (wParam);
2116 HWND cid = (HWND)lParam;
2117 frame = XFRAME (mswindows_find_frame (hwnd));
2119 #ifdef HAVE_TOOLBARS
2120 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2124 #ifdef HAVE_MENUBARS
2125 if (!NILP (mswindows_handle_wm_command (frame, id)))
2129 /* Bite me - a spurious command. This cannot happen. */
2130 error ("XEMACS BUG: Cannot decode command message");
2134 #ifdef HAVE_DRAGNDROP
2135 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2137 UINT filecount, i, len;
2143 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2144 struct gcpro gcpro1, gcpro2, gcpro3;
2146 emacs_event = Fmake_event (Qnil, Qnil);
2147 event = XEVENT(emacs_event);
2149 GCPRO3 (emacs_event, l_dndlist, l_item);
2151 if (!DragQueryPoint ((HANDLE) wParam, &point))
2152 point.x = point.y = -1; /* outside client area */
2154 event->event_type = misc_user_event;
2155 event->channel = mswindows_find_frame(hwnd);
2156 event->timestamp = GetMessageTime();
2157 event->event.misc.button = 1; /* #### Should try harder */
2158 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2159 event->event.misc.x = point.x;
2160 event->event.misc.y = point.y;
2161 event->event.misc.function = Qdragdrop_drop_dispatch;
2163 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2164 for (i=0; i<filecount; i++)
2166 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2167 /* The URLs that we make here aren't correct according to section
2168 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2169 * because they may contain reserved characters. But that's OK. */
2171 fname = (char *)xmalloc (len+1);
2172 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2173 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2174 strcpy (filename, "file:");
2175 cygwin32_win32_to_posix_path_list (fname, filename+5);
2178 filename = (char *)xmalloc (len+6);
2179 strcpy (filename, "file:");
2180 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2181 dostounix_filename (filename+5);
2183 l_item = make_string (filename, strlen (filename));
2184 l_dndlist = Fcons (l_item, l_dndlist);
2187 DragFinish ((HANDLE) wParam);
2189 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2190 mswindows_enqueue_dispatch_event (emacs_event);
2198 return DefWindowProc (hwnd, message, wParam, lParam);
2204 /************************************************************************/
2205 /* keyboard, mouse & other helpers for the windows procedure */
2206 /************************************************************************/
2208 mswindows_set_chord_timer (HWND hwnd)
2212 /* We get one third half system double click threshold */
2213 if (mswindows_mouse_button_tolerance <= 0)
2214 interval = GetDoubleClickTime () / 3;
2216 interval = mswindows_mouse_button_tolerance;
2218 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2222 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2225 if (mswindows_mouse_button_max_skew_x <= 0)
2226 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2228 dx = mswindows_mouse_button_max_skew_x;
2230 if (mswindows_mouse_button_max_skew_y <= 0)
2231 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2233 dy = mswindows_mouse_button_max_skew_y;
2235 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2239 mswindows_current_layout_has_AltGr (void)
2241 /* This simple caching mechanism saves 10% of CPU
2242 time when a key typed at autorepeat rate of 30 cps! */
2243 static HKL last_hkl = 0;
2244 static int last_hkl_has_AltGr;
2246 HKL current_hkl = GetKeyboardLayout (0);
2247 if (current_hkl != last_hkl)
2250 last_hkl_has_AltGr = 0;
2251 /* In this loop, we query whether a character requires
2252 AltGr to be down to generate it. If at least such one
2253 found, this means that the layout does regard AltGr */
2254 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2255 if (HIBYTE (VkKeyScan (c)) == 6)
2256 last_hkl_has_AltGr = 1;
2257 last_hkl = current_hkl;
2259 return last_hkl_has_AltGr;
2263 /* Returns the state of the modifier keys in the format expected by the
2264 * Lisp_Event key_data, button_data and motion_data modifiers member */
2265 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2271 keymap = (BYTE*) alloca(256);
2272 GetKeyboardState (keymap);
2273 has_AltGr = mswindows_current_layout_has_AltGr ();
2276 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2278 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2279 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2283 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2284 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2287 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2293 * Translate a mswindows virtual key to a keysym.
2294 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2295 * or whose ASCII codes (like space) xemacs doesn't like.
2296 * Virtual key values are defined in winresrc.h
2297 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2299 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2301 switch (mswindows_key)
2303 /* First the predefined ones */
2304 case VK_BACK: return QKbackspace;
2305 case VK_TAB: return QKtab;
2306 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2307 case VK_RETURN: return QKreturn;
2308 case VK_ESCAPE: return QKescape;
2309 case VK_SPACE: return QKspace;
2310 case VK_DELETE: return QKdelete;
2313 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2314 case VK_PRIOR: return KEYSYM ("prior");
2315 case VK_NEXT: return KEYSYM ("next");
2316 case VK_END: return KEYSYM ("end");
2317 case VK_HOME: return KEYSYM ("home");
2318 case VK_LEFT: return KEYSYM ("left");
2319 case VK_UP: return KEYSYM ("up");
2320 case VK_RIGHT: return KEYSYM ("right");
2321 case VK_DOWN: return KEYSYM ("down");
2322 case VK_SELECT: return KEYSYM ("select");
2323 case VK_PRINT: return KEYSYM ("print");
2324 case VK_EXECUTE: return KEYSYM ("execute");
2325 case VK_SNAPSHOT: return KEYSYM ("print");
2326 case VK_INSERT: return KEYSYM ("insert");
2327 case VK_HELP: return KEYSYM ("help");
2328 #if 0 /* XXX What are these supposed to do? */
2329 case VK_LWIN return KEYSYM ("");
2330 case VK_RWIN return KEYSYM ("");
2332 case VK_APPS: return KEYSYM ("menu");
2333 case VK_F1: return KEYSYM ("f1");
2334 case VK_F2: return KEYSYM ("f2");
2335 case VK_F3: return KEYSYM ("f3");
2336 case VK_F4: return KEYSYM ("f4");
2337 case VK_F5: return KEYSYM ("f5");
2338 case VK_F6: return KEYSYM ("f6");
2339 case VK_F7: return KEYSYM ("f7");
2340 case VK_F8: return KEYSYM ("f8");
2341 case VK_F9: return KEYSYM ("f9");
2342 case VK_F10: return KEYSYM ("f10");
2343 case VK_F11: return KEYSYM ("f11");
2344 case VK_F12: return KEYSYM ("f12");
2345 case VK_F13: return KEYSYM ("f13");
2346 case VK_F14: return KEYSYM ("f14");
2347 case VK_F15: return KEYSYM ("f15");
2348 case VK_F16: return KEYSYM ("f16");
2349 case VK_F17: return KEYSYM ("f17");
2350 case VK_F18: return KEYSYM ("f18");
2351 case VK_F19: return KEYSYM ("f19");
2352 case VK_F20: return KEYSYM ("f20");
2353 case VK_F21: return KEYSYM ("f21");
2354 case VK_F22: return KEYSYM ("f22");
2355 case VK_F23: return KEYSYM ("f23");
2356 case VK_F24: return KEYSYM ("f24");
2362 * Find the console that matches the supplied mswindows window handle
2365 mswindows_find_console (HWND hwnd)
2367 /* We only support one console */
2368 return XCAR (Vconsole_list);
2372 * Find the frame that matches the supplied mswindows window handle
2375 mswindows_find_frame (HWND hwnd)
2377 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2381 /* We are in progress of frame creation. Return the frame
2382 being created, as it still not remembered in the window
2384 assert (!NILP (Vmswindows_frame_being_created));
2385 return Vmswindows_frame_being_created;
2387 VOID_TO_LISP (f, l);
2392 /************************************************************************/
2394 /************************************************************************/
2397 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2400 EMACS_TIME current_time;
2401 EMACS_GET_TIME (current_time);
2402 EMACS_SUB_TIME (thyme, thyme, current_time);
2403 milliseconds = EMACS_SECS (thyme) * 1000 +
2404 (EMACS_USECS (thyme) + 500) / 1000;
2405 if (milliseconds < 1)
2407 ++mswindows_pending_timers_count;
2408 return SetTimer (NULL, 0, milliseconds,
2409 (TIMERPROC) mswindows_wm_timer_callback);
2413 emacs_mswindows_remove_timeout (int id)
2415 struct Lisp_Event match_against;
2416 Lisp_Object emacs_event;
2418 if (KillTimer (NULL, id))
2419 --mswindows_pending_timers_count;
2421 /* If there is a dispatch event generated by this
2422 timeout in the queue, we have to remove it too. */
2423 match_against.event_type = timeout_event;
2424 match_against.event.timeout.interval_id = id;
2425 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2426 if (!NILP (emacs_event))
2427 Fdeallocate_event(emacs_event);
2430 /* If `user_p' is false, then return whether there are any win32, timeout,
2431 * or subprocess events pending (that is, whether
2432 * emacs_mswindows_next_event() would return immediately without blocking).
2434 * if `user_p' is true, then return whether there are any *user generated*
2435 * events available (that is, whether there are keyboard or mouse-click
2436 * events ready to be read). This also implies that
2437 * emacs_mswindows_next_event() would not block.
2440 emacs_mswindows_event_pending_p (int user_p)
2442 mswindows_need_event (0);
2443 return (!NILP (mswindows_u_dispatch_event_queue)
2444 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2448 * Return the next event
2451 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2453 Lisp_Object event, event2;
2455 mswindows_need_event (1);
2457 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
2458 XSETEVENT (event2, emacs_event);
2459 Fcopy_event (event, event2);
2460 Fdeallocate_event (event);
2464 * Handle a magic event off the dispatch queue.
2467 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2469 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2477 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2478 struct frame *f = XFRAME (frame);
2479 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2482 /* struct gcpro gcpro1; */
2484 /* Clear sticky modifiers here (if we had any) */
2486 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2487 /* GCPRO1 (conser); XXX Not necessary? */
2488 emacs_handle_focus_change_preliminary (conser);
2489 /* Under X the stuff up to here is done in the X event handler.
2491 emacs_handle_focus_change_final (conser);
2500 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2501 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2503 Qmap_frame_hook : Qunmap_frame_hook,
2508 /* #### What about Enter & Leave */
2510 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2511 Qmouse_leave_frame_hook, 1, frame);
2520 get_process_input_waitable (struct Lisp_Process *process)
2522 Lisp_Object instr, outstr, p;
2523 XSETPROCESS (p, process);
2524 get_process_streams (process, &instr, &outstr);
2525 assert (!NILP (instr));
2526 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2527 return (network_connection_p (p)
2528 ? get_winsock_stream_waitable (XLSTREAM (instr))
2529 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2531 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2536 emacs_mswindows_select_process (struct Lisp_Process *process)
2538 HANDLE hev = get_process_input_waitable (process);
2540 if (!add_waitable_handle (hev))
2541 error ("Too many active processes");
2543 #ifdef HAVE_WIN32_PROCESSES
2546 XSETPROCESS (p, process);
2547 if (!network_connection_p (p))
2549 HANDLE hprocess = get_nt_process_handle (process);
2550 if (!add_waitable_handle (hprocess))
2552 remove_waitable_handle (hev);
2553 error ("Too many active processes");
2561 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2563 /* Process handle is removed in the event loop as soon
2564 as it is signaled, so don't bother here about it */
2565 HANDLE hev = get_process_input_waitable (process);
2566 remove_waitable_handle (hev);
2570 emacs_mswindows_select_console (struct console *con)
2575 emacs_mswindows_unselect_console (struct console *con)
2580 emacs_mswindows_quit_p (void)
2582 /* Quit cannot happen in modal loop: all program
2583 input is dedicated to Windows. */
2584 if (mswindows_in_modal_loop)
2587 /* Drain windows queue. This sets up number of quit
2588 characters in in the queue */
2589 mswindows_drain_windows_queue ();
2591 if (mswindows_quit_chars_count > 0)
2593 /* Yes there's a hidden one... Throw it away */
2594 struct Lisp_Event match_against;
2595 Lisp_Object emacs_event;
2597 match_against.event_type = key_press_event;
2598 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2600 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2601 assert (!NILP (emacs_event));
2603 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2606 Fdeallocate_event(emacs_event);
2607 --mswindows_quit_chars_count;
2612 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2613 Lisp_Object* instream,
2614 Lisp_Object* outstream,
2617 /* Handles for streams */
2619 /* fds. These just stored along with the streams, and are closed in
2620 delete stream pair method, because we need to handle fake unices
2624 /* Decode inhandle and outhandle. Their meaning depends on
2625 the process implementation being used. */
2626 #if defined (HAVE_WIN32_PROCESSES)
2627 /* We're passed in Windows handles. That's what we like most... */
2628 hin = (HANDLE) inhandle;
2629 hout = (HANDLE) outhandle;
2631 #elif defined (HAVE_UNIX_PROCESSES)
2632 /* We are passed UNIX fds. This must be Cygwin.
2634 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2635 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2639 #error "So, WHICH kind of processes do you want?"
2642 *instream = (hin == INVALID_HANDLE_VALUE
2644 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2645 : flags & STREAM_NETWORK_CONNECTION
2646 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2648 : make_ntpipe_input_stream (hin, fdi));
2650 #ifdef HAVE_WIN32_PROCESSES
2651 *outstream = (hout == INVALID_HANDLE_VALUE
2653 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2654 : flags & STREAM_NETWORK_CONNECTION
2655 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2657 : make_ntpipe_output_stream (hout, fdo));
2658 #elif defined (HAVE_UNIX_PROCESSES)
2659 *outstream = (fdo >= 0
2660 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2663 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2664 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2665 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2667 Bufbyte eof_char = get_eof_char (fdo);
2668 int pty_max_bytes = get_pty_max_bytes (fdo);
2669 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2674 return (NILP (*instream)
2676 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2677 : flags & STREAM_NETWORK_CONNECTION
2678 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2680 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2684 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2685 Lisp_Object outstream)
2687 /* Oh nothing special here for Win32 at all */
2688 #if defined (HAVE_UNIX_PROCESSES)
2689 int in = (NILP(instream)
2691 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2692 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2693 ? get_winsock_stream_param (XLSTREAM (instream))
2695 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2696 int out = (NILP(outstream) ? -1
2697 : filedesc_stream_fd (XLSTREAM (outstream)));
2701 if (out != in && out >= 0)
2705 return (NILP (instream)
2707 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2708 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2709 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2711 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2714 #ifndef HAVE_X_WINDOWS
2715 /* This is called from GC when a process object is about to be freed.
2716 If we've still got pointers to it in this file, we're gonna lose hard.
2719 debug_process_finalization (struct Lisp_Process *p)
2722 Lisp_Object instr, outstr;
2724 get_process_streams (p, &instr, &outstr);
2725 /* if it still has fds, then it hasn't been killed yet. */
2726 assert (NILP(instr));
2727 assert (NILP(outstr));
2729 /* #### More checks here */
2734 /************************************************************************/
2735 /* initialization */
2736 /************************************************************************/
2739 vars_of_event_mswindows (void)
2741 mswindows_u_dispatch_event_queue = Qnil;
2742 staticpro (&mswindows_u_dispatch_event_queue);
2743 mswindows_u_dispatch_event_queue_tail = Qnil;
2745 mswindows_s_dispatch_event_queue = Qnil;
2746 staticpro (&mswindows_s_dispatch_event_queue);
2747 mswindows_s_dispatch_event_queue_tail = Qnil;
2749 mswindows_error_caught_in_modal_loop = Qnil;
2750 staticpro (&mswindows_error_caught_in_modal_loop);
2751 mswindows_in_modal_loop = 0;
2752 mswindows_pending_timers_count = 0;
2754 mswindows_event_stream = xnew (struct event_stream);
2756 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2757 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2758 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2759 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2760 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2761 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2762 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2763 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2764 #ifdef HAVE_MSG_SELECT
2765 mswindows_event_stream->select_process_cb =
2766 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2767 mswindows_event_stream->unselect_process_cb =
2768 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2769 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2770 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2772 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2773 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2774 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2775 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2778 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2779 *Controls redrawing frame contents during mouse-drag or keyboard resize
2780 operation. When non-nil, the frame is redrawn while being resized. When
2781 nil, frame is not redrawn, and exposed areas are filled with default
2782 MDI application background color. Note that this option only has effect
2783 if "Show window contents while dragging" is on in system Display/Plus!
2785 Default is t on fast machines, nil on slow.
2788 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2789 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2790 *Analogue of double click interval for faking middle mouse events.
2791 The value is the minimum time in milliseconds that must elapse between
2792 left/right button down events before they are considered distinct events.
2793 If both mouse buttons are depressed within this interval, a middle mouse
2794 button down event is generated instead.
2795 If negative or zero, currently set system default is used instead.
2798 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2799 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2800 Number of physical mouse buttons.
2803 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2804 *Maximum horizontal distance in pixels between points in which left and
2805 right button clicks occurred for them to be translated into single
2806 middle button event. Clicks must occur in time not longer than defined
2807 by the variable `mswindows-mouse-button-tolerance'.
2808 If negative or zero, currently set system default is used instead.
2811 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2812 *Maximum vertical distance in pixels between points in which left and
2813 right button clicks occurred for them to be translated into single
2814 middle button event. Clicks must occur in time not longer than defined
2815 by the variable `mswindows-mouse-button-tolerance'.
2816 If negative or zero, currently set system default is used instead.
2819 mswindows_mouse_button_max_skew_x = 0;
2820 mswindows_mouse_button_max_skew_y = 0;
2821 mswindows_mouse_button_tolerance = 0;
2825 syms_of_event_mswindows (void)
2830 lstream_type_create_mswindows_selectable (void)
2832 init_slurp_stream ();
2833 init_shove_stream ();
2834 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2835 init_winsock_stream ();
2840 init_event_mswindows_late (void)
2842 #ifdef HAVE_MSG_SELECT
2843 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2844 assert (windows_fd>=0);
2845 FD_SET (windows_fd, &input_wait_mask);
2846 FD_ZERO(&zero_mask);
2849 event_stream = mswindows_event_stream;
2851 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2852 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);