static void client_get_gravity(ObClient *self);
static void client_get_client_machine(ObClient *self);
static void client_get_colormap(ObClient *self);
+static void client_get_transientness(ObClient *self);
static void client_change_allowed_actions(ObClient *self);
static void client_change_state(ObClient *self);
static void client_change_wm_state(ObClient *self);
static void client_apply_startup_state(ObClient *self, gint x, gint y);
static void client_restore_session_state(ObClient *self);
-static void client_restore_session_stacking(ObClient *self);
+static gboolean client_restore_session_stacking(ObClient *self);
static ObAppSettings *client_get_settings_state(ObClient *self);
+static void client_update_transient_tree(ObClient *self,
+ ObGroup *oldgroup, ObGroup *newgroup,
+ ObClient* oldparent,
+ ObClient *newparent);
+static void client_present(ObClient *self, gboolean here, gboolean raise);
+static GSList *client_search_all_top_parents_internal(ObClient *self,
+ gboolean bylayer,
+ ObStackingLayer layer);
void client_startup(gboolean reconfig)
{
grab_server(FALSE);
stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
- client_restore_session_stacking(self);
/* focus the new window? */
if (ob_state() != OB_STATE_STARTING &&
+ (!self->session || self->session->focused) &&
!self->iconic &&
/* this means focus=true for window is same as config_focus_new=true */
((config_focus_new || (settings && settings->focus == 1)) ||
*/
ob_debug("placing window 0x%x at %d, %d with size %d x %d\n",
self->window, newx, newy, self->area.width, self->area.height);
+ if (self->session)
+ ob_debug("session requested %d %d\n",
+ self->session->x, self->session->y);
+
client_apply_startup_state(self, newx, newy);
mouse_grab_for_client(self, TRUE);
Also if you don't have focus_new enabled, then it's going to get
raised to the top. Legacy begets legacy I guess?
*/
- client_raise(self);
+ if (!client_restore_session_stacking(self))
+ client_raise(self);
}
/* this has to happen before we try focus the window, but we want it to
a window maps since its not based on an action from the user like
clicking a window to activate it. so keep the new window out of the way
but do focus it. */
- if (activate)
- client_activate(self, FALSE, TRUE);
+ if (activate) {
+ gboolean stacked = client_restore_session_stacking(self);
+ client_present(self, FALSE, !stacked);
+ }
/* add to client list/map */
client_list = g_list_append(client_list, self);
g_free(self->icons[j].data);
if (self->nicons > 0)
g_free(self->icons);
+ g_free(self->wm_command);
g_free(self->title);
g_free(self->icon_title);
g_free(self->name);
{
GList *it;
- if (!(it = session_state_find(self)))
+ ob_debug_type(OB_DEBUG_SM,
+ "Restore session for client %s\n", self->title);
+
+ if (!(it = session_state_find(self))) {
+ ob_debug_type(OB_DEBUG_SM,
+ "Session data not found for client %s\n", self->title);
return;
+ }
self->session = it->data;
+ ob_debug_type(OB_DEBUG_SM, "Session data loaded for client %s\n",
+ self->title);
+
RECT_SET_POINT(self->area, self->session->x, self->session->y);
- self->positioned = PPosition;
+ self->positioned = USPosition;
if (self->session->w > 0)
self->area.width = self->session->w;
if (self->session->h > 0)
self->below = self->session->below;
self->max_horz = self->session->max_horz;
self->max_vert = self->session->max_vert;
+ self->undecorated = self->session->undecorated;
}
-static void client_restore_session_stacking(ObClient *self)
+static gboolean client_restore_session_stacking(ObClient *self)
{
- GList *it;
+ GList *it, *mypos;
- if (!self->session) return;
+ if (!self->session) return FALSE;
- it = g_list_find(session_saved_state, self->session);
- for (it = g_list_previous(it); it; it = g_list_previous(it)) {
+ mypos = g_list_find(session_saved_state, self->session);
+ if (!mypos) return FALSE;
+
+ /* start above me and look for the first client */
+ for (it = g_list_previous(mypos); it; it = g_list_previous(it)) {
GList *cit;
- for (cit = client_list; cit; cit = g_list_next(cit))
- if (session_state_cmp(it->data, cit->data))
- break;
- if (cit) {
- client_calc_layer(self);
- stacking_below(CLIENT_AS_WINDOW(self),
- CLIENT_AS_WINDOW(cit->data));
- break;
+ for (cit = client_list; cit; cit = g_list_next(cit)) {
+ ObClient *c = cit->data;
+ /* found a client that was in the session, so go below it */
+ if (c->session == it->data) {
+ stacking_below(CLIENT_AS_WINDOW(self),
+ CLIENT_AS_WINDOW(cit->data));
+ return TRUE;
+ }
}
}
+ return FALSE;
}
void client_move_onscreen(ObClient *self, gboolean rude)
if (!rude) {
Point oldtl, oldtr, oldbl, oldbr;
Point newtl, newtr, newbl, newbr;
- gboolean stationary;
+ gboolean stationary_l, stationary_r, stationary_t, stationary_b;
POINT_SET(oldtl, self->frame->area.x, self->frame->area.y);
POINT_SET(oldbr, self->frame->area.x + self->frame->area.width - 1,
POINT_SET(newbl, newtl.x, newbr.y);
/* is it moving or just resizing from some corner? */
- stationary = (POINT_EQUAL(oldtl, newtl) || POINT_EQUAL(oldtr, newtr) ||
- POINT_EQUAL(oldbl, newbl) || POINT_EQUAL(oldbr, newbr));
+ stationary_l = oldtl.x == oldtl.x;
+ stationary_r = oldtr.x == oldtr.x;
+ stationary_t = oldtl.y == oldtl.y;
+ stationary_b = oldbl.y == oldbl.y;
- /* if left edge is growing */
- if (stationary && newtl.x < oldtl.x)
+ /* if left edge is growing and didnt move right edge */
+ if (stationary_r && newtl.x < oldtl.x)
rudel = TRUE;
- /* if right edge is growing */
- if (stationary && newtr.x > oldtr.x)
+ /* if right edge is growing and didnt move left edge */
+ if (stationary_l && newtr.x > oldtr.x)
ruder = TRUE;
- /* if top edge is growing */
- if (stationary && newtl.y < oldtl.y)
+ /* if top edge is growing and didnt move bottom edge */
+ if (stationary_b && newtl.y < oldtl.y)
rudet = TRUE;
- /* if bottom edge is growing */
- if (stationary && newbl.y > oldbl.y)
+ /* if bottom edge is growing and didnt move top edge */
+ if (stationary_t && newbl.y > oldbl.y)
rudeb = TRUE;
}
client_get_area(self);
client_get_mwm_hints(self);
- /* The transient hint is used to pick a type, but the type can also affect
- transiency (dialogs are always made transients of their group if they
- have one). This is Havoc's idea, but it is needed to make some apps
- work right (eg tsclient). */
- client_update_transient_for(self);
+ /* The transient-ness of a window is used to pick a type, but the type can
+ also affect transiency.
+
+ Dialogs are always made transients for their group if they have one.
+
+ I also have made non-application type windows be transients for their
+ group (eg utility windows).
+ */
+ client_get_transientness(self);
client_get_type(self);/* this can change the mwmhints for special cases */
client_get_state(self);
- client_update_transient_for(self);
client_update_wmhints(self);
+ /* this may have already been called from client_update_wmhints */
+ if (self->transient_for == NULL)
+ client_update_transient_for(self);
client_get_startup_id(self);
client_get_desktop(self);/* uses transient data/group/startup id if a
desktop is not specified */
client_update_title(self);
client_update_class(self);
client_update_sm_client_id(self);
+ client_update_command(self);
client_update_strut(self);
client_update_icons(self);
client_update_user_time(self);
+ client_update_icon_geometry(self);
}
static void client_get_startup_id(ObClient *self)
self->below = TRUE;
else if (state[i] == prop_atoms.net_wm_state_demands_attention)
self->demands_attention = TRUE;
- else if (state[i] == prop_atoms.ob_wm_state_undecorated)
+ else if (state[i] == prop_atoms.openbox_wm_state_undecorated)
self->undecorated = TRUE;
}
#endif
}
+void client_get_transientness(ObClient *self)
+{
+ Window t;
+ if (XGetTransientForHint(ob_display, self->window, &t))
+ self->transient = TRUE;
+}
+
void client_update_transient_for(ObClient *self)
{
Window t = None;
}
}
}
- } else if (self->group) {
- if (self->type == OB_CLIENT_TYPE_DIALOG ||
- self->type == OB_CLIENT_TYPE_TOOLBAR ||
- self->type == OB_CLIENT_TYPE_MENU ||
- self->type == OB_CLIENT_TYPE_UTILITY)
- {
- self->transient = TRUE;
+ } else if (self->type == OB_CLIENT_TYPE_DIALOG ||
+ self->type == OB_CLIENT_TYPE_TOOLBAR ||
+ self->type == OB_CLIENT_TYPE_MENU ||
+ self->type == OB_CLIENT_TYPE_UTILITY)
+ {
+ self->transient = TRUE;
+ if (self->group)
target = OB_TRAN_GROUP;
- }
} else
self->transient = FALSE;
- /* if anything has changed... */
- if (target != self->transient_for) {
- if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
- GSList *it;
+ client_update_transient_tree(self, self->group, self->group,
+ self->transient_for, target);
+ self->transient_for = target;
+
+}
- /* remove from old parents */
- for (it = self->group->members; it; it = g_slist_next(it)) {
- ObClient *c = it->data;
- if (c != self && (!c->transient_for ||
- c->transient_for != OB_TRAN_GROUP))
- c->transients = g_slist_remove(c->transients, self);
- }
- } else if (self->transient_for != NULL) { /* transient of window */
- /* remove from old parent */
- self->transient_for->transients =
- g_slist_remove(self->transient_for->transients, self);
+static void client_update_transient_tree(ObClient *self,
+ ObGroup *oldgroup, ObGroup *newgroup,
+ ObClient* oldparent,
+ ObClient *newparent)
+{
+ GSList *it, *next;
+ ObClient *c;
+
+ /* No change has occured */
+ if (oldgroup == newgroup && 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 that window can't be a child of this window anymore */
+ if (oldparent != newparent &&
+ newparent != NULL && newparent != OB_TRAN_GROUP &&
+ newparent->transient_for == OB_TRAN_GROUP &&
+ newgroup != NULL && newgroup == oldgroup)
+ {
+ self->transients = g_slist_remove(self->transients, newparent);
+ }
+
+
+ /* If the group changed then we need to remove any old group transient
+ windows from our children. But if we're transient for the group, then
+ other group transients are not our children. */
+ if (oldgroup != newgroup && oldgroup != NULL &&
+ oldparent != OB_TRAN_GROUP)
+ {
+ for (it = self->transients; it; it = next) {
+ next = g_slist_next(it);
+ c = it->data;
+ if (c->group == oldgroup)
+ self->transients = g_slist_delete_link(self->transients, it);
}
- self->transient_for = target;
- if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
- GSList *it;
+ }
- /* add to new parents */
- for (it = self->group->members; it; it = g_slist_next(it)) {
- ObClient *c = it->data;
- if (c != self && (!c->transient_for ||
- c->transient_for != OB_TRAN_GROUP))
- c->transients = g_slist_append(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 (oldparent == OB_TRAN_GROUP && (oldgroup != newgroup ||
+ oldparent != newparent))
+ {
+ 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))
+ c->transients = g_slist_remove(c->transients, 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 != NULL && oldparent != OB_TRAN_GROUP &&
+ oldparent != newparent)
+ oldparent->transients = g_slist_remove(oldparent->transients, self);
-/* XXX can i remove this ?? */
- /* remove all transients which are in the group, that causes
- circlular pointer hell of doom */
- for (it = self->group->members; it; it = g_slist_next(it)) {
- GSList *sit, *next;
- for (sit = self->transients; sit; sit = next) {
- next = g_slist_next(sit);
- if (sit->data == it->data)
- self->transients =
- g_slist_delete_link(self->transients, sit);
- }
+ /** 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 (newparent == OB_TRAN_GROUP && (oldgroup != newgroup ||
+ oldparent != newparent))
+ {
+ 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))
+ c->transients = g_slist_prepend(c->transients, self);
+ }
+ }
+ /* If we are now transient for a single window which we weren't before,
+ we need to add ourselves to its children
+
+ WARNING: Cyclical transient ness is possible if two windows are
+ transient for eachother.
+ */
+ 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))
+ newparent->transients = g_slist_prepend(newparent->transients, self);
+
+ /* 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.
+
+ WARNING: Cyclical transient-ness is possible. For e.g. if:
+ A is transient for the group
+ B is a member of the group and transient for A
+ */
+ if (oldgroup != newgroup && newgroup != NULL &&
+ newparent != OB_TRAN_GROUP)
+ {
+ for (it = newgroup->members; it; it = g_slist_next(it)) {
+ 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))
+ {
+ self->transients = g_slist_prepend(self->transients, c);
}
- } else if (self->transient_for != NULL) { /* transient of window */
- /* add to new parent */
- self->transient_for->transients =
- g_slist_append(self->transient_for->transients, self);
}
}
}
void client_update_wmhints(ObClient *self)
{
XWMHints *hints;
- GSList *it;
/* assume a window takes input if it doesnt specify */
self->can_focus = TRUE;
/* did the group state change? */
if (hints->window_group !=
- (self->group ? self->group->leader : None)) {
+ (self->group ? self->group->leader : None))
+ {
+ ObGroup *oldgroup = self->group;
+
/* remove from the old group if there was one */
if (self->group != NULL) {
- /* remove transients of the group */
- for (it = self->group->members; it; it = g_slist_next(it))
- self->transients = g_slist_remove(self->transients,
- it->data);
-
- /* remove myself from parents in the group */
- if (self->transient_for == OB_TRAN_GROUP) {
- for (it = self->group->members; it;
- it = g_slist_next(it))
- {
- ObClient *c = it->data;
-
- if (c != self && !c->transient_for)
- c->transients = g_slist_remove(c->transients,
- self);
- }
- }
-
group_remove(self->group, self);
self->group = NULL;
}
+
+ /* add ourself to the group if we have one */
if (hints->window_group != None) {
self->group = group_add(hints->window_group, self);
-
- /* i can only have transients from the group if i am not
- transient myself */
- if (!self->transient_for) {
- /* add other transients of the group that are already
- set up */
- for (it = self->group->members; it;
- it = g_slist_next(it))
- {
- ObClient *c = it->data;
- if (c != self && c->transient_for == OB_TRAN_GROUP)
- self->transients =
- g_slist_append(self->transients, c);
- }
- }
}
- /* because the self->transient flag wont change from this call,
- we don't need to update the window's type and such, only its
- transient_for, and the transients lists of other windows in
- the group may be affected */
- client_update_transient_for(self);
+ /* Put ourselves into the new group's transient tree, and remove
+ ourselves from the old group's */
+ client_update_transient_tree(self, oldgroup, self->group,
+ self->transient_for,
+ self->transient_for);
+
+ /* Lastly, being in a group, or not, can change if the window is
+ transient for anything.
+
+ The logic for this is:
+ self->transient = TRUE always if the window wants to be
+ transient for something, even if transient_for was NULL because
+ it wasn't in a group before.
+
+ If transient_for was NULL and oldgroup was NULL we can assume
+ that when we add the new group, it will become transient for
+ something.
+
+ If transient_for was OB_TRAN_GROUP, then it must have already
+ had a group. If it is getting a new group, the above call to
+ client_update_transient_tree has already taken care of
+ everything ! If it is losing all group status then it will
+ no longer be transient for anything and that needs to be
+ updated.
+ */
+ if (self->transient &&
+ ((self->transient_for == NULL && oldgroup == NULL) ||
+ (self->transient_for == OB_TRAN_GROUP && !self->group)))
+ client_update_transient_for(self);
}
/* the WM_HINTS can contain an icon */
}
}
+void client_update_icon_geometry(ObClient *self)
+{
+ guint num;
+ guint32 *data;
+
+ RECT_SET(self->icon_geometry, 0, 0, 0, 0);
+
+ if (PROP_GETA32(self->window, net_wm_icon_geometry, cardinal, &data, &num)
+ && num == 4)
+ {
+ /* don't let them set it with an area < 0 */
+ RECT_SET(self->icon_geometry, data[0], data[1],
+ MAX(data[2],0), MAX(data[3],0));
+ }
+}
+
static void client_get_client_machine(ObClient *self)
{
gchar *data = NULL;
old = self->wmstate;
- if (self->shaded || self->iconic || !self->frame->visible)
+ if (self->shaded || !self->frame->visible)
self->wmstate = IconicState;
else
self->wmstate = NormalState;
if (self->demands_attention)
netstate[num++] = prop_atoms.net_wm_state_demands_attention;
if (self->undecorated)
- netstate[num++] = prop_atoms.ob_wm_state_undecorated;
+ netstate[num++] = prop_atoms.openbox_wm_state_undecorated;
PROP_SETA32(self->window, net_wm_state, atom, netstate, num);
if (self->frame)
{
ObStackingLayer l;
- if (self->fullscreen &&
- (client_focused(self) || client_search_focus_tree(self)))
- l = OB_STACKING_LAYER_FULLSCREEN;
- else if (self->type == OB_CLIENT_TYPE_DESKTOP)
+ if (self->type == OB_CLIENT_TYPE_DESKTOP)
l = OB_STACKING_LAYER_DESKTOP;
else if (self->type == OB_CLIENT_TYPE_DOCK) {
if (self->below) l = OB_STACKING_LAYER_NORMAL;
else l = OB_STACKING_LAYER_ABOVE;
}
+ else if ((self->fullscreen ||
+ /* no decorations and fills the monitor = oldskool fullscreen */
+ (self->frame != NULL &&
+ (self->frame->size.right == 0 && self->frame->size.left == 0 &&
+ self->frame->size.bottom == 0 && self->frame->size.top == 0 &&
+ RECT_EQUAL(self->area,
+ *screen_physical_area_monitor
+ (client_monitor(self)))))) &&
+ (client_focused(self) || client_search_focus_tree(self)))
+ l = OB_STACKING_LAYER_FULLSCREEN;
else if (self->above) l = OB_STACKING_LAYER_ABOVE;
else if (self->below) l = OB_STACKING_LAYER_BELOW;
else l = OB_STACKING_LAYER_NORMAL;
} else {
self->iconic = iconic;
- if (curdesk)
+ if (curdesk && self->desktop != screen_desktop &&
+ self->desktop != DESKTOP_ALL)
client_set_desktop(self, screen_desktop, FALSE);
/* this puts it after the current focused window */
if (changed) {
client_change_state(self);
+ if (ob_state() != OB_STATE_STARTING && config_animate_iconify)
+ frame_begin_iconify_animation(self->frame, iconic);
+ /* do this after starting the animation so it doesn't flash */
client_showhide(self);
- if (STRUT_EXISTS(self->strut))
- screen_update_areas();
}
/* iconify all direct transients, and deiconify all transients
void client_iconify(ObClient *self, gboolean iconic, gboolean curdesk)
{
/* move up the transient chain as far as possible first */
- self = client_search_top_parent(self);
+ self = client_search_top_normal_parent(self);
client_iconify_recursive(self, iconic, curdesk);
}
void client_set_desktop(ObClient *self, guint target, gboolean donthide)
{
- self = client_search_top_parent(self);
+ self = client_search_top_normal_parent(self);
client_set_desktop_recursive(self, target, donthide);
}
action = self->demands_attention ?
prop_atoms.net_wm_state_remove :
prop_atoms.net_wm_state_add;
- else if (state == prop_atoms.ob_wm_state_undecorated)
+ else if (state == prop_atoms.openbox_wm_state_undecorated)
action = undecorated ? prop_atoms.net_wm_state_remove :
prop_atoms.net_wm_state_add;
}
self->below = TRUE;
} else if (state == prop_atoms.net_wm_state_demands_attention) {
demands_attention = TRUE;
- } else if (state == prop_atoms.ob_wm_state_undecorated) {
+ } else if (state == prop_atoms.openbox_wm_state_undecorated) {
undecorated = TRUE;
}
self->below = FALSE;
} else if (state == prop_atoms.net_wm_state_demands_attention) {
demands_attention = FALSE;
- } else if (state == prop_atoms.ob_wm_state_undecorated) {
+ } else if (state == prop_atoms.openbox_wm_state_undecorated) {
undecorated = FALSE;
}
}
return TRUE;
}
+/*! Present the client to the user.
+ @param raise If the client should be raised or not. You should only set
+ raise to false if you don't care if the window is completely
+ hidden.
+*/
+static void client_present(ObClient *self, gboolean here, gboolean raise)
+{
+ /* if using focus_delay, stop the timer now so that focus doesn't
+ go moving on us */
+ event_halt_focus_delay();
+
+ if (client_normal(self) && screen_showing_desktop)
+ screen_show_desktop(FALSE, FALSE);
+ if (self->iconic)
+ client_iconify(self, FALSE, here);
+ if (self->desktop != DESKTOP_ALL &&
+ self->desktop != screen_desktop)
+ {
+ if (here)
+ client_set_desktop(self, screen_desktop, FALSE);
+ else
+ screen_set_desktop(self->desktop, FALSE);
+ } else if (!self->frame->visible)
+ /* if its not visible for other reasons, then don't mess
+ with it */
+ return;
+ if (self->shaded)
+ client_shade(self, FALSE);
+
+ client_focus(self);
+
+ if (raise) {
+ /* we do this as an action here. this is rather important. this is
+ because we want the results from the focus change to take place
+ BEFORE we go about raising the window. when a fullscreen window
+ loses focus, we need this or else the raise wont be able to raise
+ above the to-lose-focus fullscreen window. */
+ client_raise(self);
+ }
+}
+
void client_activate(ObClient *self, gboolean here, gboolean user)
{
guint32 last_time = focus_client ? focus_client->user_time : CurrentTime;
if (event_curtime != CurrentTime)
self->user_time = event_curtime;
- /* if using focus_delay, stop the timer now so that focus doesn't
- go moving on us */
- event_halt_focus_delay();
-
- if (client_normal(self) && screen_showing_desktop)
- screen_show_desktop(FALSE);
- if (self->iconic)
- client_iconify(self, FALSE, here);
- if (self->desktop != DESKTOP_ALL &&
- self->desktop != screen_desktop) {
- if (here)
- client_set_desktop(self, screen_desktop, FALSE);
- else
- screen_set_desktop(self->desktop);
- } else if (!self->frame->visible)
- /* if its not visible for other reasons, then don't mess
- with it */
- return;
- if (self->shaded)
- client_shade(self, FALSE);
-
- client_focus(self);
-
- /* we do this as an action here. this is rather important. this is
- because we want the results from the focus change to take place
- BEFORE we go about raising the window. when a fullscreen window
- loses focus, we need this or else the raise wont be able to raise
- above the to-lose-focus fullscreen window. */
- client_raise(self);
+ client_present(self, here, TRUE);
}
}
return screen_find_monitor(&self->frame->area);
}
-ObClient *client_search_top_parent(ObClient *self)
+ObClient *client_search_top_normal_parent(ObClient *self)
{
while (self->transient_for && self->transient_for != OB_TRAN_GROUP &&
- client_normal(self))
+ client_normal(self->transient_for))
self = self->transient_for;
return self;
}
-GSList *client_search_all_top_parents(ObClient *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)
+ 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)
for (it = self->group->members; it; it = g_slist_next(it)) {
ObClient *c = it->data;
- if (!c->transient_for && client_normal(c))
+ if (!c->transient_for && client_normal(c) &&
+ (!bylayer || c->layer == layer))
+ {
ret = g_slist_prepend(ret, c);
+ }
}
if (ret == NULL) /* no group parents */
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) {
g_free(self->sm_client_id);
self->sm_client_id = NULL;
- if (!PROP_GETS(self->window, sm_client_id, locale, &self->sm_client_id) &&
- self->group)
- PROP_GETS(self->group->leader, sm_client_id, locale,
- &self->sm_client_id);
+ if (!PROP_GETS(self->window, sm_client_id, locale, &self->sm_client_id))
+ if (self->group)
+ PROP_GETS(self->group->leader, sm_client_id, locale,
+ &self->sm_client_id);
+}
+
+void client_update_command(ObClient *self)
+{
+ gchar **data;
+
+ g_free(self->wm_command);
+ self->wm_command = NULL;
+
+ if (PROP_GETSS(self->window, wm_command, locale, &data)) {
+ /* merge/mash them all together */
+ gchar *merge = NULL;
+ gint i;
+
+ for (i = 0; data[i]; ++i) {
+ gchar *tmp = merge;
+ if (merge)
+ merge = g_strconcat(merge, data[i], NULL);
+ else
+ merge = g_strconcat(data[i], NULL);
+ g_free(tmp);
+ }
+ g_strfreev(data);
+
+ self->wm_command = merge;
+ }
}
#define WANT_EDGE(cur, c) \
if(cur == c) \
continue; \
- if(!client_normal(cur)) \
+ if(!client_normal(cur)) \
continue; \
if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \
continue; \
if (WINDOW_IS_CLIENT(it->data)) {
ObClient *c = WINDOW_AS_CLIENT(it->data);
if (c->frame->visible &&
- RECT_CONTAINS(c->frame->area, x, y)) {
+ /* ignore all animating windows */
+ !frame_iconify_animating(c->frame) &&
+ RECT_CONTAINS(c->frame->area, x, y))
+ {
ret = c;
break;
}