From db086ef336e01ee23c777f3dc6678568565d44ef Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Mon, 7 Apr 2003 03:46:41 +0000 Subject: [PATCH] put focus_cycle into focus.c, use it there in the action. improved it as well to handle odd cases like modal windows. added functions to client.c which are needed by the focus cycling routine. --- openbox/action.c | 51 ++---------------------------- openbox/client.c | 25 +++++++++++---- openbox/client.h | 8 +++++ openbox/focus.c | 81 +++++++++++++++++++++++++++++++++++++++++------- openbox/focus.h | 8 ++--- 5 files changed, 103 insertions(+), 70 deletions(-) diff --git a/openbox/action.c b/openbox/action.c index cc934206..8196ef67 100644 --- a/openbox/action.c +++ b/openbox/action.c @@ -716,54 +716,7 @@ void action_showmenu(union ActionData *data) void action_cycle_windows(union ActionData *data) { - static Client *first = NULL; - static Client *t = NULL; - static GList *order = NULL; - GList *it, *start, *list; - - if (data->cycle.cancel) { - if (first) client_focus(first); - goto done_cycle; - } - if (!first) first = focus_client; - - if (data->cycle.linear) - list = client_list; - else { - if (!order) order = g_list_copy(focus_order[screen_desktop]); - list = order; - } - start = it = g_list_find(list, data->cycle.c); - if (!start) goto done_cycle; - - if (!data->cycle.final) { - t = NULL; - if (!start) /* switched desktops or something? */ - goto done_cycle; - - do { - if (data->cycle.forward) { - it = it->next; - if (it == NULL) it = list; - } else { - it = it->prev; - if (it == NULL) it = g_list_last(list); - } - if (client_focus(it->data)) { - t = it->data; - focus_ignore_in++; - break; - } - } while (it != start); - } else { - if (t) stacking_raise(t); - goto done_cycle; - } - return; - - done_cycle: - first = NULL; - g_list_free(order); - order = NULL; + focus_cycle(data->cycle.forward, data->cycle.linear, data->cycle.final, + data->cycle.cancel); } diff --git a/openbox/client.c b/openbox/client.c index 36ca352c..1b1fedad 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -1916,20 +1916,32 @@ void client_set_state(Client *self, Atom action, long data1, long data2) client_change_state(self); /* change the hint to relect these changes */ } -gboolean client_focus(Client *self) +Client *client_focus_target(Client *self) { - XEvent ev; Client *child; /* if we have a modal child, then focus it, not us */ child = client_find_modal_child(self); - if (child) - return client_focus(child); + if (child) return child; + return self; +} +gboolean client_focusable(Client *self) +{ /* won't try focus if the client doesn't want it, or if the window isn't visible on the screen */ - if (!(self->frame->visible && - (self->can_focus || self->focus_notify))) + return self->frame->visible && + (self->can_focus || self->focus_notify); +} + +gboolean client_focus(Client *self) +{ + XEvent ev; + + /* choose the correct target */ + self = client_focus_target(self); + + if (!client_focusable(self)) return FALSE; /* do a check to see if the window has already been unmapped or destroyed @@ -1984,6 +1996,7 @@ gboolean client_focus(Client *self) void client_unfocus(Client *self) { g_assert(focus_client == self); + g_message("client_unfocus"); focus_fallback(FALSE); } diff --git a/openbox/client.h b/openbox/client.h index 94bcf38c..89bdb518 100644 --- a/openbox/client.h +++ b/openbox/client.h @@ -410,6 +410,14 @@ void client_set_wm_state(Client *self, long state); */ void client_set_state(Client *self, Atom action, long data1, long data2); +/* Given a Client, find the client that focus would actually be sent to if + you wanted to give focus to the specified Client. Will return the same + Client passed to it or another Client if appropriate. */ +Client *client_focus_target(Client *self); + +/* Returns if a client can be focused or not */ +gboolean client_focusable(Client *self); + /*! Attempt to focus the client window */ gboolean client_focus(Client *self); diff --git a/openbox/focus.c b/openbox/focus.c index 4ff85c5d..ed2c79d6 100644 --- a/openbox/focus.c +++ b/openbox/focus.c @@ -7,6 +7,7 @@ #include "dispatch.h" #include "focus.h" #include "parse.h" +#include "engine.h" #include #include @@ -18,7 +19,8 @@ GList **focus_order = NULL; /* these lists are created when screen_startup Window focus_backup = None; gboolean focus_new = TRUE; gboolean focus_follow = TRUE; -int focus_ignore_in = 0; + +static gboolean noreorder = 0; static void parse_assign(char *name, ParseToken *value) { @@ -79,11 +81,21 @@ void focus_shutdown() event_lasttime); } +static void push_to_top(Client *client) +{ + guint desktop; + + desktop = client->desktop; + if (desktop == DESKTOP_ALL) desktop = screen_desktop; + focus_order[desktop] = g_list_remove(focus_order[desktop], client); + focus_order[desktop] = g_list_prepend(focus_order[desktop], client); + g_message("REORDERING"); +} + void focus_set_client(Client *client) { Window active; Client *old; - guint desktop; /* uninstall the old colormap, and install the new one */ screen_install_colormap(focus_client, FALSE); @@ -100,15 +112,10 @@ void focus_set_client(Client *client) focus_client = client; /* move to the top of the list */ - if (focus_ignore_in) { - g_assert(focus_ignore_in > 0); - --focus_ignore_in; - } else if (client != NULL) { - desktop = client->desktop; - if (desktop == DESKTOP_ALL) desktop = screen_desktop; - focus_order[desktop] = g_list_remove(focus_order[desktop], client); - focus_order[desktop] = g_list_prepend(focus_order[desktop], client); - } + if (noreorder) + --noreorder; + else if (client != NULL) + push_to_top(client); /* set the NET_ACTIVE_WINDOW hint */ active = client ? client->window : None; @@ -171,3 +178,55 @@ void focus_fallback(gboolean switching_desks) focus_set_client(NULL); } } + +void focus_cycle(gboolean forward, gboolean linear, gboolean done, + gboolean cancel) +{ + static Client *first = NULL; + static Client *t = NULL; + static GList *order = NULL; + GList *it, *start, *list; + Client *ft; + + if (cancel) { + if (first) client_focus(first); + goto done_cycle; + } else if (done) { + if (focus_client) { + push_to_top(focus_client); /* move to top of focus_order */ + stacking_raise(focus_client); + } + goto done_cycle; + } + if (!first) first = focus_client; + + if (linear) list = client_list; + else list = focus_order[screen_desktop]; + + start = it = g_list_find(list, focus_client); + if (!start) goto done_cycle; /* switched desktops or something? */ + + do { + if (forward) { + it = it->next; + if (it == NULL) it = list; + } else { + it = it->prev; + if (it == NULL) it = g_list_last(list); + } + ft = client_focus_target(it->data); + if (ft == it->data && focus_client != ft && client_focusable(ft)) { + if (client_focus(ft)) { + noreorder++; /* avoid reordering the focus_order */ + break; + } + } + } while (it != start); + return; + +done_cycle: + t = NULL; + first = NULL; + g_list_free(order); + order = NULL; +} diff --git a/openbox/focus.h b/openbox/focus.h index 976b50df..19e3b363 100644 --- a/openbox/focus.h +++ b/openbox/focus.h @@ -12,10 +12,6 @@ extern Window focus_backup; /*! The client which is currently focused */ extern struct Client *focus_client; -/* The number of FocusIn events which should be ignored for tracking the focus - order */ -extern int focus_ignore_in; - /*! The recent focus order on each desktop */ extern GList **focus_order; @@ -34,4 +30,8 @@ void focus_set_client(struct Client *client); /*! Call this when you need to focus something! */ void focus_fallback(gboolean switching_desks); +/*! Cycle focus amongst windows */ +void focus_cycle(gboolean forward, gboolean linear, gboolean done, + gboolean cancel); + #endif -- 2.44.0