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