49a2446b33ba367a5fb01676dcc9ab7c65e23120
[chise/xemacs-chise.git.1] / src / event-msw.c
1 /* The  mswindows event_stream interface.
2    Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3    Copyright (C) 1995 Sun Microsystems, Inc.
4    Copyright (C) 1996 Ben Wing.
5    Copyright (C) 1997 Jonathan Harris.
6
7 This file is part of XEmacs.
8
9 XEmacs is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 2, or (at your option) any
12 later version.
13
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17 for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with XEmacs; see the file COPYING.  If not, write to
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23
24 /* Synched up with: Not in FSF. */
25
26 /* Authorship:
27
28    Ultimately based on FSF.
29    Rewritten by Ben Wing.
30    Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0.
31    Subprocess and modal loop support by Kirill M. Katsnelson.
32  */
33
34 #include <config.h>
35 #include "lisp.h"
36
37 #include "console-msw.h"
38
39 #ifdef HAVE_SCROLLBARS
40 # include "scrollbar-msw.h"
41 #endif
42
43 #ifdef HAVE_MENUBARS
44 # include "menubar-msw.h"
45 #endif
46
47 #ifdef HAVE_DRAGNDROP
48 # include "dragdrop.h"
49 #endif
50
51 #include "device.h"
52 #include "events.h"
53 #include "frame.h"
54 #include "buffer.h"
55 #include "faces.h"
56 #include "lstream.h"
57 #include "process.h"
58 #include "redisplay.h"
59 #include "sysproc.h"
60 #include "syswait.h"
61 #include "systime.h"
62 #include "sysdep.h"
63 #include "objects-msw.h"
64
65 #include "events-mod.h"
66 #ifdef HAVE_MSG_SELECT
67 #include "sysfile.h"
68 #include "console-tty.h"
69 #elif defined(__CYGWIN32__)
70 typedef unsigned int SOCKET;
71 #endif
72 #include <io.h>
73 #include <errno.h>
74
75 #if defined (__CYGWIN32__) && !defined (CYGWIN_VERSION_DLL_MAJOR)
76 typedef 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           SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)index,
1974                        (LPARAM)&item);
1975           
1976           mswindows_handle_gui_wm_command (frame, 0, item.lParam);
1977         }
1978     }
1979     break;
1980     
1981   case WM_PAINT:
1982     {
1983       PAINTSTRUCT paintStruct;
1984       
1985       frame = XFRAME (mswindows_find_frame (hwnd));
1986
1987       BeginPaint (hwnd, &paintStruct);
1988       mswindows_redraw_exposed_area (frame,
1989                         paintStruct.rcPaint.left, paintStruct.rcPaint.top,
1990                         paintStruct.rcPaint.right, paintStruct.rcPaint.bottom);
1991       EndPaint (hwnd, &paintStruct);
1992     }
1993     break;
1994
1995   case WM_SIZE:
1996     /* We only care about this message if our size has really changed */
1997     if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED)
1998     {
1999       RECT rect;
2000       int columns, rows;
2001
2002       fobj = mswindows_find_frame (hwnd);
2003       frame = XFRAME (fobj);
2004       msframe  = FRAME_MSWINDOWS_DATA (frame);
2005
2006       /* We cannot handle frame map and unmap hooks right in
2007          this routine, because these may throw. We queue
2008          magic events to run these hooks instead - kkm */
2009
2010       if (wParam==SIZE_MINIMIZED)
2011         {
2012           /* Iconified */
2013           FRAME_VISIBLE_P (frame) = 0;
2014           mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME);
2015         }
2016       else
2017         {
2018           GetClientRect(hwnd, &rect);
2019           FRAME_PIXWIDTH(frame) = rect.right;
2020           FRAME_PIXHEIGHT(frame) = rect.bottom;
2021
2022           pixel_to_real_char_size (frame, rect.right, rect.bottom,
2023                                    &FRAME_MSWINDOWS_CHARWIDTH (frame),
2024                                    &FRAME_MSWINDOWS_CHARHEIGHT (frame));
2025
2026           pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows);
2027           change_frame_size (frame, rows, columns, 1);
2028
2029           /* If we are inside frame creation, we have to apply geometric
2030              properties now. */
2031           if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2032             {
2033               /* Yes, we have to size again */
2034               mswindows_size_frame_internal ( frame, 
2035                                               FRAME_MSWINDOWS_TARGET_RECT 
2036                                               (frame));
2037               /* Reset so we do not get here again. The SetWindowPos call in
2038                * mswindows_size_frame_internal can cause recursion here. */
2039               if (FRAME_MSWINDOWS_TARGET_RECT (frame))
2040                 {
2041                   xfree (FRAME_MSWINDOWS_TARGET_RECT (frame));
2042                   FRAME_MSWINDOWS_TARGET_RECT (frame) = 0;
2043                 }
2044             }
2045           else
2046             {
2047               if (!msframe->sizing && !FRAME_VISIBLE_P (frame))
2048                 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME);
2049               FRAME_VISIBLE_P (frame) = 1;
2050               
2051               if (!msframe->sizing || mswindows_dynamic_frame_resize)
2052                 redisplay ();
2053             }
2054         }
2055     }
2056     break;
2057
2058   /* Misc magic events which only require that the frame be identified */
2059   case WM_SETFOCUS:
2060   case WM_KILLFOCUS:
2061     mswindows_enqueue_magic_event (hwnd, message);
2062     break;
2063
2064   case WM_WINDOWPOSCHANGING:
2065     {
2066       WINDOWPOS *wp = (LPWINDOWPOS) lParam;
2067       WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) };
2068       GetWindowPlacement(hwnd, &wpl);
2069
2070       /* Only interested if size is changing and we're not being iconified */
2071       if (wpl.showCmd != SW_SHOWMINIMIZED
2072           && wpl.showCmd != SW_SHOWMAXIMIZED
2073           && !(wp->flags & SWP_NOSIZE))
2074       {
2075         RECT ncsize = { 0, 0, 0, 0 };
2076         int pixwidth, pixheight;
2077         AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE),
2078                             GetMenu(hwnd) != NULL,
2079                             GetWindowLong (hwnd, GWL_EXSTYLE));
2080
2081         round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)),
2082                                  wp->cx - (ncsize.right - ncsize.left),
2083                                  wp->cy - (ncsize.bottom - ncsize.top),
2084                                  &pixwidth, &pixheight);
2085
2086         /* Convert client sizes to window sizes */
2087         pixwidth += (ncsize.right - ncsize.left);
2088         pixheight += (ncsize.bottom - ncsize.top);
2089
2090         if (wpl.showCmd != SW_SHOWMAXIMIZED)
2091           {
2092             /* Adjust so that the bottom or right doesn't move if it's
2093              * the top or left that's being changed */
2094             RECT rect;
2095             GetWindowRect (hwnd, &rect);
2096
2097             if (rect.left != wp->x)
2098               wp->x += wp->cx - pixwidth;
2099             if (rect.top != wp->y)
2100               wp->y += wp->cy - pixheight;
2101           }
2102
2103         wp->cx = pixwidth;
2104         wp->cy = pixheight;
2105       }
2106       /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts
2107          window position if the user tries to track window too small */
2108     }
2109     goto defproc;
2110
2111   case WM_ENTERSIZEMOVE:
2112     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2113     msframe->sizing = 1;
2114     return 0;
2115
2116   case WM_EXITSIZEMOVE:
2117     msframe  = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd)));
2118     msframe->sizing = 0;
2119     /* Queue noop event */
2120     mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE);
2121     return 0;
2122
2123 #ifdef HAVE_SCROLLBARS
2124   case WM_VSCROLL:
2125   case WM_HSCROLL:
2126     {
2127       /* Direction of scroll is determined by scrollbar instance. */
2128       int code = (int) LOWORD(wParam);
2129       int pos = (short int) HIWORD(wParam);
2130       HWND hwndScrollBar = (HWND) lParam;
2131       struct gcpro gcpro1, gcpro2;
2132
2133       mswindows_handle_scrollbar_event (hwndScrollBar, code,  pos);
2134       GCPRO2 (emacs_event, fobj);
2135       if (UNBOUNDP(mswindows_pump_outstanding_events()))        /* Can GC */
2136         {
2137           /* Error during event pumping - cancel scroll */
2138           SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0);
2139         }
2140       UNGCPRO;
2141       break;     
2142     }
2143 #endif
2144
2145 #ifdef HAVE_MENUBARS
2146   case WM_INITMENU:
2147     if (UNBOUNDP (mswindows_handle_wm_initmenu (
2148                         (HMENU) wParam,
2149                         XFRAME (mswindows_find_frame (hwnd)))))
2150       SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2151     break;
2152
2153   case WM_INITMENUPOPUP:
2154     if (!HIWORD(lParam))
2155       {
2156         if (UNBOUNDP (mswindows_handle_wm_initmenupopup (
2157                         (HMENU) wParam,
2158                          XFRAME (mswindows_find_frame (hwnd)))))
2159           SendMessage (hwnd, WM_CANCELMODE, 0, 0);
2160       }
2161     break;
2162
2163 #endif /* HAVE_MENUBARS */
2164
2165   case WM_COMMAND:
2166     {
2167       WORD id = LOWORD (wParam);
2168       WORD nid = HIWORD (wParam);
2169       HWND cid = (HWND)lParam;
2170       frame = XFRAME (mswindows_find_frame (hwnd));
2171
2172 #ifdef HAVE_TOOLBARS
2173       if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id)))
2174         break;
2175 #endif
2176       /* widgets in a buffer only eval a callback for suitable events.*/
2177       switch (nid)
2178         {
2179         case BN_CLICKED:
2180         case EN_CHANGE:
2181         case CBN_EDITCHANGE:
2182         case CBN_SELCHANGE:
2183           if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id)))
2184             return 0;
2185         }
2186       /* menubars always must come last since the hashtables do not
2187          always exist*/
2188 #ifdef HAVE_MENUBARS
2189       if (!NILP (mswindows_handle_wm_command (frame, id)))
2190         break;
2191 #endif
2192
2193       return DefWindowProc (hwnd, message, wParam, lParam);
2194       /* Bite me - a spurious command. This used to not be able to
2195          happen but with the introduction of widgets its now
2196          possible. */
2197     }
2198   break;
2199
2200   case WM_CTLCOLORBTN:
2201   case WM_CTLCOLORLISTBOX:
2202   case WM_CTLCOLOREDIT:
2203   case WM_CTLCOLORSTATIC:
2204   case WM_CTLCOLORSCROLLBAR:
2205     {
2206       /* if we get an opportunity to paint a widget then do so if
2207          there is an appropriate face */
2208       HWND crtlwnd = (HWND)lParam;
2209       LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA);
2210       if (ii)
2211         {
2212           Lisp_Object image_instance;
2213           VOID_TO_LISP (image_instance, ii);
2214           if (IMAGE_INSTANCEP (image_instance)
2215               && 
2216               IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)
2217               &&
2218               !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance)))
2219             {
2220               /* set colors for the buttons */
2221               HDC hdc = (HDC)wParam;
2222               if (last_widget_brushed != ii)
2223                 {
2224                   if (widget_brush)
2225                     DeleteObject (widget_brush);
2226                   widget_brush = CreateSolidBrush 
2227                     (COLOR_INSTANCE_MSWINDOWS_COLOR 
2228                      (XCOLOR_INSTANCE 
2229                       (FACE_BACKGROUND 
2230                        (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2231                         XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2232                 }
2233               last_widget_brushed = ii;
2234               SetTextColor
2235                 (hdc,
2236                  COLOR_INSTANCE_MSWINDOWS_COLOR 
2237                  (XCOLOR_INSTANCE 
2238                   (FACE_FOREGROUND 
2239                    (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2240                     XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2241               SetBkMode (hdc, OPAQUE);
2242               SetBkColor
2243                 (hdc,
2244                  COLOR_INSTANCE_MSWINDOWS_COLOR 
2245                  (XCOLOR_INSTANCE 
2246                   (FACE_BACKGROUND 
2247                    (XIMAGE_INSTANCE_WIDGET_FACE (image_instance),
2248                     XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance)))));
2249               return (LRESULT)widget_brush;
2250             }
2251         }
2252     }
2253     goto defproc;
2254
2255 #ifdef HAVE_DRAGNDROP
2256   case WM_DROPFILES:    /* implementation ripped-off from event-Xt.c */
2257     {
2258       UINT filecount, i, len;
2259       POINT point;
2260       char* filename;
2261 #ifdef __CYGWIN32__
2262       char* fname;
2263 #endif
2264       Lisp_Object l_dndlist = Qnil, l_item = Qnil;
2265       struct gcpro gcpro1, gcpro2, gcpro3;
2266
2267       emacs_event = Fmake_event (Qnil, Qnil);
2268       event = XEVENT(emacs_event);
2269
2270       GCPRO3 (emacs_event, l_dndlist, l_item);
2271
2272       if (!DragQueryPoint ((HANDLE) wParam, &point))
2273         point.x = point.y = -1;         /* outside client area */
2274
2275       event->event_type = misc_user_event;
2276       event->channel = mswindows_find_frame(hwnd);
2277       event->timestamp = GetMessageTime();
2278       event->event.misc.button = 1;             /* #### Should try harder */
2279       event->event.misc.modifiers = mswindows_modifier_state (NULL, 0);
2280       event->event.misc.x = point.x;
2281       event->event.misc.y = point.y;
2282       event->event.misc.function = Qdragdrop_drop_dispatch;
2283
2284       filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0);
2285       for (i=0; i<filecount; i++)
2286         {
2287           len = DragQueryFile ((HANDLE) wParam, i, NULL, 0);
2288           /* The URLs that we make here aren't correct according to section
2289            * 3.10 of rfc1738 because they're missing the //<host>/ part and
2290            * because they may contain reserved characters. But that's OK. */
2291 #ifdef __CYGWIN32__
2292           fname = (char *)xmalloc (len+1);
2293           DragQueryFile ((HANDLE) wParam, i, fname, len+1);
2294           filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5);
2295           strcpy (filename, "file:");
2296           cygwin32_win32_to_posix_path_list (fname, filename+5);
2297           xfree (fname);
2298 #else
2299           filename = (char *)xmalloc (len+6);
2300           strcpy (filename, "file:");
2301           DragQueryFile ((HANDLE) wParam, i, filename+5, len+1);
2302           dostounix_filename (filename+5);
2303 #endif
2304           l_item = make_string (filename, strlen (filename));
2305           l_dndlist = Fcons (l_item, l_dndlist);
2306           xfree (filename);
2307         }
2308       DragFinish ((HANDLE) wParam);
2309
2310       event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist);
2311       mswindows_enqueue_dispatch_event (emacs_event);
2312       UNGCPRO;
2313     }
2314   break;
2315 #endif
2316
2317   defproc:
2318   default:
2319     return DefWindowProc (hwnd, message, wParam, lParam);
2320   }
2321   return (0);
2322 }
2323
2324
2325 /************************************************************************/
2326 /*      keyboard, mouse & other helpers for the windows procedure       */
2327 /************************************************************************/
2328 static void
2329 mswindows_set_chord_timer (HWND hwnd)
2330 {
2331   int interval;
2332
2333   /* We get one third half system double click threshold */
2334   if (mswindows_mouse_button_tolerance <= 0)
2335     interval = GetDoubleClickTime () / 3;
2336   else
2337     interval = mswindows_mouse_button_tolerance;
2338
2339   SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0);
2340 }
2341
2342 static int
2343 mswindows_button2_near_enough (POINTS p1, POINTS p2)
2344 {
2345   int dx, dy;
2346   if (mswindows_mouse_button_max_skew_x <= 0)
2347     dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2;
2348   else
2349     dx = mswindows_mouse_button_max_skew_x;
2350
2351   if (mswindows_mouse_button_max_skew_y <= 0)
2352     dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2;
2353   else
2354     dy = mswindows_mouse_button_max_skew_y;
2355
2356   return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy;
2357 }
2358
2359 static int
2360 mswindows_current_layout_has_AltGr (void)
2361 {
2362   /* This simple caching mechanism saves 10% of CPU
2363      time when a key typed at autorepeat rate of 30 cps! */
2364   static HKL last_hkl = 0;
2365   static int last_hkl_has_AltGr;
2366
2367   HKL current_hkl = GetKeyboardLayout (0);
2368   if (current_hkl != last_hkl)
2369     {
2370       TCHAR c;
2371       last_hkl_has_AltGr = 0;
2372       /* In this loop, we query whether a character requires
2373          AltGr to be down to generate it. If at least such one
2374          found, this means that the layout does regard AltGr */
2375       for (c = ' '; c <= 0xFFU && c != 0 && !last_hkl_has_AltGr; ++c)
2376         if (HIBYTE (VkKeyScan (c)) == 6)
2377           last_hkl_has_AltGr = 1;
2378       last_hkl = current_hkl;
2379     }
2380   return last_hkl_has_AltGr;
2381 }
2382
2383
2384 /* Returns the state of the modifier keys in the format expected by the
2385  * Lisp_Event key_data, button_data and motion_data modifiers member */
2386 int mswindows_modifier_state (BYTE* keymap, int has_AltGr)
2387 {
2388   int mods = 0;
2389
2390   if (keymap == NULL)
2391     {
2392       keymap = (BYTE*) alloca(256);
2393       GetKeyboardState (keymap);
2394       has_AltGr = mswindows_current_layout_has_AltGr ();
2395     }
2396
2397   if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80))
2398     {
2399       mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0;
2400       mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0;
2401     }
2402   else
2403     {
2404       mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0;
2405       mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0;
2406     }
2407
2408   mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0;
2409
2410   return mods;
2411 }
2412
2413 /*
2414  * Translate a mswindows virtual key to a keysym.
2415  * Only returns non-Qnil for keys that don't generate WM_CHAR messages
2416  * or whose ASCII codes (like space) xemacs doesn't like.
2417  * Virtual key values are defined in winresrc.h
2418  * XXX I'm not sure that KEYSYM("name") is the best thing to use here.
2419  */
2420 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods)
2421 {
2422   switch (mswindows_key)
2423   {
2424   /* First the predefined ones */
2425   case VK_BACK:         return QKbackspace;
2426   case VK_TAB:          return QKtab;
2427   case '\n':            return QKlinefeed;  /* No VK_LINEFEED in winresrc.h */
2428   case VK_RETURN:       return QKreturn;
2429   case VK_ESCAPE:       return QKescape;
2430   case VK_SPACE:        return QKspace;
2431   case VK_DELETE:       return QKdelete;
2432
2433   /* The rest */
2434   case VK_CLEAR:        return KEYSYM ("clear");  /* Should do ^L ? */
2435   case VK_PRIOR:        return KEYSYM ("prior");
2436   case VK_NEXT:         return KEYSYM ("next");
2437   case VK_END:          return KEYSYM ("end");
2438   case VK_HOME:         return KEYSYM ("home");
2439   case VK_LEFT:         return KEYSYM ("left");
2440   case VK_UP:           return KEYSYM ("up");
2441   case VK_RIGHT:        return KEYSYM ("right");
2442   case VK_DOWN:         return KEYSYM ("down");
2443   case VK_SELECT:       return KEYSYM ("select");
2444   case VK_PRINT:        return KEYSYM ("print");
2445   case VK_EXECUTE:      return KEYSYM ("execute");
2446   case VK_SNAPSHOT:     return KEYSYM ("print");
2447   case VK_INSERT:       return KEYSYM ("insert");
2448   case VK_HELP:         return KEYSYM ("help");
2449 #if 0   /* XXX What are these supposed to do? */
2450   case VK_LWIN          return KEYSYM ("");
2451   case VK_RWIN          return KEYSYM ("");
2452 #endif
2453   case VK_APPS:         return KEYSYM ("menu");
2454   case VK_F1:           return KEYSYM ("f1");
2455   case VK_F2:           return KEYSYM ("f2");
2456   case VK_F3:           return KEYSYM ("f3");
2457   case VK_F4:           return KEYSYM ("f4");
2458   case VK_F5:           return KEYSYM ("f5");
2459   case VK_F6:           return KEYSYM ("f6");
2460   case VK_F7:           return KEYSYM ("f7");
2461   case VK_F8:           return KEYSYM ("f8");
2462   case VK_F9:           return KEYSYM ("f9");
2463   case VK_F10:          return KEYSYM ("f10");
2464   case VK_F11:          return KEYSYM ("f11");
2465   case VK_F12:          return KEYSYM ("f12");
2466   case VK_F13:          return KEYSYM ("f13");
2467   case VK_F14:          return KEYSYM ("f14");
2468   case VK_F15:          return KEYSYM ("f15");
2469   case VK_F16:          return KEYSYM ("f16");
2470   case VK_F17:          return KEYSYM ("f17");
2471   case VK_F18:          return KEYSYM ("f18");
2472   case VK_F19:          return KEYSYM ("f19");
2473   case VK_F20:          return KEYSYM ("f20");
2474   case VK_F21:          return KEYSYM ("f21");
2475   case VK_F22:          return KEYSYM ("f22");
2476   case VK_F23:          return KEYSYM ("f23");
2477   case VK_F24:          return KEYSYM ("f24");
2478   }
2479   return Qnil;
2480 }
2481
2482 /*
2483  * Find the console that matches the supplied mswindows window handle
2484  */
2485 Lisp_Object
2486 mswindows_find_console (HWND hwnd)
2487 {
2488   /* We only support one console */
2489   return XCAR (Vconsole_list);
2490 }
2491
2492 /*
2493  * Find the frame that matches the supplied mswindows window handle
2494  */
2495 static Lisp_Object
2496 mswindows_find_frame (HWND hwnd)
2497 {
2498   LONG l = GetWindowLong (hwnd, XWL_FRAMEOBJ);
2499   Lisp_Object f;
2500   if (l == 0)
2501     {
2502       /* We are in progress of frame creation. Return the frame
2503          being created, as it still not remembered in the window
2504          extra storage. */
2505       assert (!NILP (Vmswindows_frame_being_created));
2506       return Vmswindows_frame_being_created;
2507     }
2508   VOID_TO_LISP (f, l);
2509   return f;
2510 }
2511
2512 \f
2513 /************************************************************************/
2514 /*                            methods                                   */
2515 /************************************************************************/
2516
2517 static int
2518 emacs_mswindows_add_timeout (EMACS_TIME thyme)
2519 {
2520   int milliseconds;
2521   EMACS_TIME current_time;
2522   EMACS_GET_TIME (current_time);
2523   EMACS_SUB_TIME (thyme, thyme, current_time);
2524   milliseconds = EMACS_SECS (thyme) * 1000 +
2525     (EMACS_USECS (thyme) + 500) / 1000;
2526   if (milliseconds < 1)
2527     milliseconds = 1;
2528   ++mswindows_pending_timers_count;
2529   return SetTimer (NULL, 0, milliseconds,
2530                    (TIMERPROC) mswindows_wm_timer_callback);
2531 }
2532
2533 static void
2534 emacs_mswindows_remove_timeout (int id)
2535 {
2536   struct Lisp_Event match_against;
2537   Lisp_Object emacs_event;
2538
2539   if (KillTimer (NULL, id))
2540     --mswindows_pending_timers_count;
2541
2542   /* If there is a dispatch event generated by this
2543      timeout in the queue, we have to remove it too. */
2544   match_against.event_type = timeout_event;
2545   match_against.event.timeout.interval_id = id;
2546   emacs_event = mswindows_cancel_dispatch_event (&match_against);
2547   if (!NILP (emacs_event))
2548     Fdeallocate_event(emacs_event);
2549 }
2550
2551 /* If `user_p' is false, then return whether there are any win32, timeout,
2552  * or subprocess events pending (that is, whether
2553  * emacs_mswindows_next_event() would return immediately without blocking).
2554  *
2555  * if `user_p' is true, then return whether there are any *user generated*
2556  * events available (that is, whether there are keyboard or mouse-click
2557  * events ready to be read).  This also implies that
2558  * emacs_mswindows_next_event() would not block.
2559  */
2560 static int
2561 emacs_mswindows_event_pending_p (int user_p)
2562 {
2563   mswindows_need_event (0);
2564   return (!NILP (mswindows_u_dispatch_event_queue)
2565           || (!user_p && !NILP (mswindows_s_dispatch_event_queue)));
2566 }
2567
2568 /*
2569  * Return the next event
2570  */
2571 static void
2572 emacs_mswindows_next_event (struct Lisp_Event *emacs_event)
2573 {
2574   Lisp_Object event, event2;
2575
2576   mswindows_need_event (1);
2577
2578   event = mswindows_dequeue_dispatch_event ();
2579   XSETEVENT (event2, emacs_event);
2580   Fcopy_event (event, event2);
2581   Fdeallocate_event (event);
2582 }
2583
2584 /*
2585  * Handle a magic event off the dispatch queue.
2586  */
2587 static void
2588 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event)
2589 {
2590   switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event))
2591     {
2592     case XM_BUMPQUEUE:
2593       break;
2594     
2595     case WM_SETFOCUS:
2596     case WM_KILLFOCUS:
2597       {
2598         Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2599         struct frame *f = XFRAME (frame);
2600         int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS);
2601         Lisp_Object conser;
2602
2603         /* struct gcpro gcpro1; */
2604
2605         /* Clear sticky modifiers here (if we had any) */
2606
2607         conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil));
2608         /* GCPRO1 (conser); XXX Not necessary? */
2609         emacs_handle_focus_change_preliminary (conser);
2610         /* Under X the stuff up to here is done in the X event handler.
2611            I Don't know why */
2612         emacs_handle_focus_change_final (conser);
2613         /* UNGCPRO; */
2614
2615       }
2616       break;
2617
2618     case XM_MAPFRAME:
2619     case XM_UNMAPFRAME:
2620       {
2621         Lisp_Object frame = EVENT_CHANNEL (emacs_event);
2622         va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) 
2623                                == XM_MAPFRAME ?
2624                                Qmap_frame_hook : Qunmap_frame_hook, 
2625                                1, frame);
2626       }
2627       break;
2628                             
2629       /* #### What about Enter & Leave */
2630 #if 0
2631       va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook :
2632                              Qmouse_leave_frame_hook, 1, frame);
2633 #endif
2634
2635     default:
2636       assert(0);
2637     }
2638 }
2639
2640 #ifndef HAVE_MSG_SELECT
2641 static HANDLE
2642 get_process_input_waitable (struct Lisp_Process *process)
2643 {
2644   Lisp_Object instr, outstr, p;
2645   XSETPROCESS (p, process);
2646   get_process_streams (process, &instr, &outstr);
2647   assert (!NILP (instr));
2648 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2649   return (network_connection_p (p)
2650           ? get_winsock_stream_waitable (XLSTREAM (instr))
2651           : get_ntpipe_input_stream_waitable (XLSTREAM (instr)));
2652 #else
2653     return get_ntpipe_input_stream_waitable (XLSTREAM (instr));
2654 #endif
2655 }
2656
2657 static void
2658 emacs_mswindows_select_process (struct Lisp_Process *process)
2659 {
2660   HANDLE hev = get_process_input_waitable (process);
2661
2662   if (!add_waitable_handle (hev))
2663     error ("Too many active processes");
2664
2665 #ifdef HAVE_WIN32_PROCESSES
2666   {
2667     Lisp_Object p;
2668     XSETPROCESS (p, process);
2669     if (!network_connection_p (p))
2670       {
2671         HANDLE hprocess = get_nt_process_handle (process);
2672         if (!add_waitable_handle (hprocess))
2673           {
2674             remove_waitable_handle (hev);
2675             error ("Too many active processes");
2676           }
2677       }
2678   }
2679 #endif
2680 }
2681
2682 static void
2683 emacs_mswindows_unselect_process (struct Lisp_Process *process)
2684 {
2685   /* Process handle is removed in the event loop as soon
2686      as it is signaled, so don't bother here about it */
2687   HANDLE hev = get_process_input_waitable (process);
2688   remove_waitable_handle (hev);
2689 }
2690 #endif /* HAVE_MSG_SELECT */
2691
2692 static void
2693 emacs_mswindows_select_console (struct console *con)
2694 {
2695 #ifdef HAVE_MSG_SELECT
2696   if (CONSOLE_MSWINDOWS_P (con))
2697     return; /* mswindows consoles are automatically selected */
2698
2699   event_stream_unixoid_select_console (con);
2700 #endif
2701 }
2702
2703 static void
2704 emacs_mswindows_unselect_console (struct console *con)
2705 {
2706 #ifdef HAVE_MSG_SELECT
2707   if (CONSOLE_MSWINDOWS_P (con))
2708     return; /* mswindows consoles are automatically selected */
2709
2710   event_stream_unixoid_unselect_console (con);
2711 #endif
2712 }
2713
2714 static void
2715 emacs_mswindows_quit_p (void)
2716 {
2717   MSG msg;
2718
2719   /* Quit cannot happen in modal loop: all program
2720      input is dedicated to Windows. */
2721   if (mswindows_in_modal_loop)
2722     return;
2723
2724   /* Drain windows queue. This sets up number of quit characters in the queue
2725    * (and also processes wm focus change, move, resize, etc messages).
2726    * We don't want to process WM_PAINT messages because this function can be
2727    * called from almost anywhere and the windows' states may be changing. */
2728   while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) ||
2729          PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE))
2730       DispatchMessage (&msg);
2731
2732   if (mswindows_quit_chars_count > 0)
2733     {
2734       /* Yes there's a hidden one... Throw it away */
2735       struct Lisp_Event match_against;
2736       Lisp_Object emacs_event;
2737
2738       match_against.event_type = key_press_event;
2739       match_against.event.key.modifiers = FAKE_MOD_QUIT;
2740
2741       emacs_event = mswindows_cancel_dispatch_event (&match_against);
2742       assert (!NILP (emacs_event));
2743
2744       Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT
2745                     ? Qcritical : Qt);
2746
2747       Fdeallocate_event(emacs_event);
2748       --mswindows_quit_chars_count;
2749     }
2750 }
2751
2752 USID
2753 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle,
2754                                     Lisp_Object* instream,
2755                                     Lisp_Object* outstream,
2756                                     int flags)
2757 {
2758   /* Handles for streams */
2759   HANDLE hin, hout;
2760   /* fds. These just stored along with the streams, and are closed in
2761      delete stream pair method, because we need to handle fake unices
2762      here. */
2763   int fdi, fdo;
2764
2765   /* Decode inhandle and outhandle. Their meaning depends on
2766      the process implementation being used. */
2767 #if defined (HAVE_WIN32_PROCESSES)
2768   /* We're passed in Windows handles. That's what we like most... */
2769   hin = (HANDLE) inhandle;
2770   hout = (HANDLE) outhandle;
2771   fdi = fdo = -1;
2772 #elif defined (HAVE_UNIX_PROCESSES)
2773   /* We are passed UNIX fds. This must be Cygwin.
2774      Fetch os handles */
2775   hin = inhandle >= 0 ? (HANDLE)get_osfhandle ((int)inhandle) : INVALID_HANDLE_VALUE;
2776   hout = outhandle >= 0 ? (HANDLE)get_osfhandle ((int)outhandle) : INVALID_HANDLE_VALUE;
2777   fdi=(int)inhandle;
2778   fdo=(int)outhandle;
2779 #else
2780 #error "So, WHICH kind of processes do you want?"
2781 #endif
2782
2783   *instream = (hin == INVALID_HANDLE_VALUE
2784                ? Qnil
2785 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2786                : flags & STREAM_NETWORK_CONNECTION
2787                ? make_winsock_input_stream ((SOCKET)hin, fdi)
2788 #endif
2789                : make_ntpipe_input_stream (hin, fdi));
2790
2791 #ifdef HAVE_WIN32_PROCESSES
2792   *outstream = (hout == INVALID_HANDLE_VALUE
2793                 ? Qnil
2794 #if defined (HAVE_SOCKETS) && !defined (HAVE_MSG_SELECT)
2795                 : flags & STREAM_NETWORK_CONNECTION
2796                 ? make_winsock_output_stream ((SOCKET)hout, fdo)
2797 #endif
2798                 : make_ntpipe_output_stream (hout, fdo));
2799 #elif defined (HAVE_UNIX_PROCESSES)
2800   *outstream = (fdo >= 0
2801                 ? make_filedesc_output_stream (fdo, 0, -1, LSTR_BLOCKED_OK)
2802                 : Qnil);
2803
2804 #if defined(HAVE_UNIX_PROCESSES) && defined(HAVE_PTYS)
2805   /* FLAGS is process->pty_flag for UNIX_PROCESSES */
2806   if ((flags & STREAM_PTY_FLUSHING) && fdo >= 0)
2807     {
2808       Bufbyte eof_char = get_eof_char (fdo);
2809       int pty_max_bytes = get_pty_max_bytes (fdo);
2810       filedesc_stream_set_pty_flushing (XLSTREAM(*outstream), pty_max_bytes, eof_char);
2811     }
2812 #endif
2813 #endif
2814
2815   return (NILP (*instream)
2816           ? USID_ERROR
2817 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2818           : flags & STREAM_NETWORK_CONNECTION
2819           ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream)))
2820 #endif
2821           : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream))));
2822 }
2823
2824 USID
2825 emacs_mswindows_delete_stream_pair (Lisp_Object instream,
2826                                          Lisp_Object outstream)
2827 {
2828   /* Oh nothing special here for Win32 at all */
2829 #if defined (HAVE_UNIX_PROCESSES)
2830   int in = (NILP(instream)
2831             ? -1
2832 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2833             : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2834             ? get_winsock_stream_param (XLSTREAM (instream))
2835 #endif
2836             : get_ntpipe_input_stream_param (XLSTREAM (instream)));
2837   int out = (NILP(outstream) ? -1
2838              : filedesc_stream_fd (XLSTREAM (outstream)));
2839
2840   if (in >= 0)
2841     close (in);
2842   if (out != in && out >= 0)
2843     close (out);
2844 #endif
2845
2846   return (NILP (instream)
2847           ? USID_DONTHASH
2848 #if defined(HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2849           : LSTREAM_TYPE_P (XLSTREAM (instream), winsock)
2850           ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream)))
2851 #endif
2852           : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream))));
2853 }
2854
2855 #ifndef HAVE_X_WINDOWS
2856 /* This is called from GC when a process object is about to be freed.
2857    If we've still got pointers to it in this file, we're gonna lose hard.
2858  */
2859 void
2860 debug_process_finalization (struct Lisp_Process *p)
2861 {
2862 #if 0 /* #### */
2863   Lisp_Object instr, outstr;
2864
2865   get_process_streams (p, &instr, &outstr);
2866   /* if it still has fds, then it hasn't been killed yet. */
2867   assert (NILP(instr));
2868   assert (NILP(outstr));
2869
2870   /* #### More checks here */
2871 #endif
2872 }
2873 #endif
2874
2875 /************************************************************************/
2876 /*                            initialization                            */
2877 /************************************************************************/
2878  
2879 void
2880 vars_of_event_mswindows (void)
2881 {
2882   mswindows_u_dispatch_event_queue = Qnil;
2883   staticpro (&mswindows_u_dispatch_event_queue);
2884   mswindows_u_dispatch_event_queue_tail = Qnil;
2885
2886   mswindows_s_dispatch_event_queue = Qnil;
2887   staticpro (&mswindows_s_dispatch_event_queue);
2888   mswindows_s_dispatch_event_queue_tail = Qnil;
2889
2890   mswindows_error_caught_in_modal_loop = Qnil;
2891   staticpro (&mswindows_error_caught_in_modal_loop);
2892   mswindows_in_modal_loop = 0;
2893   mswindows_pending_timers_count = 0;
2894
2895   mswindows_event_stream = xnew (struct event_stream);
2896
2897   mswindows_event_stream->event_pending_p       = emacs_mswindows_event_pending_p;
2898   mswindows_event_stream->next_event_cb         = emacs_mswindows_next_event;
2899   mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event;
2900   mswindows_event_stream->add_timeout_cb        = emacs_mswindows_add_timeout;
2901   mswindows_event_stream->remove_timeout_cb     = emacs_mswindows_remove_timeout;
2902   mswindows_event_stream->quit_p_cb             = emacs_mswindows_quit_p;
2903   mswindows_event_stream->select_console_cb     = emacs_mswindows_select_console;
2904   mswindows_event_stream->unselect_console_cb   = emacs_mswindows_unselect_console;
2905 #ifdef HAVE_MSG_SELECT
2906   mswindows_event_stream->select_process_cb     = 
2907     (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process;
2908   mswindows_event_stream->unselect_process_cb   = 
2909     (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process;
2910   mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair;
2911   mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair;
2912 #else
2913   mswindows_event_stream->select_process_cb     = emacs_mswindows_select_process;
2914   mswindows_event_stream->unselect_process_cb   = emacs_mswindows_unselect_process;
2915   mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair;
2916   mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair;
2917 #endif
2918
2919   DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /*
2920 *Controls redrawing frame contents during mouse-drag or keyboard resize
2921 operation. When non-nil, the frame is redrawn while being resized. When
2922 nil, frame is not redrawn, and exposed areas are filled with default
2923 MDI application background color. Note that this option only has effect
2924 if "Show window contents while dragging" is on in system Display/Plus!
2925 settings.
2926 Default is t on fast machines, nil on slow.
2927 */ );
2928
2929 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2930   DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /*
2931 *Analogue of double click interval for faking middle mouse events.
2932 The value is the minimum time in milliseconds that must elapse between
2933 left/right button down events before they are considered distinct events.
2934 If both mouse buttons are depressed within this interval, a middle mouse
2935 button down event is generated instead.
2936 If negative or zero, currently set system default is used instead.
2937 */ );
2938
2939 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */
2940   DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /*
2941 Number of physical mouse buttons.
2942 */ );
2943
2944   DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /*
2945 *Maximum horizontal distance in pixels between points in which left and
2946 right button clicks occurred for them to be translated into single
2947 middle button event. Clicks must occur in time not longer than defined
2948 by the variable `mswindows-mouse-button-tolerance'.
2949 If negative or zero, currently set system default is used instead.
2950 */ );
2951
2952   DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /*
2953 *Maximum vertical distance in pixels between points in which left and
2954 right button clicks occurred for them to be translated into single
2955 middle button event. Clicks must occur in time not longer than defined
2956 by the variable `mswindows-mouse-button-tolerance'.
2957 If negative or zero, currently set system default is used instead.
2958 */ );
2959
2960   mswindows_mouse_button_max_skew_x = 0;
2961   mswindows_mouse_button_max_skew_y = 0;
2962   mswindows_mouse_button_tolerance = 0;
2963 }
2964
2965 void
2966 syms_of_event_mswindows (void)
2967 {
2968 }
2969
2970 void
2971 lstream_type_create_mswindows_selectable (void)
2972 {
2973   init_slurp_stream ();
2974   init_shove_stream ();
2975 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT)
2976   init_winsock_stream ();
2977 #endif
2978 }
2979
2980 void
2981 init_event_mswindows_late (void)
2982 {
2983 #ifdef HAVE_MSG_SELECT
2984   windows_fd = open("/dev/windows", O_RDONLY | O_NONBLOCK, 0);
2985   assert (windows_fd>=0);
2986   FD_SET (windows_fd, &input_wait_mask);
2987   FD_ZERO(&zero_mask);
2988 #endif
2989
2990   event_stream = mswindows_event_stream;
2991
2992   mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE);
2993   mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
2994 }