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