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