X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=c475fba309054982c873a1942fe258c556a75bbb;hb=02c7f2e8afbfe5ebc589415a87a2ac156c9ef5af;hp=da3a8e323713b3999bd68419f970ad4b74bdf500;hpb=077cd7f94440a5001d62a2df03131a2c33a8c3e2;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index da3a8e32..c475fba3 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -1,4 +1,5 @@ #include "client.h" +#include "startup.h" #include "screen.h" #include "moveresize.h" #include "prop.h" @@ -26,9 +27,6 @@ GList *client_list = NULL; GHashTable *client_map = NULL; -static Window *client_startup_stack_order = NULL; -static guint client_startup_stack_size = 0; - static void client_get_all(Client *self); static void client_toggle_border(Client *self, gboolean show); static void client_get_area(Client *self); @@ -53,11 +51,6 @@ void client_startup() client_map = g_hash_table_new((GHashFunc)map_hash, (GEqualFunc)map_key_comp); - /* save the stacking order on startup! */ - PROP_GETA32(ob_root, net_client_list_stacking, window, - (guint32**)&client_startup_stack_order, - &client_startup_stack_size); - client_set_list(); } @@ -95,6 +88,7 @@ void client_manage_all() Window w, *children; XWMHints *wmhints; XWindowAttributes attrib; + Client *active; XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild); @@ -130,19 +124,22 @@ void client_manage_all() why with stacking_lower? Why, because then windows who aren't in the stacking list are on the top where you can see them instead of buried at the bottom! */ - for (i = client_startup_stack_size; i > 0; --i) { + for (i = startup_stack_size; i > 0; --i) { Client *c; - w = client_startup_stack_order[i-1]; + w = startup_stack_order[i-1]; c = g_hash_table_lookup(client_map, &w); if (c) stacking_lower(c); } - g_free(client_startup_stack_order); - client_startup_stack_order = NULL; - client_startup_stack_size = 0; + g_free(startup_stack_order); + startup_stack_order = NULL; + startup_stack_size = 0; - if (config_focus_new) - focus_fallback(Fallback_NoFocus); + if (config_focus_new) { + active = g_hash_table_lookup(client_map, &startup_active); + if (!active || !client_focus(active)) + focus_fallback(Fallback_NoFocus); + } } void client_manage(Window window) @@ -152,7 +149,6 @@ void client_manage(Window window) XWindowAttributes attrib; XSetWindowAttributes attrib_set; /* XWMHints *wmhint; */ - guint i; grab_server(TRUE); @@ -222,13 +218,7 @@ void client_manage(Window window) g_hash_table_insert(client_map, &self->window, self); /* update the focus lists */ - if (self->desktop == DESKTOP_ALL) { - for (i = 0; i < screen_num_desktops; ++i) - focus_order[i] = g_list_append(focus_order[i], self); - } else { - i = self->desktop; - focus_order[i] = g_list_append(focus_order[i], self); - } + focus_order_add_new(self); stacking_raise(self); @@ -239,23 +229,46 @@ void client_manage(Window window) client_showhide(self); /* focus the new window? */ - if (ob_state != State_Starting && client_normal(self)) { - if (config_focus_new) - client_focus(self); - else if (self->transient_for) { + if (ob_state != State_Starting) { + Client *parent; + gboolean group_foc = FALSE; + + parent = NULL; + + if (self->group) { + GSList *it; + + for (it = self->group->members; it; it = it->next) + if (client_focused(it->data)) { + group_foc = TRUE; + break; + } + } + if (!group_foc && self->transient_for) { if (self->transient_for != TRAN_GROUP) {/* transient of a window */ - if (focus_client == self->transient_for) - client_focus(self); + parent = self->transient_for; } else { /* transient of a group */ GSList *it; for (it = self->group->members; it; it = it->next) - if (focus_client == it->data) { - client_focus(self); - break; - } + if (it->data != self && + ((Client*)it->data)->transient_for != TRAN_GROUP) + parent = it->data; } } + /* note the check against Type_Normal, not client_normal(self), which + would also include dialog types. in this case we want more strict + rules for focus */ + if ((config_focus_new && + (self->type == Type_Normal || + (self->type == Type_Dialog && + (group_foc || + (!parent && (!self->group || + !self->group->members->next)))))) || + (parent && (client_focused(parent) || + search_focus_tree(parent, parent)))) { + client_focus(self); + } } /* update the list hints */ @@ -277,7 +290,6 @@ void client_unmanage_all() void client_unmanage(Client *self) { - guint i; int j; GSList *it; @@ -299,13 +311,7 @@ void client_unmanage(Client *self) g_hash_table_remove(client_map, &self->window); /* update the focus lists */ - if (self->desktop == DESKTOP_ALL) { - for (i = 0; i < screen_num_desktops; ++i) - focus_order[i] = g_list_remove(focus_order[i], self); - } else { - i = self->desktop; - focus_order[i] = g_list_remove(focus_order[i], self); - } + focus_order_remove(self); /* once the client is out of the list, update the struts to remove it's influence */ @@ -335,8 +341,14 @@ void client_unmanage(Client *self) if (moveresize_client == self) moveresize_end(TRUE); - if (focus_client == self) + if (focus_client == self) { + XEvent e; + + /* focus the last focused window on the desktop, and ignore enter + events from the unmap so it doesnt mess with the focus */ + while (XCheckTypedEvent(ob_display, EnterNotify, &e)); client_unfocus(self); + } /* remove from its group */ if (self->group) { @@ -367,6 +379,7 @@ void client_unmanage(Client *self) XMapWindow(ob_display, self->window); } + g_message("Unmanaged window 0x%lx", self->window); /* free all data allocated in the client struct */ @@ -635,22 +648,24 @@ void client_update_transient_for(Client *self) Window t = None; Client *c = NULL; - if (XGetTransientForHint(ob_display, self->window, &t) && - t != self->window) { /* cant be transient to itself! */ + if (XGetTransientForHint(ob_display, self->window, &t)) { self->transient = TRUE; - c = g_hash_table_lookup(client_map, &t); - g_assert(c != self);/* if this happens then we need to check for it*/ - - if (!c && self->group) { - /* not transient to a client, see if it is transient for a - group */ - if (t == self->group->leader || - t == None || - t == ob_root) { - /* window is a transient for its group! */ - c = TRAN_GROUP; - } - } + if (t != self->window) { /* cant be transient to itself! */ + c = g_hash_table_lookup(client_map, &t); + /* if this happens then we need to check for it*/ + g_assert(c != self); + + if (!c && self->group) { + /* not transient to a client, see if it is transient for a + group */ + if (t == self->group->leader || + t == None || + t == ob_root) { + /* window is a transient for its group! */ + c = TRAN_GROUP; + } + } + } } else self->transient = FALSE; @@ -661,7 +676,8 @@ void client_update_transient_for(Client *self) /* remove from old parents */ for (it = self->group->members; it; it = it->next) - if (it->data != self) + if (it->data != self && + (((Client*)it->data)->transient_for != TRAN_GROUP)) ((Client*)it->data)->transients = g_slist_remove(((Client*)it->data)->transients, self); } else if (self->transient_for != NULL) { /* transient of window */ @@ -675,9 +691,22 @@ void client_update_transient_for(Client *self) /* add to new parents */ for (it = self->group->members; it; it = it->next) - if (it->data != self) + if (it->data != self && + (((Client*)it->data)->transient_for != TRAN_GROUP)) ((Client*)it->data)->transients = g_slist_append(((Client*)it->data)->transients, self); + + /* remove all transients which are in the group, that causes + circlular pointer hell of doom */ + for (it = self->group->members; it; it = it->next) { + GSList *sit, *next; + for (sit = self->transients; sit; sit = next) { + next = sit->next; + if (sit->data == it->data) + self->transients = g_slist_remove(self->transients, + sit->data); + } + } } else if (self->transient_for != NULL) { /* transient of window */ /* add to new parent */ self->transient_for->transients = @@ -1704,6 +1733,9 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk) /* we unmap the client itself so that we can get MapRequest events, and because the ICCCM tells us to! */ XUnmapWindow(ob_display, self->window); + + /* update the focus lists.. iconic windows go to the bottom */ + focus_order_to_bottom(self); } else { if (curdesk) client_set_desktop(self, screen_desktop, FALSE); @@ -1872,7 +1904,7 @@ void client_kill(Client *self) void client_set_desktop(Client *self, guint target, gboolean donthide) { - guint old, i; + guint old; if (target == self->desktop) return; @@ -1880,6 +1912,9 @@ void client_set_desktop(Client *self, guint target, gboolean donthide) g_assert(target < screen_num_desktops || target == DESKTOP_ALL); + /* remove from the old desktop(s) */ + focus_order_remove(self); + old = self->desktop; self->desktop = target; PROP_SET32(self->window, net_wm_desktop, cardinal, target); @@ -1893,25 +1928,11 @@ void client_set_desktop(Client *self, guint target, gboolean donthide) stacking_raise(self); screen_update_struts(); - /* update the focus lists */ - if (old == DESKTOP_ALL) { - for (i = 0; i < screen_num_desktops; ++i) - focus_order[i] = g_list_remove(focus_order[i], self); - } else - focus_order[old] = g_list_remove(focus_order[old], self); - if (target == DESKTOP_ALL) { - for (i = 0; i < screen_num_desktops; ++i) { - if (config_focus_new) - focus_order[i] = g_list_prepend(focus_order[i], self); - else - focus_order[i] = g_list_append(focus_order[i], self); - } - } else { - if (config_focus_new) - focus_order[target] = g_list_prepend(focus_order[target], self); - else - focus_order[target] = g_list_append(focus_order[target], self); - } + /* add to the new desktop(s) */ + if (config_focus_new) + focus_order_to_top(self); + else + focus_order_to_bottom(self); dispatch_client(Event_Client_Desktop, self, target, old); } @@ -2098,38 +2119,23 @@ Client *client_focus_target(Client *self) 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 */ - return self->frame->visible && - (self->can_focus || self->focus_notify); -} - gboolean client_focus(Client *self) { XEvent ev; - guint i; /* choose the correct target */ self = client_focus_target(self); if (self->desktop != DESKTOP_ALL && self->desktop != screen_desktop) { /* update the focus lists */ - if (self->desktop == DESKTOP_ALL) { - for (i = 0; i < screen_num_desktops; ++i) { - focus_order[i] = g_list_remove(focus_order[i], self); - focus_order[i] = g_list_prepend(focus_order[i], self); - } - } else { - i = self->desktop; - focus_order[i] = g_list_remove(focus_order[i], self); - focus_order[i] = g_list_prepend(focus_order[i], self); - } + focus_order_to_top(self); return FALSE; } - if (!client_focusable(self)) + if (!((self->can_focus || self->focus_notify) && + (self->desktop == screen_desktop || + self->desktop == DESKTOP_ALL) && + !self->iconic)) return FALSE; /* do a check to see if the window has already been unmapped or destroyed @@ -2151,7 +2157,7 @@ gboolean client_focus(Client *self) } if (self->can_focus) - /* RevertToPointerRoot causes much more headache than TevertToNone, so + /* RevertToPointerRoot causes much more headache than RevertToNone, so I choose to use it always, hopefully to find errors quicker, if any are left. (I hate X. I hate focus events.) */ XSetInputFocus(ob_display, self->window, RevertToPointerRoot, @@ -2173,7 +2179,9 @@ gboolean client_focus(Client *self) } #ifdef DEBUG_FOCUS - g_message("focusing %lx", self->window); + g_message("%sively focusing %lx at %d", (self->can_focus ? "act" : "pass"), + self->window, (int) + event_lasttime); #endif /* Cause the FocusIn to come back to us. Important for desktop switches, @@ -2187,7 +2195,7 @@ void client_unfocus(Client *self) { g_assert(focus_client == self); #ifdef DEBUG_FOCUS - g_message("client_unfocus"); + g_message("client_unfocus for %lx", self->window); #endif focus_fallback(Fallback_Unfocusing); }