comparison src/event-msw.c @ 1268:fffe735e63ee

[xemacs-hg @ 2003-02-07 11:50:50 by ben] fixes for menu crashes + better preemption behavior This contains two related changes: (1) Fix problems with reentrant calling of lwlib and associated crashes when selecting menu items. (2) Improve redisplay handling of preemption. Turn on lazy lock and hold down page-down or page-up and you'll see what I mean. They are related because they both touch on the code that retrieves events and handles the internal queues. console-msw.h, event-msw.c, event-stream.c, events.h, menubar-msw.c, menubar-x.c, menubar.h: mswindows_protect_modal_loop() has been generalized to event_stream_protect_modal_loop(), and moved to event-stream.c. mswindows_in_modal_loop ->in_modal_loop likewise. Changes in event-msw.c and menubar-msw.c for the new names and calling format (use structures instead of static variables in menubar-msw.c). Delete former in_menu_callback and use in_modal_loop in its place. Remove emacs_mswindows_quit_check_disallowed_p(), superseded by in_modal_loop. Use event_stream_protect_modal_loop() in pre_activate_callback() so that we get no lwlib reentrancy. Rearrange some of the code in event-msw.c to be grouped better. Make mswindows_drain_windows_queue() respect in_modal_loop and do nothing if so. cmdloop.c, event-stream.c: Don't conditionalize on LWLIB_MENUBARS_LUCID when giving error when in_modal_loop, and give better error. event-Xt.c, event-gtk.c: If in_modal_loop, only retrieve process and timeout events. Don't retrieve any X events because processing them can lead to reentrancy in lwlib -> death. event-stream.c: Remove unused parameter to check_event_stream_ok() and change all callers. lisp.h, event-stream.c: Rearrange some functions for increased clarity -- in particular, group all the input-pending/QUIT-related stuff together, and put right next to next-event stuff, to which it's related. Add the concept of "HOW_MANY" -- when asking whether user input is pending, you can ask if at least HOW_MANY events are pending, not just if any are. Add parameter to detect_input_pending() for this. Change recursive_sit_for from a Lisp_Object (which could only be Qt or Qnil) to an int, like it should be. event-Xt.c, event-gtk.c, event-xlike-inc.c: New file. Abstract out similar code in event_{Xt/gtk}_pending_p() and write only once, using include-file tricks. Rewrite this function to implement HOW_MANY and only process events when not in_modal_loop. event-msw.c: Implement HOW_MANY and only process events when not in_modal_loop. event-tty.c: Implement HOW_MANY. redisplay.c: Add var `max-preempts' to control maximum number of preempts. (#### perhaps not useful) Rewrite preemption check so that, rather than preempting when any user events are available, only preempt when a certain number (currently 4) of them are backed up. This effectively allows redisplay to proceed to completion in the presence of a fast auto-repeat (usually the auto-repeating is generated dynamically as necessary), and you get much better display behavior with lazy-lock active. event-unixoid.c: Comment changes. event-stream.c: Rewrite discard-input much more simply and safely using the drain-queue functions. I think the old version might loop forever if called when in_modal_loop. SEMI-UNRELATED CHANGES: ----------------------- event-stream.c: Turn QUIT-checking back on when running the pre-idle hook so it can be quit out of. indent.c: Document exact functioning of `vertical-motion' better, and its differences from GNU Emacs.
author ben
date Fri, 07 Feb 2003 11:50:54 +0000
parents f0af455e89d9
children cd0abfdb9e9d
comparison
equal deleted inserted replaced
1267:c57f32e44416 1268:fffe735e63ee
1 /* The mswindows event_stream interface. 1 /* The mswindows event_stream interface.
2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. 2 Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3 Copyright (C) 1995 Sun Microsystems, Inc. 3 Copyright (C) 1995 Sun Microsystems, Inc.
4 Copyright (C) 1996, 2000, 2001, 2002 Ben Wing. 4 Copyright (C) 1996, 2000, 2001, 2002, 2003 Ben Wing.
5 Copyright (C) 1997 Jonathan Harris. 5 Copyright (C) 1997 Jonathan Harris.
6 6
7 This file is part of XEmacs. 7 This file is part of XEmacs.
8 8
9 XEmacs is free software; you can redistribute it and/or modify it 9 XEmacs is free software; you can redistribute it and/or modify it
167 #endif 167 #endif
168 168
169 /* This is the event signaled by the event pump. 169 /* This is the event signaled by the event pump.
170 See mswindows_pump_outstanding_events for comments */ 170 See mswindows_pump_outstanding_events for comments */
171 static int mswindows_error_caught_in_modal_loop; 171 static int mswindows_error_caught_in_modal_loop;
172 static int mswindows_in_modal_loop;
173 172
174 /* Count of wound timers */ 173 /* Count of wound timers */
175 static int mswindows_pending_timers_count; 174 static int mswindows_pending_timers_count;
176 175
177 static DWORD mswindows_last_mouse_button_state; 176 static DWORD mswindows_last_mouse_button_state;
1127 return 0; 1126 return 0;
1128 1127
1129 return !ascii_strcasecmp (class_name_buf, XEMACS_CLASS); 1128 return !ascii_strcasecmp (class_name_buf, XEMACS_CLASS);
1130 } 1129 }
1131 1130
1132 struct mswindows_protect_modal_loop
1133 {
1134 Lisp_Object (*bfun) (Lisp_Object barg);
1135 Lisp_Object barg;
1136 };
1137
1138 static Lisp_Object
1139 mswindows_protect_modal_loop_1 (void *gack)
1140 {
1141 struct mswindows_protect_modal_loop *gata =
1142 (struct mswindows_protect_modal_loop *) gack;
1143
1144 return (gata->bfun) (gata->barg);
1145 }
1146
1147 Lisp_Object
1148 mswindows_protect_modal_loop (const char *error_string,
1149 Lisp_Object (*bfun) (Lisp_Object barg),
1150 Lisp_Object barg, int flags)
1151 {
1152 Lisp_Object tmp;
1153 struct mswindows_protect_modal_loop bluh;
1154
1155 bluh.bfun = bfun;
1156 bluh.barg = barg;
1157
1158 ++mswindows_in_modal_loop;
1159 tmp = call_trapping_problems (Qevent, error_string,
1160 flags, 0,
1161 mswindows_protect_modal_loop_1, &bluh);
1162 if (UNBOUNDP (tmp))
1163 mswindows_error_caught_in_modal_loop = 1;
1164 --mswindows_in_modal_loop;
1165
1166 return tmp;
1167 }
1168
1169 void 1131 void
1170 mswindows_unmodalize_signal_maybe (void) 1132 mswindows_unmodalize_signal_maybe (void)
1171 { 1133 {
1172 mswindows_error_caught_in_modal_loop = 0; 1134 mswindows_error_caught_in_modal_loop = 0;
1173 } 1135 }
1175 /* 1137 /*
1176 * This is an unsafe part of event pump, guarded by 1138 * This is an unsafe part of event pump, guarded by
1177 * condition_case. See mswindows_pump_outstanding_events 1139 * condition_case. See mswindows_pump_outstanding_events
1178 */ 1140 */
1179 static Lisp_Object 1141 static Lisp_Object
1180 mswindows_unsafe_pump_events (Lisp_Object u_n_u_s_e_d) 1142 mswindows_unsafe_pump_events (void *arg)
1181 { 1143 {
1182 /* This function can call lisp */ 1144 /* This function can call lisp */
1183 Lisp_Object event = Fmake_event (Qnil, Qnil); 1145 Lisp_Object event = Fmake_event (Qnil, Qnil);
1184 struct gcpro gcpro1; 1146 struct gcpro gcpro1;
1185 int do_redisplay = 0; 1147 int do_redisplay = 0;
1186 GCPRO1 (event); 1148 GCPRO1 (event);
1187 1149
1188 while (detect_input_pending ()) 1150 while (detect_input_pending (1))
1189 { 1151 {
1190 Fnext_event (event, Qnil); 1152 Fnext_event (event, Qnil);
1191 Fdispatch_event (event); 1153 Fdispatch_event (event);
1192 do_redisplay = 1; 1154 do_redisplay = 1;
1193 } 1155 }
1210 * 1172 *
1211 * Windows message queue is not looked into during the call, 1173 * Windows message queue is not looked into during the call,
1212 * neither are waitable handles checked. The function pumps 1174 * neither are waitable handles checked. The function pumps
1213 * thus only dispatch events already queued, as well as those 1175 * thus only dispatch events already queued, as well as those
1214 * resulted in dispatching thereof. This is done by setting 1176 * resulted in dispatching thereof. This is done by setting
1215 * module local variable mswindows_in_modal_loop to nonzero. 1177 * in_modal_loop to nonzero.
1216 * 1178 *
1217 * Return value is Qt if no errors was trapped, or Qunbound if 1179 * Return value is Qt if no errors was trapped, or Qunbound if
1218 * there was an error. 1180 * there was an error.
1219 * 1181 *
1220 * In case of error, a warning is issued and the module local variable 1182 * In case of error, a warning is issued and the module local variable
1242 Lisp_Object result = Qt; 1204 Lisp_Object result = Qt;
1243 struct gcpro gcpro1; 1205 struct gcpro gcpro1;
1244 GCPRO1 (result); 1206 GCPRO1 (result);
1245 1207
1246 if (!mswindows_error_caught_in_modal_loop) 1208 if (!mswindows_error_caught_in_modal_loop)
1247 result = mswindows_protect_modal_loop 1209 result = event_stream_protect_modal_loop
1248 ("Error during event handling", mswindows_unsafe_pump_events, Qnil, 0); 1210 ("Error during event handling", mswindows_unsafe_pump_events, 0, 0);
1249 UNGCPRO; 1211 UNGCPRO;
1212 if (UNBOUNDP (result))
1213 mswindows_error_caught_in_modal_loop = 1;
1250 return result; 1214 return result;
1251 }
1252
1253 /*
1254 * KEYBOARD_ONLY_P is set to non-zero when we are called from
1255 * QUITP, and are interesting in keyboard messages only.
1256 */
1257 static void
1258 mswindows_drain_windows_queue (void)
1259 {
1260 MSG msg;
1261
1262 /* should call mswindows_need_event_in_modal_loop() if in modal loop */
1263 assert (!mswindows_in_modal_loop);
1264
1265 while (qxePeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1266 {
1267 #ifdef HAVE_DIALOGS
1268 /* Don't translate messages destined for a dialog box, this
1269 makes keyboard traversal work. I think?? */
1270 if (mswindows_is_dialog_msg (&msg))
1271 {
1272 mswindows_unmodalize_signal_maybe ();
1273 continue;
1274 }
1275 #endif /* HAVE_DIALOGS */
1276
1277 /* We have to translate messages that are not sent to an XEmacs
1278 frame. This is so that key presses work ok in things like
1279 edit fields. However, we *musn't* translate message for XEmacs
1280 frames as this is handled in the wnd proc.
1281 We also have to avoid generating paint magic events for windows
1282 that aren't XEmacs frames */
1283
1284 if (!mswindows_window_is_xemacs (msg.hwnd))
1285 TranslateMessage (&msg);
1286 else if (msg.message == WM_PAINT)
1287 {
1288 struct mswindows_frame *msframe;
1289
1290 /* hdc will be NULL unless this is a subwindow - in which case we
1291 shouldn't have received a paint message for it here. */
1292 assert (msg.wParam == 0);
1293
1294 /* Queue a magic event for handling when safe */
1295 msframe =
1296 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1297 if (!msframe->paint_pending)
1298 {
1299 msframe->paint_pending = 1;
1300 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1301 }
1302 /* Don't dispatch. WM_PAINT is always the last message in the
1303 queue so it's OK to just return. */
1304 return;
1305 }
1306 qxeDispatchMessage (&msg);
1307 mswindows_unmodalize_signal_maybe ();
1308 }
1309 }
1310
1311 static void
1312 emacs_mswindows_drain_queue (void)
1313 {
1314 mswindows_drain_windows_queue ();
1315 #ifdef HAVE_TTY
1316 drain_tty_devices ();
1317 #endif
1318 }
1319
1320 static int
1321 emacs_mswindows_quit_check_disallowed_p (void)
1322 {
1323 /* Quit cannot happen in modal loop: all program
1324 input is dedicated to Windows. */
1325 return mswindows_in_modal_loop;
1326 } 1215 }
1327 1216
1328 /* 1217 /*
1329 * This is a special flavor of the mswindows_need_event function, 1218 * This is a special flavor of the mswindows_need_event function,
1330 * used while in event pump. Actually, there is only kind of events 1219 * used while in event pump. Actually, there is only kind of events
1369 if (qxeGetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0) 1258 if (qxeGetMessage (&msg, NULL, WM_TIMER, WM_TIMER) > 0)
1370 qxeDispatchMessage (&msg); 1259 qxeDispatchMessage (&msg);
1371 } 1260 }
1372 } 1261 }
1373 1262
1263 /* BADLY_P non-zero means we were called from mswindows_need_event(1). It
1264 only matters when we are in a modal loop, and causes us to fetch timer
1265 events (the only kinds we can fetch in such a case).
1266 */
1267 static void
1268 mswindows_drain_windows_queue (int badly_p)
1269 {
1270 MSG msg;
1271
1272 if (in_modal_loop)
1273 mswindows_need_event_in_modal_loop (badly_p);
1274 else
1275 while (qxePeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
1276 {
1277 #ifdef HAVE_DIALOGS
1278 /* Don't translate messages destined for a dialog box, this
1279 makes keyboard traversal work. I think?? */
1280 if (mswindows_is_dialog_msg (&msg))
1281 {
1282 mswindows_unmodalize_signal_maybe ();
1283 continue;
1284 }
1285 #endif /* HAVE_DIALOGS */
1286
1287 /* We have to translate messages that are not sent to an XEmacs
1288 frame. This is so that key presses work ok in things like
1289 edit fields. However, we *musn't* translate message for XEmacs
1290 frames as this is handled in the wnd proc.
1291 We also have to avoid generating paint magic events for windows
1292 that aren't XEmacs frames */
1293
1294 if (!mswindows_window_is_xemacs (msg.hwnd))
1295 TranslateMessage (&msg);
1296 else if (msg.message == WM_PAINT)
1297 {
1298 struct mswindows_frame *msframe;
1299
1300 /* hdc will be NULL unless this is a subwindow - in which case we
1301 shouldn't have received a paint message for it here. */
1302 assert (msg.wParam == 0);
1303
1304 /* Queue a magic event for handling when safe */
1305 msframe =
1306 FRAME_MSWINDOWS_DATA (XFRAME (mswindows_find_frame (msg.hwnd)));
1307 if (!msframe->paint_pending)
1308 {
1309 msframe->paint_pending = 1;
1310 mswindows_enqueue_magic_event (msg.hwnd, WM_PAINT);
1311 }
1312 /* Don't dispatch. WM_PAINT is always the last message in the
1313 queue so it's OK to just return. */
1314 return;
1315 }
1316 qxeDispatchMessage (&msg);
1317 mswindows_unmodalize_signal_maybe ();
1318 }
1319 }
1320
1321 static void
1322 emacs_mswindows_drain_queue (void)
1323 {
1324 mswindows_drain_windows_queue (0);
1325 #ifdef HAVE_TTY
1326 drain_tty_devices ();
1327 #endif
1328 }
1329
1374 /* 1330 /*
1375 * This drains the event queue and fills up two internal queues until 1331 * This drains the event queue and fills up two internal queues until
1376 * an event of a type specified by USER_P is retrieved. 1332 * an event of a type specified by USER_P is retrieved.
1377 * 1333 *
1378 * 1334 *
1396 else 1352 else
1397 { 1353 {
1398 EMACS_SET_SECS_USECS (sometime, 0, 0); 1354 EMACS_SET_SECS_USECS (sometime, 0, 0);
1399 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block); 1355 EMACS_TIME_TO_SELECT_TIME (sometime, select_time_to_block);
1400 pointer_to_this = &select_time_to_block; 1356 pointer_to_this = &select_time_to_block;
1401 if (mswindows_in_modal_loop) 1357 if (in_modal_loop)
1402 /* In modal loop with badly_p false, don't care about 1358 /* In modal loop with badly_p false, don't care about
1403 Windows events. */ 1359 Windows events. */
1404 FD_CLR (windows_fd, &temp_mask); 1360 FD_CLR (windows_fd, &temp_mask);
1405 } 1361 }
1406 1362
1412 return; /* timeout */ 1368 return; /* timeout */
1413 } 1369 }
1414 else if (active > 0) 1370 else if (active > 0)
1415 { 1371 {
1416 if (FD_ISSET (windows_fd, &temp_mask)) 1372 if (FD_ISSET (windows_fd, &temp_mask))
1417 { 1373 mswindows_drain_windows_queue (badly_p);
1418 if (mswindows_in_modal_loop)
1419 mswindows_need_event_in_modal_loop (badly_p);
1420 else
1421 mswindows_drain_windows_queue ();
1422 }
1423 else 1374 else
1424 { 1375 {
1425 #ifdef HAVE_TTY 1376 #ifdef HAVE_TTY
1426 /* Look for a TTY event */ 1377 /* Look for a TTY event */
1427 for (i = 0; i < MAXDESC; i++) 1378 for (i = 0; i < MAXDESC; i++)
1484 } 1435 }
1485 #else /* not CYGWIN */ 1436 #else /* not CYGWIN */
1486 /* Now try getting a message or process event */ 1437 /* Now try getting a message or process event */
1487 DWORD active; 1438 DWORD active;
1488 DWORD what_events; 1439 DWORD what_events;
1489 if (mswindows_in_modal_loop) 1440 if (in_modal_loop)
1490 /* In a modal loop, only look for timer events, and only if 1441 /* In a modal loop, only look for timer events, and only if
1491 we really need one. */ 1442 we really need one. */
1492 { 1443 {
1493 if (badly_p) 1444 if (badly_p)
1494 what_events = QS_TIMER; 1445 what_events = QS_TIMER;
1605 { 1556 {
1606 /* No luck trying - just return what we've already got */ 1557 /* No luck trying - just return what we've already got */
1607 return; 1558 return;
1608 } 1559 }
1609 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count) 1560 else if (active == WAIT_OBJECT_0 + mswindows_waitable_count)
1610 { 1561 mswindows_drain_windows_queue (badly_p);
1611 /* Got your message, thanks */
1612 if (mswindows_in_modal_loop)
1613 mswindows_need_event_in_modal_loop (badly_p);
1614 else
1615 mswindows_drain_windows_queue ();
1616 }
1617 else 1562 else
1618 { 1563 {
1619 int ix = active - WAIT_OBJECT_0; 1564 int ix = active - WAIT_OBJECT_0;
1620 1565
1621 /* look for a stream console event; see 1566 /* look for a stream console event; see
4382 * events available (that is, whether there are keyboard or mouse-click 4327 * events available (that is, whether there are keyboard or mouse-click
4383 * events ready to be read). This also implies that 4328 * events ready to be read). This also implies that
4384 * emacs_mswindows_next_event() would not block. 4329 * emacs_mswindows_next_event() would not block.
4385 */ 4330 */
4386 static int 4331 static int
4387 emacs_mswindows_event_pending_p (int user_p) 4332 emacs_mswindows_event_pending_p (int how_many)
4388 { 4333 {
4389 mswindows_need_event (0); 4334 if (!how_many)
4390 return (!NILP (dispatch_event_queue) 4335 {
4391 || (!user_p && !NILP (mswindows_s_dispatch_event_queue))); 4336 mswindows_need_event (0);
4337 return (!NILP (dispatch_event_queue)
4338 || !NILP (mswindows_s_dispatch_event_queue));
4339 }
4340 else
4341 {
4342 Lisp_Object event;
4343 int count = 0;
4344
4345 EVENT_CHAIN_LOOP (event, dispatch_event_queue)
4346 count++;
4347
4348 if (count >= how_many)
4349 return 1;
4350
4351 emacs_mswindows_drain_queue ();
4352
4353 EVENT_CHAIN_LOOP (event, dispatch_event_queue)
4354 count++;
4355
4356 return count >= how_many;
4357 }
4392 } 4358 }
4393 4359
4394 /* 4360 /*
4395 * Return the next event 4361 * Return the next event
4396 */ 4362 */
5143 /************************************************************************/ 5109 /************************************************************************/
5144 5110
5145 void 5111 void
5146 reinit_vars_of_event_mswindows (void) 5112 reinit_vars_of_event_mswindows (void)
5147 { 5113 {
5148 mswindows_in_modal_loop = 0;
5149 mswindows_pending_timers_count = 0; 5114 mswindows_pending_timers_count = 0;
5150 5115
5151 mswindows_event_stream = xnew_and_zero (struct event_stream); 5116 mswindows_event_stream = xnew_and_zero (struct event_stream);
5152 5117
5153 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p; 5118 mswindows_event_stream->event_pending_p = emacs_mswindows_event_pending_p;
5157 mswindows_event_stream->compare_magic_event_cb= emacs_mswindows_compare_magic_event; 5122 mswindows_event_stream->compare_magic_event_cb= emacs_mswindows_compare_magic_event;
5158 mswindows_event_stream->hash_magic_event_cb = emacs_mswindows_hash_magic_event; 5123 mswindows_event_stream->hash_magic_event_cb = emacs_mswindows_hash_magic_event;
5159 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout; 5124 mswindows_event_stream->add_timeout_cb = emacs_mswindows_add_timeout;
5160 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout; 5125 mswindows_event_stream->remove_timeout_cb = emacs_mswindows_remove_timeout;
5161 mswindows_event_stream->drain_queue_cb = emacs_mswindows_drain_queue; 5126 mswindows_event_stream->drain_queue_cb = emacs_mswindows_drain_queue;
5162 mswindows_event_stream->quit_check_disallowed_p_cb = emacs_mswindows_quit_check_disallowed_p;
5163 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console; 5127 mswindows_event_stream->select_console_cb = emacs_mswindows_select_console;
5164 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console; 5128 mswindows_event_stream->unselect_console_cb = emacs_mswindows_unselect_console;
5165 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process; 5129 mswindows_event_stream->select_process_cb = emacs_mswindows_select_process;
5166 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process; 5130 mswindows_event_stream->unselect_process_cb = emacs_mswindows_unselect_process;
5167 mswindows_event_stream->create_io_streams_cb = emacs_mswindows_create_io_streams; 5131 mswindows_event_stream->create_io_streams_cb = emacs_mswindows_create_io_streams;