(g2-UU+928B): Add `ideographic-structure'.
[chise/xemacs-chise.git-] / src / event-msw.c
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.
6
7 This file is part of XEmacs.
8
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
12 later version.
13
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
17 for more details.
18
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.  */
23
24 /* Synched up with: Not in FSF. */
25
26 /* Authorship:
27
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.
32  */
33
34 #include <config.h>
35 #include "lisp.h"
36
37 #include "console-msw.h"
38
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
41 #endif
42
43 #ifdef HAVE_MENUBARS
44 # include "menubar.h"
45 # include "menubar-msw.h"
46 #endif
47
48 #ifdef HAVE_DRAGNDROP
49 # include "dragdrop.h"
50 #endif
51
52 #include "buffer.h"
53 #include "device.h"
54 #include "events.h"
55 #include "faces.h"
56 #include "frame.h"
57 #include "lstream.h"
58 #include "objects-msw.h"
59 #include "process.h"
60 #include "redisplay.h"
61 #include "select.h"
62 #include "sysdep.h"
63 #include "window.h"
64
65 #include "sysfile.h"
66 #include "sysproc.h"
67 #include "systime.h"
68 #include "syswait.h"
69
70 #include "events-mod.h"
71
72 #ifdef HAVE_MSG_SELECT
73 #include "console-tty.h"
74 #elif defined(CYGWIN)
75 typedef unsigned int SOCKET;
76 #endif
77
78 #if !(defined(CYGWIN) || defined(MINGW))
79 # include <shlobj.h>    /* For IShellLink */
80 #endif
81
82 #ifdef HAVE_MENUBARS
83 #define ADJR_MENUFLAG TRUE
84 #else
85 #define ADJR_MENUFLAG FALSE
86 #endif
87
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)
92
93 /* Timer ID used for button2 emulation */
94 #define BUTTON_2_TIMER_ID 1
95
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,
99                                                   int extendedp);
100 static int mswindows_modifier_state (BYTE* keymap, DWORD fwKeys,
101                                      int has_AltGr);
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);
107
108 static struct event_stream *mswindows_event_stream;
109
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;
115 int windows_fd;
116 #endif
117
118 /*
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
122  * one.
123  */
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;
126
127 /* The number of things we can wait on */
128 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1)
129
130 #ifndef HAVE_MSG_SELECT
131 /* List of mswindows waitable handles. */
132 static HANDLE mswindows_waitable_handles[MAX_WAITABLE];
133
134 /* Number of wait handles */
135 static int mswindows_waitable_count=0;
136 #endif /* HAVE_MSG_SELECT */
137
138 /* Brush for painting widgets */
139 static HBRUSH widget_brush = 0;
140 static LONG     last_widget_brushed = 0;
141
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;
146
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;
154
155 #ifdef DEBUG_XEMACS
156 Fixnum debug_mswindows_events;
157
158 static void debug_output_mswin_message (HWND hwnd, UINT message_,
159                                         WPARAM wParam, LPARAM lParam);
160 #endif
161
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;
166
167 /* Count of wound timers */
168 static int mswindows_pending_timers_count;
169
170 static DWORD mswindows_last_mouse_button_state;
171 \f
172 /************************************************************************/
173 /*                Pipe instream - reads process output                  */
174 /************************************************************************/
175
176 #define PIPE_READ_DELAY 20
177
178 #define HANDLE_TO_USID(h) ((USID)(h))
179
180 #define NTPIPE_SLURP_STREAM_DATA(stream) \
181   LSTREAM_TYPE_DATA (stream, ntpipe_slurp)
182
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. */
193
194 struct ntpipe_slurp_stream_shared_data
195 {
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                */
209 };
210
211 #define MAX_SLURP_STREAMS 32
212 struct ntpipe_slurp_stream_shared_data
213 shared_data_block[MAX_SLURP_STREAMS]={{0}};
214
215 struct ntpipe_slurp_stream
216 {
217   LPARAM user_data;     /* Any user data stored in the stream object     */
218   struct ntpipe_slurp_stream_shared_data* thread_data;
219 };
220
221 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", lstream_ntpipe_slurp,
222                                sizeof (struct ntpipe_slurp_stream));
223
224 /* This function is thread-safe, and is called from either thread
225    context. It serializes freeing shared data structure */
226 static void
227 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data* s)
228 {
229   if (InterlockedDecrement (&s->lock_count) == 0)
230     {
231       /* Destroy events */
232       CloseHandle (s->hev_thread);
233       CloseHandle (s->hev_caller);
234       CloseHandle (s->hev_unsleep);
235       CloseHandle (s->hpipe);
236       s->inuse_p = 0;
237     }
238 }
239
240 static struct ntpipe_slurp_stream_shared_data*
241 slurper_allocate_shared_data (void)
242 {
243   int i=0;
244   for (i=0; i<MAX_SLURP_STREAMS; i++)
245     {
246       if (!shared_data_block[i].inuse_p)
247         {
248           shared_data_block[i].inuse_p=1;
249           return &shared_data_block[i];
250         }
251     }
252   return (struct ntpipe_slurp_stream_shared_data*)0;
253 }
254
255 static DWORD WINAPI
256 slurp_thread (LPVOID vparam)
257 {
258   struct ntpipe_slurp_stream_shared_data *s =
259     (struct ntpipe_slurp_stream_shared_data*)vparam;
260
261   for (;;)
262     {
263       /* Read one byte from the pipe */
264       DWORD actually_read;
265       if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL))
266         {
267           DWORD err = GetLastError ();
268           if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA)
269             s->eof_p = TRUE;
270           else
271             s->error_p = TRUE;
272         }
273       else if (actually_read == 0)
274         s->eof_p = TRUE;
275
276       /* We must terminate on an error or eof */
277       if (s->eof_p || s->error_p)
278         InterlockedIncrement (&s->die_p);
279
280       /* Before we notify caller, we unsignal our event. */
281       ResetEvent (s->hev_thread);
282
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
288          immediately. */
289       if (!s->die_p)
290         WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY);
291
292       /* Either make event loop generate a process event, or
293          inblock reader */
294       SetEvent (s->hev_caller);
295
296       /* Cleanup and exit if we're shot off */
297       if (s->die_p)
298         break;
299
300       /* Block until the client finishes with retrieving the rest of
301          pipe data */
302       WaitForSingleObject (s->hev_thread, INFINITE);
303     }
304
305   slurper_free_shared_data_maybe (s);
306
307   return 0;
308 }
309
310 static Lisp_Object
311 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param)
312 {
313   Lisp_Object obj;
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;
317   HANDLE hthread;
318
319   /* We deal only with pipes, for we're using PeekNamedPipe api */
320   assert (GetFileType (hpipe) == FILE_TYPE_PIPE);
321
322   s->thread_data = slurper_allocate_shared_data();
323
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);
328   if (hthread == NULL)
329     {
330       Lstream_delete (lstr);
331       s->thread_data->inuse_p=0;
332       return Qnil;
333     }
334
335   /* Shared data are initially owned by both main and slurper
336      threads. */
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;
343
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);
350
351   /* Now let it go */
352   ResumeThread (hthread);
353   CloseHandle (hthread);
354
355   lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
356   XSETLSTREAM (obj, lstr);
357   return obj;
358 }
359
360 static LPARAM
361 get_ntpipe_input_stream_param (Lstream *stream)
362 {
363   struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
364   return s->user_data;
365 }
366
367 static HANDLE
368 get_ntpipe_input_stream_waitable (Lstream *stream)
369 {
370   struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream);
371   return s->thread_data->hev_caller;
372 }
373
374 static Lstream_data_count
375 ntpipe_slurp_reader (Lstream *stream, unsigned char *data,
376                      Lstream_data_count size)
377 {
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;
381
382   if (!s->die_p)
383     {
384       DWORD wait_result;
385       /* Disallow pipe read delay for the thread: we need a character
386          ASAP */
387       SetEvent (s->hev_unsleep);
388
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);
392
393       /* Revert to the normal sleep behavior. */
394       ResetEvent (s->hev_unsleep);
395
396       /* If there's no byte buffered yet, give up */
397       if (wait_result == WAIT_TIMEOUT)
398         {
399           errno = EAGAIN;
400           return -1;
401         }
402     }
403
404   /* Reset caller unlock event now, as we've handled the pending
405      process output event */
406   ResetEvent (s->hev_caller);
407
408   /* It is now safe to do anything with contents of S, except for
409      changing s->die_p, which still should be interlocked */
410
411   if (s->eof_p)
412     return 0;
413   if (s->error_p || s->die_p)
414     return -1;
415
416   /* Ok, there were no error neither eof - we've got a byte from the
417      pipe */
418   *(data++) = s->onebyte;
419   --size;
420
421   {
422     DWORD bytes_read = 0;
423     if (size > 0)
424       {
425         DWORD bytes_available;
426
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))
430           {
431
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. */
435             if (bytes_available)
436               ReadFile (s->hpipe, data, min (bytes_available, size),
437                         &bytes_read, NULL);
438           }
439
440         /* Now we can unblock thread, so it attempts to read more */
441         SetEvent (s->hev_thread);
442         return bytes_read + 1;
443       }
444   }
445   return 0;
446 }
447
448 static int
449 ntpipe_slurp_closer (Lstream *stream)
450 {
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;
454
455   /* Force thread to stop */
456   InterlockedIncrement (&s->die_p);
457
458   /* Set events which could possibly block slurper. Let it finish soon
459      or later. */
460   SetEvent (s->hev_unsleep);
461   SetEvent (s->hev_thread);
462
463   /* Unlock and maybe free shared data */
464   slurper_free_shared_data_maybe (s);
465
466   return 0;
467 }
468
469 static void
470 init_slurp_stream (void)
471 {
472   LSTREAM_HAS_METHOD (ntpipe_slurp, reader);
473   LSTREAM_HAS_METHOD (ntpipe_slurp, closer);
474 }
475 \f
476 /************************************************************************/
477 /*                Pipe outstream - writes process input                 */
478 /************************************************************************/
479
480 #define NTPIPE_SHOVE_STREAM_DATA(stream) \
481   LSTREAM_TYPE_DATA (stream, ntpipe_shove)
482
483 #define MAX_SHOVE_BUFFER_SIZE 512
484
485 struct ntpipe_shove_stream
486 {
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       */
498 };
499
500 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", lstream_ntpipe_shove,
501                                sizeof (struct ntpipe_shove_stream));
502
503 #ifndef HAVE_MSG_SELECT
504 static DWORD WINAPI
505 shove_thread (LPVOID vparam)
506 {
507   struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam;
508
509   for (;;)
510     {
511       DWORD bytes_written;
512
513       /* Block on event and wait for a job */
514       InterlockedIncrement (&s->idle_p);
515       WaitForSingleObject (s->hev_thread, INFINITE);
516
517       /* Write passed buffer if any */
518       if (s->size > 0)
519         {
520          if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL)
521              || bytes_written != s->size)
522            {
523              s->error_p = TRUE;
524              InterlockedIncrement (&s->die_p);
525            }
526          /* Set size to zero so we won't write it again if the closer sets
527             die_p and kicks us */
528          s->size = 0;
529         }
530
531       if (s->die_p)
532         break;
533     }
534
535   return 0;
536 }
537
538 static Lisp_Object
539 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param)
540 {
541   Lisp_Object obj;
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;
545
546   s->die_p = 0;
547   s->error_p = FALSE;
548   s->hpipe = hpipe;
549   s->user_data = param;
550
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)
556     {
557       Lstream_delete (lstr);
558       return Qnil;
559     }
560
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))
564     {
565       CloseHandle (s->hthread);
566       Lstream_delete (lstr);
567       return Qnil;
568     }
569
570   /* hev_thread is an auto-reset event, initially nonsignaled */
571   s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL);
572
573   /* Now let it go */
574   ResumeThread (s->hthread);
575
576   lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
577   XSETLSTREAM (obj, lstr);
578   return obj;
579 }
580
581 static LPARAM
582 get_ntpipe_output_stream_param (Lstream *stream)
583 {
584   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
585   return s->user_data;
586 }
587 #endif
588
589 static Lstream_data_count
590 ntpipe_shove_writer (Lstream *stream, const unsigned char *data,
591                      Lstream_data_count size)
592 {
593   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
594
595   if (s->error_p)
596     return -1;
597
598   s->blocking_p = !s->idle_p;
599   if (s->blocking_p)
600     return 0;
601
602   if (size>MAX_SHOVE_BUFFER_SIZE)
603     return 0;
604
605   memcpy (s->buffer, data, size);
606   s->size = size;
607
608   /* Start output */
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 ();
615   return size;
616 }
617
618 static int
619 ntpipe_shove_was_blocked_p (Lstream *stream)
620 {
621   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
622   return s->blocking_p;
623 }
624
625 static int
626 ntpipe_shove_closer (Lstream *stream)
627 {
628   struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream);
629
630   /* Force thread stop */
631   InterlockedIncrement (&s->die_p);
632
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
635      pending output. */
636   SetEvent (s->hev_thread);
637
638   /* Wait while thread terminates */
639   WaitForSingleObject (s->hthread, INFINITE);
640
641   /* Close pipe handle, possibly breaking it */
642   CloseHandle (s->hpipe);
643
644   /* Close the thread handle */
645   CloseHandle (s->hthread);
646
647   /* Destroy the event */
648   CloseHandle (s->hev_thread);
649
650   return 0;
651 }
652
653 static void
654 init_shove_stream (void)
655 {
656   LSTREAM_HAS_METHOD (ntpipe_shove, writer);
657   LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p);
658   LSTREAM_HAS_METHOD (ntpipe_shove, closer);
659 }
660 \f
661 /************************************************************************/
662 /*                         Winsock I/O stream                           */
663 /************************************************************************/
664 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
665
666 #define WINSOCK_READ_BUFFER_SIZE 1024
667
668 struct winsock_stream
669 {
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            */
680 };
681
682 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock)
683
684 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", lstream_winsock,
685                                sizeof (struct winsock_stream));
686
687 static void
688 winsock_initiate_read (struct winsock_stream *str)
689 {
690   ResetEvent (str->ov.hEvent);
691   str->bufpos = 0;
692
693   if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE,
694                  &str->bufsize, &str->ov))
695     {
696       if (GetLastError () == ERROR_IO_PENDING)
697         str->pending_p = 1;
698       else if (GetLastError () == ERROR_HANDLE_EOF)
699         str->eof_p = 1;
700       else
701         str->error_p = 1;
702     }
703   else if (str->bufsize == 0)
704     str->eof_p = 1;
705 }
706
707 static Lstream_data_count
708 winsock_reader (Lstream *stream, unsigned char *data, Lstream_data_count size)
709 {
710   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
711
712   /* If the current operation is not yet complete, there's nothing to
713      give back */
714   if (str->pending_p)
715     {
716       if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
717         {
718           errno = EAGAIN;
719           return -1;
720         }
721       else
722         {
723           if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, TRUE))
724             {
725               if (GetLastError() == ERROR_HANDLE_EOF)
726                 str->bufsize = 0;
727               else
728                 str->error_p = 1;
729             }
730           if (str->bufsize == 0)
731             str->eof_p = 1;
732           str->pending_p = 0;
733         }
734     }
735
736   if (str->eof_p)
737     return 0;
738   if (str->error_p)
739     return -1;
740
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);
744   str->bufpos += size;
745
746   /* Read more if buffer is exhausted */
747   if (str->bufsize == str->bufpos)
748     winsock_initiate_read (str);
749
750   return size;
751 }
752
753 static Lstream_data_count
754 winsock_writer (Lstream *stream, const unsigned char *data,
755                 Lstream_data_count size)
756 {
757   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
758
759   if (str->pending_p)
760     {
761       if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT)
762         {
763           str->blocking_p = 1;
764           return -1;
765         }
766       else
767         {
768           DWORD dw_unused;
769           if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, TRUE))
770             str->error_p = 1;
771           str->pending_p = 0;
772         }
773     }
774
775   str->blocking_p = 0;
776
777   if (str->error_p)
778     return -1;
779
780   if (size == 0)
781     return 0;
782
783   ResetEvent (str->ov.hEvent);
784
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);
791
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,
796                  &str->ov)
797       || GetLastError() == ERROR_IO_PENDING)
798     str->pending_p = 1;
799   else
800     str->error_p = 1;
801
802   return str->error_p ? -1 : size;
803 }
804
805 static int
806 winsock_closer (Lstream *lstr)
807 {
808   struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
809
810   if (lstr->flags & LSTREAM_FL_READ)
811     shutdown (str->s, 0);
812   else
813     shutdown (str->s, 1);
814
815   closesocket (str->s);
816   if (str->pending_p)
817     WaitForSingleObject (str->ov.hEvent, INFINITE);
818
819   if (str->buffer)
820     {
821       xfree (str->buffer);
822       str->buffer = 0;
823     }
824
825   CloseHandle (str->ov.hEvent);
826   return 0;
827 }
828
829 static int
830 winsock_was_blocked_p (Lstream *stream)
831 {
832   struct winsock_stream *str = WINSOCK_STREAM_DATA (stream);
833   return str->blocking_p;
834 }
835
836 static Lisp_Object
837 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode)
838 {
839   Lisp_Object obj;
840   Lstream *lstr = Lstream_new (lstream_winsock, mode);
841   struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
842
843   xzero (*str);
844   str->s = s;
845   str->user_data = param;
846
847   str->ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
848
849   if (lstr->flags & LSTREAM_FL_READ)
850     {
851       str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE);
852       winsock_initiate_read (str);
853     }
854
855   lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE;
856   XSETLSTREAM (obj, lstr);
857   return obj;
858 }
859
860 static Lisp_Object
861 make_winsock_input_stream (SOCKET s, LPARAM param)
862 {
863   return make_winsock_stream_1 (s, param, "r");
864 }
865
866 static Lisp_Object
867 make_winsock_output_stream (SOCKET s, LPARAM param)
868 {
869   return make_winsock_stream_1 (s, param, "w");
870 }
871
872 static HANDLE
873 get_winsock_stream_waitable (Lstream *lstr)
874 {
875   struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
876   return str->ov.hEvent;
877 }
878
879 static LPARAM
880 get_winsock_stream_param (Lstream *lstr)
881 {
882   struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr);
883   return str->user_data;
884 }
885
886 static void
887 init_winsock_stream (void)
888 {
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);
893 }
894 #endif /* defined (HAVE_SOCKETS) */
895 \f
896 /************************************************************************/
897 /*                     Dispatch queue management                        */
898 /************************************************************************/
899
900 static int
901 mswindows_user_event_p (Lisp_Event* sevt)
902 {
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);
907 }
908
909 /*
910  * Add an emacs event to the proper dispatch queue
911  */
912 void
913 mswindows_enqueue_dispatch_event (Lisp_Object event)
914 {
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);
921
922   /* Avoid blocking on WaitMessage */
923   PostMessage (NULL, XM_BUMPQUEUE, 0, 0);
924 }
925
926 /*
927  * Add a misc-user event to the dispatch queue.
928  *
929  * Stuff it into our own dispatch queue, so we have something
930  * to return from next_event callback.
931  */
932 void
933 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function,
934                                    Lisp_Object object)
935 {
936   Lisp_Object event = Fmake_event (Qnil, Qnil);
937   Lisp_Event* e = XEVENT (event);
938
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;
944
945   mswindows_enqueue_dispatch_event (event);
946 }
947
948 void
949 mswindows_enqueue_magic_event (HWND hwnd, UINT msg)
950 {
951   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
952   Lisp_Event* event = XEVENT (emacs_event);
953
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;
958
959   mswindows_enqueue_dispatch_event (emacs_event);
960 }
961
962 static void
963 mswindows_enqueue_process_event (Lisp_Process* p)
964 {
965   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
966   Lisp_Event* event = XEVENT (emacs_event);
967   Lisp_Object process;
968   XSETPROCESS (process, p);
969
970   event->event_type = process_event;
971   event->timestamp  = GetTickCount ();
972   event->event.process.process = process;
973
974   mswindows_enqueue_dispatch_event (emacs_event);
975 }
976
977 static void
978 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where,
979                                       int mods, DWORD when)
980 {
981   int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN ||
982                msg == WM_RBUTTONDOWN);
983
984   /* Wheel rotation amount: positive is away from user, negative towards user */
985   int delta = (short) HIWORD (mods);
986   
987   /* We always use last message time, because mouse button
988      events may get delayed, and XEmacs double click
989      recognition will fail */
990
991   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
992   Lisp_Event* event = XEVENT (emacs_event);
993
994   mswindows_handle_sticky_modifiers (0, 0, downp, 0);
995   event->channel = mswindows_find_frame (hwnd);
996   event->timestamp = when;
997   event->event.button.button =
998     (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 :
999     (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONUP) ? 2 :
1000     (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 :
1001     (msg==WM_MOUSEWHEEL && delta>0) ? 4 : 5;
1002   event->event.button.x = where.x;
1003   event->event.button.y = where.y;
1004   event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0);
1005
1006   if (downp)
1007     {
1008       event->event_type = button_press_event;
1009       SetCapture (hwnd);
1010       /* we need this to make sure the main window regains the focus
1011          from control subwindows */
1012       if (GetFocus() != hwnd)
1013         {
1014           SetFocus (hwnd);
1015           mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS);
1016         }
1017     }
1018   else
1019     {
1020       event->event_type = button_release_event;
1021       ReleaseCapture ();
1022     }
1023
1024   mswindows_enqueue_dispatch_event (emacs_event);
1025 }
1026
1027 static void
1028 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods)
1029 {
1030   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1031   Lisp_Event* event = XEVENT(emacs_event);
1032
1033   event->channel = mswindows_find_console(hwnd);
1034   event->timestamp = GetMessageTime();
1035   event->event_type = key_press_event;
1036   event->event.key.keysym = keysym;
1037   event->event.key.modifiers = mods;
1038   mswindows_enqueue_dispatch_event (emacs_event);
1039 }
1040
1041 /*
1042  * Remove and return the first emacs event on the dispatch queue.
1043  * Give a preference to user events over non-user ones.
1044  */
1045 static Lisp_Object
1046 mswindows_dequeue_dispatch_event (void)
1047 {
1048   Lisp_Object event;
1049   Lisp_Event* sevt;
1050
1051   assert (!NILP(mswindows_u_dispatch_event_queue) ||
1052           !NILP(mswindows_s_dispatch_event_queue));
1053
1054   event = dequeue_event (
1055                          NILP(mswindows_u_dispatch_event_queue) ?
1056                          &mswindows_s_dispatch_event_queue :
1057                          &mswindows_u_dispatch_event_queue,
1058                          NILP(mswindows_u_dispatch_event_queue) ?
1059                          &mswindows_s_dispatch_event_queue_tail :
1060                          &mswindows_u_dispatch_event_queue_tail);
1061
1062   sevt = XEVENT (event);
1063   if (sevt->event_type == key_press_event
1064       && (sevt->event.key.modifiers & FAKE_MOD_QUIT))
1065     sevt->event.key.modifiers &=
1066       ~(FAKE_MOD_QUIT | FAKE_MOD_QUIT_CRITICAL);
1067
1068   return event;
1069 }
1070
1071 /*
1072  * Remove and return the first emacs event on the dispatch queue that matches
1073  * the supplied event.
1074  * Timeout event matches if interval_id is equal to that of the given event.
1075  * Keypress event matches if logical AND between modifiers bitmask of the
1076  * event in the queue and that of the given event is non-zero.
1077  * For all other event types, this function ABORTs.
1078  */
1079
1080 Lisp_Object
1081 mswindows_cancel_dispatch_event (Lisp_Event *match)
1082 {
1083   Lisp_Object event;
1084   Lisp_Object previous_event = Qnil;
1085   int user_p = mswindows_user_event_p (match);
1086   Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue :
1087     &mswindows_s_dispatch_event_queue;
1088   Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail :
1089     &mswindows_s_dispatch_event_queue_tail;
1090
1091   assert (match->event_type == timeout_event
1092           || match->event_type == key_press_event);
1093
1094   EVENT_CHAIN_LOOP (event, *head)
1095     {
1096       Lisp_Event *e = XEVENT (event);
1097       if ((e->event_type == match->event_type) &&
1098           ((e->event_type == timeout_event) ?
1099            (e->event.timeout.interval_id == match->event.timeout.interval_id) :
1100            /* Must be key_press_event */
1101            ((e->event.key.modifiers & match->event.key.modifiers) != 0)))
1102         {
1103           if (NILP (previous_event))
1104             dequeue_event (head, tail);
1105           else
1106             {
1107               XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event));
1108               if (EQ (*tail, event))
1109                 *tail = previous_event;
1110             }
1111
1112           return event;
1113         }
1114       previous_event = event;
1115     }
1116   return Qnil;
1117 }
1118 \f
1119 #ifndef HAVE_MSG_SELECT
1120 /************************************************************************/
1121 /*                     Waitable handles manipulation                    */
1122 /************************************************************************/
1123 static int
1124 find_waitable_handle (HANDLE h)
1125 {
1126   int i;
1127   for (i = 0; i < mswindows_waitable_count; ++i)
1128     if (mswindows_waitable_handles[i] == h)
1129       return i;
1130
1131   return -1;
1132 }
1133
1134 static BOOL
1135 add_waitable_handle (HANDLE h)
1136 {
1137   assert (find_waitable_handle (h) < 0);
1138   if (mswindows_waitable_count == MAX_WAITABLE)
1139     return FALSE;
1140
1141   mswindows_waitable_handles [mswindows_waitable_count++] = h;
1142   return TRUE;
1143 }
1144
1145 static void
1146 remove_waitable_handle (HANDLE h)
1147 {
1148   int ix = find_waitable_handle (h);
1149   if (ix < 0)
1150     return;
1151
1152   mswindows_waitable_handles [ix] =
1153     mswindows_waitable_handles [--mswindows_waitable_count];
1154 }
1155 #endif /* HAVE_MSG_SELECT */
1156
1157 /*
1158  * Given a lisp process pointer remove the corresponding process handle
1159  * from mswindows_waitable_handles if it is in it.  Normally the handle is
1160  * removed when the process terminates, but if the lisp process structure
1161  * is deleted before the process terminates we must delete the process
1162  * handle since it will be invalid and will cause the wait to fail
1163  */
1164 void
1165 mswindows_unwait_process (Lisp_Process *p)
1166 {
1167 #ifndef HAVE_MSG_SELECT
1168   remove_waitable_handle (get_nt_process_handle (p));
1169 #endif /* HAVE_MSG_SELECT */
1170 }
1171
1172 \f
1173 /************************************************************************/
1174 /*                             Event pump                               */
1175 /************************************************************************/
1176
1177 static Lisp_Object
1178 mswindows_modal_loop_error_handler (Lisp_Object cons_sig_data,
1179                                     Lisp_Object u_n_u_s_e_d)
1180 {
1181   mswindows_error_caught_in_modal_loop = cons_sig_data;
1182   return Qunbound;
1183 }
1184
1185 Lisp_Object
1186 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg),
1187                               Lisp_Object barg)
1188 {
1189   Lisp_Object tmp;
1190
1191   ++mswindows_in_modal_loop;
1192   tmp = condition_case_1 (Qt,
1193                           bfun, barg,
1194                           mswindows_modal_loop_error_handler, Qnil);
1195   --mswindows_in_modal_loop;
1196
1197   return tmp;
1198 }
1199
1200 void
1201 mswindows_unmodalize_signal_maybe (void)
1202 {
1203   if (!NILP (mswindows_error_caught_in_modal_loop))
1204     {
1205       /* Got an error while messages were pumped while
1206          in window procedure - have to resignal */
1207       Lisp_Object sym = XCAR (mswindows_error_caught_in_modal_loop);
1208       Lisp_Object data = XCDR (mswindows_error_caught_in_modal_loop);
1209       mswindows_error_caught_in_modal_loop = Qnil;
1210       Fsignal (sym, data);
1211     }
1212 }
1213
1214 /*
1215  * This is an unsafe part of event pump, guarded by
1216  * condition_case. See mswindows_pump_outstanding_events
1217  */
1218 static Lisp_Object
1219 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d)
1220 {
1221   /* This function can call lisp */
1222   Lisp_Object event = Fmake_event (Qnil, Qnil);
1223   struct gcpro gcpro1;
1224   int do_redisplay = 0;
1225   GCPRO1 (event);
1226
1227   while (detect_input_pending ())
1228     {
1229       Fnext_event (event, Qnil);
1230       Fdispatch_event (event);
1231       do_redisplay = 1;
1232     }
1233
1234   if (do_redisplay)
1235     redisplay ();
1236
1237   Fdeallocate_event (event);
1238   UNGCPRO;
1239
1240   /* Qt becomes return value of mswindows_pump_outstanding_events
1241      once we get here */
1242   return Qt;
1243 }
1244
1245 /*
1246  * This function pumps emacs events, while available, by using
1247  * next_message/dispatch_message loop. Errors are trapped around
1248  * the loop so the function always returns.
1249  *
1250  * Windows message queue is not looked into during the call,
1251  * neither are waitable handles checked. The function pumps
1252  * thus only dispatch events already queued, as well as those
1253  * resulted in dispatching thereof. This is done by setting
1254  * module local variable mswindows_in_modal_loop to nonzero.
1255  *
1256  * Return value is Qt if no errors was trapped, or Qunbound if
1257  * there was an error.
1258  *
1259  * In case of error, a cons representing the error, in the
1260  * form (SIGNAL . DATA), is stored in the module local variable
1261  * mswindows_error_caught_in_modal_loop. This error is signaled
1262  * again when DispatchMessage returns. Thus, Windows internal
1263  * modal loops are protected against throws, which are proven
1264  * to corrupt internal Windows structures.
1265  *
1266  * In case of success, mswindows_error_caught_in_modal_loop is
1267  * assigned Qnil.
1268  *
1269  * If the value of mswindows_error_caught_in_modal_loop is not
1270  * nil already upon entry, the function just returns non-nil.
1271  * This situation means that a new event has been queued while
1272  * in cancel mode. The event will be dequeued on the next regular
1273  * call of next-event; the pump is off since error is caught.
1274  * The caller must *unconditionally* cancel modal loop if the
1275  * value returned by this function is nil. Otherwise, everything
1276  * will become frozen until the modal loop exits under normal
1277  * condition (scrollbar drag is released, menu closed etc.)
1278  */
1279 Lisp_Object
1280 mswindows_pump_outstanding_events (void)
1281 {
1282   /* This function can call lisp */
1283
1284   Lisp_Object result = Qt;
1285   struct gcpro gcpro1;
1286   GCPRO1 (result);
1287
1288   if (NILP(mswindows_error_caught_in_modal_loop))
1289     result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil);
1290   UNGCPRO;
1291   return result;
1292 }
1293
1294 /*
1295  * KEYBOARD_ONLY_P is set to non-zero when we are called from
1296  * QUITP, and are interesting in keyboard messages only.
1297  */
1298 static void
1299 mswindows_drain_windows_queue (void)
1300 {
1301   MSG msg;
1302
1303   /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1304   assert (!mswindows_in_modal_loop);
1305
1306   while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1307     {
1308       char class_name_buf [sizeof (XEMACS_CLASS) + 2] = "";
1309
1310       /* Don't translate messages destined for a dialog box, this
1311          makes keyboard traversal work. I think?? */
1312       if (mswindows_is_dialog_msg (&msg))
1313         {
1314           mswindows_unmodalize_signal_maybe ();
1315           continue;
1316         }
1317
1318       /* We have to translate messages that are not sent to an XEmacs
1319          frame. This is so that key presses work ok in things like
1320          edit fields. However, we *musn't* translate message for XEmacs
1321          frames as this is handled in the wnd proc.
1322          We also have to avoid generating paint magic events for windows
1323          that aren't XEmacs frames */
1324       /* GetClassName will truncate a longer class name. By adding one
1325          extra character, we are forcing textual comparison to fail
1326          if the name is longer than XEMACS_CLASS */
1327
1328       GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1);
1329       if (stricmp (class_name_buf, XEMACS_CLASS) != 0)
1330         {
1331           /* Not an XEmacs frame */
1332           TranslateMessage (&msg);
1333         }
1334       else if (msg.message == WM_PAINT)
1335         {
1336           struct mswindows_frame* msframe;
1337
1338           /* hdc will be NULL unless this is a subwindow - in which case we
1339              shouldn't have received a paint message for it here. */
1340           assert (msg.wParam == 0);
1341
1342           /* Queue a magic event for handling when safe */
1343           msframe =
1344             FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1345           if (!msframe->paint_pending)
1346             {
1347               msframe->paint_pending = 1;
1348               mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1349             }
1350           /* Don't dispatch. WM_PAINT is always the last message in the
1351              queue so it's OK to just return. */
1352           return;
1353         }
1354       DispatchMessage (&msg);
1355       mswindows_unmodalize_signal_maybe ();
1356     }
1357 }
1358
1359 /*
1360  * This is a special flavor of the mswindows_need_event function,
1361  * used while in event pump. Actually, there is only kind of events
1362  * allowed while in event pump: a timer.  An attempt to fetch any
1363  * other event leads to a deadlock, as there's no source of user input
1364  * ('cause event pump mirrors windows modal loop, which is a sole
1365  * owner of thread message queue).
1366  *
1367  * To detect this, we use a counter of active timers, and allow
1368  * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER
1369  * which will never come when there are no pending timers, which leads
1370  * to deadlock, we simply signal an error.
1371  *
1372  * It might be possible to combine this with mswindows_drain_windows_queue
1373  * which fetches events when not in a modal loop.  It's not clear
1374  * whether the result would be more complex than is justified.
1375  */
1376 static void
1377 mswindows_need_event_in_modal_loop (int badly_p)
1378 {
1379   MSG msg;
1380
1381   /* Check if already have one */
1382   if (!NILP (mswindows_u_dispatch_event_queue)
1383       || !NILP (mswindows_s_dispatch_event_queue))
1384     return;
1385
1386   /* No event is ok */
1387   if (!badly_p)
1388     return;
1389
1390   /* We do not check the _u_ queue, because timers go to _s_ */
1391   while (NILP (mswindows_s_dispatch_event_queue))
1392     {
1393       /* We'll deadlock if go waiting */
1394       if (mswindows_pending_timers_count == 0)
1395         error ("Deadlock due to an attempt to call next-event in a wrong context");
1396
1397       /* Fetch and dispatch any pending timers */
1398       if (GetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1399        DispatchMessage (&msg);
1400     }
1401 }
1402
1403 /*
1404  * This drains the event queue and fills up two internal queues until
1405  * an event of a type specified by USER_P is retrieved.
1406  *
1407  *
1408  * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event
1409  */
1410 static void
1411 mswindows_need_event (int badly_p)
1412 {
1413   int active;
1414
1415   while (NILP (mswindows_u_dispatch_event_queue)
1416          && NILP (mswindows_s_dispatch_event_queue))
1417     {
1418 #ifdef HAVE_MSG_SELECT
1419       int i;
1420       SELECT_TYPE temp_mask = input_wait_mask;
1421       EMACS_TIME sometime;
1422       EMACS_SELECT_TIME select_time_to_block, *pointer_to_this;
1423
1424       if (badly_p)
1425         pointer_to_this = 0;
1426       else
1427         {
1428           EMACS_SET_SECS_USECS (sometime, 0, 0);
1429           EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1430           pointer_to_this = &select_time_to_block;
1431          if (mswindows_in_modal_loop)
1432            /* In modal loop with badly_p false, don't care about
1433               Windows events. */
1434            FD_CLR (windows_fd, &temp_mask);
1435         }
1436
1437       active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this);
1438
1439       if (active == 0)
1440         {
1441           assert (!badly_p);
1442           return;               /* timeout */
1443         }
1444       else if (active > 0)
1445         {
1446           if (FD_ISSET (windows_fd, &temp_mask))
1447             {
1448              if (mswindows_in_modal_loop)
1449                mswindows_need_event_in_modal_loop (badly_p);
1450              else
1451                mswindows_drain_windows_queue ();
1452             }
1453           else
1454             {
1455 #ifdef HAVE_TTY
1456               /* Look for a TTY event */
1457               for (i = 0; i < MAXDESC-1; i++)
1458                 {
1459                   /* To avoid race conditions (among other things, an infinite
1460                      loop when called from Fdiscard_input()), we must return
1461                      user events ahead of process events. */
1462                   if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask))
1463                     {
1464                       struct console *c = tty_find_console_from_fd (i);
1465                       Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1466                       Lisp_Event* event = XEVENT (emacs_event);
1467
1468                       assert (c);
1469                       if (read_event_from_tty_or_stream_desc (event, c, i))
1470                         {
1471                           mswindows_enqueue_dispatch_event (emacs_event);
1472                           return;
1473                         }
1474                     }
1475                 }
1476 #endif
1477               /* Look for a process event */
1478               for (i = 0; i < MAXDESC-1; i++)
1479                 {
1480                   if (FD_ISSET (i, &temp_mask))
1481                     {
1482                       if (FD_ISSET (i, &process_only_mask))
1483                         {
1484                           Lisp_Process *p =
1485                             get_process_from_usid (FD_TO_USID(i));
1486
1487                           mswindows_enqueue_process_event (p);
1488                         }
1489                       else
1490                         {
1491                           /* We might get here when a fake event came
1492                              through a signal. Return a dummy event, so
1493                              that a cycle of the command loop will
1494                              occur. */
1495                           drain_signal_event_pipe ();
1496                           mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1497                         }
1498                     }
1499                 }
1500             }
1501         }
1502       else if (active==-1)
1503         {
1504           if (errno != EINTR)
1505             {
1506               /* something bad happened */
1507               assert(0);
1508             }
1509         }
1510       else
1511         {
1512           assert(0);
1513         }
1514 #else
1515       /* Now try getting a message or process event */
1516       DWORD what_events;
1517       MSG msg;
1518
1519       if (mswindows_in_modal_loop)
1520        /* In a modal loop, only look for timer events, and only if
1521           we really need one. */
1522        {
1523          if (badly_p)
1524            what_events = QS_TIMER;
1525          else
1526            what_events = 0;
1527        }
1528       else
1529        /* Look for any event */
1530        what_events = QS_ALLINPUT;
1531
1532       /* This fixes a long outstanding bug, where XEmacs would occasionally
1533        * not redraw its window (or process other events) until "something
1534        * happened" - usually the mouse moving over a frame.
1535        *
1536        * The problem is that MsgWaitForMultipleObjects only checks to see
1537        * if NEW messages have been placed into the thread queue. So we
1538        * specifically check to see if the queue is empty (using PeekMessage
1539        * with the PM_NOREMOVE flag) before we wait.
1540        */
1541       if (what_events == QS_ALLINPUT && badly_p &&
1542           PeekMessage (&msg, 0, 0, 0, PM_NOREMOVE))
1543         active = WAIT_OBJECT_0 + mswindows_waitable_count;
1544       else
1545         active = MsgWaitForMultipleObjects (mswindows_waitable_count,
1546                                             mswindows_waitable_handles,
1547                                             FALSE, badly_p ? INFINITE : 0,
1548                                             what_events);
1549
1550       /* This will assert if handle being waited for becomes abandoned.
1551          Not the case currently tho */
1552       assert ((!badly_p && active == WAIT_TIMEOUT) ||
1553               (active >= WAIT_OBJECT_0 &&
1554                active <= WAIT_OBJECT_0 + mswindows_waitable_count));
1555
1556       if (active == WAIT_TIMEOUT)
1557         {
1558           /* No luck trying - just return what we've already got */
1559           return;
1560         }
1561       else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1562         {
1563           /* Got your message, thanks */
1564           if (mswindows_in_modal_loop)
1565             mswindows_need_event_in_modal_loop (badly_p);
1566           else
1567             mswindows_drain_windows_queue ();
1568         }
1569       else
1570         {
1571           int ix = active - WAIT_OBJECT_0;
1572           /* First, try to find which process' output has signaled */
1573           Lisp_Process *p =
1574             get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix]));
1575           if (p != NULL)
1576             {
1577               /* Found a signaled process input handle */
1578               mswindows_enqueue_process_event (p);
1579             }
1580           else
1581             {
1582               /* None. This means that the process handle itself has signaled.
1583                  Remove the handle from the wait vector, and make status_notify
1584                 note the exited process.  First find the process object if
1585                 possible. */
1586              LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail)
1587                if (get_nt_process_handle (XPROCESS (vaffanculo)) ==
1588                    mswindows_waitable_handles [ix])
1589                  break;
1590               mswindows_waitable_handles [ix] =
1591                 mswindows_waitable_handles [--mswindows_waitable_count];
1592               kick_status_notify ();
1593               /* We need to return a process event here so that
1594                  (1) accept-process-output will return when called on this
1595                  process, and (2) status notifications will happen in
1596                  accept-process-output, sleep-for, and sit-for. */
1597               /* #### horrible kludge till my real process fixes go in.
1598                 #### Replaced with a slightly less horrible kluge that
1599                      at least finds the right process instead of axing the
1600                      first one on the list.
1601                */
1602              if (!NILP (vproctail))
1603                 {
1604                   mswindows_enqueue_process_event (XPROCESS (vaffanculo));
1605                 }
1606               else /* trash me soon. */
1607                 /* Have to return something: there may be no accompanying
1608                    process event */
1609                 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
1610             }
1611         }
1612 #endif
1613     } /* while */
1614 }
1615
1616 /************************************************************************/
1617 /*                           Event generators                           */
1618 /************************************************************************/
1619
1620 /*
1621  * Callback procedure for synchronous timer messages
1622  */
1623 static void CALLBACK
1624 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime)
1625 {
1626   Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1627   Lisp_Event *event = XEVENT (emacs_event);
1628
1629   if (KillTimer (NULL, id_timer))
1630     --mswindows_pending_timers_count;
1631
1632   event->channel = Qnil;
1633   event->timestamp = dwtime;
1634   event->event_type = timeout_event;
1635   event->event.timeout.interval_id = id_timer;
1636   event->event.timeout.function = Qnil;
1637   event->event.timeout.object = Qnil;
1638
1639   mswindows_enqueue_dispatch_event (emacs_event);
1640 }
1641
1642 /*
1643  * Callback procedure for dde messages
1644  *
1645  * We execute a dde Open("file") by simulating a file drop, so dde support
1646  * depends on dnd support.
1647  */
1648 #ifdef HAVE_DRAGNDROP
1649 extern int mswindows_dde_enable;
1650
1651 HDDEDATA CALLBACK
1652 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1653                         HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1654                         DWORD dwData1, DWORD dwData2)
1655 {
1656   switch (uType)
1657     {
1658     case XTYP_CONNECT:
1659       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1660         return (HDDEDATA)TRUE;
1661       return (HDDEDATA)FALSE;
1662
1663     case XTYP_WILDCONNECT:
1664       {
1665         /* We only support one {service,topic} pair */
1666         HSZPAIR pairs[2] = {
1667           { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1668
1669         if (!(hszItem  || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1670             !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)))
1671           return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1672                                        sizeof (pairs), 0L, 0, uFmt, 0));
1673       }
1674       return (HDDEDATA)NULL;
1675
1676     case XTYP_EXECUTE:
1677       if (!mswindows_dde_enable)
1678         return (HDDEDATA) DDE_FBUSY;
1679
1680       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1681         {
1682           DWORD len = DdeGetData (hdata, NULL, 0, 0);
1683           LPBYTE cmd = (LPBYTE) alloca (len+1);
1684           char *end;
1685           char *filename;
1686           struct gcpro gcpro1, gcpro2;
1687           Lisp_Object l_dndlist = Qnil;
1688           Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1689           Lisp_Object frmcons, devcons, concons;
1690           Lisp_Event *event = XEVENT (emacs_event);
1691
1692           DdeGetData (hdata, cmd, len, 0);
1693           cmd[len] = '\0';
1694           DdeFreeDataHandle (hdata);
1695
1696           /* Check syntax & that it's an [Open("foo")] command, which we
1697            * treat like a file drop */
1698           /* #### Ought to be generalised and accept some other commands */
1699           if (*cmd == '[')
1700             cmd++;
1701           if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1702                         strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1703             return DDE_FNOTPROCESSED;
1704           cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1705           while (*cmd==' ')
1706             cmd++;
1707           if (*cmd!='(' || *(cmd+1)!='\"')
1708             return DDE_FNOTPROCESSED;
1709           end = (cmd+=2);
1710           while (*end && *end!='\"')
1711             end++;
1712           if (!*end)
1713             return DDE_FNOTPROCESSED;
1714           *end = '\0';
1715           if (*(++end)!=')')
1716             return DDE_FNOTPROCESSED;
1717           if (*(++end)==']')
1718             end++;
1719           if (*end)
1720             return DDE_FNOTPROCESSED;
1721
1722 #ifdef CYGWIN
1723           filename = alloca (cygwin_win32_to_posix_path_list_buf_size (cmd) + 5);
1724           strcpy (filename, "file:");
1725           cygwin_win32_to_posix_path_list (cmd, filename+5);
1726 #else
1727           dostounix_filename (cmd);
1728           filename = alloca (strlen (cmd)+6);
1729           strcpy (filename, "file:");
1730           strcat (filename, cmd);
1731 #endif
1732           GCPRO2 (emacs_event, l_dndlist);
1733           l_dndlist = make_string (filename, strlen (filename));
1734
1735           /* Find a mswindows frame */
1736           event->channel = Qnil;
1737           FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1738             {
1739               Lisp_Object frame = XCAR (frmcons);
1740               if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1741                 event->channel = frame;
1742             };
1743           assert (!NILP (event->channel));
1744
1745           event->timestamp = GetTickCount();
1746           event->event_type = misc_user_event;
1747           event->event.misc.button = 1;
1748           event->event.misc.modifiers = 0;
1749           event->event.misc.x = -1;
1750           event->event.misc.y = -1;
1751           event->event.misc.function = Qdragdrop_drop_dispatch;
1752           event->event.misc.object = Fcons (Qdragdrop_URL,
1753                                             Fcons (l_dndlist, Qnil));
1754           mswindows_enqueue_dispatch_event (emacs_event);
1755           UNGCPRO;
1756           return (HDDEDATA) DDE_FACK;
1757         }
1758       DdeFreeDataHandle (hdata);
1759       return (HDDEDATA) DDE_FNOTPROCESSED;
1760
1761     default:
1762       return (HDDEDATA) NULL;
1763     }
1764 }
1765 #endif
1766
1767 /*
1768  * Helper to do repainting - repaints can happen both from the windows
1769  * procedure and from magic events
1770  */
1771 static void
1772 mswindows_handle_paint (struct frame *frame)
1773 {
1774   HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame);
1775
1776   /* According to the docs we need to check GetUpdateRect() before
1777      actually doing a WM_PAINT */
1778   if (GetUpdateRect (hwnd, NULL, FALSE))
1779     {
1780       PAINTSTRUCT paintStruct;
1781       int x, y, width, height;
1782
1783       BeginPaint (hwnd, &paintStruct);
1784       x = paintStruct.rcPaint.left;
1785       y = paintStruct.rcPaint.top;
1786       width = paintStruct.rcPaint.right - paintStruct.rcPaint.left;
1787       height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top;
1788       /* Normally we want to ignore expose events when child
1789          windows are unmapped, however once we are in the guts of
1790          WM_PAINT we need to make sure that we don't register
1791          unmaps then because they will not actually occur. */
1792       /* #### commenting out the next line seems to fix some problems
1793          but not all.  only andy currently understands this stuff and
1794          he needs to review it more carefully. --ben */
1795       if (!check_for_ignored_expose (frame, x, y, width, height))
1796         {
1797           hold_ignored_expose_registration = 1;
1798           mswindows_redraw_exposed_area (frame, x, y, width, height);
1799           hold_ignored_expose_registration = 0;
1800         }
1801       EndPaint (hwnd, &paintStruct);
1802     }
1803 }
1804
1805 /*
1806  * Returns 1 if a key is a real modifier or special key, which
1807  * is better handled by DefWindowProc
1808  */
1809 static int
1810 key_needs_default_processing_p (UINT vkey)
1811 {
1812   if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU
1813       /* if we let ALT activate the menu like this, then sticky ALT-modified
1814          keystrokes become impossible. */
1815       && !modifier_keys_are_sticky)
1816     return 1;
1817
1818   return 0;
1819 }
1820
1821 /* key-handling code is always ugly.  It just ends up working out
1822    that way.
1823
1824    #### Most of the sticky-modifier code below is copied from similar
1825    code in event-Xt.c.  They should somehow or other be merged.
1826
1827    Here are some pointers:
1828
1829    -- DOWN_MASK indicates which modifiers should be treated as "down"
1830       when the corresponding upstroke happens.  It gets reset for
1831       a particular modifier when that modifier goes up, and reset
1832       for all modifiers when a non-modifier key is pressed.  Example:
1833
1834       I press Control-A-Shift and then release Control-A-Shift.
1835       I want the Shift key to be sticky but not the Control key.
1836
1837    -- If a modifier key is sticky, I can unstick it by pressing
1838       the modifier key again. */
1839
1840 static WPARAM last_downkey;
1841 static int need_to_add_mask, down_mask;
1842
1843 #define XEMSW_LCONTROL (1<<0)
1844 #define XEMSW_RCONTROL (1<<1)
1845 #define XEMSW_LSHIFT (1<<2)
1846 #define XEMSW_RSHIFT (1<<3)
1847 #define XEMSW_LMENU (1<<4)
1848 #define XEMSW_RMENU (1<<5)
1849
1850 static int
1851 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam,
1852                                    int downp, int keyp)
1853 {
1854   int mods = 0;
1855
1856   if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */
1857     return 0;
1858
1859   if (! (keyp &&
1860          (wParam == VK_CONTROL || wParam == VK_LCONTROL ||
1861           wParam == VK_RCONTROL ||
1862           wParam == VK_MENU || wParam == VK_LMENU ||
1863           wParam == VK_RMENU ||
1864           wParam == VK_SHIFT || wParam == VK_LSHIFT ||
1865           wParam == VK_RSHIFT)))
1866     { /* Not a modifier key */
1867       if (downp && keyp && !last_downkey)
1868         last_downkey = wParam;
1869       /* If I hold press-and-release the Control key and then press
1870          and hold down the right arrow, I want it to auto-repeat
1871          Control-Right.  On the other hand, if I do the same but
1872          manually press the Right arrow a bunch of times, I want
1873          to see one Control-Right and then a bunch of Rights.
1874          This means that we need to distinguish between an
1875          auto-repeated key and a key pressed and released a bunch
1876          of times. */
1877       else if ((downp && !keyp) ||
1878                (downp && keyp && last_downkey &&
1879                 (wParam != last_downkey ||
1880                  /* the "previous key state" bit indicates autorepeat */
1881                  ! (lParam & (1 << 30)))))
1882         {
1883           need_to_add_mask = 0;
1884           last_downkey = 0;
1885         }
1886       if (downp)
1887         down_mask = 0;
1888
1889       mods = need_to_add_mask;
1890     }
1891   else                          /* Modifier key pressed */
1892     {
1893       /* If a non-modifier key was pressed in the middle of a bunch
1894          of modifiers, then it unsticks all the modifiers that were
1895          previously pressed.  We cannot unstick the modifiers until
1896          now because we want to check for auto-repeat of the
1897          non-modifier key. */
1898
1899       if (last_downkey)
1900         {
1901           last_downkey = 0;
1902           need_to_add_mask = 0;
1903         }
1904
1905 #define FROB(mask)                              \
1906 do {                                            \
1907   if (downp && keyp)                            \
1908     {                                           \
1909       /* If modifier key is already sticky,     \
1910          then unstick it.  Note that we do      \
1911          not test down_mask to deal with the    \
1912          unlikely but possible case that the    \
1913          modifier key auto-repeats. */          \
1914       if (need_to_add_mask & mask)              \
1915         {                                       \
1916           need_to_add_mask &= ~mask;            \
1917           down_mask &= ~mask;                   \
1918         }                                       \
1919       else                                      \
1920         down_mask |= mask;                      \
1921     }                                           \
1922   else                                          \
1923     {                                           \
1924       if (down_mask & mask)                     \
1925         {                                       \
1926           down_mask &= ~mask;                   \
1927           need_to_add_mask |= mask;             \
1928         }                                       \
1929     }                                           \
1930 } while (0)
1931
1932       if ((wParam == VK_CONTROL && (lParam & 0x1000000))
1933           || wParam == VK_RCONTROL)
1934         FROB (XEMSW_RCONTROL);
1935       if ((wParam == VK_CONTROL && !(lParam & 0x1000000))
1936           || wParam == VK_LCONTROL)
1937         FROB (XEMSW_LCONTROL);
1938
1939       if ((wParam == VK_SHIFT && (lParam & 0x1000000))
1940           || wParam == VK_RSHIFT)
1941         FROB (XEMSW_RSHIFT);
1942       if ((wParam == VK_SHIFT && !(lParam & 0x1000000))
1943           || wParam == VK_LSHIFT)
1944         FROB (XEMSW_LSHIFT);
1945
1946       if ((wParam == VK_MENU && (lParam & 0x1000000))
1947           || wParam == VK_RMENU)
1948         FROB (XEMSW_RMENU);
1949       if ((wParam == VK_MENU && !(lParam & 0x1000000))
1950           || wParam == VK_LMENU)
1951         FROB (XEMSW_LMENU);
1952     }
1953 #undef FROB
1954
1955   if (mods && downp)
1956     {
1957       BYTE keymap[256];
1958
1959       GetKeyboardState (keymap);
1960
1961       if (mods & XEMSW_LCONTROL)
1962         {
1963           keymap [VK_CONTROL] |= 0x80;
1964           keymap [VK_LCONTROL] |= 0x80;
1965         }
1966       if (mods & XEMSW_RCONTROL)
1967         {
1968           keymap [VK_CONTROL] |= 0x80;
1969           keymap [VK_RCONTROL] |= 0x80;
1970         }
1971
1972       if (mods & XEMSW_LSHIFT)
1973         {
1974           keymap [VK_SHIFT] |= 0x80;
1975           keymap [VK_LSHIFT] |= 0x80;
1976         }
1977       if (mods & XEMSW_RSHIFT)
1978         {
1979           keymap [VK_SHIFT] |= 0x80;
1980           keymap [VK_RSHIFT] |= 0x80;
1981         }
1982
1983       if (mods & XEMSW_LMENU)
1984         {
1985           keymap [VK_MENU] |= 0x80;
1986           keymap [VK_LMENU] |= 0x80;
1987         }
1988       if (mods & XEMSW_RMENU)
1989         {
1990           keymap [VK_MENU] |= 0x80;
1991           keymap [VK_RMENU] |= 0x80;
1992         }
1993
1994       SetKeyboardState (keymap);
1995       return 1;
1996     }
1997
1998   return 0;
1999 }
2000
2001 static void
2002 clear_sticky_modifiers (void)
2003 {
2004   need_to_add_mask = 0;
2005   last_downkey     = 0;
2006   down_mask        = 0;
2007 }
2008
2009 #ifdef DEBUG_XEMACS
2010
2011 #if 0
2012
2013 static void
2014 output_modifier_keyboard_state (void)
2015 {
2016   BYTE keymap[256];
2017
2018   GetKeyboardState (keymap);
2019
2020   stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2021               keymap[VK_MENU] & 0x80 ? 1 : 0,
2022               keymap[VK_MENU] & 0x1 ? 1 : 0,
2023               keymap[VK_LMENU] & 0x80 ? 1 : 0,
2024               keymap[VK_LMENU] & 0x1 ? 1 : 0,
2025               keymap[VK_RMENU] & 0x80 ? 1 : 0,
2026               keymap[VK_RMENU] & 0x1 ? 1 : 0);
2027   stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n",
2028               keymap[VK_CONTROL] & 0x80 ? 1 : 0,
2029               keymap[VK_CONTROL] & 0x1 ? 1 : 0,
2030               keymap[VK_LCONTROL] & 0x80 ? 1 : 0,
2031               keymap[VK_LCONTROL] & 0x1 ? 1 : 0,
2032               keymap[VK_RCONTROL] & 0x80 ? 1 : 0,
2033               keymap[VK_RCONTROL] & 0x1 ? 1 : 0);
2034   stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n",
2035               keymap[VK_SHIFT] & 0x80 ? 1 : 0,
2036               keymap[VK_SHIFT] & 0x1 ? 1 : 0,
2037               keymap[VK_LSHIFT] & 0x80 ? 1 : 0,
2038               keymap[VK_LSHIFT] & 0x1 ? 1 : 0,
2039               keymap[VK_RSHIFT] & 0x80 ? 1 : 0,
2040               keymap[VK_RSHIFT] & 0x1 ? 1 : 0);
2041 }
2042
2043 #endif
2044
2045 /* try to debug the stuck-alt-key problem.
2046
2047  #### this happens only inconsistently, and may only happen when using
2048  StickyKeys in the Win2000 accessibility section of the control panel,
2049  which is extremely broken for other reasons.  */
2050
2051 static void
2052 output_alt_keyboard_state (void)
2053 {
2054   BYTE keymap[256];
2055   SHORT keystate[3];
2056   // SHORT asyncstate[3];
2057
2058   GetKeyboardState (keymap);
2059   keystate[0] = GetKeyState (VK_MENU);
2060   keystate[1] = GetKeyState (VK_LMENU);
2061   keystate[2] = GetKeyState (VK_RMENU);
2062   /* Doing this interferes with key processing. */
2063 /*   asyncstate[0] = GetAsyncKeyState (VK_MENU); */
2064 /*   asyncstate[1] = GetAsyncKeyState (VK_LMENU); */
2065 /*   asyncstate[2] = GetAsyncKeyState (VK_RMENU); */
2066
2067   stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2068               keymap[VK_MENU] & 0x80 ? 1 : 0,
2069               keymap[VK_MENU] & 0x1 ? 1 : 0,
2070               keymap[VK_LMENU] & 0x80 ? 1 : 0,
2071               keymap[VK_LMENU] & 0x1 ? 1 : 0,
2072               keymap[VK_RMENU] & 0x80 ? 1 : 0,
2073               keymap[VK_RMENU] & 0x1 ? 1 : 0);
2074   stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n",
2075               keystate[0] & 0x8000 ? 1 : 0,
2076               keystate[0] & 0x1 ? 1 : 0,
2077               keystate[1] & 0x8000 ? 1 : 0,
2078               keystate[1] & 0x1 ? 1 : 0,
2079               keystate[2] & 0x8000 ? 1 : 0,
2080               keystate[2] & 0x1 ? 1 : 0);
2081 /*   stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */
2082 /*            asyncstate[0] & 0x8000 ? 1 : 0, */
2083 /*            asyncstate[0] & 0x1 ? 1 : 0, */
2084 /*            asyncstate[1] & 0x8000 ? 1 : 0, */
2085 /*            asyncstate[1] & 0x1 ? 1 : 0, */
2086 /*            asyncstate[2] & 0x8000 ? 1 : 0, */
2087 /*            asyncstate[2] & 0x1 ? 1 : 0); */
2088 }
2089
2090 #endif /* DEBUG_XEMACS */
2091
2092
2093 /*
2094  * The windows procedure for the window class XEMACS_CLASS
2095  */
2096 LRESULT WINAPI
2097 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam)
2098 {
2099   /* Note: Remember to initialize emacs_event and event before use.
2100      This code calls code that can GC. You must GCPRO before calling such code. */
2101   Lisp_Object emacs_event = Qnil;
2102   Lisp_Object fobj = Qnil;
2103
2104   Lisp_Event *event;
2105   struct frame *frame;
2106   struct mswindows_frame* msframe;
2107
2108   /* If you hit this, rewrite the offending API call to occur after GC,
2109      using register_post_gc_action(). */
2110   assert (!gc_in_progress);
2111
2112 #ifdef DEBUG_XEMACS
2113   if (debug_mswindows_events)
2114     debug_output_mswin_message (hwnd, message_, wParam, lParam);
2115 #endif /* DEBUG_XEMACS */
2116
2117   assert (!GetWindowLong (hwnd, GWL_USERDATA));
2118   switch (message_)
2119     {
2120     case WM_DESTROYCLIPBOARD:
2121       /* We own the clipboard and someone else wants it.  Delete our
2122          cached copy of the clipboard contents so we'll ask for it from
2123          Windows again when someone does a paste, and destroy any memory
2124          objects we hold on the clipboard that are not in the list of types
2125          that Windows will delete itself. */
2126       mswindows_destroy_selection (QCLIPBOARD);
2127       handle_selection_clear (QCLIPBOARD);
2128       break;
2129
2130     case WM_ERASEBKGND:
2131       /* Erase background only during non-dynamic sizing */
2132       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2133       if (msframe->sizing && !mswindows_dynamic_frame_resize)
2134         goto defproc;
2135       return 1;
2136
2137     case WM_CLOSE:
2138       fobj = mswindows_find_frame (hwnd);
2139       mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
2140       break;
2141
2142     case WM_KEYUP:
2143     case WM_SYSKEYUP:
2144
2145       /* See Win95 comment under WM_KEYDOWN */
2146       {
2147         BYTE keymap[256];
2148         int should_set_keymap = 0;
2149
2150 #ifdef DEBUG_XEMACS
2151         if (debug_mswindows_events > 2)
2152           output_alt_keyboard_state ();
2153 #endif /* DEBUG_XEMACS */
2154
2155         mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1);
2156         if (wParam == VK_CONTROL)
2157           {
2158             GetKeyboardState (keymap);
2159             keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
2160             should_set_keymap = 1;
2161           }
2162         else if (wParam == VK_MENU)
2163           {
2164             GetKeyboardState (keymap);
2165             keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
2166             should_set_keymap = 1;
2167           }
2168
2169         if (should_set_keymap)
2170           //        && (message_ != WM_SYSKEYUP
2171           //    || NILP (Vmenu_accelerator_enabled)))
2172           SetKeyboardState (keymap);
2173
2174       }
2175
2176       if (key_needs_default_processing_p (wParam))
2177         goto defproc;
2178       else
2179         break;
2180
2181     case WM_KEYDOWN:
2182     case WM_SYSKEYDOWN:
2183
2184       /* In some locales the right-hand Alt key is labelled AltGr. This key
2185        * should produce alternative characters when combined with another key.
2186        * eg on a German keyboard pressing AltGr+q should produce '@'.
2187        * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
2188        * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
2189        * it translates as if AltGr were down.
2190        * We get round this by removing all modifiers from the keymap before
2191        * calling TranslateMessage() unless AltGr is *really* down. */
2192       {
2193         BYTE keymap_trans[256];
2194         BYTE keymap_orig[256];
2195         BYTE keymap_sticky[256];
2196         int has_AltGr = mswindows_current_layout_has_AltGr ();
2197         int mods = 0, mods_with_shift = 0;
2198         int extendedp = lParam & 0x1000000;
2199         Lisp_Object keysym;
2200         int sticky_changed;
2201
2202 #ifdef DEBUG_XEMACS
2203         if (debug_mswindows_events > 2)
2204           output_alt_keyboard_state ();
2205 #endif /* DEBUG_XEMACS */
2206
2207         GetKeyboardState (keymap_orig);
2208         frame = XFRAME (mswindows_find_frame (hwnd));
2209         if ((sticky_changed =
2210              mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1)))
2211           {
2212             GetKeyboardState (keymap_sticky);
2213             if (keymap_sticky[VK_MENU] & 0x80)
2214               {
2215                 message_ = WM_SYSKEYDOWN;
2216                 /* We have to set the "context bit" so that the
2217                    TranslateMessage() call below that generates the
2218                    SYSCHAR message does its thing; see the documentation
2219                    on WM_SYSKEYDOWN */
2220                 lParam |= 1 << 29;
2221               }
2222           }
2223         else
2224           memcpy (keymap_sticky, keymap_orig, 256);
2225
2226         mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr);
2227         mods_with_shift = mods;
2228
2229         /* Handle non-printables */
2230         if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods,
2231                                                            extendedp)))
2232           {
2233             mswindows_enqueue_keypress_event (hwnd, keysym, mods);
2234             if (sticky_changed)
2235               SetKeyboardState (keymap_orig);
2236           }
2237         else    /* Normal keys & modifiers */
2238           {
2239             Emchar quit_ch =
2240               CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
2241             POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) };
2242             MSG msg, tranmsg;
2243             int potential_accelerator = 0;
2244             int got_accelerator = 0;
2245
2246             msg.hwnd = hwnd;
2247             msg.message = message_;
2248             msg.wParam = wParam;
2249             msg.lParam = lParam;
2250             msg.time = GetMessageTime();
2251             msg.pt = pnt;
2252
2253             /* GetKeyboardState() does not work as documented on Win95. We have
2254              * to loosely track Left and Right modifiers on behalf of the OS,
2255              * without screwing up Windows NT which tracks them properly. */
2256             if (wParam == VK_CONTROL)
2257               {
2258                 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2259                 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
2260               }
2261             else if (wParam == VK_MENU)
2262               {
2263                 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2264                 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80;
2265               }
2266
2267             if (!NILP (Vmenu_accelerator_enabled) &&
2268                 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN)
2269               potential_accelerator = 1;
2270
2271             /* Remove shift modifier from an ascii character */
2272             mods &= ~XEMACS_MOD_SHIFT;
2273
2274             memcpy (keymap_trans, keymap_sticky, 256);
2275
2276             /* Clear control and alt modifiers unless AltGr is pressed */
2277             keymap_trans[VK_RCONTROL] = 0;
2278             keymap_trans[VK_LMENU] = 0;
2279             if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80)
2280                 || !(keymap_trans[VK_RMENU] & 0x80))
2281               {
2282                 keymap_trans[VK_LCONTROL] = 0;
2283                 keymap_trans[VK_CONTROL] = 0;
2284                 keymap_trans[VK_RMENU] = 0;
2285                 keymap_trans[VK_MENU] = 0;
2286               }
2287             SetKeyboardState (keymap_trans);
2288
2289             /* Maybe generate some WM_[SYS]CHARs in the queue */
2290             TranslateMessage (&msg);
2291
2292             while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
2293                    || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR,
2294                                    PM_REMOVE))
2295               {
2296                 int mods_with_quit = mods;
2297                 WPARAM ch = tranmsg.wParam;
2298
2299 #ifdef DEBUG_XEMACS
2300                 if (debug_mswindows_events)
2301                   {
2302                     stderr_out ("-> ");
2303                     debug_output_mswin_message (tranmsg.hwnd, tranmsg.message,
2304                                                 tranmsg.wParam,
2305                                                 tranmsg.lParam);
2306                   }
2307 #endif /* DEBUG_XEMACS */
2308
2309                 /* If a quit char with no modifiers other than control and
2310                    shift, then mark it with a fake modifier, which is removed
2311                    upon dequeueing the event */
2312                 /* !!#### Fix this in my mule ws -- replace current_buffer
2313                    with 0 */
2314                 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL)
2315                       && DOWNCASE (current_buffer, quit_ch + 'a' - 1) ==
2316                       DOWNCASE (current_buffer, ch))
2317                      || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL)
2318                          && DOWNCASE (current_buffer, quit_ch) ==
2319                          DOWNCASE (current_buffer, ch)))
2320                     && ((mods_with_shift &
2321                          ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT))
2322                         == 0))
2323                   {
2324                     mods_with_quit |= FAKE_MOD_QUIT;
2325                     if (mods_with_shift & XEMACS_MOD_SHIFT)
2326                       mods_with_quit |= FAKE_MOD_QUIT_CRITICAL;
2327                     mswindows_quit_chars_count++;
2328                   }
2329                 else if (potential_accelerator && !got_accelerator &&
2330                          mswindows_char_is_accelerator (frame, ch))
2331                   {
2332                     got_accelerator = 1;
2333                     break;
2334                   }
2335                 mswindows_enqueue_keypress_event (hwnd, make_char (ch),
2336                                                   mods_with_quit);
2337               } /* while */
2338
2339             /* This generates WM_SYSCHAR messages, which are interpreted
2340                by DefWindowProc as the menu selections. */
2341             if (got_accelerator)
2342               {
2343                 SetKeyboardState (keymap_sticky);
2344                 TranslateMessage (&msg);
2345                 SetKeyboardState (keymap_orig);
2346                 goto defproc;
2347               }
2348
2349             SetKeyboardState (keymap_orig);
2350           } /* else */
2351       }
2352
2353       if (key_needs_default_processing_p (wParam))
2354         goto defproc;
2355       else
2356         break;
2357
2358     case WM_MBUTTONDOWN:
2359     case WM_MBUTTONUP:
2360       /* Real middle mouse button has nothing to do with emulated one:
2361          if one wants to exercise fingers playing chords on the mouse,
2362          he is allowed to do that! */
2363       mswindows_enqueue_mouse_button_event (hwnd, message_,
2364                                             MAKEPOINTS (lParam),
2365                                             wParam &~ MK_MBUTTON,
2366                                             GetMessageTime());
2367       break;
2368
2369     case WM_LBUTTONUP:
2370       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2371       msframe->last_click_time =  GetMessageTime();
2372
2373       KillTimer (hwnd, BUTTON_2_TIMER_ID);
2374       msframe->button2_need_lbutton = 0;
2375       if (msframe->ignore_next_lbutton_up)
2376         {
2377           msframe->ignore_next_lbutton_up = 0;
2378         }
2379       else if (msframe->button2_is_down)
2380         {
2381           msframe->button2_is_down = 0;
2382           msframe->ignore_next_rbutton_up = 1;
2383           mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2384                                                 MAKEPOINTS (lParam),
2385                                                 wParam
2386                                                 &~ (MK_LBUTTON | MK_MBUTTON
2387                                                     | MK_RBUTTON),
2388                                                 GetMessageTime());
2389         }
2390       else
2391         {
2392           if (msframe->button2_need_rbutton)
2393             {
2394               msframe->button2_need_rbutton = 0;
2395               mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2396                                                     MAKEPOINTS (lParam),
2397                                                     wParam &~ MK_LBUTTON,
2398                                                     GetMessageTime());
2399             }
2400           mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
2401                                                 MAKEPOINTS (lParam),
2402                                                 wParam &~ MK_LBUTTON,
2403                                                 GetMessageTime());
2404         }
2405       break;
2406
2407     case WM_RBUTTONUP:
2408       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2409       msframe->last_click_time =  GetMessageTime();
2410
2411       KillTimer (hwnd, BUTTON_2_TIMER_ID);
2412       msframe->button2_need_rbutton = 0;
2413       if (msframe->ignore_next_rbutton_up)
2414         {
2415           msframe->ignore_next_rbutton_up = 0;
2416         }
2417       else if (msframe->button2_is_down)
2418         {
2419           msframe->button2_is_down = 0;
2420           msframe->ignore_next_lbutton_up = 1;
2421           mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
2422                                                 MAKEPOINTS (lParam),
2423                                                 wParam
2424                                                 &~ (MK_LBUTTON | MK_MBUTTON
2425                                                     | MK_RBUTTON),
2426                                                 GetMessageTime());
2427         }
2428       else
2429         {
2430           if (msframe->button2_need_lbutton)
2431             {
2432               msframe->button2_need_lbutton = 0;
2433               mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2434                                                     MAKEPOINTS (lParam),
2435                                                     wParam &~ MK_RBUTTON,
2436                                                     GetMessageTime());
2437             }
2438           mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
2439                                                 MAKEPOINTS (lParam),
2440                                                 wParam &~ MK_RBUTTON,
2441                                                 GetMessageTime());
2442         }
2443       break;
2444
2445     case WM_LBUTTONDOWN:
2446       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2447
2448       if (msframe->button2_need_lbutton)
2449         {
2450           KillTimer (hwnd, BUTTON_2_TIMER_ID);
2451           msframe->button2_need_lbutton = 0;
2452           msframe->button2_need_rbutton = 0;
2453           if (mswindows_button2_near_enough (msframe->last_click_point,
2454                                              MAKEPOINTS (lParam)))
2455             {
2456               mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2457                                                     MAKEPOINTS (lParam),
2458                                                     wParam
2459                                                     &~ (MK_LBUTTON | MK_MBUTTON
2460                                                         | MK_RBUTTON),
2461                                                     GetMessageTime());
2462               msframe->button2_is_down = 1;
2463             }
2464           else
2465             {
2466               mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2467                                                     msframe->last_click_point,
2468                                                     msframe->last_click_mods
2469                                                     &~ MK_RBUTTON,
2470                                                     msframe->last_click_time);
2471               mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2472                                                     MAKEPOINTS (lParam),
2473                                                     wParam &~ MK_LBUTTON,
2474                                                     GetMessageTime());
2475             }
2476         }
2477       else
2478         {
2479           mswindows_set_chord_timer (hwnd);
2480           msframe->button2_need_rbutton = 1;
2481           msframe->last_click_point = MAKEPOINTS (lParam);
2482           msframe->last_click_mods = wParam;
2483         }
2484       msframe->last_click_time =  GetMessageTime();
2485       break;
2486
2487     case WM_RBUTTONDOWN:
2488       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2489
2490       if (msframe->button2_need_rbutton)
2491         {
2492           KillTimer (hwnd, BUTTON_2_TIMER_ID);
2493           msframe->button2_need_lbutton = 0;
2494           msframe->button2_need_rbutton = 0;
2495           if (mswindows_button2_near_enough (msframe->last_click_point,
2496                                              MAKEPOINTS (lParam)))
2497             {
2498               mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
2499                                                     MAKEPOINTS (lParam),
2500                                                     wParam
2501                                                     &~ (MK_LBUTTON | MK_MBUTTON
2502                                                         | MK_RBUTTON),
2503                                                     GetMessageTime());
2504               msframe->button2_is_down = 1;
2505             }
2506           else
2507             {
2508               mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2509                                                     msframe->last_click_point,
2510                                                     msframe->last_click_mods
2511                                                     &~ MK_LBUTTON,
2512                                                     msframe->last_click_time);
2513               mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2514                                                     MAKEPOINTS (lParam),
2515                                                     wParam &~ MK_RBUTTON,
2516                                                     GetMessageTime());
2517             }
2518         }
2519       else
2520         {
2521           mswindows_set_chord_timer (hwnd);
2522           msframe->button2_need_lbutton = 1;
2523           msframe->last_click_point = MAKEPOINTS (lParam);
2524           msframe->last_click_mods = wParam;
2525         }
2526       msframe->last_click_time =  GetMessageTime();
2527       break;
2528
2529     case WM_TIMER:
2530       if (wParam == BUTTON_2_TIMER_ID)
2531         {
2532           msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2533           KillTimer (hwnd, BUTTON_2_TIMER_ID);
2534
2535           if (msframe->button2_need_lbutton)
2536             {
2537               msframe->button2_need_lbutton = 0;
2538               mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
2539                                                     msframe->last_click_point,
2540                                                     msframe->last_click_mods
2541                                                     &~ MK_RBUTTON,
2542                                                     msframe->last_click_time);
2543             }
2544           else if (msframe->button2_need_rbutton)
2545             {
2546               msframe->button2_need_rbutton = 0;
2547               mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
2548                                                     msframe->last_click_point,
2549                                                     msframe->last_click_mods
2550                                                     &~ MK_LBUTTON,
2551                                                     msframe->last_click_time);
2552             }
2553         }
2554       else
2555         assert ("Spurious timer fired" == 0);
2556       break;
2557
2558     case WM_MOUSEMOVE:
2559       /* Optimization: don't report mouse movement while size is changing */
2560       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2561       if (!msframe->sizing)
2562         {
2563           /* When waiting for the second mouse button to finish
2564              button2 emulation, and have moved too far, just pretend
2565              as if timer has expired. This improves drag-select feedback */
2566           if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
2567               && !mswindows_button2_near_enough (msframe->last_click_point,
2568                                                  MAKEPOINTS (lParam)))
2569             {
2570               KillTimer (hwnd, BUTTON_2_TIMER_ID);
2571               SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
2572             }
2573
2574           emacs_event = Fmake_event (Qnil, Qnil);
2575           event = XEVENT(emacs_event);
2576
2577           event->channel = mswindows_find_frame(hwnd);
2578           event->timestamp = GetMessageTime();
2579           event->event_type = pointer_motion_event;
2580           event->event.motion.x = MAKEPOINTS(lParam).x;
2581           event->event.motion.y = MAKEPOINTS(lParam).y;
2582           event->event.motion.modifiers =
2583             mswindows_modifier_state (NULL, wParam, 0);
2584
2585           mswindows_enqueue_dispatch_event (emacs_event);
2586         }
2587       break;
2588
2589     case WM_CANCELMODE:
2590       ReleaseCapture ();
2591       /* Queue a `cancel-mode-internal' misc user event, so mouse
2592          selection would be canceled if any */
2593       mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
2594                                          Qcancel_mode_internal, Qnil);
2595       break;
2596
2597     case WM_NOTIFY:
2598       {
2599         LPNMHDR nmhdr = (LPNMHDR)lParam;
2600
2601         if (nmhdr->code ==  TTN_NEEDTEXT)
2602           {
2603 #ifdef HAVE_TOOLBARS
2604             LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
2605             Lisp_Object btext;
2606
2607             /* find out which toolbar */
2608             frame = XFRAME (mswindows_find_frame (hwnd));
2609             btext = mswindows_get_toolbar_button_text ( frame,
2610                                                         nmhdr->idFrom );
2611
2612             tttext->lpszText = NULL;
2613             tttext->hinst = NULL;
2614
2615             if (!NILP(btext))
2616               {
2617                 /* I think this is safe since the text will only go away
2618                    when the toolbar does...*/
2619                 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative);
2620               }
2621 #endif
2622           }
2623         /* handle tree view callbacks */
2624         else if (nmhdr->code == TVN_SELCHANGED)
2625           {
2626             NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam;
2627             frame = XFRAME (mswindows_find_frame (hwnd));
2628             mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam);
2629           }
2630         /* handle tab control callbacks */
2631         else if (nmhdr->code == TCN_SELCHANGE)
2632           {
2633             TC_ITEM item;
2634             int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0);
2635             frame = XFRAME (mswindows_find_frame (hwnd));
2636
2637             item.mask = TCIF_PARAM;
2638             SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx,
2639                          (LPARAM)&item);
2640
2641             mswindows_handle_gui_wm_command (frame, 0, item.lParam);
2642           }
2643       }
2644       break;
2645
2646     case WM_PAINT:
2647       /* hdc will be NULL unless this is a subwindow - in which case we
2648          shouldn't have received a paint message for it here. */
2649       assert (wParam == 0);
2650
2651       /* Can't queue a magic event because windows goes modal and sends paint
2652          messages directly to the windows procedure when doing solid drags
2653          and the message queue doesn't get processed. */
2654       mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd)));
2655       break;
2656
2657     case WM_ACTIVATE:
2658       {
2659         /*
2660          * If we receive a WM_ACTIVATE message that indicates that our frame
2661          * is being activated, make sure that the frame is marked visible
2662          * if the window itself is visible. This seems to fix the problem
2663          * where XEmacs appears to lock-up after switching desktops with
2664          * some virtual window managers.
2665          */
2666         int state = (int)(short) LOWORD(wParam);
2667 #ifdef DEBUG_XEMACS
2668         if (debug_mswindows_events)
2669           stderr_out("state = %d\n", state);
2670 #endif /* DEBUG_XEMACS */
2671         if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
2672           {
2673 #ifdef DEBUG_XEMACS
2674             if (debug_mswindows_events)
2675               stderr_out("  activating\n");
2676 #endif /* DEBUG_XEMACS */
2677             
2678             fobj = mswindows_find_frame (hwnd);
2679             frame = XFRAME (fobj);
2680             if (IsWindowVisible (hwnd))
2681               {
2682 #ifdef DEBUG_XEMACS
2683                 if (debug_mswindows_events)
2684                   stderr_out("  window is visible\n");
2685 #endif /* DEBUG_XEMACS */
2686                 if (!FRAME_VISIBLE_P (frame))
2687                   {
2688 #ifdef DEBUG_XEMACS
2689                     if (debug_mswindows_events)
2690                       stderr_out("  frame is not visible\n");
2691 #endif /* DEBUG_XEMACS */
2692                     /*
2693                      * It seems that we have to enqueue the XM_MAPFRAME event
2694                      * prior to setting the frame visible so that
2695                      * suspend-or-iconify-emacs works properly.
2696                      */
2697                     mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2698                     FRAME_VISIBLE_P (frame) = 1;
2699                     FRAME_ICONIFIED_P (frame) = 0;
2700                   }
2701 #ifdef DEBUG_XEMACS
2702                 else
2703                   {
2704                     if (debug_mswindows_events)
2705                       stderr_out("  frame is visible\n");
2706                   }
2707 #endif /* DEBUG_XEMACS */
2708               }
2709 #ifdef DEBUG_XEMACS
2710             else
2711               {     
2712                 if (debug_mswindows_events)
2713                   stderr_out("  window is not visible\n");
2714               }
2715 #endif /* DEBUG_XEMACS */
2716           }
2717         return DefWindowProc (hwnd, message_, wParam, lParam);
2718       }
2719       break;
2720       
2721     case WM_WINDOWPOSCHANGED:
2722       /* This is sent before WM_SIZE; in fact, the processing of this
2723          by DefWindowProc() sends WM_SIZE.  But WM_SIZE is not sent when
2724          a window is hidden (make-frame-invisible), so we need to process
2725          this and update the state flags. */
2726       {
2727         fobj = mswindows_find_frame (hwnd);
2728         frame = XFRAME (fobj);
2729         if (IsIconic (hwnd))
2730           {
2731             FRAME_VISIBLE_P (frame) = 0;
2732             FRAME_ICONIFIED_P (frame) = 1;
2733           }
2734         else if (IsWindowVisible (hwnd))
2735           {
2736             /* APA: It's too early here to set the frame visible.
2737              * Let's do this later, in WM_SIZE processing, after the
2738              * magic XM_MAPFRAME event has been sent (just like 21.1
2739              * did). */
2740             /* FRAME_VISIBLE_P (frame) = 1; */
2741             FRAME_ICONIFIED_P (frame) = 0;
2742           }
2743         else
2744           {
2745             FRAME_VISIBLE_P (frame) = 0;
2746             FRAME_ICONIFIED_P (frame) = 0;
2747           }         
2748
2749         return DefWindowProc (hwnd, message_, wParam, lParam);
2750       }
2751
2752     case WM_SHOWWINDOW:
2753       /*
2754          The WM_SHOWWINDOW message is sent to a window when the window
2755          is about to be hidden or shown.
2756          APA: This message is also sent when switching to a virtual
2757          desktop under the virtuawin virtual window manager.
2758       
2759       */
2760       {
2761         fobj = mswindows_find_frame (hwnd);
2762         frame = XFRAME (fobj);
2763         if (wParam == TRUE)
2764           {
2765             mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2766             FRAME_VISIBLE_P (frame) = 1;
2767           }
2768         else
2769           {
2770             mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2771             FRAME_VISIBLE_P (frame) = 0;
2772           }
2773       }
2774       break;
2775
2776     case WM_SIZE:
2777       /* We only care about this message if our size has really changed */
2778       if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
2779         {
2780           RECT rect;
2781           int columns, rows;
2782
2783           fobj = mswindows_find_frame (hwnd);
2784           frame = XFRAME (fobj);
2785           msframe  = FRAME_MSWINDOWS_DATA (frame);
2786
2787           /* We cannot handle frame map and unmap hooks right in
2788              this routine, because these may throw. We queue
2789              magic events to run these hooks instead - kkm */
2790
2791           if (wParam==SIZE_MINIMIZED)
2792             {
2793               /* Iconified */
2794               mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2795             }
2796           else
2797             {
2798               GetClientRect(hwnd, &rect);
2799               FRAME_PIXWIDTH(frame) = rect.right;
2800               FRAME_PIXHEIGHT(frame) = rect.bottom;
2801
2802               pixel_to_real_char_size (frame, rect.right, rect.bottom,
2803                                        &FRAME_MSWINDOWS_CHARWIDTH (frame),
2804                                        &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2805
2806               pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2807               change_frame_size (frame, rows, columns, 1);
2808
2809               /* If we are inside frame creation, we have to apply geometric
2810                  properties now. */
2811               if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2812                 {
2813                   /* Yes, we have to size again */
2814                   mswindows_size_frame_internal ( frame,
2815                                                   FRAME_MSWINDOWS_TARGET_RECT
2816                                                   (frame));
2817                   /* Reset so we do not get here again. The SetWindowPos call in
2818                    * mswindows_size_frame_internal can cause recursion here. */
2819                   if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2820                     {
2821                       xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2822                       FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2823                     }
2824                 }
2825               else
2826                 {
2827                   if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2828                     {
2829                       mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2830                       /* APA: Now that the magic XM_MAPFRAME event has
2831                        * been sent we can mark the frame as visible (just
2832                        * like 21.1 did). */
2833                       FRAME_VISIBLE_P (frame) = 1;
2834                     }
2835
2836                   if (!msframe->sizing || mswindows_dynamic_frame_resize)
2837                     redisplay ();
2838                 }
2839             }
2840         }
2841       break;
2842
2843     case WM_DISPLAYCHANGE:
2844       {
2845         struct device *d;
2846         DWORD message_tick = GetMessageTime ();
2847
2848         fobj = mswindows_find_frame (hwnd);
2849         frame = XFRAME (fobj);
2850         d = XDEVICE (FRAME_DEVICE (frame));
2851
2852         /* Do this only once per message. XEmacs can receive this message
2853            through as many frames as it currently has open. Message time
2854            will be the same for all these messages. Despite extreme
2855            efficiency, the code below has about one in 4 billion
2856            probability that the HDC is not recreated, provided that
2857            XEmacs is running sufficiently longer than 52 days. */
2858         if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick)
2859           {
2860             DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick;
2861             DeleteDC (DEVICE_MSWINDOWS_HCDC(d));
2862             DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL);
2863           }
2864       }
2865       break;
2866
2867       /* Misc magic events which only require that the frame be identified */
2868     case WM_SETFOCUS:
2869     case WM_KILLFOCUS:
2870       mswindows_enqueue_magic_event (hwnd, message_);
2871       break;
2872
2873     case WM_WINDOWPOSCHANGING:
2874       {
2875         WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2876         WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2877         GetWindowPlacement(hwnd, &wpl);
2878
2879         /* Only interested if size is changing and we're not being iconified */
2880         if (wpl.showCmd != SW_SHOWMINIMIZED
2881             && wpl.showCmd != SW_SHOWMAXIMIZED
2882             && !(wp->flags & SWP_NOSIZE))
2883           {
2884             RECT ncsize = { 0, 0, 0, 0 };
2885             int pixwidth, pixheight;
2886             AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2887                                 GetMenu(hwnd) != NULL,
2888                                 GetWindowLong (hwnd, GWL_EXSTYLE));
2889
2890             round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2891                                      wp->cx - (ncsize.right - ncsize.left),
2892                                      wp->cy - (ncsize.bottom - ncsize.top),
2893                                      &pixwidth, &pixheight);
2894
2895             /* Convert client sizes to window sizes */
2896             pixwidth += (ncsize.right - ncsize.left);
2897             pixheight += (ncsize.bottom - ncsize.top);
2898
2899             if (wpl.showCmd != SW_SHOWMAXIMIZED)
2900               {
2901                 /* Adjust so that the bottom or right doesn't move if it's
2902                  * the top or left that's being changed */
2903                 RECT rect;
2904                 GetWindowRect (hwnd, &rect);
2905
2906                 if (rect.left != wp->x)
2907                   wp->x += wp->cx - pixwidth;
2908                 if (rect.top != wp->y)
2909                   wp->y += wp->cy - pixheight;
2910               }
2911
2912             wp->cx = pixwidth;
2913             wp->cy = pixheight;
2914           }
2915         /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2916            window position if the user tries to track window too small */
2917       }
2918       goto defproc;
2919
2920     case WM_ENTERSIZEMOVE:
2921       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2922       msframe->sizing = 1;
2923       return 0;
2924
2925     case WM_EXITSIZEMOVE:
2926       msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2927       msframe->sizing = 0;
2928       /* Queue noop event */
2929       mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2930       return 0;
2931
2932 #ifdef HAVE_SCROLLBARS
2933     case WM_VSCROLL:
2934     case WM_HSCROLL:
2935       {
2936         /* Direction of scroll is determined by scrollbar instance. */
2937         int code = (int) LOWORD(wParam);
2938         int pos = (short int) HIWORD(wParam);
2939         HWND hwndScrollBar = (HWND) lParam;
2940         struct gcpro gcpro1, gcpro2;
2941
2942         mswindows_handle_scrollbar_event (hwndScrollBar, code,  pos);
2943         GCPRO2 (emacs_event, fobj);
2944         if (UNBOUNDP(mswindows_pump_outstanding_events()))      /* Can GC */
2945           {
2946             /* Error during event pumping - cancel scroll */
2947             SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2948           }
2949         UNGCPRO;
2950         break;
2951       }
2952
2953     case WM_MOUSEWHEEL:
2954       {
2955         int keys = LOWORD (wParam); /* Modifier key flags */
2956         int delta = (short) HIWORD (wParam); /* Wheel rotation amount */
2957
2958         /* enqueue button4/5 events if mswindows_handle_mousewheel_event
2959            doesn't handle the event, such as when the scrollbars are not
2960            displayed */
2961         if (!mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd),
2962                                                keys, delta,
2963                                                MAKEPOINTS (lParam)))
2964           mswindows_enqueue_mouse_button_event (hwnd, message_,
2965                                                 MAKEPOINTS (lParam),
2966                                                 wParam,
2967                                                 GetMessageTime());
2968         /* We are not in a modal loop so no pumping is necessary. */
2969         break;
2970       }
2971 #endif
2972
2973 #ifdef HAVE_MENUBARS
2974     case WM_INITMENU:
2975       if (UNBOUNDP (mswindows_handle_wm_initmenu (
2976                                                   (HMENU) wParam,
2977                                                   XFRAME (mswindows_find_frame (hwnd)))))
2978         SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2979       break;
2980
2981     case WM_INITMENUPOPUP:
2982       if (!HIWORD(lParam))
2983         {
2984           if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2985                                                            (HMENU) wParam,
2986                                                            XFRAME (mswindows_find_frame (hwnd)))))
2987             SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2988         }
2989       break;
2990
2991 #endif /* HAVE_MENUBARS */
2992
2993     case WM_COMMAND:
2994       {
2995         WORD id = LOWORD (wParam);
2996         WORD nid = HIWORD (wParam);
2997         HWND cid = (HWND)lParam;
2998         frame = XFRAME (mswindows_find_frame (hwnd));
2999
3000 #ifdef HAVE_TOOLBARS
3001         if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
3002           break;
3003 #endif
3004         /* widgets in a buffer only eval a callback for suitable events.*/
3005         switch (nid)
3006           {
3007           case BN_CLICKED:
3008           case EN_CHANGE:
3009           case CBN_EDITCHANGE:
3010           case CBN_SELCHANGE:
3011             if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
3012               return 0;
3013           }
3014         /* menubars always must come last since the hashtables do not
3015            always exist*/
3016 #ifdef HAVE_MENUBARS
3017         if (!NILP (mswindows_handle_wm_command (frame, id)))
3018           break;
3019 #endif
3020
3021         return DefWindowProc (hwnd, message_, wParam, lParam);
3022         /* Bite me - a spurious command. This used to not be able to
3023            happen but with the introduction of widgets its now
3024            possible. */
3025       }
3026       break;
3027
3028     case WM_CTLCOLORBTN:
3029     case WM_CTLCOLORLISTBOX:
3030     case WM_CTLCOLOREDIT:
3031     case WM_CTLCOLORSTATIC:
3032     case WM_CTLCOLORSCROLLBAR:
3033       {
3034         /* if we get an opportunity to paint a widget then do so if
3035            there is an appropriate face */
3036         HWND crtlwnd = (HWND)lParam;
3037         LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
3038         if (ii)
3039           {
3040             Lisp_Object image_instance;
3041             VOID_TO_LISP (image_instance, ii);
3042             if (IMAGE_INSTANCEP (image_instance)
3043                 &&
3044                 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET))
3045               {
3046                 /* set colors for the buttons */
3047                 HDC hdc = (HDC)wParam;
3048                 if (last_widget_brushed != ii)
3049                   {
3050                     if (widget_brush)
3051                       DeleteObject (widget_brush);
3052                     widget_brush = CreateSolidBrush
3053                       (COLOR_INSTANCE_MSWINDOWS_COLOR
3054                        (XCOLOR_INSTANCE
3055                         (FACE_BACKGROUND
3056                          (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3057                           XIMAGE_INSTANCE_FRAME (image_instance)))));
3058                   }
3059                 last_widget_brushed = ii;
3060                 SetTextColor
3061                   (hdc,
3062                    COLOR_INSTANCE_MSWINDOWS_COLOR
3063                    (XCOLOR_INSTANCE
3064                     (FACE_FOREGROUND
3065                      (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3066                       XIMAGE_INSTANCE_FRAME (image_instance)))));
3067                 SetBkMode (hdc, OPAQUE);
3068                 SetBkColor
3069                   (hdc,
3070                    COLOR_INSTANCE_MSWINDOWS_COLOR
3071                    (XCOLOR_INSTANCE
3072                     (FACE_BACKGROUND
3073                      (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
3074                       XIMAGE_INSTANCE_FRAME (image_instance)))));
3075                 return (LRESULT)widget_brush;
3076               }
3077           }
3078       }
3079       goto defproc;
3080
3081 #ifdef HAVE_DRAGNDROP
3082     case WM_DROPFILES:  /* implementation ripped-off from event-Xt.c */
3083       {
3084         UINT filecount, i, len;
3085         POINT point;
3086         char* filename;
3087         char* fname;
3088
3089         Lisp_Object l_dndlist = Qnil, l_item = Qnil;
3090         struct gcpro gcpro1, gcpro2, gcpro3;
3091
3092         emacs_event = Fmake_event (Qnil, Qnil);
3093         event = XEVENT(emacs_event);
3094
3095         GCPRO3 (emacs_event, l_dndlist, l_item);
3096
3097         if (!DragQueryPoint ((HDROP) wParam, &point))
3098           point.x = point.y = -1;               /* outside client area */
3099
3100         event->event_type = misc_user_event;
3101         event->channel = mswindows_find_frame(hwnd);
3102         event->timestamp = GetMessageTime();
3103         event->event.misc.button = 1;           /* #### Should try harder */
3104         event->event.misc.modifiers = mswindows_modifier_state (NULL,
3105                                                                 (DWORD) -1, 0);
3106         event->event.misc.x = point.x;
3107         event->event.misc.y = point.y;
3108         event->event.misc.function = Qdragdrop_drop_dispatch;
3109
3110         filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0);
3111         for (i=0; i<filecount; i++)
3112           {
3113             len = DragQueryFile ((HDROP) wParam, i, NULL, 0);
3114             /* The URLs that we make here aren't correct according to section
3115              * 3.10 of rfc1738 because they're missing the //<host>/ part and
3116              * because they may contain reserved characters. But that's OK -
3117              * they just need to be good enough to keep dragdrop.el happy. */
3118             fname = (char *)xmalloc (len+1);
3119             DragQueryFile ((HANDLE) wParam, i, fname, len+1);
3120
3121             /* May be a shell link aka "shortcut" - replace fname if so */
3122 #if !(defined(CYGWIN) || defined(MINGW))
3123             /* cygwin doesn't define this COM stuff */
3124             if (!stricmp (fname + strlen (fname) - 4, ".LNK"))
3125               {
3126                 IShellLink* psl;
3127
3128                 if (CoCreateInstance (&CLSID_ShellLink, NULL,
3129                                       CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK)
3130                   {
3131                     IPersistFile* ppf;
3132
3133                     if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile,
3134                                                      &ppf) == S_OK)
3135                       {
3136                         OLECHAR wsz[PATH_MAX];
3137                         WIN32_FIND_DATA wfd;
3138                         LPSTR resolved = (char *) xmalloc (PATH_MAX+1);
3139
3140                         MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, PATH_MAX);
3141
3142                         if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) &&
3143                             (psl->lpVtbl->GetPath (psl, resolved, PATH_MAX,
3144                                                    &wfd, 0)==S_OK))
3145                           {
3146                             xfree (fname);
3147                             fname = resolved;
3148                             len = strlen (fname);
3149                           }
3150
3151                         ppf->lpVtbl->Release (ppf);
3152                       }
3153
3154                     psl->lpVtbl->Release (psl);
3155                   }
3156               }
3157 #endif
3158
3159 #ifdef CYGWIN
3160             filename = xmalloc (cygwin_win32_to_posix_path_list_buf_size (fname) + 5);
3161             strcpy (filename, "file:");
3162             cygwin_win32_to_posix_path_list (fname, filename+5);
3163 #else
3164             filename = (char *)xmalloc (len+6);
3165             strcat (strcpy (filename, "file:"), fname);
3166             dostounix_filename (filename+5);
3167 #endif
3168             xfree (fname);
3169             l_item = make_string (filename, strlen (filename));
3170             l_dndlist = Fcons (l_item, l_dndlist);
3171             xfree (filename);
3172           }
3173         DragFinish ((HDROP) wParam);
3174
3175         event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
3176         mswindows_enqueue_dispatch_event (emacs_event);
3177         UNGCPRO;
3178       }
3179       break;
3180 #endif
3181
3182     defproc:
3183     default:
3184       return DefWindowProc (hwnd, message_, wParam, lParam);
3185     }
3186   return (0);
3187 }
3188
3189
3190 /************************************************************************/
3191 /*      keyboard, mouse & other helpers for the windows procedure       */
3192 /************************************************************************/
3193 static void
3194 mswindows_set_chord_timer (HWND hwnd)
3195 {
3196   int interval;
3197
3198   /* We get one third half system double click threshold */
3199   if (mswindows_mouse_button_tolerance <= 0)
3200     interval = GetDoubleClickTime () / 3;
3201   else
3202     interval = mswindows_mouse_button_tolerance;
3203
3204   SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
3205 }
3206
3207 static int
3208 mswindows_button2_near_enough (POINTS p1, POINTS p2)
3209 {
3210   int dx, dy;
3211   if (mswindows_mouse_button_max_skew_x <= 0)
3212     dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
3213   else
3214     dx = mswindows_mouse_button_max_skew_x;
3215
3216   if (mswindows_mouse_button_max_skew_y <= 0)
3217     dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
3218   else
3219     dy = mswindows_mouse_button_max_skew_y;
3220
3221   return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
3222 }
3223
3224 static int
3225 mswindows_current_layout_has_AltGr (void)
3226 {
3227   /* This simple caching mechanism saves 10% of CPU
3228      time when a key typed at autorepeat rate of 30 cps! */
3229   static HKL last_hkl = 0;
3230   static int last_hkl_has_AltGr;
3231   HKL current_hkl = (HKL) -1;
3232
3233   if (xGetKeyboardLayout) /* not in NT 3.5 */
3234     current_hkl = xGetKeyboardLayout (0);
3235   if (current_hkl != last_hkl)
3236     {
3237       TCHAR c;
3238       last_hkl_has_AltGr = 0;
3239       /* In this loop, we query whether a character requires
3240          AltGr to be down to generate it. If at least such one
3241          found, this means that the layout does regard AltGr */
3242       for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
3243         if (HIBYTE (VkKeyScan (c)) == 6)
3244           last_hkl_has_AltGr = 1;
3245       last_hkl = current_hkl;
3246     }
3247   return last_hkl_has_AltGr;
3248 }
3249
3250
3251 /* Returns the state of the modifier keys in the format expected by the
3252  * Lisp_Event key_data, button_data and motion_data modifiers member */
3253 static int
3254 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr)
3255 {
3256   int mods = 0;
3257   int keys_is_real = 0;
3258   BYTE keymap2[256];
3259
3260   if (fwKeys == (DWORD) -1)
3261     fwKeys = mswindows_last_mouse_button_state;
3262   else
3263     {
3264       keys_is_real = 1;
3265       mswindows_last_mouse_button_state = fwKeys;
3266     }
3267
3268   if (keymap == NULL)
3269     {
3270       keymap = keymap2;
3271       GetKeyboardState (keymap);
3272       has_AltGr = mswindows_current_layout_has_AltGr ();
3273     }
3274
3275   /* #### should look at fwKeys for MK_CONTROL.  I don't understand how
3276      AltGr works. */
3277   if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
3278     {
3279       mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0;
3280       mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3281     }
3282   else
3283     {
3284       mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0;
3285       mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0;
3286     }
3287
3288   mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80))
3289     ? XEMACS_MOD_SHIFT : 0;
3290   mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0;
3291   mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0;
3292   mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0;
3293
3294   return mods;
3295 }
3296
3297 /*
3298  * Translate a mswindows virtual key to a keysym.
3299  * Only returns non-Qnil for keys that don't generate WM_CHAR messages
3300  * or whose ASCII codes (like space) xemacs doesn't like.
3301  */
3302 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods,
3303                                            int extendedp)
3304 {
3305   if (extendedp)        /* Keys not present on a 82 key keyboard */
3306     {
3307       switch (mswindows_key)
3308         {
3309         case VK_CANCEL:         return KEYSYM ("pause");
3310         case VK_RETURN:         return KEYSYM ("kp-enter");
3311         case VK_PRIOR:          return KEYSYM ("prior");
3312         case VK_NEXT:           return KEYSYM ("next");
3313         case VK_END:            return KEYSYM ("end");
3314         case VK_HOME:           return KEYSYM ("home");
3315         case VK_LEFT:           return KEYSYM ("left");
3316         case VK_UP:             return KEYSYM ("up");
3317         case VK_RIGHT:          return KEYSYM ("right");
3318         case VK_DOWN:           return KEYSYM ("down");
3319         case VK_INSERT:         return KEYSYM ("insert");
3320         case VK_DELETE:         return QKdelete;
3321 #if 0   /* FSF Emacs allows these to return configurable syms/mods */
3322         case VK_LWIN            return KEYSYM ("");
3323         case VK_RWIN            return KEYSYM ("");
3324 #endif
3325         case VK_APPS:           return KEYSYM ("menu");
3326         }
3327     }
3328   else
3329     {
3330       switch (mswindows_key)
3331         {
3332         case VK_BACK:           return QKbackspace;
3333         case VK_TAB:            return QKtab;
3334         case '\n':              return QKlinefeed;
3335         case VK_CLEAR:          return KEYSYM ("clear");
3336         case VK_RETURN:         return QKreturn;
3337         case VK_PAUSE:          return KEYSYM ("pause");
3338         case VK_ESCAPE:         return QKescape;
3339         case VK_SPACE:          return QKspace;
3340         case VK_PRIOR:          return KEYSYM ("kp-prior");
3341         case VK_NEXT:           return KEYSYM ("kp-next");
3342         case VK_END:            return KEYSYM ("kp-end");
3343         case VK_HOME:           return KEYSYM ("kp-home");
3344         case VK_LEFT:           return KEYSYM ("kp-left");
3345         case VK_UP:             return KEYSYM ("kp-up");
3346         case VK_RIGHT:          return KEYSYM ("kp-right");
3347         case VK_DOWN:           return KEYSYM ("kp-down");
3348         case VK_SELECT:         return KEYSYM ("select");
3349         case VK_PRINT:          return KEYSYM ("print");
3350         case VK_EXECUTE:        return KEYSYM ("execute");
3351         case VK_SNAPSHOT:       return KEYSYM ("print");
3352         case VK_INSERT:         return KEYSYM ("kp-insert");
3353         case VK_DELETE:         return KEYSYM ("kp-delete");
3354         case VK_HELP:           return KEYSYM ("help");
3355         case VK_NUMPAD0:        return KEYSYM ("kp-0");
3356         case VK_NUMPAD1:        return KEYSYM ("kp-1");
3357         case VK_NUMPAD2:        return KEYSYM ("kp-2");
3358         case VK_NUMPAD3:        return KEYSYM ("kp-3");
3359         case VK_NUMPAD4:        return KEYSYM ("kp-4");
3360         case VK_NUMPAD5:        return KEYSYM ("kp-5");
3361         case VK_NUMPAD6:        return KEYSYM ("kp-6");
3362         case VK_NUMPAD7:        return KEYSYM ("kp-7");
3363         case VK_NUMPAD8:        return KEYSYM ("kp-8");
3364         case VK_NUMPAD9:        return KEYSYM ("kp-9");
3365         case VK_MULTIPLY:       return KEYSYM ("kp-multiply");
3366         case VK_ADD:            return KEYSYM ("kp-add");
3367         case VK_SEPARATOR:      return KEYSYM ("kp-separator");
3368         case VK_SUBTRACT:       return KEYSYM ("kp-subtract");
3369         case VK_DECIMAL:        return KEYSYM ("kp-decimal");
3370         case VK_DIVIDE:         return KEYSYM ("kp-divide");
3371         case VK_F1:             return KEYSYM ("f1");
3372         case VK_F2:             return KEYSYM ("f2");
3373         case VK_F3:             return KEYSYM ("f3");
3374         case VK_F4:             return KEYSYM ("f4");
3375         case VK_F5:             return KEYSYM ("f5");
3376         case VK_F6:             return KEYSYM ("f6");
3377         case VK_F7:             return KEYSYM ("f7");
3378         case VK_F8:             return KEYSYM ("f8");
3379         case VK_F9:             return KEYSYM ("f9");
3380         case VK_F10:            return KEYSYM ("f10");
3381         case VK_F11:            return KEYSYM ("f11");
3382         case VK_F12:            return KEYSYM ("f12");
3383         case VK_F13:            return KEYSYM ("f13");
3384         case VK_F14:            return KEYSYM ("f14");
3385         case VK_F15:            return KEYSYM ("f15");
3386         case VK_F16:            return KEYSYM ("f16");
3387         case VK_F17:            return KEYSYM ("f17");
3388         case VK_F18:            return KEYSYM ("f18");
3389         case VK_F19:            return KEYSYM ("f19");
3390         case VK_F20:            return KEYSYM ("f20");
3391         case VK_F21:            return KEYSYM ("f21");
3392         case VK_F22:            return KEYSYM ("f22");
3393         case VK_F23:            return KEYSYM ("f23");
3394         case VK_F24:            return KEYSYM ("f24");
3395         }
3396     }
3397   return Qnil;
3398 }
3399
3400 /*
3401  * Find the console that matches the supplied mswindows window handle
3402  */
3403 Lisp_Object
3404 mswindows_find_console (HWND hwnd)
3405 {
3406   /* We only support one console */
3407   return XCAR (Vconsole_list);
3408 }
3409
3410 /*
3411  * Find the frame that matches the supplied mswindows window handle
3412  */
3413 Lisp_Object
3414 mswindows_find_frame (HWND hwnd)
3415 {
3416   LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
3417   Lisp_Object f;
3418   if (l == 0)
3419     {
3420       /* We are in progress of frame creation. Return the frame
3421          being created, as it still not remembered in the window
3422          extra storage. */
3423       assert (!NILP (Vmswindows_frame_being_created));
3424       return Vmswindows_frame_being_created;
3425     }
3426   VOID_TO_LISP (f, l);
3427   return f;
3428 }
3429
3430 \f
3431 /************************************************************************/
3432 /*                            methods                                   */
3433 /************************************************************************/
3434
3435 static int
3436 emacs_mswindows_add_timeout (EMACS_TIME thyme)
3437 {
3438   int milliseconds;
3439   EMACS_TIME current_time;
3440   EMACS_GET_TIME (current_time);
3441   EMACS_SUB_TIME (thyme, thyme, current_time);
3442   milliseconds = EMACS_SECS (thyme) * 1000 +
3443     (EMACS_USECS (thyme) + 500) / 1000;
3444   if (milliseconds < 1)
3445     milliseconds = 1;
3446   ++mswindows_pending_timers_count;
3447   return SetTimer (NULL, 0, milliseconds,
3448                    (TIMERPROC) mswindows_wm_timer_callback);
3449 }
3450
3451 static void
3452 emacs_mswindows_remove_timeout (int id)
3453 {
3454   Lisp_Event match_against;
3455   Lisp_Object emacs_event;
3456
3457   if (KillTimer (NULL, id))
3458     --mswindows_pending_timers_count;
3459
3460   /* If there is a dispatch event generated by this
3461      timeout in the queue, we have to remove it too. */
3462   match_against.event_type = timeout_event;
3463   match_against.event.timeout.interval_id = id;
3464   emacs_event = mswindows_cancel_dispatch_event (&match_against);
3465   if (!NILP (emacs_event))
3466     Fdeallocate_event(emacs_event);
3467 }
3468
3469 /* If `user_p' is false, then return whether there are any win32, timeout,
3470  * or subprocess events pending (that is, whether
3471  * emacs_mswindows_next_event() would return immediately without blocking).
3472  *
3473  * if `user_p' is true, then return whether there are any *user generated*
3474  * events available (that is, whether there are keyboard or mouse-click
3475  * events ready to be read).  This also implies that
3476  * emacs_mswindows_next_event() would not block.
3477  */
3478 static int
3479 emacs_mswindows_event_pending_p (int user_p)
3480 {
3481   mswindows_need_event (0);
3482   return (!NILP (mswindows_u_dispatch_event_queue)
3483           || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
3484 }
3485
3486 /*
3487  * Return the next event
3488  */
3489 static void
3490 emacs_mswindows_next_event (Lisp_Event *emacs_event)
3491 {
3492   Lisp_Object event, event2;
3493
3494   mswindows_need_event (1);
3495
3496   event = mswindows_dequeue_dispatch_event ();
3497   XSETEVENT (event2, emacs_event);
3498   Fcopy_event (event, event2);
3499   Fdeallocate_event (event);
3500 }
3501
3502 /*
3503  * Handle a magic event off the dispatch queue.
3504  */
3505 static void
3506 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event)
3507 {
3508   switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
3509     {
3510     case XM_BUMPQUEUE:
3511       break;
3512
3513     case WM_PAINT:
3514       {
3515         struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event));
3516         mswindows_handle_paint (f);
3517         (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0;
3518       }
3519       break;
3520
3521     case WM_SETFOCUS:
3522     case WM_KILLFOCUS:
3523       {
3524         Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3525         struct frame *f = XFRAME (frame);
3526         int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
3527         Lisp_Object conser;
3528         struct gcpro gcpro1;
3529
3530         /* On focus change, clear all memory of sticky modifiers
3531            to avoid non-intuitive behavior. */
3532         clear_sticky_modifiers ();
3533
3534         conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
3535         GCPRO1 (conser);
3536         emacs_handle_focus_change_preliminary (conser);
3537         /* Under X the stuff up to here is done in the X event handler.
3538            I Don't know why */
3539         emacs_handle_focus_change_final (conser);
3540         UNGCPRO;
3541
3542       }
3543       break;
3544
3545     case XM_MAPFRAME:
3546     case XM_UNMAPFRAME:
3547       {
3548         Lisp_Object frame = EVENT_CHANNEL (emacs_event);
3549         va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)
3550                                == XM_MAPFRAME ?
3551                                Qmap_frame_hook : Qunmap_frame_hook,
3552                                1, frame);
3553       }
3554       break;
3555
3556       /* #### What about Enter & Leave */
3557 #if 0
3558       va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
3559                              Qmouse_leave_frame_hook, 1, frame);
3560 #endif
3561
3562     default:
3563       assert(0);
3564     }
3565 }
3566
3567 #ifndef HAVE_MSG_SELECT
3568 static HANDLE
3569 get_process_input_waitable (Lisp_Process *process)
3570 {
3571   Lisp_Object instr, outstr, p;
3572   XSETPROCESS (p, process);
3573   get_process_streams (process, &instr, &outstr);
3574   assert (!NILP (instr));
3575 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3576   return (network_connection_p (p)
3577           ? get_winsock_stream_waitable (XLSTREAM (instr))
3578           : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
3579 #else
3580   return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
3581 #endif
3582 }
3583
3584 static void
3585 emacs_mswindows_select_process (Lisp_Process *process)
3586 {
3587   HANDLE hev = get_process_input_waitable (process);
3588
3589   if (!add_waitable_handle (hev))
3590     error ("Too many active processes");
3591
3592 #ifdef HAVE_WIN32_PROCESSES
3593   {
3594     Lisp_Object p;
3595     XSETPROCESS (p, process);
3596     if (!network_connection_p (p))
3597       {
3598         HANDLE hprocess = get_nt_process_handle (process);
3599         if (!add_waitable_handle (hprocess))
3600           {
3601             remove_waitable_handle (hev);
3602             error ("Too many active processes");
3603           }
3604       }
3605   }
3606 #endif
3607 }
3608
3609 static void
3610 emacs_mswindows_unselect_process (Lisp_Process *process)
3611 {
3612   /* Process handle is removed in the event loop as soon
3613      as it is signaled, so don't bother here about it */
3614   HANDLE hev = get_process_input_waitable (process);
3615   remove_waitable_handle (hev);
3616 }
3617 #endif /* HAVE_MSG_SELECT */
3618
3619 static void
3620 emacs_mswindows_select_console (struct console *con)
3621 {
3622 #ifdef HAVE_MSG_SELECT
3623   if (CONSOLE_MSWINDOWS_P (con))
3624     return; /* mswindows consoles are automatically selected */
3625
3626   event_stream_unixoid_select_console (con);
3627 #endif
3628 }
3629
3630 static void
3631 emacs_mswindows_unselect_console (struct console *con)
3632 {
3633 #ifdef HAVE_MSG_SELECT
3634   if (CONSOLE_MSWINDOWS_P (con))
3635     return; /* mswindows consoles are automatically selected */
3636
3637   event_stream_unixoid_unselect_console (con);
3638 #endif
3639 }
3640
3641 static void
3642 emacs_mswindows_quit_p (void)
3643 {
3644   /* Quit cannot happen in modal loop: all program
3645      input is dedicated to Windows. */
3646   if (mswindows_in_modal_loop)
3647     return;
3648
3649   mswindows_quit_chars_count = 0;
3650   /* Drain windows queue.  This sets up number of quit characters in
3651      the queue. */
3652   mswindows_drain_windows_queue ();
3653
3654   if (mswindows_quit_chars_count > 0)
3655     {
3656       /* Yes there's a hidden one... Throw it away */
3657       Lisp_Event match_against;
3658       Lisp_Object emacs_event;
3659       int critical_p = 0;
3660
3661       match_against.event_type = key_press_event;
3662       match_against.event.key.modifiers = FAKE_MOD_QUIT;
3663
3664       while (mswindows_quit_chars_count > 0)
3665         {
3666           emacs_event = mswindows_cancel_dispatch_event (&match_against);
3667           assert (!NILP (emacs_event));
3668
3669           if (XEVENT (emacs_event)->event.key.modifiers &
3670               FAKE_MOD_QUIT_CRITICAL)
3671             critical_p = 1;
3672
3673           Fdeallocate_event (emacs_event);
3674           mswindows_quit_chars_count--;
3675         }
3676
3677       Vquit_flag = critical_p ? Qcritical : Qt;
3678     }
3679 }
3680
3681 USID
3682 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
3683                                     Lisp_Object* instream,
3684                                     Lisp_Object* outstream,
3685                                     int flags)
3686 {
3687   /* Handles for streams */
3688   HANDLE hin, hout;
3689   /* fds. These just stored along with the streams, and are closed in
3690      delete stream pair method, because we need to handle fake unices
3691      here. */
3692   int fdi, fdo;
3693
3694   /* Decode inhandle and outhandle. Their meaning depends on
3695      the process implementation being used. */
3696 #if defined (HAVE_WIN32_PROCESSES)
3697   /* We're passed in Windows handles. That's what we like most... */
3698   hin = (HANDLE) inhandle;
3699   hout = (HANDLE) outhandle;
3700   fdi = fdo = -1;
3701 #elif defined (HAVE_UNIX_PROCESSES)
3702   /* We are passed UNIX fds. This must be Cygwin.
3703      Fetch os handles */
3704   hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
3705   hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
3706   fdi=(int)inhandle;
3707   fdo=(int)outhandle;
3708 #else
3709 #error "So, WHICH kind of processes do you want?"
3710 #endif
3711
3712   *instream = (hin == INVALID_HANDLE_VALUE
3713                ? Qnil
3714 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3715                : flags & STREAM_NETWORK_CONNECTION
3716                ? make_winsock_input_stream ((SOCKET)hin, fdi)
3717 #endif
3718                : make_ntpipe_input_stream (hin, fdi));
3719
3720 #ifdef HAVE_WIN32_PROCESSES
3721   *outstream = (hout == INVALID_HANDLE_VALUE
3722                 ? Qnil
3723 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
3724                 : flags & STREAM_NETWORK_CONNECTION
3725                 ? make_winsock_output_stream ((SOCKET)hout, fdo)
3726 #endif
3727                 : make_ntpipe_output_stream (hout, fdo));
3728 #elif defined (HAVE_UNIX_PROCESSES)
3729   *outstream = (fdo >= 0
3730                 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
3731                 : Qnil);
3732
3733 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
3734   /* FLAGS is process->pty_flag for UNIX_PROCESSES */
3735   if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
3736     {
3737       Bufbyte eof_char = get_eof_char (fdo);
3738       int pty_max_bytes = get_pty_max_bytes (fdo);
3739       filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
3740     }
3741 #endif
3742 #endif
3743
3744   return (NILP (*instream)
3745           ? USID_ERROR
3746 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3747           : flags & STREAM_NETWORK_CONNECTION
3748           ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
3749 #endif
3750           : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
3751 }
3752
3753 USID
3754 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
3755                                     Lisp_Object outstream)
3756 {
3757   /* Oh nothing special here for Win32 at all */
3758 #if defined (HAVE_UNIX_PROCESSES)
3759   int in = (NILP(instream)
3760             ? -1
3761 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3762             : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3763             ? get_winsock_stream_param (XLSTREAM (instream))
3764 #endif
3765             : get_ntpipe_input_stream_param (XLSTREAM (instream)));
3766   int out = (NILP(outstream) ? -1
3767              : filedesc_stream_fd (XLSTREAM (outstream)));
3768
3769   if (in >= 0)
3770     close (in);
3771   if (out != in && out >= 0)
3772     close (out);
3773 #endif
3774
3775   return (NILP (instream)
3776           ? USID_DONTHASH
3777 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
3778           : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
3779           ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
3780 #endif
3781           : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
3782 }
3783
3784 static int
3785 emacs_mswindows_current_event_timestamp (struct console *c)
3786 {
3787   return GetTickCount ();
3788 }
3789
3790 #ifndef HAVE_X_WINDOWS
3791 /* This is called from GC when a process object is about to be freed.
3792    If we've still got pointers to it in this file, we're gonna lose hard.
3793  */
3794 void
3795 debug_process_finalization (Lisp_Process *p)
3796 {
3797 #if 0 /* #### */
3798   Lisp_Object instr, outstr;
3799
3800   get_process_streams (p, &instr, &outstr);
3801   /* if it still has fds, then it hasn't been killed yet. */
3802   assert (NILP(instr));
3803   assert (NILP(outstr));
3804
3805   /* #### More checks here */
3806 #endif
3807 }
3808 #endif
3809
3810 #ifdef DEBUG_XEMACS
3811
3812 struct mswin_message_debug
3813 {
3814   int mess;
3815   char *string;
3816 };
3817
3818 #define FROB(val) { val, #val, },
3819
3820 struct mswin_message_debug debug_mswin_messages[] =
3821 {
3822 FROB (WM_NULL)
3823 FROB (WM_CREATE)
3824 FROB (WM_DESTROY)
3825 FROB (WM_MOVE)
3826 FROB (WM_SIZE)
3827
3828 FROB (WM_ACTIVATE)
3829
3830 FROB (WM_SETFOCUS)
3831 FROB (WM_KILLFOCUS)
3832 FROB (WM_ENABLE)
3833 FROB (WM_SETREDRAW)
3834 FROB (WM_SETTEXT)
3835 FROB (WM_GETTEXT)
3836 FROB (WM_GETTEXTLENGTH)
3837 FROB (WM_PAINT)
3838 FROB (WM_CLOSE)
3839 FROB (WM_QUERYENDSESSION)
3840 FROB (WM_QUIT)
3841 FROB (WM_QUERYOPEN)
3842 FROB (WM_ERASEBKGND)
3843 FROB (WM_SYSCOLORCHANGE)
3844 FROB (WM_ENDSESSION)
3845 FROB (WM_SHOWWINDOW)
3846 FROB (WM_WININICHANGE)
3847 #if(WINVER >= 0x0400)
3848 FROB (WM_SETTINGCHANGE)
3849 #endif /* WINVER >= 0x0400 */
3850
3851 FROB (WM_DEVMODECHANGE)
3852 FROB (WM_ACTIVATEAPP)
3853 FROB (WM_FONTCHANGE)
3854 FROB (WM_TIMECHANGE)
3855 FROB (WM_CANCELMODE)
3856 FROB (WM_SETCURSOR)
3857 FROB (WM_MOUSEACTIVATE)
3858 FROB (WM_CHILDACTIVATE)
3859 FROB (WM_QUEUESYNC)
3860
3861 FROB (WM_GETMINMAXINFO)
3862
3863 FROB (WM_PAINTICON)
3864 FROB (WM_ICONERASEBKGND)
3865 FROB (WM_NEXTDLGCTL)
3866 FROB (WM_SPOOLERSTATUS)
3867 FROB (WM_DRAWITEM)
3868 FROB (WM_MEASUREITEM)
3869 FROB (WM_DELETEITEM)
3870 FROB (WM_VKEYTOITEM)
3871 FROB (WM_CHARTOITEM)
3872 FROB (WM_SETFONT)
3873 FROB (WM_GETFONT)
3874 FROB (WM_SETHOTKEY)
3875 FROB (WM_GETHOTKEY)
3876 FROB (WM_QUERYDRAGICON)
3877 FROB (WM_COMPAREITEM)
3878 #if(WINVER >= 0x0500) && defined(WM_GETOBJECT)
3879 FROB (WM_GETOBJECT)
3880 #endif /* WINVER >= 0x0500 */
3881 FROB (WM_COMPACTING)
3882 FROB (WM_COMMNOTIFY)
3883 FROB (WM_WINDOWPOSCHANGING)
3884 FROB (WM_WINDOWPOSCHANGED)
3885
3886 FROB (WM_POWER)
3887
3888 FROB (WM_COPYDATA)
3889 FROB (WM_CANCELJOURNAL)
3890
3891 #if(WINVER >= 0x0400)
3892 FROB (WM_NOTIFY)
3893 FROB (WM_INPUTLANGCHANGEREQUEST)
3894 FROB (WM_INPUTLANGCHANGE)
3895 FROB (WM_TCARD)
3896 FROB (WM_HELP)
3897 FROB (WM_USERCHANGED)
3898 FROB (WM_NOTIFYFORMAT)
3899
3900 FROB (WM_CONTEXTMENU)
3901 FROB (WM_STYLECHANGING)
3902 FROB (WM_STYLECHANGED)
3903 FROB (WM_DISPLAYCHANGE)
3904 FROB (WM_GETICON)
3905 FROB (WM_SETICON)
3906 #endif /* WINVER >= 0x0400 */
3907
3908 FROB (WM_NCCREATE)
3909 FROB (WM_NCDESTROY)
3910 FROB (WM_NCCALCSIZE)
3911 FROB (WM_NCHITTEST)
3912 FROB (WM_NCPAINT)
3913 FROB (WM_NCACTIVATE)
3914 FROB (WM_GETDLGCODE)
3915 #ifdef WM_SYNCPAINT /* not in VC 5 */
3916 FROB (WM_SYNCPAINT)
3917 #endif /* WM_SYNCPAINT */
3918 FROB (WM_NCMOUSEMOVE)
3919 FROB (WM_NCLBUTTONDOWN)
3920 FROB (WM_NCLBUTTONUP)
3921 FROB (WM_NCLBUTTONDBLCLK)
3922 FROB (WM_NCRBUTTONDOWN)
3923 FROB (WM_NCRBUTTONUP)
3924 FROB (WM_NCRBUTTONDBLCLK)
3925 FROB (WM_NCMBUTTONDOWN)
3926 FROB (WM_NCMBUTTONUP)
3927 FROB (WM_NCMBUTTONDBLCLK)
3928
3929 /* FROB (WM_KEYFIRST) */
3930 FROB (WM_KEYDOWN)
3931 FROB (WM_KEYUP)
3932 FROB (WM_CHAR)
3933 FROB (WM_DEADCHAR)
3934 FROB (WM_SYSKEYDOWN)
3935 FROB (WM_SYSKEYUP)
3936 FROB (WM_SYSCHAR)
3937 FROB (WM_SYSDEADCHAR)
3938 FROB (WM_KEYLAST)
3939
3940 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION)
3941 FROB (WM_IME_STARTCOMPOSITION)
3942 FROB (WM_IME_ENDCOMPOSITION)
3943 FROB (WM_IME_COMPOSITION)
3944 FROB (WM_IME_KEYLAST)
3945 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */
3946
3947 FROB (WM_INITDIALOG)
3948 FROB (WM_COMMAND)
3949 FROB (WM_SYSCOMMAND)
3950 FROB (WM_TIMER)
3951 FROB (WM_HSCROLL)
3952 FROB (WM_VSCROLL)
3953 FROB (WM_INITMENU)
3954 FROB (WM_INITMENUPOPUP)
3955 FROB (WM_MENUSELECT)
3956 FROB (WM_MENUCHAR)
3957 FROB (WM_ENTERIDLE)
3958 #if(WINVER >= 0x0500)
3959 FROB (WM_MENURBUTTONUP)
3960 #ifdef WM_MENUDRAG
3961 FROB (WM_MENUDRAG)
3962 #endif
3963 #ifdef WM_MENUGETOBJECT
3964 FROB (WM_MENUGETOBJECT)
3965 #endif
3966 #ifdef WM_UNINITMENUPOPUP
3967 FROB (WM_UNINITMENUPOPUP)
3968 #endif
3969 #ifdef WM_MENUCOMMAND
3970 FROB (WM_MENUCOMMAND)
3971 #endif
3972 #endif /* WINVER >= 0x0500 */
3973
3974
3975 FROB (WM_CTLCOLORMSGBOX)
3976 FROB (WM_CTLCOLOREDIT)
3977 FROB (WM_CTLCOLORLISTBOX)
3978 FROB (WM_CTLCOLORBTN)
3979 FROB (WM_CTLCOLORDLG)
3980 FROB (WM_CTLCOLORSCROLLBAR)
3981 FROB (WM_CTLCOLORSTATIC)
3982
3983
3984 /* FROB (WM_MOUSEFIRST) */
3985 FROB (WM_MOUSEMOVE)
3986 FROB (WM_LBUTTONDOWN)
3987 FROB (WM_LBUTTONUP)
3988 FROB (WM_LBUTTONDBLCLK)
3989 FROB (WM_RBUTTONDOWN)
3990 FROB (WM_RBUTTONUP)
3991 FROB (WM_RBUTTONDBLCLK)
3992 FROB (WM_MBUTTONDOWN)
3993 FROB (WM_MBUTTONUP)
3994 FROB (WM_MBUTTONDBLCLK)
3995
3996 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
3997 FROB (WM_MOUSEWHEEL)
3998 FROB (WM_MOUSELAST)
3999 #else
4000 FROB (WM_MOUSELAST)
4001 #endif /* if (_WIN32_WINNT < 0x0400) */
4002
4003 FROB (WM_PARENTNOTIFY)
4004 FROB (WM_ENTERMENULOOP)
4005 FROB (WM_EXITMENULOOP)
4006
4007 #if(WINVER >= 0x0400)
4008 FROB (WM_NEXTMENU)
4009
4010 FROB (WM_SIZING)
4011 FROB (WM_CAPTURECHANGED)
4012 FROB (WM_MOVING)
4013 FROB (WM_POWERBROADCAST)
4014
4015 FROB (WM_DEVICECHANGE)
4016
4017 #endif /* WINVER >= 0x0400 */
4018
4019 FROB (WM_MDICREATE)
4020 FROB (WM_MDIDESTROY)
4021 FROB (WM_MDIACTIVATE)
4022 FROB (WM_MDIRESTORE)
4023 FROB (WM_MDINEXT)
4024 FROB (WM_MDIMAXIMIZE)
4025 FROB (WM_MDITILE)
4026 FROB (WM_MDICASCADE)
4027 FROB (WM_MDIICONARRANGE)
4028 FROB (WM_MDIGETACTIVE)
4029
4030
4031 FROB (WM_MDISETMENU)
4032 FROB (WM_ENTERSIZEMOVE)
4033 FROB (WM_EXITSIZEMOVE)
4034 FROB (WM_DROPFILES)
4035 FROB (WM_MDIREFRESHMENU)
4036
4037 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */
4038
4039 #if(WINVER >= 0x0400) && !defined(CYGWIN)
4040 FROB (WM_IME_SETCONTEXT)
4041 FROB (WM_IME_NOTIFY)
4042 FROB (WM_IME_CONTROL)
4043 FROB (WM_IME_COMPOSITIONFULL)
4044 FROB (WM_IME_SELECT)
4045 FROB (WM_IME_CHAR)
4046 #endif /* WINVER >= 0x0400 */
4047 #if(WINVER >= 0x0500) && defined(WM_IME_REQUEST)
4048 FROB (WM_IME_REQUEST)
4049 #endif /* WINVER >= 0x0500 */
4050 #if(WINVER >= 0x0400) && !defined(CYGWIN)
4051 FROB (WM_IME_KEYDOWN)
4052 FROB (WM_IME_KEYUP)
4053 #endif /* WINVER >= 0x0400 */
4054
4055 #endif /* WM_IME_SETCONTEXT */
4056
4057 #if(_WIN32_WINNT >= 0x0400)
4058 FROB (WM_MOUSEHOVER)
4059 FROB (WM_MOUSELEAVE)
4060 #endif /* _WIN32_WINNT >= 0x0400 */
4061
4062 FROB (WM_CUT)
4063 FROB (WM_COPY)
4064 FROB (WM_PASTE)
4065 FROB (WM_CLEAR)
4066 FROB (WM_UNDO)
4067 FROB (WM_RENDERFORMAT)
4068 FROB (WM_RENDERALLFORMATS)
4069 FROB (WM_DESTROYCLIPBOARD)
4070 FROB (WM_DRAWCLIPBOARD)
4071 FROB (WM_PAINTCLIPBOARD)
4072 FROB (WM_VSCROLLCLIPBOARD)
4073 FROB (WM_SIZECLIPBOARD)
4074 FROB (WM_ASKCBFORMATNAME)
4075 FROB (WM_CHANGECBCHAIN)
4076 FROB (WM_HSCROLLCLIPBOARD)
4077 FROB (WM_QUERYNEWPALETTE)
4078 FROB (WM_PALETTEISCHANGING)
4079 FROB (WM_PALETTECHANGED)
4080 FROB (WM_HOTKEY)
4081
4082 #if(WINVER >= 0x0400)
4083 FROB (WM_PRINT)
4084 FROB (WM_PRINTCLIENT)
4085
4086 FROB (WM_HANDHELDFIRST)
4087 FROB (WM_HANDHELDLAST)
4088
4089 FROB (WM_AFXFIRST)
4090 FROB (WM_AFXLAST)
4091 #endif /* WINVER >= 0x0400 */
4092
4093 FROB (WM_PENWINFIRST)
4094 FROB (WM_PENWINLAST)
4095 };
4096
4097 #undef FROB
4098
4099 static void
4100 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam,
4101                             LPARAM lParam)
4102 {
4103   Lisp_Object frame = mswindows_find_frame (hwnd);
4104   int i;
4105   char *str = 0;
4106   /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */
4107
4108   for (i = 0; i < countof (debug_mswin_messages); i++)
4109     {
4110       if (debug_mswin_messages[i].mess == message_)
4111         {
4112           str = debug_mswin_messages[i].string;
4113           break;
4114         }
4115     }
4116
4117   if (str)
4118     stderr_out ("%s", str);
4119   else
4120     stderr_out ("%x", message_);
4121
4122   if (debug_mswindows_events > 1)
4123     {
4124       stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ",
4125                   wParam, (int) lParam, (unsigned int) hwnd);
4126       debug_print (frame);
4127       if (message_ == WM_WINDOWPOSCHANGED ||
4128           message_ == WM_WINDOWPOSCHANGING)
4129         {
4130           WINDOWPOS *wp = (WINDOWPOS *) lParam;
4131           stderr_out("  WINDOWPOS: x=%d, y=%d, h=%d, w=%d\n",
4132                      wp->x, wp->y, wp->cx, wp->cy);
4133         }
4134       else if (message_ == WM_MOVE)
4135         {
4136           int x = (int)(short) LOWORD(lParam);   /* horizontal position */
4137           int y = (int)(short) HIWORD(lParam);   /* vertical position */
4138           stderr_out("  MOVE: x=%d, y=%d\n", x, y);
4139         }
4140       else if (message_ == WM_SIZE)
4141         {
4142           int w = (int)(short) LOWORD(lParam);   /* width */
4143           int h = (int)(short) HIWORD(lParam);   /* height */
4144           stderr_out("  SIZE: w=%d, h=%d\n", w, h);
4145         }
4146     }
4147   else
4148     stderr_out ("\n");
4149 }
4150
4151 #endif /* DEBUG_XEMACS */
4152
4153 /************************************************************************/
4154 /*                            initialization                            */
4155 /************************************************************************/
4156
4157 void
4158 reinit_vars_of_event_mswindows (void)
4159 {
4160   mswindows_in_modal_loop = 0;
4161   mswindows_pending_timers_count = 0;
4162
4163   mswindows_event_stream = xnew (struct event_stream);
4164
4165   mswindows_event_stream->event_pending_p       = emacs_mswindows_event_pending_p;
4166   mswindows_event_stream->force_event_pending = 0;
4167   mswindows_event_stream->next_event_cb         = emacs_mswindows_next_event;
4168   mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
4169   mswindows_event_stream->add_timeout_cb        = emacs_mswindows_add_timeout;
4170   mswindows_event_stream->remove_timeout_cb     = emacs_mswindows_remove_timeout;
4171   mswindows_event_stream->quit_p_cb             = emacs_mswindows_quit_p;
4172   mswindows_event_stream->select_console_cb     = emacs_mswindows_select_console;
4173   mswindows_event_stream->unselect_console_cb   = emacs_mswindows_unselect_console;
4174 #ifdef HAVE_MSG_SELECT
4175   mswindows_event_stream->select_process_cb     =
4176     (void (*)(Lisp_Process*))event_stream_unixoid_select_process;
4177   mswindows_event_stream->unselect_process_cb   =
4178     (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process;
4179   mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
4180   mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
4181 #else
4182   mswindows_event_stream->select_process_cb     = emacs_mswindows_select_process;
4183   mswindows_event_stream->unselect_process_cb   = emacs_mswindows_unselect_process;
4184   mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
4185   mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
4186 #endif
4187   mswindows_event_stream->current_event_timestamp_cb =
4188     emacs_mswindows_current_event_timestamp;
4189 }
4190
4191 void
4192 vars_of_event_mswindows (void)
4193 {
4194   reinit_vars_of_event_mswindows ();
4195
4196   mswindows_u_dispatch_event_queue = Qnil;
4197   staticpro (&mswindows_u_dispatch_event_queue);
4198   mswindows_u_dispatch_event_queue_tail = Qnil;
4199   dump_add_root_object (&mswindows_u_dispatch_event_queue_tail);
4200
4201   mswindows_s_dispatch_event_queue = Qnil;
4202   staticpro (&mswindows_s_dispatch_event_queue);
4203   mswindows_s_dispatch_event_queue_tail = Qnil;
4204   dump_add_root_object (&mswindows_s_dispatch_event_queue_tail);
4205
4206   mswindows_error_caught_in_modal_loop = Qnil;
4207   staticpro (&mswindows_error_caught_in_modal_loop);
4208
4209
4210 #ifdef DEBUG_XEMACS
4211   DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /*
4212 If non-zero, display debug information about Windows messages that XEmacs sees.
4213 Information is displayed in a console window.  Currently defined values are:
4214
4215 1 == non-verbose output (just the message name)
4216 2 == verbose output (all parameters)
4217 3 == even more verbose output (extra debugging info)
4218 */ );
4219   debug_mswindows_events = 0;
4220 #endif
4221
4222   DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu",
4223                &mswindows_alt_by_itself_activates_menu /*
4224 *Controls whether pressing and releasing the Alt key activates the menubar.
4225 This applies only if no intervening key was pressed.  See also
4226 `menu-accelerator-enabled', which is probably the behavior you actually want.
4227 Default is t.
4228 */ );
4229
4230   DEFVAR_BOOL ("mswindows-dynamic-frame-resize",
4231                &mswindows_dynamic_frame_resize /*
4232 *Controls redrawing frame contents during mouse-drag or keyboard resize
4233 operation. When non-nil, the frame is redrawn while being resized. When
4234 nil, frame is not redrawn, and exposed areas are filled with default
4235 MDI application background color. Note that this option only has effect
4236 if "Show window contents while dragging" is on in system Display/Plus!
4237 settings.
4238 Default is t on fast machines, nil on slow.
4239 */ );
4240
4241   DEFVAR_INT ("mswindows-mouse-button-tolerance",
4242               &mswindows_mouse_button_tolerance /*
4243 *Analogue of double click interval for faking middle mouse events.
4244 The value is the minimum time in milliseconds that must elapse between
4245 left/right button down events before they are considered distinct events.
4246 If both mouse buttons are depressed within this interval, a middle mouse
4247 button down event is generated instead.
4248 If negative or zero, currently set system default is used instead.
4249 */ );
4250
4251   DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
4252 Number of physical mouse buttons.
4253 */ );
4254
4255   DEFVAR_INT ("mswindows-mouse-button-max-skew-x",
4256               &mswindows_mouse_button_max_skew_x /*
4257 *Maximum horizontal distance in pixels between points in which left and
4258 right button clicks occurred for them to be translated into single
4259 middle button event. Clicks must occur in time not longer than defined
4260 by the variable `mswindows-mouse-button-tolerance'.
4261 If negative or zero, currently set system default is used instead.
4262 */ );
4263
4264   DEFVAR_INT ("mswindows-mouse-button-max-skew-y",
4265               &mswindows_mouse_button_max_skew_y /*
4266 *Maximum vertical distance in pixels between points in which left and
4267 right button clicks occurred for them to be translated into single
4268 middle button event. Clicks must occur in time not longer than defined
4269 by the variable `mswindows-mouse-button-tolerance'.
4270 If negative or zero, currently set system default is used instead.
4271 */ );
4272
4273   mswindows_mouse_button_max_skew_x = 0;
4274   mswindows_mouse_button_max_skew_y = 0;
4275   mswindows_mouse_button_tolerance = 0;
4276   mswindows_alt_by_itself_activates_menu = 1;
4277 }
4278
4279 void
4280 syms_of_event_mswindows (void)
4281 {
4282 }
4283
4284 void
4285 lstream_type_create_mswindows_selectable (void)
4286 {
4287   init_slurp_stream ();
4288   init_shove_stream ();
4289 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
4290   init_winsock_stream ();
4291 #endif
4292 }
4293
4294 void
4295 init_event_mswindows_late (void)
4296 {
4297 #ifdef HAVE_MSG_SELECT
4298   windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
4299   assert (windows_fd>=0);
4300   FD_SET (windows_fd, &input_wait_mask);
4301   FD_ZERO(&zero_mask);
4302 #endif
4303
4304   event_stream = mswindows_event_stream;
4305
4306   mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
4307   mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
4308 }