1 /* The mswindows event_stream interface.
2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1996, 2000 Ben Wing.
5 Copyright (C) 1997 Jonathan Harris.
7 This file is part of XEmacs.
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING. If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
24 /* Synched up with: Not in FSF. */
28 Ultimately based on FSF.
29 Rewritten by Ben Wing.
30 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
31 Subprocess and modal loop support by Kirill M. Katsnelson.
37 #include "console-msw.h"
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
45 # include "menubar-msw.h"
49 # include "dragdrop.h"
58 #include "objects-msw.h"
60 #include "redisplay.h"
70 #include "events-mod.h"
72 #ifdef HAVE_MSG_SELECT
73 #include "console-tty.h"
75 typedef unsigned int SOCKET;
78 #if !(defined(CYGWIN) || defined(MINGW))
79 # include <shlobj.h> /* For IShellLink */
83 #define ADJR_MENUFLAG TRUE
85 #define ADJR_MENUFLAG FALSE
88 /* Fake key modifier which is attached to a quit char event.
89 Removed upon dequeueing an event */
90 #define FAKE_MOD_QUIT (1 << 20)
91 #define FAKE_MOD_QUIT_CRITICAL (1 << 21)
93 /* Timer ID used for button2 emulation */
94 #define BUTTON_2_TIMER_ID 1
96 static Lisp_Object mswindows_find_frame (HWND hwnd);
97 static Lisp_Object mswindows_find_console (HWND hwnd);
98 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
100 static int mswindows_modifier_state (BYTE* keymap, DWORD fwKeys,
102 static void mswindows_set_chord_timer (HWND hwnd);
103 static int mswindows_button2_near_enough (POINTS p1, POINTS p2);
104 static int mswindows_current_layout_has_AltGr (void);
105 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
106 int downp, int keyp);
108 static struct event_stream *mswindows_event_stream;
110 #ifdef HAVE_MSG_SELECT
111 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask;
112 extern SELECT_TYPE process_only_mask, tty_only_mask;
113 SELECT_TYPE zero_mask;
114 extern int signal_event_pipe_initialized;
119 * Two separate queues, for efficiency, one (_u_) for user events, and
120 * another (_s_) for non-user ones. We always return events out of the
121 * first one until it is empty and only then proceed with the second
124 static Lisp_Object mswindows_u_dispatch_event_queue, mswindows_u_dispatch_event_queue_tail;
125 static Lisp_Object mswindows_s_dispatch_event_queue, mswindows_s_dispatch_event_queue_tail;
127 /* The number of things we can wait on */
128 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
130 #ifndef HAVE_MSG_SELECT
131 /* List of mswindows waitable handles. */
132 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
134 /* Number of wait handles */
135 static int mswindows_waitable_count=0;
136 #endif /* HAVE_MSG_SELECT */
138 /* Brush for painting widgets */
139 static HBRUSH widget_brush = 0;
140 static LONG last_widget_brushed = 0;
142 /* Count of quit chars currently in the queue */
143 /* Incremented in WM_[SYS]KEYDOWN handler in the mswindows_wnd_proc()
144 Decremented in mswindows_dequeue_dispatch_event() */
145 int mswindows_quit_chars_count = 0;
147 /* These are Lisp integers; see DEFVARS in this file for description. */
148 int mswindows_dynamic_frame_resize;
149 int mswindows_alt_by_itself_activates_menu;
150 Fixnum mswindows_num_mouse_buttons;
151 Fixnum mswindows_mouse_button_max_skew_x;
152 Fixnum mswindows_mouse_button_max_skew_y;
153 Fixnum mswindows_mouse_button_tolerance;
156 Fixnum debug_mswindows_events;
158 static void debug_output_mswin_message (HWND hwnd, UINT message_,
159 WPARAM wParam, LPARAM lParam);
162 /* This is the event signaled by the event pump.
163 See mswindows_pump_outstanding_events for comments */
164 static Lisp_Object mswindows_error_caught_in_modal_loop;
165 static int mswindows_in_modal_loop;
167 /* Count of wound timers */
168 static int mswindows_pending_timers_count;
170 static DWORD mswindows_last_mouse_button_state;
172 /************************************************************************/
173 /* Pipe instream - reads process output */
174 /************************************************************************/
176 #define PIPE_READ_DELAY 20
178 #define HANDLE_TO_USID(h) ((USID)(h))
180 #define NTPIPE_SLURP_STREAM_DATA(stream) \
181 LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
183 /* This structure is allocated by the main thread, and is deallocated
184 in the thread upon exit. There are situations when a thread
185 remains blocked for a long time, much longer than the lstream
186 exists. For example, "start notepad" command is issued from the
187 shell, then the shell is closed by C-c C-d. Although the shell
188 process exits, its output pipe will not get closed until the
189 notepad process exits also, because it inherits the pipe form the
190 shell. In this case, we abandon the thread, and let it live until
191 all such processes exit. While struct ntpipe_slurp_stream is
192 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */
194 struct ntpipe_slurp_stream_shared_data
196 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
197 /* This is a manual-reset object. */
198 HANDLE hev_caller; /* Caller blocks on this, and we signal it */
199 /* This is a manual-reset object. */
200 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */
201 /* This is a manual-reset object. */
202 HANDLE hpipe; /* Pipe read end handle. */
203 LONG die_p; /* Thread must exit ASAP if non-zero */
204 BOOL eof_p : 1; /* Set when thread saw EOF */
205 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
206 BOOL inuse_p : 1; /* this structure is in use */
207 LONG lock_count; /* Client count of this struct, 0=safe to free */
208 BYTE onebyte; /* One byte buffer read by thread */
211 #define MAX_SLURP_STREAMS 32
212 struct ntpipe_slurp_stream_shared_data
213 shared_data_block[MAX_SLURP_STREAMS]={{0}};
215 struct ntpipe_slurp_stream
217 LPARAM user_data; /* Any user data stored in the stream object */
218 struct ntpipe_slurp_stream_shared_data* thread_data;
221 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
222 sizeof (struct ntpipe_slurp_stream));
224 /* This function is thread-safe, and is called from either thread
225 context. It serializes freeing shared data structure */
227 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
229 if (InterlockedDecrement (&s->lock_count) == 0)
232 CloseHandle (s->hev_thread);
233 CloseHandle (s->hev_caller);
234 CloseHandle (s->hev_unsleep);
239 static struct ntpipe_slurp_stream_shared_data*
240 slurper_allocate_shared_data (void)
243 for (i=0; i<MAX_SLURP_STREAMS; i++)
245 if (!shared_data_block[i].inuse_p)
247 shared_data_block[i].inuse_p=1;
248 return &shared_data_block[i];
251 return (struct ntpipe_slurp_stream_shared_data*)0;
255 slurp_thread (LPVOID vparam)
257 struct ntpipe_slurp_stream_shared_data *s =
258 (struct ntpipe_slurp_stream_shared_data*)vparam;
262 /* Read one byte from the pipe */
264 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
266 DWORD err = GetLastError ();
267 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
272 else if (actually_read == 0)
275 /* We must terminate on an error or eof */
276 if (s->eof_p || s->error_p)
277 InterlockedIncrement (&s->die_p);
279 /* Before we notify caller, we unsignal our event. */
280 ResetEvent (s->hev_thread);
282 /* Now we got something to notify caller, either a byte or an
283 error/eof indication. Before we do, allow internal pipe
284 buffer to accumulate little bit more data.
285 Reader function pulses this event before waiting for
286 a character, to avoid pipe delay, and to get the byte
289 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
291 /* Either make event loop generate a process event, or
293 SetEvent (s->hev_caller);
295 /* Cleanup and exit if we're shot off */
299 /* Block until the client finishes with retrieving the rest of
301 WaitForSingleObject (s->hev_thread, INFINITE);
304 slurper_free_shared_data_maybe (s);
310 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
313 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
314 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
315 DWORD thread_id_unused;
318 /* We deal only with pipes, for we're using PeekNamedPipe api */
319 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
321 s->thread_data = slurper_allocate_shared_data();
323 /* Create reader thread. This could fail, so do not create events
324 until thread is created */
325 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
326 CREATE_SUSPENDED, &thread_id_unused);
329 Lstream_delete (lstr);
330 s->thread_data->inuse_p=0;
334 /* Shared data are initially owned by both main and slurper
336 s->thread_data->lock_count = 2;
337 s->thread_data->die_p = 0;
338 s->thread_data->eof_p = FALSE;
339 s->thread_data->error_p = FALSE;
340 s->thread_data->hpipe = hpipe;
341 s->user_data = param;
343 /* hev_thread is a manual-reset event, initially signaled */
344 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
345 /* hev_caller is a manual-reset event, initially nonsignaled */
346 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
347 /* hev_unsleep is a manual-reset event, initially nonsignaled */
348 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
351 ResumeThread (hthread);
352 CloseHandle (hthread);
354 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
355 XSETLSTREAM (obj, lstr);
360 get_ntpipe_input_stream_param (Lstream *stream)
362 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
367 get_ntpipe_input_stream_waitable (Lstream *stream)
369 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
370 return s->thread_data->hev_caller;
373 static Lstream_data_count
374 ntpipe_slurp_reader (Lstream *stream, unsigned char *data,
375 Lstream_data_count size)
377 /* This function must be called from the main thread only */
378 struct ntpipe_slurp_stream_shared_data* s =
379 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
384 /* Disallow pipe read delay for the thread: we need a character
386 SetEvent (s->hev_unsleep);
388 /* Check if we have a character ready. Give it a short delay,
389 for the thread to awake from pipe delay, just ion case*/
390 wait_result = WaitForSingleObject (s->hev_caller, 2);
392 /* Revert to the normal sleep behavior. */
393 ResetEvent (s->hev_unsleep);
395 /* If there's no byte buffered yet, give up */
396 if (wait_result == WAIT_TIMEOUT)
403 /* Reset caller unlock event now, as we've handled the pending
404 process output event */
405 ResetEvent (s->hev_caller);
407 /* It is now safe to do anything with contents of S, except for
408 changing s->die_p, which still should be interlocked */
412 if (s->error_p || s->die_p)
415 /* Ok, there were no error neither eof - we've got a byte from the
417 *(data++) = s->onebyte;
421 DWORD bytes_read = 0;
424 DWORD bytes_available;
426 /* If the api call fails, return at least one byte already
427 read. ReadFile in thread will return error */
428 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
431 /* Fetch available bytes. The same consideration applies,
432 so do not check for errors. ReadFile in the thread will
433 fail if the next call fails. */
435 ReadFile (s->hpipe, data, min (bytes_available, size),
439 /* Now we can unblock thread, so it attempts to read more */
440 SetEvent (s->hev_thread);
441 return bytes_read + 1;
448 ntpipe_slurp_closer (Lstream *stream)
450 /* This function must be called from the main thread only */
451 struct ntpipe_slurp_stream_shared_data* s =
452 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
454 /* Force thread to stop */
455 InterlockedIncrement (&s->die_p);
457 /* Set events which could possibly block slurper. Let it finish soon
459 SetEvent (s->hev_unsleep);
460 SetEvent (s->hev_thread);
462 /* Unlock and maybe free shared data */
463 slurper_free_shared_data_maybe (s);
469 init_slurp_stream (void)
471 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
472 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
475 /************************************************************************/
476 /* Pipe outstream - writes process input */
477 /************************************************************************/
479 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
480 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
482 #define MAX_SHOVE_BUFFER_SIZE 512
484 struct ntpipe_shove_stream
486 LPARAM user_data; /* Any user data stored in the stream object */
487 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
488 /* This is an auto-reset object. */
489 HANDLE hpipe; /* Pipe write end handle. */
490 HANDLE hthread; /* Reader thread handle. */
491 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
492 DWORD size; /* Number of bytes to write */
493 LONG die_p; /* Thread must exit ASAP if non-zero */
494 LONG idle_p; /* Non-zero if thread is waiting for job */
495 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
496 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
499 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
500 sizeof (struct ntpipe_shove_stream));
502 #ifndef HAVE_MSG_SELECT
504 shove_thread (LPVOID vparam)
506 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
512 /* Block on event and wait for a job */
513 InterlockedIncrement (&s->idle_p);
514 WaitForSingleObject (s->hev_thread, INFINITE);
516 /* Write passed buffer if any */
519 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
520 || bytes_written != s->size)
523 InterlockedIncrement (&s->die_p);
525 /* Set size to zero so we won't write it again if the closer sets
526 die_p and kicks us */
538 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
541 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
542 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
543 DWORD thread_id_unused;
548 s->user_data = param;
550 /* Create reader thread. This could fail, so do not
551 create the event until thread is created */
552 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
553 CREATE_SUSPENDED, &thread_id_unused);
554 if (s->hthread == NULL)
556 Lstream_delete (lstr);
560 /* Set the priority of the thread higher so we don't end up waiting
561 on it to send things. */
562 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST))
564 CloseHandle (s->hthread);
565 Lstream_delete (lstr);
569 /* hev_thread is an auto-reset event, initially nonsignaled */
570 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
573 ResumeThread (s->hthread);
575 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
576 XSETLSTREAM (obj, lstr);
581 get_ntpipe_output_stream_param (Lstream *stream)
583 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
588 static Lstream_data_count
589 ntpipe_shove_writer (Lstream *stream, const unsigned char *data,
590 Lstream_data_count size)
592 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
597 s->blocking_p = !s->idle_p;
601 if (size>MAX_SHOVE_BUFFER_SIZE)
604 memcpy (s->buffer, data, size);
608 InterlockedDecrement (&s->idle_p);
609 SetEvent (s->hev_thread);
610 /* Give it a chance to run -- this dramatically improves performance
611 of things like crypt. */
612 if (xSwitchToThread) /* not in Win9x or NT 3.51 */
613 (void) xSwitchToThread ();
618 ntpipe_shove_was_blocked_p (Lstream *stream)
620 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
621 return s->blocking_p;
625 ntpipe_shove_closer (Lstream *stream)
627 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
629 /* Force thread stop */
630 InterlockedIncrement (&s->die_p);
632 /* Thread will end upon unblocking. If it's already unblocked this will
633 do nothing, but the thread won't look at die_p until it's written any
635 SetEvent (s->hev_thread);
637 /* Wait while thread terminates */
638 WaitForSingleObject (s->hthread, INFINITE);
640 /* Close pipe handle, possibly breaking it */
641 CloseHandle (s->hpipe);
643 /* Close the thread handle */
644 CloseHandle (s->hthread);
646 /* Destroy the event */
647 CloseHandle (s->hev_thread);
653 init_shove_stream (void)
655 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
656 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
657 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
660 /************************************************************************/
661 /* Winsock I/O stream */
662 /************************************************************************/
663 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
665 #define WINSOCK_READ_BUFFER_SIZE 1024
667 struct winsock_stream
669 LPARAM user_data; /* Any user data stored in the stream object */
670 SOCKET s; /* Socket handle (which is a Win32 handle) */
671 OVERLAPPED ov; /* Overlapped I/O structure */
672 void* buffer; /* Buffer. */
673 unsigned long bufsize; /* Number of bytes last read */
674 unsigned long bufpos; /* Position in buffer for next fetch */
675 unsigned int error_p :1; /* I/O Error seen */
676 unsigned int eof_p :1; /* EOF Error seen */
677 unsigned int pending_p :1; /* There is a pending I/O operation */
678 unsigned int blocking_p :1; /* Last write attempt would block */
681 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
683 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
684 sizeof (struct winsock_stream));
687 winsock_initiate_read (struct winsock_stream *str)
689 ResetEvent (str->ov.hEvent);
692 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
693 &str->bufsize, &str->ov))
695 if (GetLastError () == ERROR_IO_PENDING)
697 else if (GetLastError () == ERROR_HANDLE_EOF)
702 else if (str->bufsize == 0)
706 static Lstream_data_count
707 winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
709 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
711 /* If the current operation is not yet complete, there's nothing to
715 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
722 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
724 if (GetLastError() == ERROR_HANDLE_EOF)
729 if (str->bufsize == 0)
740 /* Return as much of buffer as we have */
741 size = min (size, (Lstream_data_count) (str->bufsize - str->bufpos));
742 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
745 /* Read more if buffer is exhausted */
746 if (str->bufsize == str->bufpos)
747 winsock_initiate_read (str);
752 static Lstream_data_count
753 winsock_writer (Lstream *stream, const unsigned char *data,
754 Lstream_data_count size)
756 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
760 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
768 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
782 ResetEvent (str->ov.hEvent);
784 /* According to WriteFile docs, we must hold onto the data we pass to it
785 and not make any changes until it finishes -- which may not be until
786 the next time we get here, since we use asynchronous I/O. We have
787 in fact seen data loss as a result of not doing this. */
788 str->buffer = xrealloc (str->buffer, size);
789 memcpy (str->buffer, data, size);
791 /* According to MSDN WriteFile docs, the fourth parameter cannot be NULL
792 on Win95 even when doing an overlapped operation, as we are, where
793 the return value through that parameter is not meaningful. */
794 if (WriteFile ((HANDLE)str->s, str->buffer, size, &str->bufsize,
796 || GetLastError() == ERROR_IO_PENDING)
801 return str->error_p ? -1 : size;
805 winsock_closer (Lstream *lstr)
807 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
809 if (lstr->flags & LSTREAM_FL_READ)
810 shutdown (str->s, 0);
812 shutdown (str->s, 1);
814 CloseHandle ((HANDLE)str->s);
816 WaitForSingleObject (str->ov.hEvent, INFINITE);
824 CloseHandle (str->ov.hEvent);
829 winsock_was_blocked_p (Lstream *stream)
831 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
832 return str->blocking_p;
836 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
839 Lstream *lstr = Lstream_new (lstream_winsock, mode);
840 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
844 str->user_data = param;
846 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
848 if (lstr->flags & LSTREAM_FL_READ)
850 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
851 winsock_initiate_read (str);
854 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
855 XSETLSTREAM (obj, lstr);
860 make_winsock_input_stream (SOCKET s, LPARAM param)
862 return make_winsock_stream_1 (s, param, "r");
866 make_winsock_output_stream (SOCKET s, LPARAM param)
868 return make_winsock_stream_1 (s, param, "w");
872 get_winsock_stream_waitable (Lstream *lstr)
874 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
875 return str->ov.hEvent;
879 get_winsock_stream_param (Lstream *lstr)
881 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
882 return str->user_data;
886 init_winsock_stream (void)
888 LSTREAM_HAS_METHOD (winsock, reader);
889 LSTREAM_HAS_METHOD (winsock, writer);
890 LSTREAM_HAS_METHOD (winsock, closer);
891 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
893 #endif /* defined (HAVE_SOCKETS) */
895 /************************************************************************/
896 /* Dispatch queue management */
897 /************************************************************************/
900 mswindows_user_event_p (Lisp_Event* sevt)
902 return (sevt->event_type == key_press_event
903 || sevt->event_type == button_press_event
904 || sevt->event_type == button_release_event
905 || sevt->event_type == misc_user_event);
909 * Add an emacs event to the proper dispatch queue
912 mswindows_enqueue_dispatch_event (Lisp_Object event)
914 int user_p = mswindows_user_event_p (XEVENT(event));
915 enqueue_event (event,
916 user_p ? &mswindows_u_dispatch_event_queue :
917 &mswindows_s_dispatch_event_queue,
918 user_p ? &mswindows_u_dispatch_event_queue_tail :
919 &mswindows_s_dispatch_event_queue_tail);
921 /* Avoid blocking on WaitMessage */
922 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
926 * Add a misc-user event to the dispatch queue.
928 * Stuff it into our own dispatch queue, so we have something
929 * to return from next_event callback.
932 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
935 Lisp_Object event = Fmake_event (Qnil, Qnil);
936 Lisp_Event* e = XEVENT (event);
938 e->event_type = misc_user_event;
939 e->channel = channel;
940 e->timestamp = GetTickCount ();
941 e->event.misc.function = function;
942 e->event.misc.object = object;
944 mswindows_enqueue_dispatch_event (event);
948 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
950 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
951 Lisp_Event* event = XEVENT (emacs_event);
953 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
954 event->timestamp = GetMessageTime();
955 event->event_type = magic_event;
956 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
958 mswindows_enqueue_dispatch_event (emacs_event);
962 mswindows_enqueue_process_event (Lisp_Process* p)
964 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
965 Lisp_Event* event = XEVENT (emacs_event);
967 XSETPROCESS (process, p);
969 event->event_type = process_event;
970 event->timestamp = GetTickCount ();
971 event->event.process.process = process;
973 mswindows_enqueue_dispatch_event (emacs_event);
977 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
978 int mods, DWORD when)
980 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
981 msg == WM_RBUTTONDOWN);
983 /* We always use last message time, because mouse button
984 events may get delayed, and XEmacs double click
985 recognition will fail */
987 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
988 Lisp_Event* event = XEVENT (emacs_event);
990 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
991 event->channel = mswindows_find_frame (hwnd);
992 event->timestamp = when;
993 event->event.button.button =
994 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
995 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
996 event->event.button.x = where.x;
997 event->event.button.y = where.y;
998 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
1002 event->event_type = button_press_event;
1004 /* we need this to make sure the main window regains the focus
1005 from control subwindows */
1006 if (GetFocus() != hwnd)
1009 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1014 event->event_type = button_release_event;
1018 mswindows_enqueue_dispatch_event (emacs_event);
1022 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1024 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1025 Lisp_Event* event = XEVENT(emacs_event);
1027 event->channel = mswindows_find_console(hwnd);
1028 event->timestamp = GetMessageTime();
1029 event->event_type = key_press_event;
1030 event->event.key.keysym = keysym;
1031 event->event.key.modifiers = mods;
1032 mswindows_enqueue_dispatch_event (emacs_event);
1036 * Remove and return the first emacs event on the dispatch queue.
1037 * Give a preference to user events over non-user ones.
1040 mswindows_dequeue_dispatch_event (void)
1045 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1046 !NILP(mswindows_s_dispatch_event_queue));
1048 event = dequeue_event (
1049 NILP(mswindows_u_dispatch_event_queue) ?
1050 &mswindows_s_dispatch_event_queue :
1051 &mswindows_u_dispatch_event_queue,
1052 NILP(mswindows_u_dispatch_event_queue) ?
1053 &mswindows_s_dispatch_event_queue_tail :
1054 &mswindows_u_dispatch_event_queue_tail);
1056 sevt = XEVENT (event);
1057 if (sevt->event_type == key_press_event
1058 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1059 sevt->event.key.modifiers &=
1060 ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
1066 * Remove and return the first emacs event on the dispatch queue that matches
1067 * the supplied event.
1068 * Timeout event matches if interval_id is equal to that of the given event.
1069 * Keypress event matches if logical AND between modifiers bitmask of the
1070 * event in the queue and that of the given event is non-zero.
1071 * For all other event types, this function aborts.
1075 mswindows_cancel_dispatch_event (Lisp_Event *match)
1078 Lisp_Object previous_event = Qnil;
1079 int user_p = mswindows_user_event_p (match);
1080 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1081 &mswindows_s_dispatch_event_queue;
1082 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1083 &mswindows_s_dispatch_event_queue_tail;
1085 assert (match->event_type == timeout_event
1086 || match->event_type == key_press_event);
1088 EVENT_CHAIN_LOOP (event, *head)
1090 Lisp_Event *e = XEVENT (event);
1091 if ((e->event_type == match->event_type) &&
1092 ((e->event_type == timeout_event) ?
1093 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1094 /* Must be key_press_event */
1095 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1097 if (NILP (previous_event))
1098 dequeue_event (head, tail);
1101 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1102 if (EQ (*tail, event))
1103 *tail = previous_event;
1108 previous_event = event;
1113 #ifndef HAVE_MSG_SELECT
1114 /************************************************************************/
1115 /* Waitable handles manipulation */
1116 /************************************************************************/
1118 find_waitable_handle (HANDLE h)
1121 for (i = 0; i < mswindows_waitable_count; ++i)
1122 if (mswindows_waitable_handles[i] == h)
1129 add_waitable_handle (HANDLE h)
1131 assert (find_waitable_handle (h) < 0);
1132 if (mswindows_waitable_count == MAX_WAITABLE)
1135 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1140 remove_waitable_handle (HANDLE h)
1142 int ix = find_waitable_handle (h);
1146 mswindows_waitable_handles [ix] =
1147 mswindows_waitable_handles [--mswindows_waitable_count];
1149 #endif /* HAVE_MSG_SELECT */
1152 /************************************************************************/
1154 /************************************************************************/
1157 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1158 Lisp_Object u_n_u_s_e_d)
1160 mswindows_error_caught_in_modal_loop = cons_sig_data;
1165 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1170 ++mswindows_in_modal_loop;
1171 tmp = condition_case_1 (Qt,
1173 mswindows_modal_loop_error_handler, Qnil);
1174 --mswindows_in_modal_loop;
1180 mswindows_unmodalize_signal_maybe (void)
1182 if (!NILP (mswindows_error_caught_in_modal_loop))
1184 /* Got an error while messages were pumped while
1185 in window procedure - have to resignal */
1186 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1187 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1188 mswindows_error_caught_in_modal_loop = Qnil;
1189 Fsignal (sym, data);
1194 * This is an unsafe part of event pump, guarded by
1195 * condition_case. See mswindows_pump_outstanding_events
1198 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1200 /* This function can call lisp */
1201 Lisp_Object event = Fmake_event (Qnil, Qnil);
1202 struct gcpro gcpro1;
1203 int do_redisplay = 0;
1206 while (detect_input_pending ())
1208 Fnext_event (event, Qnil);
1209 Fdispatch_event (event);
1216 Fdeallocate_event (event);
1219 /* Qt becomes return value of mswindows_pump_outstanding_events
1225 * This function pumps emacs events, while available, by using
1226 * next_message/dispatch_message loop. Errors are trapped around
1227 * the loop so the function always returns.
1229 * Windows message queue is not looked into during the call,
1230 * neither are waitable handles checked. The function pumps
1231 * thus only dispatch events already queued, as well as those
1232 * resulted in dispatching thereof. This is done by setting
1233 * module local variable mswindows_in_modal_loop to nonzero.
1235 * Return value is Qt if no errors was trapped, or Qunbound if
1236 * there was an error.
1238 * In case of error, a cons representing the error, in the
1239 * form (SIGNAL . DATA), is stored in the module local variable
1240 * mswindows_error_caught_in_modal_loop. This error is signaled
1241 * again when DispatchMessage returns. Thus, Windows internal
1242 * modal loops are protected against throws, which are proven
1243 * to corrupt internal Windows structures.
1245 * In case of success, mswindows_error_caught_in_modal_loop is
1248 * If the value of mswindows_error_caught_in_modal_loop is not
1249 * nil already upon entry, the function just returns non-nil.
1250 * This situation means that a new event has been queued while
1251 * in cancel mode. The event will be dequeued on the next regular
1252 * call of next-event; the pump is off since error is caught.
1253 * The caller must *unconditionally* cancel modal loop if the
1254 * value returned by this function is nil. Otherwise, everything
1255 * will become frozen until the modal loop exits under normal
1256 * condition (scrollbar drag is released, menu closed etc.)
1259 mswindows_pump_outstanding_events (void)
1261 /* This function can call lisp */
1263 Lisp_Object result = Qt;
1264 struct gcpro gcpro1;
1267 if (NILP(mswindows_error_caught_in_modal_loop))
1268 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1274 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1275 * QUITP, and are interesting in keyboard messages only.
1278 mswindows_drain_windows_queue (void)
1282 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1283 assert (!mswindows_in_modal_loop);
1285 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1287 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1289 /* Don't translate messages destined for a dialog box, this
1290 makes keyboard traversal work. I think?? */
1291 if (mswindows_is_dialog_msg (&msg))
1293 mswindows_unmodalize_signal_maybe ();
1297 /* We have to translate messages that are not sent to an XEmacs
1298 frame. This is so that key presses work ok in things like
1299 edit fields. However, we *musn't* translate message for XEmacs
1300 frames as this is handled in the wnd proc.
1301 We also have to avoid generating paint magic events for windows
1302 that aren't XEmacs frames */
1303 /* GetClassName will truncate a longer class name. By adding one
1304 extra character, we are forcing textual comparison to fail
1305 if the name is longer than XEMACS_CLASS */
1307 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1308 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1310 /* Not an XEmacs frame */
1311 TranslateMessage (&msg);
1313 else if (msg.message == WM_PAINT)
1315 struct mswindows_frame* msframe;
1317 /* hdc will be NULL unless this is a subwindow - in which case we
1318 shouldn't have received a paint message for it here. */
1319 assert (msg.wParam == 0);
1321 /* Queue a magic event for handling when safe */
1323 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1324 if (!msframe->paint_pending)
1326 msframe->paint_pending = 1;
1327 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1329 /* Don't dispatch. WM_PAINT is always the last message in the
1330 queue so it's OK to just return. */
1333 DispatchMessage (&msg);
1334 mswindows_unmodalize_signal_maybe ();
1339 * This is a special flavor of the mswindows_need_event function,
1340 * used while in event pump. Actually, there is only kind of events
1341 * allowed while in event pump: a timer. An attempt to fetch any
1342 * other event leads to a deadlock, as there's no source of user input
1343 * ('cause event pump mirrors windows modal loop, which is a sole
1344 * owner of thread message queue).
1346 * To detect this, we use a counter of active timers, and allow
1347 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1348 * which will never come when there are no pending timers, which leads
1349 * to deadlock, we simply signal an error.
1351 * It might be possible to combine this with mswindows_drain_windows_queue
1352 * which fetches events when not in a modal loop. It's not clear
1353 * whether the result would be more complex than is justified.
1356 mswindows_need_event_in_modal_loop (int badly_p)
1360 /* Check if already have one */
1361 if (!NILP (mswindows_u_dispatch_event_queue)
1362 || !NILP (mswindows_s_dispatch_event_queue))
1365 /* No event is ok */
1369 /* We do not check the _u_ queue, because timers go to _s_ */
1370 while (NILP (mswindows_s_dispatch_event_queue))
1372 /* We'll deadlock if go waiting */
1373 if (mswindows_pending_timers_count == 0)
1374 error ("Deadlock due to an attempt to call next-event in a wrong context");
1376 /* Fetch and dispatch any pending timers */
1377 if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1378 DispatchMessage (&msg);
1383 * This drains the event queue and fills up two internal queues until
1384 * an event of a type specified by USER_P is retrieved.
1387 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1390 mswindows_need_event (int badly_p)
1394 while (NILP (mswindows_u_dispatch_event_queue)
1395 && NILP (mswindows_s_dispatch_event_queue))
1397 #ifdef HAVE_MSG_SELECT
1399 SELECT_TYPE temp_mask = input_wait_mask;
1400 EMACS_TIME sometime;
1401 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1404 pointer_to_this = 0;
1407 EMACS_SET_SECS_USECS (sometime, 0, 0);
1408 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1409 pointer_to_this = &select_time_to_block;
1410 if (mswindows_in_modal_loop)
1411 /* In modal loop with badly_p false, don't care about
1413 FD_CLR (windows_fd, &temp_mask);
1416 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1421 return; /* timeout */
1423 else if (active > 0)
1425 if (FD_ISSET (windows_fd, &temp_mask))
1427 if (mswindows_in_modal_loop)
1428 mswindows_need_event_in_modal_loop (badly_p);
1430 mswindows_drain_windows_queue ();
1435 /* Look for a TTY event */
1436 for (i = 0; i < MAXDESC-1; i++)
1438 /* To avoid race conditions (among other things, an infinite
1439 loop when called from Fdiscard_input()), we must return
1440 user events ahead of process events. */
1441 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1443 struct console *c = tty_find_console_from_fd (i);
1444 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1445 Lisp_Event* event = XEVENT (emacs_event);
1448 if (read_event_from_tty_or_stream_desc (event, c, i))
1450 mswindows_enqueue_dispatch_event (emacs_event);
1456 /* Look for a process event */
1457 for (i = 0; i < MAXDESC-1; i++)
1459 if (FD_ISSET (i, &temp_mask))
1461 if (FD_ISSET (i, &process_only_mask))
1464 get_process_from_usid (FD_TO_USID(i));
1466 mswindows_enqueue_process_event (p);
1470 /* We might get here when a fake event came
1471 through a signal. Return a dummy event, so
1472 that a cycle of the command loop will
1474 drain_signal_event_pipe ();
1475 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1481 else if (active==-1)
1485 /* something bad happened */
1494 /* Now try getting a message or process event */
1496 if (mswindows_in_modal_loop)
1497 /* In a modal loop, only look for timer events, and only if
1498 we really need one. */
1501 what_events = QS_TIMER;
1506 /* Look for any event */
1507 what_events = QS_ALLINPUT;
1509 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1510 mswindows_waitable_handles,
1511 FALSE, badly_p ? INFINITE : 0,
1514 /* This will assert if handle being waited for becomes abandoned.
1515 Not the case currently tho */
1516 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1517 (active >= WAIT_OBJECT_0 &&
1518 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1520 if (active == WAIT_TIMEOUT)
1522 /* No luck trying - just return what we've already got */
1525 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1527 /* Got your message, thanks */
1528 if (mswindows_in_modal_loop)
1529 mswindows_need_event_in_modal_loop (badly_p);
1531 mswindows_drain_windows_queue ();
1535 int ix = active - WAIT_OBJECT_0;
1536 /* First, try to find which process' output has signaled */
1538 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1541 /* Found a signaled process input handle */
1542 mswindows_enqueue_process_event (p);
1546 /* None. This means that the process handle itself has signaled.
1547 Remove the handle from the wait vector, and make status_notify
1548 note the exited process. First find the process object if
1550 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
1551 if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
1552 mswindows_waitable_handles [ix])
1554 mswindows_waitable_handles [ix] =
1555 mswindows_waitable_handles [--mswindows_waitable_count];
1556 kick_status_notify ();
1557 /* We need to return a process event here so that
1558 (1) accept-process-output will return when called on this
1559 process, and (2) status notifications will happen in
1560 accept-process-output, sleep-for, and sit-for. */
1561 /* #### horrible kludge till my real process fixes go in.
1562 #### Replaced with a slightly less horrible kluge that
1563 at least finds the right process instead of axing the
1564 first one on the list.
1566 if (!NILP (vproctail))
1568 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1570 else /* trash me soon. */
1571 /* Have to return something: there may be no accompanying
1573 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1580 /************************************************************************/
1581 /* Event generators */
1582 /************************************************************************/
1585 * Callback procedure for synchronous timer messages
1587 static void CALLBACK
1588 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1590 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1591 Lisp_Event *event = XEVENT (emacs_event);
1593 if (KillTimer (NULL, id_timer))
1594 --mswindows_pending_timers_count;
1596 event->channel = Qnil;
1597 event->timestamp = dwtime;
1598 event->event_type = timeout_event;
1599 event->event.timeout.interval_id = id_timer;
1600 event->event.timeout.function = Qnil;
1601 event->event.timeout.object = Qnil;
1603 mswindows_enqueue_dispatch_event (emacs_event);
1607 * Callback procedure for dde messages
1609 * We execute a dde Open("file") by simulating a file drop, so dde support
1610 * depends on dnd support.
1612 #ifdef HAVE_DRAGNDROP
1613 extern int mswindows_dde_enable;
1616 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1617 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1618 DWORD dwData1, DWORD dwData2)
1623 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1624 return (HDDEDATA)TRUE;
1625 return (HDDEDATA)FALSE;
1627 case XTYP_WILDCONNECT:
1629 /* We only support one {service,topic} pair */
1630 HSZPAIR pairs[2] = {
1631 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1633 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1634 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1635 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1636 sizeof (pairs), 0L, 0, uFmt, 0));
1638 return (HDDEDATA)NULL;
1641 if (!mswindows_dde_enable)
1642 return (HDDEDATA) DDE_FBUSY;
1644 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1646 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1647 LPBYTE cmd = (LPBYTE) alloca (len+1);
1650 struct gcpro gcpro1, gcpro2;
1651 Lisp_Object l_dndlist = Qnil;
1652 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1653 Lisp_Object frmcons, devcons, concons;
1654 Lisp_Event *event = XEVENT (emacs_event);
1656 DdeGetData (hdata, cmd, len, 0);
1658 DdeFreeDataHandle (hdata);
1660 /* Check syntax & that it's an [Open("foo")] command, which we
1661 * treat like a file drop */
1662 /* #### Ought to be generalised and accept some other commands */
1665 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1666 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1667 return DDE_FNOTPROCESSED;
1668 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1671 if (*cmd!='(' || *(cmd+1)!='\"')
1672 return DDE_FNOTPROCESSED;
1674 while (*end && *end!='\"')
1677 return DDE_FNOTPROCESSED;
1680 return DDE_FNOTPROCESSED;
1684 return DDE_FNOTPROCESSED;
1687 filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5);
1688 strcpy (filename, "file:");
1689 cygwin_win32_to_posix_path_list (cmd, filename+5);
1691 dostounix_filename (cmd);
1692 filename = alloca (strlen (cmd)+6);
1693 strcpy (filename, "file:");
1694 strcat (filename, cmd);
1696 GCPRO2 (emacs_event, l_dndlist);
1697 l_dndlist = make_string (filename, strlen (filename));
1699 /* Find a mswindows frame */
1700 event->channel = Qnil;
1701 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1703 Lisp_Object frame = XCAR (frmcons);
1704 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1705 event->channel = frame;
1707 assert (!NILP (event->channel));
1709 event->timestamp = GetTickCount();
1710 event->event_type = misc_user_event;
1711 event->event.misc.button = 1;
1712 event->event.misc.modifiers = 0;
1713 event->event.misc.x = -1;
1714 event->event.misc.y = -1;
1715 event->event.misc.function = Qdragdrop_drop_dispatch;
1716 event->event.misc.object = Fcons (Qdragdrop_URL,
1717 Fcons (l_dndlist, Qnil));
1718 mswindows_enqueue_dispatch_event (emacs_event);
1720 return (HDDEDATA) DDE_FACK;
1722 DdeFreeDataHandle (hdata);
1723 return (HDDEDATA) DDE_FNOTPROCESSED;
1726 return (HDDEDATA) NULL;
1732 * Helper to do repainting - repaints can happen both from the windows
1733 * procedure and from magic events
1736 mswindows_handle_paint (struct frame *frame)
1738 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1740 /* According to the docs we need to check GetUpdateRect() before
1741 actually doing a WM_PAINT */
1742 if (GetUpdateRect (hwnd, NULL, FALSE))
1744 PAINTSTRUCT paintStruct;
1745 int x, y, width, height;
1747 BeginPaint (hwnd, &paintStruct);
1748 x = paintStruct.rcPaint.left;
1749 y = paintStruct.rcPaint.top;
1750 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1751 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1752 /* Normally we want to ignore expose events when child
1753 windows are unmapped, however once we are in the guts of
1754 WM_PAINT we need to make sure that we don't register
1755 unmaps then because they will not actually occur. */
1756 /* #### commenting out the next line seems to fix some problems
1757 but not all. only andy currently understands this stuff and
1758 he needs to review it more carefully. --ben */
1759 if (!check_for_ignored_expose (frame, x, y, width, height))
1761 hold_ignored_expose_registration = 1;
1762 mswindows_redraw_exposed_area (frame, x, y, width, height);
1763 hold_ignored_expose_registration = 0;
1765 EndPaint (hwnd, &paintStruct);
1770 * Returns 1 if a key is a real modifier or special key, which
1771 * is better handled by DefWindowProc
1774 key_needs_default_processing_p (UINT vkey)
1776 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1777 /* if we let ALT activate the menu like this, then sticky ALT-modified
1778 keystrokes become impossible. */
1779 && !modifier_keys_are_sticky)
1785 /* key-handling code is always ugly. It just ends up working out
1788 #### Most of the sticky-modifier code below is copied from similar
1789 code in event-Xt.c. They should somehow or other be merged.
1791 Here are some pointers:
1793 -- DOWN_MASK indicates which modifiers should be treated as "down"
1794 when the corresponding upstroke happens. It gets reset for
1795 a particular modifier when that modifier goes up, and reset
1796 for all modifiers when a non-modifier key is pressed. Example:
1798 I press Control-A-Shift and then release Control-A-Shift.
1799 I want the Shift key to be sticky but not the Control key.
1801 -- If a modifier key is sticky, I can unstick it by pressing
1802 the modifier key again. */
1804 static WPARAM last_downkey;
1805 static int need_to_add_mask, down_mask;
1807 #define XEMSW_LCONTROL (1<<0)
1808 #define XEMSW_RCONTROL (1<<1)
1809 #define XEMSW_LSHIFT (1<<2)
1810 #define XEMSW_RSHIFT (1<<3)
1811 #define XEMSW_LMENU (1<<4)
1812 #define XEMSW_RMENU (1<<5)
1815 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1816 int downp, int keyp)
1820 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1824 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1825 wParam == VK_RCONTROL ||
1826 wParam == VK_MENU || wParam == VK_LMENU ||
1827 wParam == VK_RMENU ||
1828 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1829 wParam == VK_RSHIFT)))
1830 { /* Not a modifier key */
1831 if (downp && keyp && !last_downkey)
1832 last_downkey = wParam;
1833 /* If I hold press-and-release the Control key and then press
1834 and hold down the right arrow, I want it to auto-repeat
1835 Control-Right. On the other hand, if I do the same but
1836 manually press the Right arrow a bunch of times, I want
1837 to see one Control-Right and then a bunch of Rights.
1838 This means that we need to distinguish between an
1839 auto-repeated key and a key pressed and released a bunch
1841 else if ((downp && !keyp) ||
1842 (downp && keyp && last_downkey &&
1843 (wParam != last_downkey ||
1844 /* the "previous key state" bit indicates autorepeat */
1845 ! (lParam & (1 << 30)))))
1847 need_to_add_mask = 0;
1853 mods = need_to_add_mask;
1855 else /* Modifier key pressed */
1857 /* If a non-modifier key was pressed in the middle of a bunch
1858 of modifiers, then it unsticks all the modifiers that were
1859 previously pressed. We cannot unstick the modifiers until
1860 now because we want to check for auto-repeat of the
1861 non-modifier key. */
1866 need_to_add_mask = 0;
1869 #define FROB(mask) \
1871 if (downp && keyp) \
1873 /* If modifier key is already sticky, \
1874 then unstick it. Note that we do \
1875 not test down_mask to deal with the \
1876 unlikely but possible case that the \
1877 modifier key auto-repeats. */ \
1878 if (need_to_add_mask & mask) \
1880 need_to_add_mask &= ~mask; \
1881 down_mask &= ~mask; \
1884 down_mask |= mask; \
1888 if (down_mask & mask) \
1890 down_mask &= ~mask; \
1891 need_to_add_mask |= mask; \
1896 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1897 || wParam == VK_RCONTROL)
1898 FROB (XEMSW_RCONTROL);
1899 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1900 || wParam == VK_LCONTROL)
1901 FROB (XEMSW_LCONTROL);
1903 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1904 || wParam == VK_RSHIFT)
1905 FROB (XEMSW_RSHIFT);
1906 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1907 || wParam == VK_LSHIFT)
1908 FROB (XEMSW_LSHIFT);
1910 if ((wParam == VK_MENU && (lParam & 0x1000000))
1911 || wParam == VK_RMENU)
1913 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1914 || wParam == VK_LMENU)
1923 GetKeyboardState (keymap);
1925 if (mods & XEMSW_LCONTROL)
1927 keymap [VK_CONTROL] |= 0x80;
1928 keymap [VK_LCONTROL] |= 0x80;
1930 if (mods & XEMSW_RCONTROL)
1932 keymap [VK_CONTROL] |= 0x80;
1933 keymap [VK_RCONTROL] |= 0x80;
1936 if (mods & XEMSW_LSHIFT)
1938 keymap [VK_SHIFT] |= 0x80;
1939 keymap [VK_LSHIFT] |= 0x80;
1941 if (mods & XEMSW_RSHIFT)
1943 keymap [VK_SHIFT] |= 0x80;
1944 keymap [VK_RSHIFT] |= 0x80;
1947 if (mods & XEMSW_LMENU)
1949 keymap [VK_MENU] |= 0x80;
1950 keymap [VK_LMENU] |= 0x80;
1952 if (mods & XEMSW_RMENU)
1954 keymap [VK_MENU] |= 0x80;
1955 keymap [VK_RMENU] |= 0x80;
1958 SetKeyboardState (keymap);
1966 clear_sticky_modifiers (void)
1968 need_to_add_mask = 0;
1978 output_modifier_keyboard_state (void)
1982 GetKeyboardState (keymap);
1984 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1985 keymap[VK_MENU] & 0x80 ? 1 : 0,
1986 keymap[VK_MENU] & 0x1 ? 1 : 0,
1987 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1988 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1989 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1990 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1991 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1992 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1993 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1994 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1995 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1996 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1997 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1998 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1999 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
2000 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
2001 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
2002 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
2003 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
2004 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
2009 /* try to debug the stuck-alt-key problem.
2011 #### this happens only inconsistently, and may only happen when using
2012 StickyKeys in the Win2000 accessibility section of the control panel,
2013 which is extremely broken for other reasons. */
2016 output_alt_keyboard_state (void)
2020 // SHORT asyncstate[3];
2022 GetKeyboardState (keymap);
2023 keystate[0] = GetKeyState (VK_MENU);
2024 keystate[1] = GetKeyState (VK_LMENU);
2025 keystate[2] = GetKeyState (VK_RMENU);
2026 /* Doing this interferes with key processing. */
2027 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2028 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2029 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2031 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2032 keymap[VK_MENU] & 0x80 ? 1 : 0,
2033 keymap[VK_MENU] & 0x1 ? 1 : 0,
2034 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2035 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2036 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2037 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2038 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2039 keystate[0] & 0x8000 ? 1 : 0,
2040 keystate[0] & 0x1 ? 1 : 0,
2041 keystate[1] & 0x8000 ? 1 : 0,
2042 keystate[1] & 0x1 ? 1 : 0,
2043 keystate[2] & 0x8000 ? 1 : 0,
2044 keystate[2] & 0x1 ? 1 : 0);
2045 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2046 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2047 /* asyncstate[0] & 0x1 ? 1 : 0, */
2048 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2049 /* asyncstate[1] & 0x1 ? 1 : 0, */
2050 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2051 /* asyncstate[2] & 0x1 ? 1 : 0); */
2054 #endif /* DEBUG_XEMACS */
2058 * The windows procedure for the window class XEMACS_CLASS
2061 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2063 /* Note: Remember to initialize emacs_event and event before use.
2064 This code calls code that can GC. You must GCPRO before calling such code. */
2065 Lisp_Object emacs_event = Qnil;
2066 Lisp_Object fobj = Qnil;
2069 struct frame *frame;
2070 struct mswindows_frame* msframe;
2072 /* If you hit this, rewrite the offending API call to occur after GC,
2073 using register_post_gc_action(). */
2074 assert (!gc_in_progress);
2077 if (debug_mswindows_events)
2078 debug_output_mswin_message (hwnd, message_, wParam, lParam);
2079 #endif /* DEBUG_XEMACS */
2081 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2084 case WM_DESTROYCLIPBOARD:
2085 /* We own the clipboard and someone else wants it. Delete our
2086 cached copy of the clipboard contents so we'll ask for it from
2087 Windows again when someone does a paste, and destroy any memory
2088 objects we hold on the clipboard that are not in the list of types
2089 that Windows will delete itself. */
2090 mswindows_destroy_selection (QCLIPBOARD);
2091 handle_selection_clear (QCLIPBOARD);
2095 /* Erase background only during non-dynamic sizing */
2096 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2097 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2102 fobj = mswindows_find_frame (hwnd);
2103 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2109 /* See Win95 comment under WM_KEYDOWN */
2112 int should_set_keymap = 0;
2115 if (debug_mswindows_events > 2)
2116 output_alt_keyboard_state ();
2117 #endif /* DEBUG_XEMACS */
2119 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2120 if (wParam == VK_CONTROL)
2122 GetKeyboardState (keymap);
2123 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2124 should_set_keymap = 1;
2126 else if (wParam == VK_MENU)
2128 GetKeyboardState (keymap);
2129 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2130 should_set_keymap = 1;
2133 if (should_set_keymap)
2134 // && (message_ != WM_SYSKEYUP
2135 // || NILP (Vmenu_accelerator_enabled)))
2136 SetKeyboardState (keymap);
2140 if (key_needs_default_processing_p (wParam))
2148 /* In some locales the right-hand Alt key is labelled AltGr. This key
2149 * should produce alternative characters when combined with another key.
2150 * eg on a German keyboard pressing AltGr+q should produce '@'.
2151 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2152 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2153 * it translates as if AltGr were down.
2154 * We get round this by removing all modifiers from the keymap before
2155 * calling TranslateMessage() unless AltGr is *really* down. */
2157 BYTE keymap_trans[256];
2158 BYTE keymap_orig[256];
2159 BYTE keymap_sticky[256];
2160 int has_AltGr = mswindows_current_layout_has_AltGr ();
2161 int mods = 0, mods_with_shift = 0;
2162 int extendedp = lParam & 0x1000000;
2167 if (debug_mswindows_events > 2)
2168 output_alt_keyboard_state ();
2169 #endif /* DEBUG_XEMACS */
2171 GetKeyboardState (keymap_orig);
2172 frame = XFRAME (mswindows_find_frame (hwnd));
2173 if ((sticky_changed =
2174 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2176 GetKeyboardState (keymap_sticky);
2177 if (keymap_sticky[VK_MENU] & 0x80)
2179 message_ = WM_SYSKEYDOWN;
2180 /* We have to set the "context bit" so that the
2181 TranslateMessage() call below that generates the
2182 SYSCHAR message does its thing; see the documentation
2188 memcpy (keymap_sticky, keymap_orig, 256);
2190 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2191 mods_with_shift = mods;
2193 /* Handle non-printables */
2194 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2197 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2199 SetKeyboardState (keymap_orig);
2201 else /* Normal keys & modifiers */
2204 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2205 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2207 int potential_accelerator = 0;
2208 int got_accelerator = 0;
2211 msg.message = message_;
2212 msg.wParam = wParam;
2213 msg.lParam = lParam;
2214 msg.time = GetMessageTime();
2217 /* GetKeyboardState() does not work as documented on Win95. We have
2218 * to loosely track Left and Right modifiers on behalf of the OS,
2219 * without screwing up Windows NT which tracks them properly. */
2220 if (wParam == VK_CONTROL)
2222 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2223 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2225 else if (wParam == VK_MENU)
2227 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2228 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2231 if (!NILP (Vmenu_accelerator_enabled) &&
2232 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2233 potential_accelerator = 1;
2235 /* Remove shift modifier from an ascii character */
2236 mods &= ~XEMACS_MOD_SHIFT;
2238 memcpy (keymap_trans, keymap_sticky, 256);
2240 /* Clear control and alt modifiers unless AltGr is pressed */
2241 keymap_trans[VK_RCONTROL] = 0;
2242 keymap_trans[VK_LMENU] = 0;
2243 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2244 || !(keymap_trans[VK_RMENU] & 0x80))
2246 keymap_trans[VK_LCONTROL] = 0;
2247 keymap_trans[VK_CONTROL] = 0;
2248 keymap_trans[VK_RMENU] = 0;
2249 keymap_trans[VK_MENU] = 0;
2251 SetKeyboardState (keymap_trans);
2253 /* Maybe generate some WM_[SYS]CHARs in the queue */
2254 TranslateMessage (&msg);
2256 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2257 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2260 int mods_with_quit = mods;
2261 WPARAM ch = tranmsg.wParam;
2264 if (debug_mswindows_events)
2267 debug_output_mswin_message (tranmsg.hwnd, tranmsg.message,
2271 #endif /* DEBUG_XEMACS */
2273 /* If a quit char with no modifiers other than control and
2274 shift, then mark it with a fake modifier, which is removed
2275 upon dequeueing the event */
2276 /* !!#### Fix this in my mule ws -- replace current_buffer
2278 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2279 && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2280 DOWNCASE (current_buffer, ch))
2281 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2282 && DOWNCASE (current_buffer, quit_ch) ==
2283 DOWNCASE (current_buffer, ch)))
2284 && ((mods_with_shift &
2285 ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2288 mods_with_quit |= FAKE_MOD_QUIT;
2289 if (mods_with_shift & XEMACS_MOD_SHIFT)
2290 mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2291 mswindows_quit_chars_count++;
2293 else if (potential_accelerator && !got_accelerator &&
2294 mswindows_char_is_accelerator (frame, ch))
2296 got_accelerator = 1;
2299 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2303 /* This generates WM_SYSCHAR messages, which are interpreted
2304 by DefWindowProc as the menu selections. */
2305 if (got_accelerator)
2307 SetKeyboardState (keymap_sticky);
2308 TranslateMessage (&msg);
2309 SetKeyboardState (keymap_orig);
2313 SetKeyboardState (keymap_orig);
2317 if (key_needs_default_processing_p (wParam))
2322 case WM_MBUTTONDOWN:
2324 /* Real middle mouse button has nothing to do with emulated one:
2325 if one wants to exercise fingers playing chords on the mouse,
2326 he is allowed to do that! */
2327 mswindows_enqueue_mouse_button_event (hwnd, message_,
2328 MAKEPOINTS (lParam),
2329 wParam &~ MK_MBUTTON,
2334 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2335 msframe->last_click_time = GetMessageTime();
2337 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2338 msframe->button2_need_lbutton = 0;
2339 if (msframe->ignore_next_lbutton_up)
2341 msframe->ignore_next_lbutton_up = 0;
2343 else if (msframe->button2_is_down)
2345 msframe->button2_is_down = 0;
2346 msframe->ignore_next_rbutton_up = 1;
2347 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2348 MAKEPOINTS (lParam),
2350 &~ (MK_LBUTTON | MK_MBUTTON
2356 if (msframe->button2_need_rbutton)
2358 msframe->button2_need_rbutton = 0;
2359 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2360 MAKEPOINTS (lParam),
2361 wParam &~ MK_LBUTTON,
2364 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2365 MAKEPOINTS (lParam),
2366 wParam &~ MK_LBUTTON,
2372 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2373 msframe->last_click_time = GetMessageTime();
2375 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2376 msframe->button2_need_rbutton = 0;
2377 if (msframe->ignore_next_rbutton_up)
2379 msframe->ignore_next_rbutton_up = 0;
2381 else if (msframe->button2_is_down)
2383 msframe->button2_is_down = 0;
2384 msframe->ignore_next_lbutton_up = 1;
2385 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2386 MAKEPOINTS (lParam),
2388 &~ (MK_LBUTTON | MK_MBUTTON
2394 if (msframe->button2_need_lbutton)
2396 msframe->button2_need_lbutton = 0;
2397 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2398 MAKEPOINTS (lParam),
2399 wParam &~ MK_RBUTTON,
2402 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2403 MAKEPOINTS (lParam),
2404 wParam &~ MK_RBUTTON,
2409 case WM_LBUTTONDOWN:
2410 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2412 if (msframe->button2_need_lbutton)
2414 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2415 msframe->button2_need_lbutton = 0;
2416 msframe->button2_need_rbutton = 0;
2417 if (mswindows_button2_near_enough (msframe->last_click_point,
2418 MAKEPOINTS (lParam)))
2420 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2421 MAKEPOINTS (lParam),
2423 &~ (MK_LBUTTON | MK_MBUTTON
2426 msframe->button2_is_down = 1;
2430 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2431 msframe->last_click_point,
2432 msframe->last_click_mods
2434 msframe->last_click_time);
2435 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2436 MAKEPOINTS (lParam),
2437 wParam &~ MK_LBUTTON,
2443 mswindows_set_chord_timer (hwnd);
2444 msframe->button2_need_rbutton = 1;
2445 msframe->last_click_point = MAKEPOINTS (lParam);
2446 msframe->last_click_mods = wParam;
2448 msframe->last_click_time = GetMessageTime();
2451 case WM_RBUTTONDOWN:
2452 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2454 if (msframe->button2_need_rbutton)
2456 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2457 msframe->button2_need_lbutton = 0;
2458 msframe->button2_need_rbutton = 0;
2459 if (mswindows_button2_near_enough (msframe->last_click_point,
2460 MAKEPOINTS (lParam)))
2462 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2463 MAKEPOINTS (lParam),
2465 &~ (MK_LBUTTON | MK_MBUTTON
2468 msframe->button2_is_down = 1;
2472 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2473 msframe->last_click_point,
2474 msframe->last_click_mods
2476 msframe->last_click_time);
2477 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2478 MAKEPOINTS (lParam),
2479 wParam &~ MK_RBUTTON,
2485 mswindows_set_chord_timer (hwnd);
2486 msframe->button2_need_lbutton = 1;
2487 msframe->last_click_point = MAKEPOINTS (lParam);
2488 msframe->last_click_mods = wParam;
2490 msframe->last_click_time = GetMessageTime();
2494 if (wParam == BUTTON_2_TIMER_ID)
2496 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2497 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2499 if (msframe->button2_need_lbutton)
2501 msframe->button2_need_lbutton = 0;
2502 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2503 msframe->last_click_point,
2504 msframe->last_click_mods
2506 msframe->last_click_time);
2508 else if (msframe->button2_need_rbutton)
2510 msframe->button2_need_rbutton = 0;
2511 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2512 msframe->last_click_point,
2513 msframe->last_click_mods
2515 msframe->last_click_time);
2519 assert ("Spurious timer fired" == 0);
2523 /* Optimization: don't report mouse movement while size is changing */
2524 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2525 if (!msframe->sizing)
2527 /* When waiting for the second mouse button to finish
2528 button2 emulation, and have moved too far, just pretend
2529 as if timer has expired. This improves drag-select feedback */
2530 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2531 && !mswindows_button2_near_enough (msframe->last_click_point,
2532 MAKEPOINTS (lParam)))
2534 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2535 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2538 emacs_event = Fmake_event (Qnil, Qnil);
2539 event = XEVENT(emacs_event);
2541 event->channel = mswindows_find_frame(hwnd);
2542 event->timestamp = GetMessageTime();
2543 event->event_type = pointer_motion_event;
2544 event->event.motion.x = MAKEPOINTS(lParam).x;
2545 event->event.motion.y = MAKEPOINTS(lParam).y;
2546 event->event.motion.modifiers =
2547 mswindows_modifier_state (NULL, wParam, 0);
2549 mswindows_enqueue_dispatch_event (emacs_event);
2555 /* Queue a `cancel-mode-internal' misc user event, so mouse
2556 selection would be canceled if any */
2557 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2558 Qcancel_mode_internal, Qnil);
2563 LPNMHDR nmhdr = (LPNMHDR)lParam;
2565 if (nmhdr->code == TTN_NEEDTEXT)
2567 #ifdef HAVE_TOOLBARS
2568 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2571 /* find out which toolbar */
2572 frame = XFRAME (mswindows_find_frame (hwnd));
2573 btext = mswindows_get_toolbar_button_text ( frame,
2576 tttext->lpszText = NULL;
2577 tttext->hinst = NULL;
2581 /* I think this is safe since the text will only go away
2582 when the toolbar does...*/
2583 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2587 /* handle tree view callbacks */
2588 else if (nmhdr->code == TVN_SELCHANGED)
2590 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2591 frame = XFRAME (mswindows_find_frame (hwnd));
2592 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2594 /* handle tab control callbacks */
2595 else if (nmhdr->code == TCN_SELCHANGE)
2598 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2599 frame = XFRAME (mswindows_find_frame (hwnd));
2601 item.mask = TCIF_PARAM;
2602 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2605 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2611 /* hdc will be NULL unless this is a subwindow - in which case we
2612 shouldn't have received a paint message for it here. */
2613 assert (wParam == 0);
2615 /* Can't queue a magic event because windows goes modal and sends paint
2616 messages directly to the windows procedure when doing solid drags
2617 and the message queue doesn't get processed. */
2618 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2621 case WM_WINDOWPOSCHANGED:
2622 /* This is sent before WM_SIZE; in fact, the processing of this
2623 by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when
2624 a window is hidden (make-frame-invisible), so we need to process
2625 this and update the state flags. */
2627 fobj = mswindows_find_frame (hwnd);
2628 frame = XFRAME (fobj);
2629 if (IsIconic (hwnd))
2631 FRAME_VISIBLE_P (frame) = 0;
2632 FRAME_ICONIFIED_P (frame) = 1;
2634 else if (IsWindowVisible (hwnd))
2636 FRAME_VISIBLE_P (frame) = 1;
2637 FRAME_ICONIFIED_P (frame) = 0;
2641 FRAME_VISIBLE_P (frame) = 0;
2642 FRAME_ICONIFIED_P (frame) = 0;
2645 return DefWindowProc (hwnd, message_, wParam, lParam);
2649 /* We only care about this message if our size has really changed */
2650 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2655 fobj = mswindows_find_frame (hwnd);
2656 frame = XFRAME (fobj);
2657 msframe = FRAME_MSWINDOWS_DATA (frame);
2659 /* We cannot handle frame map and unmap hooks right in
2660 this routine, because these may throw. We queue
2661 magic events to run these hooks instead - kkm */
2663 if (wParam==SIZE_MINIMIZED)
2666 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2670 GetClientRect(hwnd, &rect);
2671 FRAME_PIXWIDTH(frame) = rect.right;
2672 FRAME_PIXHEIGHT(frame) = rect.bottom;
2674 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2675 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2676 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2678 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2679 change_frame_size (frame, rows, columns, 1);
2681 /* If we are inside frame creation, we have to apply geometric
2683 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2685 /* Yes, we have to size again */
2686 mswindows_size_frame_internal ( frame,
2687 FRAME_MSWINDOWS_TARGET_RECT
2689 /* Reset so we do not get here again. The SetWindowPos call in
2690 * mswindows_size_frame_internal can cause recursion here. */
2691 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2693 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2694 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2699 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2700 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2702 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2709 case WM_DISPLAYCHANGE:
2712 DWORD message_tick = GetMessageTime ();
2714 fobj = mswindows_find_frame (hwnd);
2715 frame = XFRAME (fobj);
2716 d = XDEVICE (FRAME_DEVICE (frame));
2718 /* Do this only once per message. XEmacs can receive this message
2719 through as many frames as it currently has open. Message time
2720 will be the same for all these messages. Despite extreme
2721 efficiency, the code below has about one in 4 billion
2722 probability that the HDC is not recreated, provided that
2723 XEmacs is running sufficiently longer than 52 days. */
2724 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2726 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2727 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2728 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2733 /* Misc magic events which only require that the frame be identified */
2736 mswindows_enqueue_magic_event (hwnd, message_);
2739 case WM_WINDOWPOSCHANGING:
2741 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2742 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2743 GetWindowPlacement(hwnd, &wpl);
2745 /* Only interested if size is changing and we're not being iconified */
2746 if (wpl.showCmd != SW_SHOWMINIMIZED
2747 && wpl.showCmd != SW_SHOWMAXIMIZED
2748 && !(wp->flags & SWP_NOSIZE))
2750 RECT ncsize = { 0, 0, 0, 0 };
2751 int pixwidth, pixheight;
2752 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2753 GetMenu(hwnd) != NULL,
2754 GetWindowLong (hwnd, GWL_EXSTYLE));
2756 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2757 wp->cx - (ncsize.right - ncsize.left),
2758 wp->cy - (ncsize.bottom - ncsize.top),
2759 &pixwidth, &pixheight);
2761 /* Convert client sizes to window sizes */
2762 pixwidth += (ncsize.right - ncsize.left);
2763 pixheight += (ncsize.bottom - ncsize.top);
2765 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2767 /* Adjust so that the bottom or right doesn't move if it's
2768 * the top or left that's being changed */
2770 GetWindowRect (hwnd, &rect);
2772 if (rect.left != wp->x)
2773 wp->x += wp->cx - pixwidth;
2774 if (rect.top != wp->y)
2775 wp->y += wp->cy - pixheight;
2781 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2782 window position if the user tries to track window too small */
2786 case WM_ENTERSIZEMOVE:
2787 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2788 msframe->sizing = 1;
2791 case WM_EXITSIZEMOVE:
2792 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2793 msframe->sizing = 0;
2794 /* Queue noop event */
2795 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2798 #ifdef HAVE_SCROLLBARS
2802 /* Direction of scroll is determined by scrollbar instance. */
2803 int code = (int) LOWORD(wParam);
2804 int pos = (short int) HIWORD(wParam);
2805 HWND hwndScrollBar = (HWND) lParam;
2806 struct gcpro gcpro1, gcpro2;
2808 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2809 GCPRO2 (emacs_event, fobj);
2810 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2812 /* Error during event pumping - cancel scroll */
2813 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2821 int keys = LOWORD (wParam); /* Modifier key flags */
2822 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2823 struct gcpro gcpro1, gcpro2;
2825 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2827 MAKEPOINTS (lParam)))
2829 GCPRO2 (emacs_event, fobj);
2830 mswindows_pump_outstanding_events (); /* Can GC */
2839 #ifdef HAVE_MENUBARS
2841 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2843 XFRAME (mswindows_find_frame (hwnd)))))
2844 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2847 case WM_INITMENUPOPUP:
2848 if (!HIWORD(lParam))
2850 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2852 XFRAME (mswindows_find_frame (hwnd)))))
2853 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2857 #endif /* HAVE_MENUBARS */
2861 WORD id = LOWORD (wParam);
2862 WORD nid = HIWORD (wParam);
2863 HWND cid = (HWND)lParam;
2864 frame = XFRAME (mswindows_find_frame (hwnd));
2866 #ifdef HAVE_TOOLBARS
2867 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2870 /* widgets in a buffer only eval a callback for suitable events.*/
2875 case CBN_EDITCHANGE:
2877 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2880 /* menubars always must come last since the hashtables do not
2882 #ifdef HAVE_MENUBARS
2883 if (!NILP (mswindows_handle_wm_command (frame, id)))
2887 return DefWindowProc (hwnd, message_, wParam, lParam);
2888 /* Bite me - a spurious command. This used to not be able to
2889 happen but with the introduction of widgets its now
2894 case WM_CTLCOLORBTN:
2895 case WM_CTLCOLORLISTBOX:
2896 case WM_CTLCOLOREDIT:
2897 case WM_CTLCOLORSTATIC:
2898 case WM_CTLCOLORSCROLLBAR:
2900 /* if we get an opportunity to paint a widget then do so if
2901 there is an appropriate face */
2902 HWND crtlwnd = (HWND)lParam;
2903 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2906 Lisp_Object image_instance;
2907 VOID_TO_LISP (image_instance, ii);
2908 if (IMAGE_INSTANCEP (image_instance)
2910 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2912 /* set colors for the buttons */
2913 HDC hdc = (HDC)wParam;
2914 if (last_widget_brushed != ii)
2917 DeleteObject (widget_brush);
2918 widget_brush = CreateSolidBrush
2919 (COLOR_INSTANCE_MSWINDOWS_COLOR
2922 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2923 XIMAGE_INSTANCE_FRAME (image_instance)))));
2925 last_widget_brushed = ii;
2928 COLOR_INSTANCE_MSWINDOWS_COLOR
2931 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2932 XIMAGE_INSTANCE_FRAME (image_instance)))));
2933 SetBkMode (hdc, OPAQUE);
2936 COLOR_INSTANCE_MSWINDOWS_COLOR
2939 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2940 XIMAGE_INSTANCE_FRAME (image_instance)))));
2941 return (LRESULT)widget_brush;
2947 #ifdef HAVE_DRAGNDROP
2948 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2950 UINT filecount, i, len;
2955 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2956 struct gcpro gcpro1, gcpro2, gcpro3;
2958 emacs_event = Fmake_event (Qnil, Qnil);
2959 event = XEVENT(emacs_event);
2961 GCPRO3 (emacs_event, l_dndlist, l_item);
2963 if (!DragQueryPoint ((HDROP) wParam, &point))
2964 point.x = point.y = -1; /* outside client area */
2966 event->event_type = misc_user_event;
2967 event->channel = mswindows_find_frame(hwnd);
2968 event->timestamp = GetMessageTime();
2969 event->event.misc.button = 1; /* #### Should try harder */
2970 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2972 event->event.misc.x = point.x;
2973 event->event.misc.y = point.y;
2974 event->event.misc.function = Qdragdrop_drop_dispatch;
2976 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2977 for (i=0; i<filecount; i++)
2979 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2980 /* The URLs that we make here aren't correct according to section
2981 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2982 * because they may contain reserved characters. But that's OK -
2983 * they just need to be good enough to keep dragdrop.el happy. */
2984 fname = (char *)xmalloc (len+1);
2985 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2987 /* May be a shell link aka "shortcut" - replace fname if so */
2988 #if !(defined(CYGWIN) || defined(MINGW))
2989 /* cygwin doesn't define this COM stuff */
2990 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2994 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2995 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
2999 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
3002 OLECHAR wsz[PATH_MAX];
3003 WIN32_FIND_DATA wfd;
3004 LPSTR resolved = (char *) xmalloc (PATH_MAX+1);
3006 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX);
3008 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
3009 (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX,
3014 len = strlen (fname);
3017 ppf->lpVtbl->Release (ppf);
3020 psl->lpVtbl->Release (psl);
3026 filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5);
3027 strcpy (filename, "file:");
3028 cygwin_win32_to_posix_path_list (fname, filename+5);
3030 filename = (char *)xmalloc (len+6);
3031 strcat (strcpy (filename, "file:"), fname);
3032 dostounix_filename (filename+5);
3035 l_item = make_string (filename, strlen (filename));
3036 l_dndlist = Fcons (l_item, l_dndlist);
3039 DragFinish ((HDROP) wParam);
3041 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3042 mswindows_enqueue_dispatch_event (emacs_event);
3050 return DefWindowProc (hwnd, message_, wParam, lParam);
3056 /************************************************************************/
3057 /* keyboard, mouse & other helpers for the windows procedure */
3058 /************************************************************************/
3060 mswindows_set_chord_timer (HWND hwnd)
3064 /* We get one third half system double click threshold */
3065 if (mswindows_mouse_button_tolerance <= 0)
3066 interval = GetDoubleClickTime () / 3;
3068 interval = mswindows_mouse_button_tolerance;
3070 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3074 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3077 if (mswindows_mouse_button_max_skew_x <= 0)
3078 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3080 dx = mswindows_mouse_button_max_skew_x;
3082 if (mswindows_mouse_button_max_skew_y <= 0)
3083 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3085 dy = mswindows_mouse_button_max_skew_y;
3087 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3091 mswindows_current_layout_has_AltGr (void)
3093 /* This simple caching mechanism saves 10% of CPU
3094 time when a key typed at autorepeat rate of 30 cps! */
3095 static HKL last_hkl = 0;
3096 static int last_hkl_has_AltGr;
3097 HKL current_hkl = (HKL) -1;
3099 if (xGetKeyboardLayout) /* not in NT 3.5 */
3100 current_hkl = xGetKeyboardLayout (0);
3101 if (current_hkl != last_hkl)
3104 last_hkl_has_AltGr = 0;
3105 /* In this loop, we query whether a character requires
3106 AltGr to be down to generate it. If at least such one
3107 found, this means that the layout does regard AltGr */
3108 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3109 if (HIBYTE (VkKeyScan (c)) == 6)
3110 last_hkl_has_AltGr = 1;
3111 last_hkl = current_hkl;
3113 return last_hkl_has_AltGr;
3117 /* Returns the state of the modifier keys in the format expected by the
3118 * Lisp_Event key_data, button_data and motion_data modifiers member */
3120 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3123 int keys_is_real = 0;
3126 if (fwKeys == (DWORD) -1)
3127 fwKeys = mswindows_last_mouse_button_state;
3131 mswindows_last_mouse_button_state = fwKeys;
3137 GetKeyboardState (keymap);
3138 has_AltGr = mswindows_current_layout_has_AltGr ();
3141 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3143 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3145 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3146 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3150 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3151 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3154 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3155 ? XEMACS_MOD_SHIFT : 0;
3156 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3157 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3158 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3164 * Translate a mswindows virtual key to a keysym.
3165 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3166 * or whose ASCII codes (like space) xemacs doesn't like.
3168 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3171 if (extendedp) /* Keys not present on a 82 key keyboard */
3173 switch (mswindows_key)
3175 case VK_CANCEL: return KEYSYM ("pause");
3176 case VK_RETURN: return KEYSYM ("kp-enter");
3177 case VK_PRIOR: return KEYSYM ("prior");
3178 case VK_NEXT: return KEYSYM ("next");
3179 case VK_END: return KEYSYM ("end");
3180 case VK_HOME: return KEYSYM ("home");
3181 case VK_LEFT: return KEYSYM ("left");
3182 case VK_UP: return KEYSYM ("up");
3183 case VK_RIGHT: return KEYSYM ("right");
3184 case VK_DOWN: return KEYSYM ("down");
3185 case VK_INSERT: return KEYSYM ("insert");
3186 case VK_DELETE: return QKdelete;
3187 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3188 case VK_LWIN return KEYSYM ("");
3189 case VK_RWIN return KEYSYM ("");
3191 case VK_APPS: return KEYSYM ("menu");
3196 switch (mswindows_key)
3198 case VK_BACK: return QKbackspace;
3199 case VK_TAB: return QKtab;
3200 case '\n': return QKlinefeed;
3201 case VK_CLEAR: return KEYSYM ("clear");
3202 case VK_RETURN: return QKreturn;
3203 case VK_PAUSE: return KEYSYM ("pause");
3204 case VK_ESCAPE: return QKescape;
3205 case VK_SPACE: return QKspace;
3206 case VK_PRIOR: return KEYSYM ("kp-prior");
3207 case VK_NEXT: return KEYSYM ("kp-next");
3208 case VK_END: return KEYSYM ("kp-end");
3209 case VK_HOME: return KEYSYM ("kp-home");
3210 case VK_LEFT: return KEYSYM ("kp-left");
3211 case VK_UP: return KEYSYM ("kp-up");
3212 case VK_RIGHT: return KEYSYM ("kp-right");
3213 case VK_DOWN: return KEYSYM ("kp-down");
3214 case VK_SELECT: return KEYSYM ("select");
3215 case VK_PRINT: return KEYSYM ("print");
3216 case VK_EXECUTE: return KEYSYM ("execute");
3217 case VK_SNAPSHOT: return KEYSYM ("print");
3218 case VK_INSERT: return KEYSYM ("kp-insert");
3219 case VK_DELETE: return KEYSYM ("kp-delete");
3220 case VK_HELP: return KEYSYM ("help");
3221 case VK_NUMPAD0: return KEYSYM ("kp-0");
3222 case VK_NUMPAD1: return KEYSYM ("kp-1");
3223 case VK_NUMPAD2: return KEYSYM ("kp-2");
3224 case VK_NUMPAD3: return KEYSYM ("kp-3");
3225 case VK_NUMPAD4: return KEYSYM ("kp-4");
3226 case VK_NUMPAD5: return KEYSYM ("kp-5");
3227 case VK_NUMPAD6: return KEYSYM ("kp-6");
3228 case VK_NUMPAD7: return KEYSYM ("kp-7");
3229 case VK_NUMPAD8: return KEYSYM ("kp-8");
3230 case VK_NUMPAD9: return KEYSYM ("kp-9");
3231 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3232 case VK_ADD: return KEYSYM ("kp-add");
3233 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3234 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3235 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3236 case VK_DIVIDE: return KEYSYM ("kp-divide");
3237 case VK_F1: return KEYSYM ("f1");
3238 case VK_F2: return KEYSYM ("f2");
3239 case VK_F3: return KEYSYM ("f3");
3240 case VK_F4: return KEYSYM ("f4");
3241 case VK_F5: return KEYSYM ("f5");
3242 case VK_F6: return KEYSYM ("f6");
3243 case VK_F7: return KEYSYM ("f7");
3244 case VK_F8: return KEYSYM ("f8");
3245 case VK_F9: return KEYSYM ("f9");
3246 case VK_F10: return KEYSYM ("f10");
3247 case VK_F11: return KEYSYM ("f11");
3248 case VK_F12: return KEYSYM ("f12");
3249 case VK_F13: return KEYSYM ("f13");
3250 case VK_F14: return KEYSYM ("f14");
3251 case VK_F15: return KEYSYM ("f15");
3252 case VK_F16: return KEYSYM ("f16");
3253 case VK_F17: return KEYSYM ("f17");
3254 case VK_F18: return KEYSYM ("f18");
3255 case VK_F19: return KEYSYM ("f19");
3256 case VK_F20: return KEYSYM ("f20");
3257 case VK_F21: return KEYSYM ("f21");
3258 case VK_F22: return KEYSYM ("f22");
3259 case VK_F23: return KEYSYM ("f23");
3260 case VK_F24: return KEYSYM ("f24");
3267 * Find the console that matches the supplied mswindows window handle
3270 mswindows_find_console (HWND hwnd)
3272 /* We only support one console */
3273 return XCAR (Vconsole_list);
3277 * Find the frame that matches the supplied mswindows window handle
3280 mswindows_find_frame (HWND hwnd)
3282 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3286 /* We are in progress of frame creation. Return the frame
3287 being created, as it still not remembered in the window
3289 assert (!NILP (Vmswindows_frame_being_created));
3290 return Vmswindows_frame_being_created;
3292 VOID_TO_LISP (f, l);
3297 /************************************************************************/
3299 /************************************************************************/
3302 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3305 EMACS_TIME current_time;
3306 EMACS_GET_TIME (current_time);
3307 EMACS_SUB_TIME (thyme, thyme, current_time);
3308 milliseconds = EMACS_SECS (thyme) * 1000 +
3309 (EMACS_USECS (thyme) + 500) / 1000;
3310 if (milliseconds < 1)
3312 ++mswindows_pending_timers_count;
3313 return SetTimer (NULL, 0, milliseconds,
3314 (TIMERPROC) mswindows_wm_timer_callback);
3318 emacs_mswindows_remove_timeout (int id)
3320 Lisp_Event match_against;
3321 Lisp_Object emacs_event;
3323 if (KillTimer (NULL, id))
3324 --mswindows_pending_timers_count;
3326 /* If there is a dispatch event generated by this
3327 timeout in the queue, we have to remove it too. */
3328 match_against.event_type = timeout_event;
3329 match_against.event.timeout.interval_id = id;
3330 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3331 if (!NILP (emacs_event))
3332 Fdeallocate_event(emacs_event);
3335 /* If `user_p' is false, then return whether there are any win32, timeout,
3336 * or subprocess events pending (that is, whether
3337 * emacs_mswindows_next_event() would return immediately without blocking).
3339 * if `user_p' is true, then return whether there are any *user generated*
3340 * events available (that is, whether there are keyboard or mouse-click
3341 * events ready to be read). This also implies that
3342 * emacs_mswindows_next_event() would not block.
3345 emacs_mswindows_event_pending_p (int user_p)
3347 mswindows_need_event (0);
3348 return (!NILP (mswindows_u_dispatch_event_queue)
3349 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3353 * Return the next event
3356 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3358 Lisp_Object event, event2;
3360 mswindows_need_event (1);
3362 event = mswindows_dequeue_dispatch_event ();
3363 XSETEVENT (event2, emacs_event);
3364 Fcopy_event (event, event2);
3365 Fdeallocate_event (event);
3369 * Handle a magic event off the dispatch queue.
3372 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3374 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3381 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3382 mswindows_handle_paint (f);
3383 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3390 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3391 struct frame *f = XFRAME (frame);
3392 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3394 struct gcpro gcpro1;
3396 /* On focus change, clear all memory of sticky modifiers
3397 to avoid non-intuitive behavior. */
3398 clear_sticky_modifiers ();
3400 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3402 emacs_handle_focus_change_preliminary (conser);
3403 /* Under X the stuff up to here is done in the X event handler.
3405 emacs_handle_focus_change_final (conser);
3414 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3415 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3417 Qmap_frame_hook : Qunmap_frame_hook,
3422 /* #### What about Enter & Leave */
3424 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3425 Qmouse_leave_frame_hook, 1, frame);
3433 #ifndef HAVE_MSG_SELECT
3435 get_process_input_waitable (Lisp_Process *process)
3437 Lisp_Object instr, outstr, p;
3438 XSETPROCESS (p, process);
3439 get_process_streams (process, &instr, &outstr);
3440 assert (!NILP (instr));
3441 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3442 return (network_connection_p (p)
3443 ? get_winsock_stream_waitable (XLSTREAM (instr))
3444 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3446 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3451 emacs_mswindows_select_process (Lisp_Process *process)
3453 HANDLE hev = get_process_input_waitable (process);
3455 if (!add_waitable_handle (hev))
3456 error ("Too many active processes");
3458 #ifdef HAVE_WIN32_PROCESSES
3461 XSETPROCESS (p, process);
3462 if (!network_connection_p (p))
3464 HANDLE hprocess = get_nt_process_handle (process);
3465 if (!add_waitable_handle (hprocess))
3467 remove_waitable_handle (hev);
3468 error ("Too many active processes");
3476 emacs_mswindows_unselect_process (Lisp_Process *process)
3478 /* Process handle is removed in the event loop as soon
3479 as it is signaled, so don't bother here about it */
3480 HANDLE hev = get_process_input_waitable (process);
3481 remove_waitable_handle (hev);
3483 #endif /* HAVE_MSG_SELECT */
3486 emacs_mswindows_select_console (struct console *con)
3488 #ifdef HAVE_MSG_SELECT
3489 if (CONSOLE_MSWINDOWS_P (con))
3490 return; /* mswindows consoles are automatically selected */
3492 event_stream_unixoid_select_console (con);
3497 emacs_mswindows_unselect_console (struct console *con)
3499 #ifdef HAVE_MSG_SELECT
3500 if (CONSOLE_MSWINDOWS_P (con))
3501 return; /* mswindows consoles are automatically selected */
3503 event_stream_unixoid_unselect_console (con);
3508 emacs_mswindows_quit_p (void)
3510 /* Quit cannot happen in modal loop: all program
3511 input is dedicated to Windows. */
3512 if (mswindows_in_modal_loop)
3515 mswindows_quit_chars_count = 0;
3516 /* Drain windows queue. This sets up number of quit characters in
3518 mswindows_drain_windows_queue ();
3520 if (mswindows_quit_chars_count > 0)
3522 /* Yes there's a hidden one... Throw it away */
3523 Lisp_Event match_against;
3524 Lisp_Object emacs_event;
3527 match_against.event_type = key_press_event;
3528 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3530 while (mswindows_quit_chars_count > 0)
3532 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3533 assert (!NILP (emacs_event));
3535 if (XEVENT (emacs_event)->event.key.modifiers &
3536 FAKE_MOD_QUIT_CRITICAL)
3539 Fdeallocate_event (emacs_event);
3540 mswindows_quit_chars_count--;
3543 Vquit_flag = critical_p ? Qcritical : Qt;
3548 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3549 Lisp_Object* instream,
3550 Lisp_Object* outstream,
3553 /* Handles for streams */
3555 /* fds. These just stored along with the streams, and are closed in
3556 delete stream pair method, because we need to handle fake unices
3560 /* Decode inhandle and outhandle. Their meaning depends on
3561 the process implementation being used. */
3562 #if defined (HAVE_WIN32_PROCESSES)
3563 /* We're passed in Windows handles. That's what we like most... */
3564 hin = (HANDLE) inhandle;
3565 hout = (HANDLE) outhandle;
3567 #elif defined (HAVE_UNIX_PROCESSES)
3568 /* We are passed UNIX fds. This must be Cygwin.
3570 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3571 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3575 #error "So, WHICH kind of processes do you want?"
3578 *instream = (hin == INVALID_HANDLE_VALUE
3580 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3581 : flags & STREAM_NETWORK_CONNECTION
3582 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3584 : make_ntpipe_input_stream (hin, fdi));
3586 #ifdef HAVE_WIN32_PROCESSES
3587 *outstream = (hout == INVALID_HANDLE_VALUE
3589 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3590 : flags & STREAM_NETWORK_CONNECTION
3591 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3593 : make_ntpipe_output_stream (hout, fdo));
3594 #elif defined (HAVE_UNIX_PROCESSES)
3595 *outstream = (fdo >= 0
3596 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3599 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3600 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3601 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3603 Bufbyte eof_char = get_eof_char (fdo);
3604 int pty_max_bytes = get_pty_max_bytes (fdo);
3605 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3610 return (NILP (*instream)
3612 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3613 : flags & STREAM_NETWORK_CONNECTION
3614 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3616 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3620 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3621 Lisp_Object outstream)
3623 /* Oh nothing special here for Win32 at all */
3624 #if defined (HAVE_UNIX_PROCESSES)
3625 int in = (NILP(instream)
3627 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3628 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3629 ? get_winsock_stream_param (XLSTREAM (instream))
3631 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3632 int out = (NILP(outstream) ? -1
3633 : filedesc_stream_fd (XLSTREAM (outstream)));
3637 if (out != in && out >= 0)
3641 return (NILP (instream)
3643 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3644 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3645 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3647 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3651 emacs_mswindows_current_event_timestamp (struct console *c)
3653 return GetTickCount ();
3656 #ifndef HAVE_X_WINDOWS
3657 /* This is called from GC when a process object is about to be freed.
3658 If we've still got pointers to it in this file, we're gonna lose hard.
3661 debug_process_finalization (Lisp_Process *p)
3664 Lisp_Object instr, outstr;
3666 get_process_streams (p, &instr, &outstr);
3667 /* if it still has fds, then it hasn't been killed yet. */
3668 assert (NILP(instr));
3669 assert (NILP(outstr));
3671 /* #### More checks here */
3678 struct mswin_message_debug
3684 #define FROB(val) { val, #val, },
3686 struct mswin_message_debug debug_mswin_messages[] =
3702 FROB (WM_GETTEXTLENGTH)
3705 FROB (WM_QUERYENDSESSION)
3708 FROB (WM_ERASEBKGND)
3709 FROB (WM_SYSCOLORCHANGE)
3710 FROB (WM_ENDSESSION)
3711 FROB (WM_SHOWWINDOW)
3712 FROB (WM_WININICHANGE)
3713 #if(WINVER >= 0x0400)
3714 FROB (WM_SETTINGCHANGE)
3715 #endif /* WINVER >= 0x0400 */
3717 FROB (WM_DEVMODECHANGE)
3718 FROB (WM_ACTIVATEAPP)
3719 FROB (WM_FONTCHANGE)
3720 FROB (WM_TIMECHANGE)
3721 FROB (WM_CANCELMODE)
3723 FROB (WM_MOUSEACTIVATE)
3724 FROB (WM_CHILDACTIVATE)
3727 FROB (WM_GETMINMAXINFO)
3730 FROB (WM_ICONERASEBKGND)
3731 FROB (WM_NEXTDLGCTL)
3732 FROB (WM_SPOOLERSTATUS)
3734 FROB (WM_MEASUREITEM)
3735 FROB (WM_DELETEITEM)
3736 FROB (WM_VKEYTOITEM)
3737 FROB (WM_CHARTOITEM)
3742 FROB (WM_QUERYDRAGICON)
3743 FROB (WM_COMPAREITEM)
3744 #if(WINVER >= 0x0500)
3746 #endif /* WINVER >= 0x0500 */
3747 FROB (WM_COMPACTING)
3748 FROB (WM_COMMNOTIFY)
3749 FROB (WM_WINDOWPOSCHANGING)
3750 FROB (WM_WINDOWPOSCHANGED)
3755 FROB (WM_CANCELJOURNAL)
3757 #if(WINVER >= 0x0400)
3759 FROB (WM_INPUTLANGCHANGEREQUEST)
3760 FROB (WM_INPUTLANGCHANGE)
3763 FROB (WM_USERCHANGED)
3764 FROB (WM_NOTIFYFORMAT)
3766 FROB (WM_CONTEXTMENU)
3767 FROB (WM_STYLECHANGING)
3768 FROB (WM_STYLECHANGED)
3769 FROB (WM_DISPLAYCHANGE)
3772 #endif /* WINVER >= 0x0400 */
3776 FROB (WM_NCCALCSIZE)
3779 FROB (WM_NCACTIVATE)
3780 FROB (WM_GETDLGCODE)
3781 #ifdef WM_SYNCPAINT /* not in VC 5 */
3783 #endif /* WM_SYNCPAINT */
3784 FROB (WM_NCMOUSEMOVE)
3785 FROB (WM_NCLBUTTONDOWN)
3786 FROB (WM_NCLBUTTONUP)
3787 FROB (WM_NCLBUTTONDBLCLK)
3788 FROB (WM_NCRBUTTONDOWN)
3789 FROB (WM_NCRBUTTONUP)
3790 FROB (WM_NCRBUTTONDBLCLK)
3791 FROB (WM_NCMBUTTONDOWN)
3792 FROB (WM_NCMBUTTONUP)
3793 FROB (WM_NCMBUTTONDBLCLK)
3795 /* FROB (WM_KEYFIRST) */
3800 FROB (WM_SYSKEYDOWN)
3803 FROB (WM_SYSDEADCHAR)
3806 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION)
3807 FROB (WM_IME_STARTCOMPOSITION)
3808 FROB (WM_IME_ENDCOMPOSITION)
3809 FROB (WM_IME_COMPOSITION)
3810 FROB (WM_IME_KEYLAST)
3811 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */
3813 FROB (WM_INITDIALOG)
3815 FROB (WM_SYSCOMMAND)
3820 FROB (WM_INITMENUPOPUP)
3821 FROB (WM_MENUSELECT)
3824 #if(WINVER >= 0x0500)
3825 FROB (WM_MENURBUTTONUP)
3827 FROB (WM_MENUGETOBJECT)
3828 FROB (WM_UNINITMENUPOPUP)
3829 FROB (WM_MENUCOMMAND)
3830 #endif /* WINVER >= 0x0500 */
3833 FROB (WM_CTLCOLORMSGBOX)
3834 FROB (WM_CTLCOLOREDIT)
3835 FROB (WM_CTLCOLORLISTBOX)
3836 FROB (WM_CTLCOLORBTN)
3837 FROB (WM_CTLCOLORDLG)
3838 FROB (WM_CTLCOLORSCROLLBAR)
3839 FROB (WM_CTLCOLORSTATIC)
3842 /* FROB (WM_MOUSEFIRST) */
3844 FROB (WM_LBUTTONDOWN)
3846 FROB (WM_LBUTTONDBLCLK)
3847 FROB (WM_RBUTTONDOWN)
3849 FROB (WM_RBUTTONDBLCLK)
3850 FROB (WM_MBUTTONDOWN)
3852 FROB (WM_MBUTTONDBLCLK)
3854 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
3855 FROB (WM_MOUSEWHEEL)
3859 #endif /* if (_WIN32_WINNT < 0x0400) */
3861 FROB (WM_PARENTNOTIFY)
3862 FROB (WM_ENTERMENULOOP)
3863 FROB (WM_EXITMENULOOP)
3865 #if(WINVER >= 0x0400)
3869 FROB (WM_CAPTURECHANGED)
3871 FROB (WM_POWERBROADCAST)
3873 FROB (WM_DEVICECHANGE)
3875 #endif /* WINVER >= 0x0400 */
3878 FROB (WM_MDIDESTROY)
3879 FROB (WM_MDIACTIVATE)
3880 FROB (WM_MDIRESTORE)
3882 FROB (WM_MDIMAXIMIZE)
3884 FROB (WM_MDICASCADE)
3885 FROB (WM_MDIICONARRANGE)
3886 FROB (WM_MDIGETACTIVE)
3889 FROB (WM_MDISETMENU)
3890 FROB (WM_ENTERSIZEMOVE)
3891 FROB (WM_EXITSIZEMOVE)
3893 FROB (WM_MDIREFRESHMENU)
3895 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */
3897 #if(WINVER >= 0x0400) && !defined(CYGWIN)
3898 FROB (WM_IME_SETCONTEXT)
3899 FROB (WM_IME_NOTIFY)
3900 FROB (WM_IME_CONTROL)
3901 FROB (WM_IME_COMPOSITIONFULL)
3902 FROB (WM_IME_SELECT)
3904 #endif /* WINVER >= 0x0400 */
3905 #if(WINVER >= 0x0500)
3906 FROB (WM_IME_REQUEST)
3907 #endif /* WINVER >= 0x0500 */
3908 #if(WINVER >= 0x0400) && !defined(CYGWIN)
3909 FROB (WM_IME_KEYDOWN)
3911 #endif /* WINVER >= 0x0400 */
3913 #endif /* WM_IME_SETCONTEXT */
3915 #if(_WIN32_WINNT >= 0x0400)
3916 FROB (WM_MOUSEHOVER)
3917 FROB (WM_MOUSELEAVE)
3918 #endif /* _WIN32_WINNT >= 0x0400 */
3925 FROB (WM_RENDERFORMAT)
3926 FROB (WM_RENDERALLFORMATS)
3927 FROB (WM_DESTROYCLIPBOARD)
3928 FROB (WM_DRAWCLIPBOARD)
3929 FROB (WM_PAINTCLIPBOARD)
3930 FROB (WM_VSCROLLCLIPBOARD)
3931 FROB (WM_SIZECLIPBOARD)
3932 FROB (WM_ASKCBFORMATNAME)
3933 FROB (WM_CHANGECBCHAIN)
3934 FROB (WM_HSCROLLCLIPBOARD)
3935 FROB (WM_QUERYNEWPALETTE)
3936 FROB (WM_PALETTEISCHANGING)
3937 FROB (WM_PALETTECHANGED)
3940 #if(WINVER >= 0x0400)
3942 FROB (WM_PRINTCLIENT)
3944 FROB (WM_HANDHELDFIRST)
3945 FROB (WM_HANDHELDLAST)
3949 #endif /* WINVER >= 0x0400 */
3951 FROB (WM_PENWINFIRST)
3952 FROB (WM_PENWINLAST)
3958 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
3961 Lisp_Object frame = mswindows_find_frame (hwnd);
3964 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */
3966 for (i = 0; i < countof (debug_mswin_messages); i++)
3968 if (debug_mswin_messages[i].mess == message_)
3970 str = debug_mswin_messages[i].string;
3976 stderr_out ("%s", str);
3978 stderr_out ("%x", message_);
3980 if (debug_mswindows_events > 1)
3982 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
3983 wParam, (int) lParam, (unsigned int) hwnd);
3984 debug_print (frame);
3990 #endif /* DEBUG_XEMACS */
3992 /************************************************************************/
3993 /* initialization */
3994 /************************************************************************/
3997 reinit_vars_of_event_mswindows (void)
3999 mswindows_in_modal_loop = 0;
4000 mswindows_pending_timers_count = 0;
4002 mswindows_event_stream = xnew (struct event_stream);
4004 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
4005 mswindows_event_stream->force_event_pending = 0;
4006 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
4007 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
4008 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
4009 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
4010 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
4011 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
4012 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
4013 #ifdef HAVE_MSG_SELECT
4014 mswindows_event_stream->select_process_cb =
4015 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
4016 mswindows_event_stream->unselect_process_cb =
4017 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
4018 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
4019 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
4021 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
4022 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
4023 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
4024 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
4026 mswindows_event_stream->current_event_timestamp_cb =
4027 emacs_mswindows_current_event_timestamp;
4031 vars_of_event_mswindows (void)
4033 reinit_vars_of_event_mswindows ();
4035 mswindows_u_dispatch_event_queue = Qnil;
4036 staticpro (&mswindows_u_dispatch_event_queue);
4037 mswindows_u_dispatch_event_queue_tail = Qnil;
4038 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
4040 mswindows_s_dispatch_event_queue = Qnil;
4041 staticpro (&mswindows_s_dispatch_event_queue);
4042 mswindows_s_dispatch_event_queue_tail = Qnil;
4043 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
4045 mswindows_error_caught_in_modal_loop = Qnil;
4046 staticpro (&mswindows_error_caught_in_modal_loop);
4050 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
4051 If non-zero, display debug information about Windows messages that XEmacs sees.
4052 Information is displayed in a console window. Currently defined values are:
4054 1 == non-verbose output (just the message name)
4055 2 == verbose output (all parameters)
4056 3 == even more verbose output (extra debugging info)
4058 debug_mswindows_events = 0;
4061 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
4062 &mswindows_alt_by_itself_activates_menu /*
4063 *Controls whether pressing and releasing the Alt key activates the menubar.
4064 This applies only if no intervening key was pressed. See also
4065 `menu-accelerator-enabled', which is probably the behavior you actually want.
4069 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
4070 &mswindows_dynamic_frame_resize /*
4071 *Controls redrawing frame contents during mouse-drag or keyboard resize
4072 operation. When non-nil, the frame is redrawn while being resized. When
4073 nil, frame is not redrawn, and exposed areas are filled with default
4074 MDI application background color. Note that this option only has effect
4075 if "Show window contents while dragging" is on in system Display/Plus!
4077 Default is t on fast machines, nil on slow.
4080 DEFVAR_INT ("mswindows-mouse-button-tolerance",
4081 &mswindows_mouse_button_tolerance /*
4082 *Analogue of double click interval for faking middle mouse events.
4083 The value is the minimum time in milliseconds that must elapse between
4084 left/right button down events before they are considered distinct events.
4085 If both mouse buttons are depressed within this interval, a middle mouse
4086 button down event is generated instead.
4087 If negative or zero, currently set system default is used instead.
4090 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
4091 Number of physical mouse buttons.
4094 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
4095 &mswindows_mouse_button_max_skew_x /*
4096 *Maximum horizontal distance in pixels between points in which left and
4097 right button clicks occurred for them to be translated into single
4098 middle button event. Clicks must occur in time not longer than defined
4099 by the variable `mswindows-mouse-button-tolerance'.
4100 If negative or zero, currently set system default is used instead.
4103 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
4104 &mswindows_mouse_button_max_skew_y /*
4105 *Maximum vertical distance in pixels between points in which left and
4106 right button clicks occurred for them to be translated into single
4107 middle button event. Clicks must occur in time not longer than defined
4108 by the variable `mswindows-mouse-button-tolerance'.
4109 If negative or zero, currently set system default is used instead.
4112 mswindows_mouse_button_max_skew_x = 0;
4113 mswindows_mouse_button_max_skew_y = 0;
4114 mswindows_mouse_button_tolerance = 0;
4115 mswindows_alt_by_itself_activates_menu = 1;
4119 syms_of_event_mswindows (void)
4124 lstream_type_create_mswindows_selectable (void)
4126 init_slurp_stream ();
4127 init_shove_stream ();
4128 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
4129 init_winsock_stream ();
4134 init_event_mswindows_late (void)
4136 #ifdef HAVE_MSG_SELECT
4137 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
4138 assert (windows_fd>=0);
4139 FD_SET (windows_fd, &input_wait_mask);
4140 FD_ZERO(&zero_mask);
4143 event_stream = mswindows_event_stream;
4145 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
4146 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);