X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=6cd8454b062247b0186765e2b4e728e6e72be55e;hb=58cfbb7f8419e084af6b6b8b00c88ed270c29e88;hp=c475fba309054982c873a1942fe258c556a75bbb;hpb=fd89a7eadc4caf62ef5ce4b8ce96216a1b506c5a;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index c475fba3..6cd8454b 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -1,4 +1,5 @@ #include "client.h" +#include "slit.h" #include "startup.h" #include "screen.h" #include "moveresize.h" @@ -38,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; } @@ -82,6 +80,37 @@ 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; @@ -129,7 +158,7 @@ void client_manage_all() 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(startup_stack_order); startup_stack_order = NULL; @@ -137,7 +166,7 @@ void client_manage_all() if (config_focus_new) { active = g_hash_table_lookup(client_map, &startup_active); - if (!active || !client_focus(active)) + if (!(active && client_focus(active))) focus_fallback(Fallback_NoFocus); } } @@ -148,7 +177,7 @@ void client_manage(Window window) XEvent e; XWindowAttributes attrib; XSetWindowAttributes attrib_set; -/* XWMHints *wmhint; */ + XWMHints *wmhint; grab_server(TRUE); @@ -169,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 */ @@ -193,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); @@ -213,14 +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 */ focus_order_add_new(self); - stacking_raise(self); + stacking_raise(CLIENT_AS_WINDOW(self)); screen_update_struts(); @@ -266,7 +296,7 @@ void client_manage(Window window) (!parent && (!self->group || !self->group->members->next)))))) || (parent && (client_focused(parent) || - search_focus_tree(parent, parent)))) { + client_search_focus_tree(parent)))) { client_focus(self); } } @@ -307,7 +337,7 @@ 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 */ @@ -399,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; @@ -415,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); @@ -496,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; @@ -529,7 +560,6 @@ static void client_get_all(Client *self) client_setup_decor_and_functions(self); client_update_title(self); - client_update_icon_title(self); client_update_class(self); client_update_strut(self); client_update_icons(self); @@ -782,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) @@ -991,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; } } @@ -1004,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; @@ -1154,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); @@ -1165,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); @@ -1172,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); @@ -1342,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) { @@ -1393,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) @@ -1694,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 */ @@ -1734,13 +1832,18 @@ void client_iconify(Client *self, gboolean iconic, gboolean curdesk) 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); + /* 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); @@ -1925,7 +2028,7 @@ 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(); /* add to the new desktop(s) */ @@ -1937,25 +2040,19 @@ void client_set_desktop(Client *self, guint target, gboolean donthide) 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; @@ -2114,7 +2211,7 @@ 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; } @@ -2200,6 +2297,22 @@ void client_unfocus(Client *self) 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;