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"
58 #include "objects-msw.h"
60 #include "redisplay.h"
70 #include "events-mod.h"
72 #ifdef HAVE_MSG_SELECT
73 #include "console-tty.h"
75 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 (1 << 20)
91 #define FAKE_MOD_QUIT_CRITICAL (1 << 21)
93 /* Timer ID used for button2 emulation */
94 #define BUTTON_2_TIMER_ID 1
96 Lisp_Object mswindows_find_frame (HWND hwnd);
97 static Lisp_Object mswindows_find_console (HWND hwnd);
98 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
100 static int mswindows_modifier_state (BYTE* keymap, DWORD fwKeys,
102 static void mswindows_set_chord_timer (HWND hwnd);
103 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
104 static int mswindows_current_layout_has_AltGr (void);
105 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
106 int downp, int keyp);
108 static struct event_stream *mswindows_event_stream;
110 #ifdef HAVE_MSG_SELECT
111 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
112 extern SELECT_TYPE process_only_mask, tty_only_mask;
113 SELECT_TYPE zero_mask;
114 extern int signal_event_pipe_initialized;
119 * Two separate queues, for efficiency, one (_u_) for user events, and
120 * another (_s_) for non-user ones. We always return events out of the
121 * first one until it is empty and only then proceed with the second
124 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
125 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
127 /* The number of things we can wait on */
128 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
130 #ifndef HAVE_MSG_SELECT
131 /* List of mswindows waitable handles. */
132 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
134 /* Number of wait handles */
135 static int mswindows_waitable_count=0;
136 #endif /* HAVE_MSG_SELECT */
138 /* Brush for painting widgets */
139 static HBRUSH widget_brush = 0;
140 static LONG last_widget_brushed = 0;
142 /* Count of quit chars currently in the queue */
143 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
144 Decremented in mswindows_dequeue_dispatch_event() */
145 int mswindows_quit_chars_count = 0;
147 /* These are Lisp integers; see DEFVARS in this file for description. */
148 int mswindows_dynamic_frame_resize;
149 int mswindows_alt_by_itself_activates_menu;
150 Fixnum mswindows_num_mouse_buttons;
151 Fixnum mswindows_mouse_button_max_skew_x;
152 Fixnum mswindows_mouse_button_max_skew_y;
153 Fixnum mswindows_mouse_button_tolerance;
156 Fixnum debug_mswindows_events;
158 static void debug_output_mswin_message (HWND hwnd, UINT message_,
159 WPARAM wParam, LPARAM lParam);
162 /* This is the event signaled by the event pump.
163 See mswindows_pump_outstanding_events for comments */
164 static Lisp_Object mswindows_error_caught_in_modal_loop;
165 static int mswindows_in_modal_loop;
167 /* Count of wound timers */
168 static int mswindows_pending_timers_count;
170 static DWORD mswindows_last_mouse_button_state;
172 /************************************************************************/
173 /* Pipe instream - reads process output */
174 /************************************************************************/
176 #define PIPE_READ_DELAY 20
178 #define HANDLE_TO_USID(h) ((USID)(h))
180 #define NTPIPE_SLURP_STREAM_DATA(stream) \
181 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
183 /* This structure is allocated by the main thread, and is deallocated
184 in the thread upon exit. There are situations when a thread
185 remains blocked for a long time, much longer than the lstream
186 exists. For example, "start notepad" command is issued from the
187 shell, then the shell is closed by C-c C-d. Although the shell
188 process exits, its output pipe will not get closed until the
189 notepad process exits also, because it inherits the pipe form the
190 shell. In this case, we abandon the thread, and let it live until
191 all such processes exit. While struct ntpipe_slurp_stream is
192 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
194 struct ntpipe_slurp_stream_shared_data
196 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
197 /* This is a manual-reset object. */
198 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
199 /* This is a manual-reset object. */
200 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
201 /* This is a manual-reset object. */
202 HANDLE hpipe; /* Pipe read end handle. */
203 LONG die_p; /* Thread must exit ASAP if non-zero */
204 BOOL eof_p : 1; /* Set when thread saw EOF */
205 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
206 BOOL inuse_p : 1; /* this structure is in use */
207 LONG lock_count; /* Client count of this struct, 0=safe to free */
208 BYTE onebyte; /* One byte buffer read by thread */
211 #define MAX_SLURP_STREAMS 32
212 struct ntpipe_slurp_stream_shared_data
213 shared_data_block[MAX_SLURP_STREAMS]={{0}};
215 struct ntpipe_slurp_stream
217 LPARAM user_data; /* Any user data stored in the stream object */
218 struct ntpipe_slurp_stream_shared_data* thread_data;
221 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
222 sizeof (struct ntpipe_slurp_stream));
224 /* This function is thread-safe, and is called from either thread
225 context. It serializes freeing shared data structure */
227 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
229 if (InterlockedDecrement (&s->lock_count) == 0)
232 CloseHandle (s->hev_thread);
233 CloseHandle (s->hev_caller);
234 CloseHandle (s->hev_unsleep);
235 CloseHandle (s->hpipe);
240 static struct ntpipe_slurp_stream_shared_data*
241 slurper_allocate_shared_data (void)
244 for (i=0; i<MAX_SLURP_STREAMS; i++)
246 if (!shared_data_block[i].inuse_p)
248 shared_data_block[i].inuse_p=1;
249 return &shared_data_block[i];
252 return (struct ntpipe_slurp_stream_shared_data*)0;
256 slurp_thread (LPVOID vparam)
258 struct ntpipe_slurp_stream_shared_data *s =
259 (struct ntpipe_slurp_stream_shared_data*)vparam;
263 /* Read one byte from the pipe */
265 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
267 DWORD err = GetLastError ();
268 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
273 else if (actually_read == 0)
276 /* We must terminate on an error or eof */
277 if (s->eof_p || s->error_p)
278 InterlockedIncrement (&s->die_p);
280 /* Before we notify caller, we unsignal our event. */
281 ResetEvent (s->hev_thread);
283 /* Now we got something to notify caller, either a byte or an
284 error/eof indication. Before we do, allow internal pipe
285 buffer to accumulate little bit more data.
286 Reader function pulses this event before waiting for
287 a character, to avoid pipe delay, and to get the byte
290 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
292 /* Either make event loop generate a process event, or
294 SetEvent (s->hev_caller);
296 /* Cleanup and exit if we're shot off */
300 /* Block until the client finishes with retrieving the rest of
302 WaitForSingleObject (s->hev_thread, INFINITE);
305 slurper_free_shared_data_maybe (s);
311 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
314 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
315 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
316 DWORD thread_id_unused;
319 /* We deal only with pipes, for we're using PeekNamedPipe api */
320 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
322 s->thread_data = slurper_allocate_shared_data();
324 /* Create reader thread. This could fail, so do not create events
325 until thread is created */
326 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
327 CREATE_SUSPENDED, &thread_id_unused);
330 Lstream_delete (lstr);
331 s->thread_data->inuse_p=0;
335 /* Shared data are initially owned by both main and slurper
337 s->thread_data->lock_count = 2;
338 s->thread_data->die_p = 0;
339 s->thread_data->eof_p = FALSE;
340 s->thread_data->error_p = FALSE;
341 s->thread_data->hpipe = hpipe;
342 s->user_data = param;
344 /* hev_thread is a manual-reset event, initially signaled */
345 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
346 /* hev_caller is a manual-reset event, initially nonsignaled */
347 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
348 /* hev_unsleep is a manual-reset event, initially nonsignaled */
349 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
352 ResumeThread (hthread);
353 CloseHandle (hthread);
355 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
356 XSETLSTREAM (obj, lstr);
361 get_ntpipe_input_stream_param (Lstream *stream)
363 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
368 get_ntpipe_input_stream_waitable (Lstream *stream)
370 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
371 return s->thread_data->hev_caller;
374 static Lstream_data_count
375 ntpipe_slurp_reader (Lstream *stream, unsigned char *data,
376 Lstream_data_count size)
378 /* This function must be called from the main thread only */
379 struct ntpipe_slurp_stream_shared_data* s =
380 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
385 /* Disallow pipe read delay for the thread: we need a character
387 SetEvent (s->hev_unsleep);
389 /* Check if we have a character ready. Give it a short delay,
390 for the thread to awake from pipe delay, just ion case*/
391 wait_result = WaitForSingleObject (s->hev_caller, 2);
393 /* Revert to the normal sleep behavior. */
394 ResetEvent (s->hev_unsleep);
396 /* If there's no byte buffered yet, give up */
397 if (wait_result == WAIT_TIMEOUT)
404 /* Reset caller unlock event now, as we've handled the pending
405 process output event */
406 ResetEvent (s->hev_caller);
408 /* It is now safe to do anything with contents of S, except for
409 changing s->die_p, which still should be interlocked */
413 if (s->error_p || s->die_p)
416 /* Ok, there were no error neither eof - we've got a byte from the
418 *(data++) = s->onebyte;
422 DWORD bytes_read = 0;
425 DWORD bytes_available;
427 /* If the api call fails, return at least one byte already
428 read. ReadFile in thread will return error */
429 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
432 /* Fetch available bytes. The same consideration applies,
433 so do not check for errors. ReadFile in the thread will
434 fail if the next call fails. */
436 ReadFile (s->hpipe, data, min (bytes_available, size),
440 /* Now we can unblock thread, so it attempts to read more */
441 SetEvent (s->hev_thread);
442 return bytes_read + 1;
449 ntpipe_slurp_closer (Lstream *stream)
451 /* This function must be called from the main thread only */
452 struct ntpipe_slurp_stream_shared_data* s =
453 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
455 /* Force thread to stop */
456 InterlockedIncrement (&s->die_p);
458 /* Set events which could possibly block slurper. Let it finish soon
460 SetEvent (s->hev_unsleep);
461 SetEvent (s->hev_thread);
463 /* Unlock and maybe free shared data */
464 slurper_free_shared_data_maybe (s);
470 init_slurp_stream (void)
472 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
473 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
476 /************************************************************************/
477 /* Pipe outstream - writes process input */
478 /************************************************************************/
480 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
481 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
483 #define MAX_SHOVE_BUFFER_SIZE 512
485 struct ntpipe_shove_stream
487 LPARAM user_data; /* Any user data stored in the stream object */
488 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
489 /* This is an auto-reset object. */
490 HANDLE hpipe; /* Pipe write end handle. */
491 HANDLE hthread; /* Reader thread handle. */
492 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
493 DWORD size; /* Number of bytes to write */
494 LONG die_p; /* Thread must exit ASAP if non-zero */
495 LONG idle_p; /* Non-zero if thread is waiting for job */
496 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
497 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
500 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
501 sizeof (struct ntpipe_shove_stream));
503 #ifndef HAVE_MSG_SELECT
505 shove_thread (LPVOID vparam)
507 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
513 /* Block on event and wait for a job */
514 InterlockedIncrement (&s->idle_p);
515 WaitForSingleObject (s->hev_thread, INFINITE);
517 /* Write passed buffer if any */
520 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
521 || bytes_written != s->size)
524 InterlockedIncrement (&s->die_p);
526 /* Set size to zero so we won't write it again if the closer sets
527 die_p and kicks us */
539 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
542 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
543 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
544 DWORD thread_id_unused;
549 s->user_data = param;
551 /* Create reader thread. This could fail, so do not
552 create the event until thread is created */
553 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
554 CREATE_SUSPENDED, &thread_id_unused);
555 if (s->hthread == NULL)
557 Lstream_delete (lstr);
561 /* Set the priority of the thread higher so we don't end up waiting
562 on it to send things. */
563 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST))
565 CloseHandle (s->hthread);
566 Lstream_delete (lstr);
570 /* hev_thread is an auto-reset event, initially nonsignaled */
571 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
574 ResumeThread (s->hthread);
576 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
577 XSETLSTREAM (obj, lstr);
582 get_ntpipe_output_stream_param (Lstream *stream)
584 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
589 static Lstream_data_count
590 ntpipe_shove_writer (Lstream *stream, const unsigned char *data,
591 Lstream_data_count size)
593 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
598 s->blocking_p = !s->idle_p;
602 if (size>MAX_SHOVE_BUFFER_SIZE)
605 memcpy (s->buffer, data, size);
609 InterlockedDecrement (&s->idle_p);
610 SetEvent (s->hev_thread);
611 /* Give it a chance to run -- this dramatically improves performance
612 of things like crypt. */
613 if (xSwitchToThread) /* not in Win9x or NT 3.51 */
614 (void) xSwitchToThread ();
619 ntpipe_shove_was_blocked_p (Lstream *stream)
621 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
622 return s->blocking_p;
626 ntpipe_shove_closer (Lstream *stream)
628 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
630 /* Force thread stop */
631 InterlockedIncrement (&s->die_p);
633 /* Thread will end upon unblocking. If it's already unblocked this will
634 do nothing, but the thread won't look at die_p until it's written any
636 SetEvent (s->hev_thread);
638 /* Wait while thread terminates */
639 WaitForSingleObject (s->hthread, INFINITE);
641 /* Close pipe handle, possibly breaking it */
642 CloseHandle (s->hpipe);
644 /* Close the thread handle */
645 CloseHandle (s->hthread);
647 /* Destroy the event */
648 CloseHandle (s->hev_thread);
654 init_shove_stream (void)
656 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
657 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
658 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
661 /************************************************************************/
662 /* Winsock I/O stream */
663 /************************************************************************/
664 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
666 #define WINSOCK_READ_BUFFER_SIZE 1024
668 struct winsock_stream
670 LPARAM user_data; /* Any user data stored in the stream object */
671 SOCKET s; /* Socket handle (which is a Win32 handle) */
672 OVERLAPPED ov; /* Overlapped I/O structure */
673 void* buffer; /* Buffer. */
674 unsigned long bufsize; /* Number of bytes last read */
675 unsigned long bufpos; /* Position in buffer for next fetch */
676 unsigned int error_p :1; /* I/O Error seen */
677 unsigned int eof_p :1; /* EOF Error seen */
678 unsigned int pending_p :1; /* There is a pending I/O operation */
679 unsigned int blocking_p :1; /* Last write attempt would block */
682 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
684 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
685 sizeof (struct winsock_stream));
688 winsock_initiate_read (struct winsock_stream *str)
690 ResetEvent (str->ov.hEvent);
693 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
694 &str->bufsize, &str->ov))
696 if (GetLastError () == ERROR_IO_PENDING)
698 else if (GetLastError () == ERROR_HANDLE_EOF)
703 else if (str->bufsize == 0)
707 static Lstream_data_count
708 winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
710 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
712 /* If the current operation is not yet complete, there's nothing to
716 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
723 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
725 if (GetLastError() == ERROR_HANDLE_EOF)
730 if (str->bufsize == 0)
741 /* Return as much of buffer as we have */
742 size = min (size, (Lstream_data_count) (str->bufsize - str->bufpos));
743 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
746 /* Read more if buffer is exhausted */
747 if (str->bufsize == str->bufpos)
748 winsock_initiate_read (str);
753 static Lstream_data_count
754 winsock_writer (Lstream *stream, const unsigned char *data,
755 Lstream_data_count size)
757 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
761 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
769 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
783 ResetEvent (str->ov.hEvent);
785 /* According to WriteFile docs, we must hold onto the data we pass to it
786 and not make any changes until it finishes -- which may not be until
787 the next time we get here, since we use asynchronous I/O. We have
788 in fact seen data loss as a result of not doing this. */
789 str->buffer = xrealloc (str->buffer, size);
790 memcpy (str->buffer, data, size);
792 /* According to MSDN WriteFile docs, the fourth parameter cannot be NULL
793 on Win95 even when doing an overlapped operation, as we are, where
794 the return value through that parameter is not meaningful. */
795 if (WriteFile ((HANDLE)str->s, str->buffer, size, &str->bufsize,
797 || GetLastError() == ERROR_IO_PENDING)
802 return str->error_p ? -1 : size;
806 winsock_closer (Lstream *lstr)
808 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
810 if (lstr->flags & LSTREAM_FL_READ)
811 shutdown (str->s, 0);
813 shutdown (str->s, 1);
815 CloseHandle ((HANDLE)str->s);
817 WaitForSingleObject (str->ov.hEvent, INFINITE);
825 CloseHandle (str->ov.hEvent);
830 winsock_was_blocked_p (Lstream *stream)
832 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
833 return str->blocking_p;
837 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
840 Lstream *lstr = Lstream_new (lstream_winsock, mode);
841 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
845 str->user_data = param;
847 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
849 if (lstr->flags & LSTREAM_FL_READ)
851 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
852 winsock_initiate_read (str);
855 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
856 XSETLSTREAM (obj, lstr);
861 make_winsock_input_stream (SOCKET s, LPARAM param)
863 return make_winsock_stream_1 (s, param, "r");
867 make_winsock_output_stream (SOCKET s, LPARAM param)
869 return make_winsock_stream_1 (s, param, "w");
873 get_winsock_stream_waitable (Lstream *lstr)
875 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
876 return str->ov.hEvent;
880 get_winsock_stream_param (Lstream *lstr)
882 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
883 return str->user_data;
887 init_winsock_stream (void)
889 LSTREAM_HAS_METHOD (winsock, reader);
890 LSTREAM_HAS_METHOD (winsock, writer);
891 LSTREAM_HAS_METHOD (winsock, closer);
892 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
894 #endif /* defined (HAVE_SOCKETS) */
896 /************************************************************************/
897 /* Dispatch queue management */
898 /************************************************************************/
901 mswindows_user_event_p (Lisp_Event* sevt)
903 return (sevt->event_type == key_press_event
904 || sevt->event_type == button_press_event
905 || sevt->event_type == button_release_event
906 || sevt->event_type == misc_user_event);
910 * Add an emacs event to the proper dispatch queue
913 mswindows_enqueue_dispatch_event (Lisp_Object event)
915 int user_p = mswindows_user_event_p (XEVENT(event));
916 enqueue_event (event,
917 user_p ? &mswindows_u_dispatch_event_queue :
918 &mswindows_s_dispatch_event_queue,
919 user_p ? &mswindows_u_dispatch_event_queue_tail :
920 &mswindows_s_dispatch_event_queue_tail);
922 /* Avoid blocking on WaitMessage */
923 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
927 * Add a misc-user event to the dispatch queue.
929 * Stuff it into our own dispatch queue, so we have something
930 * to return from next_event callback.
933 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
936 Lisp_Object event = Fmake_event (Qnil, Qnil);
937 Lisp_Event* e = XEVENT (event);
939 e->event_type = misc_user_event;
940 e->channel = channel;
941 e->timestamp = GetTickCount ();
942 e->event.misc.function = function;
943 e->event.misc.object = object;
945 mswindows_enqueue_dispatch_event (event);
949 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
951 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
952 Lisp_Event* event = XEVENT (emacs_event);
954 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
955 event->timestamp = GetMessageTime();
956 event->event_type = magic_event;
957 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
959 mswindows_enqueue_dispatch_event (emacs_event);
963 mswindows_enqueue_process_event (Lisp_Process* p)
965 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
966 Lisp_Event* event = XEVENT (emacs_event);
968 XSETPROCESS (process, p);
970 event->event_type = process_event;
971 event->timestamp = GetTickCount ();
972 event->event.process.process = process;
974 mswindows_enqueue_dispatch_event (emacs_event);
978 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
979 int mods, DWORD when)
981 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
982 msg == WM_RBUTTONDOWN);
984 /* We always use last message time, because mouse button
985 events may get delayed, and XEmacs double click
986 recognition will fail */
988 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
989 Lisp_Event* event = XEVENT (emacs_event);
991 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
992 event->channel = mswindows_find_frame (hwnd);
993 event->timestamp = when;
994 event->event.button.button =
995 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
996 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
997 event->event.button.x = where.x;
998 event->event.button.y = where.y;
999 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
1003 event->event_type = button_press_event;
1005 /* we need this to make sure the main window regains the focus
1006 from control subwindows */
1007 if (GetFocus() != hwnd)
1010 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1015 event->event_type = button_release_event;
1019 mswindows_enqueue_dispatch_event (emacs_event);
1023 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1025 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1026 Lisp_Event* event = XEVENT(emacs_event);
1028 event->channel = mswindows_find_console(hwnd);
1029 event->timestamp = GetMessageTime();
1030 event->event_type = key_press_event;
1031 event->event.key.keysym = keysym;
1032 event->event.key.modifiers = mods;
1033 mswindows_enqueue_dispatch_event (emacs_event);
1037 * Remove and return the first emacs event on the dispatch queue.
1038 * Give a preference to user events over non-user ones.
1041 mswindows_dequeue_dispatch_event (void)
1046 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1047 !NILP(mswindows_s_dispatch_event_queue));
1049 event = dequeue_event (
1050 NILP(mswindows_u_dispatch_event_queue) ?
1051 &mswindows_s_dispatch_event_queue :
1052 &mswindows_u_dispatch_event_queue,
1053 NILP(mswindows_u_dispatch_event_queue) ?
1054 &mswindows_s_dispatch_event_queue_tail :
1055 &mswindows_u_dispatch_event_queue_tail);
1057 sevt = XEVENT (event);
1058 if (sevt->event_type == key_press_event
1059 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1060 sevt->event.key.modifiers &=
1061 ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
1067 * Remove and return the first emacs event on the dispatch queue that matches
1068 * the supplied event.
1069 * Timeout event matches if interval_id is equal to that of the given event.
1070 * Keypress event matches if logical AND between modifiers bitmask of the
1071 * event in the queue and that of the given event is non-zero.
1072 * For all other event types, this function aborts.
1076 mswindows_cancel_dispatch_event (Lisp_Event *match)
1079 Lisp_Object previous_event = Qnil;
1080 int user_p = mswindows_user_event_p (match);
1081 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1082 &mswindows_s_dispatch_event_queue;
1083 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1084 &mswindows_s_dispatch_event_queue_tail;
1086 assert (match->event_type == timeout_event
1087 || match->event_type == key_press_event);
1089 EVENT_CHAIN_LOOP (event, *head)
1091 Lisp_Event *e = XEVENT (event);
1092 if ((e->event_type == match->event_type) &&
1093 ((e->event_type == timeout_event) ?
1094 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1095 /* Must be key_press_event */
1096 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1098 if (NILP (previous_event))
1099 dequeue_event (head, tail);
1102 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1103 if (EQ (*tail, event))
1104 *tail = previous_event;
1109 previous_event = event;
1114 #ifndef HAVE_MSG_SELECT
1115 /************************************************************************/
1116 /* Waitable handles manipulation */
1117 /************************************************************************/
1119 find_waitable_handle (HANDLE h)
1122 for (i = 0; i < mswindows_waitable_count; ++i)
1123 if (mswindows_waitable_handles[i] == h)
1130 add_waitable_handle (HANDLE h)
1132 assert (find_waitable_handle (h) < 0);
1133 if (mswindows_waitable_count == MAX_WAITABLE)
1136 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1141 remove_waitable_handle (HANDLE h)
1143 int ix = find_waitable_handle (h);
1147 mswindows_waitable_handles [ix] =
1148 mswindows_waitable_handles [--mswindows_waitable_count];
1150 #endif /* HAVE_MSG_SELECT */
1153 /************************************************************************/
1155 /************************************************************************/
1158 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1159 Lisp_Object u_n_u_s_e_d)
1161 mswindows_error_caught_in_modal_loop = cons_sig_data;
1166 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1171 ++mswindows_in_modal_loop;
1172 tmp = condition_case_1 (Qt,
1174 mswindows_modal_loop_error_handler, Qnil);
1175 --mswindows_in_modal_loop;
1181 mswindows_unmodalize_signal_maybe (void)
1183 if (!NILP (mswindows_error_caught_in_modal_loop))
1185 /* Got an error while messages were pumped while
1186 in window procedure - have to resignal */
1187 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1188 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1189 mswindows_error_caught_in_modal_loop = Qnil;
1190 Fsignal (sym, data);
1195 * This is an unsafe part of event pump, guarded by
1196 * condition_case. See mswindows_pump_outstanding_events
1199 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1201 /* This function can call lisp */
1202 Lisp_Object event = Fmake_event (Qnil, Qnil);
1203 struct gcpro gcpro1;
1204 int do_redisplay = 0;
1207 while (detect_input_pending ())
1209 Fnext_event (event, Qnil);
1210 Fdispatch_event (event);
1217 Fdeallocate_event (event);
1220 /* Qt becomes return value of mswindows_pump_outstanding_events
1226 * This function pumps emacs events, while available, by using
1227 * next_message/dispatch_message loop. Errors are trapped around
1228 * the loop so the function always returns.
1230 * Windows message queue is not looked into during the call,
1231 * neither are waitable handles checked. The function pumps
1232 * thus only dispatch events already queued, as well as those
1233 * resulted in dispatching thereof. This is done by setting
1234 * module local variable mswindows_in_modal_loop to nonzero.
1236 * Return value is Qt if no errors was trapped, or Qunbound if
1237 * there was an error.
1239 * In case of error, a cons representing the error, in the
1240 * form (SIGNAL . DATA), is stored in the module local variable
1241 * mswindows_error_caught_in_modal_loop. This error is signaled
1242 * again when DispatchMessage returns. Thus, Windows internal
1243 * modal loops are protected against throws, which are proven
1244 * to corrupt internal Windows structures.
1246 * In case of success, mswindows_error_caught_in_modal_loop is
1249 * If the value of mswindows_error_caught_in_modal_loop is not
1250 * nil already upon entry, the function just returns non-nil.
1251 * This situation means that a new event has been queued while
1252 * in cancel mode. The event will be dequeued on the next regular
1253 * call of next-event; the pump is off since error is caught.
1254 * The caller must *unconditionally* cancel modal loop if the
1255 * value returned by this function is nil. Otherwise, everything
1256 * will become frozen until the modal loop exits under normal
1257 * condition (scrollbar drag is released, menu closed etc.)
1260 mswindows_pump_outstanding_events (void)
1262 /* This function can call lisp */
1264 Lisp_Object result = Qt;
1265 struct gcpro gcpro1;
1268 if (NILP(mswindows_error_caught_in_modal_loop))
1269 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1275 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1276 * QUITP, and are interesting in keyboard messages only.
1279 mswindows_drain_windows_queue (void)
1283 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1284 assert (!mswindows_in_modal_loop);
1286 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1288 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1290 /* Don't translate messages destined for a dialog box, this
1291 makes keyboard traversal work. I think?? */
1292 if (mswindows_is_dialog_msg (&msg))
1294 mswindows_unmodalize_signal_maybe ();
1298 /* We have to translate messages that are not sent to an XEmacs
1299 frame. This is so that key presses work ok in things like
1300 edit fields. However, we *musn't* translate message for XEmacs
1301 frames as this is handled in the wnd proc.
1302 We also have to avoid generating paint magic events for windows
1303 that aren't XEmacs frames */
1304 /* GetClassName will truncate a longer class name. By adding one
1305 extra character, we are forcing textual comparison to fail
1306 if the name is longer than XEMACS_CLASS */
1308 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1309 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1311 /* Not an XEmacs frame */
1312 TranslateMessage (&msg);
1314 else if (msg.message == WM_PAINT)
1316 struct mswindows_frame* msframe;
1318 /* hdc will be NULL unless this is a subwindow - in which case we
1319 shouldn't have received a paint message for it here. */
1320 assert (msg.wParam == 0);
1322 /* Queue a magic event for handling when safe */
1324 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1325 if (!msframe->paint_pending)
1327 msframe->paint_pending = 1;
1328 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1330 /* Don't dispatch. WM_PAINT is always the last message in the
1331 queue so it's OK to just return. */
1334 DispatchMessage (&msg);
1335 mswindows_unmodalize_signal_maybe ();
1340 * This is a special flavor of the mswindows_need_event function,
1341 * used while in event pump. Actually, there is only kind of events
1342 * allowed while in event pump: a timer. An attempt to fetch any
1343 * other event leads to a deadlock, as there's no source of user input
1344 * ('cause event pump mirrors windows modal loop, which is a sole
1345 * owner of thread message queue).
1347 * To detect this, we use a counter of active timers, and allow
1348 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1349 * which will never come when there are no pending timers, which leads
1350 * to deadlock, we simply signal an error.
1352 * It might be possible to combine this with mswindows_drain_windows_queue
1353 * which fetches events when not in a modal loop. It's not clear
1354 * whether the result would be more complex than is justified.
1357 mswindows_need_event_in_modal_loop (int badly_p)
1361 /* Check if already have one */
1362 if (!NILP (mswindows_u_dispatch_event_queue)
1363 || !NILP (mswindows_s_dispatch_event_queue))
1366 /* No event is ok */
1370 /* We do not check the _u_ queue, because timers go to _s_ */
1371 while (NILP (mswindows_s_dispatch_event_queue))
1373 /* We'll deadlock if go waiting */
1374 if (mswindows_pending_timers_count == 0)
1375 error ("Deadlock due to an attempt to call next-event in a wrong context");
1377 /* Fetch and dispatch any pending timers */
1378 if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1379 DispatchMessage (&msg);
1384 * This drains the event queue and fills up two internal queues until
1385 * an event of a type specified by USER_P is retrieved.
1388 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1391 mswindows_need_event (int badly_p)
1395 while (NILP (mswindows_u_dispatch_event_queue)
1396 && NILP (mswindows_s_dispatch_event_queue))
1398 #ifdef HAVE_MSG_SELECT
1400 SELECT_TYPE temp_mask = input_wait_mask;
1401 EMACS_TIME sometime;
1402 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1405 pointer_to_this = 0;
1408 EMACS_SET_SECS_USECS (sometime, 0, 0);
1409 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1410 pointer_to_this = &select_time_to_block;
1411 if (mswindows_in_modal_loop)
1412 /* In modal loop with badly_p false, don't care about
1414 FD_CLR (windows_fd, &temp_mask);
1417 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1422 return; /* timeout */
1424 else if (active > 0)
1426 if (FD_ISSET (windows_fd, &temp_mask))
1428 if (mswindows_in_modal_loop)
1429 mswindows_need_event_in_modal_loop (badly_p);
1431 mswindows_drain_windows_queue ();
1436 /* Look for a TTY event */
1437 for (i = 0; i < MAXDESC-1; i++)
1439 /* To avoid race conditions (among other things, an infinite
1440 loop when called from Fdiscard_input()), we must return
1441 user events ahead of process events. */
1442 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1444 struct console *c = tty_find_console_from_fd (i);
1445 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1446 Lisp_Event* event = XEVENT (emacs_event);
1449 if (read_event_from_tty_or_stream_desc (event, c, i))
1451 mswindows_enqueue_dispatch_event (emacs_event);
1457 /* Look for a process event */
1458 for (i = 0; i < MAXDESC-1; i++)
1460 if (FD_ISSET (i, &temp_mask))
1462 if (FD_ISSET (i, &process_only_mask))
1465 get_process_from_usid (FD_TO_USID(i));
1467 mswindows_enqueue_process_event (p);
1471 /* We might get here when a fake event came
1472 through a signal. Return a dummy event, so
1473 that a cycle of the command loop will
1475 drain_signal_event_pipe ();
1476 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1482 else if (active==-1)
1486 /* something bad happened */
1495 /* Now try getting a message or process event */
1497 if (mswindows_in_modal_loop)
1498 /* In a modal loop, only look for timer events, and only if
1499 we really need one. */
1502 what_events = QS_TIMER;
1507 /* Look for any event */
1508 what_events = QS_ALLINPUT;
1510 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1511 mswindows_waitable_handles,
1512 FALSE, badly_p ? INFINITE : 0,
1515 /* This will assert if handle being waited for becomes abandoned.
1516 Not the case currently tho */
1517 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1518 (active >= WAIT_OBJECT_0 &&
1519 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1521 if (active == WAIT_TIMEOUT)
1523 /* No luck trying - just return what we've already got */
1526 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1528 /* Got your message, thanks */
1529 if (mswindows_in_modal_loop)
1530 mswindows_need_event_in_modal_loop (badly_p);
1532 mswindows_drain_windows_queue ();
1536 int ix = active - WAIT_OBJECT_0;
1537 /* First, try to find which process' output has signaled */
1539 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1542 /* Found a signaled process input handle */
1543 mswindows_enqueue_process_event (p);
1547 /* None. This means that the process handle itself has signaled.
1548 Remove the handle from the wait vector, and make status_notify
1549 note the exited process. First find the process object if
1551 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
1552 if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
1553 mswindows_waitable_handles [ix])
1555 mswindows_waitable_handles [ix] =
1556 mswindows_waitable_handles [--mswindows_waitable_count];
1557 kick_status_notify ();
1558 /* We need to return a process event here so that
1559 (1) accept-process-output will return when called on this
1560 process, and (2) status notifications will happen in
1561 accept-process-output, sleep-for, and sit-for. */
1562 /* #### horrible kludge till my real process fixes go in.
1563 #### Replaced with a slightly less horrible kluge that
1564 at least finds the right process instead of axing the
1565 first one on the list.
1567 if (!NILP (vproctail))
1569 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1571 else /* trash me soon. */
1572 /* Have to return something: there may be no accompanying
1574 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1581 /************************************************************************/
1582 /* Event generators */
1583 /************************************************************************/
1586 * Callback procedure for synchronous timer messages
1588 static void CALLBACK
1589 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1591 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1592 Lisp_Event *event = XEVENT (emacs_event);
1594 if (KillTimer (NULL, id_timer))
1595 --mswindows_pending_timers_count;
1597 event->channel = Qnil;
1598 event->timestamp = dwtime;
1599 event->event_type = timeout_event;
1600 event->event.timeout.interval_id = id_timer;
1601 event->event.timeout.function = Qnil;
1602 event->event.timeout.object = Qnil;
1604 mswindows_enqueue_dispatch_event (emacs_event);
1608 * Callback procedure for dde messages
1610 * We execute a dde Open("file") by simulating a file drop, so dde support
1611 * depends on dnd support.
1613 #ifdef HAVE_DRAGNDROP
1614 extern int mswindows_dde_enable;
1617 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1618 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1619 DWORD dwData1, DWORD dwData2)
1624 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1625 return (HDDEDATA)TRUE;
1626 return (HDDEDATA)FALSE;
1628 case XTYP_WILDCONNECT:
1630 /* We only support one {service,topic} pair */
1631 HSZPAIR pairs[2] = {
1632 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1634 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1635 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1636 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1637 sizeof (pairs), 0L, 0, uFmt, 0));
1639 return (HDDEDATA)NULL;
1642 if (!mswindows_dde_enable)
1643 return (HDDEDATA) DDE_FBUSY;
1645 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1647 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1648 LPBYTE cmd = (LPBYTE) alloca (len+1);
1651 struct gcpro gcpro1, gcpro2;
1652 Lisp_Object l_dndlist = Qnil;
1653 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1654 Lisp_Object frmcons, devcons, concons;
1655 Lisp_Event *event = XEVENT (emacs_event);
1657 DdeGetData (hdata, cmd, len, 0);
1659 DdeFreeDataHandle (hdata);
1661 /* Check syntax & that it's an [Open("foo")] command, which we
1662 * treat like a file drop */
1663 /* #### Ought to be generalised and accept some other commands */
1666 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1667 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1668 return DDE_FNOTPROCESSED;
1669 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1672 if (*cmd!='(' || *(cmd+1)!='\"')
1673 return DDE_FNOTPROCESSED;
1675 while (*end && *end!='\"')
1678 return DDE_FNOTPROCESSED;
1681 return DDE_FNOTPROCESSED;
1685 return DDE_FNOTPROCESSED;
1688 filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5);
1689 strcpy (filename, "file:");
1690 cygwin_win32_to_posix_path_list (cmd, filename+5);
1692 dostounix_filename (cmd);
1693 filename = alloca (strlen (cmd)+6);
1694 strcpy (filename, "file:");
1695 strcat (filename, cmd);
1697 GCPRO2 (emacs_event, l_dndlist);
1698 l_dndlist = make_string (filename, strlen (filename));
1700 /* Find a mswindows frame */
1701 event->channel = Qnil;
1702 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1704 Lisp_Object frame = XCAR (frmcons);
1705 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1706 event->channel = frame;
1708 assert (!NILP (event->channel));
1710 event->timestamp = GetTickCount();
1711 event->event_type = misc_user_event;
1712 event->event.misc.button = 1;
1713 event->event.misc.modifiers = 0;
1714 event->event.misc.x = -1;
1715 event->event.misc.y = -1;
1716 event->event.misc.function = Qdragdrop_drop_dispatch;
1717 event->event.misc.object = Fcons (Qdragdrop_URL,
1718 Fcons (l_dndlist, Qnil));
1719 mswindows_enqueue_dispatch_event (emacs_event);
1721 return (HDDEDATA) DDE_FACK;
1723 DdeFreeDataHandle (hdata);
1724 return (HDDEDATA) DDE_FNOTPROCESSED;
1727 return (HDDEDATA) NULL;
1733 * Helper to do repainting - repaints can happen both from the windows
1734 * procedure and from magic events
1737 mswindows_handle_paint (struct frame *frame)
1739 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1741 /* According to the docs we need to check GetUpdateRect() before
1742 actually doing a WM_PAINT */
1743 if (GetUpdateRect (hwnd, NULL, FALSE))
1745 PAINTSTRUCT paintStruct;
1746 int x, y, width, height;
1748 BeginPaint (hwnd, &paintStruct);
1749 x = paintStruct.rcPaint.left;
1750 y = paintStruct.rcPaint.top;
1751 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1752 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1753 /* Normally we want to ignore expose events when child
1754 windows are unmapped, however once we are in the guts of
1755 WM_PAINT we need to make sure that we don't register
1756 unmaps then because they will not actually occur. */
1757 /* #### commenting out the next line seems to fix some problems
1758 but not all. only andy currently understands this stuff and
1759 he needs to review it more carefully. --ben */
1760 if (!check_for_ignored_expose (frame, x, y, width, height))
1762 hold_ignored_expose_registration = 1;
1763 mswindows_redraw_exposed_area (frame, x, y, width, height);
1764 hold_ignored_expose_registration = 0;
1766 EndPaint (hwnd, &paintStruct);
1771 * Returns 1 if a key is a real modifier or special key, which
1772 * is better handled by DefWindowProc
1775 key_needs_default_processing_p (UINT vkey)
1777 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1778 /* if we let ALT activate the menu like this, then sticky ALT-modified
1779 keystrokes become impossible. */
1780 && !modifier_keys_are_sticky)
1786 /* key-handling code is always ugly. It just ends up working out
1789 #### Most of the sticky-modifier code below is copied from similar
1790 code in event-Xt.c. They should somehow or other be merged.
1792 Here are some pointers:
1794 -- DOWN_MASK indicates which modifiers should be treated as "down"
1795 when the corresponding upstroke happens. It gets reset for
1796 a particular modifier when that modifier goes up, and reset
1797 for all modifiers when a non-modifier key is pressed. Example:
1799 I press Control-A-Shift and then release Control-A-Shift.
1800 I want the Shift key to be sticky but not the Control key.
1802 -- If a modifier key is sticky, I can unstick it by pressing
1803 the modifier key again. */
1805 static WPARAM last_downkey;
1806 static int need_to_add_mask, down_mask;
1808 #define XEMSW_LCONTROL (1<<0)
1809 #define XEMSW_RCONTROL (1<<1)
1810 #define XEMSW_LSHIFT (1<<2)
1811 #define XEMSW_RSHIFT (1<<3)
1812 #define XEMSW_LMENU (1<<4)
1813 #define XEMSW_RMENU (1<<5)
1816 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1817 int downp, int keyp)
1821 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1825 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1826 wParam == VK_RCONTROL ||
1827 wParam == VK_MENU || wParam == VK_LMENU ||
1828 wParam == VK_RMENU ||
1829 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1830 wParam == VK_RSHIFT)))
1831 { /* Not a modifier key */
1832 if (downp && keyp && !last_downkey)
1833 last_downkey = wParam;
1834 /* If I hold press-and-release the Control key and then press
1835 and hold down the right arrow, I want it to auto-repeat
1836 Control-Right. On the other hand, if I do the same but
1837 manually press the Right arrow a bunch of times, I want
1838 to see one Control-Right and then a bunch of Rights.
1839 This means that we need to distinguish between an
1840 auto-repeated key and a key pressed and released a bunch
1842 else if ((downp && !keyp) ||
1843 (downp && keyp && last_downkey &&
1844 (wParam != last_downkey ||
1845 /* the "previous key state" bit indicates autorepeat */
1846 ! (lParam & (1 << 30)))))
1848 need_to_add_mask = 0;
1854 mods = need_to_add_mask;
1856 else /* Modifier key pressed */
1858 /* If a non-modifier key was pressed in the middle of a bunch
1859 of modifiers, then it unsticks all the modifiers that were
1860 previously pressed. We cannot unstick the modifiers until
1861 now because we want to check for auto-repeat of the
1862 non-modifier key. */
1867 need_to_add_mask = 0;
1870 #define FROB(mask) \
1872 if (downp && keyp) \
1874 /* If modifier key is already sticky, \
1875 then unstick it. Note that we do \
1876 not test down_mask to deal with the \
1877 unlikely but possible case that the \
1878 modifier key auto-repeats. */ \
1879 if (need_to_add_mask & mask) \
1881 need_to_add_mask &= ~mask; \
1882 down_mask &= ~mask; \
1885 down_mask |= mask; \
1889 if (down_mask & mask) \
1891 down_mask &= ~mask; \
1892 need_to_add_mask |= mask; \
1897 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1898 || wParam == VK_RCONTROL)
1899 FROB (XEMSW_RCONTROL);
1900 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1901 || wParam == VK_LCONTROL)
1902 FROB (XEMSW_LCONTROL);
1904 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1905 || wParam == VK_RSHIFT)
1906 FROB (XEMSW_RSHIFT);
1907 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1908 || wParam == VK_LSHIFT)
1909 FROB (XEMSW_LSHIFT);
1911 if ((wParam == VK_MENU && (lParam & 0x1000000))
1912 || wParam == VK_RMENU)
1914 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1915 || wParam == VK_LMENU)
1924 GetKeyboardState (keymap);
1926 if (mods & XEMSW_LCONTROL)
1928 keymap [VK_CONTROL] |= 0x80;
1929 keymap [VK_LCONTROL] |= 0x80;
1931 if (mods & XEMSW_RCONTROL)
1933 keymap [VK_CONTROL] |= 0x80;
1934 keymap [VK_RCONTROL] |= 0x80;
1937 if (mods & XEMSW_LSHIFT)
1939 keymap [VK_SHIFT] |= 0x80;
1940 keymap [VK_LSHIFT] |= 0x80;
1942 if (mods & XEMSW_RSHIFT)
1944 keymap [VK_SHIFT] |= 0x80;
1945 keymap [VK_RSHIFT] |= 0x80;
1948 if (mods & XEMSW_LMENU)
1950 keymap [VK_MENU] |= 0x80;
1951 keymap [VK_LMENU] |= 0x80;
1953 if (mods & XEMSW_RMENU)
1955 keymap [VK_MENU] |= 0x80;
1956 keymap [VK_RMENU] |= 0x80;
1959 SetKeyboardState (keymap);
1967 clear_sticky_modifiers (void)
1969 need_to_add_mask = 0;
1979 output_modifier_keyboard_state (void)
1983 GetKeyboardState (keymap);
1985 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1986 keymap[VK_MENU] & 0x80 ? 1 : 0,
1987 keymap[VK_MENU] & 0x1 ? 1 : 0,
1988 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1989 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1990 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1991 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1992 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1993 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1994 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1995 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1996 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1997 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1998 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1999 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
2000 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
2001 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
2002 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
2003 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
2004 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
2005 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
2010 /* try to debug the stuck-alt-key problem.
2012 #### this happens only inconsistently, and may only happen when using
2013 StickyKeys in the Win2000 accessibility section of the control panel,
2014 which is extremely broken for other reasons. */
2017 output_alt_keyboard_state (void)
2021 // SHORT asyncstate[3];
2023 GetKeyboardState (keymap);
2024 keystate[0] = GetKeyState (VK_MENU);
2025 keystate[1] = GetKeyState (VK_LMENU);
2026 keystate[2] = GetKeyState (VK_RMENU);
2027 /* Doing this interferes with key processing. */
2028 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2029 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2030 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2032 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2033 keymap[VK_MENU] & 0x80 ? 1 : 0,
2034 keymap[VK_MENU] & 0x1 ? 1 : 0,
2035 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2036 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2037 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2038 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2039 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2040 keystate[0] & 0x8000 ? 1 : 0,
2041 keystate[0] & 0x1 ? 1 : 0,
2042 keystate[1] & 0x8000 ? 1 : 0,
2043 keystate[1] & 0x1 ? 1 : 0,
2044 keystate[2] & 0x8000 ? 1 : 0,
2045 keystate[2] & 0x1 ? 1 : 0);
2046 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2047 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2048 /* asyncstate[0] & 0x1 ? 1 : 0, */
2049 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2050 /* asyncstate[1] & 0x1 ? 1 : 0, */
2051 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2052 /* asyncstate[2] & 0x1 ? 1 : 0); */
2055 #endif /* DEBUG_XEMACS */
2059 * The windows procedure for the window class XEMACS_CLASS
2062 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2064 /* Note: Remember to initialize emacs_event and event before use.
2065 This code calls code that can GC. You must GCPRO before calling such code. */
2066 Lisp_Object emacs_event = Qnil;
2067 Lisp_Object fobj = Qnil;
2070 struct frame *frame;
2071 struct mswindows_frame* msframe;
2073 /* If you hit this, rewrite the offending API call to occur after GC,
2074 using register_post_gc_action(). */
2075 assert (!gc_in_progress);
2078 if (debug_mswindows_events)
2079 debug_output_mswin_message (hwnd, message_, wParam, lParam);
2080 #endif /* DEBUG_XEMACS */
2082 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2085 case WM_DESTROYCLIPBOARD:
2086 /* We own the clipboard and someone else wants it. Delete our
2087 cached copy of the clipboard contents so we'll ask for it from
2088 Windows again when someone does a paste, and destroy any memory
2089 objects we hold on the clipboard that are not in the list of types
2090 that Windows will delete itself. */
2091 mswindows_destroy_selection (QCLIPBOARD);
2092 handle_selection_clear (QCLIPBOARD);
2096 /* Erase background only during non-dynamic sizing */
2097 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2098 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2103 fobj = mswindows_find_frame (hwnd);
2104 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2110 /* See Win95 comment under WM_KEYDOWN */
2113 int should_set_keymap = 0;
2116 if (debug_mswindows_events > 2)
2117 output_alt_keyboard_state ();
2118 #endif /* DEBUG_XEMACS */
2120 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2121 if (wParam == VK_CONTROL)
2123 GetKeyboardState (keymap);
2124 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2125 should_set_keymap = 1;
2127 else if (wParam == VK_MENU)
2129 GetKeyboardState (keymap);
2130 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2131 should_set_keymap = 1;
2134 if (should_set_keymap)
2135 // && (message_ != WM_SYSKEYUP
2136 // || NILP (Vmenu_accelerator_enabled)))
2137 SetKeyboardState (keymap);
2141 if (key_needs_default_processing_p (wParam))
2149 /* In some locales the right-hand Alt key is labelled AltGr. This key
2150 * should produce alternative characters when combined with another key.
2151 * eg on a German keyboard pressing AltGr+q should produce '@'.
2152 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2153 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2154 * it translates as if AltGr were down.
2155 * We get round this by removing all modifiers from the keymap before
2156 * calling TranslateMessage() unless AltGr is *really* down. */
2158 BYTE keymap_trans[256];
2159 BYTE keymap_orig[256];
2160 BYTE keymap_sticky[256];
2161 int has_AltGr = mswindows_current_layout_has_AltGr ();
2162 int mods = 0, mods_with_shift = 0;
2163 int extendedp = lParam & 0x1000000;
2168 if (debug_mswindows_events > 2)
2169 output_alt_keyboard_state ();
2170 #endif /* DEBUG_XEMACS */
2172 GetKeyboardState (keymap_orig);
2173 frame = XFRAME (mswindows_find_frame (hwnd));
2174 if ((sticky_changed =
2175 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2177 GetKeyboardState (keymap_sticky);
2178 if (keymap_sticky[VK_MENU] & 0x80)
2180 message_ = WM_SYSKEYDOWN;
2181 /* We have to set the "context bit" so that the
2182 TranslateMessage() call below that generates the
2183 SYSCHAR message does its thing; see the documentation
2189 memcpy (keymap_sticky, keymap_orig, 256);
2191 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2192 mods_with_shift = mods;
2194 /* Handle non-printables */
2195 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2198 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2200 SetKeyboardState (keymap_orig);
2202 else /* Normal keys & modifiers */
2205 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2206 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2208 int potential_accelerator = 0;
2209 int got_accelerator = 0;
2212 msg.message = message_;
2213 msg.wParam = wParam;
2214 msg.lParam = lParam;
2215 msg.time = GetMessageTime();
2218 /* GetKeyboardState() does not work as documented on Win95. We have
2219 * to loosely track Left and Right modifiers on behalf of the OS,
2220 * without screwing up Windows NT which tracks them properly. */
2221 if (wParam == VK_CONTROL)
2223 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2224 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2226 else if (wParam == VK_MENU)
2228 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2229 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2232 if (!NILP (Vmenu_accelerator_enabled) &&
2233 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2234 potential_accelerator = 1;
2236 /* Remove shift modifier from an ascii character */
2237 mods &= ~XEMACS_MOD_SHIFT;
2239 memcpy (keymap_trans, keymap_sticky, 256);
2241 /* Clear control and alt modifiers unless AltGr is pressed */
2242 keymap_trans[VK_RCONTROL] = 0;
2243 keymap_trans[VK_LMENU] = 0;
2244 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2245 || !(keymap_trans[VK_RMENU] & 0x80))
2247 keymap_trans[VK_LCONTROL] = 0;
2248 keymap_trans[VK_CONTROL] = 0;
2249 keymap_trans[VK_RMENU] = 0;
2250 keymap_trans[VK_MENU] = 0;
2252 SetKeyboardState (keymap_trans);
2254 /* Maybe generate some WM_[SYS]CHARs in the queue */
2255 TranslateMessage (&msg);
2257 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2258 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2261 int mods_with_quit = mods;
2262 WPARAM ch = tranmsg.wParam;
2265 if (debug_mswindows_events)
2268 debug_output_mswin_message (tranmsg.hwnd, tranmsg.message,
2272 #endif /* DEBUG_XEMACS */
2274 /* If a quit char with no modifiers other than control and
2275 shift, then mark it with a fake modifier, which is removed
2276 upon dequeueing the event */
2277 /* !!#### Fix this in my mule ws -- replace current_buffer
2279 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2280 && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2281 DOWNCASE (current_buffer, ch))
2282 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2283 && DOWNCASE (current_buffer, quit_ch) ==
2284 DOWNCASE (current_buffer, ch)))
2285 && ((mods_with_shift &
2286 ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2289 mods_with_quit |= FAKE_MOD_QUIT;
2290 if (mods_with_shift & XEMACS_MOD_SHIFT)
2291 mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2292 mswindows_quit_chars_count++;
2294 else if (potential_accelerator && !got_accelerator &&
2295 mswindows_char_is_accelerator (frame, ch))
2297 got_accelerator = 1;
2300 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2304 /* This generates WM_SYSCHAR messages, which are interpreted
2305 by DefWindowProc as the menu selections. */
2306 if (got_accelerator)
2308 SetKeyboardState (keymap_sticky);
2309 TranslateMessage (&msg);
2310 SetKeyboardState (keymap_orig);
2314 SetKeyboardState (keymap_orig);
2318 if (key_needs_default_processing_p (wParam))
2323 case WM_MBUTTONDOWN:
2325 /* Real middle mouse button has nothing to do with emulated one:
2326 if one wants to exercise fingers playing chords on the mouse,
2327 he is allowed to do that! */
2328 mswindows_enqueue_mouse_button_event (hwnd, message_,
2329 MAKEPOINTS (lParam),
2330 wParam &~ MK_MBUTTON,
2335 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2336 msframe->last_click_time = GetMessageTime();
2338 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2339 msframe->button2_need_lbutton = 0;
2340 if (msframe->ignore_next_lbutton_up)
2342 msframe->ignore_next_lbutton_up = 0;
2344 else if (msframe->button2_is_down)
2346 msframe->button2_is_down = 0;
2347 msframe->ignore_next_rbutton_up = 1;
2348 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2349 MAKEPOINTS (lParam),
2351 &~ (MK_LBUTTON | MK_MBUTTON
2357 if (msframe->button2_need_rbutton)
2359 msframe->button2_need_rbutton = 0;
2360 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2361 MAKEPOINTS (lParam),
2362 wParam &~ MK_LBUTTON,
2365 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2366 MAKEPOINTS (lParam),
2367 wParam &~ MK_LBUTTON,
2373 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2374 msframe->last_click_time = GetMessageTime();
2376 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2377 msframe->button2_need_rbutton = 0;
2378 if (msframe->ignore_next_rbutton_up)
2380 msframe->ignore_next_rbutton_up = 0;
2382 else if (msframe->button2_is_down)
2384 msframe->button2_is_down = 0;
2385 msframe->ignore_next_lbutton_up = 1;
2386 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2387 MAKEPOINTS (lParam),
2389 &~ (MK_LBUTTON | MK_MBUTTON
2395 if (msframe->button2_need_lbutton)
2397 msframe->button2_need_lbutton = 0;
2398 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2399 MAKEPOINTS (lParam),
2400 wParam &~ MK_RBUTTON,
2403 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2404 MAKEPOINTS (lParam),
2405 wParam &~ MK_RBUTTON,
2410 case WM_LBUTTONDOWN:
2411 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2413 if (msframe->button2_need_lbutton)
2415 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2416 msframe->button2_need_lbutton = 0;
2417 msframe->button2_need_rbutton = 0;
2418 if (mswindows_button2_near_enough (msframe->last_click_point,
2419 MAKEPOINTS (lParam)))
2421 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2422 MAKEPOINTS (lParam),
2424 &~ (MK_LBUTTON | MK_MBUTTON
2427 msframe->button2_is_down = 1;
2431 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2432 msframe->last_click_point,
2433 msframe->last_click_mods
2435 msframe->last_click_time);
2436 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2437 MAKEPOINTS (lParam),
2438 wParam &~ MK_LBUTTON,
2444 mswindows_set_chord_timer (hwnd);
2445 msframe->button2_need_rbutton = 1;
2446 msframe->last_click_point = MAKEPOINTS (lParam);
2447 msframe->last_click_mods = wParam;
2449 msframe->last_click_time = GetMessageTime();
2452 case WM_RBUTTONDOWN:
2453 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2455 if (msframe->button2_need_rbutton)
2457 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2458 msframe->button2_need_lbutton = 0;
2459 msframe->button2_need_rbutton = 0;
2460 if (mswindows_button2_near_enough (msframe->last_click_point,
2461 MAKEPOINTS (lParam)))
2463 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2464 MAKEPOINTS (lParam),
2466 &~ (MK_LBUTTON | MK_MBUTTON
2469 msframe->button2_is_down = 1;
2473 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2474 msframe->last_click_point,
2475 msframe->last_click_mods
2477 msframe->last_click_time);
2478 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2479 MAKEPOINTS (lParam),
2480 wParam &~ MK_RBUTTON,
2486 mswindows_set_chord_timer (hwnd);
2487 msframe->button2_need_lbutton = 1;
2488 msframe->last_click_point = MAKEPOINTS (lParam);
2489 msframe->last_click_mods = wParam;
2491 msframe->last_click_time = GetMessageTime();
2495 if (wParam == BUTTON_2_TIMER_ID)
2497 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2498 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2500 if (msframe->button2_need_lbutton)
2502 msframe->button2_need_lbutton = 0;
2503 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2504 msframe->last_click_point,
2505 msframe->last_click_mods
2507 msframe->last_click_time);
2509 else if (msframe->button2_need_rbutton)
2511 msframe->button2_need_rbutton = 0;
2512 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2513 msframe->last_click_point,
2514 msframe->last_click_mods
2516 msframe->last_click_time);
2520 assert ("Spurious timer fired" == 0);
2524 /* Optimization: don't report mouse movement while size is changing */
2525 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2526 if (!msframe->sizing)
2528 /* When waiting for the second mouse button to finish
2529 button2 emulation, and have moved too far, just pretend
2530 as if timer has expired. This improves drag-select feedback */
2531 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2532 && !mswindows_button2_near_enough (msframe->last_click_point,
2533 MAKEPOINTS (lParam)))
2535 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2536 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2539 emacs_event = Fmake_event (Qnil, Qnil);
2540 event = XEVENT(emacs_event);
2542 event->channel = mswindows_find_frame(hwnd);
2543 event->timestamp = GetMessageTime();
2544 event->event_type = pointer_motion_event;
2545 event->event.motion.x = MAKEPOINTS(lParam).x;
2546 event->event.motion.y = MAKEPOINTS(lParam).y;
2547 event->event.motion.modifiers =
2548 mswindows_modifier_state (NULL, wParam, 0);
2550 mswindows_enqueue_dispatch_event (emacs_event);
2556 /* Queue a `cancel-mode-internal' misc user event, so mouse
2557 selection would be canceled if any */
2558 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2559 Qcancel_mode_internal, Qnil);
2564 LPNMHDR nmhdr = (LPNMHDR)lParam;
2566 if (nmhdr->code == TTN_NEEDTEXT)
2568 #ifdef HAVE_TOOLBARS
2569 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2572 /* find out which toolbar */
2573 frame = XFRAME (mswindows_find_frame (hwnd));
2574 btext = mswindows_get_toolbar_button_text ( frame,
2577 tttext->lpszText = NULL;
2578 tttext->hinst = NULL;
2582 /* I think this is safe since the text will only go away
2583 when the toolbar does...*/
2584 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2588 /* handle tree view callbacks */
2589 else if (nmhdr->code == TVN_SELCHANGED)
2591 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2592 frame = XFRAME (mswindows_find_frame (hwnd));
2593 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2595 /* handle tab control callbacks */
2596 else if (nmhdr->code == TCN_SELCHANGE)
2599 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2600 frame = XFRAME (mswindows_find_frame (hwnd));
2602 item.mask = TCIF_PARAM;
2603 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2606 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2612 /* hdc will be NULL unless this is a subwindow - in which case we
2613 shouldn't have received a paint message for it here. */
2614 assert (wParam == 0);
2616 /* Can't queue a magic event because windows goes modal and sends paint
2617 messages directly to the windows procedure when doing solid drags
2618 and the message queue doesn't get processed. */
2619 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2622 case WM_WINDOWPOSCHANGED:
2623 /* This is sent before WM_SIZE; in fact, the processing of this
2624 by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when
2625 a window is hidden (make-frame-invisible), so we need to process
2626 this and update the state flags. */
2628 fobj = mswindows_find_frame (hwnd);
2629 frame = XFRAME (fobj);
2630 if (IsIconic (hwnd))
2632 FRAME_VISIBLE_P (frame) = 0;
2633 FRAME_ICONIFIED_P (frame) = 1;
2635 else if (IsWindowVisible (hwnd))
2637 FRAME_VISIBLE_P (frame) = 1;
2638 FRAME_ICONIFIED_P (frame) = 0;
2642 FRAME_VISIBLE_P (frame) = 0;
2643 FRAME_ICONIFIED_P (frame) = 0;
2646 return DefWindowProc (hwnd, message_, wParam, lParam);
2650 /* We only care about this message if our size has really changed */
2651 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2656 fobj = mswindows_find_frame (hwnd);
2657 frame = XFRAME (fobj);
2658 msframe = FRAME_MSWINDOWS_DATA (frame);
2660 /* We cannot handle frame map and unmap hooks right in
2661 this routine, because these may throw. We queue
2662 magic events to run these hooks instead - kkm */
2664 if (wParam==SIZE_MINIMIZED)
2667 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2671 GetClientRect(hwnd, &rect);
2672 FRAME_PIXWIDTH(frame) = rect.right;
2673 FRAME_PIXHEIGHT(frame) = rect.bottom;
2675 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2676 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2677 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2679 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2680 change_frame_size (frame, rows, columns, 1);
2682 /* If we are inside frame creation, we have to apply geometric
2684 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2686 /* Yes, we have to size again */
2687 mswindows_size_frame_internal ( frame,
2688 FRAME_MSWINDOWS_TARGET_RECT
2690 /* Reset so we do not get here again. The SetWindowPos call in
2691 * mswindows_size_frame_internal can cause recursion here. */
2692 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2694 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2695 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2700 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2701 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2703 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2710 case WM_DISPLAYCHANGE:
2713 DWORD message_tick = GetMessageTime ();
2715 fobj = mswindows_find_frame (hwnd);
2716 frame = XFRAME (fobj);
2717 d = XDEVICE (FRAME_DEVICE (frame));
2719 /* Do this only once per message. XEmacs can receive this message
2720 through as many frames as it currently has open. Message time
2721 will be the same for all these messages. Despite extreme
2722 efficiency, the code below has about one in 4 billion
2723 probability that the HDC is not recreated, provided that
2724 XEmacs is running sufficiently longer than 52 days. */
2725 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2727 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2728 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2729 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2734 /* Misc magic events which only require that the frame be identified */
2737 mswindows_enqueue_magic_event (hwnd, message_);
2740 case WM_WINDOWPOSCHANGING:
2742 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2743 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2744 GetWindowPlacement(hwnd, &wpl);
2746 /* Only interested if size is changing and we're not being iconified */
2747 if (wpl.showCmd != SW_SHOWMINIMIZED
2748 && wpl.showCmd != SW_SHOWMAXIMIZED
2749 && !(wp->flags & SWP_NOSIZE))
2751 RECT ncsize = { 0, 0, 0, 0 };
2752 int pixwidth, pixheight;
2753 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2754 GetMenu(hwnd) != NULL,
2755 GetWindowLong (hwnd, GWL_EXSTYLE));
2757 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2758 wp->cx - (ncsize.right - ncsize.left),
2759 wp->cy - (ncsize.bottom - ncsize.top),
2760 &pixwidth, &pixheight);
2762 /* Convert client sizes to window sizes */
2763 pixwidth += (ncsize.right - ncsize.left);
2764 pixheight += (ncsize.bottom - ncsize.top);
2766 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2768 /* Adjust so that the bottom or right doesn't move if it's
2769 * the top or left that's being changed */
2771 GetWindowRect (hwnd, &rect);
2773 if (rect.left != wp->x)
2774 wp->x += wp->cx - pixwidth;
2775 if (rect.top != wp->y)
2776 wp->y += wp->cy - pixheight;
2782 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2783 window position if the user tries to track window too small */
2787 case WM_ENTERSIZEMOVE:
2788 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2789 msframe->sizing = 1;
2792 case WM_EXITSIZEMOVE:
2793 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2794 msframe->sizing = 0;
2795 /* Queue noop event */
2796 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2799 #ifdef HAVE_SCROLLBARS
2803 /* Direction of scroll is determined by scrollbar instance. */
2804 int code = (int) LOWORD(wParam);
2805 int pos = (short int) HIWORD(wParam);
2806 HWND hwndScrollBar = (HWND) lParam;
2807 struct gcpro gcpro1, gcpro2;
2809 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2810 GCPRO2 (emacs_event, fobj);
2811 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2813 /* Error during event pumping - cancel scroll */
2814 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2822 int keys = LOWORD (wParam); /* Modifier key flags */
2823 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2824 struct gcpro gcpro1, gcpro2;
2826 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2828 MAKEPOINTS (lParam)))
2830 GCPRO2 (emacs_event, fobj);
2831 if (UNBOUNDP(mswindows_pump_outstanding_events ())) /* Can GC */
2832 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2841 #ifdef HAVE_MENUBARS
2843 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2845 XFRAME (mswindows_find_frame (hwnd)))))
2846 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2849 case WM_INITMENUPOPUP:
2850 if (!HIWORD(lParam))
2852 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2854 XFRAME (mswindows_find_frame (hwnd)))))
2855 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2859 #endif /* HAVE_MENUBARS */
2863 WORD id = LOWORD (wParam);
2864 WORD nid = HIWORD (wParam);
2865 HWND cid = (HWND)lParam;
2866 frame = XFRAME (mswindows_find_frame (hwnd));
2868 #ifdef HAVE_TOOLBARS
2869 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2872 /* widgets in a buffer only eval a callback for suitable events.*/
2877 case CBN_EDITCHANGE:
2879 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2882 /* menubars always must come last since the hashtables do not
2884 #ifdef HAVE_MENUBARS
2885 if (!NILP (mswindows_handle_wm_command (frame, id)))
2889 return DefWindowProc (hwnd, message_, wParam, lParam);
2890 /* Bite me - a spurious command. This used to not be able to
2891 happen but with the introduction of widgets its now
2896 case WM_CTLCOLORBTN:
2897 case WM_CTLCOLORLISTBOX:
2898 case WM_CTLCOLOREDIT:
2899 case WM_CTLCOLORSTATIC:
2900 case WM_CTLCOLORSCROLLBAR:
2902 /* if we get an opportunity to paint a widget then do so if
2903 there is an appropriate face */
2904 HWND crtlwnd = (HWND)lParam;
2905 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2908 Lisp_Object image_instance;
2909 VOID_TO_LISP (image_instance, ii);
2910 if (IMAGE_INSTANCEP (image_instance)
2912 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2914 /* set colors for the buttons */
2915 HDC hdc = (HDC)wParam;
2916 if (last_widget_brushed != ii)
2919 DeleteObject (widget_brush);
2920 widget_brush = CreateSolidBrush
2921 (COLOR_INSTANCE_MSWINDOWS_COLOR
2924 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2925 XIMAGE_INSTANCE_FRAME (image_instance)))));
2927 last_widget_brushed = ii;
2930 COLOR_INSTANCE_MSWINDOWS_COLOR
2933 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2934 XIMAGE_INSTANCE_FRAME (image_instance)))));
2935 SetBkMode (hdc, OPAQUE);
2938 COLOR_INSTANCE_MSWINDOWS_COLOR
2941 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2942 XIMAGE_INSTANCE_FRAME (image_instance)))));
2943 return (LRESULT)widget_brush;
2949 #ifdef HAVE_DRAGNDROP
2950 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2952 UINT filecount, i, len;
2957 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2958 struct gcpro gcpro1, gcpro2, gcpro3;
2960 emacs_event = Fmake_event (Qnil, Qnil);
2961 event = XEVENT(emacs_event);
2963 GCPRO3 (emacs_event, l_dndlist, l_item);
2965 if (!DragQueryPoint ((HDROP) wParam, &point))
2966 point.x = point.y = -1; /* outside client area */
2968 event->event_type = misc_user_event;
2969 event->channel = mswindows_find_frame(hwnd);
2970 event->timestamp = GetMessageTime();
2971 event->event.misc.button = 1; /* #### Should try harder */
2972 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2974 event->event.misc.x = point.x;
2975 event->event.misc.y = point.y;
2976 event->event.misc.function = Qdragdrop_drop_dispatch;
2978 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2979 for (i=0; i<filecount; i++)
2981 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2982 /* The URLs that we make here aren't correct according to section
2983 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2984 * because they may contain reserved characters. But that's OK -
2985 * they just need to be good enough to keep dragdrop.el happy. */
2986 fname = (char *)xmalloc (len+1);
2987 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2989 /* May be a shell link aka "shortcut" - replace fname if so */
2990 #if !(defined(CYGWIN) || defined(MINGW))
2991 /* cygwin doesn't define this COM stuff */
2992 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2996 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2997 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
3001 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
3004 OLECHAR wsz[PATH_MAX];
3005 WIN32_FIND_DATA wfd;
3006 LPSTR resolved = (char *) xmalloc (PATH_MAX+1);
3008 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX);
3010 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
3011 (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX,
3016 len = strlen (fname);
3019 ppf->lpVtbl->Release (ppf);
3022 psl->lpVtbl->Release (psl);
3028 filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5);
3029 strcpy (filename, "file:");
3030 cygwin_win32_to_posix_path_list (fname, filename+5);
3032 filename = (char *)xmalloc (len+6);
3033 strcat (strcpy (filename, "file:"), fname);
3034 dostounix_filename (filename+5);
3037 l_item = make_string (filename, strlen (filename));
3038 l_dndlist = Fcons (l_item, l_dndlist);
3041 DragFinish ((HDROP) wParam);
3043 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3044 mswindows_enqueue_dispatch_event (emacs_event);
3052 return DefWindowProc (hwnd, message_, wParam, lParam);
3058 /************************************************************************/
3059 /* keyboard, mouse & other helpers for the windows procedure */
3060 /************************************************************************/
3062 mswindows_set_chord_timer (HWND hwnd)
3066 /* We get one third half system double click threshold */
3067 if (mswindows_mouse_button_tolerance <= 0)
3068 interval = GetDoubleClickTime () / 3;
3070 interval = mswindows_mouse_button_tolerance;
3072 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3076 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3079 if (mswindows_mouse_button_max_skew_x <= 0)
3080 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3082 dx = mswindows_mouse_button_max_skew_x;
3084 if (mswindows_mouse_button_max_skew_y <= 0)
3085 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3087 dy = mswindows_mouse_button_max_skew_y;
3089 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3093 mswindows_current_layout_has_AltGr (void)
3095 /* This simple caching mechanism saves 10% of CPU
3096 time when a key typed at autorepeat rate of 30 cps! */
3097 static HKL last_hkl = 0;
3098 static int last_hkl_has_AltGr;
3099 HKL current_hkl = (HKL) -1;
3101 if (xGetKeyboardLayout) /* not in NT 3.5 */
3102 current_hkl = xGetKeyboardLayout (0);
3103 if (current_hkl != last_hkl)
3106 last_hkl_has_AltGr = 0;
3107 /* In this loop, we query whether a character requires
3108 AltGr to be down to generate it. If at least such one
3109 found, this means that the layout does regard AltGr */
3110 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3111 if (HIBYTE (VkKeyScan (c)) == 6)
3112 last_hkl_has_AltGr = 1;
3113 last_hkl = current_hkl;
3115 return last_hkl_has_AltGr;
3119 /* Returns the state of the modifier keys in the format expected by the
3120 * Lisp_Event key_data, button_data and motion_data modifiers member */
3122 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3125 int keys_is_real = 0;
3128 if (fwKeys == (DWORD) -1)
3129 fwKeys = mswindows_last_mouse_button_state;
3133 mswindows_last_mouse_button_state = fwKeys;
3139 GetKeyboardState (keymap);
3140 has_AltGr = mswindows_current_layout_has_AltGr ();
3143 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3145 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3147 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3148 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3152 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3153 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3156 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3157 ? XEMACS_MOD_SHIFT : 0;
3158 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3159 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3160 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3166 * Translate a mswindows virtual key to a keysym.
3167 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3168 * or whose ASCII codes (like space) xemacs doesn't like.
3170 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3173 if (extendedp) /* Keys not present on a 82 key keyboard */
3175 switch (mswindows_key)
3177 case VK_CANCEL: return KEYSYM ("pause");
3178 case VK_RETURN: return KEYSYM ("kp-enter");
3179 case VK_PRIOR: return KEYSYM ("prior");
3180 case VK_NEXT: return KEYSYM ("next");
3181 case VK_END: return KEYSYM ("end");
3182 case VK_HOME: return KEYSYM ("home");
3183 case VK_LEFT: return KEYSYM ("left");
3184 case VK_UP: return KEYSYM ("up");
3185 case VK_RIGHT: return KEYSYM ("right");
3186 case VK_DOWN: return KEYSYM ("down");
3187 case VK_INSERT: return KEYSYM ("insert");
3188 case VK_DELETE: return QKdelete;
3189 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3190 case VK_LWIN return KEYSYM ("");
3191 case VK_RWIN return KEYSYM ("");
3193 case VK_APPS: return KEYSYM ("menu");
3198 switch (mswindows_key)
3200 case VK_BACK: return QKbackspace;
3201 case VK_TAB: return QKtab;
3202 case '\n': return QKlinefeed;
3203 case VK_CLEAR: return KEYSYM ("clear");
3204 case VK_RETURN: return QKreturn;
3205 case VK_PAUSE: return KEYSYM ("pause");
3206 case VK_ESCAPE: return QKescape;
3207 case VK_SPACE: return QKspace;
3208 case VK_PRIOR: return KEYSYM ("kp-prior");
3209 case VK_NEXT: return KEYSYM ("kp-next");
3210 case VK_END: return KEYSYM ("kp-end");
3211 case VK_HOME: return KEYSYM ("kp-home");
3212 case VK_LEFT: return KEYSYM ("kp-left");
3213 case VK_UP: return KEYSYM ("kp-up");
3214 case VK_RIGHT: return KEYSYM ("kp-right");
3215 case VK_DOWN: return KEYSYM ("kp-down");
3216 case VK_SELECT: return KEYSYM ("select");
3217 case VK_PRINT: return KEYSYM ("print");
3218 case VK_EXECUTE: return KEYSYM ("execute");
3219 case VK_SNAPSHOT: return KEYSYM ("print");
3220 case VK_INSERT: return KEYSYM ("kp-insert");
3221 case VK_DELETE: return KEYSYM ("kp-delete");
3222 case VK_HELP: return KEYSYM ("help");
3223 case VK_NUMPAD0: return KEYSYM ("kp-0");
3224 case VK_NUMPAD1: return KEYSYM ("kp-1");
3225 case VK_NUMPAD2: return KEYSYM ("kp-2");
3226 case VK_NUMPAD3: return KEYSYM ("kp-3");
3227 case VK_NUMPAD4: return KEYSYM ("kp-4");
3228 case VK_NUMPAD5: return KEYSYM ("kp-5");
3229 case VK_NUMPAD6: return KEYSYM ("kp-6");
3230 case VK_NUMPAD7: return KEYSYM ("kp-7");
3231 case VK_NUMPAD8: return KEYSYM ("kp-8");
3232 case VK_NUMPAD9: return KEYSYM ("kp-9");
3233 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3234 case VK_ADD: return KEYSYM ("kp-add");
3235 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3236 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3237 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3238 case VK_DIVIDE: return KEYSYM ("kp-divide");
3239 case VK_F1: return KEYSYM ("f1");
3240 case VK_F2: return KEYSYM ("f2");
3241 case VK_F3: return KEYSYM ("f3");
3242 case VK_F4: return KEYSYM ("f4");
3243 case VK_F5: return KEYSYM ("f5");
3244 case VK_F6: return KEYSYM ("f6");
3245 case VK_F7: return KEYSYM ("f7");
3246 case VK_F8: return KEYSYM ("f8");
3247 case VK_F9: return KEYSYM ("f9");
3248 case VK_F10: return KEYSYM ("f10");
3249 case VK_F11: return KEYSYM ("f11");
3250 case VK_F12: return KEYSYM ("f12");
3251 case VK_F13: return KEYSYM ("f13");
3252 case VK_F14: return KEYSYM ("f14");
3253 case VK_F15: return KEYSYM ("f15");
3254 case VK_F16: return KEYSYM ("f16");
3255 case VK_F17: return KEYSYM ("f17");
3256 case VK_F18: return KEYSYM ("f18");
3257 case VK_F19: return KEYSYM ("f19");
3258 case VK_F20: return KEYSYM ("f20");
3259 case VK_F21: return KEYSYM ("f21");
3260 case VK_F22: return KEYSYM ("f22");
3261 case VK_F23: return KEYSYM ("f23");
3262 case VK_F24: return KEYSYM ("f24");
3269 * Find the console that matches the supplied mswindows window handle
3272 mswindows_find_console (HWND hwnd)
3274 /* We only support one console */
3275 return XCAR (Vconsole_list);
3279 * Find the frame that matches the supplied mswindows window handle
3282 mswindows_find_frame (HWND hwnd)
3284 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3288 /* We are in progress of frame creation. Return the frame
3289 being created, as it still not remembered in the window
3291 assert (!NILP (Vmswindows_frame_being_created));
3292 return Vmswindows_frame_being_created;
3294 VOID_TO_LISP (f, l);
3299 /************************************************************************/
3301 /************************************************************************/
3304 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3307 EMACS_TIME current_time;
3308 EMACS_GET_TIME (current_time);
3309 EMACS_SUB_TIME (thyme, thyme, current_time);
3310 milliseconds = EMACS_SECS (thyme) * 1000 +
3311 (EMACS_USECS (thyme) + 500) / 1000;
3312 if (milliseconds < 1)
3314 ++mswindows_pending_timers_count;
3315 return SetTimer (NULL, 0, milliseconds,
3316 (TIMERPROC) mswindows_wm_timer_callback);
3320 emacs_mswindows_remove_timeout (int id)
3322 Lisp_Event match_against;
3323 Lisp_Object emacs_event;
3325 if (KillTimer (NULL, id))
3326 --mswindows_pending_timers_count;
3328 /* If there is a dispatch event generated by this
3329 timeout in the queue, we have to remove it too. */
3330 match_against.event_type = timeout_event;
3331 match_against.event.timeout.interval_id = id;
3332 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3333 if (!NILP (emacs_event))
3334 Fdeallocate_event(emacs_event);
3337 /* If `user_p' is false, then return whether there are any win32, timeout,
3338 * or subprocess events pending (that is, whether
3339 * emacs_mswindows_next_event() would return immediately without blocking).
3341 * if `user_p' is true, then return whether there are any *user generated*
3342 * events available (that is, whether there are keyboard or mouse-click
3343 * events ready to be read). This also implies that
3344 * emacs_mswindows_next_event() would not block.
3347 emacs_mswindows_event_pending_p (int user_p)
3349 mswindows_need_event (0);
3350 return (!NILP (mswindows_u_dispatch_event_queue)
3351 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3355 * Return the next event
3358 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3360 Lisp_Object event, event2;
3362 mswindows_need_event (1);
3364 event = mswindows_dequeue_dispatch_event ();
3365 XSETEVENT (event2, emacs_event);
3366 Fcopy_event (event, event2);
3367 Fdeallocate_event (event);
3371 * Handle a magic event off the dispatch queue.
3374 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3376 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3383 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3384 mswindows_handle_paint (f);
3385 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3392 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3393 struct frame *f = XFRAME (frame);
3394 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3396 struct gcpro gcpro1;
3398 /* On focus change, clear all memory of sticky modifiers
3399 to avoid non-intuitive behavior. */
3400 clear_sticky_modifiers ();
3402 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3404 emacs_handle_focus_change_preliminary (conser);
3405 /* Under X the stuff up to here is done in the X event handler.
3407 emacs_handle_focus_change_final (conser);
3416 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3417 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3419 Qmap_frame_hook : Qunmap_frame_hook,
3424 /* #### What about Enter & Leave */
3426 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3427 Qmouse_leave_frame_hook, 1, frame);
3435 #ifndef HAVE_MSG_SELECT
3437 get_process_input_waitable (Lisp_Process *process)
3439 Lisp_Object instr, outstr, p;
3440 XSETPROCESS (p, process);
3441 get_process_streams (process, &instr, &outstr);
3442 assert (!NILP (instr));
3443 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3444 return (network_connection_p (p)
3445 ? get_winsock_stream_waitable (XLSTREAM (instr))
3446 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3448 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3453 emacs_mswindows_select_process (Lisp_Process *process)
3455 HANDLE hev = get_process_input_waitable (process);
3457 if (!add_waitable_handle (hev))
3458 error ("Too many active processes");
3460 #ifdef HAVE_WIN32_PROCESSES
3463 XSETPROCESS (p, process);
3464 if (!network_connection_p (p))
3466 HANDLE hprocess = get_nt_process_handle (process);
3467 if (!add_waitable_handle (hprocess))
3469 remove_waitable_handle (hev);
3470 error ("Too many active processes");
3478 emacs_mswindows_unselect_process (Lisp_Process *process)
3480 /* Process handle is removed in the event loop as soon
3481 as it is signaled, so don't bother here about it */
3482 HANDLE hev = get_process_input_waitable (process);
3483 remove_waitable_handle (hev);
3485 #endif /* HAVE_MSG_SELECT */
3488 emacs_mswindows_select_console (struct console *con)
3490 #ifdef HAVE_MSG_SELECT
3491 if (CONSOLE_MSWINDOWS_P (con))
3492 return; /* mswindows consoles are automatically selected */
3494 event_stream_unixoid_select_console (con);
3499 emacs_mswindows_unselect_console (struct console *con)
3501 #ifdef HAVE_MSG_SELECT
3502 if (CONSOLE_MSWINDOWS_P (con))
3503 return; /* mswindows consoles are automatically selected */
3505 event_stream_unixoid_unselect_console (con);
3510 emacs_mswindows_quit_p (void)
3512 /* Quit cannot happen in modal loop: all program
3513 input is dedicated to Windows. */
3514 if (mswindows_in_modal_loop)
3517 mswindows_quit_chars_count = 0;
3518 /* Drain windows queue. This sets up number of quit characters in
3520 mswindows_drain_windows_queue ();
3522 if (mswindows_quit_chars_count > 0)
3524 /* Yes there's a hidden one... Throw it away */
3525 Lisp_Event match_against;
3526 Lisp_Object emacs_event;
3529 match_against.event_type = key_press_event;
3530 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3532 while (mswindows_quit_chars_count > 0)
3534 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3535 assert (!NILP (emacs_event));
3537 if (XEVENT (emacs_event)->event.key.modifiers &
3538 FAKE_MOD_QUIT_CRITICAL)
3541 Fdeallocate_event (emacs_event);
3542 mswindows_quit_chars_count--;
3545 Vquit_flag = critical_p ? Qcritical : Qt;
3550 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3551 Lisp_Object* instream,
3552 Lisp_Object* outstream,
3555 /* Handles for streams */
3557 /* fds. These just stored along with the streams, and are closed in
3558 delete stream pair method, because we need to handle fake unices
3562 /* Decode inhandle and outhandle. Their meaning depends on
3563 the process implementation being used. */
3564 #if defined (HAVE_WIN32_PROCESSES)
3565 /* We're passed in Windows handles. That's what we like most... */
3566 hin = (HANDLE) inhandle;
3567 hout = (HANDLE) outhandle;
3569 #elif defined (HAVE_UNIX_PROCESSES)
3570 /* We are passed UNIX fds. This must be Cygwin.
3572 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3573 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3577 #error "So, WHICH kind of processes do you want?"
3580 *instream = (hin == INVALID_HANDLE_VALUE
3582 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3583 : flags & STREAM_NETWORK_CONNECTION
3584 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3586 : make_ntpipe_input_stream (hin, fdi));
3588 #ifdef HAVE_WIN32_PROCESSES
3589 *outstream = (hout == INVALID_HANDLE_VALUE
3591 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3592 : flags & STREAM_NETWORK_CONNECTION
3593 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3595 : make_ntpipe_output_stream (hout, fdo));
3596 #elif defined (HAVE_UNIX_PROCESSES)
3597 *outstream = (fdo >= 0
3598 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3601 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3602 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3603 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3605 Bufbyte eof_char = get_eof_char (fdo);
3606 int pty_max_bytes = get_pty_max_bytes (fdo);
3607 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3612 return (NILP (*instream)
3614 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3615 : flags & STREAM_NETWORK_CONNECTION
3616 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3618 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3622 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3623 Lisp_Object outstream)
3625 /* Oh nothing special here for Win32 at all */
3626 #if defined (HAVE_UNIX_PROCESSES)
3627 int in = (NILP(instream)
3629 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3630 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3631 ? get_winsock_stream_param (XLSTREAM (instream))
3633 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3634 int out = (NILP(outstream) ? -1
3635 : filedesc_stream_fd (XLSTREAM (outstream)));
3639 if (out != in && out >= 0)
3643 return (NILP (instream)
3645 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3646 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3647 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3649 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3653 emacs_mswindows_current_event_timestamp (struct console *c)
3655 return GetTickCount ();
3658 #ifndef HAVE_X_WINDOWS
3659 /* This is called from GC when a process object is about to be freed.
3660 If we've still got pointers to it in this file, we're gonna lose hard.
3663 debug_process_finalization (Lisp_Process *p)
3666 Lisp_Object instr, outstr;
3668 get_process_streams (p, &instr, &outstr);
3669 /* if it still has fds, then it hasn't been killed yet. */
3670 assert (NILP(instr));
3671 assert (NILP(outstr));
3673 /* #### More checks here */
3680 struct mswin_message_debug
3686 #define FROB(val) { val, #val, },
3688 struct mswin_message_debug debug_mswin_messages[] =
3704 FROB (WM_GETTEXTLENGTH)
3707 FROB (WM_QUERYENDSESSION)
3710 FROB (WM_ERASEBKGND)
3711 FROB (WM_SYSCOLORCHANGE)
3712 FROB (WM_ENDSESSION)
3713 FROB (WM_SHOWWINDOW)
3714 FROB (WM_WININICHANGE)
3715 #if(WINVER >= 0x0400)
3716 FROB (WM_SETTINGCHANGE)
3717 #endif /* WINVER >= 0x0400 */
3719 FROB (WM_DEVMODECHANGE)
3720 FROB (WM_ACTIVATEAPP)
3721 FROB (WM_FONTCHANGE)
3722 FROB (WM_TIMECHANGE)
3723 FROB (WM_CANCELMODE)
3725 FROB (WM_MOUSEACTIVATE)
3726 FROB (WM_CHILDACTIVATE)
3729 FROB (WM_GETMINMAXINFO)
3732 FROB (WM_ICONERASEBKGND)
3733 FROB (WM_NEXTDLGCTL)
3734 FROB (WM_SPOOLERSTATUS)
3736 FROB (WM_MEASUREITEM)
3737 FROB (WM_DELETEITEM)
3738 FROB (WM_VKEYTOITEM)
3739 FROB (WM_CHARTOITEM)
3744 FROB (WM_QUERYDRAGICON)
3745 FROB (WM_COMPAREITEM)
3746 #if(WINVER >= 0x0500)
3748 #endif /* WINVER >= 0x0500 */
3749 FROB (WM_COMPACTING)
3750 FROB (WM_COMMNOTIFY)
3751 FROB (WM_WINDOWPOSCHANGING)
3752 FROB (WM_WINDOWPOSCHANGED)
3757 FROB (WM_CANCELJOURNAL)
3759 #if(WINVER >= 0x0400)
3761 FROB (WM_INPUTLANGCHANGEREQUEST)
3762 FROB (WM_INPUTLANGCHANGE)
3765 FROB (WM_USERCHANGED)
3766 FROB (WM_NOTIFYFORMAT)
3768 FROB (WM_CONTEXTMENU)
3769 FROB (WM_STYLECHANGING)
3770 FROB (WM_STYLECHANGED)
3771 FROB (WM_DISPLAYCHANGE)
3774 #endif /* WINVER >= 0x0400 */
3778 FROB (WM_NCCALCSIZE)
3781 FROB (WM_NCACTIVATE)
3782 FROB (WM_GETDLGCODE)
3783 #ifdef WM_SYNCPAINT /* not in VC 5 */
3785 #endif /* WM_SYNCPAINT */
3786 FROB (WM_NCMOUSEMOVE)
3787 FROB (WM_NCLBUTTONDOWN)
3788 FROB (WM_NCLBUTTONUP)
3789 FROB (WM_NCLBUTTONDBLCLK)
3790 FROB (WM_NCRBUTTONDOWN)
3791 FROB (WM_NCRBUTTONUP)
3792 FROB (WM_NCRBUTTONDBLCLK)
3793 FROB (WM_NCMBUTTONDOWN)
3794 FROB (WM_NCMBUTTONUP)
3795 FROB (WM_NCMBUTTONDBLCLK)
3797 /* FROB (WM_KEYFIRST) */
3802 FROB (WM_SYSKEYDOWN)
3805 FROB (WM_SYSDEADCHAR)
3808 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION)
3809 FROB (WM_IME_STARTCOMPOSITION)
3810 FROB (WM_IME_ENDCOMPOSITION)
3811 FROB (WM_IME_COMPOSITION)
3812 FROB (WM_IME_KEYLAST)
3813 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */
3815 FROB (WM_INITDIALOG)
3817 FROB (WM_SYSCOMMAND)
3822 FROB (WM_INITMENUPOPUP)
3823 FROB (WM_MENUSELECT)
3826 #if(WINVER >= 0x0500)
3827 FROB (WM_MENURBUTTONUP)
3829 FROB (WM_MENUGETOBJECT)
3830 FROB (WM_UNINITMENUPOPUP)
3831 FROB (WM_MENUCOMMAND)
3832 #endif /* WINVER >= 0x0500 */
3835 FROB (WM_CTLCOLORMSGBOX)
3836 FROB (WM_CTLCOLOREDIT)
3837 FROB (WM_CTLCOLORLISTBOX)
3838 FROB (WM_CTLCOLORBTN)
3839 FROB (WM_CTLCOLORDLG)
3840 FROB (WM_CTLCOLORSCROLLBAR)
3841 FROB (WM_CTLCOLORSTATIC)
3844 /* FROB (WM_MOUSEFIRST) */
3846 FROB (WM_LBUTTONDOWN)
3848 FROB (WM_LBUTTONDBLCLK)
3849 FROB (WM_RBUTTONDOWN)
3851 FROB (WM_RBUTTONDBLCLK)
3852 FROB (WM_MBUTTONDOWN)
3854 FROB (WM_MBUTTONDBLCLK)
3856 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
3857 FROB (WM_MOUSEWHEEL)
3861 #endif /* if (_WIN32_WINNT < 0x0400) */
3863 FROB (WM_PARENTNOTIFY)
3864 FROB (WM_ENTERMENULOOP)
3865 FROB (WM_EXITMENULOOP)
3867 #if(WINVER >= 0x0400)
3871 FROB (WM_CAPTURECHANGED)
3873 FROB (WM_POWERBROADCAST)
3875 FROB (WM_DEVICECHANGE)
3877 #endif /* WINVER >= 0x0400 */
3880 FROB (WM_MDIDESTROY)
3881 FROB (WM_MDIACTIVATE)
3882 FROB (WM_MDIRESTORE)
3884 FROB (WM_MDIMAXIMIZE)
3886 FROB (WM_MDICASCADE)
3887 FROB (WM_MDIICONARRANGE)
3888 FROB (WM_MDIGETACTIVE)
3891 FROB (WM_MDISETMENU)
3892 FROB (WM_ENTERSIZEMOVE)
3893 FROB (WM_EXITSIZEMOVE)
3895 FROB (WM_MDIREFRESHMENU)
3897 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */
3899 #if(WINVER >= 0x0400) && !defined(CYGWIN)
3900 FROB (WM_IME_SETCONTEXT)
3901 FROB (WM_IME_NOTIFY)
3902 FROB (WM_IME_CONTROL)
3903 FROB (WM_IME_COMPOSITIONFULL)
3904 FROB (WM_IME_SELECT)
3906 #endif /* WINVER >= 0x0400 */
3907 #if(WINVER >= 0x0500)
3908 FROB (WM_IME_REQUEST)
3909 #endif /* WINVER >= 0x0500 */
3910 #if(WINVER >= 0x0400) && !defined(CYGWIN)
3911 FROB (WM_IME_KEYDOWN)
3913 #endif /* WINVER >= 0x0400 */
3915 #endif /* WM_IME_SETCONTEXT */
3917 #if(_WIN32_WINNT >= 0x0400)
3918 FROB (WM_MOUSEHOVER)
3919 FROB (WM_MOUSELEAVE)
3920 #endif /* _WIN32_WINNT >= 0x0400 */
3927 FROB (WM_RENDERFORMAT)
3928 FROB (WM_RENDERALLFORMATS)
3929 FROB (WM_DESTROYCLIPBOARD)
3930 FROB (WM_DRAWCLIPBOARD)
3931 FROB (WM_PAINTCLIPBOARD)
3932 FROB (WM_VSCROLLCLIPBOARD)
3933 FROB (WM_SIZECLIPBOARD)
3934 FROB (WM_ASKCBFORMATNAME)
3935 FROB (WM_CHANGECBCHAIN)
3936 FROB (WM_HSCROLLCLIPBOARD)
3937 FROB (WM_QUERYNEWPALETTE)
3938 FROB (WM_PALETTEISCHANGING)
3939 FROB (WM_PALETTECHANGED)
3942 #if(WINVER >= 0x0400)
3944 FROB (WM_PRINTCLIENT)
3946 FROB (WM_HANDHELDFIRST)
3947 FROB (WM_HANDHELDLAST)
3951 #endif /* WINVER >= 0x0400 */
3953 FROB (WM_PENWINFIRST)
3954 FROB (WM_PENWINLAST)
3960 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
3963 Lisp_Object frame = mswindows_find_frame (hwnd);
3966 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */
3968 for (i = 0; i < countof (debug_mswin_messages); i++)
3970 if (debug_mswin_messages[i].mess == message_)
3972 str = debug_mswin_messages[i].string;
3978 stderr_out ("%s", str);
3980 stderr_out ("%x", message_);
3982 if (debug_mswindows_events > 1)
3984 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
3985 wParam, (int) lParam, (unsigned int) hwnd);
3986 debug_print (frame);
3992 #endif /* DEBUG_XEMACS */
3994 /************************************************************************/
3995 /* initialization */
3996 /************************************************************************/
3999 reinit_vars_of_event_mswindows (void)
4001 mswindows_in_modal_loop = 0;
4002 mswindows_pending_timers_count = 0;
4004 mswindows_event_stream = xnew (struct event_stream);
4006 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
4007 mswindows_event_stream->force_event_pending = 0;
4008 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
4009 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
4010 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
4011 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
4012 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
4013 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
4014 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
4015 #ifdef HAVE_MSG_SELECT
4016 mswindows_event_stream->select_process_cb =
4017 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
4018 mswindows_event_stream->unselect_process_cb =
4019 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
4020 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
4021 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
4023 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
4024 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
4025 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
4026 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
4028 mswindows_event_stream->current_event_timestamp_cb =
4029 emacs_mswindows_current_event_timestamp;
4033 vars_of_event_mswindows (void)
4035 reinit_vars_of_event_mswindows ();
4037 mswindows_u_dispatch_event_queue = Qnil;
4038 staticpro (&mswindows_u_dispatch_event_queue);
4039 mswindows_u_dispatch_event_queue_tail = Qnil;
4040 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
4042 mswindows_s_dispatch_event_queue = Qnil;
4043 staticpro (&mswindows_s_dispatch_event_queue);
4044 mswindows_s_dispatch_event_queue_tail = Qnil;
4045 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
4047 mswindows_error_caught_in_modal_loop = Qnil;
4048 staticpro (&mswindows_error_caught_in_modal_loop);
4052 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
4053 If non-zero, display debug information about Windows messages that XEmacs sees.
4054 Information is displayed in a console window. Currently defined values are:
4056 1 == non-verbose output (just the message name)
4057 2 == verbose output (all parameters)
4058 3 == even more verbose output (extra debugging info)
4060 debug_mswindows_events = 0;
4063 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
4064 &mswindows_alt_by_itself_activates_menu /*
4065 *Controls whether pressing and releasing the Alt key activates the menubar.
4066 This applies only if no intervening key was pressed. See also
4067 `menu-accelerator-enabled', which is probably the behavior you actually want.
4071 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
4072 &mswindows_dynamic_frame_resize /*
4073 *Controls redrawing frame contents during mouse-drag or keyboard resize
4074 operation. When non-nil, the frame is redrawn while being resized. When
4075 nil, frame is not redrawn, and exposed areas are filled with default
4076 MDI application background color. Note that this option only has effect
4077 if "Show window contents while dragging" is on in system Display/Plus!
4079 Default is t on fast machines, nil on slow.
4082 DEFVAR_INT ("mswindows-mouse-button-tolerance",
4083 &mswindows_mouse_button_tolerance /*
4084 *Analogue of double click interval for faking middle mouse events.
4085 The value is the minimum time in milliseconds that must elapse between
4086 left/right button down events before they are considered distinct events.
4087 If both mouse buttons are depressed within this interval, a middle mouse
4088 button down event is generated instead.
4089 If negative or zero, currently set system default is used instead.
4092 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
4093 Number of physical mouse buttons.
4096 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
4097 &mswindows_mouse_button_max_skew_x /*
4098 *Maximum horizontal distance in pixels between points in which left and
4099 right button clicks occurred for them to be translated into single
4100 middle button event. Clicks must occur in time not longer than defined
4101 by the variable `mswindows-mouse-button-tolerance'.
4102 If negative or zero, currently set system default is used instead.
4105 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
4106 &mswindows_mouse_button_max_skew_y /*
4107 *Maximum vertical distance in pixels between points in which left and
4108 right button clicks occurred for them to be translated into single
4109 middle button event. Clicks must occur in time not longer than defined
4110 by the variable `mswindows-mouse-button-tolerance'.
4111 If negative or zero, currently set system default is used instead.
4114 mswindows_mouse_button_max_skew_x = 0;
4115 mswindows_mouse_button_max_skew_y = 0;
4116 mswindows_mouse_button_tolerance = 0;
4117 mswindows_alt_by_itself_activates_menu = 1;
4121 syms_of_event_mswindows (void)
4126 lstream_type_create_mswindows_selectable (void)
4128 init_slurp_stream ();
4129 init_shove_stream ();
4130 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
4131 init_winsock_stream ();
4136 init_event_mswindows_late (void)
4138 #ifdef HAVE_MSG_SELECT
4139 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
4140 assert (windows_fd>=0);
4141 FD_SET (windows_fd, &input_wait_mask);
4142 FD_ZERO(&zero_mask);
4145 event_stream = mswindows_event_stream;
4147 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
4148 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);