comparison src/event-msw.c @ 428:3ecd8885ac67 r21-2-22

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