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