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 {