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, 2000 Ben Wing.
5 Copyright (C) 1997 Jonathan Harris.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
28 Ultimately based on FSF.
29 Rewritten by Ben Wing.
30 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
31 Subprocess and modal loop support by Kirill M. Katsnelson.
37 #include "console-msw.h"
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
45 # include "menubar-msw.h"
49 # include "dragdrop.h"
59 #include "redisplay.h"
66 #include "objects-msw.h"
68 #include "events-mod.h"
69 #ifdef HAVE_MSG_SELECT
71 #include "console-tty.h"
73 typedef unsigned int SOCKET;
78 #if !(defined(CYGWIN) || defined(MINGW))
79 # include <shlobj.h> /* For IShellLink */
83 #define ADJR_MENUFLAG TRUE
85 #define ADJR_MENUFLAG FALSE
88 /* Fake key modifier which is attached to a quit char event.
89 Removed upon dequeueing an event */
90 #define FAKE_MOD_QUIT 0x80
92 /* Timer ID used for button2 emulation */
93 #define BUTTON_2_TIMER_ID 1
95 static Lisp_Object mswindows_find_frame (HWND hwnd);
96 static Lisp_Object mswindows_find_console (HWND hwnd);
97 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
99 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr);
100 static void mswindows_set_chord_timer (HWND hwnd);
101 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
102 static int mswindows_current_layout_has_AltGr (void);
103 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
104 int downp, int keyp);
106 static struct event_stream *mswindows_event_stream;
108 #ifdef HAVE_MSG_SELECT
109 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
110 extern SELECT_TYPE process_only_mask, tty_only_mask;
111 SELECT_TYPE zero_mask;
112 extern int signal_event_pipe_initialized;
117 * Two separate queues, for efficiency, one (_u_) for user events, and
118 * another (_s_) for non-user ones. We always return events out of the
119 * first one until it is empty and only then proceed with the second
122 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
123 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
125 /* The number of things we can wait on */
126 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
128 #ifndef HAVE_MSG_SELECT
129 /* List of mswindows waitable handles. */
130 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
132 /* Number of wait handles */
133 static int mswindows_waitable_count=0;
134 #endif /* HAVE_MSG_SELECT */
136 /* Brush for painting widgets */
137 static HBRUSH widget_brush = 0;
138 static LONG last_widget_brushed = 0;
140 /* Count of quit chars currently in the queue */
141 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
142 Decremented in mswindows_dequeue_dispatch_event() */
143 int mswindows_quit_chars_count = 0;
145 /* These are Lisp integers; see DEFVARS in this file for description. */
146 int mswindows_dynamic_frame_resize;
147 int mswindows_alt_by_itself_activates_menu;
148 int mswindows_num_mouse_buttons;
149 int mswindows_mouse_button_max_skew_x;
150 int mswindows_mouse_button_max_skew_y;
151 int mswindows_mouse_button_tolerance;
154 int mswindows_debug_events;
157 /* This is the event signaled by the event pump.
158 See mswindows_pump_outstanding_events for comments */
159 static Lisp_Object mswindows_error_caught_in_modal_loop;
160 static int mswindows_in_modal_loop;
162 /* Count of wound timers */
163 static int mswindows_pending_timers_count;
165 /************************************************************************/
166 /* Pipe instream - reads process output */
167 /************************************************************************/
169 #define PIPE_READ_DELAY 20
171 #define HANDLE_TO_USID(h) ((USID)(h))
173 #define NTPIPE_SLURP_STREAM_DATA(stream) \
174 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
176 /* This structure is allocated by the main thread, and is deallocated
177 in the thread upon exit. There are situations when a thread
178 remains blocked for a long time, much longer than the lstream
179 exists. For example, "start notepad" command is issued from the
180 shell, then the shell is closed by C-c C-d. Although the shell
181 process exits, its output pipe will not get closed until the
182 notepad process exits also, because it inherits the pipe form the
183 shell. In this case, we abandon the thread, and let it live until
184 all such processes exit. While struct ntpipe_slurp_stream is
185 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
187 struct ntpipe_slurp_stream_shared_data
189 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
190 /* This is a manual-reset object. */
191 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
192 /* This is a manual-reset object. */
193 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
194 /* This is a manual-reset object. */
195 HANDLE hpipe; /* Pipe read end handle. */
196 LONG die_p; /* Thread must exit ASAP if non-zero */
197 BOOL eof_p : 1; /* Set when thread saw EOF */
198 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
199 BOOL inuse_p : 1; /* this structure is in use */
200 LONG lock_count; /* Client count of this struct, 0=safe to free */
201 BYTE onebyte; /* One byte buffer read by thread */
204 #define MAX_SLURP_STREAMS 32
205 struct ntpipe_slurp_stream_shared_data
206 shared_data_block[MAX_SLURP_STREAMS]={{0}};
208 struct ntpipe_slurp_stream
210 LPARAM user_data; /* Any user data stored in the stream object */
211 struct ntpipe_slurp_stream_shared_data* thread_data;
214 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
215 sizeof (struct ntpipe_slurp_stream));
217 /* This function is thread-safe, and is called from either thread
218 context. It serializes freeing shared data structure */
220 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
222 if (InterlockedDecrement (&s->lock_count) == 0)
225 CloseHandle (s->hev_thread);
226 CloseHandle (s->hev_caller);
227 CloseHandle (s->hev_unsleep);
232 static struct ntpipe_slurp_stream_shared_data*
233 slurper_allocate_shared_data (void)
236 for (i=0; i<MAX_SLURP_STREAMS; i++)
238 if (!shared_data_block[i].inuse_p)
240 shared_data_block[i].inuse_p=1;
241 return &shared_data_block[i];
244 return (struct ntpipe_slurp_stream_shared_data*)0;
248 slurp_thread (LPVOID vparam)
250 struct ntpipe_slurp_stream_shared_data *s =
251 (struct ntpipe_slurp_stream_shared_data*)vparam;
255 /* Read one byte from the pipe */
257 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
259 DWORD err = GetLastError ();
260 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
265 else if (actually_read == 0)
268 /* We must terminate on an error or eof */
269 if (s->eof_p || s->error_p)
270 InterlockedIncrement (&s->die_p);
272 /* Before we notify caller, we unsignal our event. */
273 ResetEvent (s->hev_thread);
275 /* Now we got something to notify caller, either a byte or an
276 error/eof indication. Before we do, allow internal pipe
277 buffer to accumulate little bit more data.
278 Reader function pulses this event before waiting for
279 a character, to avoid pipe delay, and to get the byte
282 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
284 /* Either make event loop generate a process event, or
286 SetEvent (s->hev_caller);
288 /* Cleanup and exit if we're shot off */
292 /* Block until the client finishes with retrieving the rest of
294 WaitForSingleObject (s->hev_thread, INFINITE);
297 slurper_free_shared_data_maybe (s);
303 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
306 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
307 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
308 DWORD thread_id_unused;
311 /* We deal only with pipes, for we're using PeekNamedPipe api */
312 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
314 s->thread_data = slurper_allocate_shared_data();
316 /* Create reader thread. This could fail, so do not create events
317 until thread is created */
318 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
319 CREATE_SUSPENDED, &thread_id_unused);
322 Lstream_delete (lstr);
323 s->thread_data->inuse_p=0;
327 /* Shared data are initially owned by both main and slurper
329 s->thread_data->lock_count = 2;
330 s->thread_data->die_p = 0;
331 s->thread_data->eof_p = FALSE;
332 s->thread_data->error_p = FALSE;
333 s->thread_data->hpipe = hpipe;
334 s->user_data = param;
336 /* hev_thread is a manual-reset event, initially signaled */
337 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
338 /* hev_caller is a manual-reset event, initially nonsignaled */
339 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
340 /* hev_unsleep is a manual-reset event, initially nonsignaled */
341 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
344 ResumeThread (hthread);
345 CloseHandle (hthread);
347 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
348 XSETLSTREAM (obj, lstr);
353 get_ntpipe_input_stream_param (Lstream *stream)
355 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
360 get_ntpipe_input_stream_waitable (Lstream *stream)
362 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
363 return s->thread_data->hev_caller;
367 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
369 /* This function must be called from the main thread only */
370 struct ntpipe_slurp_stream_shared_data* s =
371 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
376 /* Disallow pipe read delay for the thread: we need a character
378 SetEvent (s->hev_unsleep);
380 /* Check if we have a character ready. Give it a short delay,
381 for the thread to awake from pipe delay, just ion case*/
382 wait_result = WaitForSingleObject (s->hev_caller, 2);
384 /* Revert to the normal sleep behavior. */
385 ResetEvent (s->hev_unsleep);
387 /* If there's no byte buffered yet, give up */
388 if (wait_result == WAIT_TIMEOUT)
395 /* Reset caller unlock event now, as we've handled the pending
396 process output event */
397 ResetEvent (s->hev_caller);
399 /* It is now safe to do anything with contents of S, except for
400 changing s->die_p, which still should be interlocked */
404 if (s->error_p || s->die_p)
407 /* Ok, there were no error neither eof - we've got a byte from the
409 *(data++) = s->onebyte;
413 DWORD bytes_read = 0;
416 DWORD bytes_available;
418 /* If the api call fails, return at least one byte already
419 read. ReadFile in thread will return error */
420 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
423 /* Fetch available bytes. The same consideration applies,
424 so do not check for errors. ReadFile in the thread will
425 fail if the next call fails. */
427 ReadFile (s->hpipe, data, min (bytes_available, size),
431 /* Now we can unblock thread, so it attempts to read more */
432 SetEvent (s->hev_thread);
433 return bytes_read + 1;
440 ntpipe_slurp_closer (Lstream *stream)
442 /* This function must be called from the main thread only */
443 struct ntpipe_slurp_stream_shared_data* s =
444 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
446 /* Force thread to stop */
447 InterlockedIncrement (&s->die_p);
449 /* Set events which could possibly block slurper. Let it finish soon
451 SetEvent (s->hev_unsleep);
452 SetEvent (s->hev_thread);
454 /* Unlock and maybe free shared data */
455 slurper_free_shared_data_maybe (s);
461 init_slurp_stream (void)
463 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
464 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
467 /************************************************************************/
468 /* Pipe outstream - writes process input */
469 /************************************************************************/
471 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
472 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
474 #define MAX_SHOVE_BUFFER_SIZE 512
476 struct ntpipe_shove_stream
478 LPARAM user_data; /* Any user data stored in the stream object */
479 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
480 /* This is an auto-reset object. */
481 HANDLE hpipe; /* Pipe write end handle. */
482 HANDLE hthread; /* Reader thread handle. */
483 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
484 DWORD size; /* Number of bytes to write */
485 LONG die_p; /* Thread must exit ASAP if non-zero */
486 LONG idle_p; /* Non-zero if thread is waiting for job */
487 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
488 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
491 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
492 sizeof (struct ntpipe_shove_stream));
494 #ifndef HAVE_MSG_SELECT
496 shove_thread (LPVOID vparam)
498 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
504 /* Block on event and wait for a job */
505 InterlockedIncrement (&s->idle_p);
506 WaitForSingleObject (s->hev_thread, INFINITE);
508 /* Write passed buffer if any */
511 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
512 || bytes_written != s->size)
515 InterlockedIncrement (&s->die_p);
517 /* Set size to zero so we won't write it again if the closer sets
518 die_p and kicks us */
530 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
533 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
534 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
535 DWORD thread_id_unused;
540 s->user_data = param;
542 /* Create reader thread. This could fail, so do not
543 create the event until thread is created */
544 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
545 CREATE_SUSPENDED, &thread_id_unused);
546 if (s->hthread == NULL)
548 Lstream_delete (lstr);
552 /* Set the priority of the thread higher so we don't end up waiting
553 on it to send things. */
554 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST))
556 CloseHandle (s->hthread);
557 Lstream_delete (lstr);
561 /* hev_thread is an auto-reset event, initially nonsignaled */
562 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
565 ResumeThread (s->hthread);
567 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
568 XSETLSTREAM (obj, lstr);
573 get_ntpipe_output_stream_param (Lstream *stream)
575 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
581 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
583 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
588 s->blocking_p = !s->idle_p;
592 if (size>MAX_SHOVE_BUFFER_SIZE)
595 memcpy (s->buffer, data, size);
599 InterlockedDecrement (&s->idle_p);
600 SetEvent (s->hev_thread);
601 /* Give it a chance to run -- this dramatically improves performance
602 of things like crypt. */
603 (void) SwitchToThread ();
608 ntpipe_shove_was_blocked_p (Lstream *stream)
610 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
611 return s->blocking_p;
615 ntpipe_shove_closer (Lstream *stream)
617 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
619 /* Force thread stop */
620 InterlockedIncrement (&s->die_p);
622 /* Thread will end upon unblocking. If it's already unblocked this will
623 do nothing, but the thread won't look at die_p until it's written any
625 SetEvent (s->hev_thread);
627 /* Wait while thread terminates */
628 WaitForSingleObject (s->hthread, INFINITE);
630 /* Close pipe handle, possibly breaking it */
631 CloseHandle (s->hpipe);
633 /* Close the thread handle */
634 CloseHandle (s->hthread);
636 /* Destroy the event */
637 CloseHandle (s->hev_thread);
643 init_shove_stream (void)
645 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
646 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
647 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
650 /************************************************************************/
651 /* Winsock I/O stream */
652 /************************************************************************/
653 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
655 #define WINSOCK_READ_BUFFER_SIZE 1024
657 struct winsock_stream
659 LPARAM user_data; /* Any user data stored in the stream object */
660 SOCKET s; /* Socket handle (which is a Win32 handle) */
661 OVERLAPPED ov; /* Overlapped I/O structure */
662 void* buffer; /* Buffer. Allocated for input stream only */
663 unsigned long bufsize; /* Number of bytes last read */
664 unsigned long bufpos; /* Position in buffer for next fetch */
665 unsigned int error_p :1; /* I/O Error seen */
666 unsigned int eof_p :1; /* EOF Error seen */
667 unsigned int pending_p :1; /* There is a pending I/O operation */
668 unsigned int blocking_p :1; /* Last write attempt would block */
671 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
673 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
674 sizeof (struct winsock_stream));
677 winsock_initiate_read (struct winsock_stream *str)
679 ResetEvent (str->ov.hEvent);
682 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
683 &str->bufsize, &str->ov))
685 if (GetLastError () == ERROR_IO_PENDING)
687 else if (GetLastError () == ERROR_HANDLE_EOF)
692 else if (str->bufsize == 0)
697 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
699 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
701 /* If the current operation is not yet complete, there's nothing to
705 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
712 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
714 if (GetLastError() == ERROR_HANDLE_EOF)
719 if (str->bufsize == 0)
730 /* Return as much of buffer as we have */
731 size = min (size, (size_t) (str->bufsize - str->bufpos));
732 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
735 /* Read more if buffer is exhausted */
736 if (str->bufsize == str->bufpos)
737 winsock_initiate_read (str);
743 winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
745 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
749 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
757 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
772 ResetEvent (str->ov.hEvent);
774 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
775 * an overlapped operation. This fails on Win95 with winsock 1.x so we
776 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
777 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
778 || GetLastError() == ERROR_IO_PENDING)
784 return str->error_p ? -1 : size;
788 winsock_closer (Lstream *lstr)
790 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
792 if (lstr->flags & LSTREAM_FL_READ)
793 shutdown (str->s, 0);
795 shutdown (str->s, 1);
797 CloseHandle ((HANDLE)str->s);
799 WaitForSingleObject (str->ov.hEvent, INFINITE);
801 if (lstr->flags & LSTREAM_FL_READ)
804 CloseHandle (str->ov.hEvent);
809 winsock_was_blocked_p (Lstream *stream)
811 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
812 return str->blocking_p;
816 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
819 Lstream *lstr = Lstream_new (lstream_winsock, mode);
820 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
827 str->user_data = param;
830 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
832 if (lstr->flags & LSTREAM_FL_READ)
834 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
835 winsock_initiate_read (str);
838 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
839 XSETLSTREAM (obj, lstr);
844 make_winsock_input_stream (SOCKET s, LPARAM param)
846 return make_winsock_stream_1 (s, param, "r");
850 make_winsock_output_stream (SOCKET s, LPARAM param)
852 return make_winsock_stream_1 (s, param, "w");
856 get_winsock_stream_waitable (Lstream *lstr)
858 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
859 return str->ov.hEvent;
863 get_winsock_stream_param (Lstream *lstr)
865 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
866 return str->user_data;
870 init_winsock_stream (void)
872 LSTREAM_HAS_METHOD (winsock, reader);
873 LSTREAM_HAS_METHOD (winsock, writer);
874 LSTREAM_HAS_METHOD (winsock, closer);
875 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
877 #endif /* defined (HAVE_SOCKETS) */
879 /************************************************************************/
880 /* Dispatch queue management */
881 /************************************************************************/
884 mswindows_user_event_p (Lisp_Event* sevt)
886 return (sevt->event_type == key_press_event
887 || sevt->event_type == button_press_event
888 || sevt->event_type == button_release_event
889 || sevt->event_type == misc_user_event);
893 * Add an emacs event to the proper dispatch queue
896 mswindows_enqueue_dispatch_event (Lisp_Object event)
898 int user_p = mswindows_user_event_p (XEVENT(event));
899 enqueue_event (event,
900 user_p ? &mswindows_u_dispatch_event_queue :
901 &mswindows_s_dispatch_event_queue,
902 user_p ? &mswindows_u_dispatch_event_queue_tail :
903 &mswindows_s_dispatch_event_queue_tail);
905 /* Avoid blocking on WaitMessage */
906 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
910 * Add a misc-user event to the dispatch queue.
912 * Stuff it into our own dispatch queue, so we have something
913 * to return from next_event callback.
916 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
919 Lisp_Object event = Fmake_event (Qnil, Qnil);
920 Lisp_Event* e = XEVENT (event);
922 e->event_type = misc_user_event;
923 e->channel = channel;
924 e->timestamp = GetTickCount ();
925 e->event.misc.function = function;
926 e->event.misc.object = object;
928 mswindows_enqueue_dispatch_event (event);
932 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
934 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
935 Lisp_Event* event = XEVENT (emacs_event);
937 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
938 event->timestamp = GetMessageTime();
939 event->event_type = magic_event;
940 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
942 mswindows_enqueue_dispatch_event (emacs_event);
946 mswindows_enqueue_process_event (Lisp_Process* p)
948 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
949 Lisp_Event* event = XEVENT (emacs_event);
951 XSETPROCESS (process, p);
953 event->event_type = process_event;
954 event->timestamp = GetTickCount ();
955 event->event.process.process = process;
957 mswindows_enqueue_dispatch_event (emacs_event);
961 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
964 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
965 msg == WM_RBUTTONDOWN);
967 /* We always use last message time, because mouse button
968 events may get delayed, and XEmacs double click
969 recognition will fail */
971 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
972 Lisp_Event* event = XEVENT (emacs_event);
974 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
975 event->channel = mswindows_find_frame (hwnd);
976 event->timestamp = when;
977 event->event.button.button =
978 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
979 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
980 event->event.button.x = where.x;
981 event->event.button.y = where.y;
982 event->event.button.modifiers = mswindows_modifier_state (NULL, 0);
986 event->event_type = button_press_event;
988 /* we need this to make sure the main window regains the focus
989 from control subwindows */
990 if (GetFocus() != hwnd)
993 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
998 event->event_type = button_release_event;
1002 mswindows_enqueue_dispatch_event (emacs_event);
1006 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1008 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1009 Lisp_Event* event = XEVENT(emacs_event);
1011 event->channel = mswindows_find_console(hwnd);
1012 event->timestamp = GetMessageTime();
1013 event->event_type = key_press_event;
1014 event->event.key.keysym = keysym;
1015 event->event.key.modifiers = mods;
1016 mswindows_enqueue_dispatch_event (emacs_event);
1020 * Remove and return the first emacs event on the dispatch queue.
1021 * Give a preference to user events over non-user ones.
1024 mswindows_dequeue_dispatch_event (void)
1029 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1030 !NILP(mswindows_s_dispatch_event_queue));
1032 event = dequeue_event (
1033 NILP(mswindows_u_dispatch_event_queue) ?
1034 &mswindows_s_dispatch_event_queue :
1035 &mswindows_u_dispatch_event_queue,
1036 NILP(mswindows_u_dispatch_event_queue) ?
1037 &mswindows_s_dispatch_event_queue_tail :
1038 &mswindows_u_dispatch_event_queue_tail);
1040 sevt = XEVENT(event);
1041 if (sevt->event_type == key_press_event
1042 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1044 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1045 --mswindows_quit_chars_count;
1052 * Remove and return the first emacs event on the dispatch queue that matches
1053 * the supplied event.
1054 * Timeout event matches if interval_id is equal to that of the given event.
1055 * Keypress event matches if logical AND between modifiers bitmask of the
1056 * event in the queue and that of the given event is non-zero.
1057 * For all other event types, this function aborts.
1061 mswindows_cancel_dispatch_event (Lisp_Event *match)
1064 Lisp_Object previous_event = Qnil;
1065 int user_p = mswindows_user_event_p (match);
1066 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1067 &mswindows_s_dispatch_event_queue;
1068 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1069 &mswindows_s_dispatch_event_queue_tail;
1071 assert (match->event_type == timeout_event
1072 || match->event_type == key_press_event);
1074 EVENT_CHAIN_LOOP (event, *head)
1076 Lisp_Event *e = XEVENT (event);
1077 if ((e->event_type == match->event_type) &&
1078 ((e->event_type == timeout_event) ?
1079 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1080 /* Must be key_press_event */
1081 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1083 if (NILP (previous_event))
1084 dequeue_event (head, tail);
1087 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1088 if (EQ (*tail, event))
1089 *tail = previous_event;
1094 previous_event = event;
1099 #ifndef HAVE_MSG_SELECT
1100 /************************************************************************/
1101 /* Waitable handles manipulation */
1102 /************************************************************************/
1104 find_waitable_handle (HANDLE h)
1107 for (i = 0; i < mswindows_waitable_count; ++i)
1108 if (mswindows_waitable_handles[i] == h)
1115 add_waitable_handle (HANDLE h)
1117 assert (find_waitable_handle (h) < 0);
1118 if (mswindows_waitable_count == MAX_WAITABLE)
1121 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1126 remove_waitable_handle (HANDLE h)
1128 int ix = find_waitable_handle (h);
1132 mswindows_waitable_handles [ix] =
1133 mswindows_waitable_handles [--mswindows_waitable_count];
1135 #endif /* HAVE_MSG_SELECT */
1138 /************************************************************************/
1140 /************************************************************************/
1143 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1144 Lisp_Object u_n_u_s_e_d)
1146 mswindows_error_caught_in_modal_loop = cons_sig_data;
1151 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1156 ++mswindows_in_modal_loop;
1157 tmp = condition_case_1 (Qt,
1159 mswindows_modal_loop_error_handler, Qnil);
1160 --mswindows_in_modal_loop;
1166 mswindows_unmodalize_signal_maybe (void)
1168 if (!NILP (mswindows_error_caught_in_modal_loop))
1170 /* Got an error while messages were pumped while
1171 in window procedure - have to resignal */
1172 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1173 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1174 mswindows_error_caught_in_modal_loop = Qnil;
1175 Fsignal (sym, data);
1180 * This is an unsafe part of event pump, guarded by
1181 * condition_case. See mswindows_pump_outstanding_events
1184 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1186 /* This function can call lisp */
1187 Lisp_Object event = Fmake_event (Qnil, Qnil);
1188 struct gcpro gcpro1;
1189 int do_redisplay = 0;
1192 while (detect_input_pending ())
1194 Fnext_event (event, Qnil);
1195 Fdispatch_event (event);
1202 Fdeallocate_event (event);
1205 /* Qt becomes return value of mswindows_pump_outstanding_events
1211 * This function pumps emacs events, while available, by using
1212 * next_message/dispatch_message loop. Errors are trapped around
1213 * the loop so the function always returns.
1215 * Windows message queue is not looked into during the call,
1216 * neither are waitable handles checked. The function pumps
1217 * thus only dispatch events already queued, as well as those
1218 * resulted in dispatching thereof. This is done by setting
1219 * module local variable mswindows_in_modal_loop to nonzero.
1221 * Return value is Qt if no errors was trapped, or Qunbound if
1222 * there was an error.
1224 * In case of error, a cons representing the error, in the
1225 * form (SIGNAL . DATA), is stored in the module local variable
1226 * mswindows_error_caught_in_modal_loop. This error is signaled
1227 * again when DispatchMessage returns. Thus, Windows internal
1228 * modal loops are protected against throws, which are proven
1229 * to corrupt internal Windows structures.
1231 * In case of success, mswindows_error_caught_in_modal_loop is
1234 * If the value of mswindows_error_caught_in_modal_loop is not
1235 * nil already upon entry, the function just returns non-nil.
1236 * This situation means that a new event has been queued while
1237 * in cancel mode. The event will be dequeued on the next regular
1238 * call of next-event; the pump is off since error is caught.
1239 * The caller must *unconditionally* cancel modal loop if the
1240 * value returned by this function is nil. Otherwise, everything
1241 * will become frozen until the modal loop exits under normal
1242 * condition (scrollbar drag is released, menu closed etc.)
1245 mswindows_pump_outstanding_events (void)
1247 /* This function can call lisp */
1249 Lisp_Object result = Qt;
1250 struct gcpro gcpro1;
1253 if (NILP(mswindows_error_caught_in_modal_loop))
1254 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1260 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1261 * QUITP, and are interesting in keyboard messages only.
1264 mswindows_drain_windows_queue (void)
1268 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1269 assert (!mswindows_in_modal_loop);
1271 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1273 /* We have to translate messages that are not sent to an XEmacs
1274 frame. This is so that key presses work ok in things like
1275 edit fields. However, we *musn't* translate message for XEmacs
1276 frames as this is handled in the wnd proc.
1277 We also have to avoid generating paint magic events for windows
1278 that aren't XEmacs frames */
1279 /* GetClassName will truncate a longer class name. By adding one
1280 extra character, we are forcing textual comparison to fail
1281 if the name is longer than XEMACS_CLASS */
1282 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1283 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1284 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1286 /* Not an XEmacs frame */
1287 TranslateMessage (&msg);
1289 else if (msg.message == WM_PAINT)
1291 struct mswindows_frame* msframe;
1293 /* hdc will be NULL unless this is a subwindow - in which case we
1294 shouldn't have received a paint message for it here. */
1295 assert (msg.wParam == 0);
1297 /* Queue a magic event for handling when safe */
1299 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1300 if (!msframe->paint_pending)
1302 msframe->paint_pending = 1;
1303 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1305 /* Don't dispatch. WM_PAINT is always the last message in the
1306 queue so it's OK to just return. */
1309 DispatchMessage (&msg);
1310 mswindows_unmodalize_signal_maybe ();
1315 * This is a special flavor of the mswindows_need_event function,
1316 * used while in event pump. Actually, there is only kind of events
1317 * allowed while in event pump: a timer. An attempt to fetch any
1318 * other event leads to a deadlock, as there's no source of user input
1319 * ('cause event pump mirrors windows modal loop, which is a sole
1320 * owner of thread message queue).
1322 * To detect this, we use a counter of active timers, and allow
1323 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1324 * which will never come when there are no pending timers, which leads
1325 * to deadlock, we simply signal an error.
1328 mswindows_need_event_in_modal_loop (int badly_p)
1332 /* Check if already have one */
1333 if (!NILP (mswindows_u_dispatch_event_queue)
1334 || !NILP (mswindows_s_dispatch_event_queue))
1337 /* No event is ok */
1341 /* We do not check the _u_ queue, because timers go to _s_ */
1342 while (NILP (mswindows_s_dispatch_event_queue))
1344 /* We'll deadlock if go waiting */
1345 if (mswindows_pending_timers_count == 0)
1346 error ("Deadlock due to an attempt to call next-event in a wrong context");
1348 /* Fetch and dispatch any pending timers */
1349 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1350 DispatchMessage (&msg);
1355 * This drains the event queue and fills up two internal queues until
1356 * an event of a type specified by USER_P is retrieved.
1359 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1362 mswindows_need_event (int badly_p)
1366 if (mswindows_in_modal_loop)
1368 mswindows_need_event_in_modal_loop (badly_p);
1372 while (NILP (mswindows_u_dispatch_event_queue)
1373 && NILP (mswindows_s_dispatch_event_queue))
1375 #ifdef HAVE_MSG_SELECT
1377 SELECT_TYPE temp_mask = input_wait_mask;
1378 EMACS_TIME sometime;
1379 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1382 pointer_to_this = 0;
1385 EMACS_SET_SECS_USECS (sometime, 0, 0);
1386 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1387 pointer_to_this = &select_time_to_block;
1390 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1395 return; /* timeout */
1397 else if (active > 0)
1399 if (FD_ISSET (windows_fd, &temp_mask))
1401 mswindows_drain_windows_queue ();
1406 /* Look for a TTY event */
1407 for (i = 0; i < MAXDESC-1; i++)
1409 /* To avoid race conditions (among other things, an infinite
1410 loop when called from Fdiscard_input()), we must return
1411 user events ahead of process events. */
1412 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1414 struct console *c = tty_find_console_from_fd (i);
1415 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1416 Lisp_Event* event = XEVENT (emacs_event);
1419 if (read_event_from_tty_or_stream_desc (event, c, i))
1421 mswindows_enqueue_dispatch_event (emacs_event);
1427 /* Look for a process event */
1428 for (i = 0; i < MAXDESC-1; i++)
1430 if (FD_ISSET (i, &temp_mask))
1432 if (FD_ISSET (i, &process_only_mask))
1435 get_process_from_usid (FD_TO_USID(i));
1437 mswindows_enqueue_process_event (p);
1441 /* We might get here when a fake event came
1442 through a signal. Return a dummy event, so
1443 that a cycle of the command loop will
1445 drain_signal_event_pipe ();
1446 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1452 else if (active==-1)
1456 /* something bad happened */
1465 /* Now try getting a message or process event */
1466 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1467 mswindows_waitable_handles,
1468 FALSE, badly_p ? INFINITE : 0,
1471 /* This will assert if handle being waited for becomes abandoned.
1472 Not the case currently tho */
1473 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1474 (active >= WAIT_OBJECT_0 &&
1475 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1477 if (active == WAIT_TIMEOUT)
1479 /* No luck trying - just return what we've already got */
1482 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1484 /* Got your message, thanks */
1485 mswindows_drain_windows_queue ();
1489 int ix = active - WAIT_OBJECT_0;
1490 /* First, try to find which process' output has signaled */
1492 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1495 /* Found a signaled process input handle */
1496 mswindows_enqueue_process_event (p);
1500 /* None. This means that the process handle itself has signaled.
1501 Remove the handle from the wait vector, and make status_notify
1502 note the exited process */
1503 mswindows_waitable_handles [ix] =
1504 mswindows_waitable_handles [--mswindows_waitable_count];
1505 kick_status_notify ();
1506 /* We need to return a process event here so that
1507 (1) accept-process-output will return when called on this
1508 process, and (2) status notifications will happen in
1509 accept-process-output, sleep-for, and sit-for. */
1510 /* #### horrible kludge till my real process fixes go in.
1512 if (!NILP (Vprocess_list))
1514 Lisp_Object vaffanculo = XCAR (Vprocess_list);
1515 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1517 else /* trash me soon. */
1518 /* Have to return something: there may be no accompanying
1520 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1527 /************************************************************************/
1528 /* Event generators */
1529 /************************************************************************/
1532 * Callback procedure for synchronous timer messages
1534 static void CALLBACK
1535 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1537 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1538 Lisp_Event *event = XEVENT (emacs_event);
1540 if (KillTimer (NULL, id_timer))
1541 --mswindows_pending_timers_count;
1543 event->channel = Qnil;
1544 event->timestamp = dwtime;
1545 event->event_type = timeout_event;
1546 event->event.timeout.interval_id = id_timer;
1547 event->event.timeout.function = Qnil;
1548 event->event.timeout.object = Qnil;
1550 mswindows_enqueue_dispatch_event (emacs_event);
1554 * Callback procedure for dde messages
1556 * We execute a dde Open("file") by simulating a file drop, so dde support
1557 * depends on dnd support.
1559 #ifdef HAVE_DRAGNDROP
1561 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1562 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1563 DWORD dwData1, DWORD dwData2)
1568 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1569 return (HDDEDATA)TRUE;
1570 return (HDDEDATA)FALSE;
1572 case XTYP_WILDCONNECT:
1574 /* We only support one {service,topic} pair */
1575 HSZPAIR pairs[2] = {
1576 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1578 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1579 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1580 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1581 sizeof (pairs), 0L, 0, uFmt, 0));
1583 return (HDDEDATA)NULL;
1586 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1588 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1589 LPBYTE cmd = (LPBYTE) alloca (len+1);
1592 struct gcpro gcpro1, gcpro2;
1593 Lisp_Object l_dndlist = Qnil;
1594 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1595 Lisp_Object frmcons, devcons, concons;
1596 Lisp_Event *event = XEVENT (emacs_event);
1598 DdeGetData (hdata, cmd, len, 0);
1600 DdeFreeDataHandle (hdata);
1602 /* Check syntax & that it's an [Open("foo")] command, which we
1603 * treat like a file drop */
1604 /* #### Ought to be generalised and accept some other commands */
1607 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1608 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1609 return DDE_FNOTPROCESSED;
1610 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1613 if (*cmd!='(' || *(cmd+1)!='\"')
1614 return DDE_FNOTPROCESSED;
1616 while (*end && *end!='\"')
1619 return DDE_FNOTPROCESSED;
1622 return DDE_FNOTPROCESSED;
1626 return DDE_FNOTPROCESSED;
1629 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1630 strcpy (filename, "file:");
1631 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1633 dostounix_filename (cmd);
1634 filename = alloca (strlen (cmd)+6);
1635 strcpy (filename, "file:");
1636 strcat (filename, cmd);
1638 GCPRO2 (emacs_event, l_dndlist);
1639 l_dndlist = make_string (filename, strlen (filename));
1641 /* Find a mswindows frame */
1642 event->channel = Qnil;
1643 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1645 Lisp_Object frame = XCAR (frmcons);
1646 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1647 event->channel = frame;
1649 assert (!NILP (event->channel));
1651 event->timestamp = GetTickCount();
1652 event->event_type = misc_user_event;
1653 event->event.misc.button = 1;
1654 event->event.misc.modifiers = 0;
1655 event->event.misc.x = -1;
1656 event->event.misc.y = -1;
1657 event->event.misc.function = Qdragdrop_drop_dispatch;
1658 event->event.misc.object = Fcons (Qdragdrop_URL,
1659 Fcons (l_dndlist, Qnil));
1660 mswindows_enqueue_dispatch_event (emacs_event);
1662 return (HDDEDATA) DDE_FACK;
1664 DdeFreeDataHandle (hdata);
1665 return (HDDEDATA) DDE_FNOTPROCESSED;
1668 return (HDDEDATA) NULL;
1674 * Helper to do repainting - repaints can happen both from the windows
1675 * procedure and from magic events
1678 mswindows_handle_paint (struct frame *frame)
1680 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1682 /* According to the docs we need to check GetUpdateRect() before
1683 actually doing a WM_PAINT */
1684 if (GetUpdateRect (hwnd, NULL, FALSE))
1686 PAINTSTRUCT paintStruct;
1687 int x, y, width, height;
1689 BeginPaint (hwnd, &paintStruct);
1690 x = paintStruct.rcPaint.left;
1691 y = paintStruct.rcPaint.top;
1692 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1693 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1694 /* Normally we want to ignore expose events when child
1695 windows are unmapped, however once we are in the guts of
1696 WM_PAINT we need to make sure that we don't register
1697 unmaps then because they will not actually occur. */
1698 /* #### commenting out the next line seems to fix some problems
1699 but not all. only andy currently understands this stuff and
1700 he needs to review it more carefully. --ben */
1701 if (!check_for_ignored_expose (frame, x, y, width, height))
1703 hold_ignored_expose_registration = 1;
1704 mswindows_redraw_exposed_area (frame, x, y, width, height);
1705 hold_ignored_expose_registration = 0;
1707 EndPaint (hwnd, &paintStruct);
1712 * Returns 1 if a key is a real modifier or special key, which
1713 * is better handled by DefWindowProc
1716 key_needs_default_processing_p (UINT vkey)
1718 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1719 /* if we let ALT activate the menu like this, then sticky ALT-modified
1720 keystrokes become impossible. */
1721 && !modifier_keys_are_sticky)
1727 /* key-handling code is always ugly. It just ends up working out
1730 #### Most of the sticky-modifier code below is copied from similar
1731 code in event-Xt.c. They should somehow or other be merged.
1733 Here are some pointers:
1735 -- DOWN_MASK indicates which modifiers should be treated as "down"
1736 when the corresponding upstroke happens. It gets reset for
1737 a particular modifier when that modifier goes up, and reset
1738 for all modifiers when a non-modifier key is pressed. Example:
1740 I press Control-A-Shift and then release Control-A-Shift.
1741 I want the Shift key to be sticky but not the Control key.
1743 -- If a modifier key is sticky, I can unstick it by pressing
1744 the modifier key again. */
1746 static WPARAM last_downkey;
1747 static int need_to_add_mask, down_mask;
1749 #define XEMSW_LCONTROL (1<<0)
1750 #define XEMSW_RCONTROL (1<<1)
1751 #define XEMSW_LSHIFT (1<<2)
1752 #define XEMSW_RSHIFT (1<<3)
1753 #define XEMSW_LMENU (1<<4)
1754 #define XEMSW_RMENU (1<<5)
1757 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1758 int downp, int keyp)
1762 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1766 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1767 wParam == VK_RCONTROL ||
1768 wParam == VK_MENU || wParam == VK_LMENU ||
1769 wParam == VK_RMENU ||
1770 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1771 wParam == VK_RSHIFT)))
1772 { /* Not a modifier key */
1773 if (downp && keyp && !last_downkey)
1774 last_downkey = wParam;
1775 /* If I hold press-and-release the Control key and then press
1776 and hold down the right arrow, I want it to auto-repeat
1777 Control-Right. On the other hand, if I do the same but
1778 manually press the Right arrow a bunch of times, I want
1779 to see one Control-Right and then a bunch of Rights.
1780 This means that we need to distinguish between an
1781 auto-repeated key and a key pressed and released a bunch
1783 else if ((downp && !keyp) ||
1784 (downp && keyp && last_downkey &&
1785 (wParam != last_downkey ||
1786 /* the "previous key state" bit indicates autorepeat */
1787 ! (lParam & (1 << 30)))))
1789 need_to_add_mask = 0;
1795 mods = need_to_add_mask;
1797 else /* Modifier key pressed */
1799 /* If a non-modifier key was pressed in the middle of a bunch
1800 of modifiers, then it unsticks all the modifiers that were
1801 previously pressed. We cannot unstick the modifiers until
1802 now because we want to check for auto-repeat of the
1803 non-modifier key. */
1808 need_to_add_mask = 0;
1811 #define FROB(mask) \
1813 if (downp && keyp) \
1815 /* If modifier key is already sticky, \
1816 then unstick it. Note that we do \
1817 not test down_mask to deal with the \
1818 unlikely but possible case that the \
1819 modifier key auto-repeats. */ \
1820 if (need_to_add_mask & mask) \
1822 need_to_add_mask &= ~mask; \
1823 down_mask &= ~mask; \
1826 down_mask |= mask; \
1830 if (down_mask & mask) \
1832 down_mask &= ~mask; \
1833 need_to_add_mask |= mask; \
1838 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1839 || wParam == VK_RCONTROL)
1840 FROB (XEMSW_RCONTROL);
1841 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1842 || wParam == VK_LCONTROL)
1843 FROB (XEMSW_LCONTROL);
1845 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1846 || wParam == VK_RSHIFT)
1847 FROB (XEMSW_RSHIFT);
1848 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1849 || wParam == VK_LSHIFT)
1850 FROB (XEMSW_LSHIFT);
1852 if ((wParam == VK_MENU && (lParam & 0x1000000))
1853 || wParam == VK_RMENU)
1855 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1856 || wParam == VK_LMENU)
1865 GetKeyboardState (keymap);
1867 if (mods & XEMSW_LCONTROL)
1869 keymap [VK_CONTROL] |= 0x80;
1870 keymap [VK_LCONTROL] |= 0x80;
1872 if (mods & XEMSW_RCONTROL)
1874 keymap [VK_CONTROL] |= 0x80;
1875 keymap [VK_RCONTROL] |= 0x80;
1878 if (mods & XEMSW_LSHIFT)
1880 keymap [VK_SHIFT] |= 0x80;
1881 keymap [VK_LSHIFT] |= 0x80;
1883 if (mods & XEMSW_RSHIFT)
1885 keymap [VK_SHIFT] |= 0x80;
1886 keymap [VK_RSHIFT] |= 0x80;
1889 if (mods & XEMSW_LMENU)
1891 keymap [VK_MENU] |= 0x80;
1892 keymap [VK_LMENU] |= 0x80;
1894 if (mods & XEMSW_RMENU)
1896 keymap [VK_MENU] |= 0x80;
1897 keymap [VK_RMENU] |= 0x80;
1900 SetKeyboardState (keymap);
1908 clear_sticky_modifiers (void)
1910 need_to_add_mask = 0;
1920 output_modifier_keyboard_state (void)
1924 GetKeyboardState (keymap);
1926 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1927 keymap[VK_MENU] & 0x80 ? 1 : 0,
1928 keymap[VK_MENU] & 0x1 ? 1 : 0,
1929 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1930 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1931 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1932 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1933 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1934 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1935 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1936 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1937 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1938 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1939 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1940 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1941 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1942 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1943 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1944 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1945 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1946 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
1951 /* try to debug the stuck-alt-key problem.
1953 #### this happens only inconsistently, and may only happen when using
1954 StickyKeys in the Win2000 accessibility section of the control panel,
1955 which is extremely broken for other reasons. */
1958 output_alt_keyboard_state (void)
1962 // SHORT asyncstate[3];
1964 GetKeyboardState (keymap);
1965 keystate[0] = GetKeyState (VK_MENU);
1966 keystate[1] = GetKeyState (VK_LMENU);
1967 keystate[2] = GetKeyState (VK_RMENU);
1968 /* Doing this interferes with key processing. */
1969 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
1970 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
1971 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
1973 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1974 keymap[VK_MENU] & 0x80 ? 1 : 0,
1975 keymap[VK_MENU] & 0x1 ? 1 : 0,
1976 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1977 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1978 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1979 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1980 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1981 keystate[0] & 0x8000 ? 1 : 0,
1982 keystate[0] & 0x1 ? 1 : 0,
1983 keystate[1] & 0x8000 ? 1 : 0,
1984 keystate[1] & 0x1 ? 1 : 0,
1985 keystate[2] & 0x8000 ? 1 : 0,
1986 keystate[2] & 0x1 ? 1 : 0);
1987 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
1988 /* asyncstate[0] & 0x8000 ? 1 : 0, */
1989 /* asyncstate[0] & 0x1 ? 1 : 0, */
1990 /* asyncstate[1] & 0x8000 ? 1 : 0, */
1991 /* asyncstate[1] & 0x1 ? 1 : 0, */
1992 /* asyncstate[2] & 0x8000 ? 1 : 0, */
1993 /* asyncstate[2] & 0x1 ? 1 : 0); */
1996 #endif /* DEBUG_XEMACS */
2000 * The windows procedure for the window class XEMACS_CLASS
2003 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2005 /* Note: Remember to initialize emacs_event and event before use.
2006 This code calls code that can GC. You must GCPRO before calling such code. */
2007 Lisp_Object emacs_event = Qnil;
2008 Lisp_Object fobj = Qnil;
2011 struct frame *frame;
2012 struct mswindows_frame* msframe;
2014 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2017 case WM_DESTROYCLIPBOARD:
2018 /* We own the clipboard and someone else wants it. Delete our
2019 cached copy of the clipboard contents so we'll ask for it from
2020 Windows again when someone does a paste, and destroy any memory
2021 objects we hold on the clipboard that are not in the list of types
2022 that Windows will delete itself. */
2023 mswindows_destroy_selection (QCLIPBOARD);
2024 handle_selection_clear (QCLIPBOARD);
2028 /* Erase background only during non-dynamic sizing */
2029 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2030 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2035 fobj = mswindows_find_frame (hwnd);
2036 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2042 /* See Win95 comment under WM_KEYDOWN */
2045 int should_set_keymap = 0;
2048 if (mswindows_debug_events)
2050 stderr_out ("%s wparam=%d lparam=%d\n",
2051 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
2052 wParam, (int)lParam);
2053 output_alt_keyboard_state ();
2055 #endif /* DEBUG_XEMACS */
2057 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2058 if (wParam == VK_CONTROL)
2060 GetKeyboardState (keymap);
2061 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2062 should_set_keymap = 1;
2064 else if (wParam == VK_MENU)
2066 GetKeyboardState (keymap);
2067 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2068 should_set_keymap = 1;
2071 if (should_set_keymap)
2072 // && (message_ != WM_SYSKEYUP
2073 // || NILP (Vmenu_accelerator_enabled)))
2074 SetKeyboardState (keymap);
2078 if (key_needs_default_processing_p (wParam))
2086 /* In some locales the right-hand Alt key is labelled AltGr. This key
2087 * should produce alternative charcaters when combined with another key.
2088 * eg on a German keyboard pressing AltGr+q should produce '@'.
2089 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2090 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2091 * it translates as if AltGr were down.
2092 * We get round this by removing all modifiers from the keymap before
2093 * calling TranslateMessage() unless AltGr is *really* down. */
2095 BYTE keymap_trans[256];
2096 BYTE keymap_orig[256];
2097 BYTE keymap_sticky[256];
2098 int has_AltGr = mswindows_current_layout_has_AltGr ();
2100 int extendedp = lParam & 0x1000000;
2105 if (mswindows_debug_events)
2107 stderr_out ("%s wparam=%d lparam=%d\n",
2108 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
2109 wParam, (int)lParam);
2110 output_alt_keyboard_state ();
2112 #endif /* DEBUG_XEMACS */
2114 GetKeyboardState (keymap_orig);
2115 frame = XFRAME (mswindows_find_frame (hwnd));
2116 if ((sticky_changed =
2117 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2119 GetKeyboardState (keymap_sticky);
2120 if (keymap_sticky[VK_MENU] & 0x80)
2122 message_ = WM_SYSKEYDOWN;
2123 /* We have to set the "context bit" so that the
2124 TranslateMessage() call below that generates the
2125 SYSCHAR message does its thing; see the documentation
2131 memcpy (keymap_sticky, keymap_orig, 256);
2133 mods = mswindows_modifier_state (keymap_sticky, has_AltGr);
2135 /* Handle non-printables */
2136 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2139 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2141 SetKeyboardState (keymap_orig);
2143 else /* Normal keys & modifiers */
2146 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2147 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2149 int potential_accelerator = 0;
2150 int got_accelerator = 0;
2153 msg.message = message_;
2154 msg.wParam = wParam;
2155 msg.lParam = lParam;
2156 msg.time = GetMessageTime();
2159 /* GetKeyboardState() does not work as documented on Win95. We have
2160 * to loosely track Left and Right modifiers on behalf of the OS,
2161 * without screwing up Windows NT which tracks them properly. */
2162 if (wParam == VK_CONTROL)
2164 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2165 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2167 else if (wParam == VK_MENU)
2169 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2170 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2173 if (!NILP (Vmenu_accelerator_enabled) &&
2174 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2175 potential_accelerator = 1;
2177 /* Remove shift modifier from an ascii character */
2178 mods &= ~XEMACS_MOD_SHIFT;
2180 memcpy (keymap_trans, keymap_sticky, 256);
2182 /* Clear control and alt modifiers unless AltGr is pressed */
2183 keymap_trans[VK_RCONTROL] = 0;
2184 keymap_trans[VK_LMENU] = 0;
2185 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2186 || !(keymap_trans[VK_RMENU] & 0x80))
2188 keymap_trans[VK_LCONTROL] = 0;
2189 keymap_trans[VK_CONTROL] = 0;
2190 keymap_trans[VK_RMENU] = 0;
2191 keymap_trans[VK_MENU] = 0;
2193 SetKeyboardState (keymap_trans);
2195 /* Maybe generate some WM_[SYS]CHARs in the queue */
2196 TranslateMessage (&msg);
2198 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2199 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2203 WPARAM ch = tranmsg.wParam;
2205 /* If a quit char with no modifiers other than control and
2206 shift, then mark it with a fake modifier, which is removed
2207 upon dequeueing the event */
2208 /* #### This might also not withstand localization, if
2209 quit character is not a latin-1 symbol */
2210 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2211 && quit_ch + 'a' - 1 == ch)
2212 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2214 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2217 mods1 |= FAKE_MOD_QUIT;
2218 ++mswindows_quit_chars_count;
2220 else if (potential_accelerator && !got_accelerator &&
2221 mswindows_char_is_accelerator (frame, ch))
2223 got_accelerator = 1;
2226 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
2229 /* This generates WM_SYSCHAR messages, which are interpreted
2230 by DefWindowProc as the menu selections. */
2231 if (got_accelerator)
2233 SetKeyboardState (keymap_sticky);
2234 TranslateMessage (&msg);
2235 SetKeyboardState (keymap_orig);
2239 SetKeyboardState (keymap_orig);
2243 if (key_needs_default_processing_p (wParam))
2248 case WM_MBUTTONDOWN:
2250 /* Real middle mouse button has nothing to do with emulated one:
2251 if one wants to exercise fingers playing chords on the mouse,
2252 he is allowed to do that! */
2253 mswindows_enqueue_mouse_button_event (hwnd, message_,
2254 MAKEPOINTS (lParam), GetMessageTime());
2258 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2259 msframe->last_click_time = GetMessageTime();
2261 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2262 msframe->button2_need_lbutton = 0;
2263 if (msframe->ignore_next_lbutton_up)
2265 msframe->ignore_next_lbutton_up = 0;
2267 else if (msframe->button2_is_down)
2269 msframe->button2_is_down = 0;
2270 msframe->ignore_next_rbutton_up = 1;
2271 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2272 MAKEPOINTS (lParam), GetMessageTime());
2276 if (msframe->button2_need_rbutton)
2278 msframe->button2_need_rbutton = 0;
2279 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2280 MAKEPOINTS (lParam), GetMessageTime());
2282 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2283 MAKEPOINTS (lParam), GetMessageTime());
2288 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2289 msframe->last_click_time = GetMessageTime();
2291 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2292 msframe->button2_need_rbutton = 0;
2293 if (msframe->ignore_next_rbutton_up)
2295 msframe->ignore_next_rbutton_up = 0;
2297 else if (msframe->button2_is_down)
2299 msframe->button2_is_down = 0;
2300 msframe->ignore_next_lbutton_up = 1;
2301 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2302 MAKEPOINTS (lParam), GetMessageTime());
2306 if (msframe->button2_need_lbutton)
2308 msframe->button2_need_lbutton = 0;
2309 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2310 MAKEPOINTS (lParam), GetMessageTime());
2312 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2313 MAKEPOINTS (lParam), GetMessageTime());
2317 case WM_LBUTTONDOWN:
2318 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2320 if (msframe->button2_need_lbutton)
2322 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2323 msframe->button2_need_lbutton = 0;
2324 msframe->button2_need_rbutton = 0;
2325 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
2327 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2328 MAKEPOINTS (lParam), GetMessageTime());
2329 msframe->button2_is_down = 1;
2333 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2334 msframe->last_click_point, msframe->last_click_time);
2335 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2336 MAKEPOINTS (lParam), GetMessageTime());
2341 mswindows_set_chord_timer (hwnd);
2342 msframe->button2_need_rbutton = 1;
2343 msframe->last_click_point = MAKEPOINTS (lParam);
2345 msframe->last_click_time = GetMessageTime();
2348 case WM_RBUTTONDOWN:
2349 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2351 if (msframe->button2_need_rbutton)
2353 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2354 msframe->button2_need_lbutton = 0;
2355 msframe->button2_need_rbutton = 0;
2356 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
2358 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2359 MAKEPOINTS (lParam), GetMessageTime());
2360 msframe->button2_is_down = 1;
2364 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2365 msframe->last_click_point, msframe->last_click_time);
2366 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2367 MAKEPOINTS (lParam), GetMessageTime());
2372 mswindows_set_chord_timer (hwnd);
2373 msframe->button2_need_lbutton = 1;
2374 msframe->last_click_point = MAKEPOINTS (lParam);
2376 msframe->last_click_time = GetMessageTime();
2380 if (wParam == BUTTON_2_TIMER_ID)
2382 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2383 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2385 if (msframe->button2_need_lbutton)
2387 msframe->button2_need_lbutton = 0;
2388 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2389 msframe->last_click_point, msframe->last_click_time);
2391 else if (msframe->button2_need_rbutton)
2393 msframe->button2_need_rbutton = 0;
2394 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2395 msframe->last_click_point, msframe->last_click_time);
2399 assert ("Spurious timer fired" == 0);
2403 /* Optimization: don't report mouse movement while size is changing */
2404 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2405 if (!msframe->sizing)
2407 /* When waiting for the second mouse button to finish
2408 button2 emulation, and have moved too far, just pretend
2409 as if timer has expired. This improves drag-select feedback */
2410 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2411 && !mswindows_button2_near_enough (msframe->last_click_point,
2412 MAKEPOINTS (lParam)))
2414 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2415 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2418 emacs_event = Fmake_event (Qnil, Qnil);
2419 event = XEVENT(emacs_event);
2421 event->channel = mswindows_find_frame(hwnd);
2422 event->timestamp = GetMessageTime();
2423 event->event_type = pointer_motion_event;
2424 event->event.motion.x = MAKEPOINTS(lParam).x;
2425 event->event.motion.y = MAKEPOINTS(lParam).y;
2426 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
2428 mswindows_enqueue_dispatch_event (emacs_event);
2434 /* Queue a `cancel-mode-internal' misc user event, so mouse
2435 selection would be canceled if any */
2436 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2437 Qcancel_mode_internal, Qnil);
2442 LPNMHDR nmhdr = (LPNMHDR)lParam;
2444 if (nmhdr->code == TTN_NEEDTEXT)
2446 #ifdef HAVE_TOOLBARS
2447 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2450 /* find out which toolbar */
2451 frame = XFRAME (mswindows_find_frame (hwnd));
2452 btext = mswindows_get_toolbar_button_text ( frame,
2455 tttext->lpszText = NULL;
2456 tttext->hinst = NULL;
2460 /* I think this is safe since the text will only go away
2461 when the toolbar does...*/
2462 TO_EXTERNAL_FORMAT (LISP_STRING, btext,
2463 C_STRING_ALLOCA, tttext->lpszText,
2468 /* handle tree view callbacks */
2469 else if (nmhdr->code == TVN_SELCHANGED)
2471 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2472 frame = XFRAME (mswindows_find_frame (hwnd));
2473 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2475 /* handle tab control callbacks */
2476 else if (nmhdr->code == TCN_SELCHANGE)
2479 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2480 frame = XFRAME (mswindows_find_frame (hwnd));
2482 item.mask = TCIF_PARAM;
2483 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2486 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2492 /* hdc will be NULL unless this is a subwindow - in which case we
2493 shouldn't have received a paint message for it here. */
2494 assert (wParam == 0);
2496 /* Can't queue a magic event because windows goes modal and sends paint
2497 messages directly to the windows procedure when doing solid drags
2498 and the message queue doesn't get processed. */
2499 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2503 /* We only care about this message if our size has really changed */
2504 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2509 fobj = mswindows_find_frame (hwnd);
2510 frame = XFRAME (fobj);
2511 msframe = FRAME_MSWINDOWS_DATA (frame);
2513 /* We cannot handle frame map and unmap hooks right in
2514 this routine, because these may throw. We queue
2515 magic events to run these hooks instead - kkm */
2517 if (wParam==SIZE_MINIMIZED)
2520 FRAME_VISIBLE_P (frame) = 0;
2521 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2525 GetClientRect(hwnd, &rect);
2526 FRAME_PIXWIDTH(frame) = rect.right;
2527 FRAME_PIXHEIGHT(frame) = rect.bottom;
2529 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2530 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2531 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2533 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2534 change_frame_size (frame, rows, columns, 1);
2536 /* If we are inside frame creation, we have to apply geometric
2538 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2540 /* Yes, we have to size again */
2541 mswindows_size_frame_internal ( frame,
2542 FRAME_MSWINDOWS_TARGET_RECT
2544 /* Reset so we do not get here again. The SetWindowPos call in
2545 * mswindows_size_frame_internal can cause recursion here. */
2546 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2548 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2549 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2554 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2555 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2556 FRAME_VISIBLE_P (frame) = 1;
2558 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2565 case WM_DISPLAYCHANGE:
2568 DWORD message_tick = GetMessageTime ();
2570 fobj = mswindows_find_frame (hwnd);
2571 frame = XFRAME (fobj);
2572 d = XDEVICE (FRAME_DEVICE (frame));
2574 /* Do this only once per message. XEmacs can receive this message
2575 through as many frames as it currently has open. Message time
2576 will be the same for all these messages. Despite extreme
2577 efficiency, the code below has about one in 4 billion
2578 probability that the HDC is not recreated, provided that
2579 XEmacs is running sufficiently longer than 52 days. */
2580 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2582 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2583 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2584 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2589 /* Misc magic events which only require that the frame be identified */
2592 mswindows_enqueue_magic_event (hwnd, message_);
2595 case WM_WINDOWPOSCHANGING:
2597 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2598 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2599 GetWindowPlacement(hwnd, &wpl);
2601 /* Only interested if size is changing and we're not being iconified */
2602 if (wpl.showCmd != SW_SHOWMINIMIZED
2603 && wpl.showCmd != SW_SHOWMAXIMIZED
2604 && !(wp->flags & SWP_NOSIZE))
2606 RECT ncsize = { 0, 0, 0, 0 };
2607 int pixwidth, pixheight;
2608 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2609 GetMenu(hwnd) != NULL,
2610 GetWindowLong (hwnd, GWL_EXSTYLE));
2612 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2613 wp->cx - (ncsize.right - ncsize.left),
2614 wp->cy - (ncsize.bottom - ncsize.top),
2615 &pixwidth, &pixheight);
2617 /* Convert client sizes to window sizes */
2618 pixwidth += (ncsize.right - ncsize.left);
2619 pixheight += (ncsize.bottom - ncsize.top);
2621 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2623 /* Adjust so that the bottom or right doesn't move if it's
2624 * the top or left that's being changed */
2626 GetWindowRect (hwnd, &rect);
2628 if (rect.left != wp->x)
2629 wp->x += wp->cx - pixwidth;
2630 if (rect.top != wp->y)
2631 wp->y += wp->cy - pixheight;
2637 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2638 window position if the user tries to track window too small */
2642 case WM_ENTERSIZEMOVE:
2643 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2644 msframe->sizing = 1;
2647 case WM_EXITSIZEMOVE:
2648 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2649 msframe->sizing = 0;
2650 /* Queue noop event */
2651 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2654 #ifdef HAVE_SCROLLBARS
2658 /* Direction of scroll is determined by scrollbar instance. */
2659 int code = (int) LOWORD(wParam);
2660 int pos = (short int) HIWORD(wParam);
2661 HWND hwndScrollBar = (HWND) lParam;
2662 struct gcpro gcpro1, gcpro2;
2664 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2665 GCPRO2 (emacs_event, fobj);
2666 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2668 /* Error during event pumping - cancel scroll */
2669 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2677 int keys = LOWORD (wParam); /* Modifier key flags */
2678 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2679 struct gcpro gcpro1, gcpro2;
2681 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2683 GCPRO2 (emacs_event, fobj);
2684 mswindows_pump_outstanding_events (); /* Can GC */
2693 #ifdef HAVE_MENUBARS
2695 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2697 XFRAME (mswindows_find_frame (hwnd)))))
2698 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2701 case WM_INITMENUPOPUP:
2702 if (!HIWORD(lParam))
2704 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2706 XFRAME (mswindows_find_frame (hwnd)))))
2707 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2711 #endif /* HAVE_MENUBARS */
2715 WORD id = LOWORD (wParam);
2716 WORD nid = HIWORD (wParam);
2717 HWND cid = (HWND)lParam;
2718 frame = XFRAME (mswindows_find_frame (hwnd));
2720 #ifdef HAVE_TOOLBARS
2721 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2724 /* widgets in a buffer only eval a callback for suitable events.*/
2729 case CBN_EDITCHANGE:
2731 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2734 /* menubars always must come last since the hashtables do not
2736 #ifdef HAVE_MENUBARS
2737 if (!NILP (mswindows_handle_wm_command (frame, id)))
2741 return DefWindowProc (hwnd, message_, wParam, lParam);
2742 /* Bite me - a spurious command. This used to not be able to
2743 happen but with the introduction of widgets its now
2748 case WM_CTLCOLORBTN:
2749 case WM_CTLCOLORLISTBOX:
2750 case WM_CTLCOLOREDIT:
2751 case WM_CTLCOLORSTATIC:
2752 case WM_CTLCOLORSCROLLBAR:
2754 /* if we get an opportunity to paint a widget then do so if
2755 there is an appropriate face */
2756 HWND crtlwnd = (HWND)lParam;
2757 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2760 Lisp_Object image_instance;
2761 VOID_TO_LISP (image_instance, ii);
2762 if (IMAGE_INSTANCEP (image_instance)
2764 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2766 /* set colors for the buttons */
2767 HDC hdc = (HDC)wParam;
2768 if (last_widget_brushed != ii)
2771 DeleteObject (widget_brush);
2772 widget_brush = CreateSolidBrush
2773 (COLOR_INSTANCE_MSWINDOWS_COLOR
2776 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2777 XIMAGE_INSTANCE_FRAME (image_instance)))));
2779 last_widget_brushed = ii;
2782 COLOR_INSTANCE_MSWINDOWS_COLOR
2785 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2786 XIMAGE_INSTANCE_FRAME (image_instance)))));
2787 SetBkMode (hdc, OPAQUE);
2790 COLOR_INSTANCE_MSWINDOWS_COLOR
2793 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2794 XIMAGE_INSTANCE_FRAME (image_instance)))));
2795 return (LRESULT)widget_brush;
2801 #ifdef HAVE_DRAGNDROP
2802 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2804 UINT filecount, i, len;
2809 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2810 struct gcpro gcpro1, gcpro2, gcpro3;
2812 emacs_event = Fmake_event (Qnil, Qnil);
2813 event = XEVENT(emacs_event);
2815 GCPRO3 (emacs_event, l_dndlist, l_item);
2817 if (!DragQueryPoint ((HDROP) wParam, &point))
2818 point.x = point.y = -1; /* outside client area */
2820 event->event_type = misc_user_event;
2821 event->channel = mswindows_find_frame(hwnd);
2822 event->timestamp = GetMessageTime();
2823 event->event.misc.button = 1; /* #### Should try harder */
2824 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2825 event->event.misc.x = point.x;
2826 event->event.misc.y = point.y;
2827 event->event.misc.function = Qdragdrop_drop_dispatch;
2829 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2830 for (i=0; i<filecount; i++)
2832 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2833 /* The URLs that we make here aren't correct according to section
2834 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2835 * because they may contain reserved characters. But that's OK -
2836 * they just need to be good enough to keep dragdrop.el happy. */
2837 fname = (char *)xmalloc (len+1);
2838 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2840 /* May be a shell link aka "shortcut" - replace fname if so */
2841 #if !(defined(CYGWIN) || defined(MINGW))
2842 /* cygwin doesn't define this COM stuff */
2843 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2847 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2848 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2852 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2856 WIN32_FIND_DATA wfd;
2857 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2859 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2861 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2862 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2867 len = strlen (fname);
2870 ppf->lpVtbl->Release (ppf);
2873 psl->lpVtbl->Release (psl);
2879 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2880 strcpy (filename, "file:");
2881 cygwin32_win32_to_posix_path_list (fname, filename+5);
2883 filename = (char *)xmalloc (len+6);
2884 strcat (strcpy (filename, "file:"), fname);
2885 dostounix_filename (filename+5);
2888 l_item = make_string (filename, strlen (filename));
2889 l_dndlist = Fcons (l_item, l_dndlist);
2892 DragFinish ((HDROP) wParam);
2894 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2895 mswindows_enqueue_dispatch_event (emacs_event);
2903 return DefWindowProc (hwnd, message_, wParam, lParam);
2909 /************************************************************************/
2910 /* keyboard, mouse & other helpers for the windows procedure */
2911 /************************************************************************/
2913 mswindows_set_chord_timer (HWND hwnd)
2917 /* We get one third half system double click threshold */
2918 if (mswindows_mouse_button_tolerance <= 0)
2919 interval = GetDoubleClickTime () / 3;
2921 interval = mswindows_mouse_button_tolerance;
2923 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2927 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2930 if (mswindows_mouse_button_max_skew_x <= 0)
2931 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2933 dx = mswindows_mouse_button_max_skew_x;
2935 if (mswindows_mouse_button_max_skew_y <= 0)
2936 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2938 dy = mswindows_mouse_button_max_skew_y;
2940 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2944 mswindows_current_layout_has_AltGr (void)
2946 /* This simple caching mechanism saves 10% of CPU
2947 time when a key typed at autorepeat rate of 30 cps! */
2948 static HKL last_hkl = 0;
2949 static int last_hkl_has_AltGr;
2951 HKL current_hkl = GetKeyboardLayout (0);
2952 if (current_hkl != last_hkl)
2955 last_hkl_has_AltGr = 0;
2956 /* In this loop, we query whether a character requires
2957 AltGr to be down to generate it. If at least such one
2958 found, this means that the layout does regard AltGr */
2959 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2960 if (HIBYTE (VkKeyScan (c)) == 6)
2961 last_hkl_has_AltGr = 1;
2962 last_hkl = current_hkl;
2964 return last_hkl_has_AltGr;
2968 /* Returns the state of the modifier keys in the format expected by the
2969 * Lisp_Event key_data, button_data and motion_data modifiers member */
2971 mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2979 GetKeyboardState (keymap);
2980 has_AltGr = mswindows_current_layout_has_AltGr ();
2983 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2985 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
2986 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
2990 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
2991 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
2994 mods |= (keymap [VK_SHIFT] & 0x80) ? XEMACS_MOD_SHIFT : 0;
3000 * Translate a mswindows virtual key to a keysym.
3001 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3002 * or whose ASCII codes (like space) xemacs doesn't like.
3003 * Virtual key values are defined in winresrc.h
3005 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3008 if (extendedp) /* Keys not present on a 82 key keyboard */
3010 switch (mswindows_key)
3012 case VK_RETURN: return KEYSYM ("kp-enter");
3013 case VK_PRIOR: return KEYSYM ("prior");
3014 case VK_NEXT: return KEYSYM ("next");
3015 case VK_END: return KEYSYM ("end");
3016 case VK_HOME: return KEYSYM ("home");
3017 case VK_LEFT: return KEYSYM ("left");
3018 case VK_UP: return KEYSYM ("up");
3019 case VK_RIGHT: return KEYSYM ("right");
3020 case VK_DOWN: return KEYSYM ("down");
3021 case VK_INSERT: return KEYSYM ("insert");
3022 case VK_DELETE: return QKdelete;
3027 switch (mswindows_key)
3029 case VK_BACK: return QKbackspace;
3030 case VK_TAB: return QKtab;
3031 case '\n': return QKlinefeed;
3032 case VK_CLEAR: return KEYSYM ("clear");
3033 case VK_RETURN: return QKreturn;
3034 case VK_ESCAPE: return QKescape;
3035 case VK_SPACE: return QKspace;
3036 case VK_PRIOR: return KEYSYM ("kp-prior");
3037 case VK_NEXT: return KEYSYM ("kp-next");
3038 case VK_END: return KEYSYM ("kp-end");
3039 case VK_HOME: return KEYSYM ("kp-home");
3040 case VK_LEFT: return KEYSYM ("kp-left");
3041 case VK_UP: return KEYSYM ("kp-up");
3042 case VK_RIGHT: return KEYSYM ("kp-right");
3043 case VK_DOWN: return KEYSYM ("kp-down");
3044 case VK_SELECT: return KEYSYM ("select");
3045 case VK_PRINT: return KEYSYM ("print");
3046 case VK_EXECUTE: return KEYSYM ("execute");
3047 case VK_SNAPSHOT: return KEYSYM ("print");
3048 case VK_INSERT: return KEYSYM ("kp-insert");
3049 case VK_DELETE: return KEYSYM ("kp-delete");
3050 case VK_HELP: return KEYSYM ("help");
3051 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3052 case VK_LWIN return KEYSYM ("");
3053 case VK_RWIN return KEYSYM ("");
3055 case VK_APPS: return KEYSYM ("menu");
3056 case VK_NUMPAD0: return KEYSYM ("kp-0");
3057 case VK_NUMPAD1: return KEYSYM ("kp-1");
3058 case VK_NUMPAD2: return KEYSYM ("kp-2");
3059 case VK_NUMPAD3: return KEYSYM ("kp-3");
3060 case VK_NUMPAD4: return KEYSYM ("kp-4");
3061 case VK_NUMPAD5: return KEYSYM ("kp-5");
3062 case VK_NUMPAD6: return KEYSYM ("kp-6");
3063 case VK_NUMPAD7: return KEYSYM ("kp-7");
3064 case VK_NUMPAD8: return KEYSYM ("kp-8");
3065 case VK_NUMPAD9: return KEYSYM ("kp-9");
3066 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3067 case VK_ADD: return KEYSYM ("kp-add");
3068 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3069 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3070 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3071 case VK_DIVIDE: return KEYSYM ("kp-divide");
3072 case VK_F1: return KEYSYM ("f1");
3073 case VK_F2: return KEYSYM ("f2");
3074 case VK_F3: return KEYSYM ("f3");
3075 case VK_F4: return KEYSYM ("f4");
3076 case VK_F5: return KEYSYM ("f5");
3077 case VK_F6: return KEYSYM ("f6");
3078 case VK_F7: return KEYSYM ("f7");
3079 case VK_F8: return KEYSYM ("f8");
3080 case VK_F9: return KEYSYM ("f9");
3081 case VK_F10: return KEYSYM ("f10");
3082 case VK_F11: return KEYSYM ("f11");
3083 case VK_F12: return KEYSYM ("f12");
3084 case VK_F13: return KEYSYM ("f13");
3085 case VK_F14: return KEYSYM ("f14");
3086 case VK_F15: return KEYSYM ("f15");
3087 case VK_F16: return KEYSYM ("f16");
3088 case VK_F17: return KEYSYM ("f17");
3089 case VK_F18: return KEYSYM ("f18");
3090 case VK_F19: return KEYSYM ("f19");
3091 case VK_F20: return KEYSYM ("f20");
3092 case VK_F21: return KEYSYM ("f21");
3093 case VK_F22: return KEYSYM ("f22");
3094 case VK_F23: return KEYSYM ("f23");
3095 case VK_F24: return KEYSYM ("f24");
3102 * Find the console that matches the supplied mswindows window handle
3105 mswindows_find_console (HWND hwnd)
3107 /* We only support one console */
3108 return XCAR (Vconsole_list);
3112 * Find the frame that matches the supplied mswindows window handle
3115 mswindows_find_frame (HWND hwnd)
3117 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3121 /* We are in progress of frame creation. Return the frame
3122 being created, as it still not remembered in the window
3124 assert (!NILP (Vmswindows_frame_being_created));
3125 return Vmswindows_frame_being_created;
3127 VOID_TO_LISP (f, l);
3132 /************************************************************************/
3134 /************************************************************************/
3137 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3140 EMACS_TIME current_time;
3141 EMACS_GET_TIME (current_time);
3142 EMACS_SUB_TIME (thyme, thyme, current_time);
3143 milliseconds = EMACS_SECS (thyme) * 1000 +
3144 (EMACS_USECS (thyme) + 500) / 1000;
3145 if (milliseconds < 1)
3147 ++mswindows_pending_timers_count;
3148 return SetTimer (NULL, 0, milliseconds,
3149 (TIMERPROC) mswindows_wm_timer_callback);
3153 emacs_mswindows_remove_timeout (int id)
3155 Lisp_Event match_against;
3156 Lisp_Object emacs_event;
3158 if (KillTimer (NULL, id))
3159 --mswindows_pending_timers_count;
3161 /* If there is a dispatch event generated by this
3162 timeout in the queue, we have to remove it too. */
3163 match_against.event_type = timeout_event;
3164 match_against.event.timeout.interval_id = id;
3165 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3166 if (!NILP (emacs_event))
3167 Fdeallocate_event(emacs_event);
3170 /* If `user_p' is false, then return whether there are any win32, timeout,
3171 * or subprocess events pending (that is, whether
3172 * emacs_mswindows_next_event() would return immediately without blocking).
3174 * if `user_p' is true, then return whether there are any *user generated*
3175 * events available (that is, whether there are keyboard or mouse-click
3176 * events ready to be read). This also implies that
3177 * emacs_mswindows_next_event() would not block.
3180 emacs_mswindows_event_pending_p (int user_p)
3182 mswindows_need_event (0);
3183 return (!NILP (mswindows_u_dispatch_event_queue)
3184 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3188 * Return the next event
3191 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3193 Lisp_Object event, event2;
3195 mswindows_need_event (1);
3197 event = mswindows_dequeue_dispatch_event ();
3198 XSETEVENT (event2, emacs_event);
3199 Fcopy_event (event, event2);
3200 Fdeallocate_event (event);
3204 * Handle a magic event off the dispatch queue.
3207 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3209 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3216 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3217 mswindows_handle_paint (f);
3218 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3225 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3226 struct frame *f = XFRAME (frame);
3227 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3229 struct gcpro gcpro1;
3231 /* On focus change, clear all memory of sticky modifiers
3232 to avoid non-intuitive behavior. */
3233 clear_sticky_modifiers ();
3235 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3237 emacs_handle_focus_change_preliminary (conser);
3238 /* Under X the stuff up to here is done in the X event handler.
3240 emacs_handle_focus_change_final (conser);
3249 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3250 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3252 Qmap_frame_hook : Qunmap_frame_hook,
3257 /* #### What about Enter & Leave */
3259 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3260 Qmouse_leave_frame_hook, 1, frame);
3268 #ifndef HAVE_MSG_SELECT
3270 get_process_input_waitable (Lisp_Process *process)
3272 Lisp_Object instr, outstr, p;
3273 XSETPROCESS (p, process);
3274 get_process_streams (process, &instr, &outstr);
3275 assert (!NILP (instr));
3276 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3277 return (network_connection_p (p)
3278 ? get_winsock_stream_waitable (XLSTREAM (instr))
3279 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3281 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3286 emacs_mswindows_select_process (Lisp_Process *process)
3288 HANDLE hev = get_process_input_waitable (process);
3290 if (!add_waitable_handle (hev))
3291 error ("Too many active processes");
3293 #ifdef HAVE_WIN32_PROCESSES
3296 XSETPROCESS (p, process);
3297 if (!network_connection_p (p))
3299 HANDLE hprocess = get_nt_process_handle (process);
3300 if (!add_waitable_handle (hprocess))
3302 remove_waitable_handle (hev);
3303 error ("Too many active processes");
3311 emacs_mswindows_unselect_process (Lisp_Process *process)
3313 /* Process handle is removed in the event loop as soon
3314 as it is signaled, so don't bother here about it */
3315 HANDLE hev = get_process_input_waitable (process);
3316 remove_waitable_handle (hev);
3318 #endif /* HAVE_MSG_SELECT */
3321 emacs_mswindows_select_console (struct console *con)
3323 #ifdef HAVE_MSG_SELECT
3324 if (CONSOLE_MSWINDOWS_P (con))
3325 return; /* mswindows consoles are automatically selected */
3327 event_stream_unixoid_select_console (con);
3332 emacs_mswindows_unselect_console (struct console *con)
3334 #ifdef HAVE_MSG_SELECT
3335 if (CONSOLE_MSWINDOWS_P (con))
3336 return; /* mswindows consoles are automatically selected */
3338 event_stream_unixoid_unselect_console (con);
3343 emacs_mswindows_quit_p (void)
3345 /* Quit cannot happen in modal loop: all program
3346 input is dedicated to Windows. */
3347 if (mswindows_in_modal_loop)
3350 /* Drain windows queue. This sets up number of quit characters in
3352 mswindows_drain_windows_queue ();
3354 if (mswindows_quit_chars_count > 0)
3356 /* Yes there's a hidden one... Throw it away */
3357 Lisp_Event match_against;
3358 Lisp_Object emacs_event;
3361 match_against.event_type = key_press_event;
3362 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3364 while (mswindows_quit_chars_count-- > 0)
3366 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3367 assert (!NILP (emacs_event));
3369 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
3372 Fdeallocate_event(emacs_event);
3375 Vquit_flag = critical_p ? Qcritical : Qt;
3380 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3381 Lisp_Object* instream,
3382 Lisp_Object* outstream,
3385 /* Handles for streams */
3387 /* fds. These just stored along with the streams, and are closed in
3388 delete stream pair method, because we need to handle fake unices
3392 /* Decode inhandle and outhandle. Their meaning depends on
3393 the process implementation being used. */
3394 #if defined (HAVE_WIN32_PROCESSES)
3395 /* We're passed in Windows handles. That's what we like most... */
3396 hin = (HANDLE) inhandle;
3397 hout = (HANDLE) outhandle;
3399 #elif defined (HAVE_UNIX_PROCESSES)
3400 /* We are passed UNIX fds. This must be Cygwin.
3402 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3403 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3407 #error "So, WHICH kind of processes do you want?"
3410 *instream = (hin == INVALID_HANDLE_VALUE
3412 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3413 : flags & STREAM_NETWORK_CONNECTION
3414 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3416 : make_ntpipe_input_stream (hin, fdi));
3418 #ifdef HAVE_WIN32_PROCESSES
3419 *outstream = (hout == INVALID_HANDLE_VALUE
3421 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3422 : flags & STREAM_NETWORK_CONNECTION
3423 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3425 : make_ntpipe_output_stream (hout, fdo));
3426 #elif defined (HAVE_UNIX_PROCESSES)
3427 *outstream = (fdo >= 0
3428 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3431 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3432 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3433 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3435 Bufbyte eof_char = get_eof_char (fdo);
3436 int pty_max_bytes = get_pty_max_bytes (fdo);
3437 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3442 return (NILP (*instream)
3444 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3445 : flags & STREAM_NETWORK_CONNECTION
3446 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3448 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3452 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3453 Lisp_Object outstream)
3455 /* Oh nothing special here for Win32 at all */
3456 #if defined (HAVE_UNIX_PROCESSES)
3457 int in = (NILP(instream)
3459 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3460 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3461 ? get_winsock_stream_param (XLSTREAM (instream))
3463 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3464 int out = (NILP(outstream) ? -1
3465 : filedesc_stream_fd (XLSTREAM (outstream)));
3469 if (out != in && out >= 0)
3473 return (NILP (instream)
3475 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3476 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3477 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3479 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3482 #ifndef HAVE_X_WINDOWS
3483 /* This is called from GC when a process object is about to be freed.
3484 If we've still got pointers to it in this file, we're gonna lose hard.
3487 debug_process_finalization (Lisp_Process *p)
3490 Lisp_Object instr, outstr;
3492 get_process_streams (p, &instr, &outstr);
3493 /* if it still has fds, then it hasn't been killed yet. */
3494 assert (NILP(instr));
3495 assert (NILP(outstr));
3497 /* #### More checks here */
3502 /************************************************************************/
3503 /* initialization */
3504 /************************************************************************/
3507 reinit_vars_of_event_mswindows (void)
3509 mswindows_in_modal_loop = 0;
3510 mswindows_pending_timers_count = 0;
3512 mswindows_event_stream = xnew (struct event_stream);
3514 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3515 mswindows_event_stream->force_event_pending = 0;
3516 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3517 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3518 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3519 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3520 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3521 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3522 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3523 #ifdef HAVE_MSG_SELECT
3524 mswindows_event_stream->select_process_cb =
3525 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3526 mswindows_event_stream->unselect_process_cb =
3527 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3528 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3529 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3531 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3532 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3533 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3534 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3539 vars_of_event_mswindows (void)
3541 reinit_vars_of_event_mswindows ();
3543 mswindows_u_dispatch_event_queue = Qnil;
3544 staticpro (&mswindows_u_dispatch_event_queue);
3545 mswindows_u_dispatch_event_queue_tail = Qnil;
3546 pdump_wire (&mswindows_u_dispatch_event_queue_tail);
3548 mswindows_s_dispatch_event_queue = Qnil;
3549 staticpro (&mswindows_s_dispatch_event_queue);
3550 mswindows_s_dispatch_event_queue_tail = Qnil;
3551 pdump_wire (&mswindows_s_dispatch_event_queue_tail);
3553 mswindows_error_caught_in_modal_loop = Qnil;
3554 staticpro (&mswindows_error_caught_in_modal_loop);
3558 DEFVAR_INT ("mswindows-debug-events", &mswindows_debug_events /*
3559 If non-zero, display debug information about Windows events that XEmacs sees.
3560 Information is displayed in a console window. Currently defined values are:
3562 1 == non-verbose output
3565 #### Unfortunately, not yet implemented.
3567 mswindows_debug_events = 0;
3570 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3571 &mswindows_alt_by_itself_activates_menu /*
3572 *Controls whether pressing and releasing the Alt key activates the menubar.
3573 This applies only if no intervening key was pressed. See also
3574 `menu-accelerator-enabled', which is probably the behavior you actually want.
3578 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3579 &mswindows_dynamic_frame_resize /*
3580 *Controls redrawing frame contents during mouse-drag or keyboard resize
3581 operation. When non-nil, the frame is redrawn while being resized. When
3582 nil, frame is not redrawn, and exposed areas are filled with default
3583 MDI application background color. Note that this option only has effect
3584 if "Show window contents while dragging" is on in system Display/Plus!
3586 Default is t on fast machines, nil on slow.
3589 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3590 &mswindows_mouse_button_tolerance /*
3591 *Analogue of double click interval for faking middle mouse events.
3592 The value is the minimum time in milliseconds that must elapse between
3593 left/right button down events before they are considered distinct events.
3594 If both mouse buttons are depressed within this interval, a middle mouse
3595 button down event is generated instead.
3596 If negative or zero, currently set system default is used instead.
3599 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3600 Number of physical mouse buttons.
3603 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3604 &mswindows_mouse_button_max_skew_x /*
3605 *Maximum horizontal distance in pixels between points in which left and
3606 right button clicks occurred for them to be translated into single
3607 middle button event. Clicks must occur in time not longer than defined
3608 by the variable `mswindows-mouse-button-tolerance'.
3609 If negative or zero, currently set system default is used instead.
3612 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3613 &mswindows_mouse_button_max_skew_y /*
3614 *Maximum vertical distance in pixels between points in which left and
3615 right button clicks occurred for them to be translated into single
3616 middle button event. Clicks must occur in time not longer than defined
3617 by the variable `mswindows-mouse-button-tolerance'.
3618 If negative or zero, currently set system default is used instead.
3621 mswindows_mouse_button_max_skew_x = 0;
3622 mswindows_mouse_button_max_skew_y = 0;
3623 mswindows_mouse_button_tolerance = 0;
3624 mswindows_alt_by_itself_activates_menu = 1;
3628 syms_of_event_mswindows (void)
3633 lstream_type_create_mswindows_selectable (void)
3635 init_slurp_stream ();
3636 init_shove_stream ();
3637 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3638 init_winsock_stream ();
3643 init_event_mswindows_late (void)
3645 #ifdef HAVE_MSG_SELECT
3646 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3647 assert (windows_fd>=0);
3648 FD_SET (windows_fd, &input_wait_mask);
3649 FD_ZERO(&zero_mask);
3652 event_stream = mswindows_event_stream;
3654 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3655 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);