add the maginificent client_update_transient_tree.
add a whole lot of comments ! i think like half of this commit is comments speed up mapping windows a little! less re-updating of the transient info by far. and... yeah fix the crash created from r6035.
This commit is contained in:
parent
32630da2bf
commit
7ff21ad74f
1 changed files with 151 additions and 82 deletions
233
openbox/client.c
233
openbox/client.c
|
@ -77,6 +77,7 @@ static void client_get_mwm_hints(ObClient *self);
|
||||||
static void client_get_gravity(ObClient *self);
|
static void client_get_gravity(ObClient *self);
|
||||||
static void client_get_client_machine(ObClient *self);
|
static void client_get_client_machine(ObClient *self);
|
||||||
static void client_get_colormap(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_allowed_actions(ObClient *self);
|
||||||
static void client_change_state(ObClient *self);
|
static void client_change_state(ObClient *self);
|
||||||
static void client_change_wm_state(ObClient *self);
|
static void client_change_wm_state(ObClient *self);
|
||||||
|
@ -84,6 +85,10 @@ 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_state(ObClient *self);
|
||||||
static void client_restore_session_stacking(ObClient *self);
|
static void client_restore_session_stacking(ObClient *self);
|
||||||
static ObAppSettings *client_get_settings_state(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);
|
||||||
|
|
||||||
void client_startup(gboolean reconfig)
|
void client_startup(gboolean reconfig)
|
||||||
{
|
{
|
||||||
|
@ -912,19 +917,20 @@ static void client_get_all(ObClient *self)
|
||||||
client_get_area(self);
|
client_get_area(self);
|
||||||
client_get_mwm_hints(self);
|
client_get_mwm_hints(self);
|
||||||
|
|
||||||
/* The transient hint is used to pick a type, but the type can also affect
|
/* The transient-ness of a window is used to pick a type, but the type can
|
||||||
transiency (dialogs are always made transients of their group if they
|
also affect transiency.
|
||||||
have one). This is Havoc's idea, but it is needed to make some apps
|
|
||||||
work right (eg tsclient).
|
Dialogs are always made transients for their group if they have one.
|
||||||
I also have made non-application type windows be transients based on
|
|
||||||
their type, like dialogs.
|
I also have made non-application type windows be transients for their
|
||||||
|
group (eg utility windows).
|
||||||
*/
|
*/
|
||||||
client_update_transient_for(self);
|
client_get_transientness(self);
|
||||||
client_get_type(self);/* this can change the mwmhints for special cases */
|
client_get_type(self);/* this can change the mwmhints for special cases */
|
||||||
client_get_state(self);
|
client_get_state(self);
|
||||||
client_update_transient_for(self);
|
|
||||||
|
|
||||||
client_update_wmhints(self);
|
client_update_wmhints(self);
|
||||||
|
client_update_transient_for(self);
|
||||||
client_get_startup_id(self);
|
client_get_startup_id(self);
|
||||||
client_get_desktop(self);/* uses transient data/group/startup id if a
|
client_get_desktop(self);/* uses transient data/group/startup id if a
|
||||||
desktop is not specified */
|
desktop is not specified */
|
||||||
|
@ -1121,6 +1127,13 @@ static void client_get_shaped(ObClient *self)
|
||||||
#endif
|
#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)
|
void client_update_transient_for(ObClient *self)
|
||||||
{
|
{
|
||||||
Window t = None;
|
Window t = None;
|
||||||
|
@ -1176,38 +1189,104 @@ void client_update_transient_for(ObClient *self)
|
||||||
} else
|
} else
|
||||||
self->transient = FALSE;
|
self->transient = FALSE;
|
||||||
|
|
||||||
/* if anything has changed... */
|
client_update_transient_tree(self, self->group, self->group,
|
||||||
if (target != self->transient_for) {
|
self->transient_for, target);
|
||||||
if (self->transient_for == OB_TRAN_GROUP) { /* transient of group */
|
self->transient_for = target;
|
||||||
GSList *it;
|
|
||||||
|
}
|
||||||
|
|
||||||
/* remove from old parents */
|
static void client_update_transient_tree(ObClient *self,
|
||||||
for (it = self->group->members; it; it = g_slist_next(it)) {
|
ObGroup *oldgroup, ObGroup *newgroup,
|
||||||
ObClient *c = it->data;
|
ObClient* oldparent,
|
||||||
if (c != self && (!c->transient_for ||
|
ObClient *newparent)
|
||||||
c->transient_for != OB_TRAN_GROUP))
|
{
|
||||||
c->transients = g_slist_remove(c->transients, self);
|
GSList *it, *next;
|
||||||
}
|
ObClient *c;
|
||||||
} else if (self->transient_for != NULL) { /* transient of window */
|
|
||||||
/* remove from old parent */
|
/* No change has occured */
|
||||||
self->transient_for->transients =
|
if (oldgroup == newgroup && oldparent == newparent) return;
|
||||||
g_slist_remove(self->transient_for->transients, self);
|
|
||||||
|
/** Remove the client from the transient tree wherever it has changed **/
|
||||||
|
|
||||||
|
/* 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 */
|
/* If we used to be transient for a group and now we are not, or we're
|
||||||
for (it = self->group->members; it; it = g_slist_next(it)) {
|
transient for a new group, then we need to remove ourselves from all
|
||||||
ObClient *c = it->data;
|
our ex-parents */
|
||||||
if (c != self && (!c->transient_for ||
|
if (oldparent == OB_TRAN_GROUP && (oldgroup != newgroup ||
|
||||||
c->transient_for != OB_TRAN_GROUP))
|
oldparent != newparent))
|
||||||
c->transients = g_slist_append(c->transients, self);
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
/** 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 != newparent &&
|
||||||
|
/* 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 old 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1631,60 +1710,50 @@ void client_update_wmhints(ObClient *self)
|
||||||
|
|
||||||
/* did the group state change? */
|
/* did the group state change? */
|
||||||
if (hints->window_group !=
|
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 */
|
/* remove from the old group if there was one */
|
||||||
if (self->group != NULL) {
|
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->transient_for != OB_TRAN_GROUP))
|
|
||||||
c->transients = g_slist_remove(c->transients,
|
|
||||||
self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
group_remove(self->group, self);
|
group_remove(self->group, self);
|
||||||
self->group = NULL;
|
self->group = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add ourself to the group */
|
/* add ourself to the group if we have one */
|
||||||
if (hints->window_group != None)
|
if (hints->window_group != None) {
|
||||||
self->group = group_add(hints->window_group, self);
|
self->group = group_add(hints->window_group, self);
|
||||||
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
|
|
||||||
do this before adding transients from the group so we know if
|
|
||||||
we are actually transient for the group or not.
|
|
||||||
*/
|
|
||||||
client_update_transient_for(self);
|
|
||||||
|
|
||||||
/* i can only have transients from the group if i am not
|
|
||||||
transient for the group myself */
|
|
||||||
if (self->group && (self->transient_for == NULL ||
|
|
||||||
self->transient_for != OB_TRAN_GROUP))
|
|
||||||
{
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 == NULL))
|
||||||
|
client_update_transient_for(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* the WM_HINTS can contain an icon */
|
/* the WM_HINTS can contain an icon */
|
||||||
|
|
Loading…
Reference in a new issue