]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
save session state for old clients that dont use XSMP. more session improvements...
[chaz/openbox] / openbox / client.c
index e943421791aafa266fbb1822370f00e34ff694a6..cbd42ef4ae836642fd98a5860c85b623fb8db227 100644 (file)
@@ -77,13 +77,22 @@ 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)
 {
@@ -316,10 +325,10 @@ void client_manage(Window window)
     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)) ||
@@ -372,6 +381,10 @@ void client_manage(Window window)
     */
     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);
@@ -438,7 +451,8 @@ void client_manage(Window window)
            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
@@ -451,8 +465,10 @@ void client_manage(Window window)
        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);
@@ -596,6 +612,7 @@ void client_unmanage(ObClient *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);
@@ -680,13 +697,22 @@ static void client_restore_session_state(ObClient *self)
 {
     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)
@@ -708,28 +734,33 @@ static void client_restore_session_state(ObClient *self)
     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 FALSE;
 
-    if (!self->session) return;
+    mypos = g_list_find(session_saved_state, self->session);
+    if (!mypos) return FALSE;
 
-    it = g_list_find(session_saved_state, self->session);
-    for (it = g_list_previous(it); it; it = g_list_previous(it)) {
+    /* 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)
@@ -788,7 +819,7 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
     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,
@@ -802,20 +833,22 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
         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;
     }
 
@@ -912,19 +945,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 */
@@ -959,9 +995,11 @@ static void client_get_all(ObClient *self)
     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)
@@ -1094,7 +1132,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;
         }
 
@@ -1121,6 +1159,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;
@@ -1164,50 +1209,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);
         }
     }
 }
@@ -1602,7 +1723,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;
@@ -1631,60 +1751,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 */
@@ -1942,6 +2052,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;
@@ -1964,7 +2090,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;
@@ -2008,7 +2134,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)
@@ -2059,15 +2185,22 @@ static ObStackingLayer calc_layer(ObClient *self)
 {
     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;
@@ -2627,9 +2760,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
@@ -2643,7 +2777,7 @@ static void client_iconify_recursive(ObClient *self,
 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);
 }
 
@@ -2838,7 +2972,7 @@ void client_set_desktop_recursive(ObClient *self,
 
 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);
 }
 
@@ -2955,7 +3089,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;
         }
@@ -2985,7 +3119,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;
             }
 
@@ -3012,7 +3146,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;
             }
         }
@@ -3154,6 +3288,47 @@ gboolean client_focus(ObClient *self)
     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;
@@ -3176,36 +3351,7 @@ void client_activate(ObClient *self, gboolean here, gboolean user)
         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);
     }
 }
 
@@ -3317,20 +3463,24 @@ guint client_monitor(ObClient *self)
     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)
@@ -3343,8 +3493,11 @@ GSList *client_search_all_top_parents(ObClient *self)
             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 */
@@ -3354,6 +3507,16 @@ GSList *client_search_all_top_parents(ObClient *self)
     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) {
@@ -3418,16 +3581,42 @@ 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);
+    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;                                                     \
@@ -3619,7 +3808,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;
                 }
This page took 0.040508 seconds and 4 git commands to generate.