X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fevent.c;h=9d82a51d2e4364cea03fd0b7d9192f782caf7b9f;hb=242dc35a36b0056029adb4b702ed0b7ffe12feae;hp=6c3d61bbba096ffd6d9d6e1b3f44786e4fe1fb17;hpb=f6ba1f27b9790f56bda1e5831069e2dd7e2c96a2;p=chaz%2Fopenbox diff --git a/openbox/event.c b/openbox/event.c index 6c3d61bb..9d82a51d 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -55,12 +55,9 @@ #include #endif -typedef struct -{ - gboolean ignored; -} ObEventData; - static void event_process(const XEvent *e, gpointer data); +static void event_done(gpointer data); +static void event_client_dest(ObClient *client, gpointer data); static void event_handle_root(XEvent *e); static void event_handle_menu(XEvent *e); static void event_handle_dock(ObDock *s, XEvent *e); @@ -73,14 +70,6 @@ static void focus_delay_client_dest(ObClient *client, gpointer data); static gboolean menu_hide_delay_func(gpointer data); -#define INVALID_FOCUSIN(e) ((e)->xfocus.detail == NotifyInferior || \ - (e)->xfocus.detail == NotifyAncestor || \ - (e)->xfocus.detail > NotifyNonlinearVirtual) -#define INVALID_FOCUSOUT(e) ((e)->xfocus.mode == NotifyGrab || \ - (e)->xfocus.detail == NotifyInferior || \ - (e)->xfocus.detail == NotifyAncestor || \ - (e)->xfocus.detail > NotifyNonlinearVirtual) - Time event_lasttime = 0; /*! The value of the mask for the NumLock modifier */ @@ -100,6 +89,8 @@ static guint ignore_enter_focus = 0; static gboolean menu_can_hide; +static ObClient *focus_in, *focus_out; + #ifdef USE_SM static void ice_handler(int fd, gpointer conn) { @@ -151,13 +142,14 @@ void event_startup(gboolean reconfig) } } - ob_main_loop_x_add(ob_main_loop, event_process, NULL, NULL); + ob_main_loop_x_add(ob_main_loop, event_process, event_done, NULL, NULL); #ifdef USE_SM IceAddConnectionWatch(ice_watch, NULL); #endif client_add_destructor(focus_delay_client_dest, NULL); + client_add_destructor(event_client_dest, NULL); } void event_shutdown(gboolean reconfig) @@ -309,126 +301,53 @@ static gboolean event_ignore(XEvent *e, ObClient *client) return TRUE; break; case FocusIn: - /* NotifyAncestor is not ignored in FocusIn like it is in FocusOut - because of RevertToPointerRoot. If the focus ends up reverting to - pointer root on a workspace change, then the FocusIn event that we - want will be of type NotifyAncestor. This situation does not occur - for FocusOut, so it is safely ignored there. - */ - if (INVALID_FOCUSIN(e) || - client == NULL) { -#ifdef DEBUG_FOCUS - ob_debug("FocusIn on %lx mode %d detail %d IGNORED\n", - e->xfocus.window, e->xfocus.mode, e->xfocus.detail); -#endif - /* says a client was not found for the event (or a valid FocusIn - event was not found. - */ - e->xfocus.window = None; + if (e->xfocus.detail > NotifyNonlinearVirtual) return TRUE; - } - -#ifdef DEBUG_FOCUS - ob_debug("FocusIn on %lx mode %d detail %d\n", e->xfocus.window, - e->xfocus.mode, e->xfocus.detail); -#endif break; case FocusOut: - if (INVALID_FOCUSOUT(e)) { -#ifdef DEBUG_FOCUS - ob_debug("FocusOut on %lx mode %d detail %d IGNORED\n", - e->xfocus.window, e->xfocus.mode, e->xfocus.detail); -#endif + if (e->xfocus.detail > NotifyNonlinearVirtual) return TRUE; - } + if (e->xfocus.detail == NotifyInferior || + e->xfocus.mode == NotifyGrab) + return TRUE; + break; + } + return FALSE; +} -#ifdef DEBUG_FOCUS - ob_debug("FocusOut on %lx mode %d detail %d\n", - e->xfocus.window, e->xfocus.mode, e->xfocus.detail); -#endif +static void event_client_dest(ObClient *client, gpointer data) +{ + if (client == focus_in) + focus_in = NULL; + if (client == focus_out) + focus_out = NULL; +} - { - XEvent fe; - gboolean fallback = TRUE; - - while (TRUE) { - if (!XCheckTypedWindowEvent(ob_display, e->xfocus.window, - FocusOut, &fe)) - if (!XCheckTypedEvent(ob_display, FocusIn, &fe)) - break; - if (fe.type == FocusOut) { -#ifdef DEBUG_FOCUS - ob_debug("found pending FocusOut\n"); -#endif - if (!INVALID_FOCUSOUT(&fe)) { - /* if there is a VALID FocusOut still coming, don't - fallback focus yet, we'll deal with it then */ - XPutBackEvent(ob_display, &fe); - fallback = FALSE; - break; - } - } else { -#ifdef DEBUG_FOCUS - ob_debug("found pending FocusIn\n"); -#endif - /* is the focused window getting a FocusOut/In back to - itself? - */ - if (fe.xfocus.window == e->xfocus.window && - !event_ignore(&fe, client)) { - /* - if focus_client is not set, then we can't do - this. we need the FocusIn. This happens in the - case when the set_focus_client(NULL) in the - focus_fallback function fires and then - focus_fallback picks the currently focused - window (such as on a SendToDesktop-esque action. - */ - if (focus_client) { -#ifdef DEBUG_FOCUS - ob_debug("focused window got an Out/In back to " - "itself IGNORED both\n"); -#endif - return TRUE; - } else { - event_process(&fe, NULL); -#ifdef DEBUG_FOCUS - ob_debug("focused window got an Out/In back to " - "itself but focus_client was null " - "IGNORED just the Out\n"); -#endif - return TRUE; - } - } - - { - ObEventData d; - - /* once all the FocusOut's have been dealt with, if - there is a FocusIn still left and it is valid, then - use it */ - event_process(&fe, &d); - if (!d.ignored) { -#ifdef DEBUG_FOCUS - ob_debug("FocusIn was OK, so don't fallback\n"); -#endif - fallback = FALSE; - break; - } - } - } - } - if (fallback) { -#ifdef DEBUG_FOCUS - ob_debug("no valid FocusIn and no FocusOut events found, " - "falling back\n"); -#endif - focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); - } +static void event_done(gpointer data) +{ + static ObClient *last = NULL; + + if (focus_in) { + if (focus_in != focus_client) { + focus_set_client(focus_in); + frame_adjust_focus(focus_in->frame, TRUE); + client_calc_layer(focus_in); } - break; + } + if (focus_out) { + if (focus_out == focus_client) + focus_set_client(NULL); + frame_adjust_focus(focus_out->frame, FALSE); + client_calc_layer(focus_out); } - return FALSE; + + if (focus_client != last) { + if (!focus_client) + focus_fallback(OB_FOCUS_FALLBACK_NOFOCUS); + last = focus_client; + } + + focus_in = focus_out = NULL; } static void event_process(const XEvent *ec, gpointer data) @@ -440,7 +359,6 @@ static void event_process(const XEvent *ec, gpointer data) ObDockApp *dockapp = NULL; ObWindow *obwin = NULL; XEvent ee, *e; - ObEventData *ed = data; /* make a copy we can mangle */ ee = *ec; @@ -470,30 +388,26 @@ static void event_process(const XEvent *ec, gpointer data) event_set_lasttime(e); event_hack_mods(e); - if (event_ignore(e, client)) { - if (ed) - ed->ignored = TRUE; + if (event_ignore(e, client)) return; - } else if (ed) - ed->ignored = FALSE; /* deal with it in the kernel */ if (group) - event_handle_group(group, e); + event_handle_group(group, e); else if (client) - event_handle_client(client, e); + event_handle_client(client, e); else if (dockapp) - event_handle_dockapp(dockapp, e); + event_handle_dockapp(dockapp, e); else if (dock) - event_handle_dock(dock, e); + event_handle_dock(dock, e); else if (window == RootWindow(ob_display, ob_screen)) - event_handle_root(e); + event_handle_root(e); else if (e->type == MapRequest) - client_manage(window); + client_manage(window); else if (e->type == ConfigureRequest) { - /* unhandled configure requests must be used to configure the - window directly */ - XWindowChanges xwc; + /* unhandled configure requests must be used to configure the + window directly */ + XWindowChanges xwc; xwc.x = e->xconfigurerequest.x; xwc.y = e->xconfigurerequest.y; @@ -617,6 +531,7 @@ void event_enter_client(ObClient *client) config_focus_delay, focus_delay_func, client, NULL); + ob_debug("added focus timeout\n"); } else focus_delay_func(client); } @@ -669,20 +584,22 @@ static void event_handle_client(ObClient *client, XEvent *e) break; case FocusIn: #ifdef DEBUG_FOCUS - ob_debug("FocusIn on client for %lx\n", client->window); + ob_debug("FocusIn on client for %lx (client %lx) mode %d detail %d\n", + e->xfocus.window, client->window, e->xfocus.mode, e->xfocus.detail); #endif - if (client != focus_client) { - focus_set_client(client); - frame_adjust_focus(client->frame, TRUE); - client_calc_layer(client); - } + focus_in = client; + if (focus_out == client) + focus_out = NULL; break; case FocusOut: #ifdef DEBUG_FOCUS - ob_debug("FocusOut on client for %lx\n", client->window); + ob_debug("FocusOut on client for %lx (client %lx) mode %d detail %d\n", + e->xfocus.window, client->window, e->xfocus.mode, e->xfocus.detail); #endif - frame_adjust_focus(client->frame, FALSE); - client_calc_layer(client); + if (focus_in == client) + focus_in = NULL; + if (client == focus_client) + focus_out = client; break; case LeaveNotify: con = frame_context(client, e->xcrossing.window); @@ -763,10 +680,11 @@ static void event_handle_client(ObClient *client, XEvent *e) } else { #ifdef DEBUG_FOCUS ob_debug("%sNotify mode %d detail %d on %lx, " - "focusing window\n", + "focusing window: %d\n", (e->type == EnterNotify ? "Enter" : "Leave"), e->xcrossing.mode, - e->xcrossing.detail, client?client->window:0); + e->xcrossing.detail, (client?client->window:0), + !nofocus); #endif if (!nofocus && config_focus_follow) event_enter_client(client); @@ -1166,14 +1084,25 @@ static void event_handle_dockapp(ObDockApp *app, XEvent *e) ObMenuFrame* find_active_menu() { GList *it; - ObMenuFrame *f; + ObMenuFrame *ret = NULL; for (it = menu_frame_visible; it; it = g_list_next(it)) { - f = it->data; - if (f->selected) + ret = it->data; + if (ret->selected) break; + ret = NULL; } - return it ? it->data : NULL; + return ret; +} + +ObMenuFrame* find_active_or_last_menu() +{ + ObMenuFrame *ret = NULL; + + ret = find_active_menu(); + if (!ret && menu_frame_visible) + ret = menu_frame_visible->data; + return ret; } static void event_handle_menu(XEvent *ev) @@ -1183,11 +1112,13 @@ static void event_handle_menu(XEvent *ev) switch (ev->type) { case ButtonRelease: - if ((e = menu_entry_frame_under(ev->xbutton.x_root, - ev->xbutton.y_root))) - menu_entry_frame_execute(e, ev->xbutton.state); - else if (menu_can_hide) - menu_frame_hide_all(); + if (menu_can_hide) { + if ((e = menu_entry_frame_under(ev->xbutton.x_root, + ev->xbutton.y_root))) + menu_entry_frame_execute(e, ev->xbutton.state); + else + menu_frame_hide_all(); + } break; case MotionNotify: if ((f = menu_frame_under(ev->xmotion.x_root, @@ -1217,19 +1148,19 @@ static void event_handle_menu(XEvent *ev) menu_entry_frame_execute(f->selected, ev->xkey.state); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_LEFT)) { ObMenuFrame *f; - if ((f = find_active_menu()) && f->parent) + if ((f = find_active_or_last_menu()) && f->parent) menu_frame_select(f, NULL); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_RIGHT)) { ObMenuFrame *f; - if ((f = find_active_menu()) && f->child) + if ((f = find_active_or_last_menu()) && f->child) menu_frame_select_next(f->child); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_UP)) { ObMenuFrame *f; - if ((f = find_active_menu())) + if ((f = find_active_or_last_menu())) menu_frame_select_previous(f); } else if (ev->xkey.keycode == ob_keycode(OB_KEY_DOWN)) { ObMenuFrame *f; - if ((f = find_active_menu())) + if ((f = find_active_or_last_menu())) menu_frame_select_next(f); } break; @@ -1246,9 +1177,12 @@ static gboolean focus_delay_func(gpointer data) { ObClient *c = data; - client_focus(c); - if (config_focus_raise) - client_raise(c); + ob_debug("focus timeout %d\n", focus_client != c); + if (focus_client != c) { + client_focus(c); + if (config_focus_raise) + client_raise(c); + } return FALSE; /* no repeat */ } @@ -1268,8 +1202,13 @@ void event_ignore_queued_enters() while (TRUE) { e = g_new(XEvent, 1); if (XCheckTypedEvent(ob_display, EnterNotify, e)) { + ObWindow *win; + + win = g_hash_table_lookup(window_map, &e->xany.window); + if (win && WINDOW_IS_CLIENT(win)) + ++ignore_enter_focus; + saved = g_slist_append(saved, e); - ++ignore_enter_focus; } else { g_free(e); break;