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 /* We always use last message time, because mouse button
985 events may get delayed, and XEmacs double click
986 recognition will fail */
988 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
989 Lisp_Event* event = XEVENT (emacs_event);
991 mswindows_handle_sticky_modifiers (0, 0, downp, 0);
992 event->channel = mswindows_find_frame (hwnd);
993 event->timestamp = when;
994 event->event.button.button =
995 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
996 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2);
997 event->event.button.x = where.x;
998 event->event.button.y = where.y;
999 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
1003 event->event_type = button_press_event;
1005 /* we need this to make sure the main window regains the focus
1006 from control subwindows */
1007 if (GetFocus() != hwnd)
1010 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1015 event->event_type = button_release_event;
1019 mswindows_enqueue_dispatch_event (emacs_event);
1023 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1025 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1026 Lisp_Event* event = XEVENT(emacs_event);
1028 event->channel = mswindows_find_console(hwnd);
1029 event->timestamp = GetMessageTime();
1030 event->event_type = key_press_event;
1031 event->event.key.keysym = keysym;
1032 event->event.key.modifiers = mods;
1033 mswindows_enqueue_dispatch_event (emacs_event);
1037 * Remove and return the first emacs event on the dispatch queue.
1038 * Give a preference to user events over non-user ones.
1041 mswindows_dequeue_dispatch_event (void)
1046 assert (!NILP(mswindows_u_dispatch_event_queue) ||
1047 !NILP(mswindows_s_dispatch_event_queue));
1049 event = dequeue_event (
1050 NILP(mswindows_u_dispatch_event_queue) ?
1051 &mswindows_s_dispatch_event_queue :
1052 &mswindows_u_dispatch_event_queue,
1053 NILP(mswindows_u_dispatch_event_queue) ?
1054 &mswindows_s_dispatch_event_queue_tail :
1055 &mswindows_u_dispatch_event_queue_tail);
1057 sevt = XEVENT (event);
1058 if (sevt->event_type == key_press_event
1059 && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1060 sevt->event.key.modifiers &=
1061 ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
1067 * Remove and return the first emacs event on the dispatch queue that matches
1068 * the supplied event.
1069 * Timeout event matches if interval_id is equal to that of the given event.
1070 * Keypress event matches if logical AND between modifiers bitmask of the
1071 * event in the queue and that of the given event is non-zero.
1072 * For all other event types, this function aborts.
1076 mswindows_cancel_dispatch_event (Lisp_Event *match)
1079 Lisp_Object previous_event = Qnil;
1080 int user_p = mswindows_user_event_p (match);
1081 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1082 &mswindows_s_dispatch_event_queue;
1083 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1084 &mswindows_s_dispatch_event_queue_tail;
1086 assert (match->event_type == timeout_event
1087 || match->event_type == key_press_event);
1089 EVENT_CHAIN_LOOP (event, *head)
1091 Lisp_Event *e = XEVENT (event);
1092 if ((e->event_type == match->event_type) &&
1093 ((e->event_type == timeout_event) ?
1094 (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1095 /* Must be key_press_event */
1096 ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1098 if (NILP (previous_event))
1099 dequeue_event (head, tail);
1102 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1103 if (EQ (*tail, event))
1104 *tail = previous_event;
1109 previous_event = event;
1114 #ifndef HAVE_MSG_SELECT
1115 /************************************************************************/
1116 /* Waitable handles manipulation */
1117 /************************************************************************/
1119 find_waitable_handle (HANDLE h)
1122 for (i = 0; i < mswindows_waitable_count; ++i)
1123 if (mswindows_waitable_handles[i] == h)
1130 add_waitable_handle (HANDLE h)
1132 assert (find_waitable_handle (h) < 0);
1133 if (mswindows_waitable_count == MAX_WAITABLE)
1136 mswindows_waitable_handles [mswindows_waitable_count++] = h;
1141 remove_waitable_handle (HANDLE h)
1143 int ix = find_waitable_handle (h);
1147 mswindows_waitable_handles [ix] =
1148 mswindows_waitable_handles [--mswindows_waitable_count];
1150 #endif /* HAVE_MSG_SELECT */
1153 * Given a lisp process pointer remove the corresponding process handle
1154 * from mswindows_waitable_handles if it is in it. Normally the handle is
1155 * removed when the process terminates, but if the lisp process structure
1156 * is deleted before the process terminates we must delete the process
1157 * handle since it will be invalid and will cause the wait to fail
1160 mswindows_unwait_process (Lisp_Process *p)
1162 #ifndef HAVE_MSG_SELECT
1163 remove_waitable_handle (get_nt_process_handle (p));
1164 #endif /* HAVE_MSG_SELECT */
1168 /************************************************************************/
1170 /************************************************************************/
1173 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1174 Lisp_Object u_n_u_s_e_d)
1176 mswindows_error_caught_in_modal_loop = cons_sig_data;
1181 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1186 ++mswindows_in_modal_loop;
1187 tmp = condition_case_1 (Qt,
1189 mswindows_modal_loop_error_handler, Qnil);
1190 --mswindows_in_modal_loop;
1196 mswindows_unmodalize_signal_maybe (void)
1198 if (!NILP (mswindows_error_caught_in_modal_loop))
1200 /* Got an error while messages were pumped while
1201 in window procedure - have to resignal */
1202 Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1203 Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1204 mswindows_error_caught_in_modal_loop = Qnil;
1205 Fsignal (sym, data);
1210 * This is an unsafe part of event pump, guarded by
1211 * condition_case. See mswindows_pump_outstanding_events
1214 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1216 /* This function can call lisp */
1217 Lisp_Object event = Fmake_event (Qnil, Qnil);
1218 struct gcpro gcpro1;
1219 int do_redisplay = 0;
1222 while (detect_input_pending ())
1224 Fnext_event (event, Qnil);
1225 Fdispatch_event (event);
1232 Fdeallocate_event (event);
1235 /* Qt becomes return value of mswindows_pump_outstanding_events
1241 * This function pumps emacs events, while available, by using
1242 * next_message/dispatch_message loop. Errors are trapped around
1243 * the loop so the function always returns.
1245 * Windows message queue is not looked into during the call,
1246 * neither are waitable handles checked. The function pumps
1247 * thus only dispatch events already queued, as well as those
1248 * resulted in dispatching thereof. This is done by setting
1249 * module local variable mswindows_in_modal_loop to nonzero.
1251 * Return value is Qt if no errors was trapped, or Qunbound if
1252 * there was an error.
1254 * In case of error, a cons representing the error, in the
1255 * form (SIGNAL . DATA), is stored in the module local variable
1256 * mswindows_error_caught_in_modal_loop. This error is signaled
1257 * again when DispatchMessage returns. Thus, Windows internal
1258 * modal loops are protected against throws, which are proven
1259 * to corrupt internal Windows structures.
1261 * In case of success, mswindows_error_caught_in_modal_loop is
1264 * If the value of mswindows_error_caught_in_modal_loop is not
1265 * nil already upon entry, the function just returns non-nil.
1266 * This situation means that a new event has been queued while
1267 * in cancel mode. The event will be dequeued on the next regular
1268 * call of next-event; the pump is off since error is caught.
1269 * The caller must *unconditionally* cancel modal loop if the
1270 * value returned by this function is nil. Otherwise, everything
1271 * will become frozen until the modal loop exits under normal
1272 * condition (scrollbar drag is released, menu closed etc.)
1275 mswindows_pump_outstanding_events (void)
1277 /* This function can call lisp */
1279 Lisp_Object result = Qt;
1280 struct gcpro gcpro1;
1283 if (NILP(mswindows_error_caught_in_modal_loop))
1284 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1290 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1291 * QUITP, and are interesting in keyboard messages only.
1294 mswindows_drain_windows_queue (void)
1298 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1299 assert (!mswindows_in_modal_loop);
1301 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1303 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1305 /* Don't translate messages destined for a dialog box, this
1306 makes keyboard traversal work. I think?? */
1307 if (mswindows_is_dialog_msg (&msg))
1309 mswindows_unmodalize_signal_maybe ();
1313 /* We have to translate messages that are not sent to an XEmacs
1314 frame. This is so that key presses work ok in things like
1315 edit fields. However, we *musn't* translate message for XEmacs
1316 frames as this is handled in the wnd proc.
1317 We also have to avoid generating paint magic events for windows
1318 that aren't XEmacs frames */
1319 /* GetClassName will truncate a longer class name. By adding one
1320 extra character, we are forcing textual comparison to fail
1321 if the name is longer than XEMACS_CLASS */
1323 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1324 if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1326 /* Not an XEmacs frame */
1327 TranslateMessage (&msg);
1329 else if (msg.message == WM_PAINT)
1331 struct mswindows_frame* msframe;
1333 /* hdc will be NULL unless this is a subwindow - in which case we
1334 shouldn't have received a paint message for it here. */
1335 assert (msg.wParam == 0);
1337 /* Queue a magic event for handling when safe */
1339 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1340 if (!msframe->paint_pending)
1342 msframe->paint_pending = 1;
1343 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1345 /* Don't dispatch. WM_PAINT is always the last message in the
1346 queue so it's OK to just return. */
1349 DispatchMessage (&msg);
1350 mswindows_unmodalize_signal_maybe ();
1355 * This is a special flavor of the mswindows_need_event function,
1356 * used while in event pump. Actually, there is only kind of events
1357 * allowed while in event pump: a timer. An attempt to fetch any
1358 * other event leads to a deadlock, as there's no source of user input
1359 * ('cause event pump mirrors windows modal loop, which is a sole
1360 * owner of thread message queue).
1362 * To detect this, we use a counter of active timers, and allow
1363 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1364 * which will never come when there are no pending timers, which leads
1365 * to deadlock, we simply signal an error.
1367 * It might be possible to combine this with mswindows_drain_windows_queue
1368 * which fetches events when not in a modal loop. It's not clear
1369 * whether the result would be more complex than is justified.
1372 mswindows_need_event_in_modal_loop (int badly_p)
1376 /* Check if already have one */
1377 if (!NILP (mswindows_u_dispatch_event_queue)
1378 || !NILP (mswindows_s_dispatch_event_queue))
1381 /* No event is ok */
1385 /* We do not check the _u_ queue, because timers go to _s_ */
1386 while (NILP (mswindows_s_dispatch_event_queue))
1388 /* We'll deadlock if go waiting */
1389 if (mswindows_pending_timers_count == 0)
1390 error ("Deadlock due to an attempt to call next-event in a wrong context");
1392 /* Fetch and dispatch any pending timers */
1393 if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1394 DispatchMessage (&msg);
1399 * This drains the event queue and fills up two internal queues until
1400 * an event of a type specified by USER_P is retrieved.
1403 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1406 mswindows_need_event (int badly_p)
1410 while (NILP (mswindows_u_dispatch_event_queue)
1411 && NILP (mswindows_s_dispatch_event_queue))
1413 #ifdef HAVE_MSG_SELECT
1415 SELECT_TYPE temp_mask = input_wait_mask;
1416 EMACS_TIME sometime;
1417 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1420 pointer_to_this = 0;
1423 EMACS_SET_SECS_USECS (sometime, 0, 0);
1424 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1425 pointer_to_this = &select_time_to_block;
1426 if (mswindows_in_modal_loop)
1427 /* In modal loop with badly_p false, don't care about
1429 FD_CLR (windows_fd, &temp_mask);
1432 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1437 return; /* timeout */
1439 else if (active > 0)
1441 if (FD_ISSET (windows_fd, &temp_mask))
1443 if (mswindows_in_modal_loop)
1444 mswindows_need_event_in_modal_loop (badly_p);
1446 mswindows_drain_windows_queue ();
1451 /* Look for a TTY event */
1452 for (i = 0; i < MAXDESC-1; i++)
1454 /* To avoid race conditions (among other things, an infinite
1455 loop when called from Fdiscard_input()), we must return
1456 user events ahead of process events. */
1457 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1459 struct console *c = tty_find_console_from_fd (i);
1460 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1461 Lisp_Event* event = XEVENT (emacs_event);
1464 if (read_event_from_tty_or_stream_desc (event, c, i))
1466 mswindows_enqueue_dispatch_event (emacs_event);
1472 /* Look for a process event */
1473 for (i = 0; i < MAXDESC-1; i++)
1475 if (FD_ISSET (i, &temp_mask))
1477 if (FD_ISSET (i, &process_only_mask))
1480 get_process_from_usid (FD_TO_USID(i));
1482 mswindows_enqueue_process_event (p);
1486 /* We might get here when a fake event came
1487 through a signal. Return a dummy event, so
1488 that a cycle of the command loop will
1490 drain_signal_event_pipe ();
1491 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1497 else if (active==-1)
1501 /* something bad happened */
1510 /* Now try getting a message or process event */
1514 if (mswindows_in_modal_loop)
1515 /* In a modal loop, only look for timer events, and only if
1516 we really need one. */
1519 what_events = QS_TIMER;
1524 /* Look for any event */
1525 what_events = QS_ALLINPUT;
1527 /* This fixes a long outstanding bug, where XEmacs would occasionally
1528 * not redraw its window (or process other events) until "something
1529 * happened" - usually the mouse moving over a frame.
1531 * The problem is that MsgWaitForMultipleObjects only checks to see
1532 * if NEW messages have been placed into the thread queue. So we
1533 * specifically check to see if the queue is empty (using PeekMessage
1534 * with the PM_NOREMOVE flag) before we wait.
1536 if (what_events == QS_ALLINPUT && badly_p &&
1537 PeekMessage (&msg, 0, 0, 0, PM_NOREMOVE))
1538 active = WAIT_OBJECT_0 + mswindows_waitable_count;
1540 active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1541 mswindows_waitable_handles,
1542 FALSE, badly_p ? INFINITE : 0,
1545 /* This will assert if handle being waited for becomes abandoned.
1546 Not the case currently tho */
1547 assert ((!badly_p && active == WAIT_TIMEOUT) ||
1548 (active >= WAIT_OBJECT_0 &&
1549 active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1551 if (active == WAIT_TIMEOUT)
1553 /* No luck trying - just return what we've already got */
1556 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1558 /* Got your message, thanks */
1559 if (mswindows_in_modal_loop)
1560 mswindows_need_event_in_modal_loop (badly_p);
1562 mswindows_drain_windows_queue ();
1566 int ix = active - WAIT_OBJECT_0;
1567 /* First, try to find which process' output has signaled */
1569 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1572 /* Found a signaled process input handle */
1573 mswindows_enqueue_process_event (p);
1577 /* None. This means that the process handle itself has signaled.
1578 Remove the handle from the wait vector, and make status_notify
1579 note the exited process. First find the process object if
1581 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
1582 if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
1583 mswindows_waitable_handles [ix])
1585 mswindows_waitable_handles [ix] =
1586 mswindows_waitable_handles [--mswindows_waitable_count];
1587 kick_status_notify ();
1588 /* We need to return a process event here so that
1589 (1) accept-process-output will return when called on this
1590 process, and (2) status notifications will happen in
1591 accept-process-output, sleep-for, and sit-for. */
1592 /* #### horrible kludge till my real process fixes go in.
1593 #### Replaced with a slightly less horrible kluge that
1594 at least finds the right process instead of axing the
1595 first one on the list.
1597 if (!NILP (vproctail))
1599 mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1601 else /* trash me soon. */
1602 /* Have to return something: there may be no accompanying
1604 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1611 /************************************************************************/
1612 /* Event generators */
1613 /************************************************************************/
1616 * Callback procedure for synchronous timer messages
1618 static void CALLBACK
1619 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1621 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1622 Lisp_Event *event = XEVENT (emacs_event);
1624 if (KillTimer (NULL, id_timer))
1625 --mswindows_pending_timers_count;
1627 event->channel = Qnil;
1628 event->timestamp = dwtime;
1629 event->event_type = timeout_event;
1630 event->event.timeout.interval_id = id_timer;
1631 event->event.timeout.function = Qnil;
1632 event->event.timeout.object = Qnil;
1634 mswindows_enqueue_dispatch_event (emacs_event);
1638 * Callback procedure for dde messages
1640 * We execute a dde Open("file") by simulating a file drop, so dde support
1641 * depends on dnd support.
1643 #ifdef HAVE_DRAGNDROP
1644 extern int mswindows_dde_enable;
1647 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1648 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1649 DWORD dwData1, DWORD dwData2)
1654 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1655 return (HDDEDATA)TRUE;
1656 return (HDDEDATA)FALSE;
1658 case XTYP_WILDCONNECT:
1660 /* We only support one {service,topic} pair */
1661 HSZPAIR pairs[2] = {
1662 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1664 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1665 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1666 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1667 sizeof (pairs), 0L, 0, uFmt, 0));
1669 return (HDDEDATA)NULL;
1672 if (!mswindows_dde_enable)
1673 return (HDDEDATA) DDE_FBUSY;
1675 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1677 DWORD len = DdeGetData (hdata, NULL, 0, 0);
1678 LPBYTE cmd = (LPBYTE) alloca (len+1);
1681 struct gcpro gcpro1, gcpro2;
1682 Lisp_Object l_dndlist = Qnil;
1683 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1684 Lisp_Object frmcons, devcons, concons;
1685 Lisp_Event *event = XEVENT (emacs_event);
1687 DdeGetData (hdata, cmd, len, 0);
1689 DdeFreeDataHandle (hdata);
1691 /* Check syntax & that it's an [Open("foo")] command, which we
1692 * treat like a file drop */
1693 /* #### Ought to be generalised and accept some other commands */
1696 if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1697 strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1698 return DDE_FNOTPROCESSED;
1699 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1702 if (*cmd!='(' || *(cmd+1)!='\"')
1703 return DDE_FNOTPROCESSED;
1705 while (*end && *end!='\"')
1708 return DDE_FNOTPROCESSED;
1711 return DDE_FNOTPROCESSED;
1715 return DDE_FNOTPROCESSED;
1718 filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5);
1719 strcpy (filename, "file:");
1720 cygwin_win32_to_posix_path_list (cmd, filename+5);
1722 dostounix_filename (cmd);
1723 filename = alloca (strlen (cmd)+6);
1724 strcpy (filename, "file:");
1725 strcat (filename, cmd);
1727 GCPRO2 (emacs_event, l_dndlist);
1728 l_dndlist = make_string (filename, strlen (filename));
1730 /* Find a mswindows frame */
1731 event->channel = Qnil;
1732 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1734 Lisp_Object frame = XCAR (frmcons);
1735 if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1736 event->channel = frame;
1738 assert (!NILP (event->channel));
1740 event->timestamp = GetTickCount();
1741 event->event_type = misc_user_event;
1742 event->event.misc.button = 1;
1743 event->event.misc.modifiers = 0;
1744 event->event.misc.x = -1;
1745 event->event.misc.y = -1;
1746 event->event.misc.function = Qdragdrop_drop_dispatch;
1747 event->event.misc.object = Fcons (Qdragdrop_URL,
1748 Fcons (l_dndlist, Qnil));
1749 mswindows_enqueue_dispatch_event (emacs_event);
1751 return (HDDEDATA) DDE_FACK;
1753 DdeFreeDataHandle (hdata);
1754 return (HDDEDATA) DDE_FNOTPROCESSED;
1757 return (HDDEDATA) NULL;
1763 * Helper to do repainting - repaints can happen both from the windows
1764 * procedure and from magic events
1767 mswindows_handle_paint (struct frame *frame)
1769 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1771 /* According to the docs we need to check GetUpdateRect() before
1772 actually doing a WM_PAINT */
1773 if (GetUpdateRect (hwnd, NULL, FALSE))
1775 PAINTSTRUCT paintStruct;
1776 int x, y, width, height;
1778 BeginPaint (hwnd, &paintStruct);
1779 x = paintStruct.rcPaint.left;
1780 y = paintStruct.rcPaint.top;
1781 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1782 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1783 /* Normally we want to ignore expose events when child
1784 windows are unmapped, however once we are in the guts of
1785 WM_PAINT we need to make sure that we don't register
1786 unmaps then because they will not actually occur. */
1787 /* #### commenting out the next line seems to fix some problems
1788 but not all. only andy currently understands this stuff and
1789 he needs to review it more carefully. --ben */
1790 if (!check_for_ignored_expose (frame, x, y, width, height))
1792 hold_ignored_expose_registration = 1;
1793 mswindows_redraw_exposed_area (frame, x, y, width, height);
1794 hold_ignored_expose_registration = 0;
1796 EndPaint (hwnd, &paintStruct);
1801 * Returns 1 if a key is a real modifier or special key, which
1802 * is better handled by DefWindowProc
1805 key_needs_default_processing_p (UINT vkey)
1807 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1808 /* if we let ALT activate the menu like this, then sticky ALT-modified
1809 keystrokes become impossible. */
1810 && !modifier_keys_are_sticky)
1816 /* key-handling code is always ugly. It just ends up working out
1819 #### Most of the sticky-modifier code below is copied from similar
1820 code in event-Xt.c. They should somehow or other be merged.
1822 Here are some pointers:
1824 -- DOWN_MASK indicates which modifiers should be treated as "down"
1825 when the corresponding upstroke happens. It gets reset for
1826 a particular modifier when that modifier goes up, and reset
1827 for all modifiers when a non-modifier key is pressed. Example:
1829 I press Control-A-Shift and then release Control-A-Shift.
1830 I want the Shift key to be sticky but not the Control key.
1832 -- If a modifier key is sticky, I can unstick it by pressing
1833 the modifier key again. */
1835 static WPARAM last_downkey;
1836 static int need_to_add_mask, down_mask;
1838 #define XEMSW_LCONTROL (1<<0)
1839 #define XEMSW_RCONTROL (1<<1)
1840 #define XEMSW_LSHIFT (1<<2)
1841 #define XEMSW_RSHIFT (1<<3)
1842 #define XEMSW_LMENU (1<<4)
1843 #define XEMSW_RMENU (1<<5)
1846 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1847 int downp, int keyp)
1851 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1855 (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1856 wParam == VK_RCONTROL ||
1857 wParam == VK_MENU || wParam == VK_LMENU ||
1858 wParam == VK_RMENU ||
1859 wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1860 wParam == VK_RSHIFT)))
1861 { /* Not a modifier key */
1862 if (downp && keyp && !last_downkey)
1863 last_downkey = wParam;
1864 /* If I hold press-and-release the Control key and then press
1865 and hold down the right arrow, I want it to auto-repeat
1866 Control-Right. On the other hand, if I do the same but
1867 manually press the Right arrow a bunch of times, I want
1868 to see one Control-Right and then a bunch of Rights.
1869 This means that we need to distinguish between an
1870 auto-repeated key and a key pressed and released a bunch
1872 else if ((downp && !keyp) ||
1873 (downp && keyp && last_downkey &&
1874 (wParam != last_downkey ||
1875 /* the "previous key state" bit indicates autorepeat */
1876 ! (lParam & (1 << 30)))))
1878 need_to_add_mask = 0;
1884 mods = need_to_add_mask;
1886 else /* Modifier key pressed */
1888 /* If a non-modifier key was pressed in the middle of a bunch
1889 of modifiers, then it unsticks all the modifiers that were
1890 previously pressed. We cannot unstick the modifiers until
1891 now because we want to check for auto-repeat of the
1892 non-modifier key. */
1897 need_to_add_mask = 0;
1900 #define FROB(mask) \
1902 if (downp && keyp) \
1904 /* If modifier key is already sticky, \
1905 then unstick it. Note that we do \
1906 not test down_mask to deal with the \
1907 unlikely but possible case that the \
1908 modifier key auto-repeats. */ \
1909 if (need_to_add_mask & mask) \
1911 need_to_add_mask &= ~mask; \
1912 down_mask &= ~mask; \
1915 down_mask |= mask; \
1919 if (down_mask & mask) \
1921 down_mask &= ~mask; \
1922 need_to_add_mask |= mask; \
1927 if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1928 || wParam == VK_RCONTROL)
1929 FROB (XEMSW_RCONTROL);
1930 if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1931 || wParam == VK_LCONTROL)
1932 FROB (XEMSW_LCONTROL);
1934 if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1935 || wParam == VK_RSHIFT)
1936 FROB (XEMSW_RSHIFT);
1937 if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1938 || wParam == VK_LSHIFT)
1939 FROB (XEMSW_LSHIFT);
1941 if ((wParam == VK_MENU && (lParam & 0x1000000))
1942 || wParam == VK_RMENU)
1944 if ((wParam == VK_MENU && !(lParam & 0x1000000))
1945 || wParam == VK_LMENU)
1954 GetKeyboardState (keymap);
1956 if (mods & XEMSW_LCONTROL)
1958 keymap [VK_CONTROL] |= 0x80;
1959 keymap [VK_LCONTROL] |= 0x80;
1961 if (mods & XEMSW_RCONTROL)
1963 keymap [VK_CONTROL] |= 0x80;
1964 keymap [VK_RCONTROL] |= 0x80;
1967 if (mods & XEMSW_LSHIFT)
1969 keymap [VK_SHIFT] |= 0x80;
1970 keymap [VK_LSHIFT] |= 0x80;
1972 if (mods & XEMSW_RSHIFT)
1974 keymap [VK_SHIFT] |= 0x80;
1975 keymap [VK_RSHIFT] |= 0x80;
1978 if (mods & XEMSW_LMENU)
1980 keymap [VK_MENU] |= 0x80;
1981 keymap [VK_LMENU] |= 0x80;
1983 if (mods & XEMSW_RMENU)
1985 keymap [VK_MENU] |= 0x80;
1986 keymap [VK_RMENU] |= 0x80;
1989 SetKeyboardState (keymap);
1997 clear_sticky_modifiers (void)
1999 need_to_add_mask = 0;
2009 output_modifier_keyboard_state (void)
2013 GetKeyboardState (keymap);
2015 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2016 keymap[VK_MENU] & 0x80 ? 1 : 0,
2017 keymap[VK_MENU] & 0x1 ? 1 : 0,
2018 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2019 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2020 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2021 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2022 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
2023 keymap[VK_CONTROL] & 0x80 ? 1 : 0,
2024 keymap[VK_CONTROL] & 0x1 ? 1 : 0,
2025 keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
2026 keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
2027 keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
2028 keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
2029 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
2030 keymap[VK_SHIFT] & 0x80 ? 1 : 0,
2031 keymap[VK_SHIFT] & 0x1 ? 1 : 0,
2032 keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
2033 keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
2034 keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
2035 keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
2040 /* try to debug the stuck-alt-key problem.
2042 #### this happens only inconsistently, and may only happen when using
2043 StickyKeys in the Win2000 accessibility section of the control panel,
2044 which is extremely broken for other reasons. */
2047 output_alt_keyboard_state (void)
2051 // SHORT asyncstate[3];
2053 GetKeyboardState (keymap);
2054 keystate[0] = GetKeyState (VK_MENU);
2055 keystate[1] = GetKeyState (VK_LMENU);
2056 keystate[2] = GetKeyState (VK_RMENU);
2057 /* Doing this interferes with key processing. */
2058 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2059 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2060 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2062 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2063 keymap[VK_MENU] & 0x80 ? 1 : 0,
2064 keymap[VK_MENU] & 0x1 ? 1 : 0,
2065 keymap[VK_LMENU] & 0x80 ? 1 : 0,
2066 keymap[VK_LMENU] & 0x1 ? 1 : 0,
2067 keymap[VK_RMENU] & 0x80 ? 1 : 0,
2068 keymap[VK_RMENU] & 0x1 ? 1 : 0);
2069 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2070 keystate[0] & 0x8000 ? 1 : 0,
2071 keystate[0] & 0x1 ? 1 : 0,
2072 keystate[1] & 0x8000 ? 1 : 0,
2073 keystate[1] & 0x1 ? 1 : 0,
2074 keystate[2] & 0x8000 ? 1 : 0,
2075 keystate[2] & 0x1 ? 1 : 0);
2076 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2077 /* asyncstate[0] & 0x8000 ? 1 : 0, */
2078 /* asyncstate[0] & 0x1 ? 1 : 0, */
2079 /* asyncstate[1] & 0x8000 ? 1 : 0, */
2080 /* asyncstate[1] & 0x1 ? 1 : 0, */
2081 /* asyncstate[2] & 0x8000 ? 1 : 0, */
2082 /* asyncstate[2] & 0x1 ? 1 : 0); */
2085 #endif /* DEBUG_XEMACS */
2089 * The windows procedure for the window class XEMACS_CLASS
2092 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2094 /* Note: Remember to initialize emacs_event and event before use.
2095 This code calls code that can GC. You must GCPRO before calling such code. */
2096 Lisp_Object emacs_event = Qnil;
2097 Lisp_Object fobj = Qnil;
2100 struct frame *frame;
2101 struct mswindows_frame* msframe;
2103 /* If you hit this, rewrite the offending API call to occur after GC,
2104 using register_post_gc_action(). */
2105 assert (!gc_in_progress);
2108 if (debug_mswindows_events)
2109 debug_output_mswin_message (hwnd, message_, wParam, lParam);
2110 #endif /* DEBUG_XEMACS */
2112 assert (!GetWindowLong (hwnd, GWL_USERDATA));
2115 case WM_DESTROYCLIPBOARD:
2116 /* We own the clipboard and someone else wants it. Delete our
2117 cached copy of the clipboard contents so we'll ask for it from
2118 Windows again when someone does a paste, and destroy any memory
2119 objects we hold on the clipboard that are not in the list of types
2120 that Windows will delete itself. */
2121 mswindows_destroy_selection (QCLIPBOARD);
2122 handle_selection_clear (QCLIPBOARD);
2126 /* Erase background only during non-dynamic sizing */
2127 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2128 if (msframe->sizing && !mswindows_dynamic_frame_resize)
2133 fobj = mswindows_find_frame (hwnd);
2134 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2140 /* See Win95 comment under WM_KEYDOWN */
2143 int should_set_keymap = 0;
2146 if (debug_mswindows_events > 2)
2147 output_alt_keyboard_state ();
2148 #endif /* DEBUG_XEMACS */
2150 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2151 if (wParam == VK_CONTROL)
2153 GetKeyboardState (keymap);
2154 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2155 should_set_keymap = 1;
2157 else if (wParam == VK_MENU)
2159 GetKeyboardState (keymap);
2160 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2161 should_set_keymap = 1;
2164 if (should_set_keymap)
2165 // && (message_ != WM_SYSKEYUP
2166 // || NILP (Vmenu_accelerator_enabled)))
2167 SetKeyboardState (keymap);
2171 if (key_needs_default_processing_p (wParam))
2179 /* In some locales the right-hand Alt key is labelled AltGr. This key
2180 * should produce alternative characters when combined with another key.
2181 * eg on a German keyboard pressing AltGr+q should produce '@'.
2182 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2183 * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2184 * it translates as if AltGr were down.
2185 * We get round this by removing all modifiers from the keymap before
2186 * calling TranslateMessage() unless AltGr is *really* down. */
2188 BYTE keymap_trans[256];
2189 BYTE keymap_orig[256];
2190 BYTE keymap_sticky[256];
2191 int has_AltGr = mswindows_current_layout_has_AltGr ();
2192 int mods = 0, mods_with_shift = 0;
2193 int extendedp = lParam & 0x1000000;
2198 if (debug_mswindows_events > 2)
2199 output_alt_keyboard_state ();
2200 #endif /* DEBUG_XEMACS */
2202 GetKeyboardState (keymap_orig);
2203 frame = XFRAME (mswindows_find_frame (hwnd));
2204 if ((sticky_changed =
2205 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2207 GetKeyboardState (keymap_sticky);
2208 if (keymap_sticky[VK_MENU] & 0x80)
2210 message_ = WM_SYSKEYDOWN;
2211 /* We have to set the "context bit" so that the
2212 TranslateMessage() call below that generates the
2213 SYSCHAR message does its thing; see the documentation
2219 memcpy (keymap_sticky, keymap_orig, 256);
2221 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2222 mods_with_shift = mods;
2224 /* Handle non-printables */
2225 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2228 mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2230 SetKeyboardState (keymap_orig);
2232 else /* Normal keys & modifiers */
2235 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2236 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2238 int potential_accelerator = 0;
2239 int got_accelerator = 0;
2242 msg.message = message_;
2243 msg.wParam = wParam;
2244 msg.lParam = lParam;
2245 msg.time = GetMessageTime();
2248 /* GetKeyboardState() does not work as documented on Win95. We have
2249 * to loosely track Left and Right modifiers on behalf of the OS,
2250 * without screwing up Windows NT which tracks them properly. */
2251 if (wParam == VK_CONTROL)
2253 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2254 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2256 else if (wParam == VK_MENU)
2258 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2259 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2262 if (!NILP (Vmenu_accelerator_enabled) &&
2263 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2264 potential_accelerator = 1;
2266 /* Remove shift modifier from an ascii character */
2267 mods &= ~XEMACS_MOD_SHIFT;
2269 memcpy (keymap_trans, keymap_sticky, 256);
2271 /* Clear control and alt modifiers unless AltGr is pressed */
2272 keymap_trans[VK_RCONTROL] = 0;
2273 keymap_trans[VK_LMENU] = 0;
2274 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2275 || !(keymap_trans[VK_RMENU] & 0x80))
2277 keymap_trans[VK_LCONTROL] = 0;
2278 keymap_trans[VK_CONTROL] = 0;
2279 keymap_trans[VK_RMENU] = 0;
2280 keymap_trans[VK_MENU] = 0;
2282 SetKeyboardState (keymap_trans);
2284 /* Maybe generate some WM_[SYS]CHARs in the queue */
2285 TranslateMessage (&msg);
2287 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2288 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2291 int mods_with_quit = mods;
2292 WPARAM ch = tranmsg.wParam;
2295 if (debug_mswindows_events)
2298 debug_output_mswin_message (tranmsg.hwnd, tranmsg.message,
2302 #endif /* DEBUG_XEMACS */
2304 /* If a quit char with no modifiers other than control and
2305 shift, then mark it with a fake modifier, which is removed
2306 upon dequeueing the event */
2307 /* !!#### Fix this in my mule ws -- replace current_buffer
2309 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2310 && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2311 DOWNCASE (current_buffer, ch))
2312 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2313 && DOWNCASE (current_buffer, quit_ch) ==
2314 DOWNCASE (current_buffer, ch)))
2315 && ((mods_with_shift &
2316 ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2319 mods_with_quit |= FAKE_MOD_QUIT;
2320 if (mods_with_shift & XEMACS_MOD_SHIFT)
2321 mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2322 mswindows_quit_chars_count++;
2324 else if (potential_accelerator && !got_accelerator &&
2325 mswindows_char_is_accelerator (frame, ch))
2327 got_accelerator = 1;
2330 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2334 /* This generates WM_SYSCHAR messages, which are interpreted
2335 by DefWindowProc as the menu selections. */
2336 if (got_accelerator)
2338 SetKeyboardState (keymap_sticky);
2339 TranslateMessage (&msg);
2340 SetKeyboardState (keymap_orig);
2344 SetKeyboardState (keymap_orig);
2348 if (key_needs_default_processing_p (wParam))
2353 case WM_MBUTTONDOWN:
2355 /* Real middle mouse button has nothing to do with emulated one:
2356 if one wants to exercise fingers playing chords on the mouse,
2357 he is allowed to do that! */
2358 mswindows_enqueue_mouse_button_event (hwnd, message_,
2359 MAKEPOINTS (lParam),
2360 wParam &~ MK_MBUTTON,
2365 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2366 msframe->last_click_time = GetMessageTime();
2368 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2369 msframe->button2_need_lbutton = 0;
2370 if (msframe->ignore_next_lbutton_up)
2372 msframe->ignore_next_lbutton_up = 0;
2374 else if (msframe->button2_is_down)
2376 msframe->button2_is_down = 0;
2377 msframe->ignore_next_rbutton_up = 1;
2378 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2379 MAKEPOINTS (lParam),
2381 &~ (MK_LBUTTON | MK_MBUTTON
2387 if (msframe->button2_need_rbutton)
2389 msframe->button2_need_rbutton = 0;
2390 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2391 MAKEPOINTS (lParam),
2392 wParam &~ MK_LBUTTON,
2395 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2396 MAKEPOINTS (lParam),
2397 wParam &~ MK_LBUTTON,
2403 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2404 msframe->last_click_time = GetMessageTime();
2406 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2407 msframe->button2_need_rbutton = 0;
2408 if (msframe->ignore_next_rbutton_up)
2410 msframe->ignore_next_rbutton_up = 0;
2412 else if (msframe->button2_is_down)
2414 msframe->button2_is_down = 0;
2415 msframe->ignore_next_lbutton_up = 1;
2416 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2417 MAKEPOINTS (lParam),
2419 &~ (MK_LBUTTON | MK_MBUTTON
2425 if (msframe->button2_need_lbutton)
2427 msframe->button2_need_lbutton = 0;
2428 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2429 MAKEPOINTS (lParam),
2430 wParam &~ MK_RBUTTON,
2433 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2434 MAKEPOINTS (lParam),
2435 wParam &~ MK_RBUTTON,
2440 case WM_LBUTTONDOWN:
2441 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2443 if (msframe->button2_need_lbutton)
2445 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2446 msframe->button2_need_lbutton = 0;
2447 msframe->button2_need_rbutton = 0;
2448 if (mswindows_button2_near_enough (msframe->last_click_point,
2449 MAKEPOINTS (lParam)))
2451 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2452 MAKEPOINTS (lParam),
2454 &~ (MK_LBUTTON | MK_MBUTTON
2457 msframe->button2_is_down = 1;
2461 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2462 msframe->last_click_point,
2463 msframe->last_click_mods
2465 msframe->last_click_time);
2466 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2467 MAKEPOINTS (lParam),
2468 wParam &~ MK_LBUTTON,
2474 mswindows_set_chord_timer (hwnd);
2475 msframe->button2_need_rbutton = 1;
2476 msframe->last_click_point = MAKEPOINTS (lParam);
2477 msframe->last_click_mods = wParam;
2479 msframe->last_click_time = GetMessageTime();
2482 case WM_RBUTTONDOWN:
2483 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2485 if (msframe->button2_need_rbutton)
2487 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2488 msframe->button2_need_lbutton = 0;
2489 msframe->button2_need_rbutton = 0;
2490 if (mswindows_button2_near_enough (msframe->last_click_point,
2491 MAKEPOINTS (lParam)))
2493 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2494 MAKEPOINTS (lParam),
2496 &~ (MK_LBUTTON | MK_MBUTTON
2499 msframe->button2_is_down = 1;
2503 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2504 msframe->last_click_point,
2505 msframe->last_click_mods
2507 msframe->last_click_time);
2508 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2509 MAKEPOINTS (lParam),
2510 wParam &~ MK_RBUTTON,
2516 mswindows_set_chord_timer (hwnd);
2517 msframe->button2_need_lbutton = 1;
2518 msframe->last_click_point = MAKEPOINTS (lParam);
2519 msframe->last_click_mods = wParam;
2521 msframe->last_click_time = GetMessageTime();
2525 if (wParam == BUTTON_2_TIMER_ID)
2527 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2528 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2530 if (msframe->button2_need_lbutton)
2532 msframe->button2_need_lbutton = 0;
2533 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2534 msframe->last_click_point,
2535 msframe->last_click_mods
2537 msframe->last_click_time);
2539 else if (msframe->button2_need_rbutton)
2541 msframe->button2_need_rbutton = 0;
2542 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2543 msframe->last_click_point,
2544 msframe->last_click_mods
2546 msframe->last_click_time);
2550 assert ("Spurious timer fired" == 0);
2554 /* Optimization: don't report mouse movement while size is changing */
2555 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2556 if (!msframe->sizing)
2558 /* When waiting for the second mouse button to finish
2559 button2 emulation, and have moved too far, just pretend
2560 as if timer has expired. This improves drag-select feedback */
2561 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2562 && !mswindows_button2_near_enough (msframe->last_click_point,
2563 MAKEPOINTS (lParam)))
2565 KillTimer (hwnd, BUTTON_2_TIMER_ID);
2566 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2569 emacs_event = Fmake_event (Qnil, Qnil);
2570 event = XEVENT(emacs_event);
2572 event->channel = mswindows_find_frame(hwnd);
2573 event->timestamp = GetMessageTime();
2574 event->event_type = pointer_motion_event;
2575 event->event.motion.x = MAKEPOINTS(lParam).x;
2576 event->event.motion.y = MAKEPOINTS(lParam).y;
2577 event->event.motion.modifiers =
2578 mswindows_modifier_state (NULL, wParam, 0);
2580 mswindows_enqueue_dispatch_event (emacs_event);
2586 /* Queue a `cancel-mode-internal' misc user event, so mouse
2587 selection would be canceled if any */
2588 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2589 Qcancel_mode_internal, Qnil);
2594 LPNMHDR nmhdr = (LPNMHDR)lParam;
2596 if (nmhdr->code == TTN_NEEDTEXT)
2598 #ifdef HAVE_TOOLBARS
2599 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2602 /* find out which toolbar */
2603 frame = XFRAME (mswindows_find_frame (hwnd));
2604 btext = mswindows_get_toolbar_button_text ( frame,
2607 tttext->lpszText = NULL;
2608 tttext->hinst = NULL;
2612 /* I think this is safe since the text will only go away
2613 when the toolbar does...*/
2614 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2618 /* handle tree view callbacks */
2619 else if (nmhdr->code == TVN_SELCHANGED)
2621 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2622 frame = XFRAME (mswindows_find_frame (hwnd));
2623 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2625 /* handle tab control callbacks */
2626 else if (nmhdr->code == TCN_SELCHANGE)
2629 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2630 frame = XFRAME (mswindows_find_frame (hwnd));
2632 item.mask = TCIF_PARAM;
2633 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2636 mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2642 /* hdc will be NULL unless this is a subwindow - in which case we
2643 shouldn't have received a paint message for it here. */
2644 assert (wParam == 0);
2646 /* Can't queue a magic event because windows goes modal and sends paint
2647 messages directly to the windows procedure when doing solid drags
2648 and the message queue doesn't get processed. */
2649 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2655 * If we receive a WM_ACTIVATE message that indicates that our frame
2656 * is being activated, make sure that the frame is marked visible
2657 * if the window itself is visible. This seems to fix the problem
2658 * where XEmacs appears to lock-up after switching desktops with
2659 * some virtual window managers.
2661 int state = (int)(short) LOWORD(wParam);
2663 if (debug_mswindows_events)
2664 stderr_out("state = %d\n", state);
2665 #endif /* DEBUG_XEMACS */
2666 if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
2669 if (debug_mswindows_events)
2670 stderr_out(" activating\n");
2671 #endif /* DEBUG_XEMACS */
2673 fobj = mswindows_find_frame (hwnd);
2674 frame = XFRAME (fobj);
2675 if (IsWindowVisible (hwnd))
2678 if (debug_mswindows_events)
2679 stderr_out(" window is visible\n");
2680 #endif /* DEBUG_XEMACS */
2681 if (!FRAME_VISIBLE_P (frame))
2684 if (debug_mswindows_events)
2685 stderr_out(" frame is not visible\n");
2686 #endif /* DEBUG_XEMACS */
2688 * It seems that we have to enqueue the XM_MAPFRAME event
2689 * prior to setting the frame visible so that
2690 * suspend-or-iconify-emacs works properly.
2692 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2693 FRAME_VISIBLE_P (frame) = 1;
2694 FRAME_ICONIFIED_P (frame) = 0;
2699 if (debug_mswindows_events)
2700 stderr_out(" frame is visible\n");
2702 #endif /* DEBUG_XEMACS */
2707 if (debug_mswindows_events)
2708 stderr_out(" window is not visible\n");
2710 #endif /* DEBUG_XEMACS */
2712 return DefWindowProc (hwnd, message_, wParam, lParam);
2716 case WM_WINDOWPOSCHANGED:
2717 /* This is sent before WM_SIZE; in fact, the processing of this
2718 by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when
2719 a window is hidden (make-frame-invisible), so we need to process
2720 this and update the state flags. */
2722 fobj = mswindows_find_frame (hwnd);
2723 frame = XFRAME (fobj);
2724 if (IsIconic (hwnd))
2726 FRAME_VISIBLE_P (frame) = 0;
2727 FRAME_ICONIFIED_P (frame) = 1;
2729 else if (IsWindowVisible (hwnd))
2731 /* APA: It's too early here to set the frame visible.
2732 * Let's do this later, in WM_SIZE processing, after the
2733 * magic XM_MAPFRAME event has been sent (just like 21.1
2735 /* FRAME_VISIBLE_P (frame) = 1; */
2736 FRAME_ICONIFIED_P (frame) = 0;
2740 FRAME_VISIBLE_P (frame) = 0;
2741 FRAME_ICONIFIED_P (frame) = 0;
2744 return DefWindowProc (hwnd, message_, wParam, lParam);
2749 The WM_SHOWWINDOW message is sent to a window when the window
2750 is about to be hidden or shown.
2751 APA: This message is also sent when switching to a virtual
2752 desktop under the virtuawin virtual window manager.
2756 fobj = mswindows_find_frame (hwnd);
2757 frame = XFRAME (fobj);
2760 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2761 FRAME_VISIBLE_P (frame) = 1;
2765 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2766 FRAME_VISIBLE_P (frame) = 0;
2772 /* We only care about this message if our size has really changed */
2773 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2778 fobj = mswindows_find_frame (hwnd);
2779 frame = XFRAME (fobj);
2780 msframe = FRAME_MSWINDOWS_DATA (frame);
2782 /* We cannot handle frame map and unmap hooks right in
2783 this routine, because these may throw. We queue
2784 magic events to run these hooks instead - kkm */
2786 if (wParam==SIZE_MINIMIZED)
2789 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2793 GetClientRect(hwnd, &rect);
2794 FRAME_PIXWIDTH(frame) = rect.right;
2795 FRAME_PIXHEIGHT(frame) = rect.bottom;
2797 pixel_to_real_char_size (frame, rect.right, rect.bottom,
2798 &FRAME_MSWINDOWS_CHARWIDTH (frame),
2799 &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2801 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2802 change_frame_size (frame, rows, columns, 1);
2804 /* If we are inside frame creation, we have to apply geometric
2806 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2808 /* Yes, we have to size again */
2809 mswindows_size_frame_internal ( frame,
2810 FRAME_MSWINDOWS_TARGET_RECT
2812 /* Reset so we do not get here again. The SetWindowPos call in
2813 * mswindows_size_frame_internal can cause recursion here. */
2814 if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2816 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2817 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2822 if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2824 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2825 /* APA: Now that the magic XM_MAPFRAME event has
2826 * been sent we can mark the frame as visible (just
2827 * like 21.1 did). */
2828 FRAME_VISIBLE_P (frame) = 1;
2831 if (!msframe->sizing || mswindows_dynamic_frame_resize)
2838 case WM_DISPLAYCHANGE:
2841 DWORD message_tick = GetMessageTime ();
2843 fobj = mswindows_find_frame (hwnd);
2844 frame = XFRAME (fobj);
2845 d = XDEVICE (FRAME_DEVICE (frame));
2847 /* Do this only once per message. XEmacs can receive this message
2848 through as many frames as it currently has open. Message time
2849 will be the same for all these messages. Despite extreme
2850 efficiency, the code below has about one in 4 billion
2851 probability that the HDC is not recreated, provided that
2852 XEmacs is running sufficiently longer than 52 days. */
2853 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2855 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2856 DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2857 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2862 /* Misc magic events which only require that the frame be identified */
2865 mswindows_enqueue_magic_event (hwnd, message_);
2868 case WM_WINDOWPOSCHANGING:
2870 WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2871 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2872 GetWindowPlacement(hwnd, &wpl);
2874 /* Only interested if size is changing and we're not being iconified */
2875 if (wpl.showCmd != SW_SHOWMINIMIZED
2876 && wpl.showCmd != SW_SHOWMAXIMIZED
2877 && !(wp->flags & SWP_NOSIZE))
2879 RECT ncsize = { 0, 0, 0, 0 };
2880 int pixwidth, pixheight;
2881 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2882 GetMenu(hwnd) != NULL,
2883 GetWindowLong (hwnd, GWL_EXSTYLE));
2885 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2886 wp->cx - (ncsize.right - ncsize.left),
2887 wp->cy - (ncsize.bottom - ncsize.top),
2888 &pixwidth, &pixheight);
2890 /* Convert client sizes to window sizes */
2891 pixwidth += (ncsize.right - ncsize.left);
2892 pixheight += (ncsize.bottom - ncsize.top);
2894 if (wpl.showCmd != SW_SHOWMAXIMIZED)
2896 /* Adjust so that the bottom or right doesn't move if it's
2897 * the top or left that's being changed */
2899 GetWindowRect (hwnd, &rect);
2901 if (rect.left != wp->x)
2902 wp->x += wp->cx - pixwidth;
2903 if (rect.top != wp->y)
2904 wp->y += wp->cy - pixheight;
2910 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2911 window position if the user tries to track window too small */
2915 case WM_ENTERSIZEMOVE:
2916 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2917 msframe->sizing = 1;
2920 case WM_EXITSIZEMOVE:
2921 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2922 msframe->sizing = 0;
2923 /* Queue noop event */
2924 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2927 #ifdef HAVE_SCROLLBARS
2931 /* Direction of scroll is determined by scrollbar instance. */
2932 int code = (int) LOWORD(wParam);
2933 int pos = (short int) HIWORD(wParam);
2934 HWND hwndScrollBar = (HWND) lParam;
2935 struct gcpro gcpro1, gcpro2;
2937 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos);
2938 GCPRO2 (emacs_event, fobj);
2939 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */
2941 /* Error during event pumping - cancel scroll */
2942 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2950 int keys = LOWORD (wParam); /* Modifier key flags */
2951 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2953 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2955 MAKEPOINTS (lParam)))
2956 /* We are not in a modal loop so no pumping is necessary. */
2963 #ifdef HAVE_MENUBARS
2965 if (UNBOUNDP (mswindows_handle_wm_initmenu (
2967 XFRAME (mswindows_find_frame (hwnd)))))
2968 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2971 case WM_INITMENUPOPUP:
2972 if (!HIWORD(lParam))
2974 if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2976 XFRAME (mswindows_find_frame (hwnd)))))
2977 SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2981 #endif /* HAVE_MENUBARS */
2985 WORD id = LOWORD (wParam);
2986 WORD nid = HIWORD (wParam);
2987 HWND cid = (HWND)lParam;
2988 frame = XFRAME (mswindows_find_frame (hwnd));
2990 #ifdef HAVE_TOOLBARS
2991 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2994 /* widgets in a buffer only eval a callback for suitable events.*/
2999 case CBN_EDITCHANGE:
3001 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
3004 /* menubars always must come last since the hashtables do not
3006 #ifdef HAVE_MENUBARS
3007 if (!NILP (mswindows_handle_wm_command (frame, id)))
3011 return DefWindowProc (hwnd, message_, wParam, lParam);
3012 /* Bite me - a spurious command. This used to not be able to
3013 happen but with the introduction of widgets its now
3018 case WM_CTLCOLORBTN:
3019 case WM_CTLCOLORLISTBOX:
3020 case WM_CTLCOLOREDIT:
3021 case WM_CTLCOLORSTATIC:
3022 case WM_CTLCOLORSCROLLBAR:
3024 /* if we get an opportunity to paint a widget then do so if
3025 there is an appropriate face */
3026 HWND crtlwnd = (HWND)lParam;
3027 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
3030 Lisp_Object image_instance;
3031 VOID_TO_LISP (image_instance, ii);
3032 if (IMAGE_INSTANCEP (image_instance)
3034 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
3036 /* set colors for the buttons */
3037 HDC hdc = (HDC)wParam;
3038 if (last_widget_brushed != ii)
3041 DeleteObject (widget_brush);
3042 widget_brush = CreateSolidBrush
3043 (COLOR_INSTANCE_MSWINDOWS_COLOR
3046 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3047 XIMAGE_INSTANCE_FRAME (image_instance)))));
3049 last_widget_brushed = ii;
3052 COLOR_INSTANCE_MSWINDOWS_COLOR
3055 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3056 XIMAGE_INSTANCE_FRAME (image_instance)))));
3057 SetBkMode (hdc, OPAQUE);
3060 COLOR_INSTANCE_MSWINDOWS_COLOR
3063 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3064 XIMAGE_INSTANCE_FRAME (image_instance)))));
3065 return (LRESULT)widget_brush;
3071 #ifdef HAVE_DRAGNDROP
3072 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */
3074 UINT filecount, i, len;
3079 Lisp_Object l_dndlist = Qnil, l_item = Qnil;
3080 struct gcpro gcpro1, gcpro2, gcpro3;
3082 emacs_event = Fmake_event (Qnil, Qnil);
3083 event = XEVENT(emacs_event);
3085 GCPRO3 (emacs_event, l_dndlist, l_item);
3087 if (!DragQueryPoint ((HDROP) wParam, &point))
3088 point.x = point.y = -1; /* outside client area */
3090 event->event_type = misc_user_event;
3091 event->channel = mswindows_find_frame(hwnd);
3092 event->timestamp = GetMessageTime();
3093 event->event.misc.button = 1; /* #### Should try harder */
3094 event->event.misc.modifiers = mswindows_modifier_state (NULL,
3096 event->event.misc.x = point.x;
3097 event->event.misc.y = point.y;
3098 event->event.misc.function = Qdragdrop_drop_dispatch;
3100 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
3101 for (i=0; i<filecount; i++)
3103 len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
3104 /* The URLs that we make here aren't correct according to section
3105 * 3.10 of rfc1738 because they're missing the //<host>/ part and
3106 * because they may contain reserved characters. But that's OK -
3107 * they just need to be good enough to keep dragdrop.el happy. */
3108 fname = (char *)xmalloc (len+1);
3109 DragQueryFile ((HANDLE) wParam, i, fname, len+1);
3111 /* May be a shell link aka "shortcut" - replace fname if so */
3112 #if !(defined(CYGWIN) || defined(MINGW))
3113 /* cygwin doesn't define this COM stuff */
3114 if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
3118 if (CoCreateInstance (&CLSID_ShellLink, NULL,
3119 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
3123 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
3126 OLECHAR wsz[PATH_MAX];
3127 WIN32_FIND_DATA wfd;
3128 LPSTR resolved = (char *) xmalloc (PATH_MAX+1);
3130 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX);
3132 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
3133 (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX,
3138 len = strlen (fname);
3141 ppf->lpVtbl->Release (ppf);
3144 psl->lpVtbl->Release (psl);
3150 filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5);
3151 strcpy (filename, "file:");
3152 cygwin_win32_to_posix_path_list (fname, filename+5);
3154 filename = (char *)xmalloc (len+6);
3155 strcat (strcpy (filename, "file:"), fname);
3156 dostounix_filename (filename+5);
3159 l_item = make_string (filename, strlen (filename));
3160 l_dndlist = Fcons (l_item, l_dndlist);
3163 DragFinish ((HDROP) wParam);
3165 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3166 mswindows_enqueue_dispatch_event (emacs_event);
3174 return DefWindowProc (hwnd, message_, wParam, lParam);
3180 /************************************************************************/
3181 /* keyboard, mouse & other helpers for the windows procedure */
3182 /************************************************************************/
3184 mswindows_set_chord_timer (HWND hwnd)
3188 /* We get one third half system double click threshold */
3189 if (mswindows_mouse_button_tolerance <= 0)
3190 interval = GetDoubleClickTime () / 3;
3192 interval = mswindows_mouse_button_tolerance;
3194 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3198 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3201 if (mswindows_mouse_button_max_skew_x <= 0)
3202 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3204 dx = mswindows_mouse_button_max_skew_x;
3206 if (mswindows_mouse_button_max_skew_y <= 0)
3207 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3209 dy = mswindows_mouse_button_max_skew_y;
3211 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3215 mswindows_current_layout_has_AltGr (void)
3217 /* This simple caching mechanism saves 10% of CPU
3218 time when a key typed at autorepeat rate of 30 cps! */
3219 static HKL last_hkl = 0;
3220 static int last_hkl_has_AltGr;
3221 HKL current_hkl = (HKL) -1;
3223 if (xGetKeyboardLayout) /* not in NT 3.5 */
3224 current_hkl = xGetKeyboardLayout (0);
3225 if (current_hkl != last_hkl)
3228 last_hkl_has_AltGr = 0;
3229 /* In this loop, we query whether a character requires
3230 AltGr to be down to generate it. If at least such one
3231 found, this means that the layout does regard AltGr */
3232 for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3233 if (HIBYTE (VkKeyScan (c)) == 6)
3234 last_hkl_has_AltGr = 1;
3235 last_hkl = current_hkl;
3237 return last_hkl_has_AltGr;
3241 /* Returns the state of the modifier keys in the format expected by the
3242 * Lisp_Event key_data, button_data and motion_data modifiers member */
3244 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3247 int keys_is_real = 0;
3250 if (fwKeys == (DWORD) -1)
3251 fwKeys = mswindows_last_mouse_button_state;
3255 mswindows_last_mouse_button_state = fwKeys;
3261 GetKeyboardState (keymap);
3262 has_AltGr = mswindows_current_layout_has_AltGr ();
3265 /* #### should look at fwKeys for MK_CONTROL. I don't understand how
3267 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3269 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3270 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3274 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3275 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3278 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3279 ? XEMACS_MOD_SHIFT : 0;
3280 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3281 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3282 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3288 * Translate a mswindows virtual key to a keysym.
3289 * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3290 * or whose ASCII codes (like space) xemacs doesn't like.
3292 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3295 if (extendedp) /* Keys not present on a 82 key keyboard */
3297 switch (mswindows_key)
3299 case VK_CANCEL: return KEYSYM ("pause");
3300 case VK_RETURN: return KEYSYM ("kp-enter");
3301 case VK_PRIOR: return KEYSYM ("prior");
3302 case VK_NEXT: return KEYSYM ("next");
3303 case VK_END: return KEYSYM ("end");
3304 case VK_HOME: return KEYSYM ("home");
3305 case VK_LEFT: return KEYSYM ("left");
3306 case VK_UP: return KEYSYM ("up");
3307 case VK_RIGHT: return KEYSYM ("right");
3308 case VK_DOWN: return KEYSYM ("down");
3309 case VK_INSERT: return KEYSYM ("insert");
3310 case VK_DELETE: return QKdelete;
3311 #if 0 /* FSF Emacs allows these to return configurable syms/mods */
3312 case VK_LWIN return KEYSYM ("");
3313 case VK_RWIN return KEYSYM ("");
3315 case VK_APPS: return KEYSYM ("menu");
3320 switch (mswindows_key)
3322 case VK_BACK: return QKbackspace;
3323 case VK_TAB: return QKtab;
3324 case '\n': return QKlinefeed;
3325 case VK_CLEAR: return KEYSYM ("clear");
3326 case VK_RETURN: return QKreturn;
3327 case VK_PAUSE: return KEYSYM ("pause");
3328 case VK_ESCAPE: return QKescape;
3329 case VK_SPACE: return QKspace;
3330 case VK_PRIOR: return KEYSYM ("kp-prior");
3331 case VK_NEXT: return KEYSYM ("kp-next");
3332 case VK_END: return KEYSYM ("kp-end");
3333 case VK_HOME: return KEYSYM ("kp-home");
3334 case VK_LEFT: return KEYSYM ("kp-left");
3335 case VK_UP: return KEYSYM ("kp-up");
3336 case VK_RIGHT: return KEYSYM ("kp-right");
3337 case VK_DOWN: return KEYSYM ("kp-down");
3338 case VK_SELECT: return KEYSYM ("select");
3339 case VK_PRINT: return KEYSYM ("print");
3340 case VK_EXECUTE: return KEYSYM ("execute");
3341 case VK_SNAPSHOT: return KEYSYM ("print");
3342 case VK_INSERT: return KEYSYM ("kp-insert");
3343 case VK_DELETE: return KEYSYM ("kp-delete");
3344 case VK_HELP: return KEYSYM ("help");
3345 case VK_NUMPAD0: return KEYSYM ("kp-0");
3346 case VK_NUMPAD1: return KEYSYM ("kp-1");
3347 case VK_NUMPAD2: return KEYSYM ("kp-2");
3348 case VK_NUMPAD3: return KEYSYM ("kp-3");
3349 case VK_NUMPAD4: return KEYSYM ("kp-4");
3350 case VK_NUMPAD5: return KEYSYM ("kp-5");
3351 case VK_NUMPAD6: return KEYSYM ("kp-6");
3352 case VK_NUMPAD7: return KEYSYM ("kp-7");
3353 case VK_NUMPAD8: return KEYSYM ("kp-8");
3354 case VK_NUMPAD9: return KEYSYM ("kp-9");
3355 case VK_MULTIPLY: return KEYSYM ("kp-multiply");
3356 case VK_ADD: return KEYSYM ("kp-add");
3357 case VK_SEPARATOR: return KEYSYM ("kp-separator");
3358 case VK_SUBTRACT: return KEYSYM ("kp-subtract");
3359 case VK_DECIMAL: return KEYSYM ("kp-decimal");
3360 case VK_DIVIDE: return KEYSYM ("kp-divide");
3361 case VK_F1: return KEYSYM ("f1");
3362 case VK_F2: return KEYSYM ("f2");
3363 case VK_F3: return KEYSYM ("f3");
3364 case VK_F4: return KEYSYM ("f4");
3365 case VK_F5: return KEYSYM ("f5");
3366 case VK_F6: return KEYSYM ("f6");
3367 case VK_F7: return KEYSYM ("f7");
3368 case VK_F8: return KEYSYM ("f8");
3369 case VK_F9: return KEYSYM ("f9");
3370 case VK_F10: return KEYSYM ("f10");
3371 case VK_F11: return KEYSYM ("f11");
3372 case VK_F12: return KEYSYM ("f12");
3373 case VK_F13: return KEYSYM ("f13");
3374 case VK_F14: return KEYSYM ("f14");
3375 case VK_F15: return KEYSYM ("f15");
3376 case VK_F16: return KEYSYM ("f16");
3377 case VK_F17: return KEYSYM ("f17");
3378 case VK_F18: return KEYSYM ("f18");
3379 case VK_F19: return KEYSYM ("f19");
3380 case VK_F20: return KEYSYM ("f20");
3381 case VK_F21: return KEYSYM ("f21");
3382 case VK_F22: return KEYSYM ("f22");
3383 case VK_F23: return KEYSYM ("f23");
3384 case VK_F24: return KEYSYM ("f24");
3391 * Find the console that matches the supplied mswindows window handle
3394 mswindows_find_console (HWND hwnd)
3396 /* We only support one console */
3397 return XCAR (Vconsole_list);
3401 * Find the frame that matches the supplied mswindows window handle
3404 mswindows_find_frame (HWND hwnd)
3406 LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3410 /* We are in progress of frame creation. Return the frame
3411 being created, as it still not remembered in the window
3413 assert (!NILP (Vmswindows_frame_being_created));
3414 return Vmswindows_frame_being_created;
3416 VOID_TO_LISP (f, l);
3421 /************************************************************************/
3423 /************************************************************************/
3426 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3429 EMACS_TIME current_time;
3430 EMACS_GET_TIME (current_time);
3431 EMACS_SUB_TIME (thyme, thyme, current_time);
3432 milliseconds = EMACS_SECS (thyme) * 1000 +
3433 (EMACS_USECS (thyme) + 500) / 1000;
3434 if (milliseconds < 1)
3436 ++mswindows_pending_timers_count;
3437 return SetTimer (NULL, 0, milliseconds,
3438 (TIMERPROC) mswindows_wm_timer_callback);
3442 emacs_mswindows_remove_timeout (int id)
3444 Lisp_Event match_against;
3445 Lisp_Object emacs_event;
3447 if (KillTimer (NULL, id))
3448 --mswindows_pending_timers_count;
3450 /* If there is a dispatch event generated by this
3451 timeout in the queue, we have to remove it too. */
3452 match_against.event_type = timeout_event;
3453 match_against.event.timeout.interval_id = id;
3454 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3455 if (!NILP (emacs_event))
3456 Fdeallocate_event(emacs_event);
3459 /* If `user_p' is false, then return whether there are any win32, timeout,
3460 * or subprocess events pending (that is, whether
3461 * emacs_mswindows_next_event() would return immediately without blocking).
3463 * if `user_p' is true, then return whether there are any *user generated*
3464 * events available (that is, whether there are keyboard or mouse-click
3465 * events ready to be read). This also implies that
3466 * emacs_mswindows_next_event() would not block.
3469 emacs_mswindows_event_pending_p (int user_p)
3471 mswindows_need_event (0);
3472 return (!NILP (mswindows_u_dispatch_event_queue)
3473 || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3477 * Return the next event
3480 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3482 Lisp_Object event, event2;
3484 mswindows_need_event (1);
3486 event = mswindows_dequeue_dispatch_event ();
3487 XSETEVENT (event2, emacs_event);
3488 Fcopy_event (event, event2);
3489 Fdeallocate_event (event);
3493 * Handle a magic event off the dispatch queue.
3496 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3498 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3505 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3506 mswindows_handle_paint (f);
3507 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3514 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3515 struct frame *f = XFRAME (frame);
3516 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3518 struct gcpro gcpro1;
3520 /* On focus change, clear all memory of sticky modifiers
3521 to avoid non-intuitive behavior. */
3522 clear_sticky_modifiers ();
3524 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3526 emacs_handle_focus_change_preliminary (conser);
3527 /* Under X the stuff up to here is done in the X event handler.
3529 emacs_handle_focus_change_final (conser);
3538 Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3539 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3541 Qmap_frame_hook : Qunmap_frame_hook,
3546 /* #### What about Enter & Leave */
3548 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3549 Qmouse_leave_frame_hook, 1, frame);
3557 #ifndef HAVE_MSG_SELECT
3559 get_process_input_waitable (Lisp_Process *process)
3561 Lisp_Object instr, outstr, p;
3562 XSETPROCESS (p, process);
3563 get_process_streams (process, &instr, &outstr);
3564 assert (!NILP (instr));
3565 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3566 return (network_connection_p (p)
3567 ? get_winsock_stream_waitable (XLSTREAM (instr))
3568 : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3570 return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3575 emacs_mswindows_select_process (Lisp_Process *process)
3577 HANDLE hev = get_process_input_waitable (process);
3579 if (!add_waitable_handle (hev))
3580 error ("Too many active processes");
3582 #ifdef HAVE_WIN32_PROCESSES
3585 XSETPROCESS (p, process);
3586 if (!network_connection_p (p))
3588 HANDLE hprocess = get_nt_process_handle (process);
3589 if (!add_waitable_handle (hprocess))
3591 remove_waitable_handle (hev);
3592 error ("Too many active processes");
3600 emacs_mswindows_unselect_process (Lisp_Process *process)
3602 /* Process handle is removed in the event loop as soon
3603 as it is signaled, so don't bother here about it */
3604 HANDLE hev = get_process_input_waitable (process);
3605 remove_waitable_handle (hev);
3607 #endif /* HAVE_MSG_SELECT */
3610 emacs_mswindows_select_console (struct console *con)
3612 #ifdef HAVE_MSG_SELECT
3613 if (CONSOLE_MSWINDOWS_P (con))
3614 return; /* mswindows consoles are automatically selected */
3616 event_stream_unixoid_select_console (con);
3621 emacs_mswindows_unselect_console (struct console *con)
3623 #ifdef HAVE_MSG_SELECT
3624 if (CONSOLE_MSWINDOWS_P (con))
3625 return; /* mswindows consoles are automatically selected */
3627 event_stream_unixoid_unselect_console (con);
3632 emacs_mswindows_quit_p (void)
3634 /* Quit cannot happen in modal loop: all program
3635 input is dedicated to Windows. */
3636 if (mswindows_in_modal_loop)
3639 mswindows_quit_chars_count = 0;
3640 /* Drain windows queue. This sets up number of quit characters in
3642 mswindows_drain_windows_queue ();
3644 if (mswindows_quit_chars_count > 0)
3646 /* Yes there's a hidden one... Throw it away */
3647 Lisp_Event match_against;
3648 Lisp_Object emacs_event;
3651 match_against.event_type = key_press_event;
3652 match_against.event.key.modifiers = FAKE_MOD_QUIT;
3654 while (mswindows_quit_chars_count > 0)
3656 emacs_event = mswindows_cancel_dispatch_event (&match_against);
3657 assert (!NILP (emacs_event));
3659 if (XEVENT (emacs_event)->event.key.modifiers &
3660 FAKE_MOD_QUIT_CRITICAL)
3663 Fdeallocate_event (emacs_event);
3664 mswindows_quit_chars_count--;
3667 Vquit_flag = critical_p ? Qcritical : Qt;
3672 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3673 Lisp_Object* instream,
3674 Lisp_Object* outstream,
3677 /* Handles for streams */
3679 /* fds. These just stored along with the streams, and are closed in
3680 delete stream pair method, because we need to handle fake unices
3684 /* Decode inhandle and outhandle. Their meaning depends on
3685 the process implementation being used. */
3686 #if defined (HAVE_WIN32_PROCESSES)
3687 /* We're passed in Windows handles. That's what we like most... */
3688 hin = (HANDLE) inhandle;
3689 hout = (HANDLE) outhandle;
3691 #elif defined (HAVE_UNIX_PROCESSES)
3692 /* We are passed UNIX fds. This must be Cygwin.
3694 hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3695 hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3699 #error "So, WHICH kind of processes do you want?"
3702 *instream = (hin == INVALID_HANDLE_VALUE
3704 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3705 : flags & STREAM_NETWORK_CONNECTION
3706 ? make_winsock_input_stream ((SOCKET)hin, fdi)
3708 : make_ntpipe_input_stream (hin, fdi));
3710 #ifdef HAVE_WIN32_PROCESSES
3711 *outstream = (hout == INVALID_HANDLE_VALUE
3713 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3714 : flags & STREAM_NETWORK_CONNECTION
3715 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3717 : make_ntpipe_output_stream (hout, fdo));
3718 #elif defined (HAVE_UNIX_PROCESSES)
3719 *outstream = (fdo >= 0
3720 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3723 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3724 /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3725 if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3727 Bufbyte eof_char = get_eof_char (fdo);
3728 int pty_max_bytes = get_pty_max_bytes (fdo);
3729 filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3734 return (NILP (*instream)
3736 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3737 : flags & STREAM_NETWORK_CONNECTION
3738 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3740 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3744 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3745 Lisp_Object outstream)
3747 /* Oh nothing special here for Win32 at all */
3748 #if defined (HAVE_UNIX_PROCESSES)
3749 int in = (NILP(instream)
3751 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3752 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3753 ? get_winsock_stream_param (XLSTREAM (instream))
3755 : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3756 int out = (NILP(outstream) ? -1
3757 : filedesc_stream_fd (XLSTREAM (outstream)));
3761 if (out != in && out >= 0)
3765 return (NILP (instream)
3767 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3768 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3769 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3771 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3775 emacs_mswindows_current_event_timestamp (struct console *c)
3777 return GetTickCount ();
3780 #ifndef HAVE_X_WINDOWS
3781 /* This is called from GC when a process object is about to be freed.
3782 If we've still got pointers to it in this file, we're gonna lose hard.
3785 debug_process_finalization (Lisp_Process *p)
3788 Lisp_Object instr, outstr;
3790 get_process_streams (p, &instr, &outstr);
3791 /* if it still has fds, then it hasn't been killed yet. */
3792 assert (NILP(instr));
3793 assert (NILP(outstr));
3795 /* #### More checks here */
3802 struct mswin_message_debug
3808 #define FROB(val) { val, #val, },
3810 struct mswin_message_debug debug_mswin_messages[] =
3826 FROB (WM_GETTEXTLENGTH)
3829 FROB (WM_QUERYENDSESSION)
3832 FROB (WM_ERASEBKGND)
3833 FROB (WM_SYSCOLORCHANGE)
3834 FROB (WM_ENDSESSION)
3835 FROB (WM_SHOWWINDOW)
3836 FROB (WM_WININICHANGE)
3837 #if(WINVER >= 0x0400)
3838 FROB (WM_SETTINGCHANGE)
3839 #endif /* WINVER >= 0x0400 */
3841 FROB (WM_DEVMODECHANGE)
3842 FROB (WM_ACTIVATEAPP)
3843 FROB (WM_FONTCHANGE)
3844 FROB (WM_TIMECHANGE)
3845 FROB (WM_CANCELMODE)
3847 FROB (WM_MOUSEACTIVATE)
3848 FROB (WM_CHILDACTIVATE)
3851 FROB (WM_GETMINMAXINFO)
3854 FROB (WM_ICONERASEBKGND)
3855 FROB (WM_NEXTDLGCTL)
3856 FROB (WM_SPOOLERSTATUS)
3858 FROB (WM_MEASUREITEM)
3859 FROB (WM_DELETEITEM)
3860 FROB (WM_VKEYTOITEM)
3861 FROB (WM_CHARTOITEM)
3866 FROB (WM_QUERYDRAGICON)
3867 FROB (WM_COMPAREITEM)
3868 #if(WINVER >= 0x0500)
3870 #endif /* WINVER >= 0x0500 */
3871 FROB (WM_COMPACTING)
3872 FROB (WM_COMMNOTIFY)
3873 FROB (WM_WINDOWPOSCHANGING)
3874 FROB (WM_WINDOWPOSCHANGED)
3879 FROB (WM_CANCELJOURNAL)
3881 #if(WINVER >= 0x0400)
3883 FROB (WM_INPUTLANGCHANGEREQUEST)
3884 FROB (WM_INPUTLANGCHANGE)
3887 FROB (WM_USERCHANGED)
3888 FROB (WM_NOTIFYFORMAT)
3890 FROB (WM_CONTEXTMENU)
3891 FROB (WM_STYLECHANGING)
3892 FROB (WM_STYLECHANGED)
3893 FROB (WM_DISPLAYCHANGE)
3896 #endif /* WINVER >= 0x0400 */
3900 FROB (WM_NCCALCSIZE)
3903 FROB (WM_NCACTIVATE)
3904 FROB (WM_GETDLGCODE)
3905 #ifdef WM_SYNCPAINT /* not in VC 5 */
3907 #endif /* WM_SYNCPAINT */
3908 FROB (WM_NCMOUSEMOVE)
3909 FROB (WM_NCLBUTTONDOWN)
3910 FROB (WM_NCLBUTTONUP)
3911 FROB (WM_NCLBUTTONDBLCLK)
3912 FROB (WM_NCRBUTTONDOWN)
3913 FROB (WM_NCRBUTTONUP)
3914 FROB (WM_NCRBUTTONDBLCLK)
3915 FROB (WM_NCMBUTTONDOWN)
3916 FROB (WM_NCMBUTTONUP)
3917 FROB (WM_NCMBUTTONDBLCLK)
3919 /* FROB (WM_KEYFIRST) */
3924 FROB (WM_SYSKEYDOWN)
3927 FROB (WM_SYSDEADCHAR)
3930 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION)
3931 FROB (WM_IME_STARTCOMPOSITION)
3932 FROB (WM_IME_ENDCOMPOSITION)
3933 FROB (WM_IME_COMPOSITION)
3934 FROB (WM_IME_KEYLAST)
3935 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */
3937 FROB (WM_INITDIALOG)
3939 FROB (WM_SYSCOMMAND)
3944 FROB (WM_INITMENUPOPUP)
3945 FROB (WM_MENUSELECT)
3948 #if(WINVER >= 0x0500)
3949 FROB (WM_MENURBUTTONUP)
3951 FROB (WM_MENUGETOBJECT)
3952 FROB (WM_UNINITMENUPOPUP)
3953 FROB (WM_MENUCOMMAND)
3954 #endif /* WINVER >= 0x0500 */
3957 FROB (WM_CTLCOLORMSGBOX)
3958 FROB (WM_CTLCOLOREDIT)
3959 FROB (WM_CTLCOLORLISTBOX)
3960 FROB (WM_CTLCOLORBTN)
3961 FROB (WM_CTLCOLORDLG)
3962 FROB (WM_CTLCOLORSCROLLBAR)
3963 FROB (WM_CTLCOLORSTATIC)
3966 /* FROB (WM_MOUSEFIRST) */
3968 FROB (WM_LBUTTONDOWN)
3970 FROB (WM_LBUTTONDBLCLK)
3971 FROB (WM_RBUTTONDOWN)
3973 FROB (WM_RBUTTONDBLCLK)
3974 FROB (WM_MBUTTONDOWN)
3976 FROB (WM_MBUTTONDBLCLK)
3978 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
3979 FROB (WM_MOUSEWHEEL)
3983 #endif /* if (_WIN32_WINNT < 0x0400) */
3985 FROB (WM_PARENTNOTIFY)
3986 FROB (WM_ENTERMENULOOP)
3987 FROB (WM_EXITMENULOOP)
3989 #if(WINVER >= 0x0400)
3993 FROB (WM_CAPTURECHANGED)
3995 FROB (WM_POWERBROADCAST)
3997 FROB (WM_DEVICECHANGE)
3999 #endif /* WINVER >= 0x0400 */
4002 FROB (WM_MDIDESTROY)
4003 FROB (WM_MDIACTIVATE)
4004 FROB (WM_MDIRESTORE)
4006 FROB (WM_MDIMAXIMIZE)
4008 FROB (WM_MDICASCADE)
4009 FROB (WM_MDIICONARRANGE)
4010 FROB (WM_MDIGETACTIVE)
4013 FROB (WM_MDISETMENU)
4014 FROB (WM_ENTERSIZEMOVE)
4015 FROB (WM_EXITSIZEMOVE)
4017 FROB (WM_MDIREFRESHMENU)
4019 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */
4021 #if(WINVER >= 0x0400) && !defined(CYGWIN)
4022 FROB (WM_IME_SETCONTEXT)
4023 FROB (WM_IME_NOTIFY)
4024 FROB (WM_IME_CONTROL)
4025 FROB (WM_IME_COMPOSITIONFULL)
4026 FROB (WM_IME_SELECT)
4028 #endif /* WINVER >= 0x0400 */
4029 #if(WINVER >= 0x0500)
4030 FROB (WM_IME_REQUEST)
4031 #endif /* WINVER >= 0x0500 */
4032 #if(WINVER >= 0x0400) && !defined(CYGWIN)
4033 FROB (WM_IME_KEYDOWN)
4035 #endif /* WINVER >= 0x0400 */
4037 #endif /* WM_IME_SETCONTEXT */
4039 #if(_WIN32_WINNT >= 0x0400)
4040 FROB (WM_MOUSEHOVER)
4041 FROB (WM_MOUSELEAVE)
4042 #endif /* _WIN32_WINNT >= 0x0400 */
4049 FROB (WM_RENDERFORMAT)
4050 FROB (WM_RENDERALLFORMATS)
4051 FROB (WM_DESTROYCLIPBOARD)
4052 FROB (WM_DRAWCLIPBOARD)
4053 FROB (WM_PAINTCLIPBOARD)
4054 FROB (WM_VSCROLLCLIPBOARD)
4055 FROB (WM_SIZECLIPBOARD)
4056 FROB (WM_ASKCBFORMATNAME)
4057 FROB (WM_CHANGECBCHAIN)
4058 FROB (WM_HSCROLLCLIPBOARD)
4059 FROB (WM_QUERYNEWPALETTE)
4060 FROB (WM_PALETTEISCHANGING)
4061 FROB (WM_PALETTECHANGED)
4064 #if(WINVER >= 0x0400)
4066 FROB (WM_PRINTCLIENT)
4068 FROB (WM_HANDHELDFIRST)
4069 FROB (WM_HANDHELDLAST)
4073 #endif /* WINVER >= 0x0400 */
4075 FROB (WM_PENWINFIRST)
4076 FROB (WM_PENWINLAST)
4082 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
4085 Lisp_Object frame = mswindows_find_frame (hwnd);
4088 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */
4090 for (i = 0; i < countof (debug_mswin_messages); i++)
4092 if (debug_mswin_messages[i].mess == message_)
4094 str = debug_mswin_messages[i].string;
4100 stderr_out ("%s", str);
4102 stderr_out ("%x", message_);
4104 if (debug_mswindows_events > 1)
4106 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
4107 wParam, (int) lParam, (unsigned int) hwnd);
4108 debug_print (frame);
4109 if (message_ == WM_WINDOWPOSCHANGED ||
4110 message_ == WM_WINDOWPOSCHANGING)
4112 WINDOWPOS *wp = (WINDOWPOS *) lParam;
4113 stderr_out(" WINDOWPOS: x=%d, y=%d, h=%d, w=%d\n",
4114 wp->x, wp->y, wp->cx, wp->cy);
4116 else if (message_ == WM_MOVE)
4118 int x = (int)(short) LOWORD(lParam); /* horizontal position */
4119 int y = (int)(short) HIWORD(lParam); /* vertical position */
4120 stderr_out(" MOVE: x=%d, y=%d\n", x, y);
4122 else if (message_ == WM_SIZE)
4124 int w = (int)(short) LOWORD(lParam); /* width */
4125 int h = (int)(short) HIWORD(lParam); /* height */
4126 stderr_out(" SIZE: w=%d, h=%d\n", w, h);
4133 #endif /* DEBUG_XEMACS */
4135 /************************************************************************/
4136 /* initialization */
4137 /************************************************************************/
4140 reinit_vars_of_event_mswindows (void)
4142 mswindows_in_modal_loop = 0;
4143 mswindows_pending_timers_count = 0;
4145 mswindows_event_stream = xnew (struct event_stream);
4147 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
4148 mswindows_event_stream->force_event_pending = 0;
4149 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event;
4150 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
4151 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
4152 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
4153 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p;
4154 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
4155 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
4156 #ifdef HAVE_MSG_SELECT
4157 mswindows_event_stream->select_process_cb =
4158 (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
4159 mswindows_event_stream->unselect_process_cb =
4160 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
4161 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
4162 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
4164 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
4165 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
4166 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
4167 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
4169 mswindows_event_stream->current_event_timestamp_cb =
4170 emacs_mswindows_current_event_timestamp;
4174 vars_of_event_mswindows (void)
4176 reinit_vars_of_event_mswindows ();
4178 mswindows_u_dispatch_event_queue = Qnil;
4179 staticpro (&mswindows_u_dispatch_event_queue);
4180 mswindows_u_dispatch_event_queue_tail = Qnil;
4181 dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
4183 mswindows_s_dispatch_event_queue = Qnil;
4184 staticpro (&mswindows_s_dispatch_event_queue);
4185 mswindows_s_dispatch_event_queue_tail = Qnil;
4186 dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
4188 mswindows_error_caught_in_modal_loop = Qnil;
4189 staticpro (&mswindows_error_caught_in_modal_loop);
4193 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
4194 If non-zero, display debug information about Windows messages that XEmacs sees.
4195 Information is displayed in a console window. Currently defined values are:
4197 1 == non-verbose output (just the message name)
4198 2 == verbose output (all parameters)
4199 3 == even more verbose output (extra debugging info)
4201 debug_mswindows_events = 0;
4204 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
4205 &mswindows_alt_by_itself_activates_menu /*
4206 *Controls whether pressing and releasing the Alt key activates the menubar.
4207 This applies only if no intervening key was pressed. See also
4208 `menu-accelerator-enabled', which is probably the behavior you actually want.
4212 DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
4213 &mswindows_dynamic_frame_resize /*
4214 *Controls redrawing frame contents during mouse-drag or keyboard resize
4215 operation. When non-nil, the frame is redrawn while being resized. When
4216 nil, frame is not redrawn, and exposed areas are filled with default
4217 MDI application background color. Note that this option only has effect
4218 if "Show window contents while dragging" is on in system Display/Plus!
4220 Default is t on fast machines, nil on slow.
4223 DEFVAR_INT ("mswindows-mouse-button-tolerance",
4224 &mswindows_mouse_button_tolerance /*
4225 *Analogue of double click interval for faking middle mouse events.
4226 The value is the minimum time in milliseconds that must elapse between
4227 left/right button down events before they are considered distinct events.
4228 If both mouse buttons are depressed within this interval, a middle mouse
4229 button down event is generated instead.
4230 If negative or zero, currently set system default is used instead.
4233 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
4234 Number of physical mouse buttons.
4237 DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
4238 &mswindows_mouse_button_max_skew_x /*
4239 *Maximum horizontal distance in pixels between points in which left and
4240 right button clicks occurred for them to be translated into single
4241 middle button event. Clicks must occur in time not longer than defined
4242 by the variable `mswindows-mouse-button-tolerance'.
4243 If negative or zero, currently set system default is used instead.
4246 DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
4247 &mswindows_mouse_button_max_skew_y /*
4248 *Maximum vertical distance in pixels between points in which left and
4249 right button clicks occurred for them to be translated into single
4250 middle button event. Clicks must occur in time not longer than defined
4251 by the variable `mswindows-mouse-button-tolerance'.
4252 If negative or zero, currently set system default is used instead.
4255 mswindows_mouse_button_max_skew_x = 0;
4256 mswindows_mouse_button_max_skew_y = 0;
4257 mswindows_mouse_button_tolerance = 0;
4258 mswindows_alt_by_itself_activates_menu = 1;
4262 syms_of_event_mswindows (void)
4267 lstream_type_create_mswindows_selectable (void)
4269 init_slurp_stream ();
4270 init_shove_stream ();
4271 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
4272 init_winsock_stream ();
4277 init_event_mswindows_late (void)
4279 #ifdef HAVE_MSG_SELECT
4280 windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
4281 assert (windows_fd>=0);
4282 FD_SET (windows_fd, &input_wait_mask);
4283 FD_ZERO(&zero_mask);
4286 event_stream = mswindows_event_stream;
4288 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
4289 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);