static void client_get_all(ObClient *self);
static void client_toggle_border(ObClient *self, gboolean show);
static void client_get_startup_id(ObClient *self);
+static void client_get_session_ids(ObClient *self);
static void client_get_area(ObClient *self);
static void client_get_desktop(ObClient *self);
static void client_get_state(ObClient *self);
static void client_get_shaped(ObClient *self);
static void client_get_mwm_hints(ObClient *self);
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)
{
self->wmstate = WithdrawnState; /* make sure it gets updated first time */
self->layer = -1;
self->desktop = screen_num_desktops; /* always an invalid value */
- self->user_time = CurrentTime;
+ self->user_time = focus_client ? focus_client->user_time : CurrentTime;
client_get_all(self);
/* per-app settings override stuff, and return the settings for other
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)) ||
/* make sure the window is visible. */
client_find_onscreen(self, &newx, &newy,
- self->frame->area.width,
- self->frame->area.height,
+ self->area.width,
+ self->area.height,
/* non-normal clients has less rules, and
windows that are being restored from a
session do also. we can assume you want
*/
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);
focus_client->user_time : CurrentTime;
/* This is focus stealing prevention */
- ob_debug("Want to focus new window 0x%x with time %u (last time %u)\n",
- self->window, self->user_time, last_time);
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Want to focus new window 0x%x with time %u "
+ "(last time %u)\n",
+ self->window, self->user_time, last_time);
/* if it's on another desktop */
if (!(self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
!event_time_after(self->user_time, screen_desktop_user_time))
{
activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because its on another "
+ "desktop\n");
}
- /* If nothing is focused, or a parent was focused, then focus this
- always
- */
- else if (!focus_client || client_search_focus_parent(self) != NULL)
- activate = TRUE;
- else
+ /* If something is focused, and it's not our parent... */
+ else if (focus_client && client_search_focus_parent(self) == NULL)
{
/* If time stamp is old, don't steal focus */
if (self->user_time && last_time &&
!event_time_after(self->user_time, last_time))
{
activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because the time is "
+ "too old\n");
}
/* Don't steal focus from globally active clients.
I stole this idea from KWin. It seems nice.
*/
- if (!(focus_client->can_focus || focus_client->focus_notify))
+ if (!(focus_client->can_focus || focus_client->focus_notify)) {
activate = FALSE;
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Not focusing the window because a globally "
+ "active client has focus\n");
+ }
}
if (!activate) {
- ob_debug("Focus stealing prevention activated for %s with time %u "
- "(last time %u)\n",
- self->title, self->user_time, last_time);
+ ob_debug_type(OB_DEBUG_FOCUS,
+ "Focus stealing prevention activated for %s with "
+ "time %u (last time %u)\n",
+ self->title, self->user_time, last_time);
/* if the client isn't focused, then hilite it so the user
knows it is there */
client_hilite(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);
/* update the focus lists */
focus_order_remove(self);
if (client_focused(self)) {
- /* we have to fall back here because we might not get a focus out.
- 1. we need to xselectinput off the window before we unmap it because
- otherwise we end up getting unmapnotifies we don't want and they
- can mess up mapping it again quickly
- 2. this means that if we unmanage from a synthetic unmapnotify, we
- are the ones unmapped it, and causing the focusout. so we won't
- get the focusout event.
- 3. we can't handle focusin events on the root window because they
- come from all screens, so the focus change gets lost
-
- if this ever gets removed in the future MAKE SURE to replace it
- with:
- /- don't leave an invalid focus_client -/
- focus_client = NULL;
- */
- focus_fallback(FALSE);
+ /* don't leave an invalid focus_client */
+ focus_client = NULL;
}
client_list = g_list_remove(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);
|| (app->class && app->name && !strcmp(app->class, self->class)
&& !strcmp(app->name, self->name)))
{
- ob_debug("Window matching: %s\n", app->name);
/* Match if no role was specified in the per app setting, or if the
* string matches the beginning of the role, since apps like to set
* the role to things like browser-window-23c4b2f */
if (!app->role
|| !strncmp(app->role, self->role, strlen(app->role)))
{
+ ob_debug("Window matching: %s\n", app->name);
/* use this one */
settings = app;
break;
if (settings->fullscreen != -1)
self->fullscreen = !!settings->fullscreen;
- if (settings->desktop < screen_num_desktops
- || settings->desktop == DESKTOP_ALL)
- self->desktop = settings->desktop;
+ if (settings->desktop) {
+ if (settings->desktop == DESKTOP_ALL)
+ self->desktop = settings->desktop;
+ else if (settings->desktop > 0 &&
+ settings->desktop <= screen_num_desktops)
+ self->desktop = settings->desktop - 1;
+ }
if (settings->layer == -1) {
self->below = TRUE;
{
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)
gint x = self->area.x;
gint y = self->area.y;
if (client_find_onscreen(self, &x, &y,
- self->frame->area.width,
- self->frame->area.height, rude)) {
+ self->area.width,
+ self->area.height, rude)) {
client_move(self, x, y);
}
}
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 */
#ifdef SYNC
client_update_sync_request_counter(self);
#endif
- client_get_client_machine(self);
+
+ /* get the session related properties */
+ client_get_session_ids(self);
+
client_get_colormap(self);
client_update_title(self);
- client_update_class(self);
- client_update_sm_client_id(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, 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 ||
+ (newparent == OB_TRAN_GROUP && oldparent != newparent)) &&
+ 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);
- /* 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 */
self->icon_title = data;
}
-void client_update_class(ObClient *self)
-{
- gchar **data;
- gchar *s;
-
- if (self->name) g_free(self->name);
- if (self->class) g_free(self->class);
- if (self->role) g_free(self->role);
-
- self->name = self->class = self->role = NULL;
-
- if (PROP_GETSS(self->window, wm_class, locale, &data)) {
- if (data[0]) {
- self->name = g_strdup(data[0]);
- if (data[1])
- self->class = g_strdup(data[1]);
- }
- g_strfreev(data);
- }
-
- if (PROP_GETS(self->window, wm_window_role, locale, &s))
- self->role = s;
-
- if (self->name == NULL) self->name = g_strdup("");
- if (self->class == NULL) self->class = g_strdup("");
- if (self->role == NULL) self->role = g_strdup("");
-}
-
void client_update_strut(ObClient *self)
{
guint num;
}
}
-static void client_get_client_machine(ObClient *self)
+void client_update_icon_geometry(ObClient *self)
{
- gchar *data = NULL;
- gchar localhost[128];
+ guint num;
+ guint32 *data;
- g_free(self->client_machine);
+ 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_session_ids(ObClient *self)
+{
+ guint32 leader;
+ gboolean got;
+ gchar *s;
+ gchar **ss;
+
+ if (!PROP_GET32(self->window, wm_client_leader, window, &leader))
+ leader = None;
+
+ /* get the SM_CLIENT_ID */
+ got = FALSE;
+ if (leader)
+ got = PROP_GETS(leader, sm_client_id, locale, &self->sm_client_id);
+ if (!got)
+ PROP_GETS(self->window, sm_client_id, locale, &self->sm_client_id);
+
+ /* get the WM_CLASS (name and class). make them "" if they are not
+ provided */
+ got = FALSE;
+ if (leader)
+ got = PROP_GETSS(leader, wm_class, locale, &ss);
+ if (!got)
+ got = PROP_GETSS(self->window, wm_class, locale, &ss);
+
+ if (got) {
+ if (ss[0]) {
+ self->name = g_strdup(ss[0]);
+ if (ss[1])
+ self->class = g_strdup(ss[1]);
+ }
+ g_strfreev(ss);
+ }
+
+ if (self->name == NULL) self->name = g_strdup("");
+ if (self->class == NULL) self->class = g_strdup("");
+
+ /* get the WM_WINDOW_ROLE. make it "" if it is not provided */
+ got = FALSE;
+ if (leader)
+ got = PROP_GETS(leader, wm_window_role, locale, &s);
+ if (!got)
+ got = PROP_GETS(self->window, wm_window_role, locale, &s);
+
+ if (got)
+ self->role = s;
+ else
+ self->role = g_strdup("");
+
+ /* get the WM_COMMAND */
+ got = FALSE;
+
+ if (leader)
+ got = PROP_GETSS(leader, wm_command, locale, &ss);
+ if (!got)
+ got = PROP_GETSS(self->window, wm_command, locale, &ss);
+
+ if (got) {
+ /* merge/mash them all together */
+ gchar *merge = NULL;
+ gint i;
+
+ for (i = 0; ss[i]; ++i) {
+ gchar *tmp = merge;
+ if (merge)
+ merge = g_strconcat(merge, ss[i], NULL);
+ else
+ merge = g_strconcat(ss[i], NULL);
+ g_free(tmp);
+ }
+ g_strfreev(ss);
+
+ self->wm_command = merge;
+ }
+
+ /* get the WM_CLIENT_MACHINE */
+ got = FALSE;
+ if (leader)
+ got = PROP_GETS(leader, wm_client_machine, locale, &s);
+ if (!got)
+ got = PROP_GETS(self->window, wm_client_machine, locale, &s);
+
+ if (got) {
+ gchar localhost[128];
- if (PROP_GETS(self->window, wm_client_machine, locale, &data)) {
gethostname(localhost, 127);
localhost[127] = '\0';
- if (strcmp(localhost, data))
- self->client_machine = data;
+ if (strcmp(localhost, s) != 0)
+ self->client_machine = s;
}
}
old = self->wmstate;
- if (self->shaded || self->iconic || !self->frame->visible)
+ if (self->shaded || self->iconic ||
+ (self->desktop != DESKTOP_ALL && self->desktop != screen_desktop))
+ {
self->wmstate = IconicState;
- else
+ } else
self->wmstate = NormalState;
if (old != self->wmstate) {
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;
return FALSE;
if (client_normal(self) && screen_showing_desktop)
return FALSE;
- /*
- if (self->transient_for) {
- if (self->transient_for != OB_TRAN_GROUP)
- return client_should_show(self->transient_for);
- 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 (client_should_show(c))
- return TRUE;
- }
- }
- }
- }
- */
if (self->desktop == screen_desktop || self->desktop == DESKTOP_ALL)
return TRUE;
self->type == OB_CLIENT_TYPE_SPLASH);
}
+gboolean client_application(ObClient *self)
+{
+ return (self->type == OB_CLIENT_TYPE_NORMAL ||
+ self->type == OB_CLIENT_TYPE_DIALOG);
+}
+
static void client_apply_startup_state(ObClient *self, gint x, gint y)
{
gboolean pos = FALSE; /* has the window's position been configured? */
} 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 */
+ /* iconify all direct transients, and deiconify all transients
+ (non-direct too) */
for (it = self->transients; it; it = g_slist_next(it))
if (it->data != self)
- if (client_is_direct_child(self, it->data))
+ if (client_is_direct_child(self, it->data) || !iconic)
client_iconify_recursive(it->data, iconic, curdesk);
}
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) {
return NULL;
}
-void client_update_sm_client_id(ObClient *self)
-{
- 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);
-}
-
#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;
}
{
return self->group && self->group->members->next;
}
+
+gboolean client_has_application_group_siblings(ObClient *self)
+{
+ GSList *it;
+
+ if (!self->group) return FALSE;
+
+ for (it = self->group->members; it; it = g_slist_next(it)) {
+ ObClient *c = it->data;
+ if (c != self && client_application(c))
+ return TRUE;
+ }
+ return FALSE;
+}