1 /* The mswindows event_stream interface.
2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1996, 2000 Ben Wing.
5 Copyright (C) 1997 Jonathan Harris.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
28 Ultimately based on FSF.
29 Rewritten by Ben Wing.
30 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
31 Subprocess and modal loop support by Kirill M. Katsnelson.
37 #include "console-msw.h"
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
45 # include "menubar-msw.h"
49 # include "dragdrop.h"
59 #include "redisplay.h"
66 #include "objects-msw.h"
68 #include "events-mod.h"
69 #ifdef HAVE_MSG_SELECT
71 #include "console-tty.h"
73 typedef unsigned int SOCKET;
78 #if !(defined(CYGWIN) || defined(MINGW))
79 # include <shlobj.h> /* For IShellLink */
83 #define ADJR_MENUFLAG TRUE
85 #define ADJR_MENUFLAG FALSE
88 /* Fake key modifier which is attached to a quit char event.
89 Removed upon dequeueing an event */
90 #define FAKE_MOD_QUIT (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 static 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;
159 /* This is the event signaled by the event pump.
160 See mswindows_pump_outstanding_events for comments */
161 static Lisp_Object mswindows_error_caught_in_modal_loop;
162 static int mswindows_in_modal_loop;
164 /* Count of wound timers */
165 static int mswindows_pending_timers_count;
167 static DWORD mswindows_last_mouse_button_state;
169 /************************************************************************/
170 /* Pipe instream - reads process output */
171 /************************************************************************/
173 #define PIPE_READ_DELAY 20
175 #define HANDLE_TO_USID(h) ((USID)(h))
177 #define NTPIPE_SLURP_STREAM_DATA(stream) \
178 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
180 /* This structure is allocated by the main thread, and is deallocated
181 in the thread upon exit. There are situations when a thread
182 remains blocked for a long time, much longer than the lstream
183 exists. For example, "start notepad" command is issued from the
184 shell, then the shell is closed by C-c C-d. Although the shell
185 process exits, its output pipe will not get closed until the
186 notepad process exits also, because it inherits the pipe form the
187 shell. In this case, we abandon the thread, and let it live until
188 all such processes exit. While struct ntpipe_slurp_stream is
189 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
191 struct ntpipe_slurp_stream_shared_data
193 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
194 /* This is a manual-reset object. */
195 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
196 /* This is a manual-reset object. */
197 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
198 /* This is a manual-reset object. */
199 HANDLE hpipe; /* Pipe read end handle. */
200 LONG die_p; /* Thread must exit ASAP if non-zero */
201 BOOL eof_p : 1; /* Set when thread saw EOF */
202 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
203 BOOL inuse_p : 1; /* this structure is in use */
204 LONG lock_count; /* Client count of this struct, 0=safe to free */
205 BYTE onebyte; /* One byte buffer read by thread */
208 #define MAX_SLURP_STREAMS 32
209 struct ntpipe_slurp_stream_shared_data
210 shared_data_block[MAX_SLURP_STREAMS]={{0}};
212 struct ntpipe_slurp_stream
214 LPARAM user_data; /* Any user data stored in the stream object */
215 struct ntpipe_slurp_stream_shared_data* thread_data;
218 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
219 sizeof (struct ntpipe_slurp_stream));
221 /* This function is thread-safe, and is called from either thread
222 context. It serializes freeing shared data structure */
224 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
226 if (InterlockedDecrement (&s->lock_count) == 0)
229 CloseHandle (s->hev_thread);
230 CloseHandle (s->hev_caller);
231 CloseHandle (s->hev_unsleep);
236 static struct ntpipe_slurp_stream_shared_data*
237 slurper_allocate_shared_data (void)
240 for (i=0; i<MAX_SLURP_STREAMS; i++)
242 if (!shared_data_block[i].inuse_p)
244 shared_data_block[i].inuse_p=1;
245 return &shared_data_block[i];
248 return (struct ntpipe_slurp_stream_shared_data*)0;
252 slurp_thread (LPVOID vparam)
254 struct ntpipe_slurp_stream_shared_data *s =
255 (struct ntpipe_slurp_stream_shared_data*)vparam;
259 /* Read one byte from the pipe */
261 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
263 DWORD err = GetLastError ();
264 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
269 else if (actually_read == 0)
272 /* We must terminate on an error or eof */
273 if (s->eof_p || s->error_p)
274 InterlockedIncrement (&s->die_p);
276 /* Before we notify caller, we unsignal our event. */
277 ResetEvent (s->hev_thread);
279 /* Now we got something to notify caller, either a byte or an
280 error/eof indication. Before we do, allow internal pipe
281 buffer to accumulate little bit more data.
282 Reader function pulses this event before waiting for
283 a character, to avoid pipe delay, and to get the byte
286 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
288 /* Either make event loop generate a process event, or
290 SetEvent (s->hev_caller);
292 /* Cleanup and exit if we're shot off */
296 /* Block until the client finishes with retrieving the rest of
298 WaitForSingleObject (s->hev_thread, INFINITE);
301 slurper_free_shared_data_maybe (s);
307 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
310 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
311 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
312 DWORD thread_id_unused;
315 /* We deal only with pipes, for we're using PeekNamedPipe api */
316 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
318 s->thread_data = slurper_allocate_shared_data();
320 /* Create reader thread. This could fail, so do not create events
321 until thread is created */
322 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
323 CREATE_SUSPENDED, &thread_id_unused);
326 Lstream_delete (lstr);
327 s->thread_data->inuse_p=0;
331 /* Shared data are initially owned by both main and slurper
333 s->thread_data->lock_count = 2;
334 s->thread_data->die_p = 0;
335 s->thread_data->eof_p = FALSE;
336 s->thread_data->error_p = FALSE;
337 s->thread_data->hpipe = hpipe;
338 s->user_data = param;
340 /* hev_thread is a manual-reset event, initially signaled */
341 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
342 /* hev_caller is a manual-reset event, initially nonsignaled */
343 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
344 /* hev_unsleep is a manual-reset event, initially nonsignaled */
345 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
348 ResumeThread (hthread);
349 CloseHandle (hthread);
351 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
352 XSETLSTREAM (obj, lstr);
357 get_ntpipe_input_stream_param (Lstream *stream)
359 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
364 get_ntpipe_input_stream_waitable (Lstream *stream)
366 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
367 return s->thread_data->hev_caller;
370 static Lstream_data_count
371 ntpipe_slurp_reader (Lstream *stream, unsigned char *data,
372 Lstream_data_count size)
374 /* This function must be called from the main thread only */
375 struct ntpipe_slurp_stream_shared_data* s =
376 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
381 /* Disallow pipe read delay for the thread: we need a character
383 SetEvent (s->hev_unsleep);
385 /* Check if we have a character ready. Give it a short delay,
386 for the thread to awake from pipe delay, just ion case*/
387 wait_result = WaitForSingleObject (s->hev_caller, 2);
389 /* Revert to the normal sleep behavior. */
390 ResetEvent (s->hev_unsleep);
392 /* If there's no byte buffered yet, give up */
393 if (wait_result == WAIT_TIMEOUT)
400 /* Reset caller unlock event now, as we've handled the pending
401 process output event */
402 ResetEvent (s->hev_caller);
404 /* It is now safe to do anything with contents of S, except for
405 changing s->die_p, which still should be interlocked */
409 if (s->error_p || s->die_p)
412 /* Ok, there were no error neither eof - we've got a byte from the
414 *(data++) = s->onebyte;
418 DWORD bytes_read = 0;
421 DWORD bytes_available;
423 /* If the api call fails, return at least one byte already
424 read. ReadFile in thread will return error */
425 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
428 /* Fetch available bytes. The same consideration applies,
429 so do not check for errors. ReadFile in the thread will
430 fail if the next call fails. */
432 ReadFile (s->hpipe, data, min (bytes_available, size),
436 /* Now we can unblock thread, so it attempts to read more */
437 SetEvent (s->hev_thread);
438 return bytes_read + 1;
445 ntpipe_slurp_closer (Lstream *stream)
447 /* This function must be called from the main thread only */
448 struct ntpipe_slurp_stream_shared_data* s =
449 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
451 /* Force thread to stop */
452 InterlockedIncrement (&s->die_p);
454 /* Set events which could possibly block slurper. Let it finish soon
456 SetEvent (s->hev_unsleep);
457 SetEvent (s->hev_thread);
459 /* Unlock and maybe free shared data */
460 slurper_free_shared_data_maybe (s);
466 init_slurp_stream (void)
468 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
469 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
472 /************************************************************************/
473 /* Pipe outstream - writes process input */
474 /************************************************************************/
476 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
477 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
479 #define MAX_SHOVE_BUFFER_SIZE 512
481 struct ntpipe_shove_stream
483 LPARAM user_data; /* Any user data stored in the stream object */
484 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
485 /* This is an auto-reset object. */
486 HANDLE hpipe; /* Pipe write end handle. */
487 HANDLE hthread; /* Reader thread handle. */
488 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
489 DWORD size; /* Number of bytes to write */
490 LONG die_p; /* Thread must exit ASAP if non-zero */
491 LONG idle_p; /* Non-zero if thread is waiting for job */
492 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
493 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
496 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
497 sizeof (struct ntpipe_shove_stream));
499 #ifndef HAVE_MSG_SELECT
501 shove_thread (LPVOID vparam)
503 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
509 /* Block on event and wait for a job */
510 InterlockedIncrement (&s->idle_p);
511 WaitForSingleObject (s->hev_thread, INFINITE);
513 /* Write passed buffer if any */
516 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
517 || bytes_written != s->size)
520 InterlockedIncrement (&s->die_p);
522 /* Set size to zero so we won't write it again if the closer sets
523 die_p and kicks us */
535 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
538 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
539 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
540 DWORD thread_id_unused;
545 s->user_data = param;
547 /* Create reader thread. This could fail, so do not
548 create the event until thread is created */
549 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
550 CREATE_SUSPENDED, &thread_id_unused);
551 if (s->hthread == NULL)
553 Lstream_delete (lstr);
557 /* Set the priority of the thread higher so we don't end up waiting
558 on it to send things. */
559 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST))
561 CloseHandle (s->hthread);
562 Lstream_delete (lstr);
566 /* hev_thread is an auto-reset event, initially nonsignaled */
567 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
570 ResumeThread (s->hthread);
572 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
573 XSETLSTREAM (obj, lstr);
578 get_ntpipe_output_stream_param (Lstream *stream)
580 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
585 static Lstream_data_count
586 ntpipe_shove_writer (Lstream *stream, const unsigned char *data,
587 Lstream_data_count size)
589 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
594 s->blocking_p = !s->idle_p;
598 if (size>MAX_SHOVE_BUFFER_SIZE)
601 memcpy (s->buffer, data, size);
605 InterlockedDecrement (&s->idle_p);
606 SetEvent (s->hev_thread);
607 /* Give it a chance to run -- this dramatically improves performance
608 of things like crypt. */
609 if (xSwitchToThread) /* not in Win9x or NT 3.51 */
610 (void) xSwitchToThread ();
615 ntpipe_shove_was_blocked_p (Lstream *stream)
617 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
618 return s->blocking_p;
622 ntpipe_shove_closer (Lstream *stream)
624 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
626 /* Force thread stop */
627 InterlockedIncrement (&s->die_p);
629 /* Thread will end upon unblocking. If it's already unblocked this will
630 do nothing, but the thread won't look at die_p until it's written any
632 SetEvent (s->hev_thread);
634 /* Wait while thread terminates */
635 WaitForSingleObject (s->hthread, INFINITE);
637 /* Close pipe handle, possibly breaking it */
638 CloseHandle (s->hpipe);
640 /* Close the thread handle */
641 CloseHandle (s->hthread);
643 /* Destroy the event */
644 CloseHandle (s->hev_thread);
650 init_shove_stream (void)
652 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
653 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
654 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
657 /************************************************************************/
658 /* Winsock I/O stream */
659 /************************************************************************/
660 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
662 #define WINSOCK_READ_BUFFER_SIZE 1024
664 struct winsock_stream
666 LPARAM user_data; /* Any user data stored in the stream object */
667 SOCKET s; /* Socket handle (which is a Win32 handle) */
668 OVERLAPPED ov; /* Overlapped I/O structure */
669 void* buffer; /* Buffer. Allocated for input stream only */
670 unsigned long bufsize; /* Number of bytes last read */
671 unsigned long bufpos; /* Position in buffer for next fetch */
672 unsigned int error_p :1; /* I/O Error seen */
673 unsigned int eof_p :1; /* EOF Error seen */
674 unsigned int pending_p :1; /* There is a pending I/O operation */
675 unsigned int blocking_p :1; /* Last write attempt would block */
678 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
680 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
681 sizeof (struct winsock_stream));
684 winsock_initiate_read (struct winsock_stream *str)
686 ResetEvent (str->ov.hEvent);
689 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
690 &str->bufsize, &str->ov))
692 if (GetLastError () == ERROR_IO_PENDING)
694 else if (GetLastError () == ERROR_HANDLE_EOF)
699 else if (str->bufsize == 0)
703 static Lstream_data_count
704 winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
706 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
708 /* If the current operation is not yet complete, there's nothing to
712 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
719 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
721 if (GetLastError() == ERROR_HANDLE_EOF)
726 if (str->bufsize == 0)
737 /* Return as much of buffer as we have */
738 size = min (size, (Lstream_data_count) (str->bufsize - str->bufpos));
739 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
742 /* Read more if buffer is exhausted */
743 if (str->bufsize == str->bufpos)
744 winsock_initiate_read (str);
749 static Lstream_data_count
750 winsock_writer (Lstream *stream, const unsigned char *data,
751 Lstream_data_count size)
753 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
757 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
765 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
780 ResetEvent (str->ov.hEvent);
782 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
783 * an overlapped operation. This fails on Win95 with winsock 1.x so we
784 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
785 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
786 || GetLastError() == ERROR_IO_PENDING)
792 return str->error_p ? -1 : size;
796 winsock_closer (Lstream *lstr)
798 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
800 if (lstr->flags & LSTREAM_FL_READ)
801 shutdown (str->s, 0);
803 shutdown (str->s, 1);
805 CloseHandle ((HANDLE)str->s);
807 WaitForSingleObject (str->ov.hEvent, INFINITE);
809 if (lstr->flags & LSTREAM_FL_READ)
812 CloseHandle (str->ov.hEvent);
817 winsock_was_blocked_p (Lstream *stream)
819 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
820 return str->blocking_p;
824 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
827 Lstream *lstr = Lstream_new (lstream_winsock, mode);
828 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
835 str->user_data = param;
838 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
840 if (lstr->flags & LSTREAM_FL_READ)
842 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
843 winsock_initiate_read (str);
846 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
847 XSETLSTREAM (obj, lstr);
852 make_winsock_input_stream (SOCKET s, LPARAM param)
854 return make_winsock_stream_1 (s, param, "r");
858 make_winsock_output_stream (SOCKET s, LPARAM param)
860 return make_winsock_stream_1 (s, param, "w");
864 get_winsock_stream_waitable (Lstream *lstr)
866 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
867 return str->ov.hEvent;
871 get_winsock_stream_param (Lstream *lstr)
873 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
874 return str->user_data;
878 init_winsock_stream (void)
880 LSTREAM_HAS_METHOD (winsock, reader);
881 LSTREAM_HAS_METHOD (winsock, writer);
882 LSTREAM_HAS_METHOD (winsock, closer);
883 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
885 #endif /* defined (HAVE_SOCKETS) */
887 /************************************************************************/
888 /* Dispatch queue management */
889 /************************************************************************/
892 mswindows_user_event_p (Lisp_Event* sevt)
894 return (sevt->event_type == key_press_event
895 || sevt->event_type == button_press_event
896 || sevt->event_type == button_release_event
897 || sevt->event_type == misc_user_event);
901 * Add an emacs event to the proper dispatch queue
904 mswindows_enqueue_dispatch_event (Lisp_Object event)
906 int user_p = mswindows_user_event_p (XEVENT(event));
907 enqueue_event (event,
908 user_p ? &mswindows_u_dispatch_event_queue :
909 &mswindows_s_dispatch_event_queue,
910 user_p ? &mswindows_u_dispatch_event_queue_tail :
911 &mswindows_s_dispatch_event_queue_tail);
913 /* Avoid blocking on WaitMessage */
914 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
918 * Add a misc-user event to the dispatch queue.
920 * Stuff it into our own dispatch queue, so we have something
921 * to return from next_event callback.
924 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
927 Lisp_Object event = Fmake_event (Qnil, Qnil);
928 Lisp_Event* e = XEVENT (event);
930 e->event_type = misc_user_event;
931 e->channel = channel;
932 e->timestamp = GetTickCount ();
933 e->event.misc.function = function;
934 e->event.misc.object = object;
936 mswindows_enqueue_dispatch_event (event);
940 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
942 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
943 Lisp_Event* event = XEVENT (emacs_event);
945 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
946 event->timestamp = GetMessageTime();
947 event->event_type = magic_event;
948 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
950 mswindows_enqueue_dispatch_event (emacs_event);
954 mswindows_enqueue_process_event (Lisp_Process* p)
956 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
957 Lisp_Event* event = XEVENT (emacs_event);
959 XSETPROCESS (process, p);
961 event->event_type = process_event;
962 event->timestamp = GetTickCount ();
963 event->event.process.process = process;
965 mswindows_enqueue_dispatch_event (emacs_event);
969 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
970 int mods, DWORD when)
972 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
973 msg == WM_RBUTTONDOWN);
975 /* We always use last message time, because mouse button
976 events may get delayed, and XEmacs double click
977 recognition will fail */
979 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
980 Lisp_Event* event = XEVENT (emacs_event);
982 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
983 event->channel = mswindows_find_frame (hwnd);
984 event->timestamp = when;
985 event->event.button.button =
986 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
987 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
988 event->event.button.x = where.x;
989 event->event.button.y = where.y;
990 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
994 event->event_type = button_press_event;
996 /* we need this to make sure the main window regains the focus
997 from control subwindows */
998 if (GetFocus() != hwnd)
1001 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1006 event->event_type = button_release_event;
1010 mswindows_enqueue_dispatch_event (emacs_event);
1014 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1016 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1017 Lisp_Event* event = XEVENT(emacs_event);
1019 event->channel = mswindows_find_console(hwnd);
1020 event->timestamp = GetMessageTime();
1021 event->event_type = key_press_event;
1022 event->event.key.keysym = keysym;
1023 event->event.key.modifiers = mods;
1024 mswindows_enqueue_dispatch_event (emacs_event);
1028 * Remove and return the first emacs event on the dispatch queue.
1029 * Give a preference to user events over non-user ones.
1032 mswindows_dequeue_dispatch_event (void)
1037 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1038 !NILP(mswindows_s_dispatch_event_queue));
1040 event = dequeue_event (
1041 NILP(mswindows_u_dispatch_event_queue) ?
1042 &mswindows_s_dispatch_event_queue :
1043 &mswindows_u_dispatch_event_queue,
1044 NILP(mswindows_u_dispatch_event_queue) ?
1045 &mswindows_s_dispatch_event_queue_tail :
1046 &mswindows_u_dispatch_event_queue_tail);
1048 sevt = XEVENT(event);
1049 if (sevt->event_type == key_press_event
1050 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1052 sevt->event.key.modifiers &=
1053 ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
1054 --mswindows_quit_chars_count;
1061 * Remove and return the first emacs event on the dispatch queue that matches
1062 * the supplied event.
1063 * Timeout event matches if interval_id is equal to that of the given event.
1064 * Keypress event matches if logical AND between modifiers bitmask of the
1065 * event in the queue and that of the given event is non-zero.
1066 * For all other event types, this function aborts.
1070 mswindows_cancel_dispatch_event (Lisp_Event *match)
1073 Lisp_Object previous_event = Qnil;
1074 int user_p = mswindows_user_event_p (match);
1075 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1076 &mswindows_s_dispatch_event_queue;
1077 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1078 &mswindows_s_dispatch_event_queue_tail;
1080 assert (match->event_type == timeout_event
1081 || match->event_type == key_press_event);
1083 EVENT_CHAIN_LOOP (event, *head)
1085 Lisp_Event *e = XEVENT (event);
1086 if ((e->event_type == match->event_type) &&
1087 ((e->event_type == timeout_event) ?
1088 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1089 /* Must be key_press_event */
1090 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1092 if (NILP (previous_event))
1093 dequeue_event (head, tail);
1096 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1097 if (EQ (*tail, event))
1098 *tail = previous_event;
1103 previous_event = event;
1108 #ifndef HAVE_MSG_SELECT
1109 /************************************************************************/
1110 /* Waitable handles manipulation */
1111 /************************************************************************/
1113 find_waitable_handle (HANDLE h)
1116 for (i = 0; i < mswindows_waitable_count; ++i)
1117 if (mswindows_waitable_handles[i] == h)
1124 add_waitable_handle (HANDLE h)
1126 assert (find_waitable_handle (h) < 0);
1127 if (mswindows_waitable_count == MAX_WAITABLE)
1130 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1135 remove_waitable_handle (HANDLE h)
1137 int ix = find_waitable_handle (h);
1141 mswindows_waitable_handles [ix] =
1142 mswindows_waitable_handles [--mswindows_waitable_count];
1144 #endif /* HAVE_MSG_SELECT */
1147 /************************************************************************/
1149 /************************************************************************/
1152 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1153 Lisp_Object u_n_u_s_e_d)
1155 mswindows_error_caught_in_modal_loop = cons_sig_data;
1160 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1165 ++mswindows_in_modal_loop;
1166 tmp = condition_case_1 (Qt,
1168 mswindows_modal_loop_error_handler, Qnil);
1169 --mswindows_in_modal_loop;
1175 mswindows_unmodalize_signal_maybe (void)
1177 if (!NILP (mswindows_error_caught_in_modal_loop))
1179 /* Got an error while messages were pumped while
1180 in window procedure - have to resignal */
1181 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1182 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1183 mswindows_error_caught_in_modal_loop = Qnil;
1184 Fsignal (sym, data);
1189 * This is an unsafe part of event pump, guarded by
1190 * condition_case. See mswindows_pump_outstanding_events
1193 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1195 /* This function can call lisp */
1196 Lisp_Object event = Fmake_event (Qnil, Qnil);
1197 struct gcpro gcpro1;
1198 int do_redisplay = 0;
1201 while (detect_input_pending ())
1203 Fnext_event (event, Qnil);
1204 Fdispatch_event (event);
1211 Fdeallocate_event (event);
1214 /* Qt becomes return value of mswindows_pump_outstanding_events
1220 * This function pumps emacs events, while available, by using
1221 * next_message/dispatch_message loop. Errors are trapped around
1222 * the loop so the function always returns.
1224 * Windows message queue is not looked into during the call,
1225 * neither are waitable handles checked. The function pumps
1226 * thus only dispatch events already queued, as well as those
1227 * resulted in dispatching thereof. This is done by setting
1228 * module local variable mswindows_in_modal_loop to nonzero.
1230 * Return value is Qt if no errors was trapped, or Qunbound if
1231 * there was an error.
1233 * In case of error, a cons representing the error, in the
1234 * form (SIGNAL . DATA), is stored in the module local variable
1235 * mswindows_error_caught_in_modal_loop. This error is signaled
1236 * again when DispatchMessage returns. Thus, Windows internal
1237 * modal loops are protected against throws, which are proven
1238 * to corrupt internal Windows structures.
1240 * In case of success, mswindows_error_caught_in_modal_loop is
1243 * If the value of mswindows_error_caught_in_modal_loop is not
1244 * nil already upon entry, the function just returns non-nil.
1245 * This situation means that a new event has been queued while
1246 * in cancel mode. The event will be dequeued on the next regular
1247 * call of next-event; the pump is off since error is caught.
1248 * The caller must *unconditionally* cancel modal loop if the
1249 * value returned by this function is nil. Otherwise, everything
1250 * will become frozen until the modal loop exits under normal
1251 * condition (scrollbar drag is released, menu closed etc.)
1254 mswindows_pump_outstanding_events (void)
1256 /* This function can call lisp */
1258 Lisp_Object result = Qt;
1259 struct gcpro gcpro1;
1262 if (NILP(mswindows_error_caught_in_modal_loop))
1263 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1269 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1270 * QUITP, and are interesting in keyboard messages only.
1273 mswindows_drain_windows_queue (void)
1277 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1278 assert (!mswindows_in_modal_loop);
1280 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1282 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1284 /* Don't translate messages destined for a dialog box, this
1285 makes keyboard traversal work. I think?? */
1286 if (mswindows_is_dialog_msg (&msg))
1288 mswindows_unmodalize_signal_maybe ();
1292 /* We have to translate messages that are not sent to an XEmacs
1293 frame. This is so that key presses work ok in things like
1294 edit fields. However, we *musn't* translate message for XEmacs
1295 frames as this is handled in the wnd proc.
1296 We also have to avoid generating paint magic events for windows
1297 that aren't XEmacs frames */
1298 /* GetClassName will truncate a longer class name. By adding one
1299 extra character, we are forcing textual comparison to fail
1300 if the name is longer than XEMACS_CLASS */
1302 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1303 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1305 /* Not an XEmacs frame */
1306 TranslateMessage (&msg);
1308 else if (msg.message == WM_PAINT)
1310 struct mswindows_frame* msframe;
1312 /* hdc will be NULL unless this is a subwindow - in which case we
1313 shouldn't have received a paint message for it here. */
1314 assert (msg.wParam == 0);
1316 /* Queue a magic event for handling when safe */
1318 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1319 if (!msframe->paint_pending)
1321 msframe->paint_pending = 1;
1322 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1324 /* Don't dispatch. WM_PAINT is always the last message in the
1325 queue so it's OK to just return. */
1328 DispatchMessage (&msg);
1329 mswindows_unmodalize_signal_maybe ();
1334 * This is a special flavor of the mswindows_need_event function,
1335 * used while in event pump. Actually, there is only kind of events
1336 * allowed while in event pump: a timer. An attempt to fetch any
1337 * other event leads to a deadlock, as there's no source of user input
1338 * ('cause event pump mirrors windows modal loop, which is a sole
1339 * owner of thread message queue).
1341 * To detect this, we use a counter of active timers, and allow
1342 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1343 * which will never come when there are no pending timers, which leads
1344 * to deadlock, we simply signal an error.
1346 * It might be possible to combine this with mswindows_drain_windows_queue
1347 * which fetches events when not in a modal loop. It's not clear
1348 * whether the result would be more complex than is justified.
1351 mswindows_need_event_in_modal_loop (int badly_p)
1355 /* Check if already have one */
1356 if (!NILP (mswindows_u_dispatch_event_queue)
1357 || !NILP (mswindows_s_dispatch_event_queue))
1360 /* No event is ok */
1364 /* We do not check the _u_ queue, because timers go to _s_ */
1365 while (NILP (mswindows_s_dispatch_event_queue))
1367 /* We'll deadlock if go waiting */
1368 if (mswindows_pending_timers_count == 0)
1369 error ("Deadlock due to an attempt to call next-event in a wrong context");
1371 /* Fetch and dispatch any pending timers */
1372 if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1373 DispatchMessage (&msg);
1378 * This drains the event queue and fills up two internal queues until
1379 * an event of a type specified by USER_P is retrieved.
1382 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1385 mswindows_need_event (int badly_p)
1389 while (NILP (mswindows_u_dispatch_event_queue)
1390 && NILP (mswindows_s_dispatch_event_queue))
1392 #ifdef HAVE_MSG_SELECT
1394 SELECT_TYPE temp_mask = input_wait_mask;
1395 EMACS_TIME sometime;
1396 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1399 pointer_to_this = 0;
1402 EMACS_SET_SECS_USECS (sometime, 0, 0);
1403 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1404 pointer_to_this = &select_time_to_block;
1405 if (mswindows_in_modal_loop)
1406 /* In modal loop with badly_p false, don't care about
1408 FD_CLR (windows_fd, &temp_mask);
1411 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1416 return; /* timeout */
1418 else if (active > 0)
1420 if (FD_ISSET (windows_fd, &temp_mask))
1422 if (mswindows_in_modal_loop)
1423 mswindows_need_event_in_modal_loop (badly_p);
1425 mswindows_drain_windows_queue ();
1430 /* Look for a TTY event */
1431 for (i = 0; i < MAXDESC-1; i++)
1433 /* To avoid race conditions (among other things, an infinite
1434 loop when called from Fdiscard_input()), we must return
1435 user events ahead of process events. */
1436 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1438 struct console *c = tty_find_console_from_fd (i);
1439 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1440 Lisp_Event* event = XEVENT (emacs_event);
1443 if (read_event_from_tty_or_stream_desc (event, c, i))
1445 mswindows_enqueue_dispatch_event (emacs_event);
1451 /* Look for a process event */
1452 for (i = 0; i < MAXDESC-1; i++)
1454 if (FD_ISSET (i, &temp_mask))
1456 if (FD_ISSET (i, &process_only_mask))
1459 get_process_from_usid (FD_TO_USID(i));
1461 mswindows_enqueue_process_event (p);
1465 /* We might get here when a fake event came
1466 through a signal. Return a dummy event, so
1467 that a cycle of the command loop will
1469 drain_signal_event_pipe ();
1470 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1476 else if (active==-1)
1480 /* something bad happened */
1489 /* Now try getting a message or process event */
1491 if (mswindows_in_modal_loop)
1492 /* In a modal loop, only look for timer events, and only if
1493 we really need one. */
1496 what_events = QS_TIMER;
1501 /* Look for any event */
1502 what_events = QS_ALLINPUT;
1504 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1505 mswindows_waitable_handles,
1506 FALSE, badly_p ? INFINITE : 0,
1509 /* This will assert if handle being waited for becomes abandoned.
1510 Not the case currently tho */
1511 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1512 (active >= WAIT_OBJECT_0 &&
1513 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1515 if (active == WAIT_TIMEOUT)
1517 /* No luck trying - just return what we've already got */
1520 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1522 /* Got your message, thanks */
1523 if (mswindows_in_modal_loop)
1524 mswindows_need_event_in_modal_loop (badly_p);
1526 mswindows_drain_windows_queue ();
1530 int ix = active - WAIT_OBJECT_0;
1531 /* First, try to find which process' output has signaled */
1533 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1536 /* Found a signaled process input handle */
1537 mswindows_enqueue_process_event (p);
1541 /* None. This means that the process handle itself has signaled.
1542 Remove the handle from the wait vector, and make status_notify
1543 note the exited process. First find the process object if
1545 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
1546 if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
1547 mswindows_waitable_handles [ix])
1549 mswindows_waitable_handles [ix] =
1550 mswindows_waitable_handles [--mswindows_waitable_count];
1551 kick_status_notify ();
1552 /* We need to return a process event here so that
1553 (1) accept-process-output will return when called on this
1554 process, and (2) status notifications will happen in
1555 accept-process-output, sleep-for, and sit-for. */
1556 /* #### horrible kludge till my real process fixes go in.
1557 #### Replaced with a slightly less horrible kluge that
1558 at least finds the right process instead of axing the
1559 first one on the list.
1561 if (!NILP (vproctail))
1563 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1565 else /* trash me soon. */
1566 /* Have to return something: there may be no accompanying
1568 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1575 /************************************************************************/
1576 /* Event generators */
1577 /************************************************************************/
1580 * Callback procedure for synchronous timer messages
1582 static void CALLBACK
1583 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1585 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1586 Lisp_Event *event = XEVENT (emacs_event);
1588 if (KillTimer (NULL, id_timer))
1589 --mswindows_pending_timers_count;
1591 event->channel = Qnil;
1592 event->timestamp = dwtime;
1593 event->event_type = timeout_event;
1594 event->event.timeout.interval_id = id_timer;
1595 event->event.timeout.function = Qnil;
1596 event->event.timeout.object = Qnil;
1598 mswindows_enqueue_dispatch_event (emacs_event);
1602 * Callback procedure for dde messages
1604 * We execute a dde Open("file") by simulating a file drop, so dde support
1605 * depends on dnd support.
1607 #ifdef HAVE_DRAGNDROP
1609 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1610 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1611 DWORD dwData1, DWORD dwData2)
1616 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1617 return (HDDEDATA)TRUE;
1618 return (HDDEDATA)FALSE;
1620 case XTYP_WILDCONNECT:
1622 /* We only support one {service,topic} pair */
1623 HSZPAIR pairs[2] = {
1624 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1626 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1627 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1628 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1629 sizeof (pairs), 0L, 0, uFmt, 0));
1631 return (HDDEDATA)NULL;
1634 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1636 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1637 LPBYTE cmd = (LPBYTE) alloca (len+1);
1640 struct gcpro gcpro1, gcpro2;
1641 Lisp_Object l_dndlist = Qnil;
1642 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1643 Lisp_Object frmcons, devcons, concons;
1644 Lisp_Event *event = XEVENT (emacs_event);
1646 DdeGetData (hdata, cmd, len, 0);
1648 DdeFreeDataHandle (hdata);
1650 /* Check syntax & that it's an [Open("foo")] command, which we
1651 * treat like a file drop */
1652 /* #### Ought to be generalised and accept some other commands */
1655 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1656 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1657 return DDE_FNOTPROCESSED;
1658 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1661 if (*cmd!='(' || *(cmd+1)!='\"')
1662 return DDE_FNOTPROCESSED;
1664 while (*end && *end!='\"')
1667 return DDE_FNOTPROCESSED;
1670 return DDE_FNOTPROCESSED;
1674 return DDE_FNOTPROCESSED;
1677 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1678 strcpy (filename, "file:");
1679 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1681 dostounix_filename (cmd);
1682 filename = alloca (strlen (cmd)+6);
1683 strcpy (filename, "file:");
1684 strcat (filename, cmd);
1686 GCPRO2 (emacs_event, l_dndlist);
1687 l_dndlist = make_string (filename, strlen (filename));
1689 /* Find a mswindows frame */
1690 event->channel = Qnil;
1691 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1693 Lisp_Object frame = XCAR (frmcons);
1694 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1695 event->channel = frame;
1697 assert (!NILP (event->channel));
1699 event->timestamp = GetTickCount();
1700 event->event_type = misc_user_event;
1701 event->event.misc.button = 1;
1702 event->event.misc.modifiers = 0;
1703 event->event.misc.x = -1;
1704 event->event.misc.y = -1;
1705 event->event.misc.function = Qdragdrop_drop_dispatch;
1706 event->event.misc.object = Fcons (Qdragdrop_URL,
1707 Fcons (l_dndlist, Qnil));
1708 mswindows_enqueue_dispatch_event (emacs_event);
1710 return (HDDEDATA) DDE_FACK;
1712 DdeFreeDataHandle (hdata);
1713 return (HDDEDATA) DDE_FNOTPROCESSED;
1716 return (HDDEDATA) NULL;
1722 * Helper to do repainting - repaints can happen both from the windows
1723 * procedure and from magic events
1726 mswindows_handle_paint (struct frame *frame)
1728 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1730 /* According to the docs we need to check GetUpdateRect() before
1731 actually doing a WM_PAINT */
1732 if (GetUpdateRect (hwnd, NULL, FALSE))
1734 PAINTSTRUCT paintStruct;
1735 int x, y, width, height;
1737 BeginPaint (hwnd, &paintStruct);
1738 x = paintStruct.rcPaint.left;
1739 y = paintStruct.rcPaint.top;
1740 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1741 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1742 /* Normally we want to ignore expose events when child
1743 windows are unmapped, however once we are in the guts of
1744 WM_PAINT we need to make sure that we don't register
1745 unmaps then because they will not actually occur. */
1746 /* #### commenting out the next line seems to fix some problems
1747 but not all. only andy currently understands this stuff and
1748 he needs to review it more carefully. --ben */
1749 if (!check_for_ignored_expose (frame, x, y, width, height))
1751 hold_ignored_expose_registration = 1;
1752 mswindows_redraw_exposed_area (frame, x, y, width, height);
1753 hold_ignored_expose_registration = 0;
1755 EndPaint (hwnd, &paintStruct);
1760 * Returns 1 if a key is a real modifier or special key, which
1761 * is better handled by DefWindowProc
1764 key_needs_default_processing_p (UINT vkey)
1766 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1767 /* if we let ALT activate the menu like this, then sticky ALT-modified
1768 keystrokes become impossible. */
1769 && !modifier_keys_are_sticky)
1775 /* key-handling code is always ugly. It just ends up working out
1778 #### Most of the sticky-modifier code below is copied from similar
1779 code in event-Xt.c. They should somehow or other be merged.
1781 Here are some pointers:
1783 -- DOWN_MASK indicates which modifiers should be treated as "down"
1784 when the corresponding upstroke happens. It gets reset for
1785 a particular modifier when that modifier goes up, and reset
1786 for all modifiers when a non-modifier key is pressed. Example:
1788 I press Control-A-Shift and then release Control-A-Shift.
1789 I want the Shift key to be sticky but not the Control key.
1791 -- If a modifier key is sticky, I can unstick it by pressing
1792 the modifier key again. */
1794 static WPARAM last_downkey;
1795 static int need_to_add_mask, down_mask;
1797 #define XEMSW_LCONTROL (1<<0)
1798 #define XEMSW_RCONTROL (1<<1)
1799 #define XEMSW_LSHIFT (1<<2)
1800 #define XEMSW_RSHIFT (1<<3)
1801 #define XEMSW_LMENU (1<<4)
1802 #define XEMSW_RMENU (1<<5)
1805 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1806 int downp, int keyp)
1810 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1814 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1815 wParam == VK_RCONTROL ||
1816 wParam == VK_MENU || wParam == VK_LMENU ||
1817 wParam == VK_RMENU ||
1818 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1819 wParam == VK_RSHIFT)))
1820 { /* Not a modifier key */
1821 if (downp && keyp && !last_downkey)
1822 last_downkey = wParam;
1823 /* If I hold press-and-release the Control key and then press
1824 and hold down the right arrow, I want it to auto-repeat
1825 Control-Right. On the other hand, if I do the same but
1826 manually press the Right arrow a bunch of times, I want
1827 to see one Control-Right and then a bunch of Rights.
1828 This means that we need to distinguish between an
1829 auto-repeated key and a key pressed and released a bunch
1831 else if ((downp && !keyp) ||
1832 (downp && keyp && last_downkey &&
1833 (wParam != last_downkey ||
1834 /* the "previous key state" bit indicates autorepeat */
1835 ! (lParam & (1 << 30)))))
1837 need_to_add_mask = 0;
1843 mods = need_to_add_mask;
1845 else /* Modifier key pressed */
1847 /* If a non-modifier key was pressed in the middle of a bunch
1848 of modifiers, then it unsticks all the modifiers that were
1849 previously pressed. We cannot unstick the modifiers until
1850 now because we want to check for auto-repeat of the
1851 non-modifier key. */
1856 need_to_add_mask = 0;
1859 #define FROB(mask) \
1861 if (downp && keyp) \
1863 /* If modifier key is already sticky, \
1864 then unstick it. Note that we do \
1865 not test down_mask to deal with the \
1866 unlikely but possible case that the \
1867 modifier key auto-repeats. */ \
1868 if (need_to_add_mask & mask) \
1870 need_to_add_mask &= ~mask; \
1871 down_mask &= ~mask; \
1874 down_mask |= mask; \
1878 if (down_mask & mask) \
1880 down_mask &= ~mask; \
1881 need_to_add_mask |= mask; \
1886 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1887 || wParam == VK_RCONTROL)
1888 FROB (XEMSW_RCONTROL);
1889 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1890 || wParam == VK_LCONTROL)
1891 FROB (XEMSW_LCONTROL);
1893 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1894 || wParam == VK_RSHIFT)
1895 FROB (XEMSW_RSHIFT);
1896 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1897 || wParam == VK_LSHIFT)
1898 FROB (XEMSW_LSHIFT);
1900 if ((wParam == VK_MENU && (lParam & 0x1000000))
1901 || wParam == VK_RMENU)
1903 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1904 || wParam == VK_LMENU)
1913 GetKeyboardState (keymap);
1915 if (mods & XEMSW_LCONTROL)
1917 keymap [VK_CONTROL] |= 0x80;
1918 keymap [VK_LCONTROL] |= 0x80;
1920 if (mods & XEMSW_RCONTROL)
1922 keymap [VK_CONTROL] |= 0x80;
1923 keymap [VK_RCONTROL] |= 0x80;
1926 if (mods & XEMSW_LSHIFT)
1928 keymap [VK_SHIFT] |= 0x80;
1929 keymap [VK_LSHIFT] |= 0x80;
1931 if (mods & XEMSW_RSHIFT)
1933 keymap [VK_SHIFT] |= 0x80;
1934 keymap [VK_RSHIFT] |= 0x80;
1937 if (mods & XEMSW_LMENU)
1939 keymap [VK_MENU] |= 0x80;
1940 keymap [VK_LMENU] |= 0x80;
1942 if (mods & XEMSW_RMENU)
1944 keymap [VK_MENU] |= 0x80;
1945 keymap [VK_RMENU] |= 0x80;
1948 SetKeyboardState (keymap);
1956 clear_sticky_modifiers (void)
1958 need_to_add_mask = 0;
1968 output_modifier_keyboard_state (void)
1972 GetKeyboardState (keymap);
1974 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1975 keymap[VK_MENU] & 0x80 ? 1 : 0,
1976 keymap[VK_MENU] & 0x1 ? 1 : 0,
1977 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1978 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1979 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1980 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1981 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1982 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1983 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1984 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1985 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1986 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1987 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1988 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1989 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1990 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1991 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1992 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1993 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1994 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
1999 /* try to debug the stuck-alt-key problem.
2001 #### this happens only inconsistently, and may only happen when using
2002 StickyKeys in the Win2000 accessibility section of the control panel,
2003 which is extremely broken for other reasons. */
2006 output_alt_keyboard_state (void)
2010 // SHORT asyncstate[3];
2012 GetKeyboardState (keymap);
2013 keystate[0] = GetKeyState (VK_MENU);
2014 keystate[1] = GetKeyState (VK_LMENU);
2015 keystate[2] = GetKeyState (VK_RMENU);
2016 /* Doing this interferes with key processing. */
2017 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2018 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2019 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2021 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2022 keymap[VK_MENU] & 0x80 ? 1 : 0,
2023 keymap[VK_MENU] & 0x1 ? 1 : 0,
2024 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2025 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2026 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2027 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2028 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2029 keystate[0] & 0x8000 ? 1 : 0,
2030 keystate[0] & 0x1 ? 1 : 0,
2031 keystate[1] & 0x8000 ? 1 : 0,
2032 keystate[1] & 0x1 ? 1 : 0,
2033 keystate[2] & 0x8000 ? 1 : 0,
2034 keystate[2] & 0x1 ? 1 : 0);
2035 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2036 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2037 /* asyncstate[0] & 0x1 ? 1 : 0, */
2038 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2039 /* asyncstate[1] & 0x1 ? 1 : 0, */
2040 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2041 /* asyncstate[2] & 0x1 ? 1 : 0); */
2044 #endif /* DEBUG_XEMACS */
2048 * The windows procedure for the window class XEMACS_CLASS
2051 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2053 /* Note: Remember to initialize emacs_event and event before use.
2054 This code calls code that can GC. You must GCPRO before calling such code. */
2055 Lisp_Object emacs_event = Qnil;
2056 Lisp_Object fobj = Qnil;
2059 struct frame *frame;
2060 struct mswindows_frame* msframe;
2062 /* Not perfect but avoids crashes. There is potential for wierd
2067 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2070 case WM_DESTROYCLIPBOARD:
2071 /* We own the clipboard and someone else wants it. Delete our
2072 cached copy of the clipboard contents so we'll ask for it from
2073 Windows again when someone does a paste, and destroy any memory
2074 objects we hold on the clipboard that are not in the list of types
2075 that Windows will delete itself. */
2076 mswindows_destroy_selection (QCLIPBOARD);
2077 handle_selection_clear (QCLIPBOARD);
2081 /* Erase background only during non-dynamic sizing */
2082 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2083 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2088 fobj = mswindows_find_frame (hwnd);
2089 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2095 /* See Win95 comment under WM_KEYDOWN */
2098 int should_set_keymap = 0;
2101 if (debug_mswindows_events)
2103 stderr_out ("%s wparam=%d lparam=%d\n",
2104 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
2105 wParam, (int)lParam);
2106 output_alt_keyboard_state ();
2108 #endif /* DEBUG_XEMACS */
2110 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2111 if (wParam == VK_CONTROL)
2113 GetKeyboardState (keymap);
2114 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2115 should_set_keymap = 1;
2117 else if (wParam == VK_MENU)
2119 GetKeyboardState (keymap);
2120 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2121 should_set_keymap = 1;
2124 if (should_set_keymap)
2125 // && (message_ != WM_SYSKEYUP
2126 // || NILP (Vmenu_accelerator_enabled)))
2127 SetKeyboardState (keymap);
2131 if (key_needs_default_processing_p (wParam))
2139 /* In some locales the right-hand Alt key is labelled AltGr. This key
2140 * should produce alternative characters when combined with another key.
2141 * eg on a German keyboard pressing AltGr+q should produce '@'.
2142 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2143 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2144 * it translates as if AltGr were down.
2145 * We get round this by removing all modifiers from the keymap before
2146 * calling TranslateMessage() unless AltGr is *really* down. */
2148 BYTE keymap_trans[256];
2149 BYTE keymap_orig[256];
2150 BYTE keymap_sticky[256];
2151 int has_AltGr = mswindows_current_layout_has_AltGr ();
2152 int mods = 0, mods_with_shift = 0;
2153 int extendedp = lParam & 0x1000000;
2158 if (debug_mswindows_events)
2160 stderr_out ("%s wparam=%d lparam=%d\n",
2161 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
2162 wParam, (int)lParam);
2163 output_alt_keyboard_state ();
2165 #endif /* DEBUG_XEMACS */
2167 GetKeyboardState (keymap_orig);
2168 frame = XFRAME (mswindows_find_frame (hwnd));
2169 if ((sticky_changed =
2170 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2172 GetKeyboardState (keymap_sticky);
2173 if (keymap_sticky[VK_MENU] & 0x80)
2175 message_ = WM_SYSKEYDOWN;
2176 /* We have to set the "context bit" so that the
2177 TranslateMessage() call below that generates the
2178 SYSCHAR message does its thing; see the documentation
2184 memcpy (keymap_sticky, keymap_orig, 256);
2186 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2187 mods_with_shift = mods;
2189 /* Handle non-printables */
2190 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2193 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2195 SetKeyboardState (keymap_orig);
2197 else /* Normal keys & modifiers */
2200 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2201 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2203 int potential_accelerator = 0;
2204 int got_accelerator = 0;
2207 msg.message = message_;
2208 msg.wParam = wParam;
2209 msg.lParam = lParam;
2210 msg.time = GetMessageTime();
2213 /* GetKeyboardState() does not work as documented on Win95. We have
2214 * to loosely track Left and Right modifiers on behalf of the OS,
2215 * without screwing up Windows NT which tracks them properly. */
2216 if (wParam == VK_CONTROL)
2218 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2219 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2221 else if (wParam == VK_MENU)
2223 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2224 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2227 if (!NILP (Vmenu_accelerator_enabled) &&
2228 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2229 potential_accelerator = 1;
2231 /* Remove shift modifier from an ascii character */
2232 mods &= ~XEMACS_MOD_SHIFT;
2234 memcpy (keymap_trans, keymap_sticky, 256);
2236 /* Clear control and alt modifiers unless AltGr is pressed */
2237 keymap_trans[VK_RCONTROL] = 0;
2238 keymap_trans[VK_LMENU] = 0;
2239 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2240 || !(keymap_trans[VK_RMENU] & 0x80))
2242 keymap_trans[VK_LCONTROL] = 0;
2243 keymap_trans[VK_CONTROL] = 0;
2244 keymap_trans[VK_RMENU] = 0;
2245 keymap_trans[VK_MENU] = 0;
2247 SetKeyboardState (keymap_trans);
2249 /* Maybe generate some WM_[SYS]CHARs in the queue */
2250 TranslateMessage (&msg);
2252 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2253 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2256 int mods_with_quit = mods;
2257 WPARAM ch = tranmsg.wParam;
2259 /* If a quit char with no modifiers other than control and
2260 shift, then mark it with a fake modifier, which is removed
2261 upon dequeueing the event */
2262 /* !!#### Fix this in my mule ws -- replace current_buffer
2264 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2265 && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2266 DOWNCASE (current_buffer, ch))
2267 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2268 && DOWNCASE (current_buffer, quit_ch) ==
2269 DOWNCASE (current_buffer, ch)))
2270 && ((mods_with_shift &
2271 ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2274 mods_with_quit |= FAKE_MOD_QUIT;
2275 if (mods_with_shift & XEMACS_MOD_SHIFT)
2276 mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2277 ++mswindows_quit_chars_count;
2279 else if (potential_accelerator && !got_accelerator &&
2280 mswindows_char_is_accelerator (frame, ch))
2282 got_accelerator = 1;
2285 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2289 /* This generates WM_SYSCHAR messages, which are interpreted
2290 by DefWindowProc as the menu selections. */
2291 if (got_accelerator)
2293 SetKeyboardState (keymap_sticky);
2294 TranslateMessage (&msg);
2295 SetKeyboardState (keymap_orig);
2299 SetKeyboardState (keymap_orig);
2303 if (key_needs_default_processing_p (wParam))
2308 case WM_MBUTTONDOWN:
2310 /* Real middle mouse button has nothing to do with emulated one:
2311 if one wants to exercise fingers playing chords on the mouse,
2312 he is allowed to do that! */
2313 mswindows_enqueue_mouse_button_event (hwnd, message_,
2314 MAKEPOINTS (lParam),
2315 wParam &~ MK_MBUTTON,
2320 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2321 msframe->last_click_time = GetMessageTime();
2323 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2324 msframe->button2_need_lbutton = 0;
2325 if (msframe->ignore_next_lbutton_up)
2327 msframe->ignore_next_lbutton_up = 0;
2329 else if (msframe->button2_is_down)
2331 msframe->button2_is_down = 0;
2332 msframe->ignore_next_rbutton_up = 1;
2333 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2334 MAKEPOINTS (lParam),
2336 &~ (MK_LBUTTON | MK_MBUTTON
2342 if (msframe->button2_need_rbutton)
2344 msframe->button2_need_rbutton = 0;
2345 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2346 MAKEPOINTS (lParam),
2347 wParam &~ MK_LBUTTON,
2350 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2351 MAKEPOINTS (lParam),
2352 wParam &~ MK_LBUTTON,
2358 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2359 msframe->last_click_time = GetMessageTime();
2361 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2362 msframe->button2_need_rbutton = 0;
2363 if (msframe->ignore_next_rbutton_up)
2365 msframe->ignore_next_rbutton_up = 0;
2367 else if (msframe->button2_is_down)
2369 msframe->button2_is_down = 0;
2370 msframe->ignore_next_lbutton_up = 1;
2371 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2372 MAKEPOINTS (lParam),
2374 &~ (MK_LBUTTON | MK_MBUTTON
2380 if (msframe->button2_need_lbutton)
2382 msframe->button2_need_lbutton = 0;
2383 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2384 MAKEPOINTS (lParam),
2385 wParam &~ MK_RBUTTON,
2388 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2389 MAKEPOINTS (lParam),
2390 wParam &~ MK_RBUTTON,
2395 case WM_LBUTTONDOWN:
2396 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2398 if (msframe->button2_need_lbutton)
2400 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2401 msframe->button2_need_lbutton = 0;
2402 msframe->button2_need_rbutton = 0;
2403 if (mswindows_button2_near_enough (msframe->last_click_point,
2404 MAKEPOINTS (lParam)))
2406 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2407 MAKEPOINTS (lParam),
2409 &~ (MK_LBUTTON | MK_MBUTTON
2412 msframe->button2_is_down = 1;
2416 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2417 msframe->last_click_point,
2418 msframe->last_click_mods
2420 msframe->last_click_time);
2421 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2422 MAKEPOINTS (lParam),
2423 wParam &~ MK_LBUTTON,
2429 mswindows_set_chord_timer (hwnd);
2430 msframe->button2_need_rbutton = 1;
2431 msframe->last_click_point = MAKEPOINTS (lParam);
2432 msframe->last_click_mods = wParam;
2434 msframe->last_click_time = GetMessageTime();
2437 case WM_RBUTTONDOWN:
2438 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2440 if (msframe->button2_need_rbutton)
2442 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2443 msframe->button2_need_lbutton = 0;
2444 msframe->button2_need_rbutton = 0;
2445 if (mswindows_button2_near_enough (msframe->last_click_point,
2446 MAKEPOINTS (lParam)))
2448 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2449 MAKEPOINTS (lParam),
2451 &~ (MK_LBUTTON | MK_MBUTTON
2454 msframe->button2_is_down = 1;
2458 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2459 msframe->last_click_point,
2460 msframe->last_click_mods
2462 msframe->last_click_time);
2463 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2464 MAKEPOINTS (lParam),
2465 wParam &~ MK_RBUTTON,
2471 mswindows_set_chord_timer (hwnd);
2472 msframe->button2_need_lbutton = 1;
2473 msframe->last_click_point = MAKEPOINTS (lParam);
2474 msframe->last_click_mods = wParam;
2476 msframe->last_click_time = GetMessageTime();
2480 if (wParam == BUTTON_2_TIMER_ID)
2482 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2483 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2485 if (msframe->button2_need_lbutton)
2487 msframe->button2_need_lbutton = 0;
2488 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2489 msframe->last_click_point,
2490 msframe->last_click_mods
2492 msframe->last_click_time);
2494 else if (msframe->button2_need_rbutton)
2496 msframe->button2_need_rbutton = 0;
2497 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2498 msframe->last_click_point,
2499 msframe->last_click_mods
2501 msframe->last_click_time);
2505 assert ("Spurious timer fired" == 0);
2509 /* Optimization: don't report mouse movement while size is changing */
2510 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2511 if (!msframe->sizing)
2513 /* When waiting for the second mouse button to finish
2514 button2 emulation, and have moved too far, just pretend
2515 as if timer has expired. This improves drag-select feedback */
2516 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2517 && !mswindows_button2_near_enough (msframe->last_click_point,
2518 MAKEPOINTS (lParam)))
2520 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2521 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2524 emacs_event = Fmake_event (Qnil, Qnil);
2525 event = XEVENT(emacs_event);
2527 event->channel = mswindows_find_frame(hwnd);
2528 event->timestamp = GetMessageTime();
2529 event->event_type = pointer_motion_event;
2530 event->event.motion.x = MAKEPOINTS(lParam).x;
2531 event->event.motion.y = MAKEPOINTS(lParam).y;
2532 event->event.motion.modifiers =
2533 mswindows_modifier_state (NULL, wParam, 0);
2535 mswindows_enqueue_dispatch_event (emacs_event);
2541 /* Queue a `cancel-mode-internal' misc user event, so mouse
2542 selection would be canceled if any */
2543 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2544 Qcancel_mode_internal, Qnil);
2549 LPNMHDR nmhdr = (LPNMHDR)lParam;
2551 if (nmhdr->code == TTN_NEEDTEXT)
2553 #ifdef HAVE_TOOLBARS
2554 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2557 /* find out which toolbar */
2558 frame = XFRAME (mswindows_find_frame (hwnd));
2559 btext = mswindows_get_toolbar_button_text ( frame,
2562 tttext->lpszText = NULL;
2563 tttext->hinst = NULL;
2567 /* I think this is safe since the text will only go away
2568 when the toolbar does...*/
2569 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2573 /* handle tree view callbacks */
2574 else if (nmhdr->code == TVN_SELCHANGED)
2576 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2577 frame = XFRAME (mswindows_find_frame (hwnd));
2578 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2580 /* handle tab control callbacks */
2581 else if (nmhdr->code == TCN_SELCHANGE)
2584 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2585 frame = XFRAME (mswindows_find_frame (hwnd));
2587 item.mask = TCIF_PARAM;
2588 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2591 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2597 /* hdc will be NULL unless this is a subwindow - in which case we
2598 shouldn't have received a paint message for it here. */
2599 assert (wParam == 0);
2601 /* Can't queue a magic event because windows goes modal and sends paint
2602 messages directly to the windows procedure when doing solid drags
2603 and the message queue doesn't get processed. */
2604 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2608 /* We only care about this message if our size has really changed */
2609 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2614 fobj = mswindows_find_frame (hwnd);
2615 frame = XFRAME (fobj);
2616 msframe = FRAME_MSWINDOWS_DATA (frame);
2618 /* We cannot handle frame map and unmap hooks right in
2619 this routine, because these may throw. We queue
2620 magic events to run these hooks instead - kkm */
2622 if (wParam==SIZE_MINIMIZED)
2625 FRAME_VISIBLE_P (frame) = 0;
2626 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2630 GetClientRect(hwnd, &rect);
2631 FRAME_PIXWIDTH(frame) = rect.right;
2632 FRAME_PIXHEIGHT(frame) = rect.bottom;
2634 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2635 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2636 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2638 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2639 change_frame_size (frame, rows, columns, 1);
2641 /* If we are inside frame creation, we have to apply geometric
2643 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2645 /* Yes, we have to size again */
2646 mswindows_size_frame_internal ( frame,
2647 FRAME_MSWINDOWS_TARGET_RECT
2649 /* Reset so we do not get here again. The SetWindowPos call in
2650 * mswindows_size_frame_internal can cause recursion here. */
2651 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2653 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2654 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2659 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2660 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2661 FRAME_VISIBLE_P (frame) = 1;
2663 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2670 case WM_DISPLAYCHANGE:
2673 DWORD message_tick = GetMessageTime ();
2675 fobj = mswindows_find_frame (hwnd);
2676 frame = XFRAME (fobj);
2677 d = XDEVICE (FRAME_DEVICE (frame));
2679 /* Do this only once per message. XEmacs can receive this message
2680 through as many frames as it currently has open. Message time
2681 will be the same for all these messages. Despite extreme
2682 efficiency, the code below has about one in 4 billion
2683 probability that the HDC is not recreated, provided that
2684 XEmacs is running sufficiently longer than 52 days. */
2685 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2687 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2688 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2689 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2694 /* Misc magic events which only require that the frame be identified */
2697 mswindows_enqueue_magic_event (hwnd, message_);
2700 case WM_WINDOWPOSCHANGING:
2702 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2703 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2704 GetWindowPlacement(hwnd, &wpl);
2706 /* Only interested if size is changing and we're not being iconified */
2707 if (wpl.showCmd != SW_SHOWMINIMIZED
2708 && wpl.showCmd != SW_SHOWMAXIMIZED
2709 && !(wp->flags & SWP_NOSIZE))
2711 RECT ncsize = { 0, 0, 0, 0 };
2712 int pixwidth, pixheight;
2713 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2714 GetMenu(hwnd) != NULL,
2715 GetWindowLong (hwnd, GWL_EXSTYLE));
2717 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2718 wp->cx - (ncsize.right - ncsize.left),
2719 wp->cy - (ncsize.bottom - ncsize.top),
2720 &pixwidth, &pixheight);
2722 /* Convert client sizes to window sizes */
2723 pixwidth += (ncsize.right - ncsize.left);
2724 pixheight += (ncsize.bottom - ncsize.top);
2726 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2728 /* Adjust so that the bottom or right doesn't move if it's
2729 * the top or left that's being changed */
2731 GetWindowRect (hwnd, &rect);
2733 if (rect.left != wp->x)
2734 wp->x += wp->cx - pixwidth;
2735 if (rect.top != wp->y)
2736 wp->y += wp->cy - pixheight;
2742 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2743 window position if the user tries to track window too small */
2747 case WM_ENTERSIZEMOVE:
2748 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2749 msframe->sizing = 1;
2752 case WM_EXITSIZEMOVE:
2753 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2754 msframe->sizing = 0;
2755 /* Queue noop event */
2756 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2759 #ifdef HAVE_SCROLLBARS
2763 /* Direction of scroll is determined by scrollbar instance. */
2764 int code = (int) LOWORD(wParam);
2765 int pos = (short int) HIWORD(wParam);
2766 HWND hwndScrollBar = (HWND) lParam;
2767 struct gcpro gcpro1, gcpro2;
2769 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2770 GCPRO2 (emacs_event, fobj);
2771 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2773 /* Error during event pumping - cancel scroll */
2774 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2782 int keys = LOWORD (wParam); /* Modifier key flags */
2783 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2784 struct gcpro gcpro1, gcpro2;
2786 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2788 MAKEPOINTS (lParam)))
2790 GCPRO2 (emacs_event, fobj);
2791 mswindows_pump_outstanding_events (); /* Can GC */
2800 #ifdef HAVE_MENUBARS
2802 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2804 XFRAME (mswindows_find_frame (hwnd)))))
2805 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2808 case WM_INITMENUPOPUP:
2809 if (!HIWORD(lParam))
2811 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2813 XFRAME (mswindows_find_frame (hwnd)))))
2814 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2818 #endif /* HAVE_MENUBARS */
2822 WORD id = LOWORD (wParam);
2823 WORD nid = HIWORD (wParam);
2824 HWND cid = (HWND)lParam;
2825 frame = XFRAME (mswindows_find_frame (hwnd));
2827 #ifdef HAVE_TOOLBARS
2828 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2831 /* widgets in a buffer only eval a callback for suitable events.*/
2836 case CBN_EDITCHANGE:
2838 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2841 /* menubars always must come last since the hashtables do not
2843 #ifdef HAVE_MENUBARS
2844 if (!NILP (mswindows_handle_wm_command (frame, id)))
2848 return DefWindowProc (hwnd, message_, wParam, lParam);
2849 /* Bite me - a spurious command. This used to not be able to
2850 happen but with the introduction of widgets its now
2855 case WM_CTLCOLORBTN:
2856 case WM_CTLCOLORLISTBOX:
2857 case WM_CTLCOLOREDIT:
2858 case WM_CTLCOLORSTATIC:
2859 case WM_CTLCOLORSCROLLBAR:
2861 /* if we get an opportunity to paint a widget then do so if
2862 there is an appropriate face */
2863 HWND crtlwnd = (HWND)lParam;
2864 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2867 Lisp_Object image_instance;
2868 VOID_TO_LISP (image_instance, ii);
2869 if (IMAGE_INSTANCEP (image_instance)
2871 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2873 /* set colors for the buttons */
2874 HDC hdc = (HDC)wParam;
2875 if (last_widget_brushed != ii)
2878 DeleteObject (widget_brush);
2879 widget_brush = CreateSolidBrush
2880 (COLOR_INSTANCE_MSWINDOWS_COLOR
2883 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2884 XIMAGE_INSTANCE_FRAME (image_instance)))));
2886 last_widget_brushed = ii;
2889 COLOR_INSTANCE_MSWINDOWS_COLOR
2892 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2893 XIMAGE_INSTANCE_FRAME (image_instance)))));
2894 SetBkMode (hdc, OPAQUE);
2897 COLOR_INSTANCE_MSWINDOWS_COLOR
2900 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2901 XIMAGE_INSTANCE_FRAME (image_instance)))));
2902 return (LRESULT)widget_brush;
2908 #ifdef HAVE_DRAGNDROP
2909 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2911 UINT filecount, i, len;
2916 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2917 struct gcpro gcpro1, gcpro2, gcpro3;
2919 emacs_event = Fmake_event (Qnil, Qnil);
2920 event = XEVENT(emacs_event);
2922 GCPRO3 (emacs_event, l_dndlist, l_item);
2924 if (!DragQueryPoint ((HDROP) wParam, &point))
2925 point.x = point.y = -1; /* outside client area */
2927 event->event_type = misc_user_event;
2928 event->channel = mswindows_find_frame(hwnd);
2929 event->timestamp = GetMessageTime();
2930 event->event.misc.button = 1; /* #### Should try harder */
2931 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2933 event->event.misc.x = point.x;
2934 event->event.misc.y = point.y;
2935 event->event.misc.function = Qdragdrop_drop_dispatch;
2937 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2938 for (i=0; i<filecount; i++)
2940 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2941 /* The URLs that we make here aren't correct according to section
2942 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2943 * because they may contain reserved characters. But that's OK -
2944 * they just need to be good enough to keep dragdrop.el happy. */
2945 fname = (char *)xmalloc (len+1);
2946 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2948 /* May be a shell link aka "shortcut" - replace fname if so */
2949 #if !(defined(CYGWIN) || defined(MINGW))
2950 /* cygwin doesn't define this COM stuff */
2951 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2955 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2956 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2960 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2964 WIN32_FIND_DATA wfd;
2965 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2967 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2969 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2970 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2975 len = strlen (fname);
2978 ppf->lpVtbl->Release (ppf);
2981 psl->lpVtbl->Release (psl);
2987 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2988 strcpy (filename, "file:");
2989 cygwin32_win32_to_posix_path_list (fname, filename+5);
2991 filename = (char *)xmalloc (len+6);
2992 strcat (strcpy (filename, "file:"), fname);
2993 dostounix_filename (filename+5);
2996 l_item = make_string (filename, strlen (filename));
2997 l_dndlist = Fcons (l_item, l_dndlist);
3000 DragFinish ((HDROP) wParam);
3002 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3003 mswindows_enqueue_dispatch_event (emacs_event);
3011 return DefWindowProc (hwnd, message_, wParam, lParam);
3017 /************************************************************************/
3018 /* keyboard, mouse & other helpers for the windows procedure */
3019 /************************************************************************/
3021 mswindows_set_chord_timer (HWND hwnd)
3025 /* We get one third half system double click threshold */
3026 if (mswindows_mouse_button_tolerance <= 0)
3027 interval = GetDoubleClickTime () / 3;
3029 interval = mswindows_mouse_button_tolerance;
3031 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3035 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3038 if (mswindows_mouse_button_max_skew_x <= 0)
3039 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3041 dx = mswindows_mouse_button_max_skew_x;
3043 if (mswindows_mouse_button_max_skew_y <= 0)
3044 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3046 dy = mswindows_mouse_button_max_skew_y;
3048 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3052 mswindows_current_layout_has_AltGr (void)
3054 /* This simple caching mechanism saves 10% of CPU
3055 time when a key typed at autorepeat rate of 30 cps! */
3056 static HKL last_hkl = 0;
3057 static int last_hkl_has_AltGr;
3058 HKL current_hkl = (HKL) -1;
3060 if (xGetKeyboardLayout) /* not in NT 3.5 */
3061 current_hkl = xGetKeyboardLayout (0);
3062 if (current_hkl != last_hkl)
3065 last_hkl_has_AltGr = 0;
3066 /* In this loop, we query whether a character requires
3067 AltGr to be down to generate it. If at least such one
3068 found, this means that the layout does regard AltGr */
3069 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3070 if (HIBYTE (VkKeyScan (c)) == 6)
3071 last_hkl_has_AltGr = 1;
3072 last_hkl = current_hkl;
3074 return last_hkl_has_AltGr;
3078 /* Returns the state of the modifier keys in the format expected by the
3079 * Lisp_Event key_data, button_data and motion_data modifiers member */
3081 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3084 int keys_is_real = 0;
3087 if (fwKeys == (DWORD) -1)
3088 fwKeys = mswindows_last_mouse_button_state;
3092 mswindows_last_mouse_button_state = fwKeys;
3098 GetKeyboardState (keymap);
3099 has_AltGr = mswindows_current_layout_has_AltGr ();
3102 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3104 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3106 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3107 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3111 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3112 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3115 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3116 ? XEMACS_MOD_SHIFT : 0;
3117 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3118 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3119 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3125 * Translate a mswindows virtual key to a keysym.
3126 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3127 * or whose ASCII codes (like space) xemacs doesn't like.
3129 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3132 if (extendedp) /* Keys not present on a 82 key keyboard */
3134 switch (mswindows_key)
3136 case VK_CANCEL: return KEYSYM ("pause");
3137 case VK_RETURN: return KEYSYM ("kp-enter");
3138 case VK_PRIOR: return KEYSYM ("prior");
3139 case VK_NEXT: return KEYSYM ("next");
3140 case VK_END: return KEYSYM ("end");
3141 case VK_HOME: return KEYSYM ("home");
3142 case VK_LEFT: return KEYSYM ("left");
3143 case VK_UP: return KEYSYM ("up");
3144 case VK_RIGHT: return KEYSYM ("right");
3145 case VK_DOWN: return KEYSYM ("down");
3146 case VK_INSERT: return KEYSYM ("insert");
3147 case VK_DELETE: return QKdelete;
3148 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3149 case VK_LWIN return KEYSYM ("");
3150 case VK_RWIN return KEYSYM ("");
3152 case VK_APPS: return KEYSYM ("menu");
3157 switch (mswindows_key)
3159 case VK_BACK: return QKbackspace;
3160 case VK_TAB: return QKtab;
3161 case '\n': return QKlinefeed;
3162 case VK_CLEAR: return KEYSYM ("clear");
3163 case VK_RETURN: return QKreturn;
3164 case VK_PAUSE: return KEYSYM ("pause");
3165 case VK_ESCAPE: return QKescape;
3166 case VK_SPACE: return QKspace;
3167 case VK_PRIOR: return KEYSYM ("kp-prior");
3168 case VK_NEXT: return KEYSYM ("kp-next");
3169 case VK_END: return KEYSYM ("kp-end");
3170 case VK_HOME: return KEYSYM ("kp-home");
3171 case VK_LEFT: return KEYSYM ("kp-left");
3172 case VK_UP: return KEYSYM ("kp-up");
3173 case VK_RIGHT: return KEYSYM ("kp-right");
3174 case VK_DOWN: return KEYSYM ("kp-down");
3175 case VK_SELECT: return KEYSYM ("select");
3176 case VK_PRINT: return KEYSYM ("print");
3177 case VK_EXECUTE: return KEYSYM ("execute");
3178 case VK_SNAPSHOT: return KEYSYM ("print");
3179 case VK_INSERT: return KEYSYM ("kp-insert");
3180 case VK_DELETE: return KEYSYM ("kp-delete");
3181 case VK_HELP: return KEYSYM ("help");
3182 case VK_NUMPAD0: return KEYSYM ("kp-0");
3183 case VK_NUMPAD1: return KEYSYM ("kp-1");
3184 case VK_NUMPAD2: return KEYSYM ("kp-2");
3185 case VK_NUMPAD3: return KEYSYM ("kp-3");
3186 case VK_NUMPAD4: return KEYSYM ("kp-4");
3187 case VK_NUMPAD5: return KEYSYM ("kp-5");
3188 case VK_NUMPAD6: return KEYSYM ("kp-6");
3189 case VK_NUMPAD7: return KEYSYM ("kp-7");
3190 case VK_NUMPAD8: return KEYSYM ("kp-8");
3191 case VK_NUMPAD9: return KEYSYM ("kp-9");
3192 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3193 case VK_ADD: return KEYSYM ("kp-add");
3194 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3195 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3196 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3197 case VK_DIVIDE: return KEYSYM ("kp-divide");
3198 case VK_F1: return KEYSYM ("f1");
3199 case VK_F2: return KEYSYM ("f2");
3200 case VK_F3: return KEYSYM ("f3");
3201 case VK_F4: return KEYSYM ("f4");
3202 case VK_F5: return KEYSYM ("f5");
3203 case VK_F6: return KEYSYM ("f6");
3204 case VK_F7: return KEYSYM ("f7");
3205 case VK_F8: return KEYSYM ("f8");
3206 case VK_F9: return KEYSYM ("f9");
3207 case VK_F10: return KEYSYM ("f10");
3208 case VK_F11: return KEYSYM ("f11");
3209 case VK_F12: return KEYSYM ("f12");
3210 case VK_F13: return KEYSYM ("f13");
3211 case VK_F14: return KEYSYM ("f14");
3212 case VK_F15: return KEYSYM ("f15");
3213 case VK_F16: return KEYSYM ("f16");
3214 case VK_F17: return KEYSYM ("f17");
3215 case VK_F18: return KEYSYM ("f18");
3216 case VK_F19: return KEYSYM ("f19");
3217 case VK_F20: return KEYSYM ("f20");
3218 case VK_F21: return KEYSYM ("f21");
3219 case VK_F22: return KEYSYM ("f22");
3220 case VK_F23: return KEYSYM ("f23");
3221 case VK_F24: return KEYSYM ("f24");
3228 * Find the console that matches the supplied mswindows window handle
3231 mswindows_find_console (HWND hwnd)
3233 /* We only support one console */
3234 return XCAR (Vconsole_list);
3238 * Find the frame that matches the supplied mswindows window handle
3241 mswindows_find_frame (HWND hwnd)
3243 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3247 /* We are in progress of frame creation. Return the frame
3248 being created, as it still not remembered in the window
3250 assert (!NILP (Vmswindows_frame_being_created));
3251 return Vmswindows_frame_being_created;
3253 VOID_TO_LISP (f, l);
3258 /************************************************************************/
3260 /************************************************************************/
3263 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3266 EMACS_TIME current_time;
3267 EMACS_GET_TIME (current_time);
3268 EMACS_SUB_TIME (thyme, thyme, current_time);
3269 milliseconds = EMACS_SECS (thyme) * 1000 +
3270 (EMACS_USECS (thyme) + 500) / 1000;
3271 if (milliseconds < 1)
3273 ++mswindows_pending_timers_count;
3274 return SetTimer (NULL, 0, milliseconds,
3275 (TIMERPROC) mswindows_wm_timer_callback);
3279 emacs_mswindows_remove_timeout (int id)
3281 Lisp_Event match_against;
3282 Lisp_Object emacs_event;
3284 if (KillTimer (NULL, id))
3285 --mswindows_pending_timers_count;
3287 /* If there is a dispatch event generated by this
3288 timeout in the queue, we have to remove it too. */
3289 match_against.event_type = timeout_event;
3290 match_against.event.timeout.interval_id = id;
3291 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3292 if (!NILP (emacs_event))
3293 Fdeallocate_event(emacs_event);
3296 /* If `user_p' is false, then return whether there are any win32, timeout,
3297 * or subprocess events pending (that is, whether
3298 * emacs_mswindows_next_event() would return immediately without blocking).
3300 * if `user_p' is true, then return whether there are any *user generated*
3301 * events available (that is, whether there are keyboard or mouse-click
3302 * events ready to be read). This also implies that
3303 * emacs_mswindows_next_event() would not block.
3306 emacs_mswindows_event_pending_p (int user_p)
3308 mswindows_need_event (0);
3309 return (!NILP (mswindows_u_dispatch_event_queue)
3310 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3314 * Return the next event
3317 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3319 Lisp_Object event, event2;
3321 mswindows_need_event (1);
3323 event = mswindows_dequeue_dispatch_event ();
3324 XSETEVENT (event2, emacs_event);
3325 Fcopy_event (event, event2);
3326 Fdeallocate_event (event);
3330 * Handle a magic event off the dispatch queue.
3333 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3335 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3342 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3343 mswindows_handle_paint (f);
3344 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3351 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3352 struct frame *f = XFRAME (frame);
3353 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3355 struct gcpro gcpro1;
3357 /* On focus change, clear all memory of sticky modifiers
3358 to avoid non-intuitive behavior. */
3359 clear_sticky_modifiers ();
3361 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3363 emacs_handle_focus_change_preliminary (conser);
3364 /* Under X the stuff up to here is done in the X event handler.
3366 emacs_handle_focus_change_final (conser);
3375 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3376 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3378 Qmap_frame_hook : Qunmap_frame_hook,
3383 /* #### What about Enter & Leave */
3385 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3386 Qmouse_leave_frame_hook, 1, frame);
3394 #ifndef HAVE_MSG_SELECT
3396 get_process_input_waitable (Lisp_Process *process)
3398 Lisp_Object instr, outstr, p;
3399 XSETPROCESS (p, process);
3400 get_process_streams (process, &instr, &outstr);
3401 assert (!NILP (instr));
3402 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3403 return (network_connection_p (p)
3404 ? get_winsock_stream_waitable (XLSTREAM (instr))
3405 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3407 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3412 emacs_mswindows_select_process (Lisp_Process *process)
3414 HANDLE hev = get_process_input_waitable (process);
3416 if (!add_waitable_handle (hev))
3417 error ("Too many active processes");
3419 #ifdef HAVE_WIN32_PROCESSES
3422 XSETPROCESS (p, process);
3423 if (!network_connection_p (p))
3425 HANDLE hprocess = get_nt_process_handle (process);
3426 if (!add_waitable_handle (hprocess))
3428 remove_waitable_handle (hev);
3429 error ("Too many active processes");
3437 emacs_mswindows_unselect_process (Lisp_Process *process)
3439 /* Process handle is removed in the event loop as soon
3440 as it is signaled, so don't bother here about it */
3441 HANDLE hev = get_process_input_waitable (process);
3442 remove_waitable_handle (hev);
3444 #endif /* HAVE_MSG_SELECT */
3447 emacs_mswindows_select_console (struct console *con)
3449 #ifdef HAVE_MSG_SELECT
3450 if (CONSOLE_MSWINDOWS_P (con))
3451 return; /* mswindows consoles are automatically selected */
3453 event_stream_unixoid_select_console (con);
3458 emacs_mswindows_unselect_console (struct console *con)
3460 #ifdef HAVE_MSG_SELECT
3461 if (CONSOLE_MSWINDOWS_P (con))
3462 return; /* mswindows consoles are automatically selected */
3464 event_stream_unixoid_unselect_console (con);
3469 emacs_mswindows_quit_p (void)
3471 /* Quit cannot happen in modal loop: all program
3472 input is dedicated to Windows. */
3473 if (mswindows_in_modal_loop)
3476 /* Drain windows queue. This sets up number of quit characters in
3478 mswindows_drain_windows_queue ();
3480 if (mswindows_quit_chars_count > 0)
3482 /* Yes there's a hidden one... Throw it away */
3483 Lisp_Event match_against;
3484 Lisp_Object emacs_event;
3487 match_against.event_type = key_press_event;
3488 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3490 while (mswindows_quit_chars_count-- > 0)
3492 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3493 assert (!NILP (emacs_event));
3495 if (XEVENT (emacs_event)->event.key.modifiers &
3496 FAKE_MOD_QUIT_CRITICAL)
3499 Fdeallocate_event (emacs_event);
3502 Vquit_flag = critical_p ? Qcritical : Qt;
3507 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3508 Lisp_Object* instream,
3509 Lisp_Object* outstream,
3512 /* Handles for streams */
3514 /* fds. These just stored along with the streams, and are closed in
3515 delete stream pair method, because we need to handle fake unices
3519 /* Decode inhandle and outhandle. Their meaning depends on
3520 the process implementation being used. */
3521 #if defined (HAVE_WIN32_PROCESSES)
3522 /* We're passed in Windows handles. That's what we like most... */
3523 hin = (HANDLE) inhandle;
3524 hout = (HANDLE) outhandle;
3526 #elif defined (HAVE_UNIX_PROCESSES)
3527 /* We are passed UNIX fds. This must be Cygwin.
3529 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3530 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3534 #error "So, WHICH kind of processes do you want?"
3537 *instream = (hin == INVALID_HANDLE_VALUE
3539 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3540 : flags & STREAM_NETWORK_CONNECTION
3541 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3543 : make_ntpipe_input_stream (hin, fdi));
3545 #ifdef HAVE_WIN32_PROCESSES
3546 *outstream = (hout == INVALID_HANDLE_VALUE
3548 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3549 : flags & STREAM_NETWORK_CONNECTION
3550 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3552 : make_ntpipe_output_stream (hout, fdo));
3553 #elif defined (HAVE_UNIX_PROCESSES)
3554 *outstream = (fdo >= 0
3555 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3558 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3559 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3560 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3562 Bufbyte eof_char = get_eof_char (fdo);
3563 int pty_max_bytes = get_pty_max_bytes (fdo);
3564 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3569 return (NILP (*instream)
3571 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3572 : flags & STREAM_NETWORK_CONNECTION
3573 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3575 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3579 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3580 Lisp_Object outstream)
3582 /* Oh nothing special here for Win32 at all */
3583 #if defined (HAVE_UNIX_PROCESSES)
3584 int in = (NILP(instream)
3586 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3587 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3588 ? get_winsock_stream_param (XLSTREAM (instream))
3590 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3591 int out = (NILP(outstream) ? -1
3592 : filedesc_stream_fd (XLSTREAM (outstream)));
3596 if (out != in && out >= 0)
3600 return (NILP (instream)
3602 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3603 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3604 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3606 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3610 emacs_mswindows_current_event_timestamp (struct console *c)
3612 return GetTickCount ();
3615 #ifndef HAVE_X_WINDOWS
3616 /* This is called from GC when a process object is about to be freed.
3617 If we've still got pointers to it in this file, we're gonna lose hard.
3620 debug_process_finalization (Lisp_Process *p)
3623 Lisp_Object instr, outstr;
3625 get_process_streams (p, &instr, &outstr);
3626 /* if it still has fds, then it hasn't been killed yet. */
3627 assert (NILP(instr));
3628 assert (NILP(outstr));
3630 /* #### More checks here */
3635 /************************************************************************/
3636 /* initialization */
3637 /************************************************************************/
3640 reinit_vars_of_event_mswindows (void)
3642 mswindows_in_modal_loop = 0;
3643 mswindows_pending_timers_count = 0;
3645 mswindows_event_stream = xnew (struct event_stream);
3647 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3648 mswindows_event_stream->force_event_pending = 0;
3649 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3650 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3651 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3652 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3653 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3654 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3655 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3656 #ifdef HAVE_MSG_SELECT
3657 mswindows_event_stream->select_process_cb =
3658 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3659 mswindows_event_stream->unselect_process_cb =
3660 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3661 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3662 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3664 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3665 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3666 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3667 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3669 mswindows_event_stream->current_event_timestamp_cb =
3670 emacs_mswindows_current_event_timestamp;
3674 vars_of_event_mswindows (void)
3676 reinit_vars_of_event_mswindows ();
3678 mswindows_u_dispatch_event_queue = Qnil;
3679 staticpro (&mswindows_u_dispatch_event_queue);
3680 mswindows_u_dispatch_event_queue_tail = Qnil;
3681 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
3683 mswindows_s_dispatch_event_queue = Qnil;
3684 staticpro (&mswindows_s_dispatch_event_queue);
3685 mswindows_s_dispatch_event_queue_tail = Qnil;
3686 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
3688 mswindows_error_caught_in_modal_loop = Qnil;
3689 staticpro (&mswindows_error_caught_in_modal_loop);
3693 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
3694 If non-zero, display debug information about Windows events that XEmacs sees.
3695 Information is displayed in a console window. Currently defined values are:
3697 1 == non-verbose output
3700 #### Unfortunately, not yet implemented.
3702 debug_mswindows_events = 0;
3705 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3706 &mswindows_alt_by_itself_activates_menu /*
3707 *Controls whether pressing and releasing the Alt key activates the menubar.
3708 This applies only if no intervening key was pressed. See also
3709 `menu-accelerator-enabled', which is probably the behavior you actually want.
3713 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3714 &mswindows_dynamic_frame_resize /*
3715 *Controls redrawing frame contents during mouse-drag or keyboard resize
3716 operation. When non-nil, the frame is redrawn while being resized. When
3717 nil, frame is not redrawn, and exposed areas are filled with default
3718 MDI application background color. Note that this option only has effect
3719 if "Show window contents while dragging" is on in system Display/Plus!
3721 Default is t on fast machines, nil on slow.
3724 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3725 &mswindows_mouse_button_tolerance /*
3726 *Analogue of double click interval for faking middle mouse events.
3727 The value is the minimum time in milliseconds that must elapse between
3728 left/right button down events before they are considered distinct events.
3729 If both mouse buttons are depressed within this interval, a middle mouse
3730 button down event is generated instead.
3731 If negative or zero, currently set system default is used instead.
3734 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3735 Number of physical mouse buttons.
3738 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3739 &mswindows_mouse_button_max_skew_x /*
3740 *Maximum horizontal distance in pixels between points in which left and
3741 right button clicks occurred for them to be translated into single
3742 middle button event. Clicks must occur in time not longer than defined
3743 by the variable `mswindows-mouse-button-tolerance'.
3744 If negative or zero, currently set system default is used instead.
3747 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3748 &mswindows_mouse_button_max_skew_y /*
3749 *Maximum vertical distance in pixels between points in which left and
3750 right button clicks occurred for them to be translated into single
3751 middle button event. Clicks must occur in time not longer than defined
3752 by the variable `mswindows-mouse-button-tolerance'.
3753 If negative or zero, currently set system default is used instead.
3756 mswindows_mouse_button_max_skew_x = 0;
3757 mswindows_mouse_button_max_skew_y = 0;
3758 mswindows_mouse_button_tolerance = 0;
3759 mswindows_alt_by_itself_activates_menu = 1;
3763 syms_of_event_mswindows (void)
3768 lstream_type_create_mswindows_selectable (void)
3770 init_slurp_stream ();
3771 init_shove_stream ();
3772 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3773 init_winsock_stream ();
3778 init_event_mswindows_late (void)
3780 #ifdef HAVE_MSG_SELECT
3781 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3782 assert (windows_fd>=0);
3783 FD_SET (windows_fd, &input_wait_mask);
3784 FD_ZERO(&zero_mask);
3787 event_stream = mswindows_event_stream;
3789 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3790 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);