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 #ifdef HAVE_MSG_SELECT
70 #include "console-tty.h"
72 typedef unsigned int SOCKET;
77 #if !(defined(CYGWIN) || defined(MINGW))
78 # include <shlobj.h> /* For IShellLink */
82 #define ADJR_MENUFLAG TRUE
84 #define ADJR_MENUFLAG FALSE
87 /* Fake key modifier which is attached to a quit char event.
88 Removed upon dequeueing an event */
89 #define FAKE_MOD_QUIT (1 << 20)
90 #define FAKE_MOD_QUIT_CRITICAL (1 << 21)
92 /* Timer ID used for button2 emulation */
93 #define BUTTON_2_TIMER_ID 1
95 static Lisp_Object mswindows_find_frame (HWND hwnd);
96 static Lisp_Object mswindows_find_console (HWND hwnd);
97 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
99 static int mswindows_modifier_state (BYTE* keymap, DWORD fwKeys,
101 static void mswindows_set_chord_timer (HWND hwnd);
102 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
103 static int mswindows_current_layout_has_AltGr (void);
104 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
105 int downp, int keyp);
107 static struct event_stream *mswindows_event_stream;
109 #ifdef HAVE_MSG_SELECT
110 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
111 extern SELECT_TYPE process_only_mask, tty_only_mask;
112 SELECT_TYPE zero_mask;
113 extern int signal_event_pipe_initialized;
118 * Two separate queues, for efficiency, one (_u_) for user events, and
119 * another (_s_) for non-user ones. We always return events out of the
120 * first one until it is empty and only then proceed with the second
123 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
124 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
126 /* The number of things we can wait on */
127 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
129 #ifndef HAVE_MSG_SELECT
130 /* List of mswindows waitable handles. */
131 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
133 /* Number of wait handles */
134 static int mswindows_waitable_count=0;
135 #endif /* HAVE_MSG_SELECT */
137 /* Brush for painting widgets */
138 static HBRUSH widget_brush = 0;
139 static LONG last_widget_brushed = 0;
141 /* Count of quit chars currently in the queue */
142 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
143 Decremented in mswindows_dequeue_dispatch_event() */
144 int mswindows_quit_chars_count = 0;
146 /* These are Lisp integers; see DEFVARS in this file for description. */
147 int mswindows_dynamic_frame_resize;
148 int mswindows_alt_by_itself_activates_menu;
149 Fixnum mswindows_num_mouse_buttons;
150 Fixnum mswindows_mouse_button_max_skew_x;
151 Fixnum mswindows_mouse_button_max_skew_y;
152 Fixnum mswindows_mouse_button_tolerance;
155 Fixnum debug_mswindows_events;
158 /* This is the event signaled by the event pump.
159 See mswindows_pump_outstanding_events for comments */
160 static Lisp_Object mswindows_error_caught_in_modal_loop;
161 static int mswindows_in_modal_loop;
163 /* Count of wound timers */
164 static int mswindows_pending_timers_count;
166 static DWORD mswindows_last_mouse_button_state;
168 /************************************************************************/
169 /* Pipe instream - reads process output */
170 /************************************************************************/
172 #define PIPE_READ_DELAY 20
174 #define HANDLE_TO_USID(h) ((USID)(h))
176 #define NTPIPE_SLURP_STREAM_DATA(stream) \
177 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
179 /* This structure is allocated by the main thread, and is deallocated
180 in the thread upon exit. There are situations when a thread
181 remains blocked for a long time, much longer than the lstream
182 exists. For example, "start notepad" command is issued from the
183 shell, then the shell is closed by C-c C-d. Although the shell
184 process exits, its output pipe will not get closed until the
185 notepad process exits also, because it inherits the pipe form the
186 shell. In this case, we abandon the thread, and let it live until
187 all such processes exit. While struct ntpipe_slurp_stream is
188 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
190 struct ntpipe_slurp_stream_shared_data
192 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
193 /* This is a manual-reset object. */
194 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
195 /* This is a manual-reset object. */
196 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
197 /* This is a manual-reset object. */
198 HANDLE hpipe; /* Pipe read end handle. */
199 LONG die_p; /* Thread must exit ASAP if non-zero */
200 BOOL eof_p : 1; /* Set when thread saw EOF */
201 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
202 BOOL inuse_p : 1; /* this structure is in use */
203 LONG lock_count; /* Client count of this struct, 0=safe to free */
204 BYTE onebyte; /* One byte buffer read by thread */
207 #define MAX_SLURP_STREAMS 32
208 struct ntpipe_slurp_stream_shared_data
209 shared_data_block[MAX_SLURP_STREAMS]={{0}};
211 struct ntpipe_slurp_stream
213 LPARAM user_data; /* Any user data stored in the stream object */
214 struct ntpipe_slurp_stream_shared_data* thread_data;
217 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
218 sizeof (struct ntpipe_slurp_stream));
220 /* This function is thread-safe, and is called from either thread
221 context. It serializes freeing shared data structure */
223 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
225 if (InterlockedDecrement (&s->lock_count) == 0)
228 CloseHandle (s->hev_thread);
229 CloseHandle (s->hev_caller);
230 CloseHandle (s->hev_unsleep);
235 static struct ntpipe_slurp_stream_shared_data*
236 slurper_allocate_shared_data (void)
239 for (i=0; i<MAX_SLURP_STREAMS; i++)
241 if (!shared_data_block[i].inuse_p)
243 shared_data_block[i].inuse_p=1;
244 return &shared_data_block[i];
247 return (struct ntpipe_slurp_stream_shared_data*)0;
251 slurp_thread (LPVOID vparam)
253 struct ntpipe_slurp_stream_shared_data *s =
254 (struct ntpipe_slurp_stream_shared_data*)vparam;
258 /* Read one byte from the pipe */
260 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
262 DWORD err = GetLastError ();
263 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
268 else if (actually_read == 0)
271 /* We must terminate on an error or eof */
272 if (s->eof_p || s->error_p)
273 InterlockedIncrement (&s->die_p);
275 /* Before we notify caller, we unsignal our event. */
276 ResetEvent (s->hev_thread);
278 /* Now we got something to notify caller, either a byte or an
279 error/eof indication. Before we do, allow internal pipe
280 buffer to accumulate little bit more data.
281 Reader function pulses this event before waiting for
282 a character, to avoid pipe delay, and to get the byte
285 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
287 /* Either make event loop generate a process event, or
289 SetEvent (s->hev_caller);
291 /* Cleanup and exit if we're shot off */
295 /* Block until the client finishes with retrieving the rest of
297 WaitForSingleObject (s->hev_thread, INFINITE);
300 slurper_free_shared_data_maybe (s);
306 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
309 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
310 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
311 DWORD thread_id_unused;
314 /* We deal only with pipes, for we're using PeekNamedPipe api */
315 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
317 s->thread_data = slurper_allocate_shared_data();
319 /* Create reader thread. This could fail, so do not create events
320 until thread is created */
321 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
322 CREATE_SUSPENDED, &thread_id_unused);
325 Lstream_delete (lstr);
326 s->thread_data->inuse_p=0;
330 /* Shared data are initially owned by both main and slurper
332 s->thread_data->lock_count = 2;
333 s->thread_data->die_p = 0;
334 s->thread_data->eof_p = FALSE;
335 s->thread_data->error_p = FALSE;
336 s->thread_data->hpipe = hpipe;
337 s->user_data = param;
339 /* hev_thread is a manual-reset event, initially signaled */
340 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
341 /* hev_caller is a manual-reset event, initially nonsignaled */
342 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
343 /* hev_unsleep is a manual-reset event, initially nonsignaled */
344 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
347 ResumeThread (hthread);
348 CloseHandle (hthread);
350 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
351 XSETLSTREAM (obj, lstr);
356 get_ntpipe_input_stream_param (Lstream *stream)
358 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
363 get_ntpipe_input_stream_waitable (Lstream *stream)
365 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
366 return s->thread_data->hev_caller;
369 static Lstream_data_count
370 ntpipe_slurp_reader (Lstream *stream, unsigned char *data,
371 Lstream_data_count size)
373 /* This function must be called from the main thread only */
374 struct ntpipe_slurp_stream_shared_data* s =
375 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
380 /* Disallow pipe read delay for the thread: we need a character
382 SetEvent (s->hev_unsleep);
384 /* Check if we have a character ready. Give it a short delay,
385 for the thread to awake from pipe delay, just ion case*/
386 wait_result = WaitForSingleObject (s->hev_caller, 2);
388 /* Revert to the normal sleep behavior. */
389 ResetEvent (s->hev_unsleep);
391 /* If there's no byte buffered yet, give up */
392 if (wait_result == WAIT_TIMEOUT)
399 /* Reset caller unlock event now, as we've handled the pending
400 process output event */
401 ResetEvent (s->hev_caller);
403 /* It is now safe to do anything with contents of S, except for
404 changing s->die_p, which still should be interlocked */
408 if (s->error_p || s->die_p)
411 /* Ok, there were no error neither eof - we've got a byte from the
413 *(data++) = s->onebyte;
417 DWORD bytes_read = 0;
420 DWORD bytes_available;
422 /* If the api call fails, return at least one byte already
423 read. ReadFile in thread will return error */
424 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
427 /* Fetch available bytes. The same consideration applies,
428 so do not check for errors. ReadFile in the thread will
429 fail if the next call fails. */
431 ReadFile (s->hpipe, data, min (bytes_available, size),
435 /* Now we can unblock thread, so it attempts to read more */
436 SetEvent (s->hev_thread);
437 return bytes_read + 1;
444 ntpipe_slurp_closer (Lstream *stream)
446 /* This function must be called from the main thread only */
447 struct ntpipe_slurp_stream_shared_data* s =
448 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
450 /* Force thread to stop */
451 InterlockedIncrement (&s->die_p);
453 /* Set events which could possibly block slurper. Let it finish soon
455 SetEvent (s->hev_unsleep);
456 SetEvent (s->hev_thread);
458 /* Unlock and maybe free shared data */
459 slurper_free_shared_data_maybe (s);
465 init_slurp_stream (void)
467 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
468 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
471 /************************************************************************/
472 /* Pipe outstream - writes process input */
473 /************************************************************************/
475 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
476 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
478 #define MAX_SHOVE_BUFFER_SIZE 512
480 struct ntpipe_shove_stream
482 LPARAM user_data; /* Any user data stored in the stream object */
483 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
484 /* This is an auto-reset object. */
485 HANDLE hpipe; /* Pipe write end handle. */
486 HANDLE hthread; /* Reader thread handle. */
487 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
488 DWORD size; /* Number of bytes to write */
489 LONG die_p; /* Thread must exit ASAP if non-zero */
490 LONG idle_p; /* Non-zero if thread is waiting for job */
491 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
492 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
495 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
496 sizeof (struct ntpipe_shove_stream));
498 #ifndef HAVE_MSG_SELECT
500 shove_thread (LPVOID vparam)
502 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
508 /* Block on event and wait for a job */
509 InterlockedIncrement (&s->idle_p);
510 WaitForSingleObject (s->hev_thread, INFINITE);
512 /* Write passed buffer if any */
515 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
516 || bytes_written != s->size)
519 InterlockedIncrement (&s->die_p);
521 /* Set size to zero so we won't write it again if the closer sets
522 die_p and kicks us */
534 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
537 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
538 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
539 DWORD thread_id_unused;
544 s->user_data = param;
546 /* Create reader thread. This could fail, so do not
547 create the event until thread is created */
548 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
549 CREATE_SUSPENDED, &thread_id_unused);
550 if (s->hthread == NULL)
552 Lstream_delete (lstr);
556 /* Set the priority of the thread higher so we don't end up waiting
557 on it to send things. */
558 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST))
560 CloseHandle (s->hthread);
561 Lstream_delete (lstr);
565 /* hev_thread is an auto-reset event, initially nonsignaled */
566 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
569 ResumeThread (s->hthread);
571 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
572 XSETLSTREAM (obj, lstr);
577 get_ntpipe_output_stream_param (Lstream *stream)
579 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
584 static Lstream_data_count
585 ntpipe_shove_writer (Lstream *stream, const unsigned char *data,
586 Lstream_data_count size)
588 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
593 s->blocking_p = !s->idle_p;
597 if (size>MAX_SHOVE_BUFFER_SIZE)
600 memcpy (s->buffer, data, size);
604 InterlockedDecrement (&s->idle_p);
605 SetEvent (s->hev_thread);
606 /* Give it a chance to run -- this dramatically improves performance
607 of things like crypt. */
608 if (xSwitchToThread) /* not in Win9x or NT 3.51 */
609 (void) xSwitchToThread ();
614 ntpipe_shove_was_blocked_p (Lstream *stream)
616 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
617 return s->blocking_p;
621 ntpipe_shove_closer (Lstream *stream)
623 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
625 /* Force thread stop */
626 InterlockedIncrement (&s->die_p);
628 /* Thread will end upon unblocking. If it's already unblocked this will
629 do nothing, but the thread won't look at die_p until it's written any
631 SetEvent (s->hev_thread);
633 /* Wait while thread terminates */
634 WaitForSingleObject (s->hthread, INFINITE);
636 /* Close pipe handle, possibly breaking it */
637 CloseHandle (s->hpipe);
639 /* Close the thread handle */
640 CloseHandle (s->hthread);
642 /* Destroy the event */
643 CloseHandle (s->hev_thread);
649 init_shove_stream (void)
651 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
652 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
653 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
656 /************************************************************************/
657 /* Winsock I/O stream */
658 /************************************************************************/
659 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
661 #define WINSOCK_READ_BUFFER_SIZE 1024
663 struct winsock_stream
665 LPARAM user_data; /* Any user data stored in the stream object */
666 SOCKET s; /* Socket handle (which is a Win32 handle) */
667 OVERLAPPED ov; /* Overlapped I/O structure */
668 void* buffer; /* Buffer. Allocated for input stream only */
669 unsigned long bufsize; /* Number of bytes last read */
670 unsigned long bufpos; /* Position in buffer for next fetch */
671 unsigned int error_p :1; /* I/O Error seen */
672 unsigned int eof_p :1; /* EOF Error seen */
673 unsigned int pending_p :1; /* There is a pending I/O operation */
674 unsigned int blocking_p :1; /* Last write attempt would block */
677 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
679 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
680 sizeof (struct winsock_stream));
683 winsock_initiate_read (struct winsock_stream *str)
685 ResetEvent (str->ov.hEvent);
688 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
689 &str->bufsize, &str->ov))
691 if (GetLastError () == ERROR_IO_PENDING)
693 else if (GetLastError () == ERROR_HANDLE_EOF)
698 else if (str->bufsize == 0)
702 static Lstream_data_count
703 winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
705 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
707 /* If the current operation is not yet complete, there's nothing to
711 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
718 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
720 if (GetLastError() == ERROR_HANDLE_EOF)
725 if (str->bufsize == 0)
736 /* Return as much of buffer as we have */
737 size = min (size, (Lstream_data_count) (str->bufsize - str->bufpos));
738 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
741 /* Read more if buffer is exhausted */
742 if (str->bufsize == str->bufpos)
743 winsock_initiate_read (str);
748 static Lstream_data_count
749 winsock_writer (Lstream *stream, const unsigned char *data,
750 Lstream_data_count size)
752 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
756 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
764 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
779 ResetEvent (str->ov.hEvent);
781 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is
782 * an overlapped operation. This fails on Win95 with winsock 1.x so we
783 * supply a spare address which is ignored by Win95 anyway. Sheesh. */
784 if (WriteFile ((HANDLE)str->s, data, size, (LPDWORD)&str->buffer, &str->ov)
785 || GetLastError() == ERROR_IO_PENDING)
791 return str->error_p ? -1 : size;
795 winsock_closer (Lstream *lstr)
797 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
799 if (lstr->flags & LSTREAM_FL_READ)
800 shutdown (str->s, 0);
802 shutdown (str->s, 1);
804 CloseHandle ((HANDLE)str->s);
806 WaitForSingleObject (str->ov.hEvent, INFINITE);
808 if (lstr->flags & LSTREAM_FL_READ)
811 CloseHandle (str->ov.hEvent);
816 winsock_was_blocked_p (Lstream *stream)
818 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
819 return str->blocking_p;
823 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
826 Lstream *lstr = Lstream_new (lstream_winsock, mode);
827 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
834 str->user_data = param;
837 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
839 if (lstr->flags & LSTREAM_FL_READ)
841 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
842 winsock_initiate_read (str);
845 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
846 XSETLSTREAM (obj, lstr);
851 make_winsock_input_stream (SOCKET s, LPARAM param)
853 return make_winsock_stream_1 (s, param, "r");
857 make_winsock_output_stream (SOCKET s, LPARAM param)
859 return make_winsock_stream_1 (s, param, "w");
863 get_winsock_stream_waitable (Lstream *lstr)
865 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
866 return str->ov.hEvent;
870 get_winsock_stream_param (Lstream *lstr)
872 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
873 return str->user_data;
877 init_winsock_stream (void)
879 LSTREAM_HAS_METHOD (winsock, reader);
880 LSTREAM_HAS_METHOD (winsock, writer);
881 LSTREAM_HAS_METHOD (winsock, closer);
882 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
884 #endif /* defined (HAVE_SOCKETS) */
886 /************************************************************************/
887 /* Dispatch queue management */
888 /************************************************************************/
891 mswindows_user_event_p (Lisp_Event* sevt)
893 return (sevt->event_type == key_press_event
894 || sevt->event_type == button_press_event
895 || sevt->event_type == button_release_event
896 || sevt->event_type == misc_user_event);
900 * Add an emacs event to the proper dispatch queue
903 mswindows_enqueue_dispatch_event (Lisp_Object event)
905 int user_p = mswindows_user_event_p (XEVENT(event));
906 enqueue_event (event,
907 user_p ? &mswindows_u_dispatch_event_queue :
908 &mswindows_s_dispatch_event_queue,
909 user_p ? &mswindows_u_dispatch_event_queue_tail :
910 &mswindows_s_dispatch_event_queue_tail);
912 /* Avoid blocking on WaitMessage */
913 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
917 * Add a misc-user event to the dispatch queue.
919 * Stuff it into our own dispatch queue, so we have something
920 * to return from next_event callback.
923 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
926 Lisp_Object event = Fmake_event (Qnil, Qnil);
927 Lisp_Event* e = XEVENT (event);
929 e->event_type = misc_user_event;
930 e->channel = channel;
931 e->timestamp = GetTickCount ();
932 e->event.misc.function = function;
933 e->event.misc.object = object;
935 mswindows_enqueue_dispatch_event (event);
939 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
941 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
942 Lisp_Event* event = XEVENT (emacs_event);
944 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
945 event->timestamp = GetMessageTime();
946 event->event_type = magic_event;
947 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
949 mswindows_enqueue_dispatch_event (emacs_event);
953 mswindows_enqueue_process_event (Lisp_Process* p)
955 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
956 Lisp_Event* event = XEVENT (emacs_event);
958 XSETPROCESS (process, p);
960 event->event_type = process_event;
961 event->timestamp = GetTickCount ();
962 event->event.process.process = process;
964 mswindows_enqueue_dispatch_event (emacs_event);
968 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
969 int mods, DWORD when)
971 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
972 msg == WM_RBUTTONDOWN);
974 /* We always use last message time, because mouse button
975 events may get delayed, and XEmacs double click
976 recognition will fail */
978 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
979 Lisp_Event* event = XEVENT (emacs_event);
981 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
982 event->channel = mswindows_find_frame (hwnd);
983 event->timestamp = when;
984 event->event.button.button =
985 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
986 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
987 event->event.button.x = where.x;
988 event->event.button.y = where.y;
989 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
993 event->event_type = button_press_event;
995 /* we need this to make sure the main window regains the focus
996 from control subwindows */
997 if (GetFocus() != hwnd)
1000 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1005 event->event_type = button_release_event;
1009 mswindows_enqueue_dispatch_event (emacs_event);
1013 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1015 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1016 Lisp_Event* event = XEVENT(emacs_event);
1018 event->channel = mswindows_find_console(hwnd);
1019 event->timestamp = GetMessageTime();
1020 event->event_type = key_press_event;
1021 event->event.key.keysym = keysym;
1022 event->event.key.modifiers = mods;
1023 mswindows_enqueue_dispatch_event (emacs_event);
1027 * Remove and return the first emacs event on the dispatch queue.
1028 * Give a preference to user events over non-user ones.
1031 mswindows_dequeue_dispatch_event (void)
1036 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1037 !NILP(mswindows_s_dispatch_event_queue));
1039 event = dequeue_event (
1040 NILP(mswindows_u_dispatch_event_queue) ?
1041 &mswindows_s_dispatch_event_queue :
1042 &mswindows_u_dispatch_event_queue,
1043 NILP(mswindows_u_dispatch_event_queue) ?
1044 &mswindows_s_dispatch_event_queue_tail :
1045 &mswindows_u_dispatch_event_queue_tail);
1047 sevt = XEVENT(event);
1048 if (sevt->event_type == key_press_event
1049 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1051 sevt->event.key.modifiers &=
1052 ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
1053 --mswindows_quit_chars_count;
1060 * Remove and return the first emacs event on the dispatch queue that matches
1061 * the supplied event.
1062 * Timeout event matches if interval_id is equal to that of the given event.
1063 * Keypress event matches if logical AND between modifiers bitmask of the
1064 * event in the queue and that of the given event is non-zero.
1065 * For all other event types, this function aborts.
1069 mswindows_cancel_dispatch_event (Lisp_Event *match)
1072 Lisp_Object previous_event = Qnil;
1073 int user_p = mswindows_user_event_p (match);
1074 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1075 &mswindows_s_dispatch_event_queue;
1076 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1077 &mswindows_s_dispatch_event_queue_tail;
1079 assert (match->event_type == timeout_event
1080 || match->event_type == key_press_event);
1082 EVENT_CHAIN_LOOP (event, *head)
1084 Lisp_Event *e = XEVENT (event);
1085 if ((e->event_type == match->event_type) &&
1086 ((e->event_type == timeout_event) ?
1087 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1088 /* Must be key_press_event */
1089 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1091 if (NILP (previous_event))
1092 dequeue_event (head, tail);
1095 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1096 if (EQ (*tail, event))
1097 *tail = previous_event;
1102 previous_event = event;
1107 #ifndef HAVE_MSG_SELECT
1108 /************************************************************************/
1109 /* Waitable handles manipulation */
1110 /************************************************************************/
1112 find_waitable_handle (HANDLE h)
1115 for (i = 0; i < mswindows_waitable_count; ++i)
1116 if (mswindows_waitable_handles[i] == h)
1123 add_waitable_handle (HANDLE h)
1125 assert (find_waitable_handle (h) < 0);
1126 if (mswindows_waitable_count == MAX_WAITABLE)
1129 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1134 remove_waitable_handle (HANDLE h)
1136 int ix = find_waitable_handle (h);
1140 mswindows_waitable_handles [ix] =
1141 mswindows_waitable_handles [--mswindows_waitable_count];
1143 #endif /* HAVE_MSG_SELECT */
1146 /************************************************************************/
1148 /************************************************************************/
1151 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1152 Lisp_Object u_n_u_s_e_d)
1154 mswindows_error_caught_in_modal_loop = cons_sig_data;
1159 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1164 ++mswindows_in_modal_loop;
1165 tmp = condition_case_1 (Qt,
1167 mswindows_modal_loop_error_handler, Qnil);
1168 --mswindows_in_modal_loop;
1174 mswindows_unmodalize_signal_maybe (void)
1176 if (!NILP (mswindows_error_caught_in_modal_loop))
1178 /* Got an error while messages were pumped while
1179 in window procedure - have to resignal */
1180 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1181 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1182 mswindows_error_caught_in_modal_loop = Qnil;
1183 Fsignal (sym, data);
1188 * This is an unsafe part of event pump, guarded by
1189 * condition_case. See mswindows_pump_outstanding_events
1192 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1194 /* This function can call lisp */
1195 Lisp_Object event = Fmake_event (Qnil, Qnil);
1196 struct gcpro gcpro1;
1197 int do_redisplay = 0;
1200 while (detect_input_pending ())
1202 Fnext_event (event, Qnil);
1203 Fdispatch_event (event);
1210 Fdeallocate_event (event);
1213 /* Qt becomes return value of mswindows_pump_outstanding_events
1219 * This function pumps emacs events, while available, by using
1220 * next_message/dispatch_message loop. Errors are trapped around
1221 * the loop so the function always returns.
1223 * Windows message queue is not looked into during the call,
1224 * neither are waitable handles checked. The function pumps
1225 * thus only dispatch events already queued, as well as those
1226 * resulted in dispatching thereof. This is done by setting
1227 * module local variable mswindows_in_modal_loop to nonzero.
1229 * Return value is Qt if no errors was trapped, or Qunbound if
1230 * there was an error.
1232 * In case of error, a cons representing the error, in the
1233 * form (SIGNAL . DATA), is stored in the module local variable
1234 * mswindows_error_caught_in_modal_loop. This error is signaled
1235 * again when DispatchMessage returns. Thus, Windows internal
1236 * modal loops are protected against throws, which are proven
1237 * to corrupt internal Windows structures.
1239 * In case of success, mswindows_error_caught_in_modal_loop is
1242 * If the value of mswindows_error_caught_in_modal_loop is not
1243 * nil already upon entry, the function just returns non-nil.
1244 * This situation means that a new event has been queued while
1245 * in cancel mode. The event will be dequeued on the next regular
1246 * call of next-event; the pump is off since error is caught.
1247 * The caller must *unconditionally* cancel modal loop if the
1248 * value returned by this function is nil. Otherwise, everything
1249 * will become frozen until the modal loop exits under normal
1250 * condition (scrollbar drag is released, menu closed etc.)
1253 mswindows_pump_outstanding_events (void)
1255 /* This function can call lisp */
1257 Lisp_Object result = Qt;
1258 struct gcpro gcpro1;
1261 if (NILP(mswindows_error_caught_in_modal_loop))
1262 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1268 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1269 * QUITP, and are interesting in keyboard messages only.
1272 mswindows_drain_windows_queue (void)
1276 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1277 assert (!mswindows_in_modal_loop);
1279 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1281 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1283 /* Don't translate messages destined for a dialog box, this
1284 makes keyboard traversal work. I think?? */
1285 if (mswindows_is_dialog_msg (&msg))
1287 mswindows_unmodalize_signal_maybe ();
1291 /* We have to translate messages that are not sent to an XEmacs
1292 frame. This is so that key presses work ok in things like
1293 edit fields. However, we *musn't* translate message for XEmacs
1294 frames as this is handled in the wnd proc.
1295 We also have to avoid generating paint magic events for windows
1296 that aren't XEmacs frames */
1297 /* GetClassName will truncate a longer class name. By adding one
1298 extra character, we are forcing textual comparison to fail
1299 if the name is longer than XEMACS_CLASS */
1301 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1302 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1304 /* Not an XEmacs frame */
1305 TranslateMessage (&msg);
1307 else if (msg.message == WM_PAINT)
1309 struct mswindows_frame* msframe;
1311 /* hdc will be NULL unless this is a subwindow - in which case we
1312 shouldn't have received a paint message for it here. */
1313 assert (msg.wParam == 0);
1315 /* Queue a magic event for handling when safe */
1317 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1318 if (!msframe->paint_pending)
1320 msframe->paint_pending = 1;
1321 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1323 /* Don't dispatch. WM_PAINT is always the last message in the
1324 queue so it's OK to just return. */
1327 DispatchMessage (&msg);
1328 mswindows_unmodalize_signal_maybe ();
1333 * This is a special flavor of the mswindows_need_event function,
1334 * used while in event pump. Actually, there is only kind of events
1335 * allowed while in event pump: a timer. An attempt to fetch any
1336 * other event leads to a deadlock, as there's no source of user input
1337 * ('cause event pump mirrors windows modal loop, which is a sole
1338 * owner of thread message queue).
1340 * To detect this, we use a counter of active timers, and allow
1341 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1342 * which will never come when there are no pending timers, which leads
1343 * to deadlock, we simply signal an error.
1345 * It might be possible to combine this with mswindows_drain_windows_queue
1346 * which fetches events when not in a modal loop. It's not clear
1347 * whether the result would be more complex than is justified.
1350 mswindows_need_event_in_modal_loop (int badly_p)
1354 /* Check if already have one */
1355 if (!NILP (mswindows_u_dispatch_event_queue)
1356 || !NILP (mswindows_s_dispatch_event_queue))
1359 /* No event is ok */
1363 /* We do not check the _u_ queue, because timers go to _s_ */
1364 while (NILP (mswindows_s_dispatch_event_queue))
1366 /* We'll deadlock if go waiting */
1367 if (mswindows_pending_timers_count == 0)
1368 error ("Deadlock due to an attempt to call next-event in a wrong context");
1370 /* Fetch and dispatch any pending timers */
1371 if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1372 DispatchMessage (&msg);
1377 * This drains the event queue and fills up two internal queues until
1378 * an event of a type specified by USER_P is retrieved.
1381 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1384 mswindows_need_event (int badly_p)
1388 while (NILP (mswindows_u_dispatch_event_queue)
1389 && NILP (mswindows_s_dispatch_event_queue))
1391 #ifdef HAVE_MSG_SELECT
1393 SELECT_TYPE temp_mask = input_wait_mask;
1394 EMACS_TIME sometime;
1395 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1398 pointer_to_this = 0;
1401 EMACS_SET_SECS_USECS (sometime, 0, 0);
1402 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1403 pointer_to_this = &select_time_to_block;
1404 if (mswindows_in_modal_loop)
1405 /* In modal loop with badly_p false, don't care about
1407 FD_CLR (windows_fd, &temp_mask);
1410 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1415 return; /* timeout */
1417 else if (active > 0)
1419 if (FD_ISSET (windows_fd, &temp_mask))
1421 if (mswindows_in_modal_loop)
1422 mswindows_need_event_in_modal_loop (badly_p);
1424 mswindows_drain_windows_queue ();
1429 /* Look for a TTY event */
1430 for (i = 0; i < MAXDESC-1; i++)
1432 /* To avoid race conditions (among other things, an infinite
1433 loop when called from Fdiscard_input()), we must return
1434 user events ahead of process events. */
1435 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1437 struct console *c = tty_find_console_from_fd (i);
1438 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1439 Lisp_Event* event = XEVENT (emacs_event);
1442 if (read_event_from_tty_or_stream_desc (event, c, i))
1444 mswindows_enqueue_dispatch_event (emacs_event);
1450 /* Look for a process event */
1451 for (i = 0; i < MAXDESC-1; i++)
1453 if (FD_ISSET (i, &temp_mask))
1455 if (FD_ISSET (i, &process_only_mask))
1458 get_process_from_usid (FD_TO_USID(i));
1460 mswindows_enqueue_process_event (p);
1464 /* We might get here when a fake event came
1465 through a signal. Return a dummy event, so
1466 that a cycle of the command loop will
1468 drain_signal_event_pipe ();
1469 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1475 else if (active==-1)
1479 /* something bad happened */
1488 /* Now try getting a message or process event */
1490 if (mswindows_in_modal_loop)
1491 /* In a modal loop, only look for timer events, and only if
1492 we really need one. */
1495 what_events = QS_TIMER;
1500 /* Look for any event */
1501 what_events = QS_ALLINPUT;
1503 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1504 mswindows_waitable_handles,
1505 FALSE, badly_p ? INFINITE : 0,
1508 /* This will assert if handle being waited for becomes abandoned.
1509 Not the case currently tho */
1510 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1511 (active >= WAIT_OBJECT_0 &&
1512 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1514 if (active == WAIT_TIMEOUT)
1516 /* No luck trying - just return what we've already got */
1519 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1521 /* Got your message, thanks */
1522 if (mswindows_in_modal_loop)
1523 mswindows_need_event_in_modal_loop (badly_p);
1525 mswindows_drain_windows_queue ();
1529 int ix = active - WAIT_OBJECT_0;
1530 /* First, try to find which process' output has signaled */
1532 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1535 /* Found a signaled process input handle */
1536 mswindows_enqueue_process_event (p);
1540 /* None. This means that the process handle itself has signaled.
1541 Remove the handle from the wait vector, and make status_notify
1542 note the exited process. First find the process object if
1544 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
1545 if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
1546 mswindows_waitable_handles [ix])
1548 mswindows_waitable_handles [ix] =
1549 mswindows_waitable_handles [--mswindows_waitable_count];
1550 kick_status_notify ();
1551 /* We need to return a process event here so that
1552 (1) accept-process-output will return when called on this
1553 process, and (2) status notifications will happen in
1554 accept-process-output, sleep-for, and sit-for. */
1555 /* #### horrible kludge till my real process fixes go in.
1556 #### Replaced with a slightly less horrible kluge that
1557 at least finds the right process instead of axing the
1558 first one on the list.
1560 if (!NILP (vproctail))
1562 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1564 else /* trash me soon. */
1565 /* Have to return something: there may be no accompanying
1567 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1574 /************************************************************************/
1575 /* Event generators */
1576 /************************************************************************/
1579 * Callback procedure for synchronous timer messages
1581 static void CALLBACK
1582 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1584 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1585 Lisp_Event *event = XEVENT (emacs_event);
1587 if (KillTimer (NULL, id_timer))
1588 --mswindows_pending_timers_count;
1590 event->channel = Qnil;
1591 event->timestamp = dwtime;
1592 event->event_type = timeout_event;
1593 event->event.timeout.interval_id = id_timer;
1594 event->event.timeout.function = Qnil;
1595 event->event.timeout.object = Qnil;
1597 mswindows_enqueue_dispatch_event (emacs_event);
1601 * Callback procedure for dde messages
1603 * We execute a dde Open("file") by simulating a file drop, so dde support
1604 * depends on dnd support.
1606 #ifdef HAVE_DRAGNDROP
1608 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1609 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1610 DWORD dwData1, DWORD dwData2)
1615 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1616 return (HDDEDATA)TRUE;
1617 return (HDDEDATA)FALSE;
1619 case XTYP_WILDCONNECT:
1621 /* We only support one {service,topic} pair */
1622 HSZPAIR pairs[2] = {
1623 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1625 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1626 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1627 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1628 sizeof (pairs), 0L, 0, uFmt, 0));
1630 return (HDDEDATA)NULL;
1633 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1635 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1636 LPBYTE cmd = (LPBYTE) alloca (len+1);
1639 struct gcpro gcpro1, gcpro2;
1640 Lisp_Object l_dndlist = Qnil;
1641 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1642 Lisp_Object frmcons, devcons, concons;
1643 Lisp_Event *event = XEVENT (emacs_event);
1645 DdeGetData (hdata, cmd, len, 0);
1647 DdeFreeDataHandle (hdata);
1649 /* Check syntax & that it's an [Open("foo")] command, which we
1650 * treat like a file drop */
1651 /* #### Ought to be generalised and accept some other commands */
1654 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1655 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1656 return DDE_FNOTPROCESSED;
1657 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1660 if (*cmd!='(' || *(cmd+1)!='\"')
1661 return DDE_FNOTPROCESSED;
1663 while (*end && *end!='\"')
1666 return DDE_FNOTPROCESSED;
1669 return DDE_FNOTPROCESSED;
1673 return DDE_FNOTPROCESSED;
1676 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1677 strcpy (filename, "file:");
1678 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1680 dostounix_filename (cmd);
1681 filename = alloca (strlen (cmd)+6);
1682 strcpy (filename, "file:");
1683 strcat (filename, cmd);
1685 GCPRO2 (emacs_event, l_dndlist);
1686 l_dndlist = make_string (filename, strlen (filename));
1688 /* Find a mswindows frame */
1689 event->channel = Qnil;
1690 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1692 Lisp_Object frame = XCAR (frmcons);
1693 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1694 event->channel = frame;
1696 assert (!NILP (event->channel));
1698 event->timestamp = GetTickCount();
1699 event->event_type = misc_user_event;
1700 event->event.misc.button = 1;
1701 event->event.misc.modifiers = 0;
1702 event->event.misc.x = -1;
1703 event->event.misc.y = -1;
1704 event->event.misc.function = Qdragdrop_drop_dispatch;
1705 event->event.misc.object = Fcons (Qdragdrop_URL,
1706 Fcons (l_dndlist, Qnil));
1707 mswindows_enqueue_dispatch_event (emacs_event);
1709 return (HDDEDATA) DDE_FACK;
1711 DdeFreeDataHandle (hdata);
1712 return (HDDEDATA) DDE_FNOTPROCESSED;
1715 return (HDDEDATA) NULL;
1721 * Helper to do repainting - repaints can happen both from the windows
1722 * procedure and from magic events
1725 mswindows_handle_paint (struct frame *frame)
1727 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1729 /* According to the docs we need to check GetUpdateRect() before
1730 actually doing a WM_PAINT */
1731 if (GetUpdateRect (hwnd, NULL, FALSE))
1733 PAINTSTRUCT paintStruct;
1734 int x, y, width, height;
1736 BeginPaint (hwnd, &paintStruct);
1737 x = paintStruct.rcPaint.left;
1738 y = paintStruct.rcPaint.top;
1739 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1740 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1741 /* Normally we want to ignore expose events when child
1742 windows are unmapped, however once we are in the guts of
1743 WM_PAINT we need to make sure that we don't register
1744 unmaps then because they will not actually occur. */
1745 /* #### commenting out the next line seems to fix some problems
1746 but not all. only andy currently understands this stuff and
1747 he needs to review it more carefully. --ben */
1748 if (!check_for_ignored_expose (frame, x, y, width, height))
1750 hold_ignored_expose_registration = 1;
1751 mswindows_redraw_exposed_area (frame, x, y, width, height);
1752 hold_ignored_expose_registration = 0;
1754 EndPaint (hwnd, &paintStruct);
1759 * Returns 1 if a key is a real modifier or special key, which
1760 * is better handled by DefWindowProc
1763 key_needs_default_processing_p (UINT vkey)
1765 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1766 /* if we let ALT activate the menu like this, then sticky ALT-modified
1767 keystrokes become impossible. */
1768 && !modifier_keys_are_sticky)
1774 /* key-handling code is always ugly. It just ends up working out
1777 #### Most of the sticky-modifier code below is copied from similar
1778 code in event-Xt.c. They should somehow or other be merged.
1780 Here are some pointers:
1782 -- DOWN_MASK indicates which modifiers should be treated as "down"
1783 when the corresponding upstroke happens. It gets reset for
1784 a particular modifier when that modifier goes up, and reset
1785 for all modifiers when a non-modifier key is pressed. Example:
1787 I press Control-A-Shift and then release Control-A-Shift.
1788 I want the Shift key to be sticky but not the Control key.
1790 -- If a modifier key is sticky, I can unstick it by pressing
1791 the modifier key again. */
1793 static WPARAM last_downkey;
1794 static int need_to_add_mask, down_mask;
1796 #define XEMSW_LCONTROL (1<<0)
1797 #define XEMSW_RCONTROL (1<<1)
1798 #define XEMSW_LSHIFT (1<<2)
1799 #define XEMSW_RSHIFT (1<<3)
1800 #define XEMSW_LMENU (1<<4)
1801 #define XEMSW_RMENU (1<<5)
1804 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1805 int downp, int keyp)
1809 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1813 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1814 wParam == VK_RCONTROL ||
1815 wParam == VK_MENU || wParam == VK_LMENU ||
1816 wParam == VK_RMENU ||
1817 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1818 wParam == VK_RSHIFT)))
1819 { /* Not a modifier key */
1820 if (downp && keyp && !last_downkey)
1821 last_downkey = wParam;
1822 /* If I hold press-and-release the Control key and then press
1823 and hold down the right arrow, I want it to auto-repeat
1824 Control-Right. On the other hand, if I do the same but
1825 manually press the Right arrow a bunch of times, I want
1826 to see one Control-Right and then a bunch of Rights.
1827 This means that we need to distinguish between an
1828 auto-repeated key and a key pressed and released a bunch
1830 else if ((downp && !keyp) ||
1831 (downp && keyp && last_downkey &&
1832 (wParam != last_downkey ||
1833 /* the "previous key state" bit indicates autorepeat */
1834 ! (lParam & (1 << 30)))))
1836 need_to_add_mask = 0;
1842 mods = need_to_add_mask;
1844 else /* Modifier key pressed */
1846 /* If a non-modifier key was pressed in the middle of a bunch
1847 of modifiers, then it unsticks all the modifiers that were
1848 previously pressed. We cannot unstick the modifiers until
1849 now because we want to check for auto-repeat of the
1850 non-modifier key. */
1855 need_to_add_mask = 0;
1858 #define FROB(mask) \
1860 if (downp && keyp) \
1862 /* If modifier key is already sticky, \
1863 then unstick it. Note that we do \
1864 not test down_mask to deal with the \
1865 unlikely but possible case that the \
1866 modifier key auto-repeats. */ \
1867 if (need_to_add_mask & mask) \
1869 need_to_add_mask &= ~mask; \
1870 down_mask &= ~mask; \
1873 down_mask |= mask; \
1877 if (down_mask & mask) \
1879 down_mask &= ~mask; \
1880 need_to_add_mask |= mask; \
1885 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1886 || wParam == VK_RCONTROL)
1887 FROB (XEMSW_RCONTROL);
1888 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1889 || wParam == VK_LCONTROL)
1890 FROB (XEMSW_LCONTROL);
1892 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1893 || wParam == VK_RSHIFT)
1894 FROB (XEMSW_RSHIFT);
1895 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1896 || wParam == VK_LSHIFT)
1897 FROB (XEMSW_LSHIFT);
1899 if ((wParam == VK_MENU && (lParam & 0x1000000))
1900 || wParam == VK_RMENU)
1902 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1903 || wParam == VK_LMENU)
1912 GetKeyboardState (keymap);
1914 if (mods & XEMSW_LCONTROL)
1916 keymap [VK_CONTROL] |= 0x80;
1917 keymap [VK_LCONTROL] |= 0x80;
1919 if (mods & XEMSW_RCONTROL)
1921 keymap [VK_CONTROL] |= 0x80;
1922 keymap [VK_RCONTROL] |= 0x80;
1925 if (mods & XEMSW_LSHIFT)
1927 keymap [VK_SHIFT] |= 0x80;
1928 keymap [VK_LSHIFT] |= 0x80;
1930 if (mods & XEMSW_RSHIFT)
1932 keymap [VK_SHIFT] |= 0x80;
1933 keymap [VK_RSHIFT] |= 0x80;
1936 if (mods & XEMSW_LMENU)
1938 keymap [VK_MENU] |= 0x80;
1939 keymap [VK_LMENU] |= 0x80;
1941 if (mods & XEMSW_RMENU)
1943 keymap [VK_MENU] |= 0x80;
1944 keymap [VK_RMENU] |= 0x80;
1947 SetKeyboardState (keymap);
1955 clear_sticky_modifiers (void)
1957 need_to_add_mask = 0;
1967 output_modifier_keyboard_state (void)
1971 GetKeyboardState (keymap);
1973 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1974 keymap[VK_MENU] & 0x80 ? 1 : 0,
1975 keymap[VK_MENU] & 0x1 ? 1 : 0,
1976 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1977 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1978 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1979 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1980 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1981 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1982 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1983 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1984 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1985 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1986 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1987 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1988 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1989 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1990 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1991 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1992 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1993 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
1998 /* try to debug the stuck-alt-key problem.
2000 #### this happens only inconsistently, and may only happen when using
2001 StickyKeys in the Win2000 accessibility section of the control panel,
2002 which is extremely broken for other reasons. */
2005 output_alt_keyboard_state (void)
2009 // SHORT asyncstate[3];
2011 GetKeyboardState (keymap);
2012 keystate[0] = GetKeyState (VK_MENU);
2013 keystate[1] = GetKeyState (VK_LMENU);
2014 keystate[2] = GetKeyState (VK_RMENU);
2015 /* Doing this interferes with key processing. */
2016 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2017 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2018 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2020 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2021 keymap[VK_MENU] & 0x80 ? 1 : 0,
2022 keymap[VK_MENU] & 0x1 ? 1 : 0,
2023 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2024 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2025 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2026 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2027 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2028 keystate[0] & 0x8000 ? 1 : 0,
2029 keystate[0] & 0x1 ? 1 : 0,
2030 keystate[1] & 0x8000 ? 1 : 0,
2031 keystate[1] & 0x1 ? 1 : 0,
2032 keystate[2] & 0x8000 ? 1 : 0,
2033 keystate[2] & 0x1 ? 1 : 0);
2034 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2035 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2036 /* asyncstate[0] & 0x1 ? 1 : 0, */
2037 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2038 /* asyncstate[1] & 0x1 ? 1 : 0, */
2039 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2040 /* asyncstate[2] & 0x1 ? 1 : 0); */
2043 #endif /* DEBUG_XEMACS */
2047 * The windows procedure for the window class XEMACS_CLASS
2050 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2052 /* Note: Remember to initialize emacs_event and event before use.
2053 This code calls code that can GC. You must GCPRO before calling such code. */
2054 Lisp_Object emacs_event = Qnil;
2055 Lisp_Object fobj = Qnil;
2058 struct frame *frame;
2059 struct mswindows_frame* msframe;
2061 /* Not perfect but avoids crashes. There is potential for wierd
2066 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2069 case WM_DESTROYCLIPBOARD:
2070 /* We own the clipboard and someone else wants it. Delete our
2071 cached copy of the clipboard contents so we'll ask for it from
2072 Windows again when someone does a paste, and destroy any memory
2073 objects we hold on the clipboard that are not in the list of types
2074 that Windows will delete itself. */
2075 mswindows_destroy_selection (QCLIPBOARD);
2076 handle_selection_clear (QCLIPBOARD);
2080 /* Erase background only during non-dynamic sizing */
2081 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2082 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2087 fobj = mswindows_find_frame (hwnd);
2088 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2094 /* See Win95 comment under WM_KEYDOWN */
2097 int should_set_keymap = 0;
2100 if (debug_mswindows_events)
2102 stderr_out ("%s wparam=%d lparam=%d\n",
2103 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
2104 wParam, (int)lParam);
2105 output_alt_keyboard_state ();
2107 #endif /* DEBUG_XEMACS */
2109 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2110 if (wParam == VK_CONTROL)
2112 GetKeyboardState (keymap);
2113 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2114 should_set_keymap = 1;
2116 else if (wParam == VK_MENU)
2118 GetKeyboardState (keymap);
2119 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2120 should_set_keymap = 1;
2123 if (should_set_keymap)
2124 // && (message_ != WM_SYSKEYUP
2125 // || NILP (Vmenu_accelerator_enabled)))
2126 SetKeyboardState (keymap);
2130 if (key_needs_default_processing_p (wParam))
2138 /* In some locales the right-hand Alt key is labelled AltGr. This key
2139 * should produce alternative characters when combined with another key.
2140 * eg on a German keyboard pressing AltGr+q should produce '@'.
2141 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2142 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2143 * it translates as if AltGr were down.
2144 * We get round this by removing all modifiers from the keymap before
2145 * calling TranslateMessage() unless AltGr is *really* down. */
2147 BYTE keymap_trans[256];
2148 BYTE keymap_orig[256];
2149 BYTE keymap_sticky[256];
2150 int has_AltGr = mswindows_current_layout_has_AltGr ();
2151 int mods = 0, mods_with_shift = 0;
2152 int extendedp = lParam & 0x1000000;
2157 if (debug_mswindows_events)
2159 stderr_out ("%s wparam=%d lparam=%d\n",
2160 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
2161 wParam, (int)lParam);
2162 output_alt_keyboard_state ();
2164 #endif /* DEBUG_XEMACS */
2166 GetKeyboardState (keymap_orig);
2167 frame = XFRAME (mswindows_find_frame (hwnd));
2168 if ((sticky_changed =
2169 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2171 GetKeyboardState (keymap_sticky);
2172 if (keymap_sticky[VK_MENU] & 0x80)
2174 message_ = WM_SYSKEYDOWN;
2175 /* We have to set the "context bit" so that the
2176 TranslateMessage() call below that generates the
2177 SYSCHAR message does its thing; see the documentation
2183 memcpy (keymap_sticky, keymap_orig, 256);
2185 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2186 mods_with_shift = mods;
2188 /* Handle non-printables */
2189 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2192 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2194 SetKeyboardState (keymap_orig);
2196 else /* Normal keys & modifiers */
2199 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2200 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2202 int potential_accelerator = 0;
2203 int got_accelerator = 0;
2206 msg.message = message_;
2207 msg.wParam = wParam;
2208 msg.lParam = lParam;
2209 msg.time = GetMessageTime();
2212 /* GetKeyboardState() does not work as documented on Win95. We have
2213 * to loosely track Left and Right modifiers on behalf of the OS,
2214 * without screwing up Windows NT which tracks them properly. */
2215 if (wParam == VK_CONTROL)
2217 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2218 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2220 else if (wParam == VK_MENU)
2222 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2223 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2226 if (!NILP (Vmenu_accelerator_enabled) &&
2227 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2228 potential_accelerator = 1;
2230 /* Remove shift modifier from an ascii character */
2231 mods &= ~XEMACS_MOD_SHIFT;
2233 memcpy (keymap_trans, keymap_sticky, 256);
2235 /* Clear control and alt modifiers unless AltGr is pressed */
2236 keymap_trans[VK_RCONTROL] = 0;
2237 keymap_trans[VK_LMENU] = 0;
2238 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2239 || !(keymap_trans[VK_RMENU] & 0x80))
2241 keymap_trans[VK_LCONTROL] = 0;
2242 keymap_trans[VK_CONTROL] = 0;
2243 keymap_trans[VK_RMENU] = 0;
2244 keymap_trans[VK_MENU] = 0;
2246 SetKeyboardState (keymap_trans);
2248 /* Maybe generate some WM_[SYS]CHARs in the queue */
2249 TranslateMessage (&msg);
2251 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2252 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2255 int mods_with_quit = mods;
2256 WPARAM ch = tranmsg.wParam;
2258 /* If a quit char with no modifiers other than control and
2259 shift, then mark it with a fake modifier, which is removed
2260 upon dequeueing the event */
2261 /* !!#### Fix this in my mule ws -- replace current_buffer
2263 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2264 && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2265 DOWNCASE (current_buffer, ch))
2266 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2267 && DOWNCASE (current_buffer, quit_ch) ==
2268 DOWNCASE (current_buffer, ch)))
2269 && ((mods_with_shift &
2270 ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2273 mods_with_quit |= FAKE_MOD_QUIT;
2274 if (mods_with_shift & XEMACS_MOD_SHIFT)
2275 mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2276 ++mswindows_quit_chars_count;
2278 else if (potential_accelerator && !got_accelerator &&
2279 mswindows_char_is_accelerator (frame, ch))
2281 got_accelerator = 1;
2284 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2288 /* This generates WM_SYSCHAR messages, which are interpreted
2289 by DefWindowProc as the menu selections. */
2290 if (got_accelerator)
2292 SetKeyboardState (keymap_sticky);
2293 TranslateMessage (&msg);
2294 SetKeyboardState (keymap_orig);
2298 SetKeyboardState (keymap_orig);
2302 if (key_needs_default_processing_p (wParam))
2307 case WM_MBUTTONDOWN:
2309 /* Real middle mouse button has nothing to do with emulated one:
2310 if one wants to exercise fingers playing chords on the mouse,
2311 he is allowed to do that! */
2312 mswindows_enqueue_mouse_button_event (hwnd, message_,
2313 MAKEPOINTS (lParam),
2314 wParam &~ MK_MBUTTON,
2319 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2320 msframe->last_click_time = GetMessageTime();
2322 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2323 msframe->button2_need_lbutton = 0;
2324 if (msframe->ignore_next_lbutton_up)
2326 msframe->ignore_next_lbutton_up = 0;
2328 else if (msframe->button2_is_down)
2330 msframe->button2_is_down = 0;
2331 msframe->ignore_next_rbutton_up = 1;
2332 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2333 MAKEPOINTS (lParam),
2335 &~ (MK_LBUTTON | MK_MBUTTON
2341 if (msframe->button2_need_rbutton)
2343 msframe->button2_need_rbutton = 0;
2344 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2345 MAKEPOINTS (lParam),
2346 wParam &~ MK_LBUTTON,
2349 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2350 MAKEPOINTS (lParam),
2351 wParam &~ MK_LBUTTON,
2357 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2358 msframe->last_click_time = GetMessageTime();
2360 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2361 msframe->button2_need_rbutton = 0;
2362 if (msframe->ignore_next_rbutton_up)
2364 msframe->ignore_next_rbutton_up = 0;
2366 else if (msframe->button2_is_down)
2368 msframe->button2_is_down = 0;
2369 msframe->ignore_next_lbutton_up = 1;
2370 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2371 MAKEPOINTS (lParam),
2373 &~ (MK_LBUTTON | MK_MBUTTON
2379 if (msframe->button2_need_lbutton)
2381 msframe->button2_need_lbutton = 0;
2382 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2383 MAKEPOINTS (lParam),
2384 wParam &~ MK_RBUTTON,
2387 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2388 MAKEPOINTS (lParam),
2389 wParam &~ MK_RBUTTON,
2394 case WM_LBUTTONDOWN:
2395 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2397 if (msframe->button2_need_lbutton)
2399 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2400 msframe->button2_need_lbutton = 0;
2401 msframe->button2_need_rbutton = 0;
2402 if (mswindows_button2_near_enough (msframe->last_click_point,
2403 MAKEPOINTS (lParam)))
2405 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2406 MAKEPOINTS (lParam),
2408 &~ (MK_LBUTTON | MK_MBUTTON
2411 msframe->button2_is_down = 1;
2415 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2416 msframe->last_click_point,
2417 msframe->last_click_mods
2419 msframe->last_click_time);
2420 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2421 MAKEPOINTS (lParam),
2422 wParam &~ MK_LBUTTON,
2428 mswindows_set_chord_timer (hwnd);
2429 msframe->button2_need_rbutton = 1;
2430 msframe->last_click_point = MAKEPOINTS (lParam);
2431 msframe->last_click_mods = wParam;
2433 msframe->last_click_time = GetMessageTime();
2436 case WM_RBUTTONDOWN:
2437 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2439 if (msframe->button2_need_rbutton)
2441 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2442 msframe->button2_need_lbutton = 0;
2443 msframe->button2_need_rbutton = 0;
2444 if (mswindows_button2_near_enough (msframe->last_click_point,
2445 MAKEPOINTS (lParam)))
2447 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2448 MAKEPOINTS (lParam),
2450 &~ (MK_LBUTTON | MK_MBUTTON
2453 msframe->button2_is_down = 1;
2457 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2458 msframe->last_click_point,
2459 msframe->last_click_mods
2461 msframe->last_click_time);
2462 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2463 MAKEPOINTS (lParam),
2464 wParam &~ MK_RBUTTON,
2470 mswindows_set_chord_timer (hwnd);
2471 msframe->button2_need_lbutton = 1;
2472 msframe->last_click_point = MAKEPOINTS (lParam);
2473 msframe->last_click_mods = wParam;
2475 msframe->last_click_time = GetMessageTime();
2479 if (wParam == BUTTON_2_TIMER_ID)
2481 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2482 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2484 if (msframe->button2_need_lbutton)
2486 msframe->button2_need_lbutton = 0;
2487 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2488 msframe->last_click_point,
2489 msframe->last_click_mods
2491 msframe->last_click_time);
2493 else if (msframe->button2_need_rbutton)
2495 msframe->button2_need_rbutton = 0;
2496 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2497 msframe->last_click_point,
2498 msframe->last_click_mods
2500 msframe->last_click_time);
2504 assert ("Spurious timer fired" == 0);
2508 /* Optimization: don't report mouse movement while size is changing */
2509 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2510 if (!msframe->sizing)
2512 /* When waiting for the second mouse button to finish
2513 button2 emulation, and have moved too far, just pretend
2514 as if timer has expired. This improves drag-select feedback */
2515 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2516 && !mswindows_button2_near_enough (msframe->last_click_point,
2517 MAKEPOINTS (lParam)))
2519 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2520 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2523 emacs_event = Fmake_event (Qnil, Qnil);
2524 event = XEVENT(emacs_event);
2526 event->channel = mswindows_find_frame(hwnd);
2527 event->timestamp = GetMessageTime();
2528 event->event_type = pointer_motion_event;
2529 event->event.motion.x = MAKEPOINTS(lParam).x;
2530 event->event.motion.y = MAKEPOINTS(lParam).y;
2531 event->event.motion.modifiers =
2532 mswindows_modifier_state (NULL, wParam, 0);
2534 mswindows_enqueue_dispatch_event (emacs_event);
2540 /* Queue a `cancel-mode-internal' misc user event, so mouse
2541 selection would be canceled if any */
2542 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2543 Qcancel_mode_internal, Qnil);
2548 LPNMHDR nmhdr = (LPNMHDR)lParam;
2550 if (nmhdr->code == TTN_NEEDTEXT)
2552 #ifdef HAVE_TOOLBARS
2553 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2556 /* find out which toolbar */
2557 frame = XFRAME (mswindows_find_frame (hwnd));
2558 btext = mswindows_get_toolbar_button_text ( frame,
2561 tttext->lpszText = NULL;
2562 tttext->hinst = NULL;
2566 /* I think this is safe since the text will only go away
2567 when the toolbar does...*/
2568 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2572 /* handle tree view callbacks */
2573 else if (nmhdr->code == TVN_SELCHANGED)
2575 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2576 frame = XFRAME (mswindows_find_frame (hwnd));
2577 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2579 /* handle tab control callbacks */
2580 else if (nmhdr->code == TCN_SELCHANGE)
2583 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2584 frame = XFRAME (mswindows_find_frame (hwnd));
2586 item.mask = TCIF_PARAM;
2587 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2590 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2596 /* hdc will be NULL unless this is a subwindow - in which case we
2597 shouldn't have received a paint message for it here. */
2598 assert (wParam == 0);
2600 /* Can't queue a magic event because windows goes modal and sends paint
2601 messages directly to the windows procedure when doing solid drags
2602 and the message queue doesn't get processed. */
2603 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2607 /* We only care about this message if our size has really changed */
2608 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2613 fobj = mswindows_find_frame (hwnd);
2614 frame = XFRAME (fobj);
2615 msframe = FRAME_MSWINDOWS_DATA (frame);
2617 /* We cannot handle frame map and unmap hooks right in
2618 this routine, because these may throw. We queue
2619 magic events to run these hooks instead - kkm */
2621 if (wParam==SIZE_MINIMIZED)
2624 FRAME_VISIBLE_P (frame) = 0;
2625 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2629 GetClientRect(hwnd, &rect);
2630 FRAME_PIXWIDTH(frame) = rect.right;
2631 FRAME_PIXHEIGHT(frame) = rect.bottom;
2633 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2634 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2635 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2637 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2638 change_frame_size (frame, rows, columns, 1);
2640 /* If we are inside frame creation, we have to apply geometric
2642 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2644 /* Yes, we have to size again */
2645 mswindows_size_frame_internal ( frame,
2646 FRAME_MSWINDOWS_TARGET_RECT
2648 /* Reset so we do not get here again. The SetWindowPos call in
2649 * mswindows_size_frame_internal can cause recursion here. */
2650 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2652 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2653 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2658 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2659 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2660 FRAME_VISIBLE_P (frame) = 1;
2662 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2669 case WM_DISPLAYCHANGE:
2672 DWORD message_tick = GetMessageTime ();
2674 fobj = mswindows_find_frame (hwnd);
2675 frame = XFRAME (fobj);
2676 d = XDEVICE (FRAME_DEVICE (frame));
2678 /* Do this only once per message. XEmacs can receive this message
2679 through as many frames as it currently has open. Message time
2680 will be the same for all these messages. Despite extreme
2681 efficiency, the code below has about one in 4 billion
2682 probability that the HDC is not recreated, provided that
2683 XEmacs is running sufficiently longer than 52 days. */
2684 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2686 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2687 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2688 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2693 /* Misc magic events which only require that the frame be identified */
2696 mswindows_enqueue_magic_event (hwnd, message_);
2699 case WM_WINDOWPOSCHANGING:
2701 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2702 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2703 GetWindowPlacement(hwnd, &wpl);
2705 /* Only interested if size is changing and we're not being iconified */
2706 if (wpl.showCmd != SW_SHOWMINIMIZED
2707 && wpl.showCmd != SW_SHOWMAXIMIZED
2708 && !(wp->flags & SWP_NOSIZE))
2710 RECT ncsize = { 0, 0, 0, 0 };
2711 int pixwidth, pixheight;
2712 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2713 GetMenu(hwnd) != NULL,
2714 GetWindowLong (hwnd, GWL_EXSTYLE));
2716 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2717 wp->cx - (ncsize.right - ncsize.left),
2718 wp->cy - (ncsize.bottom - ncsize.top),
2719 &pixwidth, &pixheight);
2721 /* Convert client sizes to window sizes */
2722 pixwidth += (ncsize.right - ncsize.left);
2723 pixheight += (ncsize.bottom - ncsize.top);
2725 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2727 /* Adjust so that the bottom or right doesn't move if it's
2728 * the top or left that's being changed */
2730 GetWindowRect (hwnd, &rect);
2732 if (rect.left != wp->x)
2733 wp->x += wp->cx - pixwidth;
2734 if (rect.top != wp->y)
2735 wp->y += wp->cy - pixheight;
2741 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2742 window position if the user tries to track window too small */
2746 case WM_ENTERSIZEMOVE:
2747 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2748 msframe->sizing = 1;
2751 case WM_EXITSIZEMOVE:
2752 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2753 msframe->sizing = 0;
2754 /* Queue noop event */
2755 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2758 #ifdef HAVE_SCROLLBARS
2762 /* Direction of scroll is determined by scrollbar instance. */
2763 int code = (int) LOWORD(wParam);
2764 int pos = (short int) HIWORD(wParam);
2765 HWND hwndScrollBar = (HWND) lParam;
2766 struct gcpro gcpro1, gcpro2;
2768 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2769 GCPRO2 (emacs_event, fobj);
2770 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2772 /* Error during event pumping - cancel scroll */
2773 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2781 int keys = LOWORD (wParam); /* Modifier key flags */
2782 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2783 struct gcpro gcpro1, gcpro2;
2785 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2787 MAKEPOINTS (lParam)))
2789 GCPRO2 (emacs_event, fobj);
2790 mswindows_pump_outstanding_events (); /* Can GC */
2799 #ifdef HAVE_MENUBARS
2801 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2803 XFRAME (mswindows_find_frame (hwnd)))))
2804 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2807 case WM_INITMENUPOPUP:
2808 if (!HIWORD(lParam))
2810 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2812 XFRAME (mswindows_find_frame (hwnd)))))
2813 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2817 #endif /* HAVE_MENUBARS */
2821 WORD id = LOWORD (wParam);
2822 WORD nid = HIWORD (wParam);
2823 HWND cid = (HWND)lParam;
2824 frame = XFRAME (mswindows_find_frame (hwnd));
2826 #ifdef HAVE_TOOLBARS
2827 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2830 /* widgets in a buffer only eval a callback for suitable events.*/
2835 case CBN_EDITCHANGE:
2837 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2840 /* menubars always must come last since the hashtables do not
2842 #ifdef HAVE_MENUBARS
2843 if (!NILP (mswindows_handle_wm_command (frame, id)))
2847 return DefWindowProc (hwnd, message_, wParam, lParam);
2848 /* Bite me - a spurious command. This used to not be able to
2849 happen but with the introduction of widgets its now
2854 case WM_CTLCOLORBTN:
2855 case WM_CTLCOLORLISTBOX:
2856 case WM_CTLCOLOREDIT:
2857 case WM_CTLCOLORSTATIC:
2858 case WM_CTLCOLORSCROLLBAR:
2860 /* if we get an opportunity to paint a widget then do so if
2861 there is an appropriate face */
2862 HWND crtlwnd = (HWND)lParam;
2863 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2866 Lisp_Object image_instance;
2867 VOID_TO_LISP (image_instance, ii);
2868 if (IMAGE_INSTANCEP (image_instance)
2870 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2872 /* set colors for the buttons */
2873 HDC hdc = (HDC)wParam;
2874 if (last_widget_brushed != ii)
2877 DeleteObject (widget_brush);
2878 widget_brush = CreateSolidBrush
2879 (COLOR_INSTANCE_MSWINDOWS_COLOR
2882 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2883 XIMAGE_INSTANCE_FRAME (image_instance)))));
2885 last_widget_brushed = ii;
2888 COLOR_INSTANCE_MSWINDOWS_COLOR
2891 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2892 XIMAGE_INSTANCE_FRAME (image_instance)))));
2893 SetBkMode (hdc, OPAQUE);
2896 COLOR_INSTANCE_MSWINDOWS_COLOR
2899 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2900 XIMAGE_INSTANCE_FRAME (image_instance)))));
2901 return (LRESULT)widget_brush;
2907 #ifdef HAVE_DRAGNDROP
2908 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2910 UINT filecount, i, len;
2915 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2916 struct gcpro gcpro1, gcpro2, gcpro3;
2918 emacs_event = Fmake_event (Qnil, Qnil);
2919 event = XEVENT(emacs_event);
2921 GCPRO3 (emacs_event, l_dndlist, l_item);
2923 if (!DragQueryPoint ((HDROP) wParam, &point))
2924 point.x = point.y = -1; /* outside client area */
2926 event->event_type = misc_user_event;
2927 event->channel = mswindows_find_frame(hwnd);
2928 event->timestamp = GetMessageTime();
2929 event->event.misc.button = 1; /* #### Should try harder */
2930 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2932 event->event.misc.x = point.x;
2933 event->event.misc.y = point.y;
2934 event->event.misc.function = Qdragdrop_drop_dispatch;
2936 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2937 for (i=0; i<filecount; i++)
2939 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2940 /* The URLs that we make here aren't correct according to section
2941 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2942 * because they may contain reserved characters. But that's OK -
2943 * they just need to be good enough to keep dragdrop.el happy. */
2944 fname = (char *)xmalloc (len+1);
2945 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2947 /* May be a shell link aka "shortcut" - replace fname if so */
2948 #if !(defined(CYGWIN) || defined(MINGW))
2949 /* cygwin doesn't define this COM stuff */
2950 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2954 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2955 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2959 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2963 WIN32_FIND_DATA wfd;
2964 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2966 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2968 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2969 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2974 len = strlen (fname);
2977 ppf->lpVtbl->Release (ppf);
2980 psl->lpVtbl->Release (psl);
2986 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2987 strcpy (filename, "file:");
2988 cygwin32_win32_to_posix_path_list (fname, filename+5);
2990 filename = (char *)xmalloc (len+6);
2991 strcat (strcpy (filename, "file:"), fname);
2992 dostounix_filename (filename+5);
2995 l_item = make_string (filename, strlen (filename));
2996 l_dndlist = Fcons (l_item, l_dndlist);
2999 DragFinish ((HDROP) wParam);
3001 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3002 mswindows_enqueue_dispatch_event (emacs_event);
3010 return DefWindowProc (hwnd, message_, wParam, lParam);
3016 /************************************************************************/
3017 /* keyboard, mouse & other helpers for the windows procedure */
3018 /************************************************************************/
3020 mswindows_set_chord_timer (HWND hwnd)
3024 /* We get one third half system double click threshold */
3025 if (mswindows_mouse_button_tolerance <= 0)
3026 interval = GetDoubleClickTime () / 3;
3028 interval = mswindows_mouse_button_tolerance;
3030 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3034 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3037 if (mswindows_mouse_button_max_skew_x <= 0)
3038 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3040 dx = mswindows_mouse_button_max_skew_x;
3042 if (mswindows_mouse_button_max_skew_y <= 0)
3043 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3045 dy = mswindows_mouse_button_max_skew_y;
3047 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3051 mswindows_current_layout_has_AltGr (void)
3053 /* This simple caching mechanism saves 10% of CPU
3054 time when a key typed at autorepeat rate of 30 cps! */
3055 static HKL last_hkl = 0;
3056 static int last_hkl_has_AltGr;
3057 HKL current_hkl = (HKL) -1;
3059 if (xGetKeyboardLayout) /* not in NT 3.5 */
3060 current_hkl = xGetKeyboardLayout (0);
3061 if (current_hkl != last_hkl)
3064 last_hkl_has_AltGr = 0;
3065 /* In this loop, we query whether a character requires
3066 AltGr to be down to generate it. If at least such one
3067 found, this means that the layout does regard AltGr */
3068 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3069 if (HIBYTE (VkKeyScan (c)) == 6)
3070 last_hkl_has_AltGr = 1;
3071 last_hkl = current_hkl;
3073 return last_hkl_has_AltGr;
3077 /* Returns the state of the modifier keys in the format expected by the
3078 * Lisp_Event key_data, button_data and motion_data modifiers member */
3080 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3083 int keys_is_real = 0;
3086 if (fwKeys == (DWORD) -1)
3087 fwKeys = mswindows_last_mouse_button_state;
3091 mswindows_last_mouse_button_state = fwKeys;
3097 GetKeyboardState (keymap);
3098 has_AltGr = mswindows_current_layout_has_AltGr ();
3101 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3103 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3105 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3106 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3110 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3111 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3114 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3115 ? XEMACS_MOD_SHIFT : 0;
3116 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3117 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3118 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3124 * Translate a mswindows virtual key to a keysym.
3125 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3126 * or whose ASCII codes (like space) xemacs doesn't like.
3128 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3131 if (extendedp) /* Keys not present on a 82 key keyboard */
3133 switch (mswindows_key)
3135 case VK_CANCEL: return KEYSYM ("pause");
3136 case VK_RETURN: return KEYSYM ("kp-enter");
3137 case VK_PRIOR: return KEYSYM ("prior");
3138 case VK_NEXT: return KEYSYM ("next");
3139 case VK_END: return KEYSYM ("end");
3140 case VK_HOME: return KEYSYM ("home");
3141 case VK_LEFT: return KEYSYM ("left");
3142 case VK_UP: return KEYSYM ("up");
3143 case VK_RIGHT: return KEYSYM ("right");
3144 case VK_DOWN: return KEYSYM ("down");
3145 case VK_INSERT: return KEYSYM ("insert");
3146 case VK_DELETE: return QKdelete;
3147 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3148 case VK_LWIN return KEYSYM ("");
3149 case VK_RWIN return KEYSYM ("");
3151 case VK_APPS: return KEYSYM ("menu");
3156 switch (mswindows_key)
3158 case VK_BACK: return QKbackspace;
3159 case VK_TAB: return QKtab;
3160 case '\n': return QKlinefeed;
3161 case VK_CLEAR: return KEYSYM ("clear");
3162 case VK_RETURN: return QKreturn;
3163 case VK_PAUSE: return KEYSYM ("pause");
3164 case VK_ESCAPE: return QKescape;
3165 case VK_SPACE: return QKspace;
3166 case VK_PRIOR: return KEYSYM ("kp-prior");
3167 case VK_NEXT: return KEYSYM ("kp-next");
3168 case VK_END: return KEYSYM ("kp-end");
3169 case VK_HOME: return KEYSYM ("kp-home");
3170 case VK_LEFT: return KEYSYM ("kp-left");
3171 case VK_UP: return KEYSYM ("kp-up");
3172 case VK_RIGHT: return KEYSYM ("kp-right");
3173 case VK_DOWN: return KEYSYM ("kp-down");
3174 case VK_SELECT: return KEYSYM ("select");
3175 case VK_PRINT: return KEYSYM ("print");
3176 case VK_EXECUTE: return KEYSYM ("execute");
3177 case VK_SNAPSHOT: return KEYSYM ("print");
3178 case VK_INSERT: return KEYSYM ("kp-insert");
3179 case VK_DELETE: return KEYSYM ("kp-delete");
3180 case VK_HELP: return KEYSYM ("help");
3181 case VK_NUMPAD0: return KEYSYM ("kp-0");
3182 case VK_NUMPAD1: return KEYSYM ("kp-1");
3183 case VK_NUMPAD2: return KEYSYM ("kp-2");
3184 case VK_NUMPAD3: return KEYSYM ("kp-3");
3185 case VK_NUMPAD4: return KEYSYM ("kp-4");
3186 case VK_NUMPAD5: return KEYSYM ("kp-5");
3187 case VK_NUMPAD6: return KEYSYM ("kp-6");
3188 case VK_NUMPAD7: return KEYSYM ("kp-7");
3189 case VK_NUMPAD8: return KEYSYM ("kp-8");
3190 case VK_NUMPAD9: return KEYSYM ("kp-9");
3191 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3192 case VK_ADD: return KEYSYM ("kp-add");
3193 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3194 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3195 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3196 case VK_DIVIDE: return KEYSYM ("kp-divide");
3197 case VK_F1: return KEYSYM ("f1");
3198 case VK_F2: return KEYSYM ("f2");
3199 case VK_F3: return KEYSYM ("f3");
3200 case VK_F4: return KEYSYM ("f4");
3201 case VK_F5: return KEYSYM ("f5");
3202 case VK_F6: return KEYSYM ("f6");
3203 case VK_F7: return KEYSYM ("f7");
3204 case VK_F8: return KEYSYM ("f8");
3205 case VK_F9: return KEYSYM ("f9");
3206 case VK_F10: return KEYSYM ("f10");
3207 case VK_F11: return KEYSYM ("f11");
3208 case VK_F12: return KEYSYM ("f12");
3209 case VK_F13: return KEYSYM ("f13");
3210 case VK_F14: return KEYSYM ("f14");
3211 case VK_F15: return KEYSYM ("f15");
3212 case VK_F16: return KEYSYM ("f16");
3213 case VK_F17: return KEYSYM ("f17");
3214 case VK_F18: return KEYSYM ("f18");
3215 case VK_F19: return KEYSYM ("f19");
3216 case VK_F20: return KEYSYM ("f20");
3217 case VK_F21: return KEYSYM ("f21");
3218 case VK_F22: return KEYSYM ("f22");
3219 case VK_F23: return KEYSYM ("f23");
3220 case VK_F24: return KEYSYM ("f24");
3227 * Find the console that matches the supplied mswindows window handle
3230 mswindows_find_console (HWND hwnd)
3232 /* We only support one console */
3233 return XCAR (Vconsole_list);
3237 * Find the frame that matches the supplied mswindows window handle
3240 mswindows_find_frame (HWND hwnd)
3242 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3246 /* We are in progress of frame creation. Return the frame
3247 being created, as it still not remembered in the window
3249 assert (!NILP (Vmswindows_frame_being_created));
3250 return Vmswindows_frame_being_created;
3252 VOID_TO_LISP (f, l);
3257 /************************************************************************/
3259 /************************************************************************/
3262 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3265 EMACS_TIME current_time;
3266 EMACS_GET_TIME (current_time);
3267 EMACS_SUB_TIME (thyme, thyme, current_time);
3268 milliseconds = EMACS_SECS (thyme) * 1000 +
3269 (EMACS_USECS (thyme) + 500) / 1000;
3270 if (milliseconds < 1)
3272 ++mswindows_pending_timers_count;
3273 return SetTimer (NULL, 0, milliseconds,
3274 (TIMERPROC) mswindows_wm_timer_callback);
3278 emacs_mswindows_remove_timeout (int id)
3280 Lisp_Event match_against;
3281 Lisp_Object emacs_event;
3283 if (KillTimer (NULL, id))
3284 --mswindows_pending_timers_count;
3286 /* If there is a dispatch event generated by this
3287 timeout in the queue, we have to remove it too. */
3288 match_against.event_type = timeout_event;
3289 match_against.event.timeout.interval_id = id;
3290 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3291 if (!NILP (emacs_event))
3292 Fdeallocate_event(emacs_event);
3295 /* If `user_p' is false, then return whether there are any win32, timeout,
3296 * or subprocess events pending (that is, whether
3297 * emacs_mswindows_next_event() would return immediately without blocking).
3299 * if `user_p' is true, then return whether there are any *user generated*
3300 * events available (that is, whether there are keyboard or mouse-click
3301 * events ready to be read). This also implies that
3302 * emacs_mswindows_next_event() would not block.
3305 emacs_mswindows_event_pending_p (int user_p)
3307 mswindows_need_event (0);
3308 return (!NILP (mswindows_u_dispatch_event_queue)
3309 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3313 * Return the next event
3316 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3318 Lisp_Object event, event2;
3320 mswindows_need_event (1);
3322 event = mswindows_dequeue_dispatch_event ();
3323 XSETEVENT (event2, emacs_event);
3324 Fcopy_event (event, event2);
3325 Fdeallocate_event (event);
3329 * Handle a magic event off the dispatch queue.
3332 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3334 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3341 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3342 mswindows_handle_paint (f);
3343 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3350 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3351 struct frame *f = XFRAME (frame);
3352 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3354 struct gcpro gcpro1;
3356 /* On focus change, clear all memory of sticky modifiers
3357 to avoid non-intuitive behavior. */
3358 clear_sticky_modifiers ();
3360 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3362 emacs_handle_focus_change_preliminary (conser);
3363 /* Under X the stuff up to here is done in the X event handler.
3365 emacs_handle_focus_change_final (conser);
3374 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3375 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3377 Qmap_frame_hook : Qunmap_frame_hook,
3382 /* #### What about Enter & Leave */
3384 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3385 Qmouse_leave_frame_hook, 1, frame);
3393 #ifndef HAVE_MSG_SELECT
3395 get_process_input_waitable (Lisp_Process *process)
3397 Lisp_Object instr, outstr, p;
3398 XSETPROCESS (p, process);
3399 get_process_streams (process, &instr, &outstr);
3400 assert (!NILP (instr));
3401 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3402 return (network_connection_p (p)
3403 ? get_winsock_stream_waitable (XLSTREAM (instr))
3404 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3406 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3411 emacs_mswindows_select_process (Lisp_Process *process)
3413 HANDLE hev = get_process_input_waitable (process);
3415 if (!add_waitable_handle (hev))
3416 error ("Too many active processes");
3418 #ifdef HAVE_WIN32_PROCESSES
3421 XSETPROCESS (p, process);
3422 if (!network_connection_p (p))
3424 HANDLE hprocess = get_nt_process_handle (process);
3425 if (!add_waitable_handle (hprocess))
3427 remove_waitable_handle (hev);
3428 error ("Too many active processes");
3436 emacs_mswindows_unselect_process (Lisp_Process *process)
3438 /* Process handle is removed in the event loop as soon
3439 as it is signaled, so don't bother here about it */
3440 HANDLE hev = get_process_input_waitable (process);
3441 remove_waitable_handle (hev);
3443 #endif /* HAVE_MSG_SELECT */
3446 emacs_mswindows_select_console (struct console *con)
3448 #ifdef HAVE_MSG_SELECT
3449 if (CONSOLE_MSWINDOWS_P (con))
3450 return; /* mswindows consoles are automatically selected */
3452 event_stream_unixoid_select_console (con);
3457 emacs_mswindows_unselect_console (struct console *con)
3459 #ifdef HAVE_MSG_SELECT
3460 if (CONSOLE_MSWINDOWS_P (con))
3461 return; /* mswindows consoles are automatically selected */
3463 event_stream_unixoid_unselect_console (con);
3468 emacs_mswindows_quit_p (void)
3470 /* Quit cannot happen in modal loop: all program
3471 input is dedicated to Windows. */
3472 if (mswindows_in_modal_loop)
3475 /* Drain windows queue. This sets up number of quit characters in
3477 mswindows_drain_windows_queue ();
3479 if (mswindows_quit_chars_count > 0)
3481 /* Yes there's a hidden one... Throw it away */
3482 Lisp_Event match_against;
3483 Lisp_Object emacs_event;
3486 match_against.event_type = key_press_event;
3487 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3489 while (mswindows_quit_chars_count-- > 0)
3491 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3492 assert (!NILP (emacs_event));
3494 if (XEVENT (emacs_event)->event.key.modifiers &
3495 FAKE_MOD_QUIT_CRITICAL)
3498 Fdeallocate_event (emacs_event);
3501 Vquit_flag = critical_p ? Qcritical : Qt;
3506 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3507 Lisp_Object* instream,
3508 Lisp_Object* outstream,
3511 /* Handles for streams */
3513 /* fds. These just stored along with the streams, and are closed in
3514 delete stream pair method, because we need to handle fake unices
3518 /* Decode inhandle and outhandle. Their meaning depends on
3519 the process implementation being used. */
3520 #if defined (HAVE_WIN32_PROCESSES)
3521 /* We're passed in Windows handles. That's what we like most... */
3522 hin = (HANDLE) inhandle;
3523 hout = (HANDLE) outhandle;
3525 #elif defined (HAVE_UNIX_PROCESSES)
3526 /* We are passed UNIX fds. This must be Cygwin.
3528 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3529 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3533 #error "So, WHICH kind of processes do you want?"
3536 *instream = (hin == INVALID_HANDLE_VALUE
3538 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3539 : flags & STREAM_NETWORK_CONNECTION
3540 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3542 : make_ntpipe_input_stream (hin, fdi));
3544 #ifdef HAVE_WIN32_PROCESSES
3545 *outstream = (hout == INVALID_HANDLE_VALUE
3547 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3548 : flags & STREAM_NETWORK_CONNECTION
3549 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3551 : make_ntpipe_output_stream (hout, fdo));
3552 #elif defined (HAVE_UNIX_PROCESSES)
3553 *outstream = (fdo >= 0
3554 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3557 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3558 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3559 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3561 Bufbyte eof_char = get_eof_char (fdo);
3562 int pty_max_bytes = get_pty_max_bytes (fdo);
3563 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3568 return (NILP (*instream)
3570 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3571 : flags & STREAM_NETWORK_CONNECTION
3572 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3574 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3578 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3579 Lisp_Object outstream)
3581 /* Oh nothing special here for Win32 at all */
3582 #if defined (HAVE_UNIX_PROCESSES)
3583 int in = (NILP(instream)
3585 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3586 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3587 ? get_winsock_stream_param (XLSTREAM (instream))
3589 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3590 int out = (NILP(outstream) ? -1
3591 : filedesc_stream_fd (XLSTREAM (outstream)));
3595 if (out != in && out >= 0)
3599 return (NILP (instream)
3601 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3602 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3603 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3605 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3609 emacs_mswindows_current_event_timestamp (struct console *c)
3611 return GetTickCount ();
3614 #ifndef HAVE_X_WINDOWS
3615 /* This is called from GC when a process object is about to be freed.
3616 If we've still got pointers to it in this file, we're gonna lose hard.
3619 debug_process_finalization (Lisp_Process *p)
3622 Lisp_Object instr, outstr;
3624 get_process_streams (p, &instr, &outstr);
3625 /* if it still has fds, then it hasn't been killed yet. */
3626 assert (NILP(instr));
3627 assert (NILP(outstr));
3629 /* #### More checks here */
3634 /************************************************************************/
3635 /* initialization */
3636 /************************************************************************/
3639 reinit_vars_of_event_mswindows (void)
3641 mswindows_in_modal_loop = 0;
3642 mswindows_pending_timers_count = 0;
3644 mswindows_event_stream = xnew (struct event_stream);
3646 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3647 mswindows_event_stream->force_event_pending = 0;
3648 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3649 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3650 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3651 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3652 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3653 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3654 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3655 #ifdef HAVE_MSG_SELECT
3656 mswindows_event_stream->select_process_cb =
3657 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3658 mswindows_event_stream->unselect_process_cb =
3659 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3660 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3661 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3663 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3664 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3665 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3666 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3668 mswindows_event_stream->current_event_timestamp_cb =
3669 emacs_mswindows_current_event_timestamp;
3673 vars_of_event_mswindows (void)
3675 reinit_vars_of_event_mswindows ();
3677 mswindows_u_dispatch_event_queue = Qnil;
3678 staticpro (&mswindows_u_dispatch_event_queue);
3679 mswindows_u_dispatch_event_queue_tail = Qnil;
3680 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
3682 mswindows_s_dispatch_event_queue = Qnil;
3683 staticpro (&mswindows_s_dispatch_event_queue);
3684 mswindows_s_dispatch_event_queue_tail = Qnil;
3685 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
3687 mswindows_error_caught_in_modal_loop = Qnil;
3688 staticpro (&mswindows_error_caught_in_modal_loop);
3692 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
3693 If non-zero, display debug information about Windows events that XEmacs sees.
3694 Information is displayed in a console window. Currently defined values are:
3696 1 == non-verbose output
3699 #### Unfortunately, not yet implemented.
3701 debug_mswindows_events = 0;
3704 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3705 &mswindows_alt_by_itself_activates_menu /*
3706 *Controls whether pressing and releasing the Alt key activates the menubar.
3707 This applies only if no intervening key was pressed. See also
3708 `menu-accelerator-enabled', which is probably the behavior you actually want.
3712 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3713 &mswindows_dynamic_frame_resize /*
3714 *Controls redrawing frame contents during mouse-drag or keyboard resize
3715 operation. When non-nil, the frame is redrawn while being resized. When
3716 nil, frame is not redrawn, and exposed areas are filled with default
3717 MDI application background color. Note that this option only has effect
3718 if "Show window contents while dragging" is on in system Display/Plus!
3720 Default is t on fast machines, nil on slow.
3723 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3724 &mswindows_mouse_button_tolerance /*
3725 *Analogue of double click interval for faking middle mouse events.
3726 The value is the minimum time in milliseconds that must elapse between
3727 left/right button down events before they are considered distinct events.
3728 If both mouse buttons are depressed within this interval, a middle mouse
3729 button down event is generated instead.
3730 If negative or zero, currently set system default is used instead.
3733 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3734 Number of physical mouse buttons.
3737 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3738 &mswindows_mouse_button_max_skew_x /*
3739 *Maximum horizontal distance in pixels between points in which left and
3740 right button clicks occurred for them to be translated into single
3741 middle button event. Clicks must occur in time not longer than defined
3742 by the variable `mswindows-mouse-button-tolerance'.
3743 If negative or zero, currently set system default is used instead.
3746 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3747 &mswindows_mouse_button_max_skew_y /*
3748 *Maximum vertical distance in pixels between points in which left and
3749 right button clicks occurred for them to be translated into single
3750 middle button event. Clicks must occur in time not longer than defined
3751 by the variable `mswindows-mouse-button-tolerance'.
3752 If negative or zero, currently set system default is used instead.
3755 mswindows_mouse_button_max_skew_x = 0;
3756 mswindows_mouse_button_max_skew_y = 0;
3757 mswindows_mouse_button_tolerance = 0;
3758 mswindows_alt_by_itself_activates_menu = 1;
3762 syms_of_event_mswindows (void)
3767 lstream_type_create_mswindows_selectable (void)
3769 init_slurp_stream ();
3770 init_shove_stream ();
3771 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3772 init_winsock_stream ();
3777 init_event_mswindows_late (void)
3779 #ifdef HAVE_MSG_SELECT
3780 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3781 assert (windows_fd>=0);
3782 FD_SET (windows_fd, &input_wait_mask);
3783 FD_ZERO(&zero_mask);
3786 event_stream = mswindows_event_stream;
3788 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3789 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);