/* get all the stuff off the window */
client_get_all(self, TRUE);
+ ob_debug("Window type: %d\n", self->type);
+ ob_debug("Window group: 0x%x\n", self->group?self->group->leader:0);
+
/* specify that if we exit, the window should not be destroyed and
should be reparented back to root automatically */
XChangeSaveSet(ob_display, window, SetModeInsert);
client_search_focus_tree_full(self)) &&
/* this checks for focus=false for the window */
(!settings || settings->focus != 0) &&
- focus_valid_target(self, FALSE, TRUE, FALSE, FALSE))
+ focus_valid_target(self, FALSE, FALSE, TRUE, FALSE, FALSE))
{
activate = TRUE;
}
oldgtran == newgtran &&
oldparent == newparent) return;
- /** Remove the client from the transient tree wherever it has changed **/
-
- /* If the window is becoming a direct transient for a window in its group
- then any group transients which were our children and are now becoming
- our parents need to stop being our children.
+ /** Remove the client from the transient tree **/
- Group transients can't be children of group transients already, but
- we could have any number of direct parents above up, any of which could
- be transient for the group, and we need to remove it from our children.
- */
- if (!oldgtran && oldparent != newparent && newparent != NULL &&
- newgroup != NULL && newgroup == oldgroup &&
- client_normal(newparent))
- {
- ObClient *look = client_search_top_direct_parent(newparent);
- self->transients = g_slist_remove(self->transients, look);
- look->parents = g_slist_remove(look->parents, self);
+ for (it = self->transients; it; it = next) {
+ next = g_slist_next(it);
+ c = it->data;
+ self->transients = g_slist_delete_link(self->transients, it);
+ c->parents = g_slist_remove(c->parents, self);
}
-
-
- /* If the group changed, or if we are just becoming transient for the
- group, then we need to remove any old group transient windows
- from our children. But if we were already transient for the group, then
- other group transients are not our children. */
- if ((oldgroup != newgroup || (newgtran && oldgtran != newgtran)) &&
- oldgroup != NULL && !oldgtran)
- {
- for (it = self->transients; it; it = next) {
- next = g_slist_next(it);
- c = it->data;
- if (c->group == oldgroup && client_normal(self)) {
- self->transients = g_slist_delete_link(self->transients, it);
- c->parents = g_slist_remove(c->parents, self);
- }
- }
+ for (it = self->parents; it; it = next) {
+ next = g_slist_next(it);
+ c = it->data;
+ self->parents = g_slist_delete_link(self->parents, it);
+ c->transients = g_slist_remove(c->transients, self);
}
- /* If we used to be transient for a group and now we are not, or we're
- transient for a new group, then we need to remove ourselves from all
- our ex-parents */
- if (oldgtran && (oldgroup != newgroup || oldgtran != newgtran))
- {
- for (it = self->parents; it; it = next) {
- next = g_slist_next(it);
- c = it->data;
- if (!c->transient_for_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 && 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 **/
- /** Re-add the client to the transient tree wherever it has changed **/
-
- /* If we're now transient for a group and we weren't transient for it
- before then we need to add ourselves to all our new parents */
- if (newgtran && (oldgroup != newgroup || oldgtran != newgtran))
- {
- for (it = oldgroup->members; it; it = g_slist_next(it)) {
+ /* If we're transient for a group then we need to add ourselves to all our
+ parents */
+ if (newgtran) {
+ for (it = newgroup->members; it; it = g_slist_next(it)) {
c = it->data;
- if (c != self && !c->transient_for_group && client_normal(c))
+ if (c != self &&
+ !client_search_top_direct_parent(c)->transient_for_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,
- we need to add ourselves to its children
+
+ /* If we are now transient for a single window we need to add ourselves to
+ its children
WARNING: Cyclical transient ness is possible if two windows are
transient for eachother.
*/
- else if (newparent && newparent != oldparent &&
+ else if (newparent &&
/* don't make ourself its child if it is already our child */
!client_is_direct_child(self, newparent) &&
client_normal(newparent))
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
- other group transients are not our children.
+ /* Add any group transient windows to our children. But if we're transient
+ for the group, then other group transients are not our children.
WARNING: Cyclical transient-ness is possible. For e.g. if:
A is transient for the group
C is transient for B
A can't be transient for C or we have a cycle
*/
- if (oldgroup != newgroup && newgroup != NULL && !newgtran &&
+ if (!newgtran &&
+ (!newparent ||
+ !client_search_top_direct_parent(newparent)->transient_for_group) &&
client_normal(self))
{
for (it = newgroup->members; it; it = g_slist_next(it)) {
}
}
}
+
+ /** If we change our group transient-ness, our children change their
+ effect group transient-ness, which affects how they relate to other
+ group windows **/
+
+ for (it = self->transients; it; it = g_slist_next(it)) {
+ c = it->data;
+ if (!c->transient_for_group)
+ client_update_transient_tree(c, c->group, c->group,
+ c->transient_for_group,
+ c->transient_for_group,
+ client_direct_parent(c),
+ client_direct_parent(c));
+ }
}
static void client_get_mwm_hints(ObClient *self)
return NULL;
}
-#define WANT_EDGE(cur, c) \
- if (cur == c) \
- continue; \
- if (c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL && \
- cur->desktop != screen_desktop) \
- continue; \
- if (cur->iconic) \
- continue;
-
-void client_find_move_directional(ObClient *self, ObDirection dir,
- gint *x, gint *y)
+void client_find_edge_directional(ObClient *self, ObDirection dir,
+ gint my_head, gint my_size,
+ gint my_edge_start, gint my_edge_size,
+ gint *dest, gboolean *near_edge)
{
- gint dest, edge, my_edge_start, my_edge_size, my_pos;
GList *it;
Rect *a, *mon;
-
- *x = self->frame->area.x;
- *y = self->frame->area.y;
+ gint edge;
a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS,
&self->frame->area);
switch(dir) {
case OB_DIRECTION_NORTH:
- case OB_DIRECTION_SOUTH:
- my_edge_start = RECT_LEFT(self->frame->area);
- my_edge_size = self->frame->area.width;
- my_pos = RECT_TOP(self->frame->area);
- break;
- case OB_DIRECTION_EAST:
- case OB_DIRECTION_WEST:
- my_edge_start = RECT_TOP(self->frame->area);
- my_edge_size = self->frame->area.height;
- my_pos = RECT_LEFT(self->frame->area);
- break;
- default:
- g_assert_not_reached();
- }
-
- switch(dir) {
- case OB_DIRECTION_NORTH:
- if (RECT_TOP(self->frame->area) > RECT_TOP(*mon))
- edge = RECT_TOP(*mon);
+ if (my_head >= RECT_TOP(*mon))
+ edge = RECT_TOP(*mon) - 1;
else
- edge = RECT_TOP(*a);
+ edge = RECT_TOP(*a) - 1;
break;
case OB_DIRECTION_SOUTH:
- if (RECT_BOTTOM(self->frame->area) < RECT_BOTTOM(*mon))
- edge = RECT_BOTTOM(*mon) - self->frame->area.height;
+ if (my_head <= RECT_BOTTOM(*mon))
+ edge = RECT_BOTTOM(*mon) + 1;
else
- edge = RECT_BOTTOM(*a) - self->frame->area.height;
+ edge = RECT_BOTTOM(*a) + 1;
break;
case OB_DIRECTION_EAST:
- if (RECT_RIGHT(self->frame->area) < RECT_RIGHT(*mon))
- edge = RECT_RIGHT(*mon) - self->frame->area.width;
+ if (my_head <= RECT_RIGHT(*mon))
+ edge = RECT_RIGHT(*mon) + 1;
else
- edge = RECT_RIGHT(*a) - self->frame->area.width;
+ edge = RECT_RIGHT(*a) + 1;
break;
case OB_DIRECTION_WEST:
- if (RECT_LEFT(self->frame->area) > RECT_LEFT(*mon))
- edge = RECT_LEFT(*mon);
+ if (my_head >= RECT_LEFT(*mon))
+ edge = RECT_LEFT(*mon) - 1;
else
- edge = RECT_LEFT(*a);
+ edge = RECT_LEFT(*a) - 1;
break;
default:
g_assert_not_reached();
}
/* default to the far edge, then narrow it down */
- dest = edge;
+ *dest = edge;
+ *near_edge = TRUE;
- for(it = client_list; it && dest != my_pos; it = g_list_next(it)) {
+ for(it = client_list; it; it = g_list_next(it)) {
ObClient *cur = it->data;
gint edge_start, edge_size, head, tail;
gboolean skip_head = FALSE, skip_tail = FALSE;
- WANT_EDGE(cur, self); /* skip windows to not bump into */
+ /* skip windows to not bump into */
+ if (cur == self)
+ continue;
+ if (cur->iconic)
+ continue;
+ if (self->desktop != cur->desktop && cur->desktop != DESKTOP_ALL &&
+ cur->desktop != screen_desktop)
+ continue;
+
+ ob_debug("trying window %s\n", cur->title);
switch(dir) {
case OB_DIRECTION_NORTH:
switch(dir) {
case OB_DIRECTION_NORTH:
+ head = RECT_BOTTOM(cur->frame->area);
+ tail = RECT_TOP(cur->frame->area);
+ break;
case OB_DIRECTION_SOUTH:
- head = RECT_TOP(cur->frame->area) - self->frame->area.height;
- tail = RECT_BOTTOM(cur->frame->area) + 1;
+ head = RECT_TOP(cur->frame->area);
+ tail = RECT_BOTTOM(cur->frame->area);
break;
case OB_DIRECTION_EAST:
+ head = RECT_LEFT(cur->frame->area);
+ tail = RECT_RIGHT(cur->frame->area);
+ break;
case OB_DIRECTION_WEST:
- head = RECT_LEFT(cur->frame->area) - self->frame->area.width;
- tail = RECT_RIGHT(cur->frame->area) + 1;
+ head = RECT_RIGHT(cur->frame->area);
+ tail = RECT_LEFT(cur->frame->area);
break;
default:
g_assert_not_reached();
switch(dir) {
case OB_DIRECTION_NORTH:
case OB_DIRECTION_WEST:
- if (my_pos <= head)
+ if (my_head <= head + 1)
skip_head = TRUE;
- if (my_pos <= tail)
+ if (my_head + my_size - 1 <= tail)
skip_tail = TRUE;
- if (head < edge)
+ if (head < *dest)
skip_head = TRUE;
- if (tail < edge)
+ if (tail - my_size < *dest)
skip_tail = TRUE;
break;
case OB_DIRECTION_SOUTH:
case OB_DIRECTION_EAST:
- if (my_pos >= head)
+ if (my_head >= head - 1)
skip_head = TRUE;
- if (my_pos >= tail)
+ if (my_head - my_size + 1 >= tail)
skip_tail = TRUE;
- if (head > edge)
+ if (head > *dest)
skip_head = TRUE;
- if (tail > edge)
+ if (tail + my_size > *dest)
skip_tail = TRUE;
break;
default:
g_assert_not_reached();
}
- if (!skip_head)
- dest = head;
- else if (!skip_tail)
- dest = tail;
+ ob_debug("my head %d size %d\n", my_head, my_size);
+ ob_debug("head %d tail %d deest %d\n", head, tail, *dest);
+ if (!skip_head) {
+ ob_debug("using near edge %d\n", head);
+ *dest = head;
+ *near_edge = TRUE;
+ }
+ else if (!skip_tail) {
+ ob_debug("using far edge %d\n", tail);
+ *dest = tail;
+ *near_edge = FALSE;
+ }
}
+}
- switch(dir) {
+void client_find_move_directional(ObClient *self, ObDirection dir,
+ gint *x, gint *y)
+{
+ gint head, size;
+ gint e, e_start, e_size;
+ gboolean near;
+
+ switch (dir) {
+ case OB_DIRECTION_EAST:
+ head = RECT_RIGHT(self->frame->area);
+ size = self->frame->area.width;
+ e_start = RECT_TOP(self->frame->area);
+ e_size = self->frame->area.height;
+ break;
+ case OB_DIRECTION_WEST:
+ head = RECT_LEFT(self->frame->area);
+ size = self->frame->area.width;
+ e_start = RECT_TOP(self->frame->area);
+ e_size = self->frame->area.height;
+ break;
case OB_DIRECTION_NORTH:
+ head = RECT_TOP(self->frame->area);
+ size = self->frame->area.height;
+ e_start = RECT_LEFT(self->frame->area);
+ e_size = self->frame->area.width;
+ break;
case OB_DIRECTION_SOUTH:
- *y = dest;
+ head = RECT_BOTTOM(self->frame->area);
+ size = self->frame->area.height;
+ e_start = RECT_LEFT(self->frame->area);
+ e_size = self->frame->area.width;
break;
- case OB_DIRECTION_WEST:
+ default:
+ g_assert_not_reached();
+ }
+
+ client_find_edge_directional(self, dir, head, size,
+ e_start, e_size, &e, &near);
+ *x = self->frame->area.x;
+ *y = self->frame->area.y;
+ switch (dir) {
case OB_DIRECTION_EAST:
- *x = dest;
+ if (near) e -= self->frame->area.width;
+ else e++;
+ *x = e;
+ break;
+ case OB_DIRECTION_WEST:
+ if (near) e++;
+ else e -= self->frame->area.width;
+ *x = e;
+ break;
+ case OB_DIRECTION_NORTH:
+ if (near) e++;
+ else e -= self->frame->area.height;
+ *y = e;
+ break;
+ case OB_DIRECTION_SOUTH:
+ if (near) e -= self->frame->area.height;
+ else e++;
+ *y = e;
break;
default:
g_assert_not_reached();
}
+ frame_frame_gravity(self->frame, x, y);
+}
- g_free(a);
- g_free(mon);
+void client_find_resize_directional(ObClient *self, ObDirection side,
+ gboolean grow,
+ gint *x, gint *y, gint *w, gint *h)
+{
+ gint head;
+ gint e, e_start, e_size, delta;
+ gboolean near;
+ ObDirection dir;
+ switch (side) {
+ case OB_DIRECTION_EAST:
+ head = RECT_RIGHT(self->frame->area) +
+ (self->size_inc.width - 1) * (grow ? 1 : -1);
+ e_start = RECT_TOP(self->frame->area);
+ e_size = self->frame->area.height;
+ dir = grow ? OB_DIRECTION_EAST : OB_DIRECTION_WEST;
+ break;
+ case OB_DIRECTION_WEST:
+ head = RECT_LEFT(self->frame->area) -
+ (self->size_inc.width - 1) * (grow ? 1 : -1);
+ e_start = RECT_TOP(self->frame->area);
+ e_size = self->frame->area.height;
+ dir = grow ? OB_DIRECTION_WEST : OB_DIRECTION_EAST;
+ break;
+ case OB_DIRECTION_NORTH:
+ head = RECT_TOP(self->frame->area) -
+ (self->size_inc.height - 1) * (grow ? 1 : -1);
+ e_start = RECT_LEFT(self->frame->area);
+ e_size = self->frame->area.width;
+ dir = grow ? OB_DIRECTION_NORTH : OB_DIRECTION_SOUTH;
+ break;
+ case OB_DIRECTION_SOUTH:
+ head = RECT_BOTTOM(self->frame->area) +
+ (self->size_inc.height - 1) * (grow ? 1 : -1);
+ e_start = RECT_LEFT(self->frame->area);
+ e_size = self->frame->area.width;
+ dir = grow ? OB_DIRECTION_SOUTH : OB_DIRECTION_NORTH;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ ob_debug("head %d dir %d\n", head, dir);
+ client_find_edge_directional(self, dir, head, 1,
+ e_start, e_size, &e, &near);
+ ob_debug("edge %d\n", e);
+ *x = self->frame->area.x;
+ *y = self->frame->area.y;
+ *w = self->frame->area.width;
+ *h = self->frame->area.height;
+ switch (side) {
+ case OB_DIRECTION_EAST:
+ if (grow == near) --e;
+ delta = e - RECT_RIGHT(self->frame->area);
+ *w += delta;
+ break;
+ case OB_DIRECTION_WEST:
+ if (grow == near) ++e;
+ delta = RECT_LEFT(self->frame->area) - e;
+ *x -= delta;
+ *w += delta;
+ break;
+ case OB_DIRECTION_NORTH:
+ if (grow == near) ++e;
+ delta = RECT_TOP(self->frame->area) - e;
+ *y -= delta;
+ *h += delta;
+ break;
+ case OB_DIRECTION_SOUTH:
+ if (grow == near) --e;
+ delta = e - RECT_BOTTOM(self->frame->area);
+ *h += delta;
+ break;
+ default:
+ g_assert_not_reached();
+ }
frame_frame_gravity(self->frame, x, y);
+ *w -= self->frame->size.left + self->frame->size.right;
+ *h -= self->frame->size.top + self->frame->size.bottom;
}
ObClient* client_under_pointer()
{
return self->group && self->group->members->next;
}
-
-ObClientIcon *client_thumbnail(ObClient *self, gint wantw, gint wanth)
-{
- ObClientIcon *ret;
- RrPixel32 *data;
- gint w, h;
-
- if (!self->frame->pixmap) return NULL;
- if (!RrPixmapToRGBA(ob_rr_inst, self->frame->pixmap, None, &w, &h, &data))
- return NULL;
-
- /* resize the thumbnail (within aspect ratio) to the given sizes */
-
- ret = g_new(ObClientIcon, 1);
- ret->data = data;
- ret->width = w;
- ret->height = h;
- return ret;
-}
-
-void clienticon_free(ObClientIcon *ci)
-{
- if (ci) {
- g_free(ci->data);
- g_free(ci);
- }
-}