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 extern int signal_event_pipe_initialized;
106 * Two separate queues, for efficiency, one (_u_) for user events, and
107 * another (_s_) for non-user ones. We always return events out of the
108 * first one until it is empty and only then proceed with the second
111 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
112 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
114 /* The number of things we can wait on */
115 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
117 /* List of mswindows waitable handles. */
118 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
120 /* Number of wait handles */
121 static int mswindows_waitable_count=0;
123 /* Count of quit chars currently in the queue */
124 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
125 Decremented in mswindows_dequeue_dispatch_event() */
126 int mswindows_quit_chars_count = 0;
128 /* These are Lisp integers; see DEFVARS in this file for description. */
129 int mswindows_dynamic_frame_resize;
130 int mswindows_num_mouse_buttons;
131 int mswindows_mouse_button_max_skew_x;
132 int mswindows_mouse_button_max_skew_y;
133 int mswindows_mouse_button_tolerance;
135 /* This is the event signaled by the event pump.
136 See mswindows_pump_outstanding_events for comments */
137 static Lisp_Object mswindows_error_caught_in_modal_loop;
138 static int mswindows_in_modal_loop;
140 /* Count of wound timers */
141 static int mswindows_pending_timers_count;
143 /************************************************************************/
144 /* Pipe instream - reads process output */
145 /************************************************************************/
147 #define PIPE_READ_DELAY 20
149 #define HANDLE_TO_USID(h) ((USID)(h))
151 #define NTPIPE_SLURP_STREAM_DATA(stream) \
152 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
154 /* This structure is allocated by the main thread, and is deallocated
155 in the thread upon exit. There are situations when a thread
156 remains blocked for a long time, much longer than the lstream
157 exists. For exmaple, "start notepad" command is issued from the
158 shell, then the shell is closed by C-c C-d. Although the shell
159 process exits, its output pipe will not get closed until the
160 notepad process exits also, because it inherits the pipe form the
161 shell. In this case, we abandon the thread, and let it live until
162 all such processes exit. While struct ntpipe_slurp_stream is
163 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
165 struct ntpipe_slurp_stream_shared_data
167 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
168 /* This is a manual-reset object. */
169 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
170 /* This is a manual-reset object. */
171 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
172 /* This is a manual-reset object. */
173 HANDLE hpipe; /* Pipe read end handle. */
174 LONG die_p; /* Thread must exit ASAP if non-zero */
175 BOOL eof_p : 1; /* Set when thread saw EOF */
176 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
177 BOOL inuse_p : 1; /* this structure is in use */
178 LONG lock_count; /* Client count of this struct, 0=safe to free */
179 BYTE onebyte; /* One byte buffer read by thread */
182 #define MAX_SLURP_STREAMS 32
183 struct ntpipe_slurp_stream_shared_data
184 shared_data_block[MAX_SLURP_STREAMS]={{0}};
186 struct ntpipe_slurp_stream
188 LPARAM user_data; /* Any user data stored in the stream object */
189 struct ntpipe_slurp_stream_shared_data* thread_data;
192 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
193 sizeof (struct ntpipe_slurp_stream));
195 /* This function is thread-safe, and is called from either thread
196 context. It serializes freeing shared dtata structure */
198 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
200 if (InterlockedDecrement (&s->lock_count) == 0)
203 CloseHandle (s->hev_thread);
204 CloseHandle (s->hev_caller);
205 CloseHandle (s->hev_unsleep);
210 static struct ntpipe_slurp_stream_shared_data*
211 slurper_allocate_shared_data()
214 for (i=0; i<MAX_SLURP_STREAMS; i++)
216 if (!shared_data_block[i].inuse_p)
218 shared_data_block[i].inuse_p=1;
219 return &shared_data_block[i];
222 return (struct ntpipe_slurp_stream_shared_data*)0;
226 slurp_thread (LPVOID vparam)
228 struct ntpipe_slurp_stream_shared_data *s =
229 (struct ntpipe_slurp_stream_shared_data*)vparam;
233 /* Read one byte from the pipe */
235 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
237 DWORD err = GetLastError ();
238 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
243 else if (actually_read == 0)
246 /* We must terminate on an error or eof */
247 if (s->eof_p || s->error_p)
248 InterlockedIncrement (&s->die_p);
250 /* Before we notify caller, we unsignal our event. */
251 ResetEvent (s->hev_thread);
253 /* Now we got something to notify caller, either a byte or an
254 error/eof indication. Before we do, allow internal pipe
255 buffer to accumulate little bit more data.
256 Reader function pulses this event before waiting for
257 a character, to avoid pipe delay, and to get the byte
260 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
262 /* Either make event loop generate a process event, or
264 SetEvent (s->hev_caller);
266 /* Cleanup and exit if we're shot off */
270 /* Block until the client finishes with retireving the rest of
272 WaitForSingleObject (s->hev_thread, INFINITE);
275 slurper_free_shared_data_maybe (s);
281 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
284 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
285 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
286 DWORD thread_id_unused;
289 /* We deal only with pipes, for we're using PeekNamedPipe api */
290 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
292 s->thread_data = slurper_allocate_shared_data();
294 /* Create reader thread. This could fail, so do not create events
295 until thread is created */
296 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
297 CREATE_SUSPENDED, &thread_id_unused);
300 Lstream_delete (lstr);
301 s->thread_data->inuse_p=0;
305 /* Shared data are initially owned by both main and slurper
307 s->thread_data->lock_count = 2;
308 s->thread_data->die_p = 0;
309 s->thread_data->eof_p = FALSE;
310 s->thread_data->error_p = FALSE;
311 s->thread_data->hpipe = hpipe;
312 s->user_data = param;
314 /* hev_thread is a manual-reset event, initially signaled */
315 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
316 /* hev_caller is a manual-reset event, initially nonsignaled */
317 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
318 /* hev_unsleep is a manual-reset event, initially nonsignaled */
319 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
322 ResumeThread (hthread);
323 CloseHandle (hthread);
325 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
326 XSETLSTREAM (obj, lstr);
331 get_ntpipe_input_stream_param (Lstream *stream)
333 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
338 get_ntpipe_input_stream_waitable (Lstream *stream)
340 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
341 return s->thread_data->hev_caller;
345 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
347 /* This function must be called from the main thread only */
348 struct ntpipe_slurp_stream_shared_data* s =
349 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
354 /* Disallow pipe read delay for the thread: we need a character
356 SetEvent (s->hev_unsleep);
358 /* Check if we have a character ready. Give it a short delay,
359 for the thread to awake from pipe delay, just ion case*/
360 wait_result = WaitForSingleObject (s->hev_caller, 2);
362 /* Revert to the normal sleep behavior. */
363 ResetEvent (s->hev_unsleep);
365 /* If there's no byte buffered yet, give up */
366 if (wait_result == WAIT_TIMEOUT)
373 /* Reset caller unlock event now, as we've handled the pending
374 process output event */
375 ResetEvent (s->hev_caller);
377 /* It is now safe to do anything with contents of S, except for
378 changing s->die_p, which still should be interlocked */
382 if (s->error_p || s->die_p)
385 /* Ok, there were no error neither eof - we've got a byte from the
387 *(data++) = s->onebyte;
391 DWORD bytes_read = 0;
394 DWORD bytes_available;
396 /* If the api call fails, return at least one byte already
397 read. ReadFile in thread will return error */
398 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
401 /* Fetch available bytes. The same consideration applies,
402 so do not check for errors. ReadFile in the thread will
403 fail if the next call fails. */
405 ReadFile (s->hpipe, data, min (bytes_available, size),
409 /* Now we can unblock thread, so it attempts to read more */
410 SetEvent (s->hev_thread);
411 return bytes_read + 1;
418 ntpipe_slurp_closer (Lstream *stream)
420 /* This function must be called from the main thread only */
421 struct ntpipe_slurp_stream_shared_data* s =
422 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
424 /* Force thread to stop */
425 InterlockedIncrement (&s->die_p);
427 /* Set events which could possibly block slurper. Let it finish soon
429 SetEvent (s->hev_unsleep);
430 SetEvent (s->hev_thread);
432 /* Unlock and maybe free shared data */
433 slurper_free_shared_data_maybe (s);
439 init_slurp_stream (void)
441 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
442 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
445 /************************************************************************/
446 /* Pipe outstream - writes process input */
447 /************************************************************************/
449 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
450 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
452 #define MAX_SHOVE_BUFFER_SIZE 128
454 struct ntpipe_shove_stream
456 LPARAM user_data; /* Any user data stored in the stream object */
457 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
458 /* This is an auto-reset object. */
459 HANDLE hpipe; /* Pipe write end handle. */
460 HANDLE hthread; /* Reader thread handle. */
461 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
462 DWORD size; /* Number of bytes to write */
463 LONG die_p; /* Thread must exit ASAP if non-zero */
464 LONG idle_p; /* Non-zero if thread is waiting for job */
465 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
466 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
469 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
470 sizeof (struct ntpipe_shove_stream));
473 shove_thread (LPVOID vparam)
475 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
481 /* Block on event and wait for a job */
482 InterlockedIncrement (&s->idle_p);
483 WaitForSingleObject (s->hev_thread, INFINITE);
488 /* Write passed buffer */
489 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
490 || bytes_written != s->size)
493 InterlockedIncrement (&s->die_p);
504 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
507 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
508 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
509 DWORD thread_id_unused;
514 s->user_data = param;
516 /* Create reader thread. This could fail, so do not
517 create the event until thread is created */
518 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
519 CREATE_SUSPENDED, &thread_id_unused);
520 if (s->hthread == NULL)
522 Lstream_delete (lstr);
526 /* hev_thread is an auto-reset event, initially nonsignaled */
527 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
530 ResumeThread (s->hthread);
532 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
533 XSETLSTREAM (obj, lstr);
538 get_ntpipe_output_stream_param (Lstream *stream)
540 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
545 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
547 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
552 s->blocking_p = !s->idle_p;
556 if (size>MAX_SHOVE_BUFFER_SIZE)
559 memcpy (s->buffer, data, size);
563 InterlockedDecrement (&s->idle_p);
564 SetEvent (s->hev_thread);
569 ntpipe_shove_was_blocked_p (Lstream *stream)
571 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
572 return s->blocking_p;
576 ntpipe_shove_closer (Lstream *stream)
578 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
580 /* Force thread stop */
581 InterlockedIncrement (&s->die_p);
583 /* Close pipe handle, possibly breaking it */
584 CloseHandle (s->hpipe);
586 /* Thread will end upon unblocking */
587 SetEvent (s->hev_thread);
589 /* Wait while thread terminates */
590 WaitForSingleObject (s->hthread, INFINITE);
591 CloseHandle (s->hthread);
593 /* Destroy the event */
594 CloseHandle (s->hev_thread);
600 init_shove_stream (void)
602 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
603 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
604 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
607 /************************************************************************/
608 /* Winsock I/O stream */
609 /************************************************************************/
610 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
612 #define WINSOCK_READ_BUFFER_SIZE 1024
614 struct winsock_stream
616 LPARAM user_data; /* Any user data stored in the stream object */
617 SOCKET s; /* Socket handle (which is a Win32 handle) */
618 OVERLAPPED ov; /* Overlapped I/O structure */
619 void* buffer; /* Buffer. Allocated for input stream only */
620 unsigned int bufsize; /* Number of bytes last read */
621 unsigned int bufpos; /* Psition in buffer for next fetch */
622 unsigned int error_p :1; /* I/O Error seen */
623 unsigned int eof_p :1; /* EOF Error seen */
624 unsigned int pending_p :1; /* There is a pending I/O operation */
625 unsigned int blocking_p :1; /* Last write attempt would block */
628 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
630 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
631 sizeof (struct winsock_stream));
634 winsock_initiate_read (struct winsock_stream *str)
636 ResetEvent (str->ov.hEvent);
639 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
640 &str->bufsize, &str->ov))
642 if (GetLastError () == ERROR_IO_PENDING)
644 else if (GetLastError () == ERROR_HANDLE_EOF)
649 else if (str->bufsize == 0)
654 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
656 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
658 /* If the current operation is not yet complete, there's nothing to
662 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
669 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
671 if (GetLastError() == ERROR_HANDLE_EOF)
676 if (str->bufsize == 0)
687 /* Return as much of buffer as we have */
688 size = min (size, (size_t) (str->bufsize - str->bufpos));
689 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
692 /* Read more if buffer is exhausted */
693 if (str->bufsize == str->bufpos)
694 winsock_initiate_read (str);
700 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size)
702 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
706 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
714 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
729 ResetEvent (str->ov.hEvent);
731 if (WriteFile ((HANDLE)str->s, data, size, NULL, &str->ov)
732 || GetLastError() == ERROR_IO_PENDING)
738 return str->error_p ? -1 : size;
742 winsock_closer (Lstream *lstr)
744 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
746 if (lstr->flags & LSTREAM_FL_READ)
747 shutdown (str->s, 0);
749 shutdown (str->s, 1);
751 CloseHandle ((HANDLE)str->s);
753 WaitForSingleObject (str->ov.hEvent, INFINITE);
755 if (lstr->flags & LSTREAM_FL_READ)
758 CloseHandle (str->ov.hEvent);
763 winsock_was_blocked_p (Lstream *stream)
765 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
766 return str->blocking_p;
770 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode)
773 Lstream *lstr = Lstream_new (lstream_winsock, mode);
774 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
781 str->user_data = param;
784 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
786 if (lstr->flags & LSTREAM_FL_READ)
788 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
789 winsock_initiate_read (str);
792 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
793 XSETLSTREAM (obj, lstr);
798 make_winsock_input_stream (SOCKET s, LPARAM param)
800 return make_winsock_stream_1 (s, param, "r");
804 make_winsock_output_stream (SOCKET s, LPARAM param)
806 return make_winsock_stream_1 (s, param, "w");
810 get_winsock_stream_waitable (Lstream *lstr)
812 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
813 return str->ov.hEvent;
817 get_winsock_stream_param (Lstream *lstr)
819 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
820 return str->user_data;
824 init_winsock_stream (void)
826 LSTREAM_HAS_METHOD (winsock, reader);
827 LSTREAM_HAS_METHOD (winsock, writer);
828 LSTREAM_HAS_METHOD (winsock, closer);
829 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
831 #endif /* defined (HAVE_SOCKETS) */
833 /************************************************************************/
834 /* Dispatch queue management */
835 /************************************************************************/
838 mswindows_user_event_p (struct Lisp_Event* sevt)
840 return (sevt->event_type == key_press_event
841 || sevt->event_type == button_press_event
842 || sevt->event_type == button_release_event
843 || sevt->event_type == misc_user_event);
847 * Add an emacs event to the proper dispatch queue
850 mswindows_enqueue_dispatch_event (Lisp_Object event)
852 int user_p = mswindows_user_event_p (XEVENT(event));
853 enqueue_event (event,
854 user_p ? &mswindows_u_dispatch_event_queue :
855 &mswindows_s_dispatch_event_queue,
856 user_p ? &mswindows_u_dispatch_event_queue_tail :
857 &mswindows_s_dispatch_event_queue_tail);
859 /* Avoid blocking on WaitMessage */
860 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
864 * Add a misc-user event to the dispatch queue.
866 * Stuff it into our own dispatch queue, so we have something
867 * to return from next_event callback.
870 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
873 Lisp_Object event = Fmake_event (Qnil, Qnil);
874 struct Lisp_Event* e = XEVENT (event);
876 e->event_type = misc_user_event;
877 e->channel = channel;
878 e->event.misc.function = function;
879 e->event.misc.object = object;
881 mswindows_enqueue_dispatch_event (event);
885 mswindows_enqueue_magic_event (HWND hwnd, UINT message)
887 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
888 struct Lisp_Event* event = XEVENT (emacs_event);
890 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
891 event->timestamp = GetMessageTime();
892 event->event_type = magic_event;
893 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message;
895 mswindows_enqueue_dispatch_event (emacs_event);
899 mswindows_enqueue_process_event (struct Lisp_Process* p)
901 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
902 struct Lisp_Event* event = XEVENT (emacs_event);
904 XSETPROCESS (process, p);
906 event->event_type = process_event;
907 event->timestamp = GetTickCount ();
908 event->event.process.process = process;
910 mswindows_enqueue_dispatch_event (emacs_event);
914 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when)
917 /* We always use last message time, because mouse button
918 events may get delayed, and XEmacs double click
919 recognition will fail */
921 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
922 struct Lisp_Event* event = XEVENT(emacs_event);
924 event->channel = mswindows_find_frame(hwnd);
925 event->timestamp = when;
926 event->event.button.button =
927 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 :
928 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2);
929 event->event.button.x = where.x;
930 event->event.button.y = where.y;
931 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
933 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN ||
934 message==WM_RBUTTONDOWN)
936 event->event_type = button_press_event;
941 event->event_type = button_release_event;
945 mswindows_enqueue_dispatch_event (emacs_event);
949 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
951 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
952 struct Lisp_Event* event = XEVENT(emacs_event);
954 event->channel = mswindows_find_console(hwnd);
955 event->timestamp = GetMessageTime();
956 event->event_type = key_press_event;
957 event->event.key.keysym = keysym;
958 event->event.key.modifiers = mods;
959 mswindows_enqueue_dispatch_event (emacs_event);
963 * Remove and return the first emacs event on the dispatch queue.
964 * Give a preference to user events over non-user ones.
967 mswindows_dequeue_dispatch_event ()
970 struct Lisp_Event* sevt;
972 assert (!NILP(mswindows_u_dispatch_event_queue) ||
973 !NILP(mswindows_s_dispatch_event_queue));
975 event = dequeue_event (
976 NILP(mswindows_u_dispatch_event_queue) ?
977 &mswindows_s_dispatch_event_queue :
978 &mswindows_u_dispatch_event_queue,
979 NILP(mswindows_u_dispatch_event_queue) ?
980 &mswindows_s_dispatch_event_queue_tail :
981 &mswindows_u_dispatch_event_queue_tail);
983 sevt = XEVENT(event);
984 if (sevt->event_type == key_press_event
985 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
987 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
988 --mswindows_quit_chars_count;
995 * Remove and return the first emacs event on the dispatch queue that matches
997 * Timeout event matches if interval_id equals to that of the given event.
998 * Keypress event matches if logical AND between modifiers bitmask of the
999 * event in the queue and that of the given event is non-zero
1000 * For all other event types, this function asserts.
1004 mswindows_cancel_dispatch_event (struct Lisp_Event* match)
1007 Lisp_Object previous_event=Qnil;
1008 int user_p = mswindows_user_event_p (match);
1009 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1010 &mswindows_s_dispatch_event_queue;
1011 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1012 &mswindows_s_dispatch_event_queue_tail;
1014 assert (match->event_type == timeout_event
1015 || match->event_type == key_press_event);
1017 EVENT_CHAIN_LOOP (event, *head)
1020 if (XEVENT_TYPE (event) != match->event_type)
1022 if (found && match->event_type == timeout_event
1023 && (XEVENT(event)->event.timeout.interval_id !=
1024 match->event.timeout.interval_id))
1026 if (found && match->event_type == key_press_event
1027 && ((XEVENT(event)->event.key.modifiers &
1028 match->event.key.modifiers) == 0))
1033 if (NILP (previous_event))
1034 dequeue_event (head, tail);
1037 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1038 if (EQ (*tail, event))
1039 *tail = previous_event;
1044 previous_event = event;
1049 /************************************************************************/
1050 /* Waitable handles manipulation */
1051 /************************************************************************/
1053 find_waitable_handle (HANDLE h)
1056 for (i = 0; i < mswindows_waitable_count; ++i)
1057 if (mswindows_waitable_handles[i] == h)
1064 add_waitable_handle (HANDLE h)
1066 assert (find_waitable_handle (h) < 0);
1067 if (mswindows_waitable_count == MAX_WAITABLE)
1070 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1075 remove_waitable_handle (HANDLE h)
1077 int ix = find_waitable_handle (h);
1081 mswindows_waitable_handles [ix] =
1082 mswindows_waitable_handles [--mswindows_waitable_count];
1086 /************************************************************************/
1088 /************************************************************************/
1091 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1092 Lisp_Object u_n_u_s_e_d)
1094 mswindows_error_caught_in_modal_loop = cons_sig_data;
1099 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1104 ++mswindows_in_modal_loop;
1105 tmp = condition_case_1 (Qt,
1107 mswindows_modal_loop_error_handler, Qnil);
1108 --mswindows_in_modal_loop;
1114 mswindows_unmodalize_signal_maybe (void)
1116 if (!NILP (mswindows_error_caught_in_modal_loop))
1118 /* Got an error while messages were pumped while
1119 in window procedure - have to resignal */
1120 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1121 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1122 mswindows_error_caught_in_modal_loop = Qnil;
1123 Fsignal (sym, data);
1128 * This is an unsafe part of event pump, guarded by
1129 * condition_case. See mswindows_pump_outstanding_events
1132 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1134 /* This function can call lisp */
1135 Lisp_Object event = Fmake_event (Qnil, Qnil);
1136 struct gcpro gcpro1;
1137 int do_redisplay = 0;
1140 while (detect_input_pending ())
1142 Fnext_event (event, Qnil);
1143 Fdispatch_event (event);
1150 Fdeallocate_event (event);
1153 /* Qt becomes return value of mswindows_pump_outstanding_events
1159 * This function pumps emacs events, while available, by using
1160 * next_message/dispatch_message loop. Errors are trapped around
1161 * the loop so the function always returns.
1163 * Windows message queue is not looked into during the call,
1164 * neither are waitable handles checked. The function pumps
1165 * thus only dispatch events already queued, as well as those
1166 * resulted in dispatching thereof. This is done by setting
1167 * module local variable mswidows_in_modal_loop to nonzero.
1169 * Return value is Qt if no errors was trapped, or Qunbound if
1170 * there was an error.
1172 * In case of error, a cons representing the error, in the
1173 * form (SIGNAL . DATA), is stored in the module local variable
1174 * mswindows_error_caught_in_modal_loop. This error is signaled
1175 * again when DispatchMessage returns. Thus, Windows internal
1176 * modal loops are protected against throws, which are proven
1177 * to corrupt internal Windows structures.
1179 * In case of success, mswindows_error_caught_in_modal_loop is
1182 * If the value of mswindows_error_caught_in_modal_loop is not
1183 * nil already upon entry, the function just returns non-nil.
1184 * This situation means that a new event has been queued while
1185 * cancleng mode. The event will be dequeued on the next regular
1186 * call of next-event; the pump is off since error is caught.
1187 * The caller must *unconditionally* cancel modal loop if the
1188 * value returned by this function is nil. Otherwise, everything
1189 * will become frozen until the modal loop exits under normal
1190 * condition (scrollbar drag is released, menu closed etc.)
1193 mswindows_pump_outstanding_events (void)
1195 /* This function can call lisp */
1197 Lisp_Object result = Qt;
1198 struct gcpro gcpro1;
1201 if (NILP(mswindows_error_caught_in_modal_loop))
1202 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1208 mswindows_drain_windows_queue ()
1211 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1213 DispatchMessage (&msg);
1214 mswindows_unmodalize_signal_maybe ();
1219 * This is a special flavour of the mswindows_need_event function,
1220 * used while in event pump. Actually, there is only kind of events
1221 * allowed while in event pump: a timer. An attempt to fetch any
1222 * other event leads to a dealock, as there's no source of user input
1223 * ('cause event pump mirrors windows modal loop, which is a sole
1224 * owner of thread message queue).
1226 * To detect this, we use a counter of active timers, and allow
1227 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1228 * which will never come when there are no pending timers, which leads
1229 * to deadlock, we simply signal an error.
1232 mswindows_need_event_in_modal_loop (int badly_p)
1236 /* Check if already have one */
1237 if (!NILP (mswindows_u_dispatch_event_queue)
1238 || !NILP (mswindows_s_dispatch_event_queue))
1241 /* No event is ok */
1245 /* We do not check the _u_ queue, because timers go to _s_ */
1246 while (NILP (mswindows_s_dispatch_event_queue))
1248 /* We'll deadlock if go waiting */
1249 if (mswindows_pending_timers_count == 0)
1250 error ("Deadlock due to an attempt to call next-event in a wrong context");
1252 /* Fetch and dispatch any pending timers */
1253 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1254 DispatchMessage (&msg);
1259 * This drains the event queue and fills up two internal queues until
1260 * an event of a type specified by USER_P is retrieved.
1263 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1266 mswindows_need_event (int badly_p)
1270 if (mswindows_in_modal_loop)
1272 mswindows_need_event_in_modal_loop (badly_p);
1276 /* Have to drain Windows message queue first, otherwise, we may miss
1277 quit char when called from quit_p */
1278 mswindows_drain_windows_queue ();
1280 while (NILP (mswindows_u_dispatch_event_queue)
1281 && NILP (mswindows_s_dispatch_event_queue))
1283 #ifdef HAVE_MSG_SELECT
1285 SELECT_TYPE temp_mask = input_wait_mask;
1286 EMACS_TIME sometime;
1287 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1290 pointer_to_this = 0;
1293 EMACS_SET_SECS_USECS (sometime, 0, 0);
1294 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1295 pointer_to_this = &select_time_to_block;
1297 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1301 return; /* timeout */
1303 else if (active > 0)
1305 if (FD_ISSET (windows_fd, &temp_mask))
1307 mswindows_drain_windows_queue ();
1310 /* Look for a process event */
1311 for (i = 0; i < MAXDESC-1; i++)
1313 if (FD_ISSET (i, &temp_mask))
1315 if (FD_ISSET (i, &process_only_mask))
1317 struct Lisp_Process *p =
1318 get_process_from_usid (FD_TO_USID(i));
1320 mswindows_enqueue_process_event (p);
1322 else if (FD_ISSET (i, &tty_only_mask))
1324 /* do we care about tty events? Do we
1325 ever get tty events? */
1329 /* We might get here when a fake event came
1330 through a signal. Return a dummy event, so
1331 that a cycle of the command loop will
1333 drain_signal_event_pipe ();
1334 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1339 else if (active==-1)
1343 /* something bad happended */
1352 /* Now try getting a message or process event */
1353 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1354 mswindows_waitable_handles,
1355 FALSE, badly_p ? INFINITE : 0,
1358 /* This will assert if handle being waited for becomes abandoned.
1359 Not the case currently tho */
1360 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1361 (active >= WAIT_OBJECT_0 &&
1362 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1364 if (active == WAIT_TIMEOUT)
1366 /* No luck trying - just return what we've already got */
1369 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1371 /* Got your message, thanks */
1372 mswindows_drain_windows_queue ();
1376 int ix = active - WAIT_OBJECT_0;
1377 /* First, try to find which process' ouptut has signaled */
1378 struct Lisp_Process *p =
1379 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1382 /* Found a signaled process input handle */
1383 mswindows_enqueue_process_event (p);
1387 /* None. This means that the process handle itself has signaled.
1388 Remove the handle from the wait vector, and make status_ntoify
1389 note the exited process */
1390 mswindows_waitable_handles [ix] =
1391 mswindows_waitable_handles [--mswindows_waitable_count];
1392 kick_status_notify ();
1393 /* Have to return something: there may be no accompanying
1395 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1402 /************************************************************************/
1403 /* Event generators */
1404 /************************************************************************/
1407 * Callback procedure for synchronous timer messages
1409 static void CALLBACK
1410 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1412 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1413 struct Lisp_Event *event = XEVENT (emacs_event);
1415 if (KillTimer (NULL, id_timer))
1416 --mswindows_pending_timers_count;
1418 event->channel = Qnil;
1419 event->timestamp = dwtime;
1420 event->event_type = timeout_event;
1421 event->event.timeout.interval_id = id_timer;
1423 mswindows_enqueue_dispatch_event (emacs_event);
1427 * Callback procedure for dde messages
1429 * We execute a dde Open("file") by simulating a file drop, so dde support
1430 * depends on dnd support.
1432 #ifdef HAVE_DRAGNDROP
1434 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1435 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1436 DWORD dwData1, DWORD dwData2)
1441 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1442 return (HDDEDATA)TRUE;
1443 return (HDDEDATA)FALSE;
1445 case XTYP_WILDCONNECT:
1447 /* We only support one {service,topic} pair */
1448 HSZPAIR pairs[2] = {
1449 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1451 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1452 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1453 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1454 sizeof (pairs), 0L, 0, uFmt, 0));
1456 return (HDDEDATA)NULL;
1459 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1461 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1462 char *cmd = alloca (len+1);
1465 struct gcpro gcpro1, gcpro2;
1466 Lisp_Object l_dndlist = Qnil;
1467 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1468 Lisp_Object frmcons, devcons, concons;
1469 struct Lisp_Event *event = XEVENT (emacs_event);
1471 DdeGetData (hdata, cmd, len, 0);
1473 DdeFreeDataHandle (hdata);
1475 /* Check syntax & that it's an [Open("foo")] command, which we
1476 * treat like a file drop */
1477 /* #### Ought to be generalised and accept some other commands */
1480 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1481 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1482 return DDE_FNOTPROCESSED;
1483 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1486 if (*cmd!='(' || *(cmd+1)!='\"')
1487 return DDE_FNOTPROCESSED;
1489 while (*end && *end!='\"')
1492 return DDE_FNOTPROCESSED;
1495 return DDE_FNOTPROCESSED;
1499 return DDE_FNOTPROCESSED;
1502 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1503 strcpy (filename, "file:");
1504 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1506 dostounix_filename (cmd);
1507 filename = alloca (strlen (cmd)+6);
1508 strcpy (filename, "file:");
1509 strcat (filename, cmd);
1511 GCPRO2 (emacs_event, l_dndlist);
1512 l_dndlist = make_string (filename, strlen (filename));
1514 /* Find a mswindows frame */
1515 event->channel = Qnil;
1516 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1518 Lisp_Object frame = XCAR (frmcons);
1519 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1520 event->channel = frame;
1522 assert (!NILP (event->channel));
1524 event->timestamp = GetTickCount();
1525 event->event_type = misc_user_event;
1526 event->event.misc.button = 1;
1527 event->event.misc.modifiers = 0;
1528 event->event.misc.x = -1;
1529 event->event.misc.y = -1;
1530 event->event.misc.function = Qdragdrop_drop_dispatch;
1531 event->event.misc.object = Fcons (Qdragdrop_URL,
1532 Fcons (l_dndlist, Qnil));
1533 mswindows_enqueue_dispatch_event (emacs_event);
1535 return (HDDEDATA) DDE_FACK;
1537 DdeFreeDataHandle (hdata);
1538 return (HDDEDATA) DDE_FNOTPROCESSED;
1541 return (HDDEDATA) NULL;
1547 * The windows procedure for the window class XEMACS_CLASS
1550 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1552 /* Note: Remember to initialise emacs_event and event before use.
1553 This code calls code that can GC. You must GCPRO before calling such code. */
1554 Lisp_Object emacs_event = Qnil;
1555 Lisp_Object fobj = Qnil;
1557 struct Lisp_Event *event;
1558 struct frame *frame;
1559 struct mswindows_frame* msframe;
1564 /* Erase background only during non-dynamic sizing */
1565 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1566 if (msframe->sizing && !mswindows_dynamic_frame_resize)
1571 fobj = mswindows_find_frame (hwnd);
1572 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1579 int has_AltGr = mswindows_current_layout_has_AltGr ();
1583 GetKeyboardState (keymap);
1584 mods = mswindows_modifier_state (keymap, has_AltGr);
1586 /* Handle those keys that TranslateMessage won't generate a WM_CHAR for */
1587 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1588 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1591 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1592 BYTE keymap_orig[256];
1593 MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
1594 memcpy (keymap_orig, keymap, 256);
1596 /* Remove shift modifier from an ascii character */
1599 /* Clear control and alt modifiers out of the keymap */
1600 keymap [VK_RCONTROL] = 0;
1601 keymap [VK_LMENU] = 0;
1602 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1604 keymap [VK_LCONTROL] = 0;
1605 keymap [VK_CONTROL] = 0;
1606 keymap [VK_RMENU] = 0;
1607 keymap [VK_MENU] = 0;
1609 SetKeyboardState (keymap);
1611 /* Have some WM_[SYS]CHARS in the queue */
1612 TranslateMessage (&msg);
1614 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1615 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1618 WPARAM ch = msg.wParam;
1620 /* If a quit char with no modifiers other than control and
1621 shift, then mark it with a fake modifier, which is removed
1622 upon dequeueing the event */
1623 /* #### This might also not withstand localization, if
1624 quit character is not a latin-1 symbol */
1625 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1626 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1627 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1629 mods1 |= FAKE_MOD_QUIT;
1630 ++mswindows_quit_chars_count;
1633 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1635 SetKeyboardState (keymap_orig);
1638 /* F10 causes menu activation by default. We do not want this */
1639 if (wParam != VK_F10)
1643 case WM_MBUTTONDOWN:
1645 /* Real middle mouse button has nothing to do with emulated one:
1646 if one wants to exercise fingers playing chords on the mouse,
1647 he is allowed to do that! */
1648 mswindows_enqueue_mouse_button_event (hwnd, message,
1649 MAKEPOINTS (lParam), GetMessageTime());
1653 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1654 msframe->last_click_time = GetMessageTime();
1656 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1657 msframe->button2_need_lbutton = 0;
1658 if (msframe->ignore_next_lbutton_up)
1660 msframe->ignore_next_lbutton_up = 0;
1662 else if (msframe->button2_is_down)
1664 msframe->button2_is_down = 0;
1665 msframe->ignore_next_rbutton_up = 1;
1666 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1667 MAKEPOINTS (lParam), GetMessageTime());
1671 if (msframe->button2_need_rbutton)
1673 msframe->button2_need_rbutton = 0;
1674 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1675 MAKEPOINTS (lParam), GetMessageTime());
1677 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1678 MAKEPOINTS (lParam), GetMessageTime());
1683 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1684 msframe->last_click_time = GetMessageTime();
1686 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1687 msframe->button2_need_rbutton = 0;
1688 if (msframe->ignore_next_rbutton_up)
1690 msframe->ignore_next_rbutton_up = 0;
1692 else if (msframe->button2_is_down)
1694 msframe->button2_is_down = 0;
1695 msframe->ignore_next_lbutton_up = 1;
1696 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1697 MAKEPOINTS (lParam), GetMessageTime());
1701 if (msframe->button2_need_lbutton)
1703 msframe->button2_need_lbutton = 0;
1704 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1705 MAKEPOINTS (lParam), GetMessageTime());
1707 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1708 MAKEPOINTS (lParam), GetMessageTime());
1712 case WM_LBUTTONDOWN:
1713 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1715 if (msframe->button2_need_lbutton)
1717 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1718 msframe->button2_need_lbutton = 0;
1719 msframe->button2_need_rbutton = 0;
1720 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1722 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1723 MAKEPOINTS (lParam), GetMessageTime());
1724 msframe->button2_is_down = 1;
1728 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1729 msframe->last_click_point, msframe->last_click_time);
1730 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1731 MAKEPOINTS (lParam), GetMessageTime());
1736 mswindows_set_chord_timer (hwnd);
1737 msframe->button2_need_rbutton = 1;
1738 msframe->last_click_point = MAKEPOINTS (lParam);
1740 msframe->last_click_time = GetMessageTime();
1743 case WM_RBUTTONDOWN:
1744 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1746 if (msframe->button2_need_rbutton)
1748 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1749 msframe->button2_need_lbutton = 0;
1750 msframe->button2_need_rbutton = 0;
1751 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1753 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1754 MAKEPOINTS (lParam), GetMessageTime());
1755 msframe->button2_is_down = 1;
1759 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1760 msframe->last_click_point, msframe->last_click_time);
1761 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1762 MAKEPOINTS (lParam), GetMessageTime());
1767 mswindows_set_chord_timer (hwnd);
1768 msframe->button2_need_lbutton = 1;
1769 msframe->last_click_point = MAKEPOINTS (lParam);
1771 msframe->last_click_time = GetMessageTime();
1775 if (wParam == BUTTON_2_TIMER_ID)
1777 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1778 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1780 if (msframe->button2_need_lbutton)
1782 msframe->button2_need_lbutton = 0;
1783 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1784 msframe->last_click_point, msframe->last_click_time);
1786 else if (msframe->button2_need_rbutton)
1788 msframe->button2_need_rbutton = 0;
1789 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1790 msframe->last_click_point, msframe->last_click_time);
1794 assert ("Spurious timer fired" == 0);
1798 /* Optimization: don't report mouse movement while size is changind */
1799 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1800 if (!msframe->sizing)
1802 /* When waiting for the second mouse button to finish
1803 button2 emulation, and have moved too far, just pretend
1804 as if timer has expired. This impoves drag-select feedback */
1805 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1806 && !mswindows_button2_near_enough (msframe->last_click_point,
1807 MAKEPOINTS (lParam)))
1809 KillTimer (hwnd, BUTTON_2_TIMER_ID);
1810 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1813 emacs_event = Fmake_event (Qnil, Qnil);
1814 event = XEVENT(emacs_event);
1816 event->channel = mswindows_find_frame(hwnd);
1817 event->timestamp = GetMessageTime();
1818 event->event_type = pointer_motion_event;
1819 event->event.motion.x = MAKEPOINTS(lParam).x;
1820 event->event.motion.y = MAKEPOINTS(lParam).y;
1821 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1823 mswindows_enqueue_dispatch_event (emacs_event);
1829 /* Queue a `cancel-mode-internal' misc user event, so mouse
1830 selection would be canceled if any */
1831 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1832 Qcancel_mode_internal, Qnil);
1835 #ifdef HAVE_TOOLBARS
1838 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1840 if (tttext->hdr.code == TTN_NEEDTEXT)
1842 /* find out which toolbar */
1843 frame = XFRAME (mswindows_find_frame (hwnd));
1844 btext = mswindows_get_toolbar_button_text ( frame,
1845 tttext->hdr.idFrom );
1847 tttext->lpszText = NULL;
1848 tttext->hinst = NULL;
1852 /* I think this is safe since the text will only go away
1853 when the toolbar does...*/
1854 tttext->lpszText=XSTRING_DATA (btext);
1857 tttext->uFlags |= TTF_DI_SETITEM;
1866 PAINTSTRUCT paintStruct;
1868 frame = XFRAME (mswindows_find_frame (hwnd));
1870 BeginPaint (hwnd, &paintStruct);
1871 mswindows_redraw_exposed_area (frame,
1872 paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1873 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1874 EndPaint (hwnd, &paintStruct);
1879 /* We only care about this message if our size has really changed */
1880 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1885 fobj = mswindows_find_frame (hwnd);
1886 frame = XFRAME (fobj);
1887 msframe = FRAME_MSWINDOWS_DATA (frame);
1889 /* We cannot handle frame map and unmap hooks right in
1890 this routine, because these may throw. We queue
1891 magic events to run these hooks instead - kkm */
1893 if (wParam==SIZE_MINIMIZED)
1896 FRAME_VISIBLE_P (frame) = 0;
1897 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
1901 GetClientRect(hwnd, &rect);
1902 FRAME_PIXWIDTH(frame) = rect.right;
1903 FRAME_PIXHEIGHT(frame) = rect.bottom;
1905 pixel_to_real_char_size (frame, rect.right, rect.bottom,
1906 &FRAME_MSWINDOWS_CHARWIDTH (frame),
1907 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
1909 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
1910 change_frame_size (frame, rows, columns, 1);
1912 /* If we are inside frame creation, we have to apply geometric
1914 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1916 /* Yes, we have to size again */
1917 mswindows_size_frame_internal ( frame,
1918 FRAME_MSWINDOWS_TARGET_RECT
1920 /* Reset so we do not get here again. The SetWindowPos call in
1921 * mswindows_size_frame_internal can cause recursion here. */
1922 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1924 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
1925 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
1930 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
1931 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
1932 FRAME_VISIBLE_P (frame) = 1;
1934 if (!msframe->sizing || mswindows_dynamic_frame_resize)
1941 /* Misc magic events which only require that the frame be identified */
1944 mswindows_enqueue_magic_event (hwnd, message);
1947 case WM_WINDOWPOSCHANGING:
1949 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
1950 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
1951 GetWindowPlacement(hwnd, &wpl);
1953 /* Only interested if size is changing and we're not being iconified */
1954 if (wpl.showCmd != SW_SHOWMINIMIZED
1955 && wpl.showCmd != SW_SHOWMAXIMIZED
1956 && !(wp->flags & SWP_NOSIZE))
1958 RECT ncsize = { 0, 0, 0, 0 };
1959 int pixwidth, pixheight;
1960 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
1961 GetMenu(hwnd) != NULL,
1962 GetWindowLong (hwnd, GWL_EXSTYLE));
1964 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
1965 wp->cx - (ncsize.right - ncsize.left),
1966 wp->cy - (ncsize.bottom - ncsize.top),
1967 &pixwidth, &pixheight);
1969 /* Convert client sizes to window sizes */
1970 pixwidth += (ncsize.right - ncsize.left);
1971 pixheight += (ncsize.bottom - ncsize.top);
1973 if (wpl.showCmd != SW_SHOWMAXIMIZED)
1975 /* Adjust so that the bottom or right doesn't move if it's
1976 * the top or left that's being changed */
1978 GetWindowRect (hwnd, &rect);
1980 if (rect.left != wp->x)
1981 wp->x += wp->cx - pixwidth;
1982 if (rect.top != wp->y)
1983 wp->y += wp->cy - pixheight;
1989 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
1990 window position if the user tries to track window too small */
1994 case WM_ENTERSIZEMOVE:
1995 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1996 msframe->sizing = 1;
1999 case WM_EXITSIZEMOVE:
2000 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2001 msframe->sizing = 0;
2002 /* Queue noop event */
2003 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2006 #ifdef HAVE_SCROLLBARS
2010 /* Direction of scroll is determined by scrollbar instance. */
2011 int code = (int) LOWORD(wParam);
2012 int pos = (short int) HIWORD(wParam);
2013 HWND hwndScrollBar = (HWND) lParam;
2014 struct gcpro gcpro1, gcpro2;
2016 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2017 GCPRO2 (emacs_event, fobj);
2018 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2020 /* Error during event pumping - cancel scroll */
2021 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2028 #ifdef HAVE_MENUBARS
2030 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2032 XFRAME (mswindows_find_frame (hwnd)))))
2033 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2036 case WM_INITMENUPOPUP:
2037 if (!HIWORD(lParam))
2039 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2041 XFRAME (mswindows_find_frame (hwnd)))))
2042 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2046 #endif /* HAVE_MENUBARS */
2050 WORD id = LOWORD (wParam);
2051 HWND cid = (HWND)lParam;
2052 frame = XFRAME (mswindows_find_frame (hwnd));
2054 #ifdef HAVE_TOOLBARS
2055 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2059 #ifdef HAVE_MENUBARS
2060 if (!NILP (mswindows_handle_wm_command (frame, id)))
2064 /* Bite me - a spurious command. This cannot happen. */
2065 error ("XEMACS BUG: Cannot decode command message");
2069 #ifdef HAVE_DRAGNDROP
2070 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2072 UINT filecount, i, len;
2078 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2079 struct gcpro gcpro1, gcpro2, gcpro3;
2081 emacs_event = Fmake_event (Qnil, Qnil);
2082 event = XEVENT(emacs_event);
2084 GCPRO3 (emacs_event, l_dndlist, l_item);
2086 if (!DragQueryPoint ((HANDLE) wParam, &point))
2087 point.x = point.y = -1; /* outside client area */
2089 event->event_type = misc_user_event;
2090 event->channel = mswindows_find_frame(hwnd);
2091 event->timestamp = GetMessageTime();
2092 event->event.misc.button = 1; /* #### Should try harder */
2093 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2094 event->event.misc.x = point.x;
2095 event->event.misc.y = point.y;
2096 event->event.misc.function = Qdragdrop_drop_dispatch;
2098 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2099 for (i=0; i<filecount; i++)
2101 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2102 /* The URLs that we make here aren't correct according to section
2103 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2104 * because they may contain reserved characters. But that's OK. */
2106 fname = (char *)xmalloc (len+1);
2107 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2108 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2109 strcpy (filename, "file:");
2110 cygwin32_win32_to_posix_path_list (fname, filename+5);
2113 filename = (char *)xmalloc (len+6);
2114 strcpy (filename, "file:");
2115 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2116 dostounix_filename (filename+5);
2118 l_item = make_string (filename, strlen (filename));
2119 l_dndlist = Fcons (l_item, l_dndlist);
2122 DragFinish ((HANDLE) wParam);
2124 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2125 mswindows_enqueue_dispatch_event (emacs_event);
2133 return DefWindowProc (hwnd, message, wParam, lParam);
2139 /************************************************************************/
2140 /* keyboard, mouse & other helpers for the windows procedure */
2141 /************************************************************************/
2143 mswindows_set_chord_timer (HWND hwnd)
2147 /* We get one third half system double click threshold */
2148 if (mswindows_mouse_button_tolerance <= 0)
2149 interval = GetDoubleClickTime () / 3;
2151 interval = mswindows_mouse_button_tolerance;
2153 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2157 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2160 if (mswindows_mouse_button_max_skew_x <= 0)
2161 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2163 dx = mswindows_mouse_button_max_skew_x;
2165 if (mswindows_mouse_button_max_skew_y <= 0)
2166 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2168 dy = mswindows_mouse_button_max_skew_y;
2170 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2174 mswindows_current_layout_has_AltGr (void)
2176 /* This simple caching mechanism saves 10% of CPU
2177 time when a key typed at autorepeat rate of 30 cps! */
2178 static HKL last_hkl = 0;
2179 static int last_hkl_has_AltGr;
2181 HKL current_hkl = GetKeyboardLayout (0);
2182 if (current_hkl != last_hkl)
2185 last_hkl_has_AltGr = 0;
2186 /* In this loop, we query whether a character requires
2187 AltGr to be down to generate it. If at least such one
2188 found, this means that the layout does regard AltGr */
2189 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2190 if (HIBYTE (VkKeyScan (c)) == 6)
2191 last_hkl_has_AltGr = 1;
2192 last_hkl = current_hkl;
2194 return last_hkl_has_AltGr;
2198 /* Returns the state of the modifier keys in the format expected by the
2199 * Lisp_Event key_data, button_data and motion_data modifiers member */
2200 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2206 keymap = (BYTE*) alloca(256);
2207 GetKeyboardState (keymap);
2208 has_AltGr = mswindows_current_layout_has_AltGr ();
2211 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2213 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2214 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2218 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2219 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2222 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2228 * Translate a mswindows virtual key to a keysym.
2229 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2230 * or whose ASCII codes (like space) xemacs doesn't like.
2231 * Virtual key values are defined in winresrc.h
2232 * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2234 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2236 switch (mswindows_key)
2238 /* First the predefined ones */
2239 case VK_BACK: return QKbackspace;
2240 case VK_TAB: return QKtab;
2241 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */
2242 case VK_RETURN: return QKreturn;
2243 case VK_ESCAPE: return QKescape;
2244 case VK_SPACE: return QKspace;
2245 case VK_DELETE: return QKdelete;
2248 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */
2249 case VK_PRIOR: return KEYSYM ("prior");
2250 case VK_NEXT: return KEYSYM ("next");
2251 case VK_END: return KEYSYM ("end");
2252 case VK_HOME: return KEYSYM ("home");
2253 case VK_LEFT: return KEYSYM ("left");
2254 case VK_UP: return KEYSYM ("up");
2255 case VK_RIGHT: return KEYSYM ("right");
2256 case VK_DOWN: return KEYSYM ("down");
2257 case VK_SELECT: return KEYSYM ("select");
2258 case VK_PRINT: return KEYSYM ("print");
2259 case VK_EXECUTE: return KEYSYM ("execute");
2260 case VK_SNAPSHOT: return KEYSYM ("print");
2261 case VK_INSERT: return KEYSYM ("insert");
2262 case VK_HELP: return KEYSYM ("help");
2263 #if 0 /* XXX What are these supposed to do? */
2264 case VK_LWIN return KEYSYM ("");
2265 case VK_RWIN return KEYSYM ("");
2267 case VK_APPS: return KEYSYM ("menu");
2268 case VK_F1: return KEYSYM ("f1");
2269 case VK_F2: return KEYSYM ("f2");
2270 case VK_F3: return KEYSYM ("f3");
2271 case VK_F4: return KEYSYM ("f4");
2272 case VK_F5: return KEYSYM ("f5");
2273 case VK_F6: return KEYSYM ("f6");
2274 case VK_F7: return KEYSYM ("f7");
2275 case VK_F8: return KEYSYM ("f8");
2276 case VK_F9: return KEYSYM ("f9");
2277 case VK_F10: return KEYSYM ("f10");
2278 case VK_F11: return KEYSYM ("f11");
2279 case VK_F12: return KEYSYM ("f12");
2280 case VK_F13: return KEYSYM ("f13");
2281 case VK_F14: return KEYSYM ("f14");
2282 case VK_F15: return KEYSYM ("f15");
2283 case VK_F16: return KEYSYM ("f16");
2284 case VK_F17: return KEYSYM ("f17");
2285 case VK_F18: return KEYSYM ("f18");
2286 case VK_F19: return KEYSYM ("f19");
2287 case VK_F20: return KEYSYM ("f20");
2288 case VK_F21: return KEYSYM ("f21");
2289 case VK_F22: return KEYSYM ("f22");
2290 case VK_F23: return KEYSYM ("f23");
2291 case VK_F24: return KEYSYM ("f24");
2297 * Find the console that matches the supplied mswindows window handle
2300 mswindows_find_console (HWND hwnd)
2302 /* We only support one console */
2303 return XCAR (Vconsole_list);
2307 * Find the frame that matches the supplied mswindows window handle
2310 mswindows_find_frame (HWND hwnd)
2312 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2316 /* We are in progress of frame creation. Return the frame
2317 being created, as it still not remembered in the window
2319 assert (!NILP (Vmswindows_frame_being_created));
2320 return Vmswindows_frame_being_created;
2322 VOID_TO_LISP (f, l);
2327 /************************************************************************/
2329 /************************************************************************/
2332 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2335 EMACS_TIME current_time;
2336 EMACS_GET_TIME (current_time);
2337 EMACS_SUB_TIME (thyme, thyme, current_time);
2338 milliseconds = EMACS_SECS (thyme) * 1000 +
2339 (EMACS_USECS (thyme) + 500) / 1000;
2340 if (milliseconds < 1)
2342 ++mswindows_pending_timers_count;
2343 return SetTimer (NULL, 0, milliseconds,
2344 (TIMERPROC) mswindows_wm_timer_callback);
2348 emacs_mswindows_remove_timeout (int id)
2350 struct Lisp_Event match_against;
2351 Lisp_Object emacs_event;
2353 if (KillTimer (NULL, id))
2354 --mswindows_pending_timers_count;
2356 /* If there is a dispatch event generated by this
2357 timeout in the queue, we have to remove it too. */
2358 match_against.event_type = timeout_event;
2359 match_against.event.timeout.interval_id = id;
2360 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2361 if (!NILP (emacs_event))
2362 Fdeallocate_event(emacs_event);
2365 /* If `user_p' is false, then return whether there are any win32, timeout,
2366 * or subprocess events pending (that is, whether
2367 * emacs_mswindows_next_event() would return immediately without blocking).
2369 * if `user_p' is true, then return whether there are any *user generated*
2370 * events available (that is, whether there are keyboard or mouse-click
2371 * events ready to be read). This also implies that
2372 * emacs_mswindows_next_event() would not block.
2375 emacs_mswindows_event_pending_p (int user_p)
2377 mswindows_need_event (0);
2378 return (!NILP (mswindows_u_dispatch_event_queue)
2379 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2383 * Return the next event
2386 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2388 Lisp_Object event, event2;
2390 mswindows_need_event (1);
2392 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
2393 XSETEVENT (event2, emacs_event);
2394 Fcopy_event (event, event2);
2395 Fdeallocate_event (event);
2399 * Handle a magic event off the dispatch queue.
2402 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2404 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2412 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2413 struct frame *f = XFRAME (frame);
2414 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2417 /* struct gcpro gcpro1; */
2419 /* Clear sticky modifiers here (if we had any) */
2421 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2422 /* GCPRO1 (conser); XXX Not necessary? */
2423 emacs_handle_focus_change_preliminary (conser);
2424 /* Under X the stuff up to here is done in the X event handler.
2426 emacs_handle_focus_change_final (conser);
2435 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2436 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
2438 Qmap_frame_hook : Qunmap_frame_hook,
2443 /* #### What about Enter & Leave */
2445 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2446 Qmouse_leave_frame_hook, 1, frame);
2455 get_process_input_waitable (struct Lisp_Process *process)
2457 Lisp_Object instr, outstr, p;
2458 XSETPROCESS (p, process);
2459 get_process_streams (process, &instr, &outstr);
2460 assert (!NILP (instr));
2461 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2462 return (network_connection_p (p)
2463 ? get_winsock_stream_waitable (XLSTREAM (instr))
2464 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2466 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2471 emacs_mswindows_select_process (struct Lisp_Process *process)
2473 HANDLE hev = get_process_input_waitable (process);
2475 if (!add_waitable_handle (hev))
2476 error ("Too many active processes");
2478 #ifdef HAVE_WIN32_PROCESSES
2481 XSETPROCESS (p, process);
2482 if (!network_connection_p (p))
2484 HANDLE hprocess = get_nt_process_handle (process);
2485 if (!add_waitable_handle (hprocess))
2487 remove_waitable_handle (hev);
2488 error ("Too many active processes");
2496 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2498 /* Process handle is removed in the event loop as soon
2499 as it is signaled, so don't bother here about it */
2500 HANDLE hev = get_process_input_waitable (process);
2501 remove_waitable_handle (hev);
2505 emacs_mswindows_select_console (struct console *con)
2510 emacs_mswindows_unselect_console (struct console *con)
2515 emacs_mswindows_quit_p (void)
2517 /* Quit cannot happen in modal loop: all program
2518 input is dedicated to Windows. */
2519 if (mswindows_in_modal_loop)
2522 /* Drain windows queue. This sets up number of quit
2523 characters in in the queue */
2524 mswindows_drain_windows_queue ();
2526 if (mswindows_quit_chars_count > 0)
2528 /* Yes there's a hidden one... Throw it away */
2529 struct Lisp_Event match_against;
2530 Lisp_Object emacs_event;
2532 match_against.event_type = key_press_event;
2533 match_against.event.key.modifiers = FAKE_MOD_QUIT;
2535 emacs_event = mswindows_cancel_dispatch_event (&match_against);
2536 assert (!NILP (emacs_event));
2538 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2541 Fdeallocate_event(emacs_event);
2542 --mswindows_quit_chars_count;
2547 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2548 Lisp_Object* instream,
2549 Lisp_Object* outstream,
2552 /* Handles for streams */
2554 /* fds. These just stored along with the streams, and are closed in
2555 delete stream pair method, because we need to handle fake unices
2559 /* Decode inhandle and outhandle. Their meaning depends on
2560 the process implementation being used. */
2561 #if defined (HAVE_WIN32_PROCESSES)
2562 /* We're passed in Windows handles. That's what we like most... */
2563 hin = (HANDLE) inhandle;
2564 hout = (HANDLE) outhandle;
2566 #elif defined (HAVE_UNIX_PROCESSES)
2567 /* We are passed UNIX fds. This must be Cygwin.
2569 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2570 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2574 #error "So, WHICH kind of processes do you want?"
2577 *instream = (hin == INVALID_HANDLE_VALUE
2579 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2580 : flags & STREAM_NETWORK_CONNECTION
2581 ? make_winsock_input_stream ((SOCKET)hin, fdi)
2583 : make_ntpipe_input_stream (hin, fdi));
2585 #ifdef HAVE_WIN32_PROCESSES
2586 *outstream = (hout == INVALID_HANDLE_VALUE
2588 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2589 : flags & STREAM_NETWORK_CONNECTION
2590 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2592 : make_ntpipe_output_stream (hout, fdo));
2593 #elif defined (HAVE_UNIX_PROCESSES)
2594 *outstream = (fdo >= 0
2595 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2598 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2599 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2600 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2602 Bufbyte eof_char = get_eof_char (fdo);
2603 int pty_max_bytes = get_pty_max_bytes (fdo);
2604 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2609 return (NILP (*instream)
2611 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2612 : flags & STREAM_NETWORK_CONNECTION
2613 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2615 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2619 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2620 Lisp_Object outstream)
2622 /* Oh nothing special here for Win32 at all */
2623 #if defined (HAVE_UNIX_PROCESSES)
2624 int in = (NILP(instream)
2626 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2627 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2628 ? get_winsock_stream_param (XLSTREAM (instream))
2630 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2631 int out = (NILP(outstream) ? -1
2632 : filedesc_stream_fd (XLSTREAM (outstream)));
2636 if (out != in && out >= 0)
2640 return (NILP (instream)
2642 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2643 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2644 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2646 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2649 #ifndef HAVE_X_WINDOWS
2650 /* This is called from GC when a process object is about to be freed.
2651 If we've still got pointers to it in this file, we're gonna lose hard.
2654 debug_process_finalization (struct Lisp_Process *p)
2657 Lisp_Object instr, outstr;
2659 get_process_streams (p, &instr, &outstr);
2660 /* if it still has fds, then it hasn't been killed yet. */
2661 assert (NILP(instr));
2662 assert (NILP(outstr));
2664 /* #### More checks here */
2669 /************************************************************************/
2670 /* initialization */
2671 /************************************************************************/
2674 vars_of_event_mswindows (void)
2676 mswindows_u_dispatch_event_queue = Qnil;
2677 staticpro (&mswindows_u_dispatch_event_queue);
2678 mswindows_u_dispatch_event_queue_tail = Qnil;
2680 mswindows_s_dispatch_event_queue = Qnil;
2681 staticpro (&mswindows_s_dispatch_event_queue);
2682 mswindows_s_dispatch_event_queue_tail = Qnil;
2684 mswindows_error_caught_in_modal_loop = Qnil;
2685 staticpro (&mswindows_error_caught_in_modal_loop);
2686 mswindows_in_modal_loop = 0;
2687 mswindows_pending_timers_count = 0;
2689 mswindows_event_stream = xnew (struct event_stream);
2691 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
2692 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
2693 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2694 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
2695 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
2696 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
2697 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
2698 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
2699 #ifdef HAVE_MSG_SELECT
2700 mswindows_event_stream->select_process_cb =
2701 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2702 mswindows_event_stream->unselect_process_cb =
2703 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2704 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2705 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2707 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
2708 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
2709 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2710 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2713 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2714 *Controls redrawing frame contents during mouse-drag or keyboard resize
2715 operation. When non-nil, the frame is redrawn while being resized. When
2716 nil, frame is not redrawn, and exposed areas are filled with default
2717 MDI application background color. Note that this option only has effect
2718 if "Show window contents while dragging" is on in system Display/Plus!
2720 Default is t on fast machines, nil on slow.
2723 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2724 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2725 *Analogue of double click interval for faking middle mouse events.
2726 The value is the minimum time in milliseconds that must elapse between
2727 left/right button down events before they are considered distinct events.
2728 If both mouse buttons are depressed within this interval, a middle mouse
2729 button down event is generated instead.
2730 If negative or zero, currently set system default is used instead.
2733 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2734 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2735 Number of physical mouse buttons.
2738 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2739 *Maximum horizontal distance in pixels between points in which left and
2740 right button clicks occured for them to be translated into single
2741 middle button event. Clicks must occur in time not longer than defined
2742 by the variable `mswindows-mouse-button-tolerance'.
2743 If negative or zero, currently set system default is used instead.
2746 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2747 *Maximum vertical distance in pixels between points in which left and
2748 right button clicks occured for them to be translated into single
2749 middle button event. Clicks must occur in time not longer than defined
2750 by the variable `mswindows-mouse-button-tolerance'.
2751 If negative or zero, currently set system default is used instead.
2754 mswindows_mouse_button_max_skew_x = 0;
2755 mswindows_mouse_button_max_skew_y = 0;
2756 mswindows_mouse_button_tolerance = 0;
2760 syms_of_event_mswindows (void)
2765 lstream_type_create_mswindows_selectable (void)
2767 init_slurp_stream ();
2768 init_shove_stream ();
2769 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2770 init_winsock_stream ();
2775 init_event_mswindows_late (void)
2777 #ifdef HAVE_MSG_SELECT
2778 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2779 assert (windows_fd>=0);
2780 FD_SET (windows_fd, &input_wait_mask);
2781 /* for some reason I get blocks on the signal event pipe, which is
2783 signal_event_pipe_initialized = 0; */
2786 event_stream = mswindows_event_stream;
2788 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2789 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);