GList *client_list = NULL;
+extern ObDock *dock;
+
static GSList *client_destroy_notifies = NULL;
static void client_get_all(ObClient *self, gboolean real);
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 && newgroup &&
+ (!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;
}
+static void detect_edge(Rect area, ObDirection dir,
+ gint my_head, gint my_size,
+ gint my_edge_start, gint my_edge_size,
+ gint *dest, gboolean *near_edge)
+{
+ gint edge_start, edge_size, head, tail;
+ gboolean skip_head = FALSE, skip_tail = FALSE;
+
+ switch(dir) {
+ case OB_DIRECTION_NORTH:
+ case OB_DIRECTION_SOUTH:
+ edge_start = area.x;
+ edge_size = area.width;
+ break;
+ case OB_DIRECTION_EAST:
+ case OB_DIRECTION_WEST:
+ edge_start = area.y;
+ edge_size = area.height;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* do we collide with this window? */
+ if (!RANGES_INTERSECT(my_edge_start, my_edge_size,
+ edge_start, edge_size))
+ return;
+
+ switch(dir) {
+ case OB_DIRECTION_NORTH:
+ head = RECT_BOTTOM(area);
+ tail = RECT_TOP(area);
+ break;
+ case OB_DIRECTION_SOUTH:
+ head = RECT_TOP(area);
+ tail = RECT_BOTTOM(area);
+ break;
+ case OB_DIRECTION_EAST:
+ head = RECT_LEFT(area);
+ tail = RECT_RIGHT(area);
+ break;
+ case OB_DIRECTION_WEST:
+ head = RECT_RIGHT(area);
+ tail = RECT_LEFT(area);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ switch(dir) {
+ case OB_DIRECTION_NORTH:
+ case OB_DIRECTION_WEST:
+ if (my_head <= head + 1)
+ skip_head = TRUE;
+ if (my_head + my_size - 1 <= tail)
+ skip_tail = TRUE;
+ if (head < *dest)
+ skip_head = TRUE;
+ if (tail - my_size < *dest)
+ skip_tail = TRUE;
+ break;
+ case OB_DIRECTION_SOUTH:
+ case OB_DIRECTION_EAST:
+ if (my_head >= head - 1)
+ skip_head = TRUE;
+ if (my_head - my_size + 1 >= tail)
+ skip_tail = TRUE;
+ if (head > *dest)
+ skip_head = TRUE;
+ if (tail + my_size > *dest)
+ skip_tail = TRUE;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ 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;
+ }
+
+}
+
void client_find_edge_directional(ObClient *self, ObDirection dir,
gint my_head, gint my_size,
gint my_edge_start, gint my_edge_size,
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;
/* skip windows to not bump into */
if (cur == self)
ob_debug("trying window %s\n", cur->title);
- switch(dir) {
- case OB_DIRECTION_NORTH:
- case OB_DIRECTION_SOUTH:
- edge_start = cur->frame->area.x;
- edge_size = cur->frame->area.width;
- break;
- case OB_DIRECTION_EAST:
- case OB_DIRECTION_WEST:
- edge_start = cur->frame->area.y;
- edge_size = cur->frame->area.height;
- break;
- default:
- g_assert_not_reached();
- }
-
- /* do we collide with this window? */
- if (!RANGES_INTERSECT(my_edge_start, my_edge_size,
- edge_start, edge_size))
- continue;
-
- 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);
- 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_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_head <= head + 1)
- skip_head = TRUE;
- if (my_head + my_size - 1 <= tail + 1)
- skip_tail = TRUE;
- if (head < *dest)
- skip_head = TRUE;
- if (tail - my_size < *dest)
- skip_tail = TRUE;
- break;
- case OB_DIRECTION_SOUTH:
- case OB_DIRECTION_EAST:
- if (my_head >= head - 1)
- skip_head = TRUE;
- if (my_head - my_size + 1 >= tail - 1)
- skip_tail = TRUE;
- if (head > *dest)
- skip_head = TRUE;
- if (tail + my_size > *dest)
- skip_tail = TRUE;
- break;
- default:
- g_assert_not_reached();
- }
-
- 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;
- }
+ detect_edge(cur->frame->area, dir, my_head, my_size, my_edge_start,
+ my_edge_size, dest, near_edge);
}
+ detect_edge(dock->area, dir, my_head, my_size, my_edge_start,
+ my_edge_size, dest, near_edge);
}
void client_find_move_directional(ObClient *self, ObDirection dir,
gboolean grow,
gint *x, gint *y, gint *w, gint *h)
{
- gint head, size;
+ 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);
- size = self->frame->area.width;
+ 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);
- size = self->frame->area.width;
+ 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);
- size = self->frame->area.height;
+ 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);
- size = self->frame->area.height;
+ 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;
g_assert_not_reached();
}
- client_find_edge_directional(self, dir, head, size,
+ 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 (near) --e;
+ if (grow == near) --e;
delta = e - RECT_RIGHT(self->frame->area);
*w += delta;
break;
case OB_DIRECTION_WEST:
- if (near) ++e;
+ if (grow == near) ++e;
delta = RECT_LEFT(self->frame->area) - e;
*x -= delta;
*w += delta;
break;
case OB_DIRECTION_NORTH:
- if (near) ++e;
+ if (grow == near) ++e;
delta = RECT_TOP(self->frame->area) - e;
*y -= delta;
*h += delta;
break;
case OB_DIRECTION_SOUTH:
- if (near) --e;
+ if (grow == near) --e;
delta = e - RECT_BOTTOM(self->frame->area);
*h += delta;
break;
{
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);
- }
-}