Mercurial > hg > xemacs-beta
annotate src/event-msw.c @ 5050:6f2158fa75ed
Fix quick-build, use asserts() in place of ABORT()
-------------------- ChangeLog entries follow: --------------------
ChangeLog addition:
2010-02-20 Ben Wing <ben@xemacs.org>
* configure.ac (XE_COMPLEX_ARG):
Correct doc of --quick-build: It also doesn't check for Lisp shadows.
src/ChangeLog addition:
2010-02-20 Ben Wing <ben@xemacs.org>
* EmacsFrame.c:
* EmacsFrame.c (EmacsFrameRecomputeCellSize):
* alloca.c (i00afunc):
* buffer.c:
* buffer.c (MARKED_SLOT):
* buffer.c (complex_vars_of_buffer):
* cm.c:
* cm.c (cmcheckmagic):
* console.c:
* console.c (MARKED_SLOT):
* device-x.c:
* device-x.c (x_get_visual_depth):
* emacs.c (sort_args):
* eval.c (throw_or_bomb_out):
* event-stream.c:
* event-stream.c (Fadd_timeout):
* event-stream.c (Fadd_async_timeout):
* event-stream.c (Frecent_keys):
* events.c:
* events.c (Fdeallocate_event):
* events.c (event_pixel_translation):
* extents.c:
* extents.c (process_extents_for_insertion_mapper):
* fns.c (Fbase64_encode_region):
* fns.c (Fbase64_encode_string):
* fns.c (Fbase64_decode_region):
* fns.c (Fbase64_decode_string):
* font-lock.c:
* font-lock.c (find_context):
* frame-x.c:
* frame-x.c (x_wm_mark_shell_size_user_specified):
* frame-x.c (x_wm_mark_shell_position_user_specified):
* frame-x.c (x_wm_set_shell_iconic_p):
* frame-x.c (x_wm_set_cell_size):
* frame-x.c (x_wm_set_variable_size):
* frame-x.c (x_wm_store_class_hints):
* frame-x.c (x_wm_maybe_store_wm_command):
* frame-x.c (x_initialize_frame_size):
* frame.c (delete_frame_internal):
* frame.c (change_frame_size_1):
* free-hook.c (check_free):
* free-hook.c (note_block_input):
* free-hook.c (log_gcpro):
* gccache-gtk.c (gc_cache_lookup):
* gccache-x.c:
* gccache-x.c (gc_cache_lookup):
* glyphs-gtk.c:
* glyphs-gtk.c (init_image_instance_from_gdk_pixmap):
* glyphs-x.c:
* glyphs-x.c (extract_xpm_color_names):
* insdel.c:
* insdel.c (move_gap):
* keymap.c:
* keymap.c (keymap_lookup_directly):
* keymap.c (keymap_delete_inverse_internal):
* keymap.c (accessible_keymaps_mapper_1):
* keymap.c (where_is_recursive_mapper):
* lisp.h:
* lstream.c (make_lisp_buffer_stream_1):
* macros.c:
* macros.c (pop_kbd_macro_event):
* mc-alloc.c (remove_page_from_used_list):
* menubar-x.c:
* menubar-x.c (set_frame_menubar):
* ralloc.c:
* ralloc.c (obtain):
* ralloc.c (relinquish):
* ralloc.c (relocate_blocs):
* ralloc.c (resize_bloc):
* ralloc.c (r_alloc_free):
* ralloc.c (r_re_alloc):
* ralloc.c (r_alloc_thaw):
* ralloc.c (init_ralloc):
* ralloc.c (Free_Addr_Block):
* scrollbar-x.c:
* scrollbar-x.c (x_update_scrollbar_instance_status):
* sunplay.c (init_device):
* unexnt.c:
* unexnt.c (read_in_bss):
* unexnt.c (map_in_heap):
* window.c:
* window.c (real_window):
* window.c (window_display_lines):
* window.c (window_display_buffer):
* window.c (set_window_display_buffer):
* window.c (unshow_buffer):
* window.c (Fget_lru_window):
if (...) ABORT(); ---> assert();
More specifically:
if (x == y) ABORT (); --> assert (x != y);
if (x != y) ABORT (); --> assert (x == y);
if (x > y) ABORT (); --> assert (x <= y);
etc.
if (!x) ABORT (); --> assert (x);
if (x) ABORT (); --> assert (!x);
DeMorgan's Law's applied and manually simplified:
if (x && !y) ABORT (); --> assert (!x || y);
if (!x || y >= z) ABORT (); --> assert (x && y < z);
Checked to make sure that assert() of an expression with side
effects ensures that the side effects get executed even when
asserts are disabled, and add a comment about this being a
requirement of any "disabled assert" expression.
* depend:
* make-src-depend:
* make-src-depend (PrintDeps):
Fix broken code in make-src-depend so it does what it was always
supposed to do, which was separate out config.h and lisp.h and
all the files they include into separate variables in the
depend part of Makefile so that quick-build can turn off the
lisp.h/config.h/text.h/etc. dependencies of the source files, to
speed up recompilation.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Sat, 20 Feb 2010 05:05:54 -0600 |
parents | ae48681c47fa |
children | d0c14ea98592 |
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. | |
3025 | 4 Copyright (C) 1996, 2000, 2001, 2002, 2003, 2005 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 |
3389 pixel_to_real_char_size (frame, rect.right, rect.bottom, | |
3390 &FRAME_MSWINDOWS_CHARWIDTH (frame), | |
3391 &FRAME_MSWINDOWS_CHARHEIGHT (frame)); | |
3392 | |
771 | 3393 pixel_to_char_size (frame, rect.right, rect.bottom, &columns, |
3394 &rows); | |
442 | 3395 change_frame_size (frame, rows, columns, 1); |
3396 | |
3397 /* If we are inside frame creation, we have to apply geometric | |
3398 properties now. */ | |
3399 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) | |
3400 { | |
3401 /* Yes, we have to size again */ | |
771 | 3402 mswindows_size_frame_internal (frame, |
3403 FRAME_MSWINDOWS_TARGET_RECT | |
3404 (frame)); | |
3405 /* Reset so we do not get here again. The SetWindowPos | |
3406 * call in mswindows_size_frame_internal can cause | |
3407 * recursion here. */ | |
442 | 3408 if (FRAME_MSWINDOWS_TARGET_RECT (frame)) |
3409 { | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
3410 xfree (FRAME_MSWINDOWS_TARGET_RECT (frame)); |
442 | 3411 FRAME_MSWINDOWS_TARGET_RECT (frame) = 0; |
3412 } | |
3413 } | |
3414 else | |
3415 { | |
903 | 3416 if (!msframe->sizing && !FRAME_VISIBLE_P (frame)) |
3417 { | |
3418 mswindows_enqueue_magic_event (hwnd, XM_MAPFRAME); | |
3419 /* APA: Now that the magic XM_MAPFRAME event has | |
3420 * been sent we can mark the frame as visible (just | |
3421 * like 21.1 did). */ | |
3422 FRAME_VISIBLE_P (frame) = 1; | |
3423 } | |
442 | 3424 |
1279 | 3425 if (frame->init_finished && |
3426 (!msframe->sizing || mswindows_dynamic_frame_resize)) | |
442 | 3427 redisplay (); |
3428 } | |
428 | 3429 } |
3430 } | |
442 | 3431 break; |
3432 | |
3433 case WM_DISPLAYCHANGE: | |
3434 { | |
3435 struct device *d; | |
3436 DWORD message_tick = GetMessageTime (); | |
3437 | |
3438 fobj = mswindows_find_frame (hwnd); | |
3439 frame = XFRAME (fobj); | |
3440 d = XDEVICE (FRAME_DEVICE (frame)); | |
3441 | |
3442 /* Do this only once per message. XEmacs can receive this message | |
3443 through as many frames as it currently has open. Message time | |
3444 will be the same for all these messages. Despite extreme | |
3445 efficiency, the code below has about one in 4 billion | |
3446 probability that the HDC is not recreated, provided that | |
3447 XEmacs is running sufficiently longer than 52 days. */ | |
1279 | 3448 if (DEVICE_MSWINDOWS_UPDATE_TICK (d) != message_tick) |
442 | 3449 { |
1279 | 3450 DEVICE_MSWINDOWS_UPDATE_TICK (d) = message_tick; |
3451 DeleteDC (DEVICE_MSWINDOWS_HCDC (d)); | |
3452 DEVICE_MSWINDOWS_HCDC (d) = CreateCompatibleDC (NULL); | |
442 | 3453 } |
3454 } | |
3455 break; | |
3456 | |
3457 /* Misc magic events which only require that the frame be identified */ | |
3458 case WM_SETFOCUS: | |
3459 case WM_KILLFOCUS: | |
3460 mswindows_enqueue_magic_event (hwnd, message_); | |
3461 break; | |
3462 | |
3463 case WM_WINDOWPOSCHANGING: | |
428 | 3464 { |
442 | 3465 WINDOWPOS *wp = (LPWINDOWPOS) lParam; |
3466 WINDOWPLACEMENT wpl = { sizeof(WINDOWPLACEMENT) }; | |
3467 GetWindowPlacement(hwnd, &wpl); | |
3468 | |
3469 /* Only interested if size is changing and we're not being iconified */ | |
3470 if (wpl.showCmd != SW_SHOWMINIMIZED | |
3471 && wpl.showCmd != SW_SHOWMAXIMIZED | |
3472 && !(wp->flags & SWP_NOSIZE)) | |
428 | 3473 { |
442 | 3474 RECT ncsize = { 0, 0, 0, 0 }; |
3475 int pixwidth, pixheight; | |
771 | 3476 AdjustWindowRectEx (&ncsize, qxeGetWindowLong (hwnd, GWL_STYLE), |
442 | 3477 GetMenu(hwnd) != NULL, |
771 | 3478 qxeGetWindowLong (hwnd, GWL_EXSTYLE)); |
442 | 3479 |
3480 round_size_to_real_char (XFRAME (mswindows_find_frame (hwnd)), | |
3481 wp->cx - (ncsize.right - ncsize.left), | |
3482 wp->cy - (ncsize.bottom - ncsize.top), | |
3483 &pixwidth, &pixheight); | |
3484 | |
3485 /* Convert client sizes to window sizes */ | |
3486 pixwidth += (ncsize.right - ncsize.left); | |
3487 pixheight += (ncsize.bottom - ncsize.top); | |
3488 | |
3489 if (wpl.showCmd != SW_SHOWMAXIMIZED) | |
3490 { | |
3491 /* Adjust so that the bottom or right doesn't move if it's | |
3492 * the top or left that's being changed */ | |
3493 RECT rect; | |
3494 GetWindowRect (hwnd, &rect); | |
3495 | |
3496 if (rect.left != wp->x) | |
3497 wp->x += wp->cx - pixwidth; | |
3498 if (rect.top != wp->y) | |
3499 wp->y += wp->cy - pixheight; | |
3500 } | |
3501 | |
3502 wp->cx = pixwidth; | |
3503 wp->cy = pixheight; | |
428 | 3504 } |
442 | 3505 /* DefWindowProc sends useful WM_GETMINMAXINFO message, and adjusts |
3506 window position if the user tries to track window too small */ | |
428 | 3507 } |
442 | 3508 goto defproc; |
3509 | |
3510 case WM_ENTERSIZEMOVE: | |
771 | 3511 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3512 msframe->sizing = 1; |
3513 return 0; | |
3514 | |
3515 case WM_EXITSIZEMOVE: | |
771 | 3516 msframe = FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (hwnd))); |
442 | 3517 msframe->sizing = 0; |
3518 /* Queue noop event */ | |
3519 mswindows_enqueue_magic_event (NULL, XM_BUMPQUEUE); | |
3520 return 0; | |
428 | 3521 |
3522 #ifdef HAVE_SCROLLBARS | |
442 | 3523 case WM_VSCROLL: |
3524 case WM_HSCROLL: | |
3525 { | |
3526 /* Direction of scroll is determined by scrollbar instance. */ | |
1279 | 3527 int code = (int) LOWORD (wParam); |
3528 int pos = (short int) HIWORD (wParam); | |
442 | 3529 HWND hwndScrollBar = (HWND) lParam; |
3530 struct gcpro gcpro1, gcpro2; | |
3531 | |
3532 mswindows_handle_scrollbar_event (hwndScrollBar, code, pos); | |
3533 GCPRO2 (emacs_event, fobj); | |
853 | 3534 if (UNBOUNDP (mswindows_pump_outstanding_events ())) /* Can GC */ |
442 | 3535 { |
3536 /* Error during event pumping - cancel scroll */ | |
771 | 3537 qxeSendMessage (hwndScrollBar, WM_CANCELMODE, 0, 0); |
442 | 3538 } |
3539 UNGCPRO; | |
3540 break; | |
3541 } | |
3542 | |
3543 case WM_MOUSEWHEEL: | |
3544 { | |
3545 int keys = LOWORD (wParam); /* Modifier key flags */ | |
3546 int delta = (short) HIWORD (wParam); /* Wheel rotation amount */ | |
3547 | |
1622 | 3548 /* enqueue button4/5 events if mswindows_handle_mousewheel_event |
3549 doesn't handle the event, such as when the scrollbars are not | |
3550 displayed */ | |
3551 if (!mswindows_handle_mousewheel_event (mswindows_find_frame (hwnd), | |
464 | 3552 keys, delta, |
2367 | 3553 XE_MAKEPOINTS (lParam))) |
1622 | 3554 mswindows_enqueue_mouse_button_event (hwnd, message_, |
2367 | 3555 XE_MAKEPOINTS (lParam), |
1622 | 3556 wParam, |
3557 GetMessageTime()); | |
3558 /* We are not in a modal loop so no pumping is necessary. */ | |
3559 break; | |
442 | 3560 } |
428 | 3561 #endif |
3562 | |
3563 #ifdef HAVE_MENUBARS | |
442 | 3564 case WM_INITMENU: |
771 | 3565 if (UNBOUNDP (mswindows_handle_wm_initmenu |
3566 ((HMENU) wParam, | |
3567 XFRAME (mswindows_find_frame (hwnd))))) | |
3568 qxeSendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
442 | 3569 break; |
3570 | |
3571 case WM_INITMENUPOPUP: | |
3572 if (!HIWORD(lParam)) | |
3573 { | |
771 | 3574 if (UNBOUNDP (mswindows_handle_wm_initmenupopup |
3575 ((HMENU) wParam, | |
3576 XFRAME (mswindows_find_frame (hwnd))))) | |
3577 qxeSendMessage (hwnd, WM_CANCELMODE, 0, 0); | |
442 | 3578 } |
3579 break; | |
428 | 3580 |
3581 #endif /* HAVE_MENUBARS */ | |
3582 | |
442 | 3583 case WM_COMMAND: |
3584 { | |
3585 WORD id = LOWORD (wParam); | |
3586 WORD nid = HIWORD (wParam); | |
3587 HWND cid = (HWND)lParam; | |
3588 frame = XFRAME (mswindows_find_frame (hwnd)); | |
428 | 3589 |
3590 #ifdef HAVE_TOOLBARS | |
442 | 3591 if (!NILP (mswindows_handle_toolbar_wm_command (frame, cid, id))) |
3592 break; | |
428 | 3593 #endif |
771 | 3594 /* widgets in a buffer only eval a callback for suitable events. */ |
442 | 3595 switch (nid) |
3596 { | |
3597 case BN_CLICKED: | |
3598 case EN_CHANGE: | |
3599 case CBN_EDITCHANGE: | |
3600 case CBN_SELCHANGE: | |
3601 if (!NILP (mswindows_handle_gui_wm_command (frame, cid, id))) | |
3602 return 0; | |
3603 } | |
3604 /* menubars always must come last since the hashtables do not | |
771 | 3605 always exist */ |
428 | 3606 #ifdef HAVE_MENUBARS |
442 | 3607 if (!NILP (mswindows_handle_wm_command (frame, id))) |
3608 break; | |
428 | 3609 #endif |
3610 | |
771 | 3611 goto defproc; |
3612 /* Bite me - a spurious command. This used to not be able to | |
3613 happen but with the introduction of widgets it's now | |
3614 possible. #### Andy, fix the god-damn widget code! It has | |
3615 more bugs than a termite's nest! */ | |
442 | 3616 } |
3617 break; | |
3618 | |
3619 case WM_CTLCOLORBTN: | |
3620 case WM_CTLCOLORLISTBOX: | |
3621 case WM_CTLCOLOREDIT: | |
3622 case WM_CTLCOLORSTATIC: | |
3623 case WM_CTLCOLORSCROLLBAR: | |
3624 { | |
3625 /* if we get an opportunity to paint a widget then do so if | |
3626 there is an appropriate face */ | |
771 | 3627 HWND crtlwnd = (HWND) lParam; |
3628 LONG ii = qxeGetWindowLong (crtlwnd, GWL_USERDATA); | |
442 | 3629 if (ii) |
3630 { | |
3631 Lisp_Object image_instance; | |
5013 | 3632 image_instance = GET_LISP_FROM_VOID ((void *) ii); |
442 | 3633 if (IMAGE_INSTANCEP (image_instance) |
3634 && | |
3635 IMAGE_INSTANCE_TYPE_P (image_instance, IMAGE_WIDGET)) | |
3636 { | |
3637 /* set colors for the buttons */ | |
771 | 3638 HDC hdc = (HDC) wParam; |
442 | 3639 if (last_widget_brushed != ii) |
3640 { | |
3641 if (widget_brush) | |
3642 DeleteObject (widget_brush); | |
3643 widget_brush = CreateSolidBrush | |
3644 (COLOR_INSTANCE_MSWINDOWS_COLOR | |
3645 (XCOLOR_INSTANCE | |
3646 (FACE_BACKGROUND | |
3647 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3648 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3649 } | |
3650 last_widget_brushed = ii; | |
3651 SetTextColor | |
3652 (hdc, | |
3653 COLOR_INSTANCE_MSWINDOWS_COLOR | |
3654 (XCOLOR_INSTANCE | |
3655 (FACE_FOREGROUND | |
3656 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3657 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3658 SetBkMode (hdc, OPAQUE); | |
3659 SetBkColor | |
3660 (hdc, | |
3661 COLOR_INSTANCE_MSWINDOWS_COLOR | |
3662 (XCOLOR_INSTANCE | |
3663 (FACE_BACKGROUND | |
3664 (XIMAGE_INSTANCE_WIDGET_FACE (image_instance), | |
3665 XIMAGE_INSTANCE_FRAME (image_instance))))); | |
3666 return (LRESULT)widget_brush; | |
3667 } | |
3668 } | |
3669 } | |
3670 goto defproc; | |
428 | 3671 |
3672 #ifdef HAVE_DRAGNDROP | |
853 | 3673 case WM_DROPFILES: /* implementation ripped-off from event-Xt.c */ |
442 | 3674 { |
771 | 3675 UINT filecount, i; |
442 | 3676 POINT point; |
3677 | |
3678 Lisp_Object l_dndlist = Qnil, l_item = Qnil; | |
3679 struct gcpro gcpro1, gcpro2, gcpro3; | |
3680 | |
3681 emacs_event = Fmake_event (Qnil, Qnil); | |
771 | 3682 event = XEVENT (emacs_event); |
442 | 3683 |
3684 GCPRO3 (emacs_event, l_dndlist, l_item); | |
3685 | |
3686 if (!DragQueryPoint ((HDROP) wParam, &point)) | |
853 | 3687 point.x = point.y = -1; /* outside client area */ |
442 | 3688 |
964 | 3689 XSET_EVENT_TYPE (emacs_event, misc_user_event); |
3690 XSET_EVENT_CHANNEL (emacs_event, mswindows_find_frame(hwnd)); | |
3691 XSET_EVENT_TIMESTAMP (emacs_event, GetMessageTime()); | |
1204 | 3692 XSET_EVENT_MISC_USER_BUTTON (emacs_event, 1); |
3693 XSET_EVENT_MISC_USER_MODIFIERS (emacs_event, | |
964 | 3694 mswindows_modifier_state (NULL, (DWORD) -1, 0)); |
1204 | 3695 XSET_EVENT_MISC_USER_X (emacs_event, point.x); |
3696 XSET_EVENT_MISC_USER_Y (emacs_event, point.y); | |
3697 XSET_EVENT_MISC_USER_FUNCTION (emacs_event, | |
964 | 3698 Qdragdrop_drop_dispatch); |
442 | 3699 |
771 | 3700 filecount = qxeDragQueryFile ((HDROP) wParam, 0xffffffff, NULL, 0); |
3701 for (i = 0; i < filecount; i++) | |
442 | 3702 { |
867 | 3703 Ibyte *fname; |
771 | 3704 Extbyte *fname_ext; |
3705 Bytecount fnamelen; | |
3706 Charcount len = qxeDragQueryFile ((HDROP) wParam, i, NULL, 0); | |
2526 | 3707 int freeme = 0; |
442 | 3708 /* The URLs that we make here aren't correct according to section |
3709 * 3.10 of rfc1738 because they're missing the //<host>/ part and | |
3710 * because they may contain reserved characters. But that's OK - | |
3711 * they just need to be good enough to keep dragdrop.el happy. */ | |
2367 | 3712 fname_ext = alloca_extbytes ((len + 1) * XETCHAR_SIZE); |
771 | 3713 qxeDragQueryFile ((HDROP) wParam, i, fname_ext, len + 1); |
3714 | |
3715 TO_INTERNAL_FORMAT (DATA, (fname_ext, len * XETCHAR_SIZE), | |
3716 ALLOCA, (fname, fnamelen), | |
3717 Qmswindows_tstr); | |
442 | 3718 |
2526 | 3719 |
442 | 3720 /* May be a shell link aka "shortcut" - replace fname if so */ |
2367 | 3721 if (!qxestrcasecmp_ascii (fname + fnamelen - 4, ".LNK")) |
442 | 3722 { |
2526 | 3723 fname = mswindows_read_link (fname); |
3724 freeme = 1; | |
442 | 3725 } |
2526 | 3726 |
771 | 3727 { |
2526 | 3728 Ibyte *fname2 = urlify_filename (fname); |
4953
304aebb79cd3
function renamings to track names of char typedefs
Ben Wing <ben@xemacs.org>
parents:
4952
diff
changeset
|
3729 l_item = build_istring (fname2); |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
3730 xfree (fname2); |
2526 | 3731 if (freeme) |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4953
diff
changeset
|
3732 xfree (fname); |
771 | 3733 l_dndlist = Fcons (l_item, l_dndlist); |
3734 } | |
442 | 3735 } |
771 | 3736 |
442 | 3737 DragFinish ((HDROP) wParam); |
3738 | |
1204 | 3739 SET_EVENT_MISC_USER_OBJECT (event, |
964 | 3740 Fcons (Qdragdrop_URL, l_dndlist)); |
442 | 3741 mswindows_enqueue_dispatch_event (emacs_event); |
3742 UNGCPRO; | |
3743 } | |
3744 break; | |
771 | 3745 #endif /* HAVE_DRAGNDROP */ |
3746 | |
3747 #ifdef MULE | |
3748 case WM_IME_CHAR: | |
3749 | |
3750 case WM_IME_STARTCOMPOSITION: | |
3751 mswindows_start_ime_composition (XFRAME (mswindows_find_frame (hwnd))); | |
3752 goto defproc; | |
3753 | |
3754 case WM_IME_COMPOSITION: | |
3755 if (lParam & GCS_RESULTSTR) | |
3756 { | |
3757 HIMC imc = ImmGetContext (hwnd); | |
3758 Extbyte *result; | |
3759 Bytecount len; | |
867 | 3760 Ibyte *resultint, *endptr; |
771 | 3761 Bytecount lenint; |
3762 int speccount; | |
3763 | |
3764 if (!imc) | |
3765 break; | |
3766 | |
3767 /* See WM_KEYDOWN above. */ | |
3768 speccount = begin_dont_check_for_quit (); | |
3769 | |
3770 /* Sizes always in bytes, even for unicode. | |
3771 ImmGetCompositionStringW is supported even on Windows 9x, and | |
3772 allows us to handle multiple languages. */ | |
3773 len = ImmGetCompositionStringW (imc, GCS_RESULTSTR, NULL, 0); | |
2367 | 3774 result = alloca_extbytes (len); |
771 | 3775 ImmGetCompositionStringW (imc, GCS_RESULTSTR, (WCHAR *) result, len); |
3776 ImmReleaseContext (hwnd, imc); | |
3777 | |
3778 TO_INTERNAL_FORMAT (DATA, (result, len), | |
3779 ALLOCA, (resultint, lenint), | |
3780 Qmswindows_tstr); | |
3781 | |
3782 endptr = resultint + lenint; | |
3783 | |
3784 while (resultint < endptr) | |
3785 { | |
867 | 3786 Ichar ch = itext_ichar (resultint); |
771 | 3787 if (ch == ' ') |
3788 mswindows_enqueue_keypress_event (hwnd, QKspace, 0); | |
3789 else | |
3790 mswindows_enqueue_keypress_event (hwnd, make_char (ch), 0); | |
867 | 3791 INC_IBYTEPTR (resultint); |
771 | 3792 } |
3793 | |
3794 unbind_to (speccount); | |
3795 } | |
3796 goto defproc; | |
3797 #endif /* MULE */ | |
442 | 3798 |
3799 defproc: | |
3800 default: | |
771 | 3801 return qxeDefWindowProc (hwnd, message_, wParam, lParam); |
428 | 3802 } |
3803 return (0); | |
3804 } | |
3805 | |
3806 | |
3807 /************************************************************************/ | |
3808 /* keyboard, mouse & other helpers for the windows procedure */ | |
3809 /************************************************************************/ | |
3810 static void | |
3811 mswindows_set_chord_timer (HWND hwnd) | |
3812 { | |
3813 int interval; | |
3814 | |
3815 /* We get one third half system double click threshold */ | |
3816 if (mswindows_mouse_button_tolerance <= 0) | |
3817 interval = GetDoubleClickTime () / 3; | |
3818 else | |
3819 interval = mswindows_mouse_button_tolerance; | |
3820 | |
3821 SetTimer (hwnd, BUTTON_2_TIMER_ID, interval, 0); | |
3822 } | |
3823 | |
3824 static int | |
3825 mswindows_button2_near_enough (POINTS p1, POINTS p2) | |
3826 { | |
3827 int dx, dy; | |
3828 if (mswindows_mouse_button_max_skew_x <= 0) | |
3829 dx = GetSystemMetrics (SM_CXDOUBLECLK) / 2; | |
3830 else | |
3831 dx = mswindows_mouse_button_max_skew_x; | |
3832 | |
3833 if (mswindows_mouse_button_max_skew_y <= 0) | |
3834 dy = GetSystemMetrics (SM_CYDOUBLECLK) / 2; | |
3835 else | |
3836 dy = mswindows_mouse_button_max_skew_y; | |
3837 | |
3838 return abs (p1.x - p2.x) < dx && abs (p1.y- p2.y)< dy; | |
3839 } | |
3840 | |
3841 static int | |
3842 mswindows_current_layout_has_AltGr (void) | |
3843 { | |
3844 /* This simple caching mechanism saves 10% of CPU | |
3845 time when a key typed at autorepeat rate of 30 cps! */ | |
3846 static HKL last_hkl = 0; | |
3847 static int last_hkl_has_AltGr; | |
771 | 3848 HKL current_hkl = GetKeyboardLayout (0); |
3849 | |
428 | 3850 if (current_hkl != last_hkl) |
3851 { | |
647 | 3852 int c; |
428 | 3853 last_hkl_has_AltGr = 0; |
3854 /* In this loop, we query whether a character requires | |
3855 AltGr to be down to generate it. If at least such one | |
3856 found, this means that the layout does regard AltGr */ | |
647 | 3857 for (c = ' '; c <= 255 && !last_hkl_has_AltGr; ++c) |
3858 /* #### This is not really such a good check. What about under | |
3859 CJK locales? It may not matter there, though. We always | |
3860 call VkKeyScanA so that we check the locale-specific characters | |
3861 in non-Latin-1 locales, instead of just the Latin-1 characters. */ | |
3862 if (HIBYTE (VkKeyScanA ((char) c)) == 6) | |
428 | 3863 last_hkl_has_AltGr = 1; |
3864 last_hkl = current_hkl; | |
3865 } | |
3866 return last_hkl_has_AltGr; | |
3867 } | |
3868 | |
3869 | |
3870 /* Returns the state of the modifier keys in the format expected by the | |
3871 * Lisp_Event key_data, button_data and motion_data modifiers member */ | |
442 | 3872 static int |
771 | 3873 mswindows_modifier_state (BYTE *keymap, DWORD fwKeys, int has_AltGr) |
428 | 3874 { |
3875 int mods = 0; | |
442 | 3876 int keys_is_real = 0; |
3877 BYTE keymap2[256]; | |
3878 | |
3879 if (fwKeys == (DWORD) -1) | |
3880 fwKeys = mswindows_last_mouse_button_state; | |
3881 else | |
3882 { | |
3883 keys_is_real = 1; | |
3884 mswindows_last_mouse_button_state = fwKeys; | |
3885 } | |
428 | 3886 |
3887 if (keymap == NULL) | |
3888 { | |
442 | 3889 keymap = keymap2; |
428 | 3890 GetKeyboardState (keymap); |
3891 has_AltGr = mswindows_current_layout_has_AltGr (); | |
3892 } | |
3893 | |
442 | 3894 /* #### should look at fwKeys for MK_CONTROL. I don't understand how |
3895 AltGr works. */ | |
428 | 3896 if (has_AltGr && (keymap [VK_LCONTROL] & 0x80) && (keymap [VK_RMENU] & 0x80)) |
3897 { | |
442 | 3898 mods |= (keymap [VK_LMENU] & 0x80) ? XEMACS_MOD_META : 0; |
3899 mods |= (keymap [VK_RCONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | |
428 | 3900 } |
3901 else | |
3902 { | |
442 | 3903 mods |= (keymap [VK_MENU] & 0x80) ? XEMACS_MOD_META : 0; |
3904 mods |= (keymap [VK_CONTROL] & 0x80) ? XEMACS_MOD_CONTROL : 0; | |
428 | 3905 } |
3906 | |
1111 | 3907 mods |= (keys_is_real ? (int) (fwKeys & MK_SHIFT) : |
3908 (keymap [VK_SHIFT] & 0x80)) ? XEMACS_MOD_SHIFT : 0; | |
442 | 3909 mods |= fwKeys & MK_LBUTTON ? XEMACS_MOD_BUTTON1 : 0; |
3910 mods |= fwKeys & MK_MBUTTON ? XEMACS_MOD_BUTTON2 : 0; | |
3911 mods |= fwKeys & MK_RBUTTON ? XEMACS_MOD_BUTTON3 : 0; | |
428 | 3912 |
3913 return mods; | |
3914 } | |
3915 | |
3916 /* | |
3917 * Translate a mswindows virtual key to a keysym. | |
3918 * Only returns non-Qnil for keys that don't generate WM_CHAR messages | |
3919 * or whose ASCII codes (like space) xemacs doesn't like. | |
3920 */ | |
2286 | 3921 Lisp_Object mswindows_key_to_emacs_keysym (int mswindows_key, |
3922 int UNUSED (mods), int extendedp) | |
428 | 3923 { |
3924 if (extendedp) /* Keys not present on a 82 key keyboard */ | |
3925 { | |
3926 switch (mswindows_key) | |
3927 { | |
442 | 3928 case VK_CANCEL: return KEYSYM ("pause"); |
428 | 3929 case VK_RETURN: return KEYSYM ("kp-enter"); |
3930 case VK_PRIOR: return KEYSYM ("prior"); | |
3931 case VK_NEXT: return KEYSYM ("next"); | |
3932 case VK_END: return KEYSYM ("end"); | |
3933 case VK_HOME: return KEYSYM ("home"); | |
3934 case VK_LEFT: return KEYSYM ("left"); | |
3935 case VK_UP: return KEYSYM ("up"); | |
3936 case VK_RIGHT: return KEYSYM ("right"); | |
3937 case VK_DOWN: return KEYSYM ("down"); | |
3938 case VK_INSERT: return KEYSYM ("insert"); | |
3939 case VK_DELETE: return QKdelete; | |
442 | 3940 #if 0 /* FSF Emacs allows these to return configurable syms/mods */ |
3941 case VK_LWIN return KEYSYM (""); | |
3942 case VK_RWIN return KEYSYM (""); | |
3943 #endif | |
3944 case VK_APPS: return KEYSYM ("menu"); | |
428 | 3945 } |
3946 } | |
3947 else | |
3948 { | |
3949 switch (mswindows_key) | |
3950 { | |
771 | 3951 |
3952 #if 0 | |
3953 VK_LBUTTON: | |
3954 VK_RBUTTON: | |
3955 VK_CANCEL: | |
3956 VK_MBUTTON: | |
3957 VK_XBUTTON1: | |
3958 VK_XBUTTON2: | |
3959 #endif /* 0 */ | |
3960 | |
428 | 3961 case VK_BACK: return QKbackspace; |
3962 case VK_TAB: return QKtab; | |
771 | 3963 /* #### Officially 0A (and 0B too) are "reserved". */ |
428 | 3964 case '\n': return QKlinefeed; |
3965 case VK_CLEAR: return KEYSYM ("clear"); | |
3966 case VK_RETURN: return QKreturn; | |
771 | 3967 |
3968 #if 0 | |
3969 VK_SHIFT: "shift" | |
3970 VK_CONTROL: "control" | |
3971 VK_MENU: "alt" | |
3972 #endif /* 0 */ | |
3973 | |
442 | 3974 case VK_PAUSE: return KEYSYM ("pause"); |
771 | 3975 |
3976 #if 0 | |
3977 VK_CAPITAL: "caps-lock" | |
3978 VK_KANA: IME Kana mode | |
3979 VK_HANGUEL: IME Hanguel mode (maintained for compatibility; use VK_HANGUL) | |
3980 VK_HANGUL: IME Hangul mode | |
3981 VK_JUNJA: IME Junja mode | |
3982 VK_FINAL: IME final mode | |
3983 VK_HANJA: IME Hanja mode | |
3984 VK_KANJI: IME Kanji mode | |
3985 #endif /* 0 */ | |
3986 | |
428 | 3987 case VK_ESCAPE: return QKescape; |
771 | 3988 |
3989 #if 0 | |
3990 VK_CONVERT: IME convert | |
3991 VK_NONCONVERT: IME nonconvert | |
3992 VK_ACCEPT: IME accept | |
3993 VK_MODECHANGE: IME mode change request | |
3994 #endif /* 0 */ | |
3995 | |
428 | 3996 case VK_SPACE: return QKspace; |
3997 case VK_PRIOR: return KEYSYM ("kp-prior"); | |
3998 case VK_NEXT: return KEYSYM ("kp-next"); | |
3999 case VK_END: return KEYSYM ("kp-end"); | |
4000 case VK_HOME: return KEYSYM ("kp-home"); | |
4001 case VK_LEFT: return KEYSYM ("kp-left"); | |
4002 case VK_UP: return KEYSYM ("kp-up"); | |
4003 case VK_RIGHT: return KEYSYM ("kp-right"); | |
4004 case VK_DOWN: return KEYSYM ("kp-down"); | |
4005 case VK_SELECT: return KEYSYM ("select"); | |
4006 case VK_PRINT: return KEYSYM ("print"); | |
4007 case VK_EXECUTE: return KEYSYM ("execute"); | |
4008 case VK_SNAPSHOT: return KEYSYM ("print"); | |
4009 case VK_INSERT: return KEYSYM ("kp-insert"); | |
4010 case VK_DELETE: return KEYSYM ("kp-delete"); | |
4011 case VK_HELP: return KEYSYM ("help"); | |
771 | 4012 #if 0 |
4013 '0' through '9': numeric keys | |
4014 'A' through 'Z': alphabetic keys | |
4015 VK_LWIN: "lwin" | |
4016 VK_RWIN: "rwin" | |
4017 VK_APPS: "apps" | |
4018 VK_SLEEP: "sleep" | |
4019 #endif /* 0 */ | |
428 | 4020 case VK_NUMPAD0: return KEYSYM ("kp-0"); |
4021 case VK_NUMPAD1: return KEYSYM ("kp-1"); | |
4022 case VK_NUMPAD2: return KEYSYM ("kp-2"); | |
4023 case VK_NUMPAD3: return KEYSYM ("kp-3"); | |
4024 case VK_NUMPAD4: return KEYSYM ("kp-4"); | |
4025 case VK_NUMPAD5: return KEYSYM ("kp-5"); | |
4026 case VK_NUMPAD6: return KEYSYM ("kp-6"); | |
4027 case VK_NUMPAD7: return KEYSYM ("kp-7"); | |
4028 case VK_NUMPAD8: return KEYSYM ("kp-8"); | |
4029 case VK_NUMPAD9: return KEYSYM ("kp-9"); | |
4030 case VK_MULTIPLY: return KEYSYM ("kp-multiply"); | |
4031 case VK_ADD: return KEYSYM ("kp-add"); | |
4032 case VK_SEPARATOR: return KEYSYM ("kp-separator"); | |
4033 case VK_SUBTRACT: return KEYSYM ("kp-subtract"); | |
4034 case VK_DECIMAL: return KEYSYM ("kp-decimal"); | |
4035 case VK_DIVIDE: return KEYSYM ("kp-divide"); | |
4036 case VK_F1: return KEYSYM ("f1"); | |
4037 case VK_F2: return KEYSYM ("f2"); | |
4038 case VK_F3: return KEYSYM ("f3"); | |
4039 case VK_F4: return KEYSYM ("f4"); | |
4040 case VK_F5: return KEYSYM ("f5"); | |
4041 case VK_F6: return KEYSYM ("f6"); | |
4042 case VK_F7: return KEYSYM ("f7"); | |
4043 case VK_F8: return KEYSYM ("f8"); | |
4044 case VK_F9: return KEYSYM ("f9"); | |
4045 case VK_F10: return KEYSYM ("f10"); | |
4046 case VK_F11: return KEYSYM ("f11"); | |
4047 case VK_F12: return KEYSYM ("f12"); | |
4048 case VK_F13: return KEYSYM ("f13"); | |
4049 case VK_F14: return KEYSYM ("f14"); | |
4050 case VK_F15: return KEYSYM ("f15"); | |
4051 case VK_F16: return KEYSYM ("f16"); | |
4052 case VK_F17: return KEYSYM ("f17"); | |
4053 case VK_F18: return KEYSYM ("f18"); | |
4054 case VK_F19: return KEYSYM ("f19"); | |
4055 case VK_F20: return KEYSYM ("f20"); | |
4056 case VK_F21: return KEYSYM ("f21"); | |
4057 case VK_F22: return KEYSYM ("f22"); | |
4058 case VK_F23: return KEYSYM ("f23"); | |
4059 case VK_F24: return KEYSYM ("f24"); | |
771 | 4060 |
4061 #if 0 | |
4062 VK_NUMLOCK: 90 NUM LOCK key | |
4063 VK_SCROLL: 91 SCROLL LOCK key | |
4064 92~96 OEM specific; | |
4065 VK_LSHIFT: | |
4066 VK_RSHIFT: | |
4067 VK_LCONTROL: | |
4068 VK_RCONTROL: | |
4069 VK_LMENU: | |
4070 VK_RMENU: | |
4071 | |
4072 #ifdef VK_BROWSER_BACK /* Windows 2000 only */ | |
4073 VK_BROWSER_BACK: Browser Back key | |
4074 VK_BROWSER_FORWARD: Browser Forward key | |
4075 VK_BROWSER_REFRESH: Browser Refresh key | |
4076 VK_BROWSER_STOP: Browser Stop key | |
4077 VK_BROWSER_SEARCH: Browser Search key | |
4078 VK_BROWSER_FAVORITES: Browser Favorites key | |
4079 VK_BROWSER_HOME: Browser Start and Home key | |
4080 VK_VOLUME_MUTE: Volume Mute key | |
4081 VK_VOLUME_DOWN: Volume Down key | |
4082 VK_VOLUME_UP: Volume Up key | |
4083 VK_MEDIA_NEXT_TRACK: Next Track key | |
4084 VK_MEDIA_PREV_TRACK: Previous Track key | |
4085 VK_MEDIA_STOP: Stop Media key | |
4086 VK_MEDIA_PLAY_PAUSE: Play/Pause Media key | |
4087 VK_LAUNCH_MAIL: Start Mail key | |
4088 VK_LAUNCH_MEDIA_SELECT: Select Media key | |
4089 VK_LAUNCH_APP1: Start Application 1 key | |
4090 VK_LAUNCH_APP2: Start Application 2 key | |
4091 B8-B9 Reserved; | |
4092 VK_OEM_1: For the US standard keyboard, the ';:' key | |
4093 VK_OEM_PLUS: For any country/region, the '+' key | |
4094 VK_OEM_COMMA: For any country/region, the ',' key | |
4095 VK_OEM_MINUS: For any country/region, the '-' key | |
4096 VK_OEM_PERIOD: For any country/region, the '.' key | |
4097 VK_OEM_2: For the US standard keyboard, the '/?' key | |
4098 VK_OEM_3: For the US standard keyboard, the '`~' key | |
4099 C1~D7 Reserved; | |
4100 D8~DA Unassigned; | |
4101 VK_OEM_4: For the US standard keyboard, the '[{' key | |
4102 VK_OEM_5: For the US standard keyboard, the '\|' key | |
4103 VK_OEM_6: For the US standard keyboard, the ']}' key | |
4104 VK_OEM_7: For the US standard keyboard, the 'single-quote/double-quote' key | |
4105 VK_OEM_8: | |
4106 E0 Reserved; | |
4107 E1 OEM specific; | |
4108 VK_OEM_102: Either the angle bracket key or the backslash key on the RT 102-key keyboard | |
4109 E3~E4 OEM specific; | |
4110 #endif /* VK_BROWSER_BACK */ | |
4111 VK_PROCESSKEY: E5 Windows 95/98, Windows NT 4.0, Windows 2000: IME PROCESS key | |
4112 E6 OEM specific; | |
4113 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 | |
4114 E8 Unassigned; | |
4115 E9~F5 OEM specific; | |
4116 VK_ATTN: Attn key | |
4117 VK_CRSEL: CrSel key | |
4118 VK_EXSEL: ExSel key | |
4119 VK_EREOF: Erase EOF key | |
4120 VK_PLAY: Play key | |
4121 VK_ZOOM: Zoom key | |
4122 VK_NONAME: Reserved for future use | |
4123 VK_PA1: PA1 key | |
4124 VK_OEM_CLEAR: Clear key | |
4125 #endif /* 0 */ | |
4126 | |
428 | 4127 } |
4128 } | |
4129 return Qnil; | |
4130 } | |
4131 | |
4132 /* | |
4133 * Find the console that matches the supplied mswindows window handle | |
4134 */ | |
4135 Lisp_Object | |
2286 | 4136 mswindows_find_console (HWND UNUSED (hwnd)) |
428 | 4137 { |
4138 /* We only support one console */ | |
4139 return XCAR (Vconsole_list); | |
4140 } | |
4141 | |
4142 /* | |
4143 * Find the frame that matches the supplied mswindows window handle | |
4144 */ | |
546 | 4145 Lisp_Object |
428 | 4146 mswindows_find_frame (HWND hwnd) |
4147 { | |
771 | 4148 LONG l = qxeGetWindowLong (hwnd, XWL_FRAMEOBJ); |
428 | 4149 Lisp_Object f; |
4150 if (l == 0) | |
4151 { | |
4152 /* We are in progress of frame creation. Return the frame | |
4153 being created, as it still not remembered in the window | |
4154 extra storage. */ | |
4155 assert (!NILP (Vmswindows_frame_being_created)); | |
4156 return Vmswindows_frame_being_created; | |
4157 } | |
5013 | 4158 f = GET_LISP_FROM_VOID ((void *) l); |
428 | 4159 return f; |
4160 } | |
4161 | |
4162 | |
4163 /************************************************************************/ | |
4164 /* methods */ | |
4165 /************************************************************************/ | |
4166 | |
4167 static int | |
4168 emacs_mswindows_add_timeout (EMACS_TIME thyme) | |
4169 { | |
4170 int milliseconds; | |
4171 EMACS_TIME current_time; | |
4172 EMACS_GET_TIME (current_time); | |
4173 EMACS_SUB_TIME (thyme, thyme, current_time); | |
4174 milliseconds = EMACS_SECS (thyme) * 1000 + | |
4175 (EMACS_USECS (thyme) + 500) / 1000; | |
4176 if (milliseconds < 1) | |
4177 milliseconds = 1; | |
4178 ++mswindows_pending_timers_count; | |
4179 return SetTimer (NULL, 0, milliseconds, | |
4180 (TIMERPROC) mswindows_wm_timer_callback); | |
4181 } | |
4182 | |
1204 | 4183 static int |
4184 remove_timeout_mapper (Lisp_Object ev, void *data) | |
4185 { | |
4186 if (XEVENT_TYPE (ev) == timeout_event) | |
4187 { | |
4188 if ((int) data == XEVENT_TIMEOUT_INTERVAL_ID (ev)) | |
4189 return 1; | |
4190 } | |
4191 | |
4192 return 0; | |
4193 } | |
4194 | |
428 | 4195 static void |
4196 emacs_mswindows_remove_timeout (int id) | |
4197 { | |
4198 if (KillTimer (NULL, id)) | |
4199 --mswindows_pending_timers_count; | |
4200 | |
4201 /* If there is a dispatch event generated by this | |
4202 timeout in the queue, we have to remove it too. */ | |
1204 | 4203 map_event_chain_remove (remove_timeout_mapper, |
4204 &mswindows_s_dispatch_event_queue, | |
4205 &mswindows_s_dispatch_event_queue_tail, | |
4206 (void *) id, MECR_DEALLOCATE_EVENT); | |
428 | 4207 } |
4208 | |
4209 /* If `user_p' is false, then return whether there are any win32, timeout, | |
4210 * or subprocess events pending (that is, whether | |
4211 * emacs_mswindows_next_event() would return immediately without blocking). | |
4212 * | |
4213 * if `user_p' is true, then return whether there are any *user generated* | |
4214 * events available (that is, whether there are keyboard or mouse-click | |
4215 * events ready to be read). This also implies that | |
4216 * emacs_mswindows_next_event() would not block. | |
4217 */ | |
4218 static int | |
1268 | 4219 emacs_mswindows_event_pending_p (int how_many) |
428 | 4220 { |
1318 | 4221 /* This can call Lisp */ |
1268 | 4222 if (!how_many) |
4223 { | |
4224 mswindows_need_event (0); | |
4225 return (!NILP (dispatch_event_queue) | |
4226 || !NILP (mswindows_s_dispatch_event_queue)); | |
4227 } | |
4228 else | |
4229 { | |
4230 Lisp_Object event; | |
4231 int count = 0; | |
4232 | |
4233 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
4234 count++; | |
4235 | |
4236 if (count >= how_many) | |
4237 return 1; | |
4238 | |
4239 emacs_mswindows_drain_queue (); | |
4240 | |
4241 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
4242 count++; | |
4243 | |
4244 return count >= how_many; | |
4245 } | |
428 | 4246 } |
4247 | |
4248 /* | |
4249 * Return the next event | |
4250 */ | |
4251 static void | |
440 | 4252 emacs_mswindows_next_event (Lisp_Event *emacs_event) |
428 | 4253 { |
4254 Lisp_Object event, event2; | |
4255 | |
4256 mswindows_need_event (1); | |
4257 | |
4258 event = mswindows_dequeue_dispatch_event (); | |
793 | 4259 event2 = wrap_event (emacs_event); |
428 | 4260 Fcopy_event (event, event2); |
4261 Fdeallocate_event (event); | |
4262 } | |
4263 | |
788 | 4264 static void |
4265 emacs_mswindows_format_magic_event (Lisp_Event *emacs_event, | |
4266 Lisp_Object pstream) | |
4267 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
4268 #define FROB(msg) case msg: write_ascstring (pstream, "type=" #msg); break |
788 | 4269 |
1204 | 4270 switch (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event)) |
788 | 4271 { |
4272 FROB (XM_BUMPQUEUE); | |
4273 FROB (WM_PAINT); | |
4274 FROB (WM_SETFOCUS); | |
4275 FROB (WM_KILLFOCUS); | |
4276 FROB (XM_MAPFRAME); | |
4277 FROB (XM_UNMAPFRAME); | |
4278 | |
2500 | 4279 default: ABORT (); |
788 | 4280 } |
4281 #undef FROB | |
4282 | |
4283 if (!NILP (EVENT_CHANNEL (emacs_event))) | |
4284 { | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
4932
diff
changeset
|
4285 write_ascstring (pstream, " "); |
788 | 4286 print_internal (EVENT_CHANNEL (emacs_event), pstream, 1); |
4287 } | |
4288 } | |
4289 | |
4290 static int | |
4291 emacs_mswindows_compare_magic_event (Lisp_Event *e1, Lisp_Event *e2) | |
4292 { | |
1204 | 4293 return (EVENT_MAGIC_MSWINDOWS_EVENT (e1) == |
4294 EVENT_MAGIC_MSWINDOWS_EVENT (e2)); | |
788 | 4295 } |
4296 | |
4297 static Hashcode | |
4298 emacs_mswindows_hash_magic_event (Lisp_Event *e) | |
4299 { | |
1204 | 4300 return (EVENT_MAGIC_MSWINDOWS_EVENT (e)); |
788 | 4301 } |
4302 | |
428 | 4303 /* |
4304 * Handle a magic event off the dispatch queue. | |
4305 */ | |
4306 static void | |
440 | 4307 emacs_mswindows_handle_magic_event (Lisp_Event *emacs_event) |
428 | 4308 { |
1204 | 4309 switch (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event)) |
428 | 4310 { |
4311 case XM_BUMPQUEUE: | |
4312 break; | |
4313 | |
442 | 4314 case WM_PAINT: |
4315 { | |
4316 struct frame *f = XFRAME (EVENT_CHANNEL (emacs_event)); | |
4317 mswindows_handle_paint (f); | |
4318 (FRAME_MSWINDOWS_DATA (f))->paint_pending = 0; | |
4319 } | |
4320 break; | |
4321 | |
428 | 4322 case WM_SETFOCUS: |
4323 case WM_KILLFOCUS: | |
4324 { | |
4325 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
4326 struct frame *f = XFRAME (frame); | |
1204 | 4327 int in_p = (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event) |
964 | 4328 == WM_SETFOCUS); |
428 | 4329 Lisp_Object conser; |
442 | 4330 struct gcpro gcpro1; |
4331 | |
4332 /* On focus change, clear all memory of sticky modifiers | |
4333 to avoid non-intuitive behavior. */ | |
4334 clear_sticky_modifiers (); | |
428 | 4335 |
4336 conser = Fcons (frame, Fcons (FRAME_DEVICE (f), in_p ? Qt : Qnil)); | |
442 | 4337 GCPRO1 (conser); |
428 | 4338 emacs_handle_focus_change_preliminary (conser); |
4339 /* Under X the stuff up to here is done in the X event handler. | |
4340 I Don't know why */ | |
4341 emacs_handle_focus_change_final (conser); | |
442 | 4342 UNGCPRO; |
428 | 4343 |
4344 } | |
4345 break; | |
4346 | |
4347 case XM_MAPFRAME: | |
4348 case XM_UNMAPFRAME: | |
4349 { | |
4350 Lisp_Object frame = EVENT_CHANNEL (emacs_event); | |
1204 | 4351 va_run_hook_with_args (EVENT_MAGIC_MSWINDOWS_EVENT (emacs_event) |
428 | 4352 == XM_MAPFRAME ? |
4353 Qmap_frame_hook : Qunmap_frame_hook, | |
4354 1, frame); | |
4355 } | |
4356 break; | |
4357 | |
4358 /* #### What about Enter & Leave */ | |
4359 #if 0 | |
4360 va_run_hook_with_args (in_p ? Qmouse_enter_frame_hook : | |
4361 Qmouse_leave_frame_hook, 1, frame); | |
4362 #endif | |
4363 | |
4364 default: | |
4365 assert(0); | |
4366 } | |
4367 } | |
4368 | |
853 | 4369 #ifndef CYGWIN |
4370 | |
428 | 4371 static HANDLE |
440 | 4372 get_process_input_waitable (Lisp_Process *process) |
428 | 4373 { |
853 | 4374 Lisp_Object instr, outstr, errstr, p; |
793 | 4375 p = wrap_process (process); |
853 | 4376 get_process_streams (process, &instr, &outstr, &errstr); |
428 | 4377 assert (!NILP (instr)); |
4378 return (network_connection_p (p) | |
4379 ? get_winsock_stream_waitable (XLSTREAM (instr)) | |
4380 : get_ntpipe_input_stream_waitable (XLSTREAM (instr))); | |
4381 } | |
4382 | |
853 | 4383 static HANDLE |
4384 get_process_stderr_waitable (Lisp_Process *process) | |
4385 { | |
4386 Lisp_Object instr, outstr, errstr; | |
4387 get_process_streams (process, &instr, &outstr, &errstr); | |
4388 if (NILP (errstr)) | |
4389 return INVALID_HANDLE_VALUE; | |
4390 return get_ntpipe_input_stream_waitable (XLSTREAM (errstr)); | |
4391 } | |
4392 | |
4393 #endif /* not CYGWIN */ | |
4394 | |
428 | 4395 static void |
853 | 4396 emacs_mswindows_select_process (Lisp_Process *process, int doin, int doerr) |
428 | 4397 { |
853 | 4398 #ifdef CYGWIN |
4399 int infd, errfd; | |
4400 | |
4401 event_stream_unixoid_select_process (process, doin, doerr, &infd, &errfd); | |
4402 #else | |
4403 HANDLE hev = INVALID_HANDLE_VALUE; | |
4404 HANDLE herr = INVALID_HANDLE_VALUE; | |
4405 | |
4406 if (doin) | |
4407 { | |
4408 hev = get_process_input_waitable (process); | |
4409 if (!add_waitable_handle (hev)) | |
4410 { | |
4411 hev = INVALID_HANDLE_VALUE; | |
4412 goto err; | |
4413 } | |
4414 } | |
4415 | |
4416 if (doerr) | |
4417 { | |
4418 herr = get_process_stderr_waitable (process); | |
4419 if (herr != INVALID_HANDLE_VALUE && !add_waitable_handle (herr)) | |
4420 { | |
4421 herr = INVALID_HANDLE_VALUE; | |
4422 goto err; | |
4423 } | |
4424 } | |
4425 | |
428 | 4426 { |
853 | 4427 /* Also select on the process handle itself, so we can receive |
4428 exit notifications. Only do this once, not each time this | |
4429 function is called (which can happen many times, e.g. if | |
4430 (set-process-filter proc t) is called and then a process filter | |
4431 is set again). It will be unselected in mswindows_need_event(). */ | |
793 | 4432 Lisp_Object p = wrap_process (process); |
4433 | |
428 | 4434 if (!network_connection_p (p)) |
4435 { | |
853 | 4436 HANDLE hprocess = get_nt_process_handle_only_first_time (process); |
4437 if (hprocess != INVALID_HANDLE_VALUE | |
4438 && !add_waitable_handle (hprocess)) | |
4439 goto err; | |
428 | 4440 } |
4441 } | |
853 | 4442 |
4443 return; | |
4444 | |
4445 err: | |
4446 if (hev != INVALID_HANDLE_VALUE) | |
4447 remove_waitable_handle (hev); | |
4448 if (herr != INVALID_HANDLE_VALUE) | |
4449 remove_waitable_handle (herr); | |
4450 invalid_operation ("Too many active processes", wrap_process (process)); | |
4451 #endif /* CYGWIN */ | |
428 | 4452 } |
4453 | |
4454 static void | |
853 | 4455 emacs_mswindows_unselect_process (Lisp_Process *process, int doin, int doerr) |
428 | 4456 { |
853 | 4457 #ifdef CYGWIN |
4458 int infd, errfd; | |
4459 | |
4460 event_stream_unixoid_unselect_process (process, doin, doerr, &infd, &errfd); | |
4461 #else | |
4462 if (doin) | |
4463 { | |
4464 /* Process handle is removed in the event loop as soon | |
4465 as it is signaled, so don't bother here about it */ | |
4466 HANDLE hev = get_process_input_waitable (process); | |
4467 remove_waitable_handle (hev); | |
4468 } | |
4469 if (doerr) | |
4470 { | |
4471 /* Process handle is removed in the event loop as soon | |
4472 as it is signaled, so don't bother here about it */ | |
4473 HANDLE herr = get_process_stderr_waitable (process); | |
4474 if (herr != INVALID_HANDLE_VALUE) | |
4475 remove_waitable_handle (herr); | |
4476 } | |
4477 #endif /* CYGWIN */ | |
428 | 4478 } |
4479 | |
4480 static void | |
2286 | 4481 emacs_mswindows_select_console (struct console *USED_IF_CYGWIN (con)) |
428 | 4482 { |
853 | 4483 #ifdef CYGWIN |
428 | 4484 if (CONSOLE_MSWINDOWS_P (con)) |
4485 return; /* mswindows consoles are automatically selected */ | |
4486 | |
4487 event_stream_unixoid_select_console (con); | |
1204 | 4488 #else |
4489 #if 0 | |
4490 /* This is an attempt to get `xemacs -batch -l dunnet' to work. | |
4491 Doesn't currently work and fucks other things up. */ | |
4492 if (CONSOLE_STREAM_P (con) && | |
4493 !UNBOUNDP (CONSOLE_STREAM_DATA (con)->instream)) | |
4494 { | |
4495 HANDLE h = | |
4496 (HANDLE) _get_osfhandle (fileno (CONSOLE_STREAM_DATA (con)->in)); | |
4497 if (PeekNamedPipe (h, 0, 0, 0, 0, 0)) | |
4498 { | |
4499 Lisp_Object lstr = make_ntpipe_input_stream (h, 0); | |
4500 HANDLE hwait = get_ntpipe_input_stream_waitable (XLSTREAM (lstr)); | |
4501 | |
4502 if (!add_waitable_handle (hwait)) | |
4503 invalid_operation ("Too many active processes", | |
4504 wrap_console (con)); | |
4505 CONSOLE_STREAM_DATA (con)->instream = lstr; | |
4506 } | |
4507 else | |
4508 /* Unable to select on this stream */ | |
4509 CONSOLE_STREAM_DATA (con)->instream = Qunbound; | |
4510 } | |
4511 #endif /* 0 */ | |
428 | 4512 #endif |
4513 } | |
4514 | |
4515 static void | |
2286 | 4516 emacs_mswindows_unselect_console (struct console *USED_IF_CYGWIN (con)) |
428 | 4517 { |
853 | 4518 #ifdef CYGWIN |
428 | 4519 if (CONSOLE_MSWINDOWS_P (con)) |
4520 return; /* mswindows consoles are automatically selected */ | |
4521 | |
4522 event_stream_unixoid_unselect_console (con); | |
1204 | 4523 #else |
4524 #if 0 /* see above */ | |
4525 if (CONSOLE_STREAM_P (con) && | |
4526 !UNBOUNDP (CONSOLE_STREAM_DATA (con)->instream)) | |
428 | 4527 { |
1204 | 4528 Lisp_Object instr = CONSOLE_STREAM_DATA (con)->instream; |
4529 HANDLE hwait; | |
4530 | |
4531 assert (!NILP (instr)); | |
4532 hwait = get_ntpipe_input_stream_waitable (XLSTREAM (instr)); | |
4533 | |
4534 remove_waitable_handle (hwait); | |
428 | 4535 } |
1204 | 4536 #endif /* 0 */ |
4537 #endif | |
428 | 4538 } |
4539 | |
853 | 4540 static void |
4541 emacs_mswindows_create_io_streams (void *inhandle, void *outhandle, | |
4542 void *errhandle, Lisp_Object *instream, | |
4543 Lisp_Object *outstream, | |
4544 Lisp_Object *errstream, | |
4545 USID *in_usid, | |
4546 USID *err_usid, | |
4547 int flags) | |
428 | 4548 { |
853 | 4549 #ifdef CYGWIN |
4550 event_stream_unixoid_create_io_streams (inhandle, outhandle, | |
4551 errhandle, instream, | |
4552 outstream, errstream, | |
4553 in_usid, err_usid, flags); | |
4554 #else | |
428 | 4555 /* Handles for streams */ |
853 | 4556 HANDLE hin, hout, herr; |
428 | 4557 /* fds. These just stored along with the streams, and are closed in |
4558 delete stream pair method, because we need to handle fake unices | |
4559 here. */ | |
853 | 4560 int fdi, fdo, fde; |
4561 | |
4562 /* Decode inhandle, outhandle, errhandle. Their meaning depends on | |
428 | 4563 the process implementation being used. */ |
4564 hin = (HANDLE) inhandle; | |
4565 hout = (HANDLE) outhandle; | |
853 | 4566 if (errhandle == (void *) -1) |
4567 herr = INVALID_HANDLE_VALUE; | |
4568 else | |
4569 herr = (HANDLE) errhandle; | |
4570 fdi = fdo = fde = -1; | |
428 | 4571 |
4572 *instream = (hin == INVALID_HANDLE_VALUE | |
4573 ? Qnil | |
4574 : flags & STREAM_NETWORK_CONNECTION | |
853 | 4575 ? make_winsock_input_stream ((SOCKET) hin, fdi) |
428 | 4576 : make_ntpipe_input_stream (hin, fdi)); |
4577 | |
853 | 4578 *errstream = (herr == INVALID_HANDLE_VALUE |
4579 ? Qnil | |
4580 : make_ntpipe_input_stream (herr, fde)); | |
4581 | |
428 | 4582 *outstream = (hout == INVALID_HANDLE_VALUE |
4583 ? Qnil | |
4584 : flags & STREAM_NETWORK_CONNECTION | |
4585 ? make_winsock_output_stream ((SOCKET)hout, fdo) | |
4586 : make_ntpipe_output_stream (hout, fdo)); | |
853 | 4587 |
4588 *in_usid = | |
4589 (NILP (*instream) | |
4590 ? USID_ERROR | |
4591 : flags & STREAM_NETWORK_CONNECTION | |
4592 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (*instream))) | |
4593 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4594 (*instream)))); | |
4595 | |
4596 *err_usid = | |
4597 (NILP (*errstream) | |
4598 ? USID_DONTHASH | |
4599 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4600 (*errstream)))); | |
4601 #endif /* CYGWIN */ | |
428 | 4602 } |
4603 | |
853 | 4604 static void |
4605 emacs_mswindows_delete_io_streams (Lisp_Object instream, | |
2286 | 4606 Lisp_Object USED_IF_CYGWIN (outstream), |
853 | 4607 Lisp_Object errstream, |
4608 USID *in_usid, | |
4609 USID *err_usid) | |
428 | 4610 { |
853 | 4611 #ifdef CYGWIN |
4612 event_stream_unixoid_delete_io_streams (instream, outstream, errstream, | |
4613 in_usid, err_usid); | |
4614 #else | |
4615 *in_usid = | |
4616 (NILP (instream) | |
4617 ? USID_DONTHASH | |
4618 : LSTREAM_TYPE_P (XLSTREAM (instream), winsock) | |
4619 ? HANDLE_TO_USID (get_winsock_stream_waitable (XLSTREAM (instream))) | |
4620 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4621 (instream)))); | |
4622 | |
4623 *err_usid = | |
4624 (NILP (errstream) | |
4625 ? USID_DONTHASH | |
4626 : HANDLE_TO_USID (get_ntpipe_input_stream_waitable (XLSTREAM | |
4627 (errstream)))); | |
4628 #endif /* CYGWIN */ | |
428 | 4629 } |
4630 | |
442 | 4631 static int |
2286 | 4632 emacs_mswindows_current_event_timestamp (struct console *UNUSED (c)) |
442 | 4633 { |
4634 return GetTickCount (); | |
4635 } | |
4636 | |
428 | 4637 #ifndef HAVE_X_WINDOWS |
4638 /* This is called from GC when a process object is about to be freed. | |
4639 If we've still got pointers to it in this file, we're gonna lose hard. | |
853 | 4640 */ |
4641 void debug_process_finalization (Lisp_Process *p); | |
428 | 4642 void |
2286 | 4643 debug_process_finalization (Lisp_Process *UNUSED (p)) |
428 | 4644 { |
4645 #if 0 /* #### */ | |
853 | 4646 Lisp_Object instr, outstr, errstr; |
4647 | |
4648 get_process_streams (p, &instr, &outstr, &errstr); | |
428 | 4649 /* if it still has fds, then it hasn't been killed yet. */ |
771 | 4650 assert (NILP (instr)); |
4651 assert (NILP (outstr)); | |
853 | 4652 assert (NILP (errstr)); |
428 | 4653 |
4654 /* #### More checks here */ | |
4655 #endif | |
4656 } | |
4657 #endif | |
4658 | |
593 | 4659 #ifdef DEBUG_XEMACS |
4660 | |
4661 struct mswin_message_debug | |
4662 { | |
4663 int mess; | |
4932 | 4664 const Ascbyte *string; |
593 | 4665 }; |
4666 | |
4667 #define FROB(val) { val, #val, }, | |
4668 | |
4669 struct mswin_message_debug debug_mswin_messages[] = | |
4670 { | |
4671 FROB (WM_NULL) | |
4672 FROB (WM_CREATE) | |
4673 FROB (WM_DESTROY) | |
4674 FROB (WM_MOVE) | |
4675 FROB (WM_SIZE) | |
4676 | |
4677 FROB (WM_ACTIVATE) | |
4678 | |
4679 FROB (WM_SETFOCUS) | |
4680 FROB (WM_KILLFOCUS) | |
4681 FROB (WM_ENABLE) | |
4682 FROB (WM_SETREDRAW) | |
4683 FROB (WM_SETTEXT) | |
4684 FROB (WM_GETTEXT) | |
4685 FROB (WM_GETTEXTLENGTH) | |
4686 FROB (WM_PAINT) | |
4687 FROB (WM_CLOSE) | |
4688 FROB (WM_QUERYENDSESSION) | |
4689 FROB (WM_QUIT) | |
4690 FROB (WM_QUERYOPEN) | |
4691 FROB (WM_ERASEBKGND) | |
4692 FROB (WM_SYSCOLORCHANGE) | |
4693 FROB (WM_ENDSESSION) | |
4694 FROB (WM_SHOWWINDOW) | |
4695 FROB (WM_WININICHANGE) | |
4696 #if(WINVER >= 0x0400) | |
4697 FROB (WM_SETTINGCHANGE) | |
4698 #endif /* WINVER >= 0x0400 */ | |
4699 | |
4700 FROB (WM_DEVMODECHANGE) | |
4701 FROB (WM_ACTIVATEAPP) | |
4702 FROB (WM_FONTCHANGE) | |
4703 FROB (WM_TIMECHANGE) | |
4704 FROB (WM_CANCELMODE) | |
4705 FROB (WM_SETCURSOR) | |
4706 FROB (WM_MOUSEACTIVATE) | |
4707 FROB (WM_CHILDACTIVATE) | |
4708 FROB (WM_QUEUESYNC) | |
4709 | |
4710 FROB (WM_GETMINMAXINFO) | |
4711 | |
4712 FROB (WM_PAINTICON) | |
4713 FROB (WM_ICONERASEBKGND) | |
4714 FROB (WM_NEXTDLGCTL) | |
4715 FROB (WM_SPOOLERSTATUS) | |
4716 FROB (WM_DRAWITEM) | |
4717 FROB (WM_MEASUREITEM) | |
4718 FROB (WM_DELETEITEM) | |
4719 FROB (WM_VKEYTOITEM) | |
4720 FROB (WM_CHARTOITEM) | |
4721 FROB (WM_SETFONT) | |
4722 FROB (WM_GETFONT) | |
4723 FROB (WM_SETHOTKEY) | |
4724 FROB (WM_GETHOTKEY) | |
4725 FROB (WM_QUERYDRAGICON) | |
4726 FROB (WM_COMPAREITEM) | |
1687 | 4727 #if(WINVER >= 0x0500) && defined(WM_GETOBJECT) |
593 | 4728 FROB (WM_GETOBJECT) |
4729 #endif /* WINVER >= 0x0500 */ | |
4730 FROB (WM_COMPACTING) | |
4731 FROB (WM_COMMNOTIFY) | |
4732 FROB (WM_WINDOWPOSCHANGING) | |
4733 FROB (WM_WINDOWPOSCHANGED) | |
4734 | |
4735 FROB (WM_POWER) | |
4736 | |
4737 FROB (WM_COPYDATA) | |
4738 FROB (WM_CANCELJOURNAL) | |
4739 | |
4740 #if(WINVER >= 0x0400) | |
4741 FROB (WM_NOTIFY) | |
4742 FROB (WM_INPUTLANGCHANGEREQUEST) | |
4743 FROB (WM_INPUTLANGCHANGE) | |
4744 FROB (WM_TCARD) | |
4745 FROB (WM_HELP) | |
4746 FROB (WM_USERCHANGED) | |
4747 FROB (WM_NOTIFYFORMAT) | |
4748 | |
4749 FROB (WM_CONTEXTMENU) | |
4750 FROB (WM_STYLECHANGING) | |
4751 FROB (WM_STYLECHANGED) | |
4752 FROB (WM_DISPLAYCHANGE) | |
4753 FROB (WM_GETICON) | |
4754 FROB (WM_SETICON) | |
4755 #endif /* WINVER >= 0x0400 */ | |
4756 | |
4757 FROB (WM_NCCREATE) | |
4758 FROB (WM_NCDESTROY) | |
4759 FROB (WM_NCCALCSIZE) | |
4760 FROB (WM_NCHITTEST) | |
4761 FROB (WM_NCPAINT) | |
4762 FROB (WM_NCACTIVATE) | |
4763 FROB (WM_GETDLGCODE) | |
604 | 4764 #ifdef WM_SYNCPAINT /* not in VC 5 */ |
593 | 4765 FROB (WM_SYNCPAINT) |
604 | 4766 #endif /* WM_SYNCPAINT */ |
593 | 4767 FROB (WM_NCMOUSEMOVE) |
4768 FROB (WM_NCLBUTTONDOWN) | |
4769 FROB (WM_NCLBUTTONUP) | |
4770 FROB (WM_NCLBUTTONDBLCLK) | |
4771 FROB (WM_NCRBUTTONDOWN) | |
4772 FROB (WM_NCRBUTTONUP) | |
4773 FROB (WM_NCRBUTTONDBLCLK) | |
4774 FROB (WM_NCMBUTTONDOWN) | |
4775 FROB (WM_NCMBUTTONUP) | |
4776 FROB (WM_NCMBUTTONDBLCLK) | |
4777 | |
4778 /* FROB (WM_KEYFIRST) */ | |
4779 FROB (WM_KEYDOWN) | |
4780 FROB (WM_KEYUP) | |
4781 FROB (WM_CHAR) | |
4782 FROB (WM_DEADCHAR) | |
4783 FROB (WM_SYSKEYDOWN) | |
4784 FROB (WM_SYSKEYUP) | |
4785 FROB (WM_SYSCHAR) | |
4786 FROB (WM_SYSDEADCHAR) | |
4787 FROB (WM_KEYLAST) | |
4788 | |
604 | 4789 #if(WINVER >= 0x0400) && defined (WM_IME_STARTCOMPOSITION) |
4790 /* not in Cygwin? */ | |
593 | 4791 FROB (WM_IME_STARTCOMPOSITION) |
4792 FROB (WM_IME_ENDCOMPOSITION) | |
4793 FROB (WM_IME_COMPOSITION) | |
4794 FROB (WM_IME_KEYLAST) | |
604 | 4795 #endif /* WINVER >= 0x0400 && defined (WM_IME_STARTCOMPOSITION) */ |
593 | 4796 |
4797 FROB (WM_INITDIALOG) | |
4798 FROB (WM_COMMAND) | |
4799 FROB (WM_SYSCOMMAND) | |
4800 FROB (WM_TIMER) | |
4801 FROB (WM_HSCROLL) | |
4802 FROB (WM_VSCROLL) | |
4803 FROB (WM_INITMENU) | |
4804 FROB (WM_INITMENUPOPUP) | |
4805 FROB (WM_MENUSELECT) | |
4806 FROB (WM_MENUCHAR) | |
4807 FROB (WM_ENTERIDLE) | |
4808 #if(WINVER >= 0x0500) | |
4809 FROB (WM_MENURBUTTONUP) | |
1687 | 4810 #ifdef WM_MENUDRAG |
593 | 4811 FROB (WM_MENUDRAG) |
1687 | 4812 #endif |
4813 #ifdef WM_MENUGETOBJECT | |
593 | 4814 FROB (WM_MENUGETOBJECT) |
1687 | 4815 #endif |
4816 #ifdef WM_UNINITMENUPOPUP | |
593 | 4817 FROB (WM_UNINITMENUPOPUP) |
1687 | 4818 #endif |
4819 #ifdef WM_MENUCOMMAND | |
593 | 4820 FROB (WM_MENUCOMMAND) |
1687 | 4821 #endif |
593 | 4822 #endif /* WINVER >= 0x0500 */ |
4823 | |
4824 | |
4825 FROB (WM_CTLCOLORMSGBOX) | |
4826 FROB (WM_CTLCOLOREDIT) | |
4827 FROB (WM_CTLCOLORLISTBOX) | |
4828 FROB (WM_CTLCOLORBTN) | |
4829 FROB (WM_CTLCOLORDLG) | |
4830 FROB (WM_CTLCOLORSCROLLBAR) | |
4831 FROB (WM_CTLCOLORSTATIC) | |
4832 | |
4833 | |
4834 /* FROB (WM_MOUSEFIRST) */ | |
4835 FROB (WM_MOUSEMOVE) | |
4836 FROB (WM_LBUTTONDOWN) | |
4837 FROB (WM_LBUTTONUP) | |
4838 FROB (WM_LBUTTONDBLCLK) | |
4839 FROB (WM_RBUTTONDOWN) | |
4840 FROB (WM_RBUTTONUP) | |
4841 FROB (WM_RBUTTONDBLCLK) | |
4842 FROB (WM_MBUTTONDOWN) | |
4843 FROB (WM_MBUTTONUP) | |
4844 FROB (WM_MBUTTONDBLCLK) | |
4845 | |
4846 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) | |
4847 FROB (WM_MOUSEWHEEL) | |
4848 FROB (WM_MOUSELAST) | |
4849 #else | |
4850 FROB (WM_MOUSELAST) | |
4851 #endif /* if (_WIN32_WINNT < 0x0400) */ | |
4852 | |
4853 FROB (WM_PARENTNOTIFY) | |
4854 FROB (WM_ENTERMENULOOP) | |
4855 FROB (WM_EXITMENULOOP) | |
4856 | |
4857 #if(WINVER >= 0x0400) | |
4858 FROB (WM_NEXTMENU) | |
4859 | |
4860 FROB (WM_SIZING) | |
4861 FROB (WM_CAPTURECHANGED) | |
4862 FROB (WM_MOVING) | |
4863 FROB (WM_POWERBROADCAST) | |
4864 | |
4865 FROB (WM_DEVICECHANGE) | |
4866 | |
4867 #endif /* WINVER >= 0x0400 */ | |
4868 | |
4869 FROB (WM_MDICREATE) | |
4870 FROB (WM_MDIDESTROY) | |
4871 FROB (WM_MDIACTIVATE) | |
4872 FROB (WM_MDIRESTORE) | |
4873 FROB (WM_MDINEXT) | |
4874 FROB (WM_MDIMAXIMIZE) | |
4875 FROB (WM_MDITILE) | |
4876 FROB (WM_MDICASCADE) | |
4877 FROB (WM_MDIICONARRANGE) | |
4878 FROB (WM_MDIGETACTIVE) | |
4879 | |
4880 | |
4881 FROB (WM_MDISETMENU) | |
4882 FROB (WM_ENTERSIZEMOVE) | |
4883 FROB (WM_EXITSIZEMOVE) | |
4884 FROB (WM_DROPFILES) | |
4885 FROB (WM_MDIREFRESHMENU) | |
4886 | |
604 | 4887 #ifdef WM_IME_SETCONTEXT /* not in Cygwin? */ |
593 | 4888 |
4889 #if(WINVER >= 0x0400) | |
4890 FROB (WM_IME_SETCONTEXT) | |
4891 FROB (WM_IME_NOTIFY) | |
4892 FROB (WM_IME_CONTROL) | |
4893 FROB (WM_IME_COMPOSITIONFULL) | |
4894 FROB (WM_IME_SELECT) | |
4895 FROB (WM_IME_CHAR) | |
4896 #endif /* WINVER >= 0x0400 */ | |
1687 | 4897 #if(WINVER >= 0x0500) && defined(WM_IME_REQUEST) |
593 | 4898 FROB (WM_IME_REQUEST) |
4899 #endif /* WINVER >= 0x0500 */ | |
4900 #if(WINVER >= 0x0400) | |
4901 FROB (WM_IME_KEYDOWN) | |
4902 FROB (WM_IME_KEYUP) | |
4903 #endif /* WINVER >= 0x0400 */ | |
4904 | |
604 | 4905 #endif /* WM_IME_SETCONTEXT */ |
593 | 4906 |
4907 #if(_WIN32_WINNT >= 0x0400) | |
4908 FROB (WM_MOUSEHOVER) | |
4909 FROB (WM_MOUSELEAVE) | |
4910 #endif /* _WIN32_WINNT >= 0x0400 */ | |
4911 | |
4912 FROB (WM_CUT) | |
4913 FROB (WM_COPY) | |
4914 FROB (WM_PASTE) | |
4915 FROB (WM_CLEAR) | |
4916 FROB (WM_UNDO) | |
4917 FROB (WM_RENDERFORMAT) | |
4918 FROB (WM_RENDERALLFORMATS) | |
4919 FROB (WM_DESTROYCLIPBOARD) | |
4920 FROB (WM_DRAWCLIPBOARD) | |
4921 FROB (WM_PAINTCLIPBOARD) | |
4922 FROB (WM_VSCROLLCLIPBOARD) | |
4923 FROB (WM_SIZECLIPBOARD) | |
4924 FROB (WM_ASKCBFORMATNAME) | |
4925 FROB (WM_CHANGECBCHAIN) | |
4926 FROB (WM_HSCROLLCLIPBOARD) | |
4927 FROB (WM_QUERYNEWPALETTE) | |
4928 FROB (WM_PALETTEISCHANGING) | |
4929 FROB (WM_PALETTECHANGED) | |
4930 FROB (WM_HOTKEY) | |
4931 | |
4932 #if(WINVER >= 0x0400) | |
4933 FROB (WM_PRINT) | |
4934 FROB (WM_PRINTCLIENT) | |
4935 | |
4936 FROB (WM_HANDHELDFIRST) | |
4937 FROB (WM_HANDHELDLAST) | |
4938 | |
4939 FROB (WM_AFXFIRST) | |
4940 FROB (WM_AFXLAST) | |
4941 #endif /* WINVER >= 0x0400 */ | |
4942 | |
4943 FROB (WM_PENWINFIRST) | |
4944 FROB (WM_PENWINLAST) | |
4945 }; | |
4946 | |
4947 #undef FROB | |
4948 | |
4949 static void | |
4950 debug_output_mswin_message (HWND hwnd, UINT message_, WPARAM wParam, | |
4951 LPARAM lParam) | |
4952 { | |
4953 Lisp_Object frame = mswindows_find_frame (hwnd); | |
4954 int i; | |
4932 | 4955 const Ascbyte *str = 0; |
593 | 4956 /* struct mswin_message_debug *i_hate_cranking_out_code_like_this; */ |
4957 | |
4958 for (i = 0; i < countof (debug_mswin_messages); i++) | |
4959 { | |
647 | 4960 if (debug_mswin_messages[i].mess == (int) message_) |
593 | 4961 { |
4962 str = debug_mswin_messages[i].string; | |
4963 break; | |
4964 } | |
4965 } | |
4966 | |
4967 if (str) | |
4968 stderr_out ("%s", str); | |
4969 else | |
4970 stderr_out ("%x", message_); | |
4971 | |
4972 if (debug_mswindows_events > 1) | |
4973 { | |
4974 stderr_out (" wparam=%d lparam=%d hwnd=%x frame: ", | |
4975 wParam, (int) lParam, (unsigned int) hwnd); | |
4976 debug_print (frame); | |
903 | 4977 if (message_ == WM_WINDOWPOSCHANGED || |
4978 message_ == WM_WINDOWPOSCHANGING) | |
4979 { | |
4980 WINDOWPOS *wp = (WINDOWPOS *) lParam; | |
4981 stderr_out(" WINDOWPOS: x=%d, y=%d, h=%d, w=%d\n", | |
4982 wp->x, wp->y, wp->cx, wp->cy); | |
4983 } | |
4984 else if (message_ == WM_MOVE) | |
4985 { | |
4986 int x = (int)(short) LOWORD(lParam); /* horizontal position */ | |
4987 int y = (int)(short) HIWORD(lParam); /* vertical position */ | |
4988 stderr_out(" MOVE: x=%d, y=%d\n", x, y); | |
4989 } | |
4990 else if (message_ == WM_SIZE) | |
4991 { | |
4992 int w = (int)(short) LOWORD(lParam); /* width */ | |
4993 int h = (int)(short) HIWORD(lParam); /* height */ | |
4994 stderr_out(" SIZE: w=%d, h=%d\n", w, h); | |
4995 } | |
593 | 4996 } |
4997 else | |
4998 stderr_out ("\n"); | |
4999 } | |
5000 | |
5001 #endif /* DEBUG_XEMACS */ | |
5002 | |
428 | 5003 /************************************************************************/ |
5004 /* initialization */ | |
5005 /************************************************************************/ | |
5006 | |
5007 void | |
5008 reinit_vars_of_event_mswindows (void) | |
5009 { | |
5010 mswindows_pending_timers_count = 0; | |
5011 | |
1204 | 5012 mswindows_event_stream = xnew_and_zero (struct event_stream); |
428 | 5013 |
5014 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; | |
5015 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; | |
5016 mswindows_event_stream->handle_magic_event_cb = emacs_mswindows_handle_magic_event; | |
788 | 5017 mswindows_event_stream->format_magic_event_cb = emacs_mswindows_format_magic_event; |
5018 mswindows_event_stream->compare_magic_event_cb= emacs_mswindows_compare_magic_event; | |
5019 mswindows_event_stream->hash_magic_event_cb = emacs_mswindows_hash_magic_event; | |
428 | 5020 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; |
5021 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; | |
1204 | 5022 mswindows_event_stream->drain_queue_cb = emacs_mswindows_drain_queue; |
428 | 5023 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; |
5024 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; | |
5025 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; | |
5026 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; | |
853 | 5027 mswindows_event_stream->create_io_streams_cb = emacs_mswindows_create_io_streams; |
5028 mswindows_event_stream->delete_io_streams_cb = emacs_mswindows_delete_io_streams; | |
442 | 5029 mswindows_event_stream->current_event_timestamp_cb = |
5030 emacs_mswindows_current_event_timestamp; | |
903 | 5031 |
5032 dde_eval_pending = 0; | |
428 | 5033 } |
5034 | |
5035 void | |
5036 vars_of_event_mswindows (void) | |
5037 { | |
5038 mswindows_s_dispatch_event_queue = Qnil; | |
5039 staticpro (&mswindows_s_dispatch_event_queue); | |
5040 mswindows_s_dispatch_event_queue_tail = Qnil; | |
1204 | 5041 dump_add_root_lisp_object (&mswindows_s_dispatch_event_queue_tail); |
428 | 5042 |
853 | 5043 mswindows_error_caught_in_modal_loop = 0; |
442 | 5044 |
903 | 5045 #ifdef HAVE_DRAGNDROP |
5046 Fprovide (Qdde); | |
5047 | |
5048 DEFVAR_LISP ("dde-advise-items", &Vdde_advise_items /* | |
5049 A list of allocated DDE advise items. | |
5050 Each item is an uninterned symbol, created using dde-alloc-advise-item. | |
5051 | |
5052 The symbol's value is the data which is returned to the DDE client when | |
5053 a request for the item is made (or a dde-advise call is made). | |
5054 | |
3025 | 5055 The symbol also has a `HSZ' property, which holds the DDE string handle |
903 | 5056 for the item, as a float. This is for internal use only, and should not |
5057 be modified. | |
5058 */ ); | |
5059 Vdde_advise_items = Qnil; | |
5060 | |
5061 dde_eval_result = Qnil; | |
5062 staticpro (&dde_eval_result); | |
5063 dde_eval_error = Qnil; | |
5064 staticpro (&dde_eval_error); | |
5065 #endif | |
5066 | |
442 | 5067 #ifdef DEBUG_XEMACS |
5068 DEFVAR_INT ("debug-mswindows-events", &debug_mswindows_events /* | |
593 | 5069 If non-zero, display debug information about Windows messages that XEmacs sees. |
442 | 5070 Information is displayed in a console window. Currently defined values are: |
5071 | |
593 | 5072 1 == non-verbose output (just the message name) |
5073 2 == verbose output (all parameters) | |
5074 3 == even more verbose output (extra debugging info) | |
442 | 5075 */ ); |
5076 debug_mswindows_events = 0; | |
5077 #endif | |
5078 | |
5079 DEFVAR_BOOL ("mswindows-alt-by-itself-activates-menu", | |
5080 &mswindows_alt_by_itself_activates_menu /* | |
5081 *Controls whether pressing and releasing the Alt key activates the menubar. | |
5082 This applies only if no intervening key was pressed. See also | |
5083 `menu-accelerator-enabled', which is probably the behavior you actually want. | |
428 | 5084 Default is t. |
5085 */ ); | |
5086 | |
442 | 5087 DEFVAR_BOOL ("mswindows-dynamic-frame-resize", |
5088 &mswindows_dynamic_frame_resize /* | |
428 | 5089 *Controls redrawing frame contents during mouse-drag or keyboard resize |
5090 operation. When non-nil, the frame is redrawn while being resized. When | |
5091 nil, frame is not redrawn, and exposed areas are filled with default | |
5092 MDI application background color. Note that this option only has effect | |
5093 if "Show window contents while dragging" is on in system Display/Plus! | |
5094 settings. | |
5095 Default is t on fast machines, nil on slow. | |
5096 */ ); | |
5097 | |
442 | 5098 DEFVAR_INT ("mswindows-mouse-button-tolerance", |
5099 &mswindows_mouse_button_tolerance /* | |
428 | 5100 *Analogue of double click interval for faking middle mouse events. |
5101 The value is the minimum time in milliseconds that must elapse between | |
5102 left/right button down events before they are considered distinct events. | |
5103 If both mouse buttons are depressed within this interval, a middle mouse | |
5104 button down event is generated instead. | |
5105 If negative or zero, currently set system default is used instead. | |
5106 */ ); | |
5107 | |
5108 DEFVAR_INT ("mswindows-num-mouse-buttons", &mswindows_num_mouse_buttons /* | |
5109 Number of physical mouse buttons. | |
5110 */ ); | |
5111 | |
442 | 5112 DEFVAR_INT ("mswindows-mouse-button-max-skew-x", |
5113 &mswindows_mouse_button_max_skew_x /* | |
428 | 5114 *Maximum horizontal distance in pixels between points in which left and |
5115 right button clicks occurred for them to be translated into single | |
5116 middle button event. Clicks must occur in time not longer than defined | |
5117 by the variable `mswindows-mouse-button-tolerance'. | |
5118 If negative or zero, currently set system default is used instead. | |
5119 */ ); | |
5120 | |
442 | 5121 DEFVAR_INT ("mswindows-mouse-button-max-skew-y", |
5122 &mswindows_mouse_button_max_skew_y /* | |
428 | 5123 *Maximum vertical distance in pixels between points in which left and |
5124 right button clicks occurred for them to be translated into single | |
5125 middle button event. Clicks must occur in time not longer than defined | |
5126 by the variable `mswindows-mouse-button-tolerance'. | |
5127 If negative or zero, currently set system default is used instead. | |
5128 */ ); | |
5129 | |
5130 mswindows_mouse_button_max_skew_x = 0; | |
5131 mswindows_mouse_button_max_skew_y = 0; | |
5132 mswindows_mouse_button_tolerance = 0; | |
442 | 5133 mswindows_alt_by_itself_activates_menu = 1; |
428 | 5134 } |
5135 | |
5136 void | |
5137 syms_of_event_mswindows (void) | |
5138 { | |
903 | 5139 #ifdef HAVE_DRAGNDROP |
5140 DEFSYMBOL(QHSZ); | |
5141 DEFSUBR(Fdde_alloc_advise_item); | |
5142 DEFSUBR(Fdde_free_advise_item); | |
5143 DEFSUBR(Fdde_advise); | |
5144 #endif | |
428 | 5145 } |
5146 | |
5147 void | |
5148 lstream_type_create_mswindows_selectable (void) | |
5149 { | |
853 | 5150 #ifndef CYGWIN |
428 | 5151 init_slurp_stream (); |
5152 init_shove_stream (); | |
5153 init_winsock_stream (); | |
5154 #endif | |
5155 } | |
5156 | |
5157 void | |
5158 init_event_mswindows_late (void) | |
5159 { | |
853 | 5160 #ifdef CYGWIN |
771 | 5161 windows_fd = retry_open ("/dev/windows", O_RDONLY | O_NONBLOCK, 0); |
814 | 5162 assert (windows_fd >= 0); |
428 | 5163 FD_SET (windows_fd, &input_wait_mask); |
814 | 5164 FD_ZERO (&zero_mask); |
428 | 5165 #endif |
5166 | |
5167 event_stream = mswindows_event_stream; | |
5168 | |
5169 mswindows_dynamic_frame_resize = !GetSystemMetrics (SM_SLOWMACHINE); | |
5170 mswindows_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS); | |
5171 } |