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