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
1614 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1615 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1616 DWORD dwData1, DWORD dwData2)
1621 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1622 return (HDDEDATA)TRUE;
1623 return (HDDEDATA)FALSE;
1625 case XTYP_WILDCONNECT:
1627 /* We only support one {service,topic} pair */
1628 HSZPAIR pairs[2] = {
1629 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1631 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1632 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1633 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1634 sizeof (pairs), 0L, 0, uFmt, 0));
1636 return (HDDEDATA)NULL;
1639 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1641 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1642 LPBYTE cmd = (LPBYTE) alloca (len+1);
1645 struct gcpro gcpro1, gcpro2;
1646 Lisp_Object l_dndlist = Qnil;
1647 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1648 Lisp_Object frmcons, devcons, concons;
1649 Lisp_Event *event = XEVENT (emacs_event);
1651 DdeGetData (hdata, cmd, len, 0);
1653 DdeFreeDataHandle (hdata);
1655 /* Check syntax & that it's an [Open("foo")] command, which we
1656 * treat like a file drop */
1657 /* #### Ought to be generalised and accept some other commands */
1660 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1661 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1662 return DDE_FNOTPROCESSED;
1663 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1666 if (*cmd!='(' || *(cmd+1)!='\"')
1667 return DDE_FNOTPROCESSED;
1669 while (*end && *end!='\"')
1672 return DDE_FNOTPROCESSED;
1675 return DDE_FNOTPROCESSED;
1679 return DDE_FNOTPROCESSED;
1682 filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5);
1683 strcpy (filename, "file:");
1684 cygwin_win32_to_posix_path_list (cmd, filename+5);
1686 dostounix_filename (cmd);
1687 filename = alloca (strlen (cmd)+6);
1688 strcpy (filename, "file:");
1689 strcat (filename, cmd);
1691 GCPRO2 (emacs_event, l_dndlist);
1692 l_dndlist = make_string (filename, strlen (filename));
1694 /* Find a mswindows frame */
1695 event->channel = Qnil;
1696 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1698 Lisp_Object frame = XCAR (frmcons);
1699 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1700 event->channel = frame;
1702 assert (!NILP (event->channel));
1704 event->timestamp = GetTickCount();
1705 event->event_type = misc_user_event;
1706 event->event.misc.button = 1;
1707 event->event.misc.modifiers = 0;
1708 event->event.misc.x = -1;
1709 event->event.misc.y = -1;
1710 event->event.misc.function = Qdragdrop_drop_dispatch;
1711 event->event.misc.object = Fcons (Qdragdrop_URL,
1712 Fcons (l_dndlist, Qnil));
1713 mswindows_enqueue_dispatch_event (emacs_event);
1715 return (HDDEDATA) DDE_FACK;
1717 DdeFreeDataHandle (hdata);
1718 return (HDDEDATA) DDE_FNOTPROCESSED;
1721 return (HDDEDATA) NULL;
1727 * Helper to do repainting - repaints can happen both from the windows
1728 * procedure and from magic events
1731 mswindows_handle_paint (struct frame *frame)
1733 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1735 /* According to the docs we need to check GetUpdateRect() before
1736 actually doing a WM_PAINT */
1737 if (GetUpdateRect (hwnd, NULL, FALSE))
1739 PAINTSTRUCT paintStruct;
1740 int x, y, width, height;
1742 BeginPaint (hwnd, &paintStruct);
1743 x = paintStruct.rcPaint.left;
1744 y = paintStruct.rcPaint.top;
1745 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1746 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1747 /* Normally we want to ignore expose events when child
1748 windows are unmapped, however once we are in the guts of
1749 WM_PAINT we need to make sure that we don't register
1750 unmaps then because they will not actually occur. */
1751 /* #### commenting out the next line seems to fix some problems
1752 but not all. only andy currently understands this stuff and
1753 he needs to review it more carefully. --ben */
1754 if (!check_for_ignored_expose (frame, x, y, width, height))
1756 hold_ignored_expose_registration = 1;
1757 mswindows_redraw_exposed_area (frame, x, y, width, height);
1758 hold_ignored_expose_registration = 0;
1760 EndPaint (hwnd, &paintStruct);
1765 * Returns 1 if a key is a real modifier or special key, which
1766 * is better handled by DefWindowProc
1769 key_needs_default_processing_p (UINT vkey)
1771 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1772 /* if we let ALT activate the menu like this, then sticky ALT-modified
1773 keystrokes become impossible. */
1774 && !modifier_keys_are_sticky)
1780 /* key-handling code is always ugly. It just ends up working out
1783 #### Most of the sticky-modifier code below is copied from similar
1784 code in event-Xt.c. They should somehow or other be merged.
1786 Here are some pointers:
1788 -- DOWN_MASK indicates which modifiers should be treated as "down"
1789 when the corresponding upstroke happens. It gets reset for
1790 a particular modifier when that modifier goes up, and reset
1791 for all modifiers when a non-modifier key is pressed. Example:
1793 I press Control-A-Shift and then release Control-A-Shift.
1794 I want the Shift key to be sticky but not the Control key.
1796 -- If a modifier key is sticky, I can unstick it by pressing
1797 the modifier key again. */
1799 static WPARAM last_downkey;
1800 static int need_to_add_mask, down_mask;
1802 #define XEMSW_LCONTROL (1<<0)
1803 #define XEMSW_RCONTROL (1<<1)
1804 #define XEMSW_LSHIFT (1<<2)
1805 #define XEMSW_RSHIFT (1<<3)
1806 #define XEMSW_LMENU (1<<4)
1807 #define XEMSW_RMENU (1<<5)
1810 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1811 int downp, int keyp)
1815 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1819 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1820 wParam == VK_RCONTROL ||
1821 wParam == VK_MENU || wParam == VK_LMENU ||
1822 wParam == VK_RMENU ||
1823 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1824 wParam == VK_RSHIFT)))
1825 { /* Not a modifier key */
1826 if (downp && keyp && !last_downkey)
1827 last_downkey = wParam;
1828 /* If I hold press-and-release the Control key and then press
1829 and hold down the right arrow, I want it to auto-repeat
1830 Control-Right. On the other hand, if I do the same but
1831 manually press the Right arrow a bunch of times, I want
1832 to see one Control-Right and then a bunch of Rights.
1833 This means that we need to distinguish between an
1834 auto-repeated key and a key pressed and released a bunch
1836 else if ((downp && !keyp) ||
1837 (downp && keyp && last_downkey &&
1838 (wParam != last_downkey ||
1839 /* the "previous key state" bit indicates autorepeat */
1840 ! (lParam & (1 << 30)))))
1842 need_to_add_mask = 0;
1848 mods = need_to_add_mask;
1850 else /* Modifier key pressed */
1852 /* If a non-modifier key was pressed in the middle of a bunch
1853 of modifiers, then it unsticks all the modifiers that were
1854 previously pressed. We cannot unstick the modifiers until
1855 now because we want to check for auto-repeat of the
1856 non-modifier key. */
1861 need_to_add_mask = 0;
1864 #define FROB(mask) \
1866 if (downp && keyp) \
1868 /* If modifier key is already sticky, \
1869 then unstick it. Note that we do \
1870 not test down_mask to deal with the \
1871 unlikely but possible case that the \
1872 modifier key auto-repeats. */ \
1873 if (need_to_add_mask & mask) \
1875 need_to_add_mask &= ~mask; \
1876 down_mask &= ~mask; \
1879 down_mask |= mask; \
1883 if (down_mask & mask) \
1885 down_mask &= ~mask; \
1886 need_to_add_mask |= mask; \
1891 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1892 || wParam == VK_RCONTROL)
1893 FROB (XEMSW_RCONTROL);
1894 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1895 || wParam == VK_LCONTROL)
1896 FROB (XEMSW_LCONTROL);
1898 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1899 || wParam == VK_RSHIFT)
1900 FROB (XEMSW_RSHIFT);
1901 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1902 || wParam == VK_LSHIFT)
1903 FROB (XEMSW_LSHIFT);
1905 if ((wParam == VK_MENU && (lParam & 0x1000000))
1906 || wParam == VK_RMENU)
1908 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1909 || wParam == VK_LMENU)
1918 GetKeyboardState (keymap);
1920 if (mods & XEMSW_LCONTROL)
1922 keymap [VK_CONTROL] |= 0x80;
1923 keymap [VK_LCONTROL] |= 0x80;
1925 if (mods & XEMSW_RCONTROL)
1927 keymap [VK_CONTROL] |= 0x80;
1928 keymap [VK_RCONTROL] |= 0x80;
1931 if (mods & XEMSW_LSHIFT)
1933 keymap [VK_SHIFT] |= 0x80;
1934 keymap [VK_LSHIFT] |= 0x80;
1936 if (mods & XEMSW_RSHIFT)
1938 keymap [VK_SHIFT] |= 0x80;
1939 keymap [VK_RSHIFT] |= 0x80;
1942 if (mods & XEMSW_LMENU)
1944 keymap [VK_MENU] |= 0x80;
1945 keymap [VK_LMENU] |= 0x80;
1947 if (mods & XEMSW_RMENU)
1949 keymap [VK_MENU] |= 0x80;
1950 keymap [VK_RMENU] |= 0x80;
1953 SetKeyboardState (keymap);
1961 clear_sticky_modifiers (void)
1963 need_to_add_mask = 0;
1973 output_modifier_keyboard_state (void)
1977 GetKeyboardState (keymap);
1979 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
1980 keymap[VK_MENU] & 0x80 ? 1 : 0,
1981 keymap[VK_MENU] & 0x1 ? 1 : 0,
1982 keymap[VK_LMENU] & 0x80 ? 1 : 0,
1983 keymap[VK_LMENU] & 0x1 ? 1 : 0,
1984 keymap[VK_RMENU] & 0x80 ? 1 : 0,
1985 keymap[VK_RMENU] & 0x1 ? 1 : 0);
1986 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
1987 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
1988 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
1989 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
1990 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
1991 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
1992 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
1993 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
1994 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
1995 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
1996 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
1997 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
1998 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
1999 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
2004 /* try to debug the stuck-alt-key problem.
2006 #### this happens only inconsistently, and may only happen when using
2007 StickyKeys in the Win2000 accessibility section of the control panel,
2008 which is extremely broken for other reasons. */
2011 output_alt_keyboard_state (void)
2015 // SHORT asyncstate[3];
2017 GetKeyboardState (keymap);
2018 keystate[0] = GetKeyState (VK_MENU);
2019 keystate[1] = GetKeyState (VK_LMENU);
2020 keystate[2] = GetKeyState (VK_RMENU);
2021 /* Doing this interferes with key processing. */
2022 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2023 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2024 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2026 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2027 keymap[VK_MENU] & 0x80 ? 1 : 0,
2028 keymap[VK_MENU] & 0x1 ? 1 : 0,
2029 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2030 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2031 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2032 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2033 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2034 keystate[0] & 0x8000 ? 1 : 0,
2035 keystate[0] & 0x1 ? 1 : 0,
2036 keystate[1] & 0x8000 ? 1 : 0,
2037 keystate[1] & 0x1 ? 1 : 0,
2038 keystate[2] & 0x8000 ? 1 : 0,
2039 keystate[2] & 0x1 ? 1 : 0);
2040 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2041 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2042 /* asyncstate[0] & 0x1 ? 1 : 0, */
2043 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2044 /* asyncstate[1] & 0x1 ? 1 : 0, */
2045 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2046 /* asyncstate[2] & 0x1 ? 1 : 0); */
2049 #endif /* DEBUG_XEMACS */
2053 * The windows procedure for the window class XEMACS_CLASS
2056 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2058 /* Note: Remember to initialize emacs_event and event before use.
2059 This code calls code that can GC. You must GCPRO before calling such code. */
2060 Lisp_Object emacs_event = Qnil;
2061 Lisp_Object fobj = Qnil;
2064 struct frame *frame;
2065 struct mswindows_frame* msframe;
2067 /* Not perfect but avoids crashes. There is potential for wierd
2071 mswindows_output_console_string ("Window procedure called during GC???????\n", 41);
2072 /* Yes, this assert always triggers in a --debug XEmacs. But
2073 --debug=no is default in the stable branches.
2074 #### How about patch in <200106081225.IAA31075@gwyn.tux.org>? */
2075 assert (!gc_in_progress);
2080 if (debug_mswindows_events)
2081 debug_output_mswin_message (hwnd, message_, wParam, lParam);
2082 #endif /* DEBUG_XEMACS */
2084 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2087 case WM_DESTROYCLIPBOARD:
2088 /* We own the clipboard and someone else wants it. Delete our
2089 cached copy of the clipboard contents so we'll ask for it from
2090 Windows again when someone does a paste, and destroy any memory
2091 objects we hold on the clipboard that are not in the list of types
2092 that Windows will delete itself. */
2093 mswindows_destroy_selection (QCLIPBOARD);
2094 handle_selection_clear (QCLIPBOARD);
2098 /* Erase background only during non-dynamic sizing */
2099 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2100 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2105 fobj = mswindows_find_frame (hwnd);
2106 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2112 /* See Win95 comment under WM_KEYDOWN */
2115 int should_set_keymap = 0;
2118 if (debug_mswindows_events > 2)
2119 output_alt_keyboard_state ();
2120 #endif /* DEBUG_XEMACS */
2122 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2123 if (wParam == VK_CONTROL)
2125 GetKeyboardState (keymap);
2126 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2127 should_set_keymap = 1;
2129 else if (wParam == VK_MENU)
2131 GetKeyboardState (keymap);
2132 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2133 should_set_keymap = 1;
2136 if (should_set_keymap)
2137 // && (message_ != WM_SYSKEYUP
2138 // || NILP (Vmenu_accelerator_enabled)))
2139 SetKeyboardState (keymap);
2143 if (key_needs_default_processing_p (wParam))
2151 /* In some locales the right-hand Alt key is labelled AltGr. This key
2152 * should produce alternative characters when combined with another key.
2153 * eg on a German keyboard pressing AltGr+q should produce '@'.
2154 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2155 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2156 * it translates as if AltGr were down.
2157 * We get round this by removing all modifiers from the keymap before
2158 * calling TranslateMessage() unless AltGr is *really* down. */
2160 BYTE keymap_trans[256];
2161 BYTE keymap_orig[256];
2162 BYTE keymap_sticky[256];
2163 int has_AltGr = mswindows_current_layout_has_AltGr ();
2164 int mods = 0, mods_with_shift = 0;
2165 int extendedp = lParam & 0x1000000;
2170 if (debug_mswindows_events > 2)
2171 output_alt_keyboard_state ();
2172 #endif /* DEBUG_XEMACS */
2174 GetKeyboardState (keymap_orig);
2175 frame = XFRAME (mswindows_find_frame (hwnd));
2176 if ((sticky_changed =
2177 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2179 GetKeyboardState (keymap_sticky);
2180 if (keymap_sticky[VK_MENU] & 0x80)
2182 message_ = WM_SYSKEYDOWN;
2183 /* We have to set the "context bit" so that the
2184 TranslateMessage() call below that generates the
2185 SYSCHAR message does its thing; see the documentation
2191 memcpy (keymap_sticky, keymap_orig, 256);
2193 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2194 mods_with_shift = mods;
2196 /* Handle non-printables */
2197 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2200 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2202 SetKeyboardState (keymap_orig);
2204 else /* Normal keys & modifiers */
2207 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2208 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2210 int potential_accelerator = 0;
2211 int got_accelerator = 0;
2214 msg.message = message_;
2215 msg.wParam = wParam;
2216 msg.lParam = lParam;
2217 msg.time = GetMessageTime();
2220 /* GetKeyboardState() does not work as documented on Win95. We have
2221 * to loosely track Left and Right modifiers on behalf of the OS,
2222 * without screwing up Windows NT which tracks them properly. */
2223 if (wParam == VK_CONTROL)
2225 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2226 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2228 else if (wParam == VK_MENU)
2230 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2231 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2234 if (!NILP (Vmenu_accelerator_enabled) &&
2235 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2236 potential_accelerator = 1;
2238 /* Remove shift modifier from an ascii character */
2239 mods &= ~XEMACS_MOD_SHIFT;
2241 memcpy (keymap_trans, keymap_sticky, 256);
2243 /* Clear control and alt modifiers unless AltGr is pressed */
2244 keymap_trans[VK_RCONTROL] = 0;
2245 keymap_trans[VK_LMENU] = 0;
2246 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2247 || !(keymap_trans[VK_RMENU] & 0x80))
2249 keymap_trans[VK_LCONTROL] = 0;
2250 keymap_trans[VK_CONTROL] = 0;
2251 keymap_trans[VK_RMENU] = 0;
2252 keymap_trans[VK_MENU] = 0;
2254 SetKeyboardState (keymap_trans);
2256 /* Maybe generate some WM_[SYS]CHARs in the queue */
2257 TranslateMessage (&msg);
2259 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2260 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2263 int mods_with_quit = mods;
2264 WPARAM ch = tranmsg.wParam;
2267 if (debug_mswindows_events)
2270 debug_output_mswin_message (tranmsg.hwnd, tranmsg.message,
2274 #endif /* DEBUG_XEMACS */
2276 /* If a quit char with no modifiers other than control and
2277 shift, then mark it with a fake modifier, which is removed
2278 upon dequeueing the event */
2279 /* !!#### Fix this in my mule ws -- replace current_buffer
2281 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2282 && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2283 DOWNCASE (current_buffer, ch))
2284 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2285 && DOWNCASE (current_buffer, quit_ch) ==
2286 DOWNCASE (current_buffer, ch)))
2287 && ((mods_with_shift &
2288 ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2291 mods_with_quit |= FAKE_MOD_QUIT;
2292 if (mods_with_shift & XEMACS_MOD_SHIFT)
2293 mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2294 mswindows_quit_chars_count++;
2296 else if (potential_accelerator && !got_accelerator &&
2297 mswindows_char_is_accelerator (frame, ch))
2299 got_accelerator = 1;
2302 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2306 /* This generates WM_SYSCHAR messages, which are interpreted
2307 by DefWindowProc as the menu selections. */
2308 if (got_accelerator)
2310 SetKeyboardState (keymap_sticky);
2311 TranslateMessage (&msg);
2312 SetKeyboardState (keymap_orig);
2316 SetKeyboardState (keymap_orig);
2320 if (key_needs_default_processing_p (wParam))
2325 case WM_MBUTTONDOWN:
2327 /* Real middle mouse button has nothing to do with emulated one:
2328 if one wants to exercise fingers playing chords on the mouse,
2329 he is allowed to do that! */
2330 mswindows_enqueue_mouse_button_event (hwnd, message_,
2331 MAKEPOINTS (lParam),
2332 wParam &~ MK_MBUTTON,
2337 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2338 msframe->last_click_time = GetMessageTime();
2340 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2341 msframe->button2_need_lbutton = 0;
2342 if (msframe->ignore_next_lbutton_up)
2344 msframe->ignore_next_lbutton_up = 0;
2346 else if (msframe->button2_is_down)
2348 msframe->button2_is_down = 0;
2349 msframe->ignore_next_rbutton_up = 1;
2350 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2351 MAKEPOINTS (lParam),
2353 &~ (MK_LBUTTON | MK_MBUTTON
2359 if (msframe->button2_need_rbutton)
2361 msframe->button2_need_rbutton = 0;
2362 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2363 MAKEPOINTS (lParam),
2364 wParam &~ MK_LBUTTON,
2367 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2368 MAKEPOINTS (lParam),
2369 wParam &~ MK_LBUTTON,
2375 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2376 msframe->last_click_time = GetMessageTime();
2378 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2379 msframe->button2_need_rbutton = 0;
2380 if (msframe->ignore_next_rbutton_up)
2382 msframe->ignore_next_rbutton_up = 0;
2384 else if (msframe->button2_is_down)
2386 msframe->button2_is_down = 0;
2387 msframe->ignore_next_lbutton_up = 1;
2388 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2389 MAKEPOINTS (lParam),
2391 &~ (MK_LBUTTON | MK_MBUTTON
2397 if (msframe->button2_need_lbutton)
2399 msframe->button2_need_lbutton = 0;
2400 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2401 MAKEPOINTS (lParam),
2402 wParam &~ MK_RBUTTON,
2405 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2406 MAKEPOINTS (lParam),
2407 wParam &~ MK_RBUTTON,
2412 case WM_LBUTTONDOWN:
2413 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2415 if (msframe->button2_need_lbutton)
2417 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2418 msframe->button2_need_lbutton = 0;
2419 msframe->button2_need_rbutton = 0;
2420 if (mswindows_button2_near_enough (msframe->last_click_point,
2421 MAKEPOINTS (lParam)))
2423 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2424 MAKEPOINTS (lParam),
2426 &~ (MK_LBUTTON | MK_MBUTTON
2429 msframe->button2_is_down = 1;
2433 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2434 msframe->last_click_point,
2435 msframe->last_click_mods
2437 msframe->last_click_time);
2438 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2439 MAKEPOINTS (lParam),
2440 wParam &~ MK_LBUTTON,
2446 mswindows_set_chord_timer (hwnd);
2447 msframe->button2_need_rbutton = 1;
2448 msframe->last_click_point = MAKEPOINTS (lParam);
2449 msframe->last_click_mods = wParam;
2451 msframe->last_click_time = GetMessageTime();
2454 case WM_RBUTTONDOWN:
2455 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2457 if (msframe->button2_need_rbutton)
2459 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2460 msframe->button2_need_lbutton = 0;
2461 msframe->button2_need_rbutton = 0;
2462 if (mswindows_button2_near_enough (msframe->last_click_point,
2463 MAKEPOINTS (lParam)))
2465 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2466 MAKEPOINTS (lParam),
2468 &~ (MK_LBUTTON | MK_MBUTTON
2471 msframe->button2_is_down = 1;
2475 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2476 msframe->last_click_point,
2477 msframe->last_click_mods
2479 msframe->last_click_time);
2480 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2481 MAKEPOINTS (lParam),
2482 wParam &~ MK_RBUTTON,
2488 mswindows_set_chord_timer (hwnd);
2489 msframe->button2_need_lbutton = 1;
2490 msframe->last_click_point = MAKEPOINTS (lParam);
2491 msframe->last_click_mods = wParam;
2493 msframe->last_click_time = GetMessageTime();
2497 if (wParam == BUTTON_2_TIMER_ID)
2499 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2500 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2502 if (msframe->button2_need_lbutton)
2504 msframe->button2_need_lbutton = 0;
2505 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2506 msframe->last_click_point,
2507 msframe->last_click_mods
2509 msframe->last_click_time);
2511 else if (msframe->button2_need_rbutton)
2513 msframe->button2_need_rbutton = 0;
2514 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2515 msframe->last_click_point,
2516 msframe->last_click_mods
2518 msframe->last_click_time);
2522 assert ("Spurious timer fired" == 0);
2526 /* Optimization: don't report mouse movement while size is changing */
2527 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2528 if (!msframe->sizing)
2530 /* When waiting for the second mouse button to finish
2531 button2 emulation, and have moved too far, just pretend
2532 as if timer has expired. This improves drag-select feedback */
2533 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2534 && !mswindows_button2_near_enough (msframe->last_click_point,
2535 MAKEPOINTS (lParam)))
2537 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2538 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2541 emacs_event = Fmake_event (Qnil, Qnil);
2542 event = XEVENT(emacs_event);
2544 event->channel = mswindows_find_frame(hwnd);
2545 event->timestamp = GetMessageTime();
2546 event->event_type = pointer_motion_event;
2547 event->event.motion.x = MAKEPOINTS(lParam).x;
2548 event->event.motion.y = MAKEPOINTS(lParam).y;
2549 event->event.motion.modifiers =
2550 mswindows_modifier_state (NULL, wParam, 0);
2552 mswindows_enqueue_dispatch_event (emacs_event);
2558 /* Queue a `cancel-mode-internal' misc user event, so mouse
2559 selection would be canceled if any */
2560 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2561 Qcancel_mode_internal, Qnil);
2566 LPNMHDR nmhdr = (LPNMHDR)lParam;
2568 if (nmhdr->code == TTN_NEEDTEXT)
2570 #ifdef HAVE_TOOLBARS
2571 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2574 /* find out which toolbar */
2575 frame = XFRAME (mswindows_find_frame (hwnd));
2576 btext = mswindows_get_toolbar_button_text ( frame,
2579 tttext->lpszText = NULL;
2580 tttext->hinst = NULL;
2584 /* I think this is safe since the text will only go away
2585 when the toolbar does...*/
2586 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2590 /* handle tree view callbacks */
2591 else if (nmhdr->code == TVN_SELCHANGED)
2593 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2594 frame = XFRAME (mswindows_find_frame (hwnd));
2595 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2597 /* handle tab control callbacks */
2598 else if (nmhdr->code == TCN_SELCHANGE)
2601 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2602 frame = XFRAME (mswindows_find_frame (hwnd));
2604 item.mask = TCIF_PARAM;
2605 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2608 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2614 /* hdc will be NULL unless this is a subwindow - in which case we
2615 shouldn't have received a paint message for it here. */
2616 assert (wParam == 0);
2618 /* Can't queue a magic event because windows goes modal and sends paint
2619 messages directly to the windows procedure when doing solid drags
2620 and the message queue doesn't get processed. */
2621 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2624 case WM_WINDOWPOSCHANGED:
2625 /* This is sent before WM_SIZE; in fact, the processing of this
2626 by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when
2627 a window is hidden (make-frame-invisible), so we need to process
2628 this and update the state flags. */
2630 fobj = mswindows_find_frame (hwnd);
2631 frame = XFRAME (fobj);
2632 if (IsIconic (hwnd))
2634 FRAME_VISIBLE_P (frame) = 0;
2635 FRAME_ICONIFIED_P (frame) = 1;
2637 else if (IsWindowVisible (hwnd))
2639 FRAME_VISIBLE_P (frame) = 1;
2640 FRAME_ICONIFIED_P (frame) = 0;
2644 FRAME_VISIBLE_P (frame) = 0;
2645 FRAME_ICONIFIED_P (frame) = 0;
2648 return DefWindowProc (hwnd, message_, wParam, lParam);
2652 /* We only care about this message if our size has really changed */
2653 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2658 fobj = mswindows_find_frame (hwnd);
2659 frame = XFRAME (fobj);
2660 msframe = FRAME_MSWINDOWS_DATA (frame);
2662 /* We cannot handle frame map and unmap hooks right in
2663 this routine, because these may throw. We queue
2664 magic events to run these hooks instead - kkm */
2666 if (wParam==SIZE_MINIMIZED)
2669 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2673 GetClientRect(hwnd, &rect);
2674 FRAME_PIXWIDTH(frame) = rect.right;
2675 FRAME_PIXHEIGHT(frame) = rect.bottom;
2677 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2678 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2679 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2681 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2682 change_frame_size (frame, rows, columns, 1);
2684 /* If we are inside frame creation, we have to apply geometric
2686 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2688 /* Yes, we have to size again */
2689 mswindows_size_frame_internal ( frame,
2690 FRAME_MSWINDOWS_TARGET_RECT
2692 /* Reset so we do not get here again. The SetWindowPos call in
2693 * mswindows_size_frame_internal can cause recursion here. */
2694 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2696 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2697 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2702 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2703 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2705 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2712 case WM_DISPLAYCHANGE:
2715 DWORD message_tick = GetMessageTime ();
2717 fobj = mswindows_find_frame (hwnd);
2718 frame = XFRAME (fobj);
2719 d = XDEVICE (FRAME_DEVICE (frame));
2721 /* Do this only once per message. XEmacs can receive this message
2722 through as many frames as it currently has open. Message time
2723 will be the same for all these messages. Despite extreme
2724 efficiency, the code below has about one in 4 billion
2725 probability that the HDC is not recreated, provided that
2726 XEmacs is running sufficiently longer than 52 days. */
2727 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2729 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2730 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2731 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2736 /* Misc magic events which only require that the frame be identified */
2739 mswindows_enqueue_magic_event (hwnd, message_);
2742 case WM_WINDOWPOSCHANGING:
2744 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2745 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2746 GetWindowPlacement(hwnd, &wpl);
2748 /* Only interested if size is changing and we're not being iconified */
2749 if (wpl.showCmd != SW_SHOWMINIMIZED
2750 && wpl.showCmd != SW_SHOWMAXIMIZED
2751 && !(wp->flags & SWP_NOSIZE))
2753 RECT ncsize = { 0, 0, 0, 0 };
2754 int pixwidth, pixheight;
2755 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2756 GetMenu(hwnd) != NULL,
2757 GetWindowLong (hwnd, GWL_EXSTYLE));
2759 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2760 wp->cx - (ncsize.right - ncsize.left),
2761 wp->cy - (ncsize.bottom - ncsize.top),
2762 &pixwidth, &pixheight);
2764 /* Convert client sizes to window sizes */
2765 pixwidth += (ncsize.right - ncsize.left);
2766 pixheight += (ncsize.bottom - ncsize.top);
2768 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2770 /* Adjust so that the bottom or right doesn't move if it's
2771 * the top or left that's being changed */
2773 GetWindowRect (hwnd, &rect);
2775 if (rect.left != wp->x)
2776 wp->x += wp->cx - pixwidth;
2777 if (rect.top != wp->y)
2778 wp->y += wp->cy - pixheight;
2784 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2785 window position if the user tries to track window too small */
2789 case WM_ENTERSIZEMOVE:
2790 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2791 msframe->sizing = 1;
2794 case WM_EXITSIZEMOVE:
2795 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2796 msframe->sizing = 0;
2797 /* Queue noop event */
2798 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2801 #ifdef HAVE_SCROLLBARS
2805 /* Direction of scroll is determined by scrollbar instance. */
2806 int code = (int) LOWORD(wParam);
2807 int pos = (short int) HIWORD(wParam);
2808 HWND hwndScrollBar = (HWND) lParam;
2809 struct gcpro gcpro1, gcpro2;
2811 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2812 GCPRO2 (emacs_event, fobj);
2813 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2815 /* Error during event pumping - cancel scroll */
2816 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2824 int keys = LOWORD (wParam); /* Modifier key flags */
2825 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2826 struct gcpro gcpro1, gcpro2;
2828 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2830 MAKEPOINTS (lParam)))
2832 GCPRO2 (emacs_event, fobj);
2833 mswindows_pump_outstanding_events (); /* Can GC */
2842 #ifdef HAVE_MENUBARS
2844 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2846 XFRAME (mswindows_find_frame (hwnd)))))
2847 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2850 case WM_INITMENUPOPUP:
2851 if (!HIWORD(lParam))
2853 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2855 XFRAME (mswindows_find_frame (hwnd)))))
2856 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2860 #endif /* HAVE_MENUBARS */
2864 WORD id = LOWORD (wParam);
2865 WORD nid = HIWORD (wParam);
2866 HWND cid = (HWND)lParam;
2867 frame = XFRAME (mswindows_find_frame (hwnd));
2869 #ifdef HAVE_TOOLBARS
2870 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2873 /* widgets in a buffer only eval a callback for suitable events.*/
2878 case CBN_EDITCHANGE:
2880 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2883 /* menubars always must come last since the hashtables do not
2885 #ifdef HAVE_MENUBARS
2886 if (!NILP (mswindows_handle_wm_command (frame, id)))
2890 return DefWindowProc (hwnd, message_, wParam, lParam);
2891 /* Bite me - a spurious command. This used to not be able to
2892 happen but with the introduction of widgets its now
2897 case WM_CTLCOLORBTN:
2898 case WM_CTLCOLORLISTBOX:
2899 case WM_CTLCOLOREDIT:
2900 case WM_CTLCOLORSTATIC:
2901 case WM_CTLCOLORSCROLLBAR:
2903 /* if we get an opportunity to paint a widget then do so if
2904 there is an appropriate face */
2905 HWND crtlwnd = (HWND)lParam;
2906 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2909 Lisp_Object image_instance;
2910 VOID_TO_LISP (image_instance, ii);
2911 if (IMAGE_INSTANCEP (image_instance)
2913 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
2915 /* set colors for the buttons */
2916 HDC hdc = (HDC)wParam;
2917 if (last_widget_brushed != ii)
2920 DeleteObject (widget_brush);
2921 widget_brush = CreateSolidBrush
2922 (COLOR_INSTANCE_MSWINDOWS_COLOR
2925 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2926 XIMAGE_INSTANCE_FRAME (image_instance)))));
2928 last_widget_brushed = ii;
2931 COLOR_INSTANCE_MSWINDOWS_COLOR
2934 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2935 XIMAGE_INSTANCE_FRAME (image_instance)))));
2936 SetBkMode (hdc, OPAQUE);
2939 COLOR_INSTANCE_MSWINDOWS_COLOR
2942 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2943 XIMAGE_INSTANCE_FRAME (image_instance)))));
2944 return (LRESULT)widget_brush;
2950 #ifdef HAVE_DRAGNDROP
2951 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
2953 UINT filecount, i, len;
2958 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2959 struct gcpro gcpro1, gcpro2, gcpro3;
2961 emacs_event = Fmake_event (Qnil, Qnil);
2962 event = XEVENT(emacs_event);
2964 GCPRO3 (emacs_event, l_dndlist, l_item);
2966 if (!DragQueryPoint ((HDROP) wParam, &point))
2967 point.x = point.y = -1; /* outside client area */
2969 event->event_type = misc_user_event;
2970 event->channel = mswindows_find_frame(hwnd);
2971 event->timestamp = GetMessageTime();
2972 event->event.misc.button = 1; /* #### Should try harder */
2973 event->event.misc.modifiers = mswindows_modifier_state (NULL,
2975 event->event.misc.x = point.x;
2976 event->event.misc.y = point.y;
2977 event->event.misc.function = Qdragdrop_drop_dispatch;
2979 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
2980 for (i=0; i<filecount; i++)
2982 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
2983 /* The URLs that we make here aren't correct according to section
2984 * 3.10 of rfc1738 because they're missing the //<host>/ part and
2985 * because they may contain reserved characters. But that's OK -
2986 * they just need to be good enough to keep dragdrop.el happy. */
2987 fname = (char *)xmalloc (len+1);
2988 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2990 /* May be a shell link aka "shortcut" - replace fname if so */
2991 #if !(defined(CYGWIN) || defined(MINGW))
2992 /* cygwin doesn't define this COM stuff */
2993 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
2997 if (CoCreateInstance (&CLSID_ShellLink, NULL,
2998 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
3002 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
3005 OLECHAR wsz[PATH_MAX];
3006 WIN32_FIND_DATA wfd;
3007 LPSTR resolved = (char *) xmalloc (PATH_MAX+1);
3009 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX);
3011 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
3012 (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX,
3017 len = strlen (fname);
3020 ppf->lpVtbl->Release (ppf);
3023 psl->lpVtbl->Release (psl);
3029 filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5);
3030 strcpy (filename, "file:");
3031 cygwin_win32_to_posix_path_list (fname, filename+5);
3033 filename = (char *)xmalloc (len+6);
3034 strcat (strcpy (filename, "file:"), fname);
3035 dostounix_filename (filename+5);
3038 l_item = make_string (filename, strlen (filename));
3039 l_dndlist = Fcons (l_item, l_dndlist);
3042 DragFinish ((HDROP) wParam);
3044 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3045 mswindows_enqueue_dispatch_event (emacs_event);
3053 return DefWindowProc (hwnd, message_, wParam, lParam);
3059 /************************************************************************/
3060 /* keyboard, mouse & other helpers for the windows procedure */
3061 /************************************************************************/
3063 mswindows_set_chord_timer (HWND hwnd)
3067 /* We get one third half system double click threshold */
3068 if (mswindows_mouse_button_tolerance <= 0)
3069 interval = GetDoubleClickTime () / 3;
3071 interval = mswindows_mouse_button_tolerance;
3073 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3077 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3080 if (mswindows_mouse_button_max_skew_x <= 0)
3081 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3083 dx = mswindows_mouse_button_max_skew_x;
3085 if (mswindows_mouse_button_max_skew_y <= 0)
3086 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3088 dy = mswindows_mouse_button_max_skew_y;
3090 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3094 mswindows_current_layout_has_AltGr (void)
3096 /* This simple caching mechanism saves 10% of CPU
3097 time when a key typed at autorepeat rate of 30 cps! */
3098 static HKL last_hkl = 0;
3099 static int last_hkl_has_AltGr;
3100 HKL current_hkl = (HKL) -1;
3102 if (xGetKeyboardLayout) /* not in NT 3.5 */
3103 current_hkl = xGetKeyboardLayout (0);
3104 if (current_hkl != last_hkl)
3107 last_hkl_has_AltGr = 0;
3108 /* In this loop, we query whether a character requires
3109 AltGr to be down to generate it. If at least such one
3110 found, this means that the layout does regard AltGr */
3111 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3112 if (HIBYTE (VkKeyScan (c)) == 6)
3113 last_hkl_has_AltGr = 1;
3114 last_hkl = current_hkl;
3116 return last_hkl_has_AltGr;
3120 /* Returns the state of the modifier keys in the format expected by the
3121 * Lisp_Event key_data, button_data and motion_data modifiers member */
3123 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3126 int keys_is_real = 0;
3129 if (fwKeys == (DWORD) -1)
3130 fwKeys = mswindows_last_mouse_button_state;
3134 mswindows_last_mouse_button_state = fwKeys;
3140 GetKeyboardState (keymap);
3141 has_AltGr = mswindows_current_layout_has_AltGr ();
3144 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3146 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3148 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3149 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3153 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3154 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3157 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3158 ? XEMACS_MOD_SHIFT : 0;
3159 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3160 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3161 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3167 * Translate a mswindows virtual key to a keysym.
3168 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3169 * or whose ASCII codes (like space) xemacs doesn't like.
3171 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3174 if (extendedp) /* Keys not present on a 82 key keyboard */
3176 switch (mswindows_key)
3178 case VK_CANCEL: return KEYSYM ("pause");
3179 case VK_RETURN: return KEYSYM ("kp-enter");
3180 case VK_PRIOR: return KEYSYM ("prior");
3181 case VK_NEXT: return KEYSYM ("next");
3182 case VK_END: return KEYSYM ("end");
3183 case VK_HOME: return KEYSYM ("home");
3184 case VK_LEFT: return KEYSYM ("left");
3185 case VK_UP: return KEYSYM ("up");
3186 case VK_RIGHT: return KEYSYM ("right");
3187 case VK_DOWN: return KEYSYM ("down");
3188 case VK_INSERT: return KEYSYM ("insert");
3189 case VK_DELETE: return QKdelete;
3190 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3191 case VK_LWIN return KEYSYM ("");
3192 case VK_RWIN return KEYSYM ("");
3194 case VK_APPS: return KEYSYM ("menu");
3199 switch (mswindows_key)
3201 case VK_BACK: return QKbackspace;
3202 case VK_TAB: return QKtab;
3203 case '\n': return QKlinefeed;
3204 case VK_CLEAR: return KEYSYM ("clear");
3205 case VK_RETURN: return QKreturn;
3206 case VK_PAUSE: return KEYSYM ("pause");
3207 case VK_ESCAPE: return QKescape;
3208 case VK_SPACE: return QKspace;
3209 case VK_PRIOR: return KEYSYM ("kp-prior");
3210 case VK_NEXT: return KEYSYM ("kp-next");
3211 case VK_END: return KEYSYM ("kp-end");
3212 case VK_HOME: return KEYSYM ("kp-home");
3213 case VK_LEFT: return KEYSYM ("kp-left");
3214 case VK_UP: return KEYSYM ("kp-up");
3215 case VK_RIGHT: return KEYSYM ("kp-right");
3216 case VK_DOWN: return KEYSYM ("kp-down");
3217 case VK_SELECT: return KEYSYM ("select");
3218 case VK_PRINT: return KEYSYM ("print");
3219 case VK_EXECUTE: return KEYSYM ("execute");
3220 case VK_SNAPSHOT: return KEYSYM ("print");
3221 case VK_INSERT: return KEYSYM ("kp-insert");
3222 case VK_DELETE: return KEYSYM ("kp-delete");
3223 case VK_HELP: return KEYSYM ("help");
3224 case VK_NUMPAD0: return KEYSYM ("kp-0");
3225 case VK_NUMPAD1: return KEYSYM ("kp-1");
3226 case VK_NUMPAD2: return KEYSYM ("kp-2");
3227 case VK_NUMPAD3: return KEYSYM ("kp-3");
3228 case VK_NUMPAD4: return KEYSYM ("kp-4");
3229 case VK_NUMPAD5: return KEYSYM ("kp-5");
3230 case VK_NUMPAD6: return KEYSYM ("kp-6");
3231 case VK_NUMPAD7: return KEYSYM ("kp-7");
3232 case VK_NUMPAD8: return KEYSYM ("kp-8");
3233 case VK_NUMPAD9: return KEYSYM ("kp-9");
3234 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3235 case VK_ADD: return KEYSYM ("kp-add");
3236 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3237 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3238 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3239 case VK_DIVIDE: return KEYSYM ("kp-divide");
3240 case VK_F1: return KEYSYM ("f1");
3241 case VK_F2: return KEYSYM ("f2");
3242 case VK_F3: return KEYSYM ("f3");
3243 case VK_F4: return KEYSYM ("f4");
3244 case VK_F5: return KEYSYM ("f5");
3245 case VK_F6: return KEYSYM ("f6");
3246 case VK_F7: return KEYSYM ("f7");
3247 case VK_F8: return KEYSYM ("f8");
3248 case VK_F9: return KEYSYM ("f9");
3249 case VK_F10: return KEYSYM ("f10");
3250 case VK_F11: return KEYSYM ("f11");
3251 case VK_F12: return KEYSYM ("f12");
3252 case VK_F13: return KEYSYM ("f13");
3253 case VK_F14: return KEYSYM ("f14");
3254 case VK_F15: return KEYSYM ("f15");
3255 case VK_F16: return KEYSYM ("f16");
3256 case VK_F17: return KEYSYM ("f17");
3257 case VK_F18: return KEYSYM ("f18");
3258 case VK_F19: return KEYSYM ("f19");
3259 case VK_F20: return KEYSYM ("f20");
3260 case VK_F21: return KEYSYM ("f21");
3261 case VK_F22: return KEYSYM ("f22");
3262 case VK_F23: return KEYSYM ("f23");
3263 case VK_F24: return KEYSYM ("f24");
3270 * Find the console that matches the supplied mswindows window handle
3273 mswindows_find_console (HWND hwnd)
3275 /* We only support one console */
3276 return XCAR (Vconsole_list);
3280 * Find the frame that matches the supplied mswindows window handle
3283 mswindows_find_frame (HWND hwnd)
3285 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3289 /* We are in progress of frame creation. Return the frame
3290 being created, as it still not remembered in the window
3292 assert (!NILP (Vmswindows_frame_being_created));
3293 return Vmswindows_frame_being_created;
3295 VOID_TO_LISP (f, l);
3300 /************************************************************************/
3302 /************************************************************************/
3305 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3308 EMACS_TIME current_time;
3309 EMACS_GET_TIME (current_time);
3310 EMACS_SUB_TIME (thyme, thyme, current_time);
3311 milliseconds = EMACS_SECS (thyme) * 1000 +
3312 (EMACS_USECS (thyme) + 500) / 1000;
3313 if (milliseconds < 1)
3315 ++mswindows_pending_timers_count;
3316 return SetTimer (NULL, 0, milliseconds,
3317 (TIMERPROC) mswindows_wm_timer_callback);
3321 emacs_mswindows_remove_timeout (int id)
3323 Lisp_Event match_against;
3324 Lisp_Object emacs_event;
3326 if (KillTimer (NULL, id))
3327 --mswindows_pending_timers_count;
3329 /* If there is a dispatch event generated by this
3330 timeout in the queue, we have to remove it too. */
3331 match_against.event_type = timeout_event;
3332 match_against.event.timeout.interval_id = id;
3333 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3334 if (!NILP (emacs_event))
3335 Fdeallocate_event(emacs_event);
3338 /* If `user_p' is false, then return whether there are any win32, timeout,
3339 * or subprocess events pending (that is, whether
3340 * emacs_mswindows_next_event() would return immediately without blocking).
3342 * if `user_p' is true, then return whether there are any *user generated*
3343 * events available (that is, whether there are keyboard or mouse-click
3344 * events ready to be read). This also implies that
3345 * emacs_mswindows_next_event() would not block.
3348 emacs_mswindows_event_pending_p (int user_p)
3350 mswindows_need_event (0);
3351 return (!NILP (mswindows_u_dispatch_event_queue)
3352 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3356 * Return the next event
3359 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3361 Lisp_Object event, event2;
3363 mswindows_need_event (1);
3365 event = mswindows_dequeue_dispatch_event ();
3366 XSETEVENT (event2, emacs_event);
3367 Fcopy_event (event, event2);
3368 Fdeallocate_event (event);
3372 * Handle a magic event off the dispatch queue.
3375 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3377 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3384 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3385 mswindows_handle_paint (f);
3386 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3393 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3394 struct frame *f = XFRAME (frame);
3395 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3397 struct gcpro gcpro1;
3399 /* On focus change, clear all memory of sticky modifiers
3400 to avoid non-intuitive behavior. */
3401 clear_sticky_modifiers ();
3403 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3405 emacs_handle_focus_change_preliminary (conser);
3406 /* Under X the stuff up to here is done in the X event handler.
3408 emacs_handle_focus_change_final (conser);
3417 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3418 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3420 Qmap_frame_hook : Qunmap_frame_hook,
3425 /* #### What about Enter & Leave */
3427 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3428 Qmouse_leave_frame_hook, 1, frame);
3436 #ifndef HAVE_MSG_SELECT
3438 get_process_input_waitable (Lisp_Process *process)
3440 Lisp_Object instr, outstr, p;
3441 XSETPROCESS (p, process);
3442 get_process_streams (process, &instr, &outstr);
3443 assert (!NILP (instr));
3444 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3445 return (network_connection_p (p)
3446 ? get_winsock_stream_waitable (XLSTREAM (instr))
3447 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3449 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3454 emacs_mswindows_select_process (Lisp_Process *process)
3456 HANDLE hev = get_process_input_waitable (process);
3458 if (!add_waitable_handle (hev))
3459 error ("Too many active processes");
3461 #ifdef HAVE_WIN32_PROCESSES
3464 XSETPROCESS (p, process);
3465 if (!network_connection_p (p))
3467 HANDLE hprocess = get_nt_process_handle (process);
3468 if (!add_waitable_handle (hprocess))
3470 remove_waitable_handle (hev);
3471 error ("Too many active processes");
3479 emacs_mswindows_unselect_process (Lisp_Process *process)
3481 /* Process handle is removed in the event loop as soon
3482 as it is signaled, so don't bother here about it */
3483 HANDLE hev = get_process_input_waitable (process);
3484 remove_waitable_handle (hev);
3486 #endif /* HAVE_MSG_SELECT */
3489 emacs_mswindows_select_console (struct console *con)
3491 #ifdef HAVE_MSG_SELECT
3492 if (CONSOLE_MSWINDOWS_P (con))
3493 return; /* mswindows consoles are automatically selected */
3495 event_stream_unixoid_select_console (con);
3500 emacs_mswindows_unselect_console (struct console *con)
3502 #ifdef HAVE_MSG_SELECT
3503 if (CONSOLE_MSWINDOWS_P (con))
3504 return; /* mswindows consoles are automatically selected */
3506 event_stream_unixoid_unselect_console (con);
3511 emacs_mswindows_quit_p (void)
3513 /* Quit cannot happen in modal loop: all program
3514 input is dedicated to Windows. */
3515 if (mswindows_in_modal_loop)
3518 mswindows_quit_chars_count = 0;
3519 /* Drain windows queue. This sets up number of quit characters in
3521 mswindows_drain_windows_queue ();
3523 if (mswindows_quit_chars_count > 0)
3525 /* Yes there's a hidden one... Throw it away */
3526 Lisp_Event match_against;
3527 Lisp_Object emacs_event;
3530 match_against.event_type = key_press_event;
3531 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3533 while (mswindows_quit_chars_count > 0)
3535 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3536 assert (!NILP (emacs_event));
3538 if (XEVENT (emacs_event)->event.key.modifiers &
3539 FAKE_MOD_QUIT_CRITICAL)
3542 Fdeallocate_event (emacs_event);
3543 mswindows_quit_chars_count--;
3546 Vquit_flag = critical_p ? Qcritical : Qt;
3551 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3552 Lisp_Object* instream,
3553 Lisp_Object* outstream,
3556 /* Handles for streams */
3558 /* fds. These just stored along with the streams, and are closed in
3559 delete stream pair method, because we need to handle fake unices
3563 /* Decode inhandle and outhandle. Their meaning depends on
3564 the process implementation being used. */
3565 #if defined (HAVE_WIN32_PROCESSES)
3566 /* We're passed in Windows handles. That's what we like most... */
3567 hin = (HANDLE) inhandle;
3568 hout = (HANDLE) outhandle;
3570 #elif defined (HAVE_UNIX_PROCESSES)
3571 /* We are passed UNIX fds. This must be Cygwin.
3573 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3574 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3578 #error "So, WHICH kind of processes do you want?"
3581 *instream = (hin == INVALID_HANDLE_VALUE
3583 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3584 : flags & STREAM_NETWORK_CONNECTION
3585 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3587 : make_ntpipe_input_stream (hin, fdi));
3589 #ifdef HAVE_WIN32_PROCESSES
3590 *outstream = (hout == INVALID_HANDLE_VALUE
3592 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3593 : flags & STREAM_NETWORK_CONNECTION
3594 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3596 : make_ntpipe_output_stream (hout, fdo));
3597 #elif defined (HAVE_UNIX_PROCESSES)
3598 *outstream = (fdo >= 0
3599 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3602 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3603 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3604 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3606 Bufbyte eof_char = get_eof_char (fdo);
3607 int pty_max_bytes = get_pty_max_bytes (fdo);
3608 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3613 return (NILP (*instream)
3615 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3616 : flags & STREAM_NETWORK_CONNECTION
3617 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3619 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3623 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3624 Lisp_Object outstream)
3626 /* Oh nothing special here for Win32 at all */
3627 #if defined (HAVE_UNIX_PROCESSES)
3628 int in = (NILP(instream)
3630 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3631 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3632 ? get_winsock_stream_param (XLSTREAM (instream))
3634 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3635 int out = (NILP(outstream) ? -1
3636 : filedesc_stream_fd (XLSTREAM (outstream)));
3640 if (out != in && out >= 0)
3644 return (NILP (instream)
3646 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3647 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3648 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3650 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3654 emacs_mswindows_current_event_timestamp (struct console *c)
3656 return GetTickCount ();
3659 #ifndef HAVE_X_WINDOWS
3660 /* This is called from GC when a process object is about to be freed.
3661 If we've still got pointers to it in this file, we're gonna lose hard.
3664 debug_process_finalization (Lisp_Process *p)
3667 Lisp_Object instr, outstr;
3669 get_process_streams (p, &instr, &outstr);
3670 /* if it still has fds, then it hasn't been killed yet. */
3671 assert (NILP(instr));
3672 assert (NILP(outstr));
3674 /* #### More checks here */
3681 struct mswin_message_debug
3687 #define FROB(val) { val, #val, },
3689 struct mswin_message_debug debug_mswin_messages[] =
3705 FROB (WM_GETTEXTLENGTH)
3708 FROB (WM_QUERYENDSESSION)
3711 FROB (WM_ERASEBKGND)
3712 FROB (WM_SYSCOLORCHANGE)
3713 FROB (WM_ENDSESSION)
3714 FROB (WM_SHOWWINDOW)
3715 FROB (WM_WININICHANGE)
3716 #if(WINVER >= 0x0400)
3717 FROB (WM_SETTINGCHANGE)
3718 #endif /* WINVER >= 0x0400 */
3720 FROB (WM_DEVMODECHANGE)
3721 FROB (WM_ACTIVATEAPP)
3722 FROB (WM_FONTCHANGE)
3723 FROB (WM_TIMECHANGE)
3724 FROB (WM_CANCELMODE)
3726 FROB (WM_MOUSEACTIVATE)
3727 FROB (WM_CHILDACTIVATE)
3730 FROB (WM_GETMINMAXINFO)
3733 FROB (WM_ICONERASEBKGND)
3734 FROB (WM_NEXTDLGCTL)
3735 FROB (WM_SPOOLERSTATUS)
3737 FROB (WM_MEASUREITEM)
3738 FROB (WM_DELETEITEM)
3739 FROB (WM_VKEYTOITEM)
3740 FROB (WM_CHARTOITEM)
3745 FROB (WM_QUERYDRAGICON)
3746 FROB (WM_COMPAREITEM)
3747 #if(WINVER >= 0x0500)
3749 #endif /* WINVER >= 0x0500 */
3750 FROB (WM_COMPACTING)
3751 FROB (WM_COMMNOTIFY)
3752 FROB (WM_WINDOWPOSCHANGING)
3753 FROB (WM_WINDOWPOSCHANGED)
3758 FROB (WM_CANCELJOURNAL)
3760 #if(WINVER >= 0x0400)
3762 FROB (WM_INPUTLANGCHANGEREQUEST)
3763 FROB (WM_INPUTLANGCHANGE)
3766 FROB (WM_USERCHANGED)
3767 FROB (WM_NOTIFYFORMAT)
3769 FROB (WM_CONTEXTMENU)
3770 FROB (WM_STYLECHANGING)
3771 FROB (WM_STYLECHANGED)
3772 FROB (WM_DISPLAYCHANGE)
3775 #endif /* WINVER >= 0x0400 */
3779 FROB (WM_NCCALCSIZE)
3782 FROB (WM_NCACTIVATE)
3783 FROB (WM_GETDLGCODE)
3785 FROB (WM_NCMOUSEMOVE)
3786 FROB (WM_NCLBUTTONDOWN)
3787 FROB (WM_NCLBUTTONUP)
3788 FROB (WM_NCLBUTTONDBLCLK)
3789 FROB (WM_NCRBUTTONDOWN)
3790 FROB (WM_NCRBUTTONUP)
3791 FROB (WM_NCRBUTTONDBLCLK)
3792 FROB (WM_NCMBUTTONDOWN)
3793 FROB (WM_NCMBUTTONUP)
3794 FROB (WM_NCMBUTTONDBLCLK)
3796 /* FROB (WM_KEYFIRST) */
3801 FROB (WM_SYSKEYDOWN)
3804 FROB (WM_SYSDEADCHAR)
3807 #if(WINVER >= 0x0400) && !defined(CYGWIN)
3808 FROB (WM_IME_STARTCOMPOSITION)
3809 FROB (WM_IME_ENDCOMPOSITION)
3810 FROB (WM_IME_COMPOSITION)
3811 FROB (WM_IME_KEYLAST)
3812 #endif /* WINVER >= 0x0400 */
3814 FROB (WM_INITDIALOG)
3816 FROB (WM_SYSCOMMAND)
3821 FROB (WM_INITMENUPOPUP)
3822 FROB (WM_MENUSELECT)
3825 #if(WINVER >= 0x0500)
3826 FROB (WM_MENURBUTTONUP)
3828 FROB (WM_MENUGETOBJECT)
3829 FROB (WM_UNINITMENUPOPUP)
3830 FROB (WM_MENUCOMMAND)
3831 #endif /* WINVER >= 0x0500 */
3834 FROB (WM_CTLCOLORMSGBOX)
3835 FROB (WM_CTLCOLOREDIT)
3836 FROB (WM_CTLCOLORLISTBOX)
3837 FROB (WM_CTLCOLORBTN)
3838 FROB (WM_CTLCOLORDLG)
3839 FROB (WM_CTLCOLORSCROLLBAR)
3840 FROB (WM_CTLCOLORSTATIC)
3843 /* FROB (WM_MOUSEFIRST) */
3845 FROB (WM_LBUTTONDOWN)
3847 FROB (WM_LBUTTONDBLCLK)
3848 FROB (WM_RBUTTONDOWN)
3850 FROB (WM_RBUTTONDBLCLK)
3851 FROB (WM_MBUTTONDOWN)
3853 FROB (WM_MBUTTONDBLCLK)
3855 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
3856 FROB (WM_MOUSEWHEEL)
3860 #endif /* if (_WIN32_WINNT < 0x0400) */
3862 FROB (WM_PARENTNOTIFY)
3863 FROB (WM_ENTERMENULOOP)
3864 FROB (WM_EXITMENULOOP)
3866 #if(WINVER >= 0x0400)
3870 FROB (WM_CAPTURECHANGED)
3872 FROB (WM_POWERBROADCAST)
3874 FROB (WM_DEVICECHANGE)
3876 #endif /* WINVER >= 0x0400 */
3879 FROB (WM_MDIDESTROY)
3880 FROB (WM_MDIACTIVATE)
3881 FROB (WM_MDIRESTORE)
3883 FROB (WM_MDIMAXIMIZE)
3885 FROB (WM_MDICASCADE)
3886 FROB (WM_MDIICONARRANGE)
3887 FROB (WM_MDIGETACTIVE)
3890 FROB (WM_MDISETMENU)
3891 FROB (WM_ENTERSIZEMOVE)
3892 FROB (WM_EXITSIZEMOVE)
3894 FROB (WM_MDIREFRESHMENU)
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 */
3914 #if(_WIN32_WINNT >= 0x0400)
3915 FROB (WM_MOUSEHOVER)
3916 FROB (WM_MOUSELEAVE)
3917 #endif /* _WIN32_WINNT >= 0x0400 */
3924 FROB (WM_RENDERFORMAT)
3925 FROB (WM_RENDERALLFORMATS)
3926 FROB (WM_DESTROYCLIPBOARD)
3927 FROB (WM_DRAWCLIPBOARD)
3928 FROB (WM_PAINTCLIPBOARD)
3929 FROB (WM_VSCROLLCLIPBOARD)
3930 FROB (WM_SIZECLIPBOARD)
3931 FROB (WM_ASKCBFORMATNAME)
3932 FROB (WM_CHANGECBCHAIN)
3933 FROB (WM_HSCROLLCLIPBOARD)
3934 FROB (WM_QUERYNEWPALETTE)
3935 FROB (WM_PALETTEISCHANGING)
3936 FROB (WM_PALETTECHANGED)
3939 #if(WINVER >= 0x0400)
3941 FROB (WM_PRINTCLIENT)
3943 FROB (WM_HANDHELDFIRST)
3944 FROB (WM_HANDHELDLAST)
3948 #endif /* WINVER >= 0x0400 */
3950 FROB (WM_PENWINFIRST)
3951 FROB (WM_PENWINLAST)
3957 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
3960 Lisp_Object frame = mswindows_find_frame (hwnd);
3963 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */
3965 for (i = 0; i < countof (debug_mswin_messages); i++)
3967 if (debug_mswin_messages[i].mess == message_)
3969 str = debug_mswin_messages[i].string;
3975 stderr_out ("%s", str);
3977 stderr_out ("%x", message_);
3979 if (debug_mswindows_events > 1)
3981 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
3982 wParam, (int) lParam, (unsigned int) hwnd);
3983 debug_print (frame);
3989 #endif /* DEBUG_XEMACS */
3991 /************************************************************************/
3992 /* initialization */
3993 /************************************************************************/
3996 reinit_vars_of_event_mswindows (void)
3998 mswindows_in_modal_loop = 0;
3999 mswindows_pending_timers_count = 0;
4001 mswindows_event_stream = xnew (struct event_stream);
4003 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
4004 mswindows_event_stream->force_event_pending = 0;
4005 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
4006 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
4007 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
4008 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
4009 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
4010 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
4011 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
4012 #ifdef HAVE_MSG_SELECT
4013 mswindows_event_stream->select_process_cb =
4014 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
4015 mswindows_event_stream->unselect_process_cb =
4016 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
4017 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
4018 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
4020 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
4021 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
4022 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
4023 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
4025 mswindows_event_stream->current_event_timestamp_cb =
4026 emacs_mswindows_current_event_timestamp;
4030 vars_of_event_mswindows (void)
4032 reinit_vars_of_event_mswindows ();
4034 mswindows_u_dispatch_event_queue = Qnil;
4035 staticpro (&mswindows_u_dispatch_event_queue);
4036 mswindows_u_dispatch_event_queue_tail = Qnil;
4037 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
4039 mswindows_s_dispatch_event_queue = Qnil;
4040 staticpro (&mswindows_s_dispatch_event_queue);
4041 mswindows_s_dispatch_event_queue_tail = Qnil;
4042 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
4044 mswindows_error_caught_in_modal_loop = Qnil;
4045 staticpro (&mswindows_error_caught_in_modal_loop);
4049 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
4050 If non-zero, display debug information about Windows messages that XEmacs sees.
4051 Information is displayed in a console window. Currently defined values are:
4053 1 == non-verbose output (just the message name)
4054 2 == verbose output (all parameters)
4055 3 == even more verbose output (extra debugging info)
4057 debug_mswindows_events = 0;
4060 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
4061 &mswindows_alt_by_itself_activates_menu /*
4062 *Controls whether pressing and releasing the Alt key activates the menubar.
4063 This applies only if no intervening key was pressed. See also
4064 `menu-accelerator-enabled', which is probably the behavior you actually want.
4068 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
4069 &mswindows_dynamic_frame_resize /*
4070 *Controls redrawing frame contents during mouse-drag or keyboard resize
4071 operation. When non-nil, the frame is redrawn while being resized. When
4072 nil, frame is not redrawn, and exposed areas are filled with default
4073 MDI application background color. Note that this option only has effect
4074 if "Show window contents while dragging" is on in system Display/Plus!
4076 Default is t on fast machines, nil on slow.
4079 DEFVAR_INT ("mswindows-mouse-button-tolerance",
4080 &mswindows_mouse_button_tolerance /*
4081 *Analogue of double click interval for faking middle mouse events.
4082 The value is the minimum time in milliseconds that must elapse between
4083 left/right button down events before they are considered distinct events.
4084 If both mouse buttons are depressed within this interval, a middle mouse
4085 button down event is generated instead.
4086 If negative or zero, currently set system default is used instead.
4089 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
4090 Number of physical mouse buttons.
4093 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
4094 &mswindows_mouse_button_max_skew_x /*
4095 *Maximum horizontal distance in pixels between points in which left and
4096 right button clicks occurred for them to be translated into single
4097 middle button event. Clicks must occur in time not longer than defined
4098 by the variable `mswindows-mouse-button-tolerance'.
4099 If negative or zero, currently set system default is used instead.
4102 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
4103 &mswindows_mouse_button_max_skew_y /*
4104 *Maximum vertical distance in pixels between points in which left and
4105 right button clicks occurred for them to be translated into single
4106 middle button event. Clicks must occur in time not longer than defined
4107 by the variable `mswindows-mouse-button-tolerance'.
4108 If negative or zero, currently set system default is used instead.
4111 mswindows_mouse_button_max_skew_x = 0;
4112 mswindows_mouse_button_max_skew_y = 0;
4113 mswindows_mouse_button_tolerance = 0;
4114 mswindows_alt_by_itself_activates_menu = 1;
4118 syms_of_event_mswindows (void)
4123 lstream_type_create_mswindows_selectable (void)
4125 init_slurp_stream ();
4126 init_shove_stream ();
4127 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
4128 init_winsock_stream ();
4133 init_event_mswindows_late (void)
4135 #ifdef HAVE_MSG_SELECT
4136 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
4137 assert (windows_fd>=0);
4138 FD_SET (windows_fd, &input_wait_mask);
4139 FD_ZERO(&zero_mask);
4142 event_stream = mswindows_event_stream;
4144 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
4145 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);