From 12653a4153bccd5d9a46998753e7a1bc17479505 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Mon, 11 Jan 2010 12:47:59 -0500 Subject: [PATCH] Redraw the focus cycle popup when the list of focusable windows changes, rather than closing it --- openbox/client.c | 3 ++ openbox/client.h | 1 + openbox/focus.c | 12 ++++--- openbox/focus_cycle.c | 82 +++++++++++++++++++++++++++++++++++---------- openbox/focus_cycle.h | 4 ++- openbox/focus_cycle_popup.c | 73 +++++++++++++++++++++++++++++++--------- openbox/focus_cycle_popup.h | 10 ++++-- openbox/screen.c | 6 ++-- 8 files changed, 148 insertions(+), 43 deletions(-) diff --git a/openbox/client.c b/openbox/client.c index e3a7d6e..ae87ff0 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -304,6 +304,7 @@ void client_manage(Window window, ObPrompt *prompt) self->obwin.type = Window_Client; self->window = window; self->prompt = prompt; + self->managed = TRUE; /* non-zero defaults */ self->wmstate = WithdrawnState; /* make sure it gets updated first time */ @@ -633,6 +634,8 @@ void client_unmanage(ObClient *self) mouse_grab_for_client(self, FALSE); + self->managed = FALSE; + /* remove the window from our save set, unless we are managing an internal ObPrompt window */ if (!self->prompt) diff --git a/openbox/client.h b/openbox/client.h index 3b1e042..e5a61d5 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -73,6 +73,7 @@ struct _ObClient { ObWindow obwin; Window window; + gboolean managed; /*! If this client is managing an ObPrompt window, then this is set to the prompt */ diff --git a/openbox/focus.c b/openbox/focus.c index a0e9c66..c82c4f6 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -98,6 +98,9 @@ void focus_set_client(ObClient *client) PROP_SET32(RootWindow(ob_display, ob_screen), net_active_window, window, active); } + + /* make sure the focus cycle popup shows things in the right order */ + focus_cycle_reorder(); } static ObClient* focus_fallback_target(gboolean allow_refocus, @@ -206,16 +209,14 @@ void focus_order_add_new(ObClient *c) focus_order = g_list_insert(focus_order, c, 1); } - /* in the middle of cycling..? kill it. */ - focus_cycle_stop(c); + focus_cycle_add(c); } void focus_order_remove(ObClient *c) { focus_order = g_list_remove(focus_order, c); - /* in the middle of cycling..? kill it. */ - focus_cycle_stop(c); + focus_cycle_remove(c); } void focus_order_to_top(ObClient *c) @@ -293,6 +294,9 @@ gboolean focus_valid_target(ObClient *ft, { gboolean ok = FALSE; + /* see if the window is still managed or is going away */ + if (!ft->managed) return FALSE; + /* it's on this desktop unless you want all desktops. do this check first because it will usually filter out the most diff --git a/openbox/focus_cycle.c b/openbox/focus_cycle.c index 5849d7d..07cc2e8 100644 --- a/openbox/focus_cycle.c +++ b/openbox/focus_cycle.c @@ -31,6 +31,7 @@ #include ObClient *focus_cycle_target = NULL; +static gboolean focus_cycle_directional = FALSE; static gboolean focus_cycle_iconic_windows; static gboolean focus_cycle_all_desktops; static gboolean focus_cycle_dock_windows; @@ -51,26 +52,64 @@ void focus_cycle_shutdown(gboolean reconfig) if (reconfig) return; } -void focus_cycle_stop(ObClient *ifclient) +void focus_cycle_add(ObClient *ifclient) { - /* stop focus cycling if the given client is a valid focus target, - and so the cycling is being disrupted */ - if (focus_cycle_target && ifclient && - /* shortcut check, it is what we are pointing at right now */ - (ifclient == focus_cycle_target || - /* it's shown but it shouldn't be anymore */ - focus_cycle_popup_is_showing(ifclient) || - /* it's not shown but it should be */ - focus_valid_target(ifclient, TRUE, - focus_cycle_iconic_windows, - focus_cycle_all_desktops, - focus_cycle_dock_windows, - focus_cycle_desktop_windows, - FALSE))) - { - focus_cycle(TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,TRUE); - focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE); + if (!(focus_cycle_target && ifclient && !focus_cycle_directional)) + return; + + if (focus_valid_target(ifclient, TRUE, + focus_cycle_iconic_windows, + focus_cycle_all_desktops, + focus_cycle_dock_windows, + focus_cycle_desktop_windows, + FALSE)) + focus_cycle_popup_refresh(focus_cycle_target, + focus_cycle_iconic_windows, + focus_cycle_all_desktops, + focus_cycle_dock_windows, + focus_cycle_desktop_windows); +} + +void focus_cycle_remove(ObClient *ifclient) +{ + if (!(focus_cycle_target && ifclient)) + return; + + if (focus_cycle_directional) { + if (focus_cycle_target == ifclient) { + focus_directional_cycle(0, TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE); + } } + else { + if (!focus_valid_target(ifclient, TRUE, + focus_cycle_iconic_windows, + focus_cycle_all_desktops, + focus_cycle_dock_windows, + focus_cycle_desktop_windows, + FALSE)) { + if (focus_cycle_target == ifclient) { + focus_cycle_target = + focus_cycle_popup_revert(focus_cycle_target); + focus_cycle_update_indicator(focus_cycle_target); + } + focus_cycle_popup_refresh(focus_cycle_target, + focus_cycle_iconic_windows, + focus_cycle_all_desktops, + focus_cycle_dock_windows, + focus_cycle_desktop_windows); + } + } +} + +void focus_cycle_reorder() +{ + if (focus_cycle_target && !focus_cycle_directional) + focus_cycle_popup_refresh(focus_cycle_target, + focus_cycle_iconic_windows, + focus_cycle_all_desktops, + focus_cycle_dock_windows, + focus_cycle_desktop_windows); } ObClient* focus_cycle(gboolean forward, gboolean all_desktops, @@ -87,6 +126,7 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops, if (interactive) { if (cancel) { focus_cycle_target = NULL; + focus_cycle_directional = FALSE; goto done_cycle; } else if (done) goto done_cycle; @@ -134,6 +174,7 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops, if (interactive) { if (ft != focus_cycle_target) { /* prevents flicker */ focus_cycle_target = ft; + focus_cycle_directional = FALSE; focus_cycle_draw_indicator(showbar ? ft : NULL); } if (dialog) @@ -146,6 +187,7 @@ ObClient* focus_cycle(gboolean forward, gboolean all_desktops, return focus_cycle_target; } else if (ft != focus_cycle_target) { focus_cycle_target = ft; + focus_cycle_directional = FALSE; done = TRUE; break; } @@ -156,6 +198,7 @@ done_cycle: if (done && !cancel) ret = focus_cycle_target; focus_cycle_target = NULL; + focus_cycle_directional = FALSE; g_list_free(order); order = NULL; @@ -275,6 +318,7 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows, if (cancel) { focus_cycle_target = NULL; + focus_cycle_directional = FALSE; goto done_cycle; } else if (done && interactive) goto done_cycle; @@ -310,6 +354,7 @@ ObClient* focus_directional_cycle(ObDirection dir, gboolean dock_windows, if (ft && ft != focus_cycle_target) {/* prevents flicker */ focus_cycle_target = ft; + focus_cycle_directional = TRUE; if (!interactive) goto done_cycle; focus_cycle_draw_indicator(showbar ? ft : NULL); @@ -328,6 +373,7 @@ done_cycle: first = NULL; focus_cycle_target = NULL; + focus_cycle_directional = FALSE; focus_cycle_draw_indicator(NULL); focus_cycle_popup_single_hide(); diff --git a/openbox/focus_cycle.h b/openbox/focus_cycle.h index 6e1c2c9..c074a52 100644 --- a/openbox/focus_cycle.h +++ b/openbox/focus_cycle.h @@ -47,6 +47,8 @@ struct _ObClient* focus_directional_cycle(ObDirection dir, gboolean dialog, gboolean done, gboolean cancel); -void focus_cycle_stop(struct _ObClient *ifclient); +void focus_cycle_add(struct _ObClient *ifclient); +void focus_cycle_remove(struct _ObClient *ifclient); +void focus_cycle_reorder(); #endif diff --git a/openbox/focus_cycle_popup.c b/openbox/focus_cycle_popup.c index d01be03..aff8457 100644 --- a/openbox/focus_cycle_popup.c +++ b/openbox/focus_cycle_popup.c @@ -217,6 +217,22 @@ static void popup_setup(ObFocusCyclePopup *p, gboolean create_targets, p->maxtextw = maxwidth; } +static void popup_cleanup(void) +{ + while(popup.targets) { + ObFocusCyclePopupTarget *t = popup.targets->data; + + RrImageUnref(t->icon); + g_free(t->text); + XDestroyWindow(ob_display, t->win); + g_free(t); + + popup.targets = g_list_delete_link(popup.targets, popup.targets); + } + popup.n_targets = 0; + popup.last_target = NULL; +} + static gchar *popup_get_name(ObClient *c) { ObClient *p; @@ -479,18 +495,7 @@ void focus_cycle_popup_hide(void) popup.mapped = FALSE; - while(popup.targets) { - ObFocusCyclePopupTarget *t = popup.targets->data; - - RrImageUnref(t->icon); - g_free(t->text); - XDestroyWindow(ob_display, t->win); - g_free(t); - - popup.targets = g_list_delete_link(popup.targets, popup.targets); - } - popup.n_targets = 0; - popup.last_target = NULL; + popup_cleanup(); g_free(popup.hilite_rgba); popup.hilite_rgba = NULL; @@ -536,7 +541,7 @@ void focus_cycle_popup_single_hide(void) icon_popup_hide(single_popup); } -gboolean focus_cycle_popup_is_showing(ObClient *client) +GList* focus_cycle_popup_is_showing(ObClient *client) { if (popup.mapped) { GList *it; @@ -544,8 +549,46 @@ gboolean focus_cycle_popup_is_showing(ObClient *client) for (it = popup.targets; it; it = g_list_next(it)) { ObFocusCyclePopupTarget *t = it->data; if (t->client == client) - return TRUE; + return it; + } + } + return NULL; +} + +ObClient* focus_cycle_popup_revert(ObClient *target) +{ + GList *it; + + if (!popup.mapped) return NULL; + + for (it = popup.targets; it; it = g_list_next(it)) { + ObFocusCyclePopupTarget *t = it->data; + if (t->client == target) { + if (it->prev) + return ((ObFocusCyclePopupTarget*)it->prev->data)->client; + else if (it->next) + return ((ObFocusCyclePopupTarget*)it->next->data)->client; + else + return NULL; } } - return FALSE; + g_assert_not_reached(); +} + +void focus_cycle_popup_refresh(ObClient *target, + gboolean iconic_windows, + gboolean all_desktops, + gboolean dock_windows, + gboolean desktop_windows) +{ + if (!popup.mapped) return; + + popup_cleanup(); + popup_setup(&popup, TRUE, iconic_windows, all_desktops, + dock_windows, desktop_windows); + + popup.mapped = FALSE; + popup_render(&popup, target); + XFlush(ob_display); + popup.mapped = TRUE; } diff --git a/openbox/focus_cycle_popup.h b/openbox/focus_cycle_popup.h index 19279a6..b4c9e35 100644 --- a/openbox/focus_cycle_popup.h +++ b/openbox/focus_cycle_popup.h @@ -39,7 +39,13 @@ void focus_cycle_popup_single_show(struct _ObClient *c, gboolean desktop_windows); void focus_cycle_popup_single_hide(); -/*! Returns TRUE if the popup is showing the client, otherwise FALSE. */ -gboolean focus_cycle_popup_is_showing(struct _ObClient *client); +/*! Reverts from the current @target to a new focus cycle target window */ +struct _ObClient* focus_cycle_popup_revert(struct _ObClient *target); +/*! Redraws the focus cycle popup */ +void focus_cycle_popup_refresh(struct _ObClient *target, + gboolean iconic_windows, + gboolean all_desktops, + gboolean dock_windows, + gboolean desktop_windows); #endif diff --git a/openbox/screen.c b/openbox/screen.c index d88be43..075d307 100644 --- a/openbox/screen.c +++ b/openbox/screen.c @@ -708,7 +708,8 @@ void screen_set_desktop(guint num, gboolean dofocus) for (it = stacking_list; it; it = g_list_next(it)) { if (WINDOW_IS_CLIENT(it->data)) { ObClient *c = it->data; - client_show(c); + if (client_show(c)) + focus_cycle_add(c); } } @@ -719,8 +720,7 @@ void screen_set_desktop(guint num, gboolean dofocus) if (WINDOW_IS_CLIENT(it->data)) { ObClient *c = it->data; if (client_hide(c)) { - /* in the middle of cycling..? kill it. */ - focus_cycle_stop(c); + focus_cycle_remove(c); if (c == focus_client) { /* c was focused and we didn't do fallback clearly so make -- 1.9.1