Mercurial > hg > xemacs-beta
comparison src/event-msw.c @ 442:abe6d1db359e r21-2-36
Import from CVS: tag r21-2-36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:35:02 +0200 |
parents | 8de8e3f6228a |
children | 576fb035e263 |
comparison
equal
deleted
inserted
replaced
441:72a7cfa4a488 | 442:abe6d1db359e |
---|---|
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 Ben Wing. | 4 Copyright (C) 1996, 2000 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" | |
44 # include "menubar-msw.h" | 45 # include "menubar-msw.h" |
45 #endif | 46 #endif |
46 | 47 |
47 #ifdef HAVE_DRAGNDROP | 48 #ifdef HAVE_DRAGNDROP |
48 # include "dragdrop.h" | 49 # include "dragdrop.h" |
55 #include "faces.h" | 56 #include "faces.h" |
56 #include "lstream.h" | 57 #include "lstream.h" |
57 #include "process.h" | 58 #include "process.h" |
58 #include "redisplay.h" | 59 #include "redisplay.h" |
59 #include "select.h" | 60 #include "select.h" |
61 #include "window.h" | |
60 #include "sysproc.h" | 62 #include "sysproc.h" |
61 #include "syswait.h" | 63 #include "syswait.h" |
62 #include "systime.h" | 64 #include "systime.h" |
63 #include "sysdep.h" | 65 #include "sysdep.h" |
64 #include "objects-msw.h" | 66 #include "objects-msw.h" |
65 | 67 |
66 #include "events-mod.h" | 68 #include "events-mod.h" |
67 #ifdef HAVE_MSG_SELECT | 69 #ifdef HAVE_MSG_SELECT |
68 #include "sysfile.h" | 70 #include "sysfile.h" |
69 #include "console-tty.h" | 71 #include "console-tty.h" |
70 #elif defined(__CYGWIN32__) | 72 #elif defined(CYGWIN) |
71 typedef unsigned int SOCKET; | 73 typedef unsigned int SOCKET; |
72 #endif | 74 #endif |
73 #include <io.h> | 75 #include <io.h> |
74 #include <errno.h> | 76 #include <errno.h> |
75 | 77 |
76 #if defined (__CYGWIN32__) && (CYGWIN_VERSION_DLL_MAJOR < 20) | 78 #if !(defined(CYGWIN) || defined(MINGW)) |
77 typedef NMHDR *LPNMHDR; | 79 # include <shlobj.h> /* For IShellLink */ |
78 #endif | 80 #endif |
79 | 81 |
80 #ifdef HAVE_MENUBARS | 82 #ifdef HAVE_MENUBARS |
81 #define ADJR_MENUFLAG TRUE | 83 #define ADJR_MENUFLAG TRUE |
82 #else | 84 #else |
92 | 94 |
93 static Lisp_Object mswindows_find_frame (HWND hwnd); | 95 static Lisp_Object mswindows_find_frame (HWND hwnd); |
94 static Lisp_Object mswindows_find_console (HWND hwnd); | 96 static Lisp_Object mswindows_find_console (HWND hwnd); |
95 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, |
96 int extendedp); | 98 int extendedp); |
97 static int mswindows_modifier_state (BYTE* keymap, int has_AltGr); | 99 static int mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, |
100 int has_AltGr); | |
98 static void mswindows_set_chord_timer (HWND hwnd); | 101 static void mswindows_set_chord_timer (HWND hwnd); |
99 static int mswindows_button2_near_enough (POINTS p1, POINTS p2); | 102 static int mswindows_button2_near_enough (POINTS p1, POINTS p2); |
100 static int mswindows_current_layout_has_AltGr (void); | 103 static int mswindows_current_layout_has_AltGr (void); |
104 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, | |
105 int downp, int keyp); | |
101 | 106 |
102 static struct event_stream *mswindows_event_stream; | 107 static struct event_stream *mswindows_event_stream; |
103 | 108 |
104 #ifdef HAVE_MSG_SELECT | 109 #ifdef HAVE_MSG_SELECT |
105 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; | 110 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
126 static HANDLE mswindows_waitable_handles[MAX_WAITABLE]; | 131 static HANDLE mswindows_waitable_handles[MAX_WAITABLE]; |
127 | 132 |
128 /* Number of wait handles */ | 133 /* Number of wait handles */ |
129 static int mswindows_waitable_count=0; | 134 static int mswindows_waitable_count=0; |
130 #endif /* HAVE_MSG_SELECT */ | 135 #endif /* HAVE_MSG_SELECT */ |
136 | |
131 /* Brush for painting widgets */ | 137 /* Brush for painting widgets */ |
132 static HBRUSH widget_brush = 0; | 138 static HBRUSH widget_brush = 0; |
133 static LONG last_widget_brushed = 0; | 139 static LONG last_widget_brushed = 0; |
134 | 140 |
135 /* Count of quit chars currently in the queue */ | 141 /* Count of quit chars currently in the queue */ |
137 Decremented in mswindows_dequeue_dispatch_event() */ | 143 Decremented in mswindows_dequeue_dispatch_event() */ |
138 int mswindows_quit_chars_count = 0; | 144 int mswindows_quit_chars_count = 0; |
139 | 145 |
140 /* These are Lisp integers; see DEFVARS in this file for description. */ | 146 /* These are Lisp integers; see DEFVARS in this file for description. */ |
141 int mswindows_dynamic_frame_resize; | 147 int mswindows_dynamic_frame_resize; |
142 int mswindows_meta_activates_menu; | 148 int mswindows_alt_by_itself_activates_menu; |
143 int mswindows_num_mouse_buttons; | 149 int mswindows_num_mouse_buttons; |
144 int mswindows_mouse_button_max_skew_x; | 150 int mswindows_mouse_button_max_skew_x; |
145 int mswindows_mouse_button_max_skew_y; | 151 int mswindows_mouse_button_max_skew_y; |
146 int mswindows_mouse_button_tolerance; | 152 int mswindows_mouse_button_tolerance; |
147 | 153 |
154 #ifdef DEBUG_XEMACS | |
155 int debug_mswindows_events; | |
156 #endif | |
157 | |
148 /* This is the event signaled by the event pump. | 158 /* This is the event signaled by the event pump. |
149 See mswindows_pump_outstanding_events for comments */ | 159 See mswindows_pump_outstanding_events for comments */ |
150 static Lisp_Object mswindows_error_caught_in_modal_loop; | 160 static Lisp_Object mswindows_error_caught_in_modal_loop; |
151 static int mswindows_in_modal_loop; | 161 static int mswindows_in_modal_loop; |
152 | 162 |
153 /* Count of wound timers */ | 163 /* Count of wound timers */ |
154 static int mswindows_pending_timers_count; | 164 static int mswindows_pending_timers_count; |
165 | |
166 static DWORD mswindows_last_mouse_button_state; | |
155 | 167 |
156 /************************************************************************/ | 168 /************************************************************************/ |
157 /* Pipe instream - reads process output */ | 169 /* Pipe instream - reads process output */ |
158 /************************************************************************/ | 170 /************************************************************************/ |
159 | 171 |
176 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */ | 188 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */ |
177 | 189 |
178 struct ntpipe_slurp_stream_shared_data | 190 struct ntpipe_slurp_stream_shared_data |
179 { | 191 { |
180 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | 192 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ |
181 /* This is a manual-reset object. */ | 193 /* This is a manual-reset object. */ |
182 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ | 194 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ |
183 /* This is a manual-reset object. */ | 195 /* This is a manual-reset object. */ |
184 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ | 196 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ |
185 /* This is a manual-reset object. */ | 197 /* This is a manual-reset object. */ |
186 HANDLE hpipe; /* Pipe read end handle. */ | 198 HANDLE hpipe; /* Pipe read end handle. */ |
187 LONG die_p; /* Thread must exit ASAP if non-zero */ | 199 LONG die_p; /* Thread must exit ASAP if non-zero */ |
188 BOOL eof_p : 1; /* Set when thread saw EOF */ | 200 BOOL eof_p : 1; /* Set when thread saw EOF */ |
189 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | 201 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ |
190 BOOL inuse_p : 1; /* this structure is in use */ | 202 BOOL inuse_p : 1; /* this structure is in use */ |
219 s->inuse_p = 0; | 231 s->inuse_p = 0; |
220 } | 232 } |
221 } | 233 } |
222 | 234 |
223 static struct ntpipe_slurp_stream_shared_data* | 235 static struct ntpipe_slurp_stream_shared_data* |
224 slurper_allocate_shared_data() | 236 slurper_allocate_shared_data (void) |
225 { | 237 { |
226 int i=0; | 238 int i=0; |
227 for (i=0; i<MAX_SLURP_STREAMS; i++) | 239 for (i=0; i<MAX_SLURP_STREAMS; i++) |
228 { | 240 { |
229 if (!shared_data_block[i].inuse_p) | 241 if (!shared_data_block[i].inuse_p) |
460 /************************************************************************/ | 472 /************************************************************************/ |
461 | 473 |
462 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ | 474 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ |
463 LSTREAM_TYPE_DATA (stream, ntpipe_shove) | 475 LSTREAM_TYPE_DATA (stream, ntpipe_shove) |
464 | 476 |
465 #define MAX_SHOVE_BUFFER_SIZE 128 | 477 #define MAX_SHOVE_BUFFER_SIZE 512 |
466 | 478 |
467 struct ntpipe_shove_stream | 479 struct ntpipe_shove_stream |
468 { | 480 { |
469 LPARAM user_data; /* Any user data stored in the stream object */ | 481 LPARAM user_data; /* Any user data stored in the stream object */ |
470 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | 482 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ |
471 /* This is an auto-reset object. */ | 483 /* This is an auto-reset object. */ |
472 HANDLE hpipe; /* Pipe write end handle. */ | 484 HANDLE hpipe; /* Pipe write end handle. */ |
473 HANDLE hthread; /* Reader thread handle. */ | 485 HANDLE hthread; /* Reader thread handle. */ |
474 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ | 486 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ |
475 DWORD size; /* Number of bytes to write */ | 487 DWORD size; /* Number of bytes to write */ |
476 LONG die_p; /* Thread must exit ASAP if non-zero */ | 488 LONG die_p; /* Thread must exit ASAP if non-zero */ |
494 | 506 |
495 /* Block on event and wait for a job */ | 507 /* Block on event and wait for a job */ |
496 InterlockedIncrement (&s->idle_p); | 508 InterlockedIncrement (&s->idle_p); |
497 WaitForSingleObject (s->hev_thread, INFINITE); | 509 WaitForSingleObject (s->hev_thread, INFINITE); |
498 | 510 |
499 if (s->die_p) | 511 /* Write passed buffer if any */ |
500 break; | 512 if (s->size > 0) |
501 | 513 { |
502 /* Write passed buffer */ | 514 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) |
503 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) | 515 || bytes_written != s->size) |
504 || bytes_written != s->size) | 516 { |
505 { | 517 s->error_p = TRUE; |
506 s->error_p = TRUE; | 518 InterlockedIncrement (&s->die_p); |
507 InterlockedIncrement (&s->die_p); | 519 } |
520 /* Set size to zero so we won't write it again if the closer sets | |
521 die_p and kicks us */ | |
522 s->size = 0; | |
508 } | 523 } |
509 | 524 |
510 if (s->die_p) | 525 if (s->die_p) |
511 break; | 526 break; |
512 } | 527 } |
535 { | 550 { |
536 Lstream_delete (lstr); | 551 Lstream_delete (lstr); |
537 return Qnil; | 552 return Qnil; |
538 } | 553 } |
539 | 554 |
555 /* Set the priority of the thread higher so we don't end up waiting | |
556 on it to send things. */ | |
557 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST)) | |
558 { | |
559 CloseHandle (s->hthread); | |
560 Lstream_delete (lstr); | |
561 return Qnil; | |
562 } | |
563 | |
540 /* hev_thread is an auto-reset event, initially nonsignaled */ | 564 /* hev_thread is an auto-reset event, initially nonsignaled */ |
541 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL); | 565 s->hev_thread = CreateEvent (NULL, FALSE, FALSE, NULL); |
542 | 566 |
543 /* Now let it go */ | 567 /* Now let it go */ |
544 ResumeThread (s->hthread); | 568 ResumeThread (s->hthread); |
575 s->size = size; | 599 s->size = size; |
576 | 600 |
577 /* Start output */ | 601 /* Start output */ |
578 InterlockedDecrement (&s->idle_p); | 602 InterlockedDecrement (&s->idle_p); |
579 SetEvent (s->hev_thread); | 603 SetEvent (s->hev_thread); |
604 /* Give it a chance to run -- this dramatically improves performance | |
605 of things like crypt. */ | |
606 if (xSwitchToThread) /* not in Win9x or NT 3.51 */ | |
607 (void) xSwitchToThread (); | |
580 return size; | 608 return size; |
581 } | 609 } |
582 | 610 |
583 static int | 611 static int |
584 ntpipe_shove_was_blocked_p (Lstream *stream) | 612 ntpipe_shove_was_blocked_p (Lstream *stream) |
593 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); | 621 struct ntpipe_shove_stream* s = NTPIPE_SHOVE_STREAM_DATA(stream); |
594 | 622 |
595 /* Force thread stop */ | 623 /* Force thread stop */ |
596 InterlockedIncrement (&s->die_p); | 624 InterlockedIncrement (&s->die_p); |
597 | 625 |
626 /* Thread will end upon unblocking. If it's already unblocked this will | |
627 do nothing, but the thread won't look at die_p until it's written any | |
628 pending output. */ | |
629 SetEvent (s->hev_thread); | |
630 | |
631 /* Wait while thread terminates */ | |
632 WaitForSingleObject (s->hthread, INFINITE); | |
633 | |
598 /* Close pipe handle, possibly breaking it */ | 634 /* Close pipe handle, possibly breaking it */ |
599 CloseHandle (s->hpipe); | 635 CloseHandle (s->hpipe); |
600 | 636 |
601 /* Thread will end upon unblocking */ | 637 /* Close the thread handle */ |
602 SetEvent (s->hev_thread); | |
603 | |
604 /* Wait while thread terminates */ | |
605 WaitForSingleObject (s->hthread, INFINITE); | |
606 CloseHandle (s->hthread); | 638 CloseHandle (s->hthread); |
607 | 639 |
608 /* Destroy the event */ | 640 /* Destroy the event */ |
609 CloseHandle (s->hev_thread); | 641 CloseHandle (s->hev_thread); |
610 | 642 |
630 { | 662 { |
631 LPARAM user_data; /* Any user data stored in the stream object */ | 663 LPARAM user_data; /* Any user data stored in the stream object */ |
632 SOCKET s; /* Socket handle (which is a Win32 handle) */ | 664 SOCKET s; /* Socket handle (which is a Win32 handle) */ |
633 OVERLAPPED ov; /* Overlapped I/O structure */ | 665 OVERLAPPED ov; /* Overlapped I/O structure */ |
634 void* buffer; /* Buffer. Allocated for input stream only */ | 666 void* buffer; /* Buffer. Allocated for input stream only */ |
635 unsigned int bufsize; /* Number of bytes last read */ | 667 unsigned long bufsize; /* Number of bytes last read */ |
636 unsigned int bufpos; /* Position in buffer for next fetch */ | 668 unsigned long bufpos; /* Position in buffer for next fetch */ |
637 unsigned int error_p :1; /* I/O Error seen */ | 669 unsigned int error_p :1; /* I/O Error seen */ |
638 unsigned int eof_p :1; /* EOF Error seen */ | 670 unsigned int eof_p :1; /* EOF Error seen */ |
639 unsigned int pending_p :1; /* There is a pending I/O operation */ | 671 unsigned int pending_p :1; /* There is a pending I/O operation */ |
640 unsigned int blocking_p :1; /* Last write attempt would block */ | 672 unsigned int blocking_p :1; /* Last write attempt would block */ |
641 }; | 673 }; |
710 | 742 |
711 return size; | 743 return size; |
712 } | 744 } |
713 | 745 |
714 static ssize_t | 746 static ssize_t |
715 winsock_writer (Lstream *stream, CONST unsigned char *data, size_t size) | 747 winsock_writer (Lstream *stream, const unsigned char *data, size_t size) |
716 { | 748 { |
717 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | 749 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); |
718 | 750 |
719 if (str->pending_p) | 751 if (str->pending_p) |
720 { | 752 { |
783 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | 815 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); |
784 return str->blocking_p; | 816 return str->blocking_p; |
785 } | 817 } |
786 | 818 |
787 static Lisp_Object | 819 static Lisp_Object |
788 make_winsock_stream_1 (SOCKET s, LPARAM param, CONST char *mode) | 820 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode) |
789 { | 821 { |
790 Lisp_Object obj; | 822 Lisp_Object obj; |
791 Lstream *lstr = Lstream_new (lstream_winsock, mode); | 823 Lstream *lstr = Lstream_new (lstream_winsock, mode); |
792 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | 824 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); |
793 | 825 |
862 } | 894 } |
863 | 895 |
864 /* | 896 /* |
865 * Add an emacs event to the proper dispatch queue | 897 * Add an emacs event to the proper dispatch queue |
866 */ | 898 */ |
867 static void | 899 void |
868 mswindows_enqueue_dispatch_event (Lisp_Object event) | 900 mswindows_enqueue_dispatch_event (Lisp_Object event) |
869 { | 901 { |
870 int user_p = mswindows_user_event_p (XEVENT(event)); | 902 int user_p = mswindows_user_event_p (XEVENT(event)); |
871 enqueue_event (event, | 903 enqueue_event (event, |
872 user_p ? &mswindows_u_dispatch_event_queue : | 904 user_p ? &mswindows_u_dispatch_event_queue : |
873 &mswindows_s_dispatch_event_queue, | 905 &mswindows_s_dispatch_event_queue, |
874 user_p ? &mswindows_u_dispatch_event_queue_tail : | 906 user_p ? &mswindows_u_dispatch_event_queue_tail : |
875 &mswindows_s_dispatch_event_queue_tail); | 907 &mswindows_s_dispatch_event_queue_tail); |
876 | 908 |
877 /* Avoid blocking on WaitMessage */ | 909 /* Avoid blocking on WaitMessage */ |
878 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); | 910 PostMessage (NULL, XM_BUMPQUEUE, 0, 0); |
879 } | 911 } |
880 | 912 |
928 | 960 |
929 mswindows_enqueue_dispatch_event (emacs_event); | 961 mswindows_enqueue_dispatch_event (emacs_event); |
930 } | 962 } |
931 | 963 |
932 static void | 964 static void |
933 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, DWORD when) | 965 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, |
934 { | 966 int mods, DWORD when) |
967 { | |
968 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || | |
969 msg == WM_RBUTTONDOWN); | |
935 | 970 |
936 /* We always use last message time, because mouse button | 971 /* We always use last message time, because mouse button |
937 events may get delayed, and XEmacs double click | 972 events may get delayed, and XEmacs double click |
938 recognition will fail */ | 973 recognition will fail */ |
939 | 974 |
940 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 975 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
941 Lisp_Event* event = XEVENT(emacs_event); | 976 Lisp_Event* event = XEVENT (emacs_event); |
942 | 977 |
943 event->channel = mswindows_find_frame(hwnd); | 978 mswindows_handle_sticky_modifiers (0, 0, downp, 0); |
979 event->channel = mswindows_find_frame (hwnd); | |
944 event->timestamp = when; | 980 event->timestamp = when; |
945 event->event.button.button = | 981 event->event.button.button = |
946 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 : | 982 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 : |
947 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2); | 983 ((msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : 2); |
948 event->event.button.x = where.x; | 984 event->event.button.x = where.x; |
949 event->event.button.y = where.y; | 985 event->event.button.y = where.y; |
950 event->event.button.modifiers = mswindows_modifier_state (NULL, 0); | 986 event->event.button.modifiers = mswindows_modifier_state (NULL, mods, 0); |
951 | 987 |
952 if (msg==WM_LBUTTONDOWN || msg==WM_MBUTTONDOWN || | 988 if (downp) |
953 msg==WM_RBUTTONDOWN) | |
954 { | 989 { |
955 event->event_type = button_press_event; | 990 event->event_type = button_press_event; |
956 SetCapture (hwnd); | 991 SetCapture (hwnd); |
957 /* we need this to make sure the main window regains the focus | 992 /* we need this to make sure the main window regains the focus |
958 from control subwindows */ | 993 from control subwindows */ |
988 /* | 1023 /* |
989 * Remove and return the first emacs event on the dispatch queue. | 1024 * Remove and return the first emacs event on the dispatch queue. |
990 * Give a preference to user events over non-user ones. | 1025 * Give a preference to user events over non-user ones. |
991 */ | 1026 */ |
992 static Lisp_Object | 1027 static Lisp_Object |
993 mswindows_dequeue_dispatch_event () | 1028 mswindows_dequeue_dispatch_event (void) |
994 { | 1029 { |
995 Lisp_Object event; | 1030 Lisp_Object event; |
996 Lisp_Event* sevt; | 1031 Lisp_Event* sevt; |
997 | 1032 |
998 assert (!NILP(mswindows_u_dispatch_event_queue) || | 1033 assert (!NILP(mswindows_u_dispatch_event_queue) || |
999 !NILP(mswindows_s_dispatch_event_queue)); | 1034 !NILP(mswindows_s_dispatch_event_queue)); |
1000 | 1035 |
1001 event = dequeue_event ( | 1036 event = dequeue_event ( |
1002 NILP(mswindows_u_dispatch_event_queue) ? | 1037 NILP(mswindows_u_dispatch_event_queue) ? |
1003 &mswindows_s_dispatch_event_queue : | 1038 &mswindows_s_dispatch_event_queue : |
1004 &mswindows_u_dispatch_event_queue, | 1039 &mswindows_u_dispatch_event_queue, |
1005 NILP(mswindows_u_dispatch_event_queue) ? | 1040 NILP(mswindows_u_dispatch_event_queue) ? |
1006 &mswindows_s_dispatch_event_queue_tail : | 1041 &mswindows_s_dispatch_event_queue_tail : |
1007 &mswindows_u_dispatch_event_queue_tail); | 1042 &mswindows_u_dispatch_event_queue_tail); |
1008 | 1043 |
1009 sevt = XEVENT(event); | 1044 sevt = XEVENT(event); |
1010 if (sevt->event_type == key_press_event | 1045 if (sevt->event_type == key_press_event |
1031 { | 1066 { |
1032 Lisp_Object event; | 1067 Lisp_Object event; |
1033 Lisp_Object previous_event = Qnil; | 1068 Lisp_Object previous_event = Qnil; |
1034 int user_p = mswindows_user_event_p (match); | 1069 int user_p = mswindows_user_event_p (match); |
1035 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : | 1070 Lisp_Object* head = user_p ? &mswindows_u_dispatch_event_queue : |
1036 &mswindows_s_dispatch_event_queue; | 1071 &mswindows_s_dispatch_event_queue; |
1037 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : | 1072 Lisp_Object* tail = user_p ? &mswindows_u_dispatch_event_queue_tail : |
1038 &mswindows_s_dispatch_event_queue_tail; | 1073 &mswindows_s_dispatch_event_queue_tail; |
1039 | 1074 |
1040 assert (match->event_type == timeout_event | 1075 assert (match->event_type == timeout_event |
1041 || match->event_type == key_press_event); | 1076 || match->event_type == key_press_event); |
1042 | 1077 |
1043 EVENT_CHAIN_LOOP (event, *head) | 1078 EVENT_CHAIN_LOOP (event, *head) |
1218 Lisp_Object result = Qt; | 1253 Lisp_Object result = Qt; |
1219 struct gcpro gcpro1; | 1254 struct gcpro gcpro1; |
1220 GCPRO1 (result); | 1255 GCPRO1 (result); |
1221 | 1256 |
1222 if (NILP(mswindows_error_caught_in_modal_loop)) | 1257 if (NILP(mswindows_error_caught_in_modal_loop)) |
1223 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); | 1258 result = mswindows_protect_modal_loop (mswindows_unsafe_pump_events, Qnil); |
1224 UNGCPRO; | 1259 UNGCPRO; |
1225 return result; | 1260 return result; |
1226 } | 1261 } |
1227 | 1262 |
1228 /* | 1263 /* |
1229 * KEYBOARD_ONLY_P is set to non-zero when we are called from | 1264 * KEYBOARD_ONLY_P is set to non-zero when we are called from |
1230 * QUITP, and are interesting in keyboard messages only. | 1265 * QUITP, and are interesting in keyboard messages only. |
1231 */ | 1266 */ |
1232 static void | 1267 static void |
1233 mswindows_drain_windows_queue (int keyboard_only_till_quit_char_p) | 1268 mswindows_drain_windows_queue (void) |
1234 { | 1269 { |
1235 MSG msg; | 1270 MSG msg; |
1236 | 1271 |
1237 /* Minimize the hassle of misordered events by not fetching | 1272 /* should call mswindows_need_event_in_modal_loop() if in modal loop */ |
1238 past quit char if called from QUITP; */ | 1273 assert (!mswindows_in_modal_loop); |
1239 while (!(keyboard_only_till_quit_char_p && | 1274 |
1240 mswindows_quit_chars_count > 0) && | 1275 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) |
1241 PeekMessage (&msg, NULL, | |
1242 keyboard_only_till_quit_char_p ? WM_KEYFIRST : 0, | |
1243 keyboard_only_till_quit_char_p ? WM_KEYLAST : 0, | |
1244 PM_REMOVE)) | |
1245 { | 1276 { |
1246 /* We have to translate messages that are not sent to the main | 1277 char class_name_buf [sizeof (XEMACS_CLASS) + 2] = ""; |
1247 window. This is so that key presses work ok in things like | 1278 |
1248 edit fields. However, we *musn't* translate message for the | 1279 if (mswindows_is_dialog_msg (&msg)) |
1249 main window as this is handled in the wnd proc. */ | 1280 { |
1250 if (GetWindowLong (msg.hwnd, GWL_STYLE) & WS_CHILD) | 1281 mswindows_unmodalize_signal_maybe (); |
1251 { | 1282 continue; |
1283 } | |
1284 | |
1285 /* We have to translate messages that are not sent to an XEmacs | |
1286 frame. This is so that key presses work ok in things like | |
1287 edit fields. However, we *musn't* translate message for XEmacs | |
1288 frames as this is handled in the wnd proc. | |
1289 We also have to avoid generating paint magic events for windows | |
1290 that aren't XEmacs frames */ | |
1291 /* GetClassName will truncate a longer class name. By adding one | |
1292 extra character, we are forcing textual comparison to fail | |
1293 if the name is longer than XEMACS_CLASS */ | |
1294 | |
1295 GetClassName (msg.hwnd, class_name_buf, sizeof (class_name_buf) - 1); | |
1296 if (stricmp (class_name_buf, XEMACS_CLASS) != 0) | |
1297 { | |
1298 /* Not an XEmacs frame */ | |
1252 TranslateMessage (&msg); | 1299 TranslateMessage (&msg); |
1300 } | |
1301 else if (msg.message == WM_PAINT) | |
1302 { | |
1303 struct mswindows_frame* msframe; | |
1304 | |
1305 /* hdc will be NULL unless this is a subwindow - in which case we | |
1306 shouldn't have received a paint message for it here. */ | |
1307 assert (msg.wParam == 0); | |
1308 | |
1309 /* Queue a magic event for handling when safe */ | |
1310 msframe = | |
1311 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd))); | |
1312 if (!msframe->paint_pending) | |
1313 { | |
1314 msframe->paint_pending = 1; | |
1315 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT); | |
1316 } | |
1317 /* Don't dispatch. WM_PAINT is always the last message in the | |
1318 queue so it's OK to just return. */ | |
1319 return; | |
1253 } | 1320 } |
1254 DispatchMessage (&msg); | 1321 DispatchMessage (&msg); |
1255 mswindows_unmodalize_signal_maybe (); | 1322 mswindows_unmodalize_signal_maybe (); |
1256 } | 1323 } |
1257 } | 1324 } |
1312 { | 1379 { |
1313 mswindows_need_event_in_modal_loop (badly_p); | 1380 mswindows_need_event_in_modal_loop (badly_p); |
1314 return; | 1381 return; |
1315 } | 1382 } |
1316 | 1383 |
1317 #if 0 | |
1318 /* Have to drain Windows message queue first, otherwise, we may miss | |
1319 quit char when called from quit_p */ | |
1320 /* #### This is, ehm, not quite true -- this function is not | |
1321 called from quit_p. --kkm */ | |
1322 mswindows_drain_windows_queue (); | |
1323 #endif | |
1324 | |
1325 while (NILP (mswindows_u_dispatch_event_queue) | 1384 while (NILP (mswindows_u_dispatch_event_queue) |
1326 && NILP (mswindows_s_dispatch_event_queue)) | 1385 && NILP (mswindows_s_dispatch_event_queue)) |
1327 { | 1386 { |
1328 #ifdef HAVE_MSG_SELECT | 1387 #ifdef HAVE_MSG_SELECT |
1329 int i; | 1388 int i; |
1349 } | 1408 } |
1350 else if (active > 0) | 1409 else if (active > 0) |
1351 { | 1410 { |
1352 if (FD_ISSET (windows_fd, &temp_mask)) | 1411 if (FD_ISSET (windows_fd, &temp_mask)) |
1353 { | 1412 { |
1354 mswindows_drain_windows_queue (0); | 1413 mswindows_drain_windows_queue (); |
1355 } | 1414 } |
1415 else | |
1416 { | |
1356 #ifdef HAVE_TTY | 1417 #ifdef HAVE_TTY |
1357 /* Look for a TTY event */ | 1418 /* Look for a TTY event */ |
1358 for (i = 0; i < MAXDESC-1; i++) | 1419 for (i = 0; i < MAXDESC-1; i++) |
1359 { | |
1360 /* To avoid race conditions (among other things, an infinite | |
1361 loop when called from Fdiscard_input()), we must return | |
1362 user events ahead of process events. */ | |
1363 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) | |
1364 { | 1420 { |
1365 struct console *c = tty_find_console_from_fd (i); | 1421 /* To avoid race conditions (among other things, an infinite |
1366 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 1422 loop when called from Fdiscard_input()), we must return |
1367 Lisp_Event* event = XEVENT (emacs_event); | 1423 user events ahead of process events. */ |
1368 | 1424 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) |
1369 assert (c); | |
1370 if (read_event_from_tty_or_stream_desc (event, c, i)) | |
1371 { | 1425 { |
1372 mswindows_enqueue_dispatch_event (emacs_event); | 1426 struct console *c = tty_find_console_from_fd (i); |
1373 return; | 1427 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1428 Lisp_Event* event = XEVENT (emacs_event); | |
1429 | |
1430 assert (c); | |
1431 if (read_event_from_tty_or_stream_desc (event, c, i)) | |
1432 { | |
1433 mswindows_enqueue_dispatch_event (emacs_event); | |
1434 return; | |
1435 } | |
1374 } | 1436 } |
1375 } | 1437 } |
1376 } | 1438 #endif |
1377 #endif | 1439 /* Look for a process event */ |
1378 /* Look for a process event */ | 1440 for (i = 0; i < MAXDESC-1; i++) |
1379 for (i = 0; i < MAXDESC-1; i++) | |
1380 { | |
1381 if (FD_ISSET (i, &temp_mask)) | |
1382 { | 1441 { |
1383 if (FD_ISSET (i, &process_only_mask)) | 1442 if (FD_ISSET (i, &temp_mask)) |
1384 { | 1443 { |
1385 Lisp_Process *p = | 1444 if (FD_ISSET (i, &process_only_mask)) |
1386 get_process_from_usid (FD_TO_USID(i)); | 1445 { |
1387 | 1446 Lisp_Process *p = |
1388 mswindows_enqueue_process_event (p); | 1447 get_process_from_usid (FD_TO_USID(i)); |
1389 } | 1448 |
1390 else | 1449 mswindows_enqueue_process_event (p); |
1391 { | 1450 } |
1392 /* We might get here when a fake event came | 1451 else |
1393 through a signal. Return a dummy event, so | 1452 { |
1394 that a cycle of the command loop will | 1453 /* We might get here when a fake event came |
1395 occur. */ | 1454 through a signal. Return a dummy event, so |
1396 drain_signal_event_pipe (); | 1455 that a cycle of the command loop will |
1397 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | 1456 occur. */ |
1457 drain_signal_event_pipe (); | |
1458 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1459 } | |
1398 } | 1460 } |
1399 } | 1461 } |
1400 } | 1462 } |
1401 } | 1463 } |
1402 else if (active==-1) | 1464 else if (active==-1) |
1411 { | 1473 { |
1412 assert(0); | 1474 assert(0); |
1413 } | 1475 } |
1414 #else | 1476 #else |
1415 /* Now try getting a message or process event */ | 1477 /* Now try getting a message or process event */ |
1416 active = MsgWaitForMultipleObjects (mswindows_waitable_count, | 1478 active = MsgWaitForMultipleObjects (mswindows_waitable_count, |
1417 mswindows_waitable_handles, | 1479 mswindows_waitable_handles, |
1418 FALSE, badly_p ? INFINITE : 0, | 1480 FALSE, badly_p ? INFINITE : 0, |
1419 QS_ALLINPUT); | 1481 QS_ALLINPUT); |
1420 | 1482 |
1421 /* This will assert if handle being waited for becomes abandoned. | 1483 /* This will assert if handle being waited for becomes abandoned. |
1422 Not the case currently tho */ | 1484 Not the case currently tho */ |
1423 assert ((!badly_p && active == WAIT_TIMEOUT) || | 1485 assert ((!badly_p && active == WAIT_TIMEOUT) || |
1424 (active >= WAIT_OBJECT_0 && | 1486 (active >= WAIT_OBJECT_0 && |
1425 active <= WAIT_OBJECT_0 + mswindows_waitable_count)); | 1487 active <= WAIT_OBJECT_0 + mswindows_waitable_count)); |
1426 | 1488 |
1427 if (active == WAIT_TIMEOUT) | 1489 if (active == WAIT_TIMEOUT) |
1428 { | 1490 { |
1429 /* No luck trying - just return what we've already got */ | 1491 /* No luck trying - just return what we've already got */ |
1430 return; | 1492 return; |
1431 } | 1493 } |
1432 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) | 1494 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) |
1433 { | 1495 { |
1434 /* Got your message, thanks */ | 1496 /* Got your message, thanks */ |
1435 mswindows_drain_windows_queue (0); | 1497 mswindows_drain_windows_queue (); |
1436 } | 1498 } |
1437 else | 1499 else |
1438 { | 1500 { |
1439 int ix = active - WAIT_OBJECT_0; | 1501 int ix = active - WAIT_OBJECT_0; |
1440 /* First, try to find which process' output has signaled */ | 1502 /* First, try to find which process' output has signaled */ |
1441 Lisp_Process *p = | 1503 Lisp_Process *p = |
1442 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix])); | 1504 get_process_from_usid (HANDLE_TO_USID (mswindows_waitable_handles[ix])); |
1443 if (p != NULL) | 1505 if (p != NULL) |
1444 { | 1506 { |
1445 /* Found a signaled process input handle */ | 1507 /* Found a signaled process input handle */ |
1446 mswindows_enqueue_process_event (p); | 1508 mswindows_enqueue_process_event (p); |
1447 } | 1509 } |
1448 else | 1510 else |
1449 { | 1511 { |
1450 /* None. This means that the process handle itself has signaled. | 1512 /* None. This means that the process handle itself has signaled. |
1451 Remove the handle from the wait vector, and make status_notify | 1513 Remove the handle from the wait vector, and make status_notify |
1452 note the exited process */ | 1514 note the exited process */ |
1453 mswindows_waitable_handles [ix] = | 1515 mswindows_waitable_handles [ix] = |
1454 mswindows_waitable_handles [--mswindows_waitable_count]; | 1516 mswindows_waitable_handles [--mswindows_waitable_count]; |
1455 kick_status_notify (); | 1517 kick_status_notify (); |
1456 /* Have to return something: there may be no accompanying | 1518 /* We need to return a process event here so that |
1457 process event */ | 1519 (1) accept-process-output will return when called on this |
1458 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | 1520 process, and (2) status notifications will happen in |
1459 } | 1521 accept-process-output, sleep-for, and sit-for. */ |
1460 } | 1522 /* #### horrible kludge till my real process fixes go in. |
1461 #endif | 1523 */ |
1462 } /* while */ | 1524 if (!NILP (Vprocess_list)) |
1525 { | |
1526 Lisp_Object vaffanculo = XCAR (Vprocess_list); | |
1527 mswindows_enqueue_process_event (XPROCESS (vaffanculo)); | |
1528 } | |
1529 else /* trash me soon. */ | |
1530 /* Have to return something: there may be no accompanying | |
1531 process event */ | |
1532 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1533 } | |
1534 } | |
1535 #endif | |
1536 } /* while */ | |
1463 } | 1537 } |
1464 | 1538 |
1465 /************************************************************************/ | 1539 /************************************************************************/ |
1466 /* Event generators */ | 1540 /* Event generators */ |
1467 /************************************************************************/ | 1541 /************************************************************************/ |
1512 /* We only support one {service,topic} pair */ | 1586 /* We only support one {service,topic} pair */ |
1513 HSZPAIR pairs[2] = { | 1587 HSZPAIR pairs[2] = { |
1514 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } }; | 1588 { mswindows_dde_service, mswindows_dde_topic_system }, { 0, 0 } }; |
1515 | 1589 |
1516 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) && | 1590 if (!(hszItem || DdeCmpStringHandles (hszItem, mswindows_dde_service)) && |
1517 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))); | 1591 !(hszTopic || DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system))) |
1518 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs, | 1592 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)pairs, |
1519 sizeof (pairs), 0L, 0, uFmt, 0)); | 1593 sizeof (pairs), 0L, 0, uFmt, 0)); |
1520 } | 1594 } |
1521 return (HDDEDATA)NULL; | 1595 return (HDDEDATA)NULL; |
1522 | 1596 |
1523 case XTYP_EXECUTE: | 1597 case XTYP_EXECUTE: |
1524 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) | 1598 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) |
1525 { | 1599 { |
1526 DWORD len = DdeGetData (hdata, NULL, 0, 0); | 1600 DWORD len = DdeGetData (hdata, NULL, 0, 0); |
1527 char *cmd = alloca (len+1); | 1601 LPBYTE cmd = (LPBYTE) alloca (len+1); |
1528 char *end; | 1602 char *end; |
1529 char *filename; | 1603 char *filename; |
1530 struct gcpro gcpro1, gcpro2; | 1604 struct gcpro gcpro1, gcpro2; |
1531 Lisp_Object l_dndlist = Qnil; | 1605 Lisp_Object l_dndlist = Qnil; |
1532 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 1606 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
1561 if (*(++end)==']') | 1635 if (*(++end)==']') |
1562 end++; | 1636 end++; |
1563 if (*end) | 1637 if (*end) |
1564 return DDE_FNOTPROCESSED; | 1638 return DDE_FNOTPROCESSED; |
1565 | 1639 |
1566 #ifdef __CYGWIN32__ | 1640 #ifdef CYGWIN |
1567 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5); | 1641 filename = alloca (cygwin32_win32_to_posix_path_list_buf_size (cmd) + 5); |
1568 strcpy (filename, "file:"); | 1642 strcpy (filename, "file:"); |
1569 cygwin32_win32_to_posix_path_list (cmd, filename+5); | 1643 cygwin32_win32_to_posix_path_list (cmd, filename+5); |
1570 #else | 1644 #else |
1571 dostounix_filename (cmd); | 1645 dostounix_filename (cmd); |
1607 } | 1681 } |
1608 } | 1682 } |
1609 #endif | 1683 #endif |
1610 | 1684 |
1611 /* | 1685 /* |
1612 * Returns 1 if a key is a real modifier or special key, which | 1686 * Helper to do repainting - repaints can happen both from the windows |
1687 * procedure and from magic events | |
1688 */ | |
1689 static void | |
1690 mswindows_handle_paint (struct frame *frame) | |
1691 { | |
1692 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame); | |
1693 | |
1694 /* According to the docs we need to check GetUpdateRect() before | |
1695 actually doing a WM_PAINT */ | |
1696 if (GetUpdateRect (hwnd, NULL, FALSE)) | |
1697 { | |
1698 PAINTSTRUCT paintStruct; | |
1699 int x, y, width, height; | |
1700 | |
1701 BeginPaint (hwnd, &paintStruct); | |
1702 x = paintStruct.rcPaint.left; | |
1703 y = paintStruct.rcPaint.top; | |
1704 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; | |
1705 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; | |
1706 /* Normally we want to ignore expose events when child | |
1707 windows are unmapped, however once we are in the guts of | |
1708 WM_PAINT we need to make sure that we don't register | |
1709 unmaps then because they will not actually occur. */ | |
1710 /* #### commenting out the next line seems to fix some problems | |
1711 but not all. only andy currently understands this stuff and | |
1712 he needs to review it more carefully. --ben */ | |
1713 if (!check_for_ignored_expose (frame, x, y, width, height)) | |
1714 { | |
1715 hold_ignored_expose_registration = 1; | |
1716 mswindows_redraw_exposed_area (frame, x, y, width, height); | |
1717 hold_ignored_expose_registration = 0; | |
1718 } | |
1719 EndPaint (hwnd, &paintStruct); | |
1720 } | |
1721 } | |
1722 | |
1723 /* | |
1724 * Returns 1 if a key is a real modifier or special key, which | |
1613 * is better handled by DefWindowProc | 1725 * is better handled by DefWindowProc |
1614 */ | 1726 */ |
1615 static int | 1727 static int |
1616 key_needs_default_processing_p (UINT vkey) | 1728 key_needs_default_processing_p (UINT vkey) |
1617 { | 1729 { |
1618 if (mswindows_meta_activates_menu && vkey == VK_MENU) | 1730 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU |
1731 /* if we let ALT activate the menu like this, then sticky ALT-modified | |
1732 keystrokes become impossible. */ | |
1733 && !modifier_keys_are_sticky) | |
1619 return 1; | 1734 return 1; |
1620 | 1735 |
1621 return 0; | 1736 return 0; |
1622 } | 1737 } |
1738 | |
1739 /* key-handling code is always ugly. It just ends up working out | |
1740 that way. | |
1741 | |
1742 #### Most of the sticky-modifier code below is copied from similar | |
1743 code in event-Xt.c. They should somehow or other be merged. | |
1744 | |
1745 Here are some pointers: | |
1746 | |
1747 -- DOWN_MASK indicates which modifiers should be treated as "down" | |
1748 when the corresponding upstroke happens. It gets reset for | |
1749 a particular modifier when that modifier goes up, and reset | |
1750 for all modifiers when a non-modifier key is pressed. Example: | |
1751 | |
1752 I press Control-A-Shift and then release Control-A-Shift. | |
1753 I want the Shift key to be sticky but not the Control key. | |
1754 | |
1755 -- If a modifier key is sticky, I can unstick it by pressing | |
1756 the modifier key again. */ | |
1757 | |
1758 static WPARAM last_downkey; | |
1759 static int need_to_add_mask, down_mask; | |
1760 | |
1761 #define XEMSW_LCONTROL (1<<0) | |
1762 #define XEMSW_RCONTROL (1<<1) | |
1763 #define XEMSW_LSHIFT (1<<2) | |
1764 #define XEMSW_RSHIFT (1<<3) | |
1765 #define XEMSW_LMENU (1<<4) | |
1766 #define XEMSW_RMENU (1<<5) | |
1767 | |
1768 static int | |
1769 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, | |
1770 int downp, int keyp) | |
1771 { | |
1772 int mods = 0; | |
1773 | |
1774 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */ | |
1775 return 0; | |
1776 | |
1777 if (! (keyp && | |
1778 (wParam == VK_CONTROL || wParam == VK_LCONTROL || | |
1779 wParam == VK_RCONTROL || | |
1780 wParam == VK_MENU || wParam == VK_LMENU || | |
1781 wParam == VK_RMENU || | |
1782 wParam == VK_SHIFT || wParam == VK_LSHIFT || | |
1783 wParam == VK_RSHIFT))) | |
1784 { /* Not a modifier key */ | |
1785 if (downp && keyp && !last_downkey) | |
1786 last_downkey = wParam; | |
1787 /* If I hold press-and-release the Control key and then press | |
1788 and hold down the right arrow, I want it to auto-repeat | |
1789 Control-Right. On the other hand, if I do the same but | |
1790 manually press the Right arrow a bunch of times, I want | |
1791 to see one Control-Right and then a bunch of Rights. | |
1792 This means that we need to distinguish between an | |
1793 auto-repeated key and a key pressed and released a bunch | |
1794 of times. */ | |
1795 else if ((downp && !keyp) || | |
1796 (downp && keyp && last_downkey && | |
1797 (wParam != last_downkey || | |
1798 /* the "previous key state" bit indicates autorepeat */ | |
1799 ! (lParam & (1 << 30))))) | |
1800 { | |
1801 need_to_add_mask = 0; | |
1802 last_downkey = 0; | |
1803 } | |
1804 if (downp) | |
1805 down_mask = 0; | |
1806 | |
1807 mods = need_to_add_mask; | |
1808 } | |
1809 else /* Modifier key pressed */ | |
1810 { | |
1811 /* If a non-modifier key was pressed in the middle of a bunch | |
1812 of modifiers, then it unsticks all the modifiers that were | |
1813 previously pressed. We cannot unstick the modifiers until | |
1814 now because we want to check for auto-repeat of the | |
1815 non-modifier key. */ | |
1816 | |
1817 if (last_downkey) | |
1818 { | |
1819 last_downkey = 0; | |
1820 need_to_add_mask = 0; | |
1821 } | |
1822 | |
1823 #define FROB(mask) \ | |
1824 do { \ | |
1825 if (downp && keyp) \ | |
1826 { \ | |
1827 /* If modifier key is already sticky, \ | |
1828 then unstick it. Note that we do \ | |
1829 not test down_mask to deal with the \ | |
1830 unlikely but possible case that the \ | |
1831 modifier key auto-repeats. */ \ | |
1832 if (need_to_add_mask & mask) \ | |
1833 { \ | |
1834 need_to_add_mask &= ~mask; \ | |
1835 down_mask &= ~mask; \ | |
1836 } \ | |
1837 else \ | |
1838 down_mask |= mask; \ | |
1839 } \ | |
1840 else \ | |
1841 { \ | |
1842 if (down_mask & mask) \ | |
1843 { \ | |
1844 down_mask &= ~mask; \ | |
1845 need_to_add_mask |= mask; \ | |
1846 } \ | |
1847 } \ | |
1848 } while (0) | |
1849 | |
1850 if ((wParam == VK_CONTROL && (lParam & 0x1000000)) | |
1851 || wParam == VK_RCONTROL) | |
1852 FROB (XEMSW_RCONTROL); | |
1853 if ((wParam == VK_CONTROL && !(lParam & 0x1000000)) | |
1854 || wParam == VK_LCONTROL) | |
1855 FROB (XEMSW_LCONTROL); | |
1856 | |
1857 if ((wParam == VK_SHIFT && (lParam & 0x1000000)) | |
1858 || wParam == VK_RSHIFT) | |
1859 FROB (XEMSW_RSHIFT); | |
1860 if ((wParam == VK_SHIFT && !(lParam & 0x1000000)) | |
1861 || wParam == VK_LSHIFT) | |
1862 FROB (XEMSW_LSHIFT); | |
1863 | |
1864 if ((wParam == VK_MENU && (lParam & 0x1000000)) | |
1865 || wParam == VK_RMENU) | |
1866 FROB (XEMSW_RMENU); | |
1867 if ((wParam == VK_MENU && !(lParam & 0x1000000)) | |
1868 || wParam == VK_LMENU) | |
1869 FROB (XEMSW_LMENU); | |
1870 } | |
1871 #undef FROB | |
1872 | |
1873 if (mods && downp) | |
1874 { | |
1875 BYTE keymap[256]; | |
1876 | |
1877 GetKeyboardState (keymap); | |
1878 | |
1879 if (mods & XEMSW_LCONTROL) | |
1880 { | |
1881 keymap [VK_CONTROL] |= 0x80; | |
1882 keymap [VK_LCONTROL] |= 0x80; | |
1883 } | |
1884 if (mods & XEMSW_RCONTROL) | |
1885 { | |
1886 keymap [VK_CONTROL] |= 0x80; | |
1887 keymap [VK_RCONTROL] |= 0x80; | |
1888 } | |
1889 | |
1890 if (mods & XEMSW_LSHIFT) | |
1891 { | |
1892 keymap [VK_SHIFT] |= 0x80; | |
1893 keymap [VK_LSHIFT] |= 0x80; | |
1894 } | |
1895 if (mods & XEMSW_RSHIFT) | |
1896 { | |
1897 keymap [VK_SHIFT] |= 0x80; | |
1898 keymap [VK_RSHIFT] |= 0x80; | |
1899 } | |
1900 | |
1901 if (mods & XEMSW_LMENU) | |
1902 { | |
1903 keymap [VK_MENU] |= 0x80; | |
1904 keymap [VK_LMENU] |= 0x80; | |
1905 } | |
1906 if (mods & XEMSW_RMENU) | |
1907 { | |
1908 keymap [VK_MENU] |= 0x80; | |
1909 keymap [VK_RMENU] |= 0x80; | |
1910 } | |
1911 | |
1912 SetKeyboardState (keymap); | |
1913 return 1; | |
1914 } | |
1915 | |
1916 return 0; | |
1917 } | |
1918 | |
1919 static void | |
1920 clear_sticky_modifiers (void) | |
1921 { | |
1922 need_to_add_mask = 0; | |
1923 last_downkey = 0; | |
1924 down_mask = 0; | |
1925 } | |
1926 | |
1927 #ifdef DEBUG_XEMACS | |
1928 | |
1929 #if 0 | |
1930 | |
1931 static void | |
1932 output_modifier_keyboard_state (void) | |
1933 { | |
1934 BYTE keymap[256]; | |
1935 | |
1936 GetKeyboardState (keymap); | |
1937 | |
1938 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
1939 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
1940 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
1941 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
1942 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
1943 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
1944 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
1945 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n", | |
1946 keymap[VK_CONTROL] & 0x80 ? 1 : 0, | |
1947 keymap[VK_CONTROL] & 0x1 ? 1 : 0, | |
1948 keymap[VK_LCONTROL] & 0x80 ? 1 : 0, | |
1949 keymap[VK_LCONTROL] & 0x1 ? 1 : 0, | |
1950 keymap[VK_RCONTROL] & 0x80 ? 1 : 0, | |
1951 keymap[VK_RCONTROL] & 0x1 ? 1 : 0); | |
1952 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n", | |
1953 keymap[VK_SHIFT] & 0x80 ? 1 : 0, | |
1954 keymap[VK_SHIFT] & 0x1 ? 1 : 0, | |
1955 keymap[VK_LSHIFT] & 0x80 ? 1 : 0, | |
1956 keymap[VK_LSHIFT] & 0x1 ? 1 : 0, | |
1957 keymap[VK_RSHIFT] & 0x80 ? 1 : 0, | |
1958 keymap[VK_RSHIFT] & 0x1 ? 1 : 0); | |
1959 } | |
1960 | |
1961 #endif | |
1962 | |
1963 /* try to debug the stuck-alt-key problem. | |
1964 | |
1965 #### this happens only inconsistently, and may only happen when using | |
1966 StickyKeys in the Win2000 accessibility section of the control panel, | |
1967 which is extremely broken for other reasons. */ | |
1968 | |
1969 static void | |
1970 output_alt_keyboard_state (void) | |
1971 { | |
1972 BYTE keymap[256]; | |
1973 SHORT keystate[3]; | |
1974 // SHORT asyncstate[3]; | |
1975 | |
1976 GetKeyboardState (keymap); | |
1977 keystate[0] = GetKeyState (VK_MENU); | |
1978 keystate[1] = GetKeyState (VK_LMENU); | |
1979 keystate[2] = GetKeyState (VK_RMENU); | |
1980 /* Doing this interferes with key processing. */ | |
1981 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */ | |
1982 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */ | |
1983 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */ | |
1984 | |
1985 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
1986 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
1987 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
1988 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
1989 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
1990 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
1991 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
1992 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
1993 keystate[0] & 0x8000 ? 1 : 0, | |
1994 keystate[0] & 0x1 ? 1 : 0, | |
1995 keystate[1] & 0x8000 ? 1 : 0, | |
1996 keystate[1] & 0x1 ? 1 : 0, | |
1997 keystate[2] & 0x8000 ? 1 : 0, | |
1998 keystate[2] & 0x1 ? 1 : 0); | |
1999 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */ | |
2000 /* asyncstate[0] & 0x8000 ? 1 : 0, */ | |
2001 /* asyncstate[0] & 0x1 ? 1 : 0, */ | |
2002 /* asyncstate[1] & 0x8000 ? 1 : 0, */ | |
2003 /* asyncstate[1] & 0x1 ? 1 : 0, */ | |
2004 /* asyncstate[2] & 0x8000 ? 1 : 0, */ | |
2005 /* asyncstate[2] & 0x1 ? 1 : 0); */ | |
2006 } | |
2007 | |
2008 #endif /* DEBUG_XEMACS */ | |
2009 | |
1623 | 2010 |
1624 /* | 2011 /* |
1625 * The windows procedure for the window class XEMACS_CLASS | 2012 * The windows procedure for the window class XEMACS_CLASS |
1626 */ | 2013 */ |
1627 LRESULT WINAPI | 2014 LRESULT WINAPI |
1628 mswindows_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | 2015 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam) |
1629 { | 2016 { |
1630 /* Note: Remember to initialize emacs_event and event before use. | 2017 /* Note: Remember to initialize emacs_event and event before use. |
1631 This code calls code that can GC. You must GCPRO before calling such code. */ | 2018 This code calls code that can GC. You must GCPRO before calling such code. */ |
1632 Lisp_Object emacs_event = Qnil; | 2019 Lisp_Object emacs_event = Qnil; |
1633 Lisp_Object fobj = Qnil; | 2020 Lisp_Object fobj = Qnil; |
1634 | 2021 |
1635 Lisp_Event *event; | 2022 Lisp_Event *event; |
1636 struct frame *frame; | 2023 struct frame *frame; |
1637 struct mswindows_frame* msframe; | 2024 struct mswindows_frame* msframe; |
1638 | 2025 |
1639 switch (message) | 2026 /* Not perfect but avoids crashes. There is potential for wierd |
1640 { | 2027 behavior here. */ |
1641 case WM_DESTROYCLIPBOARD: | 2028 if (gc_in_progress) |
1642 /* We own the clipboard and someone else wants it. Delete our | 2029 goto defproc; |
1643 cached copy of the clipboard contents so we'll ask for it from | 2030 |
1644 Windows again when someone does a paste. */ | 2031 assert (!GetWindowLong (hwnd, GWL_USERDATA)); |
1645 handle_selection_clear(QCLIPBOARD); | 2032 switch (message_) |
1646 break; | |
1647 | |
1648 case WM_ERASEBKGND: | |
1649 /* Erase background only during non-dynamic sizing */ | |
1650 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1651 if (msframe->sizing && !mswindows_dynamic_frame_resize) | |
1652 goto defproc; | |
1653 return 1; | |
1654 | |
1655 case WM_CLOSE: | |
1656 fobj = mswindows_find_frame (hwnd); | |
1657 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); | |
1658 break; | |
1659 | |
1660 case WM_KEYUP: | |
1661 case WM_SYSKEYUP: | |
1662 /* See Win95 comment under WM_KEYDOWN */ | |
1663 { | 2033 { |
1664 BYTE keymap[256]; | 2034 case WM_DESTROYCLIPBOARD: |
1665 | 2035 /* We own the clipboard and someone else wants it. Delete our |
1666 if (wParam == VK_CONTROL) | 2036 cached copy of the clipboard contents so we'll ask for it from |
1667 { | 2037 Windows again when someone does a paste, and destroy any memory |
1668 GetKeyboardState (keymap); | 2038 objects we hold on the clipboard that are not in the list of types |
1669 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; | 2039 that Windows will delete itself. */ |
2040 mswindows_destroy_selection (QCLIPBOARD); | |
2041 handle_selection_clear (QCLIPBOARD); | |
2042 break; | |
2043 | |
2044 case WM_ERASEBKGND: | |
2045 /* Erase background only during non-dynamic sizing */ | |
2046 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2047 if (msframe->sizing && !mswindows_dynamic_frame_resize) | |
2048 goto defproc; | |
2049 return 1; | |
2050 | |
2051 case WM_CLOSE: | |
2052 fobj = mswindows_find_frame (hwnd); | |
2053 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, Qt)); | |
2054 break; | |
2055 | |
2056 case WM_KEYUP: | |
2057 case WM_SYSKEYUP: | |
2058 | |
2059 /* See Win95 comment under WM_KEYDOWN */ | |
2060 { | |
2061 BYTE keymap[256]; | |
2062 int should_set_keymap = 0; | |
2063 | |
2064 #ifdef DEBUG_XEMACS | |
2065 if (debug_mswindows_events) | |
2066 { | |
2067 stderr_out ("%s wparam=%d lparam=%d\n", | |
2068 message_ == WM_KEYUP ? "WM_KEYUP" : "WM_SYSKEYUP", | |
2069 wParam, (int)lParam); | |
2070 output_alt_keyboard_state (); | |
2071 } | |
2072 #endif /* DEBUG_XEMACS */ | |
2073 | |
2074 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1); | |
2075 if (wParam == VK_CONTROL) | |
2076 { | |
2077 GetKeyboardState (keymap); | |
2078 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; | |
2079 should_set_keymap = 1; | |
2080 } | |
2081 else if (wParam == VK_MENU) | |
2082 { | |
2083 GetKeyboardState (keymap); | |
2084 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; | |
2085 should_set_keymap = 1; | |
2086 } | |
2087 | |
2088 if (should_set_keymap) | |
2089 // && (message_ != WM_SYSKEYUP | |
2090 // || NILP (Vmenu_accelerator_enabled))) | |
1670 SetKeyboardState (keymap); | 2091 SetKeyboardState (keymap); |
1671 } | 2092 |
1672 else if (wParam == VK_MENU) | 2093 } |
1673 { | 2094 |
1674 GetKeyboardState (keymap); | 2095 if (key_needs_default_processing_p (wParam)) |
1675 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; | 2096 goto defproc; |
1676 SetKeyboardState (keymap); | 2097 else |
1677 } | 2098 break; |
1678 }; | 2099 |
1679 if (key_needs_default_processing_p (wParam)) | 2100 case WM_KEYDOWN: |
1680 goto defproc; | 2101 case WM_SYSKEYDOWN: |
1681 else | 2102 |
1682 break; | 2103 /* In some locales the right-hand Alt key is labelled AltGr. This key |
1683 | 2104 * should produce alternative characters when combined with another key. |
1684 case WM_KEYDOWN: | 2105 * eg on a German keyboard pressing AltGr+q should produce '@'. |
1685 case WM_SYSKEYDOWN: | 2106 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if |
1686 /* In some locales the right-hand Alt key is labelled AltGr. This key | 2107 * TranslateMessage() is called with *any* combination of Ctrl+Alt down, |
1687 * should produce alternative charcaters when combined with another key. | 2108 * it translates as if AltGr were down. |
1688 * eg on a German keyboard pressing AltGr+q should produce '@'. | 2109 * We get round this by removing all modifiers from the keymap before |
1689 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if | 2110 * calling TranslateMessage() unless AltGr is *really* down. */ |
1690 * TranslateMessage() is called with *any* combination of Ctrl+Alt down, | |
1691 * it translates as if AltGr were down. | |
1692 * We get round this by removing all modifiers from the keymap before | |
1693 * calling TranslateMessage() unless AltGr is *really* down. */ | |
1694 { | |
1695 BYTE keymap[256]; | |
1696 int has_AltGr = mswindows_current_layout_has_AltGr (); | |
1697 int mods; | |
1698 int extendedp = lParam & 0x1000000; | |
1699 Lisp_Object keysym; | |
1700 | |
1701 GetKeyboardState (keymap); | |
1702 mods = mswindows_modifier_state (keymap, has_AltGr); | |
1703 | |
1704 /* Handle non-printables */ | |
1705 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, | |
1706 extendedp))) | |
1707 mswindows_enqueue_keypress_event (hwnd, keysym, mods); | |
1708 else /* Normal keys & modifiers */ | |
1709 { | |
1710 int quit_ch = CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); | |
1711 BYTE keymap_orig[256]; | |
1712 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; | |
1713 MSG msg; | |
1714 | |
1715 msg.hwnd = hwnd; | |
1716 msg.message = message; | |
1717 msg.wParam = wParam; | |
1718 msg.lParam = lParam; | |
1719 msg.time = GetMessageTime(); | |
1720 msg.pt = pnt; | |
1721 | |
1722 /* GetKeyboardState() does not work as documented on Win95. We have | |
1723 * to loosely track Left and Right modifiers on behalf of the OS, | |
1724 * without screwing up Windows NT which tracks them properly. */ | |
1725 if (wParam == VK_CONTROL) | |
1726 keymap [extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
1727 else if (wParam == VK_MENU) | |
1728 keymap [extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | |
1729 | |
1730 memcpy (keymap_orig, keymap, 256); | |
1731 | |
1732 /* Remove shift modifier from an ascii character */ | |
1733 mods &= ~MOD_SHIFT; | |
1734 | |
1735 /* Clear control and alt modifiers unless AltGr is pressed */ | |
1736 keymap [VK_RCONTROL] = 0; | |
1737 keymap [VK_LMENU] = 0; | |
1738 if (!has_AltGr || !(keymap [VK_LCONTROL] & 0x80) | |
1739 || !(keymap [VK_RMENU] & 0x80)) | |
1740 { | |
1741 keymap [VK_LCONTROL] = 0; | |
1742 keymap [VK_CONTROL] = 0; | |
1743 keymap [VK_RMENU] = 0; | |
1744 keymap [VK_MENU] = 0; | |
1745 } | |
1746 SetKeyboardState (keymap); | |
1747 | |
1748 /* Maybe generate some WM_[SYS]CHARs in the queue */ | |
1749 TranslateMessage (&msg); | |
1750 | |
1751 while (PeekMessage (&msg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) | |
1752 || PeekMessage (&msg, hwnd, WM_SYSCHAR, WM_SYSCHAR, PM_REMOVE)) | |
1753 { | |
1754 int mods1 = mods; | |
1755 WPARAM ch = msg.wParam; | |
1756 | |
1757 /* If a quit char with no modifiers other than control and | |
1758 shift, then mark it with a fake modifier, which is removed | |
1759 upon dequeueing the event */ | |
1760 /* #### This might also not withstand localization, if | |
1761 quit character is not a latin-1 symbol */ | |
1762 if (((quit_ch < ' ' && (mods & MOD_CONTROL) && quit_ch + 'a' - 1 == ch) | |
1763 || (quit_ch >= ' ' && !(mods & MOD_CONTROL) && quit_ch == ch)) | |
1764 && ((mods & ~(MOD_CONTROL | MOD_SHIFT)) == 0)) | |
1765 { | |
1766 mods1 |= FAKE_MOD_QUIT; | |
1767 ++mswindows_quit_chars_count; | |
1768 } | |
1769 | |
1770 mswindows_enqueue_keypress_event (hwnd, make_char(ch), mods1); | |
1771 } /* while */ | |
1772 SetKeyboardState (keymap_orig); | |
1773 } /* else */ | |
1774 } | |
1775 if (key_needs_default_processing_p (wParam)) | |
1776 goto defproc; | |
1777 else | |
1778 break; | |
1779 | |
1780 case WM_MBUTTONDOWN: | |
1781 case WM_MBUTTONUP: | |
1782 /* Real middle mouse button has nothing to do with emulated one: | |
1783 if one wants to exercise fingers playing chords on the mouse, | |
1784 he is allowed to do that! */ | |
1785 mswindows_enqueue_mouse_button_event (hwnd, message, | |
1786 MAKEPOINTS (lParam), GetMessageTime()); | |
1787 break; | |
1788 | |
1789 case WM_LBUTTONUP: | |
1790 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1791 msframe->last_click_time = GetMessageTime(); | |
1792 | |
1793 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1794 msframe->button2_need_lbutton = 0; | |
1795 if (msframe->ignore_next_lbutton_up) | |
1796 { | 2111 { |
1797 msframe->ignore_next_lbutton_up = 0; | 2112 BYTE keymap_trans[256]; |
1798 } | 2113 BYTE keymap_orig[256]; |
1799 else if (msframe->button2_is_down) | 2114 BYTE keymap_sticky[256]; |
1800 { | 2115 int has_AltGr = mswindows_current_layout_has_AltGr (); |
1801 msframe->button2_is_down = 0; | 2116 int mods = 0; |
1802 msframe->ignore_next_rbutton_up = 1; | 2117 int extendedp = lParam & 0x1000000; |
1803 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | 2118 Lisp_Object keysym; |
1804 MAKEPOINTS (lParam), GetMessageTime()); | 2119 int sticky_changed; |
1805 } | 2120 |
1806 else | 2121 #ifdef DEBUG_XEMACS |
1807 { | 2122 if (debug_mswindows_events) |
1808 if (msframe->button2_need_rbutton) | |
1809 { | 2123 { |
1810 msframe->button2_need_rbutton = 0; | 2124 stderr_out ("%s wparam=%d lparam=%d\n", |
1811 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | 2125 message_ == WM_KEYDOWN ? "WM_KEYDOWN" : "WM_SYSKEYDOWN", |
1812 MAKEPOINTS (lParam), GetMessageTime()); | 2126 wParam, (int)lParam); |
2127 output_alt_keyboard_state (); | |
1813 } | 2128 } |
1814 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, | 2129 #endif /* DEBUG_XEMACS */ |
1815 MAKEPOINTS (lParam), GetMessageTime()); | 2130 |
1816 } | 2131 GetKeyboardState (keymap_orig); |
1817 break; | 2132 frame = XFRAME (mswindows_find_frame (hwnd)); |
1818 | 2133 if ((sticky_changed = |
1819 case WM_RBUTTONUP: | 2134 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1))) |
1820 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1821 msframe->last_click_time = GetMessageTime(); | |
1822 | |
1823 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1824 msframe->button2_need_rbutton = 0; | |
1825 if (msframe->ignore_next_rbutton_up) | |
1826 { | |
1827 msframe->ignore_next_rbutton_up = 0; | |
1828 } | |
1829 else if (msframe->button2_is_down) | |
1830 { | |
1831 msframe->button2_is_down = 0; | |
1832 msframe->ignore_next_lbutton_up = 1; | |
1833 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
1834 MAKEPOINTS (lParam), GetMessageTime()); | |
1835 } | |
1836 else | |
1837 { | |
1838 if (msframe->button2_need_lbutton) | |
1839 { | 2135 { |
1840 msframe->button2_need_lbutton = 0; | 2136 GetKeyboardState (keymap_sticky); |
1841 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | 2137 if (keymap_sticky[VK_MENU] & 0x80) |
1842 MAKEPOINTS (lParam), GetMessageTime()); | 2138 { |
1843 } | 2139 message_ = WM_SYSKEYDOWN; |
1844 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, | 2140 /* We have to set the "context bit" so that the |
1845 MAKEPOINTS (lParam), GetMessageTime()); | 2141 TranslateMessage() call below that generates the |
1846 } | 2142 SYSCHAR message does its thing; see the documentation |
1847 break; | 2143 on WM_SYSKEYDOWN */ |
1848 | 2144 lParam |= 1 << 29; |
1849 case WM_LBUTTONDOWN: | 2145 } |
1850 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
1851 | |
1852 if (msframe->button2_need_lbutton) | |
1853 { | |
1854 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1855 msframe->button2_need_lbutton = 0; | |
1856 msframe->button2_need_rbutton = 0; | |
1857 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | |
1858 { | |
1859 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | |
1860 MAKEPOINTS (lParam), GetMessageTime()); | |
1861 msframe->button2_is_down = 1; | |
1862 } | 2146 } |
1863 else | 2147 else |
2148 memcpy (keymap_sticky, keymap_orig, 256); | |
2149 | |
2150 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr); | |
2151 | |
2152 /* Handle non-printables */ | |
2153 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, | |
2154 extendedp))) | |
1864 { | 2155 { |
1865 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | 2156 mswindows_enqueue_keypress_event (hwnd, keysym, mods); |
1866 msframe->last_click_point, msframe->last_click_time); | 2157 if (sticky_changed) |
1867 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | 2158 SetKeyboardState (keymap_orig); |
1868 MAKEPOINTS (lParam), GetMessageTime()); | |
1869 } | 2159 } |
2160 else /* Normal keys & modifiers */ | |
2161 { | |
2162 Emchar quit_ch = | |
2163 CONSOLE_QUIT_CHAR (XCONSOLE (mswindows_find_console (hwnd))); | |
2164 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; | |
2165 MSG msg, tranmsg; | |
2166 int potential_accelerator = 0; | |
2167 int got_accelerator = 0; | |
2168 | |
2169 msg.hwnd = hwnd; | |
2170 msg.message = message_; | |
2171 msg.wParam = wParam; | |
2172 msg.lParam = lParam; | |
2173 msg.time = GetMessageTime(); | |
2174 msg.pt = pnt; | |
2175 | |
2176 /* GetKeyboardState() does not work as documented on Win95. We have | |
2177 * to loosely track Left and Right modifiers on behalf of the OS, | |
2178 * without screwing up Windows NT which tracks them properly. */ | |
2179 if (wParam == VK_CONTROL) | |
2180 { | |
2181 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
2182 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
2183 } | |
2184 else if (wParam == VK_MENU) | |
2185 { | |
2186 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | |
2187 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | |
2188 } | |
2189 | |
2190 if (!NILP (Vmenu_accelerator_enabled) && | |
2191 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN) | |
2192 potential_accelerator = 1; | |
2193 | |
2194 /* Remove shift modifier from an ascii character */ | |
2195 mods &= ~XEMACS_MOD_SHIFT; | |
2196 | |
2197 memcpy (keymap_trans, keymap_sticky, 256); | |
2198 | |
2199 /* Clear control and alt modifiers unless AltGr is pressed */ | |
2200 keymap_trans[VK_RCONTROL] = 0; | |
2201 keymap_trans[VK_LMENU] = 0; | |
2202 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80) | |
2203 || !(keymap_trans[VK_RMENU] & 0x80)) | |
2204 { | |
2205 keymap_trans[VK_LCONTROL] = 0; | |
2206 keymap_trans[VK_CONTROL] = 0; | |
2207 keymap_trans[VK_RMENU] = 0; | |
2208 keymap_trans[VK_MENU] = 0; | |
2209 } | |
2210 SetKeyboardState (keymap_trans); | |
2211 | |
2212 /* Maybe generate some WM_[SYS]CHARs in the queue */ | |
2213 TranslateMessage (&msg); | |
2214 | |
2215 while (PeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) | |
2216 || PeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, | |
2217 PM_REMOVE)) | |
2218 { | |
2219 int mods1 = mods; | |
2220 WPARAM ch = tranmsg.wParam; | |
2221 | |
2222 /* If a quit char with no modifiers other than control and | |
2223 shift, then mark it with a fake modifier, which is removed | |
2224 upon dequeueing the event */ | |
2225 /* #### This might also not withstand localization, if | |
2226 quit character is not a latin-1 symbol */ | |
2227 if (((quit_ch < ' ' && (mods & XEMACS_MOD_CONTROL) | |
2228 && quit_ch + 'a' - 1 == ch) | |
2229 || (quit_ch >= ' ' && !(mods & XEMACS_MOD_CONTROL) | |
2230 && quit_ch == ch)) | |
2231 && ((mods & ~(XEMACS_MOD_CONTROL | XEMACS_MOD_SHIFT)) | |
2232 == 0)) | |
2233 { | |
2234 mods1 |= FAKE_MOD_QUIT; | |
2235 ++mswindows_quit_chars_count; | |
2236 } | |
2237 else if (potential_accelerator && !got_accelerator && | |
2238 mswindows_char_is_accelerator (frame, ch)) | |
2239 { | |
2240 got_accelerator = 1; | |
2241 break; | |
2242 } | |
2243 mswindows_enqueue_keypress_event (hwnd, make_char (ch), mods1); | |
2244 } /* while */ | |
2245 | |
2246 /* This generates WM_SYSCHAR messages, which are interpreted | |
2247 by DefWindowProc as the menu selections. */ | |
2248 if (got_accelerator) | |
2249 { | |
2250 SetKeyboardState (keymap_sticky); | |
2251 TranslateMessage (&msg); | |
2252 SetKeyboardState (keymap_orig); | |
2253 goto defproc; | |
2254 } | |
2255 | |
2256 SetKeyboardState (keymap_orig); | |
2257 } /* else */ | |
1870 } | 2258 } |
1871 else | 2259 |
1872 { | 2260 if (key_needs_default_processing_p (wParam)) |
1873 mswindows_set_chord_timer (hwnd); | 2261 goto defproc; |
1874 msframe->button2_need_rbutton = 1; | 2262 else |
1875 msframe->last_click_point = MAKEPOINTS (lParam); | 2263 break; |
1876 } | 2264 |
1877 msframe->last_click_time = GetMessageTime(); | 2265 case WM_MBUTTONDOWN: |
1878 break; | 2266 case WM_MBUTTONUP: |
1879 | 2267 /* Real middle mouse button has nothing to do with emulated one: |
1880 case WM_RBUTTONDOWN: | 2268 if one wants to exercise fingers playing chords on the mouse, |
1881 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 2269 he is allowed to do that! */ |
1882 | 2270 mswindows_enqueue_mouse_button_event (hwnd, message_, |
1883 if (msframe->button2_need_rbutton) | 2271 MAKEPOINTS (lParam), |
1884 { | 2272 wParam &~ MK_MBUTTON, |
1885 KillTimer (hwnd, BUTTON_2_TIMER_ID); | 2273 GetMessageTime()); |
1886 msframe->button2_need_lbutton = 0; | 2274 break; |
1887 msframe->button2_need_rbutton = 0; | 2275 |
1888 if (mswindows_button2_near_enough (msframe->last_click_point, MAKEPOINTS (lParam))) | 2276 case WM_LBUTTONUP: |
1889 { | 2277 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
1890 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | 2278 msframe->last_click_time = GetMessageTime(); |
1891 MAKEPOINTS (lParam), GetMessageTime()); | 2279 |
1892 msframe->button2_is_down = 1; | 2280 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
1893 } | 2281 msframe->button2_need_lbutton = 0; |
1894 else | 2282 if (msframe->ignore_next_lbutton_up) |
1895 { | 2283 { |
1896 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | 2284 msframe->ignore_next_lbutton_up = 0; |
1897 msframe->last_click_point, msframe->last_click_time); | 2285 } |
1898 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | 2286 else if (msframe->button2_is_down) |
1899 MAKEPOINTS (lParam), GetMessageTime()); | 2287 { |
1900 } | 2288 msframe->button2_is_down = 0; |
1901 } | 2289 msframe->ignore_next_rbutton_up = 1; |
1902 else | 2290 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, |
1903 { | 2291 MAKEPOINTS (lParam), |
1904 mswindows_set_chord_timer (hwnd); | 2292 wParam |
1905 msframe->button2_need_lbutton = 1; | 2293 &~ (MK_LBUTTON | MK_MBUTTON |
1906 msframe->last_click_point = MAKEPOINTS (lParam); | 2294 | MK_RBUTTON), |
1907 } | 2295 GetMessageTime()); |
1908 msframe->last_click_time = GetMessageTime(); | 2296 } |
1909 break; | 2297 else |
1910 | 2298 { |
1911 case WM_TIMER: | 2299 if (msframe->button2_need_rbutton) |
1912 if (wParam == BUTTON_2_TIMER_ID) | 2300 { |
1913 { | 2301 msframe->button2_need_rbutton = 0; |
1914 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 2302 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, |
1915 KillTimer (hwnd, BUTTON_2_TIMER_ID); | 2303 MAKEPOINTS (lParam), |
1916 | 2304 wParam &~ MK_LBUTTON, |
1917 if (msframe->button2_need_lbutton) | 2305 GetMessageTime()); |
1918 { | 2306 } |
1919 msframe->button2_need_lbutton = 0; | 2307 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, |
1920 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | 2308 MAKEPOINTS (lParam), |
1921 msframe->last_click_point, msframe->last_click_time); | 2309 wParam &~ MK_LBUTTON, |
1922 } | 2310 GetMessageTime()); |
1923 else if (msframe->button2_need_rbutton) | 2311 } |
1924 { | 2312 break; |
1925 msframe->button2_need_rbutton = 0; | 2313 |
1926 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | 2314 case WM_RBUTTONUP: |
1927 msframe->last_click_point, msframe->last_click_time); | 2315 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
1928 } | 2316 msframe->last_click_time = GetMessageTime(); |
1929 } | 2317 |
1930 else | 2318 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
1931 assert ("Spurious timer fired" == 0); | 2319 msframe->button2_need_rbutton = 0; |
1932 break; | 2320 if (msframe->ignore_next_rbutton_up) |
1933 | 2321 { |
1934 case WM_MOUSEMOVE: | 2322 msframe->ignore_next_rbutton_up = 0; |
1935 /* Optimization: don't report mouse movement while size is changing */ | 2323 } |
1936 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | 2324 else if (msframe->button2_is_down) |
1937 if (!msframe->sizing) | 2325 { |
1938 { | 2326 msframe->button2_is_down = 0; |
1939 /* When waiting for the second mouse button to finish | 2327 msframe->ignore_next_lbutton_up = 1; |
1940 button2 emulation, and have moved too far, just pretend | 2328 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, |
1941 as if timer has expired. This improves drag-select feedback */ | 2329 MAKEPOINTS (lParam), |
1942 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) | 2330 wParam |
1943 && !mswindows_button2_near_enough (msframe->last_click_point, | 2331 &~ (MK_LBUTTON | MK_MBUTTON |
2332 | MK_RBUTTON), | |
2333 GetMessageTime()); | |
2334 } | |
2335 else | |
2336 { | |
2337 if (msframe->button2_need_lbutton) | |
2338 { | |
2339 msframe->button2_need_lbutton = 0; | |
2340 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2341 MAKEPOINTS (lParam), | |
2342 wParam &~ MK_RBUTTON, | |
2343 GetMessageTime()); | |
2344 } | |
2345 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, | |
2346 MAKEPOINTS (lParam), | |
2347 wParam &~ MK_RBUTTON, | |
2348 GetMessageTime()); | |
2349 } | |
2350 break; | |
2351 | |
2352 case WM_LBUTTONDOWN: | |
2353 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2354 | |
2355 if (msframe->button2_need_lbutton) | |
2356 { | |
2357 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2358 msframe->button2_need_lbutton = 0; | |
2359 msframe->button2_need_rbutton = 0; | |
2360 if (mswindows_button2_near_enough (msframe->last_click_point, | |
1944 MAKEPOINTS (lParam))) | 2361 MAKEPOINTS (lParam))) |
1945 { | |
1946 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
1947 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); | |
1948 } | |
1949 | |
1950 emacs_event = Fmake_event (Qnil, Qnil); | |
1951 event = XEVENT(emacs_event); | |
1952 | |
1953 event->channel = mswindows_find_frame(hwnd); | |
1954 event->timestamp = GetMessageTime(); | |
1955 event->event_type = pointer_motion_event; | |
1956 event->event.motion.x = MAKEPOINTS(lParam).x; | |
1957 event->event.motion.y = MAKEPOINTS(lParam).y; | |
1958 event->event.motion.modifiers = mswindows_modifier_state (NULL, 0); | |
1959 | |
1960 mswindows_enqueue_dispatch_event (emacs_event); | |
1961 } | |
1962 break; | |
1963 | |
1964 case WM_CANCELMODE: | |
1965 ReleaseCapture (); | |
1966 /* Queue a `cancel-mode-internal' misc user event, so mouse | |
1967 selection would be canceled if any */ | |
1968 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), | |
1969 Qcancel_mode_internal, Qnil); | |
1970 break; | |
1971 | |
1972 case WM_NOTIFY: | |
1973 { | |
1974 LPNMHDR nmhdr = (LPNMHDR)lParam; | |
1975 | |
1976 if (nmhdr->code == TTN_NEEDTEXT) | |
1977 { | |
1978 #ifdef HAVE_TOOLBARS | |
1979 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; | |
1980 Lisp_Object btext; | |
1981 | |
1982 /* find out which toolbar */ | |
1983 frame = XFRAME (mswindows_find_frame (hwnd)); | |
1984 btext = mswindows_get_toolbar_button_text ( frame, | |
1985 nmhdr->idFrom ); | |
1986 | |
1987 tttext->lpszText = NULL; | |
1988 tttext->hinst = NULL; | |
1989 | |
1990 if (!NILP(btext)) | |
1991 { | 2362 { |
1992 /* I think this is safe since the text will only go away | 2363 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, |
1993 when the toolbar does...*/ | 2364 MAKEPOINTS (lParam), |
1994 TO_EXTERNAL_FORMAT (LISP_STRING, btext, | 2365 wParam |
1995 C_STRING_ALLOCA, tttext->lpszText, | 2366 &~ (MK_LBUTTON | MK_MBUTTON |
1996 Qnative); | 2367 | MK_RBUTTON), |
1997 } | 2368 GetMessageTime()); |
1998 #endif | 2369 msframe->button2_is_down = 1; |
1999 } | |
2000 /* handle tree view callbacks */ | |
2001 else if (nmhdr->code == TVN_SELCHANGED) | |
2002 { | |
2003 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam; | |
2004 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2005 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); | |
2006 } | |
2007 /* handle tab control callbacks */ | |
2008 else if (nmhdr->code == TCN_SELCHANGE) | |
2009 { | |
2010 TC_ITEM item; | |
2011 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); | |
2012 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2013 | |
2014 item.mask = TCIF_PARAM; | |
2015 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx, | |
2016 (LPARAM)&item); | |
2017 | |
2018 mswindows_handle_gui_wm_command (frame, 0, item.lParam); | |
2019 } | |
2020 } | |
2021 break; | |
2022 | |
2023 case WM_PAINT: | |
2024 { | |
2025 /* According to the docs we need to check GetUpdateRect() before | |
2026 actually doing a WM_PAINT */ | |
2027 if (GetUpdateRect (hwnd, NULL, FALSE)) | |
2028 { | |
2029 PAINTSTRUCT paintStruct; | |
2030 int x, y, width, height; | |
2031 | |
2032 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2033 | |
2034 BeginPaint (hwnd, &paintStruct); | |
2035 x = paintStruct.rcPaint.left; | |
2036 y = paintStruct.rcPaint.top; | |
2037 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; | |
2038 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; | |
2039 /* Normally we want to ignore expose events when child | |
2040 windows are unmapped, however once we are in the guts of | |
2041 WM_PAINT we need to make sure that we don't register | |
2042 unmaps then because they will not actually occur. */ | |
2043 if (!check_for_ignored_expose (frame, x, y, width, height)) | |
2044 { | |
2045 hold_ignored_expose_registration = 1; | |
2046 mswindows_redraw_exposed_area (frame, x, y, width, height); | |
2047 hold_ignored_expose_registration = 0; | |
2048 } | |
2049 | |
2050 EndPaint (hwnd, &paintStruct); | |
2051 } | |
2052 else | |
2053 goto defproc; | |
2054 } | |
2055 break; | |
2056 | |
2057 case WM_SIZE: | |
2058 /* We only care about this message if our size has really changed */ | |
2059 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) | |
2060 { | |
2061 RECT rect; | |
2062 int columns, rows; | |
2063 | |
2064 fobj = mswindows_find_frame (hwnd); | |
2065 frame = XFRAME (fobj); | |
2066 msframe = FRAME_MSWINDOWS_DATA (frame); | |
2067 | |
2068 /* We cannot handle frame map and unmap hooks right in | |
2069 this routine, because these may throw. We queue | |
2070 magic events to run these hooks instead - kkm */ | |
2071 | |
2072 if (wParam==SIZE_MINIMIZED) | |
2073 { | |
2074 /* Iconified */ | |
2075 FRAME_VISIBLE_P (frame) = 0; | |
2076 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
2077 } | |
2078 else | |
2079 { | |
2080 GetClientRect(hwnd, &rect); | |
2081 FRAME_PIXWIDTH(frame) = rect.right; | |
2082 FRAME_PIXHEIGHT(frame) = rect.bottom; | |
2083 | |
2084 pixel_to_real_char_size (frame, rect.right, rect.bottom, | |
2085 &FRAME_MSWINDOWS_CHARWIDTH (frame), | |
2086 &FRAME_MSWINDOWS_CHARHEIGHT (frame)); | |
2087 | |
2088 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows); | |
2089 change_frame_size (frame, rows, columns, 1); | |
2090 | |
2091 /* If we are inside frame creation, we have to apply geometric | |
2092 properties now. */ | |
2093 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
2094 { | |
2095 /* Yes, we have to size again */ | |
2096 mswindows_size_frame_internal ( frame, | |
2097 FRAME_MSWINDOWS_TARGET_RECT | |
2098 (frame)); | |
2099 /* Reset so we do not get here again. The SetWindowPos call in | |
2100 * mswindows_size_frame_internal can cause recursion here. */ | |
2101 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
2102 { | |
2103 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); | |
2104 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; | |
2105 } | |
2106 } | 2370 } |
2107 else | 2371 else |
2108 { | 2372 { |
2109 if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) | 2373 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, |
2110 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | 2374 msframe->last_click_point, |
2111 FRAME_VISIBLE_P (frame) = 1; | 2375 msframe->last_click_mods |
2112 | 2376 &~ MK_RBUTTON, |
2113 if (!msframe->sizing || mswindows_dynamic_frame_resize) | 2377 msframe->last_click_time); |
2114 redisplay (); | 2378 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, |
2379 MAKEPOINTS (lParam), | |
2380 wParam &~ MK_LBUTTON, | |
2381 GetMessageTime()); | |
2115 } | 2382 } |
2116 } | 2383 } |
2384 else | |
2385 { | |
2386 mswindows_set_chord_timer (hwnd); | |
2387 msframe->button2_need_rbutton = 1; | |
2388 msframe->last_click_point = MAKEPOINTS (lParam); | |
2389 msframe->last_click_mods = wParam; | |
2390 } | |
2391 msframe->last_click_time = GetMessageTime(); | |
2392 break; | |
2393 | |
2394 case WM_RBUTTONDOWN: | |
2395 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2396 | |
2397 if (msframe->button2_need_rbutton) | |
2398 { | |
2399 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2400 msframe->button2_need_lbutton = 0; | |
2401 msframe->button2_need_rbutton = 0; | |
2402 if (mswindows_button2_near_enough (msframe->last_click_point, | |
2403 MAKEPOINTS (lParam))) | |
2404 { | |
2405 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | |
2406 MAKEPOINTS (lParam), | |
2407 wParam | |
2408 &~ (MK_LBUTTON | MK_MBUTTON | |
2409 | MK_RBUTTON), | |
2410 GetMessageTime()); | |
2411 msframe->button2_is_down = 1; | |
2412 } | |
2413 else | |
2414 { | |
2415 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
2416 msframe->last_click_point, | |
2417 msframe->last_click_mods | |
2418 &~ MK_LBUTTON, | |
2419 msframe->last_click_time); | |
2420 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2421 MAKEPOINTS (lParam), | |
2422 wParam &~ MK_RBUTTON, | |
2423 GetMessageTime()); | |
2424 } | |
2425 } | |
2426 else | |
2427 { | |
2428 mswindows_set_chord_timer (hwnd); | |
2429 msframe->button2_need_lbutton = 1; | |
2430 msframe->last_click_point = MAKEPOINTS (lParam); | |
2431 msframe->last_click_mods = wParam; | |
2432 } | |
2433 msframe->last_click_time = GetMessageTime(); | |
2434 break; | |
2435 | |
2436 case WM_TIMER: | |
2437 if (wParam == BUTTON_2_TIMER_ID) | |
2438 { | |
2439 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2440 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2441 | |
2442 if (msframe->button2_need_lbutton) | |
2443 { | |
2444 msframe->button2_need_lbutton = 0; | |
2445 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2446 msframe->last_click_point, | |
2447 msframe->last_click_mods | |
2448 &~ MK_RBUTTON, | |
2449 msframe->last_click_time); | |
2450 } | |
2451 else if (msframe->button2_need_rbutton) | |
2452 { | |
2453 msframe->button2_need_rbutton = 0; | |
2454 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
2455 msframe->last_click_point, | |
2456 msframe->last_click_mods | |
2457 &~ MK_LBUTTON, | |
2458 msframe->last_click_time); | |
2459 } | |
2460 } | |
2461 else | |
2462 assert ("Spurious timer fired" == 0); | |
2463 break; | |
2464 | |
2465 case WM_MOUSEMOVE: | |
2466 /* Optimization: don't report mouse movement while size is changing */ | |
2467 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2468 if (!msframe->sizing) | |
2469 { | |
2470 /* When waiting for the second mouse button to finish | |
2471 button2 emulation, and have moved too far, just pretend | |
2472 as if timer has expired. This improves drag-select feedback */ | |
2473 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) | |
2474 && !mswindows_button2_near_enough (msframe->last_click_point, | |
2475 MAKEPOINTS (lParam))) | |
2476 { | |
2477 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2478 SendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); | |
2479 } | |
2480 | |
2481 emacs_event = Fmake_event (Qnil, Qnil); | |
2482 event = XEVENT(emacs_event); | |
2483 | |
2484 event->channel = mswindows_find_frame(hwnd); | |
2485 event->timestamp = GetMessageTime(); | |
2486 event->event_type = pointer_motion_event; | |
2487 event->event.motion.x = MAKEPOINTS(lParam).x; | |
2488 event->event.motion.y = MAKEPOINTS(lParam).y; | |
2489 event->event.motion.modifiers = | |
2490 mswindows_modifier_state (NULL, wParam, 0); | |
2491 | |
2492 mswindows_enqueue_dispatch_event (emacs_event); | |
2493 } | |
2494 break; | |
2495 | |
2496 case WM_CANCELMODE: | |
2497 ReleaseCapture (); | |
2498 /* Queue a `cancel-mode-internal' misc user event, so mouse | |
2499 selection would be canceled if any */ | |
2500 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), | |
2501 Qcancel_mode_internal, Qnil); | |
2502 break; | |
2503 | |
2504 case WM_NOTIFY: | |
2505 { | |
2506 LPNMHDR nmhdr = (LPNMHDR)lParam; | |
2507 | |
2508 if (nmhdr->code == TTN_NEEDTEXT) | |
2509 { | |
2510 #ifdef HAVE_TOOLBARS | |
2511 LPTOOLTIPTEXT tttext = (LPTOOLTIPTEXT)lParam; | |
2512 Lisp_Object btext; | |
2513 | |
2514 /* find out which toolbar */ | |
2515 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2516 btext = mswindows_get_toolbar_button_text ( frame, | |
2517 nmhdr->idFrom ); | |
2518 | |
2519 tttext->lpszText = NULL; | |
2520 tttext->hinst = NULL; | |
2521 | |
2522 if (!NILP(btext)) | |
2523 { | |
2524 /* I think this is safe since the text will only go away | |
2525 when the toolbar does...*/ | |
2526 LISP_STRING_TO_EXTERNAL (btext, tttext->lpszText, Qnative); | |
2527 } | |
2528 #endif | |
2529 } | |
2530 /* handle tree view callbacks */ | |
2531 else if (nmhdr->code == TVN_SELCHANGED) | |
2532 { | |
2533 NM_TREEVIEW* ptree = (NM_TREEVIEW*)lParam; | |
2534 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2535 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); | |
2536 } | |
2537 /* handle tab control callbacks */ | |
2538 else if (nmhdr->code == TCN_SELCHANGE) | |
2539 { | |
2540 TC_ITEM item; | |
2541 int idx = SendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); | |
2542 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2543 | |
2544 item.mask = TCIF_PARAM; | |
2545 SendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM)idx, | |
2546 (LPARAM)&item); | |
2547 | |
2548 mswindows_handle_gui_wm_command (frame, 0, item.lParam); | |
2549 } | |
2550 } | |
2551 break; | |
2552 | |
2553 case WM_PAINT: | |
2554 /* hdc will be NULL unless this is a subwindow - in which case we | |
2555 shouldn't have received a paint message for it here. */ | |
2556 assert (wParam == 0); | |
2557 | |
2558 /* Can't queue a magic event because windows goes modal and sends paint | |
2559 messages directly to the windows procedure when doing solid drags | |
2560 and the message queue doesn't get processed. */ | |
2561 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd))); | |
2562 break; | |
2563 | |
2564 case WM_SIZE: | |
2565 /* We only care about this message if our size has really changed */ | |
2566 if (wParam==SIZE_RESTORED || wParam==SIZE_MAXIMIZED || wParam==SIZE_MINIMIZED) | |
2567 { | |
2568 RECT rect; | |
2569 int columns, rows; | |
2570 | |
2571 fobj = mswindows_find_frame (hwnd); | |
2572 frame = XFRAME (fobj); | |
2573 msframe = FRAME_MSWINDOWS_DATA (frame); | |
2574 | |
2575 /* We cannot handle frame map and unmap hooks right in | |
2576 this routine, because these may throw. We queue | |
2577 magic events to run these hooks instead - kkm */ | |
2578 | |
2579 if (wParam==SIZE_MINIMIZED) | |
2580 { | |
2581 /* Iconified */ | |
2582 FRAME_VISIBLE_P (frame) = 0; | |
2583 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
2584 } | |
2585 else | |
2586 { | |
2587 GetClientRect(hwnd, &rect); | |
2588 FRAME_PIXWIDTH(frame) = rect.right; | |
2589 FRAME_PIXHEIGHT(frame) = rect.bottom; | |
2590 | |
2591 pixel_to_real_char_size (frame, rect.right, rect.bottom, | |
2592 &FRAME_MSWINDOWS_CHARWIDTH (frame), | |
2593 &FRAME_MSWINDOWS_CHARHEIGHT (frame)); | |
2594 | |
2595 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, &rows); | |
2596 change_frame_size (frame, rows, columns, 1); | |
2597 | |
2598 /* If we are inside frame creation, we have to apply geometric | |
2599 properties now. */ | |
2600 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
2601 { | |
2602 /* Yes, we have to size again */ | |
2603 mswindows_size_frame_internal ( frame, | |
2604 FRAME_MSWINDOWS_TARGET_RECT | |
2605 (frame)); | |
2606 /* Reset so we do not get here again. The SetWindowPos call in | |
2607 * mswindows_size_frame_internal can cause recursion here. */ | |
2608 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
2609 { | |
2610 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); | |
2611 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; | |
2612 } | |
2613 } | |
2614 else | |
2615 { | |
2616 if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) | |
2617 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
2618 FRAME_VISIBLE_P (frame) = 1; | |
2619 | |
2620 if (!msframe->sizing || mswindows_dynamic_frame_resize) | |
2621 redisplay (); | |
2622 } | |
2623 } | |
2624 } | |
2625 break; | |
2626 | |
2627 case WM_DISPLAYCHANGE: | |
2628 { | |
2629 struct device *d; | |
2630 DWORD message_tick = GetMessageTime (); | |
2631 | |
2632 fobj = mswindows_find_frame (hwnd); | |
2633 frame = XFRAME (fobj); | |
2634 d = XDEVICE (FRAME_DEVICE (frame)); | |
2635 | |
2636 /* Do this only once per message. XEmacs can receive this message | |
2637 through as many frames as it currently has open. Message time | |
2638 will be the same for all these messages. Despite extreme | |
2639 efficiency, the code below has about one in 4 billion | |
2640 probability that the HDC is not recreated, provided that | |
2641 XEmacs is running sufficiently longer than 52 days. */ | |
2642 if (DEVICE_MSWINDOWS_UPDATE_TICK(d) != message_tick) | |
2643 { | |
2644 DEVICE_MSWINDOWS_UPDATE_TICK(d) = message_tick; | |
2645 DeleteDC (DEVICE_MSWINDOWS_HCDC(d)); | |
2646 DEVICE_MSWINDOWS_HCDC(d) = CreateCompatibleDC (NULL); | |
2647 } | |
2648 } | |
2649 break; | |
2650 | |
2651 /* Misc magic events which only require that the frame be identified */ | |
2652 case WM_SETFOCUS: | |
2653 case WM_KILLFOCUS: | |
2654 mswindows_enqueue_magic_event (hwnd, message_); | |
2655 break; | |
2656 | |
2657 case WM_WINDOWPOSCHANGING: | |
2658 { | |
2659 WINDOWPOS *wp = (LPWINDOWPOS) lParam; | |
2660 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
2661 GetWindowPlacement(hwnd, &wpl); | |
2662 | |
2663 /* Only interested if size is changing and we're not being iconified */ | |
2664 if (wpl.showCmd != SW_SHOWMINIMIZED | |
2665 && wpl.showCmd != SW_SHOWMAXIMIZED | |
2666 && !(wp->flags & SWP_NOSIZE)) | |
2667 { | |
2668 RECT ncsize = { 0, 0, 0, 0 }; | |
2669 int pixwidth, pixheight; | |
2670 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE), | |
2671 GetMenu(hwnd) != NULL, | |
2672 GetWindowLong (hwnd, GWL_EXSTYLE)); | |
2673 | |
2674 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), | |
2675 wp->cx - (ncsize.right - ncsize.left), | |
2676 wp->cy - (ncsize.bottom - ncsize.top), | |
2677 &pixwidth, &pixheight); | |
2678 | |
2679 /* Convert client sizes to window sizes */ | |
2680 pixwidth += (ncsize.right - ncsize.left); | |
2681 pixheight += (ncsize.bottom - ncsize.top); | |
2682 | |
2683 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
2684 { | |
2685 /* Adjust so that the bottom or right doesn't move if it's | |
2686 * the top or left that's being changed */ | |
2687 RECT rect; | |
2688 GetWindowRect (hwnd, &rect); | |
2689 | |
2690 if (rect.left != wp->x) | |
2691 wp->x += wp->cx - pixwidth; | |
2692 if (rect.top != wp->y) | |
2693 wp->y += wp->cy - pixheight; | |
2694 } | |
2695 | |
2696 wp->cx = pixwidth; | |
2697 wp->cy = pixheight; | |
2698 } | |
2699 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts | |
2700 window position if the user tries to track window too small */ | |
2701 } | |
2702 goto defproc; | |
2703 | |
2704 case WM_ENTERSIZEMOVE: | |
2705 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2706 msframe->sizing = 1; | |
2707 return 0; | |
2708 | |
2709 case WM_EXITSIZEMOVE: | |
2710 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2711 msframe->sizing = 0; | |
2712 /* Queue noop event */ | |
2713 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
2714 return 0; | |
2715 | |
2716 #ifdef HAVE_SCROLLBARS | |
2717 case WM_VSCROLL: | |
2718 case WM_HSCROLL: | |
2719 { | |
2720 /* Direction of scroll is determined by scrollbar instance. */ | |
2721 int code = (int) LOWORD(wParam); | |
2722 int pos = (short int) HIWORD(wParam); | |
2723 HWND hwndScrollBar = (HWND) lParam; | |
2724 struct gcpro gcpro1, gcpro2; | |
2725 | |
2726 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
2727 GCPRO2 (emacs_event, fobj); | |
2728 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */ | |
2729 { | |
2730 /* Error during event pumping - cancel scroll */ | |
2731 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); | |
2732 } | |
2733 UNGCPRO; | |
2734 break; | |
2735 } | |
2736 | |
2737 case WM_MOUSEWHEEL: | |
2738 { | |
2739 int keys = LOWORD (wParam); /* Modifier key flags */ | |
2740 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ | |
2741 struct gcpro gcpro1, gcpro2; | |
2742 | |
2743 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta)) | |
2744 { | |
2745 GCPRO2 (emacs_event, fobj); | |
2746 mswindows_pump_outstanding_events (); /* Can GC */ | |
2747 UNGCPRO; | |
2748 } | |
2749 else | |
2750 goto defproc; | |
2751 break; | |
2752 } | |
2753 #endif | |
2754 | |
2755 #ifdef HAVE_MENUBARS | |
2756 case WM_INITMENU: | |
2757 if (UNBOUNDP (mswindows_handle_wm_initmenu ( | |
2758 (HMENU) wParam, | |
2759 XFRAME (mswindows_find_frame (hwnd))))) | |
2760 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2761 break; | |
2762 | |
2763 case WM_INITMENUPOPUP: | |
2764 if (!HIWORD(lParam)) | |
2765 { | |
2766 if (UNBOUNDP (mswindows_handle_wm_initmenupopup ( | |
2767 (HMENU) wParam, | |
2768 XFRAME (mswindows_find_frame (hwnd))))) | |
2769 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2770 } | |
2771 break; | |
2772 | |
2773 #endif /* HAVE_MENUBARS */ | |
2774 | |
2775 case WM_COMMAND: | |
2776 { | |
2777 WORD id = LOWORD (wParam); | |
2778 WORD nid = HIWORD (wParam); | |
2779 HWND cid = (HWND)lParam; | |
2780 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2781 | |
2782 #ifdef HAVE_TOOLBARS | |
2783 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) | |
2784 break; | |
2785 #endif | |
2786 /* widgets in a buffer only eval a callback for suitable events.*/ | |
2787 switch (nid) | |
2788 { | |
2789 case BN_CLICKED: | |
2790 case EN_CHANGE: | |
2791 case CBN_EDITCHANGE: | |
2792 case CBN_SELCHANGE: | |
2793 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) | |
2794 return 0; | |
2795 } | |
2796 /* menubars always must come last since the hashtables do not | |
2797 always exist*/ | |
2798 #ifdef HAVE_MENUBARS | |
2799 if (!NILP (mswindows_handle_wm_command (frame, id))) | |
2800 break; | |
2801 #endif | |
2802 | |
2803 return DefWindowProc (hwnd, message_, wParam, lParam); | |
2804 /* Bite me - a spurious command. This used to not be able to | |
2805 happen but with the introduction of widgets its now | |
2806 possible. */ | |
2807 } | |
2808 break; | |
2809 | |
2810 case WM_CTLCOLORBTN: | |
2811 case WM_CTLCOLORLISTBOX: | |
2812 case WM_CTLCOLOREDIT: | |
2813 case WM_CTLCOLORSTATIC: | |
2814 case WM_CTLCOLORSCROLLBAR: | |
2815 { | |
2816 /* if we get an opportunity to paint a widget then do so if | |
2817 there is an appropriate face */ | |
2818 HWND crtlwnd = (HWND)lParam; | |
2819 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA); | |
2820 if (ii) | |
2821 { | |
2822 Lisp_Object image_instance; | |
2823 VOID_TO_LISP (image_instance, ii); | |
2824 if (IMAGE_INSTANCEP (image_instance) | |
2825 && | |
2826 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) | |
2827 { | |
2828 /* set colors for the buttons */ | |
2829 HDC hdc = (HDC)wParam; | |
2830 if (last_widget_brushed != ii) | |
2831 { | |
2832 if (widget_brush) | |
2833 DeleteObject (widget_brush); | |
2834 widget_brush = CreateSolidBrush | |
2835 (COLOR_INSTANCE_MSWINDOWS_COLOR | |
2836 (XCOLOR_INSTANCE | |
2837 (FACE_BACKGROUND | |
2838 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2839 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
2840 } | |
2841 last_widget_brushed = ii; | |
2842 SetTextColor | |
2843 (hdc, | |
2844 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2845 (XCOLOR_INSTANCE | |
2846 (FACE_FOREGROUND | |
2847 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2848 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
2849 SetBkMode (hdc, OPAQUE); | |
2850 SetBkColor | |
2851 (hdc, | |
2852 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2853 (XCOLOR_INSTANCE | |
2854 (FACE_BACKGROUND | |
2855 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2856 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
2857 return (LRESULT)widget_brush; | |
2858 } | |
2859 } | |
2860 } | |
2861 goto defproc; | |
2862 | |
2863 #ifdef HAVE_DRAGNDROP | |
2864 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ | |
2865 { | |
2866 UINT filecount, i, len; | |
2867 POINT point; | |
2868 char* filename; | |
2869 char* fname; | |
2870 | |
2871 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
2872 struct gcpro gcpro1, gcpro2, gcpro3; | |
2873 | |
2874 emacs_event = Fmake_event (Qnil, Qnil); | |
2875 event = XEVENT(emacs_event); | |
2876 | |
2877 GCPRO3 (emacs_event, l_dndlist, l_item); | |
2878 | |
2879 if (!DragQueryPoint ((HDROP) wParam, &point)) | |
2880 point.x = point.y = -1; /* outside client area */ | |
2881 | |
2882 event->event_type = misc_user_event; | |
2883 event->channel = mswindows_find_frame(hwnd); | |
2884 event->timestamp = GetMessageTime(); | |
2885 event->event.misc.button = 1; /* #### Should try harder */ | |
2886 event->event.misc.modifiers = mswindows_modifier_state (NULL, | |
2887 (DWORD) -1, 0); | |
2888 event->event.misc.x = point.x; | |
2889 event->event.misc.y = point.y; | |
2890 event->event.misc.function = Qdragdrop_drop_dispatch; | |
2891 | |
2892 filecount = DragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0); | |
2893 for (i=0; i<filecount; i++) | |
2894 { | |
2895 len = DragQueryFile ((HDROP) wParam, i, NULL, 0); | |
2896 /* The URLs that we make here aren't correct according to section | |
2897 * 3.10 of rfc1738 because they're missing the //<host>/ part and | |
2898 * because they may contain reserved characters. But that's OK - | |
2899 * they just need to be good enough to keep dragdrop.el happy. */ | |
2900 fname = (char *)xmalloc (len+1); | |
2901 DragQueryFile ((HANDLE) wParam, i, fname, len+1); | |
2902 | |
2903 /* May be a shell link aka "shortcut" - replace fname if so */ | |
2904 #if !(defined(CYGWIN) || defined(MINGW)) | |
2905 /* cygwin doesn't define this COM stuff */ | |
2906 if (!stricmp (fname + strlen (fname) - 4, ".LNK")) | |
2907 { | |
2908 IShellLink* psl; | |
2909 | |
2910 if (CoCreateInstance (&CLSID_ShellLink, NULL, | |
2911 CLSCTX_INPROC_SERVER, &IID_IShellLink, &psl) == S_OK) | |
2912 { | |
2913 IPersistFile* ppf; | |
2914 | |
2915 if (psl->lpVtbl->QueryInterface (psl, &IID_IPersistFile, | |
2916 &ppf) == S_OK) | |
2917 { | |
2918 WORD wsz[MAX_PATH]; | |
2919 WIN32_FIND_DATA wfd; | |
2920 LPSTR resolved = (char *) xmalloc (MAX_PATH+1); | |
2921 | |
2922 MultiByteToWideChar (CP_ACP,0, fname, -1, wsz, MAX_PATH); | |
2923 | |
2924 if ((ppf->lpVtbl->Load (ppf, wsz, STGM_READ) == S_OK) && | |
2925 (psl->lpVtbl->GetPath (psl, resolved, MAX_PATH, | |
2926 &wfd, 0)==S_OK)) | |
2927 { | |
2928 xfree (fname); | |
2929 fname = resolved; | |
2930 len = strlen (fname); | |
2931 } | |
2932 | |
2933 ppf->lpVtbl->Release (ppf); | |
2934 } | |
2935 | |
2936 psl->lpVtbl->Release (psl); | |
2937 } | |
2938 } | |
2939 #endif | |
2940 | |
2941 #ifdef CYGWIN | |
2942 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); | |
2943 strcpy (filename, "file:"); | |
2944 cygwin32_win32_to_posix_path_list (fname, filename+5); | |
2945 #else | |
2946 filename = (char *)xmalloc (len+6); | |
2947 strcat (strcpy (filename, "file:"), fname); | |
2948 dostounix_filename (filename+5); | |
2949 #endif | |
2950 xfree (fname); | |
2951 l_item = make_string (filename, strlen (filename)); | |
2952 l_dndlist = Fcons (l_item, l_dndlist); | |
2953 xfree (filename); | |
2954 } | |
2955 DragFinish ((HDROP) wParam); | |
2956 | |
2957 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist); | |
2958 mswindows_enqueue_dispatch_event (emacs_event); | |
2959 UNGCPRO; | |
2960 } | |
2961 break; | |
2962 #endif | |
2963 | |
2964 defproc: | |
2965 default: | |
2966 return DefWindowProc (hwnd, message_, wParam, lParam); | |
2117 } | 2967 } |
2118 break; | |
2119 | |
2120 /* Misc magic events which only require that the frame be identified */ | |
2121 case WM_SETFOCUS: | |
2122 case WM_KILLFOCUS: | |
2123 mswindows_enqueue_magic_event (hwnd, message); | |
2124 break; | |
2125 | |
2126 case WM_WINDOWPOSCHANGING: | |
2127 { | |
2128 WINDOWPOS *wp = (LPWINDOWPOS) lParam; | |
2129 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
2130 GetWindowPlacement(hwnd, &wpl); | |
2131 | |
2132 /* Only interested if size is changing and we're not being iconified */ | |
2133 if (wpl.showCmd != SW_SHOWMINIMIZED | |
2134 && wpl.showCmd != SW_SHOWMAXIMIZED | |
2135 && !(wp->flags & SWP_NOSIZE)) | |
2136 { | |
2137 RECT ncsize = { 0, 0, 0, 0 }; | |
2138 int pixwidth, pixheight; | |
2139 AdjustWindowRectEx (&ncsize, GetWindowLong (hwnd, GWL_STYLE), | |
2140 GetMenu(hwnd) != NULL, | |
2141 GetWindowLong (hwnd, GWL_EXSTYLE)); | |
2142 | |
2143 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), | |
2144 wp->cx - (ncsize.right - ncsize.left), | |
2145 wp->cy - (ncsize.bottom - ncsize.top), | |
2146 &pixwidth, &pixheight); | |
2147 | |
2148 /* Convert client sizes to window sizes */ | |
2149 pixwidth += (ncsize.right - ncsize.left); | |
2150 pixheight += (ncsize.bottom - ncsize.top); | |
2151 | |
2152 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
2153 { | |
2154 /* Adjust so that the bottom or right doesn't move if it's | |
2155 * the top or left that's being changed */ | |
2156 RECT rect; | |
2157 GetWindowRect (hwnd, &rect); | |
2158 | |
2159 if (rect.left != wp->x) | |
2160 wp->x += wp->cx - pixwidth; | |
2161 if (rect.top != wp->y) | |
2162 wp->y += wp->cy - pixheight; | |
2163 } | |
2164 | |
2165 wp->cx = pixwidth; | |
2166 wp->cy = pixheight; | |
2167 } | |
2168 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts | |
2169 window position if the user tries to track window too small */ | |
2170 } | |
2171 goto defproc; | |
2172 | |
2173 case WM_ENTERSIZEMOVE: | |
2174 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2175 msframe->sizing = 1; | |
2176 return 0; | |
2177 | |
2178 case WM_EXITSIZEMOVE: | |
2179 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
2180 msframe->sizing = 0; | |
2181 /* Queue noop event */ | |
2182 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
2183 return 0; | |
2184 | |
2185 #ifdef HAVE_SCROLLBARS | |
2186 case WM_VSCROLL: | |
2187 case WM_HSCROLL: | |
2188 { | |
2189 /* Direction of scroll is determined by scrollbar instance. */ | |
2190 int code = (int) LOWORD(wParam); | |
2191 int pos = (short int) HIWORD(wParam); | |
2192 HWND hwndScrollBar = (HWND) lParam; | |
2193 struct gcpro gcpro1, gcpro2; | |
2194 | |
2195 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
2196 GCPRO2 (emacs_event, fobj); | |
2197 if (UNBOUNDP(mswindows_pump_outstanding_events())) /* Can GC */ | |
2198 { | |
2199 /* Error during event pumping - cancel scroll */ | |
2200 SendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); | |
2201 } | |
2202 UNGCPRO; | |
2203 break; | |
2204 } | |
2205 | |
2206 case WM_MOUSEWHEEL: | |
2207 { | |
2208 int keys = LOWORD (wParam); /* Modifier key flags */ | |
2209 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ | |
2210 struct gcpro gcpro1, gcpro2; | |
2211 | |
2212 if (mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), keys, delta)) | |
2213 { | |
2214 GCPRO2 (emacs_event, fobj); | |
2215 mswindows_pump_outstanding_events (); /* Can GC */ | |
2216 UNGCPRO; | |
2217 } | |
2218 else | |
2219 goto defproc; | |
2220 break; | |
2221 } | |
2222 #endif | |
2223 | |
2224 #ifdef HAVE_MENUBARS | |
2225 case WM_INITMENU: | |
2226 if (UNBOUNDP (mswindows_handle_wm_initmenu ( | |
2227 (HMENU) wParam, | |
2228 XFRAME (mswindows_find_frame (hwnd))))) | |
2229 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2230 break; | |
2231 | |
2232 case WM_INITMENUPOPUP: | |
2233 if (!HIWORD(lParam)) | |
2234 { | |
2235 if (UNBOUNDP (mswindows_handle_wm_initmenupopup ( | |
2236 (HMENU) wParam, | |
2237 XFRAME (mswindows_find_frame (hwnd))))) | |
2238 SendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
2239 } | |
2240 break; | |
2241 | |
2242 #endif /* HAVE_MENUBARS */ | |
2243 | |
2244 case WM_COMMAND: | |
2245 { | |
2246 WORD id = LOWORD (wParam); | |
2247 WORD nid = HIWORD (wParam); | |
2248 HWND cid = (HWND)lParam; | |
2249 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2250 | |
2251 #ifdef HAVE_TOOLBARS | |
2252 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) | |
2253 break; | |
2254 #endif | |
2255 /* widgets in a buffer only eval a callback for suitable events.*/ | |
2256 switch (nid) | |
2257 { | |
2258 case BN_CLICKED: | |
2259 case EN_CHANGE: | |
2260 case CBN_EDITCHANGE: | |
2261 case CBN_SELCHANGE: | |
2262 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) | |
2263 return 0; | |
2264 } | |
2265 /* menubars always must come last since the hashtables do not | |
2266 always exist*/ | |
2267 #ifdef HAVE_MENUBARS | |
2268 if (!NILP (mswindows_handle_wm_command (frame, id))) | |
2269 break; | |
2270 #endif | |
2271 | |
2272 return DefWindowProc (hwnd, message, wParam, lParam); | |
2273 /* Bite me - a spurious command. This used to not be able to | |
2274 happen but with the introduction of widgets its now | |
2275 possible. */ | |
2276 } | |
2277 break; | |
2278 | |
2279 case WM_CTLCOLORBTN: | |
2280 case WM_CTLCOLORLISTBOX: | |
2281 case WM_CTLCOLOREDIT: | |
2282 case WM_CTLCOLORSTATIC: | |
2283 case WM_CTLCOLORSCROLLBAR: | |
2284 { | |
2285 /* if we get an opportunity to paint a widget then do so if | |
2286 there is an appropriate face */ | |
2287 HWND crtlwnd = (HWND)lParam; | |
2288 LONG ii = GetWindowLong (crtlwnd, GWL_USERDATA); | |
2289 if (ii) | |
2290 { | |
2291 Lisp_Object image_instance; | |
2292 VOID_TO_LISP (image_instance, ii); | |
2293 if (IMAGE_INSTANCEP (image_instance) | |
2294 && | |
2295 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) | |
2296 { | |
2297 /* set colors for the buttons */ | |
2298 HDC hdc = (HDC)wParam; | |
2299 if (last_widget_brushed != ii) | |
2300 { | |
2301 if (widget_brush) | |
2302 DeleteObject (widget_brush); | |
2303 widget_brush = CreateSolidBrush | |
2304 (COLOR_INSTANCE_MSWINDOWS_COLOR | |
2305 (XCOLOR_INSTANCE | |
2306 (FACE_BACKGROUND | |
2307 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2308 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); | |
2309 } | |
2310 last_widget_brushed = ii; | |
2311 SetTextColor | |
2312 (hdc, | |
2313 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2314 (XCOLOR_INSTANCE | |
2315 (FACE_FOREGROUND | |
2316 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2317 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); | |
2318 SetBkMode (hdc, OPAQUE); | |
2319 SetBkColor | |
2320 (hdc, | |
2321 COLOR_INSTANCE_MSWINDOWS_COLOR | |
2322 (XCOLOR_INSTANCE | |
2323 (FACE_BACKGROUND | |
2324 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
2325 XIMAGE_INSTANCE_SUBWINDOW_FRAME (image_instance))))); | |
2326 return (LRESULT)widget_brush; | |
2327 } | |
2328 } | |
2329 } | |
2330 goto defproc; | |
2331 | |
2332 #ifdef HAVE_DRAGNDROP | |
2333 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ | |
2334 { | |
2335 UINT filecount, i, len; | |
2336 POINT point; | |
2337 char* filename; | |
2338 #ifdef __CYGWIN32__ | |
2339 char* fname; | |
2340 #endif | |
2341 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
2342 struct gcpro gcpro1, gcpro2, gcpro3; | |
2343 | |
2344 emacs_event = Fmake_event (Qnil, Qnil); | |
2345 event = XEVENT(emacs_event); | |
2346 | |
2347 GCPRO3 (emacs_event, l_dndlist, l_item); | |
2348 | |
2349 if (!DragQueryPoint ((HANDLE) wParam, &point)) | |
2350 point.x = point.y = -1; /* outside client area */ | |
2351 | |
2352 event->event_type = misc_user_event; | |
2353 event->channel = mswindows_find_frame(hwnd); | |
2354 event->timestamp = GetMessageTime(); | |
2355 event->event.misc.button = 1; /* #### Should try harder */ | |
2356 event->event.misc.modifiers = mswindows_modifier_state (NULL, 0); | |
2357 event->event.misc.x = point.x; | |
2358 event->event.misc.y = point.y; | |
2359 event->event.misc.function = Qdragdrop_drop_dispatch; | |
2360 | |
2361 filecount = DragQueryFile ((HANDLE) wParam, 0xffffffff, NULL, 0); | |
2362 for (i=0; i<filecount; i++) | |
2363 { | |
2364 len = DragQueryFile ((HANDLE) wParam, i, NULL, 0); | |
2365 /* The URLs that we make here aren't correct according to section | |
2366 * 3.10 of rfc1738 because they're missing the //<host>/ part and | |
2367 * because they may contain reserved characters. But that's OK. */ | |
2368 #ifdef __CYGWIN32__ | |
2369 fname = (char *)xmalloc (len+1); | |
2370 DragQueryFile ((HANDLE) wParam, i, fname, len+1); | |
2371 filename = xmalloc (cygwin32_win32_to_posix_path_list_buf_size (fname) + 5); | |
2372 strcpy (filename, "file:"); | |
2373 cygwin32_win32_to_posix_path_list (fname, filename+5); | |
2374 xfree (fname); | |
2375 #else | |
2376 filename = (char *)xmalloc (len+6); | |
2377 strcpy (filename, "file:"); | |
2378 DragQueryFile ((HANDLE) wParam, i, filename+5, len+1); | |
2379 dostounix_filename (filename+5); | |
2380 #endif | |
2381 l_item = make_string (filename, strlen (filename)); | |
2382 l_dndlist = Fcons (l_item, l_dndlist); | |
2383 xfree (filename); | |
2384 } | |
2385 DragFinish ((HANDLE) wParam); | |
2386 | |
2387 event->event.misc.object = Fcons (Qdragdrop_URL, l_dndlist); | |
2388 mswindows_enqueue_dispatch_event (emacs_event); | |
2389 UNGCPRO; | |
2390 } | |
2391 break; | |
2392 #endif | |
2393 | |
2394 defproc: | |
2395 default: | |
2396 return DefWindowProc (hwnd, message, wParam, lParam); | |
2397 } | |
2398 return (0); | 2968 return (0); |
2399 } | 2969 } |
2400 | 2970 |
2401 | 2971 |
2402 /************************************************************************/ | 2972 /************************************************************************/ |
2438 { | 3008 { |
2439 /* This simple caching mechanism saves 10% of CPU | 3009 /* This simple caching mechanism saves 10% of CPU |
2440 time when a key typed at autorepeat rate of 30 cps! */ | 3010 time when a key typed at autorepeat rate of 30 cps! */ |
2441 static HKL last_hkl = 0; | 3011 static HKL last_hkl = 0; |
2442 static int last_hkl_has_AltGr; | 3012 static int last_hkl_has_AltGr; |
2443 | 3013 HKL current_hkl = (HKL) -1; |
2444 HKL current_hkl = GetKeyboardLayout (0); | 3014 |
3015 if (xGetKeyboardLayout) /* not in NT 3.5 */ | |
3016 current_hkl = xGetKeyboardLayout (0); | |
2445 if (current_hkl != last_hkl) | 3017 if (current_hkl != last_hkl) |
2446 { | 3018 { |
2447 TCHAR c; | 3019 TCHAR c; |
2448 last_hkl_has_AltGr = 0; | 3020 last_hkl_has_AltGr = 0; |
2449 /* In this loop, we query whether a character requires | 3021 /* In this loop, we query whether a character requires |
2458 } | 3030 } |
2459 | 3031 |
2460 | 3032 |
2461 /* Returns the state of the modifier keys in the format expected by the | 3033 /* Returns the state of the modifier keys in the format expected by the |
2462 * Lisp_Event key_data, button_data and motion_data modifiers member */ | 3034 * Lisp_Event key_data, button_data and motion_data modifiers member */ |
2463 int mswindows_modifier_state (BYTE* keymap, int has_AltGr) | 3035 static int |
3036 mswindows_modifier_state (BYTE* keymap, DWORD fwKeys, int has_AltGr) | |
2464 { | 3037 { |
2465 int mods = 0; | 3038 int mods = 0; |
3039 int keys_is_real = 0; | |
3040 BYTE keymap2[256]; | |
3041 | |
3042 if (fwKeys == (DWORD) -1) | |
3043 fwKeys = mswindows_last_mouse_button_state; | |
3044 else | |
3045 { | |
3046 keys_is_real = 1; | |
3047 mswindows_last_mouse_button_state = fwKeys; | |
3048 } | |
2466 | 3049 |
2467 if (keymap == NULL) | 3050 if (keymap == NULL) |
2468 { | 3051 { |
2469 keymap = (BYTE*) alloca(256); | 3052 keymap = keymap2; |
2470 GetKeyboardState (keymap); | 3053 GetKeyboardState (keymap); |
2471 has_AltGr = mswindows_current_layout_has_AltGr (); | 3054 has_AltGr = mswindows_current_layout_has_AltGr (); |
2472 } | 3055 } |
2473 | 3056 |
3057 /* #### should look at fwKeys for MK_CONTROL. I don't understand how | |
3058 AltGr works. */ | |
2474 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) | 3059 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) |
2475 { | 3060 { |
2476 mods |= (keymap [VK_LMENU] & 0x80) ? MOD_META : 0; | 3061 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0; |
2477 mods |= (keymap [VK_RCONTROL] & 0x80) ? MOD_CONTROL : 0; | 3062 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; |
2478 } | 3063 } |
2479 else | 3064 else |
2480 { | 3065 { |
2481 mods |= (keymap [VK_MENU] & 0x80) ? MOD_META : 0; | 3066 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0; |
2482 mods |= (keymap [VK_CONTROL] & 0x80) ? MOD_CONTROL : 0; | 3067 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; |
2483 } | 3068 } |
2484 | 3069 |
2485 mods |= (keymap [VK_SHIFT] & 0x80) ? MOD_SHIFT : 0; | 3070 mods |= (keys_is_real ? fwKeys & MK_SHIFT : (keymap [VK_SHIFT] & 0x80)) |
3071 ? XEMACS_MOD_SHIFT : 0; | |
3072 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0; | |
3073 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0; | |
3074 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0; | |
2486 | 3075 |
2487 return mods; | 3076 return mods; |
2488 } | 3077 } |
2489 | 3078 |
2490 /* | 3079 /* |
2491 * Translate a mswindows virtual key to a keysym. | 3080 * Translate a mswindows virtual key to a keysym. |
2492 * Only returns non-Qnil for keys that don't generate WM_CHAR messages | 3081 * Only returns non-Qnil for keys that don't generate WM_CHAR messages |
2493 * or whose ASCII codes (like space) xemacs doesn't like. | 3082 * or whose ASCII codes (like space) xemacs doesn't like. |
2494 * Virtual key values are defined in winresrc.h | |
2495 */ | 3083 */ |
2496 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, | 3084 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, |
2497 int extendedp) | 3085 int extendedp) |
2498 { | 3086 { |
2499 if (extendedp) /* Keys not present on a 82 key keyboard */ | 3087 if (extendedp) /* Keys not present on a 82 key keyboard */ |
2500 { | 3088 { |
2501 switch (mswindows_key) | 3089 switch (mswindows_key) |
2502 { | 3090 { |
3091 case VK_CANCEL: return KEYSYM ("pause"); | |
2503 case VK_RETURN: return KEYSYM ("kp-enter"); | 3092 case VK_RETURN: return KEYSYM ("kp-enter"); |
2504 case VK_PRIOR: return KEYSYM ("prior"); | 3093 case VK_PRIOR: return KEYSYM ("prior"); |
2505 case VK_NEXT: return KEYSYM ("next"); | 3094 case VK_NEXT: return KEYSYM ("next"); |
2506 case VK_END: return KEYSYM ("end"); | 3095 case VK_END: return KEYSYM ("end"); |
2507 case VK_HOME: return KEYSYM ("home"); | 3096 case VK_HOME: return KEYSYM ("home"); |
2509 case VK_UP: return KEYSYM ("up"); | 3098 case VK_UP: return KEYSYM ("up"); |
2510 case VK_RIGHT: return KEYSYM ("right"); | 3099 case VK_RIGHT: return KEYSYM ("right"); |
2511 case VK_DOWN: return KEYSYM ("down"); | 3100 case VK_DOWN: return KEYSYM ("down"); |
2512 case VK_INSERT: return KEYSYM ("insert"); | 3101 case VK_INSERT: return KEYSYM ("insert"); |
2513 case VK_DELETE: return QKdelete; | 3102 case VK_DELETE: return QKdelete; |
3103 #if 0 /* FSF Emacs allows these to return configurable syms/mods */ | |
3104 case VK_LWIN return KEYSYM (""); | |
3105 case VK_RWIN return KEYSYM (""); | |
3106 #endif | |
3107 case VK_APPS: return KEYSYM ("menu"); | |
2514 } | 3108 } |
2515 } | 3109 } |
2516 else | 3110 else |
2517 { | 3111 { |
2518 switch (mswindows_key) | 3112 switch (mswindows_key) |
2520 case VK_BACK: return QKbackspace; | 3114 case VK_BACK: return QKbackspace; |
2521 case VK_TAB: return QKtab; | 3115 case VK_TAB: return QKtab; |
2522 case '\n': return QKlinefeed; | 3116 case '\n': return QKlinefeed; |
2523 case VK_CLEAR: return KEYSYM ("clear"); | 3117 case VK_CLEAR: return KEYSYM ("clear"); |
2524 case VK_RETURN: return QKreturn; | 3118 case VK_RETURN: return QKreturn; |
3119 case VK_PAUSE: return KEYSYM ("pause"); | |
2525 case VK_ESCAPE: return QKescape; | 3120 case VK_ESCAPE: return QKescape; |
2526 case VK_SPACE: return QKspace; | 3121 case VK_SPACE: return QKspace; |
2527 case VK_PRIOR: return KEYSYM ("kp-prior"); | 3122 case VK_PRIOR: return KEYSYM ("kp-prior"); |
2528 case VK_NEXT: return KEYSYM ("kp-next"); | 3123 case VK_NEXT: return KEYSYM ("kp-next"); |
2529 case VK_END: return KEYSYM ("kp-end"); | 3124 case VK_END: return KEYSYM ("kp-end"); |
2537 case VK_EXECUTE: return KEYSYM ("execute"); | 3132 case VK_EXECUTE: return KEYSYM ("execute"); |
2538 case VK_SNAPSHOT: return KEYSYM ("print"); | 3133 case VK_SNAPSHOT: return KEYSYM ("print"); |
2539 case VK_INSERT: return KEYSYM ("kp-insert"); | 3134 case VK_INSERT: return KEYSYM ("kp-insert"); |
2540 case VK_DELETE: return KEYSYM ("kp-delete"); | 3135 case VK_DELETE: return KEYSYM ("kp-delete"); |
2541 case VK_HELP: return KEYSYM ("help"); | 3136 case VK_HELP: return KEYSYM ("help"); |
2542 #if 0 /* FSF Emacs allows these to return configurable syms/mods */ | |
2543 case VK_LWIN return KEYSYM (""); | |
2544 case VK_RWIN return KEYSYM (""); | |
2545 #endif | |
2546 case VK_APPS: return KEYSYM ("menu"); | |
2547 case VK_NUMPAD0: return KEYSYM ("kp-0"); | 3137 case VK_NUMPAD0: return KEYSYM ("kp-0"); |
2548 case VK_NUMPAD1: return KEYSYM ("kp-1"); | 3138 case VK_NUMPAD1: return KEYSYM ("kp-1"); |
2549 case VK_NUMPAD2: return KEYSYM ("kp-2"); | 3139 case VK_NUMPAD2: return KEYSYM ("kp-2"); |
2550 case VK_NUMPAD3: return KEYSYM ("kp-3"); | 3140 case VK_NUMPAD3: return KEYSYM ("kp-3"); |
2551 case VK_NUMPAD4: return KEYSYM ("kp-4"); | 3141 case VK_NUMPAD4: return KEYSYM ("kp-4"); |
2700 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) | 3290 switch (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event)) |
2701 { | 3291 { |
2702 case XM_BUMPQUEUE: | 3292 case XM_BUMPQUEUE: |
2703 break; | 3293 break; |
2704 | 3294 |
3295 case WM_PAINT: | |
3296 { | |
3297 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); | |
3298 mswindows_handle_paint (f); | |
3299 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0; | |
3300 } | |
3301 break; | |
3302 | |
2705 case WM_SETFOCUS: | 3303 case WM_SETFOCUS: |
2706 case WM_KILLFOCUS: | 3304 case WM_KILLFOCUS: |
2707 { | 3305 { |
2708 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | 3306 Lisp_Object frame = EVENT_CHANNEL (emacs_event); |
2709 struct frame *f = XFRAME (frame); | 3307 struct frame *f = XFRAME (frame); |
2710 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); | 3308 int in_p = (EVENT_MSWINDOWS_MAGIC_TYPE(emacs_event) == WM_SETFOCUS); |
2711 Lisp_Object conser; | 3309 Lisp_Object conser; |
2712 | 3310 struct gcpro gcpro1; |
2713 /* struct gcpro gcpro1; */ | 3311 |
2714 | 3312 /* On focus change, clear all memory of sticky modifiers |
2715 /* Clear sticky modifiers here (if we had any) */ | 3313 to avoid non-intuitive behavior. */ |
3314 clear_sticky_modifiers (); | |
2716 | 3315 |
2717 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); | 3316 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); |
2718 /* GCPRO1 (conser); XXX Not necessary? */ | 3317 GCPRO1 (conser); |
2719 emacs_handle_focus_change_preliminary (conser); | 3318 emacs_handle_focus_change_preliminary (conser); |
2720 /* Under X the stuff up to here is done in the X event handler. | 3319 /* Under X the stuff up to here is done in the X event handler. |
2721 I Don't know why */ | 3320 I Don't know why */ |
2722 emacs_handle_focus_change_final (conser); | 3321 emacs_handle_focus_change_final (conser); |
2723 /* UNGCPRO; */ | 3322 UNGCPRO; |
2724 | 3323 |
2725 } | 3324 } |
2726 break; | 3325 break; |
2727 | 3326 |
2728 case XM_MAPFRAME: | 3327 case XM_MAPFRAME: |
2758 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT) | 3357 #if defined (HAVE_SOCKETS) && !defined(HAVE_MSG_SELECT) |
2759 return (network_connection_p (p) | 3358 return (network_connection_p (p) |
2760 ? get_winsock_stream_waitable (XLSTREAM (instr)) | 3359 ? get_winsock_stream_waitable (XLSTREAM (instr)) |
2761 : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); | 3360 : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); |
2762 #else | 3361 #else |
2763 return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); | 3362 return get_ntpipe_input_stream_waitable (XLSTREAM (instr)); |
2764 #endif | 3363 #endif |
2765 } | 3364 } |
2766 | 3365 |
2767 static void | 3366 static void |
2768 emacs_mswindows_select_process (Lisp_Process *process) | 3367 emacs_mswindows_select_process (Lisp_Process *process) |
2829 if (mswindows_in_modal_loop) | 3428 if (mswindows_in_modal_loop) |
2830 return; | 3429 return; |
2831 | 3430 |
2832 /* Drain windows queue. This sets up number of quit characters in | 3431 /* Drain windows queue. This sets up number of quit characters in |
2833 the queue */ | 3432 the queue */ |
2834 mswindows_drain_windows_queue (1); | 3433 mswindows_drain_windows_queue (); |
2835 | 3434 |
2836 if (mswindows_quit_chars_count > 0) | 3435 if (mswindows_quit_chars_count > 0) |
2837 { | 3436 { |
2838 /* Yes there's a hidden one... Throw it away */ | 3437 /* Yes there's a hidden one... Throw it away */ |
2839 Lisp_Event match_against; | 3438 Lisp_Event match_against; |
2845 | 3444 |
2846 while (mswindows_quit_chars_count-- > 0) | 3445 while (mswindows_quit_chars_count-- > 0) |
2847 { | 3446 { |
2848 emacs_event = mswindows_cancel_dispatch_event (&match_against); | 3447 emacs_event = mswindows_cancel_dispatch_event (&match_against); |
2849 assert (!NILP (emacs_event)); | 3448 assert (!NILP (emacs_event)); |
2850 | 3449 |
2851 if (XEVENT(emacs_event)->event.key.modifiers & MOD_SHIFT) | 3450 if (XEVENT(emacs_event)->event.key.modifiers & XEMACS_MOD_SHIFT) |
2852 critical_p = 1; | 3451 critical_p = 1; |
2853 | 3452 |
2854 Fdeallocate_event(emacs_event); | 3453 Fdeallocate_event(emacs_event); |
2855 } | 3454 } |
2856 | 3455 |
2930 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream)))); | 3529 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (*instream)))); |
2931 } | 3530 } |
2932 | 3531 |
2933 USID | 3532 USID |
2934 emacs_mswindows_delete_stream_pair (Lisp_Object instream, | 3533 emacs_mswindows_delete_stream_pair (Lisp_Object instream, |
2935 Lisp_Object outstream) | 3534 Lisp_Object outstream) |
2936 { | 3535 { |
2937 /* Oh nothing special here for Win32 at all */ | 3536 /* Oh nothing special here for Win32 at all */ |
2938 #if defined (HAVE_UNIX_PROCESSES) | 3537 #if defined (HAVE_UNIX_PROCESSES) |
2939 int in = (NILP(instream) | 3538 int in = (NILP(instream) |
2940 ? -1 | 3539 ? -1 |
2959 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream))) | 3558 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream))) |
2960 #endif | 3559 #endif |
2961 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream)))); | 3560 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM (instream)))); |
2962 } | 3561 } |
2963 | 3562 |
3563 static int | |
3564 emacs_mswindows_current_event_timestamp (struct console *c) | |
3565 { | |
3566 return GetTickCount (); | |
3567 } | |
3568 | |
2964 #ifndef HAVE_X_WINDOWS | 3569 #ifndef HAVE_X_WINDOWS |
2965 /* This is called from GC when a process object is about to be freed. | 3570 /* This is called from GC when a process object is about to be freed. |
2966 If we've still got pointers to it in this file, we're gonna lose hard. | 3571 If we've still got pointers to it in this file, we're gonna lose hard. |
2967 */ | 3572 */ |
2968 void | 3573 void |
2992 mswindows_pending_timers_count = 0; | 3597 mswindows_pending_timers_count = 0; |
2993 | 3598 |
2994 mswindows_event_stream = xnew (struct event_stream); | 3599 mswindows_event_stream = xnew (struct event_stream); |
2995 | 3600 |
2996 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; | 3601 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; |
3602 mswindows_event_stream->force_event_pending = 0; | |
2997 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; | 3603 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; |
2998 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; | 3604 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; |
2999 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; | 3605 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; |
3000 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; | 3606 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; |
3001 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p; | 3607 mswindows_event_stream->quit_p_cb = emacs_mswindows_quit_p; |
3012 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; | 3618 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; |
3013 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; | 3619 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; |
3014 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair; | 3620 mswindows_event_stream->create_stream_pair_cb = emacs_mswindows_create_stream_pair; |
3015 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair; | 3621 mswindows_event_stream->delete_stream_pair_cb = emacs_mswindows_delete_stream_pair; |
3016 #endif | 3622 #endif |
3623 mswindows_event_stream->current_event_timestamp_cb = | |
3624 emacs_mswindows_current_event_timestamp; | |
3017 } | 3625 } |
3018 | 3626 |
3019 void | 3627 void |
3020 vars_of_event_mswindows (void) | 3628 vars_of_event_mswindows (void) |
3021 { | 3629 { |
3032 pdump_wire (&mswindows_s_dispatch_event_queue_tail); | 3640 pdump_wire (&mswindows_s_dispatch_event_queue_tail); |
3033 | 3641 |
3034 mswindows_error_caught_in_modal_loop = Qnil; | 3642 mswindows_error_caught_in_modal_loop = Qnil; |
3035 staticpro (&mswindows_error_caught_in_modal_loop); | 3643 staticpro (&mswindows_error_caught_in_modal_loop); |
3036 | 3644 |
3037 DEFVAR_BOOL ("mswindows-meta-activates-menu", &mswindows_meta_activates_menu /* | 3645 |
3038 *Controls whether pressing and releasing the Meta (Alt) key should | 3646 #ifdef DEBUG_XEMACS |
3039 activate the menubar. | 3647 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /* |
3648 If non-zero, display debug information about Windows events that XEmacs sees. | |
3649 Information is displayed in a console window. Currently defined values are: | |
3650 | |
3651 1 == non-verbose output | |
3652 2 == verbose output | |
3653 | |
3654 #### Unfortunately, not yet implemented. | |
3655 */ ); | |
3656 debug_mswindows_events = 0; | |
3657 #endif | |
3658 | |
3659 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu", | |
3660 &mswindows_alt_by_itself_activates_menu /* | |
3661 *Controls whether pressing and releasing the Alt key activates the menubar. | |
3662 This applies only if no intervening key was pressed. See also | |
3663 `menu-accelerator-enabled', which is probably the behavior you actually want. | |
3040 Default is t. | 3664 Default is t. |
3041 */ ); | 3665 */ ); |
3042 | 3666 |
3043 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", &mswindows_dynamic_frame_resize /* | 3667 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", |
3668 &mswindows_dynamic_frame_resize /* | |
3044 *Controls redrawing frame contents during mouse-drag or keyboard resize | 3669 *Controls redrawing frame contents during mouse-drag or keyboard resize |
3045 operation. When non-nil, the frame is redrawn while being resized. When | 3670 operation. When non-nil, the frame is redrawn while being resized. When |
3046 nil, frame is not redrawn, and exposed areas are filled with default | 3671 nil, frame is not redrawn, and exposed areas are filled with default |
3047 MDI application background color. Note that this option only has effect | 3672 MDI application background color. Note that this option only has effect |
3048 if "Show window contents while dragging" is on in system Display/Plus! | 3673 if "Show window contents while dragging" is on in system Display/Plus! |
3049 settings. | 3674 settings. |
3050 Default is t on fast machines, nil on slow. | 3675 Default is t on fast machines, nil on slow. |
3051 */ ); | 3676 */ ); |
3052 | 3677 |
3053 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */ | 3678 DEFVAR_INT ("mswindows-mouse-button-tolerance", |
3054 DEFVAR_INT ("mswindows-mouse-button-tolerance", &mswindows_mouse_button_tolerance /* | 3679 &mswindows_mouse_button_tolerance /* |
3055 *Analogue of double click interval for faking middle mouse events. | 3680 *Analogue of double click interval for faking middle mouse events. |
3056 The value is the minimum time in milliseconds that must elapse between | 3681 The value is the minimum time in milliseconds that must elapse between |
3057 left/right button down events before they are considered distinct events. | 3682 left/right button down events before they are considered distinct events. |
3058 If both mouse buttons are depressed within this interval, a middle mouse | 3683 If both mouse buttons are depressed within this interval, a middle mouse |
3059 button down event is generated instead. | 3684 button down event is generated instead. |
3060 If negative or zero, currently set system default is used instead. | 3685 If negative or zero, currently set system default is used instead. |
3061 */ ); | 3686 */ ); |
3062 | 3687 |
3063 /* The description copied verbatim from nt-emacs. (C) Geoff Voelker */ | |
3064 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /* | 3688 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /* |
3065 Number of physical mouse buttons. | 3689 Number of physical mouse buttons. |
3066 */ ); | 3690 */ ); |
3067 | 3691 |
3068 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", &mswindows_mouse_button_max_skew_x /* | 3692 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", |
3693 &mswindows_mouse_button_max_skew_x /* | |
3069 *Maximum horizontal distance in pixels between points in which left and | 3694 *Maximum horizontal distance in pixels between points in which left and |
3070 right button clicks occurred for them to be translated into single | 3695 right button clicks occurred for them to be translated into single |
3071 middle button event. Clicks must occur in time not longer than defined | 3696 middle button event. Clicks must occur in time not longer than defined |
3072 by the variable `mswindows-mouse-button-tolerance'. | 3697 by the variable `mswindows-mouse-button-tolerance'. |
3073 If negative or zero, currently set system default is used instead. | 3698 If negative or zero, currently set system default is used instead. |
3074 */ ); | 3699 */ ); |
3075 | 3700 |
3076 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", &mswindows_mouse_button_max_skew_y /* | 3701 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", |
3702 &mswindows_mouse_button_max_skew_y /* | |
3077 *Maximum vertical distance in pixels between points in which left and | 3703 *Maximum vertical distance in pixels between points in which left and |
3078 right button clicks occurred for them to be translated into single | 3704 right button clicks occurred for them to be translated into single |
3079 middle button event. Clicks must occur in time not longer than defined | 3705 middle button event. Clicks must occur in time not longer than defined |
3080 by the variable `mswindows-mouse-button-tolerance'. | 3706 by the variable `mswindows-mouse-button-tolerance'. |
3081 If negative or zero, currently set system default is used instead. | 3707 If negative or zero, currently set system default is used instead. |
3082 */ ); | 3708 */ ); |
3083 | 3709 |
3084 mswindows_mouse_button_max_skew_x = 0; | 3710 mswindows_mouse_button_max_skew_x = 0; |
3085 mswindows_mouse_button_max_skew_y = 0; | 3711 mswindows_mouse_button_max_skew_y = 0; |
3086 mswindows_mouse_button_tolerance = 0; | 3712 mswindows_mouse_button_tolerance = 0; |
3087 mswindows_meta_activates_menu = 1; | 3713 mswindows_alt_by_itself_activates_menu = 1; |
3088 } | 3714 } |
3089 | 3715 |
3090 void | 3716 void |
3091 syms_of_event_mswindows (void) | 3717 syms_of_event_mswindows (void) |
3092 { | 3718 { |