/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
-
+
client.c for the Openbox window manager
Copyright (c) 2006 Mikael Magnusson
Copyright (c) 2003-2007 Dana Jansens
grab_server(FALSE);
return; /* don't manage it */
}
-
+
/* is the window a docking app */
if ((wmhint = XGetWMHints(ob_display, window))) {
if ((wmhint->flags & StateHint) &&
/* 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;
}
*/
ob_state() == OB_STATE_RUNNING &&
(transient ||
- (!(self->positioned & USPosition) &&
+ (!((self->positioned & USPosition) ||
+ (settings && settings->pos_given)) &&
client_normal(self) &&
!self->session)));
}
"(last time %u)\n",
self->window, self->user_time, last_time);
+ if (menu_frame_visible || moveresize_in_progress) {
+ activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because the user is inside "
+ "an Openbox menu or is move/resizing a window and "
+ "we don't want to interrupt them\n");
+ }
+
/* if it's on another desktop */
- if (!(self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
- && /* the timestamp is from before you changed desktops */
+ else if (!(self->desktop == screen_desktop ||
+ self->desktop == DESKTOP_ALL) &&
+ /* the timestamp is from before you changed desktops */
self->user_time && screen_desktop_user_time &&
!event_time_after(self->user_time, screen_desktop_user_time))
{
frame_adjust_area(self->frame, FALSE, TRUE, TRUE);
ob_debug("gave extents left %d right %d top %d bottom %d\n",
- self->frame->size.left, self->frame->size.right,
+ self->frame->size.left, self->frame->size.right,
self->frame->size.top, self->frame->size.bottom);
/* free the ObAppSettings shallow copy */
for (i = 0; i < screen_num_monitors; ++i) {
Rect *a;
- if (!screen_physical_area_monitor_contains(i, &desired))
- continue;
+ if (!screen_physical_area_monitor_contains(i, &desired)) {
+ if (i < screen_num_monitors - 1)
+ continue;
- a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired);
+ /* the window is not inside any monitor! so just use the first
+ one */
+ a = screen_area(self->desktop, 0, NULL);
+ } else
+ a = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR, &desired);
/* This makes sure windows aren't entirely outside of the screen so you
can't see them at all.
if (!self->strut.left && *x + fw*9/10 - 1 < a->x)
*x = a->x - fw*9/10;
if (!self->strut.top && *y + fh*9/10 - 1 < a->y)
- *y = a->y - fw*9/10;
+ *y = a->y - fh*9/10;
}
/* This here doesn't let windows even a pixel outside the
if (self->type == OB_CLIENT_TYPE_DESKTOP)
self->desktop = DESKTOP_ALL;
}
-
+
#ifdef SYNC
client_update_sync_request_counter(self);
#endif
{
XWindowAttributes wattrib;
Status ret;
-
+
ret = XGetWindowAttributes(ob_display, self->window, &wattrib);
g_assert(ret != BadWindow);
self->desktop = screen_num_desktops - 1;
else
self->desktop = d;
- ob_debug("client requested desktop 0x%x\n", self->desktop);
+ ob_debug("client requested desktop 0x%x\n", self->desktop);
} else {
GSList *it;
gboolean first = TRUE;
{
guint32 *state;
guint num;
-
+
if (PROP_GETA32(self->window, net_wm_state, atom, &state, &num)) {
gulong i;
for (i = 0; i < num; ++i) {
self->transient_for_group, trangroup,
client_direct_parent(self), target);
self->transient_for_group = trangroup;
-
+
}
static void client_update_transient_tree(ObClient *self,
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.
-
- 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);
- }
-
-
- /* 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);
- }
- }
- }
+ /** Remove the client from the transient tree **/
- /* 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);
- }
- }
+ 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 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);
+ 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);
}
- /** Re-add the client to the transient tree wherever it has changed **/
+ /** Re-add the client to the transient tree **/
- /* 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)
self->type = -1;
self->transient = FALSE;
-
+
if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
/* use the first value that we know about in the array */
for (i = 0; i < num; ++i) {
if (XGetTransientForHint(ob_display, self->window, &t))
self->transient = TRUE;
-
+
if (self->type == (ObClientType) -1) {
/*the window type hint was not set, which means we either classify
ourself as a normal window or a dialog, depending on if we are a
notified whenever we want it to receive focus */
self->focus_notify = TRUE;
#ifdef SYNC
- else if (proto[i] == prop_atoms.net_wm_sync_request)
+ else if (proto[i] == prop_atoms.net_wm_sync_request)
/* if this protocol is requested, then resizing the
window will be synchronized between the frame and the
client */
if (size.flags & PMinSize)
SIZE_SET(self->min_size, size.min_width, size.min_height);
-
+
if (size.flags & PMaxSize)
SIZE_SET(self->max_size, size.max_width, size.max_height);
-
+
if (size.flags & PBaseSize)
SIZE_SET(self->base_size, size.base_width, size.base_height);
-
+
if (size.flags & PResizeInc && size.width_inc && size.height_inc)
SIZE_SET(self->size_inc, size.width_inc, size.height_inc);
/* assume a window takes input if it doesnt specify */
self->can_focus = TRUE;
-
+
if ((hints = XGetWMHints(ob_display, self->window)) != NULL) {
gboolean ur;
gchar *visible = NULL;
g_free(self->title);
-
+
/* try netwm */
if (!PROP_GETS(self->window, net_wm_name, utf8, &data)) {
/* try old x stuff */
if (!(PROP_GETS(self->window, wm_name, locale, &data)
|| PROP_GETS(self->window, wm_name, utf8, &data))) {
if (self->transient) {
- /*
- GNOME alert windows are not given titles:
- http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
- */
+ /*
+ GNOME alert windows are not given titles:
+ http://developer.gnome.org/projects/gup/hig/draft_hig_new/windows-alert.html
+ */
data = g_strdup("");
} else
data = g_strdup("Unnamed Window");
}
self->icons = g_new(ObClientIcon, self->nicons);
-
+
/* store the icons */
i = 0;
for (j = 0; j < self->nicons; ++j) {
or removes it entirely, it's not very likely it is going to set one
right away afterwards
- if it has parents, then one of them will have an icon already
+ if it has parents, then one of them will have an icon already
*/
if (self->nicons == 0 && !self->parents) {
RrPixel32 *icon = ob_rr_theme->def_win_icon;
return FALSE;
if (self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
return TRUE;
-
+
return FALSE;
}
client_shade(self, TRUE);
if (demands_attention)
client_hilite(self, TRUE);
-
+
if (max_vert && max_horz)
client_maximize(self, TRUE, 0);
else if (max_vert)
/* you cannot resize to nothing */
if (basew + *w < 1) *w = 1 - basew;
if (baseh + *h < 1) *h = 1 - baseh;
-
+
/* save the logical size */
*logicalw = incw > 1 ? *w : *w + basew;
*logicalh = inch > 1 ? *h : *h + baseh;
void client_maximize(ObClient *self, gboolean max, gint dir)
{
gint x, y, w, h;
-
+
g_assert(dir == 0 || dir == 1 || dir == 2);
if (!(self->functions & OB_CLIENT_FUNC_MAXIMIZE)) return; /* can't */
close, we just kill it */
if (!self->delete_window)
client_kill(self);
-
+
/*
XXX: itd be cool to do timeouts and shit here for killing the client's
process off
{
GSList *it;
ObClient *ret;
-
+
for (it = self->transients; it; it = g_slist_next(it)) {
ObClient *c = it->data;
if ((ret = client_search_modal_child(c))) return ret;
gboolean client_validate(ObClient *self)
{
- XEvent e;
+ XEvent e;
XSync(ob_display, FALSE); /* get all events on the server */
void client_set_wm_state(ObClient *self, glong state)
{
if (state == self->wmstate) return; /* no change */
-
+
switch (state) {
case IconicState:
client_iconify(self, TRUE, TRUE, FALSE);
action == prop_atoms.net_wm_state_remove ||
action == prop_atoms.net_wm_state_toggle))
/* an invalid action was passed to the client message, ignore it */
- return;
+ return;
for (i = 0; i < 2; ++i) {
Atom state = i == 0 ? data1 : data2;
-
+
if (!state) continue;
/* if toggling, then pick whether we're adding or removing */
action = undecorated ? prop_atoms.net_wm_state_remove :
prop_atoms.net_wm_state_add;
}
-
+
if (action == prop_atoms.net_wm_state_add) {
if (state == prop_atoms.net_wm_state_modal) {
modal = TRUE;
if ((parent = client_icon_recursive(c, w, h)))
break;
}
-
+
return parent;
}
void client_set_undecorated(ObClient *self, gboolean undecorated)
{
if (self->undecorated != undecorated &&
- /* don't let it undecorate if the function is missing, but let
+ /* don't let it undecorate if the function is missing, but let
it redecorate */
(self->functions & OB_CLIENT_FUNC_UNDECORATE || !undecorated))
{
if (!self->parents) return NULL;
if (self->transient_for_group) return NULL;
return self->parents->data;
-}
+}
ObClient *client_search_top_direct_parent(ObClient *self)
{
{
GSList *ret;
ObClient *p;
-
+
/* move up the direct transient chain as far as possible */
while ((p = client_direct_parent(self)) &&
(!bylayer || p->layer == layer))
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,
{
GList *it;
Rect *a, *mon;
+ Rect dock_area;
gint edge;
a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS,
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);
}
+ dock_get_area(&dock_area);
+ 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,
frame_frame_gravity(self->frame, x, y);
}
+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()
{
gint x, y;
{
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);
- }
-}