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