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