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