Mercurial > hg > xemacs-beta
annotate src/event-msw.c @ 5533:11da5b828d10
shell-command and shell-command-on-region API compliant with FSF 23.3.1
| author | Mats Lidell <mats.lidell@cag.se> |
|---|---|
| date | Sun, 31 Jul 2011 01:29:09 +0200 |
| 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 } |
