1 /* The mswindows event_stream interface.
2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1996, 2000 Ben Wing.
5 Copyright (C) 1997 Jonathan Harris.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
28 Ultimately based on FSF.
29 Rewritten by Ben Wing.
30 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
31 Subprocess and modal loop support by Kirill M. Katsnelson.
37 #include "console-msw.h"
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
45 # include "menubar-msw.h"
49 # include "dragdrop.h"
59 #include "redisplay.h"
66 #include "objects-msw.h"
68 #include "events-mod.h"
69 #ifdef HAVE_MSG_SELECT
71 #include "console-tty.h"
73 typedef unsigned int SOCKET;
78 #if !(defined(CYGWIN) || defined(MINGW))
79 # include <shlobj.h> /* For IShellLink */
83 #define ADJR_MENUFLAG TRUE
85 #define ADJR_MENUFLAG FALSE
88 /* Fake key modifier which is attached to a quit char event.
89 Removed upon dequeueing an event */
90 #define FAKE_MOD_QUIT 0x80
92 /* Timer ID used for button2 emulation */
93 #define BUTTON_2_TIMER_ID 1
95 static Lisp_Object mswindows_find_frame (HWND hwnd);
96 static Lisp_Object mswindows_find_console (HWND hwnd);
97 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
99 static int mswindows_modifier_state (BYTE* keymap, DWORD fwKeys,
101 static void mswindows_set_chord_timer (HWND hwnd);
102 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
103 static int mswindows_current_layout_has_AltGr (void);
104 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
105 int downp, int keyp);
107 static struct event_stream *mswindows_event_stream;
109 #ifdef HAVE_MSG_SELECT
110 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
111 extern SELECT_TYPE process_only_mask, tty_only_mask;
112 SELECT_TYPE zero_mask;
113 extern int signal_event_pipe_initialized;
118 * Two separate queues, for efficiency, one (_u_) for user events, and
119 * another (_s_) for non-user ones. We always return events out of the
120 * first one until it is empty and only then proceed with the second
123 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
124 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
126 /* The number of things we can wait on */
127 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
129 #ifndef HAVE_MSG_SELECT
130 /* List of mswindows waitable handles. */
131 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
133 /* Number of wait handles */
134 static int mswindows_waitable_count=0;
135 #endif /* HAVE_MSG_SELECT */
137 /* Brush for painting widgets */
138 static HBRUSH widget_brush = 0;
139 static LONG last_widget_brushed = 0;
141 /* Count of quit chars currently in the queue */
142 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
143 Decremented in mswindows_dequeue_dispatch_event() */
144 int mswindows_quit_chars_count = 0;
146 /* These are Lisp integers; see DEFVARS in this file for description. */
147 int mswindows_dynamic_frame_resize;
148 int mswindows_alt_by_itself_activates_menu;
149 Fixnum mswindows_num_mouse_buttons;
150 Fixnum mswindows_mouse_button_max_skew_x;
151 Fixnum mswindows_mouse_button_max_skew_y;
152 Fixnum mswindows_mouse_button_tolerance;
155 Fixnum debug_mswindows_events;
158 /* This is the event signaled by the event pump.
159 See mswindows_pump_outstanding_events for comments */
160 static Lisp_Object mswindows_error_caught_in_modal_loop;
161 static int mswindows_in_modal_loop;
163 /* Count of wound timers */
164 static int mswindows_pending_timers_count;
166 static DWORD mswindows_last_mouse_button_state;
168 /************************************************************************/
169 /* Pipe instream - reads process output */
170 /************************************************************************/
172 #define PIPE_READ_DELAY 20
174 #define HANDLE_TO_USID(h) ((USID)(h))
176 #define NTPIPE_SLURP_STREAM_DATA(stream) \
177 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
179 /* This structure is allocated by the main thread, and is deallocated
180 in the thread upon exit. There are situations when a thread
181 remains blocked for a long time, much longer than the lstream
182 exists. For example, "start notepad" command is issued from the
183 shell, then the shell is closed by C-c C-d. Although the shell
184 process exits, its output pipe will not get closed until the
185 notepad process exits also, because it inherits the pipe form the
186 shell. In this case, we abandon the thread, and let it live until
187 all such processes exit. While struct ntpipe_slurp_stream is
188 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
190 struct ntpipe_slurp_stream_shared_data
192 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
193 /* This is a manual-reset object. */
194 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
195 /* This is a manual-reset object. */
196 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
197 /* This is a manual-reset object. */
198 HANDLE hpipe; /* Pipe read end handle. */
199 LONG die_p; /* Thread must exit ASAP if non-zero */
200 BOOL eof_p : 1; /* Set when thread saw EOF */
201 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
202 BOOL inuse_p : 1; /* this structure is in use */
203 LONG lock_count; /* Client count of this struct, 0=safe to free */
204 BYTE onebyte; /* One byte buffer read by thread */
207 #define MAX_SLURP_STREAMS 32
208 struct ntpipe_slurp_stream_shared_data
209 shared_data_block[MAX_SLURP_STREAMS]={{0}};
211 struct ntpipe_slurp_stream
213 LPARAM user_data; /* Any user data stored in the stream object */
214 struct ntpipe_slurp_stream_shared_data* thread_data;
217 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
218 sizeof (struct ntpipe_slurp_stream));
220 /* This function is thread-safe, and is called from either thread
221 context. It serializes freeing shared data structure */
223 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
225 if (InterlockedDecrement (&s->lock_count) == 0)
228 CloseHandle (s->hev_thread);
229 CloseHandle (s->hev_caller);
230 CloseHandle (s->hev_unsleep);
235 static struct ntpipe_slurp_stream_shared_data*
236 slurper_allocate_shared_data (void)
239 for (i=0; i<MAX_SLURP_STREAMS; i++)
241 if (!shared_data_block[i].inuse_p)
243 shared_data_block[i].inuse_p=1;
244 return &shared_data_block[i];
247 return (struct ntpipe_slurp_stream_shared_data*)0;
251 slurp_thread (LPVOID vparam)
253 struct ntpipe_slurp_stream_shared_data *s =
254 (struct ntpipe_slurp_stream_shared_data*)vparam;
258 /* Read one byte from the pipe */
260 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
262 DWORD err = GetLastError ();
263 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
268 else if (actually_read == 0)
271 /* We must terminate on an error or eof */
272 if (s->eof_p || s->error_p)
273 InterlockedIncrement (&s->die_p);
275 /* Before we notify caller, we unsignal our event. */
276 ResetEvent (s->hev_thread);
278 /* Now we got something to notify caller, either a byte or an
279 error/eof indication. Before we do, allow internal pipe
280 buffer to accumulate little bit more data.
281 Reader function pulses this event before waiting for
282 a character, to avoid pipe delay, and to get the byte
285 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
287 /* Either make event loop generate a process event, or
289 SetEvent (s->hev_caller);
291 /* Cleanup and exit if we're shot off */
295 /* Block until the client finishes with retrieving the rest of
297 WaitForSingleObject (s->hev_thread, INFINITE);
300 slurper_free_shared_data_maybe (s);
306 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
309 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
310 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
311 DWORD thread_id_unused;
314 /* We deal only with pipes, for we're using PeekNamedPipe api */
315 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
317 s->thread_data = slurper_allocate_shared_data();
319 /* Create reader thread. This could fail, so do not create events
320 until thread is created */
321 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
322 CREATE_SUSPENDED, &thread_id_unused);
325 Lstream_delete (lstr);
326 s->thread_data->inuse_p=0;
330 /* Shared data are initially owned by both main and slurper
332 s->thread_data->lock_count = 2;
333 s->thread_data->die_p = 0;
334 s->thread_data->eof_p = FALSE;
335 s->thread_data->error_p = FALSE;
336 s->thread_data->hpipe = hpipe;
337 s->user_data = param;
339 /* hev_thread is a manual-reset event, initially signaled */
340 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
341 /* hev_caller is a manual-reset event, initially nonsignaled */
342 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
343 /* hev_unsleep is a manual-reset event, initially nonsignaled */
344 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
347 ResumeThread (hthread);
348 CloseHandle (hthread);
350 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
351 XSETLSTREAM (obj, lstr);
356 get_ntpipe_input_stream_param (Lstream *stream)
358 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
363 get_ntpipe_input_stream_waitable (Lstream *stream)
365 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
366 return s->thread_data->hev_caller;
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 &= ~FAKE_MOD_QUIT;
1052 --mswindows_quit_chars_count;
1059 * Remove and return the first emacs event on the dispatch queue that matches
1060 * the supplied event.
1061 * Timeout event matches if interval_id is equal to that of the given event.
1062 * Keypress event matches if logical AND between modifiers bitmask of the
1063 * event in the queue and that of the given event is non-zero.
1064 * For all other event types, this function aborts.
1068 mswindows_cancel_dispatch_event (Lisp_Event *match)
1071 Lisp_Object previous_event = Qnil;
1072 int user_p = mswindows_user_event_p (match);
1073 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1074 &mswindows_s_dispatch_event_queue;
1075 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1076 &mswindows_s_dispatch_event_queue_tail;
1078 assert (match->event_type == timeout_event
1079 || match->event_type == key_press_event);
1081 EVENT_CHAIN_LOOP (event, *head)
1083 Lisp_Event *e = XEVENT (event);
1084 if ((e->event_type == match->event_type) &&
1085 ((e->event_type == timeout_event) ?
1086 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1087 /* Must be key_press_event */
1088 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1090 if (NILP (previous_event))
1091 dequeue_event (head, tail);
1094 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1095 if (EQ (*tail, event))
1096 *tail = previous_event;
1101 previous_event = event;
1106 #ifndef HAVE_MSG_SELECT
1107 /************************************************************************/
1108 /* Waitable handles manipulation */
1109 /************************************************************************/
1111 find_waitable_handle (HANDLE h)
1114 for (i = 0; i < mswindows_waitable_count; ++i)
1115 if (mswindows_waitable_handles[i] == h)
1122 add_waitable_handle (HANDLE h)
1124 assert (find_waitable_handle (h) < 0);
1125 if (mswindows_waitable_count == MAX_WAITABLE)
1128 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1133 remove_waitable_handle (HANDLE h)
1135 int ix = find_waitable_handle (h);
1139 mswindows_waitable_handles [ix] =
1140 mswindows_waitable_handles [--mswindows_waitable_count];
1142 #endif /* HAVE_MSG_SELECT */
1145 /************************************************************************/
1147 /************************************************************************/
1150 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1151 Lisp_Object u_n_u_s_e_d)
1153 mswindows_error_caught_in_modal_loop = cons_sig_data;
1158 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1163 ++mswindows_in_modal_loop;
1164 tmp = condition_case_1 (Qt,
1166 mswindows_modal_loop_error_handler, Qnil);
1167 --mswindows_in_modal_loop;
1173 mswindows_unmodalize_signal_maybe (void)
1175 if (!NILP (mswindows_error_caught_in_modal_loop))
1177 /* Got an error while messages were pumped while
1178 in window procedure - have to resignal */
1179 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1180 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1181 mswindows_error_caught_in_modal_loop = Qnil;
1182 Fsignal (sym, data);
1187 * This is an unsafe part of event pump, guarded by
1188 * condition_case. See mswindows_pump_outstanding_events
1191 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1193 /* This function can call lisp */
1194 Lisp_Object event = Fmake_event (Qnil, Qnil);
1195 struct gcpro gcpro1;
1196 int do_redisplay = 0;
1199 while (detect_input_pending ())
1201 Fnext_event (event, Qnil);
1202 Fdispatch_event (event);
1209 Fdeallocate_event (event);
1212 /* Qt becomes return value of mswindows_pump_outstanding_events
1218 * This function pumps emacs events, while available, by using
1219 * next_message/dispatch_message loop. Errors are trapped around
1220 * the loop so the function always returns.
1222 * Windows message queue is not looked into during the call,
1223 * neither are waitable handles checked. The function pumps
1224 * thus only dispatch events already queued, as well as those
1225 * resulted in dispatching thereof. This is done by setting
1226 * module local variable mswindows_in_modal_loop to nonzero.
1228 * Return value is Qt if no errors was trapped, or Qunbound if
1229 * there was an error.
1231 * In case of error, a cons representing the error, in the
1232 * form (SIGNAL . DATA), is stored in the module local variable
1233 * mswindows_error_caught_in_modal_loop. This error is signaled
1234 * again when DispatchMessage returns. Thus, Windows internal
1235 * modal loops are protected against throws, which are proven
1236 * to corrupt internal Windows structures.
1238 * In case of success, mswindows_error_caught_in_modal_loop is
1241 * If the value of mswindows_error_caught_in_modal_loop is not
1242 * nil already upon entry, the function just returns non-nil.
1243 * This situation means that a new event has been queued while
1244 * in cancel mode. The event will be dequeued on the next regular
1245 * call of next-event; the pump is off since error is caught.
1246 * The caller must *unconditionally* cancel modal loop if the
1247 * value returned by this function is nil. Otherwise, everything
1248 * will become frozen until the modal loop exits under normal
1249 * condition (scrollbar drag is released, menu closed etc.)
1252 mswindows_pump_outstanding_events (void)
1254 /* This function can call lisp */
1256 Lisp_Object result = Qt;
1257 struct gcpro gcpro1;
1260 if (NILP(mswindows_error_caught_in_modal_loop))
1261 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1267 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1268 * QUITP, and are interesting in keyboard messages only.
1271 mswindows_drain_windows_queue (void)
1275 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1276 assert (!mswindows_in_modal_loop);
1278 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1280 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1282 /* Don't translate messages destined for a dialog box, this
1283 makes keyboard traversal work. I think?? */
1284 if (mswindows_is_dialog_msg (&msg))
1286 mswindows_unmodalize_signal_maybe ();
1290 /* We have to translate messages that are not sent to an XEmacs
1291 frame. This is so that key presses work ok in things like
1292 edit fields. However, we *musn't* translate message for XEmacs
1293 frames as this is handled in the wnd proc.
1294 We also have to avoid generating paint magic events for windows
1295 that aren't XEmacs frames */
1296 /* GetClassName will truncate a longer class name. By adding one
1297 extra character, we are forcing textual comparison to fail
1298 if the name is longer than XEMACS_CLASS */
1300 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1301 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1303 /* Not an XEmacs frame */
1304 TranslateMessage (&msg);
1306 else if (msg.message == WM_PAINT)
1308 struct mswindows_frame* msframe;
1310 /* hdc will be NULL unless this is a subwindow - in which case we
1311 shouldn't have received a paint message for it here. */
1312 assert (msg.wParam == 0);
1314 /* Queue a magic event for handling when safe */
1316 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1317 if (!msframe->paint_pending)
1319 msframe->paint_pending = 1;
1320 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1322 /* Don't dispatch. WM_PAINT is always the last message in the
1323 queue so it's OK to just return. */
1326 DispatchMessage (&msg);
1327 mswindows_unmodalize_signal_maybe ();
1332 * This is a special flavor of the mswindows_need_event function,
1333 * used while in event pump. Actually, there is only kind of events
1334 * allowed while in event pump: a timer. An attempt to fetch any
1335 * other event leads to a deadlock, as there's no source of user input
1336 * ('cause event pump mirrors windows modal loop, which is a sole
1337 * owner of thread message queue).
1339 * To detect this, we use a counter of active timers, and allow
1340 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1341 * which will never come when there are no pending timers, which leads
1342 * to deadlock, we simply signal an error.
1345 mswindows_need_event_in_modal_loop (int badly_p)
1349 /* Check if already have one */
1350 if (!NILP (mswindows_u_dispatch_event_queue)
1351 || !NILP (mswindows_s_dispatch_event_queue))
1354 /* No event is ok */
1358 /* We do not check the _u_ queue, because timers go to _s_ */
1359 while (NILP (mswindows_s_dispatch_event_queue))
1361 /* We'll deadlock if go waiting */
1362 if (mswindows_pending_timers_count == 0)
1363 error ("Deadlock due to an attempt to call next-event in a wrong context");
1365 /* Fetch and dispatch any pending timers */
1366 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER);
1367 DispatchMessage (&msg);
1372 * This drains the event queue and fills up two internal queues until
1373 * an event of a type specified by USER_P is retrieved.
1376 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1379 mswindows_need_event (int badly_p)
1383 if (mswindows_in_modal_loop)
1385 mswindows_need_event_in_modal_loop (badly_p);
1389 while (NILP (mswindows_u_dispatch_event_queue)
1390 && NILP (mswindows_s_dispatch_event_queue))
1392 #ifdef HAVE_MSG_SELECT
1394 SELECT_TYPE temp_mask = input_wait_mask;
1395 EMACS_TIME sometime;
1396 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1399 pointer_to_this = 0;
1402 EMACS_SET_SECS_USECS (sometime, 0, 0);
1403 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1404 pointer_to_this = &select_time_to_block;
1407 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1412 return; /* timeout */
1414 else if (active > 0)
1416 if (FD_ISSET (windows_fd, &temp_mask))
1418 mswindows_drain_windows_queue ();
1423 /* Look for a TTY event */
1424 for (i = 0; i < MAXDESC-1; i++)
1426 /* To avoid race conditions (among other things, an infinite
1427 loop when called from Fdiscard_input()), we must return
1428 user events ahead of process events. */
1429 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1431 struct console *c = tty_find_console_from_fd (i);
1432 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1433 Lisp_Event* event = XEVENT (emacs_event);
1436 if (read_event_from_tty_or_stream_desc (event, c, i))
1438 mswindows_enqueue_dispatch_event (emacs_event);
1444 /* Look for a process event */
1445 for (i = 0; i < MAXDESC-1; i++)
1447 if (FD_ISSET (i, &temp_mask))
1449 if (FD_ISSET (i, &process_only_mask))
1452 get_process_from_usid (FD_TO_USID(i));
1454 mswindows_enqueue_process_event (p);
1458 /* We might get here when a fake event came
1459 through a signal. Return a dummy event, so
1460 that a cycle of the command loop will
1462 drain_signal_event_pipe ();
1463 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1469 else if (active==-1)
1473 /* something bad happened */
1482 /* Now try getting a message or process event */
1483 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1484 mswindows_waitable_handles,
1485 FALSE, badly_p ? INFINITE : 0,
1488 /* This will assert if handle being waited for becomes abandoned.
1489 Not the case currently tho */
1490 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1491 (active >= WAIT_OBJECT_0 &&
1492 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1494 if (active == WAIT_TIMEOUT)
1496 /* No luck trying - just return what we've already got */
1499 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1501 /* Got your message, thanks */
1502 mswindows_drain_windows_queue ();
1506 int ix = active - WAIT_OBJECT_0;
1507 /* First, try to find which process' output has signaled */
1509 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1512 /* Found a signaled process input handle */
1513 mswindows_enqueue_process_event (p);
1517 /* None. This means that the process handle itself has signaled.
1518 Remove the handle from the wait vector, and make status_notify
1519 note the exited process */
1520 mswindows_waitable_handles [ix] =
1521 mswindows_waitable_handles [--mswindows_waitable_count];
1522 kick_status_notify ();
1523 /* We need to return a process event here so that
1524 (1) accept-process-output will return when called on this
1525 process, and (2) status notifications will happen in
1526 accept-process-output, sleep-for, and sit-for. */
1527 /* #### horrible kludge till my real process fixes go in.
1529 if (!NILP (Vprocess_list))
1531 Lisp_Object vaffanculo = XCAR (Vprocess_list);
1532 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1534 else /* trash me soon. */
1535 /* Have to return something: there may be no accompanying
1537 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1544 /************************************************************************/
1545 /* Event generators */
1546 /************************************************************************/
1549 * Callback procedure for synchronous timer messages
1551 static void CALLBACK
1552 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1554 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1555 Lisp_Event *event = XEVENT (emacs_event);
1557 if (KillTimer (NULL, id_timer))
1558 --mswindows_pending_timers_count;
1560 event->channel = Qnil;
1561 event->timestamp = dwtime;
1562 event->event_type = timeout_event;
1563 event->event.timeout.interval_id = id_timer;
1564 event->event.timeout.function = Qnil;
1565 event->event.timeout.object = Qnil;
1567 mswindows_enqueue_dispatch_event (emacs_event);
1571 * Callback procedure for dde messages
1573 * We execute a dde Open("file") by simulating a file drop, so dde support
1574 * depends on dnd support.
1576 #ifdef HAVE_DRAGNDROP
1578 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1579 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1580 DWORD dwData1, DWORD dwData2)
1585 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1586 return (HDDEDATA)TRUE;
1587 return (HDDEDATA)FALSE;
1589 case XTYP_WILDCONNECT:
1591 /* We only support one {service,topic} pair */
1592 HSZPAIR pairs[2] = {
1593 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1595 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1596 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1597 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1598 sizeof (pairs), 0L, 0, uFmt, 0));
1600 return (HDDEDATA)NULL;
1603 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1605 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1606 LPBYTE cmd = (LPBYTE) alloca (len+1);
1609 struct gcpro gcpro1, gcpro2;
1610 Lisp_Object l_dndlist = Qnil;
1611 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1612 Lisp_Object frmcons, devcons, concons;
1613 Lisp_Event *event = XEVENT (emacs_event);
1615 DdeGetData (hdata, cmd, len, 0);
1617 DdeFreeDataHandle (hdata);
1619 /* Check syntax & that it's an [Open("foo")] command, which we
1620 * treat like a file drop */
1621 /* #### Ought to be generalised and accept some other commands */
1624 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1625 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1626 return DDE_FNOTPROCESSED;
1627 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1630 if (*cmd!='(' || *(cmd+1)!='\"')
1631 return DDE_FNOTPROCESSED;
1633 while (*end && *end!='\"')
1636 return DDE_FNOTPROCESSED;
1639 return DDE_FNOTPROCESSED;
1643 return DDE_FNOTPROCESSED;
1646 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1647 strcpy (filename, "file:");
1648 cygwin32_win32_to_posix_path_list (cmd, filename+5);
1650 dostounix_filename (cmd);
1651 filename = alloca (strlen (cmd)+6);
1652 strcpy (filename, "file:");
1653 strcat (filename, cmd);
1655 GCPRO2 (emacs_event, l_dndlist);
1656 l_dndlist = make_string (filename, strlen (filename));
1658 /* Find a mswindows frame */
1659 event->channel = Qnil;
1660 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1662 Lisp_Object frame = XCAR (frmcons);
1663 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1664 event->channel = frame;
1666 assert (!NILP (event->channel));
1668 event->timestamp = GetTickCount();
1669 event->event_type = misc_user_event;
1670 event->event.misc.button = 1;
1671 event->event.misc.modifiers = 0;
1672 event->event.misc.x = -1;
1673 event->event.misc.y = -1;
1674 event->event.misc.function = Qdragdrop_drop_dispatch;
1675 event->event.misc.object = Fcons (Qdragdrop_URL,
1676 Fcons (l_dndlist, Qnil));
1677 mswindows_enqueue_dispatch_event (emacs_event);
1679 return (HDDEDATA) DDE_FACK;
1681 DdeFreeDataHandle (hdata);
1682 return (HDDEDATA) DDE_FNOTPROCESSED;
1685 return (HDDEDATA) NULL;
1691 * Helper to do repainting - repaints can happen both from the windows
1692 * procedure and from magic events
1695 mswindows_handle_paint (struct frame *frame)
1697 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1699 /* According to the docs we need to check GetUpdateRect() before
1700 actually doing a WM_PAINT */
1701 if (GetUpdateRect (hwnd, NULL, FALSE))
1703 PAINTSTRUCT paintStruct;
1704 int x, y, width, height;
1706 BeginPaint (hwnd, &paintStruct);
1707 x = paintStruct.rcPaint.left;
1708 y = paintStruct.rcPaint.top;
1709 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1710 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1711 /* Normally we want to ignore expose events when child
1712 windows are unmapped, however once we are in the guts of
1713 WM_PAINT we need to make sure that we don't register
1714 unmaps then because they will not actually occur. */
1715 /* #### commenting out the next line seems to fix some problems
1716 but not all. only andy currently understands this stuff and
1717 he needs to review it more carefully. --ben */
1718 if (!check_for_ignored_expose (frame, x, y, width, height))
1720 hold_ignored_expose_registration = 1;
1721 mswindows_redraw_exposed_area (frame, x, y, width, height);
1722 hold_ignored_expose_registration = 0;
1724 EndPaint (hwnd, &paintStruct);
1729 * Returns 1 if a key is a real modifier or special key, which
1730 * is better handled by DefWindowProc
1733 key_needs_default_processing_p (UINT vkey)
1735 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1736 /* if we let ALT activate the menu like this, then sticky ALT-modified
1737 keystrokes become impossible. */
1738 && !modifier_keys_are_sticky)
1744 /* key-handling code is always ugly. It just ends up working out
1747 #### Most of the sticky-modifier code below is copied from similar
1748 code in event-Xt.c. They should somehow or other be merged.
1750 Here are some pointers:
1752 -- DOWN_MASK indicates which modifiers should be treated as "down"
1753 when the corresponding upstroke happens. It gets reset for
1754 a particular modifier when that modifier goes up, and reset
1755 for all modifiers when a non-modifier key is pressed. Example:
1757 I press Control-A-Shift and then release Control-A-Shift.
1758 I want the Shift key to be sticky but not the Control key.
1760 -- If a modifier key is sticky, I can unstick it by pressing
1761 the modifier key again. */
1763 static WPARAM last_downkey;
1764 static int need_to_add_mask, down_mask;
1766 #define XEMSW_LCONTROL (1<<0)
1767 #define XEMSW_RCONTROL (1<<1)
1768 #define XEMSW_LSHIFT (1<<2)
1769 #define XEMSW_RSHIFT (1<<3)
1770 #define XEMSW_LMENU (1<<4)
1771 #define XEMSW_RMENU (1<<5)
1774 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1775 int downp, int keyp)
1779 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1783 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1784 wParam == VK_RCONTROL ||
1785 wParam == VK_MENU || wParam == VK_LMENU ||
1786 wParam == VK_RMENU ||
1787 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1788 wParam == VK_RSHIFT)))
1789 { /* Not a modifier key */
1790 if (downp && keyp && !last_downkey)
1791 last_downkey = wParam;
1792 /* If I hold press-and-release the Control key and then press
1793 and hold down the right arrow, I want it to auto-repeat
1794 Control-Right. On the other hand, if I do the same but
1795 manually press the Right arrow a bunch of times, I want
1796 to see one Control-Right and then a bunch of Rights.
1797 This means that we need to distinguish between an
1798 auto-repeated key and a key pressed and released a bunch
1800 else if ((downp && !keyp) ||
1801 (downp && keyp && last_downkey &&
1802 (wParam != last_downkey ||
1803 /* the "previous key state" bit indicates autorepeat */
1804 ! (lParam & (1 << 30)))))
1806 need_to_add_mask = 0;
1812 mods = need_to_add_mask;
1814 else /* Modifier key pressed */
1816 /* If a non-modifier key was pressed in the middle of a bunch
1817 of modifiers, then it unsticks all the modifiers that were
1818 previously pressed. We cannot unstick the modifiers until
1819 now because we want to check for auto-repeat of the
1820 non-modifier key. */
1825 need_to_add_mask = 0;
1828 #define FROB(mask) \
1830 if (downp && keyp) \
1832 /* If modifier key is already sticky, \
1833 then unstick it. Note that we do \
1834 not test down_mask to deal with the \
1835 unlikely but possible case that the \
1836 modifier key auto-repeats. */ \
1837 if (need_to_add_mask & mask) \
1839 need_to_add_mask &= ~mask; \
1840 down_mask &= ~mask; \
1843 down_mask |= mask; \
1847 if (down_mask & mask) \
1849 down_mask &= ~mask; \
1850 need_to_add_mask |= mask; \
1855 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1856 || wParam == VK_RCONTROL)
1857 FROB (XEMSW_RCONTROL);
1858 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1859 || wParam == VK_LCONTROL)
1860 FROB (XEMSW_LCONTROL);
1862 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1863 || wParam == VK_RSHIFT)
1864 FROB (XEMSW_RSHIFT);
1865 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1866 || wParam == VK_LSHIFT)
1867 FROB (XEMSW_LSHIFT);
1869 if ((wParam == VK_MENU && (lParam & 0x1000000))
1870 || wParam == VK_RMENU)
1872 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1873 || wParam == VK_LMENU)
1882 GetKeyboardState (keymap);
1884 if (mods & XEMSW_LCONTROL)
1886 keymap [VK_CONTROL] |= 0x80;
1887 keymap [VK_LCONTROL] |= 0x80;
1889 if (mods & XEMSW_RCONTROL)
1891 keymap [VK_CONTROL] |= 0x80;
1892 keymap [VK_RCONTROL] |= 0x80;
1895 if (mods & XEMSW_LSHIFT)
1897 keymap [VK_SHIFT] |= 0x80;
1898 keymap [VK_LSHIFT] |= 0x80;
1900 if (mods & XEMSW_RSHIFT)
1902 keymap [VK_SHIFT] |= 0x80;
1903 keymap [VK_RSHIFT] |= 0x80;
1906 if (mods & XEMSW_LMENU)
1908 keymap [VK_MENU] |= 0x80;
1909 keymap [VK_LMENU] |= 0x80;
1911 if (mods & XEMSW_RMENU)
1913 keymap [VK_MENU] |= 0x80;
1914 keymap [VK_RMENU] |= 0x80;
1917 SetKeyboardState (keymap);
1925 clear_sticky_modifiers (void)
1927 need_to_add_mask = 0;
1937 output_modifier_keyboard_state (void)
1941 GetKeyboardState (keymap);
1943 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1944 keymap[VK_MENU] & 0x80 ? 1 : 0,
1945 keymap[VK_MENU] & 0x1 ? 1 : 0,
1946 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1947 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1948 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1949 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1950 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1951 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1952 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1953 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1954 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1955 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1956 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1957 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1958 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1959 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1960 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1961 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1962 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1963 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
1968 /* try to debug the stuck-alt-key problem.
1970 #### this happens only inconsistently, and may only happen when using
1971 StickyKeys in the Win2000 accessibility section of the control panel,
1972 which is extremely broken for other reasons. */
1975 output_alt_keyboard_state (void)
1979 // SHORT asyncstate[3];
1981 GetKeyboardState (keymap);
1982 keystate[0] = GetKeyState (VK_MENU);
1983 keystate[1] = GetKeyState (VK_LMENU);
1984 keystate[2] = GetKeyState (VK_RMENU);
1985 /* Doing this interferes with key processing. */
1986 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
1987 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
1988 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
1990 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1991 keymap[VK_MENU] & 0x80 ? 1 : 0,
1992 keymap[VK_MENU] & 0x1 ? 1 : 0,
1993 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1994 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1995 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1996 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1997 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1998 keystate[0] & 0x8000 ? 1 : 0,
1999 keystate[0] & 0x1 ? 1 : 0,
2000 keystate[1] & 0x8000 ? 1 : 0,
2001 keystate[1] & 0x1 ? 1 : 0,
2002 keystate[2] & 0x8000 ? 1 : 0,
2003 keystate[2] & 0x1 ? 1 : 0);
2004 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2005 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2006 /* asyncstate[0] & 0x1 ? 1 : 0, */
2007 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2008 /* asyncstate[1] & 0x1 ? 1 : 0, */
2009 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2010 /* asyncstate[2] & 0x1 ? 1 : 0); */
2013 #endif /* DEBUG_XEMACS */
2017 * The windows procedure for the window class XEMACS_CLASS
2020 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2022 /* Note: Remember to initialize emacs_event and event before use.
2023 This code calls code that can GC. You must GCPRO before calling such code. */
2024 Lisp_Object emacs_event = Qnil;
2025 Lisp_Object fobj = Qnil;
2028 struct frame *frame;
2029 struct mswindows_frame* msframe;
2031 /* Not perfect but avoids crashes. There is potential for wierd
2036 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2039 case WM_DESTROYCLIPBOARD:
2040 /* We own the clipboard and someone else wants it. Delete our
2041 cached copy of the clipboard contents so we'll ask for it from
2042 Windows again when someone does a paste, and destroy any memory
2043 objects we hold on the clipboard that are not in the list of types
2044 that Windows will delete itself. */
2045 mswindows_destroy_selection (QCLIPBOARD);
2046 handle_selection_clear (QCLIPBOARD);
2050 /* Erase background only during non-dynamic sizing */
2051 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2052 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2057 fobj = mswindows_find_frame (hwnd);
2058 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2064 /* See Win95 comment under WM_KEYDOWN */
2067 int should_set_keymap = 0;
2070 if (debug_mswindows_events)
2072 stderr_out ("%s wparam=%d lparam=%d\n",
2073 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP",
2074 wParam, (int)lParam);
2075 output_alt_keyboard_state ();
2077 #endif /* DEBUG_XEMACS */
2079 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2080 if (wParam == VK_CONTROL)
2082 GetKeyboardState (keymap);
2083 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2084 should_set_keymap = 1;
2086 else if (wParam == VK_MENU)
2088 GetKeyboardState (keymap);
2089 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2090 should_set_keymap = 1;
2093 if (should_set_keymap)
2094 // && (message_ != WM_SYSKEYUP
2095 // || NILP (Vmenu_accelerator_enabled)))
2096 SetKeyboardState (keymap);
2100 if (key_needs_default_processing_p (wParam))
2108 /* In some locales the right-hand Alt key is labelled AltGr. This key
2109 * should produce alternative characters when combined with another key.
2110 * eg on a German keyboard pressing AltGr+q should produce '@'.
2111 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2112 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2113 * it translates as if AltGr were down.
2114 * We get round this by removing all modifiers from the keymap before
2115 * calling TranslateMessage() unless AltGr is *really* down. */
2117 BYTE keymap_trans[256];
2118 BYTE keymap_orig[256];
2119 BYTE keymap_sticky[256];
2120 int has_AltGr = mswindows_current_layout_has_AltGr ();
2122 int extendedp = lParam & 0x1000000;
2127 if (debug_mswindows_events)
2129 stderr_out ("%s wparam=%d lparam=%d\n",
2130 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN",
2131 wParam, (int)lParam);
2132 output_alt_keyboard_state ();
2134 #endif /* DEBUG_XEMACS */
2136 GetKeyboardState (keymap_orig);
2137 frame = XFRAME (mswindows_find_frame (hwnd));
2138 if ((sticky_changed =
2139 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2141 GetKeyboardState (keymap_sticky);
2142 if (keymap_sticky[VK_MENU] & 0x80)
2144 message_ = WM_SYSKEYDOWN;
2145 /* We have to set the "context bit" so that the
2146 TranslateMessage() call below that generates the
2147 SYSCHAR message does its thing; see the documentation
2153 memcpy (keymap_sticky, keymap_orig, 256);
2155 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2157 /* Handle non-printables */
2158 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2161 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2163 SetKeyboardState (keymap_orig);
2165 else /* Normal keys & modifiers */
2168 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2169 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2171 int potential_accelerator = 0;
2172 int got_accelerator = 0;
2175 msg.message = message_;
2176 msg.wParam = wParam;
2177 msg.lParam = lParam;
2178 msg.time = GetMessageTime();
2181 /* GetKeyboardState() does not work as documented on Win95. We have
2182 * to loosely track Left and Right modifiers on behalf of the OS,
2183 * without screwing up Windows NT which tracks them properly. */
2184 if (wParam == VK_CONTROL)
2186 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2187 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2189 else if (wParam == VK_MENU)
2191 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2192 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2195 if (!NILP (Vmenu_accelerator_enabled) &&
2196 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2197 potential_accelerator = 1;
2199 /* Remove shift modifier from an ascii character */
2200 mods &= ~XEMACS_MOD_SHIFT;
2202 memcpy (keymap_trans, keymap_sticky, 256);
2204 /* Clear control and alt modifiers unless AltGr is pressed */
2205 keymap_trans[VK_RCONTROL] = 0;
2206 keymap_trans[VK_LMENU] = 0;
2207 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2208 || !(keymap_trans[VK_RMENU] & 0x80))
2210 keymap_trans[VK_LCONTROL] = 0;
2211 keymap_trans[VK_CONTROL] = 0;
2212 keymap_trans[VK_RMENU] = 0;
2213 keymap_trans[VK_MENU] = 0;
2215 SetKeyboardState (keymap_trans);
2217 /* Maybe generate some WM_[SYS]CHARs in the queue */
2218 TranslateMessage (&msg);
2220 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2221 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2225 WPARAM ch = tranmsg.wParam;
2227 /* If a quit char with no modifiers other than control and
2228 shift, then mark it with a fake modifier, which is removed
2229 upon dequeueing the event */
2230 /* #### This might also not withstand localization, if
2231 quit character is not a latin-1 symbol */
2232 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2233 && quit_ch + 'a' - 1 == ch)
2234 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2236 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2239 mods1 |= FAKE_MOD_QUIT;
2240 ++mswindows_quit_chars_count;
2242 else if (potential_accelerator && !got_accelerator &&
2243 mswindows_char_is_accelerator (frame, ch))
2245 got_accelerator = 1;
2248 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1);
2251 /* This generates WM_SYSCHAR messages, which are interpreted
2252 by DefWindowProc as the menu selections. */
2253 if (got_accelerator)
2255 SetKeyboardState (keymap_sticky);
2256 TranslateMessage (&msg);
2257 SetKeyboardState (keymap_orig);
2261 SetKeyboardState (keymap_orig);
2265 if (key_needs_default_processing_p (wParam))
2270 case WM_MBUTTONDOWN:
2272 /* Real middle mouse button has nothing to do with emulated one:
2273 if one wants to exercise fingers playing chords on the mouse,
2274 he is allowed to do that! */
2275 mswindows_enqueue_mouse_button_event (hwnd, message_,
2276 MAKEPOINTS (lParam),
2277 wParam &~ MK_MBUTTON,
2282 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2283 msframe->last_click_time = GetMessageTime();
2285 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2286 msframe->button2_need_lbutton = 0;
2287 if (msframe->ignore_next_lbutton_up)
2289 msframe->ignore_next_lbutton_up = 0;
2291 else if (msframe->button2_is_down)
2293 msframe->button2_is_down = 0;
2294 msframe->ignore_next_rbutton_up = 1;
2295 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2296 MAKEPOINTS (lParam),
2298 &~ (MK_LBUTTON | MK_MBUTTON
2304 if (msframe->button2_need_rbutton)
2306 msframe->button2_need_rbutton = 0;
2307 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2308 MAKEPOINTS (lParam),
2309 wParam &~ MK_LBUTTON,
2312 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2313 MAKEPOINTS (lParam),
2314 wParam &~ MK_LBUTTON,
2320 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2321 msframe->last_click_time = GetMessageTime();
2323 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2324 msframe->button2_need_rbutton = 0;
2325 if (msframe->ignore_next_rbutton_up)
2327 msframe->ignore_next_rbutton_up = 0;
2329 else if (msframe->button2_is_down)
2331 msframe->button2_is_down = 0;
2332 msframe->ignore_next_lbutton_up = 1;
2333 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2334 MAKEPOINTS (lParam),
2336 &~ (MK_LBUTTON | MK_MBUTTON
2342 if (msframe->button2_need_lbutton)
2344 msframe->button2_need_lbutton = 0;
2345 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2346 MAKEPOINTS (lParam),
2347 wParam &~ MK_RBUTTON,
2350 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2351 MAKEPOINTS (lParam),
2352 wParam &~ MK_RBUTTON,
2357 case WM_LBUTTONDOWN:
2358 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2360 if (msframe->button2_need_lbutton)
2362 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2363 msframe->button2_need_lbutton = 0;
2364 msframe->button2_need_rbutton = 0;
2365 if (mswindows_button2_near_enough (msframe->last_click_point,
2366 MAKEPOINTS (lParam)))
2368 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2369 MAKEPOINTS (lParam),
2371 &~ (MK_LBUTTON | MK_MBUTTON
2374 msframe->button2_is_down = 1;
2378 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2379 msframe->last_click_point,
2380 msframe->last_click_mods
2382 msframe->last_click_time);
2383 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2384 MAKEPOINTS (lParam),
2385 wParam &~ MK_LBUTTON,
2391 mswindows_set_chord_timer (hwnd);
2392 msframe->button2_need_rbutton = 1;
2393 msframe->last_click_point = MAKEPOINTS (lParam);
2394 msframe->last_click_mods = wParam;
2396 msframe->last_click_time = GetMessageTime();
2399 case WM_RBUTTONDOWN:
2400 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2402 if (msframe->button2_need_rbutton)
2404 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2405 msframe->button2_need_lbutton = 0;
2406 msframe->button2_need_rbutton = 0;
2407 if (mswindows_button2_near_enough (msframe->last_click_point,
2408 MAKEPOINTS (lParam)))
2410 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2411 MAKEPOINTS (lParam),
2413 &~ (MK_LBUTTON | MK_MBUTTON
2416 msframe->button2_is_down = 1;
2420 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2421 msframe->last_click_point,
2422 msframe->last_click_mods
2424 msframe->last_click_time);
2425 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2426 MAKEPOINTS (lParam),
2427 wParam &~ MK_RBUTTON,
2433 mswindows_set_chord_timer (hwnd);
2434 msframe->button2_need_lbutton = 1;
2435 msframe->last_click_point = MAKEPOINTS (lParam);
2436 msframe->last_click_mods = wParam;
2438 msframe->last_click_time = GetMessageTime();
2442 if (wParam == BUTTON_2_TIMER_ID)
2444 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2445 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2447 if (msframe->button2_need_lbutton)
2449 msframe->button2_need_lbutton = 0;
2450 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2451 msframe->last_click_point,
2452 msframe->last_click_mods
2454 msframe->last_click_time);
2456 else if (msframe->button2_need_rbutton)
2458 msframe->button2_need_rbutton = 0;
2459 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2460 msframe->last_click_point,
2461 msframe->last_click_mods
2463 msframe->last_click_time);
2467 assert ("Spurious timer fired" == 0);
2471 /* Optimization: don't report mouse movement while size is changing */
2472 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2473 if (!msframe->sizing)
2475 /* When waiting for the second mouse button to finish
2476 button2 emulation, and have moved too far, just pretend
2477 as if timer has expired. This improves drag-select feedback */
2478 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2479 && !mswindows_button2_near_enough (msframe->last_click_point,
2480 MAKEPOINTS (lParam)))
2482 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2483 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2486 emacs_event = Fmake_event (Qnil, Qnil);
2487 event = XEVENT(emacs_event);
2489 event->channel = mswindows_find_frame(hwnd);
2490 event->timestamp = GetMessageTime();
2491 event->event_type = pointer_motion_event;
2492 event->event.motion.x = MAKEPOINTS(lParam).x;
2493 event->event.motion.y = MAKEPOINTS(lParam).y;
2494 event->event.motion.modifiers =
2495 mswindows_modifier_state (NULL, wParam, 0);
2497 mswindows_enqueue_dispatch_event (emacs_event);
2503 /* Queue a `cancel-mode-internal' misc user event, so mouse
2504 selection would be canceled if any */
2505 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2506 Qcancel_mode_internal, Qnil);
2511 LPNMHDR nmhdr = (LPNMHDR)lParam;
2513 if (nmhdr->code == TTN_NEEDTEXT)
2515 #ifdef HAVE_TOOLBARS
2516 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2519 /* find out which toolbar */
2520 frame = XFRAME (mswindows_find_frame (hwnd));
2521 btext = mswindows_get_toolbar_button_text ( frame,
2524 tttext->lpszText = NULL;
2525 tttext->hinst = NULL;
2529 /* I think this is safe since the text will only go away
2530 when the toolbar does...*/
2531 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2535 /* handle tree view callbacks */
2536 else if (nmhdr->code == TVN_SELCHANGED)
2538 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2539 frame = XFRAME (mswindows_find_frame (hwnd));
2540 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2542 /* handle tab control callbacks */
2543 else if (nmhdr->code == TCN_SELCHANGE)
2546 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2547 frame = XFRAME (mswindows_find_frame (hwnd));
2549 item.mask = TCIF_PARAM;
2550 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2553 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2559 /* hdc will be NULL unless this is a subwindow - in which case we
2560 shouldn't have received a paint message for it here. */
2561 assert (wParam == 0);
2563 /* Can't queue a magic event because windows goes modal and sends paint
2564 messages directly to the windows procedure when doing solid drags
2565 and the message queue doesn't get processed. */
2566 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2570 /* We only care about this message if our size has really changed */
2571 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2576 fobj = mswindows_find_frame (hwnd);
2577 frame = XFRAME (fobj);
2578 msframe = FRAME_MSWINDOWS_DATA (frame);
2580 /* We cannot handle frame map and unmap hooks right in
2581 this routine, because these may throw. We queue
2582 magic events to run these hooks instead - kkm */
2584 if (wParam==SIZE_MINIMIZED)
2587 FRAME_VISIBLE_P (frame) = 0;
2588 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2592 GetClientRect(hwnd, &rect);
2593 FRAME_PIXWIDTH(frame) = rect.right;
2594 FRAME_PIXHEIGHT(frame) = rect.bottom;
2596 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2597 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2598 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2600 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2601 change_frame_size (frame, rows, columns, 1);
2603 /* If we are inside frame creation, we have to apply geometric
2605 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2607 /* Yes, we have to size again */
2608 mswindows_size_frame_internal ( frame,
2609 FRAME_MSWINDOWS_TARGET_RECT
2611 /* Reset so we do not get here again. The SetWindowPos call in
2612 * mswindows_size_frame_internal can cause recursion here. */
2613 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2615 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2616 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2621 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2622 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2623 FRAME_VISIBLE_P (frame) = 1;
2625 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2632 case WM_DISPLAYCHANGE:
2635 DWORD message_tick = GetMessageTime ();
2637 fobj = mswindows_find_frame (hwnd);
2638 frame = XFRAME (fobj);
2639 d = XDEVICE (FRAME_DEVICE (frame));
2641 /* Do this only once per message. XEmacs can receive this message
2642 through as many frames as it currently has open. Message time
2643 will be the same for all these messages. Despite extreme
2644 efficiency, the code below has about one in 4 billion
2645 probability that the HDC is not recreated, provided that
2646 XEmacs is running sufficiently longer than 52 days. */
2647 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2649 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2650 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2651 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2656 /* Misc magic events which only require that the frame be identified */
2659 mswindows_enqueue_magic_event (hwnd, message_);
2662 case WM_WINDOWPOSCHANGING:
2664 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2665 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2666 GetWindowPlacement(hwnd, &wpl);
2668 /* Only interested if size is changing and we're not being iconified */
2669 if (wpl.showCmd != SW_SHOWMINIMIZED
2670 && wpl.showCmd != SW_SHOWMAXIMIZED
2671 && !(wp->flags & SWP_NOSIZE))
2673 RECT ncsize = { 0, 0, 0, 0 };
2674 int pixwidth, pixheight;
2675 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2676 GetMenu(hwnd) != NULL,
2677 GetWindowLong (hwnd, GWL_EXSTYLE));
2679 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2680 wp->cx - (ncsize.right - ncsize.left),
2681 wp->cy - (ncsize.bottom - ncsize.top),
2682 &pixwidth, &pixheight);
2684 /* Convert client sizes to window sizes */
2685 pixwidth += (ncsize.right - ncsize.left);
2686 pixheight += (ncsize.bottom - ncsize.top);
2688 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2690 /* Adjust so that the bottom or right doesn't move if it's
2691 * the top or left that's being changed */
2693 GetWindowRect (hwnd, &rect);
2695 if (rect.left != wp->x)
2696 wp->x += wp->cx - pixwidth;
2697 if (rect.top != wp->y)
2698 wp->y += wp->cy - pixheight;
2704 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2705 window position if the user tries to track window too small */
2709 case WM_ENTERSIZEMOVE:
2710 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2711 msframe->sizing = 1;
2714 case WM_EXITSIZEMOVE:
2715 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2716 msframe->sizing = 0;
2717 /* Queue noop event */
2718 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2721 #ifdef HAVE_SCROLLBARS
2725 /* Direction of scroll is determined by scrollbar instance. */
2726 int code = (int) LOWORD(wParam);
2727 int pos = (short int) HIWORD(wParam);
2728 HWND hwndScrollBar = (HWND) lParam;
2729 struct gcpro gcpro1, gcpro2;
2731 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2732 GCPRO2 (emacs_event, fobj);
2733 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2735 /* Error during event pumping - cancel scroll */
2736 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2744 int keys = LOWORD (wParam); /* Modifier key flags */
2745 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2746 struct gcpro gcpro1, gcpro2;
2748 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta))
2750 GCPRO2 (emacs_event, fobj);
2751 mswindows_pump_outstanding_events (); /* Can GC */
2760 #ifdef HAVE_MENUBARS
2762 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2764 XFRAME (mswindows_find_frame (hwnd)))))
2765 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2768 case WM_INITMENUPOPUP:
2769 if (!HIWORD(lParam))
2771 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2773 XFRAME (mswindows_find_frame (hwnd)))))
2774 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2778 #endif /* HAVE_MENUBARS */
2782 WORD id = LOWORD (wParam);
2783 WORD nid = HIWORD (wParam);
2784 HWND cid = (HWND)lParam;
2785 frame = XFRAME (mswindows_find_frame (hwnd));
2787 #ifdef HAVE_TOOLBARS
2788 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2791 /* widgets in a buffer only eval a callback for suitable events.*/
2796 case CBN_EDITCHANGE:
2798 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2801 /* menubars always must come last since the hashtables do not
2803 #ifdef HAVE_MENUBARS
2804 if (!NILP (mswindows_handle_wm_command (frame, id)))
2808 return DefWindowProc (hwnd, message_, wParam, lParam);
2809 /* Bite me - a spurious command. This used to not be able to
2810 happen but with the introduction of widgets its now
2815 case WM_CTLCOLORBTN:
2816 case WM_CTLCOLORLISTBOX:
2817 case WM_CTLCOLOREDIT:
2818 case WM_CTLCOLORSTATIC:
2819 case WM_CTLCOLORSCROLLBAR:
2821 /* if we get an opportunity to paint a widget then do so if
2822 there is an appropriate face */
2823 HWND crtlwnd = (HWND)lParam;
2824 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2827 Lisp_Object image_instance;
2828 VOID_TO_LISP (image_instance, ii);
2829 if (IMAGE_INSTANCEP (image_instance)
2831 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2833 /* set colors for the buttons */
2834 HDC hdc = (HDC)wParam;
2835 if (last_widget_brushed != ii)
2838 DeleteObject (widget_brush);
2839 widget_brush = CreateSolidBrush
2840 (COLOR_INSTANCE_MSWINDOWS_COLOR
2843 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2844 XIMAGE_INSTANCE_FRAME (image_instance)))));
2846 last_widget_brushed = ii;
2849 COLOR_INSTANCE_MSWINDOWS_COLOR
2852 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2853 XIMAGE_INSTANCE_FRAME (image_instance)))));
2854 SetBkMode (hdc, OPAQUE);
2857 COLOR_INSTANCE_MSWINDOWS_COLOR
2860 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2861 XIMAGE_INSTANCE_FRAME (image_instance)))));
2862 return (LRESULT)widget_brush;
2868 #ifdef HAVE_DRAGNDROP
2869 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2871 UINT filecount, i, len;
2876 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2877 struct gcpro gcpro1, gcpro2, gcpro3;
2879 emacs_event = Fmake_event (Qnil, Qnil);
2880 event = XEVENT(emacs_event);
2882 GCPRO3 (emacs_event, l_dndlist, l_item);
2884 if (!DragQueryPoint ((HDROP) wParam, &point))
2885 point.x = point.y = -1; /* outside client area */
2887 event->event_type = misc_user_event;
2888 event->channel = mswindows_find_frame(hwnd);
2889 event->timestamp = GetMessageTime();
2890 event->event.misc.button = 1; /* #### Should try harder */
2891 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2893 event->event.misc.x = point.x;
2894 event->event.misc.y = point.y;
2895 event->event.misc.function = Qdragdrop_drop_dispatch;
2897 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2898 for (i=0; i<filecount; i++)
2900 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2901 /* The URLs that we make here aren't correct according to section
2902 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2903 * because they may contain reserved characters. But that's OK -
2904 * they just need to be good enough to keep dragdrop.el happy. */
2905 fname = (char *)xmalloc (len+1);
2906 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2908 /* May be a shell link aka "shortcut" - replace fname if so */
2909 #if !(defined(CYGWIN) || defined(MINGW))
2910 /* cygwin doesn't define this COM stuff */
2911 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2915 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2916 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2920 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
2924 WIN32_FIND_DATA wfd;
2925 LPSTR resolved = (char *) xmalloc (MAX_PATH+1);
2927 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH);
2929 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
2930 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH,
2935 len = strlen (fname);
2938 ppf->lpVtbl->Release (ppf);
2941 psl->lpVtbl->Release (psl);
2947 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2948 strcpy (filename, "file:");
2949 cygwin32_win32_to_posix_path_list (fname, filename+5);
2951 filename = (char *)xmalloc (len+6);
2952 strcat (strcpy (filename, "file:"), fname);
2953 dostounix_filename (filename+5);
2956 l_item = make_string (filename, strlen (filename));
2957 l_dndlist = Fcons (l_item, l_dndlist);
2960 DragFinish ((HDROP) wParam);
2962 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2963 mswindows_enqueue_dispatch_event (emacs_event);
2971 return DefWindowProc (hwnd, message_, wParam, lParam);
2977 /************************************************************************/
2978 /* keyboard, mouse & other helpers for the windows procedure */
2979 /************************************************************************/
2981 mswindows_set_chord_timer (HWND hwnd)
2985 /* We get one third half system double click threshold */
2986 if (mswindows_mouse_button_tolerance <= 0)
2987 interval = GetDoubleClickTime () / 3;
2989 interval = mswindows_mouse_button_tolerance;
2991 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2995 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2998 if (mswindows_mouse_button_max_skew_x <= 0)
2999 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3001 dx = mswindows_mouse_button_max_skew_x;
3003 if (mswindows_mouse_button_max_skew_y <= 0)
3004 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3006 dy = mswindows_mouse_button_max_skew_y;
3008 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3012 mswindows_current_layout_has_AltGr (void)
3014 /* This simple caching mechanism saves 10% of CPU
3015 time when a key typed at autorepeat rate of 30 cps! */
3016 static HKL last_hkl = 0;
3017 static int last_hkl_has_AltGr;
3018 HKL current_hkl = (HKL) -1;
3020 if (xGetKeyboardLayout) /* not in NT 3.5 */
3021 current_hkl = xGetKeyboardLayout (0);
3022 if (current_hkl != last_hkl)
3025 last_hkl_has_AltGr = 0;
3026 /* In this loop, we query whether a character requires
3027 AltGr to be down to generate it. If at least such one
3028 found, this means that the layout does regard AltGr */
3029 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3030 if (HIBYTE (VkKeyScan (c)) == 6)
3031 last_hkl_has_AltGr = 1;
3032 last_hkl = current_hkl;
3034 return last_hkl_has_AltGr;
3038 /* Returns the state of the modifier keys in the format expected by the
3039 * Lisp_Event key_data, button_data and motion_data modifiers member */
3041 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3044 int keys_is_real = 0;
3047 if (fwKeys == (DWORD) -1)
3048 fwKeys = mswindows_last_mouse_button_state;
3052 mswindows_last_mouse_button_state = fwKeys;
3058 GetKeyboardState (keymap);
3059 has_AltGr = mswindows_current_layout_has_AltGr ();
3062 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3064 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3066 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3067 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3071 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3072 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3075 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3076 ? XEMACS_MOD_SHIFT : 0;
3077 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3078 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3079 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3085 * Translate a mswindows virtual key to a keysym.
3086 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3087 * or whose ASCII codes (like space) xemacs doesn't like.
3089 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3092 if (extendedp) /* Keys not present on a 82 key keyboard */
3094 switch (mswindows_key)
3096 case VK_CANCEL: return KEYSYM ("pause");
3097 case VK_RETURN: return KEYSYM ("kp-enter");
3098 case VK_PRIOR: return KEYSYM ("prior");
3099 case VK_NEXT: return KEYSYM ("next");
3100 case VK_END: return KEYSYM ("end");
3101 case VK_HOME: return KEYSYM ("home");
3102 case VK_LEFT: return KEYSYM ("left");
3103 case VK_UP: return KEYSYM ("up");
3104 case VK_RIGHT: return KEYSYM ("right");
3105 case VK_DOWN: return KEYSYM ("down");
3106 case VK_INSERT: return KEYSYM ("insert");
3107 case VK_DELETE: return QKdelete;
3108 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3109 case VK_LWIN return KEYSYM ("");
3110 case VK_RWIN return KEYSYM ("");
3112 case VK_APPS: return KEYSYM ("menu");
3117 switch (mswindows_key)
3119 case VK_BACK: return QKbackspace;
3120 case VK_TAB: return QKtab;
3121 case '\n': return QKlinefeed;
3122 case VK_CLEAR: return KEYSYM ("clear");
3123 case VK_RETURN: return QKreturn;
3124 case VK_PAUSE: return KEYSYM ("pause");
3125 case VK_ESCAPE: return QKescape;
3126 case VK_SPACE: return QKspace;
3127 case VK_PRIOR: return KEYSYM ("kp-prior");
3128 case VK_NEXT: return KEYSYM ("kp-next");
3129 case VK_END: return KEYSYM ("kp-end");
3130 case VK_HOME: return KEYSYM ("kp-home");
3131 case VK_LEFT: return KEYSYM ("kp-left");
3132 case VK_UP: return KEYSYM ("kp-up");
3133 case VK_RIGHT: return KEYSYM ("kp-right");
3134 case VK_DOWN: return KEYSYM ("kp-down");
3135 case VK_SELECT: return KEYSYM ("select");
3136 case VK_PRINT: return KEYSYM ("print");
3137 case VK_EXECUTE: return KEYSYM ("execute");
3138 case VK_SNAPSHOT: return KEYSYM ("print");
3139 case VK_INSERT: return KEYSYM ("kp-insert");
3140 case VK_DELETE: return KEYSYM ("kp-delete");
3141 case VK_HELP: return KEYSYM ("help");
3142 case VK_NUMPAD0: return KEYSYM ("kp-0");
3143 case VK_NUMPAD1: return KEYSYM ("kp-1");
3144 case VK_NUMPAD2: return KEYSYM ("kp-2");
3145 case VK_NUMPAD3: return KEYSYM ("kp-3");
3146 case VK_NUMPAD4: return KEYSYM ("kp-4");
3147 case VK_NUMPAD5: return KEYSYM ("kp-5");
3148 case VK_NUMPAD6: return KEYSYM ("kp-6");
3149 case VK_NUMPAD7: return KEYSYM ("kp-7");
3150 case VK_NUMPAD8: return KEYSYM ("kp-8");
3151 case VK_NUMPAD9: return KEYSYM ("kp-9");
3152 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3153 case VK_ADD: return KEYSYM ("kp-add");
3154 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3155 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3156 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3157 case VK_DIVIDE: return KEYSYM ("kp-divide");
3158 case VK_F1: return KEYSYM ("f1");
3159 case VK_F2: return KEYSYM ("f2");
3160 case VK_F3: return KEYSYM ("f3");
3161 case VK_F4: return KEYSYM ("f4");
3162 case VK_F5: return KEYSYM ("f5");
3163 case VK_F6: return KEYSYM ("f6");
3164 case VK_F7: return KEYSYM ("f7");
3165 case VK_F8: return KEYSYM ("f8");
3166 case VK_F9: return KEYSYM ("f9");
3167 case VK_F10: return KEYSYM ("f10");
3168 case VK_F11: return KEYSYM ("f11");
3169 case VK_F12: return KEYSYM ("f12");
3170 case VK_F13: return KEYSYM ("f13");
3171 case VK_F14: return KEYSYM ("f14");
3172 case VK_F15: return KEYSYM ("f15");
3173 case VK_F16: return KEYSYM ("f16");
3174 case VK_F17: return KEYSYM ("f17");
3175 case VK_F18: return KEYSYM ("f18");
3176 case VK_F19: return KEYSYM ("f19");
3177 case VK_F20: return KEYSYM ("f20");
3178 case VK_F21: return KEYSYM ("f21");
3179 case VK_F22: return KEYSYM ("f22");
3180 case VK_F23: return KEYSYM ("f23");
3181 case VK_F24: return KEYSYM ("f24");
3188 * Find the console that matches the supplied mswindows window handle
3191 mswindows_find_console (HWND hwnd)
3193 /* We only support one console */
3194 return XCAR (Vconsole_list);
3198 * Find the frame that matches the supplied mswindows window handle
3201 mswindows_find_frame (HWND hwnd)
3203 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3207 /* We are in progress of frame creation. Return the frame
3208 being created, as it still not remembered in the window
3210 assert (!NILP (Vmswindows_frame_being_created));
3211 return Vmswindows_frame_being_created;
3213 VOID_TO_LISP (f, l);
3218 /************************************************************************/
3220 /************************************************************************/
3223 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3226 EMACS_TIME current_time;
3227 EMACS_GET_TIME (current_time);
3228 EMACS_SUB_TIME (thyme, thyme, current_time);
3229 milliseconds = EMACS_SECS (thyme) * 1000 +
3230 (EMACS_USECS (thyme) + 500) / 1000;
3231 if (milliseconds < 1)
3233 ++mswindows_pending_timers_count;
3234 return SetTimer (NULL, 0, milliseconds,
3235 (TIMERPROC) mswindows_wm_timer_callback);
3239 emacs_mswindows_remove_timeout (int id)
3241 Lisp_Event match_against;
3242 Lisp_Object emacs_event;
3244 if (KillTimer (NULL, id))
3245 --mswindows_pending_timers_count;
3247 /* If there is a dispatch event generated by this
3248 timeout in the queue, we have to remove it too. */
3249 match_against.event_type = timeout_event;
3250 match_against.event.timeout.interval_id = id;
3251 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3252 if (!NILP (emacs_event))
3253 Fdeallocate_event(emacs_event);
3256 /* If `user_p' is false, then return whether there are any win32, timeout,
3257 * or subprocess events pending (that is, whether
3258 * emacs_mswindows_next_event() would return immediately without blocking).
3260 * if `user_p' is true, then return whether there are any *user generated*
3261 * events available (that is, whether there are keyboard or mouse-click
3262 * events ready to be read). This also implies that
3263 * emacs_mswindows_next_event() would not block.
3266 emacs_mswindows_event_pending_p (int user_p)
3268 mswindows_need_event (0);
3269 return (!NILP (mswindows_u_dispatch_event_queue)
3270 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3274 * Return the next event
3277 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3279 Lisp_Object event, event2;
3281 mswindows_need_event (1);
3283 event = mswindows_dequeue_dispatch_event ();
3284 XSETEVENT (event2, emacs_event);
3285 Fcopy_event (event, event2);
3286 Fdeallocate_event (event);
3290 * Handle a magic event off the dispatch queue.
3293 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3295 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3302 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3303 mswindows_handle_paint (f);
3304 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3311 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3312 struct frame *f = XFRAME (frame);
3313 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3315 struct gcpro gcpro1;
3317 /* On focus change, clear all memory of sticky modifiers
3318 to avoid non-intuitive behavior. */
3319 clear_sticky_modifiers ();
3321 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3323 emacs_handle_focus_change_preliminary (conser);
3324 /* Under X the stuff up to here is done in the X event handler.
3326 emacs_handle_focus_change_final (conser);
3335 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3336 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3338 Qmap_frame_hook : Qunmap_frame_hook,
3343 /* #### What about Enter & Leave */
3345 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3346 Qmouse_leave_frame_hook, 1, frame);
3354 #ifndef HAVE_MSG_SELECT
3356 get_process_input_waitable (Lisp_Process *process)
3358 Lisp_Object instr, outstr, p;
3359 XSETPROCESS (p, process);
3360 get_process_streams (process, &instr, &outstr);
3361 assert (!NILP (instr));
3362 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3363 return (network_connection_p (p)
3364 ? get_winsock_stream_waitable (XLSTREAM (instr))
3365 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3367 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3372 emacs_mswindows_select_process (Lisp_Process *process)
3374 HANDLE hev = get_process_input_waitable (process);
3376 if (!add_waitable_handle (hev))
3377 error ("Too many active processes");
3379 #ifdef HAVE_WIN32_PROCESSES
3382 XSETPROCESS (p, process);
3383 if (!network_connection_p (p))
3385 HANDLE hprocess = get_nt_process_handle (process);
3386 if (!add_waitable_handle (hprocess))
3388 remove_waitable_handle (hev);
3389 error ("Too many active processes");
3397 emacs_mswindows_unselect_process (Lisp_Process *process)
3399 /* Process handle is removed in the event loop as soon
3400 as it is signaled, so don't bother here about it */
3401 HANDLE hev = get_process_input_waitable (process);
3402 remove_waitable_handle (hev);
3404 #endif /* HAVE_MSG_SELECT */
3407 emacs_mswindows_select_console (struct console *con)
3409 #ifdef HAVE_MSG_SELECT
3410 if (CONSOLE_MSWINDOWS_P (con))
3411 return; /* mswindows consoles are automatically selected */
3413 event_stream_unixoid_select_console (con);
3418 emacs_mswindows_unselect_console (struct console *con)
3420 #ifdef HAVE_MSG_SELECT
3421 if (CONSOLE_MSWINDOWS_P (con))
3422 return; /* mswindows consoles are automatically selected */
3424 event_stream_unixoid_unselect_console (con);
3429 emacs_mswindows_quit_p (void)
3431 /* Quit cannot happen in modal loop: all program
3432 input is dedicated to Windows. */
3433 if (mswindows_in_modal_loop)
3436 /* Drain windows queue. This sets up number of quit characters in
3438 mswindows_drain_windows_queue ();
3440 if (mswindows_quit_chars_count > 0)
3442 /* Yes there's a hidden one... Throw it away */
3443 Lisp_Event match_against;
3444 Lisp_Object emacs_event;
3447 match_against.event_type = key_press_event;
3448 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3450 while (mswindows_quit_chars_count-- > 0)
3452 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3453 assert (!NILP (emacs_event));
3455 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT)
3458 Fdeallocate_event(emacs_event);
3461 Vquit_flag = critical_p ? Qcritical : Qt;
3466 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3467 Lisp_Object* instream,
3468 Lisp_Object* outstream,
3471 /* Handles for streams */
3473 /* fds. These just stored along with the streams, and are closed in
3474 delete stream pair method, because we need to handle fake unices
3478 /* Decode inhandle and outhandle. Their meaning depends on
3479 the process implementation being used. */
3480 #if defined (HAVE_WIN32_PROCESSES)
3481 /* We're passed in Windows handles. That's what we like most... */
3482 hin = (HANDLE) inhandle;
3483 hout = (HANDLE) outhandle;
3485 #elif defined (HAVE_UNIX_PROCESSES)
3486 /* We are passed UNIX fds. This must be Cygwin.
3488 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3489 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3493 #error "So, WHICH kind of processes do you want?"
3496 *instream = (hin == INVALID_HANDLE_VALUE
3498 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3499 : flags & STREAM_NETWORK_CONNECTION
3500 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3502 : make_ntpipe_input_stream (hin, fdi));
3504 #ifdef HAVE_WIN32_PROCESSES
3505 *outstream = (hout == INVALID_HANDLE_VALUE
3507 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3508 : flags & STREAM_NETWORK_CONNECTION
3509 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3511 : make_ntpipe_output_stream (hout, fdo));
3512 #elif defined (HAVE_UNIX_PROCESSES)
3513 *outstream = (fdo >= 0
3514 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3517 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3518 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3519 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3521 Bufbyte eof_char = get_eof_char (fdo);
3522 int pty_max_bytes = get_pty_max_bytes (fdo);
3523 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3528 return (NILP (*instream)
3530 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3531 : flags & STREAM_NETWORK_CONNECTION
3532 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3534 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3538 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3539 Lisp_Object outstream)
3541 /* Oh nothing special here for Win32 at all */
3542 #if defined (HAVE_UNIX_PROCESSES)
3543 int in = (NILP(instream)
3545 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3546 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3547 ? get_winsock_stream_param (XLSTREAM (instream))
3549 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3550 int out = (NILP(outstream) ? -1
3551 : filedesc_stream_fd (XLSTREAM (outstream)));
3555 if (out != in && out >= 0)
3559 return (NILP (instream)
3561 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3562 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3563 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3565 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3569 emacs_mswindows_current_event_timestamp (struct console *c)
3571 return GetTickCount ();
3574 #ifndef HAVE_X_WINDOWS
3575 /* This is called from GC when a process object is about to be freed.
3576 If we've still got pointers to it in this file, we're gonna lose hard.
3579 debug_process_finalization (Lisp_Process *p)
3582 Lisp_Object instr, outstr;
3584 get_process_streams (p, &instr, &outstr);
3585 /* if it still has fds, then it hasn't been killed yet. */
3586 assert (NILP(instr));
3587 assert (NILP(outstr));
3589 /* #### More checks here */
3594 /************************************************************************/
3595 /* initialization */
3596 /************************************************************************/
3599 reinit_vars_of_event_mswindows (void)
3601 mswindows_in_modal_loop = 0;
3602 mswindows_pending_timers_count = 0;
3604 mswindows_event_stream = xnew (struct event_stream);
3606 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
3607 mswindows_event_stream->force_event_pending = 0;
3608 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
3609 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
3610 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
3611 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
3612 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
3613 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
3614 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
3615 #ifdef HAVE_MSG_SELECT
3616 mswindows_event_stream->select_process_cb =
3617 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
3618 mswindows_event_stream->unselect_process_cb =
3619 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
3620 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
3621 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
3623 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
3624 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
3625 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
3626 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
3628 mswindows_event_stream->current_event_timestamp_cb =
3629 emacs_mswindows_current_event_timestamp;
3633 vars_of_event_mswindows (void)
3635 reinit_vars_of_event_mswindows ();
3637 mswindows_u_dispatch_event_queue = Qnil;
3638 staticpro (&mswindows_u_dispatch_event_queue);
3639 mswindows_u_dispatch_event_queue_tail = Qnil;
3640 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
3642 mswindows_s_dispatch_event_queue = Qnil;
3643 staticpro (&mswindows_s_dispatch_event_queue);
3644 mswindows_s_dispatch_event_queue_tail = Qnil;
3645 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
3647 mswindows_error_caught_in_modal_loop = Qnil;
3648 staticpro (&mswindows_error_caught_in_modal_loop);
3652 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
3653 If non-zero, display debug information about Windows events that XEmacs sees.
3654 Information is displayed in a console window. Currently defined values are:
3656 1 == non-verbose output
3659 #### Unfortunately, not yet implemented.
3661 debug_mswindows_events = 0;
3664 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
3665 &mswindows_alt_by_itself_activates_menu /*
3666 *Controls whether pressing and releasing the Alt key activates the menubar.
3667 This applies only if no intervening key was pressed. See also
3668 `menu-accelerator-enabled', which is probably the behavior you actually want.
3672 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
3673 &mswindows_dynamic_frame_resize /*
3674 *Controls redrawing frame contents during mouse-drag or keyboard resize
3675 operation. When non-nil, the frame is redrawn while being resized. When
3676 nil, frame is not redrawn, and exposed areas are filled with default
3677 MDI application background color. Note that this option only has effect
3678 if "Show window contents while dragging" is on in system Display/Plus!
3680 Default is t on fast machines, nil on slow.
3683 DEFVAR_INT ("mswindows-mouse-button-tolerance",
3684 &mswindows_mouse_button_tolerance /*
3685 *Analogue of double click interval for faking middle mouse events.
3686 The value is the minimum time in milliseconds that must elapse between
3687 left/right button down events before they are considered distinct events.
3688 If both mouse buttons are depressed within this interval, a middle mouse
3689 button down event is generated instead.
3690 If negative or zero, currently set system default is used instead.
3693 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
3694 Number of physical mouse buttons.
3697 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
3698 &mswindows_mouse_button_max_skew_x /*
3699 *Maximum horizontal distance in pixels between points in which left and
3700 right button clicks occurred for them to be translated into single
3701 middle button event. Clicks must occur in time not longer than defined
3702 by the variable `mswindows-mouse-button-tolerance'.
3703 If negative or zero, currently set system default is used instead.
3706 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
3707 &mswindows_mouse_button_max_skew_y /*
3708 *Maximum vertical distance in pixels between points in which left and
3709 right button clicks occurred for them to be translated into single
3710 middle button event. Clicks must occur in time not longer than defined
3711 by the variable `mswindows-mouse-button-tolerance'.
3712 If negative or zero, currently set system default is used instead.
3715 mswindows_mouse_button_max_skew_x = 0;
3716 mswindows_mouse_button_max_skew_y = 0;
3717 mswindows_mouse_button_tolerance = 0;
3718 mswindows_alt_by_itself_activates_menu = 1;
3722 syms_of_event_mswindows (void)
3727 lstream_type_create_mswindows_selectable (void)
3729 init_slurp_stream ();
3730 init_shove_stream ();
3731 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3732 init_winsock_stream ();
3737 init_event_mswindows_late (void)
3739 #ifdef HAVE_MSG_SELECT
3740 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
3741 assert (windows_fd>=0);
3742 FD_SET (windows_fd, &input_wait_mask);
3743 FD_ZERO(&zero_mask);
3746 event_stream = mswindows_event_stream;
3748 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
3749 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);