X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=a17f091b317561a3832d7b1613bb1fd13693df77;hb=571b09f999585c66e9781877c94807f663c2bd4c;hp=9bed250612df5beca6f971ce627c4a828903aef6;hpb=c7731ecb8dafc1f2edbfbfba24fb389d173cc47f;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 9bed2506..a17f091b 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -93,6 +93,7 @@ static GSList *client_search_all_top_parents_internal(ObClient *self, ObStackingLayer layer); static void client_call_notifies(ObClient *self, GSList *list); + void client_startup(gboolean reconfig) { if (reconfig) return; @@ -162,37 +163,6 @@ void client_set_list() stacking_set_list(); } -/* - void client_foreach_transient(ObClient *self, ObClientForeachFunc func, gpointer data) - { - GSList *it; - - for (it = self->transients; it; it = g_slist_next(it)) { - if (!func(it->data, data)) return; - client_foreach_transient(it->data, func, data); - } - } - - void client_foreach_ancestor(ObClient *self, ObClientForeachFunc func, gpointer data) - { - if (self->transient_for) { - if (self->transient_for != OB_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 = g_slist_next(it)) - if (it->data != self && - !((ObClient*)it->data)->transient_for) { - if (!func(it->data, data)) return; - client_foreach_ancestor(it->data, func, data); - } - } - } - } -*/ - void client_manage_all() { guint i, j, nchild; @@ -319,7 +289,7 @@ void client_manage(Window window) settings for other uses too. the returned settings is a shallow copy, that needs to be freed with g_free(). */ settings = client_get_settings_state(self); - /* the session should get the last say thought */ + /* the session should get the last say though */ client_restore_session_state(self); /* now we have all of the window's information so we can set this up */ @@ -349,15 +319,19 @@ void client_manage(Window window) client_search_focus_tree_full(self)) && /* this checks for focus=false for the window */ (!settings || settings->focus != 0) && - /* note the check against Type_Normal/Dialog, not client_normal(self), - which would also include other types. in this case we want more - strict rules for focus */ + /* note the check against type Normal/Dialog/Utility, + not client_normal(self), which would also include other types. + in this case we want more strict rules for focus */ (self->type == OB_CLIENT_TYPE_NORMAL || + self->type == OB_CLIENT_TYPE_UTILITY || self->type == OB_CLIENT_TYPE_DIALOG)) { activate = TRUE; } + /* remove the client's border */ + XSetWindowBorderWidth(ob_display, self->window, 0); + /* adjust the frame to the client's size before showing or placing the window */ frame_adjust_area(self->frame, FALSE, TRUE, FALSE); @@ -387,6 +361,8 @@ void client_manage(Window window) "program + user specified" : "BADNESS !?")))), placew, placeh); + /* splash screens are also returned as TRUE for transient, + and so will be forced on screen below */ transient = place_client(self, &placex, &placey, settings); /* make sure the window is visible. */ @@ -400,22 +376,32 @@ void client_manage(Window window) place.c or by the user are allowed partially off-screen and on xinerama divides (ie, it is up to the placement routines to avoid - the xinerama divides) */ - transient || - (!(self->positioned & USPosition) && - client_normal(self) && - !self->session)); + the xinerama divides) + + splash screens get "transient" set to TRUE by + the place_client call + */ + ob_state() == OB_STATE_RUNNING && + (transient || + (!(self->positioned & USPosition) && + client_normal(self) && + !self->session))); } /* if the window isn't user-sized, then make it fit inside the visible screen area on its monitor. Use basically the same rules for forcing the window on screen in the client_find_onscreen call. - do this after place_client, it chooses the monitor! */ - if (transient || - (!(self->sized & USSize) && - client_normal(self) && - !self->session)) + do this after place_client, it chooses the monitor! + + splash screens get "transient" set to TRUE by + the place_client call + */ + if (ob_state() == OB_STATE_RUNNING && + (transient || + (!(self->sized & USSize) && + client_normal(self) && + !self->session))) { /* make a copy to modify */ Rect a = *screen_area_monitor(self->desktop, client_monitor(self)); @@ -426,12 +412,8 @@ void client_manage(Window window) /* fit the window inside the area */ if (placew > a.width || self->area.height > a.height) { - placew = MAX(MIN(MIN(self->area.width, a.width), - self->max_size.width), - self->min_size.width); - placeh = MAX(MIN(MIN(self->area.height, a.height), - self->max_size.height), - self->min_size.height); + placew = MIN(self->area.width, a.width); + placeh = MIN(self->area.height, a.height); ob_debug("setting window size to %dx%d\n", self->area.width, self->area.height); @@ -477,7 +459,8 @@ void client_manage(Window window) "desktop\n"); } /* If something is focused, and it's not our relative... */ - else if (focus_client && client_search_focus_tree_full(self) == NULL) + else if (focus_client && client_search_focus_tree_full(self) == NULL && + client_search_focus_group_full(self) == NULL) { /* If time stamp is old, don't steal focus */ if (self->user_time && last_time && @@ -570,7 +553,7 @@ void client_manage(Window window) g_free(settings); ob_debug("Managed window 0x%lx plate 0x%x (%s)\n", - window, self->frame->plate, self->class); + window, self->frame->window, self->class); return; } @@ -619,9 +602,10 @@ void client_unmanage(ObClient *self) { guint j; GSList *it; + gulong ignore_start; ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n", - self->window, self->frame->plate, + self->window, self->frame->window, self->class, self->title ? self->title : ""); g_assert(self != NULL); @@ -630,13 +614,16 @@ void client_unmanage(ObClient *self) don't generate more events */ XSelectInput(ob_display, self->window, NoEventMask); + /* ignore enter events from the unmap so it doesnt mess with the focus */ + if (!client_focused(self) || !config_focus_under_mouse) + ignore_start = event_start_ignore_all_enters(); + frame_hide(self->frame); /* flush to send the hide to the server quickly */ XFlush(ob_display); - /* ignore enter events from the unmap so it doesnt mess with the - focus */ - event_ignore_all_queued_enters(); + if (!client_focused(self) || !config_focus_under_mouse) + event_end_ignore_all_enters(ignore_start); mouse_grab_for_client(self, FALSE); @@ -665,22 +652,16 @@ void client_unmanage(ObClient *self) client_call_notifies(self, client_destroy_notifies); /* tell our parent(s) that we're gone */ - if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */ - for (it = self->group->members; it; it = g_slist_next(it)) - if (it->data != self) - ((ObClient*)it->data)->transients = - g_slist_remove(((ObClient*)it->data)->transients,self); - } else if (self->transient_for) { /* transient of window */ - self->transient_for->transients = - g_slist_remove(self->transient_for->transients, self); - } + for (it = self->parents; it; it = g_slist_next(it)) + ((ObClient*)it->data)->transients = + g_slist_remove(((ObClient*)it->data)->transients,self); /* tell our transients that we're gone */ for (it = self->transients; it; it = g_slist_next(it)) { - if (((ObClient*)it->data)->transient_for != OB_TRAN_GROUP) { - ((ObClient*)it->data)->transient_for = NULL; - client_calc_layer(it->data); - } + ((ObClient*)it->data)->parents = + g_slist_remove(((ObClient*)it->data)->parents, self); + /* we could be keeping our children in a higher layer */ + client_calc_layer(it->data); } /* remove from its group */ @@ -713,6 +694,9 @@ void client_unmanage(ObClient *self) self->functions = OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_RESIZE; self->decorations = 0; /* unmanaged windows have no decor */ + /* give the client its border back */ + XSetWindowBorderWidth(ob_display, self->window, self->border_width); + client_move_resize(self, a.x, a.y, a.width, a.height); } @@ -1121,35 +1105,30 @@ static void client_get_desktop(ObClient *self) gboolean trdesk = FALSE; if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { - if (self->transient_for->desktop != DESKTOP_ALL) { - self->desktop = self->transient_for->desktop; - trdesk = TRUE; - } - } else { - /* if all the group is on one desktop, then open it on the - same desktop */ - GSList *it; - gboolean first = TRUE; - guint all = screen_num_desktops; /* not a valid value */ - - for (it = self->group->members; it; it = g_slist_next(it)) { - ObClient *c = it->data; - if (c != self) { - if (first) { - all = c->desktop; - first = FALSE; - } - else if (all != c->desktop) - all = screen_num_desktops; /* make it invalid */ - } - } - if (all != screen_num_desktops) { - self->desktop = all; - trdesk = TRUE; + /* if they are all on one desktop, then open it on the + same desktop */ + GSList *it; + gboolean first = TRUE; + guint all = screen_num_desktops; /* not a valid value */ + + for (it = self->parents; it; it = g_slist_next(it)) { + ObClient *c = it->data; + + if (c->desktop == DESKTOP_ALL) continue; + + if (first) { + all = c->desktop; + first = FALSE; } + else if (all != c->desktop) + all = screen_num_desktops; /* make it invalid */ + } + if (all != screen_num_desktops) { + self->desktop = all; + trdesk = TRUE; } } + if (!trdesk) { /* try get from the startup-notification protocol */ if (sn_get_desktop(self->startup_id, &self->desktop)) { @@ -1236,23 +1215,9 @@ void client_update_transient_for(ObClient *self) target = NULL; } - /* THIS IS SO ANNOYING ! ! ! ! Let me explain.... have a seat.. - - Setting the transient_for to Root is actually illegal, however + /* Setting the transient_for to Root is actually illegal, however applications from time have done this to specify transient for - their group. - - Now you can do that by being a TYPE_DIALOG and not setting - the transient_for hint at all on your window. But people still - use Root, and Kwin is very strange in this regard. - - KWin 3.0 will not consider windows with transient_for set to - Root as transient for their group *UNLESS* they are also modal. - In that case, it will make them transient for the group. This - leads to all sorts of weird behavior from KDE apps which are - only tested in KWin. I'd like to follow their behavior just to - make this work right with KDE stuff, but that seems wrong. - */ + their group */ if (!target && self->group) { /* not transient to a client, see if it is transient for a group */ @@ -1300,13 +1265,14 @@ static void client_update_transient_tree(ObClient *self, */ if (oldparent != newparent && newparent != NULL && newparent != OB_TRAN_GROUP && - newgroup != NULL && newgroup == oldgroup) + newgroup != NULL && newgroup == oldgroup && client_normal(newparent)) { ObClient *look = newparent; do { self->transients = g_slist_remove(self->transients, look); + look->parents = g_slist_remove(look->parents, self); look = look->transient_for; - } while (look != NULL && look != OB_TRAN_GROUP); + } while (look != NULL && look != OB_TRAN_GROUP && client_normal(look)); } @@ -1321,8 +1287,10 @@ static void client_update_transient_tree(ObClient *self, for (it = self->transients; it; it = next) { next = g_slist_next(it); c = it->data; - if (c->group == oldgroup) + if (c->group == oldgroup && client_normal(self)) { self->transients = g_slist_delete_link(self->transients, it); + c->parents = g_slist_remove(c->parents, self); + } } } @@ -1332,19 +1300,25 @@ static void client_update_transient_tree(ObClient *self, if (oldparent == OB_TRAN_GROUP && (oldgroup != newgroup || oldparent != newparent)) { - for (it = oldgroup->members; it; it = g_slist_next(it)) { + for (it = self->parents; it; it = next) { + next = g_slist_next(it); c = it->data; - if (c != self && (!c->transient_for || - c->transient_for != OB_TRAN_GROUP)) + if ((!c->transient_for || c->transient_for != OB_TRAN_GROUP) && + client_normal(c)) + { c->transients = g_slist_remove(c->transients, self); + self->parents = g_slist_delete_link(self->parents, it); + } } } /* If we used to be transient for a single window and we are no longer transient for it, then we need to remove ourself from its children */ else if (oldparent != NULL && oldparent != OB_TRAN_GROUP && - oldparent != newparent) + oldparent != newparent && client_normal(oldparent)) + { oldparent->transients = g_slist_remove(oldparent->transients, self); - + self->parents = g_slist_remove(self->parents, oldparent); + } /** Re-add the client to the transient tree wherever it has changed **/ @@ -1355,9 +1329,14 @@ static void client_update_transient_tree(ObClient *self, { for (it = oldgroup->members; it; it = g_slist_next(it)) { c = it->data; - if (c != self && (!c->transient_for || - c->transient_for != OB_TRAN_GROUP)) + if (c != self && + (!c->transient_for || + c->transient_for != OB_TRAN_GROUP) && + client_normal(c)) + { c->transients = g_slist_prepend(c->transients, self); + self->parents = g_slist_prepend(self->parents, c); + } } } /* If we are now transient for a single window which we weren't before, @@ -1369,8 +1348,12 @@ static void client_update_transient_tree(ObClient *self, else if (newparent != NULL && newparent != OB_TRAN_GROUP && newparent != oldparent && /* don't make ourself its child if it is already our child */ - !client_is_direct_child(self, newparent)) + !client_is_direct_child(self, newparent) && + client_normal(newparent)) + { newparent->transients = g_slist_prepend(newparent->transients, self); + self->parents = g_slist_prepend(self->parents, newparent); + } /* If the group changed then we need to add any new group transient windows to our children. But if we're transient for the group, then @@ -1389,9 +1372,11 @@ static void client_update_transient_tree(ObClient *self, c = it->data; if (c != self && c->transient_for == OB_TRAN_GROUP && /* Don't make it our child if it is already our parent */ - !client_is_direct_child(c, self)) + !client_is_direct_child(c, self) && + client_normal(self)) { self->transients = g_slist_prepend(self->transients, c); + c->parents = g_slist_prepend(c->parents, self); } } } @@ -1810,7 +1795,7 @@ void client_reconfigure(ObClient *self) { client_configure(self, self->area.x, self->area.y, self->area.width, self->area.height, - self->border_width, FALSE, TRUE); + FALSE, TRUE); } void client_update_wmhints(ObClient *self) @@ -2297,7 +2282,7 @@ static void client_change_wm_state(ObClient *self) static void client_change_state(ObClient *self) { - gulong netstate[11]; + gulong netstate[12]; guint num; num = 0; @@ -2345,47 +2330,44 @@ ObClient *client_search_focus_tree(ObClient *self) ObClient *client_search_focus_tree_full(ObClient *self) { - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { - return client_search_focus_tree_full(self->transient_for); - } else { - GSList *it; - - for (it = self->group->members; it; it = g_slist_next(it)) { - if (it->data != self) { - ObClient *c = it->data; + if (self->parents) { + GSList *it; - if (client_focused(c)) return c; - if ((c = client_search_focus_tree(it->data))) return c; - } - } + for (it = self->parents; it; it = g_slist_next(it)) { + ObClient *c = it->data; + if ((c = client_search_focus_tree_full(it->data))) return c; } - } - /* 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); + 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); + } } -gboolean client_has_parent(ObClient *self) +ObClient *client_search_focus_group_full(ObClient *self) { - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { - if (client_normal(self->transient_for)) - return TRUE; - } - else if (self->group) { - GSList *it; + GSList *it; - for (it = self->group->members; it; it = g_slist_next(it)) { - if (it->data != self && client_normal(it->data)) - return TRUE; - } + if (self->group) { + for (it = self->group->members; it; it = g_slist_next(it)) { + ObClient *c = it->data; + + if (client_focused(c)) return c; + if ((c = client_search_focus_tree(it->data))) return c; } - } - return FALSE; + } else + if (client_focused(self)) return self; + return NULL; +} + +gboolean client_has_parent(ObClient *self) +{ + return self->parents != NULL; } static ObStackingLayer calc_layer(ObClient *self) @@ -2553,6 +2535,8 @@ static void client_apply_startup_state(ObClient *self, gboolean demands_attention = self->demands_attention; gboolean max_horz = self->max_horz; gboolean max_vert = self->max_vert; + Rect oldarea; + gint l; /* turn them all off in the client, so they won't affect the window being placed */ @@ -2568,10 +2552,12 @@ static void client_apply_startup_state(ObClient *self, do this before applying the states so they have the correct pre-max/pre-fullscreen values */ - client_configure(self, x, y, w, h, self->border_width, FALSE, TRUE); + client_try_configure(self, &x, &y, &w, &h, &l, &l, FALSE); ob_debug("placed window 0x%x at %d, %d with size %d x %d\n", self->window, self->area.x, self->area.y, self->area.width, self->area.height); + oldarea = self->area; /* save the area */ + RECT_SET(self->area, x, y, w, h); /* put where it should be for the premax stuff */ /* apply the states. these are in a carefully crafted order.. */ @@ -2593,6 +2579,12 @@ static void client_apply_startup_state(ObClient *self, else if (max_horz) client_maximize(self, TRUE, 1); + /* if the window hasn't been configured yet, then do so now */ + if (!fullscreen && !max_vert && !max_horz) { + self->area = oldarea; + client_configure(self, x, y, w, h, FALSE, TRUE); + } + /* set the desktop hint, to make sure that it always exists */ PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop); @@ -2818,7 +2810,7 @@ void client_try_configure(ObClient *self, gint *x, gint *y, gint *w, gint *h, } -void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, +void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gboolean user, gboolean final) { gint oldw, oldh; @@ -2838,14 +2830,12 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, SIZE_SET(self->logical_size, logicalw, logicalh); /* figure out if we moved or resized or what */ - moved = x != self->area.x || y != self->area.y; - resized = w != self->area.width || h != self->area.height || - b != self->border_width; + moved = (x != self->area.x || y != self->area.y); + resized = (w != self->area.width || h != self->area.height); oldw = self->area.width; oldh = self->area.height; RECT_SET(self->area, x, y, w, h); - self->border_width = b; /* for app-requested resizes, always resize if 'resized' is true. for user-requested ones, only resize if final is true, or when @@ -2856,16 +2846,9 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, /* if the client is enlarging, then resize the client before the frame */ if (send_resize_client && (w > oldw || h > oldh)) { - XWindowChanges changes; - changes.x = -self->border_width; - changes.y = -self->border_width; - changes.width = MAX(w, oldw); - changes.height = MAX(h, oldh); - changes.border_width = self->border_width; - XConfigureWindow(ob_display, self->window, - CWX|CWY|CWWidth|CWHeight|CWBorderWidth, - &changes); - /* resize the plate to show the client padding color underneath */ + XMoveResizeWindow(ob_display, self->window, + self->frame->size.left, self->frame->size.top, + MAX(w, oldw), MAX(h, oldh)); frame_adjust_client_area(self->frame); } @@ -2884,7 +2867,20 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, if (fmoved || fresized) frame_adjust_area(self->frame, fmoved, fresized, FALSE); - if ((!user || (user && final)) && !resized) + /* This is kinda tricky and should not be changed.. let me explain! + + When user = FALSE, then the request is coming from the application + itself, and we are more strict about when to send a synthetic + ConfigureNotify. We strictly follow the rules of the ICCCM sec 4.1.5 + in this case. + + When user = TRUE, then the request is coming from "us", like when we + maximize a window or sometihng. In this case we are more lenient. We + used to follow the same rules as above, but _Java_ Swing can't handle + this. So just to appease Swing, when user = TRUE, we always send + a synthetic ConfigureNotify to give the window its root coordinates. + */ + if ((!user && !resized) || (user && final)) { XEvent event; @@ -2916,22 +2912,15 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, FALSE, StructureNotifyMask, &event); } - /* if the client is shrinking, then resize the frame before the client */ - if (send_resize_client && (w <= oldw && h <= oldh)) { - /* resize the plate to show the client padding color underneath */ - frame_adjust_client_area(self->frame); + /* if the client is shrinking, then resize the frame before the client. - if (send_resize_client) { - XWindowChanges changes; - changes.x = -self->border_width; - changes.y = -self->border_width; - changes.width = w; - changes.height = h; - changes.border_width = self->border_width; - XConfigureWindow(ob_display, self->window, - CWX|CWY|CWWidth|CWHeight|CWBorderWidth, - &changes); - } + both of these resize sections may run, because the top one only resizes + in the direction that is growing + */ + if (send_resize_client && (w <= oldw || h <= oldh)) { + frame_adjust_client_area(self->frame); + XMoveResizeWindow(ob_display, self->window, + self->frame->size.left, self->frame->size.top, w, h); } XFlush(ob_display); @@ -3052,7 +3041,7 @@ void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk, { if (self->functions & OB_CLIENT_FUNC_ICONIFY || !iconic) { /* move up the transient chain as far as possible first */ - self = client_search_top_normal_parent(self); + self = client_search_top_direct_parent(self); client_iconify_recursive(self, iconic, curdesk, hide_animation); } } @@ -3226,18 +3215,15 @@ void client_set_desktop_recursive(ObClient *self, client_set_desktop_recursive(it->data, target, donthide); } -void client_set_desktop(ObClient *self, guint target, - gboolean donthide) +void client_set_desktop(ObClient *self, guint target, gboolean donthide) { - self = client_search_top_normal_parent(self); + self = client_search_top_direct_parent(self); client_set_desktop_recursive(self, target, donthide); } gboolean client_is_direct_child(ObClient *parent, ObClient *child) { - while (child != parent && - child->transient_for && child->transient_for != OB_TRAN_GROUP) - child = child->transient_for; + while (child != parent && (child = client_direct_parent(child))); return child == parent; } @@ -3496,10 +3482,6 @@ gboolean client_focus(ObClient *self) self = client_focus_target(self); if (!client_can_focus(self)) { - if (!self->frame->visible) { - /* update the focus lists */ - focus_order_to_top(self); - } ob_debug_type(OB_DEBUG_FOCUS, "Client %s can't be focused\n", self->title); return FALSE; @@ -3616,29 +3598,35 @@ void client_activate(ObClient *self, gboolean here, gboolean user) static void client_bring_windows_recursive(ObClient *self, guint desktop, gboolean helpers, - gboolean modals) + gboolean modals, + gboolean iconic) { GSList *it; for (it = self->transients; it; it = g_slist_next(it)) - client_bring_windows_recursive(it->data, desktop, helpers, modals); + client_bring_windows_recursive(it->data, desktop, + helpers, modals, iconic); if (((helpers && client_helper(self)) || - (modals && self->modal))&& - self->desktop != desktop && self->desktop != DESKTOP_ALL) + (modals && self->modal)) && + ((self->desktop != desktop && self->desktop != DESKTOP_ALL) || + (iconic && self->iconic))) { - client_set_desktop(self, desktop, FALSE); + if (iconic && self->iconic) + client_iconify(self, FALSE, TRUE, FALSE); + else + client_set_desktop(self, desktop, FALSE); } } void client_bring_helper_windows(ObClient *self) { - client_bring_windows_recursive(self, self->desktop, TRUE, FALSE); + client_bring_windows_recursive(self, self->desktop, TRUE, FALSE, FALSE); } void client_bring_modal_windows(ObClient *self) { - client_bring_windows_recursive(self, self->desktop, FALSE, TRUE); + client_bring_windows_recursive(self, self->desktop, FALSE, TRUE, TRUE); } gboolean client_focused(ObClient *self) @@ -3653,20 +3641,12 @@ static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h) if (!self->nicons) { ObClientIcon *parent = NULL; + GSList *it; - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) - parent = client_icon_recursive(self->transient_for, w, h); - else { - GSList *it; - for (it = self->group->members; it; it = g_slist_next(it)) { - ObClient *c = it->data; - if (c != self && !c->transient_for) { - if ((parent = client_icon_recursive(c, w, h))) - break; - } - } - } + for (it = self->parents; it; it = g_slist_next(it)) { + ObClient *c = it->data; + if ((parent = client_icon_recursive(c, w, h))) + break; } return parent; @@ -3737,11 +3717,17 @@ guint client_monitor(ObClient *self) return screen_find_monitor(&self->frame->area); } -ObClient *client_search_top_normal_parent(ObClient *self) +ObClient *client_direct_parent(ObClient *self) { - while (self->transient_for && self->transient_for != OB_TRAN_GROUP && - client_normal(self->transient_for)) - self = self->transient_for; + if (!self->parents) return NULL; + if (self->transient_for == OB_TRAN_GROUP) return NULL; + return self->parents->data; +} + +ObClient *client_search_top_direct_parent(ObClient *self) +{ + ObClient *p; + while ((p = client_direct_parent(self))) self = p; return self; } @@ -3749,34 +3735,18 @@ static GSList *client_search_all_top_parents_internal(ObClient *self, gboolean bylayer, ObStackingLayer layer) { - GSList *ret = NULL; + GSList *ret; + ObClient *p; /* move up the direct transient chain as far as possible */ - while (self->transient_for && self->transient_for != OB_TRAN_GROUP && - (!bylayer || self->transient_for->layer == layer) && - client_normal(self->transient_for)) - self = self->transient_for; - - if (!self->transient_for) - ret = g_slist_prepend(ret, self); - else { - GSList *it; - - g_assert(self->group); + while ((p = client_direct_parent(self)) && + (!bylayer || p->layer == layer)) + self = p; - for (it = self->group->members; it; it = g_slist_next(it)) { - ObClient *c = it->data; - - if (!c->transient_for && client_normal(c) && - (!bylayer || c->layer == layer)) - { - ret = g_slist_prepend(ret, c); - } - } - - if (ret == NULL) /* no group parents */ - ret = g_slist_prepend(ret, self); - } + if (!self->parents) + ret = g_slist_prepend(NULL, self); + else + ret = g_slist_copy(self->parents); return ret; } @@ -3793,46 +3763,20 @@ GSList *client_search_all_top_parents_layer(ObClient *self) ObClient *client_search_focus_parent(ObClient *self) { - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { - if (client_focused(self->transient_for)) - return self->transient_for; - } else { - GSList *it; - - for (it = self->group->members; it; it = g_slist_next(it)) { - ObClient *c = it->data; + GSList *it; - /* checking transient_for prevents infinate loops! */ - if (c != self && !c->transient_for) - if (client_focused(c)) - return c; - } - } - } + for (it = self->parents; it; it = g_slist_next(it)) + if (client_focused(it->data)) return it->data; return NULL; } ObClient *client_search_parent(ObClient *self, ObClient *search) { - if (self->transient_for) { - if (self->transient_for != OB_TRAN_GROUP) { - if (self->transient_for == search) - return search; - } else { - GSList *it; - - for (it = self->group->members; it; it = g_slist_next(it)) { - ObClient *c = it->data; + GSList *it; - /* checking transient_for prevents infinate loops! */ - if (c != self && !c->transient_for) - if (c == search) - return search; - } - } - } + for (it = self->parents; it; it = g_slist_next(it)) + if (it->data == search) return search; return NULL; } @@ -3851,13 +3795,12 @@ ObClient *client_search_transient(ObClient *self, ObClient *search) } #define WANT_EDGE(cur, c) \ - if(cur == c) \ - continue; \ - if(!client_normal(cur)) \ + if (cur == c) \ continue; \ - if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \ + if (c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL && \ + cur->desktop != screen_desktop) \ continue; \ - if(cur->iconic) \ + if (cur->iconic) \ continue; #define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \