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