X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fevent-Xt.c;h=ccfde912b959f3eec9761c3533d4d94359eee82c;hb=515ed47192a2fc212474dc246a875771890e0cbe;hp=b9ef39225ef96e69518c4bfe25088f0ea436861e;hpb=b50fd71ea3c920afc5ba60af567d73940993be3f;p=chise%2Fxemacs-chise.git.1 diff --git a/src/event-Xt.c b/src/event-Xt.c index b9ef392..ccfde91 100644 --- a/src/event-Xt.c +++ b/src/event-Xt.c @@ -67,7 +67,9 @@ Boston, MA 02111-1307, USA. */ #include "events-mod.h" +void enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p); static void handle_focus_event_1 (struct frame *f, int in_p); +static void handle_focus_event_2 (Window w, struct frame *f, int in_p); static struct event_stream *Xt_event_stream; @@ -87,11 +89,12 @@ XtAppContext Xt_app_con; int x_allow_sendevents; #ifdef DEBUG_XEMACS -int debug_x_events; +Fixnum debug_x_events; #endif static int process_events_occurred; static int tty_events_occurred; +static Widget widget_with_focus; /* Mask of bits indicating the descriptors that we wait for input on */ extern SELECT_TYPE input_wait_mask, process_only_mask, tty_only_mask; @@ -309,9 +312,11 @@ maybe_define_x_key_as_self_inserting_character (KeySym keysym, Lisp_Object symbo { extern Lisp_Object Vcurrent_global_map; extern Lisp_Object Qascii_character; - Fput (symbol, Qascii_character, character); - if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil))) - Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command); + if (NILP (Flookup_key (Vcurrent_global_map, symbol, Qnil))) + { + Fput (symbol, Qascii_character, character); + Fdefine_key (Vcurrent_global_map, symbol, Qself_insert_command); + } } } @@ -456,7 +461,14 @@ x_reset_modifier_mapping (struct device *d) xd->lock_interpretation = 0; if (xd->x_modifier_keymap) - XFreeModifiermap (xd->x_modifier_keymap); + { + XFreeModifiermap (xd->x_modifier_keymap); + /* Set it to NULL in case we receive two MappingModifier events in a + row, and the second is processed during some CHECK_QUITs within + x_reset_key_mapping. If that happens, XFreeModifierMap will be + called twice on the same map, and we crash. */ + xd->x_modifier_keymap = NULL; + } x_reset_key_mapping (d); @@ -863,7 +875,7 @@ emacs_Xt_mapping_action (Widget w, XEvent* event) case MappingKeyboard: x_reset_key_mapping (d); break; case MappingModifier: x_reset_modifier_mapping (d); break; case MappingPointer: /* Do something here? */ break; - default: abort(); + default: ABORT(); } } @@ -1535,12 +1547,23 @@ x_event_to_emacs_event (XEvent *x_event, Lisp_Event *emacs_event) static void handle_focus_event_1 (struct frame *f, int in_p) { + handle_focus_event_2 (XtWindow (FRAME_X_TEXT_WIDGET (f)), f, in_p); +} + +static void +handle_focus_event_2 (Window win, struct frame *f, int in_p) +{ + /* Although this treats focus differently for all widgets (including + the frame) it seems to work ok. */ + Widget needs_it = XtWindowToWidget (FRAME_X_DISPLAY (f), win); + #if XtSpecificationRelease > 5 - Widget focus_widget = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f)); + widget_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f)); #endif #ifdef HAVE_XIM XIM_focus_event (f, in_p); #endif /* HAVE_XIM */ + /* On focus change, clear all memory of sticky modifiers to avoid non-intuitive behavior. */ clear_sticky_modifiers (XDEVICE (FRAME_DEVICE (f))); @@ -1564,13 +1587,24 @@ handle_focus_event_1 (struct frame *f, int in_p) click in the frame. Why is this? */ if (in_p #if XtSpecificationRelease > 5 - && FRAME_X_TEXT_WIDGET (f) != focus_widget + && needs_it != widget_with_focus #endif ) { - lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), - FRAME_X_TEXT_WIDGET (f)); + lw_set_keyboard_focus (FRAME_X_SHELL_WIDGET (f), needs_it); } + + /* If we are focusing on a native widget then record and exit. */ + if (needs_it != FRAME_X_TEXT_WIDGET (f)) { + widget_with_focus = needs_it; + return; + } + + /* We have the focus now. See comment in + emacs_Xt_handle_widget_losing_focus (). */ + if (in_p) + widget_with_focus = NULL; + /* do the generic event-stream stuff. */ { Lisp_Object frm; @@ -1587,6 +1621,40 @@ handle_focus_event_1 (struct frame *f, int in_p) } } +/* Create a synthetic X focus event. */ +void +enqueue_focus_event (Widget wants_it, Lisp_Object frame, int in_p) +{ + Lisp_Object emacs_event = Fmake_event (Qnil, Qnil); + Lisp_Event *ev = XEVENT (emacs_event); + XEvent *x_event = &ev->event.magic.underlying_x_event; + + x_event->type = in_p ? FocusIn : FocusOut; + x_event->xfocus.window = XtWindow (wants_it); + + ev->channel = frame; + ev->event_type = magic_event; + + enqueue_Xt_dispatch_event (emacs_event); +} + +/* The idea here is that when a widget glyph gets unmapped we don't + want the focus to stay with it if it has focus - because it may + well just get deleted next and then we have lost the focus until the + user does something. So handle_focus_event_1 records the widget + with keyboard focus when FocusOut is processed, and then, when a + widget gets unmapped, it calls this function to restore focus if + appropriate. */ +void emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget); +void +emacs_Xt_handle_widget_losing_focus (struct frame* f, Widget losing_widget) +{ + if (losing_widget == widget_with_focus) + { + handle_focus_event_1 (f, 1); + } +} + /* This is called from the external-widget code */ void emacs_Xt_handle_focus_event (XEvent *event); @@ -1899,7 +1967,7 @@ emacs_Xt_handle_magic_event (Lisp_Event *emacs_event) if (FRAME_X_EXTERNAL_WINDOW_P (f)) break; #endif - handle_focus_event_1 (f, event->type == FocusIn); + handle_focus_event_2 (event->xfocus.window, f, event->type == FocusIn); break; case ClientMessage: @@ -1948,12 +2016,14 @@ static int timeout_id_tick; /* Xt interval id's might not fit into an int (they're pointers, as it happens), so we need to provide a conversion list. */ +/* pending_timeouts is a set (unordered), implemented as a stack. + completed_timeouts* is a queue. */ static struct Xt_timeout { int id; XtIntervalId interval_id; struct Xt_timeout *next; -} *pending_timeouts, *completed_timeouts; +} *pending_timeouts, *completed_timeouts_head, *completed_timeouts_tail; static struct Xt_timeout_blocktype { @@ -1966,7 +2036,7 @@ Xt_timeout_callback (XtPointer closure, XtIntervalId *id) { struct Xt_timeout *timeout = (struct Xt_timeout *) closure; struct Xt_timeout *t2 = pending_timeouts; - /* Remove this one from the list of pending timeouts */ + /* Remove this one from the set of pending timeouts */ if (t2 == timeout) pending_timeouts = pending_timeouts->next; else @@ -1975,9 +2045,13 @@ Xt_timeout_callback (XtPointer closure, XtIntervalId *id) assert (t2->next); t2->next = t2->next->next; } - /* Add this one to the list of completed timeouts */ - timeout->next = completed_timeouts; - completed_timeouts = timeout; + /* Add this one to the queue of completed timeouts */ + timeout->next = NULL; + if (completed_timeouts_head) + completed_timeouts_tail->next = timeout; + else + completed_timeouts_head = timeout; + completed_timeouts_tail = timeout; } static int @@ -2032,24 +2106,27 @@ emacs_Xt_remove_timeout (int id) XtRemoveTimeOut (timeout->interval_id); } - /* It could be that the Xt call back was already called but we didn't convert - into an Emacs event yet */ - if (!timeout && completed_timeouts) + /* It could be that Xt_timeout_callback was already called but we didn't + convert into an Emacs event yet */ + if (!timeout && completed_timeouts_head) { - /* Code duplication! */ - if (id == completed_timeouts->id) + /* Thank God for code duplication! */ + if (id == completed_timeouts_head->id) { - timeout = completed_timeouts; - completed_timeouts = completed_timeouts->next; + timeout = completed_timeouts_head; + completed_timeouts_head = completed_timeouts_head->next; + /* this may not be necessary? */ + if (!completed_timeouts_head) completed_timeouts_tail = NULL; } else { - t2 = completed_timeouts; + t2 = completed_timeouts_head; while (t2->next && t2->next->id != id) t2 = t2->next; - if ( t2->next) /*found it */ + if (t2->next) /* found it */ { timeout = t2->next; t2->next = t2->next->next; + if (!t2->next) completed_timeouts_tail = t2; } } } @@ -2064,9 +2141,11 @@ emacs_Xt_remove_timeout (int id) static void Xt_timeout_to_emacs_event (Lisp_Event *emacs_event) { - struct Xt_timeout *timeout = completed_timeouts; + struct Xt_timeout *timeout = completed_timeouts_head; assert (timeout); - completed_timeouts = completed_timeouts->next; + completed_timeouts_head = completed_timeouts_head->next; + /* probably unnecessary */ + if (!completed_timeouts_head) completed_timeouts_tail = NULL; emacs_event->event_type = timeout_event; /* timeout events have nil as channel */ emacs_event->timestamp = 0; /* #### wrong!! */ @@ -2308,7 +2387,7 @@ Xt_process_to_emacs_event (Lisp_Event *emacs_event) return; } } - abort (); + ABORT (); } static void @@ -2638,7 +2717,7 @@ emacs_Xt_next_event (Lisp_Event *emacs_event) we_didnt_get_an_event: while (NILP (dispatch_event_queue) && - !completed_timeouts && + !completed_timeouts_head && !fake_event_occurred && !process_events_occurred && !tty_events_occurred) @@ -2692,7 +2771,7 @@ emacs_Xt_next_event (Lisp_Event *emacs_event) if (!Xt_tty_to_emacs_event (emacs_event)) goto we_didnt_get_an_event; } - else if (completed_timeouts) + else if (completed_timeouts_head) Xt_timeout_to_emacs_event (emacs_event); else if (fake_event_occurred) { @@ -2878,8 +2957,47 @@ emacs_Xt_quit_p (void) static void drain_X_queue (void) { + Lisp_Object devcons, concons; + CONSOLE_LOOP (concons) + { + struct console *con = XCONSOLE (XCAR (concons)); + if (!con->input_enabled) + continue; + + /* sjt sez: Have you tried the loop over devices with XtAppPending(), + not XEventsQueued()? + Ben Sigelman sez: No. + sjt sez: I'm guessing that the reason that your patch "works" is this: + + + struct device* d; + + Display* display; + + d = XDEVICE (XCAR (devcons)); + + if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) { + + Ie, if the device goes down, XEmacs detects that and deletes it. + Then the if() fails (DEVICE_X_DISPLAY(d) is NULL), and we don't go + into the Xlib-of-no-return. If you know different, I'd like to hear + about it. ;-) + + These ideas haven't been tested; the code below works for Ben. + */ + CONSOLE_DEVICE_LOOP (devcons, con) + { + struct device* d; + Display* display; + d = XDEVICE (XCAR (devcons)); + if (DEVICE_X_P (d) && DEVICE_X_DISPLAY (d)) { + display = DEVICE_X_DISPLAY (d); + while (XEventsQueued (display, QueuedAfterReading)) + XtAppProcessEvent (Xt_app_con, XtIMXEvent); + } + } + } + /* This is the old code, before Ben Sigelman's patch. */ + /* while (XtAppPending (Xt_app_con) & XtIMXEvent) XtAppProcessEvent (Xt_app_con, XtIMXEvent); + */ } static int @@ -3062,7 +3180,7 @@ XtConvertArgRec Const colorConvertArgs[] = { /* JH: We use this because I think there's a possibility this is called before the device is properly set up, in which case - I don't want to abort. */ + I don't want to ABORT. */ extern struct device *get_device_from_display_1 (Display *dpy); static @@ -3265,7 +3383,7 @@ vars_of_event_Xt (void) dispatch_event_queue = Qnil; staticpro (&dispatch_event_queue); dispatch_event_queue_tail = Qnil; - pdump_wire (&dispatch_event_queue_tail); + dump_add_root_object (&dispatch_event_queue_tail); DEFVAR_BOOL ("x-allow-sendevents", &x_allow_sendevents /* *Non-nil means to allow synthetic events. Nil means they are ignored. @@ -3311,8 +3429,9 @@ void init_event_Xt_late (void) /* called when already initialized */ { timeout_id_tick = 1; - pending_timeouts = 0; - completed_timeouts = 0; + pending_timeouts = NULL; + completed_timeouts_head = NULL; /* queue is empty */ + completed_timeouts_tail = NULL; /* just to be picky */ event_stream = Xt_event_stream;