X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=9327cbfd7333d6e554cf5df56ea34267e0612a62;hb=37875f091d8a19818b6325923a57f6f7f3cd820c;hp=3e43891e21bfc6ab5050a7af68a873204e349e76;hpb=a823e4786e8c0b5ec1940f7a6daaf4572f7d452a;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 3e43891e..9327cbfd 100644 --- a/openbox/client.c +++ b/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_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); @@ -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_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); void client_startup(gboolean reconfig) { @@ -262,7 +267,9 @@ void client_manage(Window window) /* choose the events we want to receive on the CLIENT window */ attrib_set.event_mask = CLIENT_EVENTMASK; - XChangeWindowAttributes(ob_display, window, CWEventMask, &attrib_set); + attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK; + XChangeWindowAttributes(ob_display, window, + CWEventMask|CWDontPropagate, &attrib_set); /* create the ObClient struct, and populate it from the hints on the @@ -910,19 +917,22 @@ static void client_get_all(ObClient *self) 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). - I also have made non-application type windows be transients based on - their type, like dialogs. + /* 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_update_transient_for(self); + 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 */ @@ -960,6 +970,7 @@ static void client_get_all(ObClient *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) @@ -1092,7 +1103,7 @@ static void client_get_state(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; } @@ -1119,6 +1130,13 @@ static void client_get_shaped(ObClient *self) #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; @@ -1162,50 +1180,126 @@ void client_update_transient_for(ObClient *self) } } } - } 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); + + + /** 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); } } } @@ -1600,7 +1694,6 @@ void client_reconfigure(ObClient *self) void client_update_wmhints(ObClient *self) { XWMHints *hints; - GSList *it; /* assume a window takes input if it doesnt specify */ self->can_focus = TRUE; @@ -1629,60 +1722,50 @@ void client_update_wmhints(ObClient *self) /* 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->transient_for != OB_TRAN_GROUP)) - c->transients = g_slist_remove(c->transients, - self); - } - } - group_remove(self->group, self); self->group = NULL; } - /* 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 - - 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); - + /* 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 for the group myself */ - if (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))) + client_update_transient_for(self); } /* the WM_HINTS can contain an icon */ @@ -1940,6 +2023,22 @@ void client_update_user_time(ObClient *self) } } +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; @@ -1962,7 +2061,7 @@ static void client_change_wm_state(ObClient *self) old = self->wmstate; - if (self->shaded || self->iconic || !self->frame->visible) + if (self->shaded || !self->frame->visible) self->wmstate = IconicState; else self->wmstate = NormalState; @@ -2006,7 +2105,7 @@ static void client_change_state(ObClient *self) 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) @@ -2625,9 +2724,10 @@ static void client_iconify_recursive(ObClient *self, 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 @@ -2953,7 +3053,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) 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; } @@ -2983,7 +3083,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) 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; } @@ -3010,7 +3110,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) 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; } } @@ -3179,7 +3279,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user) event_halt_focus_delay(); if (client_normal(self) && screen_showing_desktop) - screen_show_desktop(FALSE); + screen_show_desktop(FALSE, FALSE); if (self->iconic) client_iconify(self, FALSE, here); if (self->desktop != DESKTOP_ALL && @@ -3617,7 +3717,10 @@ ObClient* client_under_pointer() 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; }