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, DWORD fwKeys,
101 static void mswindows_set_chord_timer (HWND hwnd);
102 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
103 static int mswindows_current_layout_has_AltGr (void);
104 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
105 int downp, int keyp);
107 static struct event_stream *mswindows_event_stream;
109 #ifdef HAVE_MSG_SELECT
110 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
111 extern SELECT_TYPE process_only_mask, tty_only_mask;
112 SELECT_TYPE zero_mask;
113 extern int signal_event_pipe_initialized;
118 * Two separate queues, for efficiency, one (_u_) for user events, and
119 * another (_s_) for non-user ones. We always return events out of the
120 * first one until it is empty and only then proceed with the second
123 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
124 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
126 /* The number of things we can wait on */
127 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
129 #ifndef HAVE_MSG_SELECT
130 /* List of mswindows waitable handles. */
131 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
133 /* Number of wait handles */
134 static int mswindows_waitable_count=0;
135 #endif /* HAVE_MSG_SELECT */
137 /* Brush for painting widgets */
138 static HBRUSH widget_brush = 0;
139 static LONG last_widget_brushed = 0;
141 /* Count of quit chars currently in the queue */
142 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
143 Decremented in mswindows_dequeue_dispatch_event() */
144 int mswindows_quit_chars_count = 0;
146 /* These are Lisp integers; see DEFVARS in this file for description. */
147 int mswindows_dynamic_frame_resize;
148 int mswindows_alt_by_itself_activates_menu;
149 int mswindows_num_mouse_buttons;
150 int mswindows_mouse_button_max_skew_x;
151 int mswindows_mouse_button_max_skew_y;
152 int mswindows_mouse_button_tolerance;
155 int debug_mswindows_events;
158 /* This is the event signaled by the event pump.
159 See mswindows_pump_outstanding_events for comments */
160 static Lisp_Object mswindows_error_caught_in_modal_loop;
161 static int mswindows_in_modal_loop;
163 /* Count of wound timers */
164 static int mswindows_pending_timers_count;
166 static DWORD mswindows_last_mouse_button_state;
168 /************************************************************************/
169 /* Pipe instream - reads process output */
170 /************************************************************************/
172 #define PIPE_READ_DELAY 20
174 #define HANDLE_TO_USID(h) ((USID)(h))
176 #define NTPIPE_SLURP_STREAM_DATA(stream) \
177 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
179 /* This structure is allocated by the main thread, and is deallocated
180 in the thread upon exit. There are situations when a thread
181 remains blocked for a long time, much longer than the lstream
182 exists. For example, "start notepad" command is issued from the
183 shell, then the shell is closed by C-c C-d. Although the shell
184 process exits, its output pipe will not get closed until the
185 notepad process exits also, because it inherits the pipe form the
186 shell. In this case, we abandon the thread, and let it live until
187 all such processes exit. While struct ntpipe_slurp_stream is
188 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
190 struct ntpipe_slurp_stream_shared_data
192 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
193 /* This is a manual-reset object. */
194 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
195 /* This is a manual-reset object. */
196 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
197 /* This is a manual-reset object. */
198 HANDLE hpipe; /* Pipe read end handle. */
199 LONG die_p; /* Thread must exit ASAP if non-zero */
200 BOOL eof_p : 1; /* Set when thread saw EOF */
201 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
202 BOOL inuse_p : 1; /* this structure is in use */
203 LONG lock_count; /* Client count of this struct, 0=safe to free */
204 BYTE onebyte; /* One byte buffer read by thread */
207 #define MAX_SLURP_STREAMS 32
208 struct ntpipe_slurp_stream_shared_data
209 shared_data_block[MAX_SLURP_STREAMS]={{0}};
211 struct ntpipe_slurp_stream
213 LPARAM user_data; /* Any user data stored in the stream object */
214 struct ntpipe_slurp_stream_shared_data* thread_data;
217 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
218 sizeof (struct ntpipe_slurp_stream));
220 /* This function is thread-safe, and is called from either thread
221 context. It serializes freeing shared data structure */
223 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
225 if (InterlockedDecrement (&s->lock_count) == 0)
228 CloseHandle (s->hev_thread);
229 CloseHandle (s->hev_caller);
230 CloseHandle (s->hev_unsleep);
235 static struct ntpipe_slurp_stream_shared_data*
236 slurper_allocate_shared_data (void)
239 for (i=0; i<MAX_SLURP_STREAMS; i++)
241 if (!shared_data_block[i].inuse_p)
243 shared_data_block[i].inuse_p=1;
244 return &shared_data_block[i];
247 return (struct ntpipe_slurp_stream_shared_data*)0;
251 slurp_thread (LPVOID vparam)
253 struct ntpipe_slurp_stream_shared_data *s =
254 (struct ntpipe_slurp_stream_shared_data*)vparam;
258 /* Read one byte from the pipe */
260 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
262 DWORD err = GetLastError ();
263 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
268 else if (actually_read == 0)
271 /* We must terminate on an error or eof */
272 if (s->eof_p || s->error_p)
273 InterlockedIncrement (&s->die_p);
275 /* Before we notify caller, we unsignal our event. */
276 ResetEvent (s->hev_thread);
278 /* Now we got something to notify caller, either a byte or an
279 error/eof indication. Before we do, allow internal pipe
280 buffer to accumulate little bit more data.
281 Reader function pulses this event before waiting for
282 a character, to avoid pipe delay, and to get the byte
285 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
287 /* Either make event loop generate a process event, or
289 SetEvent (s->hev_caller);
291 /* Cleanup and exit if we're shot off */
295 /* Block until the client finishes with retrieving the rest of
297 WaitForSingleObject (s->hev_thread, INFINITE);
300 slurper_free_shared_data_maybe (s);
306 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
309 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
310 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
311 DWORD thread_id_unused;
314 /* We deal only with pipes, for we're using PeekNamedPipe api */
315 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
317 s->thread_data = slurper_allocate_shared_data();
319 /* Create reader thread. This could fail, so do not create events
320 until thread is created */
321 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
322 CREATE_SUSPENDED, &thread_id_unused);
325 Lstream_delete (lstr);
326 s->thread_data->inuse_p=0;
330 /* Shared data are initially owned by both main and slurper
332 s->thread_data->lock_count = 2;
333 s->thread_data->die_p = 0;
334 s->thread_data->eof_p = FALSE;
335 s->thread_data->error_p = FALSE;
336 s->thread_data->hpipe = hpipe;
337 s->user_data = param;
339 /* hev_thread is a manual-reset event, initially signaled */
340 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
341 /* hev_caller is a manual-reset event, initially nonsignaled */
342 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
343 /* hev_unsleep is a manual-reset event, initially nonsignaled */
344 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
347 ResumeThread (hthread);
348 CloseHandle (hthread);
350 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
351 XSETLSTREAM (obj, lstr);
356 get_ntpipe_input_stream_param (Lstream *stream)
358 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
363 get_ntpipe_input_stream_waitable (Lstream *stream)
365 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
366 return s->thread_data->hev_caller;
370 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size)
372 /* This function must be called from the main thread only */
373 struct ntpipe_slurp_stream_shared_data* s =
374 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
379 /* Disallow pipe read delay for the thread: we need a character
381 SetEvent (s->hev_unsleep);
383 /* Check if we have a character ready. Give it a short delay,
384 for the thread to awake from pipe delay, just ion case*/
385 wait_result = WaitForSingleObject (s->hev_caller, 2);
387 /* Revert to the normal sleep behavior. */
388 ResetEvent (s->hev_unsleep);
390 /* If there's no byte buffered yet, give up */
391 if (wait_result == WAIT_TIMEOUT)
398 /* Reset caller unlock event now, as we've handled the pending
399 process output event */
400 ResetEvent (s->hev_caller);
402 /* It is now safe to do anything with contents of S, except for
403 changing s->die_p, which still should be interlocked */
407 if (s->error_p || s->die_p)
410 /* Ok, there were no error neither eof - we've got a byte from the
412 *(data++) = s->onebyte;
416 DWORD bytes_read = 0;
419 DWORD bytes_available;
421 /* If the api call fails, return at least one byte already
422 read. ReadFile in thread will return error */
423 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
426 /* Fetch available bytes. The same consideration applies,
427 so do not check for errors. ReadFile in the thread will
428 fail if the next call fails. */
430 ReadFile (s->hpipe, data, min (bytes_available, size),
434 /* Now we can unblock thread, so it attempts to read more */
435 SetEvent (s->hev_thread);
436 return bytes_read + 1;
443 ntpipe_slurp_closer (Lstream *stream)
445 /* This function must be called from the main thread only */
446 struct ntpipe_slurp_stream_shared_data* s =
447 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
449 /* Force thread to stop */
450 InterlockedIncrement (&s->die_p);
452 /* Set events which could possibly block slurper. Let it finish soon
454 SetEvent (s->hev_unsleep);
455 SetEvent (s->hev_thread);
457 /* Unlock and maybe free shared data */
458 slurper_free_shared_data_maybe (s);
464 init_slurp_stream (void)
466 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
467 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
470 /************************************************************************/
471 /* Pipe outstream - writes process input */
472 /************************************************************************/
474 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
475 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
477 #define MAX_SHOVE_BUFFER_SIZE 512
479 struct ntpipe_shove_stream
481 LPARAM user_data; /* Any user data stored in the stream object */
482 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
483 /* This is an auto-reset object. */
484 HANDLE hpipe; /* Pipe write end handle. */
485 HANDLE hthread; /* Reader thread handle. */
486 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
487 DWORD size; /* Number of bytes to write */
488 LONG die_p; /* Thread must exit ASAP if non-zero */
489 LONG idle_p; /* Non-zero if thread is waiting for job */
490 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
491 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
494 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
495 sizeof (struct ntpipe_shove_stream));
497 #ifndef HAVE_MSG_SELECT
499 shove_thread (LPVOID vparam)
501 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
507 /* Block on event and wait for a job */
508 InterlockedIncrement (&s->idle_p);
509 WaitForSingleObject (s->hev_thread, INFINITE);
511 /* Write passed buffer if any */
514 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
515 || bytes_written != s->size)
518 InterlockedIncrement (&s->die_p);
520 /* Set size to zero so we won't write it again if the closer sets
521 die_p and kicks us */
533 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
536 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
537 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
538 DWORD thread_id_unused;
543 s->user_data = param;
545 /* Create reader thread. This could fail, so do not
546 create the event until thread is created */
547 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
548 CREATE_SUSPENDED, &thread_id_unused);
549 if (s->hthread == NULL)
551 Lstream_delete (lstr);
555 /* Set the priority of the thread higher so we don't end up waiting
556 on it to send things. */
557 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST))
559 CloseHandle (s->hthread);
560 Lstream_delete (lstr);
564 /* hev_thread is an auto-reset event, initially nonsignaled */
565 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
568 ResumeThread (s->hthread);
570 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
571 XSETLSTREAM (obj, lstr);
576 get_ntpipe_output_stream_param (Lstream *stream)
578 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
584 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size)
586 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
591 s->blocking_p = !s->idle_p;
595 if (size>MAX_SHOVE_BUFFER_SIZE)
598 memcpy (s->buffer, data, size);
602 InterlockedDecrement (&s->idle_p);
603 SetEvent (s->hev_thread);
604 /* Give it a chance to run -- this dramatically improves performance
605 of things like crypt. */
606 if (xSwitchToThread) /* not in Win9x or NT 3.51 */
607 (void) xSwitchToThread ();
612 ntpipe_shove_was_blocked_p (Lstream *stream)
614 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
615 return s->blocking_p;
619 ntpipe_shove_closer (Lstream *stream)
621 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
623 /* Force thread stop */
624 InterlockedIncrement (&s->die_p);
626 /* Thread will end upon unblocking. If it's already unblocked this will
627 do nothing, but the thread won't look at die_p until it's written any
629 SetEvent (s->hev_thread);
631 /* Wait while thread terminates */
632 WaitForSingleObject (s->hthread, INFINITE);
634 /* Close pipe handle, possibly breaking it */
635 CloseHandle (s->hpipe);
637 /* Close the thread handle */
638 CloseHandle (s->hthread);
640 /* Destroy the event */
641 CloseHandle (s->hev_thread);
647 init_shove_stream (void)
649 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
650 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
651 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
654 /************************************************************************/
655 /* Winsock I/O stream */
656 /************************************************************************/
657 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
659 #define WINSOCK_READ_BUFFER_SIZE 1024
661 struct winsock_stream
663 LPARAM user_data; /* Any user data stored in the stream object */
664 SOCKET s; /* Socket handle (which is a Win32 handle) */
665 OVERLAPPED ov; /* Overlapped I/O structure */
666 void* buffer; /* Buffer. Allocated for input stream only */
667 unsigned long bufsize; /* Number of bytes last read */
668 unsigned long bufpos; /* Position in buffer for next fetch */
669 unsigned int error_p :1; /* I/O Error seen */
670 unsigned int eof_p :1; /* EOF Error seen */
671 unsigned int pending_p :1; /* There is a pending I/O operation */
672 unsigned int blocking_p :1; /* Last write attempt would block */
675 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
677 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
678 sizeof (struct winsock_stream));
681 winsock_initiate_read (struct winsock_stream *str)
683 ResetEvent (str->ov.hEvent);
686 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
687 &str->bufsize, &str->ov))
689 if (GetLastError () == ERROR_IO_PENDING)
691 else if (GetLastError () == ERROR_HANDLE_EOF)
696 else if (str->bufsize == 0)
701 winsock_reader (Lstream *stream, unsigned char *data, size_t size)
703 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
705 /* If the current operation is not yet complete, there's nothing to
709 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
716 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
718 if (GetLastError() == ERROR_HANDLE_EOF)
723 if (str->bufsize == 0)
734 /* Return as much of buffer as we have */
735 size = min (size, (size_t) (str->bufsize - str->bufpos));
736 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
739 /* Read more if buffer is exhausted */
740 if (str->bufsize == str->bufpos)
741 winsock_initiate_read (str);
747 winsock_writer (Lstream *stream, const unsigned char *data, size_t size)
749 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
753 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
761 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
776 ResetEvent (str->ov.hEvent);
778 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
779 * an overlapped operation. This fails on Win95 with winsock 1.x so we
780 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
781 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
782 || GetLastError() == ERROR_IO_PENDING)
788 return str->error_p ? -1 : size;
792 winsock_closer (Lstream *lstr)
794 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
796 if (lstr->flags & LSTREAM_FL_READ)
797 shutdown (str->s, 0);
799 shutdown (str->s, 1);
801 CloseHandle ((HANDLE)str->s);
803 WaitForSingleObject (str->ov.hEvent, INFINITE);
805 if (lstr->flags & LSTREAM_FL_READ)
808 CloseHandle (str->ov.hEvent);
813 winsock_was_blocked_p (Lstream *stream)
815 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
816 return str->blocking_p;
820 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
823 Lstream *lstr = Lstream_new (lstream_winsock, mode);
824 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
831 str->user_data = param;
834 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
836 if (lstr->flags & LSTREAM_FL_READ)
838 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
839 winsock_initiate_read (str);
842 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
843 XSETLSTREAM (obj, lstr);
848 make_winsock_input_stream (SOCKET s, LPARAM param)
850 return make_winsock_stream_1 (s, param, "r");
854 make_winsock_output_stream (SOCKET s, LPARAM param)
856 return make_winsock_stream_1 (s, param, "w");
860 get_winsock_stream_waitable (Lstream *lstr)
862 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
863 return str->ov.hEvent;
867 get_winsock_stream_param (Lstream *lstr)
869 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
870 return str->user_data;
874 init_winsock_stream (void)
876 LSTREAM_HAS_METHOD (winsock, reader);
877 LSTREAM_HAS_METHOD (winsock, writer);
878 LSTREAM_HAS_METHOD (winsock, closer);
879 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
881 #endif /* defined (HAVE_SOCKETS) */
883 /************************************************************************/
884 /* Dispatch queue management */
885 /************************************************************************/
888 mswindows_user_event_p (Lisp_Event* sevt)
890 return (sevt->event_type == key_press_event
891 || sevt->event_type == button_press_event
892 || sevt->event_type == button_release_event
893 || sevt->event_type == misc_user_event);
897 * Add an emacs event to the proper dispatch queue
900 mswindows_enqueue_dispatch_event (Lisp_Object event)
902 int user_p = mswindows_user_event_p (XEVENT(event));
903 enqueue_event (event,
904 user_p ? &mswindows_u_dispatch_event_queue :
905 &mswindows_s_dispatch_event_queue,
906 user_p ? &mswindows_u_dispatch_event_queue_tail :
907 &mswindows_s_dispatch_event_queue_tail);
909 /* Avoid blocking on WaitMessage */
910 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
914 * Add a misc-user event to the dispatch queue.
916 * Stuff it into our own dispatch queue, so we have something
917 * to return from next_event callback.
920 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
923 Lisp_Object event = Fmake_event (Qnil, Qnil);
924 Lisp_Event* e = XEVENT (event);
926 e->event_type = misc_user_event;
927 e->channel = channel;
928 e->timestamp = GetTickCount ();
929 e->event.misc.function = function;
930 e->event.misc.object = object;
932 mswindows_enqueue_dispatch_event (event);
936 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
938 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
939 Lisp_Event* event = XEVENT (emacs_event);
941 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
942 event->timestamp = GetMessageTime();
943 event->event_type = magic_event;
944 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
946 mswindows_enqueue_dispatch_event (emacs_event);
950 mswindows_enqueue_process_event (Lisp_Process* p)
952 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
953 Lisp_Event* event = XEVENT (emacs_event);
955 XSETPROCESS (process, p);
957 event->event_type = process_event;
958 event->timestamp = GetTickCount ();
959 event->event.process.process = process;
961 mswindows_enqueue_dispatch_event (emacs_event);
965 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
966 int mods, DWORD when)
968 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
969 msg == WM_RBUTTONDOWN);
971 /* We always use last message time, because mouse button
972 events may get delayed, and XEmacs double click
973 recognition will fail */
975 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
976 Lisp_Event* event = XEVENT (emacs_event);
978 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
979 event->channel = mswindows_find_frame (hwnd);
980 event->timestamp = when;
981 event->event.button.button =
982 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
983 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
984 event->event.button.x = where.x;
985 event->event.button.y = where.y;
986 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
990 event->event_type = button_press_event;
992 /* we need this to make sure the main window regains the focus
993 from control subwindows */
994 if (GetFocus() != hwnd)
997 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1002 event->event_type = button_release_event;
1006 mswindows_enqueue_dispatch_event (emacs_event);
1010 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1012 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1013 Lisp_Event* event = XEVENT(emacs_event);
1015 event->channel = mswindows_find_console(hwnd);
1016 event->timestamp = GetMessageTime();
1017 event->event_type = key_press_event;
1018 event->event.key.keysym = keysym;
1019 event->event.key.modifiers = mods;
1020 mswindows_enqueue_dispatch_event (emacs_event);
1024 * Remove and return the first emacs event on the dispatch queue.
1025 * Give a preference to user events over non-user ones.
1028 mswindows_dequeue_dispatch_event (void)
1033 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1034 !NILP(mswindows_s_dispatch_event_queue));
1036 event = dequeue_event (
1037 NILP(mswindows_u_dispatch_event_queue) ?
1038 &mswindows_s_dispatch_event_queue :
1039 &mswindows_u_dispatch_event_queue,
1040 NILP(mswindows_u_dispatch_event_queue) ?
1041 &mswindows_s_dispatch_event_queue_tail :
1042 &mswindows_u_dispatch_event_queue_tail);
1044 sevt = XEVENT(event);
1045 if (sevt->event_type == key_press_event
1046 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1048 sevt->event.key.modifiers &= ~FAKE_MOD_QUIT;
1049 --mswindows_quit_chars_count;
1056 * Remove and return the first emacs event on the dispatch queue that matches
1057 * the supplied event.
1058 * Timeout event matches if interval_id is equal to that of the given event.
1059 * Keypress event matches if logical AND between modifiers bitmask of the
1060 * event in the queue and that of the given event is non-zero.
1061 * For all other event types, this function aborts.
1065 mswindows_cancel_dispatch_event (Lisp_Event *match)
1068 Lisp_Object previous_event = Qnil;
1069 int user_p = mswindows_user_event_p (match);
1070 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1071 &mswindows_s_dispatch_event_queue;
1072 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1073 &mswindows_s_dispatch_event_queue_tail;
1075 assert (match->event_type == timeout_event
1076 || match->event_type == key_press_event);
1078 EVENT_CHAIN_LOOP (event, *head)
1080 Lisp_Event *e = XEVENT (event);
1081 if ((e->event_type == match->event_type) &&
1082 ((e->event_type == timeout_event) ?
1083 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1084 /* Must be key_press_event */
1085 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1087 if (NILP (previous_event))
1088 dequeue_event (head, tail);
1091 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1092 if (EQ (*tail, event))
1093 *tail = previous_event;
1098 previous_event = event;
1103 #ifndef HAVE_MSG_SELECT
1104 /************************************************************************/
1105 /* Waitable handles manipulation */
1106 /************************************************************************/
1108 find_waitable_handle (HANDLE h)
1111 for (i = 0; i < mswindows_waitable_count; ++i)
1112 if (mswindows_waitable_handles[i] == h)
1119 add_waitable_handle (HANDLE h)
1121 assert (find_waitable_handle (h) < 0);
1122 if (mswindows_waitable_count == MAX_WAITABLE)
1125 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1130 remove_waitable_handle (HANDLE h)
1132 int ix = find_waitable_handle (h);
1136 mswindows_waitable_handles [ix] =
1137 mswindows_waitable_handles [--mswindows_waitable_count];
1139 #endif /* HAVE_MSG_SELECT */
1142 /************************************************************************/
1144 /************************************************************************/
1147 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1148 Lisp_Object u_n_u_s_e_d)
1150 mswindows_error_caught_in_modal_loop = cons_sig_data;
1155 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1160 ++mswindows_in_modal_loop;
1161 tmp = condition_case_1 (Qt,
1163 mswindows_modal_loop_error_handler, Qnil);
1164 --mswindows_in_modal_loop;
1170 mswindows_unmodalize_signal_maybe (void)
1172 if (!NILP (mswindows_error_caught_in_modal_loop))
1174 /* Got an error while messages were pumped while
1175 in window procedure - have to resignal */
1176 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1177 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1178 mswindows_error_caught_in_modal_loop = Qnil;
1179 Fsignal (sym, data);
1184 * This is an unsafe part of event pump, guarded by
1185 * condition_case. See mswindows_pump_outstanding_events
1188 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1190 /* This function can call lisp */
1191 Lisp_Object event = Fmake_event (Qnil, Qnil);
1192 struct gcpro gcpro1;
1193 int do_redisplay = 0;
1196 while (detect_input_pending ())
1198 Fnext_event (event, Qnil);
1199 Fdispatch_event (event);
1206 Fdeallocate_event (event);
1209 /* Qt becomes return value of mswindows_pump_outstanding_events
1215 * This function pumps emacs events, while available, by using
1216 * next_message/dispatch_message loop. Errors are trapped around
1217 * the loop so the function always returns.
1219 * Windows message queue is not looked into during the call,
1220 * neither are waitable handles checked. The function pumps
1221 * thus only dispatch events already queued, as well as those
1222 * resulted in dispatching thereof. This is done by setting
1223 * module local variable mswindows_in_modal_loop to nonzero.
1225 * Return value is Qt if no errors was trapped, or Qunbound if
1226 * there was an error.
1228 * In case of error, a cons representing the error, in the
1229 * form (SIGNAL . DATA), is stored in the module local variable
1230 * mswindows_error_caught_in_modal_loop. This error is signaled
1231 * again when DispatchMessage returns. Thus, Windows internal
1232 * modal loops are protected against throws, which are proven
1233 * to corrupt internal Windows structures.
1235 * In case of success, mswindows_error_caught_in_modal_loop is
1238 * If the value of mswindows_error_caught_in_modal_loop is not
1239 * nil already upon entry, the function just returns non-nil.
1240 * This situation means that a new event has been queued while
1241 * in cancel mode. The event will be dequeued on the next regular
1242 * call of next-event; the pump is off since error is caught.
1243 * The caller must *unconditionally* cancel modal loop if the
1244 * value returned by this function is nil. Otherwise, everything
1245 * will become frozen until the modal loop exits under normal
1246 * condition (scrollbar drag is released, menu closed etc.)
1249 mswindows_pump_outstanding_events (void)
1251 /* This function can call lisp */
1253 Lisp_Object result = Qt;
1254 struct gcpro gcpro1;
1257 if (NILP(mswindows_error_caught_in_modal_loop))
1258 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1264 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1265 * QUITP, and are interesting in keyboard messages only.
1268 mswindows_drain_windows_queue (void)
1272 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1273 assert (!mswindows_in_modal_loop);
1275 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1277 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1279 if (mswindows_is_dialog_msg (&msg))
1281 mswindows_unmodalize_signal_maybe ();
1285 /* We have to translate messages that are not sent to an XEmacs
1286 frame. This is so that key presses work ok in things like
1287 edit fields. However, we *musn't* translate message for XEmacs
1288 frames as this is handled in the wnd proc.
1289 We also have to avoid generating paint magic events for windows
1290 that aren't XEmacs frames */
1291 /* GetClassName will truncate a longer class name. By adding one
1292 extra character, we are forcing textual comparison to fail
1293 if the name is longer than XEMACS_CLASS */
1295 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1296 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1298 /* Not an XEmacs frame */
1299 TranslateMessage (&msg);
1301 else if (msg.message == WM_PAINT)
1303 struct mswindows_frame* msframe;
1305 /* hdc will be NULL unless this is a subwindow - in which case we
1306 shouldn't have received a paint message for it here. */
1307 assert (msg.wParam == 0);
1309 /* Queue a magic event for handling when safe */
1311 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1312 if (!msframe->paint_pending)
1314 msframe->paint_pending = 1;
1315 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1317 /* Don't dispatch. WM_PAINT is always the last message in the
1318 queue so it's OK to just return. */
1321 DispatchMessage (&msg);
1322 mswindows_unmodalize_signal_maybe ();
1327 * This is a special flavor of the mswindows_need_event function,
1328 * used while in event pump. Actually, there is only kind of events
1329 * allowed while in event pump: a timer. An attempt to fetch any
1330 * other event leads to a deadlock, as there's no source of user input
1331 * ('cause event pump mirrors windows modal loop, which is a sole
1332 * owner of thread message queue).
1334 * To detect this, we use a counter of active timers, and allow
1335 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1336 * which will never come when there are no pending timers, which leads
1337 * to deadlock, we simply signal an error.
1340 mswindows_need_event_in_modal_loop (int badly_p)
1344 /* Check if already have one */
1345 if (!NILP (mswindows_u_dispatch_event_queue)
1346 || !NILP (mswindows_s_dispatch_event_queue))
1349 /* No event is ok */
1353 /* We do not check the _u_ queue, because timers go to _s_ */
1354 while (NILP (mswindows_s_dispatch_event_queue))
1356 /* We'll deadlock if go waiting */
1357 if (mswindows_pending_timers_count == 0)
1358 error ("Deadlock due to an attempt to call next-event in a wrong context");
1360 /* Fetch and dispatch any pending timers */
1361 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1362 DispatchMessage (&msg);
1367 * This drains the event queue and fills up two internal queues until
1368 * an event of a type specified by USER_P is retrieved.
1371 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1374 mswindows_need_event (int badly_p)
1378 if (mswindows_in_modal_loop)
1380 mswindows_need_event_in_modal_loop (badly_p);
1384 while (NILP (mswindows_u_dispatch_event_queue)
1385 && NILP (mswindows_s_dispatch_event_queue))
1387 #ifdef HAVE_MSG_SELECT
1389 SELECT_TYPE temp_mask = input_wait_mask;
1390 EMACS_TIME sometime;
1391 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1394 pointer_to_this = 0;
1397 EMACS_SET_SECS_USECS (sometime, 0, 0);
1398 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1399 pointer_to_this = &select_time_to_block;
1402 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1407 return; /* timeout */
1409 else if (active > 0)
1411 if (FD_ISSET (windows_fd, &temp_mask))
1413 mswindows_drain_windows_queue ();
1418 /* Look for a TTY event */
1419 for (i = 0; i < MAXDESC-1; i++)
1421 /* To avoid race conditions (among other things, an infinite
1422 loop when called from Fdiscard_input()), we must return
1423 user events ahead of process events. */
1424 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1426 struct console *c = tty_find_console_from_fd (i);
1427 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1428 Lisp_Event* event = XEVENT (emacs_event);
1431 if (read_event_from_tty_or_stream_desc (event, c, i))
1433 mswindows_enqueue_dispatch_event (emacs_event);
1439 /* Look for a process event */
1440 for (i = 0; i < MAXDESC-1; i++)
1442 if (FD_ISSET (i, &temp_mask))
1444 if (FD_ISSET (i, &process_only_mask))
1447 get_process_from_usid (FD_TO_USID(i));
1449 mswindows_enqueue_process_event (p);
1453 /* We might get here when a fake event came
1454 through a signal. Return a dummy event, so
1455 that a cycle of the command loop will
1457 drain_signal_event_pipe ();
1458 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1464 else if (active==-1)
1468 /* something bad happened */
1477 /* Now try getting a message or process event */
1478 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1479 mswindows_waitable_handles,
1480 FALSE, badly_p ? INFINITE : 0,
1483 /* This will assert if handle being waited for becomes abandoned.
1484 Not the case currently tho */
1485 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1486 (active >= WAIT_OBJECT_0 &&
1487 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1489 if (active == WAIT_TIMEOUT)
1491 /* No luck trying - just return what we've already got */
1494 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1496 /* Got your message, thanks */
1497 mswindows_drain_windows_queue ();
1501 int ix = active - WAIT_OBJECT_0;
1502 /* First, try to find which process' output has signaled */
1504 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1507 /* Found a signaled process input handle */
1508 mswindows_enqueue_process_event (p);
1512 /* None. This means that the process handle itself has signaled.
1513 Remove the handle from the wait vector, and make status_notify
1514 note the exited process */
1515 mswindows_waitable_handles [ix] =
1516 mswindows_waitable_handles [--mswindows_waitable_count];
1517 kick_status_notify ();
1518 /* We need to return a process event here so that
1519 (1) accept-process-output will return when called on this
1520 process, and (2) status notifications will happen in
1521 accept-process-output, sleep-for, and sit-for. */
1522 /* #### horrible kludge till my real process fixes go in.
1524 if (!NILP (Vprocess_list))
1526 Lisp_Object vaffanculo = XCAR (Vprocess_list);
1527 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1529 else /* trash me soon. */
1530 /* Have to return something: there may be no accompanying
1532 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1539 /************************************************************************/
1540 /* Event generators */
1541 /************************************************************************/
1544 * Callback procedure for synchronous timer messages
1546 static void CALLBACK
1547 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1549 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1550 Lisp_Event *event = XEVENT (emacs_event);
1552 if (KillTimer (NULL, id_timer))
1553 --mswindows_pending_timers_count;
1555 event->channel = Qnil;
1556 event->timestamp = dwtime;
1557 event->event_type = timeout_event;
1558 event->event.timeout.interval_id = id_timer;
1559 event->event.timeout.function = Qnil;
1560 event->event.timeout.object = Qnil;
1562 mswindows_enqueue_dispatch_event (emacs_event);
1566 * Callback procedure for dde messages
1568 * We execute a dde Open("file") by simulating a file drop, so dde support
1569 * depends on dnd support.
1571 #ifdef HAVE_DRAGNDROP
1573 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1574 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1575 DWORD dwData1, DWORD dwData2)
1580 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1581 return (HDDEDATA)TRUE;
1582 return (HDDEDATA)FALSE;
1584 case XTYP_WILDCONNECT:
1586 /* We only support one {service,topic} pair */
1587 HSZPAIR pairs[2] = {
1588 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1590 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1591 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1592 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1593 sizeof (pairs), 0L, 0, uFmt, 0));
1595 return (HDDEDATA)NULL;
1598 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1600 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1601 LPBYTE cmd = (LPBYTE) alloca (len+1);
1604 struct gcpro gcpro1, gcpro2;
1605 Lisp_Object l_dndlist = Qnil;
1606 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1607 Lisp_Object frmcons, devcons, concons;
1608 Lisp_Event *event = XEVENT (emacs_event);
1610 DdeGetData (hdata, cmd, len, 0);
1612 DdeFreeDataHandle (hdata);
1614 /* Check syntax & that it's an [Open("foo")] command, which we
1615 * treat like a file drop */
1616 /* #### Ought to be generalised and accept some other commands */
1619 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1620 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1621 return DDE_FNOTPROCESSED;
1622 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1625 if (*cmd!='(' || *(cmd+1)!='\"')
1626 return DDE_FNOTPROCESSED;
1628 while (*end && *end!='\"')
1631 return DDE_FNOTPROCESSED;
1634 return DDE_FNOTPROCESSED;
1638 return DDE_FNOTPROCESSED;
1641 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1642 strcpy (filename, "file:");
1643 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1645 dostounix_filename (cmd);
1646 filename = alloca (strlen (cmd)+6);
1647 strcpy (filename, "file:");
1648 strcat (filename, cmd);
1650 GCPRO2 (emacs_event, l_dndlist);
1651 l_dndlist = make_string (filename, strlen (filename));
1653 /* Find a mswindows frame */
1654 event->channel = Qnil;
1655 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1657 Lisp_Object frame = XCAR (frmcons);
1658 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1659 event->channel = frame;
1661 assert (!NILP (event->channel));
1663 event->timestamp = GetTickCount();
1664 event->event_type = misc_user_event;
1665 event->event.misc.button = 1;
1666 event->event.misc.modifiers = 0;
1667 event->event.misc.x = -1;
1668 event->event.misc.y = -1;
1669 event->event.misc.function = Qdragdrop_drop_dispatch;
1670 event->event.misc.object = Fcons (Qdragdrop_URL,
1671 Fcons (l_dndlist, Qnil));
1672 mswindows_enqueue_dispatch_event (emacs_event);
1674 return (HDDEDATA) DDE_FACK;
1676 DdeFreeDataHandle (hdata);
1677 return (HDDEDATA) DDE_FNOTPROCESSED;
1680 return (HDDEDATA) NULL;
1686 * Helper to do repainting - repaints can happen both from the windows
1687 * procedure and from magic events
1690 mswindows_handle_paint (struct frame *frame)
1692 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1694 /* According to the docs we need to check GetUpdateRect() before
1695 actually doing a WM_PAINT */
1696 if (GetUpdateRect (hwnd, NULL, FALSE))
1698 PAINTSTRUCT paintStruct;
1699 int x, y, width, height;
1701 BeginPaint (hwnd, &paintStruct);
1702 x = paintStruct.rcPaint.left;
1703 y = paintStruct.rcPaint.top;
1704 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1705 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1706 /* Normally we want to ignore expose events when child
1707 windows are unmapped, however once we are in the guts of
1708 WM_PAINT we need to make sure that we don't register
1709 unmaps then because they will not actually occur. */
1710 /* #### commenting out the next line seems to fix some problems
1711 but not all. only andy currently understands this stuff and
1712 he needs to review it more carefully. --ben */
1713 if (!check_for_ignored_expose (frame, x, y, width, height))
1715 hold_ignored_expose_registration = 1;
1716 mswindows_redraw_exposed_area (frame, x, y, width, height);
1717 hold_ignored_expose_registration = 0;
1719 EndPaint (hwnd, &paintStruct);
1724 * Returns 1 if a key is a real modifier or special key, which
1725 * is better handled by DefWindowProc
1728 key_needs_default_processing_p (UINT vkey)
1730 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1731 /* if we let ALT activate the menu like this, then sticky ALT-modified
1732 keystrokes become impossible. */
1733 && !modifier_keys_are_sticky)
1739 /* key-handling code is always ugly. It just ends up working out
1742 #### Most of the sticky-modifier code below is copied from similar
1743 code in event-Xt.c. They should somehow or other be merged.
1745 Here are some pointers:
1747 -- DOWN_MASK indicates which modifiers should be treated as "down"
1748 when the corresponding upstroke happens. It gets reset for
1749 a particular modifier when that modifier goes up, and reset
1750 for all modifiers when a non-modifier key is pressed. Example:
1752 I press Control-A-Shift and then release Control-A-Shift.
1753 I want the Shift key to be sticky but not the Control key.
1755 -- If a modifier key is sticky, I can unstick it by pressing
1756 the modifier key again. */
1758 static WPARAM last_downkey;
1759 static int need_to_add_mask, down_mask;
1761 #define XEMSW_LCONTROL (1<<0)
1762 #define XEMSW_RCONTROL (1<<1)
1763 #define XEMSW_LSHIFT (1<<2)
1764 #define XEMSW_RSHIFT (1<<3)
1765 #define XEMSW_LMENU (1<<4)
1766 #define XEMSW_RMENU (1<<5)
1769 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1770 int downp, int keyp)
1774 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1778 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1779 wParam == VK_RCONTROL ||
1780 wParam == VK_MENU || wParam == VK_LMENU ||
1781 wParam == VK_RMENU ||
1782 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1783 wParam == VK_RSHIFT)))
1784 { /* Not a modifier key */
1785 if (downp && keyp && !last_downkey)
1786 last_downkey = wParam;
1787 /* If I hold press-and-release the Control key and then press
1788 and hold down the right arrow, I want it to auto-repeat
1789 Control-Right. On the other hand, if I do the same but
1790 manually press the Right arrow a bunch of times, I want
1791 to see one Control-Right and then a bunch of Rights.
1792 This means that we need to distinguish between an
1793 auto-repeated key and a key pressed and released a bunch
1795 else if ((downp && !keyp) ||
1796 (downp && keyp && last_downkey &&
1797 (wParam != last_downkey ||
1798 /* the "previous key state" bit indicates autorepeat */
1799 ! (lParam & (1 << 30)))))
1801 need_to_add_mask = 0;
1807 mods = need_to_add_mask;
1809 else /* Modifier key pressed */
1811 /* If a non-modifier key was pressed in the middle of a bunch
1812 of modifiers, then it unsticks all the modifiers that were
1813 previously pressed. We cannot unstick the modifiers until
1814 now because we want to check for auto-repeat of the
1815 non-modifier key. */
1820 need_to_add_mask = 0;
1823 #define FROB(mask) \
1825 if (downp && keyp) \
1827 /* If modifier key is already sticky, \
1828 then unstick it. Note that we do \
1829 not test down_mask to deal with the \
1830 unlikely but possible case that the \
1831 modifier key auto-repeats. */ \
1832 if (need_to_add_mask & mask) \
1834 need_to_add_mask &= ~mask; \
1835 down_mask &= ~mask; \
1838 down_mask |= mask; \
1842 if (down_mask & mask) \
1844 down_mask &= ~mask; \
1845 need_to_add_mask |= mask; \
1850 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1851 || wParam == VK_RCONTROL)
1852 FROB (XEMSW_RCONTROL);
1853 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1854 || wParam == VK_LCONTROL)
1855 FROB (XEMSW_LCONTROL);
1857 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1858 || wParam == VK_RSHIFT)
1859 FROB (XEMSW_RSHIFT);
1860 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1861 || wParam == VK_LSHIFT)
1862 FROB (XEMSW_LSHIFT);
1864 if ((wParam == VK_MENU && (lParam & 0x1000000))
1865 || wParam == VK_RMENU)
1867 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1868 || wParam == VK_LMENU)
1877 GetKeyboardState (keymap);
1879 if (mods & XEMSW_LCONTROL)
1881 keymap [VK_CONTROL] |= 0x80;
1882 keymap [VK_LCONTROL] |= 0x80;
1884 if (mods & XEMSW_RCONTROL)
1886 keymap [VK_CONTROL] |= 0x80;
1887 keymap [VK_RCONTROL] |= 0x80;
1890 if (mods & XEMSW_LSHIFT)
1892 keymap [VK_SHIFT] |= 0x80;
1893 keymap [VK_LSHIFT] |= 0x80;
1895 if (mods & XEMSW_RSHIFT)
1897 keymap [VK_SHIFT] |= 0x80;
1898 keymap [VK_RSHIFT] |= 0x80;
1901 if (mods & XEMSW_LMENU)
1903 keymap [VK_MENU] |= 0x80;
1904 keymap [VK_LMENU] |= 0x80;
1906 if (mods & XEMSW_RMENU)
1908 keymap [VK_MENU] |= 0x80;
1909 keymap [VK_RMENU] |= 0x80;
1912 SetKeyboardState (keymap);
1920 clear_sticky_modifiers (void)
1922 need_to_add_mask = 0;
1932 output_modifier_keyboard_state (void)
1936 GetKeyboardState (keymap);
1938 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1939 keymap[VK_MENU] & 0x80 ? 1 : 0,
1940 keymap[VK_MENU] & 0x1 ? 1 : 0,
1941 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1942 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1943 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1944 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1945 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1946 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1947 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1948 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1949 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1950 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1951 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1952 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1953 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1954 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1955 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1956 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1957 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1958 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
1963 /* try to debug the stuck-alt-key problem.
1965 #### this happens only inconsistently, and may only happen when using
1966 StickyKeys in the Win2000 accessibility section of the control panel,
1967 which is extremely broken for other reasons. */
1970 output_alt_keyboard_state (void)
1974 // SHORT asyncstate[3];
1976 GetKeyboardState (keymap);
1977 keystate[0] = GetKeyState (VK_MENU);
1978 keystate[1] = GetKeyState (VK_LMENU);
1979 keystate[2] = GetKeyState (VK_RMENU);
1980 /* Doing this interferes with key processing. */
1981 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
1982 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
1983 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
1985 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1986 keymap[VK_MENU] & 0x80 ? 1 : 0,
1987 keymap[VK_MENU] & 0x1 ? 1 : 0,
1988 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1989 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1990 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1991 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1992 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1993 keystate[0] & 0x8000 ? 1 : 0,
1994 keystate[0] & 0x1 ? 1 : 0,
1995 keystate[1] & 0x8000 ? 1 : 0,
1996 keystate[1] & 0x1 ? 1 : 0,
1997 keystate[2] & 0x8000 ? 1 : 0,
1998 keystate[2] & 0x1 ? 1 : 0);
1999 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2000 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2001 /* asyncstate[0] & 0x1 ? 1 : 0, */
2002 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2003 /* asyncstate[1] & 0x1 ? 1 : 0, */
2004 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2005 /* asyncstate[2] & 0x1 ? 1 : 0); */
2008 #endif /* DEBUG_XEMACS */
2012 * The windows procedure for the window class XEMACS_CLASS
2015 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2017 /* Note: Remember to initialize emacs_event and event before use.
2018 This code calls code that can GC. You must GCPRO before calling such code. */
2019 Lisp_Object emacs_event = Qnil;
2020 Lisp_Object fobj = Qnil;
2023 struct frame *frame;
2024 struct mswindows_frame* msframe;
2026 /* Not perfect but avoids crashes. There is potential for wierd
2031 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2034 case WM_DESTROYCLIPBOARD:
2035 /* We own the clipboard and someone else wants it. Delete our
2036 cached copy of the clipboard contents so we'll ask for it from
2037 Windows again when someone does a paste, and destroy any memory
2038 objects we hold on the clipboard that are not in the list of types
2039 that Windows will delete itself. */
2040 mswindows_destroy_selection (QCLIPBOARD);
2041 handle_selection_clear (QCLIPBOARD);
2045 /* Erase background only during non-dynamic sizing */
2046 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2047 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2052 fobj = mswindows_find_frame (hwnd);
2053 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2059 /* See Win95 comment under WM_KEYDOWN */
2062 int should_set_keymap = 0;
2065 if (debug_mswindows_events)
2067 stderr_out ("%s wparam=%d lparam=%d\n",
2068 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
2069 wParam, (int)lParam);
2070 output_alt_keyboard_state ();
2072 #endif /* DEBUG_XEMACS */
2074 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2075 if (wParam == VK_CONTROL)
2077 GetKeyboardState (keymap);
2078 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2079 should_set_keymap = 1;
2081 else if (wParam == VK_MENU)
2083 GetKeyboardState (keymap);
2084 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2085 should_set_keymap = 1;
2088 if (should_set_keymap)
2089 // && (message_ != WM_SYSKEYUP
2090 // || NILP (Vmenu_accelerator_enabled)))
2091 SetKeyboardState (keymap);
2095 if (key_needs_default_processing_p (wParam))
2103 /* In some locales the right-hand Alt key is labelled AltGr. This key
2104 * should produce alternative characters when combined with another key.
2105 * eg on a German keyboard pressing AltGr+q should produce '@'.
2106 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2107 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2108 * it translates as if AltGr were down.
2109 * We get round this by removing all modifiers from the keymap before
2110 * calling TranslateMessage() unless AltGr is *really* down. */
2112 BYTE keymap_trans[256];
2113 BYTE keymap_orig[256];
2114 BYTE keymap_sticky[256];
2115 int has_AltGr = mswindows_current_layout_has_AltGr ();
2117 int extendedp = lParam & 0x1000000;
2122 if (debug_mswindows_events)
2124 stderr_out ("%s wparam=%d lparam=%d\n",
2125 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
2126 wParam, (int)lParam);
2127 output_alt_keyboard_state ();
2129 #endif /* DEBUG_XEMACS */
2131 GetKeyboardState (keymap_orig);
2132 frame = XFRAME (mswindows_find_frame (hwnd));
2133 if ((sticky_changed =
2134 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2136 GetKeyboardState (keymap_sticky);
2137 if (keymap_sticky[VK_MENU] & 0x80)
2139 message_ = WM_SYSKEYDOWN;
2140 /* We have to set the "context bit" so that the
2141 TranslateMessage() call below that generates the
2142 SYSCHAR message does its thing; see the documentation
2148 memcpy (keymap_sticky, keymap_orig, 256);
2150 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2152 /* Handle non-printables */
2153 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2156 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2158 SetKeyboardState (keymap_orig);
2160 else /* Normal keys & modifiers */
2163 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2164 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2166 int potential_accelerator = 0;
2167 int got_accelerator = 0;
2170 msg.message = message_;
2171 msg.wParam = wParam;
2172 msg.lParam = lParam;
2173 msg.time = GetMessageTime();
2176 /* GetKeyboardState() does not work as documented on Win95. We have
2177 * to loosely track Left and Right modifiers on behalf of the OS,
2178 * without screwing up Windows NT which tracks them properly. */
2179 if (wParam == VK_CONTROL)
2181 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2182 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2184 else if (wParam == VK_MENU)
2186 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2187 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2190 if (!NILP (Vmenu_accelerator_enabled) &&
2191 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2192 potential_accelerator = 1;
2194 /* Remove shift modifier from an ascii character */
2195 mods &= ~XEMACS_MOD_SHIFT;
2197 memcpy (keymap_trans, keymap_sticky, 256);
2199 /* Clear control and alt modifiers unless AltGr is pressed */
2200 keymap_trans[VK_RCONTROL] = 0;
2201 keymap_trans[VK_LMENU] = 0;
2202 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2203 || !(keymap_trans[VK_RMENU] & 0x80))
2205 keymap_trans[VK_LCONTROL] = 0;
2206 keymap_trans[VK_CONTROL] = 0;
2207 keymap_trans[VK_RMENU] = 0;
2208 keymap_trans[VK_MENU] = 0;
2210 SetKeyboardState (keymap_trans);
2212 /* Maybe generate some WM_[SYS]CHARs in the queue */
2213 TranslateMessage (&msg);
2215 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2216 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2220 WPARAM ch = tranmsg.wParam;
2222 /* If a quit char with no modifiers other than control and
2223 shift, then mark it with a fake modifier, which is removed
2224 upon dequeueing the event */
2225 /* #### This might also not withstand localization, if
2226 quit character is not a latin-1 symbol */
2227 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2228 && quit_ch + 'a' - 1 == ch)
2229 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2231 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2234 mods1 |= FAKE_MOD_QUIT;
2235 ++mswindows_quit_chars_count;
2237 else if (potential_accelerator && !got_accelerator &&
2238 mswindows_char_is_accelerator (frame, ch))
2240 got_accelerator = 1;
2243 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
2246 /* This generates WM_SYSCHAR messages, which are interpreted
2247 by DefWindowProc as the menu selections. */
2248 if (got_accelerator)
2250 SetKeyboardState (keymap_sticky);
2251 TranslateMessage (&msg);
2252 SetKeyboardState (keymap_orig);
2256 SetKeyboardState (keymap_orig);
2260 if (key_needs_default_processing_p (wParam))
2265 case WM_MBUTTONDOWN:
2267 /* Real middle mouse button has nothing to do with emulated one:
2268 if one wants to exercise fingers playing chords on the mouse,
2269 he is allowed to do that! */
2270 mswindows_enqueue_mouse_button_event (hwnd, message_,
2271 MAKEPOINTS (lParam),
2272 wParam &~ MK_MBUTTON,
2277 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2278 msframe->last_click_time = GetMessageTime();
2280 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2281 msframe->button2_need_lbutton = 0;
2282 if (msframe->ignore_next_lbutton_up)
2284 msframe->ignore_next_lbutton_up = 0;
2286 else if (msframe->button2_is_down)
2288 msframe->button2_is_down = 0;
2289 msframe->ignore_next_rbutton_up = 1;
2290 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2291 MAKEPOINTS (lParam),
2293 &~ (MK_LBUTTON | MK_MBUTTON
2299 if (msframe->button2_need_rbutton)
2301 msframe->button2_need_rbutton = 0;
2302 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2303 MAKEPOINTS (lParam),
2304 wParam &~ MK_LBUTTON,
2307 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2308 MAKEPOINTS (lParam),
2309 wParam &~ MK_LBUTTON,
2315 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2316 msframe->last_click_time = GetMessageTime();
2318 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2319 msframe->button2_need_rbutton = 0;
2320 if (msframe->ignore_next_rbutton_up)
2322 msframe->ignore_next_rbutton_up = 0;
2324 else if (msframe->button2_is_down)
2326 msframe->button2_is_down = 0;
2327 msframe->ignore_next_lbutton_up = 1;
2328 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2329 MAKEPOINTS (lParam),
2331 &~ (MK_LBUTTON | MK_MBUTTON
2337 if (msframe->button2_need_lbutton)
2339 msframe->button2_need_lbutton = 0;
2340 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2341 MAKEPOINTS (lParam),
2342 wParam &~ MK_RBUTTON,
2345 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2346 MAKEPOINTS (lParam),
2347 wParam &~ MK_RBUTTON,
2352 case WM_LBUTTONDOWN:
2353 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2355 if (msframe->button2_need_lbutton)
2357 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2358 msframe->button2_need_lbutton = 0;
2359 msframe->button2_need_rbutton = 0;
2360 if (mswindows_button2_near_enough (msframe->last_click_point,
2361 MAKEPOINTS (lParam)))
2363 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2364 MAKEPOINTS (lParam),
2366 &~ (MK_LBUTTON | MK_MBUTTON
2369 msframe->button2_is_down = 1;
2373 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2374 msframe->last_click_point,
2375 msframe->last_click_mods
2377 msframe->last_click_time);
2378 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2379 MAKEPOINTS (lParam),
2380 wParam &~ MK_LBUTTON,
2386 mswindows_set_chord_timer (hwnd);
2387 msframe->button2_need_rbutton = 1;
2388 msframe->last_click_point = MAKEPOINTS (lParam);
2389 msframe->last_click_mods = wParam;
2391 msframe->last_click_time = GetMessageTime();
2394 case WM_RBUTTONDOWN:
2395 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2397 if (msframe->button2_need_rbutton)
2399 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2400 msframe->button2_need_lbutton = 0;
2401 msframe->button2_need_rbutton = 0;
2402 if (mswindows_button2_near_enough (msframe->last_click_point,
2403 MAKEPOINTS (lParam)))
2405 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2406 MAKEPOINTS (lParam),
2408 &~ (MK_LBUTTON | MK_MBUTTON
2411 msframe->button2_is_down = 1;
2415 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2416 msframe->last_click_point,
2417 msframe->last_click_mods
2419 msframe->last_click_time);
2420 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2421 MAKEPOINTS (lParam),
2422 wParam &~ MK_RBUTTON,
2428 mswindows_set_chord_timer (hwnd);
2429 msframe->button2_need_lbutton = 1;
2430 msframe->last_click_point = MAKEPOINTS (lParam);
2431 msframe->last_click_mods = wParam;
2433 msframe->last_click_time = GetMessageTime();
2437 if (wParam == BUTTON_2_TIMER_ID)
2439 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2440 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2442 if (msframe->button2_need_lbutton)
2444 msframe->button2_need_lbutton = 0;
2445 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2446 msframe->last_click_point,
2447 msframe->last_click_mods
2449 msframe->last_click_time);
2451 else if (msframe->button2_need_rbutton)
2453 msframe->button2_need_rbutton = 0;
2454 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2455 msframe->last_click_point,
2456 msframe->last_click_mods
2458 msframe->last_click_time);
2462 assert ("Spurious timer fired" == 0);
2466 /* Optimization: don't report mouse movement while size is changing */
2467 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2468 if (!msframe->sizing)
2470 /* When waiting for the second mouse button to finish
2471 button2 emulation, and have moved too far, just pretend
2472 as if timer has expired. This improves drag-select feedback */
2473 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2474 && !mswindows_button2_near_enough (msframe->last_click_point,
2475 MAKEPOINTS (lParam)))
2477 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2478 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2481 emacs_event = Fmake_event (Qnil, Qnil);
2482 event = XEVENT(emacs_event);
2484 event->channel = mswindows_find_frame(hwnd);
2485 event->timestamp = GetMessageTime();
2486 event->event_type = pointer_motion_event;
2487 event->event.motion.x = MAKEPOINTS(lParam).x;
2488 event->event.motion.y = MAKEPOINTS(lParam).y;
2489 event->event.motion.modifiers =
2490 mswindows_modifier_state (NULL, wParam, 0);
2492 mswindows_enqueue_dispatch_event (emacs_event);
2498 /* Queue a `cancel-mode-internal' misc user event, so mouse
2499 selection would be canceled if any */
2500 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2501 Qcancel_mode_internal, Qnil);
2506 LPNMHDR nmhdr = (LPNMHDR)lParam;
2508 if (nmhdr->code == TTN_NEEDTEXT)
2510 #ifdef HAVE_TOOLBARS
2511 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2514 /* find out which toolbar */
2515 frame = XFRAME (mswindows_find_frame (hwnd));
2516 btext = mswindows_get_toolbar_button_text ( frame,
2519 tttext->lpszText = NULL;
2520 tttext->hinst = NULL;
2524 /* I think this is safe since the text will only go away
2525 when the toolbar does...*/
2526 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2530 /* handle tree view callbacks */
2531 else if (nmhdr->code == TVN_SELCHANGED)
2533 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2534 frame = XFRAME (mswindows_find_frame (hwnd));
2535 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2537 /* handle tab control callbacks */
2538 else if (nmhdr->code == TCN_SELCHANGE)
2541 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2542 frame = XFRAME (mswindows_find_frame (hwnd));
2544 item.mask = TCIF_PARAM;
2545 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2548 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2554 /* hdc will be NULL unless this is a subwindow - in which case we
2555 shouldn't have received a paint message for it here. */
2556 assert (wParam == 0);
2558 /* Can't queue a magic event because windows goes modal and sends paint
2559 messages directly to the windows procedure when doing solid drags
2560 and the message queue doesn't get processed. */
2561 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2565 /* We only care about this message if our size has really changed */
2566 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2571 fobj = mswindows_find_frame (hwnd);
2572 frame = XFRAME (fobj);
2573 msframe = FRAME_MSWINDOWS_DATA (frame);
2575 /* We cannot handle frame map and unmap hooks right in
2576 this routine, because these may throw. We queue
2577 magic events to run these hooks instead - kkm */
2579 if (wParam==SIZE_MINIMIZED)
2582 FRAME_VISIBLE_P (frame) = 0;
2583 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2587 GetClientRect(hwnd, &rect);
2588 FRAME_PIXWIDTH(frame) = rect.right;
2589 FRAME_PIXHEIGHT(frame) = rect.bottom;
2591 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2592 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2593 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2595 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2596 change_frame_size (frame, rows, columns, 1);
2598 /* If we are inside frame creation, we have to apply geometric
2600 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2602 /* Yes, we have to size again */
2603 mswindows_size_frame_internal ( frame,
2604 FRAME_MSWINDOWS_TARGET_RECT
2606 /* Reset so we do not get here again. The SetWindowPos call in
2607 * mswindows_size_frame_internal can cause recursion here. */
2608 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2610 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2611 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2616 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2617 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2618 FRAME_VISIBLE_P (frame) = 1;
2620 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2627 case WM_DISPLAYCHANGE:
2630 DWORD message_tick = GetMessageTime ();
2632 fobj = mswindows_find_frame (hwnd);
2633 frame = XFRAME (fobj);
2634 d = XDEVICE (FRAME_DEVICE (frame));
2636 /* Do this only once per message. XEmacs can receive this message
2637 through as many frames as it currently has open. Message time
2638 will be the same for all these messages. Despite extreme
2639 efficiency, the code below has about one in 4 billion
2640 probability that the HDC is not recreated, provided that
2641 XEmacs is running sufficiently longer than 52 days. */
2642 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2644 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2645 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2646 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2651 /* Misc magic events which only require that the frame be identified */
2654 mswindows_enqueue_magic_event (hwnd, message_);
2657 case WM_WINDOWPOSCHANGING:
2659 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2660 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2661 GetWindowPlacement(hwnd, &wpl);
2663 /* Only interested if size is changing and we're not being iconified */
2664 if (wpl.showCmd != SW_SHOWMINIMIZED
2665 && wpl.showCmd != SW_SHOWMAXIMIZED
2666 && !(wp->flags & SWP_NOSIZE))
2668 RECT ncsize = { 0, 0, 0, 0 };
2669 int pixwidth, pixheight;
2670 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2671 GetMenu(hwnd) != NULL,
2672 GetWindowLong (hwnd, GWL_EXSTYLE));
2674 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2675 wp->cx - (ncsize.right - ncsize.left),
2676 wp->cy - (ncsize.bottom - ncsize.top),
2677 &pixwidth, &pixheight);
2679 /* Convert client sizes to window sizes */
2680 pixwidth += (ncsize.right - ncsize.left);
2681 pixheight += (ncsize.bottom - ncsize.top);
2683 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2685 /* Adjust so that the bottom or right doesn't move if it's
2686 * the top or left that's being changed */
2688 GetWindowRect (hwnd, &rect);
2690 if (rect.left != wp->x)
2691 wp->x += wp->cx - pixwidth;
2692 if (rect.top != wp->y)
2693 wp->y += wp->cy - pixheight;
2699 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2700 window position if the user tries to track window too small */
2704 case WM_ENTERSIZEMOVE:
2705 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2706 msframe->sizing = 1;
2709 case WM_EXITSIZEMOVE:
2710 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2711 msframe->sizing = 0;
2712 /* Queue noop event */
2713 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2716 #ifdef HAVE_SCROLLBARS
2720 /* Direction of scroll is determined by scrollbar instance. */
2721 int code = (int) LOWORD(wParam);
2722 int pos = (short int) HIWORD(wParam);
2723 HWND hwndScrollBar = (HWND) lParam;
2724 struct gcpro gcpro1, gcpro2;
2726 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2727 GCPRO2 (emacs_event, fobj);
2728 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2730 /* Error during event pumping - cancel scroll */
2731 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2739 int keys = LOWORD (wParam); /* Modifier key flags */
2740 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2741 struct gcpro gcpro1, gcpro2;
2743 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2745 GCPRO2 (emacs_event, fobj);
2746 mswindows_pump_outstanding_events (); /* Can GC */
2755 #ifdef HAVE_MENUBARS
2757 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2759 XFRAME (mswindows_find_frame (hwnd)))))
2760 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2763 case WM_INITMENUPOPUP:
2764 if (!HIWORD(lParam))
2766 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2768 XFRAME (mswindows_find_frame (hwnd)))))
2769 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2773 #endif /* HAVE_MENUBARS */
2777 WORD id = LOWORD (wParam);
2778 WORD nid = HIWORD (wParam);
2779 HWND cid = (HWND)lParam;
2780 frame = XFRAME (mswindows_find_frame (hwnd));
2782 #ifdef HAVE_TOOLBARS
2783 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2786 /* widgets in a buffer only eval a callback for suitable events.*/
2791 case CBN_EDITCHANGE:
2793 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2796 /* menubars always must come last since the hashtables do not
2798 #ifdef HAVE_MENUBARS
2799 if (!NILP (mswindows_handle_wm_command (frame, id)))
2803 return DefWindowProc (hwnd, message_, wParam, lParam);
2804 /* Bite me - a spurious command. This used to not be able to
2805 happen but with the introduction of widgets its now
2810 case WM_CTLCOLORBTN:
2811 case WM_CTLCOLORLISTBOX:
2812 case WM_CTLCOLOREDIT:
2813 case WM_CTLCOLORSTATIC:
2814 case WM_CTLCOLORSCROLLBAR:
2816 /* if we get an opportunity to paint a widget then do so if
2817 there is an appropriate face */
2818 HWND crtlwnd = (HWND)lParam;
2819 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2822 Lisp_Object image_instance;
2823 VOID_TO_LISP (image_instance, ii);
2824 if (IMAGE_INSTANCEP (image_instance)
2826 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2828 /* set colors for the buttons */
2829 HDC hdc = (HDC)wParam;
2830 if (last_widget_brushed != ii)
2833 DeleteObject (widget_brush);
2834 widget_brush = CreateSolidBrush
2835 (COLOR_INSTANCE_MSWINDOWS_COLOR
2838 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2839 XIMAGE_INSTANCE_FRAME (image_instance)))));
2841 last_widget_brushed = ii;
2844 COLOR_INSTANCE_MSWINDOWS_COLOR
2847 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2848 XIMAGE_INSTANCE_FRAME (image_instance)))));
2849 SetBkMode (hdc, OPAQUE);
2852 COLOR_INSTANCE_MSWINDOWS_COLOR
2855 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2856 XIMAGE_INSTANCE_FRAME (image_instance)))));
2857 return (LRESULT)widget_brush;
2863 #ifdef HAVE_DRAGNDROP
2864 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2866 UINT filecount, i, len;
2871 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2872 struct gcpro gcpro1, gcpro2, gcpro3;
2874 emacs_event = Fmake_event (Qnil, Qnil);
2875 event = XEVENT(emacs_event);
2877 GCPRO3 (emacs_event, l_dndlist, l_item);
2879 if (!DragQueryPoint ((HDROP) wParam, &point))
2880 point.x = point.y = -1; /* outside client area */
2882 event->event_type = misc_user_event;
2883 event->channel = mswindows_find_frame(hwnd);
2884 event->timestamp = GetMessageTime();
2885 event->event.misc.button = 1; /* #### Should try harder */
2886 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2888 event->event.misc.x = point.x;
2889 event->event.misc.y = point.y;
2890 event->event.misc.function = Qdragdrop_drop_dispatch;
2892 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2893 for (i=0; i<filecount; i++)
2895 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2896 /* The URLs that we make here aren't correct according to section
2897 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2898 * because they may contain reserved characters. But that's OK -
2899 * they just need to be good enough to keep dragdrop.el happy. */
2900 fname = (char *)xmalloc (len+1);
2901 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2903 /* May be a shell link aka "shortcut" - replace fname if so */
2904 #if !(defined(CYGWIN) || defined(MINGW))
2905 /* cygwin doesn't define this COM stuff */
2906 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2910 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2911 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2915 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2919 WIN32_FIND_DATA wfd;
2920 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2922 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2924 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2925 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2930 len = strlen (fname);
2933 ppf->lpVtbl->Release (ppf);
2936 psl->lpVtbl->Release (psl);
2942 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2943 strcpy (filename, "file:");
2944 cygwin32_win32_to_posix_path_list (fname, filename+5);
2946 filename = (char *)xmalloc (len+6);
2947 strcat (strcpy (filename, "file:"), fname);
2948 dostounix_filename (filename+5);
2951 l_item = make_string (filename, strlen (filename));
2952 l_dndlist = Fcons (l_item, l_dndlist);
2955 DragFinish ((HDROP) wParam);
2957 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2958 mswindows_enqueue_dispatch_event (emacs_event);
2966 return DefWindowProc (hwnd, message_, wParam, lParam);
2972 /************************************************************************/
2973 /* keyboard, mouse & other helpers for the windows procedure */
2974 /************************************************************************/
2976 mswindows_set_chord_timer (HWND hwnd)
2980 /* We get one third half system double click threshold */
2981 if (mswindows_mouse_button_tolerance <= 0)
2982 interval = GetDoubleClickTime () / 3;
2984 interval = mswindows_mouse_button_tolerance;
2986 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2990 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2993 if (mswindows_mouse_button_max_skew_x <= 0)
2994 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2996 dx = mswindows_mouse_button_max_skew_x;
2998 if (mswindows_mouse_button_max_skew_y <= 0)
2999 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3001 dy = mswindows_mouse_button_max_skew_y;
3003 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3007 mswindows_current_layout_has_AltGr (void)
3009 /* This simple caching mechanism saves 10% of CPU
3010 time when a key typed at autorepeat rate of 30 cps! */
3011 static HKL last_hkl = 0;
3012 static int last_hkl_has_AltGr;
3013 HKL current_hkl = (HKL) -1;
3015 if (xGetKeyboardLayout) /* not in NT 3.5 */
3016 current_hkl = xGetKeyboardLayout (0);
3017 if (current_hkl != last_hkl)
3020 last_hkl_has_AltGr = 0;
3021 /* In this loop, we query whether a character requires
3022 AltGr to be down to generate it. If at least such one
3023 found, this means that the layout does regard AltGr */
3024 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3025 if (HIBYTE (VkKeyScan (c)) == 6)
3026 last_hkl_has_AltGr = 1;
3027 last_hkl = current_hkl;
3029 return last_hkl_has_AltGr;
3033 /* Returns the state of the modifier keys in the format expected by the
3034 * Lisp_Event key_data, button_data and motion_data modifiers member */
3036 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3039 int keys_is_real = 0;
3042 if (fwKeys == (DWORD) -1)
3043 fwKeys = mswindows_last_mouse_button_state;
3047 mswindows_last_mouse_button_state = fwKeys;
3053 GetKeyboardState (keymap);
3054 has_AltGr = mswindows_current_layout_has_AltGr ();
3057 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3059 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3061 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3062 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3066 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3067 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3070 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3071 ? XEMACS_MOD_SHIFT : 0;
3072 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3073 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3074 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3080 * Translate a mswindows virtual key to a keysym.
3081 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3082 * or whose ASCII codes (like space) xemacs doesn't like.
3084 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3087 if (extendedp) /* Keys not present on a 82 key keyboard */
3089 switch (mswindows_key)
3091 case VK_CANCEL: return KEYSYM ("pause");
3092 case VK_RETURN: return KEYSYM ("kp-enter");
3093 case VK_PRIOR: return KEYSYM ("prior");
3094 case VK_NEXT: return KEYSYM ("next");
3095 case VK_END: return KEYSYM ("end");
3096 case VK_HOME: return KEYSYM ("home");
3097 case VK_LEFT: return KEYSYM ("left");
3098 case VK_UP: return KEYSYM ("up");
3099 case VK_RIGHT: return KEYSYM ("right");
3100 case VK_DOWN: return KEYSYM ("down");
3101 case VK_INSERT: return KEYSYM ("insert");
3102 case VK_DELETE: return QKdelete;
3103 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3104 case VK_LWIN return KEYSYM ("");
3105 case VK_RWIN return KEYSYM ("");
3107 case VK_APPS: return KEYSYM ("menu");
3112 switch (mswindows_key)
3114 case VK_BACK: return QKbackspace;
3115 case VK_TAB: return QKtab;
3116 case '\n': return QKlinefeed;
3117 case VK_CLEAR: return KEYSYM ("clear");
3118 case VK_RETURN: return QKreturn;
3119 case VK_PAUSE: return KEYSYM ("pause");
3120 case VK_ESCAPE: return QKescape;
3121 case VK_SPACE: return QKspace;
3122 case VK_PRIOR: return KEYSYM ("kp-prior");
3123 case VK_NEXT: return KEYSYM ("kp-next");
3124 case VK_END: return KEYSYM ("kp-end");
3125 case VK_HOME: return KEYSYM ("kp-home");
3126 case VK_LEFT: return KEYSYM ("kp-left");
3127 case VK_UP: return KEYSYM ("kp-up");
3128 case VK_RIGHT: return KEYSYM ("kp-right");
3129 case VK_DOWN: return KEYSYM ("kp-down");
3130 case VK_SELECT: return KEYSYM ("select");
3131 case VK_PRINT: return KEYSYM ("print");
3132 case VK_EXECUTE: return KEYSYM ("execute");
3133 case VK_SNAPSHOT: return KEYSYM ("print");
3134 case VK_INSERT: return KEYSYM ("kp-insert");
3135 case VK_DELETE: return KEYSYM ("kp-delete");
3136 case VK_HELP: return KEYSYM ("help");
3137 case VK_NUMPAD0: return KEYSYM ("kp-0");
3138 case VK_NUMPAD1: return KEYSYM ("kp-1");
3139 case VK_NUMPAD2: return KEYSYM ("kp-2");
3140 case VK_NUMPAD3: return KEYSYM ("kp-3");
3141 case VK_NUMPAD4: return KEYSYM ("kp-4");
3142 case VK_NUMPAD5: return KEYSYM ("kp-5");
3143 case VK_NUMPAD6: return KEYSYM ("kp-6");
3144 case VK_NUMPAD7: return KEYSYM ("kp-7");
3145 case VK_NUMPAD8: return KEYSYM ("kp-8");
3146 case VK_NUMPAD9: return KEYSYM ("kp-9");
3147 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3148 case VK_ADD: return KEYSYM ("kp-add");
3149 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3150 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3151 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3152 case VK_DIVIDE: return KEYSYM ("kp-divide");
3153 case VK_F1: return KEYSYM ("f1");
3154 case VK_F2: return KEYSYM ("f2");
3155 case VK_F3: return KEYSYM ("f3");
3156 case VK_F4: return KEYSYM ("f4");
3157 case VK_F5: return KEYSYM ("f5");
3158 case VK_F6: return KEYSYM ("f6");
3159 case VK_F7: return KEYSYM ("f7");
3160 case VK_F8: return KEYSYM ("f8");
3161 case VK_F9: return KEYSYM ("f9");
3162 case VK_F10: return KEYSYM ("f10");
3163 case VK_F11: return KEYSYM ("f11");
3164 case VK_F12: return KEYSYM ("f12");
3165 case VK_F13: return KEYSYM ("f13");
3166 case VK_F14: return KEYSYM ("f14");
3167 case VK_F15: return KEYSYM ("f15");
3168 case VK_F16: return KEYSYM ("f16");
3169 case VK_F17: return KEYSYM ("f17");
3170 case VK_F18: return KEYSYM ("f18");
3171 case VK_F19: return KEYSYM ("f19");
3172 case VK_F20: return KEYSYM ("f20");
3173 case VK_F21: return KEYSYM ("f21");
3174 case VK_F22: return KEYSYM ("f22");
3175 case VK_F23: return KEYSYM ("f23");
3176 case VK_F24: return KEYSYM ("f24");
3183 * Find the console that matches the supplied mswindows window handle
3186 mswindows_find_console (HWND hwnd)
3188 /* We only support one console */
3189 return XCAR (Vconsole_list);
3193 * Find the frame that matches the supplied mswindows window handle
3196 mswindows_find_frame (HWND hwnd)
3198 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3202 /* We are in progress of frame creation. Return the frame
3203 being created, as it still not remembered in the window
3205 assert (!NILP (Vmswindows_frame_being_created));
3206 return Vmswindows_frame_being_created;
3208 VOID_TO_LISP (f, l);
3213 /************************************************************************/
3215 /************************************************************************/
3218 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3221 EMACS_TIME current_time;
3222 EMACS_GET_TIME (current_time);
3223 EMACS_SUB_TIME (thyme, thyme, current_time);
3224 milliseconds = EMACS_SECS (thyme) * 1000 +
3225 (EMACS_USECS (thyme) + 500) / 1000;
3226 if (milliseconds < 1)
3228 ++mswindows_pending_timers_count;
3229 return SetTimer (NULL, 0, milliseconds,
3230 (TIMERPROC) mswindows_wm_timer_callback);
3234 emacs_mswindows_remove_timeout (int id)
3236 Lisp_Event match_against;
3237 Lisp_Object emacs_event;
3239 if (KillTimer (NULL, id))
3240 --mswindows_pending_timers_count;
3242 /* If there is a dispatch event generated by this
3243 timeout in the queue, we have to remove it too. */
3244 match_against.event_type = timeout_event;
3245 match_against.event.timeout.interval_id = id;
3246 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3247 if (!NILP (emacs_event))
3248 Fdeallocate_event(emacs_event);
3251 /* If `user_p' is false, then return whether there are any win32, timeout,
3252 * or subprocess events pending (that is, whether
3253 * emacs_mswindows_next_event() would return immediately without blocking).
3255 * if `user_p' is true, then return whether there are any *user generated*
3256 * events available (that is, whether there are keyboard or mouse-click
3257 * events ready to be read). This also implies that
3258 * emacs_mswindows_next_event() would not block.
3261 emacs_mswindows_event_pending_p (int user_p)
3263 mswindows_need_event (0);
3264 return (!NILP (mswindows_u_dispatch_event_queue)
3265 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3269 * Return the next event
3272 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3274 Lisp_Object event, event2;
3276 mswindows_need_event (1);
3278 event = mswindows_dequeue_dispatch_event ();
3279 XSETEVENT (event2, emacs_event);
3280 Fcopy_event (event, event2);
3281 Fdeallocate_event (event);
3285 * Handle a magic event off the dispatch queue.
3288 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3290 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3297 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3298 mswindows_handle_paint (f);
3299 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3306 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3307 struct frame *f = XFRAME (frame);
3308 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3310 struct gcpro gcpro1;
3312 /* On focus change, clear all memory of sticky modifiers
3313 to avoid non-intuitive behavior. */
3314 clear_sticky_modifiers ();
3316 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3318 emacs_handle_focus_change_preliminary (conser);
3319 /* Under X the stuff up to here is done in the X event handler.
3321 emacs_handle_focus_change_final (conser);
3330 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3331 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3333 Qmap_frame_hook : Qunmap_frame_hook,
3338 /* #### What about Enter & Leave */
3340 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3341 Qmouse_leave_frame_hook, 1, frame);
3349 #ifndef HAVE_MSG_SELECT
3351 get_process_input_waitable (Lisp_Process *process)
3353 Lisp_Object instr, outstr, p;
3354 XSETPROCESS (p, process);
3355 get_process_streams (process, &instr, &outstr);
3356 assert (!NILP (instr));
3357 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3358 return (network_connection_p (p)
3359 ? get_winsock_stream_waitable (XLSTREAM (instr))
3360 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3362 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3367 emacs_mswindows_select_process (Lisp_Process *process)
3369 HANDLE hev = get_process_input_waitable (process);
3371 if (!add_waitable_handle (hev))
3372 error ("Too many active processes");
3374 #ifdef HAVE_WIN32_PROCESSES
3377 XSETPROCESS (p, process);
3378 if (!network_connection_p (p))
3380 HANDLE hprocess = get_nt_process_handle (process);
3381 if (!add_waitable_handle (hprocess))
3383 remove_waitable_handle (hev);
3384 error ("Too many active processes");
3392 emacs_mswindows_unselect_process (Lisp_Process *process)
3394 /* Process handle is removed in the event loop as soon
3395 as it is signaled, so don't bother here about it */
3396 HANDLE hev = get_process_input_waitable (process);
3397 remove_waitable_handle (hev);
3399 #endif /* HAVE_MSG_SELECT */
3402 emacs_mswindows_select_console (struct console *con)
3404 #ifdef HAVE_MSG_SELECT
3405 if (CONSOLE_MSWINDOWS_P (con))
3406 return; /* mswindows consoles are automatically selected */
3408 event_stream_unixoid_select_console (con);
3413 emacs_mswindows_unselect_console (struct console *con)
3415 #ifdef HAVE_MSG_SELECT
3416 if (CONSOLE_MSWINDOWS_P (con))
3417 return; /* mswindows consoles are automatically selected */
3419 event_stream_unixoid_unselect_console (con);
3424 emacs_mswindows_quit_p (void)
3426 /* Quit cannot happen in modal loop: all program
3427 input is dedicated to Windows. */
3428 if (mswindows_in_modal_loop)
3431 /* Drain windows queue. This sets up number of quit characters in
3433 mswindows_drain_windows_queue ();
3435 if (mswindows_quit_chars_count > 0)
3437 /* Yes there's a hidden one... Throw it away */
3438 Lisp_Event match_against;
3439 Lisp_Object emacs_event;
3442 match_against.event_type = key_press_event;
3443 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3445 while (mswindows_quit_chars_count-- > 0)
3447 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3448 assert (!NILP (emacs_event));
3450 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
3453 Fdeallocate_event(emacs_event);
3456 Vquit_flag = critical_p ? Qcritical : Qt;
3461 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3462 Lisp_Object* instream,
3463 Lisp_Object* outstream,
3466 /* Handles for streams */
3468 /* fds. These just stored along with the streams, and are closed in
3469 delete stream pair method, because we need to handle fake unices
3473 /* Decode inhandle and outhandle. Their meaning depends on
3474 the process implementation being used. */
3475 #if defined (HAVE_WIN32_PROCESSES)
3476 /* We're passed in Windows handles. That's what we like most... */
3477 hin = (HANDLE) inhandle;
3478 hout = (HANDLE) outhandle;
3480 #elif defined (HAVE_UNIX_PROCESSES)
3481 /* We are passed UNIX fds. This must be Cygwin.
3483 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3484 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3488 #error "So, WHICH kind of processes do you want?"
3491 *instream = (hin == INVALID_HANDLE_VALUE
3493 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3494 : flags & STREAM_NETWORK_CONNECTION
3495 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3497 : make_ntpipe_input_stream (hin, fdi));
3499 #ifdef HAVE_WIN32_PROCESSES
3500 *outstream = (hout == INVALID_HANDLE_VALUE
3502 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3503 : flags & STREAM_NETWORK_CONNECTION
3504 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3506 : make_ntpipe_output_stream (hout, fdo));
3507 #elif defined (HAVE_UNIX_PROCESSES)
3508 *outstream = (fdo >= 0
3509 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3512 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3513 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3514 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3516 Bufbyte eof_char = get_eof_char (fdo);
3517 int pty_max_bytes = get_pty_max_bytes (fdo);
3518 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3523 return (NILP (*instream)
3525 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3526 : flags & STREAM_NETWORK_CONNECTION
3527 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3529 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3533 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3534 Lisp_Object outstream)
3536 /* Oh nothing special here for Win32 at all */
3537 #if defined (HAVE_UNIX_PROCESSES)
3538 int in = (NILP(instream)
3540 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3541 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3542 ? get_winsock_stream_param (XLSTREAM (instream))
3544 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3545 int out = (NILP(outstream) ? -1
3546 : filedesc_stream_fd (XLSTREAM (outstream)));
3550 if (out != in && out >= 0)
3554 return (NILP (instream)
3556 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3557 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3558 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3560 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3564 emacs_mswindows_current_event_timestamp (struct console *c)
3566 return GetTickCount ();
3569 #ifndef HAVE_X_WINDOWS
3570 /* This is called from GC when a process object is about to be freed.
3571 If we've still got pointers to it in this file, we're gonna lose hard.
3574 debug_process_finalization (Lisp_Process *p)
3577 Lisp_Object instr, outstr;
3579 get_process_streams (p, &instr, &outstr);
3580 /* if it still has fds, then it hasn't been killed yet. */
3581 assert (NILP(instr));
3582 assert (NILP(outstr));
3584 /* #### More checks here */
3589 /************************************************************************/
3590 /* initialization */
3591 /************************************************************************/
3594 reinit_vars_of_event_mswindows (void)
3596 mswindows_in_modal_loop = 0;
3597 mswindows_pending_timers_count = 0;
3599 mswindows_event_stream = xnew (struct event_stream);
3601 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3602 mswindows_event_stream->force_event_pending = 0;
3603 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3604 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3605 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3606 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3607 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3608 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3609 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3610 #ifdef HAVE_MSG_SELECT
3611 mswindows_event_stream->select_process_cb =
3612 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3613 mswindows_event_stream->unselect_process_cb =
3614 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3615 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3616 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3618 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3619 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3620 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3621 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3623 mswindows_event_stream->current_event_timestamp_cb =
3624 emacs_mswindows_current_event_timestamp;
3628 vars_of_event_mswindows (void)
3630 reinit_vars_of_event_mswindows ();
3632 mswindows_u_dispatch_event_queue = Qnil;
3633 staticpro (&mswindows_u_dispatch_event_queue);
3634 mswindows_u_dispatch_event_queue_tail = Qnil;
3635 pdump_wire (&mswindows_u_dispatch_event_queue_tail);
3637 mswindows_s_dispatch_event_queue = Qnil;
3638 staticpro (&mswindows_s_dispatch_event_queue);
3639 mswindows_s_dispatch_event_queue_tail = Qnil;
3640 pdump_wire (&mswindows_s_dispatch_event_queue_tail);
3642 mswindows_error_caught_in_modal_loop = Qnil;
3643 staticpro (&mswindows_error_caught_in_modal_loop);
3647 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
3648 If non-zero, display debug information about Windows events that XEmacs sees.
3649 Information is displayed in a console window. Currently defined values are:
3651 1 == non-verbose output
3654 #### Unfortunately, not yet implemented.
3656 debug_mswindows_events = 0;
3659 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3660 &mswindows_alt_by_itself_activates_menu /*
3661 *Controls whether pressing and releasing the Alt key activates the menubar.
3662 This applies only if no intervening key was pressed. See also
3663 `menu-accelerator-enabled', which is probably the behavior you actually want.
3667 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3668 &mswindows_dynamic_frame_resize /*
3669 *Controls redrawing frame contents during mouse-drag or keyboard resize
3670 operation. When non-nil, the frame is redrawn while being resized. When
3671 nil, frame is not redrawn, and exposed areas are filled with default
3672 MDI application background color. Note that this option only has effect
3673 if "Show window contents while dragging" is on in system Display/Plus!
3675 Default is t on fast machines, nil on slow.
3678 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3679 &mswindows_mouse_button_tolerance /*
3680 *Analogue of double click interval for faking middle mouse events.
3681 The value is the minimum time in milliseconds that must elapse between
3682 left/right button down events before they are considered distinct events.
3683 If both mouse buttons are depressed within this interval, a middle mouse
3684 button down event is generated instead.
3685 If negative or zero, currently set system default is used instead.
3688 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3689 Number of physical mouse buttons.
3692 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3693 &mswindows_mouse_button_max_skew_x /*
3694 *Maximum horizontal distance in pixels between points in which left and
3695 right button clicks occurred for them to be translated into single
3696 middle button event. Clicks must occur in time not longer than defined
3697 by the variable `mswindows-mouse-button-tolerance'.
3698 If negative or zero, currently set system default is used instead.
3701 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3702 &mswindows_mouse_button_max_skew_y /*
3703 *Maximum vertical distance in pixels between points in which left and
3704 right button clicks occurred for them to be translated into single
3705 middle button event. Clicks must occur in time not longer than defined
3706 by the variable `mswindows-mouse-button-tolerance'.
3707 If negative or zero, currently set system default is used instead.
3710 mswindows_mouse_button_max_skew_x = 0;
3711 mswindows_mouse_button_max_skew_y = 0;
3712 mswindows_mouse_button_tolerance = 0;
3713 mswindows_alt_by_itself_activates_menu = 1;
3717 syms_of_event_mswindows (void)
3722 lstream_type_create_mswindows_selectable (void)
3724 init_slurp_stream ();
3725 init_shove_stream ();
3726 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3727 init_winsock_stream ();
3732 init_event_mswindows_late (void)
3734 #ifdef HAVE_MSG_SELECT
3735 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3736 assert (windows_fd>=0);
3737 FD_SET (windows_fd, &input_wait_mask);
3738 FD_ZERO(&zero_mask);
3741 event_stream = mswindows_event_stream;
3743 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3744 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);