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 Fixnum mswindows_num_mouse_buttons;
150 Fixnum mswindows_mouse_button_max_skew_x;
151 Fixnum mswindows_mouse_button_max_skew_y;
152 Fixnum mswindows_mouse_button_tolerance;
155 Fixnum 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 /* Don't translate messages destined for a dialog box, this
1280 makes keyboard traversal work. I think?? */
1281 if (mswindows_is_dialog_msg (&msg))
1283 mswindows_unmodalize_signal_maybe ();
1287 /* We have to translate messages that are not sent to an XEmacs
1288 frame. This is so that key presses work ok in things like
1289 edit fields. However, we *musn't* translate message for XEmacs
1290 frames as this is handled in the wnd proc.
1291 We also have to avoid generating paint magic events for windows
1292 that aren't XEmacs frames */
1293 /* GetClassName will truncate a longer class name. By adding one
1294 extra character, we are forcing textual comparison to fail
1295 if the name is longer than XEMACS_CLASS */
1297 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1298 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1300 /* Not an XEmacs frame */
1301 TranslateMessage (&msg);
1303 else if (msg.message == WM_PAINT)
1305 struct mswindows_frame* msframe;
1307 /* hdc will be NULL unless this is a subwindow - in which case we
1308 shouldn't have received a paint message for it here. */
1309 assert (msg.wParam == 0);
1311 /* Queue a magic event for handling when safe */
1313 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1314 if (!msframe->paint_pending)
1316 msframe->paint_pending = 1;
1317 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1319 /* Don't dispatch. WM_PAINT is always the last message in the
1320 queue so it's OK to just return. */
1323 DispatchMessage (&msg);
1324 mswindows_unmodalize_signal_maybe ();
1329 * This is a special flavor of the mswindows_need_event function,
1330 * used while in event pump. Actually, there is only kind of events
1331 * allowed while in event pump: a timer. An attempt to fetch any
1332 * other event leads to a deadlock, as there's no source of user input
1333 * ('cause event pump mirrors windows modal loop, which is a sole
1334 * owner of thread message queue).
1336 * To detect this, we use a counter of active timers, and allow
1337 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1338 * which will never come when there are no pending timers, which leads
1339 * to deadlock, we simply signal an error.
1342 mswindows_need_event_in_modal_loop (int badly_p)
1346 /* Check if already have one */
1347 if (!NILP (mswindows_u_dispatch_event_queue)
1348 || !NILP (mswindows_s_dispatch_event_queue))
1351 /* No event is ok */
1355 /* We do not check the _u_ queue, because timers go to _s_ */
1356 while (NILP (mswindows_s_dispatch_event_queue))
1358 /* We'll deadlock if go waiting */
1359 if (mswindows_pending_timers_count == 0)
1360 error ("Deadlock due to an attempt to call next-event in a wrong context");
1362 /* Fetch and dispatch any pending timers */
1363 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1364 DispatchMessage (&msg);
1369 * This drains the event queue and fills up two internal queues until
1370 * an event of a type specified by USER_P is retrieved.
1373 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1376 mswindows_need_event (int badly_p)
1380 if (mswindows_in_modal_loop)
1382 mswindows_need_event_in_modal_loop (badly_p);
1386 while (NILP (mswindows_u_dispatch_event_queue)
1387 && NILP (mswindows_s_dispatch_event_queue))
1389 #ifdef HAVE_MSG_SELECT
1391 SELECT_TYPE temp_mask = input_wait_mask;
1392 EMACS_TIME sometime;
1393 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1396 pointer_to_this = 0;
1399 EMACS_SET_SECS_USECS (sometime, 0, 0);
1400 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1401 pointer_to_this = &select_time_to_block;
1404 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1409 return; /* timeout */
1411 else if (active > 0)
1413 if (FD_ISSET (windows_fd, &temp_mask))
1415 mswindows_drain_windows_queue ();
1420 /* Look for a TTY event */
1421 for (i = 0; i < MAXDESC-1; i++)
1423 /* To avoid race conditions (among other things, an infinite
1424 loop when called from Fdiscard_input()), we must return
1425 user events ahead of process events. */
1426 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1428 struct console *c = tty_find_console_from_fd (i);
1429 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1430 Lisp_Event* event = XEVENT (emacs_event);
1433 if (read_event_from_tty_or_stream_desc (event, c, i))
1435 mswindows_enqueue_dispatch_event (emacs_event);
1441 /* Look for a process event */
1442 for (i = 0; i < MAXDESC-1; i++)
1444 if (FD_ISSET (i, &temp_mask))
1446 if (FD_ISSET (i, &process_only_mask))
1449 get_process_from_usid (FD_TO_USID(i));
1451 mswindows_enqueue_process_event (p);
1455 /* We might get here when a fake event came
1456 through a signal. Return a dummy event, so
1457 that a cycle of the command loop will
1459 drain_signal_event_pipe ();
1460 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1466 else if (active==-1)
1470 /* something bad happened */
1479 /* Now try getting a message or process event */
1480 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1481 mswindows_waitable_handles,
1482 FALSE, badly_p ? INFINITE : 0,
1485 /* This will assert if handle being waited for becomes abandoned.
1486 Not the case currently tho */
1487 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1488 (active >= WAIT_OBJECT_0 &&
1489 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1491 if (active == WAIT_TIMEOUT)
1493 /* No luck trying - just return what we've already got */
1496 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1498 /* Got your message, thanks */
1499 mswindows_drain_windows_queue ();
1503 int ix = active - WAIT_OBJECT_0;
1504 /* First, try to find which process' output has signaled */
1506 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1509 /* Found a signaled process input handle */
1510 mswindows_enqueue_process_event (p);
1514 /* None. This means that the process handle itself has signaled.
1515 Remove the handle from the wait vector, and make status_notify
1516 note the exited process */
1517 mswindows_waitable_handles [ix] =
1518 mswindows_waitable_handles [--mswindows_waitable_count];
1519 kick_status_notify ();
1520 /* We need to return a process event here so that
1521 (1) accept-process-output will return when called on this
1522 process, and (2) status notifications will happen in
1523 accept-process-output, sleep-for, and sit-for. */
1524 /* #### horrible kludge till my real process fixes go in.
1526 if (!NILP (Vprocess_list))
1528 Lisp_Object vaffanculo = XCAR (Vprocess_list);
1529 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1531 else /* trash me soon. */
1532 /* Have to return something: there may be no accompanying
1534 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1541 /************************************************************************/
1542 /* Event generators */
1543 /************************************************************************/
1546 * Callback procedure for synchronous timer messages
1548 static void CALLBACK
1549 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1551 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1552 Lisp_Event *event = XEVENT (emacs_event);
1554 if (KillTimer (NULL, id_timer))
1555 --mswindows_pending_timers_count;
1557 event->channel = Qnil;
1558 event->timestamp = dwtime;
1559 event->event_type = timeout_event;
1560 event->event.timeout.interval_id = id_timer;
1561 event->event.timeout.function = Qnil;
1562 event->event.timeout.object = Qnil;
1564 mswindows_enqueue_dispatch_event (emacs_event);
1568 * Callback procedure for dde messages
1570 * We execute a dde Open("file") by simulating a file drop, so dde support
1571 * depends on dnd support.
1573 #ifdef HAVE_DRAGNDROP
1575 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1576 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1577 DWORD dwData1, DWORD dwData2)
1582 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1583 return (HDDEDATA)TRUE;
1584 return (HDDEDATA)FALSE;
1586 case XTYP_WILDCONNECT:
1588 /* We only support one {service,topic} pair */
1589 HSZPAIR pairs[2] = {
1590 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1592 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1593 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1594 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1595 sizeof (pairs), 0L, 0, uFmt, 0));
1597 return (HDDEDATA)NULL;
1600 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1602 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1603 LPBYTE cmd = (LPBYTE) alloca (len+1);
1606 struct gcpro gcpro1, gcpro2;
1607 Lisp_Object l_dndlist = Qnil;
1608 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1609 Lisp_Object frmcons, devcons, concons;
1610 Lisp_Event *event = XEVENT (emacs_event);
1612 DdeGetData (hdata, cmd, len, 0);
1614 DdeFreeDataHandle (hdata);
1616 /* Check syntax & that it's an [Open("foo")] command, which we
1617 * treat like a file drop */
1618 /* #### Ought to be generalised and accept some other commands */
1621 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1622 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1623 return DDE_FNOTPROCESSED;
1624 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1627 if (*cmd!='(' || *(cmd+1)!='\"')
1628 return DDE_FNOTPROCESSED;
1630 while (*end && *end!='\"')
1633 return DDE_FNOTPROCESSED;
1636 return DDE_FNOTPROCESSED;
1640 return DDE_FNOTPROCESSED;
1643 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1644 strcpy (filename, "file:");
1645 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1647 dostounix_filename (cmd);
1648 filename = alloca (strlen (cmd)+6);
1649 strcpy (filename, "file:");
1650 strcat (filename, cmd);
1652 GCPRO2 (emacs_event, l_dndlist);
1653 l_dndlist = make_string (filename, strlen (filename));
1655 /* Find a mswindows frame */
1656 event->channel = Qnil;
1657 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1659 Lisp_Object frame = XCAR (frmcons);
1660 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1661 event->channel = frame;
1663 assert (!NILP (event->channel));
1665 event->timestamp = GetTickCount();
1666 event->event_type = misc_user_event;
1667 event->event.misc.button = 1;
1668 event->event.misc.modifiers = 0;
1669 event->event.misc.x = -1;
1670 event->event.misc.y = -1;
1671 event->event.misc.function = Qdragdrop_drop_dispatch;
1672 event->event.misc.object = Fcons (Qdragdrop_URL,
1673 Fcons (l_dndlist, Qnil));
1674 mswindows_enqueue_dispatch_event (emacs_event);
1676 return (HDDEDATA) DDE_FACK;
1678 DdeFreeDataHandle (hdata);
1679 return (HDDEDATA) DDE_FNOTPROCESSED;
1682 return (HDDEDATA) NULL;
1688 * Helper to do repainting - repaints can happen both from the windows
1689 * procedure and from magic events
1692 mswindows_handle_paint (struct frame *frame)
1694 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1696 /* According to the docs we need to check GetUpdateRect() before
1697 actually doing a WM_PAINT */
1698 if (GetUpdateRect (hwnd, NULL, FALSE))
1700 PAINTSTRUCT paintStruct;
1701 int x, y, width, height;
1703 BeginPaint (hwnd, &paintStruct);
1704 x = paintStruct.rcPaint.left;
1705 y = paintStruct.rcPaint.top;
1706 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1707 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1708 /* Normally we want to ignore expose events when child
1709 windows are unmapped, however once we are in the guts of
1710 WM_PAINT we need to make sure that we don't register
1711 unmaps then because they will not actually occur. */
1712 /* #### commenting out the next line seems to fix some problems
1713 but not all. only andy currently understands this stuff and
1714 he needs to review it more carefully. --ben */
1715 if (!check_for_ignored_expose (frame, x, y, width, height))
1717 hold_ignored_expose_registration = 1;
1718 mswindows_redraw_exposed_area (frame, x, y, width, height);
1719 hold_ignored_expose_registration = 0;
1721 EndPaint (hwnd, &paintStruct);
1726 * Returns 1 if a key is a real modifier or special key, which
1727 * is better handled by DefWindowProc
1730 key_needs_default_processing_p (UINT vkey)
1732 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1733 /* if we let ALT activate the menu like this, then sticky ALT-modified
1734 keystrokes become impossible. */
1735 && !modifier_keys_are_sticky)
1741 /* key-handling code is always ugly. It just ends up working out
1744 #### Most of the sticky-modifier code below is copied from similar
1745 code in event-Xt.c. They should somehow or other be merged.
1747 Here are some pointers:
1749 -- DOWN_MASK indicates which modifiers should be treated as "down"
1750 when the corresponding upstroke happens. It gets reset for
1751 a particular modifier when that modifier goes up, and reset
1752 for all modifiers when a non-modifier key is pressed. Example:
1754 I press Control-A-Shift and then release Control-A-Shift.
1755 I want the Shift key to be sticky but not the Control key.
1757 -- If a modifier key is sticky, I can unstick it by pressing
1758 the modifier key again. */
1760 static WPARAM last_downkey;
1761 static int need_to_add_mask, down_mask;
1763 #define XEMSW_LCONTROL (1<<0)
1764 #define XEMSW_RCONTROL (1<<1)
1765 #define XEMSW_LSHIFT (1<<2)
1766 #define XEMSW_RSHIFT (1<<3)
1767 #define XEMSW_LMENU (1<<4)
1768 #define XEMSW_RMENU (1<<5)
1771 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1772 int downp, int keyp)
1776 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1780 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1781 wParam == VK_RCONTROL ||
1782 wParam == VK_MENU || wParam == VK_LMENU ||
1783 wParam == VK_RMENU ||
1784 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1785 wParam == VK_RSHIFT)))
1786 { /* Not a modifier key */
1787 if (downp && keyp && !last_downkey)
1788 last_downkey = wParam;
1789 /* If I hold press-and-release the Control key and then press
1790 and hold down the right arrow, I want it to auto-repeat
1791 Control-Right. On the other hand, if I do the same but
1792 manually press the Right arrow a bunch of times, I want
1793 to see one Control-Right and then a bunch of Rights.
1794 This means that we need to distinguish between an
1795 auto-repeated key and a key pressed and released a bunch
1797 else if ((downp && !keyp) ||
1798 (downp && keyp && last_downkey &&
1799 (wParam != last_downkey ||
1800 /* the "previous key state" bit indicates autorepeat */
1801 ! (lParam & (1 << 30)))))
1803 need_to_add_mask = 0;
1809 mods = need_to_add_mask;
1811 else /* Modifier key pressed */
1813 /* If a non-modifier key was pressed in the middle of a bunch
1814 of modifiers, then it unsticks all the modifiers that were
1815 previously pressed. We cannot unstick the modifiers until
1816 now because we want to check for auto-repeat of the
1817 non-modifier key. */
1822 need_to_add_mask = 0;
1825 #define FROB(mask) \
1827 if (downp && keyp) \
1829 /* If modifier key is already sticky, \
1830 then unstick it. Note that we do \
1831 not test down_mask to deal with the \
1832 unlikely but possible case that the \
1833 modifier key auto-repeats. */ \
1834 if (need_to_add_mask & mask) \
1836 need_to_add_mask &= ~mask; \
1837 down_mask &= ~mask; \
1840 down_mask |= mask; \
1844 if (down_mask & mask) \
1846 down_mask &= ~mask; \
1847 need_to_add_mask |= mask; \
1852 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1853 || wParam == VK_RCONTROL)
1854 FROB (XEMSW_RCONTROL);
1855 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1856 || wParam == VK_LCONTROL)
1857 FROB (XEMSW_LCONTROL);
1859 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1860 || wParam == VK_RSHIFT)
1861 FROB (XEMSW_RSHIFT);
1862 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1863 || wParam == VK_LSHIFT)
1864 FROB (XEMSW_LSHIFT);
1866 if ((wParam == VK_MENU && (lParam & 0x1000000))
1867 || wParam == VK_RMENU)
1869 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1870 || wParam == VK_LMENU)
1879 GetKeyboardState (keymap);
1881 if (mods & XEMSW_LCONTROL)
1883 keymap [VK_CONTROL] |= 0x80;
1884 keymap [VK_LCONTROL] |= 0x80;
1886 if (mods & XEMSW_RCONTROL)
1888 keymap [VK_CONTROL] |= 0x80;
1889 keymap [VK_RCONTROL] |= 0x80;
1892 if (mods & XEMSW_LSHIFT)
1894 keymap [VK_SHIFT] |= 0x80;
1895 keymap [VK_LSHIFT] |= 0x80;
1897 if (mods & XEMSW_RSHIFT)
1899 keymap [VK_SHIFT] |= 0x80;
1900 keymap [VK_RSHIFT] |= 0x80;
1903 if (mods & XEMSW_LMENU)
1905 keymap [VK_MENU] |= 0x80;
1906 keymap [VK_LMENU] |= 0x80;
1908 if (mods & XEMSW_RMENU)
1910 keymap [VK_MENU] |= 0x80;
1911 keymap [VK_RMENU] |= 0x80;
1914 SetKeyboardState (keymap);
1922 clear_sticky_modifiers (void)
1924 need_to_add_mask = 0;
1934 output_modifier_keyboard_state (void)
1938 GetKeyboardState (keymap);
1940 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1941 keymap[VK_MENU] & 0x80 ? 1 : 0,
1942 keymap[VK_MENU] & 0x1 ? 1 : 0,
1943 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1944 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1945 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1946 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1947 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1948 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1949 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1950 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1951 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1952 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1953 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1954 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1955 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1956 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1957 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1958 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1959 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1960 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
1965 /* try to debug the stuck-alt-key problem.
1967 #### this happens only inconsistently, and may only happen when using
1968 StickyKeys in the Win2000 accessibility section of the control panel,
1969 which is extremely broken for other reasons. */
1972 output_alt_keyboard_state (void)
1976 // SHORT asyncstate[3];
1978 GetKeyboardState (keymap);
1979 keystate[0] = GetKeyState (VK_MENU);
1980 keystate[1] = GetKeyState (VK_LMENU);
1981 keystate[2] = GetKeyState (VK_RMENU);
1982 /* Doing this interferes with key processing. */
1983 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
1984 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
1985 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
1987 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1988 keymap[VK_MENU] & 0x80 ? 1 : 0,
1989 keymap[VK_MENU] & 0x1 ? 1 : 0,
1990 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1991 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1992 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1993 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1994 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1995 keystate[0] & 0x8000 ? 1 : 0,
1996 keystate[0] & 0x1 ? 1 : 0,
1997 keystate[1] & 0x8000 ? 1 : 0,
1998 keystate[1] & 0x1 ? 1 : 0,
1999 keystate[2] & 0x8000 ? 1 : 0,
2000 keystate[2] & 0x1 ? 1 : 0);
2001 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2002 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2003 /* asyncstate[0] & 0x1 ? 1 : 0, */
2004 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2005 /* asyncstate[1] & 0x1 ? 1 : 0, */
2006 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2007 /* asyncstate[2] & 0x1 ? 1 : 0); */
2010 #endif /* DEBUG_XEMACS */
2014 * The windows procedure for the window class XEMACS_CLASS
2017 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2019 /* Note: Remember to initialize emacs_event and event before use.
2020 This code calls code that can GC. You must GCPRO before calling such code. */
2021 Lisp_Object emacs_event = Qnil;
2022 Lisp_Object fobj = Qnil;
2025 struct frame *frame;
2026 struct mswindows_frame* msframe;
2028 /* Not perfect but avoids crashes. There is potential for wierd
2033 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2036 case WM_DESTROYCLIPBOARD:
2037 /* We own the clipboard and someone else wants it. Delete our
2038 cached copy of the clipboard contents so we'll ask for it from
2039 Windows again when someone does a paste, and destroy any memory
2040 objects we hold on the clipboard that are not in the list of types
2041 that Windows will delete itself. */
2042 mswindows_destroy_selection (QCLIPBOARD);
2043 handle_selection_clear (QCLIPBOARD);
2047 /* Erase background only during non-dynamic sizing */
2048 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2049 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2054 fobj = mswindows_find_frame (hwnd);
2055 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2061 /* See Win95 comment under WM_KEYDOWN */
2064 int should_set_keymap = 0;
2067 if (debug_mswindows_events)
2069 stderr_out ("%s wparam=%d lparam=%d\n",
2070 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
2071 wParam, (int)lParam);
2072 output_alt_keyboard_state ();
2074 #endif /* DEBUG_XEMACS */
2076 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2077 if (wParam == VK_CONTROL)
2079 GetKeyboardState (keymap);
2080 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2081 should_set_keymap = 1;
2083 else if (wParam == VK_MENU)
2085 GetKeyboardState (keymap);
2086 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2087 should_set_keymap = 1;
2090 if (should_set_keymap)
2091 // && (message_ != WM_SYSKEYUP
2092 // || NILP (Vmenu_accelerator_enabled)))
2093 SetKeyboardState (keymap);
2097 if (key_needs_default_processing_p (wParam))
2105 /* In some locales the right-hand Alt key is labelled AltGr. This key
2106 * should produce alternative characters when combined with another key.
2107 * eg on a German keyboard pressing AltGr+q should produce '@'.
2108 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2109 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2110 * it translates as if AltGr were down.
2111 * We get round this by removing all modifiers from the keymap before
2112 * calling TranslateMessage() unless AltGr is *really* down. */
2114 BYTE keymap_trans[256];
2115 BYTE keymap_orig[256];
2116 BYTE keymap_sticky[256];
2117 int has_AltGr = mswindows_current_layout_has_AltGr ();
2119 int extendedp = lParam & 0x1000000;
2124 if (debug_mswindows_events)
2126 stderr_out ("%s wparam=%d lparam=%d\n",
2127 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
2128 wParam, (int)lParam);
2129 output_alt_keyboard_state ();
2131 #endif /* DEBUG_XEMACS */
2133 GetKeyboardState (keymap_orig);
2134 frame = XFRAME (mswindows_find_frame (hwnd));
2135 if ((sticky_changed =
2136 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2138 GetKeyboardState (keymap_sticky);
2139 if (keymap_sticky[VK_MENU] & 0x80)
2141 message_ = WM_SYSKEYDOWN;
2142 /* We have to set the "context bit" so that the
2143 TranslateMessage() call below that generates the
2144 SYSCHAR message does its thing; see the documentation
2150 memcpy (keymap_sticky, keymap_orig, 256);
2152 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2154 /* Handle non-printables */
2155 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2158 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2160 SetKeyboardState (keymap_orig);
2162 else /* Normal keys & modifiers */
2165 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2166 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2168 int potential_accelerator = 0;
2169 int got_accelerator = 0;
2172 msg.message = message_;
2173 msg.wParam = wParam;
2174 msg.lParam = lParam;
2175 msg.time = GetMessageTime();
2178 /* GetKeyboardState() does not work as documented on Win95. We have
2179 * to loosely track Left and Right modifiers on behalf of the OS,
2180 * without screwing up Windows NT which tracks them properly. */
2181 if (wParam == VK_CONTROL)
2183 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2184 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2186 else if (wParam == VK_MENU)
2188 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2189 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2192 if (!NILP (Vmenu_accelerator_enabled) &&
2193 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2194 potential_accelerator = 1;
2196 /* Remove shift modifier from an ascii character */
2197 mods &= ~XEMACS_MOD_SHIFT;
2199 memcpy (keymap_trans, keymap_sticky, 256);
2201 /* Clear control and alt modifiers unless AltGr is pressed */
2202 keymap_trans[VK_RCONTROL] = 0;
2203 keymap_trans[VK_LMENU] = 0;
2204 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2205 || !(keymap_trans[VK_RMENU] & 0x80))
2207 keymap_trans[VK_LCONTROL] = 0;
2208 keymap_trans[VK_CONTROL] = 0;
2209 keymap_trans[VK_RMENU] = 0;
2210 keymap_trans[VK_MENU] = 0;
2212 SetKeyboardState (keymap_trans);
2214 /* Maybe generate some WM_[SYS]CHARs in the queue */
2215 TranslateMessage (&msg);
2217 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2218 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2222 WPARAM ch = tranmsg.wParam;
2224 /* If a quit char with no modifiers other than control and
2225 shift, then mark it with a fake modifier, which is removed
2226 upon dequeueing the event */
2227 /* #### This might also not withstand localization, if
2228 quit character is not a latin-1 symbol */
2229 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2230 && quit_ch + 'a' - 1 == ch)
2231 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2233 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2236 mods1 |= FAKE_MOD_QUIT;
2237 ++mswindows_quit_chars_count;
2239 else if (potential_accelerator && !got_accelerator &&
2240 mswindows_char_is_accelerator (frame, ch))
2242 got_accelerator = 1;
2245 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
2248 /* This generates WM_SYSCHAR messages, which are interpreted
2249 by DefWindowProc as the menu selections. */
2250 if (got_accelerator)
2252 SetKeyboardState (keymap_sticky);
2253 TranslateMessage (&msg);
2254 SetKeyboardState (keymap_orig);
2258 SetKeyboardState (keymap_orig);
2262 if (key_needs_default_processing_p (wParam))
2267 case WM_MBUTTONDOWN:
2269 /* Real middle mouse button has nothing to do with emulated one:
2270 if one wants to exercise fingers playing chords on the mouse,
2271 he is allowed to do that! */
2272 mswindows_enqueue_mouse_button_event (hwnd, message_,
2273 MAKEPOINTS (lParam),
2274 wParam &~ MK_MBUTTON,
2279 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2280 msframe->last_click_time = GetMessageTime();
2282 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2283 msframe->button2_need_lbutton = 0;
2284 if (msframe->ignore_next_lbutton_up)
2286 msframe->ignore_next_lbutton_up = 0;
2288 else if (msframe->button2_is_down)
2290 msframe->button2_is_down = 0;
2291 msframe->ignore_next_rbutton_up = 1;
2292 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2293 MAKEPOINTS (lParam),
2295 &~ (MK_LBUTTON | MK_MBUTTON
2301 if (msframe->button2_need_rbutton)
2303 msframe->button2_need_rbutton = 0;
2304 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2305 MAKEPOINTS (lParam),
2306 wParam &~ MK_LBUTTON,
2309 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2310 MAKEPOINTS (lParam),
2311 wParam &~ MK_LBUTTON,
2317 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2318 msframe->last_click_time = GetMessageTime();
2320 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2321 msframe->button2_need_rbutton = 0;
2322 if (msframe->ignore_next_rbutton_up)
2324 msframe->ignore_next_rbutton_up = 0;
2326 else if (msframe->button2_is_down)
2328 msframe->button2_is_down = 0;
2329 msframe->ignore_next_lbutton_up = 1;
2330 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2331 MAKEPOINTS (lParam),
2333 &~ (MK_LBUTTON | MK_MBUTTON
2339 if (msframe->button2_need_lbutton)
2341 msframe->button2_need_lbutton = 0;
2342 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2343 MAKEPOINTS (lParam),
2344 wParam &~ MK_RBUTTON,
2347 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2348 MAKEPOINTS (lParam),
2349 wParam &~ MK_RBUTTON,
2354 case WM_LBUTTONDOWN:
2355 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2357 if (msframe->button2_need_lbutton)
2359 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2360 msframe->button2_need_lbutton = 0;
2361 msframe->button2_need_rbutton = 0;
2362 if (mswindows_button2_near_enough (msframe->last_click_point,
2363 MAKEPOINTS (lParam)))
2365 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2366 MAKEPOINTS (lParam),
2368 &~ (MK_LBUTTON | MK_MBUTTON
2371 msframe->button2_is_down = 1;
2375 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2376 msframe->last_click_point,
2377 msframe->last_click_mods
2379 msframe->last_click_time);
2380 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2381 MAKEPOINTS (lParam),
2382 wParam &~ MK_LBUTTON,
2388 mswindows_set_chord_timer (hwnd);
2389 msframe->button2_need_rbutton = 1;
2390 msframe->last_click_point = MAKEPOINTS (lParam);
2391 msframe->last_click_mods = wParam;
2393 msframe->last_click_time = GetMessageTime();
2396 case WM_RBUTTONDOWN:
2397 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2399 if (msframe->button2_need_rbutton)
2401 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2402 msframe->button2_need_lbutton = 0;
2403 msframe->button2_need_rbutton = 0;
2404 if (mswindows_button2_near_enough (msframe->last_click_point,
2405 MAKEPOINTS (lParam)))
2407 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2408 MAKEPOINTS (lParam),
2410 &~ (MK_LBUTTON | MK_MBUTTON
2413 msframe->button2_is_down = 1;
2417 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2418 msframe->last_click_point,
2419 msframe->last_click_mods
2421 msframe->last_click_time);
2422 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2423 MAKEPOINTS (lParam),
2424 wParam &~ MK_RBUTTON,
2430 mswindows_set_chord_timer (hwnd);
2431 msframe->button2_need_lbutton = 1;
2432 msframe->last_click_point = MAKEPOINTS (lParam);
2433 msframe->last_click_mods = wParam;
2435 msframe->last_click_time = GetMessageTime();
2439 if (wParam == BUTTON_2_TIMER_ID)
2441 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2442 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2444 if (msframe->button2_need_lbutton)
2446 msframe->button2_need_lbutton = 0;
2447 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2448 msframe->last_click_point,
2449 msframe->last_click_mods
2451 msframe->last_click_time);
2453 else if (msframe->button2_need_rbutton)
2455 msframe->button2_need_rbutton = 0;
2456 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2457 msframe->last_click_point,
2458 msframe->last_click_mods
2460 msframe->last_click_time);
2464 assert ("Spurious timer fired" == 0);
2468 /* Optimization: don't report mouse movement while size is changing */
2469 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2470 if (!msframe->sizing)
2472 /* When waiting for the second mouse button to finish
2473 button2 emulation, and have moved too far, just pretend
2474 as if timer has expired. This improves drag-select feedback */
2475 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2476 && !mswindows_button2_near_enough (msframe->last_click_point,
2477 MAKEPOINTS (lParam)))
2479 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2480 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2483 emacs_event = Fmake_event (Qnil, Qnil);
2484 event = XEVENT(emacs_event);
2486 event->channel = mswindows_find_frame(hwnd);
2487 event->timestamp = GetMessageTime();
2488 event->event_type = pointer_motion_event;
2489 event->event.motion.x = MAKEPOINTS(lParam).x;
2490 event->event.motion.y = MAKEPOINTS(lParam).y;
2491 event->event.motion.modifiers =
2492 mswindows_modifier_state (NULL, wParam, 0);
2494 mswindows_enqueue_dispatch_event (emacs_event);
2500 /* Queue a `cancel-mode-internal' misc user event, so mouse
2501 selection would be canceled if any */
2502 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2503 Qcancel_mode_internal, Qnil);
2508 LPNMHDR nmhdr = (LPNMHDR)lParam;
2510 if (nmhdr->code == TTN_NEEDTEXT)
2512 #ifdef HAVE_TOOLBARS
2513 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2516 /* find out which toolbar */
2517 frame = XFRAME (mswindows_find_frame (hwnd));
2518 btext = mswindows_get_toolbar_button_text ( frame,
2521 tttext->lpszText = NULL;
2522 tttext->hinst = NULL;
2526 /* I think this is safe since the text will only go away
2527 when the toolbar does...*/
2528 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2532 /* handle tree view callbacks */
2533 else if (nmhdr->code == TVN_SELCHANGED)
2535 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2536 frame = XFRAME (mswindows_find_frame (hwnd));
2537 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2539 /* handle tab control callbacks */
2540 else if (nmhdr->code == TCN_SELCHANGE)
2543 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2544 frame = XFRAME (mswindows_find_frame (hwnd));
2546 item.mask = TCIF_PARAM;
2547 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2550 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2556 /* hdc will be NULL unless this is a subwindow - in which case we
2557 shouldn't have received a paint message for it here. */
2558 assert (wParam == 0);
2560 /* Can't queue a magic event because windows goes modal and sends paint
2561 messages directly to the windows procedure when doing solid drags
2562 and the message queue doesn't get processed. */
2563 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2567 /* We only care about this message if our size has really changed */
2568 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2573 fobj = mswindows_find_frame (hwnd);
2574 frame = XFRAME (fobj);
2575 msframe = FRAME_MSWINDOWS_DATA (frame);
2577 /* We cannot handle frame map and unmap hooks right in
2578 this routine, because these may throw. We queue
2579 magic events to run these hooks instead - kkm */
2581 if (wParam==SIZE_MINIMIZED)
2584 FRAME_VISIBLE_P (frame) = 0;
2585 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2589 GetClientRect(hwnd, &rect);
2590 FRAME_PIXWIDTH(frame) = rect.right;
2591 FRAME_PIXHEIGHT(frame) = rect.bottom;
2593 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2594 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2595 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2597 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2598 change_frame_size (frame, rows, columns, 1);
2600 /* If we are inside frame creation, we have to apply geometric
2602 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2604 /* Yes, we have to size again */
2605 mswindows_size_frame_internal ( frame,
2606 FRAME_MSWINDOWS_TARGET_RECT
2608 /* Reset so we do not get here again. The SetWindowPos call in
2609 * mswindows_size_frame_internal can cause recursion here. */
2610 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2612 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2613 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2618 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2619 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2620 FRAME_VISIBLE_P (frame) = 1;
2622 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2629 case WM_DISPLAYCHANGE:
2632 DWORD message_tick = GetMessageTime ();
2634 fobj = mswindows_find_frame (hwnd);
2635 frame = XFRAME (fobj);
2636 d = XDEVICE (FRAME_DEVICE (frame));
2638 /* Do this only once per message. XEmacs can receive this message
2639 through as many frames as it currently has open. Message time
2640 will be the same for all these messages. Despite extreme
2641 efficiency, the code below has about one in 4 billion
2642 probability that the HDC is not recreated, provided that
2643 XEmacs is running sufficiently longer than 52 days. */
2644 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2646 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2647 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2648 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2653 /* Misc magic events which only require that the frame be identified */
2656 mswindows_enqueue_magic_event (hwnd, message_);
2659 case WM_WINDOWPOSCHANGING:
2661 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2662 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2663 GetWindowPlacement(hwnd, &wpl);
2665 /* Only interested if size is changing and we're not being iconified */
2666 if (wpl.showCmd != SW_SHOWMINIMIZED
2667 && wpl.showCmd != SW_SHOWMAXIMIZED
2668 && !(wp->flags & SWP_NOSIZE))
2670 RECT ncsize = { 0, 0, 0, 0 };
2671 int pixwidth, pixheight;
2672 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2673 GetMenu(hwnd) != NULL,
2674 GetWindowLong (hwnd, GWL_EXSTYLE));
2676 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2677 wp->cx - (ncsize.right - ncsize.left),
2678 wp->cy - (ncsize.bottom - ncsize.top),
2679 &pixwidth, &pixheight);
2681 /* Convert client sizes to window sizes */
2682 pixwidth += (ncsize.right - ncsize.left);
2683 pixheight += (ncsize.bottom - ncsize.top);
2685 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2687 /* Adjust so that the bottom or right doesn't move if it's
2688 * the top or left that's being changed */
2690 GetWindowRect (hwnd, &rect);
2692 if (rect.left != wp->x)
2693 wp->x += wp->cx - pixwidth;
2694 if (rect.top != wp->y)
2695 wp->y += wp->cy - pixheight;
2701 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2702 window position if the user tries to track window too small */
2706 case WM_ENTERSIZEMOVE:
2707 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2708 msframe->sizing = 1;
2711 case WM_EXITSIZEMOVE:
2712 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2713 msframe->sizing = 0;
2714 /* Queue noop event */
2715 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2718 #ifdef HAVE_SCROLLBARS
2722 /* Direction of scroll is determined by scrollbar instance. */
2723 int code = (int) LOWORD(wParam);
2724 int pos = (short int) HIWORD(wParam);
2725 HWND hwndScrollBar = (HWND) lParam;
2726 struct gcpro gcpro1, gcpro2;
2728 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2729 GCPRO2 (emacs_event, fobj);
2730 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2732 /* Error during event pumping - cancel scroll */
2733 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2741 int keys = LOWORD (wParam); /* Modifier key flags */
2742 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2743 struct gcpro gcpro1, gcpro2;
2745 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2747 GCPRO2 (emacs_event, fobj);
2748 mswindows_pump_outstanding_events (); /* Can GC */
2757 #ifdef HAVE_MENUBARS
2759 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2761 XFRAME (mswindows_find_frame (hwnd)))))
2762 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2765 case WM_INITMENUPOPUP:
2766 if (!HIWORD(lParam))
2768 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2770 XFRAME (mswindows_find_frame (hwnd)))))
2771 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2775 #endif /* HAVE_MENUBARS */
2779 WORD id = LOWORD (wParam);
2780 WORD nid = HIWORD (wParam);
2781 HWND cid = (HWND)lParam;
2782 frame = XFRAME (mswindows_find_frame (hwnd));
2784 #ifdef HAVE_TOOLBARS
2785 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2788 /* widgets in a buffer only eval a callback for suitable events.*/
2793 case CBN_EDITCHANGE:
2795 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2798 /* menubars always must come last since the hashtables do not
2800 #ifdef HAVE_MENUBARS
2801 if (!NILP (mswindows_handle_wm_command (frame, id)))
2805 return DefWindowProc (hwnd, message_, wParam, lParam);
2806 /* Bite me - a spurious command. This used to not be able to
2807 happen but with the introduction of widgets its now
2812 case WM_CTLCOLORBTN:
2813 case WM_CTLCOLORLISTBOX:
2814 case WM_CTLCOLOREDIT:
2815 case WM_CTLCOLORSTATIC:
2816 case WM_CTLCOLORSCROLLBAR:
2818 /* if we get an opportunity to paint a widget then do so if
2819 there is an appropriate face */
2820 HWND crtlwnd = (HWND)lParam;
2821 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2824 Lisp_Object image_instance;
2825 VOID_TO_LISP (image_instance, ii);
2826 if (IMAGE_INSTANCEP (image_instance)
2828 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2830 /* set colors for the buttons */
2831 HDC hdc = (HDC)wParam;
2832 if (last_widget_brushed != ii)
2835 DeleteObject (widget_brush);
2836 widget_brush = CreateSolidBrush
2837 (COLOR_INSTANCE_MSWINDOWS_COLOR
2840 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2841 XIMAGE_INSTANCE_FRAME (image_instance)))));
2843 last_widget_brushed = ii;
2846 COLOR_INSTANCE_MSWINDOWS_COLOR
2849 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2850 XIMAGE_INSTANCE_FRAME (image_instance)))));
2851 SetBkMode (hdc, OPAQUE);
2854 COLOR_INSTANCE_MSWINDOWS_COLOR
2857 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2858 XIMAGE_INSTANCE_FRAME (image_instance)))));
2859 return (LRESULT)widget_brush;
2865 #ifdef HAVE_DRAGNDROP
2866 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2868 UINT filecount, i, len;
2873 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2874 struct gcpro gcpro1, gcpro2, gcpro3;
2876 emacs_event = Fmake_event (Qnil, Qnil);
2877 event = XEVENT(emacs_event);
2879 GCPRO3 (emacs_event, l_dndlist, l_item);
2881 if (!DragQueryPoint ((HDROP) wParam, &point))
2882 point.x = point.y = -1; /* outside client area */
2884 event->event_type = misc_user_event;
2885 event->channel = mswindows_find_frame(hwnd);
2886 event->timestamp = GetMessageTime();
2887 event->event.misc.button = 1; /* #### Should try harder */
2888 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2890 event->event.misc.x = point.x;
2891 event->event.misc.y = point.y;
2892 event->event.misc.function = Qdragdrop_drop_dispatch;
2894 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2895 for (i=0; i<filecount; i++)
2897 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2898 /* The URLs that we make here aren't correct according to section
2899 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2900 * because they may contain reserved characters. But that's OK -
2901 * they just need to be good enough to keep dragdrop.el happy. */
2902 fname = (char *)xmalloc (len+1);
2903 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2905 /* May be a shell link aka "shortcut" - replace fname if so */
2906 #if !(defined(CYGWIN) || defined(MINGW))
2907 /* cygwin doesn't define this COM stuff */
2908 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2912 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2913 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2917 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2921 WIN32_FIND_DATA wfd;
2922 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2924 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2926 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2927 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2932 len = strlen (fname);
2935 ppf->lpVtbl->Release (ppf);
2938 psl->lpVtbl->Release (psl);
2944 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2945 strcpy (filename, "file:");
2946 cygwin32_win32_to_posix_path_list (fname, filename+5);
2948 filename = (char *)xmalloc (len+6);
2949 strcat (strcpy (filename, "file:"), fname);
2950 dostounix_filename (filename+5);
2953 l_item = make_string (filename, strlen (filename));
2954 l_dndlist = Fcons (l_item, l_dndlist);
2957 DragFinish ((HDROP) wParam);
2959 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2960 mswindows_enqueue_dispatch_event (emacs_event);
2968 return DefWindowProc (hwnd, message_, wParam, lParam);
2974 /************************************************************************/
2975 /* keyboard, mouse & other helpers for the windows procedure */
2976 /************************************************************************/
2978 mswindows_set_chord_timer (HWND hwnd)
2982 /* We get one third half system double click threshold */
2983 if (mswindows_mouse_button_tolerance <= 0)
2984 interval = GetDoubleClickTime () / 3;
2986 interval = mswindows_mouse_button_tolerance;
2988 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2992 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2995 if (mswindows_mouse_button_max_skew_x <= 0)
2996 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2998 dx = mswindows_mouse_button_max_skew_x;
3000 if (mswindows_mouse_button_max_skew_y <= 0)
3001 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3003 dy = mswindows_mouse_button_max_skew_y;
3005 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3009 mswindows_current_layout_has_AltGr (void)
3011 /* This simple caching mechanism saves 10% of CPU
3012 time when a key typed at autorepeat rate of 30 cps! */
3013 static HKL last_hkl = 0;
3014 static int last_hkl_has_AltGr;
3015 HKL current_hkl = (HKL) -1;
3017 if (xGetKeyboardLayout) /* not in NT 3.5 */
3018 current_hkl = xGetKeyboardLayout (0);
3019 if (current_hkl != last_hkl)
3022 last_hkl_has_AltGr = 0;
3023 /* In this loop, we query whether a character requires
3024 AltGr to be down to generate it. If at least such one
3025 found, this means that the layout does regard AltGr */
3026 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3027 if (HIBYTE (VkKeyScan (c)) == 6)
3028 last_hkl_has_AltGr = 1;
3029 last_hkl = current_hkl;
3031 return last_hkl_has_AltGr;
3035 /* Returns the state of the modifier keys in the format expected by the
3036 * Lisp_Event key_data, button_data and motion_data modifiers member */
3038 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3041 int keys_is_real = 0;
3044 if (fwKeys == (DWORD) -1)
3045 fwKeys = mswindows_last_mouse_button_state;
3049 mswindows_last_mouse_button_state = fwKeys;
3055 GetKeyboardState (keymap);
3056 has_AltGr = mswindows_current_layout_has_AltGr ();
3059 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3061 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3063 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3064 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3068 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3069 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3072 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3073 ? XEMACS_MOD_SHIFT : 0;
3074 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3075 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3076 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3082 * Translate a mswindows virtual key to a keysym.
3083 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3084 * or whose ASCII codes (like space) xemacs doesn't like.
3086 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3089 if (extendedp) /* Keys not present on a 82 key keyboard */
3091 switch (mswindows_key)
3093 case VK_CANCEL: return KEYSYM ("pause");
3094 case VK_RETURN: return KEYSYM ("kp-enter");
3095 case VK_PRIOR: return KEYSYM ("prior");
3096 case VK_NEXT: return KEYSYM ("next");
3097 case VK_END: return KEYSYM ("end");
3098 case VK_HOME: return KEYSYM ("home");
3099 case VK_LEFT: return KEYSYM ("left");
3100 case VK_UP: return KEYSYM ("up");
3101 case VK_RIGHT: return KEYSYM ("right");
3102 case VK_DOWN: return KEYSYM ("down");
3103 case VK_INSERT: return KEYSYM ("insert");
3104 case VK_DELETE: return QKdelete;
3105 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3106 case VK_LWIN return KEYSYM ("");
3107 case VK_RWIN return KEYSYM ("");
3109 case VK_APPS: return KEYSYM ("menu");
3114 switch (mswindows_key)
3116 case VK_BACK: return QKbackspace;
3117 case VK_TAB: return QKtab;
3118 case '\n': return QKlinefeed;
3119 case VK_CLEAR: return KEYSYM ("clear");
3120 case VK_RETURN: return QKreturn;
3121 case VK_PAUSE: return KEYSYM ("pause");
3122 case VK_ESCAPE: return QKescape;
3123 case VK_SPACE: return QKspace;
3124 case VK_PRIOR: return KEYSYM ("kp-prior");
3125 case VK_NEXT: return KEYSYM ("kp-next");
3126 case VK_END: return KEYSYM ("kp-end");
3127 case VK_HOME: return KEYSYM ("kp-home");
3128 case VK_LEFT: return KEYSYM ("kp-left");
3129 case VK_UP: return KEYSYM ("kp-up");
3130 case VK_RIGHT: return KEYSYM ("kp-right");
3131 case VK_DOWN: return KEYSYM ("kp-down");
3132 case VK_SELECT: return KEYSYM ("select");
3133 case VK_PRINT: return KEYSYM ("print");
3134 case VK_EXECUTE: return KEYSYM ("execute");
3135 case VK_SNAPSHOT: return KEYSYM ("print");
3136 case VK_INSERT: return KEYSYM ("kp-insert");
3137 case VK_DELETE: return KEYSYM ("kp-delete");
3138 case VK_HELP: return KEYSYM ("help");
3139 case VK_NUMPAD0: return KEYSYM ("kp-0");
3140 case VK_NUMPAD1: return KEYSYM ("kp-1");
3141 case VK_NUMPAD2: return KEYSYM ("kp-2");
3142 case VK_NUMPAD3: return KEYSYM ("kp-3");
3143 case VK_NUMPAD4: return KEYSYM ("kp-4");
3144 case VK_NUMPAD5: return KEYSYM ("kp-5");
3145 case VK_NUMPAD6: return KEYSYM ("kp-6");
3146 case VK_NUMPAD7: return KEYSYM ("kp-7");
3147 case VK_NUMPAD8: return KEYSYM ("kp-8");
3148 case VK_NUMPAD9: return KEYSYM ("kp-9");
3149 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3150 case VK_ADD: return KEYSYM ("kp-add");
3151 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3152 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3153 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3154 case VK_DIVIDE: return KEYSYM ("kp-divide");
3155 case VK_F1: return KEYSYM ("f1");
3156 case VK_F2: return KEYSYM ("f2");
3157 case VK_F3: return KEYSYM ("f3");
3158 case VK_F4: return KEYSYM ("f4");
3159 case VK_F5: return KEYSYM ("f5");
3160 case VK_F6: return KEYSYM ("f6");
3161 case VK_F7: return KEYSYM ("f7");
3162 case VK_F8: return KEYSYM ("f8");
3163 case VK_F9: return KEYSYM ("f9");
3164 case VK_F10: return KEYSYM ("f10");
3165 case VK_F11: return KEYSYM ("f11");
3166 case VK_F12: return KEYSYM ("f12");
3167 case VK_F13: return KEYSYM ("f13");
3168 case VK_F14: return KEYSYM ("f14");
3169 case VK_F15: return KEYSYM ("f15");
3170 case VK_F16: return KEYSYM ("f16");
3171 case VK_F17: return KEYSYM ("f17");
3172 case VK_F18: return KEYSYM ("f18");
3173 case VK_F19: return KEYSYM ("f19");
3174 case VK_F20: return KEYSYM ("f20");
3175 case VK_F21: return KEYSYM ("f21");
3176 case VK_F22: return KEYSYM ("f22");
3177 case VK_F23: return KEYSYM ("f23");
3178 case VK_F24: return KEYSYM ("f24");
3185 * Find the console that matches the supplied mswindows window handle
3188 mswindows_find_console (HWND hwnd)
3190 /* We only support one console */
3191 return XCAR (Vconsole_list);
3195 * Find the frame that matches the supplied mswindows window handle
3198 mswindows_find_frame (HWND hwnd)
3200 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3204 /* We are in progress of frame creation. Return the frame
3205 being created, as it still not remembered in the window
3207 assert (!NILP (Vmswindows_frame_being_created));
3208 return Vmswindows_frame_being_created;
3210 VOID_TO_LISP (f, l);
3215 /************************************************************************/
3217 /************************************************************************/
3220 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3223 EMACS_TIME current_time;
3224 EMACS_GET_TIME (current_time);
3225 EMACS_SUB_TIME (thyme, thyme, current_time);
3226 milliseconds = EMACS_SECS (thyme) * 1000 +
3227 (EMACS_USECS (thyme) + 500) / 1000;
3228 if (milliseconds < 1)
3230 ++mswindows_pending_timers_count;
3231 return SetTimer (NULL, 0, milliseconds,
3232 (TIMERPROC) mswindows_wm_timer_callback);
3236 emacs_mswindows_remove_timeout (int id)
3238 Lisp_Event match_against;
3239 Lisp_Object emacs_event;
3241 if (KillTimer (NULL, id))
3242 --mswindows_pending_timers_count;
3244 /* If there is a dispatch event generated by this
3245 timeout in the queue, we have to remove it too. */
3246 match_against.event_type = timeout_event;
3247 match_against.event.timeout.interval_id = id;
3248 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3249 if (!NILP (emacs_event))
3250 Fdeallocate_event(emacs_event);
3253 /* If `user_p' is false, then return whether there are any win32, timeout,
3254 * or subprocess events pending (that is, whether
3255 * emacs_mswindows_next_event() would return immediately without blocking).
3257 * if `user_p' is true, then return whether there are any *user generated*
3258 * events available (that is, whether there are keyboard or mouse-click
3259 * events ready to be read). This also implies that
3260 * emacs_mswindows_next_event() would not block.
3263 emacs_mswindows_event_pending_p (int user_p)
3265 mswindows_need_event (0);
3266 return (!NILP (mswindows_u_dispatch_event_queue)
3267 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3271 * Return the next event
3274 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3276 Lisp_Object event, event2;
3278 mswindows_need_event (1);
3280 event = mswindows_dequeue_dispatch_event ();
3281 XSETEVENT (event2, emacs_event);
3282 Fcopy_event (event, event2);
3283 Fdeallocate_event (event);
3287 * Handle a magic event off the dispatch queue.
3290 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3292 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3299 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3300 mswindows_handle_paint (f);
3301 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3308 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3309 struct frame *f = XFRAME (frame);
3310 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3312 struct gcpro gcpro1;
3314 /* On focus change, clear all memory of sticky modifiers
3315 to avoid non-intuitive behavior. */
3316 clear_sticky_modifiers ();
3318 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3320 emacs_handle_focus_change_preliminary (conser);
3321 /* Under X the stuff up to here is done in the X event handler.
3323 emacs_handle_focus_change_final (conser);
3332 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3333 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3335 Qmap_frame_hook : Qunmap_frame_hook,
3340 /* #### What about Enter & Leave */
3342 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3343 Qmouse_leave_frame_hook, 1, frame);
3351 #ifndef HAVE_MSG_SELECT
3353 get_process_input_waitable (Lisp_Process *process)
3355 Lisp_Object instr, outstr, p;
3356 XSETPROCESS (p, process);
3357 get_process_streams (process, &instr, &outstr);
3358 assert (!NILP (instr));
3359 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3360 return (network_connection_p (p)
3361 ? get_winsock_stream_waitable (XLSTREAM (instr))
3362 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3364 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3369 emacs_mswindows_select_process (Lisp_Process *process)
3371 HANDLE hev = get_process_input_waitable (process);
3373 if (!add_waitable_handle (hev))
3374 error ("Too many active processes");
3376 #ifdef HAVE_WIN32_PROCESSES
3379 XSETPROCESS (p, process);
3380 if (!network_connection_p (p))
3382 HANDLE hprocess = get_nt_process_handle (process);
3383 if (!add_waitable_handle (hprocess))
3385 remove_waitable_handle (hev);
3386 error ("Too many active processes");
3394 emacs_mswindows_unselect_process (Lisp_Process *process)
3396 /* Process handle is removed in the event loop as soon
3397 as it is signaled, so don't bother here about it */
3398 HANDLE hev = get_process_input_waitable (process);
3399 remove_waitable_handle (hev);
3401 #endif /* HAVE_MSG_SELECT */
3404 emacs_mswindows_select_console (struct console *con)
3406 #ifdef HAVE_MSG_SELECT
3407 if (CONSOLE_MSWINDOWS_P (con))
3408 return; /* mswindows consoles are automatically selected */
3410 event_stream_unixoid_select_console (con);
3415 emacs_mswindows_unselect_console (struct console *con)
3417 #ifdef HAVE_MSG_SELECT
3418 if (CONSOLE_MSWINDOWS_P (con))
3419 return; /* mswindows consoles are automatically selected */
3421 event_stream_unixoid_unselect_console (con);
3426 emacs_mswindows_quit_p (void)
3428 /* Quit cannot happen in modal loop: all program
3429 input is dedicated to Windows. */
3430 if (mswindows_in_modal_loop)
3433 /* Drain windows queue. This sets up number of quit characters in
3435 mswindows_drain_windows_queue ();
3437 if (mswindows_quit_chars_count > 0)
3439 /* Yes there's a hidden one... Throw it away */
3440 Lisp_Event match_against;
3441 Lisp_Object emacs_event;
3444 match_against.event_type = key_press_event;
3445 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3447 while (mswindows_quit_chars_count-- > 0)
3449 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3450 assert (!NILP (emacs_event));
3452 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
3455 Fdeallocate_event(emacs_event);
3458 Vquit_flag = critical_p ? Qcritical : Qt;
3463 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3464 Lisp_Object* instream,
3465 Lisp_Object* outstream,
3468 /* Handles for streams */
3470 /* fds. These just stored along with the streams, and are closed in
3471 delete stream pair method, because we need to handle fake unices
3475 /* Decode inhandle and outhandle. Their meaning depends on
3476 the process implementation being used. */
3477 #if defined (HAVE_WIN32_PROCESSES)
3478 /* We're passed in Windows handles. That's what we like most... */
3479 hin = (HANDLE) inhandle;
3480 hout = (HANDLE) outhandle;
3482 #elif defined (HAVE_UNIX_PROCESSES)
3483 /* We are passed UNIX fds. This must be Cygwin.
3485 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3486 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3490 #error "So, WHICH kind of processes do you want?"
3493 *instream = (hin == INVALID_HANDLE_VALUE
3495 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3496 : flags & STREAM_NETWORK_CONNECTION
3497 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3499 : make_ntpipe_input_stream (hin, fdi));
3501 #ifdef HAVE_WIN32_PROCESSES
3502 *outstream = (hout == INVALID_HANDLE_VALUE
3504 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3505 : flags & STREAM_NETWORK_CONNECTION
3506 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3508 : make_ntpipe_output_stream (hout, fdo));
3509 #elif defined (HAVE_UNIX_PROCESSES)
3510 *outstream = (fdo >= 0
3511 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3514 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3515 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3516 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3518 Bufbyte eof_char = get_eof_char (fdo);
3519 int pty_max_bytes = get_pty_max_bytes (fdo);
3520 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3525 return (NILP (*instream)
3527 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3528 : flags & STREAM_NETWORK_CONNECTION
3529 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3531 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3535 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3536 Lisp_Object outstream)
3538 /* Oh nothing special here for Win32 at all */
3539 #if defined (HAVE_UNIX_PROCESSES)
3540 int in = (NILP(instream)
3542 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3543 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3544 ? get_winsock_stream_param (XLSTREAM (instream))
3546 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3547 int out = (NILP(outstream) ? -1
3548 : filedesc_stream_fd (XLSTREAM (outstream)));
3552 if (out != in && out >= 0)
3556 return (NILP (instream)
3558 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3559 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3560 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3562 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3566 emacs_mswindows_current_event_timestamp (struct console *c)
3568 return GetTickCount ();
3571 #ifndef HAVE_X_WINDOWS
3572 /* This is called from GC when a process object is about to be freed.
3573 If we've still got pointers to it in this file, we're gonna lose hard.
3576 debug_process_finalization (Lisp_Process *p)
3579 Lisp_Object instr, outstr;
3581 get_process_streams (p, &instr, &outstr);
3582 /* if it still has fds, then it hasn't been killed yet. */
3583 assert (NILP(instr));
3584 assert (NILP(outstr));
3586 /* #### More checks here */
3591 /************************************************************************/
3592 /* initialization */
3593 /************************************************************************/
3596 reinit_vars_of_event_mswindows (void)
3598 mswindows_in_modal_loop = 0;
3599 mswindows_pending_timers_count = 0;
3601 mswindows_event_stream = xnew (struct event_stream);
3603 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3604 mswindows_event_stream->force_event_pending = 0;
3605 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3606 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3607 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3608 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3609 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3610 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3611 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3612 #ifdef HAVE_MSG_SELECT
3613 mswindows_event_stream->select_process_cb =
3614 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3615 mswindows_event_stream->unselect_process_cb =
3616 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3617 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3618 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3620 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3621 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3622 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3623 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3625 mswindows_event_stream->current_event_timestamp_cb =
3626 emacs_mswindows_current_event_timestamp;
3630 vars_of_event_mswindows (void)
3632 reinit_vars_of_event_mswindows ();
3634 mswindows_u_dispatch_event_queue = Qnil;
3635 staticpro (&mswindows_u_dispatch_event_queue);
3636 mswindows_u_dispatch_event_queue_tail = Qnil;
3637 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
3639 mswindows_s_dispatch_event_queue = Qnil;
3640 staticpro (&mswindows_s_dispatch_event_queue);
3641 mswindows_s_dispatch_event_queue_tail = Qnil;
3642 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
3644 mswindows_error_caught_in_modal_loop = Qnil;
3645 staticpro (&mswindows_error_caught_in_modal_loop);
3649 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
3650 If non-zero, display debug information about Windows events that XEmacs sees.
3651 Information is displayed in a console window. Currently defined values are:
3653 1 == non-verbose output
3656 #### Unfortunately, not yet implemented.
3658 debug_mswindows_events = 0;
3661 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3662 &mswindows_alt_by_itself_activates_menu /*
3663 *Controls whether pressing and releasing the Alt key activates the menubar.
3664 This applies only if no intervening key was pressed. See also
3665 `menu-accelerator-enabled', which is probably the behavior you actually want.
3669 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3670 &mswindows_dynamic_frame_resize /*
3671 *Controls redrawing frame contents during mouse-drag or keyboard resize
3672 operation. When non-nil, the frame is redrawn while being resized. When
3673 nil, frame is not redrawn, and exposed areas are filled with default
3674 MDI application background color. Note that this option only has effect
3675 if "Show window contents while dragging" is on in system Display/Plus!
3677 Default is t on fast machines, nil on slow.
3680 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3681 &mswindows_mouse_button_tolerance /*
3682 *Analogue of double click interval for faking middle mouse events.
3683 The value is the minimum time in milliseconds that must elapse between
3684 left/right button down events before they are considered distinct events.
3685 If both mouse buttons are depressed within this interval, a middle mouse
3686 button down event is generated instead.
3687 If negative or zero, currently set system default is used instead.
3690 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3691 Number of physical mouse buttons.
3694 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3695 &mswindows_mouse_button_max_skew_x /*
3696 *Maximum horizontal distance in pixels between points in which left and
3697 right button clicks occurred for them to be translated into single
3698 middle button event. Clicks must occur in time not longer than defined
3699 by the variable `mswindows-mouse-button-tolerance'.
3700 If negative or zero, currently set system default is used instead.
3703 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3704 &mswindows_mouse_button_max_skew_y /*
3705 *Maximum vertical distance in pixels between points in which left and
3706 right button clicks occurred for them to be translated into single
3707 middle button event. Clicks must occur in time not longer than defined
3708 by the variable `mswindows-mouse-button-tolerance'.
3709 If negative or zero, currently set system default is used instead.
3712 mswindows_mouse_button_max_skew_x = 0;
3713 mswindows_mouse_button_max_skew_y = 0;
3714 mswindows_mouse_button_tolerance = 0;
3715 mswindows_alt_by_itself_activates_menu = 1;
3719 syms_of_event_mswindows (void)
3724 lstream_type_create_mswindows_selectable (void)
3726 init_slurp_stream ();
3727 init_shove_stream ();
3728 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3729 init_winsock_stream ();
3734 init_event_mswindows_late (void)
3736 #ifdef HAVE_MSG_SELECT
3737 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3738 assert (windows_fd>=0);
3739 FD_SET (windows_fd, &input_wait_mask);
3740 FD_ZERO(&zero_mask);
3743 event_stream = mswindows_event_stream;
3745 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3746 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);