X-Git-Url: http://git.chise.org/gitweb/?a=blobdiff_plain;f=src%2Fevent-Xt.c;h=ccfde912b959f3eec9761c3533d4d94359eee82c;hb=506a27d9690049e121fccf1a8947ec57e62055aa;hp=04b54d3680f74aa815b3d64df5a91aeec0957935;hpb=0c693dc08f0794304711787b2eb47c144ea4bef1;p=chise%2Fxemacs-chise.git.1 diff --git a/src/event-Xt.c b/src/event-Xt.c index 04b54d3..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,7 +89,7 @@ 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; @@ -310,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); + } } } @@ -457,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); @@ -864,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(); } } @@ -1536,6 +1547,16 @@ 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_with_focus = XtGetKeyboardFocusWidget (FRAME_X_TEXT_WIDGET (f)); #endif @@ -1566,14 +1587,19 @@ 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) != widget_with_focus + && 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) @@ -1595,9 +1621,26 @@ 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 andthen we have lost the focus until the + 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 @@ -1924,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: @@ -1973,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 { @@ -1991,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 @@ -2000,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 @@ -2057,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; } } } @@ -2089,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!! */ @@ -2333,7 +2387,7 @@ Xt_process_to_emacs_event (Lisp_Event *emacs_event) return; } } - abort (); + ABORT (); } static void @@ -2663,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) @@ -2717,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) { @@ -2903,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 @@ -3087,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 @@ -3336,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;