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