X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=6cd8454b062247b0186765e2b4e728e6e72be55e;hb=58cfbb7f8419e084af6b6b8b00c88ed270c29e88;hp=17172dd99f37fb40b4597f24dad32ac4cbd9f0b2;hpb=04cfdd261dd6b8030cd7618aee5df588f25ef4d2;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 17172dd9..6cd8454b 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -1,5 +1,8 @@ #include "client.h" +#include "slit.h" +#include "startup.h" #include "screen.h" +#include "moveresize.h" #include "prop.h" #include "extensions.h" #include "frame.h" @@ -25,9 +28,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); @@ -39,10 +39,7 @@ static void client_get_gravity(Client *self); static void client_showhide(Client *self); static void client_change_allowed_actions(Client *self); static void client_change_state(Client *self); -static void client_move_onscreen(Client *self); -static Client *search_focus_tree(Client *node, Client *skip); static void client_apply_startup_state(Client *self); -static Client *search_modal_tree(Client *node, Client *skip); static guint map_hash(Window *w) { return *w; } static gboolean map_key_comp(Window *w1, Window *w2) { return *w1 == *w2; } @@ -52,11 +49,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(); } @@ -88,12 +80,44 @@ void client_set_list() stacking_set_list(); } +/* +void client_foreach_transient(Client *self, ClientForeachFunc func, void *data) +{ + GSList *it; + + for (it = self->transients; it; it = it->next) { + if (!func(it->data, data)) return; + client_foreach_transient(it->data, func, data); + } +} + +void client_foreach_ancestor(Client *self, ClientForeachFunc func, void *data) +{ + if (self->transient_for) { + if (self->transient_for != TRAN_GROUP) { + if (!func(self->transient_for, data)) return; + client_foreach_ancestor(self->transient_for, func, data); + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) + if (it->data != self && + ((Client*)it->data)->transient_for != TRAN_GROUP) { + if (!func(it->data, data)) return; + client_foreach_ancestor(it->data, func, data); + } + } + } +} +*/ + void client_manage_all() { unsigned int i, j, nchild; Window w, *children; XWMHints *wmhints; XWindowAttributes attrib; + Client *active; XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild); @@ -129,19 +153,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); + if (c) stacking_lower(CLIENT_AS_WINDOW(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) @@ -150,8 +177,7 @@ void client_manage(Window window) XEvent e; XWindowAttributes attrib; XSetWindowAttributes attrib_set; -/* XWMHints *wmhint; */ - guint i; + XWMHints *wmhint; grab_server(TRUE); @@ -172,18 +198,18 @@ void client_manage(Window window) return; /* don't manage it */ } -/* /\* is the window a docking app *\/ + /* is the window a docking app */ if ((wmhint = XGetWMHints(ob_display, window))) { if ((wmhint->flags & StateHint) && wmhint->initial_state == WithdrawnState) { - /\* XXX: make dock apps work! *\/ + slit_add(window, wmhint); grab_server(FALSE); XFree(wmhint); return; } XFree(wmhint); } -*/ + g_message("Managing window: %lx", window); /* choose the events we want to receive on the CLIENT window */ @@ -196,6 +222,7 @@ void client_manage(Window window) /* create the Client struct, and populate it from the hints on the window */ self = g_new(Client, 1); + self->obwin.type = Window_Client; self->window = window; client_get_all(self); @@ -216,20 +243,14 @@ void client_manage(Window window) grab_server(FALSE); client_list = g_list_append(client_list, self); - stacking_list = g_list_append(stacking_list, self); + stacking_add(self); g_assert(!g_hash_table_lookup(client_map, &self->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); + stacking_raise(CLIENT_AS_WINDOW(self)); screen_update_struts(); @@ -237,26 +258,47 @@ void client_manage(Window window) client_showhide(self); - dispatch_client(Event_Client_Mapped, self, 0, 0); - /* 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) || + client_search_focus_tree(parent)))) { + client_focus(self); + } } /* update the list hints */ @@ -265,6 +307,8 @@ void client_manage(Window window) /* make sure the window is visible */ client_move_onscreen(self); + dispatch_client(Event_Client_Mapped, self, 0, 0); + g_message("Managed window 0x%lx", window); } @@ -276,7 +320,6 @@ void client_unmanage_all() void client_unmanage(Client *self) { - guint i; int j; GSList *it; @@ -294,17 +337,11 @@ void client_unmanage(Client *self) frame_hide(self->frame); client_list = g_list_remove(client_list, self); - stacking_list = g_list_remove(stacking_list, self); + stacking_remove(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 */ @@ -331,8 +368,17 @@ void client_unmanage(Client *self) } } - if (focus_client == self) + if (moveresize_client == self) + moveresize_end(TRUE); + + 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) { @@ -363,6 +409,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 */ @@ -382,7 +429,7 @@ void client_unmanage(Client *self) client_set_list(); } -static void client_move_onscreen(Client *self) +void client_move_onscreen(Client *self) { Rect *a; int x = self->frame->area.x, y = self->frame->area.y; @@ -398,7 +445,7 @@ static void client_move_onscreen(Client *self) y = a->y; frame_frame_gravity(self->frame, &x, &y); /* get where the client - should be */ + should be */ client_configure(self , Corner_TopLeft, x, y, self->area.width, self->area.height, TRUE, TRUE); @@ -479,6 +526,7 @@ static void client_get_all(Client *self) /* defaults */ self->frame = NULL; self->title = self->icon_title = NULL; + self->title_count = 1; self->name = self->class = self->role = NULL; self->wmstate = NormalState; self->transient = FALSE; @@ -492,11 +540,12 @@ static void client_get_all(Client *self) self->nicons = 0; client_get_area(self); + client_update_transient_for(self); + client_update_wmhints(self); client_get_desktop(self); client_get_state(self); client_get_shaped(self); - client_update_transient_for(self); client_get_mwm_hints(self); client_get_type(self);/* this can change the mwmhints for special cases */ @@ -510,9 +559,7 @@ static void client_get_all(Client *self) (min/max sizes), so we're ready to set up the decorations/functions */ client_setup_decor_and_functions(self); - client_update_wmhints(self); client_update_title(self); - client_update_icon_title(self); client_update_class(self); client_update_strut(self); client_update_icons(self); @@ -541,9 +588,28 @@ static void client_get_desktop(Client *self) if (d >= screen_num_desktops && d != DESKTOP_ALL) d = screen_num_desktops - 1; self->desktop = d; - } else { - /* defaults to the current desktop */ - self->desktop = screen_desktop; + } else { + gboolean trdesk = FALSE; + + if (self->transient_for) { + if (self->transient_for != TRAN_GROUP) { + self->desktop = self->transient_for->desktop; + trdesk = TRUE; + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) + if (it->data != self && + ((Client*)it->data)->transient_for != TRAN_GROUP) { + self->desktop = ((Client*)it->data)->desktop; + trdesk = TRUE; + break; + } + } + } + if (!trdesk) + /* defaults to the current desktop */ + self->desktop = screen_desktop; /* set the desktop hint, to make sure that it always exists */ PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop); @@ -612,22 +678,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; @@ -638,7 +706,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 */ @@ -652,9 +721,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 = @@ -730,10 +812,6 @@ void client_get_type(Client *self) else self->type = Type_Normal; } - - /* this makes sure that these windows appear on all desktops */ - if (self->type == Type_Desktop) - self->desktop = DESKTOP_ALL; } void client_update_protocols(Client *self) @@ -939,11 +1017,19 @@ void client_setup_decor_and_functions(Client *self) client_change_allowed_actions(self); if (self->frame) { + /* this makes sure that these windows appear on all desktops */ + if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL) + client_set_desktop(self, DESKTOP_ALL, FALSE); + /* change the decors on the frame, and with more/less decorations, we may also need to be repositioned */ frame_adjust_area(self->frame, TRUE, TRUE); /* with new decor, the window's maximized size may change */ client_remaximize(self); + } else { + /* this makes sure that these windows appear on all desktops */ + if (self->type == Type_Desktop && self->desktop != DESKTOP_ALL) + self->desktop = DESKTOP_ALL; } } @@ -952,7 +1038,9 @@ static void client_change_allowed_actions(Client *self) guint32 actions[9]; int num = 0; - actions[num++] = prop_atoms.net_wm_action_change_desktop; + /* desktop windows are kept on all desktops */ + if (self->type != Type_Desktop) + actions[num++] = prop_atoms.net_wm_action_change_desktop; if (self->functions & Func_Shade) actions[num++] = prop_atoms.net_wm_action_shade; @@ -1102,7 +1190,11 @@ void client_update_wmhints(Client *self) void client_update_title(Client *self) { + GList *it; + guint32 nums; + guint i; char *data = NULL; + gboolean read_title; g_free(self->title); @@ -1113,6 +1205,29 @@ void client_update_title(Client *self) data = g_strdup("Unnamed Window"); /* look for duplicates and append a number */ + nums = 0; + for (it = client_list; it; it = it->next) + if (it->data != self) { + Client *c = it->data; + if (0 == strncmp(c->title, data, strlen(data))) + nums |= 1 << c->title_count; + } + /* find first free number */ + for (i = 1; i <= 32; ++i) + if (!(nums & (1 << i))) { + if (self->title_count == 1 || i == 1) + self->title_count = i; + break; + } + /* dont display the number for the first window */ + if (self->title_count > 1) { + char *vdata, *ndata; + ndata = g_strdup_printf(" - [%u]", self->title_count); + vdata = g_strconcat(data, ndata, NULL); + g_free(ndata); + g_free(data); + data = vdata; + } PROP_SETS(self->window, net_wm_visible_name, data); @@ -1120,19 +1235,29 @@ void client_update_title(Client *self) if (self->frame) frame_adjust_title(self->frame); -} - -void client_update_icon_title(Client *self) -{ - char *data = NULL; + /* update the icon title */ + data = NULL; g_free(self->icon_title); - + + read_title = TRUE; /* try netwm */ if (!PROP_GETS(self->window, net_wm_icon_name, utf8, &data)) /* try old x stuff */ - if (!PROP_GETS(self->window, wm_icon_name, locale, &data)) - data = g_strdup("Unnamed Window"); + if (!PROP_GETS(self->window, wm_icon_name, locale, &data)) { + data = g_strdup(self->title); + read_title = FALSE; + } + + /* append the title count, dont display the number for the first window */ + if (read_title && self->title_count > 1) { + char *vdata, *ndata; + ndata = g_strdup_printf(" - [%u]", self->title_count); + vdata = g_strconcat(data, ndata, NULL); + g_free(ndata); + g_free(data); + data = vdata; + } PROP_SETS(self->window, net_wm_visible_icon_name, data); @@ -1290,40 +1415,84 @@ static void client_change_state(Client *self) frame_adjust_state(self->frame); } -static Client *search_focus_tree(Client *node, Client *skip) +Client *client_search_focus_tree(Client *self) { GSList *it; Client *ret; - for (it = node->transients; it != NULL; it = it->next) { - Client *c = it->data; - if (c == skip) continue; /* circular? */ - if ((ret = search_focus_tree(c, skip))) return ret; - if (client_focused(c)) return c; + for (it = self->transients; it != NULL; it = it->next) { + if (client_focused(it->data)) return it->data; + if ((ret = client_search_focus_tree(it->data))) return ret; } return NULL; } -static void calc_recursive(Client *self, StackLayer l, gboolean raised) +Client *client_search_focus_tree_full(Client *self) +{ + if (self->transient_for) { + if (self->transient_for != TRAN_GROUP) { + return client_search_focus_tree_full(self->transient_for); + } else { + GSList *it; + + for (it = self->group->members; it; it = it->next) + if (((Client*)it->data)->transient_for != TRAN_GROUP) { + Client *c; + if ((c = client_search_focus_tree_full(it->data))) + return c; + } + return NULL; + } + } else { + /* this function checks the whole tree, the client_search_focus_tree + does not, so we need to check this window */ + if (client_focused(self)) + return self; + return client_search_focus_tree(self); + } +} + +static StackLayer calc_layer(Client *self) { - StackLayer old; + StackLayer l; + + if (self->fullscreen) l = Layer_Fullscreen; + else if (self->type == Type_Desktop) l = Layer_Desktop; + else if (self->type == Type_Dock) { + if (!self->below) l = Layer_Top; + else l = Layer_Normal; + } + else if (self->above) l = Layer_Above; + else if (self->below) l = Layer_Below; + else l = Layer_Normal; + + return l; +} + +static void calc_recursive(Client *self, Client *orig, StackLayer l, + gboolean raised) +{ + StackLayer old, own; GSList *it; old = self->layer; - self->layer = l; + own = calc_layer(self); + self->layer = l > own ? l : own; for (it = self->transients; it; it = it->next) - calc_recursive(it->data, l, raised ? raised : l != old); + calc_recursive(it->data, orig, l, raised ? raised : l != old); if (!raised && l != old) - if (self->frame) - stacking_raise(self); + if (orig->frame) /* only restack if the original window is managed */ + stacking_raise(CLIENT_AS_WINDOW(self)); } void client_calc_layer(Client *self) { StackLayer l; - gboolean f; + Client *orig; + + orig = self; /* transients take on the layer of their parents */ if (self->transient_for) { @@ -1341,27 +1510,9 @@ void client_calc_layer(Client *self) } } - /* is us or one of our transients focused? */ - if (client_focused(self)) - f = TRUE; - else if (search_focus_tree(self, self)) - f = TRUE; - else - f = FALSE; + l = calc_layer(self); - if (self->iconic) l = Layer_Icon; - /* fullscreen windows are only in the fullscreen layer while focused */ - else if (self->fullscreen && f) l = Layer_Fullscreen; - else if (self->type == Type_Desktop) l = Layer_Desktop; - else if (self->type == Type_Dock) { - if (!self->below) l = Layer_Top; - else l = Layer_Normal; - } - else if (self->above) l = Layer_Above; - else if (self->below) l = Layer_Below; - else l = Layer_Normal; - - calc_recursive(self, l, FALSE); + calc_recursive(self, orig, l, FALSE); } gboolean client_should_show(Client *self) @@ -1642,31 +1793,30 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk) { GSList *it; - /* move up the transient chain as far as possible first if deiconifying */ - if (!iconic) - while (self->transient_for) { - if (self->transient_for != TRAN_GROUP) { - if (self->transient_for->iconic == iconic) - break; - self = self->transient_for; - } else { - GSList *it; - - /* the check for TRAN_GROUP is to prevent an infinate loop with - 2 transients of the same group at the head of the group's - members list */ - for (it = self->group->members; it; it = it->next) { - Client *c = it->data; + /* move up the transient chain as far as possible first */ + if (self->transient_for) { + if (self->transient_for != TRAN_GROUP) { + if (self->transient_for->iconic != iconic) { + client_iconify(self->transient_for, iconic, curdesk); + return; + } + } else { + GSList *it; - if (c != self && c->transient_for->iconic != iconic && - c->transient_for != TRAN_GROUP) { - self = it->data; - break; - } + /* the check for TRAN_GROUP is to prevent an infinate loop with + 2 transients of the same group at the head of the group's + members list */ + for (it = self->group->members; it; it = it->next) { + Client *c = it->data; + if (c != self && c->iconic != iconic && + c->transient_for != TRAN_GROUP) { + client_iconify(it->data, iconic, curdesk); + break; } - if (it == NULL) break; } + if (it != NULL) return; } + } if (self->iconic == iconic) return; /* nothing to do */ @@ -1681,11 +1831,19 @@ 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 of the + list, put the new iconic window at the 'top of the bottom'. */ + focus_order_to_top(self); } else { if (curdesk) client_set_desktop(self, screen_desktop, FALSE); self->wmstate = self->shaded ? IconicState : NormalState; XMapWindow(ob_display, self->window); + + /* this puts it after the current focused window */ + focus_order_remove(self); + focus_order_add_new(self); } client_change_state(self); client_showhide(self); @@ -1849,7 +2007,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; @@ -1857,6 +2015,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); @@ -1867,51 +2028,31 @@ void client_set_desktop(Client *self, guint target, gboolean donthide) client_showhide(self); /* raise if it was not already on the desktop */ if (old != DESKTOP_ALL) - stacking_raise(self); + stacking_raise(CLIENT_AS_WINDOW(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); } -static Client *search_modal_tree(Client *node, Client *skip) +Client *client_search_modal_child(Client *self) { GSList *it; Client *ret; - for (it = node->transients; it != NULL; it = it->next) { + for (it = self->transients; it != NULL; it = it->next) { Client *c = it->data; - if (c == skip) continue; /* circular? */ - if ((ret = search_modal_tree(c, skip))) return ret; + if ((ret = client_search_modal_child(c))) return ret; if (c->modal) return c; } return NULL; } -Client *client_find_modal_child(Client *self) -{ - return search_modal_tree(self, self); -} - gboolean client_validate(Client *self) { XEvent e; @@ -2070,19 +2211,11 @@ Client *client_focus_target(Client *self) Client *child; /* if we have a modal child, then focus it, not us */ - child = client_find_modal_child(self); + child = client_search_modal_child(self); 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 */ - return self->frame->visible && - (self->can_focus || self->focus_notify); -} - gboolean client_focus(Client *self) { XEvent ev; @@ -2090,7 +2223,16 @@ gboolean client_focus(Client *self) /* choose the correct target */ self = client_focus_target(self); - if (!client_focusable(self)) + if (self->desktop != DESKTOP_ALL && self->desktop != screen_desktop) { + /* update the focus lists */ + focus_order_to_top(self); + return FALSE; + } + + 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 @@ -2112,7 +2254,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, @@ -2134,7 +2276,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, @@ -2148,11 +2292,27 @@ 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); } +void client_activate(Client *self) +{ + if (client_normal(self) && screen_showing_desktop) + screen_show_desktop(FALSE); + if (self->iconic) + client_iconify(self, FALSE, TRUE); + else if (!self->frame->visible) + /* if its not visible for other reasons, then don't mess + with it */ + return; + if (self->shaded) + client_shade(self, FALSE); + client_focus(self); + stacking_raise(CLIENT_AS_WINDOW(self)); +} + gboolean client_focused(Client *self) { return self == focus_client;