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