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