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 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 from 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);
235 CloseHandle (s->hpipe);
240 static struct ntpipe_slurp_stream_shared_data*
241 slurper_allocate_shared_data (void)
244 for (i=0; i<MAX_SLURP_STREAMS; i++)
246 if (!shared_data_block[i].inuse_p)
248 shared_data_block[i].inuse_p=1;
249 return &shared_data_block[i];
252 return (struct ntpipe_slurp_stream_shared_data*)0;
256 slurp_thread (LPVOID vparam)
258 struct ntpipe_slurp_stream_shared_data *s =
259 (struct ntpipe_slurp_stream_shared_data*)vparam;
263 /* Read one byte from the pipe */
265 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
267 DWORD err = GetLastError ();
268 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
273 else if (actually_read == 0)
276 /* We must terminate on an error or eof */
277 if (s->eof_p || s->error_p)
278 InterlockedIncrement (&s->die_p);
280 /* Before we notify caller, we unsignal our event. */
281 ResetEvent (s->hev_thread);
283 /* Now we got something to notify caller, either a byte or an
284 error/eof indication. Before we do, allow internal pipe
285 buffer to accumulate little bit more data.
286 Reader function pulses this event before waiting for
287 a character, to avoid pipe delay, and to get the byte
290 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
292 /* Either make event loop generate a process event, or
294 SetEvent (s->hev_caller);
296 /* Cleanup and exit if we're shot off */
300 /* Block until the client finishes with retrieving the rest of
302 WaitForSingleObject (s->hev_thread, INFINITE);
305 slurper_free_shared_data_maybe (s);
311 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
314 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r");
315 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA (lstr);
316 DWORD thread_id_unused;
319 /* We deal only with pipes, for we're using PeekNamedPipe api */
320 assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
322 s->thread_data = slurper_allocate_shared_data();
324 /* Create reader thread. This could fail, so do not create events
325 until thread is created */
326 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data,
327 CREATE_SUSPENDED, &thread_id_unused);
330 Lstream_delete (lstr);
331 s->thread_data->inuse_p=0;
335 /* Shared data are initially owned by both main and slurper
337 s->thread_data->lock_count = 2;
338 s->thread_data->die_p = 0;
339 s->thread_data->eof_p = FALSE;
340 s->thread_data->error_p = FALSE;
341 s->thread_data->hpipe = hpipe;
342 s->user_data = param;
344 /* hev_thread is a manual-reset event, initially signaled */
345 s->thread_data->hev_thread = CreateEvent (NULL, TRUE, TRUE, NULL);
346 /* hev_caller is a manual-reset event, initially nonsignaled */
347 s->thread_data->hev_caller = CreateEvent (NULL, TRUE, FALSE, NULL);
348 /* hev_unsleep is a manual-reset event, initially nonsignaled */
349 s->thread_data->hev_unsleep = CreateEvent (NULL, TRUE, FALSE, NULL);
352 ResumeThread (hthread);
353 CloseHandle (hthread);
355 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
356 XSETLSTREAM (obj, lstr);
361 get_ntpipe_input_stream_param (Lstream *stream)
363 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
368 get_ntpipe_input_stream_waitable (Lstream *stream)
370 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
371 return s->thread_data->hev_caller;
374 static Lstream_data_count
375 ntpipe_slurp_reader (Lstream *stream, unsigned char *data,
376 Lstream_data_count size)
378 /* This function must be called from the main thread only */
379 struct ntpipe_slurp_stream_shared_data* s =
380 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
385 /* Disallow pipe read delay for the thread: we need a character
387 SetEvent (s->hev_unsleep);
389 /* Check if we have a character ready. Give it a short delay,
390 for the thread to awake from pipe delay, just ion case*/
391 wait_result = WaitForSingleObject (s->hev_caller, 2);
393 /* Revert to the normal sleep behavior. */
394 ResetEvent (s->hev_unsleep);
396 /* If there's no byte buffered yet, give up */
397 if (wait_result == WAIT_TIMEOUT)
404 /* Reset caller unlock event now, as we've handled the pending
405 process output event */
406 ResetEvent (s->hev_caller);
408 /* It is now safe to do anything with contents of S, except for
409 changing s->die_p, which still should be interlocked */
413 if (s->error_p || s->die_p)
416 /* Ok, there were no error neither eof - we've got a byte from the
418 *(data++) = s->onebyte;
422 DWORD bytes_read = 0;
425 DWORD bytes_available;
427 /* If the api call fails, return at least one byte already
428 read. ReadFile in thread will return error */
429 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL))
432 /* Fetch available bytes. The same consideration applies,
433 so do not check for errors. ReadFile in the thread will
434 fail if the next call fails. */
436 ReadFile (s->hpipe, data, min (bytes_available, size),
440 /* Now we can unblock thread, so it attempts to read more */
441 SetEvent (s->hev_thread);
442 return bytes_read + 1;
449 ntpipe_slurp_closer (Lstream *stream)
451 /* This function must be called from the main thread only */
452 struct ntpipe_slurp_stream_shared_data* s =
453 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data;
455 /* Force thread to stop */
456 InterlockedIncrement (&s->die_p);
458 /* Set events which could possibly block slurper. Let it finish soon
460 SetEvent (s->hev_unsleep);
461 SetEvent (s->hev_thread);
463 /* Unlock and maybe free shared data */
464 slurper_free_shared_data_maybe (s);
470 init_slurp_stream (void)
472 LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
473 LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
476 /************************************************************************/
477 /* Pipe outstream - writes process input */
478 /************************************************************************/
480 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
481 LSTREAM_TYPE_DATA (stream, ntpipe_shove)
483 #define MAX_SHOVE_BUFFER_SIZE 512
485 struct ntpipe_shove_stream
487 LPARAM user_data; /* Any user data stored in the stream object */
488 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */
489 /* This is an auto-reset object. */
490 HANDLE hpipe; /* Pipe write end handle. */
491 HANDLE hthread; /* Reader thread handle. */
492 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */
493 DWORD size; /* Number of bytes to write */
494 LONG die_p; /* Thread must exit ASAP if non-zero */
495 LONG idle_p; /* Non-zero if thread is waiting for job */
496 BOOL error_p : 1; /* Read error other than EOF/broken pipe */
497 BOOL blocking_p : 1;/* Last write attempt would cause blocking */
500 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
501 sizeof (struct ntpipe_shove_stream));
503 #ifndef HAVE_MSG_SELECT
505 shove_thread (LPVOID vparam)
507 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
513 /* Block on event and wait for a job */
514 InterlockedIncrement (&s->idle_p);
515 WaitForSingleObject (s->hev_thread, INFINITE);
517 /* Write passed buffer if any */
520 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
521 || bytes_written != s->size)
524 InterlockedIncrement (&s->die_p);
526 /* Set size to zero so we won't write it again if the closer sets
527 die_p and kicks us */
539 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
542 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w");
543 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA (lstr);
544 DWORD thread_id_unused;
549 s->user_data = param;
551 /* Create reader thread. This could fail, so do not
552 create the event until thread is created */
553 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s,
554 CREATE_SUSPENDED, &thread_id_unused);
555 if (s->hthread == NULL)
557 Lstream_delete (lstr);
561 /* Set the priority of the thread higher so we don't end up waiting
562 on it to send things. */
563 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST))
565 CloseHandle (s->hthread);
566 Lstream_delete (lstr);
570 /* hev_thread is an auto-reset event, initially nonsignaled */
571 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
574 ResumeThread (s->hthread);
576 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
577 XSETLSTREAM (obj, lstr);
582 get_ntpipe_output_stream_param (Lstream *stream)
584 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
589 static Lstream_data_count
590 ntpipe_shove_writer (Lstream *stream, const unsigned char *data,
591 Lstream_data_count size)
593 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
598 s->blocking_p = !s->idle_p;
602 if (size>MAX_SHOVE_BUFFER_SIZE)
605 memcpy (s->buffer, data, size);
609 InterlockedDecrement (&s->idle_p);
610 SetEvent (s->hev_thread);
611 /* Give it a chance to run -- this dramatically improves performance
612 of things like crypt. */
613 if (xSwitchToThread) /* not in Win9x or NT 3.51 */
614 (void) xSwitchToThread ();
619 ntpipe_shove_was_blocked_p (Lstream *stream)
621 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
622 return s->blocking_p;
626 ntpipe_shove_closer (Lstream *stream)
628 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
630 /* Force thread stop */
631 InterlockedIncrement (&s->die_p);
633 /* Thread will end upon unblocking. If it's already unblocked this will
634 do nothing, but the thread won't look at die_p until it's written any
636 SetEvent (s->hev_thread);
638 /* Wait while thread terminates */
639 WaitForSingleObject (s->hthread, INFINITE);
641 /* Close pipe handle, possibly breaking it */
642 CloseHandle (s->hpipe);
644 /* Close the thread handle */
645 CloseHandle (s->hthread);
647 /* Destroy the event */
648 CloseHandle (s->hev_thread);
654 init_shove_stream (void)
656 LSTREAM_HAS_METHOD (ntpipe_shove, writer);
657 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
658 LSTREAM_HAS_METHOD (ntpipe_shove, closer);
661 /************************************************************************/
662 /* Winsock I/O stream */
663 /************************************************************************/
664 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
666 #define WINSOCK_READ_BUFFER_SIZE 1024
668 struct winsock_stream
670 LPARAM user_data; /* Any user data stored in the stream object */
671 SOCKET s; /* Socket handle (which is a Win32 handle) */
672 OVERLAPPED ov; /* Overlapped I/O structure */
673 void* buffer; /* Buffer. */
674 unsigned long bufsize; /* Number of bytes last read */
675 unsigned long bufpos; /* Position in buffer for next fetch */
676 unsigned int error_p :1; /* I/O Error seen */
677 unsigned int eof_p :1; /* EOF Error seen */
678 unsigned int pending_p :1; /* There is a pending I/O operation */
679 unsigned int blocking_p :1; /* Last write attempt would block */
682 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
684 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
685 sizeof (struct winsock_stream));
688 winsock_initiate_read (struct winsock_stream *str)
690 ResetEvent (str->ov.hEvent);
693 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
694 &str->bufsize, &str->ov))
696 if (GetLastError () == ERROR_IO_PENDING)
698 else if (GetLastError () == ERROR_HANDLE_EOF)
703 else if (str->bufsize == 0)
707 static Lstream_data_count
708 winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
710 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
712 /* If the current operation is not yet complete, there's nothing to
716 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
723 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
725 if (GetLastError() == ERROR_HANDLE_EOF)
730 if (str->bufsize == 0)
741 /* Return as much of buffer as we have */
742 size = min (size, (Lstream_data_count) (str->bufsize - str->bufpos));
743 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size);
746 /* Read more if buffer is exhausted */
747 if (str->bufsize == str->bufpos)
748 winsock_initiate_read (str);
753 static Lstream_data_count
754 winsock_writer (Lstream *stream, const unsigned char *data,
755 Lstream_data_count size)
757 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
761 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
769 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
783 ResetEvent (str->ov.hEvent);
785 /* According to WriteFile docs, we must hold onto the data we pass to it
786 and not make any changes until it finishes -- which may not be until
787 the next time we get here, since we use asynchronous I/O. We have
788 in fact seen data loss as a result of not doing this. */
789 str->buffer = xrealloc (str->buffer, size);
790 memcpy (str->buffer, data, size);
792 /* According to MSDN WriteFile docs, the fourth parameter cannot be NULL
793 on Win95 even when doing an overlapped operation, as we are, where
794 the return value through that parameter is not meaningful. */
795 if (WriteFile ((HANDLE)str->s, str->buffer, size, &str->bufsize,
797 || GetLastError() == ERROR_IO_PENDING)
802 return str->error_p ? -1 : size;
806 winsock_closer (Lstream *lstr)
808 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
810 if (lstr->flags & LSTREAM_FL_READ)
811 shutdown (str->s, 0);
813 shutdown (str->s, 1);
815 closesocket (str->s);
817 WaitForSingleObject (str->ov.hEvent, INFINITE);
825 CloseHandle (str->ov.hEvent);
830 winsock_was_blocked_p (Lstream *stream)
832 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
833 return str->blocking_p;
837 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
840 Lstream *lstr = Lstream_new (lstream_winsock, mode);
841 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
845 str->user_data = param;
847 str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
849 if (lstr->flags & LSTREAM_FL_READ)
851 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
852 winsock_initiate_read (str);
855 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
856 XSETLSTREAM (obj, lstr);
861 make_winsock_input_stream (SOCKET s, LPARAM param)
863 return make_winsock_stream_1 (s, param, "r");
867 make_winsock_output_stream (SOCKET s, LPARAM param)
869 return make_winsock_stream_1 (s, param, "w");
873 get_winsock_stream_waitable (Lstream *lstr)
875 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
876 return str->ov.hEvent;
880 get_winsock_stream_param (Lstream *lstr)
882 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
883 return str->user_data;
887 init_winsock_stream (void)
889 LSTREAM_HAS_METHOD (winsock, reader);
890 LSTREAM_HAS_METHOD (winsock, writer);
891 LSTREAM_HAS_METHOD (winsock, closer);
892 LSTREAM_HAS_METHOD (winsock, was_blocked_p);
894 #endif /* defined (HAVE_SOCKETS) */
896 /************************************************************************/
897 /* Dispatch queue management */
898 /************************************************************************/
901 mswindows_user_event_p (Lisp_Event* sevt)
903 return (sevt->event_type == key_press_event
904 || sevt->event_type == button_press_event
905 || sevt->event_type == button_release_event
906 || sevt->event_type == misc_user_event);
910 * Add an emacs event to the proper dispatch queue
913 mswindows_enqueue_dispatch_event (Lisp_Object event)
915 int user_p = mswindows_user_event_p (XEVENT(event));
916 enqueue_event (event,
917 user_p ? &mswindows_u_dispatch_event_queue :
918 &mswindows_s_dispatch_event_queue,
919 user_p ? &mswindows_u_dispatch_event_queue_tail :
920 &mswindows_s_dispatch_event_queue_tail);
922 /* Avoid blocking on WaitMessage */
923 PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
927 * Add a misc-user event to the dispatch queue.
929 * Stuff it into our own dispatch queue, so we have something
930 * to return from next_event callback.
933 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
936 Lisp_Object event = Fmake_event (Qnil, Qnil);
937 Lisp_Event* e = XEVENT (event);
939 e->event_type = misc_user_event;
940 e->channel = channel;
941 e->timestamp = GetTickCount ();
942 e->event.misc.function = function;
943 e->event.misc.object = object;
945 mswindows_enqueue_dispatch_event (event);
949 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
951 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
952 Lisp_Event* event = XEVENT (emacs_event);
954 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil;
955 event->timestamp = GetMessageTime();
956 event->event_type = magic_event;
957 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg;
959 mswindows_enqueue_dispatch_event (emacs_event);
963 mswindows_enqueue_process_event (Lisp_Process* p)
965 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
966 Lisp_Event* event = XEVENT (emacs_event);
968 XSETPROCESS (process, p);
970 event->event_type = process_event;
971 event->timestamp = GetTickCount ();
972 event->event.process.process = process;
974 mswindows_enqueue_dispatch_event (emacs_event);
978 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
979 int mods, DWORD when)
981 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
982 msg == WM_RBUTTONDOWN);
984 /* Wheel rotation amount: positive is away from user, negative towards user */
985 int delta = (short) HIWORD (mods);
987 /* We always use last message time, because mouse button
988 events may get delayed, and XEmacs double click
989 recognition will fail */
991 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
992 Lisp_Event* event = XEVENT (emacs_event);
994 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
995 event->channel = mswindows_find_frame (hwnd);
996 event->timestamp = when;
997 event->event.button.button =
998 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
999 (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONUP) ? 2 :
1000 (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 :
1001 (msg==WM_MOUSEWHEEL && delta>0) ? 4 : 5;
1002 event->event.button.x = where.x;
1003 event->event.button.y = where.y;
1004 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
1008 event->event_type = button_press_event;
1010 /* we need this to make sure the main window regains the focus
1011 from control subwindows */
1012 if (GetFocus() != hwnd)
1015 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1020 event->event_type = button_release_event;
1024 mswindows_enqueue_dispatch_event (emacs_event);
1028 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1030 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1031 Lisp_Event* event = XEVENT(emacs_event);
1033 event->channel = mswindows_find_console(hwnd);
1034 event->timestamp = GetMessageTime();
1035 event->event_type = key_press_event;
1036 event->event.key.keysym = keysym;
1037 event->event.key.modifiers = mods;
1038 mswindows_enqueue_dispatch_event (emacs_event);
1042 * Remove and return the first emacs event on the dispatch queue.
1043 * Give a preference to user events over non-user ones.
1046 mswindows_dequeue_dispatch_event (void)
1051 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1052 !NILP(mswindows_s_dispatch_event_queue));
1054 event = dequeue_event (
1055 NILP(mswindows_u_dispatch_event_queue) ?
1056 &mswindows_s_dispatch_event_queue :
1057 &mswindows_u_dispatch_event_queue,
1058 NILP(mswindows_u_dispatch_event_queue) ?
1059 &mswindows_s_dispatch_event_queue_tail :
1060 &mswindows_u_dispatch_event_queue_tail);
1062 sevt = XEVENT (event);
1063 if (sevt->event_type == key_press_event
1064 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1065 sevt->event.key.modifiers &=
1066 ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
1072 * Remove and return the first emacs event on the dispatch queue that matches
1073 * the supplied event.
1074 * Timeout event matches if interval_id is equal to that of the given event.
1075 * Keypress event matches if logical AND between modifiers bitmask of the
1076 * event in the queue and that of the given event is non-zero.
1077 * For all other event types, this function ABORTs.
1081 mswindows_cancel_dispatch_event (Lisp_Event *match)
1084 Lisp_Object previous_event = Qnil;
1085 int user_p = mswindows_user_event_p (match);
1086 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1087 &mswindows_s_dispatch_event_queue;
1088 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1089 &mswindows_s_dispatch_event_queue_tail;
1091 assert (match->event_type == timeout_event
1092 || match->event_type == key_press_event);
1094 EVENT_CHAIN_LOOP (event, *head)
1096 Lisp_Event *e = XEVENT (event);
1097 if ((e->event_type == match->event_type) &&
1098 ((e->event_type == timeout_event) ?
1099 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1100 /* Must be key_press_event */
1101 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1103 if (NILP (previous_event))
1104 dequeue_event (head, tail);
1107 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1108 if (EQ (*tail, event))
1109 *tail = previous_event;
1114 previous_event = event;
1119 #ifndef HAVE_MSG_SELECT
1120 /************************************************************************/
1121 /* Waitable handles manipulation */
1122 /************************************************************************/
1124 find_waitable_handle (HANDLE h)
1127 for (i = 0; i < mswindows_waitable_count; ++i)
1128 if (mswindows_waitable_handles[i] == h)
1135 add_waitable_handle (HANDLE h)
1137 assert (find_waitable_handle (h) < 0);
1138 if (mswindows_waitable_count == MAX_WAITABLE)
1141 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1146 remove_waitable_handle (HANDLE h)
1148 int ix = find_waitable_handle (h);
1152 mswindows_waitable_handles [ix] =
1153 mswindows_waitable_handles [--mswindows_waitable_count];
1155 #endif /* HAVE_MSG_SELECT */
1158 * Given a lisp process pointer remove the corresponding process handle
1159 * from mswindows_waitable_handles if it is in it. Normally the handle is
1160 * removed when the process terminates, but if the lisp process structure
1161 * is deleted before the process terminates we must delete the process
1162 * handle since it will be invalid and will cause the wait to fail
1165 mswindows_unwait_process (Lisp_Process *p)
1167 #ifndef HAVE_MSG_SELECT
1168 remove_waitable_handle (get_nt_process_handle (p));
1169 #endif /* HAVE_MSG_SELECT */
1173 /************************************************************************/
1175 /************************************************************************/
1178 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1179 Lisp_Object u_n_u_s_e_d)
1181 mswindows_error_caught_in_modal_loop = cons_sig_data;
1186 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1191 ++mswindows_in_modal_loop;
1192 tmp = condition_case_1 (Qt,
1194 mswindows_modal_loop_error_handler, Qnil);
1195 --mswindows_in_modal_loop;
1201 mswindows_unmodalize_signal_maybe (void)
1203 if (!NILP (mswindows_error_caught_in_modal_loop))
1205 /* Got an error while messages were pumped while
1206 in window procedure - have to resignal */
1207 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1208 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1209 mswindows_error_caught_in_modal_loop = Qnil;
1210 Fsignal (sym, data);
1215 * This is an unsafe part of event pump, guarded by
1216 * condition_case. See mswindows_pump_outstanding_events
1219 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1221 /* This function can call lisp */
1222 Lisp_Object event = Fmake_event (Qnil, Qnil);
1223 struct gcpro gcpro1;
1224 int do_redisplay = 0;
1227 while (detect_input_pending ())
1229 Fnext_event (event, Qnil);
1230 Fdispatch_event (event);
1237 Fdeallocate_event (event);
1240 /* Qt becomes return value of mswindows_pump_outstanding_events
1246 * This function pumps emacs events, while available, by using
1247 * next_message/dispatch_message loop. Errors are trapped around
1248 * the loop so the function always returns.
1250 * Windows message queue is not looked into during the call,
1251 * neither are waitable handles checked. The function pumps
1252 * thus only dispatch events already queued, as well as those
1253 * resulted in dispatching thereof. This is done by setting
1254 * module local variable mswindows_in_modal_loop to nonzero.
1256 * Return value is Qt if no errors was trapped, or Qunbound if
1257 * there was an error.
1259 * In case of error, a cons representing the error, in the
1260 * form (SIGNAL . DATA), is stored in the module local variable
1261 * mswindows_error_caught_in_modal_loop. This error is signaled
1262 * again when DispatchMessage returns. Thus, Windows internal
1263 * modal loops are protected against throws, which are proven
1264 * to corrupt internal Windows structures.
1266 * In case of success, mswindows_error_caught_in_modal_loop is
1269 * If the value of mswindows_error_caught_in_modal_loop is not
1270 * nil already upon entry, the function just returns non-nil.
1271 * This situation means that a new event has been queued while
1272 * in cancel mode. The event will be dequeued on the next regular
1273 * call of next-event; the pump is off since error is caught.
1274 * The caller must *unconditionally* cancel modal loop if the
1275 * value returned by this function is nil. Otherwise, everything
1276 * will become frozen until the modal loop exits under normal
1277 * condition (scrollbar drag is released, menu closed etc.)
1280 mswindows_pump_outstanding_events (void)
1282 /* This function can call lisp */
1284 Lisp_Object result = Qt;
1285 struct gcpro gcpro1;
1288 if (NILP(mswindows_error_caught_in_modal_loop))
1289 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1295 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1296 * QUITP, and are interesting in keyboard messages only.
1299 mswindows_drain_windows_queue (void)
1303 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1304 assert (!mswindows_in_modal_loop);
1306 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1308 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1310 /* Don't translate messages destined for a dialog box, this
1311 makes keyboard traversal work. I think?? */
1312 if (mswindows_is_dialog_msg (&msg))
1314 mswindows_unmodalize_signal_maybe ();
1318 /* We have to translate messages that are not sent to an XEmacs
1319 frame. This is so that key presses work ok in things like
1320 edit fields. However, we *musn't* translate message for XEmacs
1321 frames as this is handled in the wnd proc.
1322 We also have to avoid generating paint magic events for windows
1323 that aren't XEmacs frames */
1324 /* GetClassName will truncate a longer class name. By adding one
1325 extra character, we are forcing textual comparison to fail
1326 if the name is longer than XEMACS_CLASS */
1328 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1329 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1331 /* Not an XEmacs frame */
1332 TranslateMessage (&msg);
1334 else if (msg.message == WM_PAINT)
1336 struct mswindows_frame* msframe;
1338 /* hdc will be NULL unless this is a subwindow - in which case we
1339 shouldn't have received a paint message for it here. */
1340 assert (msg.wParam == 0);
1342 /* Queue a magic event for handling when safe */
1344 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1345 if (!msframe->paint_pending)
1347 msframe->paint_pending = 1;
1348 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1350 /* Don't dispatch. WM_PAINT is always the last message in the
1351 queue so it's OK to just return. */
1354 DispatchMessage (&msg);
1355 mswindows_unmodalize_signal_maybe ();
1360 * This is a special flavor of the mswindows_need_event function,
1361 * used while in event pump. Actually, there is only kind of events
1362 * allowed while in event pump: a timer. An attempt to fetch any
1363 * other event leads to a deadlock, as there's no source of user input
1364 * ('cause event pump mirrors windows modal loop, which is a sole
1365 * owner of thread message queue).
1367 * To detect this, we use a counter of active timers, and allow
1368 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1369 * which will never come when there are no pending timers, which leads
1370 * to deadlock, we simply signal an error.
1372 * It might be possible to combine this with mswindows_drain_windows_queue
1373 * which fetches events when not in a modal loop. It's not clear
1374 * whether the result would be more complex than is justified.
1377 mswindows_need_event_in_modal_loop (int badly_p)
1381 /* Check if already have one */
1382 if (!NILP (mswindows_u_dispatch_event_queue)
1383 || !NILP (mswindows_s_dispatch_event_queue))
1386 /* No event is ok */
1390 /* We do not check the _u_ queue, because timers go to _s_ */
1391 while (NILP (mswindows_s_dispatch_event_queue))
1393 /* We'll deadlock if go waiting */
1394 if (mswindows_pending_timers_count == 0)
1395 error ("Deadlock due to an attempt to call next-event in a wrong context");
1397 /* Fetch and dispatch any pending timers */
1398 if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1399 DispatchMessage (&msg);
1404 * This drains the event queue and fills up two internal queues until
1405 * an event of a type specified by USER_P is retrieved.
1408 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1411 mswindows_need_event (int badly_p)
1415 while (NILP (mswindows_u_dispatch_event_queue)
1416 && NILP (mswindows_s_dispatch_event_queue))
1418 #ifdef HAVE_MSG_SELECT
1420 SELECT_TYPE temp_mask = input_wait_mask;
1421 EMACS_TIME sometime;
1422 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1425 pointer_to_this = 0;
1428 EMACS_SET_SECS_USECS (sometime, 0, 0);
1429 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1430 pointer_to_this = &select_time_to_block;
1431 if (mswindows_in_modal_loop)
1432 /* In modal loop with badly_p false, don't care about
1434 FD_CLR (windows_fd, &temp_mask);
1437 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1442 return; /* timeout */
1444 else if (active > 0)
1446 if (FD_ISSET (windows_fd, &temp_mask))
1448 if (mswindows_in_modal_loop)
1449 mswindows_need_event_in_modal_loop (badly_p);
1451 mswindows_drain_windows_queue ();
1456 /* Look for a TTY event */
1457 for (i = 0; i < MAXDESC-1; i++)
1459 /* To avoid race conditions (among other things, an infinite
1460 loop when called from Fdiscard_input()), we must return
1461 user events ahead of process events. */
1462 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1464 struct console *c = tty_find_console_from_fd (i);
1465 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1466 Lisp_Event* event = XEVENT (emacs_event);
1469 if (read_event_from_tty_or_stream_desc (event, c, i))
1471 mswindows_enqueue_dispatch_event (emacs_event);
1477 /* Look for a process event */
1478 for (i = 0; i < MAXDESC-1; i++)
1480 if (FD_ISSET (i, &temp_mask))
1482 if (FD_ISSET (i, &process_only_mask))
1485 get_process_from_usid (FD_TO_USID(i));
1487 mswindows_enqueue_process_event (p);
1491 /* We might get here when a fake event came
1492 through a signal. Return a dummy event, so
1493 that a cycle of the command loop will
1495 drain_signal_event_pipe ();
1496 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1502 else if (active==-1)
1506 /* something bad happened */
1515 /* Now try getting a message or process event */
1519 if (mswindows_in_modal_loop)
1520 /* In a modal loop, only look for timer events, and only if
1521 we really need one. */
1524 what_events = QS_TIMER;
1529 /* Look for any event */
1530 what_events = QS_ALLINPUT;
1532 /* This fixes a long outstanding bug, where XEmacs would occasionally
1533 * not redraw its window (or process other events) until "something
1534 * happened" - usually the mouse moving over a frame.
1536 * The problem is that MsgWaitForMultipleObjects only checks to see
1537 * if NEW messages have been placed into the thread queue. So we
1538 * specifically check to see if the queue is empty (using PeekMessage
1539 * with the PM_NOREMOVE flag) before we wait.
1541 if (what_events == QS_ALLINPUT && badly_p &&
1542 PeekMessage (&msg, 0, 0, 0, PM_NOREMOVE))
1543 active = WAIT_OBJECT_0 + mswindows_waitable_count;
1545 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1546 mswindows_waitable_handles,
1547 FALSE, badly_p ? INFINITE : 0,
1550 /* This will assert if handle being waited for becomes abandoned.
1551 Not the case currently tho */
1552 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1553 (active >= WAIT_OBJECT_0 &&
1554 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1556 if (active == WAIT_TIMEOUT)
1558 /* No luck trying - just return what we've already got */
1561 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1563 /* Got your message, thanks */
1564 if (mswindows_in_modal_loop)
1565 mswindows_need_event_in_modal_loop (badly_p);
1567 mswindows_drain_windows_queue ();
1571 int ix = active - WAIT_OBJECT_0;
1572 /* First, try to find which process' output has signaled */
1574 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1577 /* Found a signaled process input handle */
1578 mswindows_enqueue_process_event (p);
1582 /* None. This means that the process handle itself has signaled.
1583 Remove the handle from the wait vector, and make status_notify
1584 note the exited process. First find the process object if
1586 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
1587 if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
1588 mswindows_waitable_handles [ix])
1590 mswindows_waitable_handles [ix] =
1591 mswindows_waitable_handles [--mswindows_waitable_count];
1592 kick_status_notify ();
1593 /* We need to return a process event here so that
1594 (1) accept-process-output will return when called on this
1595 process, and (2) status notifications will happen in
1596 accept-process-output, sleep-for, and sit-for. */
1597 /* #### horrible kludge till my real process fixes go in.
1598 #### Replaced with a slightly less horrible kluge that
1599 at least finds the right process instead of axing the
1600 first one on the list.
1602 if (!NILP (vproctail))
1604 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1606 else /* trash me soon. */
1607 /* Have to return something: there may be no accompanying
1609 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1616 /************************************************************************/
1617 /* Event generators */
1618 /************************************************************************/
1621 * Callback procedure for synchronous timer messages
1623 static void CALLBACK
1624 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1626 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1627 Lisp_Event *event = XEVENT (emacs_event);
1629 if (KillTimer (NULL, id_timer))
1630 --mswindows_pending_timers_count;
1632 event->channel = Qnil;
1633 event->timestamp = dwtime;
1634 event->event_type = timeout_event;
1635 event->event.timeout.interval_id = id_timer;
1636 event->event.timeout.function = Qnil;
1637 event->event.timeout.object = Qnil;
1639 mswindows_enqueue_dispatch_event (emacs_event);
1643 * Callback procedure for dde messages
1645 * We execute a dde Open("file") by simulating a file drop, so dde support
1646 * depends on dnd support.
1648 #ifdef HAVE_DRAGNDROP
1649 extern int mswindows_dde_enable;
1652 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1653 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1654 DWORD dwData1, DWORD dwData2)
1659 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1660 return (HDDEDATA)TRUE;
1661 return (HDDEDATA)FALSE;
1663 case XTYP_WILDCONNECT:
1665 /* We only support one {service,topic} pair */
1666 HSZPAIR pairs[2] = {
1667 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1669 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1670 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1671 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1672 sizeof (pairs), 0L, 0, uFmt, 0));
1674 return (HDDEDATA)NULL;
1677 if (!mswindows_dde_enable)
1678 return (HDDEDATA) DDE_FBUSY;
1680 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1682 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1683 LPBYTE cmd = (LPBYTE) alloca (len+1);
1686 struct gcpro gcpro1, gcpro2;
1687 Lisp_Object l_dndlist = Qnil;
1688 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1689 Lisp_Object frmcons, devcons, concons;
1690 Lisp_Event *event = XEVENT (emacs_event);
1692 DdeGetData (hdata, cmd, len, 0);
1694 DdeFreeDataHandle (hdata);
1696 /* Check syntax & that it's an [Open("foo")] command, which we
1697 * treat like a file drop */
1698 /* #### Ought to be generalised and accept some other commands */
1701 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1702 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1703 return DDE_FNOTPROCESSED;
1704 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1707 if (*cmd!='(' || *(cmd+1)!='\"')
1708 return DDE_FNOTPROCESSED;
1710 while (*end && *end!='\"')
1713 return DDE_FNOTPROCESSED;
1716 return DDE_FNOTPROCESSED;
1720 return DDE_FNOTPROCESSED;
1723 filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5);
1724 strcpy (filename, "file:");
1725 cygwin_win32_to_posix_path_list (cmd, filename+5);
1727 dostounix_filename (cmd);
1728 filename = alloca (strlen (cmd)+6);
1729 strcpy (filename, "file:");
1730 strcat (filename, cmd);
1732 GCPRO2 (emacs_event, l_dndlist);
1733 l_dndlist = make_string (filename, strlen (filename));
1735 /* Find a mswindows frame */
1736 event->channel = Qnil;
1737 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1739 Lisp_Object frame = XCAR (frmcons);
1740 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1741 event->channel = frame;
1743 assert (!NILP (event->channel));
1745 event->timestamp = GetTickCount();
1746 event->event_type = misc_user_event;
1747 event->event.misc.button = 1;
1748 event->event.misc.modifiers = 0;
1749 event->event.misc.x = -1;
1750 event->event.misc.y = -1;
1751 event->event.misc.function = Qdragdrop_drop_dispatch;
1752 event->event.misc.object = Fcons (Qdragdrop_URL,
1753 Fcons (l_dndlist, Qnil));
1754 mswindows_enqueue_dispatch_event (emacs_event);
1756 return (HDDEDATA) DDE_FACK;
1758 DdeFreeDataHandle (hdata);
1759 return (HDDEDATA) DDE_FNOTPROCESSED;
1762 return (HDDEDATA) NULL;
1768 * Helper to do repainting - repaints can happen both from the windows
1769 * procedure and from magic events
1772 mswindows_handle_paint (struct frame *frame)
1774 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1776 /* According to the docs we need to check GetUpdateRect() before
1777 actually doing a WM_PAINT */
1778 if (GetUpdateRect (hwnd, NULL, FALSE))
1780 PAINTSTRUCT paintStruct;
1781 int x, y, width, height;
1783 BeginPaint (hwnd, &paintStruct);
1784 x = paintStruct.rcPaint.left;
1785 y = paintStruct.rcPaint.top;
1786 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1787 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1788 /* Normally we want to ignore expose events when child
1789 windows are unmapped, however once we are in the guts of
1790 WM_PAINT we need to make sure that we don't register
1791 unmaps then because they will not actually occur. */
1792 /* #### commenting out the next line seems to fix some problems
1793 but not all. only andy currently understands this stuff and
1794 he needs to review it more carefully. --ben */
1795 if (!check_for_ignored_expose (frame, x, y, width, height))
1797 hold_ignored_expose_registration = 1;
1798 mswindows_redraw_exposed_area (frame, x, y, width, height);
1799 hold_ignored_expose_registration = 0;
1801 EndPaint (hwnd, &paintStruct);
1806 * Returns 1 if a key is a real modifier or special key, which
1807 * is better handled by DefWindowProc
1810 key_needs_default_processing_p (UINT vkey)
1812 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1813 /* if we let ALT activate the menu like this, then sticky ALT-modified
1814 keystrokes become impossible. */
1815 && !modifier_keys_are_sticky)
1821 /* key-handling code is always ugly. It just ends up working out
1824 #### Most of the sticky-modifier code below is copied from similar
1825 code in event-Xt.c. They should somehow or other be merged.
1827 Here are some pointers:
1829 -- DOWN_MASK indicates which modifiers should be treated as "down"
1830 when the corresponding upstroke happens. It gets reset for
1831 a particular modifier when that modifier goes up, and reset
1832 for all modifiers when a non-modifier key is pressed. Example:
1834 I press Control-A-Shift and then release Control-A-Shift.
1835 I want the Shift key to be sticky but not the Control key.
1837 -- If a modifier key is sticky, I can unstick it by pressing
1838 the modifier key again. */
1840 static WPARAM last_downkey;
1841 static int need_to_add_mask, down_mask;
1843 #define XEMSW_LCONTROL (1<<0)
1844 #define XEMSW_RCONTROL (1<<1)
1845 #define XEMSW_LSHIFT (1<<2)
1846 #define XEMSW_RSHIFT (1<<3)
1847 #define XEMSW_LMENU (1<<4)
1848 #define XEMSW_RMENU (1<<5)
1851 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1852 int downp, int keyp)
1856 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1860 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1861 wParam == VK_RCONTROL ||
1862 wParam == VK_MENU || wParam == VK_LMENU ||
1863 wParam == VK_RMENU ||
1864 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1865 wParam == VK_RSHIFT)))
1866 { /* Not a modifier key */
1867 if (downp && keyp && !last_downkey)
1868 last_downkey = wParam;
1869 /* If I hold press-and-release the Control key and then press
1870 and hold down the right arrow, I want it to auto-repeat
1871 Control-Right. On the other hand, if I do the same but
1872 manually press the Right arrow a bunch of times, I want
1873 to see one Control-Right and then a bunch of Rights.
1874 This means that we need to distinguish between an
1875 auto-repeated key and a key pressed and released a bunch
1877 else if ((downp && !keyp) ||
1878 (downp && keyp && last_downkey &&
1879 (wParam != last_downkey ||
1880 /* the "previous key state" bit indicates autorepeat */
1881 ! (lParam & (1 << 30)))))
1883 need_to_add_mask = 0;
1889 mods = need_to_add_mask;
1891 else /* Modifier key pressed */
1893 /* If a non-modifier key was pressed in the middle of a bunch
1894 of modifiers, then it unsticks all the modifiers that were
1895 previously pressed. We cannot unstick the modifiers until
1896 now because we want to check for auto-repeat of the
1897 non-modifier key. */
1902 need_to_add_mask = 0;
1905 #define FROB(mask) \
1907 if (downp && keyp) \
1909 /* If modifier key is already sticky, \
1910 then unstick it. Note that we do \
1911 not test down_mask to deal with the \
1912 unlikely but possible case that the \
1913 modifier key auto-repeats. */ \
1914 if (need_to_add_mask & mask) \
1916 need_to_add_mask &= ~mask; \
1917 down_mask &= ~mask; \
1920 down_mask |= mask; \
1924 if (down_mask & mask) \
1926 down_mask &= ~mask; \
1927 need_to_add_mask |= mask; \
1932 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1933 || wParam == VK_RCONTROL)
1934 FROB (XEMSW_RCONTROL);
1935 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1936 || wParam == VK_LCONTROL)
1937 FROB (XEMSW_LCONTROL);
1939 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1940 || wParam == VK_RSHIFT)
1941 FROB (XEMSW_RSHIFT);
1942 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1943 || wParam == VK_LSHIFT)
1944 FROB (XEMSW_LSHIFT);
1946 if ((wParam == VK_MENU && (lParam & 0x1000000))
1947 || wParam == VK_RMENU)
1949 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1950 || wParam == VK_LMENU)
1959 GetKeyboardState (keymap);
1961 if (mods & XEMSW_LCONTROL)
1963 keymap [VK_CONTROL] |= 0x80;
1964 keymap [VK_LCONTROL] |= 0x80;
1966 if (mods & XEMSW_RCONTROL)
1968 keymap [VK_CONTROL] |= 0x80;
1969 keymap [VK_RCONTROL] |= 0x80;
1972 if (mods & XEMSW_LSHIFT)
1974 keymap [VK_SHIFT] |= 0x80;
1975 keymap [VK_LSHIFT] |= 0x80;
1977 if (mods & XEMSW_RSHIFT)
1979 keymap [VK_SHIFT] |= 0x80;
1980 keymap [VK_RSHIFT] |= 0x80;
1983 if (mods & XEMSW_LMENU)
1985 keymap [VK_MENU] |= 0x80;
1986 keymap [VK_LMENU] |= 0x80;
1988 if (mods & XEMSW_RMENU)
1990 keymap [VK_MENU] |= 0x80;
1991 keymap [VK_RMENU] |= 0x80;
1994 SetKeyboardState (keymap);
2002 clear_sticky_modifiers (void)
2004 need_to_add_mask = 0;
2014 output_modifier_keyboard_state (void)
2018 GetKeyboardState (keymap);
2020 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2021 keymap[VK_MENU] & 0x80 ? 1 : 0,
2022 keymap[VK_MENU] & 0x1 ? 1 : 0,
2023 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2024 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2025 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2026 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2027 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
2028 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
2029 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
2030 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
2031 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
2032 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
2033 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
2034 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
2035 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
2036 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
2037 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
2038 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
2039 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
2040 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
2045 /* try to debug the stuck-alt-key problem.
2047 #### this happens only inconsistently, and may only happen when using
2048 StickyKeys in the Win2000 accessibility section of the control panel,
2049 which is extremely broken for other reasons. */
2052 output_alt_keyboard_state (void)
2056 // SHORT asyncstate[3];
2058 GetKeyboardState (keymap);
2059 keystate[0] = GetKeyState (VK_MENU);
2060 keystate[1] = GetKeyState (VK_LMENU);
2061 keystate[2] = GetKeyState (VK_RMENU);
2062 /* Doing this interferes with key processing. */
2063 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2064 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2065 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2067 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2068 keymap[VK_MENU] & 0x80 ? 1 : 0,
2069 keymap[VK_MENU] & 0x1 ? 1 : 0,
2070 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2071 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2072 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2073 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2074 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2075 keystate[0] & 0x8000 ? 1 : 0,
2076 keystate[0] & 0x1 ? 1 : 0,
2077 keystate[1] & 0x8000 ? 1 : 0,
2078 keystate[1] & 0x1 ? 1 : 0,
2079 keystate[2] & 0x8000 ? 1 : 0,
2080 keystate[2] & 0x1 ? 1 : 0);
2081 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2082 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2083 /* asyncstate[0] & 0x1 ? 1 : 0, */
2084 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2085 /* asyncstate[1] & 0x1 ? 1 : 0, */
2086 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2087 /* asyncstate[2] & 0x1 ? 1 : 0); */
2090 #endif /* DEBUG_XEMACS */
2094 * The windows procedure for the window class XEMACS_CLASS
2097 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2099 /* Note: Remember to initialize emacs_event and event before use.
2100 This code calls code that can GC. You must GCPRO before calling such code. */
2101 Lisp_Object emacs_event = Qnil;
2102 Lisp_Object fobj = Qnil;
2105 struct frame *frame;
2106 struct mswindows_frame* msframe;
2108 /* If you hit this, rewrite the offending API call to occur after GC,
2109 using register_post_gc_action(). */
2110 assert (!gc_in_progress);
2113 if (debug_mswindows_events)
2114 debug_output_mswin_message (hwnd, message_, wParam, lParam);
2115 #endif /* DEBUG_XEMACS */
2117 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2120 case WM_DESTROYCLIPBOARD:
2121 /* We own the clipboard and someone else wants it. Delete our
2122 cached copy of the clipboard contents so we'll ask for it from
2123 Windows again when someone does a paste, and destroy any memory
2124 objects we hold on the clipboard that are not in the list of types
2125 that Windows will delete itself. */
2126 mswindows_destroy_selection (QCLIPBOARD);
2127 handle_selection_clear (QCLIPBOARD);
2131 /* Erase background only during non-dynamic sizing */
2132 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2133 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2138 fobj = mswindows_find_frame (hwnd);
2139 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2145 /* See Win95 comment under WM_KEYDOWN */
2148 int should_set_keymap = 0;
2151 if (debug_mswindows_events > 2)
2152 output_alt_keyboard_state ();
2153 #endif /* DEBUG_XEMACS */
2155 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2156 if (wParam == VK_CONTROL)
2158 GetKeyboardState (keymap);
2159 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2160 should_set_keymap = 1;
2162 else if (wParam == VK_MENU)
2164 GetKeyboardState (keymap);
2165 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2166 should_set_keymap = 1;
2169 if (should_set_keymap)
2170 // && (message_ != WM_SYSKEYUP
2171 // || NILP (Vmenu_accelerator_enabled)))
2172 SetKeyboardState (keymap);
2176 if (key_needs_default_processing_p (wParam))
2184 /* In some locales the right-hand Alt key is labelled AltGr. This key
2185 * should produce alternative characters when combined with another key.
2186 * eg on a German keyboard pressing AltGr+q should produce '@'.
2187 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2188 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2189 * it translates as if AltGr were down.
2190 * We get round this by removing all modifiers from the keymap before
2191 * calling TranslateMessage() unless AltGr is *really* down. */
2193 BYTE keymap_trans[256];
2194 BYTE keymap_orig[256];
2195 BYTE keymap_sticky[256];
2196 int has_AltGr = mswindows_current_layout_has_AltGr ();
2197 int mods = 0, mods_with_shift = 0;
2198 int extendedp = lParam & 0x1000000;
2203 if (debug_mswindows_events > 2)
2204 output_alt_keyboard_state ();
2205 #endif /* DEBUG_XEMACS */
2207 GetKeyboardState (keymap_orig);
2208 frame = XFRAME (mswindows_find_frame (hwnd));
2209 if ((sticky_changed =
2210 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2212 GetKeyboardState (keymap_sticky);
2213 if (keymap_sticky[VK_MENU] & 0x80)
2215 message_ = WM_SYSKEYDOWN;
2216 /* We have to set the "context bit" so that the
2217 TranslateMessage() call below that generates the
2218 SYSCHAR message does its thing; see the documentation
2224 memcpy (keymap_sticky, keymap_orig, 256);
2226 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2227 mods_with_shift = mods;
2229 /* Handle non-printables */
2230 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2233 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2235 SetKeyboardState (keymap_orig);
2237 else /* Normal keys & modifiers */
2240 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2241 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2243 int potential_accelerator = 0;
2244 int got_accelerator = 0;
2247 msg.message = message_;
2248 msg.wParam = wParam;
2249 msg.lParam = lParam;
2250 msg.time = GetMessageTime();
2253 /* GetKeyboardState() does not work as documented on Win95. We have
2254 * to loosely track Left and Right modifiers on behalf of the OS,
2255 * without screwing up Windows NT which tracks them properly. */
2256 if (wParam == VK_CONTROL)
2258 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2259 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2261 else if (wParam == VK_MENU)
2263 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2264 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2267 if (!NILP (Vmenu_accelerator_enabled) &&
2268 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2269 potential_accelerator = 1;
2271 /* Remove shift modifier from an ascii character */
2272 mods &= ~XEMACS_MOD_SHIFT;
2274 memcpy (keymap_trans, keymap_sticky, 256);
2276 /* Clear control and alt modifiers unless AltGr is pressed */
2277 keymap_trans[VK_RCONTROL] = 0;
2278 keymap_trans[VK_LMENU] = 0;
2279 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2280 || !(keymap_trans[VK_RMENU] & 0x80))
2282 keymap_trans[VK_LCONTROL] = 0;
2283 keymap_trans[VK_CONTROL] = 0;
2284 keymap_trans[VK_RMENU] = 0;
2285 keymap_trans[VK_MENU] = 0;
2287 SetKeyboardState (keymap_trans);
2289 /* Maybe generate some WM_[SYS]CHARs in the queue */
2290 TranslateMessage (&msg);
2292 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2293 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2296 int mods_with_quit = mods;
2297 WPARAM ch = tranmsg.wParam;
2300 if (debug_mswindows_events)
2303 debug_output_mswin_message (tranmsg.hwnd, tranmsg.message,
2307 #endif /* DEBUG_XEMACS */
2309 /* If a quit char with no modifiers other than control and
2310 shift, then mark it with a fake modifier, which is removed
2311 upon dequeueing the event */
2312 /* !!#### Fix this in my mule ws -- replace current_buffer
2314 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2315 && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2316 DOWNCASE (current_buffer, ch))
2317 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2318 && DOWNCASE (current_buffer, quit_ch) ==
2319 DOWNCASE (current_buffer, ch)))
2320 && ((mods_with_shift &
2321 ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2324 mods_with_quit |= FAKE_MOD_QUIT;
2325 if (mods_with_shift & XEMACS_MOD_SHIFT)
2326 mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2327 mswindows_quit_chars_count++;
2329 else if (potential_accelerator && !got_accelerator &&
2330 mswindows_char_is_accelerator (frame, ch))
2332 got_accelerator = 1;
2335 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2339 /* This generates WM_SYSCHAR messages, which are interpreted
2340 by DefWindowProc as the menu selections. */
2341 if (got_accelerator)
2343 SetKeyboardState (keymap_sticky);
2344 TranslateMessage (&msg);
2345 SetKeyboardState (keymap_orig);
2349 SetKeyboardState (keymap_orig);
2353 if (key_needs_default_processing_p (wParam))
2358 case WM_MBUTTONDOWN:
2360 /* Real middle mouse button has nothing to do with emulated one:
2361 if one wants to exercise fingers playing chords on the mouse,
2362 he is allowed to do that! */
2363 mswindows_enqueue_mouse_button_event (hwnd, message_,
2364 MAKEPOINTS (lParam),
2365 wParam &~ MK_MBUTTON,
2370 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2371 msframe->last_click_time = GetMessageTime();
2373 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2374 msframe->button2_need_lbutton = 0;
2375 if (msframe->ignore_next_lbutton_up)
2377 msframe->ignore_next_lbutton_up = 0;
2379 else if (msframe->button2_is_down)
2381 msframe->button2_is_down = 0;
2382 msframe->ignore_next_rbutton_up = 1;
2383 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2384 MAKEPOINTS (lParam),
2386 &~ (MK_LBUTTON | MK_MBUTTON
2392 if (msframe->button2_need_rbutton)
2394 msframe->button2_need_rbutton = 0;
2395 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2396 MAKEPOINTS (lParam),
2397 wParam &~ MK_LBUTTON,
2400 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2401 MAKEPOINTS (lParam),
2402 wParam &~ MK_LBUTTON,
2408 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2409 msframe->last_click_time = GetMessageTime();
2411 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2412 msframe->button2_need_rbutton = 0;
2413 if (msframe->ignore_next_rbutton_up)
2415 msframe->ignore_next_rbutton_up = 0;
2417 else if (msframe->button2_is_down)
2419 msframe->button2_is_down = 0;
2420 msframe->ignore_next_lbutton_up = 1;
2421 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2422 MAKEPOINTS (lParam),
2424 &~ (MK_LBUTTON | MK_MBUTTON
2430 if (msframe->button2_need_lbutton)
2432 msframe->button2_need_lbutton = 0;
2433 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2434 MAKEPOINTS (lParam),
2435 wParam &~ MK_RBUTTON,
2438 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2439 MAKEPOINTS (lParam),
2440 wParam &~ MK_RBUTTON,
2445 case WM_LBUTTONDOWN:
2446 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2448 if (msframe->button2_need_lbutton)
2450 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2451 msframe->button2_need_lbutton = 0;
2452 msframe->button2_need_rbutton = 0;
2453 if (mswindows_button2_near_enough (msframe->last_click_point,
2454 MAKEPOINTS (lParam)))
2456 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2457 MAKEPOINTS (lParam),
2459 &~ (MK_LBUTTON | MK_MBUTTON
2462 msframe->button2_is_down = 1;
2466 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2467 msframe->last_click_point,
2468 msframe->last_click_mods
2470 msframe->last_click_time);
2471 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2472 MAKEPOINTS (lParam),
2473 wParam &~ MK_LBUTTON,
2479 mswindows_set_chord_timer (hwnd);
2480 msframe->button2_need_rbutton = 1;
2481 msframe->last_click_point = MAKEPOINTS (lParam);
2482 msframe->last_click_mods = wParam;
2484 msframe->last_click_time = GetMessageTime();
2487 case WM_RBUTTONDOWN:
2488 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2490 if (msframe->button2_need_rbutton)
2492 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2493 msframe->button2_need_lbutton = 0;
2494 msframe->button2_need_rbutton = 0;
2495 if (mswindows_button2_near_enough (msframe->last_click_point,
2496 MAKEPOINTS (lParam)))
2498 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2499 MAKEPOINTS (lParam),
2501 &~ (MK_LBUTTON | MK_MBUTTON
2504 msframe->button2_is_down = 1;
2508 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2509 msframe->last_click_point,
2510 msframe->last_click_mods
2512 msframe->last_click_time);
2513 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2514 MAKEPOINTS (lParam),
2515 wParam &~ MK_RBUTTON,
2521 mswindows_set_chord_timer (hwnd);
2522 msframe->button2_need_lbutton = 1;
2523 msframe->last_click_point = MAKEPOINTS (lParam);
2524 msframe->last_click_mods = wParam;
2526 msframe->last_click_time = GetMessageTime();
2530 if (wParam == BUTTON_2_TIMER_ID)
2532 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2533 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2535 if (msframe->button2_need_lbutton)
2537 msframe->button2_need_lbutton = 0;
2538 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2539 msframe->last_click_point,
2540 msframe->last_click_mods
2542 msframe->last_click_time);
2544 else if (msframe->button2_need_rbutton)
2546 msframe->button2_need_rbutton = 0;
2547 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2548 msframe->last_click_point,
2549 msframe->last_click_mods
2551 msframe->last_click_time);
2555 assert ("Spurious timer fired" == 0);
2559 /* Optimization: don't report mouse movement while size is changing */
2560 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2561 if (!msframe->sizing)
2563 /* When waiting for the second mouse button to finish
2564 button2 emulation, and have moved too far, just pretend
2565 as if timer has expired. This improves drag-select feedback */
2566 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2567 && !mswindows_button2_near_enough (msframe->last_click_point,
2568 MAKEPOINTS (lParam)))
2570 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2571 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2574 emacs_event = Fmake_event (Qnil, Qnil);
2575 event = XEVENT(emacs_event);
2577 event->channel = mswindows_find_frame(hwnd);
2578 event->timestamp = GetMessageTime();
2579 event->event_type = pointer_motion_event;
2580 event->event.motion.x = MAKEPOINTS(lParam).x;
2581 event->event.motion.y = MAKEPOINTS(lParam).y;
2582 event->event.motion.modifiers =
2583 mswindows_modifier_state (NULL, wParam, 0);
2585 mswindows_enqueue_dispatch_event (emacs_event);
2591 /* Queue a `cancel-mode-internal' misc user event, so mouse
2592 selection would be canceled if any */
2593 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2594 Qcancel_mode_internal, Qnil);
2599 LPNMHDR nmhdr = (LPNMHDR)lParam;
2601 if (nmhdr->code == TTN_NEEDTEXT)
2603 #ifdef HAVE_TOOLBARS
2604 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2607 /* find out which toolbar */
2608 frame = XFRAME (mswindows_find_frame (hwnd));
2609 btext = mswindows_get_toolbar_button_text ( frame,
2612 tttext->lpszText = NULL;
2613 tttext->hinst = NULL;
2617 /* I think this is safe since the text will only go away
2618 when the toolbar does...*/
2619 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2623 /* handle tree view callbacks */
2624 else if (nmhdr->code == TVN_SELCHANGED)
2626 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2627 frame = XFRAME (mswindows_find_frame (hwnd));
2628 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2630 /* handle tab control callbacks */
2631 else if (nmhdr->code == TCN_SELCHANGE)
2634 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2635 frame = XFRAME (mswindows_find_frame (hwnd));
2637 item.mask = TCIF_PARAM;
2638 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2641 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2647 /* hdc will be NULL unless this is a subwindow - in which case we
2648 shouldn't have received a paint message for it here. */
2649 assert (wParam == 0);
2651 /* Can't queue a magic event because windows goes modal and sends paint
2652 messages directly to the windows procedure when doing solid drags
2653 and the message queue doesn't get processed. */
2654 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2660 * If we receive a WM_ACTIVATE message that indicates that our frame
2661 * is being activated, make sure that the frame is marked visible
2662 * if the window itself is visible. This seems to fix the problem
2663 * where XEmacs appears to lock-up after switching desktops with
2664 * some virtual window managers.
2666 int state = (int)(short) LOWORD(wParam);
2668 if (debug_mswindows_events)
2669 stderr_out("state = %d\n", state);
2670 #endif /* DEBUG_XEMACS */
2671 if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
2674 if (debug_mswindows_events)
2675 stderr_out(" activating\n");
2676 #endif /* DEBUG_XEMACS */
2678 fobj = mswindows_find_frame (hwnd);
2679 frame = XFRAME (fobj);
2680 if (IsWindowVisible (hwnd))
2683 if (debug_mswindows_events)
2684 stderr_out(" window is visible\n");
2685 #endif /* DEBUG_XEMACS */
2686 if (!FRAME_VISIBLE_P (frame))
2689 if (debug_mswindows_events)
2690 stderr_out(" frame is not visible\n");
2691 #endif /* DEBUG_XEMACS */
2693 * It seems that we have to enqueue the XM_MAPFRAME event
2694 * prior to setting the frame visible so that
2695 * suspend-or-iconify-emacs works properly.
2697 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2698 FRAME_VISIBLE_P (frame) = 1;
2699 FRAME_ICONIFIED_P (frame) = 0;
2704 if (debug_mswindows_events)
2705 stderr_out(" frame is visible\n");
2707 #endif /* DEBUG_XEMACS */
2712 if (debug_mswindows_events)
2713 stderr_out(" window is not visible\n");
2715 #endif /* DEBUG_XEMACS */
2717 return DefWindowProc (hwnd, message_, wParam, lParam);
2721 case WM_WINDOWPOSCHANGED:
2722 /* This is sent before WM_SIZE; in fact, the processing of this
2723 by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when
2724 a window is hidden (make-frame-invisible), so we need to process
2725 this and update the state flags. */
2727 fobj = mswindows_find_frame (hwnd);
2728 frame = XFRAME (fobj);
2729 if (IsIconic (hwnd))
2731 FRAME_VISIBLE_P (frame) = 0;
2732 FRAME_ICONIFIED_P (frame) = 1;
2734 else if (IsWindowVisible (hwnd))
2736 /* APA: It's too early here to set the frame visible.
2737 * Let's do this later, in WM_SIZE processing, after the
2738 * magic XM_MAPFRAME event has been sent (just like 21.1
2740 /* FRAME_VISIBLE_P (frame) = 1; */
2741 FRAME_ICONIFIED_P (frame) = 0;
2745 FRAME_VISIBLE_P (frame) = 0;
2746 FRAME_ICONIFIED_P (frame) = 0;
2749 return DefWindowProc (hwnd, message_, wParam, lParam);
2754 The WM_SHOWWINDOW message is sent to a window when the window
2755 is about to be hidden or shown.
2756 APA: This message is also sent when switching to a virtual
2757 desktop under the virtuawin virtual window manager.
2761 fobj = mswindows_find_frame (hwnd);
2762 frame = XFRAME (fobj);
2765 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2766 FRAME_VISIBLE_P (frame) = 1;
2770 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2771 FRAME_VISIBLE_P (frame) = 0;
2777 /* We only care about this message if our size has really changed */
2778 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2783 fobj = mswindows_find_frame (hwnd);
2784 frame = XFRAME (fobj);
2785 msframe = FRAME_MSWINDOWS_DATA (frame);
2787 /* We cannot handle frame map and unmap hooks right in
2788 this routine, because these may throw. We queue
2789 magic events to run these hooks instead - kkm */
2791 if (wParam==SIZE_MINIMIZED)
2794 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2798 GetClientRect(hwnd, &rect);
2799 FRAME_PIXWIDTH(frame) = rect.right;
2800 FRAME_PIXHEIGHT(frame) = rect.bottom;
2802 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2803 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2804 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2806 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2807 change_frame_size (frame, rows, columns, 1);
2809 /* If we are inside frame creation, we have to apply geometric
2811 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2813 /* Yes, we have to size again */
2814 mswindows_size_frame_internal ( frame,
2815 FRAME_MSWINDOWS_TARGET_RECT
2817 /* Reset so we do not get here again. The SetWindowPos call in
2818 * mswindows_size_frame_internal can cause recursion here. */
2819 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2821 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2822 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2827 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2829 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2830 /* APA: Now that the magic XM_MAPFRAME event has
2831 * been sent we can mark the frame as visible (just
2832 * like 21.1 did). */
2833 FRAME_VISIBLE_P (frame) = 1;
2836 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2843 case WM_DISPLAYCHANGE:
2846 DWORD message_tick = GetMessageTime ();
2848 fobj = mswindows_find_frame (hwnd);
2849 frame = XFRAME (fobj);
2850 d = XDEVICE (FRAME_DEVICE (frame));
2852 /* Do this only once per message. XEmacs can receive this message
2853 through as many frames as it currently has open. Message time
2854 will be the same for all these messages. Despite extreme
2855 efficiency, the code below has about one in 4 billion
2856 probability that the HDC is not recreated, provided that
2857 XEmacs is running sufficiently longer than 52 days. */
2858 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2860 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2861 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2862 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2867 /* Misc magic events which only require that the frame be identified */
2870 mswindows_enqueue_magic_event (hwnd, message_);
2873 case WM_WINDOWPOSCHANGING:
2875 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2876 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2877 GetWindowPlacement(hwnd, &wpl);
2879 /* Only interested if size is changing and we're not being iconified */
2880 if (wpl.showCmd != SW_SHOWMINIMIZED
2881 && wpl.showCmd != SW_SHOWMAXIMIZED
2882 && !(wp->flags & SWP_NOSIZE))
2884 RECT ncsize = { 0, 0, 0, 0 };
2885 int pixwidth, pixheight;
2886 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2887 GetMenu(hwnd) != NULL,
2888 GetWindowLong (hwnd, GWL_EXSTYLE));
2890 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2891 wp->cx - (ncsize.right - ncsize.left),
2892 wp->cy - (ncsize.bottom - ncsize.top),
2893 &pixwidth, &pixheight);
2895 /* Convert client sizes to window sizes */
2896 pixwidth += (ncsize.right - ncsize.left);
2897 pixheight += (ncsize.bottom - ncsize.top);
2899 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2901 /* Adjust so that the bottom or right doesn't move if it's
2902 * the top or left that's being changed */
2904 GetWindowRect (hwnd, &rect);
2906 if (rect.left != wp->x)
2907 wp->x += wp->cx - pixwidth;
2908 if (rect.top != wp->y)
2909 wp->y += wp->cy - pixheight;
2915 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2916 window position if the user tries to track window too small */
2920 case WM_ENTERSIZEMOVE:
2921 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2922 msframe->sizing = 1;
2925 case WM_EXITSIZEMOVE:
2926 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2927 msframe->sizing = 0;
2928 /* Queue noop event */
2929 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2932 #ifdef HAVE_SCROLLBARS
2936 /* Direction of scroll is determined by scrollbar instance. */
2937 int code = (int) LOWORD(wParam);
2938 int pos = (short int) HIWORD(wParam);
2939 HWND hwndScrollBar = (HWND) lParam;
2940 struct gcpro gcpro1, gcpro2;
2942 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2943 GCPRO2 (emacs_event, fobj);
2944 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2946 /* Error during event pumping - cancel scroll */
2947 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2955 int keys = LOWORD (wParam); /* Modifier key flags */
2956 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2958 /* enqueue button4/5 events if mswindows_handle_mousewheel_event
2959 doesn't handle the event, such as when the scrollbars are not
2961 if (!mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2963 MAKEPOINTS (lParam)))
2964 mswindows_enqueue_mouse_button_event (hwnd, message_,
2965 MAKEPOINTS (lParam),
2968 /* We are not in a modal loop so no pumping is necessary. */
2973 #ifdef HAVE_MENUBARS
2975 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2977 XFRAME (mswindows_find_frame (hwnd)))))
2978 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2981 case WM_INITMENUPOPUP:
2982 if (!HIWORD(lParam))
2984 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2986 XFRAME (mswindows_find_frame (hwnd)))))
2987 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2991 #endif /* HAVE_MENUBARS */
2995 WORD id = LOWORD (wParam);
2996 WORD nid = HIWORD (wParam);
2997 HWND cid = (HWND)lParam;
2998 frame = XFRAME (mswindows_find_frame (hwnd));
3000 #ifdef HAVE_TOOLBARS
3001 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
3004 /* widgets in a buffer only eval a callback for suitable events.*/
3009 case CBN_EDITCHANGE:
3011 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
3014 /* menubars always must come last since the hashtables do not
3016 #ifdef HAVE_MENUBARS
3017 if (!NILP (mswindows_handle_wm_command (frame, id)))
3021 return DefWindowProc (hwnd, message_, wParam, lParam);
3022 /* Bite me - a spurious command. This used to not be able to
3023 happen but with the introduction of widgets its now
3028 case WM_CTLCOLORBTN:
3029 case WM_CTLCOLORLISTBOX:
3030 case WM_CTLCOLOREDIT:
3031 case WM_CTLCOLORSTATIC:
3032 case WM_CTLCOLORSCROLLBAR:
3034 /* if we get an opportunity to paint a widget then do so if
3035 there is an appropriate face */
3036 HWND crtlwnd = (HWND)lParam;
3037 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
3040 Lisp_Object image_instance;
3041 VOID_TO_LISP (image_instance, ii);
3042 if (IMAGE_INSTANCEP (image_instance)
3044 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
3046 /* set colors for the buttons */
3047 HDC hdc = (HDC)wParam;
3048 if (last_widget_brushed != ii)
3051 DeleteObject (widget_brush);
3052 widget_brush = CreateSolidBrush
3053 (COLOR_INSTANCE_MSWINDOWS_COLOR
3056 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3057 XIMAGE_INSTANCE_FRAME (image_instance)))));
3059 last_widget_brushed = ii;
3062 COLOR_INSTANCE_MSWINDOWS_COLOR
3065 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3066 XIMAGE_INSTANCE_FRAME (image_instance)))));
3067 SetBkMode (hdc, OPAQUE);
3070 COLOR_INSTANCE_MSWINDOWS_COLOR
3073 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3074 XIMAGE_INSTANCE_FRAME (image_instance)))));
3075 return (LRESULT)widget_brush;
3081 #ifdef HAVE_DRAGNDROP
3082 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
3084 UINT filecount, i, len;
3089 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
3090 struct gcpro gcpro1, gcpro2, gcpro3;
3092 emacs_event = Fmake_event (Qnil, Qnil);
3093 event = XEVENT(emacs_event);
3095 GCPRO3 (emacs_event, l_dndlist, l_item);
3097 if (!DragQueryPoint ((HDROP) wParam, &point))
3098 point.x = point.y = -1; /* outside client area */
3100 event->event_type = misc_user_event;
3101 event->channel = mswindows_find_frame(hwnd);
3102 event->timestamp = GetMessageTime();
3103 event->event.misc.button = 1; /* #### Should try harder */
3104 event->event.misc.modifiers = mswindows_modifier_state (NULL,
3106 event->event.misc.x = point.x;
3107 event->event.misc.y = point.y;
3108 event->event.misc.function = Qdragdrop_drop_dispatch;
3110 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
3111 for (i=0; i<filecount; i++)
3113 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
3114 /* The URLs that we make here aren't correct according to section
3115 * 3.10 of rfc1738 because they're missing the //<host>/ part and
3116 * because they may contain reserved characters. But that's OK -
3117 * they just need to be good enough to keep dragdrop.el happy. */
3118 fname = (char *)xmalloc (len+1);
3119 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
3121 /* May be a shell link aka "shortcut" - replace fname if so */
3122 #if !(defined(CYGWIN) || defined(MINGW))
3123 /* cygwin doesn't define this COM stuff */
3124 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
3128 if (CoCreateInstance (&CLSID_ShellLink, NULL,
3129 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
3133 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
3136 OLECHAR wsz[PATH_MAX];
3137 WIN32_FIND_DATA wfd;
3138 LPSTR resolved = (char *) xmalloc (PATH_MAX+1);
3140 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX);
3142 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
3143 (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX,
3148 len = strlen (fname);
3151 ppf->lpVtbl->Release (ppf);
3154 psl->lpVtbl->Release (psl);
3160 filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5);
3161 strcpy (filename, "file:");
3162 cygwin_win32_to_posix_path_list (fname, filename+5);
3164 filename = (char *)xmalloc (len+6);
3165 strcat (strcpy (filename, "file:"), fname);
3166 dostounix_filename (filename+5);
3169 l_item = make_string (filename, strlen (filename));
3170 l_dndlist = Fcons (l_item, l_dndlist);
3173 DragFinish ((HDROP) wParam);
3175 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3176 mswindows_enqueue_dispatch_event (emacs_event);
3184 return DefWindowProc (hwnd, message_, wParam, lParam);
3190 /************************************************************************/
3191 /* keyboard, mouse & other helpers for the windows procedure */
3192 /************************************************************************/
3194 mswindows_set_chord_timer (HWND hwnd)
3198 /* We get one third half system double click threshold */
3199 if (mswindows_mouse_button_tolerance <= 0)
3200 interval = GetDoubleClickTime () / 3;
3202 interval = mswindows_mouse_button_tolerance;
3204 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3208 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3211 if (mswindows_mouse_button_max_skew_x <= 0)
3212 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3214 dx = mswindows_mouse_button_max_skew_x;
3216 if (mswindows_mouse_button_max_skew_y <= 0)
3217 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3219 dy = mswindows_mouse_button_max_skew_y;
3221 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3225 mswindows_current_layout_has_AltGr (void)
3227 /* This simple caching mechanism saves 10% of CPU
3228 time when a key typed at autorepeat rate of 30 cps! */
3229 static HKL last_hkl = 0;
3230 static int last_hkl_has_AltGr;
3231 HKL current_hkl = (HKL) -1;
3233 if (xGetKeyboardLayout) /* not in NT 3.5 */
3234 current_hkl = xGetKeyboardLayout (0);
3235 if (current_hkl != last_hkl)
3238 last_hkl_has_AltGr = 0;
3239 /* In this loop, we query whether a character requires
3240 AltGr to be down to generate it. If at least such one
3241 found, this means that the layout does regard AltGr */
3242 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3243 if (HIBYTE (VkKeyScan (c)) == 6)
3244 last_hkl_has_AltGr = 1;
3245 last_hkl = current_hkl;
3247 return last_hkl_has_AltGr;
3251 /* Returns the state of the modifier keys in the format expected by the
3252 * Lisp_Event key_data, button_data and motion_data modifiers member */
3254 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3257 int keys_is_real = 0;
3260 if (fwKeys == (DWORD) -1)
3261 fwKeys = mswindows_last_mouse_button_state;
3265 mswindows_last_mouse_button_state = fwKeys;
3271 GetKeyboardState (keymap);
3272 has_AltGr = mswindows_current_layout_has_AltGr ();
3275 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3277 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3279 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3280 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3284 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3285 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3288 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3289 ? XEMACS_MOD_SHIFT : 0;
3290 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3291 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3292 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3298 * Translate a mswindows virtual key to a keysym.
3299 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3300 * or whose ASCII codes (like space) xemacs doesn't like.
3302 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3305 if (extendedp) /* Keys not present on a 82 key keyboard */
3307 switch (mswindows_key)
3309 case VK_CANCEL: return KEYSYM ("pause");
3310 case VK_RETURN: return KEYSYM ("kp-enter");
3311 case VK_PRIOR: return KEYSYM ("prior");
3312 case VK_NEXT: return KEYSYM ("next");
3313 case VK_END: return KEYSYM ("end");
3314 case VK_HOME: return KEYSYM ("home");
3315 case VK_LEFT: return KEYSYM ("left");
3316 case VK_UP: return KEYSYM ("up");
3317 case VK_RIGHT: return KEYSYM ("right");
3318 case VK_DOWN: return KEYSYM ("down");
3319 case VK_INSERT: return KEYSYM ("insert");
3320 case VK_DELETE: return QKdelete;
3321 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3322 case VK_LWIN return KEYSYM ("");
3323 case VK_RWIN return KEYSYM ("");
3325 case VK_APPS: return KEYSYM ("menu");
3330 switch (mswindows_key)
3332 case VK_BACK: return QKbackspace;
3333 case VK_TAB: return QKtab;
3334 case '\n': return QKlinefeed;
3335 case VK_CLEAR: return KEYSYM ("clear");
3336 case VK_RETURN: return QKreturn;
3337 case VK_PAUSE: return KEYSYM ("pause");
3338 case VK_ESCAPE: return QKescape;
3339 case VK_SPACE: return QKspace;
3340 case VK_PRIOR: return KEYSYM ("kp-prior");
3341 case VK_NEXT: return KEYSYM ("kp-next");
3342 case VK_END: return KEYSYM ("kp-end");
3343 case VK_HOME: return KEYSYM ("kp-home");
3344 case VK_LEFT: return KEYSYM ("kp-left");
3345 case VK_UP: return KEYSYM ("kp-up");
3346 case VK_RIGHT: return KEYSYM ("kp-right");
3347 case VK_DOWN: return KEYSYM ("kp-down");
3348 case VK_SELECT: return KEYSYM ("select");
3349 case VK_PRINT: return KEYSYM ("print");
3350 case VK_EXECUTE: return KEYSYM ("execute");
3351 case VK_SNAPSHOT: return KEYSYM ("print");
3352 case VK_INSERT: return KEYSYM ("kp-insert");
3353 case VK_DELETE: return KEYSYM ("kp-delete");
3354 case VK_HELP: return KEYSYM ("help");
3355 case VK_NUMPAD0: return KEYSYM ("kp-0");
3356 case VK_NUMPAD1: return KEYSYM ("kp-1");
3357 case VK_NUMPAD2: return KEYSYM ("kp-2");
3358 case VK_NUMPAD3: return KEYSYM ("kp-3");
3359 case VK_NUMPAD4: return KEYSYM ("kp-4");
3360 case VK_NUMPAD5: return KEYSYM ("kp-5");
3361 case VK_NUMPAD6: return KEYSYM ("kp-6");
3362 case VK_NUMPAD7: return KEYSYM ("kp-7");
3363 case VK_NUMPAD8: return KEYSYM ("kp-8");
3364 case VK_NUMPAD9: return KEYSYM ("kp-9");
3365 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3366 case VK_ADD: return KEYSYM ("kp-add");
3367 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3368 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3369 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3370 case VK_DIVIDE: return KEYSYM ("kp-divide");
3371 case VK_F1: return KEYSYM ("f1");
3372 case VK_F2: return KEYSYM ("f2");
3373 case VK_F3: return KEYSYM ("f3");
3374 case VK_F4: return KEYSYM ("f4");
3375 case VK_F5: return KEYSYM ("f5");
3376 case VK_F6: return KEYSYM ("f6");
3377 case VK_F7: return KEYSYM ("f7");
3378 case VK_F8: return KEYSYM ("f8");
3379 case VK_F9: return KEYSYM ("f9");
3380 case VK_F10: return KEYSYM ("f10");
3381 case VK_F11: return KEYSYM ("f11");
3382 case VK_F12: return KEYSYM ("f12");
3383 case VK_F13: return KEYSYM ("f13");
3384 case VK_F14: return KEYSYM ("f14");
3385 case VK_F15: return KEYSYM ("f15");
3386 case VK_F16: return KEYSYM ("f16");
3387 case VK_F17: return KEYSYM ("f17");
3388 case VK_F18: return KEYSYM ("f18");
3389 case VK_F19: return KEYSYM ("f19");
3390 case VK_F20: return KEYSYM ("f20");
3391 case VK_F21: return KEYSYM ("f21");
3392 case VK_F22: return KEYSYM ("f22");
3393 case VK_F23: return KEYSYM ("f23");
3394 case VK_F24: return KEYSYM ("f24");
3401 * Find the console that matches the supplied mswindows window handle
3404 mswindows_find_console (HWND hwnd)
3406 /* We only support one console */
3407 return XCAR (Vconsole_list);
3411 * Find the frame that matches the supplied mswindows window handle
3414 mswindows_find_frame (HWND hwnd)
3416 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3420 /* We are in progress of frame creation. Return the frame
3421 being created, as it still not remembered in the window
3423 assert (!NILP (Vmswindows_frame_being_created));
3424 return Vmswindows_frame_being_created;
3426 VOID_TO_LISP (f, l);
3431 /************************************************************************/
3433 /************************************************************************/
3436 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3439 EMACS_TIME current_time;
3440 EMACS_GET_TIME (current_time);
3441 EMACS_SUB_TIME (thyme, thyme, current_time);
3442 milliseconds = EMACS_SECS (thyme) * 1000 +
3443 (EMACS_USECS (thyme) + 500) / 1000;
3444 if (milliseconds < 1)
3446 ++mswindows_pending_timers_count;
3447 return SetTimer (NULL, 0, milliseconds,
3448 (TIMERPROC) mswindows_wm_timer_callback);
3452 emacs_mswindows_remove_timeout (int id)
3454 Lisp_Event match_against;
3455 Lisp_Object emacs_event;
3457 if (KillTimer (NULL, id))
3458 --mswindows_pending_timers_count;
3460 /* If there is a dispatch event generated by this
3461 timeout in the queue, we have to remove it too. */
3462 match_against.event_type = timeout_event;
3463 match_against.event.timeout.interval_id = id;
3464 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3465 if (!NILP (emacs_event))
3466 Fdeallocate_event(emacs_event);
3469 /* If `user_p' is false, then return whether there are any win32, timeout,
3470 * or subprocess events pending (that is, whether
3471 * emacs_mswindows_next_event() would return immediately without blocking).
3473 * if `user_p' is true, then return whether there are any *user generated*
3474 * events available (that is, whether there are keyboard or mouse-click
3475 * events ready to be read). This also implies that
3476 * emacs_mswindows_next_event() would not block.
3479 emacs_mswindows_event_pending_p (int user_p)
3481 mswindows_need_event (0);
3482 return (!NILP (mswindows_u_dispatch_event_queue)
3483 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3487 * Return the next event
3490 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3492 Lisp_Object event, event2;
3494 mswindows_need_event (1);
3496 event = mswindows_dequeue_dispatch_event ();
3497 XSETEVENT (event2, emacs_event);
3498 Fcopy_event (event, event2);
3499 Fdeallocate_event (event);
3503 * Handle a magic event off the dispatch queue.
3506 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3508 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3515 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3516 mswindows_handle_paint (f);
3517 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3524 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3525 struct frame *f = XFRAME (frame);
3526 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3528 struct gcpro gcpro1;
3530 /* On focus change, clear all memory of sticky modifiers
3531 to avoid non-intuitive behavior. */
3532 clear_sticky_modifiers ();
3534 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3536 emacs_handle_focus_change_preliminary (conser);
3537 /* Under X the stuff up to here is done in the X event handler.
3539 emacs_handle_focus_change_final (conser);
3548 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3549 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3551 Qmap_frame_hook : Qunmap_frame_hook,
3556 /* #### What about Enter & Leave */
3558 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3559 Qmouse_leave_frame_hook, 1, frame);
3567 #ifndef HAVE_MSG_SELECT
3569 get_process_input_waitable (Lisp_Process *process)
3571 Lisp_Object instr, outstr, p;
3572 XSETPROCESS (p, process);
3573 get_process_streams (process, &instr, &outstr);
3574 assert (!NILP (instr));
3575 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3576 return (network_connection_p (p)
3577 ? get_winsock_stream_waitable (XLSTREAM (instr))
3578 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3580 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3585 emacs_mswindows_select_process (Lisp_Process *process)
3587 HANDLE hev = get_process_input_waitable (process);
3589 if (!add_waitable_handle (hev))
3590 error ("Too many active processes");
3592 #ifdef HAVE_WIN32_PROCESSES
3595 XSETPROCESS (p, process);
3596 if (!network_connection_p (p))
3598 HANDLE hprocess = get_nt_process_handle (process);
3599 if (!add_waitable_handle (hprocess))
3601 remove_waitable_handle (hev);
3602 error ("Too many active processes");
3610 emacs_mswindows_unselect_process (Lisp_Process *process)
3612 /* Process handle is removed in the event loop as soon
3613 as it is signaled, so don't bother here about it */
3614 HANDLE hev = get_process_input_waitable (process);
3615 remove_waitable_handle (hev);
3617 #endif /* HAVE_MSG_SELECT */
3620 emacs_mswindows_select_console (struct console *con)
3622 #ifdef HAVE_MSG_SELECT
3623 if (CONSOLE_MSWINDOWS_P (con))
3624 return; /* mswindows consoles are automatically selected */
3626 event_stream_unixoid_select_console (con);
3631 emacs_mswindows_unselect_console (struct console *con)
3633 #ifdef HAVE_MSG_SELECT
3634 if (CONSOLE_MSWINDOWS_P (con))
3635 return; /* mswindows consoles are automatically selected */
3637 event_stream_unixoid_unselect_console (con);
3642 emacs_mswindows_quit_p (void)
3644 /* Quit cannot happen in modal loop: all program
3645 input is dedicated to Windows. */
3646 if (mswindows_in_modal_loop)
3649 mswindows_quit_chars_count = 0;
3650 /* Drain windows queue. This sets up number of quit characters in
3652 mswindows_drain_windows_queue ();
3654 if (mswindows_quit_chars_count > 0)
3656 /* Yes there's a hidden one... Throw it away */
3657 Lisp_Event match_against;
3658 Lisp_Object emacs_event;
3661 match_against.event_type = key_press_event;
3662 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3664 while (mswindows_quit_chars_count > 0)
3666 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3667 assert (!NILP (emacs_event));
3669 if (XEVENT (emacs_event)->event.key.modifiers &
3670 FAKE_MOD_QUIT_CRITICAL)
3673 Fdeallocate_event (emacs_event);
3674 mswindows_quit_chars_count--;
3677 Vquit_flag = critical_p ? Qcritical : Qt;
3682 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3683 Lisp_Object* instream,
3684 Lisp_Object* outstream,
3687 /* Handles for streams */
3689 /* fds. These just stored along with the streams, and are closed in
3690 delete stream pair method, because we need to handle fake unices
3694 /* Decode inhandle and outhandle. Their meaning depends on
3695 the process implementation being used. */
3696 #if defined (HAVE_WIN32_PROCESSES)
3697 /* We're passed in Windows handles. That's what we like most... */
3698 hin = (HANDLE) inhandle;
3699 hout = (HANDLE) outhandle;
3701 #elif defined (HAVE_UNIX_PROCESSES)
3702 /* We are passed UNIX fds. This must be Cygwin.
3704 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3705 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3709 #error "So, WHICH kind of processes do you want?"
3712 *instream = (hin == INVALID_HANDLE_VALUE
3714 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3715 : flags & STREAM_NETWORK_CONNECTION
3716 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3718 : make_ntpipe_input_stream (hin, fdi));
3720 #ifdef HAVE_WIN32_PROCESSES
3721 *outstream = (hout == INVALID_HANDLE_VALUE
3723 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3724 : flags & STREAM_NETWORK_CONNECTION
3725 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3727 : make_ntpipe_output_stream (hout, fdo));
3728 #elif defined (HAVE_UNIX_PROCESSES)
3729 *outstream = (fdo >= 0
3730 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3733 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3734 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3735 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3737 Bufbyte eof_char = get_eof_char (fdo);
3738 int pty_max_bytes = get_pty_max_bytes (fdo);
3739 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3744 return (NILP (*instream)
3746 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3747 : flags & STREAM_NETWORK_CONNECTION
3748 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3750 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3754 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3755 Lisp_Object outstream)
3757 /* Oh nothing special here for Win32 at all */
3758 #if defined (HAVE_UNIX_PROCESSES)
3759 int in = (NILP(instream)
3761 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3762 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3763 ? get_winsock_stream_param (XLSTREAM (instream))
3765 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3766 int out = (NILP(outstream) ? -1
3767 : filedesc_stream_fd (XLSTREAM (outstream)));
3771 if (out != in && out >= 0)
3775 return (NILP (instream)
3777 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3778 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3779 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3781 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3785 emacs_mswindows_current_event_timestamp (struct console *c)
3787 return GetTickCount ();
3790 #ifndef HAVE_X_WINDOWS
3791 /* This is called from GC when a process object is about to be freed.
3792 If we've still got pointers to it in this file, we're gonna lose hard.
3795 debug_process_finalization (Lisp_Process *p)
3798 Lisp_Object instr, outstr;
3800 get_process_streams (p, &instr, &outstr);
3801 /* if it still has fds, then it hasn't been killed yet. */
3802 assert (NILP(instr));
3803 assert (NILP(outstr));
3805 /* #### More checks here */
3812 struct mswin_message_debug
3818 #define FROB(val) { val, #val, },
3820 struct mswin_message_debug debug_mswin_messages[] =
3836 FROB (WM_GETTEXTLENGTH)
3839 FROB (WM_QUERYENDSESSION)
3842 FROB (WM_ERASEBKGND)
3843 FROB (WM_SYSCOLORCHANGE)
3844 FROB (WM_ENDSESSION)
3845 FROB (WM_SHOWWINDOW)
3846 FROB (WM_WININICHANGE)
3847 #if(WINVER >= 0x0400)
3848 FROB (WM_SETTINGCHANGE)
3849 #endif /* WINVER >= 0x0400 */
3851 FROB (WM_DEVMODECHANGE)
3852 FROB (WM_ACTIVATEAPP)
3853 FROB (WM_FONTCHANGE)
3854 FROB (WM_TIMECHANGE)
3855 FROB (WM_CANCELMODE)
3857 FROB (WM_MOUSEACTIVATE)
3858 FROB (WM_CHILDACTIVATE)
3861 FROB (WM_GETMINMAXINFO)
3864 FROB (WM_ICONERASEBKGND)
3865 FROB (WM_NEXTDLGCTL)
3866 FROB (WM_SPOOLERSTATUS)
3868 FROB (WM_MEASUREITEM)
3869 FROB (WM_DELETEITEM)
3870 FROB (WM_VKEYTOITEM)
3871 FROB (WM_CHARTOITEM)
3876 FROB (WM_QUERYDRAGICON)
3877 FROB (WM_COMPAREITEM)
3878 #if(WINVER >= 0x0500) && defined(WM_GETOBJECT)
3880 #endif /* WINVER >= 0x0500 */
3881 FROB (WM_COMPACTING)
3882 FROB (WM_COMMNOTIFY)
3883 FROB (WM_WINDOWPOSCHANGING)
3884 FROB (WM_WINDOWPOSCHANGED)
3889 FROB (WM_CANCELJOURNAL)
3891 #if(WINVER >= 0x0400)
3893 FROB (WM_INPUTLANGCHANGEREQUEST)
3894 FROB (WM_INPUTLANGCHANGE)
3897 FROB (WM_USERCHANGED)
3898 FROB (WM_NOTIFYFORMAT)
3900 FROB (WM_CONTEXTMENU)
3901 FROB (WM_STYLECHANGING)
3902 FROB (WM_STYLECHANGED)
3903 FROB (WM_DISPLAYCHANGE)
3906 #endif /* WINVER >= 0x0400 */
3910 FROB (WM_NCCALCSIZE)
3913 FROB (WM_NCACTIVATE)
3914 FROB (WM_GETDLGCODE)
3915 #ifdef WM_SYNCPAINT /* not in VC 5 */
3917 #endif /* WM_SYNCPAINT */
3918 FROB (WM_NCMOUSEMOVE)
3919 FROB (WM_NCLBUTTONDOWN)
3920 FROB (WM_NCLBUTTONUP)
3921 FROB (WM_NCLBUTTONDBLCLK)
3922 FROB (WM_NCRBUTTONDOWN)
3923 FROB (WM_NCRBUTTONUP)
3924 FROB (WM_NCRBUTTONDBLCLK)
3925 FROB (WM_NCMBUTTONDOWN)
3926 FROB (WM_NCMBUTTONUP)
3927 FROB (WM_NCMBUTTONDBLCLK)
3929 /* FROB (WM_KEYFIRST) */
3934 FROB (WM_SYSKEYDOWN)
3937 FROB (WM_SYSDEADCHAR)
3940 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION)
3941 FROB (WM_IME_STARTCOMPOSITION)
3942 FROB (WM_IME_ENDCOMPOSITION)
3943 FROB (WM_IME_COMPOSITION)
3944 FROB (WM_IME_KEYLAST)
3945 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */
3947 FROB (WM_INITDIALOG)
3949 FROB (WM_SYSCOMMAND)
3954 FROB (WM_INITMENUPOPUP)
3955 FROB (WM_MENUSELECT)
3958 #if(WINVER >= 0x0500)
3959 FROB (WM_MENURBUTTONUP)
3963 #ifdef WM_MENUGETOBJECT
3964 FROB (WM_MENUGETOBJECT)
3966 #ifdef WM_UNINITMENUPOPUP
3967 FROB (WM_UNINITMENUPOPUP)
3969 #ifdef WM_MENUCOMMAND
3970 FROB (WM_MENUCOMMAND)
3972 #endif /* WINVER >= 0x0500 */
3975 FROB (WM_CTLCOLORMSGBOX)
3976 FROB (WM_CTLCOLOREDIT)
3977 FROB (WM_CTLCOLORLISTBOX)
3978 FROB (WM_CTLCOLORBTN)
3979 FROB (WM_CTLCOLORDLG)
3980 FROB (WM_CTLCOLORSCROLLBAR)
3981 FROB (WM_CTLCOLORSTATIC)
3984 /* FROB (WM_MOUSEFIRST) */
3986 FROB (WM_LBUTTONDOWN)
3988 FROB (WM_LBUTTONDBLCLK)
3989 FROB (WM_RBUTTONDOWN)
3991 FROB (WM_RBUTTONDBLCLK)
3992 FROB (WM_MBUTTONDOWN)
3994 FROB (WM_MBUTTONDBLCLK)
3996 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
3997 FROB (WM_MOUSEWHEEL)
4001 #endif /* if (_WIN32_WINNT < 0x0400) */
4003 FROB (WM_PARENTNOTIFY)
4004 FROB (WM_ENTERMENULOOP)
4005 FROB (WM_EXITMENULOOP)
4007 #if(WINVER >= 0x0400)
4011 FROB (WM_CAPTURECHANGED)
4013 FROB (WM_POWERBROADCAST)
4015 FROB (WM_DEVICECHANGE)
4017 #endif /* WINVER >= 0x0400 */
4020 FROB (WM_MDIDESTROY)
4021 FROB (WM_MDIACTIVATE)
4022 FROB (WM_MDIRESTORE)
4024 FROB (WM_MDIMAXIMIZE)
4026 FROB (WM_MDICASCADE)
4027 FROB (WM_MDIICONARRANGE)
4028 FROB (WM_MDIGETACTIVE)
4031 FROB (WM_MDISETMENU)
4032 FROB (WM_ENTERSIZEMOVE)
4033 FROB (WM_EXITSIZEMOVE)
4035 FROB (WM_MDIREFRESHMENU)
4037 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */
4039 #if(WINVER >= 0x0400) && !defined(CYGWIN)
4040 FROB (WM_IME_SETCONTEXT)
4041 FROB (WM_IME_NOTIFY)
4042 FROB (WM_IME_CONTROL)
4043 FROB (WM_IME_COMPOSITIONFULL)
4044 FROB (WM_IME_SELECT)
4046 #endif /* WINVER >= 0x0400 */
4047 #if(WINVER >= 0x0500) && defined(WM_IME_REQUEST)
4048 FROB (WM_IME_REQUEST)
4049 #endif /* WINVER >= 0x0500 */
4050 #if(WINVER >= 0x0400) && !defined(CYGWIN)
4051 FROB (WM_IME_KEYDOWN)
4053 #endif /* WINVER >= 0x0400 */
4055 #endif /* WM_IME_SETCONTEXT */
4057 #if(_WIN32_WINNT >= 0x0400)
4058 FROB (WM_MOUSEHOVER)
4059 FROB (WM_MOUSELEAVE)
4060 #endif /* _WIN32_WINNT >= 0x0400 */
4067 FROB (WM_RENDERFORMAT)
4068 FROB (WM_RENDERALLFORMATS)
4069 FROB (WM_DESTROYCLIPBOARD)
4070 FROB (WM_DRAWCLIPBOARD)
4071 FROB (WM_PAINTCLIPBOARD)
4072 FROB (WM_VSCROLLCLIPBOARD)
4073 FROB (WM_SIZECLIPBOARD)
4074 FROB (WM_ASKCBFORMATNAME)
4075 FROB (WM_CHANGECBCHAIN)
4076 FROB (WM_HSCROLLCLIPBOARD)
4077 FROB (WM_QUERYNEWPALETTE)
4078 FROB (WM_PALETTEISCHANGING)
4079 FROB (WM_PALETTECHANGED)
4082 #if(WINVER >= 0x0400)
4084 FROB (WM_PRINTCLIENT)
4086 FROB (WM_HANDHELDFIRST)
4087 FROB (WM_HANDHELDLAST)
4091 #endif /* WINVER >= 0x0400 */
4093 FROB (WM_PENWINFIRST)
4094 FROB (WM_PENWINLAST)
4100 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
4103 Lisp_Object frame = mswindows_find_frame (hwnd);
4106 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */
4108 for (i = 0; i < countof (debug_mswin_messages); i++)
4110 if (debug_mswin_messages[i].mess == message_)
4112 str = debug_mswin_messages[i].string;
4118 stderr_out ("%s", str);
4120 stderr_out ("%x", message_);
4122 if (debug_mswindows_events > 1)
4124 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
4125 wParam, (int) lParam, (unsigned int) hwnd);
4126 debug_print (frame);
4127 if (message_ == WM_WINDOWPOSCHANGED ||
4128 message_ == WM_WINDOWPOSCHANGING)
4130 WINDOWPOS *wp = (WINDOWPOS *) lParam;
4131 stderr_out(" WINDOWPOS: x=%d, y=%d, h=%d, w=%d\n",
4132 wp->x, wp->y, wp->cx, wp->cy);
4134 else if (message_ == WM_MOVE)
4136 int x = (int)(short) LOWORD(lParam); /* horizontal position */
4137 int y = (int)(short) HIWORD(lParam); /* vertical position */
4138 stderr_out(" MOVE: x=%d, y=%d\n", x, y);
4140 else if (message_ == WM_SIZE)
4142 int w = (int)(short) LOWORD(lParam); /* width */
4143 int h = (int)(short) HIWORD(lParam); /* height */
4144 stderr_out(" SIZE: w=%d, h=%d\n", w, h);
4151 #endif /* DEBUG_XEMACS */
4153 /************************************************************************/
4154 /* initialization */
4155 /************************************************************************/
4158 reinit_vars_of_event_mswindows (void)
4160 mswindows_in_modal_loop = 0;
4161 mswindows_pending_timers_count = 0;
4163 mswindows_event_stream = xnew (struct event_stream);
4165 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
4166 mswindows_event_stream->force_event_pending = 0;
4167 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
4168 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
4169 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
4170 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
4171 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
4172 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
4173 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
4174 #ifdef HAVE_MSG_SELECT
4175 mswindows_event_stream->select_process_cb =
4176 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
4177 mswindows_event_stream->unselect_process_cb =
4178 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
4179 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
4180 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
4182 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
4183 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
4184 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
4185 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
4187 mswindows_event_stream->current_event_timestamp_cb =
4188 emacs_mswindows_current_event_timestamp;
4192 vars_of_event_mswindows (void)
4194 reinit_vars_of_event_mswindows ();
4196 mswindows_u_dispatch_event_queue = Qnil;
4197 staticpro (&mswindows_u_dispatch_event_queue);
4198 mswindows_u_dispatch_event_queue_tail = Qnil;
4199 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
4201 mswindows_s_dispatch_event_queue = Qnil;
4202 staticpro (&mswindows_s_dispatch_event_queue);
4203 mswindows_s_dispatch_event_queue_tail = Qnil;
4204 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
4206 mswindows_error_caught_in_modal_loop = Qnil;
4207 staticpro (&mswindows_error_caught_in_modal_loop);
4211 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
4212 If non-zero, display debug information about Windows messages that XEmacs sees.
4213 Information is displayed in a console window. Currently defined values are:
4215 1 == non-verbose output (just the message name)
4216 2 == verbose output (all parameters)
4217 3 == even more verbose output (extra debugging info)
4219 debug_mswindows_events = 0;
4222 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
4223 &mswindows_alt_by_itself_activates_menu /*
4224 *Controls whether pressing and releasing the Alt key activates the menubar.
4225 This applies only if no intervening key was pressed. See also
4226 `menu-accelerator-enabled', which is probably the behavior you actually want.
4230 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
4231 &mswindows_dynamic_frame_resize /*
4232 *Controls redrawing frame contents during mouse-drag or keyboard resize
4233 operation. When non-nil, the frame is redrawn while being resized. When
4234 nil, frame is not redrawn, and exposed areas are filled with default
4235 MDI application background color. Note that this option only has effect
4236 if "Show window contents while dragging" is on in system Display/Plus!
4238 Default is t on fast machines, nil on slow.
4241 DEFVAR_INT ("mswindows-mouse-button-tolerance",
4242 &mswindows_mouse_button_tolerance /*
4243 *Analogue of double click interval for faking middle mouse events.
4244 The value is the minimum time in milliseconds that must elapse between
4245 left/right button down events before they are considered distinct events.
4246 If both mouse buttons are depressed within this interval, a middle mouse
4247 button down event is generated instead.
4248 If negative or zero, currently set system default is used instead.
4251 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
4252 Number of physical mouse buttons.
4255 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
4256 &mswindows_mouse_button_max_skew_x /*
4257 *Maximum horizontal distance in pixels between points in which left and
4258 right button clicks occurred for them to be translated into single
4259 middle button event. Clicks must occur in time not longer than defined
4260 by the variable `mswindows-mouse-button-tolerance'.
4261 If negative or zero, currently set system default is used instead.
4264 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
4265 &mswindows_mouse_button_max_skew_y /*
4266 *Maximum vertical distance in pixels between points in which left and
4267 right button clicks occurred for them to be translated into single
4268 middle button event. Clicks must occur in time not longer than defined
4269 by the variable `mswindows-mouse-button-tolerance'.
4270 If negative or zero, currently set system default is used instead.
4273 mswindows_mouse_button_max_skew_x = 0;
4274 mswindows_mouse_button_max_skew_y = 0;
4275 mswindows_mouse_button_tolerance = 0;
4276 mswindows_alt_by_itself_activates_menu = 1;
4280 syms_of_event_mswindows (void)
4285 lstream_type_create_mswindows_selectable (void)
4287 init_slurp_stream ();
4288 init_shove_stream ();
4289 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
4290 init_winsock_stream ();
4295 init_event_mswindows_late (void)
4297 #ifdef HAVE_MSG_SELECT
4298 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
4299 assert (windows_fd>=0);
4300 FD_SET (windows_fd, &input_wait_mask);
4301 FD_ZERO(&zero_mask);
4304 event_stream = mswindows_event_stream;
4306 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
4307 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);