Mercurial > hg > xemacs-beta
comparison src/event-msw.c @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | de805c49cfc1 |
children | e804706bfb8c |
comparison
equal
deleted
inserted
replaced
411:12e008d41344 | 412:697ef44129c6 |
---|---|
1 /* The mswindows event_stream interface. | 1 /* The mswindows event_stream interface. |
2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. | 2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
3 Copyright (C) 1995 Sun Microsystems, Inc. | 3 Copyright (C) 1995 Sun Microsystems, Inc. |
4 Copyright (C) 1996, 2000 Ben Wing. | 4 Copyright (C) 1996 Ben Wing. |
5 Copyright (C) 1997 Jonathan Harris. | 5 Copyright (C) 1997 Jonathan Harris. |
6 | 6 |
7 This file is part of XEmacs. | 7 This file is part of XEmacs. |
8 | 8 |
9 XEmacs is free software; you can redistribute it and/or modify it | 9 XEmacs is free software; you can redistribute it and/or modify it |
39 #ifdef HAVE_SCROLLBARS | 39 #ifdef HAVE_SCROLLBARS |
40 # include "scrollbar-msw.h" | 40 # include "scrollbar-msw.h" |
41 #endif | 41 #endif |
42 | 42 |
43 #ifdef HAVE_MENUBARS | 43 #ifdef HAVE_MENUBARS |
44 # include "menubar.h" | |
45 # include "menubar-msw.h" | 44 # include "menubar-msw.h" |
46 #endif | 45 #endif |
47 | 46 |
48 #ifdef HAVE_DRAGNDROP | 47 #ifdef HAVE_DRAGNDROP |
49 # include "dragdrop.h" | 48 # include "dragdrop.h" |
55 #include "buffer.h" | 54 #include "buffer.h" |
56 #include "faces.h" | 55 #include "faces.h" |
57 #include "lstream.h" | 56 #include "lstream.h" |
58 #include "process.h" | 57 #include "process.h" |
59 #include "redisplay.h" | 58 #include "redisplay.h" |
60 #include "select.h" | |
61 #include "window.h" | |
62 #include "sysproc.h" | 59 #include "sysproc.h" |
63 #include "syswait.h" | 60 #include "syswait.h" |
64 #include "systime.h" | 61 #include "systime.h" |
65 #include "sysdep.h" | 62 #include "sysdep.h" |
66 #include "objects-msw.h" | 63 #include "objects-msw.h" |
67 | 64 |
68 #include "events-mod.h" | 65 #include "events-mod.h" |
69 #ifdef HAVE_MSG_SELECT | 66 #ifdef HAVE_MSG_SELECT |
70 #include "sysfile.h" | 67 #include "sysfile.h" |
71 #include "console-tty.h" | 68 #include "console-tty.h" |
72 #elif defined(CYGWIN) | 69 #elif defined(__CYGWIN32__) |
73 typedef unsigned int SOCKET; | 70 typedef unsigned int SOCKET; |
74 #endif | 71 #endif |
75 #include <io.h> | 72 #include <io.h> |
76 #include <errno.h> | 73 #include <errno.h> |
77 | |
78 #if !(defined(CYGWIN) || defined(MINGW)) | |
79 # include <shlobj.h> /* For IShellLink */ | |
80 #endif | |
81 | 74 |
82 #ifdef HAVE_MENUBARS | 75 #ifdef HAVE_MENUBARS |
83 #define ADJR_MENUFLAG TRUE | 76 #define ADJR_MENUFLAG TRUE |
84 #else | 77 #else |
85 #define ADJR_MENUFLAG FALSE | 78 #define ADJR_MENUFLAG FALSE |
90 #define FAKE_MOD_QUIT 0x80 | 83 #define FAKE_MOD_QUIT 0x80 |
91 | 84 |
92 /* Timer ID used for button2 emulation */ | 85 /* Timer ID used for button2 emulation */ |
93 #define BUTTON_2_TIMER_ID 1 | 86 #define BUTTON_2_TIMER_ID 1 |
94 | 87 |
88 extern Lisp_Object | |
89 mswindows_get_toolbar_button_text (struct frame* f, int command_id); | |
90 extern Lisp_Object | |
91 mswindows_handle_toolbar_wm_command (struct frame* f, HWND ctrl, WORD id); | |
92 extern Lisp_Object | |
93 mswindows_handle_gui_wm_command (struct frame* f, HWND ctrl, WORD id); | |
94 | |
95 static Lisp_Object mswindows_find_frame (HWND hwnd); | 95 static Lisp_Object mswindows_find_frame (HWND hwnd); |
96 static Lisp_Object mswindows_find_console (HWND hwnd); | 96 static Lisp_Object mswindows_find_console (HWND hwnd); |
97 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, | 97 static Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods); |
98 int extendedp); | |
99 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr); | 98 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr); |
100 static void mswindows_set_chord_timer (HWND hwnd); | 99 static void mswindows_set_chord_timer (HWND hwnd); |
101 static int mswindows_button2_near_enough (POINTS p1, POINTS p2); | 100 static int mswindows_button2_near_enough (POINTS p1, POINTS p2); |
102 static int mswindows_current_layout_has_AltGr (void); | 101 static int mswindows_current_layout_has_AltGr (void); |
103 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, | |
104 int downp, int keyp); | |
105 | 102 |
106 static struct event_stream *mswindows_event_stream; | 103 static struct event_stream *mswindows_event_stream; |
107 | 104 |
108 #ifdef HAVE_MSG_SELECT | 105 #ifdef HAVE_MSG_SELECT |
109 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; | 106 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
130 static HANDLE mswindows_waitable_handles[MAX_WAITABLE]; | 127 static HANDLE mswindows_waitable_handles[MAX_WAITABLE]; |
131 | 128 |
132 /* Number of wait handles */ | 129 /* Number of wait handles */ |
133 static int mswindows_waitable_count=0; | 130 static int mswindows_waitable_count=0; |
134 #endif /* HAVE_MSG_SELECT */ | 131 #endif /* HAVE_MSG_SELECT */ |
135 | |
136 /* Brush for painting widgets */ | 132 /* Brush for painting widgets */ |
137 static HBRUSH widget_brush = 0; | 133 static HBRUSH widget_brush = 0; |
138 static LONG last_widget_brushed = 0; | 134 static LONG last_widget_brushed = 0; |
139 | 135 |
140 /* Count of quit chars currently in the queue */ | 136 /* Count of quit chars currently in the queue */ |
142 Decremented in mswindows_dequeue_dispatch_event() */ | 138 Decremented in mswindows_dequeue_dispatch_event() */ |
143 int mswindows_quit_chars_count = 0; | 139 int mswindows_quit_chars_count = 0; |
144 | 140 |
145 /* These are Lisp integers; see DEFVARS in this file for description. */ | 141 /* These are Lisp integers; see DEFVARS in this file for description. */ |
146 int mswindows_dynamic_frame_resize; | 142 int mswindows_dynamic_frame_resize; |
147 int mswindows_alt_by_itself_activates_menu; | |
148 int mswindows_num_mouse_buttons; | 143 int mswindows_num_mouse_buttons; |
149 int mswindows_mouse_button_max_skew_x; | 144 int mswindows_mouse_button_max_skew_x; |
150 int mswindows_mouse_button_max_skew_y; | 145 int mswindows_mouse_button_max_skew_y; |
151 int mswindows_mouse_button_tolerance; | 146 int mswindows_mouse_button_tolerance; |
152 | |
153 #ifdef DEBUG_XEMACS | |
154 int mswindows_debug_events; | |
155 #endif | |
156 | 147 |
157 /* This is the event signaled by the event pump. | 148 /* This is the event signaled by the event pump. |
158 See mswindows_pump_outstanding_events for comments */ | 149 See mswindows_pump_outstanding_events for comments */ |
159 static Lisp_Object mswindows_error_caught_in_modal_loop; | 150 static Lisp_Object mswindows_error_caught_in_modal_loop; |
160 static int mswindows_in_modal_loop; | 151 static int mswindows_in_modal_loop; |
185 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */ | 176 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */ |
186 | 177 |
187 struct ntpipe_slurp_stream_shared_data | 178 struct ntpipe_slurp_stream_shared_data |
188 { | 179 { |
189 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | 180 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ |
190 /* This is a manual-reset object. */ | 181 /* This is a manual-reset object. */ |
191 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ | 182 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ |
192 /* This is a manual-reset object. */ | 183 /* This is a manual-reset object. */ |
193 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ | 184 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ |
194 /* This is a manual-reset object. */ | 185 /* This is a manual-reset object. */ |
195 HANDLE hpipe; /* Pipe read end handle. */ | 186 HANDLE hpipe; /* Pipe read end handle. */ |
196 LONG die_p; /* Thread must exit ASAP if non-zero */ | 187 LONG die_p; /* Thread must exit ASAP if non-zero */ |
197 BOOL eof_p : 1; /* Set when thread saw EOF */ | 188 BOOL eof_p : 1; /* Set when thread saw EOF */ |
198 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | 189 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ |
199 BOOL inuse_p : 1; /* this structure is in use */ | 190 BOOL inuse_p : 1; /* this structure is in use */ |
200 LONG lock_count; /* Client count of this struct, 0=safe to free */ | 191 LONG lock_count; /* Client count of this struct, 0=safe to free */ |
201 BYTE onebyte; /* One byte buffer read by thread */ | 192 BYTE onebyte; /* One byte buffer read by thread */ |
202 }; | 193 }; |
203 | 194 |
204 #define MAX_SLURP_STREAMS 32 | 195 #define MAX_SLURP_STREAMS 32 |
205 struct ntpipe_slurp_stream_shared_data | 196 struct ntpipe_slurp_stream_shared_data |
206 shared_data_block[MAX_SLURP_STREAMS]={{0}}; | 197 shared_data_block[MAX_SLURP_STREAMS]={{0}}; |
207 | 198 |
208 struct ntpipe_slurp_stream | 199 struct ntpipe_slurp_stream |
209 { | 200 { |
210 LPARAM user_data; /* Any user data stored in the stream object */ | 201 LPARAM user_data; /* Any user data stored in the stream object */ |
228 s->inuse_p = 0; | 219 s->inuse_p = 0; |
229 } | 220 } |
230 } | 221 } |
231 | 222 |
232 static struct ntpipe_slurp_stream_shared_data* | 223 static struct ntpipe_slurp_stream_shared_data* |
233 slurper_allocate_shared_data (void) | 224 slurper_allocate_shared_data() |
234 { | 225 { |
235 int i=0; | 226 int i=0; |
236 for (i=0; i<MAX_SLURP_STREAMS; i++) | 227 for (i=0; i<MAX_SLURP_STREAMS; i++) |
237 { | 228 { |
238 if (!shared_data_block[i].inuse_p) | 229 if (!shared_data_block[i].inuse_p) |
272 /* Before we notify caller, we unsignal our event. */ | 263 /* Before we notify caller, we unsignal our event. */ |
273 ResetEvent (s->hev_thread); | 264 ResetEvent (s->hev_thread); |
274 | 265 |
275 /* Now we got something to notify caller, either a byte or an | 266 /* Now we got something to notify caller, either a byte or an |
276 error/eof indication. Before we do, allow internal pipe | 267 error/eof indication. Before we do, allow internal pipe |
277 buffer to accumulate little bit more data. | 268 buffer to accumulate little bit more data. |
278 Reader function pulses this event before waiting for | 269 Reader function pulses this event before waiting for |
279 a character, to avoid pipe delay, and to get the byte | 270 a character, to avoid pipe delay, and to get the byte |
280 immediately. */ | 271 immediately. */ |
281 if (!s->die_p) | 272 if (!s->die_p) |
282 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY); | 273 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY); |
361 { | 352 { |
362 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream); | 353 struct ntpipe_slurp_stream* s = NTPIPE_SLURP_STREAM_DATA(stream); |
363 return s->thread_data->hev_caller; | 354 return s->thread_data->hev_caller; |
364 } | 355 } |
365 | 356 |
366 static ssize_t | 357 static int |
367 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) | 358 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, size_t size) |
368 { | 359 { |
369 /* This function must be called from the main thread only */ | 360 /* This function must be called from the main thread only */ |
370 struct ntpipe_slurp_stream_shared_data* s = | 361 struct ntpipe_slurp_stream_shared_data* s = |
371 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; | 362 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; |
372 | 363 |
373 if (!s->die_p) | 364 if (!s->die_p) |
374 { | 365 { |
375 DWORD wait_result; | 366 DWORD wait_result; |
376 /* Disallow pipe read delay for the thread: we need a character | 367 /* Disallow pipe read delay for the thread: we need a character |
377 ASAP */ | 368 ASAP */ |
378 SetEvent (s->hev_unsleep); | 369 SetEvent (s->hev_unsleep); |
379 | 370 |
380 /* Check if we have a character ready. Give it a short delay, | 371 /* Check if we have a character ready. Give it a short delay, |
381 for the thread to awake from pipe delay, just ion case*/ | 372 for the thread to awake from pipe delay, just ion case*/ |
382 wait_result = WaitForSingleObject (s->hev_caller, 2); | 373 wait_result = WaitForSingleObject (s->hev_caller, 2); |
383 | 374 |
384 /* Revert to the normal sleep behavior. */ | 375 /* Revert to the normal sleep behavior. */ |
425 fail if the next call fails. */ | 416 fail if the next call fails. */ |
426 if (bytes_available) | 417 if (bytes_available) |
427 ReadFile (s->hpipe, data, min (bytes_available, size), | 418 ReadFile (s->hpipe, data, min (bytes_available, size), |
428 &bytes_read, NULL); | 419 &bytes_read, NULL); |
429 } | 420 } |
430 | 421 |
431 /* Now we can unblock thread, so it attempts to read more */ | 422 /* Now we can unblock thread, so it attempts to read more */ |
432 SetEvent (s->hev_thread); | 423 SetEvent (s->hev_thread); |
433 return bytes_read + 1; | 424 return bytes_read + 1; |
434 } | 425 } |
435 } | 426 } |
436 return 0; | 427 return 0; |
437 } | 428 } |
438 | 429 |
439 static int | 430 static int |
440 ntpipe_slurp_closer (Lstream *stream) | 431 ntpipe_slurp_closer (Lstream *stream) |
441 { | 432 { |
442 /* This function must be called from the main thread only */ | 433 /* This function must be called from the main thread only */ |
443 struct ntpipe_slurp_stream_shared_data* s = | 434 struct ntpipe_slurp_stream_shared_data* s = |
444 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; | 435 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; |
445 | 436 |
446 /* Force thread to stop */ | 437 /* Force thread to stop */ |
447 InterlockedIncrement (&s->die_p); | 438 InterlockedIncrement (&s->die_p); |
448 | 439 |
469 /************************************************************************/ | 460 /************************************************************************/ |
470 | 461 |
471 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ | 462 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ |
472 LSTREAM_TYPE_DATA (stream, ntpipe_shove) | 463 LSTREAM_TYPE_DATA (stream, ntpipe_shove) |
473 | 464 |
474 #define MAX_SHOVE_BUFFER_SIZE 512 | 465 #define MAX_SHOVE_BUFFER_SIZE 128 |
475 | 466 |
476 struct ntpipe_shove_stream | 467 struct ntpipe_shove_stream |
477 { | 468 { |
478 LPARAM user_data; /* Any user data stored in the stream object */ | 469 LPARAM user_data; /* Any user data stored in the stream object */ |
479 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | 470 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ |
480 /* This is an auto-reset object. */ | 471 /* This is an auto-reset object. */ |
481 HANDLE hpipe; /* Pipe write end handle. */ | 472 HANDLE hpipe; /* Pipe write end handle. */ |
482 HANDLE hthread; /* Reader thread handle. */ | 473 HANDLE hthread; /* Reader thread handle. */ |
483 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ | 474 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ |
484 DWORD size; /* Number of bytes to write */ | 475 DWORD size; /* Number of bytes to write */ |
485 LONG die_p; /* Thread must exit ASAP if non-zero */ | 476 LONG die_p; /* Thread must exit ASAP if non-zero */ |
497 { | 488 { |
498 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam; | 489 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream*) vparam; |
499 | 490 |
500 for (;;) | 491 for (;;) |
501 { | 492 { |
502 DWORD bytes_written; | 493 DWORD bytes_written; |
503 | 494 |
504 /* Block on event and wait for a job */ | 495 /* Block on event and wait for a job */ |
505 InterlockedIncrement (&s->idle_p); | 496 InterlockedIncrement (&s->idle_p); |
506 WaitForSingleObject (s->hev_thread, INFINITE); | 497 WaitForSingleObject (s->hev_thread, INFINITE); |
507 | 498 |
508 /* Write passed buffer if any */ | 499 if (s->die_p) |
509 if (s->size > 0) | 500 break; |
501 | |
502 /* Write passed buffer */ | |
503 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) | |
504 || bytes_written != s->size) | |
510 { | 505 { |
511 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) | 506 s->error_p = TRUE; |
512 || bytes_written != s->size) | 507 InterlockedIncrement (&s->die_p); |
513 { | |
514 s->error_p = TRUE; | |
515 InterlockedIncrement (&s->die_p); | |
516 } | |
517 /* Set size to zero so we won't write it again if the closer sets | |
518 die_p and kicks us */ | |
519 s->size = 0; | |
520 } | 508 } |
521 | 509 |
522 if (s->die_p) | 510 if (s->die_p) |
523 break; | 511 break; |
524 } | 512 } |
537 s->die_p = 0; | 525 s->die_p = 0; |
538 s->error_p = FALSE; | 526 s->error_p = FALSE; |
539 s->hpipe = hpipe; | 527 s->hpipe = hpipe; |
540 s->user_data = param; | 528 s->user_data = param; |
541 | 529 |
542 /* Create reader thread. This could fail, so do not | 530 /* Create reader thread. This could fail, so do not |
543 create the event until thread is created */ | 531 create the event until thread is created */ |
544 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s, | 532 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s, |
545 CREATE_SUSPENDED, &thread_id_unused); | 533 CREATE_SUSPENDED, &thread_id_unused); |
546 if (s->hthread == NULL) | 534 if (s->hthread == NULL) |
547 { | 535 { |
548 Lstream_delete (lstr); | 536 Lstream_delete (lstr); |
549 return Qnil; | 537 return Qnil; |
550 } | 538 } |
551 | 539 |
552 /* Set the priority of the thread higher so we don't end up waiting | |
553 on it to send things. */ | |
554 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST)) | |
555 { | |
556 CloseHandle (s->hthread); | |
557 Lstream_delete (lstr); | |
558 return Qnil; | |
559 } | |
560 | |
561 /* hev_thread is an auto-reset event, initially nonsignaled */ | 540 /* hev_thread is an auto-reset event, initially nonsignaled */ |
562 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL); | 541 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL); |
563 | 542 |
564 /* Now let it go */ | 543 /* Now let it go */ |
565 ResumeThread (s->hthread); | 544 ResumeThread (s->hthread); |
575 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); | 554 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); |
576 return s->user_data; | 555 return s->user_data; |
577 } | 556 } |
578 #endif | 557 #endif |
579 | 558 |
580 static ssize_t | 559 static int |
581 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size) | 560 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, size_t size) |
582 { | 561 { |
583 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); | 562 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); |
584 | 563 |
585 if (s->error_p) | 564 if (s->error_p) |
596 s->size = size; | 575 s->size = size; |
597 | 576 |
598 /* Start output */ | 577 /* Start output */ |
599 InterlockedDecrement (&s->idle_p); | 578 InterlockedDecrement (&s->idle_p); |
600 SetEvent (s->hev_thread); | 579 SetEvent (s->hev_thread); |
601 /* Give it a chance to run -- this dramatically improves performance | |
602 of things like crypt. */ | |
603 (void) SwitchToThread (); | |
604 return size; | 580 return size; |
605 } | 581 } |
606 | 582 |
607 static int | 583 static int |
608 ntpipe_shove_was_blocked_p (Lstream *stream) | 584 ntpipe_shove_was_blocked_p (Lstream *stream) |
617 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); | 593 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); |
618 | 594 |
619 /* Force thread stop */ | 595 /* Force thread stop */ |
620 InterlockedIncrement (&s->die_p); | 596 InterlockedIncrement (&s->die_p); |
621 | 597 |
622 /* Thread will end upon unblocking. If it's already unblocked this will | 598 /* Close pipe handle, possibly breaking it */ |
623 do nothing, but the thread won't look at die_p until it's written any | 599 CloseHandle (s->hpipe); |
624 pending output. */ | 600 |
601 /* Thread will end upon unblocking */ | |
625 SetEvent (s->hev_thread); | 602 SetEvent (s->hev_thread); |
626 | 603 |
627 /* Wait while thread terminates */ | 604 /* Wait while thread terminates */ |
628 WaitForSingleObject (s->hthread, INFINITE); | 605 WaitForSingleObject (s->hthread, INFINITE); |
629 | |
630 /* Close pipe handle, possibly breaking it */ | |
631 CloseHandle (s->hpipe); | |
632 | |
633 /* Close the thread handle */ | |
634 CloseHandle (s->hthread); | 606 CloseHandle (s->hthread); |
635 | 607 |
636 /* Destroy the event */ | 608 /* Destroy the event */ |
637 CloseHandle (s->hev_thread); | 609 CloseHandle (s->hev_thread); |
638 | 610 |
658 { | 630 { |
659 LPARAM user_data; /* Any user data stored in the stream object */ | 631 LPARAM user_data; /* Any user data stored in the stream object */ |
660 SOCKET s; /* Socket handle (which is a Win32 handle) */ | 632 SOCKET s; /* Socket handle (which is a Win32 handle) */ |
661 OVERLAPPED ov; /* Overlapped I/O structure */ | 633 OVERLAPPED ov; /* Overlapped I/O structure */ |
662 void* buffer; /* Buffer. Allocated for input stream only */ | 634 void* buffer; /* Buffer. Allocated for input stream only */ |
663 unsigned long bufsize; /* Number of bytes last read */ | 635 unsigned int bufsize; /* Number of bytes last read */ |
664 unsigned long bufpos; /* Position in buffer for next fetch */ | 636 unsigned int bufpos; /* Position in buffer for next fetch */ |
665 unsigned int error_p :1; /* I/O Error seen */ | 637 unsigned int error_p :1; /* I/O Error seen */ |
666 unsigned int eof_p :1; /* EOF Error seen */ | 638 unsigned int eof_p :1; /* EOF Error seen */ |
667 unsigned int pending_p :1; /* There is a pending I/O operation */ | 639 unsigned int pending_p :1; /* There is a pending I/O operation */ |
668 unsigned int blocking_p :1; /* Last write attempt would block */ | 640 unsigned int blocking_p :1; /* Last write attempt would block */ |
669 }; | 641 }; |
691 } | 663 } |
692 else if (str->bufsize == 0) | 664 else if (str->bufsize == 0) |
693 str->eof_p = 1; | 665 str->eof_p = 1; |
694 } | 666 } |
695 | 667 |
696 static ssize_t | 668 static int |
697 winsock_reader (Lstream *stream, unsigned char *data, size_t size) | 669 winsock_reader (Lstream *stream, unsigned char *data, size_t size) |
698 { | 670 { |
699 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | 671 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); |
700 | 672 |
701 /* If the current operation is not yet complete, there's nothing to | 673 /* If the current operation is not yet complete, there's nothing to |
724 | 696 |
725 if (str->eof_p) | 697 if (str->eof_p) |
726 return 0; | 698 return 0; |
727 if (str->error_p) | 699 if (str->error_p) |
728 return -1; | 700 return -1; |
729 | 701 |
730 /* Return as much of buffer as we have */ | 702 /* Return as much of buffer as we have */ |
731 size = min (size, (size_t) (str->bufsize - str->bufpos)); | 703 size = min (size, (size_t) (str->bufsize - str->bufpos)); |
732 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size); | 704 memcpy (data, (void*)((BYTE*)str->buffer + str->bufpos), size); |
733 str->bufpos += size; | 705 str->bufpos += size; |
734 | 706 |
737 winsock_initiate_read (str); | 709 winsock_initiate_read (str); |
738 | 710 |
739 return size; | 711 return size; |
740 } | 712 } |
741 | 713 |
742 static ssize_t | 714 static int |
743 winsock_writer (Lstream *stream, const unsigned char *data, size_t size) | 715 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size) |
744 { | 716 { |
745 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | 717 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); |
746 | 718 |
747 if (str->pending_p) | 719 if (str->pending_p) |
748 { | 720 { |
765 if (str->error_p) | 737 if (str->error_p) |
766 return -1; | 738 return -1; |
767 | 739 |
768 if (size == 0) | 740 if (size == 0) |
769 return 0; | 741 return 0; |
770 | 742 |
771 { | 743 { |
772 ResetEvent (str->ov.hEvent); | 744 ResetEvent (str->ov.hEvent); |
773 | 745 |
774 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is | 746 /* Docs indicate that 4th parameter to WriteFile can be NULL since this is |
775 * an overlapped operation. This fails on Win95 with winsock 1.x so we | 747 * an overlapped operation. This fails on Win95 with winsock 1.x so we |
811 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | 783 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); |
812 return str->blocking_p; | 784 return str->blocking_p; |
813 } | 785 } |
814 | 786 |
815 static Lisp_Object | 787 static Lisp_Object |
816 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode) | 788 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode) |
817 { | 789 { |
818 Lisp_Object obj; | 790 Lisp_Object obj; |
819 Lstream *lstr = Lstream_new (lstream_winsock, mode); | 791 Lstream *lstr = Lstream_new (lstream_winsock, mode); |
820 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | 792 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); |
821 | 793 |
879 /************************************************************************/ | 851 /************************************************************************/ |
880 /* Dispatch queue management */ | 852 /* Dispatch queue management */ |
881 /************************************************************************/ | 853 /************************************************************************/ |
882 | 854 |
883 static int | 855 static int |
884 mswindows_user_event_p (Lisp_Event* sevt) | 856 mswindows_user_event_p (struct Lisp_Event* sevt) |
885 { | 857 { |
886 return (sevt->event_type == key_press_event | 858 return (sevt->event_type == key_press_event |
887 || sevt->event_type == button_press_event | 859 || sevt->event_type == button_press_event |
888 || sevt->event_type == button_release_event | 860 || sevt->event_type == button_release_event |
889 || sevt->event_type == misc_user_event); | 861 || sevt->event_type == misc_user_event); |
890 } | 862 } |
891 | 863 |
892 /* | 864 /* |
893 * Add an emacs event to the proper dispatch queue | 865 * Add an emacs event to the proper dispatch queue |
894 */ | 866 */ |
895 void | 867 static void |
896 mswindows_enqueue_dispatch_event (Lisp_Object event) | 868 mswindows_enqueue_dispatch_event (Lisp_Object event) |
897 { | 869 { |
898 int user_p = mswindows_user_event_p (XEVENT(event)); | 870 int user_p = mswindows_user_event_p (XEVENT(event)); |
899 enqueue_event (event, | 871 enqueue_event (event, |
900 user_p ? &mswindows_u_dispatch_event_queue : | 872 user_p ? &mswindows_u_dispatch_event_queue : |
901 &mswindows_s_dispatch_event_queue, | 873 &mswindows_s_dispatch_event_queue, |
902 user_p ? &mswindows_u_dispatch_event_queue_tail : | 874 user_p ? &mswindows_u_dispatch_event_queue_tail : |
903 &mswindows_s_dispatch_event_queue_tail); | 875 &mswindows_s_dispatch_event_queue_tail); |
904 | 876 |
905 /* Avoid blocking on WaitMessage */ | 877 /* Avoid blocking on WaitMessage */ |
906 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); | 878 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); |
907 } | 879 } |
908 | 880 |
915 void | 887 void |
916 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function, | 888 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function, |
917 Lisp_Object object) | 889 Lisp_Object object) |
918 { | 890 { |
919 Lisp_Object event = Fmake_event (Qnil, Qnil); | 891 Lisp_Object event = Fmake_event (Qnil, Qnil); |
920 Lisp_Event* e = XEVENT (event); | 892 struct Lisp_Event* e = XEVENT (event); |
921 | 893 |
922 e->event_type = misc_user_event; | 894 e->event_type = misc_user_event; |
923 e->channel = channel; | 895 e->channel = channel; |
924 e->timestamp = GetTickCount (); | |
925 e->event.misc.function = function; | 896 e->event.misc.function = function; |
926 e->event.misc.object = object; | 897 e->event.misc.object = object; |
927 | 898 |
928 mswindows_enqueue_dispatch_event (event); | 899 mswindows_enqueue_dispatch_event (event); |
929 } | 900 } |
930 | 901 |
931 void | 902 void |
932 mswindows_enqueue_magic_event (HWND hwnd, UINT msg) | 903 mswindows_enqueue_magic_event (HWND hwnd, UINT message) |
933 { | 904 { |
934 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 905 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
935 Lisp_Event* event = XEVENT (emacs_event); | 906 struct Lisp_Event* event = XEVENT (emacs_event); |
936 | 907 |
937 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil; | 908 event->channel = hwnd ? mswindows_find_frame (hwnd) : Qnil; |
938 event->timestamp = GetMessageTime(); | 909 event->timestamp = GetMessageTime(); |
939 event->event_type = magic_event; | 910 event->event_type = magic_event; |
940 EVENT_MSWINDOWS_MAGIC_TYPE (event) = msg; | 911 EVENT_MSWINDOWS_MAGIC_TYPE (event) = message; |
941 | 912 |
942 mswindows_enqueue_dispatch_event (emacs_event); | 913 mswindows_enqueue_dispatch_event (emacs_event); |
943 } | 914 } |
944 | 915 |
945 static void | 916 static void |
946 mswindows_enqueue_process_event (Lisp_Process* p) | 917 mswindows_enqueue_process_event (struct Lisp_Process* p) |
947 { | 918 { |
948 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 919 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
949 Lisp_Event* event = XEVENT (emacs_event); | 920 struct Lisp_Event* event = XEVENT (emacs_event); |
950 Lisp_Object process; | 921 Lisp_Object process; |
951 XSETPROCESS (process, p); | 922 XSETPROCESS (process, p); |
952 | 923 |
953 event->event_type = process_event; | 924 event->event_type = process_event; |
954 event->timestamp = GetTickCount (); | 925 event->timestamp = GetTickCount (); |
956 | 927 |
957 mswindows_enqueue_dispatch_event (emacs_event); | 928 mswindows_enqueue_dispatch_event (emacs_event); |
958 } | 929 } |
959 | 930 |
960 static void | 931 static void |
961 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, | 932 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT message, POINTS where, DWORD when) |
962 DWORD when) | 933 { |
963 { | |
964 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || | |
965 msg == WM_RBUTTONDOWN); | |
966 | 934 |
967 /* We always use last message time, because mouse button | 935 /* We always use last message time, because mouse button |
968 events may get delayed, and XEmacs double click | 936 events may get delayed, and XEmacs double click |
969 recognition will fail */ | 937 recognition will fail */ |
970 | 938 |
971 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 939 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
972 Lisp_Event* event = XEVENT (emacs_event); | 940 struct Lisp_Event* event = XEVENT(emacs_event); |
973 | 941 |
974 mswindows_handle_sticky_modifiers (0, 0, downp, 0); | 942 event->channel = mswindows_find_frame(hwnd); |
975 event->channel = mswindows_find_frame (hwnd); | |
976 event->timestamp = when; | 943 event->timestamp = when; |
977 event->event.button.button = | 944 event->event.button.button = |
978 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 : | 945 (message==WM_LBUTTONDOWN || message==WM_LBUTTONUP) ? 1 : |
979 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2); | 946 ((message==WM_RBUTTONDOWN || message==WM_RBUTTONUP) ? 3 : 2); |
980 event->event.button.x = where.x; | 947 event->event.button.x = where.x; |
981 event->event.button.y = where.y; | 948 event->event.button.y = where.y; |
982 event->event.button.modifiers = mswindows_modifier_state (NULL, 0); | 949 event->event.button.modifiers = mswindows_modifier_state (NULL, 0); |
983 | 950 |
984 if (downp) | 951 if (message==WM_LBUTTONDOWN || message==WM_MBUTTONDOWN || |
952 message==WM_RBUTTONDOWN) | |
985 { | 953 { |
986 event->event_type = button_press_event; | 954 event->event_type = button_press_event; |
987 SetCapture (hwnd); | 955 SetCapture (hwnd); |
988 /* we need this to make sure the main window regains the focus | 956 /* we need this to make sure the main window regains the focus |
989 from control subwindows */ | 957 from control subwindows */ |
996 else | 964 else |
997 { | 965 { |
998 event->event_type = button_release_event; | 966 event->event_type = button_release_event; |
999 ReleaseCapture (); | 967 ReleaseCapture (); |
1000 } | 968 } |
1001 | 969 |
1002 mswindows_enqueue_dispatch_event (emacs_event); | 970 mswindows_enqueue_dispatch_event (emacs_event); |
1003 } | 971 } |
1004 | 972 |
1005 static void | 973 static void |
1006 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods) | 974 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods) |
1007 { | 975 { |
1008 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 976 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1009 Lisp_Event* event = XEVENT(emacs_event); | 977 struct Lisp_Event* event = XEVENT(emacs_event); |
1010 | 978 |
1011 event->channel = mswindows_find_console(hwnd); | 979 event->channel = mswindows_find_console(hwnd); |
1012 event->timestamp = GetMessageTime(); | 980 event->timestamp = GetMessageTime(); |
1013 event->event_type = key_press_event; | 981 event->event_type = key_press_event; |
1014 event->event.key.keysym = keysym; | 982 event->event.key.keysym = keysym; |
1019 /* | 987 /* |
1020 * Remove and return the first emacs event on the dispatch queue. | 988 * Remove and return the first emacs event on the dispatch queue. |
1021 * Give a preference to user events over non-user ones. | 989 * Give a preference to user events over non-user ones. |
1022 */ | 990 */ |
1023 static Lisp_Object | 991 static Lisp_Object |
1024 mswindows_dequeue_dispatch_event (void) | 992 mswindows_dequeue_dispatch_event () |
1025 { | 993 { |
1026 Lisp_Object event; | 994 Lisp_Object event; |
1027 Lisp_Event* sevt; | 995 struct Lisp_Event* sevt; |
1028 | 996 |
1029 assert (!NILP(mswindows_u_dispatch_event_queue) || | 997 assert (!NILP(mswindows_u_dispatch_event_queue) || |
1030 !NILP(mswindows_s_dispatch_event_queue)); | 998 !NILP(mswindows_s_dispatch_event_queue)); |
1031 | 999 |
1032 event = dequeue_event ( | 1000 event = dequeue_event ( |
1033 NILP(mswindows_u_dispatch_event_queue) ? | 1001 NILP(mswindows_u_dispatch_event_queue) ? |
1034 &mswindows_s_dispatch_event_queue : | 1002 &mswindows_s_dispatch_event_queue : |
1035 &mswindows_u_dispatch_event_queue, | 1003 &mswindows_u_dispatch_event_queue, |
1036 NILP(mswindows_u_dispatch_event_queue) ? | 1004 NILP(mswindows_u_dispatch_event_queue) ? |
1037 &mswindows_s_dispatch_event_queue_tail : | 1005 &mswindows_s_dispatch_event_queue_tail : |
1038 &mswindows_u_dispatch_event_queue_tail); | 1006 &mswindows_u_dispatch_event_queue_tail); |
1039 | 1007 |
1040 sevt = XEVENT(event); | 1008 sevt = XEVENT(event); |
1041 if (sevt->event_type == key_press_event | 1009 if (sevt->event_type == key_press_event |
1056 * event in the queue and that of the given event is non-zero. | 1024 * event in the queue and that of the given event is non-zero. |
1057 * For all other event types, this function aborts. | 1025 * For all other event types, this function aborts. |
1058 */ | 1026 */ |
1059 | 1027 |
1060 Lisp_Object | 1028 Lisp_Object |
1061 mswindows_cancel_dispatch_event (Lisp_Event *match) | 1029 mswindows_cancel_dispatch_event (struct Lisp_Event *match) |
1062 { | 1030 { |
1063 Lisp_Object event; | 1031 Lisp_Object event; |
1064 Lisp_Object previous_event = Qnil; | 1032 Lisp_Object previous_event = Qnil; |
1065 int user_p = mswindows_user_event_p (match); | 1033 int user_p = mswindows_user_event_p (match); |
1066 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : | 1034 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : |
1067 &mswindows_s_dispatch_event_queue; | 1035 &mswindows_s_dispatch_event_queue; |
1068 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : | 1036 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : |
1069 &mswindows_s_dispatch_event_queue_tail; | 1037 &mswindows_s_dispatch_event_queue_tail; |
1070 | 1038 |
1071 assert (match->event_type == timeout_event | 1039 assert (match->event_type == timeout_event |
1072 || match->event_type == key_press_event); | 1040 || match->event_type == key_press_event); |
1073 | 1041 |
1074 EVENT_CHAIN_LOOP (event, *head) | 1042 EVENT_CHAIN_LOOP (event, *head) |
1075 { | 1043 { |
1076 Lisp_Event *e = XEVENT (event); | 1044 struct Lisp_Event *e = XEVENT (event); |
1077 if ((e->event_type == match->event_type) && | 1045 if ((e->event_type == match->event_type) && |
1078 ((e->event_type == timeout_event) ? | 1046 ((e->event_type == timeout_event) ? |
1079 (e->event.timeout.interval_id == match->event.timeout.interval_id) : | 1047 (e->event.timeout.interval_id == match->event.timeout.interval_id) : |
1080 /* Must be key_press_event */ | 1048 /* Must be key_press_event */ |
1081 ((e->event.key.modifiers & match->event.key.modifiers) != 0))) | 1049 ((e->event.key.modifiers & match->event.key.modifiers) != 0))) |
1086 { | 1054 { |
1087 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event)); | 1055 XSET_EVENT_NEXT (previous_event, XEVENT_NEXT (event)); |
1088 if (EQ (*tail, event)) | 1056 if (EQ (*tail, event)) |
1089 *tail = previous_event; | 1057 *tail = previous_event; |
1090 } | 1058 } |
1091 | 1059 |
1092 return event; | 1060 return event; |
1093 } | 1061 } |
1094 previous_event = event; | 1062 previous_event = event; |
1095 } | 1063 } |
1096 return Qnil; | 1064 return Qnil; |
1127 { | 1095 { |
1128 int ix = find_waitable_handle (h); | 1096 int ix = find_waitable_handle (h); |
1129 if (ix < 0) | 1097 if (ix < 0) |
1130 return; | 1098 return; |
1131 | 1099 |
1132 mswindows_waitable_handles [ix] = | 1100 mswindows_waitable_handles [ix] = |
1133 mswindows_waitable_handles [--mswindows_waitable_count]; | 1101 mswindows_waitable_handles [--mswindows_waitable_count]; |
1134 } | 1102 } |
1135 #endif /* HAVE_MSG_SELECT */ | 1103 #endif /* HAVE_MSG_SELECT */ |
1136 | 1104 |
1137 | 1105 |
1151 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg), | 1119 mswindows_protect_modal_loop (Lisp_Object (*bfun) (Lisp_Object barg), |
1152 Lisp_Object barg) | 1120 Lisp_Object barg) |
1153 { | 1121 { |
1154 Lisp_Object tmp; | 1122 Lisp_Object tmp; |
1155 | 1123 |
1156 ++mswindows_in_modal_loop; | 1124 ++mswindows_in_modal_loop; |
1157 tmp = condition_case_1 (Qt, | 1125 tmp = condition_case_1 (Qt, |
1158 bfun, barg, | 1126 bfun, barg, |
1159 mswindows_modal_loop_error_handler, Qnil); | 1127 mswindows_modal_loop_error_handler, Qnil); |
1160 --mswindows_in_modal_loop; | 1128 --mswindows_in_modal_loop; |
1161 | 1129 |
1175 Fsignal (sym, data); | 1143 Fsignal (sym, data); |
1176 } | 1144 } |
1177 } | 1145 } |
1178 | 1146 |
1179 /* | 1147 /* |
1180 * This is an unsafe part of event pump, guarded by | 1148 * This is an unsafe part of event pump, guarded by |
1181 * condition_case. See mswindows_pump_outstanding_events | 1149 * condition_case. See mswindows_pump_outstanding_events |
1182 */ | 1150 */ |
1183 static Lisp_Object | 1151 static Lisp_Object |
1184 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d) | 1152 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d) |
1185 { | 1153 { |
1199 if (do_redisplay) | 1167 if (do_redisplay) |
1200 redisplay (); | 1168 redisplay (); |
1201 | 1169 |
1202 Fdeallocate_event (event); | 1170 Fdeallocate_event (event); |
1203 UNGCPRO; | 1171 UNGCPRO; |
1204 | 1172 |
1205 /* Qt becomes return value of mswindows_pump_outstanding_events | 1173 /* Qt becomes return value of mswindows_pump_outstanding_events |
1206 once we get here */ | 1174 once we get here */ |
1207 return Qt; | 1175 return Qt; |
1208 } | 1176 } |
1209 | 1177 |
1247 /* This function can call lisp */ | 1215 /* This function can call lisp */ |
1248 | 1216 |
1249 Lisp_Object result = Qt; | 1217 Lisp_Object result = Qt; |
1250 struct gcpro gcpro1; | 1218 struct gcpro gcpro1; |
1251 GCPRO1 (result); | 1219 GCPRO1 (result); |
1252 | 1220 |
1253 if (NILP(mswindows_error_caught_in_modal_loop)) | 1221 if (NILP(mswindows_error_caught_in_modal_loop)) |
1254 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); | 1222 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); |
1255 UNGCPRO; | 1223 UNGCPRO; |
1256 return result; | 1224 return result; |
1257 } | 1225 } |
1258 | 1226 |
1259 /* | 1227 static void |
1260 * KEYBOARD_ONLY_P is set to non-zero when we are called from | 1228 mswindows_drain_windows_queue () |
1261 * QUITP, and are interesting in keyboard messages only. | |
1262 */ | |
1263 static void | |
1264 mswindows_drain_windows_queue (void) | |
1265 { | 1229 { |
1266 MSG msg; | 1230 MSG msg; |
1267 | |
1268 /* should call mswindows_need_event_in_modal_loop() if in modal loop */ | |
1269 assert (!mswindows_in_modal_loop); | |
1270 | |
1271 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) | 1231 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) |
1272 { | 1232 { |
1273 /* We have to translate messages that are not sent to an XEmacs | 1233 /* we have to translate messages that are not sent to the main |
1274 frame. This is so that key presses work ok in things like | 1234 window. this is so that key presses work ok in things like |
1275 edit fields. However, we *musn't* translate message for XEmacs | 1235 edit fields. however, we *musn't* translate message for the |
1276 frames as this is handled in the wnd proc. | 1236 main window as this is handled in the wnd proc. */ |
1277 We also have to avoid generating paint magic events for windows | 1237 if ( GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD ) |
1278 that aren't XEmacs frames */ | |
1279 /* GetClassName will truncate a longer class name. By adding one | |
1280 extra character, we are forcing textual comparison to fail | |
1281 if the name is longer than XEMACS_CLASS */ | |
1282 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = ""; | |
1283 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1); | |
1284 if (stricmp (class_name_buf, XEMACS_CLASS) != 0) | |
1285 { | 1238 { |
1286 /* Not an XEmacs frame */ | |
1287 TranslateMessage (&msg); | 1239 TranslateMessage (&msg); |
1288 } | |
1289 else if (msg.message == WM_PAINT) | |
1290 { | |
1291 struct mswindows_frame* msframe; | |
1292 | |
1293 /* hdc will be NULL unless this is a subwindow - in which case we | |
1294 shouldn't have received a paint message for it here. */ | |
1295 assert (msg.wParam == 0); | |
1296 | |
1297 /* Queue a magic event for handling when safe */ | |
1298 msframe = | |
1299 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd))); | |
1300 if (!msframe->paint_pending) | |
1301 { | |
1302 msframe->paint_pending = 1; | |
1303 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT); | |
1304 } | |
1305 /* Don't dispatch. WM_PAINT is always the last message in the | |
1306 queue so it's OK to just return. */ | |
1307 return; | |
1308 } | 1240 } |
1309 DispatchMessage (&msg); | 1241 DispatchMessage (&msg); |
1310 mswindows_unmodalize_signal_maybe (); | 1242 mswindows_unmodalize_signal_maybe (); |
1311 } | 1243 } |
1312 } | 1244 } |
1313 | 1245 |
1314 /* | 1246 /* |
1315 * This is a special flavor of the mswindows_need_event function, | 1247 * This is a special flavor of the mswindows_need_event function, |
1316 * used while in event pump. Actually, there is only kind of events | 1248 * used while in event pump. Actually, there is only kind of events |
1317 * allowed while in event pump: a timer. An attempt to fetch any | 1249 * allowed while in event pump: a timer. An attempt to fetch any |
1318 * other event leads to a deadlock, as there's no source of user input | 1250 * other event leads to a deadlock, as there's no source of user input |
1319 * ('cause event pump mirrors windows modal loop, which is a sole | 1251 * ('cause event pump mirrors windows modal loop, which is a sole |
1342 while (NILP (mswindows_s_dispatch_event_queue)) | 1274 while (NILP (mswindows_s_dispatch_event_queue)) |
1343 { | 1275 { |
1344 /* We'll deadlock if go waiting */ | 1276 /* We'll deadlock if go waiting */ |
1345 if (mswindows_pending_timers_count == 0) | 1277 if (mswindows_pending_timers_count == 0) |
1346 error ("Deadlock due to an attempt to call next-event in a wrong context"); | 1278 error ("Deadlock due to an attempt to call next-event in a wrong context"); |
1347 | 1279 |
1348 /* Fetch and dispatch any pending timers */ | 1280 /* Fetch and dispatch any pending timers */ |
1349 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER); | 1281 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER); |
1350 DispatchMessage (&msg); | 1282 DispatchMessage (&msg); |
1351 } | 1283 } |
1352 } | 1284 } |
1367 { | 1299 { |
1368 mswindows_need_event_in_modal_loop (badly_p); | 1300 mswindows_need_event_in_modal_loop (badly_p); |
1369 return; | 1301 return; |
1370 } | 1302 } |
1371 | 1303 |
1304 /* Have to drain Windows message queue first, otherwise, we may miss | |
1305 quit char when called from quit_p */ | |
1306 mswindows_drain_windows_queue (); | |
1307 | |
1372 while (NILP (mswindows_u_dispatch_event_queue) | 1308 while (NILP (mswindows_u_dispatch_event_queue) |
1373 && NILP (mswindows_s_dispatch_event_queue)) | 1309 && NILP (mswindows_s_dispatch_event_queue)) |
1374 { | 1310 { |
1375 #ifdef HAVE_MSG_SELECT | 1311 #ifdef HAVE_MSG_SELECT |
1376 int i; | 1312 int i; |
1377 SELECT_TYPE temp_mask = input_wait_mask; | 1313 SELECT_TYPE temp_mask = input_wait_mask; |
1378 EMACS_TIME sometime; | 1314 EMACS_TIME sometime; |
1379 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this; | 1315 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this; |
1380 | 1316 |
1381 if (badly_p) | 1317 if (badly_p) |
1382 pointer_to_this = 0; | 1318 pointer_to_this = 0; |
1383 else | 1319 else |
1384 { | 1320 { |
1385 EMACS_SET_SECS_USECS (sometime, 0, 0); | 1321 EMACS_SET_SECS_USECS (sometime, 0, 0); |
1386 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block); | 1322 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block); |
1387 pointer_to_this = &select_time_to_block; | 1323 pointer_to_this = &select_time_to_block; |
1388 } | 1324 } |
1389 | 1325 |
1390 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this); | 1326 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this); |
1391 | 1327 |
1392 if (active == 0) | 1328 if (active == 0) |
1393 { | 1329 { |
1394 assert (!badly_p); | |
1395 return; /* timeout */ | 1330 return; /* timeout */ |
1396 } | 1331 } |
1397 else if (active > 0) | 1332 else if (active > 0) |
1398 { | 1333 { |
1399 if (FD_ISSET (windows_fd, &temp_mask)) | 1334 if (FD_ISSET (windows_fd, &temp_mask)) |
1400 { | 1335 { |
1401 mswindows_drain_windows_queue (); | 1336 mswindows_drain_windows_queue (); |
1402 } | 1337 } |
1403 else | 1338 #ifdef HAVE_TTY |
1339 /* Look for a TTY event */ | |
1340 for (i = 0; i < MAXDESC-1; i++) | |
1404 { | 1341 { |
1405 #ifdef HAVE_TTY | 1342 /* To avoid race conditions (among other things, an infinite |
1406 /* Look for a TTY event */ | 1343 loop when called from Fdiscard_input()), we must return |
1407 for (i = 0; i < MAXDESC-1; i++) | 1344 user events ahead of process events. */ |
1345 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) | |
1408 { | 1346 { |
1409 /* To avoid race conditions (among other things, an infinite | 1347 struct console *c = tty_find_console_from_fd (i); |
1410 loop when called from Fdiscard_input()), we must return | 1348 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1411 user events ahead of process events. */ | 1349 struct Lisp_Event* event = XEVENT (emacs_event); |
1412 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) | 1350 |
1351 assert (c); | |
1352 if (read_event_from_tty_or_stream_desc (event, c, i)) | |
1413 { | 1353 { |
1414 struct console *c = tty_find_console_from_fd (i); | 1354 mswindows_enqueue_dispatch_event (emacs_event); |
1415 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 1355 return; |
1416 Lisp_Event* event = XEVENT (emacs_event); | |
1417 | |
1418 assert (c); | |
1419 if (read_event_from_tty_or_stream_desc (event, c, i)) | |
1420 { | |
1421 mswindows_enqueue_dispatch_event (emacs_event); | |
1422 return; | |
1423 } | |
1424 } | 1356 } |
1425 } | 1357 } |
1426 #endif | 1358 } |
1427 /* Look for a process event */ | 1359 #endif |
1428 for (i = 0; i < MAXDESC-1; i++) | 1360 /* Look for a process event */ |
1361 for (i = 0; i < MAXDESC-1; i++) | |
1362 { | |
1363 if (FD_ISSET (i, &temp_mask)) | |
1429 { | 1364 { |
1430 if (FD_ISSET (i, &temp_mask)) | 1365 if (FD_ISSET (i, &process_only_mask)) |
1431 { | 1366 { |
1432 if (FD_ISSET (i, &process_only_mask)) | 1367 struct Lisp_Process *p = |
1433 { | 1368 get_process_from_usid (FD_TO_USID(i)); |
1434 Lisp_Process *p = | 1369 |
1435 get_process_from_usid (FD_TO_USID(i)); | 1370 mswindows_enqueue_process_event (p); |
1436 | 1371 } |
1437 mswindows_enqueue_process_event (p); | 1372 else |
1438 } | 1373 { |
1439 else | 1374 /* We might get here when a fake event came |
1440 { | 1375 through a signal. Return a dummy event, so |
1441 /* We might get here when a fake event came | 1376 that a cycle of the command loop will |
1442 through a signal. Return a dummy event, so | 1377 occur. */ |
1443 that a cycle of the command loop will | 1378 drain_signal_event_pipe (); |
1444 occur. */ | 1379 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); |
1445 drain_signal_event_pipe (); | |
1446 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1447 } | |
1448 } | 1380 } |
1449 } | 1381 } |
1450 } | 1382 } |
1451 } | 1383 } |
1452 else if (active==-1) | 1384 else if (active==-1) |
1461 { | 1393 { |
1462 assert(0); | 1394 assert(0); |
1463 } | 1395 } |
1464 #else | 1396 #else |
1465 /* Now try getting a message or process event */ | 1397 /* Now try getting a message or process event */ |
1466 active = MsgWaitForMultipleObjects (mswindows_waitable_count, | 1398 active = MsgWaitForMultipleObjects (mswindows_waitable_count, |
1467 mswindows_waitable_handles, | 1399 mswindows_waitable_handles, |
1468 FALSE, badly_p ? INFINITE : 0, | 1400 FALSE, badly_p ? INFINITE : 0, |
1469 QS_ALLINPUT); | 1401 QS_ALLINPUT); |
1470 | 1402 |
1471 /* This will assert if handle being waited for becomes abandoned. | 1403 /* This will assert if handle being waited for becomes abandoned. |
1472 Not the case currently tho */ | 1404 Not the case currently tho */ |
1473 assert ((!badly_p && active == WAIT_TIMEOUT) || | 1405 assert ((!badly_p && active == WAIT_TIMEOUT) || |
1474 (active >= WAIT_OBJECT_0 && | 1406 (active >= WAIT_OBJECT_0 && |
1475 active <= WAIT_OBJECT_0 + mswindows_waitable_count)); | 1407 active <= WAIT_OBJECT_0 + mswindows_waitable_count)); |
1476 | 1408 |
1477 if (active == WAIT_TIMEOUT) | 1409 if (active == WAIT_TIMEOUT) |
1478 { | 1410 { |
1479 /* No luck trying - just return what we've already got */ | 1411 /* No luck trying - just return what we've already got */ |
1480 return; | 1412 return; |
1481 } | 1413 } |
1482 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) | 1414 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) |
1483 { | 1415 { |
1484 /* Got your message, thanks */ | 1416 /* Got your message, thanks */ |
1485 mswindows_drain_windows_queue (); | 1417 mswindows_drain_windows_queue (); |
1486 } | 1418 } |
1487 else | 1419 else |
1488 { | 1420 { |
1489 int ix = active - WAIT_OBJECT_0; | 1421 int ix = active - WAIT_OBJECT_0; |
1490 /* First, try to find which process' output has signaled */ | 1422 /* First, try to find which process' output has signaled */ |
1491 Lisp_Process *p = | 1423 struct Lisp_Process *p = |
1492 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix])); | 1424 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix])); |
1493 if (p != NULL) | 1425 if (p != NULL) |
1494 { | 1426 { |
1495 /* Found a signaled process input handle */ | 1427 /* Found a signaled process input handle */ |
1496 mswindows_enqueue_process_event (p); | 1428 mswindows_enqueue_process_event (p); |
1497 } | 1429 } |
1498 else | 1430 else |
1499 { | 1431 { |
1500 /* None. This means that the process handle itself has signaled. | 1432 /* None. This means that the process handle itself has signaled. |
1501 Remove the handle from the wait vector, and make status_notify | 1433 Remove the handle from the wait vector, and make status_notify |
1502 note the exited process */ | 1434 note the exited process */ |
1503 mswindows_waitable_handles [ix] = | 1435 mswindows_waitable_handles [ix] = |
1504 mswindows_waitable_handles [--mswindows_waitable_count]; | 1436 mswindows_waitable_handles [--mswindows_waitable_count]; |
1505 kick_status_notify (); | 1437 kick_status_notify (); |
1506 /* We need to return a process event here so that | 1438 /* Have to return something: there may be no accompanying |
1507 (1) accept-process-output will return when called on this | 1439 process event */ |
1508 process, and (2) status notifications will happen in | 1440 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); |
1509 accept-process-output, sleep-for, and sit-for. */ | 1441 } |
1510 /* #### horrible kludge till my real process fixes go in. | 1442 } |
1511 */ | 1443 #endif |
1512 if (!NILP (Vprocess_list)) | 1444 } /* while */ |
1513 { | |
1514 Lisp_Object vaffanculo = XCAR (Vprocess_list); | |
1515 mswindows_enqueue_process_event (XPROCESS (vaffanculo)); | |
1516 } | |
1517 else /* trash me soon. */ | |
1518 /* Have to return something: there may be no accompanying | |
1519 process event */ | |
1520 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1521 } | |
1522 } | |
1523 #endif | |
1524 } /* while */ | |
1525 } | 1445 } |
1526 | 1446 |
1527 /************************************************************************/ | 1447 /************************************************************************/ |
1528 /* Event generators */ | 1448 /* Event generators */ |
1529 /************************************************************************/ | 1449 /************************************************************************/ |
1530 | 1450 |
1531 /* | 1451 /* |
1532 * Callback procedure for synchronous timer messages | 1452 * Callback procedure for synchronous timer messages |
1533 */ | 1453 */ |
1534 static void CALLBACK | 1454 static void CALLBACK |
1535 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime) | 1455 mswindows_wm_timer_callback (HWND hwnd, UINT umsg, UINT id_timer, DWORD dwtime) |
1536 { | 1456 { |
1537 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 1457 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1538 Lisp_Event *event = XEVENT (emacs_event); | 1458 struct Lisp_Event *event = XEVENT (emacs_event); |
1539 | 1459 |
1540 if (KillTimer (NULL, id_timer)) | 1460 if (KillTimer (NULL, id_timer)) |
1541 --mswindows_pending_timers_count; | 1461 --mswindows_pending_timers_count; |
1542 | 1462 |
1543 event->channel = Qnil; | 1463 event->channel = Qnil; |
1548 event->event.timeout.object = Qnil; | 1468 event->event.timeout.object = Qnil; |
1549 | 1469 |
1550 mswindows_enqueue_dispatch_event (emacs_event); | 1470 mswindows_enqueue_dispatch_event (emacs_event); |
1551 } | 1471 } |
1552 | 1472 |
1553 /* | 1473 /* |
1554 * Callback procedure for dde messages | 1474 * Callback procedure for dde messages |
1555 * | 1475 * |
1556 * We execute a dde Open("file") by simulating a file drop, so dde support | 1476 * We execute a dde Open("file") by simulating a file drop, so dde support |
1557 * depends on dnd support. | 1477 * depends on dnd support. |
1558 */ | 1478 */ |
1559 #ifdef HAVE_DRAGNDROP | 1479 #ifdef HAVE_DRAGNDROP |
1560 HDDEDATA CALLBACK | 1480 HDDEDATA CALLBACK |
1561 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, | 1481 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV hconv, |
1562 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata, | 1482 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata, |
1563 DWORD dwData1, DWORD dwData2) | 1483 DWORD dwData1, DWORD dwData2) |
1564 { | 1484 { |
1565 switch (uType) | 1485 switch (uType) |
1566 { | 1486 { |
1567 case XTYP_CONNECT: | 1487 case XTYP_CONNECT: |
1568 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) | 1488 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) |
1569 return (HDDEDATA)TRUE; | 1489 return (HDDEDATA)TRUE; |
1570 return (HDDEDATA)FALSE; | 1490 return (HDDEDATA)FALSE; |
1571 | 1491 |
1574 /* We only support one {service,topic} pair */ | 1494 /* We only support one {service,topic} pair */ |
1575 HSZPAIR pairs[2] = { | 1495 HSZPAIR pairs[2] = { |
1576 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } }; | 1496 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } }; |
1577 | 1497 |
1578 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) && | 1498 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) && |
1579 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))) | 1499 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))); |
1580 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs, | 1500 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs, |
1581 sizeof (pairs), 0L, 0, uFmt, 0)); | 1501 sizeof (pairs), 0L, 0, uFmt, 0)); |
1582 } | 1502 } |
1583 return (HDDEDATA)NULL; | 1503 return (HDDEDATA)NULL; |
1584 | 1504 |
1585 case XTYP_EXECUTE: | 1505 case XTYP_EXECUTE: |
1586 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) | 1506 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) |
1587 { | 1507 { |
1588 DWORD len = DdeGetData (hdata, NULL, 0, 0); | 1508 DWORD len = DdeGetData (hdata, NULL, 0, 0); |
1589 LPBYTE cmd = (LPBYTE) alloca (len+1); | 1509 char *cmd = alloca (len+1); |
1590 char *end; | 1510 char *end; |
1591 char *filename; | 1511 char *filename; |
1592 struct gcpro gcpro1, gcpro2; | 1512 struct gcpro gcpro1, gcpro2; |
1593 Lisp_Object l_dndlist = Qnil; | 1513 Lisp_Object l_dndlist = Qnil; |
1594 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 1514 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1595 Lisp_Object frmcons, devcons, concons; | 1515 Lisp_Object frmcons, devcons, concons; |
1596 Lisp_Event *event = XEVENT (emacs_event); | 1516 struct Lisp_Event *event = XEVENT (emacs_event); |
1597 | 1517 |
1598 DdeGetData (hdata, cmd, len, 0); | 1518 DdeGetData (hdata, cmd, len, 0); |
1599 cmd[len] = '\0'; | 1519 cmd[len] = '\0'; |
1600 DdeFreeDataHandle (hdata); | 1520 DdeFreeDataHandle (hdata); |
1601 | 1521 |
1623 if (*(++end)==']') | 1543 if (*(++end)==']') |
1624 end++; | 1544 end++; |
1625 if (*end) | 1545 if (*end) |
1626 return DDE_FNOTPROCESSED; | 1546 return DDE_FNOTPROCESSED; |
1627 | 1547 |
1628 #ifdef CYGWIN | 1548 #ifdef __CYGWIN32__ |
1629 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5); | 1549 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5); |
1630 strcpy (filename, "file:"); | 1550 strcpy (filename, "file:"); |
1631 cygwin32_win32_to_posix_path_list (cmd, filename+5); | 1551 cygwin32_win32_to_posix_path_list (cmd, filename+5); |
1632 #else | 1552 #else |
1633 dostounix_filename (cmd); | 1553 dostounix_filename (cmd); |
1659 Fcons (l_dndlist, Qnil)); | 1579 Fcons (l_dndlist, Qnil)); |
1660 mswindows_enqueue_dispatch_event (emacs_event); | 1580 mswindows_enqueue_dispatch_event (emacs_event); |
1661 UNGCPRO; | 1581 UNGCPRO; |
1662 return (HDDEDATA) DDE_FACK; | 1582 return (HDDEDATA) DDE_FACK; |
1663 } | 1583 } |
1664 DdeFreeDataHandle (hdata); | 1584 DdeFreeDataHandle (hdata); |
1665 return (HDDEDATA) DDE_FNOTPROCESSED; | 1585 return (HDDEDATA) DDE_FNOTPROCESSED; |
1666 | 1586 |
1667 default: | 1587 default: |
1668 return (HDDEDATA) NULL; | 1588 return (HDDEDATA) NULL; |
1669 } | 1589 } |
1670 } | 1590 } |
1671 #endif | 1591 #endif |
1672 | |
1673 /* | |
1674 * Helper to do repainting - repaints can happen both from the windows | |
1675 * procedure and from magic events | |
1676 */ | |
1677 static void | |
1678 mswindows_handle_paint (struct frame *frame) | |
1679 { | |
1680 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame); | |
1681 | |
1682 /* According to the docs we need to check GetUpdateRect() before | |
1683 actually doing a WM_PAINT */ | |
1684 if (GetUpdateRect (hwnd, NULL, FALSE)) | |
1685 { | |
1686 PAINTSTRUCT paintStruct; | |
1687 int x, y, width, height; | |
1688 | |
1689 BeginPaint (hwnd, &paintStruct); | |
1690 x = paintStruct.rcPaint.left; | |
1691 y = paintStruct.rcPaint.top; | |
1692 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; | |
1693 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; | |
1694 /* Normally we want to ignore expose events when child | |
1695 windows are unmapped, however once we are in the guts of | |
1696 WM_PAINT we need to make sure that we don't register | |
1697 unmaps then because they will not actually occur. */ | |
1698 /* #### commenting out the next line seems to fix some problems | |
1699 but not all. only andy currently understands this stuff and | |
1700 he needs to review it more carefully. --ben */ | |
1701 if (!check_for_ignored_expose (frame, x, y, width, height)) | |
1702 { | |
1703 hold_ignored_expose_registration = 1; | |
1704 mswindows_redraw_exposed_area (frame, x, y, width, height); | |
1705 hold_ignored_expose_registration = 0; | |
1706 } | |
1707 EndPaint (hwnd, &paintStruct); | |
1708 } | |
1709 } | |
1710 | |
1711 /* | |
1712 * Returns 1 if a key is a real modifier or special key, which | |
1713 * is better handled by DefWindowProc | |
1714 */ | |
1715 static int | |
1716 key_needs_default_processing_p (UINT vkey) | |
1717 { | |
1718 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU | |
1719 /* if we let ALT activate the menu like this, then sticky ALT-modified | |
1720 keystrokes become impossible. */ | |
1721 && !modifier_keys_are_sticky) | |
1722 return 1; | |
1723 | |
1724 return 0; | |
1725 } | |
1726 | |
1727 /* key-handling code is always ugly. It just ends up working out | |
1728 that way. | |
1729 | |
1730 #### Most of the sticky-modifier code below is copied from similar | |
1731 code in event-Xt.c. They should somehow or other be merged. | |
1732 | |
1733 Here are some pointers: | |
1734 | |
1735 -- DOWN_MASK indicates which modifiers should be treated as "down" | |
1736 when the corresponding upstroke happens. It gets reset for | |
1737 a particular modifier when that modifier goes up, and reset | |
1738 for all modifiers when a non-modifier key is pressed. Example: | |
1739 | |
1740 I press Control-A-Shift and then release Control-A-Shift. | |
1741 I want the Shift key to be sticky but not the Control key. | |
1742 | |
1743 -- If a modifier key is sticky, I can unstick it by pressing | |
1744 the modifier key again. */ | |
1745 | |
1746 static WPARAM last_downkey; | |
1747 static int need_to_add_mask, down_mask; | |
1748 | |
1749 #define XEMSW_LCONTROL (1<<0) | |
1750 #define XEMSW_RCONTROL (1<<1) | |
1751 #define XEMSW_LSHIFT (1<<2) | |
1752 #define XEMSW_RSHIFT (1<<3) | |
1753 #define XEMSW_LMENU (1<<4) | |
1754 #define XEMSW_RMENU (1<<5) | |
1755 | |
1756 static int | |
1757 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, | |
1758 int downp, int keyp) | |
1759 { | |
1760 int mods = 0; | |
1761 | |
1762 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */ | |
1763 return 0; | |
1764 | |
1765 if (! (keyp && | |
1766 (wParam == VK_CONTROL || wParam == VK_LCONTROL || | |
1767 wParam == VK_RCONTROL || | |
1768 wParam == VK_MENU || wParam == VK_LMENU || | |
1769 wParam == VK_RMENU || | |
1770 wParam == VK_SHIFT || wParam == VK_LSHIFT || | |
1771 wParam == VK_RSHIFT))) | |
1772 { /* Not a modifier key */ | |
1773 if (downp && keyp && !last_downkey) | |
1774 last_downkey = wParam; | |
1775 /* If I hold press-and-release the Control key and then press | |
1776 and hold down the right arrow, I want it to auto-repeat | |
1777 Control-Right. On the other hand, if I do the same but | |
1778 manually press the Right arrow a bunch of times, I want | |
1779 to see one Control-Right and then a bunch of Rights. | |
1780 This means that we need to distinguish between an | |
1781 auto-repeated key and a key pressed and released a bunch | |
1782 of times. */ | |
1783 else if ((downp && !keyp) || | |
1784 (downp && keyp && last_downkey && | |
1785 (wParam != last_downkey || | |
1786 /* the "previous key state" bit indicates autorepeat */ | |
1787 ! (lParam & (1 << 30))))) | |
1788 { | |
1789 need_to_add_mask = 0; | |
1790 last_downkey = 0; | |
1791 } | |
1792 if (downp) | |
1793 down_mask = 0; | |
1794 | |
1795 mods = need_to_add_mask; | |
1796 } | |
1797 else /* Modifier key pressed */ | |
1798 { | |
1799 /* If a non-modifier key was pressed in the middle of a bunch | |
1800 of modifiers, then it unsticks all the modifiers that were | |
1801 previously pressed. We cannot unstick the modifiers until | |
1802 now because we want to check for auto-repeat of the | |
1803 non-modifier key. */ | |
1804 | |
1805 if (last_downkey) | |
1806 { | |
1807 last_downkey = 0; | |
1808 need_to_add_mask = 0; | |
1809 } | |
1810 | |
1811 #define FROB(mask) \ | |
1812 do { \ | |
1813 if (downp && keyp) \ | |
1814 { \ | |
1815 /* If modifier key is already sticky, \ | |
1816 then unstick it. Note that we do \ | |
1817 not test down_mask to deal with the \ | |
1818 unlikely but possible case that the \ | |
1819 modifier key auto-repeats. */ \ | |
1820 if (need_to_add_mask & mask) \ | |
1821 { \ | |
1822 need_to_add_mask &= ~mask; \ | |
1823 down_mask &= ~mask; \ | |
1824 } \ | |
1825 else \ | |
1826 down_mask |= mask; \ | |
1827 } \ | |
1828 else \ | |
1829 { \ | |
1830 if (down_mask & mask) \ | |
1831 { \ | |
1832 down_mask &= ~mask; \ | |
1833 need_to_add_mask |= mask; \ | |
1834 } \ | |
1835 } \ | |
1836 } while (0) | |
1837 | |
1838 if ((wParam == VK_CONTROL && (lParam & 0x1000000)) | |
1839 || wParam == VK_RCONTROL) | |
1840 FROB (XEMSW_RCONTROL); | |
1841 if ((wParam == VK_CONTROL && !(lParam & 0x1000000)) | |
1842 || wParam == VK_LCONTROL) | |
1843 FROB (XEMSW_LCONTROL); | |
1844 | |
1845 if ((wParam == VK_SHIFT && (lParam & 0x1000000)) | |
1846 || wParam == VK_RSHIFT) | |
1847 FROB (XEMSW_RSHIFT); | |
1848 if ((wParam == VK_SHIFT && !(lParam & 0x1000000)) | |
1849 || wParam == VK_LSHIFT) | |
1850 FROB (XEMSW_LSHIFT); | |
1851 | |
1852 if ((wParam == VK_MENU && (lParam & 0x1000000)) | |
1853 || wParam == VK_RMENU) | |
1854 FROB (XEMSW_RMENU); | |
1855 if ((wParam == VK_MENU && !(lParam & 0x1000000)) | |
1856 || wParam == VK_LMENU) | |
1857 FROB (XEMSW_LMENU); | |
1858 } | |
1859 #undef FROB | |
1860 | |
1861 if (mods && downp) | |
1862 { | |
1863 BYTE keymap[256]; | |
1864 | |
1865 GetKeyboardState (keymap); | |
1866 | |
1867 if (mods & XEMSW_LCONTROL) | |
1868 { | |
1869 keymap [VK_CONTROL] |= 0x80; | |
1870 keymap [VK_LCONTROL] |= 0x80; | |
1871 } | |
1872 if (mods & XEMSW_RCONTROL) | |
1873 { | |
1874 keymap [VK_CONTROL] |= 0x80; | |
1875 keymap [VK_RCONTROL] |= 0x80; | |
1876 } | |
1877 | |
1878 if (mods & XEMSW_LSHIFT) | |
1879 { | |
1880 keymap [VK_SHIFT] |= 0x80; | |
1881 keymap [VK_LSHIFT] |= 0x80; | |
1882 } | |
1883 if (mods & XEMSW_RSHIFT) | |
1884 { | |
1885 keymap [VK_SHIFT] |= 0x80; | |
1886 keymap [VK_RSHIFT] |= 0x80; | |
1887 } | |
1888 | |
1889 if (mods & XEMSW_LMENU) | |
1890 { | |
1891 keymap [VK_MENU] |= 0x80; | |
1892 keymap [VK_LMENU] |= 0x80; | |
1893 } | |
1894 if (mods & XEMSW_RMENU) | |
1895 { | |
1896 keymap [VK_MENU] |= 0x80; | |
1897 keymap [VK_RMENU] |= 0x80; | |
1898 } | |
1899 | |
1900 SetKeyboardState (keymap); | |
1901 return 1; | |
1902 } | |
1903 | |
1904 return 0; | |
1905 } | |
1906 | |
1907 static void | |
1908 clear_sticky_modifiers (void) | |
1909 { | |
1910 need_to_add_mask = 0; | |
1911 last_downkey = 0; | |
1912 down_mask = 0; | |
1913 } | |
1914 | |
1915 #ifdef DEBUG_XEMACS | |
1916 | |
1917 #if 0 | |
1918 | |
1919 static void | |
1920 output_modifier_keyboard_state (void) | |
1921 { | |
1922 BYTE keymap[256]; | |
1923 | |
1924 GetKeyboardState (keymap); | |
1925 | |
1926 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
1927 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
1928 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
1929 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
1930 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
1931 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
1932 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
1933 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n", | |
1934 keymap[VK_CONTROL] & 0x80 ? 1 : 0, | |
1935 keymap[VK_CONTROL] & 0x1 ? 1 : 0, | |
1936 keymap[VK_LCONTROL] & 0x80 ? 1 : 0, | |
1937 keymap[VK_LCONTROL] & 0x1 ? 1 : 0, | |
1938 keymap[VK_RCONTROL] & 0x80 ? 1 : 0, | |
1939 keymap[VK_RCONTROL] & 0x1 ? 1 : 0); | |
1940 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n", | |
1941 keymap[VK_SHIFT] & 0x80 ? 1 : 0, | |
1942 keymap[VK_SHIFT] & 0x1 ? 1 : 0, | |
1943 keymap[VK_LSHIFT] & 0x80 ? 1 : 0, | |
1944 keymap[VK_LSHIFT] & 0x1 ? 1 : 0, | |
1945 keymap[VK_RSHIFT] & 0x80 ? 1 : 0, | |
1946 keymap[VK_RSHIFT] & 0x1 ? 1 : 0); | |
1947 } | |
1948 | |
1949 #endif | |
1950 | |
1951 /* try to debug the stuck-alt-key problem. | |
1952 | |
1953 #### this happens only inconsistently, and may only happen when using | |
1954 StickyKeys in the Win2000 accessibility section of the control panel, | |
1955 which is extremely broken for other reasons. */ | |
1956 | |
1957 static void | |
1958 output_alt_keyboard_state (void) | |
1959 { | |
1960 BYTE keymap[256]; | |
1961 SHORT keystate[3]; | |
1962 // SHORT asyncstate[3]; | |
1963 | |
1964 GetKeyboardState (keymap); | |
1965 keystate[0] = GetKeyState (VK_MENU); | |
1966 keystate[1] = GetKeyState (VK_LMENU); | |
1967 keystate[2] = GetKeyState (VK_RMENU); | |
1968 /* Doing this interferes with key processing. */ | |
1969 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */ | |
1970 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */ | |
1971 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */ | |
1972 | |
1973 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
1974 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
1975 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
1976 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
1977 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
1978 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
1979 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
1980 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
1981 keystate[0] & 0x8000 ? 1 : 0, | |
1982 keystate[0] & 0x1 ? 1 : 0, | |
1983 keystate[1] & 0x8000 ? 1 : 0, | |
1984 keystate[1] & 0x1 ? 1 : 0, | |
1985 keystate[2] & 0x8000 ? 1 : 0, | |
1986 keystate[2] & 0x1 ? 1 : 0); | |
1987 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */ | |
1988 /* asyncstate[0] & 0x8000 ? 1 : 0, */ | |
1989 /* asyncstate[0] & 0x1 ? 1 : 0, */ | |
1990 /* asyncstate[1] & 0x8000 ? 1 : 0, */ | |
1991 /* asyncstate[1] & 0x1 ? 1 : 0, */ | |
1992 /* asyncstate[2] & 0x8000 ? 1 : 0, */ | |
1993 /* asyncstate[2] & 0x1 ? 1 : 0); */ | |
1994 } | |
1995 | |
1996 #endif /* DEBUG_XEMACS */ | |
1997 | |
1998 | 1592 |
1999 /* | 1593 /* |
2000 * The windows procedure for the window class XEMACS_CLASS | 1594 * The windows procedure for the window class XEMACS_CLASS |
2001 */ | 1595 */ |
2002 LRESULT WINAPI | 1596 LRESULT WINAPI |
2003 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam) | 1597 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
2004 { | 1598 { |
2005 /* Note: Remember to initialize emacs_event and event before use. | 1599 /* Note: Remember to initialize emacs_event and event before use. |
2006 This code calls code that can GC. You must GCPRO before calling such code. */ | 1600 This code calls code that can GC. You must GCPRO before calling such code. */ |
2007 Lisp_Object emacs_event = Qnil; | 1601 Lisp_Object emacs_event = Qnil; |
2008 Lisp_Object fobj = Qnil; | 1602 Lisp_Object fobj = Qnil; |
2009 | 1603 |
2010 Lisp_Event *event; | 1604 struct Lisp_Event *event; |
2011 struct frame *frame; | 1605 struct frame *frame; |
2012 struct mswindows_frame* msframe; | 1606 struct mswindows_frame* msframe; |
2013 | 1607 |
2014 assert (!GetWindowLong (hwnd, GWL_USERDATA)); | 1608 switch (message) |
2015 switch (message_) | 1609 { |
2016 { | 1610 case WM_ERASEBKGND: |
2017 case WM_DESTROYCLIPBOARD: | 1611 /* Erase background only during non-dynamic sizing */ |
2018 /* We own the clipboard and someone else wants it. Delete our | 1612 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
2019 cached copy of the clipboard contents so we'll ask for it from | 1613 if (msframe->sizing && !mswindows_dynamic_frame_resize) |
2020 Windows again when someone does a paste, and destroy any memory | 1614 goto defproc; |
2021 objects we hold on the clipboard that are not in the list of types | 1615 return 1; |
2022 that Windows will delete itself. */ | 1616 |
2023 mswindows_destroy_selection (QCLIPBOARD); | 1617 case WM_CLOSE: |
2024 handle_selection_clear (QCLIPBOARD); | 1618 fobj = mswindows_find_frame (hwnd); |
2025 break; | 1619 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); |
2026 | 1620 break; |
2027 case WM_ERASEBKGND: | 1621 |
2028 /* Erase background only during non-dynamic sizing */ | 1622 case WM_KEYUP: |
2029 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 1623 case WM_SYSKEYUP: |
2030 if (msframe->sizing && !mswindows_dynamic_frame_resize) | 1624 /* See Win95 comment under WM_KEYDOWN */ |
2031 goto defproc; | 1625 { |
2032 return 1; | 1626 BYTE keymap[256]; |
2033 | 1627 |
2034 case WM_CLOSE: | 1628 if (wParam == VK_CONTROL) |
2035 fobj = mswindows_find_frame (hwnd); | 1629 { |
2036 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); | 1630 GetKeyboardState (keymap); |
2037 break; | 1631 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; |
2038 | 1632 SetKeyboardState (keymap); |
2039 case WM_KEYUP: | 1633 } |
2040 case WM_SYSKEYUP: | 1634 else if (wParam == VK_MENU) |
2041 | 1635 { |
2042 /* See Win95 comment under WM_KEYDOWN */ | 1636 GetKeyboardState (keymap); |
1637 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; | |
1638 SetKeyboardState (keymap); | |
1639 } | |
1640 }; | |
1641 goto defproc; | |
1642 | |
1643 case WM_KEYDOWN: | |
1644 case WM_SYSKEYDOWN: | |
1645 /* In some locales the right-hand Alt key is labelled AltGr. This key | |
1646 * should produce alternative charcaters when combined with another key. | |
1647 * eg on a German keyboard pressing AltGr+q should produce '@'. | |
1648 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if | |
1649 * TranslateMessage() is called with *any* combination of Ctrl+Alt down, | |
1650 * it translates as if AltGr were down. | |
1651 * We get round this by removing all modifiers from the keymap before | |
1652 * calling TranslateMessage() unless AltGr is *really* down. */ | |
1653 { | |
1654 BYTE keymap[256]; | |
1655 int has_AltGr = mswindows_current_layout_has_AltGr (); | |
1656 int mods; | |
1657 Lisp_Object keysym; | |
1658 | |
1659 GetKeyboardState (keymap); | |
1660 mods = mswindows_modifier_state (keymap, has_AltGr); | |
1661 | |
1662 /* Handle those keys for which TranslateMessage won't generate a WM_CHAR */ | |
1663 if (!NILP (keysym = mswindows_key_to_emacs_keysym(wParam, mods))) | |
1664 mswindows_enqueue_keypress_event (hwnd, keysym, mods); | |
1665 else | |
1666 { | |
1667 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); | |
1668 BYTE keymap_orig[256]; | |
1669 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; | |
1670 MSG msg; | |
1671 | |
1672 msg.hwnd = hwnd; | |
1673 msg.message = message; | |
1674 msg.wParam = wParam; | |
1675 msg.lParam = lParam; | |
1676 msg.time = GetMessageTime(); | |
1677 msg.pt = pnt; | |
1678 | |
1679 /* GetKeyboardState() does not work as documented on Win95. We have | |
1680 * to loosely track Left and Right modifiers on behalf of the OS, | |
1681 * without screwing up Windows NT which tracks them properly. */ | |
1682 if (wParam == VK_CONTROL) | |
1683 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
1684 else if (wParam == VK_MENU) | |
1685 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] |= 0x80; | |
1686 | |
1687 memcpy (keymap_orig, keymap, 256); | |
1688 | |
1689 /* Remove shift modifier from an ascii character */ | |
1690 mods &= ~MOD_SHIFT; | |
1691 | |
1692 /* Clear control and alt modifiers unless AltGr is pressed */ | |
1693 keymap [VK_RCONTROL] = 0; | |
1694 keymap [VK_LMENU] = 0; | |
1695 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) || !(keymap [VK_RMENU] & 0x80)) | |
1696 { | |
1697 keymap [VK_LCONTROL] = 0; | |
1698 keymap [VK_CONTROL] = 0; | |
1699 keymap [VK_RMENU] = 0; | |
1700 keymap [VK_MENU] = 0; | |
1701 } | |
1702 SetKeyboardState (keymap); | |
1703 | |
1704 /* Maybe generate some WM_[SYS]CHARs in the queue */ | |
1705 TranslateMessage (&msg); | |
1706 | |
1707 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) | |
1708 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) | |
1709 { | |
1710 int mods1 = mods; | |
1711 WPARAM ch = msg.wParam; | |
1712 | |
1713 /* If a quit char with no modifiers other than control and | |
1714 shift, then mark it with a fake modifier, which is removed | |
1715 upon dequeueing the event */ | |
1716 /* #### This might also not withstand localization, if | |
1717 quit character is not a latin-1 symbol */ | |
1718 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch) | |
1719 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch)) | |
1720 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0)) | |
1721 { | |
1722 mods1 |= FAKE_MOD_QUIT; | |
1723 ++mswindows_quit_chars_count; | |
1724 } | |
1725 | |
1726 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1); | |
1727 } /* while */ | |
1728 SetKeyboardState (keymap_orig); | |
1729 } /* else */ | |
1730 } | |
1731 /* F10 causes menu activation by default. We do not want this */ | |
1732 if (wParam != VK_F10) | |
1733 goto defproc; | |
1734 break; | |
1735 | |
1736 case WM_MBUTTONDOWN: | |
1737 case WM_MBUTTONUP: | |
1738 /* Real middle mouse button has nothing to do with emulated one: | |
1739 if one wants to exercise fingers playing chords on the mouse, | |
1740 he is allowed to do that! */ | |
1741 mswindows_enqueue_mouse_button_event (hwnd, message, | |
1742 MAKEPOINTS (lParam), GetMessageTime()); | |
1743 break; | |
1744 | |
1745 case WM_LBUTTONUP: | |
1746 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1747 msframe->last_click_time = GetMessageTime(); | |
1748 | |
1749 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1750 msframe->button2_need_lbutton = 0; | |
1751 if (msframe->ignore_next_lbutton_up) | |
2043 { | 1752 { |
2044 BYTE keymap[256]; | 1753 msframe->ignore_next_lbutton_up = 0; |
2045 int should_set_keymap = 0; | 1754 } |
2046 | 1755 else if (msframe->button2_is_down) |
2047 #ifdef DEBUG_XEMACS | 1756 { |
2048 if (mswindows_debug_events) | 1757 msframe->button2_is_down = 0; |
1758 msframe->ignore_next_rbutton_up = 1; | |
1759 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
1760 MAKEPOINTS (lParam), GetMessageTime()); | |
1761 } | |
1762 else | |
1763 { | |
1764 if (msframe->button2_need_rbutton) | |
2049 { | 1765 { |
2050 stderr_out ("%s wparam=%d lparam=%d\n", | 1766 msframe->button2_need_rbutton = 0; |
2051 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP", | 1767 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, |
2052 wParam, (int)lParam); | 1768 MAKEPOINTS (lParam), GetMessageTime()); |
2053 output_alt_keyboard_state (); | 1769 } |
2054 } | 1770 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, |
2055 #endif /* DEBUG_XEMACS */ | 1771 MAKEPOINTS (lParam), GetMessageTime()); |
2056 | 1772 } |
2057 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1); | 1773 break; |
2058 if (wParam == VK_CONTROL) | 1774 |
1775 case WM_RBUTTONUP: | |
1776 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1777 msframe->last_click_time = GetMessageTime(); | |
1778 | |
1779 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1780 msframe->button2_need_rbutton = 0; | |
1781 if (msframe->ignore_next_rbutton_up) | |
1782 { | |
1783 msframe->ignore_next_rbutton_up = 0; | |
1784 } | |
1785 else if (msframe->button2_is_down) | |
1786 { | |
1787 msframe->button2_is_down = 0; | |
1788 msframe->ignore_next_lbutton_up = 1; | |
1789 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
1790 MAKEPOINTS (lParam), GetMessageTime()); | |
1791 } | |
1792 else | |
1793 { | |
1794 if (msframe->button2_need_lbutton) | |
2059 { | 1795 { |
2060 GetKeyboardState (keymap); | 1796 msframe->button2_need_lbutton = 0; |
2061 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; | 1797 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, |
2062 should_set_keymap = 1; | 1798 MAKEPOINTS (lParam), GetMessageTime()); |
2063 } | 1799 } |
2064 else if (wParam == VK_MENU) | 1800 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, |
1801 MAKEPOINTS (lParam), GetMessageTime()); | |
1802 } | |
1803 break; | |
1804 | |
1805 case WM_LBUTTONDOWN: | |
1806 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1807 | |
1808 if (msframe->button2_need_lbutton) | |
1809 { | |
1810 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1811 msframe->button2_need_lbutton = 0; | |
1812 msframe->button2_need_rbutton = 0; | |
1813 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | |
2065 { | 1814 { |
2066 GetKeyboardState (keymap); | 1815 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, |
2067 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; | 1816 MAKEPOINTS (lParam), GetMessageTime()); |
2068 should_set_keymap = 1; | 1817 msframe->button2_is_down = 1; |
2069 } | |
2070 | |
2071 if (should_set_keymap) | |
2072 // && (message_ != WM_SYSKEYUP | |
2073 // || NILP (Vmenu_accelerator_enabled))) | |
2074 SetKeyboardState (keymap); | |
2075 | |
2076 } | |
2077 | |
2078 if (key_needs_default_processing_p (wParam)) | |
2079 goto defproc; | |
2080 else | |
2081 break; | |
2082 | |
2083 case WM_KEYDOWN: | |
2084 case WM_SYSKEYDOWN: | |
2085 | |
2086 /* In some locales the right-hand Alt key is labelled AltGr. This key | |
2087 * should produce alternative charcaters when combined with another key. | |
2088 * eg on a German keyboard pressing AltGr+q should produce '@'. | |
2089 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if | |
2090 * TranslateMessage() is called with *any* combination of Ctrl+Alt down, | |
2091 * it translates as if AltGr were down. | |
2092 * We get round this by removing all modifiers from the keymap before | |
2093 * calling TranslateMessage() unless AltGr is *really* down. */ | |
2094 { | |
2095 BYTE keymap_trans[256]; | |
2096 BYTE keymap_orig[256]; | |
2097 BYTE keymap_sticky[256]; | |
2098 int has_AltGr = mswindows_current_layout_has_AltGr (); | |
2099 int mods = 0; | |
2100 int extendedp = lParam & 0x1000000; | |
2101 Lisp_Object keysym; | |
2102 int sticky_changed; | |
2103 | |
2104 #ifdef DEBUG_XEMACS | |
2105 if (mswindows_debug_events) | |
2106 { | |
2107 stderr_out ("%s wparam=%d lparam=%d\n", | |
2108 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN", | |
2109 wParam, (int)lParam); | |
2110 output_alt_keyboard_state (); | |
2111 } | |
2112 #endif /* DEBUG_XEMACS */ | |
2113 | |
2114 GetKeyboardState (keymap_orig); | |
2115 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2116 if ((sticky_changed = | |
2117 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1))) | |
2118 { | |
2119 GetKeyboardState (keymap_sticky); | |
2120 if (keymap_sticky[VK_MENU] & 0x80) | |
2121 { | |
2122 message_ = WM_SYSKEYDOWN; | |
2123 /* We have to set the "context bit" so that the | |
2124 TranslateMessage() call below that generates the | |
2125 SYSCHAR message does its thing; see the documentation | |
2126 on WM_SYSKEYDOWN */ | |
2127 lParam |= 1 << 29; | |
2128 } | |
2129 } | 1818 } |
2130 else | 1819 else |
2131 memcpy (keymap_sticky, keymap_orig, 256); | |
2132 | |
2133 mods = mswindows_modifier_state (keymap_sticky, has_AltGr); | |
2134 | |
2135 /* Handle non-printables */ | |
2136 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, | |
2137 extendedp))) | |
2138 { | 1820 { |
2139 mswindows_enqueue_keypress_event (hwnd, keysym, mods); | 1821 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, |
2140 if (sticky_changed) | 1822 msframe->last_click_point, msframe->last_click_time); |
2141 SetKeyboardState (keymap_orig); | 1823 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, |
1824 MAKEPOINTS (lParam), GetMessageTime()); | |
2142 } | 1825 } |
2143 else /* Normal keys & modifiers */ | 1826 } |
1827 else | |
1828 { | |
1829 mswindows_set_chord_timer (hwnd); | |
1830 msframe->button2_need_rbutton = 1; | |
1831 msframe->last_click_point = MAKEPOINTS (lParam); | |
1832 } | |
1833 msframe->last_click_time = GetMessageTime(); | |
1834 break; | |
1835 | |
1836 case WM_RBUTTONDOWN: | |
1837 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1838 | |
1839 if (msframe->button2_need_rbutton) | |
1840 { | |
1841 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1842 msframe->button2_need_lbutton = 0; | |
1843 msframe->button2_need_rbutton = 0; | |
1844 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | |
2144 { | 1845 { |
2145 Emchar quit_ch = | 1846 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, |
2146 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); | 1847 MAKEPOINTS (lParam), GetMessageTime()); |
2147 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; | 1848 msframe->button2_is_down = 1; |
2148 MSG msg, tranmsg; | 1849 } |
2149 int potential_accelerator = 0; | 1850 else |
2150 int got_accelerator = 0; | 1851 { |
1852 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
1853 msframe->last_click_point, msframe->last_click_time); | |
1854 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
1855 MAKEPOINTS (lParam), GetMessageTime()); | |
1856 } | |
1857 } | |
1858 else | |
1859 { | |
1860 mswindows_set_chord_timer (hwnd); | |
1861 msframe->button2_need_lbutton = 1; | |
1862 msframe->last_click_point = MAKEPOINTS (lParam); | |
1863 } | |
1864 msframe->last_click_time = GetMessageTime(); | |
1865 break; | |
1866 | |
1867 case WM_TIMER: | |
1868 if (wParam == BUTTON_2_TIMER_ID) | |
1869 { | |
1870 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1871 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1872 | |
1873 if (msframe->button2_need_lbutton) | |
1874 { | |
1875 msframe->button2_need_lbutton = 0; | |
1876 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
1877 msframe->last_click_point, msframe->last_click_time); | |
1878 } | |
1879 else if (msframe->button2_need_rbutton) | |
1880 { | |
1881 msframe->button2_need_rbutton = 0; | |
1882 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
1883 msframe->last_click_point, msframe->last_click_time); | |
1884 } | |
1885 } | |
1886 else | |
1887 assert ("Spurious timer fired" == 0); | |
1888 break; | |
1889 | |
1890 case WM_MOUSEMOVE: | |
1891 /* Optimization: don't report mouse movement while size is changing */ | |
1892 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1893 if (!msframe->sizing) | |
1894 { | |
1895 /* When waiting for the second mouse button to finish | |
1896 button2 emulation, and have moved too far, just pretend | |
1897 as if timer has expired. This improves drag-select feedback */ | |
1898 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) | |
1899 && !mswindows_button2_near_enough (msframe->last_click_point, | |
1900 MAKEPOINTS (lParam))) | |
1901 { | |
1902 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1903 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); | |
1904 } | |
1905 | |
1906 emacs_event = Fmake_event (Qnil, Qnil); | |
1907 event = XEVENT(emacs_event); | |
1908 | |
1909 event->channel = mswindows_find_frame(hwnd); | |
1910 event->timestamp = GetMessageTime(); | |
1911 event->event_type = pointer_motion_event; | |
1912 event->event.motion.x = MAKEPOINTS(lParam).x; | |
1913 event->event.motion.y = MAKEPOINTS(lParam).y; | |
1914 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); | |
1915 | |
1916 mswindows_enqueue_dispatch_event (emacs_event); | |
1917 } | |
1918 break; | |
1919 | |
1920 case WM_CANCELMODE: | |
1921 ReleaseCapture (); | |
1922 /* Queue a `cancel-mode-internal' misc user event, so mouse | |
1923 selection would be canceled if any */ | |
1924 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), | |
1925 Qcancel_mode_internal, Qnil); | |
1926 break; | |
1927 | |
1928 #ifdef HAVE_TOOLBARS | |
1929 case WM_NOTIFY: | |
1930 { | |
1931 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; | |
1932 Lisp_Object btext; | |
1933 if (tttext->hdr.code == TTN_NEEDTEXT) | |
1934 { | |
1935 /* find out which toolbar */ | |
1936 frame = XFRAME (mswindows_find_frame (hwnd)); | |
1937 btext = mswindows_get_toolbar_button_text ( frame, | |
1938 tttext->hdr.idFrom ); | |
2151 | 1939 |
2152 msg.hwnd = hwnd; | 1940 tttext->lpszText = NULL; |
2153 msg.message = message_; | 1941 tttext->hinst = NULL; |
2154 msg.wParam = wParam; | 1942 |
2155 msg.lParam = lParam; | 1943 if (!NILP(btext)) |
2156 msg.time = GetMessageTime(); | 1944 { |
2157 msg.pt = pnt; | 1945 /* I think this is safe since the text will only go away |
2158 | 1946 when the toolbar does...*/ |
2159 /* GetKeyboardState() does not work as documented on Win95. We have | 1947 GET_C_STRING_EXT_DATA_ALLOCA (btext, FORMAT_OS, |
2160 * to loosely track Left and Right modifiers on behalf of the OS, | 1948 tttext->lpszText); |
2161 * without screwing up Windows NT which tracks them properly. */ | 1949 } |
2162 if (wParam == VK_CONTROL) | 1950 #if 0 |
2163 { | 1951 tttext->uFlags |= TTF_DI_SETITEM; |
2164 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | 1952 #endif |
2165 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | 1953 } |
2166 } | 1954 } |
2167 else if (wParam == VK_MENU) | 1955 break; |
2168 { | 1956 #endif |
2169 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | 1957 |
2170 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | 1958 case WM_PAINT: |
2171 } | 1959 { |
2172 | 1960 PAINTSTRUCT paintStruct; |
2173 if (!NILP (Vmenu_accelerator_enabled) && | 1961 |
2174 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN) | 1962 frame = XFRAME (mswindows_find_frame (hwnd)); |
2175 potential_accelerator = 1; | 1963 |
2176 | 1964 BeginPaint (hwnd, &paintStruct); |
2177 /* Remove shift modifier from an ascii character */ | 1965 mswindows_redraw_exposed_area (frame, |
2178 mods &= ~XEMACS_MOD_SHIFT; | 1966 paintStruct.rcPaint.left, paintStruct.rcPaint.top, |
2179 | 1967 paintStruct.rcPaint.right, paintStruct.rcPaint.bottom); |
2180 memcpy (keymap_trans, keymap_sticky, 256); | 1968 EndPaint (hwnd, &paintStruct); |
2181 | 1969 } |
2182 /* Clear control and alt modifiers unless AltGr is pressed */ | 1970 break; |
2183 keymap_trans[VK_RCONTROL] = 0; | 1971 |
2184 keymap_trans[VK_LMENU] = 0; | 1972 case WM_SIZE: |
2185 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80) | 1973 /* We only care about this message if our size has really changed */ |
2186 || !(keymap_trans[VK_RMENU] & 0x80)) | 1974 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) |
2187 { | 1975 { |
2188 keymap_trans[VK_LCONTROL] = 0; | 1976 RECT rect; |
2189 keymap_trans[VK_CONTROL] = 0; | 1977 int columns, rows; |
2190 keymap_trans[VK_RMENU] = 0; | 1978 |
2191 keymap_trans[VK_MENU] = 0; | 1979 fobj = mswindows_find_frame (hwnd); |
2192 } | 1980 frame = XFRAME (fobj); |
2193 SetKeyboardState (keymap_trans); | 1981 msframe = FRAME_MSWINDOWS_DATA (frame); |
2194 | 1982 |
2195 /* Maybe generate some WM_[SYS]CHARs in the queue */ | 1983 /* We cannot handle frame map and unmap hooks right in |
2196 TranslateMessage (&msg); | 1984 this routine, because these may throw. We queue |
2197 | 1985 magic events to run these hooks instead - kkm */ |
2198 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) | 1986 |
2199 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, | 1987 if (wParam==SIZE_MINIMIZED) |
2200 PM_REMOVE)) | |
2201 { | |
2202 int mods1 = mods; | |
2203 WPARAM ch = tranmsg.wParam; | |
2204 | |
2205 /* If a quit char with no modifiers other than control and | |
2206 shift, then mark it with a fake modifier, which is removed | |
2207 upon dequeueing the event */ | |
2208 /* #### This might also not withstand localization, if | |
2209 quit character is not a latin-1 symbol */ | |
2210 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) | |
2211 && quit_ch + 'a' - 1 == ch) | |
2212 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) | |
2213 && quit_ch == ch)) | |
2214 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) | |
2215 == 0)) | |
2216 { | |
2217 mods1 |= FAKE_MOD_QUIT; | |
2218 ++mswindows_quit_chars_count; | |
2219 } | |
2220 else if (potential_accelerator && !got_accelerator && | |
2221 mswindows_char_is_accelerator (frame, ch)) | |
2222 { | |
2223 got_accelerator = 1; | |
2224 break; | |
2225 } | |
2226 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1); | |
2227 } /* while */ | |
2228 | |
2229 /* This generates WM_SYSCHAR messages, which are interpreted | |
2230 by DefWindowProc as the menu selections. */ | |
2231 if (got_accelerator) | |
2232 { | |
2233 SetKeyboardState (keymap_sticky); | |
2234 TranslateMessage (&msg); | |
2235 SetKeyboardState (keymap_orig); | |
2236 goto defproc; | |
2237 } | |
2238 | |
2239 SetKeyboardState (keymap_orig); | |
2240 } /* else */ | |
2241 } | |
2242 | |
2243 if (key_needs_default_processing_p (wParam)) | |
2244 goto defproc; | |
2245 else | |
2246 break; | |
2247 | |
2248 case WM_MBUTTONDOWN: | |
2249 case WM_MBUTTONUP: | |
2250 /* Real middle mouse button has nothing to do with emulated one: | |
2251 if one wants to exercise fingers playing chords on the mouse, | |
2252 he is allowed to do that! */ | |
2253 mswindows_enqueue_mouse_button_event (hwnd, message_, | |
2254 MAKEPOINTS (lParam), GetMessageTime()); | |
2255 break; | |
2256 | |
2257 case WM_LBUTTONUP: | |
2258 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2259 msframe->last_click_time = GetMessageTime(); | |
2260 | |
2261 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2262 msframe->button2_need_lbutton = 0; | |
2263 if (msframe->ignore_next_lbutton_up) | |
2264 { | 1988 { |
2265 msframe->ignore_next_lbutton_up = 0; | 1989 /* Iconified */ |
2266 } | 1990 FRAME_VISIBLE_P (frame) = 0; |
2267 else if (msframe->button2_is_down) | 1991 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); |
2268 { | |
2269 msframe->button2_is_down = 0; | |
2270 msframe->ignore_next_rbutton_up = 1; | |
2271 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
2272 MAKEPOINTS (lParam), GetMessageTime()); | |
2273 } | 1992 } |
2274 else | 1993 else |
2275 { | 1994 { |
2276 if (msframe->button2_need_rbutton) | 1995 GetClientRect(hwnd, &rect); |
1996 FRAME_PIXWIDTH(frame) = rect.right; | |
1997 FRAME_PIXHEIGHT(frame) = rect.bottom; | |
1998 | |
1999 pixel_to_real_char_size (frame, rect.right, rect.bottom, | |
2000 &FRAME_MSWINDOWS_CHARWIDTH (frame), | |
2001 &FRAME_MSWINDOWS_CHARHEIGHT (frame)); | |
2002 | |
2003 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows); | |
2004 change_frame_size (frame, rows, columns, 1); | |
2005 | |
2006 /* If we are inside frame creation, we have to apply geometric | |
2007 properties now. */ | |
2008 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
2277 { | 2009 { |
2278 msframe->button2_need_rbutton = 0; | 2010 /* Yes, we have to size again */ |
2279 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | 2011 mswindows_size_frame_internal ( frame, |
2280 MAKEPOINTS (lParam), GetMessageTime()); | 2012 FRAME_MSWINDOWS_TARGET_RECT |
2281 } | 2013 (frame)); |
2282 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, | 2014 /* Reset so we do not get here again. The SetWindowPos call in |
2283 MAKEPOINTS (lParam), GetMessageTime()); | 2015 * mswindows_size_frame_internal can cause recursion here. */ |
2284 } | 2016 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) |
2285 break; | 2017 { |
2286 | 2018 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); |
2287 case WM_RBUTTONUP: | 2019 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; |
2288 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 2020 } |
2289 msframe->last_click_time = GetMessageTime(); | |
2290 | |
2291 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2292 msframe->button2_need_rbutton = 0; | |
2293 if (msframe->ignore_next_rbutton_up) | |
2294 { | |
2295 msframe->ignore_next_rbutton_up = 0; | |
2296 } | |
2297 else if (msframe->button2_is_down) | |
2298 { | |
2299 msframe->button2_is_down = 0; | |
2300 msframe->ignore_next_lbutton_up = 1; | |
2301 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
2302 MAKEPOINTS (lParam), GetMessageTime()); | |
2303 } | |
2304 else | |
2305 { | |
2306 if (msframe->button2_need_lbutton) | |
2307 { | |
2308 msframe->button2_need_lbutton = 0; | |
2309 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2310 MAKEPOINTS (lParam), GetMessageTime()); | |
2311 } | |
2312 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, | |
2313 MAKEPOINTS (lParam), GetMessageTime()); | |
2314 } | |
2315 break; | |
2316 | |
2317 case WM_LBUTTONDOWN: | |
2318 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2319 | |
2320 if (msframe->button2_need_lbutton) | |
2321 { | |
2322 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2323 msframe->button2_need_lbutton = 0; | |
2324 msframe->button2_need_rbutton = 0; | |
2325 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | |
2326 { | |
2327 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | |
2328 MAKEPOINTS (lParam), GetMessageTime()); | |
2329 msframe->button2_is_down = 1; | |
2330 } | 2021 } |
2331 else | 2022 else |
2332 { | 2023 { |
2333 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | 2024 if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) |
2334 msframe->last_click_point, msframe->last_click_time); | 2025 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); |
2335 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | 2026 FRAME_VISIBLE_P (frame) = 1; |
2336 MAKEPOINTS (lParam), GetMessageTime()); | 2027 |
2028 if (!msframe->sizing || mswindows_dynamic_frame_resize) | |
2029 redisplay (); | |
2337 } | 2030 } |
2338 } | 2031 } |
2339 else | 2032 } |
2033 break; | |
2034 | |
2035 /* Misc magic events which only require that the frame be identified */ | |
2036 case WM_SETFOCUS: | |
2037 case WM_KILLFOCUS: | |
2038 mswindows_enqueue_magic_event (hwnd, message); | |
2039 break; | |
2040 | |
2041 case WM_WINDOWPOSCHANGING: | |
2042 { | |
2043 WINDOWPOS *wp = (LPWINDOWPOS) lParam; | |
2044 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
2045 GetWindowPlacement(hwnd, &wpl); | |
2046 | |
2047 /* Only interested if size is changing and we're not being iconified */ | |
2048 if (wpl.showCmd != SW_SHOWMINIMIZED | |
2049 && wpl.showCmd != SW_SHOWMAXIMIZED | |
2050 && !(wp->flags & SWP_NOSIZE)) | |
2051 { | |
2052 RECT ncsize = { 0, 0, 0, 0 }; | |
2053 int pixwidth, pixheight; | |
2054 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE), | |
2055 GetMenu(hwnd) != NULL, | |
2056 GetWindowLong (hwnd, GWL_EXSTYLE)); | |
2057 | |
2058 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), | |
2059 wp->cx - (ncsize.right - ncsize.left), | |
2060 wp->cy - (ncsize.bottom - ncsize.top), | |
2061 &pixwidth, &pixheight); | |
2062 | |
2063 /* Convert client sizes to window sizes */ | |
2064 pixwidth += (ncsize.right - ncsize.left); | |
2065 pixheight += (ncsize.bottom - ncsize.top); | |
2066 | |
2067 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
2068 { | |
2069 /* Adjust so that the bottom or right doesn't move if it's | |
2070 * the top or left that's being changed */ | |
2071 RECT rect; | |
2072 GetWindowRect (hwnd, &rect); | |
2073 | |
2074 if (rect.left != wp->x) | |
2075 wp->x += wp->cx - pixwidth; | |
2076 if (rect.top != wp->y) | |
2077 wp->y += wp->cy - pixheight; | |
2078 } | |
2079 | |
2080 wp->cx = pixwidth; | |
2081 wp->cy = pixheight; | |
2082 } | |
2083 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts | |
2084 window position if the user tries to track window too small */ | |
2085 } | |
2086 goto defproc; | |
2087 | |
2088 case WM_ENTERSIZEMOVE: | |
2089 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2090 msframe->sizing = 1; | |
2091 return 0; | |
2092 | |
2093 case WM_EXITSIZEMOVE: | |
2094 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2095 msframe->sizing = 0; | |
2096 /* Queue noop event */ | |
2097 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
2098 return 0; | |
2099 | |
2100 #ifdef HAVE_SCROLLBARS | |
2101 case WM_VSCROLL: | |
2102 case WM_HSCROLL: | |
2103 { | |
2104 /* Direction of scroll is determined by scrollbar instance. */ | |
2105 int code = (int) LOWORD(wParam); | |
2106 int pos = (short int) HIWORD(wParam); | |
2107 HWND hwndScrollBar = (HWND) lParam; | |
2108 struct gcpro gcpro1, gcpro2; | |
2109 | |
2110 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
2111 GCPRO2 (emacs_event, fobj); | |
2112 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */ | |
2340 { | 2113 { |
2341 mswindows_set_chord_timer (hwnd); | 2114 /* Error during event pumping - cancel scroll */ |
2342 msframe->button2_need_rbutton = 1; | 2115 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); |
2343 msframe->last_click_point = MAKEPOINTS (lParam); | |
2344 } | 2116 } |
2345 msframe->last_click_time = GetMessageTime(); | 2117 UNGCPRO; |
2346 break; | 2118 break; |
2347 | 2119 } |
2348 case WM_RBUTTONDOWN: | 2120 #endif |
2349 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 2121 |
2350 | 2122 #ifdef HAVE_MENUBARS |
2351 if (msframe->button2_need_rbutton) | 2123 case WM_INITMENU: |
2124 if (UNBOUNDP (mswindows_handle_wm_initmenu ( | |
2125 (HMENU) wParam, | |
2126 XFRAME (mswindows_find_frame (hwnd))))) | |
2127 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2128 break; | |
2129 | |
2130 case WM_INITMENUPOPUP: | |
2131 if (!HIWORD(lParam)) | |
2132 { | |
2133 if (UNBOUNDP (mswindows_handle_wm_initmenupopup ( | |
2134 (HMENU) wParam, | |
2135 XFRAME (mswindows_find_frame (hwnd))))) | |
2136 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2137 } | |
2138 break; | |
2139 | |
2140 #endif /* HAVE_MENUBARS */ | |
2141 | |
2142 case WM_COMMAND: | |
2143 { | |
2144 WORD id = LOWORD (wParam); | |
2145 WORD nid = HIWORD (wParam); | |
2146 HWND cid = (HWND)lParam; | |
2147 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2148 | |
2149 #ifdef HAVE_TOOLBARS | |
2150 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) | |
2151 break; | |
2152 #endif | |
2153 /* widgets in a buffer only eval a callback for suitable events.*/ | |
2154 switch (nid) | |
2352 { | 2155 { |
2353 KillTimer (hwnd, BUTTON_2_TIMER_ID); | 2156 case BN_CLICKED: |
2354 msframe->button2_need_lbutton = 0; | 2157 case EN_CHANGE: |
2355 msframe->button2_need_rbutton = 0; | 2158 case CBN_EDITCHANGE: |
2356 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | 2159 case CBN_SELCHANGE: |
2160 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) | |
2161 return 0; | |
2162 } | |
2163 /* menubars always must come last since the hashtables do not | |
2164 always exist*/ | |
2165 #ifdef HAVE_MENUBARS | |
2166 if (!NILP (mswindows_handle_wm_command (frame, id))) | |
2167 break; | |
2168 #endif | |
2169 | |
2170 return DefWindowProc (hwnd, message, wParam, lParam); | |
2171 /* Bite me - a spurious command. This used to not be able to | |
2172 happen but with the introduction of widgets its now | |
2173 possible. */ | |
2174 } | |
2175 break; | |
2176 | |
2177 case WM_CTLCOLORBTN: | |
2178 case WM_CTLCOLORLISTBOX: | |
2179 case WM_CTLCOLOREDIT: | |
2180 case WM_CTLCOLORSTATIC: | |
2181 case WM_CTLCOLORSCROLLBAR: | |
2182 { | |
2183 /* if we get an opportunity to paint a widget then do so if | |
2184 there is an appropriate face */ | |
2185 HWND crtlwnd = (HWND)lParam; | |
2186 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA); | |
2187 if (ii) | |
2188 { | |
2189 Lisp_Object image_instance; | |
2190 VOID_TO_LISP (image_instance, ii); | |
2191 if (IMAGE_INSTANCEP (image_instance) | |
2192 && | |
2193 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET) | |
2194 && | |
2195 !NILP (XIMAGE_INSTANCE_WIDGET_FACE (image_instance))) | |
2357 { | 2196 { |
2358 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | 2197 /* set colors for the buttons */ |
2359 MAKEPOINTS (lParam), GetMessageTime()); | 2198 HDC hdc = (HDC)wParam; |
2360 msframe->button2_is_down = 1; | 2199 if (last_widget_brushed != ii) |
2361 } | 2200 { |
2362 else | 2201 if (widget_brush) |
2363 { | 2202 DeleteObject (widget_brush); |
2364 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | 2203 widget_brush = CreateSolidBrush |
2365 msframe->last_click_point, msframe->last_click_time); | 2204 (COLOR_INSTANCE_MSWINDOWS_COLOR |
2366 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | 2205 (XCOLOR_INSTANCE |
2367 MAKEPOINTS (lParam), GetMessageTime()); | 2206 (FACE_BACKGROUND |
2207 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2208 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); | |
2209 } | |
2210 last_widget_brushed = ii; | |
2211 SetTextColor | |
2212 (hdc, | |
2213 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2214 (XCOLOR_INSTANCE | |
2215 (FACE_FOREGROUND | |
2216 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2217 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); | |
2218 SetBkMode (hdc, OPAQUE); | |
2219 SetBkColor | |
2220 (hdc, | |
2221 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2222 (XCOLOR_INSTANCE | |
2223 (FACE_BACKGROUND | |
2224 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2225 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); | |
2226 return (LRESULT)widget_brush; | |
2368 } | 2227 } |
2369 } | 2228 } |
2370 else | 2229 } |
2230 goto defproc; | |
2231 | |
2232 #ifdef HAVE_DRAGNDROP | |
2233 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ | |
2234 { | |
2235 UINT filecount, i, len; | |
2236 POINT point; | |
2237 char* filename; | |
2238 #ifdef __CYGWIN32__ | |
2239 char* fname; | |
2240 #endif | |
2241 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
2242 struct gcpro gcpro1, gcpro2, gcpro3; | |
2243 | |
2244 emacs_event = Fmake_event (Qnil, Qnil); | |
2245 event = XEVENT(emacs_event); | |
2246 | |
2247 GCPRO3 (emacs_event, l_dndlist, l_item); | |
2248 | |
2249 if (!DragQueryPoint ((HANDLE) wParam, &point)) | |
2250 point.x = point.y = -1; /* outside client area */ | |
2251 | |
2252 event->event_type = misc_user_event; | |
2253 event->channel = mswindows_find_frame(hwnd); | |
2254 event->timestamp = GetMessageTime(); | |
2255 event->event.misc.button = 1; /* #### Should try harder */ | |
2256 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0); | |
2257 event->event.misc.x = point.x; | |
2258 event->event.misc.y = point.y; | |
2259 event->event.misc.function = Qdragdrop_drop_dispatch; | |
2260 | |
2261 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0); | |
2262 for (i=0; i<filecount; i++) | |
2371 { | 2263 { |
2372 mswindows_set_chord_timer (hwnd); | 2264 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0); |
2373 msframe->button2_need_lbutton = 1; | 2265 /* The URLs that we make here aren't correct according to section |
2374 msframe->last_click_point = MAKEPOINTS (lParam); | 2266 * 3.10 of rfc1738 because they're missing the //<host>/ part and |
2267 * because they may contain reserved characters. But that's OK. */ | |
2268 #ifdef __CYGWIN32__ | |
2269 fname = (char *)xmalloc (len+1); | |
2270 DragQueryFile ((HANDLE) wParam, i, fname, len+1); | |
2271 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); | |
2272 strcpy (filename, "file:"); | |
2273 cygwin32_win32_to_posix_path_list (fname, filename+5); | |
2274 xfree (fname); | |
2275 #else | |
2276 filename = (char *)xmalloc (len+6); | |
2277 strcpy (filename, "file:"); | |
2278 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1); | |
2279 dostounix_filename (filename+5); | |
2280 #endif | |
2281 l_item = make_string (filename, strlen (filename)); | |
2282 l_dndlist = Fcons (l_item, l_dndlist); | |
2283 xfree (filename); | |
2375 } | 2284 } |
2376 msframe->last_click_time = GetMessageTime(); | 2285 DragFinish ((HANDLE) wParam); |
2377 break; | 2286 |
2378 | 2287 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist); |
2379 case WM_TIMER: | 2288 mswindows_enqueue_dispatch_event (emacs_event); |
2380 if (wParam == BUTTON_2_TIMER_ID) | 2289 UNGCPRO; |
2381 { | 2290 } |
2382 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 2291 break; |
2383 KillTimer (hwnd, BUTTON_2_TIMER_ID); | 2292 #endif |
2384 | 2293 |
2385 if (msframe->button2_need_lbutton) | 2294 defproc: |
2386 { | 2295 default: |
2387 msframe->button2_need_lbutton = 0; | 2296 return DefWindowProc (hwnd, message, wParam, lParam); |
2388 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | 2297 } |
2389 msframe->last_click_point, msframe->last_click_time); | |
2390 } | |
2391 else if (msframe->button2_need_rbutton) | |
2392 { | |
2393 msframe->button2_need_rbutton = 0; | |
2394 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
2395 msframe->last_click_point, msframe->last_click_time); | |
2396 } | |
2397 } | |
2398 else | |
2399 assert ("Spurious timer fired" == 0); | |
2400 break; | |
2401 | |
2402 case WM_MOUSEMOVE: | |
2403 /* Optimization: don't report mouse movement while size is changing */ | |
2404 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2405 if (!msframe->sizing) | |
2406 { | |
2407 /* When waiting for the second mouse button to finish | |
2408 button2 emulation, and have moved too far, just pretend | |
2409 as if timer has expired. This improves drag-select feedback */ | |
2410 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) | |
2411 && !mswindows_button2_near_enough (msframe->last_click_point, | |
2412 MAKEPOINTS (lParam))) | |
2413 { | |
2414 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2415 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); | |
2416 } | |
2417 | |
2418 emacs_event = Fmake_event (Qnil, Qnil); | |
2419 event = XEVENT(emacs_event); | |
2420 | |
2421 event->channel = mswindows_find_frame(hwnd); | |
2422 event->timestamp = GetMessageTime(); | |
2423 event->event_type = pointer_motion_event; | |
2424 event->event.motion.x = MAKEPOINTS(lParam).x; | |
2425 event->event.motion.y = MAKEPOINTS(lParam).y; | |
2426 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); | |
2427 | |
2428 mswindows_enqueue_dispatch_event (emacs_event); | |
2429 } | |
2430 break; | |
2431 | |
2432 case WM_CANCELMODE: | |
2433 ReleaseCapture (); | |
2434 /* Queue a `cancel-mode-internal' misc user event, so mouse | |
2435 selection would be canceled if any */ | |
2436 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), | |
2437 Qcancel_mode_internal, Qnil); | |
2438 break; | |
2439 | |
2440 case WM_NOTIFY: | |
2441 { | |
2442 LPNMHDR nmhdr = (LPNMHDR)lParam; | |
2443 | |
2444 if (nmhdr->code == TTN_NEEDTEXT) | |
2445 { | |
2446 #ifdef HAVE_TOOLBARS | |
2447 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; | |
2448 Lisp_Object btext; | |
2449 | |
2450 /* find out which toolbar */ | |
2451 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2452 btext = mswindows_get_toolbar_button_text ( frame, | |
2453 nmhdr->idFrom ); | |
2454 | |
2455 tttext->lpszText = NULL; | |
2456 tttext->hinst = NULL; | |
2457 | |
2458 if (!NILP(btext)) | |
2459 { | |
2460 /* I think this is safe since the text will only go away | |
2461 when the toolbar does...*/ | |
2462 TO_EXTERNAL_FORMAT (LISP_STRING, btext, | |
2463 C_STRING_ALLOCA, tttext->lpszText, | |
2464 Qnative); | |
2465 } | |
2466 #endif | |
2467 } | |
2468 /* handle tree view callbacks */ | |
2469 else if (nmhdr->code == TVN_SELCHANGED) | |
2470 { | |
2471 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam; | |
2472 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2473 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); | |
2474 } | |
2475 /* handle tab control callbacks */ | |
2476 else if (nmhdr->code == TCN_SELCHANGE) | |
2477 { | |
2478 TC_ITEM item; | |
2479 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); | |
2480 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2481 | |
2482 item.mask = TCIF_PARAM; | |
2483 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx, | |
2484 (LPARAM)&item); | |
2485 | |
2486 mswindows_handle_gui_wm_command (frame, 0, item.lParam); | |
2487 } | |
2488 } | |
2489 break; | |
2490 | |
2491 case WM_PAINT: | |
2492 /* hdc will be NULL unless this is a subwindow - in which case we | |
2493 shouldn't have received a paint message for it here. */ | |
2494 assert (wParam == 0); | |
2495 | |
2496 /* Can't queue a magic event because windows goes modal and sends paint | |
2497 messages directly to the windows procedure when doing solid drags | |
2498 and the message queue doesn't get processed. */ | |
2499 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd))); | |
2500 break; | |
2501 | |
2502 case WM_SIZE: | |
2503 /* We only care about this message if our size has really changed */ | |
2504 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) | |
2505 { | |
2506 RECT rect; | |
2507 int columns, rows; | |
2508 | |
2509 fobj = mswindows_find_frame (hwnd); | |
2510 frame = XFRAME (fobj); | |
2511 msframe = FRAME_MSWINDOWS_DATA (frame); | |
2512 | |
2513 /* We cannot handle frame map and unmap hooks right in | |
2514 this routine, because these may throw. We queue | |
2515 magic events to run these hooks instead - kkm */ | |
2516 | |
2517 if (wParam==SIZE_MINIMIZED) | |
2518 { | |
2519 /* Iconified */ | |
2520 FRAME_VISIBLE_P (frame) = 0; | |
2521 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
2522 } | |
2523 else | |
2524 { | |
2525 GetClientRect(hwnd, &rect); | |
2526 FRAME_PIXWIDTH(frame) = rect.right; | |
2527 FRAME_PIXHEIGHT(frame) = rect.bottom; | |
2528 | |
2529 pixel_to_real_char_size (frame, rect.right, rect.bottom, | |
2530 &FRAME_MSWINDOWS_CHARWIDTH (frame), | |
2531 &FRAME_MSWINDOWS_CHARHEIGHT (frame)); | |
2532 | |
2533 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows); | |
2534 change_frame_size (frame, rows, columns, 1); | |
2535 | |
2536 /* If we are inside frame creation, we have to apply geometric | |
2537 properties now. */ | |
2538 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
2539 { | |
2540 /* Yes, we have to size again */ | |
2541 mswindows_size_frame_internal ( frame, | |
2542 FRAME_MSWINDOWS_TARGET_RECT | |
2543 (frame)); | |
2544 /* Reset so we do not get here again. The SetWindowPos call in | |
2545 * mswindows_size_frame_internal can cause recursion here. */ | |
2546 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
2547 { | |
2548 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); | |
2549 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; | |
2550 } | |
2551 } | |
2552 else | |
2553 { | |
2554 if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) | |
2555 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
2556 FRAME_VISIBLE_P (frame) = 1; | |
2557 | |
2558 if (!msframe->sizing || mswindows_dynamic_frame_resize) | |
2559 redisplay (); | |
2560 } | |
2561 } | |
2562 } | |
2563 break; | |
2564 | |
2565 case WM_DISPLAYCHANGE: | |
2566 { | |
2567 struct device *d; | |
2568 DWORD message_tick = GetMessageTime (); | |
2569 | |
2570 fobj = mswindows_find_frame (hwnd); | |
2571 frame = XFRAME (fobj); | |
2572 d = XDEVICE (FRAME_DEVICE (frame)); | |
2573 | |
2574 /* Do this only once per message. XEmacs can receive this message | |
2575 through as many frames as it currently has open. Message time | |
2576 will be the same for all these messages. Despite extreme | |
2577 efficiency, the code below has about one in 4 billion | |
2578 probability that the HDC is not recreated, provided that | |
2579 XEmacs is running sufficiently longer than 52 days. */ | |
2580 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick) | |
2581 { | |
2582 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick; | |
2583 DeleteDC (DEVICE_MSWINDOWS_HCDC(d)); | |
2584 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL); | |
2585 } | |
2586 } | |
2587 break; | |
2588 | |
2589 /* Misc magic events which only require that the frame be identified */ | |
2590 case WM_SETFOCUS: | |
2591 case WM_KILLFOCUS: | |
2592 mswindows_enqueue_magic_event (hwnd, message_); | |
2593 break; | |
2594 | |
2595 case WM_WINDOWPOSCHANGING: | |
2596 { | |
2597 WINDOWPOS *wp = (LPWINDOWPOS) lParam; | |
2598 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
2599 GetWindowPlacement(hwnd, &wpl); | |
2600 | |
2601 /* Only interested if size is changing and we're not being iconified */ | |
2602 if (wpl.showCmd != SW_SHOWMINIMIZED | |
2603 && wpl.showCmd != SW_SHOWMAXIMIZED | |
2604 && !(wp->flags & SWP_NOSIZE)) | |
2605 { | |
2606 RECT ncsize = { 0, 0, 0, 0 }; | |
2607 int pixwidth, pixheight; | |
2608 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE), | |
2609 GetMenu(hwnd) != NULL, | |
2610 GetWindowLong (hwnd, GWL_EXSTYLE)); | |
2611 | |
2612 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), | |
2613 wp->cx - (ncsize.right - ncsize.left), | |
2614 wp->cy - (ncsize.bottom - ncsize.top), | |
2615 &pixwidth, &pixheight); | |
2616 | |
2617 /* Convert client sizes to window sizes */ | |
2618 pixwidth += (ncsize.right - ncsize.left); | |
2619 pixheight += (ncsize.bottom - ncsize.top); | |
2620 | |
2621 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
2622 { | |
2623 /* Adjust so that the bottom or right doesn't move if it's | |
2624 * the top or left that's being changed */ | |
2625 RECT rect; | |
2626 GetWindowRect (hwnd, &rect); | |
2627 | |
2628 if (rect.left != wp->x) | |
2629 wp->x += wp->cx - pixwidth; | |
2630 if (rect.top != wp->y) | |
2631 wp->y += wp->cy - pixheight; | |
2632 } | |
2633 | |
2634 wp->cx = pixwidth; | |
2635 wp->cy = pixheight; | |
2636 } | |
2637 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts | |
2638 window position if the user tries to track window too small */ | |
2639 } | |
2640 goto defproc; | |
2641 | |
2642 case WM_ENTERSIZEMOVE: | |
2643 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2644 msframe->sizing = 1; | |
2645 return 0; | |
2646 | |
2647 case WM_EXITSIZEMOVE: | |
2648 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2649 msframe->sizing = 0; | |
2650 /* Queue noop event */ | |
2651 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
2652 return 0; | |
2653 | |
2654 #ifdef HAVE_SCROLLBARS | |
2655 case WM_VSCROLL: | |
2656 case WM_HSCROLL: | |
2657 { | |
2658 /* Direction of scroll is determined by scrollbar instance. */ | |
2659 int code = (int) LOWORD(wParam); | |
2660 int pos = (short int) HIWORD(wParam); | |
2661 HWND hwndScrollBar = (HWND) lParam; | |
2662 struct gcpro gcpro1, gcpro2; | |
2663 | |
2664 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
2665 GCPRO2 (emacs_event, fobj); | |
2666 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */ | |
2667 { | |
2668 /* Error during event pumping - cancel scroll */ | |
2669 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); | |
2670 } | |
2671 UNGCPRO; | |
2672 break; | |
2673 } | |
2674 | |
2675 case WM_MOUSEWHEEL: | |
2676 { | |
2677 int keys = LOWORD (wParam); /* Modifier key flags */ | |
2678 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ | |
2679 struct gcpro gcpro1, gcpro2; | |
2680 | |
2681 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta)) | |
2682 { | |
2683 GCPRO2 (emacs_event, fobj); | |
2684 mswindows_pump_outstanding_events (); /* Can GC */ | |
2685 UNGCPRO; | |
2686 } | |
2687 else | |
2688 goto defproc; | |
2689 break; | |
2690 } | |
2691 #endif | |
2692 | |
2693 #ifdef HAVE_MENUBARS | |
2694 case WM_INITMENU: | |
2695 if (UNBOUNDP (mswindows_handle_wm_initmenu ( | |
2696 (HMENU) wParam, | |
2697 XFRAME (mswindows_find_frame (hwnd))))) | |
2698 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2699 break; | |
2700 | |
2701 case WM_INITMENUPOPUP: | |
2702 if (!HIWORD(lParam)) | |
2703 { | |
2704 if (UNBOUNDP (mswindows_handle_wm_initmenupopup ( | |
2705 (HMENU) wParam, | |
2706 XFRAME (mswindows_find_frame (hwnd))))) | |
2707 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2708 } | |
2709 break; | |
2710 | |
2711 #endif /* HAVE_MENUBARS */ | |
2712 | |
2713 case WM_COMMAND: | |
2714 { | |
2715 WORD id = LOWORD (wParam); | |
2716 WORD nid = HIWORD (wParam); | |
2717 HWND cid = (HWND)lParam; | |
2718 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2719 | |
2720 #ifdef HAVE_TOOLBARS | |
2721 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) | |
2722 break; | |
2723 #endif | |
2724 /* widgets in a buffer only eval a callback for suitable events.*/ | |
2725 switch (nid) | |
2726 { | |
2727 case BN_CLICKED: | |
2728 case EN_CHANGE: | |
2729 case CBN_EDITCHANGE: | |
2730 case CBN_SELCHANGE: | |
2731 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) | |
2732 return 0; | |
2733 } | |
2734 /* menubars always must come last since the hashtables do not | |
2735 always exist*/ | |
2736 #ifdef HAVE_MENUBARS | |
2737 if (!NILP (mswindows_handle_wm_command (frame, id))) | |
2738 break; | |
2739 #endif | |
2740 | |
2741 return DefWindowProc (hwnd, message_, wParam, lParam); | |
2742 /* Bite me - a spurious command. This used to not be able to | |
2743 happen but with the introduction of widgets its now | |
2744 possible. */ | |
2745 } | |
2746 break; | |
2747 | |
2748 case WM_CTLCOLORBTN: | |
2749 case WM_CTLCOLORLISTBOX: | |
2750 case WM_CTLCOLOREDIT: | |
2751 case WM_CTLCOLORSTATIC: | |
2752 case WM_CTLCOLORSCROLLBAR: | |
2753 { | |
2754 /* if we get an opportunity to paint a widget then do so if | |
2755 there is an appropriate face */ | |
2756 HWND crtlwnd = (HWND)lParam; | |
2757 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA); | |
2758 if (ii) | |
2759 { | |
2760 Lisp_Object image_instance; | |
2761 VOID_TO_LISP (image_instance, ii); | |
2762 if (IMAGE_INSTANCEP (image_instance) | |
2763 && | |
2764 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) | |
2765 { | |
2766 /* set colors for the buttons */ | |
2767 HDC hdc = (HDC)wParam; | |
2768 if (last_widget_brushed != ii) | |
2769 { | |
2770 if (widget_brush) | |
2771 DeleteObject (widget_brush); | |
2772 widget_brush = CreateSolidBrush | |
2773 (COLOR_INSTANCE_MSWINDOWS_COLOR | |
2774 (XCOLOR_INSTANCE | |
2775 (FACE_BACKGROUND | |
2776 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2777 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
2778 } | |
2779 last_widget_brushed = ii; | |
2780 SetTextColor | |
2781 (hdc, | |
2782 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2783 (XCOLOR_INSTANCE | |
2784 (FACE_FOREGROUND | |
2785 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2786 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
2787 SetBkMode (hdc, OPAQUE); | |
2788 SetBkColor | |
2789 (hdc, | |
2790 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2791 (XCOLOR_INSTANCE | |
2792 (FACE_BACKGROUND | |
2793 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2794 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
2795 return (LRESULT)widget_brush; | |
2796 } | |
2797 } | |
2798 } | |
2799 goto defproc; | |
2800 | |
2801 #ifdef HAVE_DRAGNDROP | |
2802 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ | |
2803 { | |
2804 UINT filecount, i, len; | |
2805 POINT point; | |
2806 char* filename; | |
2807 char* fname; | |
2808 | |
2809 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
2810 struct gcpro gcpro1, gcpro2, gcpro3; | |
2811 | |
2812 emacs_event = Fmake_event (Qnil, Qnil); | |
2813 event = XEVENT(emacs_event); | |
2814 | |
2815 GCPRO3 (emacs_event, l_dndlist, l_item); | |
2816 | |
2817 if (!DragQueryPoint ((HDROP) wParam, &point)) | |
2818 point.x = point.y = -1; /* outside client area */ | |
2819 | |
2820 event->event_type = misc_user_event; | |
2821 event->channel = mswindows_find_frame(hwnd); | |
2822 event->timestamp = GetMessageTime(); | |
2823 event->event.misc.button = 1; /* #### Should try harder */ | |
2824 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0); | |
2825 event->event.misc.x = point.x; | |
2826 event->event.misc.y = point.y; | |
2827 event->event.misc.function = Qdragdrop_drop_dispatch; | |
2828 | |
2829 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0); | |
2830 for (i=0; i<filecount; i++) | |
2831 { | |
2832 len = DragQueryFile ((HDROP) wParam, i, NULL, 0); | |
2833 /* The URLs that we make here aren't correct according to section | |
2834 * 3.10 of rfc1738 because they're missing the //<host>/ part and | |
2835 * because they may contain reserved characters. But that's OK - | |
2836 * they just need to be good enough to keep dragdrop.el happy. */ | |
2837 fname = (char *)xmalloc (len+1); | |
2838 DragQueryFile ((HANDLE) wParam, i, fname, len+1); | |
2839 | |
2840 /* May be a shell link aka "shortcut" - replace fname if so */ | |
2841 #if !(defined(CYGWIN) || defined(MINGW)) | |
2842 /* cygwin doesn't define this COM stuff */ | |
2843 if (!stricmp (fname + strlen (fname) - 4, ".LNK")) | |
2844 { | |
2845 IShellLink* psl; | |
2846 | |
2847 if (CoCreateInstance (&CLSID_ShellLink, NULL, | |
2848 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK) | |
2849 { | |
2850 IPersistFile* ppf; | |
2851 | |
2852 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, | |
2853 &ppf) == S_OK) | |
2854 { | |
2855 WORD wsz[MAX_PATH]; | |
2856 WIN32_FIND_DATA wfd; | |
2857 LPSTR resolved = (char *) xmalloc (MAX_PATH+1); | |
2858 | |
2859 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH); | |
2860 | |
2861 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) && | |
2862 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH, | |
2863 &wfd, 0)==S_OK)) | |
2864 { | |
2865 xfree (fname); | |
2866 fname = resolved; | |
2867 len = strlen (fname); | |
2868 } | |
2869 | |
2870 ppf->lpVtbl->Release (ppf); | |
2871 } | |
2872 | |
2873 psl->lpVtbl->Release (psl); | |
2874 } | |
2875 } | |
2876 #endif | |
2877 | |
2878 #ifdef CYGWIN | |
2879 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); | |
2880 strcpy (filename, "file:"); | |
2881 cygwin32_win32_to_posix_path_list (fname, filename+5); | |
2882 #else | |
2883 filename = (char *)xmalloc (len+6); | |
2884 strcat (strcpy (filename, "file:"), fname); | |
2885 dostounix_filename (filename+5); | |
2886 #endif | |
2887 xfree (fname); | |
2888 l_item = make_string (filename, strlen (filename)); | |
2889 l_dndlist = Fcons (l_item, l_dndlist); | |
2890 xfree (filename); | |
2891 } | |
2892 DragFinish ((HDROP) wParam); | |
2893 | |
2894 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist); | |
2895 mswindows_enqueue_dispatch_event (emacs_event); | |
2896 UNGCPRO; | |
2897 } | |
2898 break; | |
2899 #endif | |
2900 | |
2901 defproc: | |
2902 default: | |
2903 return DefWindowProc (hwnd, message_, wParam, lParam); | |
2904 } | |
2905 return (0); | 2298 return (0); |
2906 } | 2299 } |
2907 | 2300 |
2908 | 2301 |
2909 /************************************************************************/ | 2302 /************************************************************************/ |
2965 } | 2358 } |
2966 | 2359 |
2967 | 2360 |
2968 /* Returns the state of the modifier keys in the format expected by the | 2361 /* Returns the state of the modifier keys in the format expected by the |
2969 * Lisp_Event key_data, button_data and motion_data modifiers member */ | 2362 * Lisp_Event key_data, button_data and motion_data modifiers member */ |
2970 static int | 2363 int mswindows_modifier_state (BYTE* keymap, int has_AltGr) |
2971 mswindows_modifier_state (BYTE* keymap, int has_AltGr) | |
2972 { | 2364 { |
2973 int mods = 0; | 2365 int mods = 0; |
2974 BYTE keymap2[256]; | |
2975 | 2366 |
2976 if (keymap == NULL) | 2367 if (keymap == NULL) |
2977 { | 2368 { |
2978 keymap = keymap2; | 2369 keymap = (BYTE*) alloca(256); |
2979 GetKeyboardState (keymap); | 2370 GetKeyboardState (keymap); |
2980 has_AltGr = mswindows_current_layout_has_AltGr (); | 2371 has_AltGr = mswindows_current_layout_has_AltGr (); |
2981 } | 2372 } |
2982 | 2373 |
2983 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) | 2374 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) |
2984 { | 2375 { |
2985 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0; | 2376 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0; |
2986 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | 2377 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0; |
2987 } | 2378 } |
2988 else | 2379 else |
2989 { | 2380 { |
2990 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0; | 2381 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0; |
2991 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | 2382 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0; |
2992 } | 2383 } |
2993 | 2384 |
2994 mods |= (keymap [VK_SHIFT] & 0x80) ? XEMACS_MOD_SHIFT : 0; | 2385 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0; |
2995 | 2386 |
2996 return mods; | 2387 return mods; |
2997 } | 2388 } |
2998 | 2389 |
2999 /* | 2390 /* |
3000 * Translate a mswindows virtual key to a keysym. | 2391 * Translate a mswindows virtual key to a keysym. |
3001 * Only returns non-Qnil for keys that don't generate WM_CHAR messages | 2392 * Only returns non-Qnil for keys that don't generate WM_CHAR messages |
3002 * or whose ASCII codes (like space) xemacs doesn't like. | 2393 * or whose ASCII codes (like space) xemacs doesn't like. |
3003 * Virtual key values are defined in winresrc.h | 2394 * Virtual key values are defined in winresrc.h |
2395 * XXX I'm not sure that KEYSYM("name") is the best thing to use here. | |
3004 */ | 2396 */ |
3005 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, | 2397 Lisp_Object mswindows_key_to_emacs_keysym(int mswindows_key, int mods) |
3006 int extendedp) | 2398 { |
3007 { | 2399 switch (mswindows_key) |
3008 if (extendedp) /* Keys not present on a 82 key keyboard */ | 2400 { |
3009 { | 2401 /* First the predefined ones */ |
3010 switch (mswindows_key) | 2402 case VK_BACK: return QKbackspace; |
3011 { | 2403 case VK_TAB: return QKtab; |
3012 case VK_RETURN: return KEYSYM ("kp-enter"); | 2404 case '\n': return QKlinefeed; /* No VK_LINEFEED in winresrc.h */ |
3013 case VK_PRIOR: return KEYSYM ("prior"); | 2405 case VK_RETURN: return QKreturn; |
3014 case VK_NEXT: return KEYSYM ("next"); | 2406 case VK_ESCAPE: return QKescape; |
3015 case VK_END: return KEYSYM ("end"); | 2407 case VK_SPACE: return QKspace; |
3016 case VK_HOME: return KEYSYM ("home"); | 2408 case VK_DELETE: return QKdelete; |
3017 case VK_LEFT: return KEYSYM ("left"); | 2409 |
3018 case VK_UP: return KEYSYM ("up"); | 2410 /* The rest */ |
3019 case VK_RIGHT: return KEYSYM ("right"); | 2411 case VK_CLEAR: return KEYSYM ("clear"); /* Should do ^L ? */ |
3020 case VK_DOWN: return KEYSYM ("down"); | 2412 case VK_PRIOR: return KEYSYM ("prior"); |
3021 case VK_INSERT: return KEYSYM ("insert"); | 2413 case VK_NEXT: return KEYSYM ("next"); |
3022 case VK_DELETE: return QKdelete; | 2414 case VK_END: return KEYSYM ("end"); |
3023 } | 2415 case VK_HOME: return KEYSYM ("home"); |
3024 } | 2416 case VK_LEFT: return KEYSYM ("left"); |
3025 else | 2417 case VK_UP: return KEYSYM ("up"); |
3026 { | 2418 case VK_RIGHT: return KEYSYM ("right"); |
3027 switch (mswindows_key) | 2419 case VK_DOWN: return KEYSYM ("down"); |
3028 { | 2420 case VK_SELECT: return KEYSYM ("select"); |
3029 case VK_BACK: return QKbackspace; | 2421 case VK_PRINT: return KEYSYM ("print"); |
3030 case VK_TAB: return QKtab; | 2422 case VK_EXECUTE: return KEYSYM ("execute"); |
3031 case '\n': return QKlinefeed; | 2423 case VK_SNAPSHOT: return KEYSYM ("print"); |
3032 case VK_CLEAR: return KEYSYM ("clear"); | 2424 case VK_INSERT: return KEYSYM ("insert"); |
3033 case VK_RETURN: return QKreturn; | 2425 case VK_HELP: return KEYSYM ("help"); |
3034 case VK_ESCAPE: return QKescape; | 2426 #if 0 /* XXX What are these supposed to do? */ |
3035 case VK_SPACE: return QKspace; | 2427 case VK_LWIN return KEYSYM (""); |
3036 case VK_PRIOR: return KEYSYM ("kp-prior"); | 2428 case VK_RWIN return KEYSYM (""); |
3037 case VK_NEXT: return KEYSYM ("kp-next"); | 2429 #endif |
3038 case VK_END: return KEYSYM ("kp-end"); | 2430 case VK_APPS: return KEYSYM ("menu"); |
3039 case VK_HOME: return KEYSYM ("kp-home"); | 2431 case VK_F1: return KEYSYM ("f1"); |
3040 case VK_LEFT: return KEYSYM ("kp-left"); | 2432 case VK_F2: return KEYSYM ("f2"); |
3041 case VK_UP: return KEYSYM ("kp-up"); | 2433 case VK_F3: return KEYSYM ("f3"); |
3042 case VK_RIGHT: return KEYSYM ("kp-right"); | 2434 case VK_F4: return KEYSYM ("f4"); |
3043 case VK_DOWN: return KEYSYM ("kp-down"); | 2435 case VK_F5: return KEYSYM ("f5"); |
3044 case VK_SELECT: return KEYSYM ("select"); | 2436 case VK_F6: return KEYSYM ("f6"); |
3045 case VK_PRINT: return KEYSYM ("print"); | 2437 case VK_F7: return KEYSYM ("f7"); |
3046 case VK_EXECUTE: return KEYSYM ("execute"); | 2438 case VK_F8: return KEYSYM ("f8"); |
3047 case VK_SNAPSHOT: return KEYSYM ("print"); | 2439 case VK_F9: return KEYSYM ("f9"); |
3048 case VK_INSERT: return KEYSYM ("kp-insert"); | 2440 case VK_F10: return KEYSYM ("f10"); |
3049 case VK_DELETE: return KEYSYM ("kp-delete"); | 2441 case VK_F11: return KEYSYM ("f11"); |
3050 case VK_HELP: return KEYSYM ("help"); | 2442 case VK_F12: return KEYSYM ("f12"); |
3051 #if 0 /* FSF Emacs allows these to return configurable syms/mods */ | 2443 case VK_F13: return KEYSYM ("f13"); |
3052 case VK_LWIN return KEYSYM (""); | 2444 case VK_F14: return KEYSYM ("f14"); |
3053 case VK_RWIN return KEYSYM (""); | 2445 case VK_F15: return KEYSYM ("f15"); |
3054 #endif | 2446 case VK_F16: return KEYSYM ("f16"); |
3055 case VK_APPS: return KEYSYM ("menu"); | 2447 case VK_F17: return KEYSYM ("f17"); |
3056 case VK_NUMPAD0: return KEYSYM ("kp-0"); | 2448 case VK_F18: return KEYSYM ("f18"); |
3057 case VK_NUMPAD1: return KEYSYM ("kp-1"); | 2449 case VK_F19: return KEYSYM ("f19"); |
3058 case VK_NUMPAD2: return KEYSYM ("kp-2"); | 2450 case VK_F20: return KEYSYM ("f20"); |
3059 case VK_NUMPAD3: return KEYSYM ("kp-3"); | 2451 case VK_F21: return KEYSYM ("f21"); |
3060 case VK_NUMPAD4: return KEYSYM ("kp-4"); | 2452 case VK_F22: return KEYSYM ("f22"); |
3061 case VK_NUMPAD5: return KEYSYM ("kp-5"); | 2453 case VK_F23: return KEYSYM ("f23"); |
3062 case VK_NUMPAD6: return KEYSYM ("kp-6"); | 2454 case VK_F24: return KEYSYM ("f24"); |
3063 case VK_NUMPAD7: return KEYSYM ("kp-7"); | 2455 } |
3064 case VK_NUMPAD8: return KEYSYM ("kp-8"); | |
3065 case VK_NUMPAD9: return KEYSYM ("kp-9"); | |
3066 case VK_MULTIPLY: return KEYSYM ("kp-multiply"); | |
3067 case VK_ADD: return KEYSYM ("kp-add"); | |
3068 case VK_SEPARATOR: return KEYSYM ("kp-separator"); | |
3069 case VK_SUBTRACT: return KEYSYM ("kp-subtract"); | |
3070 case VK_DECIMAL: return KEYSYM ("kp-decimal"); | |
3071 case VK_DIVIDE: return KEYSYM ("kp-divide"); | |
3072 case VK_F1: return KEYSYM ("f1"); | |
3073 case VK_F2: return KEYSYM ("f2"); | |
3074 case VK_F3: return KEYSYM ("f3"); | |
3075 case VK_F4: return KEYSYM ("f4"); | |
3076 case VK_F5: return KEYSYM ("f5"); | |
3077 case VK_F6: return KEYSYM ("f6"); | |
3078 case VK_F7: return KEYSYM ("f7"); | |
3079 case VK_F8: return KEYSYM ("f8"); | |
3080 case VK_F9: return KEYSYM ("f9"); | |
3081 case VK_F10: return KEYSYM ("f10"); | |
3082 case VK_F11: return KEYSYM ("f11"); | |
3083 case VK_F12: return KEYSYM ("f12"); | |
3084 case VK_F13: return KEYSYM ("f13"); | |
3085 case VK_F14: return KEYSYM ("f14"); | |
3086 case VK_F15: return KEYSYM ("f15"); | |
3087 case VK_F16: return KEYSYM ("f16"); | |
3088 case VK_F17: return KEYSYM ("f17"); | |
3089 case VK_F18: return KEYSYM ("f18"); | |
3090 case VK_F19: return KEYSYM ("f19"); | |
3091 case VK_F20: return KEYSYM ("f20"); | |
3092 case VK_F21: return KEYSYM ("f21"); | |
3093 case VK_F22: return KEYSYM ("f22"); | |
3094 case VK_F23: return KEYSYM ("f23"); | |
3095 case VK_F24: return KEYSYM ("f24"); | |
3096 } | |
3097 } | |
3098 return Qnil; | 2456 return Qnil; |
3099 } | 2457 } |
3100 | 2458 |
3101 /* | 2459 /* |
3102 * Find the console that matches the supplied mswindows window handle | 2460 * Find the console that matches the supplied mswindows window handle |
3150 } | 2508 } |
3151 | 2509 |
3152 static void | 2510 static void |
3153 emacs_mswindows_remove_timeout (int id) | 2511 emacs_mswindows_remove_timeout (int id) |
3154 { | 2512 { |
3155 Lisp_Event match_against; | 2513 struct Lisp_Event match_against; |
3156 Lisp_Object emacs_event; | 2514 Lisp_Object emacs_event; |
3157 | 2515 |
3158 if (KillTimer (NULL, id)) | 2516 if (KillTimer (NULL, id)) |
3159 --mswindows_pending_timers_count; | 2517 --mswindows_pending_timers_count; |
3160 | 2518 |
3186 | 2544 |
3187 /* | 2545 /* |
3188 * Return the next event | 2546 * Return the next event |
3189 */ | 2547 */ |
3190 static void | 2548 static void |
3191 emacs_mswindows_next_event (Lisp_Event *emacs_event) | 2549 emacs_mswindows_next_event (struct Lisp_Event *emacs_event) |
3192 { | 2550 { |
3193 Lisp_Object event, event2; | 2551 Lisp_Object event, event2; |
3194 | 2552 |
3195 mswindows_need_event (1); | 2553 mswindows_need_event (1); |
3196 | 2554 |
3197 event = mswindows_dequeue_dispatch_event (); | 2555 event = mswindows_dequeue_dispatch_event (!NILP(mswindows_u_dispatch_event_queue)); |
3198 XSETEVENT (event2, emacs_event); | 2556 XSETEVENT (event2, emacs_event); |
3199 Fcopy_event (event, event2); | 2557 Fcopy_event (event, event2); |
3200 Fdeallocate_event (event); | 2558 Fdeallocate_event (event); |
3201 } | 2559 } |
3202 | 2560 |
3203 /* | 2561 /* |
3204 * Handle a magic event off the dispatch queue. | 2562 * Handle a magic event off the dispatch queue. |
3205 */ | 2563 */ |
3206 static void | 2564 static void |
3207 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event) | 2565 emacs_mswindows_handle_magic_event (struct Lisp_Event *emacs_event) |
3208 { | 2566 { |
3209 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) | 2567 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) |
3210 { | 2568 { |
3211 case XM_BUMPQUEUE: | 2569 case XM_BUMPQUEUE: |
3212 break; | 2570 break; |
3213 | 2571 |
3214 case WM_PAINT: | |
3215 { | |
3216 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); | |
3217 mswindows_handle_paint (f); | |
3218 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0; | |
3219 } | |
3220 break; | |
3221 | |
3222 case WM_SETFOCUS: | 2572 case WM_SETFOCUS: |
3223 case WM_KILLFOCUS: | 2573 case WM_KILLFOCUS: |
3224 { | 2574 { |
3225 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | 2575 Lisp_Object frame = EVENT_CHANNEL (emacs_event); |
3226 struct frame *f = XFRAME (frame); | 2576 struct frame *f = XFRAME (frame); |
3227 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); | 2577 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); |
3228 Lisp_Object conser; | 2578 Lisp_Object conser; |
3229 struct gcpro gcpro1; | 2579 |
3230 | 2580 /* struct gcpro gcpro1; */ |
3231 /* On focus change, clear all memory of sticky modifiers | 2581 |
3232 to avoid non-intuitive behavior. */ | 2582 /* Clear sticky modifiers here (if we had any) */ |
3233 clear_sticky_modifiers (); | |
3234 | 2583 |
3235 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); | 2584 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); |
3236 GCPRO1 (conser); | 2585 /* GCPRO1 (conser); XXX Not necessary? */ |
3237 emacs_handle_focus_change_preliminary (conser); | 2586 emacs_handle_focus_change_preliminary (conser); |
3238 /* Under X the stuff up to here is done in the X event handler. | 2587 /* Under X the stuff up to here is done in the X event handler. |
3239 I Don't know why */ | 2588 I Don't know why */ |
3240 emacs_handle_focus_change_final (conser); | 2589 emacs_handle_focus_change_final (conser); |
3241 UNGCPRO; | 2590 /* UNGCPRO; */ |
3242 | 2591 |
3243 } | 2592 } |
3244 break; | 2593 break; |
3245 | 2594 |
3246 case XM_MAPFRAME: | 2595 case XM_MAPFRAME: |
3247 case XM_UNMAPFRAME: | 2596 case XM_UNMAPFRAME: |
3248 { | 2597 { |
3249 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | 2598 Lisp_Object frame = EVENT_CHANNEL (emacs_event); |
3250 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) | 2599 va_run_hook_with_args (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) |
3251 == XM_MAPFRAME ? | 2600 == XM_MAPFRAME ? |
3252 Qmap_frame_hook : Qunmap_frame_hook, | 2601 Qmap_frame_hook : Qunmap_frame_hook, |
3253 1, frame); | 2602 1, frame); |
3254 } | 2603 } |
3255 break; | 2604 break; |
3256 | 2605 |
3257 /* #### What about Enter & Leave */ | 2606 /* #### What about Enter & Leave */ |
3258 #if 0 | 2607 #if 0 |
3259 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : | 2608 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : |
3260 Qmouse_leave_frame_hook, 1, frame); | 2609 Qmouse_leave_frame_hook, 1, frame); |
3261 #endif | 2610 #endif |
3265 } | 2614 } |
3266 } | 2615 } |
3267 | 2616 |
3268 #ifndef HAVE_MSG_SELECT | 2617 #ifndef HAVE_MSG_SELECT |
3269 static HANDLE | 2618 static HANDLE |
3270 get_process_input_waitable (Lisp_Process *process) | 2619 get_process_input_waitable (struct Lisp_Process *process) |
3271 { | 2620 { |
3272 Lisp_Object instr, outstr, p; | 2621 Lisp_Object instr, outstr, p; |
3273 XSETPROCESS (p, process); | 2622 XSETPROCESS (p, process); |
3274 get_process_streams (process, &instr, &outstr); | 2623 get_process_streams (process, &instr, &outstr); |
3275 assert (!NILP (instr)); | 2624 assert (!NILP (instr)); |
3276 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT) | 2625 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT) |
3277 return (network_connection_p (p) | 2626 return (network_connection_p (p) |
3278 ? get_winsock_stream_waitable (XLSTREAM (instr)) | 2627 ? get_winsock_stream_waitable (XLSTREAM (instr)) |
3279 : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); | 2628 : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); |
3280 #else | 2629 #else |
3281 return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); | 2630 return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); |
3282 #endif | 2631 #endif |
3283 } | 2632 } |
3284 | 2633 |
3285 static void | 2634 static void |
3286 emacs_mswindows_select_process (Lisp_Process *process) | 2635 emacs_mswindows_select_process (struct Lisp_Process *process) |
3287 { | 2636 { |
3288 HANDLE hev = get_process_input_waitable (process); | 2637 HANDLE hev = get_process_input_waitable (process); |
3289 | 2638 |
3290 if (!add_waitable_handle (hev)) | 2639 if (!add_waitable_handle (hev)) |
3291 error ("Too many active processes"); | 2640 error ("Too many active processes"); |
3306 } | 2655 } |
3307 #endif | 2656 #endif |
3308 } | 2657 } |
3309 | 2658 |
3310 static void | 2659 static void |
3311 emacs_mswindows_unselect_process (Lisp_Process *process) | 2660 emacs_mswindows_unselect_process (struct Lisp_Process *process) |
3312 { | 2661 { |
3313 /* Process handle is removed in the event loop as soon | 2662 /* Process handle is removed in the event loop as soon |
3314 as it is signaled, so don't bother here about it */ | 2663 as it is signaled, so don't bother here about it */ |
3315 HANDLE hev = get_process_input_waitable (process); | 2664 HANDLE hev = get_process_input_waitable (process); |
3316 remove_waitable_handle (hev); | 2665 remove_waitable_handle (hev); |
3340 } | 2689 } |
3341 | 2690 |
3342 static void | 2691 static void |
3343 emacs_mswindows_quit_p (void) | 2692 emacs_mswindows_quit_p (void) |
3344 { | 2693 { |
2694 MSG msg; | |
2695 | |
3345 /* Quit cannot happen in modal loop: all program | 2696 /* Quit cannot happen in modal loop: all program |
3346 input is dedicated to Windows. */ | 2697 input is dedicated to Windows. */ |
3347 if (mswindows_in_modal_loop) | 2698 if (mswindows_in_modal_loop) |
3348 return; | 2699 return; |
3349 | 2700 |
3350 /* Drain windows queue. This sets up number of quit characters in | 2701 /* Drain windows queue. This sets up number of quit characters in the queue |
3351 the queue */ | 2702 * (and also processes wm focus change, move, resize, etc messages). |
3352 mswindows_drain_windows_queue (); | 2703 * We don't want to process WM_PAINT messages because this function can be |
2704 * called from almost anywhere and the windows' states may be changing. */ | |
2705 while (PeekMessage (&msg, NULL, 0, WM_PAINT-1, PM_REMOVE) || | |
2706 PeekMessage (&msg, NULL, WM_PAINT+1, WM_USER-1, PM_REMOVE)) | |
2707 DispatchMessage (&msg); | |
3353 | 2708 |
3354 if (mswindows_quit_chars_count > 0) | 2709 if (mswindows_quit_chars_count > 0) |
3355 { | 2710 { |
3356 /* Yes there's a hidden one... Throw it away */ | 2711 /* Yes there's a hidden one... Throw it away */ |
3357 Lisp_Event match_against; | 2712 struct Lisp_Event match_against; |
3358 Lisp_Object emacs_event; | 2713 Lisp_Object emacs_event; |
3359 int critical_p = 0; | |
3360 | 2714 |
3361 match_against.event_type = key_press_event; | 2715 match_against.event_type = key_press_event; |
3362 match_against.event.key.modifiers = FAKE_MOD_QUIT; | 2716 match_against.event.key.modifiers = FAKE_MOD_QUIT; |
3363 | 2717 |
3364 while (mswindows_quit_chars_count-- > 0) | 2718 emacs_event = mswindows_cancel_dispatch_event (&match_against); |
3365 { | 2719 assert (!NILP (emacs_event)); |
3366 emacs_event = mswindows_cancel_dispatch_event (&match_against); | 2720 |
3367 assert (!NILP (emacs_event)); | 2721 Vquit_flag = (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT |
3368 | 2722 ? Qcritical : Qt); |
3369 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT) | 2723 |
3370 critical_p = 1; | 2724 Fdeallocate_event(emacs_event); |
3371 | 2725 --mswindows_quit_chars_count; |
3372 Fdeallocate_event(emacs_event); | |
3373 } | |
3374 | |
3375 Vquit_flag = critical_p ? Qcritical : Qt; | |
3376 } | 2726 } |
3377 } | 2727 } |
3378 | 2728 |
3379 USID | 2729 USID |
3380 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle, | 2730 emacs_mswindows_create_stream_pair (void* inhandle, void* outhandle, |
3448 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream)))); | 2798 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream)))); |
3449 } | 2799 } |
3450 | 2800 |
3451 USID | 2801 USID |
3452 emacs_mswindows_delete_stream_pair (Lisp_Object instream, | 2802 emacs_mswindows_delete_stream_pair (Lisp_Object instream, |
3453 Lisp_Object outstream) | 2803 Lisp_Object outstream) |
3454 { | 2804 { |
3455 /* Oh nothing special here for Win32 at all */ | 2805 /* Oh nothing special here for Win32 at all */ |
3456 #if defined (HAVE_UNIX_PROCESSES) | 2806 #if defined (HAVE_UNIX_PROCESSES) |
3457 int in = (NILP(instream) | 2807 int in = (NILP(instream) |
3458 ? -1 | 2808 ? -1 |
3482 #ifndef HAVE_X_WINDOWS | 2832 #ifndef HAVE_X_WINDOWS |
3483 /* This is called from GC when a process object is about to be freed. | 2833 /* This is called from GC when a process object is about to be freed. |
3484 If we've still got pointers to it in this file, we're gonna lose hard. | 2834 If we've still got pointers to it in this file, we're gonna lose hard. |
3485 */ | 2835 */ |
3486 void | 2836 void |
3487 debug_process_finalization (Lisp_Process *p) | 2837 debug_process_finalization (struct Lisp_Process *p) |
3488 { | 2838 { |
3489 #if 0 /* #### */ | 2839 #if 0 /* #### */ |
3490 Lisp_Object instr, outstr; | 2840 Lisp_Object instr, outstr; |
3491 | 2841 |
3492 get_process_streams (p, &instr, &outstr); | 2842 get_process_streams (p, &instr, &outstr); |
3500 #endif | 2850 #endif |
3501 | 2851 |
3502 /************************************************************************/ | 2852 /************************************************************************/ |
3503 /* initialization */ | 2853 /* initialization */ |
3504 /************************************************************************/ | 2854 /************************************************************************/ |
3505 | 2855 |
3506 void | 2856 void |
3507 reinit_vars_of_event_mswindows (void) | 2857 vars_of_event_mswindows (void) |
3508 { | 2858 { |
2859 mswindows_u_dispatch_event_queue = Qnil; | |
2860 staticpro (&mswindows_u_dispatch_event_queue); | |
2861 mswindows_u_dispatch_event_queue_tail = Qnil; | |
2862 | |
2863 mswindows_s_dispatch_event_queue = Qnil; | |
2864 staticpro (&mswindows_s_dispatch_event_queue); | |
2865 mswindows_s_dispatch_event_queue_tail = Qnil; | |
2866 | |
2867 mswindows_error_caught_in_modal_loop = Qnil; | |
2868 staticpro (&mswindows_error_caught_in_modal_loop); | |
3509 mswindows_in_modal_loop = 0; | 2869 mswindows_in_modal_loop = 0; |
3510 mswindows_pending_timers_count = 0; | 2870 mswindows_pending_timers_count = 0; |
3511 | 2871 |
3512 mswindows_event_stream = xnew (struct event_stream); | 2872 mswindows_event_stream = xnew (struct event_stream); |
3513 | 2873 |
3514 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; | 2874 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; |
3515 mswindows_event_stream->force_event_pending = 0; | |
3516 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; | 2875 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; |
3517 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; | 2876 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; |
3518 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; | 2877 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; |
3519 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; | 2878 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; |
3520 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p; | 2879 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p; |
3521 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; | 2880 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; |
3522 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; | 2881 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; |
3523 #ifdef HAVE_MSG_SELECT | 2882 #ifdef HAVE_MSG_SELECT |
3524 mswindows_event_stream->select_process_cb = | 2883 mswindows_event_stream->select_process_cb = |
3525 (void (*)(Lisp_Process*))event_stream_unixoid_select_process; | 2884 (void (*)(struct Lisp_Process*))event_stream_unixoid_select_process; |
3526 mswindows_event_stream->unselect_process_cb = | 2885 mswindows_event_stream->unselect_process_cb = |
3527 (void (*)(Lisp_Process*))event_stream_unixoid_unselect_process; | 2886 (void (*)(struct Lisp_Process*))event_stream_unixoid_unselect_process; |
3528 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair; | 2887 mswindows_event_stream->create_stream_pair_cb = event_stream_unixoid_create_stream_pair; |
3529 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair; | 2888 mswindows_event_stream->delete_stream_pair_cb = event_stream_unixoid_delete_stream_pair; |
3530 #else | 2889 #else |
3531 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; | 2890 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; |
3532 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; | 2891 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; |
3533 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair; | 2892 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair; |
3534 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair; | 2893 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair; |
3535 #endif | 2894 #endif |
3536 } | 2895 |
3537 | 2896 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /* |
3538 void | |
3539 vars_of_event_mswindows (void) | |
3540 { | |
3541 reinit_vars_of_event_mswindows (); | |
3542 | |
3543 mswindows_u_dispatch_event_queue = Qnil; | |
3544 staticpro (&mswindows_u_dispatch_event_queue); | |
3545 mswindows_u_dispatch_event_queue_tail = Qnil; | |
3546 pdump_wire (&mswindows_u_dispatch_event_queue_tail); | |
3547 | |
3548 mswindows_s_dispatch_event_queue = Qnil; | |
3549 staticpro (&mswindows_s_dispatch_event_queue); | |
3550 mswindows_s_dispatch_event_queue_tail = Qnil; | |
3551 pdump_wire (&mswindows_s_dispatch_event_queue_tail); | |
3552 | |
3553 mswindows_error_caught_in_modal_loop = Qnil; | |
3554 staticpro (&mswindows_error_caught_in_modal_loop); | |
3555 | |
3556 | |
3557 #ifdef DEBUG_XEMACS | |
3558 DEFVAR_INT ("mswindows-debug-events", &mswindows_debug_events /* | |
3559 If non-zero, display debug information about Windows events that XEmacs sees. | |
3560 Information is displayed in a console window. Currently defined values are: | |
3561 | |
3562 1 == non-verbose output | |
3563 2 == verbose output | |
3564 | |
3565 #### Unfortunately, not yet implemented. | |
3566 */ ); | |
3567 mswindows_debug_events = 0; | |
3568 #endif | |
3569 | |
3570 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu", | |
3571 &mswindows_alt_by_itself_activates_menu /* | |
3572 *Controls whether pressing and releasing the Alt key activates the menubar. | |
3573 This applies only if no intervening key was pressed. See also | |
3574 `menu-accelerator-enabled', which is probably the behavior you actually want. | |
3575 Default is t. | |
3576 */ ); | |
3577 | |
3578 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", | |
3579 &mswindows_dynamic_frame_resize /* | |
3580 *Controls redrawing frame contents during mouse-drag or keyboard resize | 2897 *Controls redrawing frame contents during mouse-drag or keyboard resize |
3581 operation. When non-nil, the frame is redrawn while being resized. When | 2898 operation. When non-nil, the frame is redrawn while being resized. When |
3582 nil, frame is not redrawn, and exposed areas are filled with default | 2899 nil, frame is not redrawn, and exposed areas are filled with default |
3583 MDI application background color. Note that this option only has effect | 2900 MDI application background color. Note that this option only has effect |
3584 if "Show window contents while dragging" is on in system Display/Plus! | 2901 if "Show window contents while dragging" is on in system Display/Plus! |
3585 settings. | 2902 settings. |
3586 Default is t on fast machines, nil on slow. | 2903 Default is t on fast machines, nil on slow. |
3587 */ ); | 2904 */ ); |
3588 | 2905 |
3589 DEFVAR_INT ("mswindows-mouse-button-tolerance", | 2906 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */ |
3590 &mswindows_mouse_button_tolerance /* | 2907 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /* |
3591 *Analogue of double click interval for faking middle mouse events. | 2908 *Analogue of double click interval for faking middle mouse events. |
3592 The value is the minimum time in milliseconds that must elapse between | 2909 The value is the minimum time in milliseconds that must elapse between |
3593 left/right button down events before they are considered distinct events. | 2910 left/right button down events before they are considered distinct events. |
3594 If both mouse buttons are depressed within this interval, a middle mouse | 2911 If both mouse buttons are depressed within this interval, a middle mouse |
3595 button down event is generated instead. | 2912 button down event is generated instead. |
3596 If negative or zero, currently set system default is used instead. | 2913 If negative or zero, currently set system default is used instead. |
3597 */ ); | 2914 */ ); |
3598 | 2915 |
2916 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */ | |
3599 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /* | 2917 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /* |
3600 Number of physical mouse buttons. | 2918 Number of physical mouse buttons. |
3601 */ ); | 2919 */ ); |
3602 | 2920 |
3603 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", | 2921 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /* |
3604 &mswindows_mouse_button_max_skew_x /* | |
3605 *Maximum horizontal distance in pixels between points in which left and | 2922 *Maximum horizontal distance in pixels between points in which left and |
3606 right button clicks occurred for them to be translated into single | 2923 right button clicks occurred for them to be translated into single |
3607 middle button event. Clicks must occur in time not longer than defined | 2924 middle button event. Clicks must occur in time not longer than defined |
3608 by the variable `mswindows-mouse-button-tolerance'. | 2925 by the variable `mswindows-mouse-button-tolerance'. |
3609 If negative or zero, currently set system default is used instead. | 2926 If negative or zero, currently set system default is used instead. |
3610 */ ); | 2927 */ ); |
3611 | 2928 |
3612 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", | 2929 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /* |
3613 &mswindows_mouse_button_max_skew_y /* | |
3614 *Maximum vertical distance in pixels between points in which left and | 2930 *Maximum vertical distance in pixels between points in which left and |
3615 right button clicks occurred for them to be translated into single | 2931 right button clicks occurred for them to be translated into single |
3616 middle button event. Clicks must occur in time not longer than defined | 2932 middle button event. Clicks must occur in time not longer than defined |
3617 by the variable `mswindows-mouse-button-tolerance'. | 2933 by the variable `mswindows-mouse-button-tolerance'. |
3618 If negative or zero, currently set system default is used instead. | 2934 If negative or zero, currently set system default is used instead. |
3619 */ ); | 2935 */ ); |
3620 | 2936 |
3621 mswindows_mouse_button_max_skew_x = 0; | 2937 mswindows_mouse_button_max_skew_x = 0; |
3622 mswindows_mouse_button_max_skew_y = 0; | 2938 mswindows_mouse_button_max_skew_y = 0; |
3623 mswindows_mouse_button_tolerance = 0; | 2939 mswindows_mouse_button_tolerance = 0; |
3624 mswindows_alt_by_itself_activates_menu = 1; | |
3625 } | 2940 } |
3626 | 2941 |
3627 void | 2942 void |
3628 syms_of_event_mswindows (void) | 2943 syms_of_event_mswindows (void) |
3629 { | 2944 { |