Mercurial > hg > xemacs-beta
annotate src/event-msw.c @ 5043:d0c14ea98592
various frame-geometry fixes
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-02-15 Ben Wing <ben@xemacs.org>
* EmacsFrame.c:
* EmacsFrame.c (EmacsFrameResize):
* console-msw-impl.h:
* console-msw-impl.h (struct mswindows_frame):
* console-msw-impl.h (FRAME_MSWINDOWS_TARGET_RECT):
* device-tty.c:
* device-tty.c (tty_asynch_device_change):
* event-msw.c:
* event-msw.c (mswindows_wnd_proc):
* faces.c (Fface_list):
* faces.h:
* frame-gtk.c:
* frame-gtk.c (gtk_set_initial_frame_size):
* frame-gtk.c (gtk_set_frame_size):
* frame-msw.c:
* frame-msw.c (mswindows_init_frame_1):
* frame-msw.c (mswindows_set_frame_size):
* frame-msw.c (mswindows_size_frame_internal):
* frame-msw.c (msprinter_init_frame_3):
* frame.c:
* frame.c (enum):
* frame.c (Fmake_frame):
* frame.c (adjust_frame_size):
* frame.c (store_minibuf_frame_prop):
* frame.c (Fframe_property):
* frame.c (Fframe_properties):
* frame.c (Fframe_displayable_pixel_height):
* frame.c (Fframe_displayable_pixel_width):
* frame.c (internal_set_frame_size):
* frame.c (Fset_frame_height):
* frame.c (Fset_frame_pixel_height):
* frame.c (Fset_frame_displayable_pixel_height):
* frame.c (Fset_frame_width):
* frame.c (Fset_frame_pixel_width):
* frame.c (Fset_frame_displayable_pixel_width):
* frame.c (Fset_frame_size):
* frame.c (Fset_frame_pixel_size):
* frame.c (Fset_frame_displayable_pixel_size):
* frame.c (frame_conversion_internal_1):
* frame.c (get_frame_displayable_pixel_size):
* frame.c (change_frame_size_1):
* frame.c (change_frame_size):
* frame.c (generate_title_string):
* frame.h:
* gtk-xemacs.c:
* gtk-xemacs.c (gtk_xemacs_size_request):
* gtk-xemacs.c (gtk_xemacs_size_allocate):
* gtk-xemacs.c (gtk_xemacs_paint):
* gutter.c:
* gutter.c (update_gutter_geometry):
* redisplay.c (end_hold_frame_size_changes):
* redisplay.c (redisplay_frame):
* toolbar.c:
* toolbar.c (update_frame_toolbars_geometry):
* window.c:
* window.c (frame_pixsize_valid_p):
* window.c (check_frame_size):
Various fixes to frame geometry to make it a bit easier to understand
and fix some bugs.
1. IMPORTANT: Some renamings. Will need to be applied carefully to
the carbon repository, in the following order:
-- pixel_to_char_size -> pixel_to_frame_unit_size
-- char_to_pixel_size -> frame_unit_to_pixel_size
-- pixel_to_real_char_size -> pixel_to_char_size
-- char_to_real_pixel_size -> char_to_pixel_size
-- Reverse second and third arguments of change_frame_size() and
change_frame_size_1() to try to make functions consistent in
putting width before height.
-- Eliminate old round_size_to_char, because it didn't really
do anything differently from round_size_to_real_char()
-- round_size_to_real_char -> round_size_to_char; any places that
called the old round_size_to_char should just call the new one.
2. IMPORTANT FOR CARBON: The set_frame_size() method is now passed
sizes in "frame units", like all other frame-sizing functions,
rather than some hacked-up combination of char-cell units and
total pixel size. This only affects window systems that use
"pixelated geometry", and I'm not sure if Carbon is one of them.
MS Windows is pixelated, X and GTK are not. For pixelated-geometry
systems, the size in set_frame_size() is in displayable pixels
rather than total pixels and needs to be converted appropriately;
take a look at the changes made to mswindows_set_frame_size()
method if necessary.
3. Add a big long comment in frame.c describing how frame geometry
works.
4. Remove MS Windows-specific character height and width fields,
duplicative and unused.
5. frame-displayable-pixel-* and set-frame-displayable-pixel-*
didn't use to work on MS Windows, but they do now.
6. In general, clean up the handling of "pixelated geometry" so
that fewer functions have to worry about this. This is really
an abomination that should be removed entirely but that will
have to happen later. Fix some buggy code in
frame_conversion_internal() that happened to "work" because it
was countered by oppositely buggy code in change_frame_size().
7. Clean up some frame-size code in toolbar.c and use functions
already provided in frame.c instead of rolling its own.
8. Fix check_frame_size() in window.c, which formerly didn't take
pixelated geometry into account.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 15 Feb 2010 22:14:11 -0600 |
parents | ae48681c47fa |
children | 8b2f75cecb89 |
rev | line source |
---|---|
442 | 1 /* The mswindows event_stream interface. |
428 | 2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. |
3 Copyright (C) 1995 Sun Microsystems, Inc. | |
5043 | 4 Copyright (C) 1996, 2000, 2001, 2002, 2003, 2005, 2010 Ben Wing. |
428 | 5 Copyright (C) 1997 Jonathan Harris. |
6 | |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* Synched up with: Not in FSF. */ | |
25 | |
771 | 26 /* This file essentially Mule-ized (except perhaps some Unicode splitting). |
27 5-2000. */ | |
28 | |
428 | 29 /* Authorship: |
30 | |
31 Ultimately based on FSF. | |
32 Rewritten by Ben Wing. | |
33 Rewritten for mswindows by Jonathan Harris, November 1997 for 21.0. | |
34 Subprocess and modal loop support by Kirill M. Katsnelson. | |
35 */ | |
36 | |
771 | 37 #define NEED_MSWINDOWS_SHLOBJ /* for IShellLink */ |
38 | |
428 | 39 #include <config.h> |
40 #include "lisp.h" | |
41 | |
2286 | 42 #ifdef CYGWIN |
43 # define USED_IF_CYGWIN(decl) decl | |
44 # define UNUSED_IF_CYGWIN(decl) UNUSED (decl) | |
45 #else | |
46 # define USED_IF_CYGWIN(decl) UNUSED (decl) | |
47 # define UNUSED_IF_CYGWIN(decl) decl | |
48 #endif | |
49 | |
853 | 50 #if defined (CYGWIN) && !defined (HAVE_MSG_SELECT) |
51 #error We do not support non-select() versions (i.e. very old) of Cygwin. | |
52 #endif | |
53 | |
54 /* Acceptable are: | |
55 | |
56 WIN32_NATIVE and HAVE_WIN32_PROCESSES and nothing else | |
57 | |
58 CYGWIN and HAVE_MSG_SELECT and HAVE_UNIX_PROCESSES and nothing else | |
59 */ | |
60 #ifdef WIN32_NATIVE | |
856 | 61 # if !(defined (HAVE_WIN32_PROCESSES) && !defined (HAVE_UNIX_PROCESSES) && !defined (HAVE_MSG_SELECT) && !defined (CYGWIN)) |
853 | 62 # error Something is wrong with your process definitions for Windows native. |
63 # endif | |
64 #elif defined (CYGWIN) | |
65 # if !(defined (HAVE_UNIX_PROCESSES) && defined (HAVE_MSG_SELECT) && !defined (HAVE_WIN32_PROCESSES) && !defined (WIN32_NATIVE)) | |
66 # error Something is wrong with your process definitions for Cygwin. | |
67 # endif | |
68 #else | |
69 # error Something is wrong -- you are neither Windows native (possibly MinGW) nor Cygwin. | |
70 #endif | |
71 | |
800 | 72 #include "buffer.h" |
872 | 73 #include "device-impl.h" |
800 | 74 #include "events.h" |
75 #include "faces.h" | |
872 | 76 #include "frame-impl.h" |
800 | 77 #include "glyphs.h" |
78 #include "lstream.h" | |
79 #include "process.h" | |
80 #include "redisplay.h" | |
81 #include "sysdep.h" | |
82 #include "window.h" | |
83 | |
1204 | 84 #include "console-stream-impl.h" |
872 | 85 #include "console-msw-impl.h" |
86 #include "objects-msw-impl.h" | |
428 | 87 |
88 #ifdef HAVE_SCROLLBARS | |
89 # include "scrollbar-msw.h" | |
90 #endif | |
91 | |
92 #ifdef HAVE_MENUBARS | |
442 | 93 # include "menubar.h" |
428 | 94 #endif |
95 | |
96 #ifdef HAVE_DRAGNDROP | |
97 # include "dragdrop.h" | |
98 #endif | |
99 | |
558 | 100 #include "sysfile.h" |
428 | 101 #include "sysproc.h" |
558 | 102 #include "systime.h" |
428 | 103 #include "syswait.h" |
104 | |
105 #ifdef HAVE_MENUBARS | |
106 #define ADJR_MENUFLAG TRUE | |
107 #else | |
108 #define ADJR_MENUFLAG FALSE | |
109 #endif | |
110 | |
111 /* Timer ID used for button2 emulation */ | |
112 #define BUTTON_2_TIMER_ID 1 | |
113 | |
114 static Lisp_Object mswindows_find_console (HWND hwnd); | |
115 static Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, int mods, | |
116 int extendedp); | |
771 | 117 static int mswindows_modifier_state (BYTE *keymap, DWORD fwKeys, |
442 | 118 int has_AltGr); |
428 | 119 static void mswindows_set_chord_timer (HWND hwnd); |
120 static int mswindows_button2_near_enough (POINTS p1, POINTS p2); | |
121 static int mswindows_current_layout_has_AltGr (void); | |
442 | 122 static int mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, |
123 int downp, int keyp); | |
428 | 124 |
125 static struct event_stream *mswindows_event_stream; | |
126 | |
853 | 127 #ifdef CYGWIN |
128 | |
428 | 129 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
130 extern SELECT_TYPE process_only_mask, tty_only_mask; | |
131 SELECT_TYPE zero_mask; | |
132 extern int signal_event_pipe_initialized; | |
133 int windows_fd; | |
853 | 134 |
135 #else | |
136 | |
856 | 137 /* The number of things we can wait on */ |
138 #define MAX_WAITABLE (MAXIMUM_WAIT_OBJECTS - 1) | |
139 | |
853 | 140 /* List of mswindows waitable handles. */ |
141 static HANDLE mswindows_waitable_handles[MAX_WAITABLE]; | |
142 | |
143 /* Number of wait handles */ | |
144 static int mswindows_waitable_count = 0; | |
145 | |
428 | 146 #endif |
147 | |
148 /* | |
1204 | 149 * We use an additional queue, as well as the normal dispatch queue, for |
150 * efficiency, the normal one for user events, and another (_s_) for non-user | |
151 * ones. We always return events out of the first one until it is empty and | |
152 * only then proceed with the second one. | |
428 | 153 */ |
1204 | 154 static Lisp_Object mswindows_s_dispatch_event_queue; |
155 static Lisp_Object mswindows_s_dispatch_event_queue_tail; | |
428 | 156 |
157 /* Brush for painting widgets */ | |
158 static HBRUSH widget_brush = 0; | |
159 static LONG last_widget_brushed = 0; | |
160 | |
161 /* These are Lisp integers; see DEFVARS in this file for description. */ | |
162 int mswindows_dynamic_frame_resize; | |
442 | 163 int mswindows_alt_by_itself_activates_menu; |
458 | 164 Fixnum mswindows_num_mouse_buttons; |
165 Fixnum mswindows_mouse_button_max_skew_x; | |
166 Fixnum mswindows_mouse_button_max_skew_y; | |
167 Fixnum mswindows_mouse_button_tolerance; | |
428 | 168 |
442 | 169 #ifdef DEBUG_XEMACS |
458 | 170 Fixnum debug_mswindows_events; |
593 | 171 |
172 static void debug_output_mswin_message (HWND hwnd, UINT message_, | |
173 WPARAM wParam, LPARAM lParam); | |
442 | 174 #endif |
175 | |
428 | 176 /* This is the event signaled by the event pump. |
177 See mswindows_pump_outstanding_events for comments */ | |
853 | 178 static int mswindows_error_caught_in_modal_loop; |
428 | 179 |
180 /* Count of wound timers */ | |
181 static int mswindows_pending_timers_count; | |
442 | 182 |
183 static DWORD mswindows_last_mouse_button_state; | |
853 | 184 |
1292 | 185 extern int mswindows_is_blocking; |
186 | |
428 | 187 |
853 | 188 #ifndef CYGWIN /* Skips past slurp, shove, or winsock streams */ |
189 | |
428 | 190 /************************************************************************/ |
191 /* Pipe instream - reads process output */ | |
192 /************************************************************************/ | |
193 | |
194 #define PIPE_READ_DELAY 20 | |
195 | |
196 #define HANDLE_TO_USID(h) ((USID)(h)) | |
197 | |
198 #define NTPIPE_SLURP_STREAM_DATA(stream) \ | |
199 LSTREAM_TYPE_DATA (stream, ntpipe_slurp) | |
200 | |
201 /* This structure is allocated by the main thread, and is deallocated | |
202 in the thread upon exit. There are situations when a thread | |
203 remains blocked for a long time, much longer than the lstream | |
204 exists. For example, "start notepad" command is issued from the | |
205 shell, then the shell is closed by C-c C-d. Although the shell | |
206 process exits, its output pipe will not get closed until the | |
656 | 207 notepad process exits also, because it inherits the pipe from the |
428 | 208 shell. In this case, we abandon the thread, and let it live until |
209 all such processes exit. While struct ntpipe_slurp_stream is | |
210 deallocated in this case, ntpipe_slurp_stream_shared_data are not. */ | |
211 | |
212 struct ntpipe_slurp_stream_shared_data | |
213 { | |
214 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | |
853 | 215 /* This is a manual-reset object. */ |
428 | 216 HANDLE hev_caller; /* Caller blocks on this, and we signal it */ |
853 | 217 /* This is a manual-reset object. */ |
428 | 218 HANDLE hev_unsleep; /* Pipe read delay is canceled if this is set */ |
853 | 219 /* This is a manual-reset object. */ |
428 | 220 HANDLE hpipe; /* Pipe read end handle. */ |
221 LONG die_p; /* Thread must exit ASAP if non-zero */ | |
222 BOOL eof_p : 1; /* Set when thread saw EOF */ | |
223 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | |
224 BOOL inuse_p : 1; /* this structure is in use */ | |
225 LONG lock_count; /* Client count of this struct, 0=safe to free */ | |
226 BYTE onebyte; /* One byte buffer read by thread */ | |
227 }; | |
228 | |
229 #define MAX_SLURP_STREAMS 32 | |
230 struct ntpipe_slurp_stream_shared_data | |
231 shared_data_block[MAX_SLURP_STREAMS]={{0}}; | |
232 | |
233 struct ntpipe_slurp_stream | |
234 { | |
235 LPARAM user_data; /* Any user data stored in the stream object */ | |
771 | 236 struct ntpipe_slurp_stream_shared_data *thread_data; |
428 | 237 }; |
238 | |
771 | 239 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-input", ntpipe_slurp); |
428 | 240 |
241 /* This function is thread-safe, and is called from either thread | |
242 context. It serializes freeing shared data structure */ | |
243 static void | |
771 | 244 slurper_free_shared_data_maybe (struct ntpipe_slurp_stream_shared_data *s) |
428 | 245 { |
246 if (InterlockedDecrement (&s->lock_count) == 0) | |
247 { | |
248 /* Destroy events */ | |
249 CloseHandle (s->hev_thread); | |
250 CloseHandle (s->hev_caller); | |
251 CloseHandle (s->hev_unsleep); | |
673 | 252 CloseHandle (s->hpipe); |
428 | 253 s->inuse_p = 0; |
254 } | |
255 } | |
256 | |
771 | 257 static struct ntpipe_slurp_stream_shared_data * |
442 | 258 slurper_allocate_shared_data (void) |
428 | 259 { |
260 int i=0; | |
771 | 261 for (i = 0; i < MAX_SLURP_STREAMS; i++) |
428 | 262 { |
263 if (!shared_data_block[i].inuse_p) | |
264 { | |
771 | 265 shared_data_block[i].inuse_p = 1; |
428 | 266 return &shared_data_block[i]; |
267 } | |
268 } | |
771 | 269 return (struct ntpipe_slurp_stream_shared_data *)0; |
428 | 270 } |
271 | |
272 static DWORD WINAPI | |
273 slurp_thread (LPVOID vparam) | |
274 { | |
275 struct ntpipe_slurp_stream_shared_data *s = | |
771 | 276 (struct ntpipe_slurp_stream_shared_data *)vparam; |
428 | 277 |
278 for (;;) | |
279 { | |
280 /* Read one byte from the pipe */ | |
281 DWORD actually_read; | |
282 if (!ReadFile (s->hpipe, &s->onebyte, 1, &actually_read, NULL)) | |
283 { | |
284 DWORD err = GetLastError (); | |
285 if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) | |
286 s->eof_p = TRUE; | |
287 else | |
288 s->error_p = TRUE; | |
289 } | |
290 else if (actually_read == 0) | |
291 s->eof_p = TRUE; | |
292 | |
293 /* We must terminate on an error or eof */ | |
294 if (s->eof_p || s->error_p) | |
295 InterlockedIncrement (&s->die_p); | |
296 | |
297 /* Before we notify caller, we unsignal our event. */ | |
298 ResetEvent (s->hev_thread); | |
299 | |
300 /* Now we got something to notify caller, either a byte or an | |
301 error/eof indication. Before we do, allow internal pipe | |
302 buffer to accumulate little bit more data. | |
303 Reader function pulses this event before waiting for | |
304 a character, to avoid pipe delay, and to get the byte | |
305 immediately. */ | |
306 if (!s->die_p) | |
307 WaitForSingleObject (s->hev_unsleep, PIPE_READ_DELAY); | |
308 | |
309 /* Either make event loop generate a process event, or | |
310 inblock reader */ | |
311 SetEvent (s->hev_caller); | |
312 | |
313 /* Cleanup and exit if we're shot off */ | |
314 if (s->die_p) | |
315 break; | |
316 | |
317 /* Block until the client finishes with retrieving the rest of | |
318 pipe data */ | |
319 WaitForSingleObject (s->hev_thread, INFINITE); | |
320 } | |
321 | |
322 slurper_free_shared_data_maybe (s); | |
323 | |
324 return 0; | |
325 } | |
326 | |
327 static Lisp_Object | |
328 make_ntpipe_input_stream (HANDLE hpipe, LPARAM param) | |
329 { | |
330 Lstream *lstr = Lstream_new (lstream_ntpipe_slurp, "r"); | |
771 | 331 struct ntpipe_slurp_stream *s = NTPIPE_SLURP_STREAM_DATA (lstr); |
428 | 332 DWORD thread_id_unused; |
333 HANDLE hthread; | |
334 | |
335 /* We deal only with pipes, for we're using PeekNamedPipe api */ | |
336 assert (GetFileType (hpipe) == FILE_TYPE_PIPE); | |
337 | |
338 s->thread_data = slurper_allocate_shared_data(); | |
339 | |
340 /* Create reader thread. This could fail, so do not create events | |
341 until thread is created */ | |
342 hthread = CreateThread (NULL, 0, slurp_thread, (LPVOID)s->thread_data, | |
343 CREATE_SUSPENDED, &thread_id_unused); | |
344 if (hthread == NULL) | |
345 { | |
346 Lstream_delete (lstr); | |
347 s->thread_data->inuse_p=0; | |
348 return Qnil; | |
349 } | |
350 | |
351 /* Shared data are initially owned by both main and slurper | |
352 threads. */ | |
353 s->thread_data->lock_count = 2; | |
354 s->thread_data->die_p = 0; | |
355 s->thread_data->eof_p = FALSE; | |
356 s->thread_data->error_p = FALSE; | |
357 s->thread_data->hpipe = hpipe; | |
358 s->user_data = param; | |
359 | |
360 /* hev_thread is a manual-reset event, initially signaled */ | |
771 | 361 s->thread_data->hev_thread = qxeCreateEvent (NULL, TRUE, TRUE, NULL); |
428 | 362 /* hev_caller is a manual-reset event, initially nonsignaled */ |
771 | 363 s->thread_data->hev_caller = qxeCreateEvent (NULL, TRUE, FALSE, NULL); |
428 | 364 /* hev_unsleep is a manual-reset event, initially nonsignaled */ |
771 | 365 s->thread_data->hev_unsleep = qxeCreateEvent (NULL, TRUE, FALSE, NULL); |
428 | 366 |
367 /* Now let it go */ | |
368 ResumeThread (hthread); | |
369 CloseHandle (hthread); | |
370 | |
371 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; | |
793 | 372 return wrap_lstream (lstr); |
428 | 373 } |
374 | |
375 static LPARAM | |
376 get_ntpipe_input_stream_param (Lstream *stream) | |
377 { | |
771 | 378 struct ntpipe_slurp_stream *s = NTPIPE_SLURP_STREAM_DATA(stream); |
428 | 379 return s->user_data; |
380 } | |
381 | |
382 static HANDLE | |
383 get_ntpipe_input_stream_waitable (Lstream *stream) | |
384 { | |
771 | 385 struct ntpipe_slurp_stream *s = NTPIPE_SLURP_STREAM_DATA(stream); |
428 | 386 return s->thread_data->hev_caller; |
387 } | |
388 | |
665 | 389 static Bytecount |
462 | 390 ntpipe_slurp_reader (Lstream *stream, unsigned char *data, |
665 | 391 Bytecount size) |
428 | 392 { |
393 /* This function must be called from the main thread only */ | |
771 | 394 struct ntpipe_slurp_stream_shared_data *s = |
428 | 395 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; |
396 | |
397 if (!s->die_p) | |
398 { | |
399 DWORD wait_result; | |
400 /* Disallow pipe read delay for the thread: we need a character | |
401 ASAP */ | |
402 SetEvent (s->hev_unsleep); | |
403 | |
404 /* Check if we have a character ready. Give it a short delay, | |
771 | 405 for the thread to awake from pipe delay, just ion case */ |
428 | 406 wait_result = WaitForSingleObject (s->hev_caller, 2); |
407 | |
408 /* Revert to the normal sleep behavior. */ | |
409 ResetEvent (s->hev_unsleep); | |
410 | |
411 /* If there's no byte buffered yet, give up */ | |
412 if (wait_result == WAIT_TIMEOUT) | |
413 { | |
414 errno = EAGAIN; | |
415 return -1; | |
416 } | |
417 } | |
418 | |
419 /* Reset caller unlock event now, as we've handled the pending | |
420 process output event */ | |
421 ResetEvent (s->hev_caller); | |
422 | |
423 /* It is now safe to do anything with contents of S, except for | |
424 changing s->die_p, which still should be interlocked */ | |
425 | |
426 if (s->eof_p) | |
427 return 0; | |
428 if (s->error_p || s->die_p) | |
429 return -1; | |
430 | |
431 /* Ok, there were no error neither eof - we've got a byte from the | |
432 pipe */ | |
433 *(data++) = s->onebyte; | |
434 --size; | |
435 | |
436 { | |
437 DWORD bytes_read = 0; | |
438 if (size > 0) | |
439 { | |
440 DWORD bytes_available; | |
441 | |
442 /* If the api call fails, return at least one byte already | |
443 read. ReadFile in thread will return error */ | |
444 if (PeekNamedPipe (s->hpipe, NULL, 0, NULL, &bytes_available, NULL)) | |
445 { | |
446 | |
447 /* Fetch available bytes. The same consideration applies, | |
448 so do not check for errors. ReadFile in the thread will | |
449 fail if the next call fails. */ | |
450 if (bytes_available) | |
647 | 451 ReadFile (s->hpipe, data, min (bytes_available, (DWORD) size), |
428 | 452 &bytes_read, NULL); |
453 } | |
454 | |
455 /* Now we can unblock thread, so it attempts to read more */ | |
456 SetEvent (s->hev_thread); | |
457 return bytes_read + 1; | |
458 } | |
459 } | |
460 return 0; | |
461 } | |
462 | |
463 static int | |
464 ntpipe_slurp_closer (Lstream *stream) | |
465 { | |
466 /* This function must be called from the main thread only */ | |
771 | 467 struct ntpipe_slurp_stream_shared_data *s = |
428 | 468 NTPIPE_SLURP_STREAM_DATA(stream)->thread_data; |
469 | |
470 /* Force thread to stop */ | |
471 InterlockedIncrement (&s->die_p); | |
472 | |
473 /* Set events which could possibly block slurper. Let it finish soon | |
474 or later. */ | |
475 SetEvent (s->hev_unsleep); | |
476 SetEvent (s->hev_thread); | |
477 | |
478 /* Unlock and maybe free shared data */ | |
479 slurper_free_shared_data_maybe (s); | |
480 | |
481 return 0; | |
482 } | |
483 | |
484 static void | |
485 init_slurp_stream (void) | |
486 { | |
487 LSTREAM_HAS_METHOD (ntpipe_slurp, reader); | |
488 LSTREAM_HAS_METHOD (ntpipe_slurp, closer); | |
489 } | |
853 | 490 |
428 | 491 |
492 /************************************************************************/ | |
493 /* Pipe outstream - writes process input */ | |
494 /************************************************************************/ | |
495 | |
496 #define NTPIPE_SHOVE_STREAM_DATA(stream) \ | |
497 LSTREAM_TYPE_DATA (stream, ntpipe_shove) | |
498 | |
442 | 499 #define MAX_SHOVE_BUFFER_SIZE 512 |
428 | 500 |
501 struct ntpipe_shove_stream | |
502 { | |
503 LPARAM user_data; /* Any user data stored in the stream object */ | |
504 HANDLE hev_thread; /* Our thread blocks on this, signaled by caller */ | |
853 | 505 /* This is an auto-reset object. */ |
428 | 506 HANDLE hpipe; /* Pipe write end handle. */ |
507 HANDLE hthread; /* Reader thread handle. */ | |
508 char buffer[MAX_SHOVE_BUFFER_SIZE]; /* Buffer being written */ | |
509 DWORD size; /* Number of bytes to write */ | |
510 LONG die_p; /* Thread must exit ASAP if non-zero */ | |
511 LONG idle_p; /* Non-zero if thread is waiting for job */ | |
512 BOOL error_p : 1; /* Read error other than EOF/broken pipe */ | |
513 BOOL blocking_p : 1;/* Last write attempt would cause blocking */ | |
514 }; | |
515 | |
771 | 516 DEFINE_LSTREAM_IMPLEMENTATION ("ntpipe-output", ntpipe_shove); |
428 | 517 |
518 static DWORD WINAPI | |
519 shove_thread (LPVOID vparam) | |
520 { | |
771 | 521 struct ntpipe_shove_stream *s = (struct ntpipe_shove_stream *) vparam; |
428 | 522 |
523 for (;;) | |
524 { | |
525 DWORD bytes_written; | |
526 | |
527 /* Block on event and wait for a job */ | |
528 InterlockedIncrement (&s->idle_p); | |
529 WaitForSingleObject (s->hev_thread, INFINITE); | |
530 | |
771 | 531 if (s->die_p) |
532 break; | |
533 | |
442 | 534 /* Write passed buffer if any */ |
535 if (s->size > 0) | |
428 | 536 { |
442 | 537 if (!WriteFile (s->hpipe, s->buffer, s->size, &bytes_written, NULL) |
538 || bytes_written != s->size) | |
539 { | |
540 s->error_p = TRUE; | |
541 InterlockedIncrement (&s->die_p); | |
542 } | |
543 /* Set size to zero so we won't write it again if the closer sets | |
544 die_p and kicks us */ | |
545 s->size = 0; | |
428 | 546 } |
547 | |
548 if (s->die_p) | |
549 break; | |
550 } | |
551 | |
552 return 0; | |
553 } | |
554 | |
555 static Lisp_Object | |
556 make_ntpipe_output_stream (HANDLE hpipe, LPARAM param) | |
557 { | |
558 Lstream *lstr = Lstream_new (lstream_ntpipe_shove, "w"); | |
771 | 559 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA (lstr); |
428 | 560 DWORD thread_id_unused; |
561 | |
562 s->die_p = 0; | |
563 s->error_p = FALSE; | |
564 s->hpipe = hpipe; | |
565 s->user_data = param; | |
566 | |
567 /* Create reader thread. This could fail, so do not | |
568 create the event until thread is created */ | |
569 s->hthread = CreateThread (NULL, 0, shove_thread, (LPVOID)s, | |
570 CREATE_SUSPENDED, &thread_id_unused); | |
571 if (s->hthread == NULL) | |
572 { | |
573 Lstream_delete (lstr); | |
574 return Qnil; | |
575 } | |
576 | |
442 | 577 /* Set the priority of the thread higher so we don't end up waiting |
578 on it to send things. */ | |
579 if (!SetThreadPriority (s->hthread, THREAD_PRIORITY_HIGHEST)) | |
580 { | |
581 CloseHandle (s->hthread); | |
582 Lstream_delete (lstr); | |
583 return Qnil; | |
584 } | |
585 | |
428 | 586 /* hev_thread is an auto-reset event, initially nonsignaled */ |
771 | 587 s->hev_thread = qxeCreateEvent (NULL, FALSE, FALSE, NULL); |
428 | 588 |
589 /* Now let it go */ | |
590 ResumeThread (s->hthread); | |
591 | |
592 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; | |
793 | 593 return wrap_lstream (lstr); |
428 | 594 } |
595 | |
596 static LPARAM | |
597 get_ntpipe_output_stream_param (Lstream *stream) | |
598 { | |
771 | 599 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 600 return s->user_data; |
601 } | |
602 | |
665 | 603 static Bytecount |
462 | 604 ntpipe_shove_writer (Lstream *stream, const unsigned char *data, |
665 | 605 Bytecount size) |
428 | 606 { |
771 | 607 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 608 |
609 if (s->error_p) | |
610 return -1; | |
611 | |
612 s->blocking_p = !s->idle_p; | |
613 if (s->blocking_p) | |
614 return 0; | |
615 | |
616 if (size>MAX_SHOVE_BUFFER_SIZE) | |
617 return 0; | |
618 | |
619 memcpy (s->buffer, data, size); | |
620 s->size = size; | |
621 | |
622 /* Start output */ | |
623 InterlockedDecrement (&s->idle_p); | |
624 SetEvent (s->hev_thread); | |
442 | 625 /* Give it a chance to run -- this dramatically improves performance |
626 of things like crypt. */ | |
771 | 627 if (xSwitchToThread) /* not in Win9x */ |
442 | 628 (void) xSwitchToThread (); |
428 | 629 return size; |
630 } | |
631 | |
632 static int | |
633 ntpipe_shove_was_blocked_p (Lstream *stream) | |
634 { | |
771 | 635 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 636 return s->blocking_p; |
637 } | |
638 | |
639 static int | |
640 ntpipe_shove_closer (Lstream *stream) | |
641 { | |
771 | 642 struct ntpipe_shove_stream *s = NTPIPE_SHOVE_STREAM_DATA(stream); |
428 | 643 |
644 /* Force thread stop */ | |
645 InterlockedIncrement (&s->die_p); | |
646 | |
771 | 647 /* Close pipe handle, possibly breaking it */ |
648 CloseHandle (s->hpipe); | |
649 | |
442 | 650 /* Thread will end upon unblocking. If it's already unblocked this will |
651 do nothing, but the thread won't look at die_p until it's written any | |
652 pending output. */ | |
428 | 653 SetEvent (s->hev_thread); |
654 | |
655 /* Wait while thread terminates */ | |
656 WaitForSingleObject (s->hthread, INFINITE); | |
442 | 657 |
658 /* Close the thread handle */ | |
428 | 659 CloseHandle (s->hthread); |
660 | |
661 /* Destroy the event */ | |
662 CloseHandle (s->hev_thread); | |
663 | |
664 return 0; | |
665 } | |
666 | |
667 static void | |
668 init_shove_stream (void) | |
669 { | |
670 LSTREAM_HAS_METHOD (ntpipe_shove, writer); | |
671 LSTREAM_HAS_METHOD (ntpipe_shove, was_blocked_p); | |
672 LSTREAM_HAS_METHOD (ntpipe_shove, closer); | |
673 } | |
674 | |
675 /************************************************************************/ | |
676 /* Winsock I/O stream */ | |
677 /************************************************************************/ | |
678 | |
679 #define WINSOCK_READ_BUFFER_SIZE 1024 | |
680 | |
681 struct winsock_stream | |
682 { | |
683 LPARAM user_data; /* Any user data stored in the stream object */ | |
684 SOCKET s; /* Socket handle (which is a Win32 handle) */ | |
685 OVERLAPPED ov; /* Overlapped I/O structure */ | |
647 | 686 void *buffer; /* Buffer. */ |
687 DWORD bufsize; /* Number of bytes last read */ | |
1204 | 688 DWORD charbpos; /* Position in buffer for next fetch */ |
428 | 689 unsigned int error_p :1; /* I/O Error seen */ |
690 unsigned int eof_p :1; /* EOF Error seen */ | |
691 unsigned int pending_p :1; /* There is a pending I/O operation */ | |
692 unsigned int blocking_p :1; /* Last write attempt would block */ | |
693 }; | |
694 | |
695 #define WINSOCK_STREAM_DATA(stream) LSTREAM_TYPE_DATA (stream, winsock) | |
696 | |
771 | 697 DEFINE_LSTREAM_IMPLEMENTATION ("winsock", winsock); |
428 | 698 |
699 static void | |
700 winsock_initiate_read (struct winsock_stream *str) | |
701 { | |
702 ResetEvent (str->ov.hEvent); | |
665 | 703 str->charbpos = 0; |
428 | 704 |
705 if (!ReadFile ((HANDLE)str->s, str->buffer, WINSOCK_READ_BUFFER_SIZE, | |
706 &str->bufsize, &str->ov)) | |
707 { | |
708 if (GetLastError () == ERROR_IO_PENDING) | |
709 str->pending_p = 1; | |
710 else if (GetLastError () == ERROR_HANDLE_EOF) | |
711 str->eof_p = 1; | |
712 else | |
713 str->error_p = 1; | |
714 } | |
715 else if (str->bufsize == 0) | |
716 str->eof_p = 1; | |
717 } | |
718 | |
665 | 719 static Bytecount |
720 winsock_reader (Lstream *stream, unsigned char *data, Bytecount size) | |
428 | 721 { |
722 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | |
723 | |
724 /* If the current operation is not yet complete, there's nothing to | |
725 give back */ | |
726 if (str->pending_p) | |
727 { | |
728 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT) | |
729 { | |
730 errno = EAGAIN; | |
731 return -1; | |
732 } | |
733 else | |
734 { | |
1204 | 735 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &str->bufsize, |
736 TRUE)) | |
428 | 737 { |
738 if (GetLastError() == ERROR_HANDLE_EOF) | |
739 str->bufsize = 0; | |
740 else | |
741 str->error_p = 1; | |
742 } | |
743 if (str->bufsize == 0) | |
744 str->eof_p = 1; | |
745 str->pending_p = 0; | |
746 } | |
747 } | |
748 | |
749 if (str->eof_p) | |
750 return 0; | |
751 if (str->error_p) | |
752 return -1; | |
753 | |
754 /* Return as much of buffer as we have */ | |
665 | 755 size = min (size, (Bytecount) (str->bufsize - str->charbpos)); |
771 | 756 memcpy (data, (void *) ((BYTE *) str->buffer + str->charbpos), size); |
665 | 757 str->charbpos += size; |
428 | 758 |
759 /* Read more if buffer is exhausted */ | |
665 | 760 if (str->bufsize == str->charbpos) |
428 | 761 winsock_initiate_read (str); |
762 | |
763 return size; | |
764 } | |
765 | |
665 | 766 static Bytecount |
462 | 767 winsock_writer (Lstream *stream, const unsigned char *data, |
665 | 768 Bytecount size) |
428 | 769 { |
770 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | |
771 | |
772 if (str->pending_p) | |
773 { | |
774 if (WaitForSingleObject (str->ov.hEvent, 0) == WAIT_TIMEOUT) | |
775 { | |
776 str->blocking_p = 1; | |
777 return -1; | |
778 } | |
779 else | |
780 { | |
781 DWORD dw_unused; | |
1204 | 782 if (!GetOverlappedResult ((HANDLE)str->s, &str->ov, &dw_unused, |
783 TRUE)) | |
428 | 784 str->error_p = 1; |
785 str->pending_p = 0; | |
786 } | |
787 } | |
788 | |
789 str->blocking_p = 0; | |
790 | |
791 if (str->error_p) | |
792 return -1; | |
793 | |
794 if (size == 0) | |
795 return 0; | |
796 | |
558 | 797 ResetEvent (str->ov.hEvent); |
798 | |
799 /* According to WriteFile docs, we must hold onto the data we pass to it | |
800 and not make any changes until it finishes -- which may not be until | |
801 the next time we get here, since we use asynchronous I/O. We have | |
802 in fact seen data loss as a result of not doing this. */ | |
803 str->buffer = xrealloc (str->buffer, size); | |
804 memcpy (str->buffer, data, size); | |
805 | |
560 | 806 /* According to MSDN WriteFile docs, the fourth parameter cannot be NULL |
807 on Win95 even when doing an overlapped operation, as we are, where | |
808 the return value through that parameter is not meaningful. */ | |
809 if (WriteFile ((HANDLE)str->s, str->buffer, size, &str->bufsize, | |
558 | 810 &str->ov) |
811 || GetLastError() == ERROR_IO_PENDING) | |
812 str->pending_p = 1; | |
813 else | |
814 str->error_p = 1; | |
428 | 815 |
816 return str->error_p ? -1 : size; | |
817 } | |
818 | |
819 static int | |
820 winsock_closer (Lstream *lstr) | |
821 { | |
822 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
823 | |
824 if (lstr->flags & LSTREAM_FL_READ) | |
825 shutdown (str->s, 0); | |
826 else | |
827 shutdown (str->s, 1); | |
828 | |
986 | 829 closesocket (str->s); |
428 | 830 if (str->pending_p) |
831 WaitForSingleObject (str->ov.hEvent, INFINITE); | |
832 | |
558 | 833 if (str->buffer) |
560 | 834 { |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
835 xfree (str->buffer); |
560 | 836 str->buffer = 0; |
837 } | |
428 | 838 |
839 CloseHandle (str->ov.hEvent); | |
840 return 0; | |
841 } | |
842 | |
843 static int | |
844 winsock_was_blocked_p (Lstream *stream) | |
845 { | |
846 struct winsock_stream *str = WINSOCK_STREAM_DATA (stream); | |
847 return str->blocking_p; | |
848 } | |
849 | |
850 static Lisp_Object | |
442 | 851 make_winsock_stream_1 (SOCKET s, LPARAM param, const char *mode) |
428 | 852 { |
853 Lstream *lstr = Lstream_new (lstream_winsock, mode); | |
854 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
855 | |
558 | 856 xzero (*str); |
428 | 857 str->s = s; |
858 str->user_data = param; | |
859 | |
771 | 860 str->ov.hEvent = qxeCreateEvent (NULL, TRUE, FALSE, NULL); |
428 | 861 |
862 if (lstr->flags & LSTREAM_FL_READ) | |
863 { | |
864 str->buffer = xmalloc (WINSOCK_READ_BUFFER_SIZE); | |
865 winsock_initiate_read (str); | |
866 } | |
867 | |
868 lstr->flags |= LSTREAM_FL_CLOSE_AT_DISKSAVE; | |
793 | 869 return wrap_lstream (lstr); |
428 | 870 } |
871 | |
872 static Lisp_Object | |
873 make_winsock_input_stream (SOCKET s, LPARAM param) | |
874 { | |
875 return make_winsock_stream_1 (s, param, "r"); | |
876 } | |
877 | |
878 static Lisp_Object | |
879 make_winsock_output_stream (SOCKET s, LPARAM param) | |
880 { | |
881 return make_winsock_stream_1 (s, param, "w"); | |
882 } | |
883 | |
884 static HANDLE | |
885 get_winsock_stream_waitable (Lstream *lstr) | |
886 { | |
887 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
888 return str->ov.hEvent; | |
889 } | |
890 | |
891 static LPARAM | |
892 get_winsock_stream_param (Lstream *lstr) | |
893 { | |
894 struct winsock_stream *str = WINSOCK_STREAM_DATA (lstr); | |
895 return str->user_data; | |
896 } | |
897 | |
898 static void | |
899 init_winsock_stream (void) | |
900 { | |
901 LSTREAM_HAS_METHOD (winsock, reader); | |
902 LSTREAM_HAS_METHOD (winsock, writer); | |
903 LSTREAM_HAS_METHOD (winsock, closer); | |
904 LSTREAM_HAS_METHOD (winsock, was_blocked_p); | |
905 } | |
853 | 906 #endif /* ! CYGWIN */ |
428 | 907 |
908 /************************************************************************/ | |
909 /* Dispatch queue management */ | |
910 /************************************************************************/ | |
911 | |
912 static int | |
771 | 913 mswindows_user_event_p (Lisp_Event *sevt) |
428 | 914 { |
915 return (sevt->event_type == key_press_event | |
916 || sevt->event_type == button_press_event | |
917 || sevt->event_type == button_release_event | |
918 || sevt->event_type == misc_user_event); | |
919 } | |
920 | |
921 /* | |
922 * Add an emacs event to the proper dispatch queue | |
923 */ | |
442 | 924 void |
428 | 925 mswindows_enqueue_dispatch_event (Lisp_Object event) |
926 { | |
1204 | 927 int user_p = mswindows_user_event_p (XEVENT (event)); |
928 if (user_p) | |
929 enqueue_dispatch_event (event); | |
930 else | |
931 enqueue_event (event, &mswindows_s_dispatch_event_queue, | |
932 &mswindows_s_dispatch_event_queue_tail); | |
428 | 933 |
934 /* Avoid blocking on WaitMessage */ | |
771 | 935 qxePostMessage (NULL, XM_BUMPQUEUE, 0, 0); |
428 | 936 } |
937 | |
938 /* | |
939 * Add a misc-user event to the dispatch queue. | |
940 */ | |
941 void | |
942 mswindows_enqueue_misc_user_event (Lisp_Object channel, Lisp_Object function, | |
943 Lisp_Object object) | |
944 { | |
945 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
964 | 946 |
947 XSET_EVENT_TYPE (event, misc_user_event); | |
948 XSET_EVENT_CHANNEL (event, channel); | |
949 XSET_EVENT_TIMESTAMP (event, GetTickCount()); | |
1204 | 950 XSET_EVENT_MISC_USER_FUNCTION (event, function); |
951 XSET_EVENT_MISC_USER_OBJECT (event, object); | |
428 | 952 |
953 mswindows_enqueue_dispatch_event (event); | |
954 } | |
955 | |
956 void | |
440 | 957 mswindows_enqueue_magic_event (HWND hwnd, UINT msg) |
428 | 958 { |
959 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
964 | 960 |
1204 | 961 XSET_EVENT_CHANNEL (emacs_event, hwnd ? mswindows_find_frame (hwnd) : Qnil); |
964 | 962 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime ()); |
963 XSET_EVENT_TYPE (emacs_event, magic_event); | |
1204 | 964 XSET_EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event, msg); |
428 | 965 |
966 mswindows_enqueue_dispatch_event (emacs_event); | |
967 } | |
968 | |
969 static void | |
771 | 970 mswindows_enqueue_process_event (Lisp_Process *p) |
428 | 971 { |
972 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
793 | 973 Lisp_Object process = wrap_process (p); |
974 | |
964 | 975 XSET_EVENT_TYPE (emacs_event, process_event); |
1204 | 976 XSET_EVENT_TIMESTAMP (emacs_event, GetTickCount ()); |
977 XSET_EVENT_PROCESS_PROCESS (emacs_event, process); | |
428 | 978 |
979 mswindows_enqueue_dispatch_event (emacs_event); | |
980 } | |
981 | |
982 static void | |
442 | 983 mswindows_enqueue_mouse_button_event (HWND hwnd, UINT msg, POINTS where, |
984 int mods, DWORD when) | |
428 | 985 { |
442 | 986 int downp = (msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || |
987 msg == WM_RBUTTONDOWN); | |
428 | 988 |
1622 | 989 /* Wheel rotation amount: positive is away from user, negative towards user */ |
990 int delta = (short) HIWORD (mods); | |
991 | |
428 | 992 /* We always use last message time, because mouse button |
993 events may get delayed, and XEmacs double click | |
994 recognition will fail */ | |
995 | |
996 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
442 | 997 |
998 mswindows_handle_sticky_modifiers (0, 0, downp, 0); | |
964 | 999 |
1000 if (downp) | |
1001 { | |
1002 XSET_EVENT_TYPE (emacs_event, button_press_event); | |
1003 } | |
1004 else | |
1005 { | |
1006 XSET_EVENT_TYPE (emacs_event, button_release_event); | |
1007 } | |
1008 | |
1009 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_frame (hwnd)); | |
1010 XSET_EVENT_TIMESTAMP (emacs_event, when); | |
1204 | 1011 XSET_EVENT_BUTTON_BUTTON (emacs_event, |
1622 | 1012 (msg==WM_LBUTTONDOWN || msg==WM_LBUTTONUP) ? 1 : |
1013 (msg==WM_MBUTTONDOWN || msg==WM_MBUTTONUP) ? 2 : | |
1014 (msg==WM_RBUTTONDOWN || msg==WM_RBUTTONUP) ? 3 : | |
1015 (msg==WM_MOUSEWHEEL && delta>0) ? 4 : 5); | |
1204 | 1016 XSET_EVENT_BUTTON_X (emacs_event, where.x); |
1017 XSET_EVENT_BUTTON_Y (emacs_event, where.y); | |
1018 XSET_EVENT_BUTTON_MODIFIERS (emacs_event, | |
1019 mswindows_modifier_state (NULL, mods, 0)); | |
442 | 1020 |
1021 if (downp) | |
428 | 1022 { |
1023 SetCapture (hwnd); | |
1024 /* we need this to make sure the main window regains the focus | |
1025 from control subwindows */ | |
1026 if (GetFocus() != hwnd) | |
1027 { | |
1028 SetFocus (hwnd); | |
1029 mswindows_enqueue_magic_event (hwnd, WM_SETFOCUS); | |
1030 } | |
1031 } | |
1032 else | |
1033 { | |
1034 ReleaseCapture (); | |
1035 } | |
1036 | |
1037 mswindows_enqueue_dispatch_event (emacs_event); | |
1038 } | |
1039 | |
771 | 1040 static Lisp_Object |
428 | 1041 mswindows_enqueue_keypress_event (HWND hwnd, Lisp_Object keysym, int mods) |
1042 { | |
1043 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
964 | 1044 |
1045 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_console(hwnd)); | |
1046 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime()); | |
1047 XSET_EVENT_TYPE (emacs_event, key_press_event); | |
1204 | 1048 XSET_EVENT_KEY_KEYSYM (emacs_event, keysym); |
1049 XSET_EVENT_KEY_MODIFIERS (emacs_event, mods); | |
428 | 1050 mswindows_enqueue_dispatch_event (emacs_event); |
771 | 1051 return emacs_event; |
428 | 1052 } |
1053 | |
1054 /* | |
1055 * Remove and return the first emacs event on the dispatch queue. | |
1056 * Give a preference to user events over non-user ones. | |
1057 */ | |
1058 static Lisp_Object | |
442 | 1059 mswindows_dequeue_dispatch_event (void) |
428 | 1060 { |
1204 | 1061 assert (!NILP (dispatch_event_queue) || |
1062 !NILP (mswindows_s_dispatch_event_queue)); | |
1063 | |
1064 if (!NILP (dispatch_event_queue)) | |
1065 return dequeue_dispatch_event (); | |
1066 else | |
1067 return dequeue_event (&mswindows_s_dispatch_event_queue, | |
1068 &mswindows_s_dispatch_event_queue_tail); | |
428 | 1069 } |
1070 | |
853 | 1071 #ifndef CYGWIN |
428 | 1072 /************************************************************************/ |
1073 /* Waitable handles manipulation */ | |
1074 /************************************************************************/ | |
1075 static int | |
1076 find_waitable_handle (HANDLE h) | |
1077 { | |
1078 int i; | |
1079 for (i = 0; i < mswindows_waitable_count; ++i) | |
1080 if (mswindows_waitable_handles[i] == h) | |
1081 return i; | |
1082 | |
1083 return -1; | |
1084 } | |
1085 | |
1086 static BOOL | |
1087 add_waitable_handle (HANDLE h) | |
1088 { | |
1089 assert (find_waitable_handle (h) < 0); | |
1090 if (mswindows_waitable_count == MAX_WAITABLE) | |
1091 return FALSE; | |
1092 | |
1093 mswindows_waitable_handles [mswindows_waitable_count++] = h; | |
1094 return TRUE; | |
1095 } | |
1096 | |
1097 static void | |
1098 remove_waitable_handle (HANDLE h) | |
1099 { | |
1100 int ix = find_waitable_handle (h); | |
1101 if (ix < 0) | |
1102 return; | |
1103 | |
1104 mswindows_waitable_handles [ix] = | |
1105 mswindows_waitable_handles [--mswindows_waitable_count]; | |
1106 } | |
853 | 1107 |
1108 #endif /* CYGWIN */ | |
428 | 1109 |
791 | 1110 /* |
1111 * Given a lisp process pointer remove the corresponding process handle | |
1112 * from mswindows_waitable_handles if it is in it. Normally the handle is | |
1113 * removed when the process terminates, but if the lisp process structure | |
1114 * is deleted before the process terminates we must delete the process | |
1115 * handle since it will be invalid and will cause the wait to fail | |
1116 */ | |
1117 void | |
2286 | 1118 mswindows_unwait_process (Lisp_Process *UNUSED_IF_CYGWIN (p)) |
791 | 1119 { |
853 | 1120 #ifndef CYGWIN |
791 | 1121 remove_waitable_handle (get_nt_process_handle (p)); |
853 | 1122 #endif /* CYGWIN */ |
791 | 1123 } |
1124 | |
428 | 1125 |
1126 /************************************************************************/ | |
1127 /* Event pump */ | |
1128 /************************************************************************/ | |
1129 | |
771 | 1130 int |
1131 mswindows_window_is_xemacs (HWND hwnd) | |
1132 { | |
1133 /* GetClassName will truncate a longer class name. By adding one | |
1134 extra character, we are forcing textual comparison to fail | |
1135 if the name is longer than XEMACS_CLASS */ | |
1136 Extbyte class_name_buf[sizeof (XEMACS_CLASS) + 2]; | |
1137 | |
1138 /* Use GetClassNameA because XEMACS_CLASS is not in Unicode format. */ | |
1139 if (!GetClassNameA (hwnd, class_name_buf, sizeof (class_name_buf) - 1)) | |
1140 return 0; | |
1141 | |
1142 return !ascii_strcasecmp (class_name_buf, XEMACS_CLASS); | |
1143 } | |
1144 | |
428 | 1145 void |
1146 mswindows_unmodalize_signal_maybe (void) | |
1147 { | |
853 | 1148 mswindows_error_caught_in_modal_loop = 0; |
428 | 1149 } |
1150 | |
1151 /* | |
1152 * This is an unsafe part of event pump, guarded by | |
1153 * condition_case. See mswindows_pump_outstanding_events | |
1154 */ | |
1155 static Lisp_Object | |
2286 | 1156 mswindows_unsafe_pump_events (void *UNUSED (arg)) |
428 | 1157 { |
1158 /* This function can call lisp */ | |
1159 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
1160 struct gcpro gcpro1; | |
1161 int do_redisplay = 0; | |
1162 GCPRO1 (event); | |
1163 | |
1268 | 1164 while (detect_input_pending (1)) |
428 | 1165 { |
1166 Fnext_event (event, Qnil); | |
1167 Fdispatch_event (event); | |
1168 do_redisplay = 1; | |
1169 } | |
1170 | |
1171 if (do_redisplay) | |
1172 redisplay (); | |
1173 | |
1174 Fdeallocate_event (event); | |
1175 UNGCPRO; | |
1176 | |
1177 /* Qt becomes return value of mswindows_pump_outstanding_events | |
1178 once we get here */ | |
1179 return Qt; | |
1180 } | |
1181 | |
1182 /* | |
1183 * This function pumps emacs events, while available, by using | |
1184 * next_message/dispatch_message loop. Errors are trapped around | |
1185 * the loop so the function always returns. | |
1186 * | |
1187 * Windows message queue is not looked into during the call, | |
1188 * neither are waitable handles checked. The function pumps | |
1189 * thus only dispatch events already queued, as well as those | |
1190 * resulted in dispatching thereof. This is done by setting | |
1268 | 1191 * in_modal_loop to nonzero. |
428 | 1192 * |
1193 * Return value is Qt if no errors was trapped, or Qunbound if | |
1194 * there was an error. | |
1195 * | |
853 | 1196 * In case of error, a warning is issued and the module local variable |
1197 * mswindows_error_caught_in_modal_loop is set to non-zero. Thus, | |
1198 * Windows internal modal loops are protected against throws, which | |
1199 * are proven to corrupt internal Windows structures. | |
428 | 1200 * |
1201 * In case of success, mswindows_error_caught_in_modal_loop is | |
853 | 1202 * assigned 0. |
428 | 1203 * |
1204 * If the value of mswindows_error_caught_in_modal_loop is not | |
853 | 1205 * zero already upon entry, the function just returns non-nil. |
428 | 1206 * This situation means that a new event has been queued while |
1207 * in cancel mode. The event will be dequeued on the next regular | |
1208 * call of next-event; the pump is off since error is caught. | |
1209 * The caller must *unconditionally* cancel modal loop if the | |
1210 * value returned by this function is nil. Otherwise, everything | |
1211 * will become frozen until the modal loop exits under normal | |
853 | 1212 * condition (scrollbar drag is released, menu closed etc.) */ |
428 | 1213 Lisp_Object |
1214 mswindows_pump_outstanding_events (void) | |
1215 { | |
1216 /* This function can call lisp */ | |
1217 | |
1218 Lisp_Object result = Qt; | |
1219 struct gcpro gcpro1; | |
1220 GCPRO1 (result); | |
1221 | |
853 | 1222 if (!mswindows_error_caught_in_modal_loop) |
1268 | 1223 result = event_stream_protect_modal_loop |
1224 ("Error during event handling", mswindows_unsafe_pump_events, 0, 0); | |
428 | 1225 UNGCPRO; |
1268 | 1226 if (UNBOUNDP (result)) |
1227 mswindows_error_caught_in_modal_loop = 1; | |
428 | 1228 return result; |
1229 } | |
1230 | |
440 | 1231 /* |
428 | 1232 * This is a special flavor of the mswindows_need_event function, |
1233 * used while in event pump. Actually, there is only kind of events | |
1234 * allowed while in event pump: a timer. An attempt to fetch any | |
1235 * other event leads to a deadlock, as there's no source of user input | |
1236 * ('cause event pump mirrors windows modal loop, which is a sole | |
1237 * owner of thread message queue). | |
1238 * | |
1239 * To detect this, we use a counter of active timers, and allow | |
1240 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER | |
1241 * which will never come when there are no pending timers, which leads | |
1242 * to deadlock, we simply signal an error. | |
487 | 1243 * |
1244 * It might be possible to combine this with mswindows_drain_windows_queue | |
1245 * which fetches events when not in a modal loop. It's not clear | |
1246 * whether the result would be more complex than is justified. | |
428 | 1247 */ |
1248 static void | |
1249 mswindows_need_event_in_modal_loop (int badly_p) | |
1250 { | |
1251 MSG msg; | |
1252 | |
1253 /* Check if already have one */ | |
1204 | 1254 if (!NILP (dispatch_event_queue) |
428 | 1255 || !NILP (mswindows_s_dispatch_event_queue)) |
1256 return; | |
1257 | |
1258 /* No event is ok */ | |
1259 if (!badly_p) | |
1260 return; | |
1261 | |
1204 | 1262 /* We do not check the user queue, because timers go to _s_ */ |
428 | 1263 while (NILP (mswindows_s_dispatch_event_queue)) |
1264 { | |
1265 /* We'll deadlock if go waiting */ | |
1266 if (mswindows_pending_timers_count == 0) | |
1204 | 1267 invalid_operation |
1268 ("Deadlock due to an attempt to call next-event in a wrong context", | |
1269 Qunbound); | |
428 | 1270 |
1271 /* Fetch and dispatch any pending timers */ | |
771 | 1272 if (qxeGetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0) |
1273 qxeDispatchMessage (&msg); | |
428 | 1274 } |
1275 } | |
1276 | |
1268 | 1277 /* BADLY_P non-zero means we were called from mswindows_need_event(1). It |
1278 only matters when we are in a modal loop, and causes us to fetch timer | |
1279 events (the only kinds we can fetch in such a case). | |
1280 */ | |
1281 static void | |
1282 mswindows_drain_windows_queue (int badly_p) | |
1283 { | |
1284 MSG msg; | |
1285 | |
1286 if (in_modal_loop) | |
1287 mswindows_need_event_in_modal_loop (badly_p); | |
1288 else | |
1289 while (qxePeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) | |
1290 { | |
1291 #ifdef HAVE_DIALOGS | |
1292 /* Don't translate messages destined for a dialog box, this | |
1293 makes keyboard traversal work. I think?? */ | |
1294 if (mswindows_is_dialog_msg (&msg)) | |
1295 { | |
1296 mswindows_unmodalize_signal_maybe (); | |
1297 continue; | |
1298 } | |
1299 #endif /* HAVE_DIALOGS */ | |
1300 | |
1301 /* We have to translate messages that are not sent to an XEmacs | |
1302 frame. This is so that key presses work ok in things like | |
1303 edit fields. However, we *musn't* translate message for XEmacs | |
1304 frames as this is handled in the wnd proc. | |
1305 We also have to avoid generating paint magic events for windows | |
1306 that aren't XEmacs frames */ | |
1307 | |
1308 if (!mswindows_window_is_xemacs (msg.hwnd)) | |
1309 TranslateMessage (&msg); | |
1310 else if (msg.message == WM_PAINT) | |
1311 { | |
1312 struct mswindows_frame *msframe; | |
1313 | |
1314 /* hdc will be NULL unless this is a subwindow - in which case we | |
1315 shouldn't have received a paint message for it here. */ | |
1316 assert (msg.wParam == 0); | |
1317 | |
1318 /* Queue a magic event for handling when safe */ | |
1319 msframe = | |
1320 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd))); | |
1321 if (!msframe->paint_pending) | |
1322 { | |
1323 msframe->paint_pending = 1; | |
1324 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT); | |
1325 } | |
1326 /* Don't dispatch. WM_PAINT is always the last message in the | |
1327 queue so it's OK to just return. */ | |
1328 return; | |
1329 } | |
1330 qxeDispatchMessage (&msg); | |
1331 mswindows_unmodalize_signal_maybe (); | |
1332 } | |
1333 } | |
1334 | |
1335 static void | |
1336 emacs_mswindows_drain_queue (void) | |
1337 { | |
1318 | 1338 /* This can call Lisp */ |
1268 | 1339 mswindows_drain_windows_queue (0); |
1340 #ifdef HAVE_TTY | |
1341 drain_tty_devices (); | |
1342 #endif | |
1343 } | |
1344 | |
428 | 1345 /* |
1346 * This drains the event queue and fills up two internal queues until | |
1347 * an event of a type specified by USER_P is retrieved. | |
1348 * | |
1349 * | |
1350 * Used by emacs_mswindows_event_pending_p and emacs_mswindows_next_event | |
1351 */ | |
1352 static void | |
1353 mswindows_need_event (int badly_p) | |
1354 { | |
1204 | 1355 while (NILP (dispatch_event_queue) |
428 | 1356 && NILP (mswindows_s_dispatch_event_queue)) |
1357 { | |
853 | 1358 #ifdef CYGWIN |
428 | 1359 int i; |
647 | 1360 int active; |
428 | 1361 SELECT_TYPE temp_mask = input_wait_mask; |
1362 EMACS_TIME sometime; | |
1363 EMACS_SELECT_TIME select_time_to_block, *pointer_to_this; | |
1364 | |
1365 if (badly_p) | |
1366 pointer_to_this = 0; | |
1367 else | |
1368 { | |
1369 EMACS_SET_SECS_USECS (sometime, 0, 0); | |
1370 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block); | |
1371 pointer_to_this = &select_time_to_block; | |
1268 | 1372 if (in_modal_loop) |
534 | 1373 /* In modal loop with badly_p false, don't care about |
1374 Windows events. */ | |
1375 FD_CLR (windows_fd, &temp_mask); | |
428 | 1376 } |
1377 | |
1292 | 1378 mswindows_is_blocking = 1; |
428 | 1379 active = select (MAXDESC, &temp_mask, 0, 0, pointer_to_this); |
1292 | 1380 mswindows_is_blocking = 0; |
428 | 1381 |
1382 if (active == 0) | |
1383 { | |
1384 assert (!badly_p); | |
1385 return; /* timeout */ | |
1386 } | |
1387 else if (active > 0) | |
1388 { | |
1389 if (FD_ISSET (windows_fd, &temp_mask)) | |
1268 | 1390 mswindows_drain_windows_queue (badly_p); |
442 | 1391 else |
428 | 1392 { |
442 | 1393 #ifdef HAVE_TTY |
1394 /* Look for a TTY event */ | |
1204 | 1395 for (i = 0; i < MAXDESC; i++) |
428 | 1396 { |
442 | 1397 /* To avoid race conditions (among other things, an infinite |
1398 loop when called from Fdiscard_input()), we must return | |
1399 user events ahead of process events. */ | |
1400 if (FD_ISSET (i, &temp_mask) && FD_ISSET (i, &tty_only_mask)) | |
428 | 1401 { |
1204 | 1402 struct console *c = |
1403 find_tty_or_stream_console_from_fd (i); | |
442 | 1404 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
771 | 1405 Lisp_Event *event = XEVENT (emacs_event); |
1406 | |
442 | 1407 assert (c); |
771 | 1408 if (read_event_from_tty_or_stream_desc (event, c)) |
442 | 1409 { |
1410 mswindows_enqueue_dispatch_event (emacs_event); | |
1411 return; | |
1412 } | |
428 | 1413 } |
1414 } | |
1415 #endif | |
442 | 1416 /* Look for a process event */ |
1204 | 1417 for (i = 0; i < MAXDESC; i++) |
428 | 1418 { |
442 | 1419 if (FD_ISSET (i, &temp_mask)) |
428 | 1420 { |
442 | 1421 if (FD_ISSET (i, &process_only_mask)) |
1422 { | |
1423 Lisp_Process *p = | |
1204 | 1424 get_process_from_usid (FD_TO_USID (i)); |
442 | 1425 |
1426 mswindows_enqueue_process_event (p); | |
1427 } | |
1428 else | |
1429 { | |
1430 /* We might get here when a fake event came | |
1431 through a signal. Return a dummy event, so | |
1432 that a cycle of the command loop will | |
1433 occur. */ | |
1434 drain_signal_event_pipe (); | |
1435 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1436 } | |
428 | 1437 } |
1438 } | |
1439 } | |
1440 } | |
771 | 1441 else if (active == -1) |
428 | 1442 { |
1443 if (errno != EINTR) | |
1444 { | |
1445 /* something bad happened */ | |
1204 | 1446 assert (0); |
428 | 1447 } |
1448 } | |
1449 else | |
1450 { | |
1204 | 1451 assert (0); |
428 | 1452 } |
853 | 1453 #else /* not CYGWIN */ |
428 | 1454 /* Now try getting a message or process event */ |
647 | 1455 DWORD active; |
487 | 1456 DWORD what_events; |
1268 | 1457 if (in_modal_loop) |
534 | 1458 /* In a modal loop, only look for timer events, and only if |
1459 we really need one. */ | |
1460 { | |
1461 if (badly_p) | |
1462 what_events = QS_TIMER; | |
1463 else | |
1464 what_events = 0; | |
1465 } | |
487 | 1466 else |
534 | 1467 /* Look for any event */ |
1468 what_events = QS_ALLINPUT; | |
487 | 1469 |
771 | 1470 /* |
1471 #### YUCK YUCK YUCK!!!! | |
1472 | |
1473 When running under a debugger, every time I hit F12 (which for me | |
1474 is mapped to right-brace) I hit a breakpoint inside of Windows! | |
1475 | |
1476 NTDLL! DbgBreakPoint@0 address 0x77f9eea9 | |
1477 KERNEL32! BaseAttachComplete@4 + 41 bytes | |
1478 KERNEL32! BaseAttachCompleteThunk@0 + 19 bytes | |
1479 USER32! MsgWaitForMultipleObjectsEx@20 + 224 bytes | |
1480 USER32! MsgWaitForMultipleObjects@20 + 30 bytes | |
1481 | |
1482 Microsoft says: | |
1483 | |
1484 (Knowledge Base Q130667, PRB: F12 Causes Hard-Coded Breakpoint | |
1485 Exception When Debugging) | |
1486 | |
1487 CAUSE | |
1488 | |
1489 When the F12 key is pressed and the application in focus is being | |
1490 debugged, Windows NT calls a function similar to DebugBreak(), | |
1491 which executes a hard coded breakpoint instruction. The integrated | |
1492 debugger then traps the exception generated by this instruction. | |
1493 | |
1494 This behavior is intentional and occurs with other debuggers such | |
1495 as WinDbg from the Windows 32-bit SDK. | |
1496 | |
1497 RESOLUTION | |
1498 | |
1499 While there is no way to disable this functionality, it doesn't | |
1500 affect the application that's being debugged other than to pause | |
1501 debugging and change focus. You can continue debugging by pressing | |
1502 the F5 key. | |
1503 | |
1504 This can be annoying if you have an application that heavily uses | |
1505 the F12 key, so you may want to temporarily assign another key to | |
1506 handle the F12 key functionality in your program when debugging. | |
1507 | |
1508 STATUS | |
1509 | |
1510 This behavior is by design. | |
1511 | |
1512 | |
1513 However, elsewhere I found this: | |
1514 | |
1515 UserDebuggerHotKey | |
1516 HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug | |
1517 | |
1518 Data type Range Default value | |
1519 REG_DWORD 0x0 - 0xFF 0x0 | |
1520 | |
1521 Description | |
1522 | |
1523 Specifies the key that, when pressed, establishes a breakpoint in | |
1524 code being debugged. | |
1525 | |
1526 The debugger interrupts code processing at the breakpoint so the | |
1527 programmer can examine a suspected problem. | |
1528 | |
1529 The key specified in this value only sets a breakpoint. It does | |
1530 not invoke the debugger (the debugger must be running before the | |
1531 key is pressed) and it does not switch the debugger to single-step | |
1532 mode. | |
1533 | |
1534 The value of this entry is a keyboard scan code. The default | |
1535 value, 0x0, represents the F12 key on a 101-key keyboard or the - | |
1536 (hyphen, VK_SUBTRACT) key on an 82-key keyboard. | |
1537 */ | |
1538 | |
853 | 1539 __try |
1540 { | |
923 | 1541 /* This fixes a long outstanding bug, where XEmacs would occasionally |
1542 * not redraw its window (or process other events) until "something | |
1543 * happened" - usually the mouse moving over a frame. | |
1544 * | |
1545 * The problem is that MsgWaitForMultipleObjects only checks to see | |
1546 * if NEW messages have been placed into the thread queue. So we | |
1547 * specifically check to see if the queue is empty (using PeekMessage | |
1548 * with the PM_NOREMOVE flag) before we wait. | |
1549 */ | |
1550 MSG msg; | |
1551 if (what_events == QS_ALLINPUT && badly_p && | |
1552 qxePeekMessage (&msg, 0, 0, 0, PM_NOREMOVE)) | |
1553 active = WAIT_OBJECT_0 + mswindows_waitable_count; | |
1554 else | |
1292 | 1555 { |
1556 mswindows_is_blocking = 1; | |
1557 active = MsgWaitForMultipleObjects (mswindows_waitable_count, | |
1558 mswindows_waitable_handles, | |
1559 FALSE, | |
1560 badly_p ? INFINITE : 0, | |
1561 what_events); | |
1562 mswindows_is_blocking = 0; | |
1563 } | |
853 | 1564 } |
1565 __except (GetExceptionCode () == EXCEPTION_BREAKPOINT ? | |
1566 EXCEPTION_CONTINUE_EXECUTION : | |
1567 EXCEPTION_CONTINUE_SEARCH) | |
1568 { | |
1569 } | |
442 | 1570 |
1571 /* This will assert if handle being waited for becomes abandoned. | |
1572 Not the case currently tho */ | |
1573 assert ((!badly_p && active == WAIT_TIMEOUT) || | |
1574 (active >= WAIT_OBJECT_0 && | |
1575 active <= WAIT_OBJECT_0 + mswindows_waitable_count)); | |
1576 | |
1577 if (active == WAIT_TIMEOUT) | |
1578 { | |
1579 /* No luck trying - just return what we've already got */ | |
1580 return; | |
1581 } | |
1582 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) | |
1268 | 1583 mswindows_drain_windows_queue (badly_p); |
442 | 1584 else |
1585 { | |
1586 int ix = active - WAIT_OBJECT_0; | |
1204 | 1587 |
1588 /* look for a stream console event; see | |
1589 emacs_mswindows_select_console below. */ | |
1590 LIST_LOOP_3 (porca_troia, Vconsole_list, vcontail) | |
442 | 1591 { |
1204 | 1592 struct console *con = XCONSOLE (porca_troia); |
1593 | |
1594 if (CONSOLE_STREAM_P (con)) | |
1595 { | |
1596 Lisp_Object instr = CONSOLE_STREAM_DATA (con)->instream; | |
1597 if (!NILP (instr) && !UNBOUNDP (instr) && | |
1598 get_ntpipe_input_stream_waitable (XLSTREAM (instr)) == | |
1599 mswindows_waitable_handles [ix]) | |
1600 { | |
1601 Ichar ch = Lstream_get_ichar (XLSTREAM (instr)); | |
1602 if (ch < 0) | |
1603 { | |
1604 /* deleting the console might not be safe right now | |
1605 ... */ | |
1606 enqueue_magic_eval_event (io_error_delete_console, | |
1607 porca_troia); | |
1608 /* but we definitely need to unselect it to avoid | |
1609 infinite loops reading EOF's */ | |
1610 Fconsole_disable_input (porca_troia); | |
1611 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1612 } | |
1613 else | |
1614 { | |
1615 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
1616 /* Here we really do want to set the | |
1617 use_console_meta_flag because the char is from the | |
1618 TTY. */ | |
4780
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4677
diff
changeset
|
1619 character_to_event (ch, XEVENT (event), con, |
2fd201d73a92
Call character_to_event on characters received from XIM, event-Xt.c
Aidan Kehoe <kehoea@parhasard.net>
parents:
4677
diff
changeset
|
1620 use_console_meta_flag, 1); |
1204 | 1621 XSET_EVENT_CHANNEL (event, porca_troia); |
1622 enqueue_dispatch_event (event); | |
1623 } | |
1624 break; | |
1625 } | |
1626 } | |
1627 } | |
1628 | |
1629 if (NILP (vcontail)) | |
1630 { /* no stream console event, look for process event */ | |
1631 /* First, try to find which process' output has signaled */ | |
1632 Lisp_Process *p = | |
1633 get_process_from_usid (HANDLE_TO_USID | |
1634 (mswindows_waitable_handles[ix])); | |
1635 if (p != NULL) | |
1636 /* Found a signaled process input handle */ | |
1637 mswindows_enqueue_process_event (p); | |
853 | 1638 else |
442 | 1639 { |
1204 | 1640 /* None. This means that the process handle itself has |
1641 signaled. Remove the handle from the wait vector, and | |
1642 make status_notify note the exited process. First | |
1643 find the process object if possible. */ | |
1644 LIST_LOOP_3 (vaffanculo, Vprocess_list, vproctail) | |
1645 if (get_nt_process_handle (XPROCESS (vaffanculo)) == | |
1646 mswindows_waitable_handles [ix]) | |
1647 break; | |
1648 mswindows_waitable_handles [ix] = | |
1649 mswindows_waitable_handles [--mswindows_waitable_count]; | |
1650 kick_status_notify (); | |
1651 /* We need to return a process event here so that (1) | |
1652 accept-process-output will return when called on this | |
1653 process, and (2) status notifications will happen in | |
1654 accept-process-output, sleep-for, and sit-for. */ | |
1655 if (!NILP (vproctail)) | |
1656 mswindows_enqueue_process_event (XPROCESS (vaffanculo)); | |
1657 else | |
1658 { | |
2500 | 1659 /* ABORT (); */ |
1204 | 1660 /* #### FUCKME! When can this happen? I hit this |
2500 | 1661 ABORT() when I tried enabling it. */ |
1204 | 1662 /* Have to return something: there may be no |
1663 accompanying process event */ | |
1664 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
1665 } | |
442 | 1666 } |
1667 } | |
1668 } | |
853 | 1669 #endif /* not CYGWIN */ |
442 | 1670 } /* while */ |
428 | 1671 } |
1672 | |
1673 /************************************************************************/ | |
1674 /* Event generators */ | |
1675 /************************************************************************/ | |
1676 | |
1677 /* | |
1678 * Callback procedure for synchronous timer messages | |
1679 */ | |
1680 static void CALLBACK | |
2286 | 1681 mswindows_wm_timer_callback (HWND UNUSED (hwnd), UINT UNUSED (umsg), |
1682 UINT id_timer, DWORD dwtime) | |
428 | 1683 { |
1684 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | |
1685 | |
1686 if (KillTimer (NULL, id_timer)) | |
1687 --mswindows_pending_timers_count; | |
1688 | |
964 | 1689 XSET_EVENT_CHANNEL (emacs_event, Qnil); |
1690 XSET_EVENT_TIMESTAMP (emacs_event, dwtime); | |
1691 XSET_EVENT_TYPE (emacs_event, timeout_event); | |
1204 | 1692 XSET_EVENT_TIMEOUT_INTERVAL_ID (emacs_event, id_timer); |
1693 XSET_EVENT_TIMEOUT_FUNCTION (emacs_event, Qnil); | |
1694 XSET_EVENT_TIMEOUT_OBJECT (emacs_event, Qnil); | |
428 | 1695 |
1696 mswindows_enqueue_dispatch_event (emacs_event); | |
1697 } | |
1698 | |
1699 /* | |
1700 * Callback procedure for dde messages | |
1701 * | |
1702 * We execute a dde Open("file") by simulating a file drop, so dde support | |
1703 * depends on dnd support. | |
1704 */ | |
1705 #ifdef HAVE_DRAGNDROP | |
657 | 1706 extern int mswindows_dde_enable; |
1707 | |
903 | 1708 EXFUN(Fread_from_string, 3); |
1709 | |
1710 /* The following variables are used to maintain consistency of result and | |
1711 * error reporting to the client. | |
1712 * The basic protocol is to Execute a lisp form, and then Request one or | |
1713 * more of the following items: Status (1 = OK, 0 = Error), Result, or Error. | |
1714 * When the lisp form is queued, the dde_eval_pending flag is set to 1, | |
1715 * to indicate that the items are not yet available. The dde_eval_pending | |
1716 * flag is set to 0 when the evaluation is complete. Requests for the result | |
1717 * items will block while the dde_eval_pending flag is 1, to avoid clients | |
1718 * getting inconsistent results. | |
1719 */ | |
1720 static int dde_eval_pending; | |
1721 static Lisp_Object dde_eval_result; | |
1722 static Lisp_Object dde_eval_error; | |
1723 | |
1724 static Lisp_Object | |
2286 | 1725 dde_error (Lisp_Object err, Lisp_Object UNUSED (obj)) |
903 | 1726 { |
1727 dde_eval_error = err; | |
1728 return Qnil; | |
1729 } | |
1730 | |
1731 /* Read lisp forms from a string. Evaluate the forms as if they were | |
1732 * wrapped in a progn form. Return the result of the form. | |
1733 */ | |
1734 static Lisp_Object | |
1735 dde_eval_string (Lisp_Object str) | |
1736 { | |
1737 struct gcpro gcpro1, gcpro2; | |
1738 Lisp_Object args[3]; | |
1739 Lisp_Object obj; | |
1740 | |
1741 /* Heavy handed GCPROing, on the principle of it's better to be safe than | |
1742 * sorry... | |
1743 */ | |
1744 args[0] = Qnil; | |
1745 args[1] = Qnil; | |
1746 args[2] = Qnil; | |
1747 GCPRO2 (args[0], str); | |
1748 gcpro1.nvars = 3; | |
1749 | |
1750 /* Wrap the user supplied string in string "(progn ...)". | |
1751 * We can now just read-from-string a single form. If we | |
1752 * get an error, or finish before the end of the string, | |
1753 * we know the original string had syntax errors. | |
1754 */ | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1755 args[0] = build_ascstring ("(progn "); |
903 | 1756 args[1] = str; |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1757 args[2] = build_ascstring (")"); |
903 | 1758 str = Fconcat (3, args); |
1759 | |
1760 obj = Fread_from_string (str, Qnil, Qnil); | |
1761 UNGCPRO; | |
1762 | |
1763 /* The following doesn't check that the length fits in an EMACS_INT. | |
1764 * This won't be a problem in reality...? | |
1765 * | |
1766 * If the read didn't get to the end of the string, we have a syntax | |
1767 * error in the string supplied by the user. | |
1768 */ | |
1769 if (XINT (XCDR (obj)) != XSTRING_LENGTH (str)) | |
1770 return Qnil; | |
1771 | |
1772 GCPRO1 (obj); | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3263
diff
changeset
|
1773 obj = IGNORE_MULTIPLE_VALUES (Feval (XCAR (obj))); |
903 | 1774 |
1204 | 1775 RETURN_UNGCPRO (obj); |
903 | 1776 } |
1777 | |
1778 /* Evaluate the supplied string as a sequence of Lisp forms, wrapped in | |
1779 * a progn. Catch any evaluation errors. Set the evaluation status and | |
1780 * result variables. | |
1781 */ | |
1782 static void | |
1783 dde_eval (Lisp_Object str) | |
1784 { | |
1785 dde_eval_error = Qnil; | |
1786 dde_eval_result = condition_case_1 (Qt, dde_eval_string, str, | |
1787 dde_error, Qnil); | |
1788 dde_eval_pending = 0; | |
1789 | |
1790 /* Re-enable callbacks in case the client is waiting on a request */ | |
1791 DdeEnableCallback (mswindows_dde_mlid, NULL, EC_ENABLEALL); | |
1792 | |
1793 /* Post advise notifications on the result item */ | |
1794 DdePostAdvise (mswindows_dde_mlid, mswindows_dde_topic_eval, | |
1795 mswindows_dde_item_result); | |
1796 } | |
1797 | |
1798 /* A list of DDE advise tokens. Each token is an uninterned symbol, | |
1799 * whose value is the DDE string handle for its name (stored as a float, | |
1800 * as a Lisp int cannot hold a full C int). | |
3025 | 1801 * The token's `dde-data' property is used to store data for a dde-advise. |
903 | 1802 */ |
1803 Lisp_Object Vdde_advise_items; | |
1804 | |
3025 | 1805 /* The symbol `HSZ' */ |
903 | 1806 Lisp_Object QHSZ; |
1807 | |
1808 DEFUN("dde-alloc-advise-item", Fdde_alloc_advise_item, 0, 1, 0, /* | |
1809 Allocate an advise item, and return its token. | |
1810 */ | |
1811 (name)) | |
1812 { | |
1813 Lisp_Object token; | |
1814 HSZ hsz; | |
1815 struct gcpro gcpro1, gcpro2; | |
1816 | |
1817 if (!NILP (name)) | |
1818 CHECK_STRING (name); | |
1819 else | |
1820 { | |
1821 static int num = 0; | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1822 Ascbyte buf[20]; |
903 | 1823 sprintf (buf, "Tok%d", num); |
1824 ++num; | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1825 name = build_ascstring (buf); |
903 | 1826 } |
1827 | |
1828 token = Qnil; | |
1829 GCPRO2 (name, token); | |
1830 token = Fmake_symbol (name); | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1831 hsz = qxeDdeCreateStringHandle (mswindows_dde_mlid, |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
1832 LISP_STRING_TO_TSTR (name), |
903 | 1833 XEUNICODE_P ? CP_WINUNICODE : CP_WINANSI); |
1834 | |
1835 Fput(token, QHSZ, make_float ((int)hsz)); | |
1836 Vdde_advise_items = Fcons (token, Vdde_advise_items); | |
1837 | |
1204 | 1838 RETURN_UNGCPRO (token); |
903 | 1839 } |
1840 | |
1841 DEFUN("dde-free-advise-item", Fdde_free_advise_item, 1, 1, 0, /* | |
1842 Free the resources associated with advise item ITEM. | |
1843 | |
1844 Frees all resources allocated to allow clients to set up advise loops | |
1845 on ITEM. It is assumed that no active advise loops remain. However, no | |
1846 problems should arise if they do - it's just that we won't ever send any | |
1847 notifications again. | |
1848 | |
1849 If the user does not free an advise item, resources will be leaked. | |
1850 */ | |
1851 (item)) | |
1852 { | |
1853 HSZ hsz; | |
1854 Lisp_Object val; | |
1855 | |
1856 CHECK_SYMBOL (item); | |
1857 val = Fget (item, QHSZ, Qnil); | |
1858 if (!FLOATP (val)) | |
1859 return Qnil; | |
1860 hsz = (HSZ)(int)XFLOAT_DATA (val); | |
1861 DdeFreeStringHandle (mswindows_dde_mlid, hsz); | |
1862 Vdde_advise_items = delq_no_quit (item, Vdde_advise_items); | |
1863 return Qnil; | |
1864 } | |
1865 | |
1866 DEFUN("dde-advise", Fdde_advise, 2, 2, 0, /* | |
1867 Post a DDE advise for ITEM with associated data DATA. | |
1868 | |
1869 Records the value DATA for sending back to clients waiting for | |
1870 notifications on DDE item ITEM in the system topic, and posts | |
1871 the advise transaction. | |
1872 | |
1873 ITEM must be an advise token allocated using dde-alloc-advise-item. | |
1874 */ | |
1875 (item, data)) | |
1876 { | |
1877 HSZ hsz; | |
1878 Lisp_Object val; | |
1879 | |
1880 CHECK_SYMBOL (item); | |
1881 val = Fget (item, QHSZ, Qnil); | |
1882 if (!FLOATP (val)) | |
1883 return Qnil; | |
1884 hsz = (HSZ)(int)XFLOAT_DATA (val); | |
1885 | |
1886 Fset (item, data); | |
1887 DdePostAdvise (mswindows_dde_mlid, mswindows_dde_topic_eval, hsz); | |
1888 return Qnil; | |
1889 } | |
1890 | |
428 | 1891 HDDEDATA CALLBACK |
2286 | 1892 mswindows_dde_callback (UINT uType, UINT uFmt, HCONV UNUSED (hconv), |
428 | 1893 HSZ hszTopic, HSZ hszItem, HDDEDATA hdata, |
2286 | 1894 DWORD UNUSED (dwData1), DWORD UNUSED (dwData2)) |
428 | 1895 { |
1896 switch (uType) | |
1897 { | |
1898 case XTYP_CONNECT: | |
903 | 1899 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system) |
1900 || !DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval)) | |
853 | 1901 return (HDDEDATA) TRUE; |
1902 return (HDDEDATA) FALSE; | |
428 | 1903 |
1904 case XTYP_WILDCONNECT: | |
1905 { | |
903 | 1906 /* We support two {service,topic} pairs */ |
1907 HSZPAIR pairs[3] = | |
771 | 1908 { |
903 | 1909 { mswindows_dde_service, mswindows_dde_topic_system }, |
1910 { mswindows_dde_service, mswindows_dde_topic_eval }, | |
1911 { 0, 0 } | |
1912 }; | |
1913 | |
1914 if ((!hszItem | |
1915 || !DdeCmpStringHandles (hszItem, mswindows_dde_service)) && | |
1916 (!hszTopic | |
1917 || !DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system) | |
1918 || !DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval))) | |
853 | 1919 return (DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE) pairs, |
428 | 1920 sizeof (pairs), 0L, 0, uFmt, 0)); |
1921 } | |
853 | 1922 return (HDDEDATA) NULL; |
428 | 1923 |
903 | 1924 case XTYP_ADVSTART: |
1925 if (!mswindows_dde_enable) | |
1926 return (HDDEDATA) FALSE; | |
1927 | |
1928 /* We only support advise loops on the eval topic for text data */ | |
1929 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval) | |
1930 && (uFmt == CF_TEXT || uFmt == CF_UNICODETEXT)) | |
1931 { | |
1932 /* Only allocated items or Result, are allowed */ | |
1933 if (!DdeCmpStringHandles (hszItem, mswindows_dde_item_result)) | |
1934 return (HDDEDATA) TRUE; | |
1935 | |
1936 { | |
1937 EXTERNAL_LIST_LOOP_2 (elt, Vdde_advise_items) | |
1938 { | |
1939 Lisp_Object val; | |
1940 HSZ hsz; | |
1941 if (!SYMBOLP (elt)) | |
1942 continue; | |
1943 val = Fget (elt, QHSZ, Qnil); | |
1944 if (!FLOATP (val)) | |
1945 continue; | |
1946 hsz = (HSZ) (int) XFLOAT_DATA (val); | |
1947 if (!DdeCmpStringHandles (hszItem, hsz)) | |
1948 return (HDDEDATA) TRUE; | |
1949 } | |
1950 } | |
1951 } | |
1952 return (HDDEDATA) FALSE; | |
1953 | |
1954 /* Both advise requests and normal requests work the same */ | |
1955 case XTYP_ADVREQ: | |
1956 case XTYP_REQUEST: | |
1957 if (!mswindows_dde_enable) | |
1958 return (HDDEDATA) NULL; | |
1959 | |
1960 if (DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval) != 0) | |
1961 return (HDDEDATA) NULL; | |
1962 | |
1963 /* If this is a normal request and we're in the middle of | |
1964 * an Execute, block until the Execute completes. | |
1965 */ | |
1966 if (dde_eval_pending && uType == XTYP_REQUEST) | |
1967 return (HDDEDATA) CBR_BLOCK; | |
1968 | |
1969 /* We can only support requests for ANSI or Unicode text */ | |
1970 if (uFmt != CF_TEXT && uFmt != CF_UNICODETEXT) | |
1971 return (HDDEDATA) NULL; | |
1972 | |
1973 { | |
1974 Lisp_Object args[2]; | |
1975 struct gcpro gcpro1; | |
1976 Lisp_Object res; | |
1977 Extbyte *result; | |
1978 DWORD bytes; | |
1979 | |
1980 args[0] = Qnil; | |
1981 args[1] = Qnil; | |
1982 GCPRO1 (args[0]); | |
1983 gcpro1.nvars = 2; | |
1984 | |
1985 | |
1986 if (!DdeCmpStringHandles (hszItem, mswindows_dde_item_result)) | |
1987 { | |
1988 if (NILP (dde_eval_error)) | |
1989 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1990 args[0] = build_ascstring ("OK: %s"); |
903 | 1991 args[1] = dde_eval_result; |
1992 } | |
1993 else | |
1994 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
1995 args[0] = build_ascstring ("ERR: %s"); |
903 | 1996 args[1] = dde_eval_error; |
1997 } | |
1998 } | |
1999 else | |
2000 { | |
2001 EXTERNAL_LIST_LOOP_2 (elt, Vdde_advise_items) | |
2002 { | |
2003 Lisp_Object val; | |
2004 HSZ hsz; | |
2005 if (!SYMBOLP (elt)) | |
2006 continue; | |
2007 val = Fget (elt, QHSZ, Qnil); | |
2008 if (!FLOATP (val)) | |
2009 continue; | |
2010 hsz = (HSZ) (int) XFLOAT_DATA (val); | |
2011 if (!DdeCmpStringHandles (hszItem, hsz)) | |
2012 args[1] = Fsymbol_value (elt); | |
2013 } | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
2014 args[0] = build_ascstring ("%s"); |
903 | 2015 } |
2016 | |
2017 res = Fformat (2, args); | |
2018 UNGCPRO; | |
2019 | |
2020 bytes = (uFmt == CF_TEXT ? 1 : 2) * (XSTRING_LENGTH (res) + 1); | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2021 result = |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2022 LISP_STRING_TO_EXTERNAL (res, |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2023 uFmt == CF_TEXT ? Qmswindows_multibyte |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2024 : Qmswindows_unicode); |
903 | 2025 |
2026 /* If we cannot create the data handle, this passes the null | |
2027 * return back to the client, which signals an error as we wish. | |
2028 */ | |
2029 return DdeCreateDataHandle (mswindows_dde_mlid, (LPBYTE)result, | |
2030 bytes, 0L, hszItem, uFmt, 0); | |
2031 } | |
2032 | |
428 | 2033 case XTYP_EXECUTE: |
657 | 2034 if (!mswindows_dde_enable) |
2035 return (HDDEDATA) DDE_FBUSY; | |
2036 | |
903 | 2037 if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_eval)) |
2038 { | |
2039 DWORD len; | |
2040 LPBYTE extcmd; | |
2041 Lisp_Object tmp; | |
2042 | |
2043 /* Grab a pointer to the raw data supplied */ | |
2044 extcmd = DdeAccessData (hdata, &len); | |
2045 | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2046 tmp = make_extstring ((Extbyte *) extcmd, len, Qmswindows_tstr); |
903 | 2047 |
2048 /* Release and free the data handle */ | |
2049 DdeUnaccessData (hdata); | |
2050 DdeFreeDataHandle (hdata); | |
2051 | |
2052 /* Set a flag to say that the evaluation isn't yet complete, | |
2053 * enqueue the evaluation, send a dummy event to trigger the | |
2054 * event loop (I've no idea why this is needed, but it works...) | |
2055 * and return success to the client. | |
2056 */ | |
2057 dde_eval_pending = 1; | |
2058 enqueue_magic_eval_event (dde_eval, tmp); | |
2059 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
2060 return (HDDEDATA) DDE_FACK; | |
2061 } | |
2062 else if (!DdeCmpStringHandles (hszTopic, mswindows_dde_topic_system)) | |
428 | 2063 { |
2064 DWORD len = DdeGetData (hdata, NULL, 0, 0); | |
2367 | 2065 Extbyte *extcmd = alloca_extbytes (len + 1); |
867 | 2066 Ibyte *cmd; |
2067 Ibyte *end; | |
428 | 2068 struct gcpro gcpro1, gcpro2; |
657 | 2069 Lisp_Object l_dndlist = Qnil; |
428 | 2070 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
2071 Lisp_Object frmcons, devcons, concons; | |
440 | 2072 Lisp_Event *event = XEVENT (emacs_event); |
428 | 2073 |
2367 | 2074 DdeGetData (hdata, (LPBYTE) extcmd, len, 0); |
428 | 2075 DdeFreeDataHandle (hdata); |
2076 | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2077 cmd = SIZED_EXTERNAL_TO_ITEXT (extcmd, len, Qmswindows_tstr); |
771 | 2078 |
428 | 2079 /* Check syntax & that it's an [Open("foo")] command, which we |
2080 * treat like a file drop */ | |
2081 if (*cmd == '[') | |
2082 cmd++; | |
2367 | 2083 if (qxestrncasecmp_ascii (cmd, MSWINDOWS_DDE_ITEM_OPEN, |
771 | 2084 strlen (MSWINDOWS_DDE_ITEM_OPEN))) |
428 | 2085 return DDE_FNOTPROCESSED; |
2086 cmd += strlen (MSWINDOWS_DDE_ITEM_OPEN); | |
771 | 2087 while (*cmd == ' ') |
428 | 2088 cmd++; |
771 | 2089 if (*cmd != '(' || *(cmd + 1) != '\"') |
428 | 2090 return DDE_FNOTPROCESSED; |
771 | 2091 end = (cmd += 2); |
2092 while (*end && *end != '\"') | |
428 | 2093 end++; |
2094 if (!*end) | |
2095 return DDE_FNOTPROCESSED; | |
2096 *end = '\0'; | |
771 | 2097 if (*++end != ')') |
428 | 2098 return DDE_FNOTPROCESSED; |
771 | 2099 if (*++end == ']') |
428 | 2100 end++; |
2101 if (*end) | |
2102 return DDE_FNOTPROCESSED; | |
2103 | |
771 | 2104 { |
2105 /* The drag-n-drop code in dragdrop.el expects pseudo-URL's, | |
2106 consisting of just file: followed by the filename. This | |
2107 should maybe work, but both Netscape and IE complain | |
2108 whenever they're not given the full file spec, like | |
2109 | |
2110 file:///C|/foo/bar/ or equivalently | |
2111 file:///C:/foo/bar/ (less portably) | |
2112 | |
2113 they don't allow relative paths at all! this is way bogus. */ | |
2114 cmd = urlify_filename (cmd); | |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
2115 l_dndlist = build_istring (cmd); |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2116 xfree (cmd); |
771 | 2117 } |
428 | 2118 GCPRO2 (emacs_event, l_dndlist); |
2119 | |
2120 /* Find a mswindows frame */ | |
2121 event->channel = Qnil; | |
2122 FRAME_LOOP_NO_BREAK (frmcons, devcons, concons) | |
2123 { | |
2124 Lisp_Object frame = XCAR (frmcons); | |
2125 if (FRAME_TYPE_P (XFRAME (frame), mswindows)) | |
2126 event->channel = frame; | |
2127 }; | |
2128 assert (!NILP (event->channel)); | |
2129 | |
964 | 2130 SET_EVENT_TIMESTAMP (event, GetTickCount()); |
2131 SET_EVENT_TYPE (event, misc_user_event); | |
1204 | 2132 SET_EVENT_MISC_USER_BUTTON (event, 1); |
2133 SET_EVENT_MISC_USER_MODIFIERS (event, 0); | |
2134 SET_EVENT_MISC_USER_X (event, -1); | |
2135 SET_EVENT_MISC_USER_Y (event, -1); | |
2136 SET_EVENT_MISC_USER_FUNCTION (event, | |
964 | 2137 Qdragdrop_drop_dispatch); |
1204 | 2138 SET_EVENT_MISC_USER_OBJECT (event, |
964 | 2139 Fcons (Qdragdrop_URL, |
2140 Fcons (l_dndlist, Qnil))); | |
428 | 2141 mswindows_enqueue_dispatch_event (emacs_event); |
2142 UNGCPRO; | |
2143 return (HDDEDATA) DDE_FACK; | |
2144 } | |
2145 DdeFreeDataHandle (hdata); | |
2146 return (HDDEDATA) DDE_FNOTPROCESSED; | |
2147 | |
2148 default: | |
2149 return (HDDEDATA) NULL; | |
2150 } | |
2151 } | |
2152 #endif | |
2153 | |
2154 /* | |
442 | 2155 * Helper to do repainting - repaints can happen both from the windows |
2156 * procedure and from magic events | |
2157 */ | |
2158 static void | |
2159 mswindows_handle_paint (struct frame *frame) | |
2160 { | |
2161 HWND hwnd = FRAME_MSWINDOWS_HANDLE (frame); | |
2162 | |
2163 /* According to the docs we need to check GetUpdateRect() before | |
2164 actually doing a WM_PAINT */ | |
2165 if (GetUpdateRect (hwnd, NULL, FALSE)) | |
2166 { | |
2167 PAINTSTRUCT paintStruct; | |
2168 int x, y, width, height; | |
2169 | |
2170 BeginPaint (hwnd, &paintStruct); | |
2171 x = paintStruct.rcPaint.left; | |
2172 y = paintStruct.rcPaint.top; | |
2173 width = paintStruct.rcPaint.right - paintStruct.rcPaint.left; | |
2174 height = paintStruct.rcPaint.bottom - paintStruct.rcPaint.top; | |
2175 /* Normally we want to ignore expose events when child | |
2176 windows are unmapped, however once we are in the guts of | |
2177 WM_PAINT we need to make sure that we don't register | |
2178 unmaps then because they will not actually occur. */ | |
2179 /* #### commenting out the next line seems to fix some problems | |
2180 but not all. only andy currently understands this stuff and | |
2181 he needs to review it more carefully. --ben */ | |
2182 if (!check_for_ignored_expose (frame, x, y, width, height)) | |
2183 { | |
2184 hold_ignored_expose_registration = 1; | |
1318 | 2185 redisplay_redraw_exposed_area (frame, x, y, width, height); |
442 | 2186 hold_ignored_expose_registration = 0; |
2187 } | |
2188 EndPaint (hwnd, &paintStruct); | |
2189 } | |
2190 } | |
2191 | |
2192 /* | |
2193 * Returns 1 if a key is a real modifier or special key, which | |
440 | 2194 * is better handled by DefWindowProc |
2195 */ | |
2196 static int | |
2197 key_needs_default_processing_p (UINT vkey) | |
2198 { | |
442 | 2199 if (mswindows_alt_by_itself_activates_menu && vkey == VK_MENU |
2200 /* if we let ALT activate the menu like this, then sticky ALT-modified | |
2201 keystrokes become impossible. */ | |
2202 && !modifier_keys_are_sticky) | |
440 | 2203 return 1; |
2204 | |
2205 return 0; | |
2206 } | |
2207 | |
442 | 2208 /* key-handling code is always ugly. It just ends up working out |
2209 that way. | |
2210 | |
2211 #### Most of the sticky-modifier code below is copied from similar | |
2212 code in event-Xt.c. They should somehow or other be merged. | |
2213 | |
2214 Here are some pointers: | |
2215 | |
2216 -- DOWN_MASK indicates which modifiers should be treated as "down" | |
2217 when the corresponding upstroke happens. It gets reset for | |
2218 a particular modifier when that modifier goes up, and reset | |
2219 for all modifiers when a non-modifier key is pressed. Example: | |
2220 | |
2221 I press Control-A-Shift and then release Control-A-Shift. | |
2222 I want the Shift key to be sticky but not the Control key. | |
2223 | |
2224 -- If a modifier key is sticky, I can unstick it by pressing | |
2225 the modifier key again. */ | |
2226 | |
2227 static WPARAM last_downkey; | |
2228 static int need_to_add_mask, down_mask; | |
2229 | |
2230 #define XEMSW_LCONTROL (1<<0) | |
2231 #define XEMSW_RCONTROL (1<<1) | |
2232 #define XEMSW_LSHIFT (1<<2) | |
2233 #define XEMSW_RSHIFT (1<<3) | |
2234 #define XEMSW_LMENU (1<<4) | |
2235 #define XEMSW_RMENU (1<<5) | |
2236 | |
2237 static int | |
2238 mswindows_handle_sticky_modifiers (WPARAM wParam, LPARAM lParam, | |
2239 int downp, int keyp) | |
2240 { | |
2241 int mods = 0; | |
2242 | |
2243 if (!modifier_keys_are_sticky) /* Optimize for non-sticky modifiers */ | |
2244 return 0; | |
2245 | |
2246 if (! (keyp && | |
2247 (wParam == VK_CONTROL || wParam == VK_LCONTROL || | |
2248 wParam == VK_RCONTROL || | |
2249 wParam == VK_MENU || wParam == VK_LMENU || | |
2250 wParam == VK_RMENU || | |
2251 wParam == VK_SHIFT || wParam == VK_LSHIFT || | |
2252 wParam == VK_RSHIFT))) | |
2253 { /* Not a modifier key */ | |
2254 if (downp && keyp && !last_downkey) | |
2255 last_downkey = wParam; | |
2256 /* If I hold press-and-release the Control key and then press | |
2257 and hold down the right arrow, I want it to auto-repeat | |
2258 Control-Right. On the other hand, if I do the same but | |
2259 manually press the Right arrow a bunch of times, I want | |
2260 to see one Control-Right and then a bunch of Rights. | |
2261 This means that we need to distinguish between an | |
2262 auto-repeated key and a key pressed and released a bunch | |
2263 of times. */ | |
2264 else if ((downp && !keyp) || | |
2265 (downp && keyp && last_downkey && | |
2266 (wParam != last_downkey || | |
2267 /* the "previous key state" bit indicates autorepeat */ | |
2268 ! (lParam & (1 << 30))))) | |
2269 { | |
2270 need_to_add_mask = 0; | |
2271 last_downkey = 0; | |
2272 } | |
2273 if (downp) | |
2274 down_mask = 0; | |
2275 | |
2276 mods = need_to_add_mask; | |
2277 } | |
2278 else /* Modifier key pressed */ | |
2279 { | |
2280 /* If a non-modifier key was pressed in the middle of a bunch | |
2281 of modifiers, then it unsticks all the modifiers that were | |
2282 previously pressed. We cannot unstick the modifiers until | |
2283 now because we want to check for auto-repeat of the | |
2284 non-modifier key. */ | |
2285 | |
2286 if (last_downkey) | |
2287 { | |
2288 last_downkey = 0; | |
2289 need_to_add_mask = 0; | |
2290 } | |
2291 | |
2292 #define FROB(mask) \ | |
2293 do { \ | |
2294 if (downp && keyp) \ | |
2295 { \ | |
2296 /* If modifier key is already sticky, \ | |
2297 then unstick it. Note that we do \ | |
2298 not test down_mask to deal with the \ | |
2299 unlikely but possible case that the \ | |
2300 modifier key auto-repeats. */ \ | |
2301 if (need_to_add_mask & mask) \ | |
2302 { \ | |
2303 need_to_add_mask &= ~mask; \ | |
2304 down_mask &= ~mask; \ | |
2305 } \ | |
2306 else \ | |
2307 down_mask |= mask; \ | |
2308 } \ | |
2309 else \ | |
2310 { \ | |
2311 if (down_mask & mask) \ | |
2312 { \ | |
2313 down_mask &= ~mask; \ | |
2314 need_to_add_mask |= mask; \ | |
2315 } \ | |
2316 } \ | |
2317 } while (0) | |
2318 | |
2319 if ((wParam == VK_CONTROL && (lParam & 0x1000000)) | |
2320 || wParam == VK_RCONTROL) | |
2321 FROB (XEMSW_RCONTROL); | |
2322 if ((wParam == VK_CONTROL && !(lParam & 0x1000000)) | |
2323 || wParam == VK_LCONTROL) | |
2324 FROB (XEMSW_LCONTROL); | |
2325 | |
2326 if ((wParam == VK_SHIFT && (lParam & 0x1000000)) | |
2327 || wParam == VK_RSHIFT) | |
2328 FROB (XEMSW_RSHIFT); | |
2329 if ((wParam == VK_SHIFT && !(lParam & 0x1000000)) | |
2330 || wParam == VK_LSHIFT) | |
2331 FROB (XEMSW_LSHIFT); | |
2332 | |
2333 if ((wParam == VK_MENU && (lParam & 0x1000000)) | |
2334 || wParam == VK_RMENU) | |
2335 FROB (XEMSW_RMENU); | |
2336 if ((wParam == VK_MENU && !(lParam & 0x1000000)) | |
2337 || wParam == VK_LMENU) | |
2338 FROB (XEMSW_LMENU); | |
2339 } | |
2340 #undef FROB | |
2341 | |
2342 if (mods && downp) | |
2343 { | |
2344 BYTE keymap[256]; | |
2345 | |
2346 GetKeyboardState (keymap); | |
2347 | |
2348 if (mods & XEMSW_LCONTROL) | |
2349 { | |
2350 keymap [VK_CONTROL] |= 0x80; | |
2351 keymap [VK_LCONTROL] |= 0x80; | |
2352 } | |
2353 if (mods & XEMSW_RCONTROL) | |
2354 { | |
2355 keymap [VK_CONTROL] |= 0x80; | |
2356 keymap [VK_RCONTROL] |= 0x80; | |
2357 } | |
2358 | |
2359 if (mods & XEMSW_LSHIFT) | |
2360 { | |
2361 keymap [VK_SHIFT] |= 0x80; | |
2362 keymap [VK_LSHIFT] |= 0x80; | |
2363 } | |
2364 if (mods & XEMSW_RSHIFT) | |
2365 { | |
2366 keymap [VK_SHIFT] |= 0x80; | |
2367 keymap [VK_RSHIFT] |= 0x80; | |
2368 } | |
2369 | |
2370 if (mods & XEMSW_LMENU) | |
2371 { | |
2372 keymap [VK_MENU] |= 0x80; | |
2373 keymap [VK_LMENU] |= 0x80; | |
2374 } | |
2375 if (mods & XEMSW_RMENU) | |
2376 { | |
2377 keymap [VK_MENU] |= 0x80; | |
2378 keymap [VK_RMENU] |= 0x80; | |
2379 } | |
2380 | |
2381 SetKeyboardState (keymap); | |
2382 return 1; | |
2383 } | |
2384 | |
2385 return 0; | |
2386 } | |
2387 | |
2388 static void | |
2389 clear_sticky_modifiers (void) | |
2390 { | |
2391 need_to_add_mask = 0; | |
2392 last_downkey = 0; | |
2393 down_mask = 0; | |
2394 } | |
2395 | |
2396 #ifdef DEBUG_XEMACS | |
2397 | |
2398 #if 0 | |
2399 | |
2400 static void | |
2401 output_modifier_keyboard_state (void) | |
2402 { | |
2403 BYTE keymap[256]; | |
2404 | |
2405 GetKeyboardState (keymap); | |
2406 | |
2407 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
2408 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
2409 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
2410 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
2411 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
2412 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
2413 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
2414 stderr_out ("GetKeyboardState VK_CONTROL %d %d VK_LCONTROL %d %d VK_RCONTROL %d %d\n", | |
2415 keymap[VK_CONTROL] & 0x80 ? 1 : 0, | |
2416 keymap[VK_CONTROL] & 0x1 ? 1 : 0, | |
2417 keymap[VK_LCONTROL] & 0x80 ? 1 : 0, | |
2418 keymap[VK_LCONTROL] & 0x1 ? 1 : 0, | |
2419 keymap[VK_RCONTROL] & 0x80 ? 1 : 0, | |
2420 keymap[VK_RCONTROL] & 0x1 ? 1 : 0); | |
2421 stderr_out ("GetKeyboardState VK_SHIFT %d %d VK_LSHIFT %d %d VK_RSHIFT %d %d\n", | |
2422 keymap[VK_SHIFT] & 0x80 ? 1 : 0, | |
2423 keymap[VK_SHIFT] & 0x1 ? 1 : 0, | |
2424 keymap[VK_LSHIFT] & 0x80 ? 1 : 0, | |
2425 keymap[VK_LSHIFT] & 0x1 ? 1 : 0, | |
2426 keymap[VK_RSHIFT] & 0x80 ? 1 : 0, | |
2427 keymap[VK_RSHIFT] & 0x1 ? 1 : 0); | |
2428 } | |
2429 | |
2430 #endif | |
2431 | |
2432 /* try to debug the stuck-alt-key problem. | |
2433 | |
2434 #### this happens only inconsistently, and may only happen when using | |
2435 StickyKeys in the Win2000 accessibility section of the control panel, | |
2436 which is extremely broken for other reasons. */ | |
2437 | |
2438 static void | |
2439 output_alt_keyboard_state (void) | |
2440 { | |
2441 BYTE keymap[256]; | |
2442 SHORT keystate[3]; | |
1242 | 2443 /* SHORT asyncstate[3]; */ |
442 | 2444 |
2445 GetKeyboardState (keymap); | |
2446 keystate[0] = GetKeyState (VK_MENU); | |
2447 keystate[1] = GetKeyState (VK_LMENU); | |
2448 keystate[2] = GetKeyState (VK_RMENU); | |
2449 /* Doing this interferes with key processing. */ | |
2450 /* asyncstate[0] = GetAsyncKeyState (VK_MENU); */ | |
2451 /* asyncstate[1] = GetAsyncKeyState (VK_LMENU); */ | |
2452 /* asyncstate[2] = GetAsyncKeyState (VK_RMENU); */ | |
2453 | |
2454 stderr_out ("GetKeyboardState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
2455 keymap[VK_MENU] & 0x80 ? 1 : 0, | |
2456 keymap[VK_MENU] & 0x1 ? 1 : 0, | |
2457 keymap[VK_LMENU] & 0x80 ? 1 : 0, | |
2458 keymap[VK_LMENU] & 0x1 ? 1 : 0, | |
2459 keymap[VK_RMENU] & 0x80 ? 1 : 0, | |
2460 keymap[VK_RMENU] & 0x1 ? 1 : 0); | |
2461 stderr_out ("GetKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", | |
2462 keystate[0] & 0x8000 ? 1 : 0, | |
2463 keystate[0] & 0x1 ? 1 : 0, | |
2464 keystate[1] & 0x8000 ? 1 : 0, | |
2465 keystate[1] & 0x1 ? 1 : 0, | |
2466 keystate[2] & 0x8000 ? 1 : 0, | |
2467 keystate[2] & 0x1 ? 1 : 0); | |
2468 /* stderr_out ("GetAsyncKeyState VK_MENU %d %d VK_LMENU %d %d VK_RMENU %d %d\n", */ | |
2469 /* asyncstate[0] & 0x8000 ? 1 : 0, */ | |
2470 /* asyncstate[0] & 0x1 ? 1 : 0, */ | |
2471 /* asyncstate[1] & 0x8000 ? 1 : 0, */ | |
2472 /* asyncstate[1] & 0x1 ? 1 : 0, */ | |
2473 /* asyncstate[2] & 0x8000 ? 1 : 0, */ | |
2474 /* asyncstate[2] & 0x1 ? 1 : 0); */ | |
2475 } | |
2476 | |
2477 #endif /* DEBUG_XEMACS */ | |
2478 | |
2479 | |
440 | 2480 /* |
428 | 2481 * The windows procedure for the window class XEMACS_CLASS |
2482 */ | |
2483 LRESULT WINAPI | |
442 | 2484 mswindows_wnd_proc (HWND hwnd, UINT message_, WPARAM wParam, LPARAM lParam) |
428 | 2485 { |
1204 | 2486 /* Note: Remember to initialize emacs_event and event before use. This |
2487 code calls code that can GC. You must GCPRO before calling such | |
2488 code. */ | |
428 | 2489 Lisp_Object emacs_event = Qnil; |
2490 Lisp_Object fobj = Qnil; | |
2491 | |
440 | 2492 Lisp_Event *event; |
428 | 2493 struct frame *frame; |
647 | 2494 struct mswindows_frame *msframe; |
428 | 2495 |
3092 | 2496 #ifndef NEW_GC |
611 | 2497 /* If you hit this, rewrite the offending API call to occur after GC, |
2498 using register_post_gc_action(). */ | |
2499 assert (!gc_in_progress); | |
3263 | 2500 #endif /* not NEW_GC */ |
593 | 2501 |
2502 #ifdef DEBUG_XEMACS | |
2503 if (debug_mswindows_events) | |
2504 debug_output_mswin_message (hwnd, message_, wParam, lParam); | |
2505 #endif /* DEBUG_XEMACS */ | |
442 | 2506 |
771 | 2507 assert (!qxeGetWindowLong (hwnd, GWL_USERDATA)); |
442 | 2508 switch (message_) |
428 | 2509 { |
442 | 2510 case WM_DESTROYCLIPBOARD: |
771 | 2511 mswindows_handle_destroyclipboard (); |
442 | 2512 break; |
2513 | |
2514 case WM_ERASEBKGND: | |
2515 /* Erase background only during non-dynamic sizing */ | |
771 | 2516 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 2517 if (msframe->sizing && !mswindows_dynamic_frame_resize) |
2518 goto defproc; | |
2519 return 1; | |
2520 | |
2521 case WM_CLOSE: | |
2522 fobj = mswindows_find_frame (hwnd); | |
853 | 2523 mswindows_enqueue_misc_user_event (fobj, Qeval, list3 (Qdelete_frame, fobj, |
2524 Qt)); | |
440 | 2525 break; |
428 | 2526 |
442 | 2527 case WM_KEYUP: |
2528 case WM_SYSKEYUP: | |
2529 | |
2530 /* See Win95 comment under WM_KEYDOWN */ | |
2531 { | |
2532 BYTE keymap[256]; | |
2533 int should_set_keymap = 0; | |
2534 | |
2535 #ifdef DEBUG_XEMACS | |
593 | 2536 if (debug_mswindows_events > 2) |
2537 output_alt_keyboard_state (); | |
442 | 2538 #endif /* DEBUG_XEMACS */ |
2539 | |
2540 mswindows_handle_sticky_modifiers (wParam, lParam, 0, 1); | |
2541 if (wParam == VK_CONTROL) | |
2542 { | |
2543 GetKeyboardState (keymap); | |
2544 keymap [(lParam & 0x1000000) ? VK_RCONTROL : VK_LCONTROL] &= ~0x80; | |
2545 should_set_keymap = 1; | |
2546 } | |
2547 else if (wParam == VK_MENU) | |
2548 { | |
2549 GetKeyboardState (keymap); | |
2550 keymap [(lParam & 0x1000000) ? VK_RMENU : VK_LMENU] &= ~0x80; | |
2551 should_set_keymap = 1; | |
2552 } | |
2553 | |
2554 if (should_set_keymap) | |
1242 | 2555 /* && (message_ != WM_SYSKEYUP */ |
2556 /* || NILP (Vmenu_accelerator_enabled))) */ | |
428 | 2557 SetKeyboardState (keymap); |
2558 | |
2559 } | |
442 | 2560 |
2561 if (key_needs_default_processing_p (wParam)) | |
2562 goto defproc; | |
2563 else | |
2564 break; | |
2565 | |
2566 case WM_KEYDOWN: | |
2567 case WM_SYSKEYDOWN: | |
2568 | |
2569 /* In some locales the right-hand Alt key is labelled AltGr. This key | |
2570 * should produce alternative characters when combined with another key. | |
2571 * eg on a German keyboard pressing AltGr+q should produce '@'. | |
2572 * AltGr generates exactly the same keystrokes as LCtrl+RAlt. But if | |
2573 * TranslateMessage() is called with *any* combination of Ctrl+Alt down, | |
2574 * it translates as if AltGr were down. | |
2575 * We get round this by removing all modifiers from the keymap before | |
2576 * calling TranslateMessage() unless AltGr is *really* down. */ | |
428 | 2577 { |
442 | 2578 BYTE keymap_trans[256]; |
2579 BYTE keymap_orig[256]; | |
2580 BYTE keymap_sticky[256]; | |
771 | 2581 /* WARNING: XEmacs code paths are far more subtle than you |
2582 think. In particular, QUIT checking will query and remove | |
2583 events, including keyboard events, from the queue. (QUIT is | |
2584 definitely invoked from TO_INTERNAL_FORMAT().) If we do | |
2585 this recursively anywhere in the following code, it will | |
2586 mess certain things up -- in particular, the OS-provided | |
2587 sticky modifier code available as part of the accessibility | |
2588 package. | |
2589 | |
2590 (Academic question: If QUIT checking is supposed to be | |
2591 triggered only every 1/4 second, why is it getting | |
2592 consistently triggered here? I saw the problem | |
2593 consistently. Answer: It appears that, currently, | |
2594 sometimes the code to pump messages is wrapped with | |
2595 begin_dont_check_for_quit() and sometimes it isn't. (#### | |
2596 FIX THIS SHIT!) cmdloop.c, for example, has it, but not | |
2597 everywhere. The current games with avoiding QUIT mean that | |
2598 the 1/4-second timer consistently fires while | |
2599 dont_check_for_quit is set [which causes the quit check to | |
2600 get deferred but the flag is still on], and so the next | |
2601 time it's unset and we call QUIT is *right here*. | |
2602 | |
2603 In my stderr-proc ws I majorly cleaned up the whole shit by | |
2604 just wrapping all the entry points in dont_check_for_quit. | |
2605 This fixed the remaining bugs with C-g getting interpreted | |
2606 wrong.) | |
2607 | |
2608 #### We should probably wrap this whole function in | |
2609 begin_dont_check_for_quit(); but then we should set this | |
2610 back to 0 when handling a menu callback, which gets invoked | |
2611 from within this function, specifically from | |
2612 DefWindowProc(). (We already do the latter in my new | |
2613 stderr-proc ws, because in that ws next_event_internal() | |
2614 calls begin_dont_check_for_quit(). */ | |
2615 | |
2616 int count = begin_dont_check_for_quit (); | |
442 | 2617 int has_AltGr = mswindows_current_layout_has_AltGr (); |
502 | 2618 int mods = 0, mods_with_shift = 0; |
442 | 2619 int extendedp = lParam & 0x1000000; |
2620 Lisp_Object keysym; | |
2621 int sticky_changed; | |
2622 | |
2623 #ifdef DEBUG_XEMACS | |
593 | 2624 if (debug_mswindows_events > 2) |
2625 output_alt_keyboard_state (); | |
442 | 2626 #endif /* DEBUG_XEMACS */ |
2627 | |
2628 GetKeyboardState (keymap_orig); | |
2629 frame = XFRAME (mswindows_find_frame (hwnd)); | |
2630 if ((sticky_changed = | |
2631 mswindows_handle_sticky_modifiers (wParam, lParam, 1, 1))) | |
428 | 2632 { |
442 | 2633 GetKeyboardState (keymap_sticky); |
2634 if (keymap_sticky[VK_MENU] & 0x80) | |
2635 { | |
2636 message_ = WM_SYSKEYDOWN; | |
2637 /* We have to set the "context bit" so that the | |
2638 TranslateMessage() call below that generates the | |
2639 SYSCHAR message does its thing; see the documentation | |
2640 on WM_SYSKEYDOWN */ | |
2641 lParam |= 1 << 29; | |
2642 } | |
428 | 2643 } |
2644 else | |
442 | 2645 memcpy (keymap_sticky, keymap_orig, 256); |
2646 | |
2647 mods = mswindows_modifier_state (keymap_sticky, (DWORD) -1, has_AltGr); | |
502 | 2648 mods_with_shift = mods; |
442 | 2649 |
2650 /* Handle non-printables */ | |
2651 if (!NILP (keysym = mswindows_key_to_emacs_keysym (wParam, mods, | |
2652 extendedp))) | |
428 | 2653 { |
442 | 2654 mswindows_enqueue_keypress_event (hwnd, keysym, mods); |
2655 if (sticky_changed) | |
2656 SetKeyboardState (keymap_orig); | |
428 | 2657 } |
442 | 2658 else /* Normal keys & modifiers */ |
428 | 2659 { |
442 | 2660 POINT pnt = { LOWORD (GetMessagePos()), HIWORD (GetMessagePos()) }; |
2661 MSG msg, tranmsg; | |
1204 | 2662 #ifdef HAVE_MENUBARS |
442 | 2663 int potential_accelerator = 0; |
1204 | 2664 #endif |
442 | 2665 int got_accelerator = 0; |
771 | 2666 /* No need to gcpro because the event is already on a |
2667 queue when we retrieve it. */ | |
2668 Lisp_Object lastev = Qnil; | |
442 | 2669 |
2670 msg.hwnd = hwnd; | |
2671 msg.message = message_; | |
2672 msg.wParam = wParam; | |
2673 msg.lParam = lParam; | |
2674 msg.time = GetMessageTime(); | |
2675 msg.pt = pnt; | |
2676 | |
2677 /* GetKeyboardState() does not work as documented on Win95. We have | |
2678 * to loosely track Left and Right modifiers on behalf of the OS, | |
2679 * without screwing up Windows NT which tracks them properly. */ | |
2680 if (wParam == VK_CONTROL) | |
2681 { | |
2682 keymap_orig[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
2683 keymap_sticky[extendedp ? VK_RCONTROL : VK_LCONTROL] |= 0x80; | |
2684 } | |
2685 else if (wParam == VK_MENU) | |
2686 { | |
2687 keymap_orig[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | |
2688 keymap_sticky[extendedp ? VK_RMENU : VK_LMENU] |= 0x80; | |
2689 } | |
2690 | |
827 | 2691 #ifdef HAVE_MENUBARS |
442 | 2692 if (!NILP (Vmenu_accelerator_enabled) && |
2693 !(mods & XEMACS_MOD_SHIFT) && message_ == WM_SYSKEYDOWN) | |
2694 potential_accelerator = 1; | |
827 | 2695 #endif |
442 | 2696 |
2697 /* Remove shift modifier from an ascii character */ | |
2698 mods &= ~XEMACS_MOD_SHIFT; | |
2699 | |
2700 memcpy (keymap_trans, keymap_sticky, 256); | |
2701 | |
2702 /* Clear control and alt modifiers unless AltGr is pressed */ | |
2703 keymap_trans[VK_RCONTROL] = 0; | |
2704 keymap_trans[VK_LMENU] = 0; | |
2705 if (!has_AltGr || !(keymap_trans[VK_LCONTROL] & 0x80) | |
2706 || !(keymap_trans[VK_RMENU] & 0x80)) | |
2707 { | |
2708 keymap_trans[VK_LCONTROL] = 0; | |
2709 keymap_trans[VK_CONTROL] = 0; | |
2710 keymap_trans[VK_RMENU] = 0; | |
2711 keymap_trans[VK_MENU] = 0; | |
2712 } | |
2713 SetKeyboardState (keymap_trans); | |
2714 | |
2715 /* Maybe generate some WM_[SYS]CHARs in the queue */ | |
2716 TranslateMessage (&msg); | |
2717 | |
771 | 2718 while (qxePeekMessage (&tranmsg, hwnd, WM_CHAR, WM_CHAR, PM_REMOVE) |
2719 || qxePeekMessage (&tranmsg, hwnd, WM_SYSCHAR, WM_SYSCHAR, | |
2720 PM_REMOVE)) | |
442 | 2721 { |
502 | 2722 int mods_with_quit = mods; |
771 | 2723 int length; |
2724 Extbyte extchar[4]; | |
867 | 2725 Ibyte *intchar; |
2726 Ichar ch; | |
771 | 2727 |
2728 if (XEUNICODE_P) | |
2729 { | |
2730 length = unicode_char_to_text (tranmsg.wParam, extchar); | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2731 intchar = SIZED_EXTERNAL_TO_ITEXT (extchar, length, |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2732 Qmswindows_unicode); |
867 | 2733 ch = itext_ichar (intchar); |
771 | 2734 } |
2735 else | |
2736 { | |
2737 length = ansi_char_to_text (tranmsg.wParam, extchar); | |
2738 intchar = (convert_multibyte_to_internal_malloc | |
2739 (extchar, length, | |
2740 mswindows_locale_to_code_page | |
2741 /* See intl-win32.c for an explanation of | |
2742 the following */ | |
2743 ((LCID) GetKeyboardLayout (0) & 0xFFFF), | |
2744 NULL)); | |
867 | 2745 ch = itext_ichar (intchar); |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2746 xfree (intchar); |
771 | 2747 } |
442 | 2748 |
593 | 2749 #ifdef DEBUG_XEMACS |
2750 if (debug_mswindows_events) | |
2751 { | |
2752 stderr_out ("-> "); | |
2753 debug_output_mswin_message (tranmsg.hwnd, tranmsg.message, | |
2754 tranmsg.wParam, | |
2755 tranmsg.lParam); | |
2756 } | |
2757 #endif /* DEBUG_XEMACS */ | |
2758 | |
827 | 2759 #ifdef HAVE_MENUBARS |
1204 | 2760 if (potential_accelerator && !got_accelerator && |
2761 mswindows_char_is_accelerator (frame, ch)) | |
442 | 2762 { |
2763 got_accelerator = 1; | |
2764 break; | |
2765 } | |
827 | 2766 #endif /* HAVE_MENUBARS */ |
2767 | |
771 | 2768 lastev = mswindows_enqueue_keypress_event (hwnd, |
2769 make_char (ch), | |
2770 mods_with_quit); | |
442 | 2771 } /* while */ |
2772 | |
771 | 2773 /* Also figure out what the character would be in other |
2774 possible keyboard layouts, in this order: | |
2775 | |
2776 -- current language environment | |
2777 -- user default language environment | |
2778 -- system default language environment | |
2779 -- same three, but checking the underlying virtual key, | |
2780 and only paying attention if it's alphabetic | |
2781 -- US ASCII | |
2782 | |
2783 See events.h, struct key_data, for why we do this. | |
2784 */ | |
2785 | |
2786 if (!NILP (lastev)) | |
2787 { | |
2788 int i; | |
2789 int scan = (lParam >> 16) && 0xFF; | |
2790 | |
2791 for (i = 0; i < KEYCHAR_LAST; i++) | |
2792 { | |
2793 int vk_only = 0; | |
2794 LCID lcid; | |
2795 int virtual_key; | |
2796 | |
2797 switch (i) | |
2798 { | |
2799 case KEYCHAR_UNDERLYING_VIRTUAL_KEY_CURRENT_LANGENV: | |
2800 vk_only = 1; | |
2801 case KEYCHAR_CURRENT_LANGENV: | |
2802 lcid = mswindows_current_locale (); | |
2803 break; | |
2804 | |
2805 case KEYCHAR_UNDERLYING_VIRTUAL_KEY_DEFAULT_USER: | |
2806 vk_only = 1; | |
2807 case KEYCHAR_DEFAULT_USER: | |
2808 lcid = GetUserDefaultLCID (); | |
2809 break; | |
2810 | |
2811 case KEYCHAR_UNDERLYING_VIRTUAL_KEY_DEFAULT_SYSTEM: | |
2812 vk_only = 1; | |
2813 case KEYCHAR_DEFAULT_SYSTEM: | |
2814 lcid = GetSystemDefaultLCID (); | |
2815 break; | |
2816 | |
2817 case KEYCHAR_QWERTY: | |
2818 lcid = MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US); | |
2819 break; | |
2820 | |
2500 | 2821 default: ABORT (); lcid = 0; |
771 | 2822 } |
2823 | |
2824 /* VERY CONFUSING! See intl-win32.c. */ | |
2825 lcid = lcid & 0xFFFF; | |
2826 | |
800 | 2827 virtual_key = qxeMapVirtualKeyEx (scan, 1, (HKL) lcid); |
771 | 2828 if (!vk_only) |
2829 { | |
2830 if (XEUNICODE_P) | |
2831 { | |
2832 Extbyte received_keys[32]; | |
2833 int tounret = | |
2834 ToUnicodeEx | |
2835 (virtual_key, scan, keymap_trans, | |
2836 (LPWSTR) received_keys, | |
2837 sizeof (received_keys) / XETCHAR_SIZE, | |
2838 0, /* #### what about this flag? "if | |
2839 bit 0 is set, a menu is | |
2840 active???" */ | |
2841 (HKL) lcid); | |
2842 if (tounret > 0) | |
2843 { | |
867 | 2844 Ibyte *intchar; |
771 | 2845 |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2846 intchar = |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2847 SIZED_EXTERNAL_TO_ITEXT |
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2848 (received_keys + (tounret - 1) * 2, 2, |
771 | 2849 Qmswindows_unicode); |
1204 | 2850 XSET_EVENT_KEY_ALT_KEYCHARS |
2851 (lastev, i, itext_ichar (intchar)); | |
771 | 2852 } |
2853 } | |
2854 else | |
2855 { | |
2856 WORD received_keys[32]; | |
2857 int tounret = | |
2858 ToAsciiEx (virtual_key, scan, keymap_trans, | |
2859 received_keys, | |
2860 0, /* #### what about this | |
2861 flag? "if bit 0 is set, a | |
2862 menu is active???" */ | |
2863 (HKL) lcid); | |
2864 if (tounret > 0) | |
2865 { | |
2866 /* #### I cannot find proper | |
2867 documentation on what format the | |
2868 return value is in. I'm assuming | |
2869 it's like WM_IME_CHAR: DBCS chars | |
2870 have the lead byte in bits 8-15 of | |
2871 the short. */ | |
867 | 2872 Ibyte *intchar; |
771 | 2873 Extbyte mbstuff[2]; |
2874 Bytecount mblength = 0; | |
2875 WORD thechar = received_keys[tounret - 1]; | |
2876 | |
2877 mbstuff[mblength++] = | |
2878 (Extbyte) (thechar & 0xFF); | |
2879 if (thechar > 0xFF) | |
2880 mbstuff[mblength++] = | |
2881 (Extbyte) ((thechar >> 8) & 0xFF); | |
2882 | |
2883 intchar = convert_multibyte_to_internal_malloc | |
2884 (mbstuff, mblength, | |
2885 mswindows_locale_to_code_page (lcid), | |
2886 NULL); | |
2887 | |
1204 | 2888 XSET_EVENT_KEY_ALT_KEYCHARS |
2889 (lastev, i, itext_ichar (intchar)); | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
2890 xfree (intchar); |
771 | 2891 } |
2892 } | |
2893 } | |
2894 else | |
2895 { | |
867 | 2896 Ichar altch; |
771 | 2897 |
2898 if (virtual_key >= 'A' && virtual_key <= 'Z') | |
2899 altch = | |
2900 virtual_key + (mods_with_shift & XEMACS_MOD_SHIFT ? | |
2901 'a' - 'A' : 0); | |
2902 else | |
2903 altch = 0; | |
2904 | |
1204 | 2905 XSET_EVENT_KEY_ALT_KEYCHARS (lastev, i, altch); |
771 | 2906 } |
2907 } | |
2908 } | |
2909 | |
442 | 2910 /* This generates WM_SYSCHAR messages, which are interpreted |
2911 by DefWindowProc as the menu selections. */ | |
2912 if (got_accelerator) | |
2913 { | |
2914 SetKeyboardState (keymap_sticky); | |
2915 TranslateMessage (&msg); | |
2916 SetKeyboardState (keymap_orig); | |
771 | 2917 unbind_to (count); |
442 | 2918 goto defproc; |
2919 } | |
2920 | |
2921 SetKeyboardState (keymap_orig); | |
2922 } /* else */ | |
771 | 2923 |
2924 if (key_needs_default_processing_p (wParam)) | |
2925 { | |
2926 unbind_to (count); | |
2927 goto defproc; | |
2928 } | |
2929 else | |
2930 { | |
2931 unbind_to (count); | |
2932 break; | |
2933 } | |
428 | 2934 } |
442 | 2935 |
2936 case WM_MBUTTONDOWN: | |
2937 case WM_MBUTTONUP: | |
2938 /* Real middle mouse button has nothing to do with emulated one: | |
2939 if one wants to exercise fingers playing chords on the mouse, | |
2940 he is allowed to do that! */ | |
2941 mswindows_enqueue_mouse_button_event (hwnd, message_, | |
2367 | 2942 XE_MAKEPOINTS (lParam), |
442 | 2943 wParam &~ MK_MBUTTON, |
2944 GetMessageTime()); | |
2945 break; | |
2946 | |
2947 case WM_LBUTTONUP: | |
771 | 2948 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
2949 msframe->last_click_time = GetMessageTime(); | |
442 | 2950 |
2951 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2952 msframe->button2_need_lbutton = 0; | |
2953 if (msframe->ignore_next_lbutton_up) | |
2954 { | |
2955 msframe->ignore_next_lbutton_up = 0; | |
2956 } | |
2957 else if (msframe->button2_is_down) | |
2958 { | |
2959 msframe->button2_is_down = 0; | |
2960 msframe->ignore_next_rbutton_up = 1; | |
2961 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
2367 | 2962 XE_MAKEPOINTS (lParam), |
442 | 2963 wParam |
2964 &~ (MK_LBUTTON | MK_MBUTTON | |
2965 | MK_RBUTTON), | |
2966 GetMessageTime()); | |
2967 } | |
2968 else | |
2969 { | |
2970 if (msframe->button2_need_rbutton) | |
2971 { | |
2972 msframe->button2_need_rbutton = 0; | |
2973 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
2367 | 2974 XE_MAKEPOINTS (lParam), |
442 | 2975 wParam &~ MK_LBUTTON, |
2976 GetMessageTime()); | |
2977 } | |
2978 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONUP, | |
2367 | 2979 XE_MAKEPOINTS (lParam), |
442 | 2980 wParam &~ MK_LBUTTON, |
2981 GetMessageTime()); | |
2982 } | |
2983 break; | |
2984 | |
2985 case WM_RBUTTONUP: | |
771 | 2986 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
2987 msframe->last_click_time = GetMessageTime(); | |
442 | 2988 |
2989 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
2990 msframe->button2_need_rbutton = 0; | |
2991 if (msframe->ignore_next_rbutton_up) | |
2992 { | |
2993 msframe->ignore_next_rbutton_up = 0; | |
2994 } | |
2995 else if (msframe->button2_is_down) | |
2996 { | |
2997 msframe->button2_is_down = 0; | |
2998 msframe->ignore_next_lbutton_up = 1; | |
2999 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONUP, | |
2367 | 3000 XE_MAKEPOINTS (lParam), |
442 | 3001 wParam |
3002 &~ (MK_LBUTTON | MK_MBUTTON | |
3003 | MK_RBUTTON), | |
3004 GetMessageTime()); | |
3005 } | |
3006 else | |
3007 { | |
3008 if (msframe->button2_need_lbutton) | |
3009 { | |
3010 msframe->button2_need_lbutton = 0; | |
3011 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2367 | 3012 XE_MAKEPOINTS (lParam), |
442 | 3013 wParam &~ MK_RBUTTON, |
3014 GetMessageTime()); | |
3015 } | |
3016 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONUP, | |
2367 | 3017 XE_MAKEPOINTS (lParam), |
442 | 3018 wParam &~ MK_RBUTTON, |
3019 GetMessageTime()); | |
3020 } | |
3021 break; | |
3022 | |
3023 case WM_LBUTTONDOWN: | |
771 | 3024 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3025 |
3026 if (msframe->button2_need_lbutton) | |
428 | 3027 { |
3028 KillTimer (hwnd, BUTTON_2_TIMER_ID); | |
442 | 3029 msframe->button2_need_lbutton = 0; |
3030 msframe->button2_need_rbutton = 0; | |
3031 if (mswindows_button2_near_enough (msframe->last_click_point, | |
2367 | 3032 XE_MAKEPOINTS (lParam))) |
428 | 3033 { |
442 | 3034 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, |
2367 | 3035 XE_MAKEPOINTS (lParam), |
442 | 3036 wParam |
3037 &~ (MK_LBUTTON | MK_MBUTTON | |
3038 | MK_RBUTTON), | |
3039 GetMessageTime()); | |
3040 msframe->button2_is_down = 1; | |
428 | 3041 } |
442 | 3042 else |
428 | 3043 { |
442 | 3044 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, |
3045 msframe->last_click_point, | |
3046 msframe->last_click_mods | |
3047 &~ MK_RBUTTON, | |
3048 msframe->last_click_time); | |
3049 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
2367 | 3050 XE_MAKEPOINTS (lParam), |
442 | 3051 wParam &~ MK_LBUTTON, |
3052 GetMessageTime()); | |
428 | 3053 } |
3054 } | |
3055 else | |
442 | 3056 { |
3057 mswindows_set_chord_timer (hwnd); | |
3058 msframe->button2_need_rbutton = 1; | |
2367 | 3059 msframe->last_click_point = XE_MAKEPOINTS (lParam); |
442 | 3060 msframe->last_click_mods = wParam; |
3061 } | |
771 | 3062 msframe->last_click_time = GetMessageTime(); |
442 | 3063 break; |
3064 | |
3065 case WM_RBUTTONDOWN: | |
771 | 3066 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3067 |
3068 if (msframe->button2_need_rbutton) | |
428 | 3069 { |
442 | 3070 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
3071 msframe->button2_need_lbutton = 0; | |
3072 msframe->button2_need_rbutton = 0; | |
3073 if (mswindows_button2_near_enough (msframe->last_click_point, | |
2367 | 3074 XE_MAKEPOINTS (lParam))) |
442 | 3075 { |
3076 mswindows_enqueue_mouse_button_event (hwnd, WM_MBUTTONDOWN, | |
2367 | 3077 XE_MAKEPOINTS (lParam), |
442 | 3078 wParam |
3079 &~ (MK_LBUTTON | MK_MBUTTON | |
3080 | MK_RBUTTON), | |
3081 GetMessageTime()); | |
3082 msframe->button2_is_down = 1; | |
3083 } | |
3084 else | |
3085 { | |
3086 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
3087 msframe->last_click_point, | |
3088 msframe->last_click_mods | |
3089 &~ MK_LBUTTON, | |
3090 msframe->last_click_time); | |
3091 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
2367 | 3092 XE_MAKEPOINTS (lParam), |
442 | 3093 wParam &~ MK_RBUTTON, |
3094 GetMessageTime()); | |
3095 } | |
428 | 3096 } |
3097 else | |
3098 { | |
442 | 3099 mswindows_set_chord_timer (hwnd); |
3100 msframe->button2_need_lbutton = 1; | |
2367 | 3101 msframe->last_click_point = XE_MAKEPOINTS (lParam); |
442 | 3102 msframe->last_click_mods = wParam; |
3103 } | |
771 | 3104 msframe->last_click_time = GetMessageTime(); |
442 | 3105 break; |
3106 | |
3107 case WM_TIMER: | |
3108 if (wParam == BUTTON_2_TIMER_ID) | |
3109 { | |
771 | 3110 msframe = |
3111 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); | |
442 | 3112 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
3113 | |
3114 if (msframe->button2_need_lbutton) | |
3115 { | |
3116 msframe->button2_need_lbutton = 0; | |
3117 mswindows_enqueue_mouse_button_event (hwnd, WM_RBUTTONDOWN, | |
3118 msframe->last_click_point, | |
3119 msframe->last_click_mods | |
3120 &~ MK_RBUTTON, | |
3121 msframe->last_click_time); | |
3122 } | |
3123 else if (msframe->button2_need_rbutton) | |
3124 { | |
3125 msframe->button2_need_rbutton = 0; | |
3126 mswindows_enqueue_mouse_button_event (hwnd, WM_LBUTTONDOWN, | |
3127 msframe->last_click_point, | |
3128 msframe->last_click_mods | |
3129 &~ MK_LBUTTON, | |
3130 msframe->last_click_time); | |
3131 } | |
3132 } | |
3133 else | |
3134 assert ("Spurious timer fired" == 0); | |
3135 break; | |
3136 | |
3137 case WM_MOUSEMOVE: | |
3138 /* Optimization: don't report mouse movement while size is changing */ | |
771 | 3139 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3140 if (!msframe->sizing) |
3141 { | |
3142 /* When waiting for the second mouse button to finish | |
3143 button2 emulation, and have moved too far, just pretend | |
3144 as if timer has expired. This improves drag-select feedback */ | |
3145 if ((msframe->button2_need_lbutton || msframe->button2_need_rbutton) | |
3146 && !mswindows_button2_near_enough (msframe->last_click_point, | |
2367 | 3147 XE_MAKEPOINTS (lParam))) |
428 | 3148 { |
442 | 3149 KillTimer (hwnd, BUTTON_2_TIMER_ID); |
771 | 3150 qxeSendMessage (hwnd, WM_TIMER, BUTTON_2_TIMER_ID, 0); |
442 | 3151 } |
3152 | |
3153 emacs_event = Fmake_event (Qnil, Qnil); | |
3154 event = XEVENT(emacs_event); | |
3155 | |
964 | 3156 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_frame(hwnd)); |
3157 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime()); | |
3158 XSET_EVENT_TYPE (emacs_event, pointer_motion_event); | |
2367 | 3159 XSET_EVENT_MOTION_X (emacs_event, XE_MAKEPOINTS (lParam).x); |
3160 XSET_EVENT_MOTION_Y (emacs_event, XE_MAKEPOINTS (lParam).y); | |
1204 | 3161 XSET_EVENT_MOTION_MODIFIERS (emacs_event, |
964 | 3162 mswindows_modifier_state (NULL, wParam, 0)); |
442 | 3163 |
3164 mswindows_enqueue_dispatch_event (emacs_event); | |
3165 } | |
3166 break; | |
3167 | |
3168 case WM_CANCELMODE: | |
3169 ReleaseCapture (); | |
3170 /* Queue a `cancel-mode-internal' misc user event, so mouse | |
3171 selection would be canceled if any */ | |
3172 mswindows_enqueue_misc_user_event (mswindows_find_frame (hwnd), | |
3173 Qcancel_mode_internal, Qnil); | |
3174 break; | |
3175 | |
3176 case WM_NOTIFY: | |
3177 { | |
647 | 3178 LPNMHDR nmhdr = (LPNMHDR) lParam; |
3179 | |
1111 | 3180 if (nmhdr->code == TTN_NEEDTEXT) |
442 | 3181 { |
3182 #ifdef HAVE_TOOLBARS | |
771 | 3183 LPTOOLTIPTEXTW tttextw = (LPTOOLTIPTEXTW) lParam; |
442 | 3184 Lisp_Object btext; |
771 | 3185 Extbyte *btextext = 0; |
442 | 3186 |
3187 /* find out which toolbar */ | |
3188 frame = XFRAME (mswindows_find_frame (hwnd)); | |
647 | 3189 btext = mswindows_get_toolbar_button_text (frame, nmhdr->idFrom); |
442 | 3190 |
771 | 3191 tttextw->hinst = NULL; |
3192 | |
3193 if (!NILP (btext)) | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
3194 btextext = LISP_STRING_TO_TSTR (btext); |
771 | 3195 |
3196 if (btextext) | |
442 | 3197 { |
771 | 3198 /* WARNING: We can't just write a '\0' into the 79th |
3199 "character" because tttextw->szText is in WCHAR's but we | |
3200 may be copying an ANSI string into it. Easiest to just | |
3201 zero the whole thing. */ | |
3202 xzero (*tttextw->szText); | |
2421 | 3203 qxetcsncpy ((Extbyte *) tttextw->szText, btextext, 79); |
442 | 3204 } |
771 | 3205 else |
3206 tttextw->lpszText = NULL; | |
442 | 3207 #endif |
3208 } | |
3209 /* handle tree view callbacks */ | |
1111 | 3210 else if (nmhdr->code == TVN_SELCHANGED) |
442 | 3211 { |
647 | 3212 NM_TREEVIEW *ptree = (NM_TREEVIEW *) lParam; |
442 | 3213 frame = XFRAME (mswindows_find_frame (hwnd)); |
3214 mswindows_handle_gui_wm_command (frame, 0, ptree->itemNew.lParam); | |
3215 } | |
3216 /* handle tab control callbacks */ | |
1111 | 3217 else if (nmhdr->code == TCN_SELCHANGE) |
442 | 3218 { |
3219 TC_ITEM item; | |
771 | 3220 int idx = qxeSendMessage (nmhdr->hwndFrom, TCM_GETCURSEL, 0, 0); |
442 | 3221 frame = XFRAME (mswindows_find_frame (hwnd)); |
3222 | |
3223 item.mask = TCIF_PARAM; | |
771 | 3224 qxeSendMessage (nmhdr->hwndFrom, TCM_GETITEM, (WPARAM) idx, |
3225 (LPARAM) &item); | |
442 | 3226 |
3227 mswindows_handle_gui_wm_command (frame, 0, item.lParam); | |
3228 } | |
3229 } | |
3230 break; | |
3231 | |
3232 case WM_PAINT: | |
3233 /* hdc will be NULL unless this is a subwindow - in which case we | |
3234 shouldn't have received a paint message for it here. */ | |
3235 assert (wParam == 0); | |
3236 | |
3237 /* Can't queue a magic event because windows goes modal and sends paint | |
3238 messages directly to the windows procedure when doing solid drags | |
3239 and the message queue doesn't get processed. */ | |
3240 mswindows_handle_paint (XFRAME (mswindows_find_frame (hwnd))); | |
3241 break; | |
3242 | |
903 | 3243 case WM_ACTIVATE: |
3244 { | |
3245 /* | |
3246 * If we receive a WM_ACTIVATE message that indicates that our frame | |
3247 * is being activated, make sure that the frame is marked visible | |
3248 * if the window itself is visible. This seems to fix the problem | |
3249 * where XEmacs appears to lock-up after switching desktops with | |
3250 * some virtual window managers. | |
3251 */ | |
3252 int state = (int)(short) LOWORD(wParam); | |
3253 #ifdef DEBUG_XEMACS | |
3254 if (debug_mswindows_events) | |
3255 stderr_out("state = %d\n", state); | |
3256 #endif /* DEBUG_XEMACS */ | |
3257 if (state == WA_ACTIVE || state == WA_CLICKACTIVE) | |
3258 { | |
3259 #ifdef DEBUG_XEMACS | |
3260 if (debug_mswindows_events) | |
3261 stderr_out(" activating\n"); | |
3262 #endif /* DEBUG_XEMACS */ | |
3263 | |
3264 fobj = mswindows_find_frame (hwnd); | |
3265 frame = XFRAME (fobj); | |
3266 if (IsWindowVisible (hwnd)) | |
3267 { | |
3268 #ifdef DEBUG_XEMACS | |
3269 if (debug_mswindows_events) | |
3270 stderr_out(" window is visible\n"); | |
3271 #endif /* DEBUG_XEMACS */ | |
3272 if (!FRAME_VISIBLE_P (frame)) | |
3273 { | |
3274 #ifdef DEBUG_XEMACS | |
3275 if (debug_mswindows_events) | |
3276 stderr_out(" frame is not visible\n"); | |
3277 #endif /* DEBUG_XEMACS */ | |
3278 /* | |
3279 * It seems that we have to enqueue the XM_MAPFRAME event | |
3280 * prior to setting the frame visible so that | |
3281 * suspend-or-iconify-emacs works properly. | |
3282 */ | |
3283 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
3284 FRAME_VISIBLE_P (frame) = 1; | |
3285 FRAME_ICONIFIED_P (frame) = 0; | |
3286 } | |
3287 #ifdef DEBUG_XEMACS | |
3288 else | |
3289 { | |
3290 if (debug_mswindows_events) | |
3291 stderr_out(" frame is visible\n"); | |
3292 } | |
3293 #endif /* DEBUG_XEMACS */ | |
3294 } | |
3295 #ifdef DEBUG_XEMACS | |
3296 else | |
3297 { | |
3298 if (debug_mswindows_events) | |
3299 stderr_out(" window is not visible\n"); | |
3300 } | |
3301 #endif /* DEBUG_XEMACS */ | |
3302 } | |
3303 return qxeDefWindowProc (hwnd, message_, wParam, lParam); | |
3304 } | |
3305 break; | |
3306 | |
593 | 3307 case WM_WINDOWPOSCHANGED: |
3308 /* This is sent before WM_SIZE; in fact, the processing of this | |
3309 by DefWindowProc() sends WM_SIZE. But WM_SIZE is not sent when | |
3310 a window is hidden (make-frame-invisible), so we need to process | |
3311 this and update the state flags. */ | |
3312 { | |
3313 fobj = mswindows_find_frame (hwnd); | |
3314 frame = XFRAME (fobj); | |
3315 if (IsIconic (hwnd)) | |
3316 { | |
3317 FRAME_VISIBLE_P (frame) = 0; | |
3318 FRAME_ICONIFIED_P (frame) = 1; | |
3319 } | |
3320 else if (IsWindowVisible (hwnd)) | |
3321 { | |
707 | 3322 /* APA: It's too early here to set the frame visible. |
3323 * Let's do this later, in WM_SIZE processing, after the | |
3324 * magic XM_MAPFRAME event has been sent (just like 21.1 | |
3325 * did). */ | |
3326 /* FRAME_VISIBLE_P (frame) = 1; */ | |
593 | 3327 FRAME_ICONIFIED_P (frame) = 0; |
3328 } | |
3329 else | |
3330 { | |
3331 FRAME_VISIBLE_P (frame) = 0; | |
3332 FRAME_ICONIFIED_P (frame) = 0; | |
3333 } | |
3334 | |
771 | 3335 goto defproc; |
593 | 3336 } |
3337 | |
731 | 3338 case WM_SHOWWINDOW: |
3339 /* | |
3340 The WM_SHOWWINDOW message is sent to a window when the window | |
3341 is about to be hidden or shown. | |
3342 APA: This message is also sent when switching to a virtual | |
3343 desktop under the virtuawin virtual window manager. | |
3344 | |
3345 */ | |
3346 { | |
3347 fobj = mswindows_find_frame (hwnd); | |
3348 frame = XFRAME (fobj); | |
3349 if (wParam == TRUE) | |
3350 { | |
3351 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
3352 FRAME_VISIBLE_P (frame) = 1; | |
3353 } | |
3354 else | |
3355 { | |
3356 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
3357 FRAME_VISIBLE_P (frame) = 0; | |
3358 } | |
3359 } | |
3360 break; | |
3361 | |
442 | 3362 case WM_SIZE: |
3363 /* We only care about this message if our size has really changed */ | |
771 | 3364 if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED || |
3365 wParam == SIZE_MINIMIZED) | |
442 | 3366 { |
3367 RECT rect; | |
3368 int columns, rows; | |
3369 | |
3370 fobj = mswindows_find_frame (hwnd); | |
3371 frame = XFRAME (fobj); | |
771 | 3372 msframe = FRAME_MSWINDOWS_DATA (frame); |
442 | 3373 |
3374 /* We cannot handle frame map and unmap hooks right in | |
3375 this routine, because these may throw. We queue | |
3376 magic events to run these hooks instead - kkm */ | |
3377 | |
771 | 3378 if (wParam == SIZE_MINIMIZED) |
442 | 3379 { |
3380 /* Iconified */ | |
3381 mswindows_enqueue_magic_event (hwnd, XM_UNMAPFRAME); | |
428 | 3382 } |
3383 else | |
3384 { | |
1279 | 3385 GetClientRect (hwnd, &rect); |
3386 FRAME_PIXWIDTH (frame) = rect.right; | |
3387 FRAME_PIXHEIGHT (frame) = rect.bottom; | |
442 | 3388 |
5043 | 3389 pixel_to_frame_unit_size (frame, rect.right, rect.bottom, &columns, |
771 | 3390 &rows); |
5043 | 3391 change_frame_size (frame, columns, rows, 1); |
442 | 3392 |
3393 /* If we are inside frame creation, we have to apply geometric | |
3394 properties now. */ | |
3395 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
3396 { | |
3397 /* Yes, we have to size again */ | |
771 | 3398 mswindows_size_frame_internal (frame, |
3399 FRAME_MSWINDOWS_TARGET_RECT | |
3400 (frame)); | |
3401 /* Reset so we do not get here again. The SetWindowPos | |
3402 * call in mswindows_size_frame_internal can cause | |
3403 * recursion here. */ | |
442 | 3404 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) |
3405 { | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
3406 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); |
442 | 3407 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; |
3408 } | |
3409 } | |
3410 else | |
3411 { | |
903 | 3412 if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) |
3413 { | |
3414 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
3415 /* APA: Now that the magic XM_MAPFRAME event has | |
3416 * been sent we can mark the frame as visible (just | |
3417 * like 21.1 did). */ | |
3418 FRAME_VISIBLE_P (frame) = 1; | |
3419 } | |
442 | 3420 |
1279 | 3421 if (frame->init_finished && |
3422 (!msframe->sizing || mswindows_dynamic_frame_resize)) | |
442 | 3423 redisplay (); |
3424 } | |
428 | 3425 } |
3426 } | |
442 | 3427 break; |
3428 | |
3429 case WM_DISPLAYCHANGE: | |
3430 { | |
3431 struct device *d; | |
3432 DWORD message_tick = GetMessageTime (); | |
3433 | |
3434 fobj = mswindows_find_frame (hwnd); | |
3435 frame = XFRAME (fobj); | |
3436 d = XDEVICE (FRAME_DEVICE (frame)); | |
3437 | |
3438 /* Do this only once per message. XEmacs can receive this message | |
3439 through as many frames as it currently has open. Message time | |
3440 will be the same for all these messages. Despite extreme | |
3441 efficiency, the code below has about one in 4 billion | |
3442 probability that the HDC is not recreated, provided that | |
3443 XEmacs is running sufficiently longer than 52 days. */ | |
1279 | 3444 if (DEVICE_MSWINDOWS_UPDATE_TICK (d) != message_tick) |
442 | 3445 { |
1279 | 3446 DEVICE_MSWINDOWS_UPDATE_TICK (d) = message_tick; |
3447 DeleteDC (DEVICE_MSWINDOWS_HCDC (d)); | |
3448 DEVICE_MSWINDOWS_HCDC (d) = CreateCompatibleDC (NULL); | |
442 | 3449 } |
3450 } | |
3451 break; | |
3452 | |
3453 /* Misc magic events which only require that the frame be identified */ | |
3454 case WM_SETFOCUS: | |
3455 case WM_KILLFOCUS: | |
3456 mswindows_enqueue_magic_event (hwnd, message_); | |
3457 break; | |
3458 | |
3459 case WM_WINDOWPOSCHANGING: | |
428 | 3460 { |
442 | 3461 WINDOWPOS *wp = (LPWINDOWPOS) lParam; |
3462 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
3463 GetWindowPlacement(hwnd, &wpl); | |
3464 | |
3465 /* Only interested if size is changing and we're not being iconified */ | |
3466 if (wpl.showCmd != SW_SHOWMINIMIZED | |
3467 && wpl.showCmd != SW_SHOWMAXIMIZED | |
3468 && !(wp->flags & SWP_NOSIZE)) | |
428 | 3469 { |
442 | 3470 RECT ncsize = { 0, 0, 0, 0 }; |
3471 int pixwidth, pixheight; | |
771 | 3472 AdjustWindowRectEx (&ncsize, qxeGetWindowLong (hwnd, GWL_STYLE), |
442 | 3473 GetMenu(hwnd) != NULL, |
771 | 3474 qxeGetWindowLong (hwnd, GWL_EXSTYLE)); |
442 | 3475 |
5043 | 3476 round_size_to_char (XFRAME (mswindows_find_frame (hwnd)), |
442 | 3477 wp->cx - (ncsize.right - ncsize.left), |
3478 wp->cy - (ncsize.bottom - ncsize.top), | |
3479 &pixwidth, &pixheight); | |
3480 | |
3481 /* Convert client sizes to window sizes */ | |
3482 pixwidth += (ncsize.right - ncsize.left); | |
3483 pixheight += (ncsize.bottom - ncsize.top); | |
3484 | |
3485 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
3486 { | |
3487 /* Adjust so that the bottom or right doesn't move if it's | |
3488 * the top or left that's being changed */ | |
3489 RECT rect; | |
3490 GetWindowRect (hwnd, &rect); | |
3491 | |
3492 if (rect.left != wp->x) | |
3493 wp->x += wp->cx - pixwidth; | |
3494 if (rect.top != wp->y) | |
3495 wp->y += wp->cy - pixheight; | |
3496 } | |
3497 | |
3498 wp->cx = pixwidth; | |
3499 wp->cy = pixheight; | |
428 | 3500 } |
442 | 3501 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts |
3502 window position if the user tries to track window too small */ | |
428 | 3503 } |
442 | 3504 goto defproc; |
3505 | |
3506 case WM_ENTERSIZEMOVE: | |
771 | 3507 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3508 msframe->sizing = 1; |
3509 return 0; | |
3510 | |
3511 case WM_EXITSIZEMOVE: | |
771 | 3512 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3513 msframe->sizing = 0; |
3514 /* Queue noop event */ | |
3515 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
3516 return 0; | |
428 | 3517 |
3518 #ifdef HAVE_SCROLLBARS | |
442 | 3519 case WM_VSCROLL: |
3520 case WM_HSCROLL: | |
3521 { | |
3522 /* Direction of scroll is determined by scrollbar instance. */ | |
1279 | 3523 int code = (int) LOWORD (wParam); |
3524 int pos = (short int) HIWORD (wParam); | |
442 | 3525 HWND hwndScrollBar = (HWND) lParam; |
3526 struct gcpro gcpro1, gcpro2; | |
3527 | |
3528 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
3529 GCPRO2 (emacs_event, fobj); | |
853 | 3530 if (UNBOUNDP (mswindows_pump_outstanding_events ())) /* Can GC */ |
442 | 3531 { |
3532 /* Error during event pumping - cancel scroll */ | |
771 | 3533 qxeSendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); |
442 | 3534 } |
3535 UNGCPRO; | |
3536 break; | |
3537 } | |
3538 | |
3539 case WM_MOUSEWHEEL: | |
3540 { | |
3541 int keys = LOWORD (wParam); /* Modifier key flags */ | |
3542 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ | |
3543 | |
1622 | 3544 /* enqueue button4/5 events if mswindows_handle_mousewheel_event |
3545 doesn't handle the event, such as when the scrollbars are not | |
3546 displayed */ | |
3547 if (!mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), | |
464 | 3548 keys, delta, |
2367 | 3549 XE_MAKEPOINTS (lParam))) |
1622 | 3550 mswindows_enqueue_mouse_button_event (hwnd, message_, |
2367 | 3551 XE_MAKEPOINTS (lParam), |
1622 | 3552 wParam, |
3553 GetMessageTime()); | |
3554 /* We are not in a modal loop so no pumping is necessary. */ | |
3555 break; | |
442 | 3556 } |
428 | 3557 #endif |
3558 | |
3559 #ifdef HAVE_MENUBARS | |
442 | 3560 case WM_INITMENU: |
771 | 3561 if (UNBOUNDP (mswindows_handle_wm_initmenu |
3562 ((HMENU) wParam, | |
3563 XFRAME (mswindows_find_frame (hwnd))))) | |
3564 qxeSendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
442 | 3565 break; |
3566 | |
3567 case WM_INITMENUPOPUP: | |
3568 if (!HIWORD(lParam)) | |
3569 { | |
771 | 3570 if (UNBOUNDP (mswindows_handle_wm_initmenupopup |
3571 ((HMENU) wParam, | |
3572 XFRAME (mswindows_find_frame (hwnd))))) | |
3573 qxeSendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
442 | 3574 } |
3575 break; | |
428 | 3576 |
3577 #endif /* HAVE_MENUBARS */ | |
3578 | |
442 | 3579 case WM_COMMAND: |
3580 { | |
3581 WORD id = LOWORD (wParam); | |
3582 WORD nid = HIWORD (wParam); | |
3583 HWND cid = (HWND)lParam; | |
3584 frame = XFRAME (mswindows_find_frame (hwnd)); | |
428 | 3585 |
3586 #ifdef HAVE_TOOLBARS | |
442 | 3587 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) |
3588 break; | |
428 | 3589 #endif |
771 | 3590 /* widgets in a buffer only eval a callback for suitable events. */ |
442 | 3591 switch (nid) |
3592 { | |
3593 case BN_CLICKED: | |
3594 case EN_CHANGE: | |
3595 case CBN_EDITCHANGE: | |
3596 case CBN_SELCHANGE: | |
3597 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) | |
3598 return 0; | |
3599 } | |
3600 /* menubars always must come last since the hashtables do not | |
771 | 3601 always exist */ |
428 | 3602 #ifdef HAVE_MENUBARS |
442 | 3603 if (!NILP (mswindows_handle_wm_command (frame, id))) |
3604 break; | |
428 | 3605 #endif |
3606 | |
771 | 3607 goto defproc; |
3608 /* Bite me - a spurious command. This used to not be able to | |
3609 happen but with the introduction of widgets it's now | |
3610 possible. #### Andy, fix the god-damn widget code! It has | |
3611 more bugs than a termite's nest! */ | |
442 | 3612 } |
3613 break; | |
3614 | |
3615 case WM_CTLCOLORBTN: | |
3616 case WM_CTLCOLORLISTBOX: | |
3617 case WM_CTLCOLOREDIT: | |
3618 case WM_CTLCOLORSTATIC: | |
3619 case WM_CTLCOLORSCROLLBAR: | |
3620 { | |
3621 /* if we get an opportunity to paint a widget then do so if | |
3622 there is an appropriate face */ | |
771 | 3623 HWND crtlwnd = (HWND) lParam; |
3624 LONG ii = qxeGetWindowLong (crtlwnd, GWL_USERDATA); | |
442 | 3625 if (ii) |
3626 { | |
3627 Lisp_Object image_instance; | |
5013 | 3628 image_instance = GET_LISP_FROM_VOID ((void *) ii); |
442 | 3629 if (IMAGE_INSTANCEP (image_instance) |
3630 && | |
3631 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) | |
3632 { | |
3633 /* set colors for the buttons */ | |
771 | 3634 HDC hdc = (HDC) wParam; |
442 | 3635 if (last_widget_brushed != ii) |
3636 { | |
3637 if (widget_brush) | |
3638 DeleteObject (widget_brush); | |
3639 widget_brush = CreateSolidBrush | |
3640 (COLOR_INSTANCE_MSWINDOWS_COLOR | |
3641 (XCOLOR_INSTANCE | |
3642 (FACE_BACKGROUND | |
3643 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3644 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3645 } | |
3646 last_widget_brushed = ii; | |
3647 SetTextColor | |
3648 (hdc, | |
3649 COLOR_INSTANCE_MSWINDOWS_COLOR | |
3650 (XCOLOR_INSTANCE | |
3651 (FACE_FOREGROUND | |
3652 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3653 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3654 SetBkMode (hdc, OPAQUE); | |
3655 SetBkColor | |
3656 (hdc, | |
3657 COLOR_INSTANCE_MSWINDOWS_COLOR | |
3658 (XCOLOR_INSTANCE | |
3659 (FACE_BACKGROUND | |
3660 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3661 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3662 return (LRESULT)widget_brush; | |
3663 } | |
3664 } | |
3665 } | |
3666 goto defproc; | |
428 | 3667 |
3668 #ifdef HAVE_DRAGNDROP | |
853 | 3669 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ |
442 | 3670 { |
771 | 3671 UINT filecount, i; |
442 | 3672 POINT point; |
3673 | |
3674 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
3675 struct gcpro gcpro1, gcpro2, gcpro3; | |
3676 | |
3677 emacs_event = Fmake_event (Qnil, Qnil); | |
771 | 3678 event = XEVENT (emacs_event); |
442 | 3679 |
3680 GCPRO3 (emacs_event, l_dndlist, l_item); | |
3681 | |
3682 if (!DragQueryPoint ((HDROP) wParam, &point)) | |
853 | 3683 point.x = point.y = -1; /* outside client area */ |
442 | 3684 |
964 | 3685 XSET_EVENT_TYPE (emacs_event, misc_user_event); |
3686 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_frame(hwnd)); | |
3687 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime()); | |
1204 | 3688 XSET_EVENT_MISC_USER_BUTTON (emacs_event, 1); |
3689 XSET_EVENT_MISC_USER_MODIFIERS (emacs_event, | |
964 | 3690 mswindows_modifier_state (NULL, (DWORD) -1, 0)); |
1204 | 3691 XSET_EVENT_MISC_USER_X (emacs_event, point.x); |
3692 XSET_EVENT_MISC_USER_Y (emacs_event, point.y); | |
3693 XSET_EVENT_MISC_USER_FUNCTION (emacs_event, | |
964 | 3694 Qdragdrop_drop_dispatch); |
442 | 3695 |
771 | 3696 filecount = qxeDragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0); |
3697 for (i = 0; i < filecount; i++) | |
442 | 3698 { |
867 | 3699 Ibyte *fname; |
771 | 3700 Extbyte *fname_ext; |
3701 Bytecount fnamelen; | |
3702 Charcount len = qxeDragQueryFile ((HDROP) wParam, i, NULL, 0); | |
2526 | 3703 int freeme = 0; |
442 | 3704 /* The URLs that we make here aren't correct according to section |
3705 * 3.10 of rfc1738 because they're missing the //<host>/ part and | |
3706 * because they may contain reserved characters. But that's OK - | |
3707 * they just need to be good enough to keep dragdrop.el happy. */ | |
2367 | 3708 fname_ext = alloca_extbytes ((len + 1) * XETCHAR_SIZE); |
771 | 3709 qxeDragQueryFile ((HDROP) wParam, i, fname_ext, len + 1); |
3710 | |
3711 TO_INTERNAL_FORMAT (DATA, (fname_ext, len * XETCHAR_SIZE), | |
3712 ALLOCA, (fname, fnamelen), | |
3713 Qmswindows_tstr); | |
442 | 3714 |
2526 | 3715 |
442 | 3716 /* May be a shell link aka "shortcut" - replace fname if so */ |
2367 | 3717 if (!qxestrcasecmp_ascii (fname + fnamelen - 4, ".LNK")) |
442 | 3718 { |
2526 | 3719 fname = mswindows_read_link (fname); |
3720 freeme = 1; | |
442 | 3721 } |
2526 | 3722 |
771 | 3723 { |
2526 | 3724 Ibyte *fname2 = urlify_filename (fname); |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
3725 l_item = build_istring (fname2); |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
3726 xfree (fname2); |
2526 | 3727 if (freeme) |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
3728 xfree (fname); |
771 | 3729 l_dndlist = Fcons (l_item, l_dndlist); |
3730 } | |
442 | 3731 } |
771 | 3732 |
442 | 3733 DragFinish ((HDROP) wParam); |
3734 | |
1204 | 3735 SET_EVENT_MISC_USER_OBJECT (event, |
964 | 3736 Fcons (Qdragdrop_URL, l_dndlist)); |
442 | 3737 mswindows_enqueue_dispatch_event (emacs_event); |
3738 UNGCPRO; | |
3739 } | |
3740 break; | |
771 | 3741 #endif /* HAVE_DRAGNDROP */ |
3742 | |
3743 #ifdef MULE | |
3744 case WM_IME_CHAR: | |
3745 | |
3746 case WM_IME_STARTCOMPOSITION: | |
3747 mswindows_start_ime_composition (XFRAME (mswindows_find_frame (hwnd))); | |
3748 goto defproc; | |
3749 | |
3750 case WM_IME_COMPOSITION: | |
3751 if (lParam & GCS_RESULTSTR) | |
3752 { | |
3753 HIMC imc = ImmGetContext (hwnd); | |
3754 Extbyte *result; | |
3755 Bytecount len; | |
867 | 3756 Ibyte *resultint, *endptr; |
771 | 3757 Bytecount lenint; |
3758 int speccount; | |
3759 | |
3760 if (!imc) | |
3761 break; | |
3762 | |
3763 /* See WM_KEYDOWN above. */ | |
3764 speccount = begin_dont_check_for_quit (); | |
3765 | |
3766 /* Sizes always in bytes, even for unicode. | |
3767 ImmGetCompositionStringW is supported even on Windows 9x, and | |
3768 allows us to handle multiple languages. */ | |
3769 len = ImmGetCompositionStringW (imc, GCS_RESULTSTR, NULL, 0); | |
2367 | 3770 result = alloca_extbytes (len); |
771 | 3771 ImmGetCompositionStringW (imc, GCS_RESULTSTR, (WCHAR *) result, len); |
3772 ImmReleaseContext (hwnd, imc); | |
3773 | |
3774 TO_INTERNAL_FORMAT (DATA, (result, len), | |
3775 ALLOCA, (resultint, lenint), | |
3776 Qmswindows_tstr); | |
3777 | |
3778 endptr = resultint + lenint; | |
3779 | |
3780 while (resultint < endptr) | |
3781 { | |
867 | 3782 Ichar ch = itext_ichar (resultint); |
771 | 3783 if (ch == ' ') |
3784 mswindows_enqueue_keypress_event (hwnd, QKspace, 0); | |
3785 else | |
3786 mswindows_enqueue_keypress_event (hwnd, make_char (ch), 0); | |
867 | 3787 INC_IBYTEPTR (resultint); |
771 | 3788 } |
3789 | |
3790 unbind_to (speccount); | |
3791 } | |
3792 goto defproc; | |
3793 #endif /* MULE */ | |
442 | 3794 |
3795 defproc: | |
3796 default: | |
771 | 3797 return qxeDefWindowProc (hwnd, message_, wParam, lParam); |
428 | 3798 } |
3799 return (0); | |
3800 } | |
3801 | |
3802 | |
3803 /************************************************************************/ | |
3804 /* keyboard, mouse & other helpers for the windows procedure */ | |
3805 /************************************************************************/ | |
3806 static void | |
3807 mswindows_set_chord_timer (HWND hwnd) | |
3808 { | |
3809 int interval; | |
3810 | |
3811 /* We get one third half system double click threshold */ | |
3812 if (mswindows_mouse_button_tolerance <= 0) | |
3813 interval = GetDoubleClickTime () / 3; | |
3814 else | |
3815 interval = mswindows_mouse_button_tolerance; | |
3816 | |
3817 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0); | |
3818 } | |
3819 | |
3820 static int | |
3821 mswindows_button2_near_enough (POINTS p1, POINTS p2) | |
3822 { | |
3823 int dx, dy; | |
3824 if (mswindows_mouse_button_max_skew_x <= 0) | |
3825 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2; | |
3826 else | |
3827 dx = mswindows_mouse_button_max_skew_x; | |
3828 | |
3829 if (mswindows_mouse_button_max_skew_y <= 0) | |
3830 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2; | |
3831 else | |
3832 dy = mswindows_mouse_button_max_skew_y; | |
3833 | |
3834 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy; | |
3835 } | |
3836 | |
3837 static int | |
3838 mswindows_current_layout_has_AltGr (void) | |
3839 { | |
3840 /* This simple caching mechanism saves 10% of CPU | |
3841 time when a key typed at autorepeat rate of 30 cps! */ | |
3842 static HKL last_hkl = 0; | |
3843 static int last_hkl_has_AltGr; | |
771 | 3844 HKL current_hkl = GetKeyboardLayout (0); |
3845 | |
428 | 3846 if (current_hkl != last_hkl) |
3847 { | |
647 | 3848 int c; |
428 | 3849 last_hkl_has_AltGr = 0; |
3850 /* In this loop, we query whether a character requires | |
3851 AltGr to be down to generate it. If at least such one | |
3852 found, this means that the layout does regard AltGr */ | |
647 | 3853 for (c = ' '; c <= 255 && !last_hkl_has_AltGr; ++c) |
3854 /* #### This is not really such a good check. What about under | |
3855 CJK locales? It may not matter there, though. We always | |
3856 call VkKeyScanA so that we check the locale-specific characters | |
3857 in non-Latin-1 locales, instead of just the Latin-1 characters. */ | |
3858 if (HIBYTE (VkKeyScanA ((char) c)) == 6) | |
428 | 3859 last_hkl_has_AltGr = 1; |
3860 last_hkl = current_hkl; | |
3861 } | |
3862 return last_hkl_has_AltGr; | |
3863 } | |
3864 | |
3865 | |
3866 /* Returns the state of the modifier keys in the format expected by the | |
3867 * Lisp_Event key_data, button_data and motion_data modifiers member */ | |
442 | 3868 static int |
771 | 3869 mswindows_modifier_state (BYTE *keymap, DWORD fwKeys, int has_AltGr) |
428 | 3870 { |
3871 int mods = 0; | |
442 | 3872 int keys_is_real = 0; |
3873 BYTE keymap2[256]; | |
3874 | |
3875 if (fwKeys == (DWORD) -1) | |
3876 fwKeys = mswindows_last_mouse_button_state; | |
3877 else | |
3878 { | |
3879 keys_is_real = 1; | |
3880 mswindows_last_mouse_button_state = fwKeys; | |
3881 } | |
428 | 3882 |
3883 if (keymap == NULL) | |
3884 { | |
442 | 3885 keymap = keymap2; |
428 | 3886 GetKeyboardState (keymap); |
3887 has_AltGr = mswindows_current_layout_has_AltGr (); | |
3888 } | |
3889 | |
442 | 3890 /* #### should look at fwKeys for MK_CONTROL. I don't understand how |
3891 AltGr works. */ | |
428 | 3892 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) |
3893 { | |
442 | 3894 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0; |
3895 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | |
428 | 3896 } |
3897 else | |
3898 { | |
442 | 3899 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0; |
3900 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | |
428 | 3901 } |
3902 | |
1111 | 3903 mods |= (keys_is_real ? (int) (fwKeys & MK_SHIFT) : |
3904 (keymap [VK_SHIFT] & 0x80)) ? XEMACS_MOD_SHIFT : 0; | |
442 | 3905 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0; |
3906 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0; | |
3907 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0; | |
428 | 3908 |
3909 return mods; | |
3910 } | |
3911 | |
3912 /* | |
3913 * Translate a mswindows virtual key to a keysym. | |
3914 * Only returns non-Qnil for keys that don't generate WM_CHAR messages | |
3915 * or whose ASCII codes (like space) xemacs doesn't like. | |
3916 */ | |
2286 | 3917 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, |
3918 int UNUSED (mods), int extendedp) | |
428 | 3919 { |
3920 if (extendedp) /* Keys not present on a 82 key keyboard */ | |
3921 { | |
3922 switch (mswindows_key) | |
3923 { | |
442 | 3924 case VK_CANCEL: return KEYSYM ("pause"); |
428 | 3925 case VK_RETURN: return KEYSYM ("kp-enter"); |
3926 case VK_PRIOR: return KEYSYM ("prior"); | |
3927 case VK_NEXT: return KEYSYM ("next"); | |
3928 case VK_END: return KEYSYM ("end"); | |
3929 case VK_HOME: return KEYSYM ("home"); | |
3930 case VK_LEFT: return KEYSYM ("left"); | |
3931 case VK_UP: return KEYSYM ("up"); | |
3932 case VK_RIGHT: return KEYSYM ("right"); | |
3933 case VK_DOWN: return KEYSYM ("down"); | |
3934 case VK_INSERT: return KEYSYM ("insert"); | |
3935 case VK_DELETE: return QKdelete; | |
442 | 3936 #if 0 /* FSF Emacs allows these to return configurable syms/mods */ |
3937 case VK_LWIN return KEYSYM (""); | |
3938 case VK_RWIN return KEYSYM (""); | |
3939 #endif | |
3940 case VK_APPS: return KEYSYM ("menu"); | |
428 | 3941 } |
3942 } | |
3943 else | |
3944 { | |
3945 switch (mswindows_key) | |
3946 { | |
771 | 3947 |
3948 #if 0 | |
3949 VK_LBUTTON: | |
3950 VK_RBUTTON: | |
3951 VK_CANCEL: | |
3952 VK_MBUTTON: | |
3953 VK_XBUTTON1: | |
3954 VK_XBUTTON2: | |
3955 #endif /* 0 */ | |
3956 | |
428 | 3957 case VK_BACK: return QKbackspace; |
3958 case VK_TAB: return QKtab; | |
771 | 3959 /* #### Officially 0A (and 0B too) are "reserved". */ |
428 | 3960 case '\n': return QKlinefeed; |
3961 case VK_CLEAR: return KEYSYM ("clear"); | |
3962 case VK_RETURN: return QKreturn; | |
771 | 3963 |
3964 #if 0 | |
3965 VK_SHIFT: "shift" | |
3966 VK_CONTROL: "control" | |
3967 VK_MENU: "alt" | |
3968 #endif /* 0 */ | |
3969 | |
442 | 3970 case VK_PAUSE: return KEYSYM ("pause"); |
771 | 3971 |
3972 #if 0 | |
3973 VK_CAPITAL: "caps-lock" | |
3974 VK_KANA: IME Kana mode | |
3975 VK_HANGUEL: IME Hanguel mode (maintained for compatibility; use VK_HANGUL) | |
3976 VK_HANGUL: IME Hangul mode | |
3977 VK_JUNJA: IME Junja mode | |
3978 VK_FINAL: IME final mode | |
3979 VK_HANJA: IME Hanja mode | |
3980 VK_KANJI: IME Kanji mode | |
3981 #endif /* 0 */ | |
3982 | |
428 | 3983 case VK_ESCAPE: return QKescape; |
771 | 3984 |
3985 #if 0 | |
3986 VK_CONVERT: IME convert | |
3987 VK_NONCONVERT: IME nonconvert | |
3988 VK_ACCEPT: IME accept | |
3989 VK_MODECHANGE: IME mode change request | |
3990 #endif /* 0 */ | |
3991 | |
428 | 3992 case VK_SPACE: return QKspace; |
3993 case VK_PRIOR: return KEYSYM ("kp-prior"); | |
3994 case VK_NEXT: return KEYSYM ("kp-next"); | |
3995 case VK_END: return KEYSYM ("kp-end"); | |
3996 case VK_HOME: return KEYSYM ("kp-home"); | |
3997 case VK_LEFT: return KEYSYM ("kp-left"); | |
3998 case VK_UP: return KEYSYM ("kp-up"); | |
3999 case VK_RIGHT: return KEYSYM ("kp-right"); | |
4000 case VK_DOWN: return KEYSYM ("kp-down"); | |
4001 case VK_SELECT: return KEYSYM ("select"); | |
4002 case VK_PRINT: return KEYSYM ("print"); | |
4003 case VK_EXECUTE: return KEYSYM ("execute"); | |
4004 case VK_SNAPSHOT: return KEYSYM ("print"); | |
4005 case VK_INSERT: return KEYSYM ("kp-insert"); | |
4006 case VK_DELETE: return KEYSYM ("kp-delete"); | |
4007 case VK_HELP: return KEYSYM ("help"); | |
771 | 4008 #if 0 |
4009 '0' through '9': numeric keys | |
4010 'A' through 'Z': alphabetic keys | |
4011 VK_LWIN: "lwin" | |
4012 VK_RWIN: "rwin" | |
4013 VK_APPS: "apps" | |
4014 VK_SLEEP: "sleep" | |
4015 #endif /* 0 */ | |
428 | 4016 case VK_NUMPAD0: return KEYSYM ("kp-0"); |
4017 case VK_NUMPAD1: return KEYSYM ("kp-1"); | |
4018 case VK_NUMPAD2: return KEYSYM ("kp-2"); | |
4019 case VK_NUMPAD3: return KEYSYM ("kp-3"); | |
4020 case VK_NUMPAD4: return KEYSYM ("kp-4"); | |
4021 case VK_NUMPAD5: return KEYSYM ("kp-5"); | |
4022 case VK_NUMPAD6: return KEYSYM ("kp-6"); | |
4023 case VK_NUMPAD7: return KEYSYM ("kp-7"); | |
4024 case VK_NUMPAD8: return KEYSYM ("kp-8"); | |
4025 case VK_NUMPAD9: return KEYSYM ("kp-9"); | |
4026 case VK_MULTIPLY: return KEYSYM ("kp-multiply"); | |
4027 case VK_ADD: return KEYSYM ("kp-add"); | |
4028 case VK_SEPARATOR: return KEYSYM ("kp-separator"); | |
4029 case VK_SUBTRACT: return KEYSYM ("kp-subtract"); | |
4030 case VK_DECIMAL: return KEYSYM ("kp-decimal"); | |
4031 case VK_DIVIDE: return KEYSYM ("kp-divide"); | |
4032 case VK_F1: return KEYSYM ("f1"); | |
4033 case VK_F2: return KEYSYM ("f2"); | |
4034 case VK_F3: return KEYSYM ("f3"); | |
4035 case VK_F4: return KEYSYM ("f4"); | |
4036 case VK_F5: return KEYSYM ("f5"); | |
4037 case VK_F6: return KEYSYM ("f6"); | |
4038 case VK_F7: return KEYSYM ("f7"); | |
4039 case VK_F8: return KEYSYM ("f8"); | |
4040 case VK_F9: return KEYSYM ("f9"); | |
4041 case VK_F10: return KEYSYM ("f10"); | |
4042 case VK_F11: return KEYSYM ("f11"); | |
4043 case VK_F12: return KEYSYM ("f12"); | |
4044 case VK_F13: return KEYSYM ("f13"); | |
4045 case VK_F14: return KEYSYM ("f14"); | |
4046 case VK_F15: return KEYSYM ("f15"); | |
4047 case VK_F16: return KEYSYM ("f16"); | |
4048 case VK_F17: return KEYSYM ("f17"); | |
4049 case VK_F18: return KEYSYM ("f18"); | |
4050 case VK_F19: return KEYSYM ("f19"); | |
4051 case VK_F20: return KEYSYM ("f20"); | |
4052 case VK_F21: return KEYSYM ("f21"); | |
4053 case VK_F22: return KEYSYM ("f22"); | |
4054 case VK_F23: return KEYSYM ("f23"); | |
4055 case VK_F24: return KEYSYM ("f24"); | |
771 | 4056 |
4057 #if 0 | |
4058 VK_NUMLOCK: 90 NUM LOCK key | |
4059 VK_SCROLL: 91 SCROLL LOCK key | |
4060 92~96 OEM specific; | |
4061 VK_LSHIFT: | |
4062 VK_RSHIFT: | |
4063 VK_LCONTROL: | |
4064 VK_RCONTROL: | |
4065 VK_LMENU: | |
4066 VK_RMENU: | |
4067 | |
4068 #ifdef VK_BROWSER_BACK /* Windows 2000 only */ | |
4069 VK_BROWSER_BACK: Browser Back key | |
4070 VK_BROWSER_FORWARD: Browser Forward key | |
4071 VK_BROWSER_REFRESH: Browser Refresh key | |
4072 VK_BROWSER_STOP: Browser Stop key | |
4073 VK_BROWSER_SEARCH: Browser Search key | |
4074 VK_BROWSER_FAVORITES: Browser Favorites key | |
4075 VK_BROWSER_HOME: Browser Start and Home key | |
4076 VK_VOLUME_MUTE: Volume Mute key | |
4077 VK_VOLUME_DOWN: Volume Down key | |
4078 VK_VOLUME_UP: Volume Up key | |
4079 VK_MEDIA_NEXT_TRACK: Next Track key | |
4080 VK_MEDIA_PREV_TRACK: Previous Track key | |
4081 VK_MEDIA_STOP: Stop Media key | |
4082 VK_MEDIA_PLAY_PAUSE: Play/Pause Media key | |
4083 VK_LAUNCH_MAIL: Start Mail key | |
4084 VK_LAUNCH_MEDIA_SELECT: Select Media key | |
4085 VK_LAUNCH_APP1: Start Application 1 key | |
4086 VK_LAUNCH_APP2: Start Application 2 key | |
4087 B8-B9 Reserved; | |
4088 VK_OEM_1: For the US standard keyboard, the ';:' key | |
4089 VK_OEM_PLUS: For any country/region, the '+' key | |
4090 VK_OEM_COMMA: For any country/region, the ',' key | |
4091 VK_OEM_MINUS: For any country/region, the '-' key | |
4092 VK_OEM_PERIOD: For any country/region, the '.' key | |
4093 VK_OEM_2: For the US standard keyboard, the '/?' key | |
4094 VK_OEM_3: For the US standard keyboard, the '`~' key | |
4095 C1~D7 Reserved; | |
4096 D8~DA Unassigned; | |
4097 VK_OEM_4: For the US standard keyboard, the '[{' key | |
4098 VK_OEM_5: For the US standard keyboard, the '\|' key | |
4099 VK_OEM_6: For the US standard keyboard, the ']}' key | |
4100 VK_OEM_7: For the US standard keyboard, the 'single-quote/double-quote' key | |
4101 VK_OEM_8: | |
4102 E0 Reserved; | |
4103 E1 OEM specific; | |
4104 VK_OEM_102: Either the angle bracket key or the backslash key on the RT 102-key keyboard | |
4105 E3~E4 OEM specific; | |
4106 #endif /* VK_BROWSER_BACK */ | |
4107 VK_PROCESSKEY: E5 Windows 95/98, Windows NT 4.0, Windows 2000: IME PROCESS key | |
4108 E6 OEM specific; | |
4109 VK_PACKET: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP | |
4110 E8 Unassigned; | |
4111 E9~F5 OEM specific; | |
4112 VK_ATTN: Attn key | |
4113 VK_CRSEL: CrSel key | |
4114 VK_EXSEL: ExSel key | |
4115 VK_EREOF: Erase EOF key | |
4116 VK_PLAY: Play key | |
4117 VK_ZOOM: Zoom key | |
4118 VK_NONAME: Reserved for future use | |
4119 VK_PA1: PA1 key | |
4120 VK_OEM_CLEAR: Clear key | |
4121 #endif /* 0 */ | |
4122 | |
428 | 4123 } |
4124 } | |
4125 return Qnil; | |
4126 } | |
4127 | |
4128 /* | |
4129 * Find the console that matches the supplied mswindows window handle | |
4130 */ | |
4131 Lisp_Object | |
2286 | 4132 mswindows_find_console (HWND UNUSED (hwnd)) |
428 | 4133 { |
4134 /* We only support one console */ | |
4135 return XCAR (Vconsole_list); | |
4136 } | |
4137 | |
4138 /* | |
4139 * Find the frame that matches the supplied mswindows window handle | |
4140 */ | |
546 | 4141 Lisp_Object |
428 | 4142 mswindows_find_frame (HWND hwnd) |
4143 { | |
771 | 4144 LONG l = qxeGetWindowLong (hwnd, XWL_FRAMEOBJ); |
428 | 4145 Lisp_Object f; |
4146 if (l == 0) | |
4147 { | |
4148 /* We are in progress of frame creation. Return the frame | |
4149 being created, as it still not remembered in the window | |
4150 extra storage. */ | |
4151 assert (!NILP (Vmswindows_frame_being_created)); | |
4152 return Vmswindows_frame_being_created; | |
4153 } | |
5013 | 4154 f = GET_LISP_FROM_VOID ((void *) l); |
428 | 4155 return f; |
4156 } | |
4157 | |
4158 | |
4159 /************************************************************************/ | |
4160 /* methods */ | |
4161 /************************************************************************/ | |
4162 | |
4163 static int | |
4164 emacs_mswindows_add_timeout (EMACS_TIME thyme) | |
4165 { | |
4166 int milliseconds; | |
4167 EMACS_TIME current_time; | |
4168 EMACS_GET_TIME (current_time); | |
4169 EMACS_SUB_TIME (thyme, thyme, current_time); | |
4170 milliseconds = EMACS_SECS (thyme) * 1000 + | |
4171 (EMACS_USECS (thyme) + 500) / 1000; | |
4172 if (milliseconds < 1) | |
4173 milliseconds = 1; | |
4174 ++mswindows_pending_timers_count; | |
4175 return SetTimer (NULL, 0, milliseconds, | |
4176 (TIMERPROC) mswindows_wm_timer_callback); | |
4177 } | |
4178 | |
1204 | 4179 static int |
4180 remove_timeout_mapper (Lisp_Object ev, void *data) | |
4181 { | |
4182 if (XEVENT_TYPE (ev) == timeout_event) | |
4183 { | |
4184 if ((int) data == XEVENT_TIMEOUT_INTERVAL_ID (ev)) | |
4185 return 1; | |
4186 } | |
4187 | |
4188 return 0; | |
4189 } | |
4190 | |
428 | 4191 static void |
4192 emacs_mswindows_remove_timeout (int id) | |
4193 { | |
4194 if (KillTimer (NULL, id)) | |
4195 --mswindows_pending_timers_count; | |
4196 | |
4197 /* If there is a dispatch event generated by this | |
4198 timeout in the queue, we have to remove it too. */ | |
1204 | 4199 map_event_chain_remove (remove_timeout_mapper, |
4200 &mswindows_s_dispatch_event_queue, | |
4201 &mswindows_s_dispatch_event_queue_tail, | |
4202 (void *) id, MECR_DEALLOCATE_EVENT); | |
428 | 4203 } |
4204 | |
4205 /* If `user_p' is false, then return whether there are any win32, timeout, | |
4206 * or subprocess events pending (that is, whether | |
4207 * emacs_mswindows_next_event() would return immediately without blocking). | |
4208 * | |
4209 * if `user_p' is true, then return whether there are any *user generated* | |
4210 * events available (that is, whether there are keyboard or mouse-click | |
4211 * events ready to be read). This also implies that | |
4212 * emacs_mswindows_next_event() would not block. | |
4213 */ | |
4214 static int | |
1268 | 4215 emacs_mswindows_event_pending_p (int how_many) |
428 | 4216 { |
1318 | 4217 /* This can call Lisp */ |
1268 | 4218 if (!how_many) |
4219 { | |
4220 mswindows_need_event (0); | |
4221 return (!NILP (dispatch_event_queue) | |
4222 || !NILP (mswindows_s_dispatch_event_queue)); | |
4223 } | |
4224 else | |
4225 { | |
4226 Lisp_Object event; | |
4227 int count = 0; | |
4228 | |
4229 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
4230 count++; | |
4231 | |
4232 if (count >= how_many) | |
4233 return 1; | |
4234 | |
4235 emacs_mswindows_drain_queue (); | |
4236 | |
4237 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
4238 count++; | |
4239 | |
4240 return count >= how_many; | |
4241 } | |
428 | 4242 } |
4243 | |
4244 /* | |
4245 * Return the next event | |
4246 */ | |
4247 static void | |
440 | 4248 emacs_mswindows_next_event (Lisp_Event *emacs_event) |
428 | 4249 { |
4250 Lisp_Object event, event2; | |
4251 | |
4252 mswindows_need_event (1); | |
4253 | |
4254 event = mswindows_dequeue_dispatch_event (); | |
793 | 4255 event2 = wrap_event (emacs_event); |
428 | 4256 Fcopy_event (event, event2); |
4257 Fdeallocate_event (event); | |
4258 } | |
4259 | |
788 | 4260 static void |
4261 emacs_mswindows_format_magic_event (Lisp_Event *emacs_event, | |
4262 Lisp_Object pstream) | |
4263 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
4264 #define FROB(msg) case msg: write_ascstring (pstream, "type=" #msg); break |
788 | 4265 |
1204 | 4266 switch (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event)) |
788 | 4267 { |
4268 FROB (XM_BUMPQUEUE); | |
4269 FROB (WM_PAINT); | |
4270 FROB (WM_SETFOCUS); | |
4271 FROB (WM_KILLFOCUS); | |
4272 FROB (XM_MAPFRAME); | |
4273 FROB (XM_UNMAPFRAME); | |
4274 | |
2500 | 4275 default: ABORT (); |
788 | 4276 } |
4277 #undef FROB | |
4278 | |
4279 if (!NILP (EVENT_CHANNEL (emacs_event))) | |
4280 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
4281 write_ascstring (pstream, " "); |
788 | 4282 print_internal (EVENT_CHANNEL (emacs_event), pstream, 1); |
4283 } | |
4284 } | |
4285 | |
4286 static int | |
4287 emacs_mswindows_compare_magic_event (Lisp_Event *e1, Lisp_Event *e2) | |
4288 { | |
1204 | 4289 return (EVENT_MAGIC_MSWINDOWS_EVENT (e1) == |
4290 EVENT_MAGIC_MSWINDOWS_EVENT (e2)); | |
788 | 4291 } |
4292 | |
4293 static Hashcode | |
4294 emacs_mswindows_hash_magic_event (Lisp_Event *e) | |
4295 { | |
1204 | 4296 return (EVENT_MAGIC_MSWINDOWS_EVENT (e)); |
788 | 4297 } |
4298 | |
428 | 4299 /* |
4300 * Handle a magic event off the dispatch queue. | |
4301 */ | |
4302 static void | |
440 | 4303 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event) |
428 | 4304 { |
1204 | 4305 switch (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event)) |
428 | 4306 { |
4307 case XM_BUMPQUEUE: | |
4308 break; | |
4309 | |
442 | 4310 case WM_PAINT: |
4311 { | |
4312 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); | |
4313 mswindows_handle_paint (f); | |
4314 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0; | |
4315 } | |
4316 break; | |
4317 | |
428 | 4318 case WM_SETFOCUS: |
4319 case WM_KILLFOCUS: | |
4320 { | |
4321 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
4322 struct frame *f = XFRAME (frame); | |
1204 | 4323 int in_p = (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event) |
964 | 4324 == WM_SETFOCUS); |
428 | 4325 Lisp_Object conser; |
442 | 4326 struct gcpro gcpro1; |
4327 | |
4328 /* On focus change, clear all memory of sticky modifiers | |
4329 to avoid non-intuitive behavior. */ | |
4330 clear_sticky_modifiers (); | |
428 | 4331 |
4332 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); | |
442 | 4333 GCPRO1 (conser); |
428 | 4334 emacs_handle_focus_change_preliminary (conser); |
4335 /* Under X the stuff up to here is done in the X event handler. | |
4336 I Don't know why */ | |
4337 emacs_handle_focus_change_final (conser); | |
442 | 4338 UNGCPRO; |
428 | 4339 |
4340 } | |
4341 break; | |
4342 | |
4343 case XM_MAPFRAME: | |
4344 case XM_UNMAPFRAME: | |
4345 { | |
4346 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
1204 | 4347 va_run_hook_with_args (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event) |
428 | 4348 == XM_MAPFRAME ? |
4349 Qmap_frame_hook : Qunmap_frame_hook, | |
4350 1, frame); | |
4351 } | |
4352 break; | |
4353 | |
4354 /* #### What about Enter & Leave */ | |
4355 #if 0 | |
4356 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : | |
4357 Qmouse_leave_frame_hook, 1, frame); | |
4358 #endif | |
4359 | |
4360 default: | |
4361 assert(0); | |
4362 } | |
4363 } | |
4364 | |
853 | 4365 #ifndef CYGWIN |
4366 | |
428 | 4367 static HANDLE |
440 | 4368 get_process_input_waitable (Lisp_Process *process) |
428 | 4369 { |
853 | 4370 Lisp_Object instr, outstr, errstr, p; |
793 | 4371 p = wrap_process (process); |
853 | 4372 get_process_streams (process, &instr, &outstr, &errstr); |
428 | 4373 assert (!NILP (instr)); |
4374 return (network_connection_p (p) | |
4375 ? get_winsock_stream_waitable (XLSTREAM (instr)) | |
4376 : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); | |
4377 } | |
4378 | |
853 | 4379 static HANDLE |
4380 get_process_stderr_waitable (Lisp_Process *process) | |
4381 { | |
4382 Lisp_Object instr, outstr, errstr; | |
4383 get_process_streams (process, &instr, &outstr, &errstr); | |
4384 if (NILP (errstr)) | |
4385 return INVALID_HANDLE_VALUE; | |
4386 return get_ntpipe_input_stream_waitable (XLSTREAM (errstr)); | |
4387 } | |
4388 | |
4389 #endif /* not CYGWIN */ | |
4390 | |
428 | 4391 static void |
853 | 4392 emacs_mswindows_select_process (Lisp_Process *process, int doin, int doerr) |
428 | 4393 { |
853 | 4394 #ifdef CYGWIN |
4395 int infd, errfd; | |
4396 | |
4397 event_stream_unixoid_select_process (process, doin, doerr, &infd, &errfd); | |
4398 #else | |
4399 HANDLE hev = INVALID_HANDLE_VALUE; | |
4400 HANDLE herr = INVALID_HANDLE_VALUE; | |
4401 | |
4402 if (doin) | |
4403 { | |
4404 hev = get_process_input_waitable (process); | |
4405 if (!add_waitable_handle (hev)) | |
4406 { | |
4407 hev = INVALID_HANDLE_VALUE; | |
4408 goto err; | |
4409 } | |
4410 } | |
4411 | |
4412 if (doerr) | |
4413 { | |
4414 herr = get_process_stderr_waitable (process); | |
4415 if (herr != INVALID_HANDLE_VALUE && !add_waitable_handle (herr)) | |
4416 { | |
4417 herr = INVALID_HANDLE_VALUE; | |
4418 goto err; | |
4419 } | |
4420 } | |
4421 | |
428 | 4422 { |
853 | 4423 /* Also select on the process handle itself, so we can receive |
4424 exit notifications. Only do this once, not each time this | |
4425 function is called (which can happen many times, e.g. if | |
4426 (set-process-filter proc t) is called and then a process filter | |
4427 is set again). It will be unselected in mswindows_need_event(). */ | |
793 | 4428 Lisp_Object p = wrap_process (process); |
4429 | |
428 | 4430 if (!network_connection_p (p)) |
4431 { | |
853 | 4432 HANDLE hprocess = get_nt_process_handle_only_first_time (process); |
4433 if (hprocess != INVALID_HANDLE_VALUE | |
4434 && !add_waitable_handle (hprocess)) | |
4435 goto err; | |
428 | 4436 } |
4437 } | |
853 | 4438 |
4439 return; | |
4440 | |
4441 err: | |
4442 if (hev != INVALID_HANDLE_VALUE) | |
4443 remove_waitable_handle (hev); | |
4444 if (herr != INVALID_HANDLE_VALUE) | |
4445 remove_waitable_handle (herr); | |
4446 invalid_operation ("Too many active processes", wrap_process (process)); | |
4447 #endif /* CYGWIN */ | |
428 | 4448 } |
4449 | |
4450 static void | |
853 | 4451 emacs_mswindows_unselect_process (Lisp_Process *process, int doin, int doerr) |
428 | 4452 { |
853 | 4453 #ifdef CYGWIN |
4454 int infd, errfd; | |
4455 | |
4456 event_stream_unixoid_unselect_process (process, doin, doerr, &infd, &errfd); | |
4457 #else | |
4458 if (doin) | |
4459 { | |
4460 /* Process handle is removed in the event loop as soon | |
4461 as it is signaled, so don't bother here about it */ | |
4462 HANDLE hev = get_process_input_waitable (process); | |
4463 remove_waitable_handle (hev); | |
4464 } | |
4465 if (doerr) | |
4466 { | |
4467 /* Process handle is removed in the event loop as soon | |
4468 as it is signaled, so don't bother here about it */ | |
4469 HANDLE herr = get_process_stderr_waitable (process); | |
4470 if (herr != INVALID_HANDLE_VALUE) | |
4471 remove_waitable_handle (herr); | |
4472 } | |
4473 #endif /* CYGWIN */ | |
428 | 4474 } |
4475 | |
4476 static void | |
2286 | 4477 emacs_mswindows_select_console (struct console *USED_IF_CYGWIN (con)) |
428 | 4478 { |
853 | 4479 #ifdef CYGWIN |
428 | 4480 if (CONSOLE_MSWINDOWS_P (con)) |
4481 return; /* mswindows consoles are automatically selected */ | |
4482 | |
4483 event_stream_unixoid_select_console (con); | |
1204 | 4484 #else |
4485 #if 0 | |
4486 /* This is an attempt to get `xemacs -batch -l dunnet' to work. | |
4487 Doesn't currently work and fucks other things up. */ | |
4488 if (CONSOLE_STREAM_P (con) && | |
4489 !UNBOUNDP (CONSOLE_STREAM_DATA (con)->instream)) | |
4490 { | |
4491 HANDLE h = | |
4492 (HANDLE) _get_osfhandle (fileno (CONSOLE_STREAM_DATA (con)->in)); | |
4493 if (PeekNamedPipe (h, 0, 0, 0, 0, 0)) | |
4494 { | |
4495 Lisp_Object lstr = make_ntpipe_input_stream (h, 0); | |
4496 HANDLE hwait = get_ntpipe_input_stream_waitable (XLSTREAM (lstr)); | |
4497 | |
4498 if (!add_waitable_handle (hwait)) | |
4499 invalid_operation ("Too many active processes", | |
4500 wrap_console (con)); | |
4501 CONSOLE_STREAM_DATA (con)->instream = lstr; | |
4502 } | |
4503 else | |
4504 /* Unable to select on this stream */ | |
4505 CONSOLE_STREAM_DATA (con)->instream = Qunbound; | |
4506 } | |
4507 #endif /* 0 */ | |
428 | 4508 #endif |
4509 } | |
4510 | |
4511 static void | |
2286 | 4512 emacs_mswindows_unselect_console (struct console *USED_IF_CYGWIN (con)) |
428 | 4513 { |
853 | 4514 #ifdef CYGWIN |
428 | 4515 if (CONSOLE_MSWINDOWS_P (con)) |
4516 return; /* mswindows consoles are automatically selected */ | |
4517 | |
4518 event_stream_unixoid_unselect_console (con); | |
1204 | 4519 #else |
4520 #if 0 /* see above */ | |
4521 if (CONSOLE_STREAM_P (con) && | |
4522 !UNBOUNDP (CONSOLE_STREAM_DATA (con)->instream)) | |
428 | 4523 { |
1204 | 4524 Lisp_Object instr = CONSOLE_STREAM_DATA (con)->instream; |
4525 HANDLE hwait; | |
4526 | |
4527 assert (!NILP (instr)); | |
4528 hwait = get_ntpipe_input_stream_waitable (XLSTREAM (instr)); | |
4529 | |
4530 remove_waitable_handle (hwait); | |
428 | 4531 } |
1204 | 4532 #endif /* 0 */ |
4533 #endif | |
428 | 4534 } |
4535 | |
853 | 4536 static void |
4537 emacs_mswindows_create_io_streams (void *inhandle, void *outhandle, | |
4538 void *errhandle, Lisp_Object *instream, | |
4539 Lisp_Object *outstream, | |
4540 Lisp_Object *errstream, | |
4541 USID *in_usid, | |
4542 USID *err_usid, | |
4543 int flags) | |
428 | 4544 { |
853 | 4545 #ifdef CYGWIN |
4546 event_stream_unixoid_create_io_streams (inhandle, outhandle, | |
4547 errhandle, instream, | |
4548 outstream, errstream, | |
4549 in_usid, err_usid, flags); | |
4550 #else | |
428 | 4551 /* Handles for streams */ |
853 | 4552 HANDLE hin, hout, herr; |
428 | 4553 /* fds. These just stored along with the streams, and are closed in |
4554 delete stream pair method, because we need to handle fake unices | |
4555 here. */ | |
853 | 4556 int fdi, fdo, fde; |
4557 | |
4558 /* Decode inhandle, outhandle, errhandle. Their meaning depends on | |
428 | 4559 the process implementation being used. */ |
4560 hin = (HANDLE) inhandle; | |
4561 hout = (HANDLE) outhandle; | |
853 | 4562 if (errhandle == (void *) -1) |
4563 herr = INVALID_HANDLE_VALUE; | |
4564 else | |
4565 herr = (HANDLE) errhandle; | |
4566 fdi = fdo = fde = -1; | |
428 | 4567 |
4568 *instream = (hin == INVALID_HANDLE_VALUE | |
4569 ? Qnil | |
4570 : flags & STREAM_NETWORK_CONNECTION | |
853 | 4571 ? make_winsock_input_stream ((SOCKET) hin, fdi) |
428 | 4572 : make_ntpipe_input_stream (hin, fdi)); |
4573 | |
853 | 4574 *errstream = (herr == INVALID_HANDLE_VALUE |
4575 ? Qnil | |
4576 : make_ntpipe_input_stream (herr, fde)); | |
4577 | |
428 | 4578 *outstream = (hout == INVALID_HANDLE_VALUE |
4579 ? Qnil | |
4580 : flags & STREAM_NETWORK_CONNECTION | |
4581 ? make_winsock_output_stream ((SOCKET)hout, fdo) | |
4582 : make_ntpipe_output_stream (hout, fdo)); | |
853 | 4583 |
4584 *in_usid = | |
4585 (NILP (*instream) | |
4586 ? USID_ERROR | |
4587 : flags & STREAM_NETWORK_CONNECTION | |
4588 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream))) | |
4589 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4590 (*instream)))); | |
4591 | |
4592 *err_usid = | |
4593 (NILP (*errstream) | |
4594 ? USID_DONTHASH | |
4595 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4596 (*errstream)))); | |
4597 #endif /* CYGWIN */ | |
428 | 4598 } |
4599 | |
853 | 4600 static void |
4601 emacs_mswindows_delete_io_streams (Lisp_Object instream, | |
2286 | 4602 Lisp_Object USED_IF_CYGWIN (outstream), |
853 | 4603 Lisp_Object errstream, |
4604 USID *in_usid, | |
4605 USID *err_usid) | |
428 | 4606 { |
853 | 4607 #ifdef CYGWIN |
4608 event_stream_unixoid_delete_io_streams (instream, outstream, errstream, | |
4609 in_usid, err_usid); | |
4610 #else | |
4611 *in_usid = | |
4612 (NILP (instream) | |
4613 ? USID_DONTHASH | |
4614 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock) | |
4615 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream))) | |
4616 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4617 (instream)))); | |
4618 | |
4619 *err_usid = | |
4620 (NILP (errstream) | |
4621 ? USID_DONTHASH | |
4622 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4623 (errstream)))); | |
4624 #endif /* CYGWIN */ | |
428 | 4625 } |
4626 | |
442 | 4627 static int |
2286 | 4628 emacs_mswindows_current_event_timestamp (struct console *UNUSED (c)) |
442 | 4629 { |
4630 return GetTickCount (); | |
4631 } | |
4632 | |
428 | 4633 #ifndef HAVE_X_WINDOWS |
4634 /* This is called from GC when a process object is about to be freed. | |
4635 If we've still got pointers to it in this file, we're gonna lose hard. | |
853 | 4636 */ |
4637 void debug_process_finalization (Lisp_Process *p); | |
428 | 4638 void |
2286 | 4639 debug_process_finalization (Lisp_Process *UNUSED (p)) |
428 | 4640 { |
4641 #if 0 /* #### */ | |
853 | 4642 Lisp_Object instr, outstr, errstr; |
4643 | |
4644 get_process_streams (p, &instr, &outstr, &errstr); | |
428 | 4645 /* if it still has fds, then it hasn't been killed yet. */ |
771 | 4646 assert (NILP (instr)); |
4647 assert (NILP (outstr)); | |
853 | 4648 assert (NILP (errstr)); |
428 | 4649 |
4650 /* #### More checks here */ | |
4651 #endif | |
4652 } | |
4653 #endif | |
4654 | |
593 | 4655 #ifdef DEBUG_XEMACS |
4656 | |
4657 struct mswin_message_debug | |
4658 { | |
4659 int mess; | |
4932 | 4660 const Ascbyte *string; |
593 | 4661 }; |
4662 | |
4663 #define FROB(val) { val, #val, }, | |
4664 | |
4665 struct mswin_message_debug debug_mswin_messages[] = | |
4666 { | |
4667 FROB (WM_NULL) | |
4668 FROB (WM_CREATE) | |
4669 FROB (WM_DESTROY) | |
4670 FROB (WM_MOVE) | |
4671 FROB (WM_SIZE) | |
4672 | |
4673 FROB (WM_ACTIVATE) | |
4674 | |
4675 FROB (WM_SETFOCUS) | |
4676 FROB (WM_KILLFOCUS) | |
4677 FROB (WM_ENABLE) | |
4678 FROB (WM_SETREDRAW) | |
4679 FROB (WM_SETTEXT) | |
4680 FROB (WM_GETTEXT) | |
4681 FROB (WM_GETTEXTLENGTH) | |
4682 FROB (WM_PAINT) | |
4683 FROB (WM_CLOSE) | |
4684 FROB (WM_QUERYENDSESSION) | |
4685 FROB (WM_QUIT) | |
4686 FROB (WM_QUERYOPEN) | |
4687 FROB (WM_ERASEBKGND) | |
4688 FROB (WM_SYSCOLORCHANGE) | |
4689 FROB (WM_ENDSESSION) | |
4690 FROB (WM_SHOWWINDOW) | |
4691 FROB (WM_WININICHANGE) | |
4692 #if(WINVER >= 0x0400) | |
4693 FROB (WM_SETTINGCHANGE) | |
4694 #endif /* WINVER >= 0x0400 */ | |
4695 | |
4696 FROB (WM_DEVMODECHANGE) | |
4697 FROB (WM_ACTIVATEAPP) | |
4698 FROB (WM_FONTCHANGE) | |
4699 FROB (WM_TIMECHANGE) | |
4700 FROB (WM_CANCELMODE) | |
4701 FROB (WM_SETCURSOR) | |
4702 FROB (WM_MOUSEACTIVATE) | |
4703 FROB (WM_CHILDACTIVATE) | |
4704 FROB (WM_QUEUESYNC) | |
4705 | |
4706 FROB (WM_GETMINMAXINFO) | |
4707 | |
4708 FROB (WM_PAINTICON) | |
4709 FROB (WM_ICONERASEBKGND) | |
4710 FROB (WM_NEXTDLGCTL) | |
4711 FROB (WM_SPOOLERSTATUS) | |
4712 FROB (WM_DRAWITEM) | |
4713 FROB (WM_MEASUREITEM) | |
4714 FROB (WM_DELETEITEM) | |
4715 FROB (WM_VKEYTOITEM) | |
4716 FROB (WM_CHARTOITEM) | |
4717 FROB (WM_SETFONT) | |
4718 FROB (WM_GETFONT) | |
4719 FROB (WM_SETHOTKEY) | |
4720 FROB (WM_GETHOTKEY) | |
4721 FROB (WM_QUERYDRAGICON) | |
4722 FROB (WM_COMPAREITEM) | |
1687 | 4723 #if(WINVER >= 0x0500) && defined(WM_GETOBJECT) |
593 | 4724 FROB (WM_GETOBJECT) |
4725 #endif /* WINVER >= 0x0500 */ | |
4726 FROB (WM_COMPACTING) | |
4727 FROB (WM_COMMNOTIFY) | |
4728 FROB (WM_WINDOWPOSCHANGING) | |
4729 FROB (WM_WINDOWPOSCHANGED) | |
4730 | |
4731 FROB (WM_POWER) | |
4732 | |
4733 FROB (WM_COPYDATA) | |
4734 FROB (WM_CANCELJOURNAL) | |
4735 | |
4736 #if(WINVER >= 0x0400) | |
4737 FROB (WM_NOTIFY) | |
4738 FROB (WM_INPUTLANGCHANGEREQUEST) | |
4739 FROB (WM_INPUTLANGCHANGE) | |
4740 FROB (WM_TCARD) | |
4741 FROB (WM_HELP) | |
4742 FROB (WM_USERCHANGED) | |
4743 FROB (WM_NOTIFYFORMAT) | |
4744 | |
4745 FROB (WM_CONTEXTMENU) | |
4746 FROB (WM_STYLECHANGING) | |
4747 FROB (WM_STYLECHANGED) | |
4748 FROB (WM_DISPLAYCHANGE) | |
4749 FROB (WM_GETICON) | |
4750 FROB (WM_SETICON) | |
4751 #endif /* WINVER >= 0x0400 */ | |
4752 | |
4753 FROB (WM_NCCREATE) | |
4754 FROB (WM_NCDESTROY) | |
4755 FROB (WM_NCCALCSIZE) | |
4756 FROB (WM_NCHITTEST) | |
4757 FROB (WM_NCPAINT) | |
4758 FROB (WM_NCACTIVATE) | |
4759 FROB (WM_GETDLGCODE) | |
604 | 4760 #ifdef WM_SYNCPAINT /* not in VC 5 */ |
593 | 4761 FROB (WM_SYNCPAINT) |
604 | 4762 #endif /* WM_SYNCPAINT */ |
593 | 4763 FROB (WM_NCMOUSEMOVE) |
4764 FROB (WM_NCLBUTTONDOWN) | |
4765 FROB (WM_NCLBUTTONUP) | |
4766 FROB (WM_NCLBUTTONDBLCLK) | |
4767 FROB (WM_NCRBUTTONDOWN) | |
4768 FROB (WM_NCRBUTTONUP) | |
4769 FROB (WM_NCRBUTTONDBLCLK) | |
4770 FROB (WM_NCMBUTTONDOWN) | |
4771 FROB (WM_NCMBUTTONUP) | |
4772 FROB (WM_NCMBUTTONDBLCLK) | |
4773 | |
4774 /* FROB (WM_KEYFIRST) */ | |
4775 FROB (WM_KEYDOWN) | |
4776 FROB (WM_KEYUP) | |
4777 FROB (WM_CHAR) | |
4778 FROB (WM_DEADCHAR) | |
4779 FROB (WM_SYSKEYDOWN) | |
4780 FROB (WM_SYSKEYUP) | |
4781 FROB (WM_SYSCHAR) | |
4782 FROB (WM_SYSDEADCHAR) | |
4783 FROB (WM_KEYLAST) | |
4784 | |
604 | 4785 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION) |
4786 /* not in Cygwin? */ | |
593 | 4787 FROB (WM_IME_STARTCOMPOSITION) |
4788 FROB (WM_IME_ENDCOMPOSITION) | |
4789 FROB (WM_IME_COMPOSITION) | |
4790 FROB (WM_IME_KEYLAST) | |
604 | 4791 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */ |
593 | 4792 |
4793 FROB (WM_INITDIALOG) | |
4794 FROB (WM_COMMAND) | |
4795 FROB (WM_SYSCOMMAND) | |
4796 FROB (WM_TIMER) | |
4797 FROB (WM_HSCROLL) | |
4798 FROB (WM_VSCROLL) | |
4799 FROB (WM_INITMENU) | |
4800 FROB (WM_INITMENUPOPUP) | |
4801 FROB (WM_MENUSELECT) | |
4802 FROB (WM_MENUCHAR) | |
4803 FROB (WM_ENTERIDLE) | |
4804 #if(WINVER >= 0x0500) | |
4805 FROB (WM_MENURBUTTONUP) | |
1687 | 4806 #ifdef WM_MENUDRAG |
593 | 4807 FROB (WM_MENUDRAG) |
1687 | 4808 #endif |
4809 #ifdef WM_MENUGETOBJECT | |
593 | 4810 FROB (WM_MENUGETOBJECT) |
1687 | 4811 #endif |
4812 #ifdef WM_UNINITMENUPOPUP | |
593 | 4813 FROB (WM_UNINITMENUPOPUP) |
1687 | 4814 #endif |
4815 #ifdef WM_MENUCOMMAND | |
593 | 4816 FROB (WM_MENUCOMMAND) |
1687 | 4817 #endif |
593 | 4818 #endif /* WINVER >= 0x0500 */ |
4819 | |
4820 | |
4821 FROB (WM_CTLCOLORMSGBOX) | |
4822 FROB (WM_CTLCOLOREDIT) | |
4823 FROB (WM_CTLCOLORLISTBOX) | |
4824 FROB (WM_CTLCOLORBTN) | |
4825 FROB (WM_CTLCOLORDLG) | |
4826 FROB (WM_CTLCOLORSCROLLBAR) | |
4827 FROB (WM_CTLCOLORSTATIC) | |
4828 | |
4829 | |
4830 /* FROB (WM_MOUSEFIRST) */ | |
4831 FROB (WM_MOUSEMOVE) | |
4832 FROB (WM_LBUTTONDOWN) | |
4833 FROB (WM_LBUTTONUP) | |
4834 FROB (WM_LBUTTONDBLCLK) | |
4835 FROB (WM_RBUTTONDOWN) | |
4836 FROB (WM_RBUTTONUP) | |
4837 FROB (WM_RBUTTONDBLCLK) | |
4838 FROB (WM_MBUTTONDOWN) | |
4839 FROB (WM_MBUTTONUP) | |
4840 FROB (WM_MBUTTONDBLCLK) | |
4841 | |
4842 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) | |
4843 FROB (WM_MOUSEWHEEL) | |
4844 FROB (WM_MOUSELAST) | |
4845 #else | |
4846 FROB (WM_MOUSELAST) | |
4847 #endif /* if (_WIN32_WINNT < 0x0400) */ | |
4848 | |
4849 FROB (WM_PARENTNOTIFY) | |
4850 FROB (WM_ENTERMENULOOP) | |
4851 FROB (WM_EXITMENULOOP) | |
4852 | |
4853 #if(WINVER >= 0x0400) | |
4854 FROB (WM_NEXTMENU) | |
4855 | |
4856 FROB (WM_SIZING) | |
4857 FROB (WM_CAPTURECHANGED) | |
4858 FROB (WM_MOVING) | |
4859 FROB (WM_POWERBROADCAST) | |
4860 | |
4861 FROB (WM_DEVICECHANGE) | |
4862 | |
4863 #endif /* WINVER >= 0x0400 */ | |
4864 | |
4865 FROB (WM_MDICREATE) | |
4866 FROB (WM_MDIDESTROY) | |
4867 FROB (WM_MDIACTIVATE) | |
4868 FROB (WM_MDIRESTORE) | |
4869 FROB (WM_MDINEXT) | |
4870 FROB (WM_MDIMAXIMIZE) | |
4871 FROB (WM_MDITILE) | |
4872 FROB (WM_MDICASCADE) | |
4873 FROB (WM_MDIICONARRANGE) | |
4874 FROB (WM_MDIGETACTIVE) | |
4875 | |
4876 | |
4877 FROB (WM_MDISETMENU) | |
4878 FROB (WM_ENTERSIZEMOVE) | |
4879 FROB (WM_EXITSIZEMOVE) | |
4880 FROB (WM_DROPFILES) | |
4881 FROB (WM_MDIREFRESHMENU) | |
4882 | |
604 | 4883 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */ |
593 | 4884 |
4885 #if(WINVER >= 0x0400) | |
4886 FROB (WM_IME_SETCONTEXT) | |
4887 FROB (WM_IME_NOTIFY) | |
4888 FROB (WM_IME_CONTROL) | |
4889 FROB (WM_IME_COMPOSITIONFULL) | |
4890 FROB (WM_IME_SELECT) | |
4891 FROB (WM_IME_CHAR) | |
4892 #endif /* WINVER >= 0x0400 */ | |
1687 | 4893 #if(WINVER >= 0x0500) && defined(WM_IME_REQUEST) |
593 | 4894 FROB (WM_IME_REQUEST) |
4895 #endif /* WINVER >= 0x0500 */ | |
4896 #if(WINVER >= 0x0400) | |
4897 FROB (WM_IME_KEYDOWN) | |
4898 FROB (WM_IME_KEYUP) | |
4899 #endif /* WINVER >= 0x0400 */ | |
4900 | |
604 | 4901 #endif /* WM_IME_SETCONTEXT */ |
593 | 4902 |
4903 #if(_WIN32_WINNT >= 0x0400) | |
4904 FROB (WM_MOUSEHOVER) | |
4905 FROB (WM_MOUSELEAVE) | |
4906 #endif /* _WIN32_WINNT >= 0x0400 */ | |
4907 | |
4908 FROB (WM_CUT) | |
4909 FROB (WM_COPY) | |
4910 FROB (WM_PASTE) | |
4911 FROB (WM_CLEAR) | |
4912 FROB (WM_UNDO) | |
4913 FROB (WM_RENDERFORMAT) | |
4914 FROB (WM_RENDERALLFORMATS) | |
4915 FROB (WM_DESTROYCLIPBOARD) | |
4916 FROB (WM_DRAWCLIPBOARD) | |
4917 FROB (WM_PAINTCLIPBOARD) | |
4918 FROB (WM_VSCROLLCLIPBOARD) | |
4919 FROB (WM_SIZECLIPBOARD) | |
4920 FROB (WM_ASKCBFORMATNAME) | |
4921 FROB (WM_CHANGECBCHAIN) | |
4922 FROB (WM_HSCROLLCLIPBOARD) | |
4923 FROB (WM_QUERYNEWPALETTE) | |
4924 FROB (WM_PALETTEISCHANGING) | |
4925 FROB (WM_PALETTECHANGED) | |
4926 FROB (WM_HOTKEY) | |
4927 | |
4928 #if(WINVER >= 0x0400) | |
4929 FROB (WM_PRINT) | |
4930 FROB (WM_PRINTCLIENT) | |
4931 | |
4932 FROB (WM_HANDHELDFIRST) | |
4933 FROB (WM_HANDHELDLAST) | |
4934 | |
4935 FROB (WM_AFXFIRST) | |
4936 FROB (WM_AFXLAST) | |
4937 #endif /* WINVER >= 0x0400 */ | |
4938 | |
4939 FROB (WM_PENWINFIRST) | |
4940 FROB (WM_PENWINLAST) | |
4941 }; | |
4942 | |
4943 #undef FROB | |
4944 | |
4945 static void | |
4946 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam, | |
4947 LPARAM lParam) | |
4948 { | |
4949 Lisp_Object frame = mswindows_find_frame (hwnd); | |
4950 int i; | |
4932 | 4951 const Ascbyte *str = 0; |
593 | 4952 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */ |
4953 | |
4954 for (i = 0; i < countof (debug_mswin_messages); i++) | |
4955 { | |
647 | 4956 if (debug_mswin_messages[i].mess == (int) message_) |
593 | 4957 { |
4958 str = debug_mswin_messages[i].string; | |
4959 break; | |
4960 } | |
4961 } | |
4962 | |
4963 if (str) | |
4964 stderr_out ("%s", str); | |
4965 else | |
4966 stderr_out ("%x", message_); | |
4967 | |
4968 if (debug_mswindows_events > 1) | |
4969 { | |
4970 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ", | |
4971 wParam, (int) lParam, (unsigned int) hwnd); | |
4972 debug_print (frame); | |
903 | 4973 if (message_ == WM_WINDOWPOSCHANGED || |
4974 message_ == WM_WINDOWPOSCHANGING) | |
4975 { | |
4976 WINDOWPOS *wp = (WINDOWPOS *) lParam; | |
4977 stderr_out(" WINDOWPOS: x=%d, y=%d, h=%d, w=%d\n", | |
4978 wp->x, wp->y, wp->cx, wp->cy); | |
4979 } | |
4980 else if (message_ == WM_MOVE) | |
4981 { | |
4982 int x = (int)(short) LOWORD(lParam); /* horizontal position */ | |
4983 int y = (int)(short) HIWORD(lParam); /* vertical position */ | |
4984 stderr_out(" MOVE: x=%d, y=%d\n", x, y); | |
4985 } | |
4986 else if (message_ == WM_SIZE) | |
4987 { | |
4988 int w = (int)(short) LOWORD(lParam); /* width */ | |
4989 int h = (int)(short) HIWORD(lParam); /* height */ | |
4990 stderr_out(" SIZE: w=%d, h=%d\n", w, h); | |
4991 } | |
593 | 4992 } |
4993 else | |
4994 stderr_out ("\n"); | |
4995 } | |
4996 | |
4997 #endif /* DEBUG_XEMACS */ | |
4998 | |
428 | 4999 /************************************************************************/ |
5000 /* initialization */ | |
5001 /************************************************************************/ | |
5002 | |
5003 void | |
5004 reinit_vars_of_event_mswindows (void) | |
5005 { | |
5006 mswindows_pending_timers_count = 0; | |
5007 | |
1204 | 5008 mswindows_event_stream = xnew_and_zero (struct event_stream); |
428 | 5009 |
5010 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; | |
5011 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; | |
5012 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; | |
788 | 5013 mswindows_event_stream->format_magic_event_cb = emacs_mswindows_format_magic_event; |
5014 mswindows_event_stream->compare_magic_event_cb= emacs_mswindows_compare_magic_event; | |
5015 mswindows_event_stream->hash_magic_event_cb = emacs_mswindows_hash_magic_event; | |
428 | 5016 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; |
5017 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; | |
1204 | 5018 mswindows_event_stream->drain_queue_cb = emacs_mswindows_drain_queue; |
428 | 5019 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; |
5020 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; | |
5021 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; | |
5022 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; | |
853 | 5023 mswindows_event_stream->create_io_streams_cb = emacs_mswindows_create_io_streams; |
5024 mswindows_event_stream->delete_io_streams_cb = emacs_mswindows_delete_io_streams; | |
442 | 5025 mswindows_event_stream->current_event_timestamp_cb = |
5026 emacs_mswindows_current_event_timestamp; | |
903 | 5027 |
5028 dde_eval_pending = 0; | |
428 | 5029 } |
5030 | |
5031 void | |
5032 vars_of_event_mswindows (void) | |
5033 { | |
5034 mswindows_s_dispatch_event_queue = Qnil; | |
5035 staticpro (&mswindows_s_dispatch_event_queue); | |
5036 mswindows_s_dispatch_event_queue_tail = Qnil; | |
1204 | 5037 dump_add_root_lisp_object (&mswindows_s_dispatch_event_queue_tail); |
428 | 5038 |
853 | 5039 mswindows_error_caught_in_modal_loop = 0; |
442 | 5040 |
903 | 5041 #ifdef HAVE_DRAGNDROP |
5042 Fprovide (Qdde); | |
5043 | |
5044 DEFVAR_LISP ("dde-advise-items", &Vdde_advise_items /* | |
5045 A list of allocated DDE advise items. | |
5046 Each item is an uninterned symbol, created using dde-alloc-advise-item. | |
5047 | |
5048 The symbol's value is the data which is returned to the DDE client when | |
5049 a request for the item is made (or a dde-advise call is made). | |
5050 | |
3025 | 5051 The symbol also has a `HSZ' property, which holds the DDE string handle |
903 | 5052 for the item, as a float. This is for internal use only, and should not |
5053 be modified. | |
5054 */ ); | |
5055 Vdde_advise_items = Qnil; | |
5056 | |
5057 dde_eval_result = Qnil; | |
5058 staticpro (&dde_eval_result); | |
5059 dde_eval_error = Qnil; | |
5060 staticpro (&dde_eval_error); | |
5061 #endif | |
5062 | |
442 | 5063 #ifdef DEBUG_XEMACS |
5064 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /* | |
593 | 5065 If non-zero, display debug information about Windows messages that XEmacs sees. |
442 | 5066 Information is displayed in a console window. Currently defined values are: |
5067 | |
593 | 5068 1 == non-verbose output (just the message name) |
5069 2 == verbose output (all parameters) | |
5070 3 == even more verbose output (extra debugging info) | |
442 | 5071 */ ); |
5072 debug_mswindows_events = 0; | |
5073 #endif | |
5074 | |
5075 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu", | |
5076 &mswindows_alt_by_itself_activates_menu /* | |
5077 *Controls whether pressing and releasing the Alt key activates the menubar. | |
5078 This applies only if no intervening key was pressed. See also | |
5079 `menu-accelerator-enabled', which is probably the behavior you actually want. | |
428 | 5080 Default is t. |
5081 */ ); | |
5082 | |
442 | 5083 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", |
5084 &mswindows_dynamic_frame_resize /* | |
428 | 5085 *Controls redrawing frame contents during mouse-drag or keyboard resize |
5086 operation. When non-nil, the frame is redrawn while being resized. When | |
5087 nil, frame is not redrawn, and exposed areas are filled with default | |
5088 MDI application background color. Note that this option only has effect | |
5089 if "Show window contents while dragging" is on in system Display/Plus! | |
5090 settings. | |
5091 Default is t on fast machines, nil on slow. | |
5092 */ ); | |
5093 | |
442 | 5094 DEFVAR_INT ("mswindows-mouse-button-tolerance", |
5095 &mswindows_mouse_button_tolerance /* | |
428 | 5096 *Analogue of double click interval for faking middle mouse events. |
5097 The value is the minimum time in milliseconds that must elapse between | |
5098 left/right button down events before they are considered distinct events. | |
5099 If both mouse buttons are depressed within this interval, a middle mouse | |
5100 button down event is generated instead. | |
5101 If negative or zero, currently set system default is used instead. | |
5102 */ ); | |
5103 | |
5104 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /* | |
5105 Number of physical mouse buttons. | |
5106 */ ); | |
5107 | |
442 | 5108 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", |
5109 &mswindows_mouse_button_max_skew_x /* | |
428 | 5110 *Maximum horizontal distance in pixels between points in which left and |
5111 right button clicks occurred for them to be translated into single | |
5112 middle button event. Clicks must occur in time not longer than defined | |
5113 by the variable `mswindows-mouse-button-tolerance'. | |
5114 If negative or zero, currently set system default is used instead. | |
5115 */ ); | |
5116 | |
442 | 5117 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", |
5118 &mswindows_mouse_button_max_skew_y /* | |
428 | 5119 *Maximum vertical distance in pixels between points in which left and |
5120 right button clicks occurred for them to be translated into single | |
5121 middle button event. Clicks must occur in time not longer than defined | |
5122 by the variable `mswindows-mouse-button-tolerance'. | |
5123 If negative or zero, currently set system default is used instead. | |
5124 */ ); | |
5125 | |
5126 mswindows_mouse_button_max_skew_x = 0; | |
5127 mswindows_mouse_button_max_skew_y = 0; | |
5128 mswindows_mouse_button_tolerance = 0; | |
442 | 5129 mswindows_alt_by_itself_activates_menu = 1; |
428 | 5130 } |
5131 | |
5132 void | |
5133 syms_of_event_mswindows (void) | |
5134 { | |
903 | 5135 #ifdef HAVE_DRAGNDROP |
5136 DEFSYMBOL(QHSZ); | |
5137 DEFSUBR(Fdde_alloc_advise_item); | |
5138 DEFSUBR(Fdde_free_advise_item); | |
5139 DEFSUBR(Fdde_advise); | |
5140 #endif | |
428 | 5141 } |
5142 | |
5143 void | |
5144 lstream_type_create_mswindows_selectable (void) | |
5145 { | |
853 | 5146 #ifndef CYGWIN |
428 | 5147 init_slurp_stream (); |
5148 init_shove_stream (); | |
5149 init_winsock_stream (); | |
5150 #endif | |
5151 } | |
5152 | |
5153 void | |
5154 init_event_mswindows_late (void) | |
5155 { | |
853 | 5156 #ifdef CYGWIN |
771 | 5157 windows_fd = retry_open ("/dev/windows", O_RDONLY | O_NONBLOCK, 0); |
814 | 5158 assert (windows_fd >= 0); |
428 | 5159 FD_SET (windows_fd, &input_wait_mask); |
814 | 5160 FD_ZERO (&zero_mask); |
428 | 5161 #endif |
5162 | |
5163 event_stream = mswindows_event_stream; | |
5164 | |
5165 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE); | |
5166 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS); | |
5167 } |