+static ObClientIcon* client_icon_recursive(ObClient *self, gint w, gint h)
+{
+ guint i;
+ gulong min_diff, min_i;
+
+ if (!self->nicons) {
+ ObClientIcon *parent = NULL;
+
+ 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;
+ }
+ }
+ }
+ }
+
+ return parent;
+ }
+
+ /* some kind of crappy approximation to find the icon closest in size to
+ what we requested, but icons are generally all the same ratio as
+ eachother so it's good enough. */
+
+ min_diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+ min_i = 0;
+
+ for (i = 1; i < self->nicons; ++i) {
+ gulong diff;
+
+ diff = ABS(self->icons[0].width - w) + ABS(self->icons[0].height - h);
+ if (diff < min_diff) {
+ min_diff = diff;
+ min_i = i;
+ }
+ }
+ return &self->icons[min_i];
+}
+
+const ObClientIcon* client_icon(ObClient *self, gint w, gint h)
+{
+ ObClientIcon *ret;
+ static ObClientIcon deficon;
+
+ if (!(ret = client_icon_recursive(self, w, h))) {
+ deficon.width = deficon.height = 48;
+ deficon.data = ob_rr_theme->def_win_icon;
+ ret = &deficon;
+ }
+ return ret;
+}
+
+void client_set_layer(ObClient *self, gint layer)
+{
+ if (layer < 0) {
+ self->below = TRUE;
+ self->above = FALSE;
+ } else if (layer == 0) {
+ self->below = self->above = FALSE;
+ } else {
+ self->below = FALSE;
+ self->above = TRUE;
+ }
+ client_calc_layer(self);
+ client_change_state(self); /* reflect this in the state hints */
+}
+
+void client_set_undecorated(ObClient *self, gboolean undecorated)
+{
+ if (self->undecorated != undecorated &&
+ /* don't let it undecorate if the function is missing, but let
+ it redecorate */
+ (self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated))
+ {
+ self->undecorated = undecorated;
+ client_setup_decor_and_functions(self);
+ client_reconfigure(self); /* show the lack of decorations */
+ client_change_state(self); /* reflect this in the state hints */
+ }
+}
+
+guint client_monitor(ObClient *self)
+{
+ return screen_find_monitor(&self->frame->area);
+}
+
+ObClient *client_search_top_normal_parent(ObClient *self)
+{
+ while (self->transient_for && self->transient_for != OB_TRAN_GROUP &&
+ client_normal(self->transient_for))
+ self = self->transient_for;
+ return self;
+}
+
+static GSList *client_search_all_top_parents_internal(ObClient *self,
+ gboolean bylayer,
+ ObStackingLayer layer)
+{
+ GSList *ret = NULL;
+
+ /* 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);
+
+ 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);
+ }
+
+ return ret;
+}
+
+GSList *client_search_all_top_parents(ObClient *self)
+{
+ return client_search_all_top_parents_internal(self, FALSE, 0);
+}
+
+GSList *client_search_all_top_parents_layer(ObClient *self)
+{
+ return client_search_all_top_parents_internal(self, TRUE, self->layer);
+}
+
+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;
+
+ /* checking transient_for prevents infinate loops! */
+ if (c != self && !c->transient_for)
+ if (client_focused(c))
+ return c;
+ }
+ }
+ }
+
+ 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;
+
+ /* checking transient_for prevents infinate loops! */
+ if (c != self && !c->transient_for)
+ if (c == search)
+ return search;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+ObClient *client_search_transient(ObClient *self, ObClient *search)
+{
+ GSList *sit;
+
+ for (sit = self->transients; sit; sit = g_slist_next(sit)) {
+ if (sit->data == search)
+ return search;
+ if (client_search_transient(sit->data, search))
+ return search;
+ }
+ return NULL;
+}
+
+#define WANT_EDGE(cur, c) \
+ if(cur == c) \
+ continue; \
+ if(!client_normal(cur)) \
+ continue; \
+ if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \
+ continue; \
+ if(cur->iconic) \
+ continue;
+
+#define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \
+ if ((his_edge_start >= my_edge_start && \
+ his_edge_start <= my_edge_end) || \
+ (my_edge_start >= his_edge_start && \
+ my_edge_start <= his_edge_end)) \
+ dest = his_offset;
+
+/* finds the nearest edge in the given direction from the current client
+ * note to self: the edge is the -frame- edge (the actual one), not the
+ * client edge.
+ */
+gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang)