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