XEmacs 21.2.6
[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   event->event.timeout.function = Qnil;
1450   event->event.timeout.object = Qnil;
1451
1452   mswindows_enqueue_dispatch_event (emacs_event);
1453 }
1454
1455 /* 
1456  * Callback procedure for dde messages
1457  *
1458  * We execute a dde Open("file") by simulating a file drop, so dde support
1459  * depends on dnd support.
1460  */
1461 #ifdef HAVE_DRAGNDROP
1462 HDDEDATA CALLBACK
1463 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv,
1464                         HSZ hszTopic, HSZ hszItem, HDDEDATA hdata,
1465                         DWORD dwData1, DWORD dwData2)
1466
1467   switch (uType)
1468     { 
1469     case XTYP_CONNECT:
1470       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1471         return (HDDEDATA)TRUE;
1472       return (HDDEDATA)FALSE;
1473
1474     case XTYP_WILDCONNECT:
1475       {
1476         /* We only support one {service,topic} pair */
1477         HSZPAIR pairs[2] = {
1478           { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } };
1479
1480         if (!(hszItem  || DdeCmpStringHandles (hszItem, mswindows_dde_service)) &&
1481             !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)));
1482           return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs,
1483                                        sizeof (pairs), 0L, 0, uFmt, 0));
1484       }
1485       return (HDDEDATA)NULL; 
1486
1487     case XTYP_EXECUTE:
1488       if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))
1489         {
1490           DWORD len = DdeGetData (hdata, NULL, 0, 0);
1491           char *cmd = alloca (len+1);
1492           char *end;
1493           char *filename;
1494           struct gcpro gcpro1, gcpro2;
1495           Lisp_Object l_dndlist = Qnil;
1496           Lisp_Object emacs_event = Fmake_event (Qnil, Qnil);
1497           Lisp_Object frmcons, devcons, concons;
1498           struct Lisp_Event *event = XEVENT (emacs_event);
1499
1500           DdeGetData (hdata, cmd, len, 0);
1501           cmd[len] = '\0';
1502           DdeFreeDataHandle (hdata);
1503
1504           /* Check syntax & that it's an [Open("foo")] command, which we
1505            * treat like a file drop */
1506           /* #### Ought to be generalised and accept some other commands */
1507           if (*cmd == '[')
1508             cmd++;
1509           if (strnicmp (cmd, MSWINDOWS_DDE_ITEM_OPEN,
1510                         strlen (MSWINDOWS_DDE_ITEM_OPEN)))
1511             return DDE_FNOTPROCESSED;
1512           cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN);
1513           while (*cmd==' ')
1514             cmd++;
1515           if (*cmd!='(' || *(cmd+1)!='\"')
1516             return DDE_FNOTPROCESSED;
1517           end = (cmd+=2);
1518           while (*end && *end!='\"')
1519             end++;
1520           if (!*end)
1521             return DDE_FNOTPROCESSED;
1522           *end = '\0';
1523           if (*(++end)!=')')
1524             return DDE_FNOTPROCESSED;
1525           if (*(++end)==']')
1526             end++;
1527           if (*end)
1528             return DDE_FNOTPROCESSED;
1529
1530 #ifdef __CYGWIN32__
1531           filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5);
1532           strcpy (filename, "file:");
1533           cygwin32_win32_to_posix_path_list (cmd, filename+5);
1534 #else
1535           dostounix_filename (cmd);
1536           filename = alloca (strlen (cmd)+6);
1537           strcpy (filename, "file:");
1538           strcat (filename, cmd);
1539 #endif
1540           GCPRO2 (emacs_event, l_dndlist);
1541           l_dndlist = make_string (filename, strlen (filename));
1542
1543           /* Find a mswindows frame */
1544           event->channel = Qnil;
1545           FRAME_LOOP_NO_BREAK (frmcons, devcons, concons)
1546             {
1547               Lisp_Object frame = XCAR (frmcons);
1548               if (FRAME_TYPE_P (XFRAME (frame), mswindows))
1549                 event->channel = frame;
1550             };
1551           assert (!NILP (event->channel));
1552
1553           event->timestamp = GetTickCount();
1554           event->event_type = misc_user_event;
1555           event->event.misc.button = 1;
1556           event->event.misc.modifiers = 0;
1557           event->event.misc.x = -1;
1558           event->event.misc.y = -1;
1559           event->event.misc.function = Qdragdrop_drop_dispatch;
1560           event->event.misc.object = Fcons (Qdragdrop_URL,
1561                                             Fcons (l_dndlist, Qnil));
1562           mswindows_enqueue_dispatch_event (emacs_event);
1563           UNGCPRO;
1564           return (HDDEDATA) DDE_FACK;
1565         }
1566       DdeFreeDataHandle (hdata); 
1567       return (HDDEDATA) DDE_FNOTPROCESSED;
1568
1569     default: 
1570       return (HDDEDATA) NULL; 
1571     } 
1572 }
1573 #endif
1574
1575 /*
1576  * The windows procedure for the window class XEMACS_CLASS
1577  */
1578 LRESULT WINAPI
1579 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1580 {
1581   /* Note: Remember to initialize emacs_event and event before use.
1582      This code calls code that can GC. You must GCPRO before calling such code. */
1583   Lisp_Object emacs_event = Qnil;
1584   Lisp_Object fobj = Qnil;
1585
1586   struct Lisp_Event *event;
1587   struct frame *frame;
1588   struct mswindows_frame* msframe;
1589
1590   switch (message)
1591   {
1592   case WM_ERASEBKGND:
1593     /* Erase background only during non-dynamic sizing */
1594     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1595     if (msframe->sizing && !mswindows_dynamic_frame_resize)
1596       goto defproc;
1597     return 1;
1598
1599   case WM_CLOSE:
1600     fobj = mswindows_find_frame (hwnd);
1601     mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt));
1602     break;
1603
1604   case WM_KEYUP:
1605   case WM_SYSKEYUP:
1606     /* See Win95 comment under WM_KEYDOWN */
1607     {
1608       BYTE keymap[256];
1609
1610       if (wParam == VK_CONTROL)
1611         {
1612           GetKeyboardState (keymap);
1613           keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80;
1614           SetKeyboardState (keymap);
1615         }
1616       else if (wParam == VK_MENU)
1617         {
1618           GetKeyboardState (keymap);
1619           keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80;
1620           SetKeyboardState (keymap);
1621         }
1622     };
1623     goto defproc;
1624
1625   case WM_KEYDOWN:
1626   case WM_SYSKEYDOWN:
1627     /* In some locales the right-hand Alt key is labelled AltGr. This key
1628      * should produce alternative charcaters when combined with another key.
1629      * eg on a German keyboard pressing AltGr+q should produce '@'.
1630      * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if
1631      * TranslateMessage() is called with *any* combination of Ctrl+Alt down,
1632      * it translates as if AltGr were down.
1633      * We get round this by removing all modifiers from the keymap before
1634      * calling TranslateMessage() unless AltGr is *really* down. */
1635     {
1636       BYTE keymap[256];
1637       int has_AltGr = mswindows_current_layout_has_AltGr ();
1638       int mods;
1639       Lisp_Object keysym;
1640
1641       GetKeyboardState (keymap);
1642       mods = mswindows_modifier_state (keymap, has_AltGr);
1643
1644       /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */
1645       if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods)))
1646         mswindows_enqueue_keypress_event (hwnd, keysym, mods);
1647       else
1648         {
1649           int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd)));
1650           BYTE keymap_orig[256];
1651           MSG msg = { hwnd, message, wParam, lParam, GetMessageTime(), (GetMessagePos()) };
1652
1653           /* GetKeyboardState() does not work as documented on Win95. We have
1654            * to loosely track Left and Right modifiers on behalf of the OS,
1655            * without screwing up Windows NT which tracks them properly. */
1656           if (wParam == VK_CONTROL)
1657             keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80;
1658           else if (wParam == VK_MENU)
1659             keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80;
1660
1661           memcpy (keymap_orig, keymap, 256);
1662
1663           /* Remove shift modifier from an ascii character */
1664           mods &= ~MOD_SHIFT;
1665
1666           /* Clear control and alt modifiers unless AltGr is pressed */
1667           keymap [VK_RCONTROL] = 0;
1668           keymap [VK_LMENU] = 0;
1669           if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80))
1670             {
1671               keymap [VK_LCONTROL] = 0;
1672               keymap [VK_CONTROL] = 0;
1673               keymap [VK_RMENU] = 0;
1674               keymap [VK_MENU] = 0;
1675             }
1676           SetKeyboardState (keymap);
1677
1678           /* Maybe generate some WM_[SYS]CHARs in the queue */
1679           TranslateMessage (&msg);
1680
1681           while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE)
1682                  || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE))
1683             {
1684               int mods1 = mods;
1685               WPARAM ch = msg.wParam;
1686
1687               /* If a quit char with no modifiers other than control and
1688                  shift, then mark it with a fake modifier, which is removed
1689                  upon dequeueing the event */
1690               /* #### This might also not withstand localization, if
1691                  quit character is not a latin-1 symbol */
1692               if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch)
1693                    || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch))
1694                   && ((mods  & ~(MOD_CONTROL | MOD_SHIFT)) == 0))
1695                 {
1696                   mods1 |= FAKE_MOD_QUIT;
1697                   ++mswindows_quit_chars_count;
1698                 }
1699
1700               mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1);
1701             } /* while */
1702           SetKeyboardState (keymap_orig);
1703         } /* else */
1704     }
1705     /* F10 causes menu activation by default. We do not want this */
1706     if (wParam != VK_F10)
1707       goto defproc;
1708     break;
1709
1710   case WM_MBUTTONDOWN:
1711   case WM_MBUTTONUP:
1712     /* Real middle mouse button has nothing to do with emulated one:
1713        if one wants to exercise fingers playing chords on the mouse,
1714        he is allowed to do that! */
1715     mswindows_enqueue_mouse_button_event (hwnd, message,
1716                                           MAKEPOINTS (lParam), GetMessageTime());
1717     break;
1718     
1719   case WM_LBUTTONUP:
1720     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1721     msframe->last_click_time =  GetMessageTime();
1722
1723     KillTimer (hwnd, BUTTON_2_TIMER_ID);
1724     msframe->button2_need_lbutton = 0;
1725     if (msframe->ignore_next_lbutton_up)
1726       {
1727         msframe->ignore_next_lbutton_up = 0;
1728       }
1729     else if (msframe->button2_is_down)
1730       {
1731         msframe->button2_is_down = 0;
1732         msframe->ignore_next_rbutton_up = 1;
1733         mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1734                                               MAKEPOINTS (lParam), GetMessageTime());
1735       }
1736     else
1737       {
1738         if (msframe->button2_need_rbutton)
1739           {
1740             msframe->button2_need_rbutton = 0;
1741             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1742                                                   MAKEPOINTS (lParam), GetMessageTime());
1743           }
1744         mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP,
1745                                               MAKEPOINTS (lParam), GetMessageTime());
1746       }
1747     break;
1748
1749   case WM_RBUTTONUP:
1750     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1751     msframe->last_click_time =  GetMessageTime();
1752
1753     KillTimer (hwnd, BUTTON_2_TIMER_ID);
1754     msframe->button2_need_rbutton = 0;
1755     if (msframe->ignore_next_rbutton_up)
1756       {
1757         msframe->ignore_next_rbutton_up = 0;
1758       }
1759     else if (msframe->button2_is_down)
1760       {
1761         msframe->button2_is_down = 0;
1762         msframe->ignore_next_lbutton_up = 1;
1763         mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP,
1764                                               MAKEPOINTS (lParam), GetMessageTime());
1765       }
1766     else
1767       {
1768         if (msframe->button2_need_lbutton)
1769           {
1770             msframe->button2_need_lbutton = 0;
1771             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1772                                                   MAKEPOINTS (lParam), GetMessageTime());
1773           }
1774         mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP,
1775                                               MAKEPOINTS (lParam), GetMessageTime());
1776       }
1777     break;
1778
1779   case WM_LBUTTONDOWN:
1780     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1781
1782     if (msframe->button2_need_lbutton)
1783       {
1784         KillTimer (hwnd, BUTTON_2_TIMER_ID);
1785         msframe->button2_need_lbutton = 0;
1786         msframe->button2_need_rbutton = 0;
1787         if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1788           {
1789             mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1790                                                   MAKEPOINTS (lParam), GetMessageTime());
1791             msframe->button2_is_down = 1;
1792           }
1793         else
1794           {
1795             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1796                         msframe->last_click_point, msframe->last_click_time);
1797             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1798                                                   MAKEPOINTS (lParam), GetMessageTime());
1799           }
1800       }
1801     else
1802       {
1803         mswindows_set_chord_timer (hwnd);
1804         msframe->button2_need_rbutton = 1;
1805         msframe->last_click_point = MAKEPOINTS (lParam);
1806       }
1807     msframe->last_click_time =  GetMessageTime();
1808     break;
1809
1810   case WM_RBUTTONDOWN:
1811     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1812
1813     if (msframe->button2_need_rbutton)
1814       {
1815         KillTimer (hwnd, BUTTON_2_TIMER_ID);
1816         msframe->button2_need_lbutton = 0;
1817         msframe->button2_need_rbutton = 0;
1818         if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam)))
1819           {
1820             mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN,
1821                                                   MAKEPOINTS (lParam), GetMessageTime());
1822             msframe->button2_is_down = 1;
1823           }
1824         else
1825           {
1826             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1827                                 msframe->last_click_point, msframe->last_click_time);
1828             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1829                                                   MAKEPOINTS (lParam), GetMessageTime());
1830           }
1831       }
1832     else
1833       {
1834         mswindows_set_chord_timer (hwnd);
1835         msframe->button2_need_lbutton = 1;
1836         msframe->last_click_point = MAKEPOINTS (lParam);
1837       }
1838     msframe->last_click_time =  GetMessageTime();
1839     break;
1840         
1841   case WM_TIMER:
1842     if (wParam == BUTTON_2_TIMER_ID)
1843       {
1844         msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1845         KillTimer (hwnd, BUTTON_2_TIMER_ID);
1846
1847         if (msframe->button2_need_lbutton)
1848           {
1849             msframe->button2_need_lbutton = 0;
1850             mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN,
1851                                 msframe->last_click_point, msframe->last_click_time);
1852           }
1853         else if (msframe->button2_need_rbutton)
1854           {
1855             msframe->button2_need_rbutton = 0;
1856             mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN,
1857                                 msframe->last_click_point, msframe->last_click_time);
1858           }
1859       }
1860     else
1861       assert ("Spurious timer fired" == 0);
1862     break;
1863
1864   case WM_MOUSEMOVE:
1865     /* Optimization: don't report mouse movement while size is changing */
1866     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
1867     if (!msframe->sizing)
1868     {
1869       /* When waiting for the second mouse button to finish
1870          button2 emulation, and have moved too far, just pretend
1871          as if timer has expired. This improves drag-select feedback */
1872       if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton)
1873           && !mswindows_button2_near_enough (msframe->last_click_point,
1874                                              MAKEPOINTS (lParam)))
1875         {
1876           KillTimer (hwnd, BUTTON_2_TIMER_ID);
1877           SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0);
1878         }
1879
1880       emacs_event = Fmake_event (Qnil, Qnil);
1881       event = XEVENT(emacs_event);
1882
1883       event->channel = mswindows_find_frame(hwnd);
1884       event->timestamp = GetMessageTime();
1885       event->event_type = pointer_motion_event;
1886       event->event.motion.x = MAKEPOINTS(lParam).x;
1887       event->event.motion.y = MAKEPOINTS(lParam).y;
1888       event->event.motion.modifiers = mswindows_modifier_state (NULL, 0);
1889       
1890       mswindows_enqueue_dispatch_event (emacs_event);
1891     }
1892     break;
1893
1894   case WM_CANCELMODE:
1895     ReleaseCapture ();
1896     /* Queue a `cancel-mode-internal' misc user event, so mouse
1897        selection would be canceled if any */
1898     mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd),
1899                                        Qcancel_mode_internal, Qnil);
1900     break;
1901
1902 #ifdef HAVE_TOOLBARS
1903   case WM_NOTIFY:
1904     {
1905       LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam;
1906       Lisp_Object btext;
1907       if (tttext->hdr.code ==  TTN_NEEDTEXT)    
1908         {
1909           /* find out which toolbar */
1910           frame = XFRAME (mswindows_find_frame (hwnd));
1911           btext = mswindows_get_toolbar_button_text ( frame, 
1912                                                       tttext->hdr.idFrom );
1913           
1914           tttext->lpszText = NULL;
1915           tttext->hinst = NULL;
1916
1917           if (!NILP(btext))
1918             {
1919               /* I think this is safe since the text will only go away
1920                  when the toolbar does...*/
1921               tttext->lpszText=XSTRING_DATA (btext);
1922             }
1923 #if 0
1924           tttext->uFlags |= TTF_DI_SETITEM;
1925 #endif
1926         }    
1927     }
1928     break;
1929 #endif
1930     
1931   case WM_PAINT:
1932     {
1933       PAINTSTRUCT paintStruct;
1934       
1935       frame = XFRAME (mswindows_find_frame (hwnd));
1936
1937       BeginPaint (hwnd, &paintStruct);
1938       mswindows_redraw_exposed_area (frame,
1939                         paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1940                         paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1941       EndPaint (hwnd, &paintStruct);
1942     }
1943     break;
1944
1945   case WM_SIZE:
1946     /* We only care about this message if our size has really changed */
1947     if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1948     {
1949       RECT rect;
1950       int columns, rows;
1951
1952       fobj = mswindows_find_frame (hwnd);
1953       frame = XFRAME (fobj);
1954       msframe  = FRAME_MSWINDOWS_DATA (frame);
1955
1956       /* We cannot handle frame map and unmap hooks right in
1957          this routine, because these may throw. We queue
1958          magic events to run these hooks instead - kkm */
1959
1960       if (wParam==SIZE_MINIMIZED)
1961         {
1962           /* Iconified */
1963           FRAME_VISIBLE_P (frame) = 0;
1964           mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
1965         }
1966       else
1967         {
1968           GetClientRect(hwnd, &rect);
1969           FRAME_PIXWIDTH(frame) = rect.right;
1970           FRAME_PIXHEIGHT(frame) = rect.bottom;
1971
1972           pixel_to_real_char_size (frame, rect.right, rect.bottom,
1973                                    &FRAME_MSWINDOWS_CHARWIDTH (frame),
1974                                    &FRAME_MSWINDOWS_CHARHEIGHT (frame));
1975
1976           pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
1977           change_frame_size (frame, rows, columns, 1);
1978
1979           /* If we are inside frame creation, we have to apply geometric
1980              properties now. */
1981           if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1982             {
1983               /* Yes, we have to size again */
1984               mswindows_size_frame_internal ( frame, 
1985                                               FRAME_MSWINDOWS_TARGET_RECT 
1986                                               (frame));
1987               /* Reset so we do not get here again. The SetWindowPos call in
1988                * mswindows_size_frame_internal can cause recursion here. */
1989               if (FRAME_MSWINDOWS_TARGET_RECT (frame))
1990                 {
1991                   xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
1992                   FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
1993                 }
1994             }
1995           else
1996             {
1997               if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
1998                 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
1999               FRAME_VISIBLE_P (frame) = 1;
2000               
2001               if (!msframe->sizing || mswindows_dynamic_frame_resize)
2002                 redisplay ();
2003             }
2004         }
2005     }
2006     break;
2007
2008   /* Misc magic events which only require that the frame be identified */
2009   case WM_SETFOCUS:
2010   case WM_KILLFOCUS:
2011     mswindows_enqueue_magic_event (hwnd, message);
2012     break;
2013
2014   case WM_WINDOWPOSCHANGING:
2015     {
2016       WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2017       WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2018       GetWindowPlacement(hwnd, &wpl);
2019
2020       /* Only interested if size is changing and we're not being iconified */
2021       if (wpl.showCmd != SW_SHOWMINIMIZED
2022           && wpl.showCmd != SW_SHOWMAXIMIZED
2023           && !(wp->flags & SWP_NOSIZE))
2024       {
2025         RECT ncsize = { 0, 0, 0, 0 };
2026         int pixwidth, pixheight;
2027         AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2028                             GetMenu(hwnd) != NULL,
2029                             GetWindowLong (hwnd, GWL_EXSTYLE));
2030
2031         round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2032                                  wp->cx - (ncsize.right - ncsize.left),
2033                                  wp->cy - (ncsize.bottom - ncsize.top),
2034                                  &pixwidth, &pixheight);
2035
2036         /* Convert client sizes to window sizes */
2037         pixwidth += (ncsize.right - ncsize.left);
2038         pixheight += (ncsize.bottom - ncsize.top);
2039
2040         if (wpl.showCmd != SW_SHOWMAXIMIZED)
2041           {
2042             /* Adjust so that the bottom or right doesn't move if it's
2043              * the top or left that's being changed */
2044             RECT rect;
2045             GetWindowRect (hwnd, &rect);
2046
2047             if (rect.left != wp->x)
2048               wp->x += wp->cx - pixwidth;
2049             if (rect.top != wp->y)
2050               wp->y += wp->cy - pixheight;
2051           }
2052
2053         wp->cx = pixwidth;
2054         wp->cy = pixheight;
2055       }
2056       /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2057          window position if the user tries to track window too small */
2058     }
2059     goto defproc;
2060
2061   case WM_ENTERSIZEMOVE:
2062     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2063     msframe->sizing = 1;
2064     return 0;
2065
2066   case WM_EXITSIZEMOVE:
2067     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2068     msframe->sizing = 0;
2069     /* Queue noop event */
2070     mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2071     return 0;
2072
2073 #ifdef HAVE_SCROLLBARS
2074   case WM_VSCROLL:
2075   case WM_HSCROLL:
2076     {
2077       /* Direction of scroll is determined by scrollbar instance. */
2078       int code = (int) LOWORD(wParam);
2079       int pos = (short int) HIWORD(wParam);
2080       HWND hwndScrollBar = (HWND) lParam;
2081       struct gcpro gcpro1, gcpro2;
2082
2083       mswindows_handle_scrollbar_event (hwndScrollBar, code,  pos);
2084       GCPRO2 (emacs_event, fobj);
2085       if (UNBOUNDP(mswindows_pump_outstanding_events()))        /* Can GC */
2086         {
2087           /* Error during event pumping - cancel scroll */
2088           SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2089         }
2090       UNGCPRO;
2091       break;     
2092     }
2093 #endif
2094
2095 #ifdef HAVE_MENUBARS
2096   case WM_INITMENU:
2097     if (UNBOUNDP (mswindows_handle_wm_initmenu (
2098                         (HMENU) wParam,
2099                         XFRAME (mswindows_find_frame (hwnd)))))
2100       SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2101     break;
2102
2103   case WM_INITMENUPOPUP:
2104     if (!HIWORD(lParam))
2105       {
2106         if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2107                         (HMENU) wParam,
2108                          XFRAME (mswindows_find_frame (hwnd)))))
2109           SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2110       }
2111     break;
2112
2113 #endif /* HAVE_MENUBARS */
2114
2115   case WM_COMMAND:
2116     {
2117       WORD id = LOWORD (wParam);
2118       HWND cid = (HWND)lParam;
2119       frame = XFRAME (mswindows_find_frame (hwnd));
2120
2121 #ifdef HAVE_TOOLBARS
2122       if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2123         break;
2124 #endif
2125
2126 #ifdef HAVE_MENUBARS
2127       if (!NILP (mswindows_handle_wm_command (frame, id)))
2128         break;
2129 #endif
2130
2131       /* Bite me - a spurious command. This cannot happen. */
2132       error ("XEMACS BUG: Cannot decode command message");
2133     }
2134   break;
2135
2136 #ifdef HAVE_DRAGNDROP
2137   case WM_DROPFILES:    /* implementation ripped-off from event-Xt.c */
2138     {
2139       UINT filecount, i, len;
2140       POINT point;
2141       char* filename;
2142 #ifdef __CYGWIN32__
2143       char* fname;
2144 #endif
2145       Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2146       struct gcpro gcpro1, gcpro2, gcpro3;
2147
2148       emacs_event = Fmake_event (Qnil, Qnil);
2149       event = XEVENT(emacs_event);
2150
2151       GCPRO3 (emacs_event, l_dndlist, l_item);
2152
2153       if (!DragQueryPoint ((HANDLE) wParam, &point))
2154         point.x = point.y = -1;         /* outside client area */
2155
2156       event->event_type = misc_user_event;
2157       event->channel = mswindows_find_frame(hwnd);
2158       event->timestamp = GetMessageTime();
2159       event->event.misc.button = 1;             /* #### Should try harder */
2160       event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2161       event->event.misc.x = point.x;
2162       event->event.misc.y = point.y;
2163       event->event.misc.function = Qdragdrop_drop_dispatch;
2164
2165       filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2166       for (i=0; i<filecount; i++)
2167         {
2168           len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2169           /* The URLs that we make here aren't correct according to section
2170            * 3.10 of rfc1738 because they're missing the //<host>/ part and
2171            * because they may contain reserved characters. But that's OK. */
2172 #ifdef __CYGWIN32__
2173           fname = (char *)xmalloc (len+1);
2174           DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2175           filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2176           strcpy (filename, "file:");
2177           cygwin32_win32_to_posix_path_list (fname, filename+5);
2178           xfree (fname);
2179 #else
2180           filename = (char *)xmalloc (len+6);
2181           strcpy (filename, "file:");
2182           DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2183           dostounix_filename (filename+5);
2184 #endif
2185           l_item = make_string (filename, strlen (filename));
2186           l_dndlist = Fcons (l_item, l_dndlist);
2187           xfree (filename);
2188         }
2189       DragFinish ((HANDLE) wParam);
2190
2191       event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2192       mswindows_enqueue_dispatch_event (emacs_event);
2193       UNGCPRO;
2194     }
2195   break;
2196 #endif
2197
2198   defproc:
2199   default:
2200     return DefWindowProc (hwnd, message, wParam, lParam);
2201   }
2202   return (0);
2203 }
2204
2205
2206 /************************************************************************/
2207 /*      keyboard, mouse & other helpers for the windows procedure       */
2208 /************************************************************************/
2209 static void
2210 mswindows_set_chord_timer (HWND hwnd)
2211 {
2212   int interval;
2213
2214   /* We get one third half system double click threshold */
2215   if (mswindows_mouse_button_tolerance <= 0)
2216     interval = GetDoubleClickTime () / 3;
2217   else
2218     interval = mswindows_mouse_button_tolerance;
2219
2220   SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2221 }
2222
2223 static int
2224 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2225 {
2226   int dx, dy;
2227   if (mswindows_mouse_button_max_skew_x <= 0)
2228     dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2229   else
2230     dx = mswindows_mouse_button_max_skew_x;
2231
2232   if (mswindows_mouse_button_max_skew_y <= 0)
2233     dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2234   else
2235     dy = mswindows_mouse_button_max_skew_y;
2236
2237   return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2238 }
2239
2240 static int
2241 mswindows_current_layout_has_AltGr (void)
2242 {
2243   /* This simple caching mechanism saves 10% of CPU
2244      time when a key typed at autorepeat rate of 30 cps! */
2245   static HKL last_hkl = 0;
2246   static int last_hkl_has_AltGr;
2247
2248   HKL current_hkl = GetKeyboardLayout (0);
2249   if (current_hkl != last_hkl)
2250     {
2251       TCHAR c;
2252       last_hkl_has_AltGr = 0;
2253       /* In this loop, we query whether a character requires
2254          AltGr to be down to generate it. If at least such one
2255          found, this means that the layout does regard AltGr */
2256       for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2257         if (HIBYTE (VkKeyScan (c)) == 6)
2258           last_hkl_has_AltGr = 1;
2259       last_hkl = current_hkl;
2260     }
2261   return last_hkl_has_AltGr;
2262 }
2263
2264
2265 /* Returns the state of the modifier keys in the format expected by the
2266  * Lisp_Event key_data, button_data and motion_data modifiers member */
2267 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2268 {
2269   int mods = 0;
2270
2271   if (keymap == NULL)
2272     {
2273       keymap = (BYTE*) alloca(256);
2274       GetKeyboardState (keymap);
2275       has_AltGr = mswindows_current_layout_has_AltGr ();
2276     }
2277
2278   if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2279     {
2280       mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2281       mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2282     }
2283   else
2284     {
2285       mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2286       mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2287     }
2288
2289   mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2290
2291   return mods;
2292 }
2293
2294 /*
2295  * Translate a mswindows virtual key to a keysym.
2296  * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2297  * or whose ASCII codes (like space) xemacs doesn't like.
2298  * Virtual key values are defined in winresrc.h
2299  * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2300  */
2301 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2302 {
2303   switch (mswindows_key)
2304   {
2305   /* First the predefined ones */
2306   case VK_BACK:         return QKbackspace;
2307   case VK_TAB:          return QKtab;
2308   case '\n':            return QKlinefeed;  /* No VK_LINEFEED in winresrc.h */
2309   case VK_RETURN:       return QKreturn;
2310   case VK_ESCAPE:       return QKescape;
2311   case VK_SPACE:        return QKspace;
2312   case VK_DELETE:       return QKdelete;
2313
2314   /* The rest */
2315   case VK_CLEAR:        return KEYSYM ("clear");  /* Should do ^L ? */
2316   case VK_PRIOR:        return KEYSYM ("prior");
2317   case VK_NEXT:         return KEYSYM ("next");
2318   case VK_END:          return KEYSYM ("end");
2319   case VK_HOME:         return KEYSYM ("home");
2320   case VK_LEFT:         return KEYSYM ("left");
2321   case VK_UP:           return KEYSYM ("up");
2322   case VK_RIGHT:        return KEYSYM ("right");
2323   case VK_DOWN:         return KEYSYM ("down");
2324   case VK_SELECT:       return KEYSYM ("select");
2325   case VK_PRINT:        return KEYSYM ("print");
2326   case VK_EXECUTE:      return KEYSYM ("execute");
2327   case VK_SNAPSHOT:     return KEYSYM ("print");
2328   case VK_INSERT:       return KEYSYM ("insert");
2329   case VK_HELP:         return KEYSYM ("help");
2330 #if 0   /* XXX What are these supposed to do? */
2331   case VK_LWIN          return KEYSYM ("");
2332   case VK_RWIN          return KEYSYM ("");
2333 #endif
2334   case VK_APPS:         return KEYSYM ("menu");
2335   case VK_F1:           return KEYSYM ("f1");
2336   case VK_F2:           return KEYSYM ("f2");
2337   case VK_F3:           return KEYSYM ("f3");
2338   case VK_F4:           return KEYSYM ("f4");
2339   case VK_F5:           return KEYSYM ("f5");
2340   case VK_F6:           return KEYSYM ("f6");
2341   case VK_F7:           return KEYSYM ("f7");
2342   case VK_F8:           return KEYSYM ("f8");
2343   case VK_F9:           return KEYSYM ("f9");
2344   case VK_F10:          return KEYSYM ("f10");
2345   case VK_F11:          return KEYSYM ("f11");
2346   case VK_F12:          return KEYSYM ("f12");
2347   case VK_F13:          return KEYSYM ("f13");
2348   case VK_F14:          return KEYSYM ("f14");
2349   case VK_F15:          return KEYSYM ("f15");
2350   case VK_F16:          return KEYSYM ("f16");
2351   case VK_F17:          return KEYSYM ("f17");
2352   case VK_F18:          return KEYSYM ("f18");
2353   case VK_F19:          return KEYSYM ("f19");
2354   case VK_F20:          return KEYSYM ("f20");
2355   case VK_F21:          return KEYSYM ("f21");
2356   case VK_F22:          return KEYSYM ("f22");
2357   case VK_F23:          return KEYSYM ("f23");
2358   case VK_F24:          return KEYSYM ("f24");
2359   }
2360   return Qnil;
2361 }
2362
2363 /*
2364  * Find the console that matches the supplied mswindows window handle
2365  */
2366 Lisp_Object
2367 mswindows_find_console (HWND hwnd)
2368 {
2369   /* We only support one console */
2370   return XCAR (Vconsole_list);
2371 }
2372
2373 /*
2374  * Find the frame that matches the supplied mswindows window handle
2375  */
2376 static Lisp_Object
2377 mswindows_find_frame (HWND hwnd)
2378 {
2379   LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2380   Lisp_Object f;
2381   if (l == 0)
2382     {
2383       /* We are in progress of frame creation. Return the frame
2384          being created, as it still not remembered in the window
2385          extra storage. */
2386       assert (!NILP (Vmswindows_frame_being_created));
2387       return Vmswindows_frame_being_created;
2388     }
2389   VOID_TO_LISP (f, l);
2390   return f;
2391 }
2392
2393 \f
2394 /************************************************************************/
2395 /*                            methods                                   */
2396 /************************************************************************/
2397
2398 static int
2399 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2400 {
2401   int milliseconds;
2402   EMACS_TIME current_time;
2403   EMACS_GET_TIME (current_time);
2404   EMACS_SUB_TIME (thyme, thyme, current_time);
2405   milliseconds = EMACS_SECS (thyme) * 1000 +
2406     (EMACS_USECS (thyme) + 500) / 1000;
2407   if (milliseconds < 1)
2408     milliseconds = 1;
2409   ++mswindows_pending_timers_count;
2410   return SetTimer (NULL, 0, milliseconds,
2411                    (TIMERPROC) mswindows_wm_timer_callback);
2412 }
2413
2414 static void
2415 emacs_mswindows_remove_timeout (int id)
2416 {
2417   struct Lisp_Event match_against;
2418   Lisp_Object emacs_event;
2419
2420   if (KillTimer (NULL, id))
2421     --mswindows_pending_timers_count;
2422
2423   /* If there is a dispatch event generated by this
2424      timeout in the queue, we have to remove it too. */
2425   match_against.event_type = timeout_event;
2426   match_against.event.timeout.interval_id = id;
2427   emacs_event = mswindows_cancel_dispatch_event (&match_against);
2428   if (!NILP (emacs_event))
2429     Fdeallocate_event(emacs_event);
2430 }
2431
2432 /* If `user_p' is false, then return whether there are any win32, timeout,
2433  * or subprocess events pending (that is, whether
2434  * emacs_mswindows_next_event() would return immediately without blocking).
2435  *
2436  * if `user_p' is true, then return whether there are any *user generated*
2437  * events available (that is, whether there are keyboard or mouse-click
2438  * events ready to be read).  This also implies that
2439  * emacs_mswindows_next_event() would not block.
2440  */
2441 static int
2442 emacs_mswindows_event_pending_p (int user_p)
2443 {
2444   mswindows_need_event (0);
2445   return (!NILP (mswindows_u_dispatch_event_queue)
2446           || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2447 }
2448
2449 /*
2450  * Return the next event
2451  */
2452 static void
2453 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2454 {
2455   Lisp_Object event, event2;
2456
2457   mswindows_need_event (1);
2458
2459   event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue));
2460   XSETEVENT (event2, emacs_event);
2461   Fcopy_event (event, event2);
2462   Fdeallocate_event (event);
2463 }
2464
2465 /*
2466  * Handle a magic event off the dispatch queue.
2467  */
2468 static void
2469 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2470 {
2471   switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2472     {
2473     case XM_BUMPQUEUE:
2474       break;
2475     
2476     case WM_SETFOCUS:
2477     case WM_KILLFOCUS:
2478       {
2479         Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2480         struct frame *f = XFRAME (frame);
2481         int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2482         Lisp_Object conser;
2483
2484         /* struct gcpro gcpro1; */
2485
2486         /* Clear sticky modifiers here (if we had any) */
2487
2488         conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2489         /* GCPRO1 (conser); XXX Not necessary? */
2490         emacs_handle_focus_change_preliminary (conser);
2491         /* Under X the stuff up to here is done in the X event handler.
2492            I Don't know why */
2493         emacs_handle_focus_change_final (conser);
2494         /* UNGCPRO; */
2495
2496       }
2497       break;
2498
2499     case XM_MAPFRAME:
2500     case XM_UNMAPFRAME:
2501       {
2502         Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2503         va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) 
2504                                == XM_MAPFRAME ?
2505                                Qmap_frame_hook : Qunmap_frame_hook, 
2506                                1, frame);
2507       }
2508       break;
2509                             
2510       /* #### What about Enter & Leave */
2511 #if 0
2512       va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2513                              Qmouse_leave_frame_hook, 1, frame);
2514 #endif
2515
2516     default:
2517       assert(0);
2518     }
2519 }
2520
2521 static HANDLE
2522 get_process_input_waitable (struct Lisp_Process *process)
2523 {
2524   Lisp_Object instr, outstr, p;
2525   XSETPROCESS (p, process);
2526   get_process_streams (process, &instr, &outstr);
2527   assert (!NILP (instr));
2528 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2529   return (network_connection_p (p)
2530           ? get_winsock_stream_waitable (XLSTREAM (instr))
2531           : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2532 #else
2533     return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2534 #endif
2535 }
2536
2537 static void
2538 emacs_mswindows_select_process (struct Lisp_Process *process)
2539 {
2540   HANDLE hev = get_process_input_waitable (process);
2541
2542   if (!add_waitable_handle (hev))
2543     error ("Too many active processes");
2544
2545 #ifdef HAVE_WIN32_PROCESSES
2546   {
2547     Lisp_Object p;
2548     XSETPROCESS (p, process);
2549     if (!network_connection_p (p))
2550       {
2551         HANDLE hprocess = get_nt_process_handle (process);
2552         if (!add_waitable_handle (hprocess))
2553           {
2554             remove_waitable_handle (hev);
2555             error ("Too many active processes");
2556           }
2557       }
2558   }
2559 #endif
2560 }
2561
2562 static void
2563 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2564 {
2565   /* Process handle is removed in the event loop as soon
2566      as it is signaled, so don't bother here about it */
2567   HANDLE hev = get_process_input_waitable (process);
2568   remove_waitable_handle (hev);
2569 }
2570
2571 static void
2572 emacs_mswindows_select_console (struct console *con)
2573 {
2574 }
2575
2576 static void
2577 emacs_mswindows_unselect_console (struct console *con)
2578 {
2579 }
2580
2581 static void
2582 emacs_mswindows_quit_p (void)
2583 {
2584   /* Quit cannot happen in modal loop: all program
2585      input is dedicated to Windows. */
2586   if (mswindows_in_modal_loop)
2587     return;
2588
2589   /* Drain windows queue. This sets up number of quit
2590      characters in in the queue */
2591   mswindows_drain_windows_queue ();
2592
2593   if (mswindows_quit_chars_count > 0)
2594     {
2595       /* Yes there's a hidden one... Throw it away */
2596       struct Lisp_Event match_against;
2597       Lisp_Object emacs_event;
2598
2599       match_against.event_type = key_press_event;
2600       match_against.event.key.modifiers = FAKE_MOD_QUIT;
2601
2602       emacs_event = mswindows_cancel_dispatch_event (&match_against);
2603       assert (!NILP (emacs_event));
2604
2605       Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2606                     ? Qcritical : Qt);
2607
2608       Fdeallocate_event(emacs_event);
2609       --mswindows_quit_chars_count;
2610     }
2611 }
2612
2613 USID
2614 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2615                                     Lisp_Object* instream,
2616                                     Lisp_Object* outstream,
2617                                     int flags)
2618 {
2619   /* Handles for streams */
2620   HANDLE hin, hout;
2621   /* fds. These just stored along with the streams, and are closed in
2622      delete stream pair method, because we need to handle fake unices
2623      here. */
2624   int fdi, fdo;
2625
2626   /* Decode inhandle and outhandle. Their meaning depends on
2627      the process implementation being used. */
2628 #if defined (HAVE_WIN32_PROCESSES)
2629   /* We're passed in Windows handles. That's what we like most... */
2630   hin = (HANDLE) inhandle;
2631   hout = (HANDLE) outhandle;
2632   fdi = fdo = -1;
2633 #elif defined (HAVE_UNIX_PROCESSES)
2634   /* We are passed UNIX fds. This must be Cygwin.
2635      Fetch os handles */
2636   hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2637   hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2638   fdi=(int)inhandle;
2639   fdo=(int)outhandle;
2640 #else
2641 #error "So, WHICH kind of processes do you want?"
2642 #endif
2643
2644   *instream = (hin == INVALID_HANDLE_VALUE
2645                ? Qnil
2646 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2647                : flags & STREAM_NETWORK_CONNECTION
2648                ? make_winsock_input_stream ((SOCKET)hin, fdi)
2649 #endif
2650                : make_ntpipe_input_stream (hin, fdi));
2651
2652 #ifdef HAVE_WIN32_PROCESSES
2653   *outstream = (hout == INVALID_HANDLE_VALUE
2654                 ? Qnil
2655 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2656                 : flags & STREAM_NETWORK_CONNECTION
2657                 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2658 #endif
2659                 : make_ntpipe_output_stream (hout, fdo));
2660 #elif defined (HAVE_UNIX_PROCESSES)
2661   *outstream = (fdo >= 0
2662                 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2663                 : Qnil);
2664
2665 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2666   /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2667   if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2668     {
2669       Bufbyte eof_char = get_eof_char (fdo);
2670       int pty_max_bytes = get_pty_max_bytes (fdo);
2671       filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2672     }
2673 #endif
2674 #endif
2675
2676   return (NILP (*instream)
2677           ? USID_ERROR
2678 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2679           : flags & STREAM_NETWORK_CONNECTION
2680           ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2681 #endif
2682           : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2683 }
2684
2685 USID
2686 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2687                                          Lisp_Object outstream)
2688 {
2689   /* Oh nothing special here for Win32 at all */
2690 #if defined (HAVE_UNIX_PROCESSES)
2691   int in = (NILP(instream)
2692             ? -1
2693 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2694             : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2695             ? get_winsock_stream_param (XLSTREAM (instream))
2696 #endif
2697             : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2698   int out = (NILP(outstream) ? -1
2699              : filedesc_stream_fd (XLSTREAM (outstream)));
2700
2701   if (in >= 0)
2702     close (in);
2703   if (out != in && out >= 0)
2704     close (out);
2705 #endif
2706
2707   return (NILP (instream)
2708           ? USID_DONTHASH
2709 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2710           : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2711           ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2712 #endif
2713           : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2714 }
2715
2716 #ifndef HAVE_X_WINDOWS
2717 /* This is called from GC when a process object is about to be freed.
2718    If we've still got pointers to it in this file, we're gonna lose hard.
2719  */
2720 void
2721 debug_process_finalization (struct Lisp_Process *p)
2722 {
2723 #if 0 /* #### */
2724   Lisp_Object instr, outstr;
2725
2726   get_process_streams (p, &instr, &outstr);
2727   /* if it still has fds, then it hasn't been killed yet. */
2728   assert (NILP(instr));
2729   assert (NILP(outstr));
2730
2731   /* #### More checks here */
2732 #endif
2733 }
2734 #endif
2735
2736 /************************************************************************/
2737 /*                            initialization                            */
2738 /************************************************************************/
2739  
2740 void
2741 vars_of_event_mswindows (void)
2742 {
2743   mswindows_u_dispatch_event_queue = Qnil;
2744   staticpro (&mswindows_u_dispatch_event_queue);
2745   mswindows_u_dispatch_event_queue_tail = Qnil;
2746
2747   mswindows_s_dispatch_event_queue = Qnil;
2748   staticpro (&mswindows_s_dispatch_event_queue);
2749   mswindows_s_dispatch_event_queue_tail = Qnil;
2750
2751   mswindows_error_caught_in_modal_loop = Qnil;
2752   staticpro (&mswindows_error_caught_in_modal_loop);
2753   mswindows_in_modal_loop = 0;
2754   mswindows_pending_timers_count = 0;
2755
2756   mswindows_event_stream = xnew (struct event_stream);
2757
2758   mswindows_event_stream->event_pending_p       = emacs_mswindows_event_pending_p;
2759   mswindows_event_stream->next_event_cb         = emacs_mswindows_next_event;
2760   mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2761   mswindows_event_stream->add_timeout_cb        = emacs_mswindows_add_timeout;
2762   mswindows_event_stream->remove_timeout_cb     = emacs_mswindows_remove_timeout;
2763   mswindows_event_stream->quit_p_cb             = emacs_mswindows_quit_p;
2764   mswindows_event_stream->select_console_cb     = emacs_mswindows_select_console;
2765   mswindows_event_stream->unselect_console_cb   = emacs_mswindows_unselect_console;
2766 #ifdef HAVE_MSG_SELECT
2767   mswindows_event_stream->select_process_cb     = 
2768     (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2769   mswindows_event_stream->unselect_process_cb   = 
2770     (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2771   mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2772   mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2773 #else
2774   mswindows_event_stream->select_process_cb     = emacs_mswindows_select_process;
2775   mswindows_event_stream->unselect_process_cb   = emacs_mswindows_unselect_process;
2776   mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2777   mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2778 #endif
2779
2780   DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2781 *Controls redrawing frame contents during mouse-drag or keyboard resize
2782 operation. When non-nil, the frame is redrawn while being resized. When
2783 nil, frame is not redrawn, and exposed areas are filled with default
2784 MDI application background color. Note that this option only has effect
2785 if "Show window contents while dragging" is on in system Display/Plus!
2786 settings.
2787 Default is t on fast machines, nil on slow.
2788 */ );
2789
2790 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2791   DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2792 *Analogue of double click interval for faking middle mouse events.
2793 The value is the minimum time in milliseconds that must elapse between
2794 left/right button down events before they are considered distinct events.
2795 If both mouse buttons are depressed within this interval, a middle mouse
2796 button down event is generated instead.
2797 If negative or zero, currently set system default is used instead.
2798 */ );
2799
2800 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2801   DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2802 Number of physical mouse buttons.
2803 */ );
2804
2805   DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2806 *Maximum horizontal distance in pixels between points in which left and
2807 right button clicks occurred for them to be translated into single
2808 middle button event. Clicks must occur in time not longer than defined
2809 by the variable `mswindows-mouse-button-tolerance'.
2810 If negative or zero, currently set system default is used instead.
2811 */ );
2812
2813   DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2814 *Maximum vertical distance in pixels between points in which left and
2815 right button clicks occurred for them to be translated into single
2816 middle button event. Clicks must occur in time not longer than defined
2817 by the variable `mswindows-mouse-button-tolerance'.
2818 If negative or zero, currently set system default is used instead.
2819 */ );
2820
2821   mswindows_mouse_button_max_skew_x = 0;
2822   mswindows_mouse_button_max_skew_y = 0;
2823   mswindows_mouse_button_tolerance = 0;
2824 }
2825
2826 void
2827 syms_of_event_mswindows (void)
2828 {
2829 }
2830
2831 void
2832 lstream_type_create_mswindows_selectable (void)
2833 {
2834   init_slurp_stream ();
2835   init_shove_stream ();
2836 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2837   init_winsock_stream ();
2838 #endif
2839 }
2840
2841 void
2842 init_event_mswindows_late (void)
2843 {
2844 #ifdef HAVE_MSG_SELECT
2845   windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2846   assert (windows_fd>=0);
2847   FD_SET (windows_fd, &input_wait_mask);
2848   FD_ZERO(&zero_mask);
2849 #endif
2850
2851   event_stream = mswindows_event_stream;
2852
2853   mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2854   mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2855 }