Mercurial > hg > xemacs-beta
comparison src/event-Xt.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 | e22b0213b713 |
children | f3437b56874d |
comparison
equal
deleted
inserted
replaced
1267:c57f32e44416 | 1268:fffe735e63ee |
---|---|
1 /* The event_stream interface for X11 with Xt, and/or tty frames. | 1 /* The event_stream interface for X11 with Xt, and/or tty frames. |
2 Copyright (C) 1991-5, 1997 Free Software Foundation, Inc. | 2 Copyright (C) 1991-5, 1997 Free Software Foundation, Inc. |
3 Copyright (C) 1995 Sun Microsystems, Inc. | 3 Copyright (C) 1995 Sun Microsystems, Inc. |
4 Copyright (C) 1996, 2001, 2002 Ben Wing. | 4 Copyright (C) 1996, 2001, 2002, 2003 Ben Wing. |
5 | 5 |
6 This file is part of XEmacs. | 6 This file is part of XEmacs. |
7 | 7 |
8 XEmacs is free software; you can redistribute it and/or modify it | 8 XEmacs is free software; you can redistribute it and/or modify it |
9 under the terms of the GNU General Public License as published by the | 9 under the terms of the GNU General Public License as published by the |
96 static int process_events_occurred; | 96 static int process_events_occurred; |
97 static int tty_events_occurred; | 97 static int tty_events_occurred; |
98 static Widget widget_with_focus; | 98 static Widget widget_with_focus; |
99 | 99 |
100 /* Mask of bits indicating the descriptors that we wait for input on */ | 100 /* Mask of bits indicating the descriptors that we wait for input on */ |
101 extern SELECT_TYPE input_wait_mask, process_only_mask, tty_only_mask; | 101 extern SELECT_TYPE input_wait_mask, non_fake_input_wait_mask; |
102 extern SELECT_TYPE process_only_mask, tty_only_mask; | |
102 | 103 |
103 static const String x_fallback_resources[] = | 104 static const String x_fallback_resources[] = |
104 { | 105 { |
105 /* This file is automatically generated from the app-defaults file | 106 /* This file is automatically generated from the app-defaults file |
106 in ../etc/Emacs.ad. These resources are consulted only if no | 107 in ../etc/Emacs.ad. These resources are consulted only if no |
118 | 119 |
119 static int last_quit_check_signal_tick_count; | 120 static int last_quit_check_signal_tick_count; |
120 | 121 |
121 Lisp_Object Qkey_mapping; | 122 Lisp_Object Qkey_mapping; |
122 Lisp_Object Qsans_modifiers; | 123 Lisp_Object Qsans_modifiers; |
124 | |
125 #define THIS_IS_X | |
126 #include "event-xlike-inc.c" | |
123 | 127 |
124 | 128 |
125 /************************************************************************/ | 129 /************************************************************************/ |
126 /* keymap handling */ | 130 /* keymap handling */ |
127 /************************************************************************/ | 131 /************************************************************************/ |
2769 !completed_timeouts && | 2773 !completed_timeouts && |
2770 !fake_event_occurred && | 2774 !fake_event_occurred && |
2771 !process_events_occurred && | 2775 !process_events_occurred && |
2772 !tty_events_occurred) | 2776 !tty_events_occurred) |
2773 { | 2777 { |
2774 | 2778 if (in_modal_loop) |
2775 /* Stupid logic in XtAppProcessEvent() dictates that, if process | 2779 { |
2776 events and X events are both available, the process event gets | 2780 /* in_modal_loop gets set when we are in the process of |
2777 taken first. This will cause an infinite loop if we're being | 2781 dispatching an event (more specifically, when we are inside of |
2778 called from Fdiscard_input(). | 2782 a menu callback -- if we get here, it means we called a filter |
2779 */ | 2783 and the filter did something that tried to fetch an event, |
2780 if (XtAppPending (Xt_app_con) & XtIMXEvent) | 2784 e.g. sit-for). In such a case, we cannot safely dispatch any |
2781 XtAppProcessEvent (Xt_app_con, XtIMXEvent); | 2785 more events. This is because those dispatching those events |
2786 could cause lwlib to be entered reentranty, specifically if | |
2787 they are menu events. lwlib is not designed for this and will | |
2788 crash. We used to see this crash constantly as a result of | |
2789 QUIT checking, but QUIT will not now function in a modal loop. | |
2790 However, we can't just not process any events at all, because | |
2791 that will make sit-for etc. hang. So we go ahead and process | |
2792 the non-X kinds of events. */ | |
2793 XtInputMask pending_value = XtAppPending (Xt_app_con); | |
2794 | |
2795 if (pending_value & (XtIMTimer | XtIMAlternateInput)) | |
2796 XtAppProcessEvent (Xt_app_con, XtIMTimer | XtIMAlternateInput); | |
2797 } | |
2782 else | 2798 else |
2783 { | 2799 { |
2784 Lisp_Object devcons, concons; | 2800 /* Stupid logic in XtAppProcessEvent() dictates that, if process |
2785 | 2801 events and X events are both available, the process event gets |
2786 /* We're about to block. Xt has a bug in it (big surprise, | 2802 taken first. This will cause an infinite loop if we're being |
2787 there) in that it blocks using select() and doesn't | 2803 called from Fdiscard_input(). |
2788 flush the Xlib output buffers (XNextEvent() does this | 2804 */ |
2789 automatically before blocking). So it's necessary | 2805 |
2790 for us to do this ourselves. If we don't do it, then | 2806 if (XtAppPending (Xt_app_con) & XtIMXEvent) |
2791 display output may not be seen until the next time | 2807 XtAppProcessEvent (Xt_app_con, XtIMXEvent); |
2792 an X event is received. (This happens esp. with | 2808 else |
2793 subprocess output that gets sent to a visible buffer.) | |
2794 | |
2795 #### The above comment may not have any validity. */ | |
2796 | |
2797 DEVICE_LOOP_NO_BREAK (devcons, concons) | |
2798 { | 2809 { |
2799 struct device *d; | 2810 Lisp_Object devcons, concons; |
2800 d = XDEVICE (XCAR (devcons)); | 2811 |
2801 | 2812 /* We're about to block. Xt has a bug in it (big surprise, |
2802 if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) | 2813 there) in that it blocks using select() and doesn't |
2803 /* emacs may be exiting */ | 2814 flush the Xlib output buffers (XNextEvent() does this |
2804 XFlush (DEVICE_X_DISPLAY (d)); | 2815 automatically before blocking). So it's necessary |
2816 for us to do this ourselves. If we don't do it, then | |
2817 display output may not be seen until the next time | |
2818 an X event is received. (This happens esp. with | |
2819 subprocess output that gets sent to a visible buffer.) | |
2820 | |
2821 #### The above comment may not have any validity. */ | |
2822 | |
2823 DEVICE_LOOP_NO_BREAK (devcons, concons) | |
2824 { | |
2825 struct device *d; | |
2826 d = XDEVICE (XCAR (devcons)); | |
2827 | |
2828 if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) | |
2829 /* emacs may be exiting */ | |
2830 XFlush (DEVICE_X_DISPLAY (d)); | |
2831 } | |
2832 XtAppProcessEvent (Xt_app_con, XtIMAll); | |
2805 } | 2833 } |
2806 XtAppProcessEvent (Xt_app_con, XtIMAll); | |
2807 } | 2834 } |
2808 } | 2835 } |
2809 | 2836 |
2810 if (!NILP (dispatch_event_queue)) | 2837 if (!NILP (dispatch_event_queue)) |
2811 { | 2838 { |
2862 | 2889 |
2863 static void | 2890 static void |
2864 emacs_Xt_drain_queue (void) | 2891 emacs_Xt_drain_queue (void) |
2865 { | 2892 { |
2866 Lisp_Object devcons, concons; | 2893 Lisp_Object devcons, concons; |
2867 CONSOLE_LOOP (concons) | 2894 if (!in_modal_loop) |
2868 { | 2895 { |
2869 struct console *con = XCONSOLE (XCAR (concons)); | 2896 CONSOLE_LOOP (concons) |
2870 if (!con->input_enabled) | |
2871 continue; | |
2872 | |
2873 CONSOLE_DEVICE_LOOP (devcons, con) | |
2874 { | 2897 { |
2875 struct device *d; | 2898 struct console *con = XCONSOLE (XCAR (concons)); |
2876 Display *display; | 2899 if (!con->input_enabled) |
2877 d = XDEVICE (XCAR (devcons)); | 2900 continue; |
2878 if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) | 2901 |
2902 CONSOLE_DEVICE_LOOP (devcons, con) | |
2879 { | 2903 { |
2880 display = DEVICE_X_DISPLAY (d); | 2904 struct device *d; |
2881 while (XEventsQueued (display, QueuedAfterReading)) | 2905 Display *display; |
2882 XtAppProcessEvent (Xt_app_con, XtIMXEvent); | 2906 d = XDEVICE (XCAR (devcons)); |
2907 if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) | |
2908 { | |
2909 display = DEVICE_X_DISPLAY (d); | |
2910 while (XEventsQueued (display, QueuedAfterReading)) | |
2911 XtAppProcessEvent (Xt_app_con, XtIMXEvent); | |
2912 } | |
2883 } | 2913 } |
2884 } | 2914 } |
2885 } | 2915 /* |
2886 /* | 2916 while (XtAppPending (Xt_app_con) & XtIMXEvent) |
2887 while (XtAppPending (Xt_app_con) & XtIMXEvent) | 2917 XtAppProcessEvent (Xt_app_con, XtIMXEvent); |
2888 XtAppProcessEvent (Xt_app_con, XtIMXEvent); | 2918 */ |
2889 */ | 2919 } |
2890 | 2920 |
2921 #ifdef HAVE_TTY | |
2891 drain_tty_devices (); | 2922 drain_tty_devices (); |
2892 } | |
2893 | |
2894 static int | |
2895 emacs_Xt_event_pending_p (int user_p) | |
2896 { | |
2897 Lisp_Object event; | |
2898 int tick_count_val; | |
2899 | |
2900 /* If `user_p' is false, then this function returns whether there are any | |
2901 X, timeout, or fd events pending (that is, whether emacs_Xt_next_event() | |
2902 would return immediately without blocking). | |
2903 | |
2904 if `user_p' is true, then this function returns whether there are any | |
2905 *user generated* events available (that is, whether there are keyboard | |
2906 or mouse-click events ready to be read). This also implies that | |
2907 emacs_Xt_next_event() would not block. | |
2908 | |
2909 In a non-SIGIO world, this also checks whether the user has typed ^G, | |
2910 since this is a convenient place to do so. We don't need to do this | |
2911 in a SIGIO world, since input causes an interrupt. | |
2912 */ | |
2913 | |
2914 #if 0 | |
2915 /* I don't think there's any point to this and it will nullify | |
2916 the speed gains achieved by the sigio_happened checking below. | |
2917 Its only advantage is that it may possibly make C-g response | |
2918 a bit faster. The C-g will be noticed within 0.25 second, anyway, | |
2919 even without this. */ | |
2920 #ifndef SIGIO | |
2921 /* First check for C-g if necessary */ | |
2922 event_stream_quit_p (); | |
2923 #endif | 2923 #endif |
2924 #endif | |
2925 | |
2926 /* This function used to simply check whether there were any X | |
2927 events (or if user_p was 1, it iterated over all the pending | |
2928 X events using XCheckIfEvent(), looking for keystrokes and | |
2929 button events). That worked in the old cheesoid event loop, | |
2930 which didn't go through XtAppDispatchEvent(), but it doesn't | |
2931 work any more -- X events may not result in anything. For | |
2932 example, a button press in a blank part of the menubar appears | |
2933 as an X event but will not result in any Emacs events (a | |
2934 button press that activates the menubar results in an Emacs | |
2935 event through the stop_next_event mechanism). | |
2936 | |
2937 The only accurate way of determining whether these X events | |
2938 translate into Emacs events is to go ahead and dispatch them | |
2939 until there's something on the dispatch queue. */ | |
2940 | |
2941 /* See if there are any user events already on the queue. */ | |
2942 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
2943 if (!user_p || command_event_p (event)) | |
2944 return 1; | |
2945 | |
2946 /* See if there's any TTY input available. | |
2947 */ | |
2948 if (poll_fds_for_input (tty_only_mask)) | |
2949 return 1; | |
2950 | |
2951 if (!user_p) | |
2952 { | |
2953 /* If not user_p and there are any timer or file-desc events | |
2954 pending, we know there will be an event so we're through. */ | |
2955 XtInputMask pending_value; | |
2956 | |
2957 /* Note that formerly we just checked the value of XtAppPending() | |
2958 to determine if there was file-desc input. This doesn't | |
2959 work any more with the signal_event_pipe; XtAppPending() | |
2960 will says "yes" in this case but there isn't really any | |
2961 input. Another way of fixing this problem is for the | |
2962 signal_event_pipe to generate actual input in the form | |
2963 of an identity eval event or something. (#### maybe this | |
2964 actually happens?) */ | |
2965 | |
2966 if (poll_fds_for_input (process_only_mask)) | |
2967 return 1; | |
2968 | |
2969 pending_value = XtAppPending (Xt_app_con); | |
2970 | |
2971 if (pending_value & XtIMTimer) | |
2972 return 1; | |
2973 } | |
2974 | |
2975 /* XtAppPending() can be super-slow, esp. over a network connection. | |
2976 Quantify results have indicated that in some cases the call to | |
2977 detect_input_pending() completely dominates the running time of | |
2978 redisplay(). Fortunately, in a SIGIO world we can more quickly | |
2979 determine whether there are any X events: if an event has | |
2980 happened since the last time we checked, then a SIGIO will have | |
2981 happened. On a machine with broken SIGIO, we'll still be in an | |
2982 OK state -- quit_check_signal_tick_count will get ticked at least | |
2983 every 1/4 second, so we'll be no more than that much behind | |
2984 reality. (In general it's OK if we erroneously report no input | |
2985 pending when input is actually pending() -- preemption is just a | |
2986 bit less efficient, that's all. It's bad bad bad if you err the | |
2987 other way -- you've promised that `next-event' won't block but it | |
2988 actually will, and some action might get delayed until the next | |
2989 time you hit a key.) | |
2990 */ | |
2991 | |
2992 /* quit_check_signal_tick_count is volatile so try to avoid race conditions | |
2993 by using a temporary variable */ | |
2994 tick_count_val = quit_check_signal_tick_count; | |
2995 if (last_quit_check_signal_tick_count != tick_count_val | |
2996 #if !defined (SIGIO) || defined (CYGWIN) | |
2997 || (XtIMXEvent & XtAppPending (Xt_app_con)) | |
2998 #endif | |
2999 ) | |
3000 { | |
3001 last_quit_check_signal_tick_count = tick_count_val; | |
3002 | |
3003 /* We need to drain the entire queue now -- if we only | |
3004 drain part of it, we may later on end up with events | |
3005 actually pending but detect_input_pending() returning | |
3006 false because there wasn't another SIGIO. */ | |
3007 emacs_Xt_drain_queue (); | |
3008 | |
3009 EVENT_CHAIN_LOOP (event, dispatch_event_queue) | |
3010 if (!user_p || command_event_p (event)) | |
3011 return 1; | |
3012 } | |
3013 | |
3014 return 0; | |
3015 } | 2924 } |
3016 | 2925 |
3017 int | 2926 int |
3018 check_if_pending_expose_event (struct device *dev) | 2927 check_if_pending_expose_event (struct device *dev) |
3019 { | 2928 { |