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