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