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