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