Mercurial > hg > xemacs-beta
comparison src/event-msw.c @ 227:0e522484dd2a r20-5b12
Import from CVS: tag r20-5b12
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:12:37 +0200 |
parents | 12579d965149 |
children | 557eaa0339bf |
comparison
equal
deleted
inserted
replaced
226:eea38c7ad7b4 | 227:0e522484dd2a |
---|---|
33 #include <config.h> | 33 #include <config.h> |
34 #include "lisp.h" | 34 #include "lisp.h" |
35 | 35 |
36 #include "device.h" | 36 #include "device.h" |
37 #include "console-msw.h" | 37 #include "console-msw.h" |
38 #include "emacsfns.h" | |
38 #include "events.h" | 39 #include "events.h" |
39 #include "frame.h" | 40 #include "frame.h" |
40 #include "process.h" | 41 #include "process.h" |
41 | 42 #include "redisplay.h" |
42 #include "sysproc.h" | 43 #include "sysproc.h" |
43 #include "syswait.h" | 44 #include "syswait.h" |
44 #include "systime.h" | 45 #include "systime.h" |
45 | 46 |
46 #include "event-msw.h" | 47 #include "event-msw.h" |
79 int mswindows_button2_max_skew_y; | 80 int mswindows_button2_max_skew_y; |
80 int mswindows_button2_chord_time; | 81 int mswindows_button2_chord_time; |
81 | 82 |
82 /* Number of wait handles */ | 83 /* Number of wait handles */ |
83 static mswindows_waitable_count=0; | 84 static mswindows_waitable_count=0; |
85 | |
86 /* This is the event signaled by the event pump. | |
87 See mswindows_pump_outstanding_events for comments */ | |
88 static Lisp_Object mswindows_error_caught_by_event_pump; | |
89 static int mswindows_in_event_pump; | |
90 | |
91 /* Count of wound timers */ | |
92 static int mswindows_pending_timers_count; | |
84 | 93 |
85 static int | 94 static int |
86 mswindows_user_event_p (struct Lisp_Event* sevt) | 95 mswindows_user_event_p (struct Lisp_Event* sevt) |
87 { | 96 { |
88 return (sevt->event_type == key_press_event | 97 return (sevt->event_type == key_press_event |
193 previous_event = event; | 202 previous_event = event; |
194 } | 203 } |
195 } | 204 } |
196 | 205 |
197 /* | 206 /* |
207 * This is an unsafe part of event pump, guarded by | |
208 * condition_case. See mswindows_pump_outstanding_events | |
209 */ | |
210 static Lisp_Object | |
211 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d) | |
212 { | |
213 /* This function can call lisp */ | |
214 Lisp_Object event = Fmake_event (Qnil, Qnil); | |
215 struct gcpro gcpro1; | |
216 int do_redisplay = 0; | |
217 GCPRO1 (event); | |
218 | |
219 while (detect_input_pending ()) | |
220 { | |
221 Fnext_event (event, Qnil); | |
222 Fdispatch_event (event); | |
223 do_redisplay = 1; | |
224 } | |
225 | |
226 if (do_redisplay) | |
227 redisplay (); | |
228 | |
229 Fdeallocate_event (event); | |
230 UNGCPRO; | |
231 | |
232 /* Qt becomes return value of mswindows_pump_outstanding_events | |
233 once we get here */ | |
234 return Qt; | |
235 } | |
236 | |
237 /* See mswindows_pump_outstanding_events */ | |
238 static Lisp_Object | |
239 mswindows_event_pump_error_handler (Lisp_Object cons_sig_data, | |
240 Lisp_Object u_n_u_s_e_d) | |
241 { | |
242 mswindows_error_caught_by_event_pump = cons_sig_data; | |
243 return Qnil; | |
244 } | |
245 | |
246 /* | |
247 * This function pumps emacs events, while available, by using | |
248 * next_message/dispatch_message loop. Errors are trapped around | |
249 * the loop so the function always returns. | |
250 * | |
251 * Windows message queue is not looked into during the call, | |
252 * neither are waitable handles checked. The function pumps | |
253 * thus only dispatch events already queued, as well as those | |
254 * resulted in dispatching thereof. This is done by setting | |
255 * module local variable mswidows_in_event_pump to nonzero. | |
256 * | |
257 * Return value is Qt if no errors was trapped, or Qnil if | |
258 * there was an error. | |
259 * | |
260 * In case of error, a cons representing the error, in the | |
261 * form (SIGNAL . DATA), is stored in the module local variable | |
262 * mswindows_error_caught_by_event_pump. This error is signaled | |
263 * again when DispatchMessage returns. Thus, Windows internal | |
264 * modal loops are protected against throws, which are proven | |
265 * to corrupt internal Windows structures. | |
266 * | |
267 * In case of success, mswindows_error_caught_by_event_pump is | |
268 * assigned Qnil. | |
269 * | |
270 * If the value of mswindows_error_caught_by_event_pump is not | |
271 * nil already upon entry, the function just returns non-nil. | |
272 * This situation means that a new event has been queued while | |
273 * cancleng mode. The event will be dequeued on the next regular | |
274 * call of next-event; the pump is off since error is caught. | |
275 * The caller must *unconditionally* cancel modal loop if the | |
276 * value returned by this function is nil. Otherwise, everything | |
277 * will become frozen until the modal loop exits under normal | |
278 * condition (scrollbar drag is released, menu closed etc.) | |
279 */ | |
280 Lisp_Object | |
281 mswindows_pump_outstanding_events (void) | |
282 { | |
283 /* This function can call lisp */ | |
284 | |
285 Lisp_Object result = Qt; | |
286 | |
287 if (NILP(mswindows_error_caught_by_event_pump)) | |
288 { | |
289 | |
290 mswindows_in_event_pump = 1; | |
291 | |
292 result = condition_case_1 (Qt, | |
293 mswindows_unsafe_pump_events, Qnil, | |
294 mswindows_event_pump_error_handler, Qnil); | |
295 | |
296 mswindows_in_event_pump = 0; | |
297 } | |
298 return result; | |
299 } | |
300 | |
301 /* | |
198 * Find a free waitable slot | 302 * Find a free waitable slot |
199 */ | 303 */ |
200 static int | 304 static int |
201 mswindows_find_free_waitable(void) | 305 mswindows_find_free_waitable(void) |
202 { | 306 { |
265 { | 369 { |
266 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); | 370 Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); |
267 struct Lisp_Event *event = XEVENT (emacs_event); | 371 struct Lisp_Event *event = XEVENT (emacs_event); |
268 | 372 |
269 KillTimer (NULL, id_timer); | 373 KillTimer (NULL, id_timer); |
374 --mswindows_pending_timers_count; | |
270 | 375 |
271 event->channel = Qnil; | 376 event->channel = Qnil; |
272 event->timestamp = dwtime; | 377 event->timestamp = dwtime; |
273 event->event_type = timeout_event; | 378 event->event_type = timeout_event; |
274 event->event.timeout.interval_id = id_timer; | 379 event->event.timeout.interval_id = id_timer; |
279 static void | 384 static void |
280 mswindows_drain_windows_queue () | 385 mswindows_drain_windows_queue () |
281 { | 386 { |
282 MSG msg; | 387 MSG msg; |
283 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) | 388 while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) |
284 DispatchMessage (&msg); | 389 { |
390 DispatchMessage (&msg); | |
391 if (!NILP (mswindows_error_caught_by_event_pump)) | |
392 { | |
393 /* Got an error while messages were pumped while | |
394 in window procedure - have to resignal */ | |
395 Lisp_Object sym = XCAR (mswindows_error_caught_by_event_pump); | |
396 Lisp_Object data = XCDR (mswindows_error_caught_by_event_pump); | |
397 mswindows_error_caught_by_event_pump = Qnil; | |
398 Fsignal (sym, data); | |
399 } | |
400 } | |
401 } | |
402 | |
403 /* | |
404 * This is a special flavour of the mswindows_need_event function, | |
405 * used while in event pump. Actually, there is only kind of events | |
406 * allowed while in event pump: a timer. An attempt to fetch any | |
407 * other event leads to a dealock, as there's no source of user input | |
408 * ('cause event pump mirrors windows modal loop, which is a sole | |
409 * owner of thread message queue). | |
410 * | |
411 * To detect this, we use a counter of active timers, and allow | |
412 * fetching WM_TIMER messages. Instead of trying to fetch a WM_TIMER | |
413 * which will never come when there are no pending timers, which leads | |
414 * to deadlock, we simply signal an error. | |
415 * | |
416 * The implementation does not honor user_p by design. | |
417 */ | |
418 static void | |
419 mswindows_need_event_in_event_pump (int user_p, int badly_p) | |
420 { | |
421 MSG msg; | |
422 | |
423 /* Check if already have one */ | |
424 if (!NILP (mswindows_u_dispatch_event_queue) | |
425 || !NILP (mswindows_s_dispatch_event_queue)) | |
426 return; | |
427 | |
428 /* No event is ok */ | |
429 if (!badly_p) | |
430 return; | |
431 | |
432 /* We do not check the _u_ queue, because timers go to _s_ */ | |
433 while (NILP (mswindows_s_dispatch_event_queue)) | |
434 { | |
435 /* We'll deadlock if go waiting */ | |
436 if (mswindows_pending_timers_count == 0) | |
437 error ("Deadlock due to an attempt to call next-event in a wrong context"); | |
438 | |
439 /* Fetch and dispatch any pending timers */ | |
440 GetMessage (&msg, NULL, WM_TIMER, WM_TIMER); | |
441 DispatchMessage (&msg); | |
442 } | |
285 } | 443 } |
286 | 444 |
287 /* | 445 /* |
288 * This drains the event queue and fills up two internal queues until | 446 * This drains the event queue and fills up two internal queues until |
289 * an event of a type specified by USER_P is retrieved. | 447 * an event of a type specified by USER_P is retrieved. |
302 */ | 460 */ |
303 static void | 461 static void |
304 mswindows_need_event (int user_p, int badly_p) | 462 mswindows_need_event (int user_p, int badly_p) |
305 { | 463 { |
306 int active; | 464 int active; |
465 | |
466 if (mswindows_in_event_pump) | |
467 { | |
468 mswindows_need_event_in_event_pump (user_p, badly_p); | |
469 return; | |
470 } | |
307 | 471 |
308 /* Have to drain Windows message queue first, otherwise, we may miss | 472 /* Have to drain Windows message queue first, otherwise, we may miss |
309 quit char when called from quit_p */ | 473 quit char when called from quit_p */ |
310 mswindows_drain_windows_queue (); | 474 mswindows_drain_windows_queue (); |
311 | 475 |
371 EMACS_SUB_TIME (thyme, thyme, current_time); | 535 EMACS_SUB_TIME (thyme, thyme, current_time); |
372 milliseconds = EMACS_SECS (thyme) * 1000 + | 536 milliseconds = EMACS_SECS (thyme) * 1000 + |
373 (EMACS_USECS (thyme) + 500) / 1000; | 537 (EMACS_USECS (thyme) + 500) / 1000; |
374 if (milliseconds < 1) | 538 if (milliseconds < 1) |
375 milliseconds = 1; | 539 milliseconds = 1; |
540 ++mswindows_pending_timers_count; | |
376 return SetTimer (NULL, 0, milliseconds, mswindows_wm_timer_callback); | 541 return SetTimer (NULL, 0, milliseconds, mswindows_wm_timer_callback); |
377 } | 542 } |
378 | 543 |
379 static void | 544 static void |
380 emacs_mswindows_remove_timeout (int id) | 545 emacs_mswindows_remove_timeout (int id) |
381 { | 546 { |
382 struct Lisp_Event match_against; | 547 struct Lisp_Event match_against; |
383 Lisp_Object emacs_event; | 548 Lisp_Object emacs_event; |
384 | 549 |
385 KillTimer (NULL, id); | 550 KillTimer (NULL, id); |
551 --mswindows_pending_timers_count; | |
386 | 552 |
387 /* If there is a dispatch event generated by this | 553 /* If there is a dispatch event generated by this |
388 timeout in the queue, we have to remove it too. */ | 554 timeout in the queue, we have to remove it too. */ |
389 match_against.event_type = timeout_event; | 555 match_against.event_type = timeout_event; |
390 match_against.event.timeout.interval_id = id; | 556 match_against.event.timeout.interval_id = id; |
570 mswindows_u_dispatch_event_queue_tail = Qnil; | 736 mswindows_u_dispatch_event_queue_tail = Qnil; |
571 | 737 |
572 mswindows_s_dispatch_event_queue = Qnil; | 738 mswindows_s_dispatch_event_queue = Qnil; |
573 staticpro (&mswindows_s_dispatch_event_queue); | 739 staticpro (&mswindows_s_dispatch_event_queue); |
574 mswindows_s_dispatch_event_queue_tail = Qnil; | 740 mswindows_s_dispatch_event_queue_tail = Qnil; |
741 | |
742 mswindows_error_caught_by_event_pump = Qnil; | |
743 staticpro (&mswindows_error_caught_by_event_pump); | |
744 mswindows_in_event_pump = 0; | |
745 mswindows_pending_timers_count = 0; | |
575 | 746 |
576 mswindows_event_stream = xnew (struct event_stream); | 747 mswindows_event_stream = xnew (struct event_stream); |
577 | 748 |
578 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; | 749 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; |
579 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; | 750 mswindows_event_stream->next_event_cb = emacs_mswindows_next_event; |