]> Dogcows Code - chaz/openbox/blobdiff - openbox/client.c
i rewrote handling of focus events. this is pretty much based on blackbox's current...
[chaz/openbox] / openbox / client.c
index 732f031f205fd7b5a357d28faa69c0767cf5554c..e4bef71d8392571db3a297a8ec35faf34d8538ed 100644 (file)
@@ -2,7 +2,7 @@
    
    client.c for the Openbox window manager
    Copyright (c) 2006        Mikael Magnusson
-   Copyright (c) 2003        Ben Jansens
+   Copyright (c) 2003-2007   Dana Jansens
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -45,8 +45,7 @@
 #include <X11/Xutil.h>
 
 /*! The event mask to grab on client windows */
-#define CLIENT_EVENTMASK (PropertyChangeMask | FocusChangeMask | \
-                          StructureNotifyMask)
+#define CLIENT_EVENTMASK (PropertyChangeMask | StructureNotifyMask)
 
 #define CLIENT_NOPROPAGATEMASK (ButtonPressMask | ButtonReleaseMask | \
                                 ButtonMotionMask)
@@ -57,8 +56,10 @@ typedef struct
     gpointer data;
 } Destructor;
 
-GList      *client_list        = NULL;
-GSList     *client_destructors = NULL;
+GList         *client_list           = NULL;
+
+static GSList *client_destructors    = NULL;
+static Time    client_last_user_time = CurrentTime;
 
 static void client_get_all(ObClient *self);
 static void client_toggle_border(ObClient *self, gboolean show);
@@ -66,6 +67,7 @@ static void client_get_startup_id(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_layer(ObClient *self);
 static void client_get_shaped(ObClient *self);
 static void client_get_mwm_hints(ObClient *self);
 static void client_get_gravity(ObClient *self);
@@ -75,7 +77,6 @@ static void client_change_state(ObClient *self);
 static void client_apply_startup_state(ObClient *self);
 static void client_restore_session_state(ObClient *self);
 static void client_restore_session_stacking(ObClient *self);
-static void client_urgent_notify(ObClient *self);
 
 void client_startup(gboolean reconfig)
 {
@@ -295,11 +296,17 @@ void client_manage(Window window)
     self->wmstate = NormalState;
     self->layer = -1;
     self->desktop = screen_num_desktops; /* always an invalid value */
+    self->user_time = ~0; /* maximum value, always newer than the real time */
 
     client_get_all(self);
     client_restore_session_state(self);
 
-    sn_app_started(self->class);
+    client_calc_layer(self);
+
+    {
+        Time t = sn_app_started(self->startup_id, self->class);
+        if (t) self->user_time = t;
+    }
 
     /* update the focus lists, do this before the call to change_state or
        it can end up in the list twice! */
@@ -326,7 +333,7 @@ void client_manage(Window window)
     /* get and set application level settings */
     settings = get_settings(self);
 
-    stacking_add(CLIENT_AS_WINDOW(self));
+    stacking_add_nonintrusive(CLIENT_AS_WINDOW(self));
     client_restore_session_stacking(self);
 
     if (settings) {
@@ -452,23 +459,69 @@ void client_manage(Window window)
     keyboard_grab_for_client(self, TRUE);
     mouse_grab_for_client(self, TRUE);
 
+    if (activate) {
+        /* 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, client_last_user_time);
+
+        /* If a nothing at all, or a parent was focused, then focus this
+           always
+        */
+        if (!focus_client || client_search_focus_parent(self) != NULL)
+            activate = TRUE;
+        else
+        {
+            /* If time stamp is old, don't steal focus */
+            if (self->user_time && self->user_time < client_last_user_time)
+                activate = FALSE;
+            /* 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)
+                activate = FALSE;
+        }
+
+        if (activate)
+        {
+            /* since focus can change the stacking orders, if we focus the
+               window then the standard raise it gets is not enough, we need
+               to queue one for after the focus change takes place */
+            client_raise(self);
+        } else {
+            ob_debug("Focus stealing prevention activated for %s with time %u "
+                     "(last time %u)\n",
+                     self->title, self->user_time, client_last_user_time);
+            /* if the client isn't focused, then hilite it so the user
+               knows it is there */
+            client_hilite(self, TRUE);
+        }
+    }
+    else {
+        /* This may look rather odd. Well it's because new windows are added
+           to the stacking order non-intrusively. If we're not going to focus
+           the new window or hilite it, then we raise it to the top. This will
+           take affect for things that don't get focused like splash screens.
+           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);
+    }
+
+    /* this has to happen before we try focus the window, but we want it to
+       happen after the client's stacking has been determined or it looks bad
+    */
     client_showhide(self);
 
     /* use client_focus instead of client_activate cuz client_activate does
        stuff like switch desktops etc and I'm not interested in all that when
        a window maps since its not based on an action from the user like
-       clicking a window to activate is. so keep the new window out of the way
+       clicking a window to activate it. so keep the new window out of the way
        but do focus it. */
     if (activate) {
-        /* if using focus_delay, stop the timer now so that focus doesn't go
-           moving on us */
+        /* if using focus_delay, stop the timer now so that focus doesn't
+           go moving on us */
         event_halt_focus_delay();
-
         client_focus(self);
-        /* since focus can change the stacking orders, if we focus the window
-           then the standard raise it gets is not enough, we need to queue one
-           for after the focus change takes place */
-        client_raise(self);
     }
 
     /* client_activate does this but we aret using it so we have to do it
@@ -501,7 +554,8 @@ void client_unmanage(ObClient *self)
     guint j;
     GSList *it;
 
-    ob_debug("Unmanaging window: %lx (%s)\n", self->window, self->class);
+    ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, self->class,
+             self->title ? self->title : "");
 
     g_assert(self != NULL);
 
@@ -619,14 +673,6 @@ void client_unmanage(ObClient *self)
         grab_pointer(FALSE, OB_CURSOR_NONE);
 }
 
-static void client_urgent_notify(ObClient *self)
-{
-    if (self->urgent)
-        frame_flash_start(self->frame);
-    else
-        frame_flash_stop(self->frame);
-}
-
 static void client_restore_session_state(ObClient *self)
 {
     GList *it;
@@ -833,6 +879,7 @@ static void client_get_all(ObClient *self)
        work right (eg tsclient). */
     client_update_transient_for(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);
@@ -841,7 +888,8 @@ static void client_get_all(ObClient *self)
                                 desktop is not specified */
     client_get_shaped(self);
 
-    client_get_state(self);
+    client_get_layer(self); /* if layer hasn't been specified, get it from
+                               other sources if possible */
 
     {
         /* a couple type-based defaults for new windows */
@@ -866,6 +914,7 @@ static void client_get_all(ObClient *self)
     client_update_sm_client_id(self);
     client_update_strut(self);
     client_update_icons(self);
+    client_update_user_time(self, FALSE);
 }
 
 static void client_get_startup_id(ObClient *self)
@@ -933,6 +982,41 @@ static void client_get_desktop(ObClient *self)
     }
 }
 
+static void client_get_layer(ObClient *self)
+{
+    if (!(self->above || self->below)) {
+        if (self->group) {
+            /* apply stuff from the group */
+            GSList *it;
+            gint layer = -2;
+
+            for (it = self->group->members; it; it = g_slist_next(it)) {
+                ObClient *c = it->data;
+                if (c != self && !client_search_transient(self, c) &&
+                    client_normal(self) && client_normal(c))
+                {
+                    layer = MAX(layer,
+                                (c->above ? 1 : (c->below ? -1 : 0)));
+                }
+            }
+            switch (layer) {
+            case -1:
+                self->below = TRUE;
+                break;
+            case -2:
+            case 0:
+                break;
+            case 1:
+                self->above = TRUE;
+                break;
+            default:
+                g_assert_not_reached();
+                break;
+            }
+        }
+    }
+}
+
 static void client_get_state(ObClient *self)
 {
     guint32 *state;
@@ -961,44 +1045,14 @@ static void client_get_state(ObClient *self)
                 self->above = TRUE;
             else if (state[i] == prop_atoms.net_wm_state_below)
                 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)
                 self->undecorated = TRUE;
         }
 
         g_free(state);
     }
-
-    if (!(self->above || self->below)) {
-        if (self->group) {
-            /* apply stuff from the group */
-            GSList *it;
-            gint layer = -2;
-
-            for (it = self->group->members; it; it = g_slist_next(it)) {
-                ObClient *c = it->data;
-                if (c != self && !client_search_transient(self, c) &&
-                    client_normal(self) && client_normal(c))
-                {
-                    layer = MAX(layer,
-                                (c->above ? 1 : (c->below ? -1 : 0)));
-                }
-            }
-            switch (layer) {
-            case -1:
-                self->below = TRUE;
-                break;
-            case -2:
-            case 0:
-                break;
-            case 1:
-                self->above = TRUE;
-                break;
-            default:
-                g_assert_not_reached();
-                break;
-            }
-        }
-    }
 }
 
 static void client_get_shaped(ObClient *self)
@@ -1036,22 +1090,42 @@ void client_update_transient_for(ObClient *self)
                    a dockapp, for example */
                 target = NULL;
             }
-            
+
+            /* THIS IS SO ANNOYING ! ! ! ! Let me explain.... have a seat..
+
+               Setting the transient_for to Root is actually illegal, however
+               applications from time have done this to specify transient for
+               their group.
+
+               Now you can do that by being a TYPE_DIALOG and not setting
+               the transient_for hint at all on your window. But people still
+               use Root, and Kwin is very strange in this regard.
+
+               KWin 3.0 will not consider windows with transient_for set to
+               Root as transient for their group *UNLESS* they are also modal.
+               In that case, it will make them transient for the group. This
+               leads to all sorts of weird behavior from KDE apps which are
+               only tested in KWin. I'd like to follow their behavior just to
+               make this work right with KDE stuff, but that seems wrong.
+            */
             if (!target && self->group) {
                 /* not transient to a client, see if it is transient for a
                    group */
-                if (t == self->group->leader ||
-                    t == None ||
-                    t == RootWindow(ob_display, ob_screen))
-                {
+                if (t == RootWindow(ob_display, ob_screen)) {
                     /* window is a transient for its group! */
                     target = OB_TRAN_GROUP;
                 }
             }
         }
-    } else if (self->type == OB_CLIENT_TYPE_DIALOG && self->group) {
-        self->transient = TRUE;
-        target = OB_TRAN_GROUP;
+    } 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;
+            target = OB_TRAN_GROUP;
+        }
     } else
         self->transient = FALSE;
 
@@ -1459,7 +1533,6 @@ void client_reconfigure(ObClient *self)
 void client_update_wmhints(ObClient *self)
 {
     XWMHints *hints;
-    gboolean ur = FALSE;
     GSList *it;
 
     /* assume a window takes input if it doesnt specify */
@@ -1475,9 +1548,6 @@ void client_update_wmhints(ObClient *self)
             if (hints->flags & StateHint)
                 self->iconic = hints->initial_state == IconicState;
 
-        if (hints->flags & XUrgencyHint)
-            ur = TRUE;
-
         if (!(hints->flags & WindowGroupHint))
             hints->window_group = None;
 
@@ -1538,14 +1608,6 @@ void client_update_wmhints(ObClient *self)
 
         XFree(hints);
     }
-
-    if (ur != self->urgent) {
-        self->urgent = ur;
-        /* fire the urgent callback if we're mapped, otherwise, wait until
-           after we're mapped */
-        if (self->frame)
-            client_urgent_notify(self);
-    }
 }
 
 void client_update_title(ObClient *self)
@@ -1786,23 +1848,6 @@ void client_update_icons(ObClient *self)
             g_assert(i <= num);
         }
 
-        g_free(data);
-    } else if (PROP_GETA32(self->window, kwm_win_icon,
-                           kwm_win_icon, &data, &num)) {
-        if (num == 2) {
-            self->nicons++;
-            self->icons = g_new(ObClientIcon, self->nicons);
-            xerror_set_ignore(TRUE);
-            if (!RrPixmapToRGBA(ob_rr_inst,
-                                data[0], data[1],
-                                &self->icons[self->nicons-1].width,
-                                &self->icons[self->nicons-1].height,
-                                &self->icons[self->nicons-1].data)) {
-                g_free(&self->icons[self->nicons-1]);
-                self->nicons--;
-            }
-            xerror_set_ignore(FALSE);
-        }
         g_free(data);
     } else {
         XWMHints *hints;
@@ -1832,6 +1877,28 @@ void client_update_icons(ObClient *self)
         frame_adjust_icon(self->frame);
 }
 
+void client_update_user_time(ObClient *self, gboolean new_event)
+{
+    guint32 time;
+
+    if (PROP_GET32(self->window, net_wm_user_time, cardinal, &time)) {
+        self->user_time = time;
+        /* we set this every time, not just when it grows, because in practice
+           sometimes time goes backwards! (ntpdate.. yay....) so.. if it goes
+           backward we don't want all windows to stop focusing. we'll just
+           assume noone is setting times older than the last one, cuz that
+           would be pretty stupid anyways
+           However! This is called when a window is mapped to get its user time
+           but it's an old number, it's not changing it from new user
+           interaction, so in that case, don't change the last user time.
+        */
+        if (new_event)
+            client_last_user_time = time;
+
+        /*ob_debug("window 0x%x user time %u\n", self->window, time);*/
+    }
+}
+
 static void client_change_state(ObClient *self)
 {
     gulong state[2];
@@ -1863,12 +1930,12 @@ static void client_change_state(ObClient *self)
         netstate[num++] = prop_atoms.net_wm_state_above;
     if (self->below)
         netstate[num++] = prop_atoms.net_wm_state_below;
+    if (self->demands_attention)
+        netstate[num++] = prop_atoms.net_wm_state_demands_attention;
     if (self->undecorated)
         netstate[num++] = prop_atoms.ob_wm_state_undecorated;
     PROP_SETA32(self->window, net_wm_state, atom, netstate, num);
 
-    client_calc_layer(self);
-
     if (self->frame)
         frame_adjust_state(self->frame);
 }
@@ -1934,20 +2001,21 @@ static ObStackingLayer calc_layer(ObClient *self)
 }
 
 static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
-                                        ObStackingLayer l, gboolean raised)
+                                        ObStackingLayer min, gboolean raised)
 {
     ObStackingLayer old, own;
     GSList *it;
 
     old = self->layer;
     own = calc_layer(self);
-    self->layer = l > own ? l : own;
+    self->layer = MAX(own, min);
 
     for (it = self->transients; it; it = g_slist_next(it))
         client_calc_layer_recursive(it->data, orig,
-                                    l, raised ? raised : l != old);
+                                    self->layer,
+                                    raised ? raised : self->layer != old);
 
-    if (!raised && l != old)
+    if (!raised && self->layer != old)
         if (orig->frame) { /* only restack if the original window is managed */
             stacking_remove(CLIENT_AS_WINDOW(self));
             stacking_add(CLIENT_AS_WINDOW(self));
@@ -1956,17 +2024,16 @@ static void client_calc_layer_recursive(ObClient *self, ObClient *orig,
 
 void client_calc_layer(ObClient *self)
 {
-    ObStackingLayer l;
     ObClient *orig;
+    GSList *it;
 
     orig = self;
 
     /* transients take on the layer of their parents */
-    self = client_search_top_transient(self);
+    it = client_search_all_top_parents(self);
 
-    l = calc_layer(self);
-
-    client_calc_layer_recursive(self, orig, l, FALSE);
+    for (; it; it = g_slist_next(it))
+        client_calc_layer_recursive(it->data, orig, 0, FALSE);
 }
 
 gboolean client_should_show(ObClient *self)
@@ -2033,8 +2100,10 @@ static void client_apply_startup_state(ObClient *self)
         self->shaded = FALSE;
         client_shade(self, TRUE);
     }
-    if (self->urgent)
-        client_urgent_notify(self);
+    if (self->demands_attention) {
+        self->demands_attention = FALSE;
+        client_hilite(self, TRUE);
+    }
   
     if (self->max_vert && self->max_horz) {
         self->max_vert = self->max_horz = FALSE;
@@ -2066,6 +2135,7 @@ void client_configure_full(ObClient *self, ObCorner anchor,
     gboolean moved = FALSE, resized = FALSE;
     guint fdecor = self->frame->decorations;
     gboolean fhorz = self->frame->max_horz;
+    Rect desired_area = {x, y, w, h};
 
     /* make the frame recalculate its dimentions n shit without changing
        anything visible for real, this way the constraints below can work with
@@ -2082,7 +2152,7 @@ void client_configure_full(ObClient *self, ObCorner anchor,
         Rect *a;
         guint i;
 
-        i = client_monitor(self);
+        i = screen_find_monitor(&desired_area);
         a = screen_physical_area_monitor(i);
 
         x = a->x;
@@ -2093,8 +2163,10 @@ void client_configure_full(ObClient *self, ObCorner anchor,
         user = FALSE; /* ignore that increment etc shit when in fullscreen */
     } else {
         Rect *a;
+        guint i;
 
-        a = screen_area_monitor(self->desktop, client_monitor(self));
+        i = screen_find_monitor(&desired_area);
+        a = screen_area_monitor(self->desktop, i);
 
         /* set the size and position if maximized */
         if (self->max_horz) {
@@ -2287,8 +2359,8 @@ void client_fullscreen(ObClient *self, gboolean fs, gboolean savearea)
         self->fullscreen == fs) return;                   /* already done */
 
     self->fullscreen = fs;
-    client_change_state(self); /* change the state hints on the client,
-                                  and adjust out layer/stacking */
+    client_change_state(self); /* change the state hints on the client */
+    client_calc_layer(self);   /* and adjust out layer/stacking */
 
     if (fs) {
         if (savearea)
@@ -2383,19 +2455,18 @@ static void client_iconify_recursive(ObClient *self,
             screen_update_areas();
     }
 
-    /* iconify all transients */
+    /* iconify all direct transients */
     for (it = self->transients; it; it = g_slist_next(it))
-        if (it->data != self) client_iconify_recursive(it->data,
-                                                       iconic, curdesk);
+        if (it->data != self)
+            if (client_is_direct_child(self, it->data))
+                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_transient(self);
-
-    client_iconify_recursive(client_search_top_transient(self),
-                             iconic, curdesk);
+    self = client_search_top_parent(self);
+    client_iconify_recursive(self, iconic, curdesk);
 }
 
 void client_maximize(ObClient *self, gboolean max, gint dir, gboolean savearea)
@@ -2540,6 +2611,20 @@ void client_kill(ObClient *self)
     XKillClient(ob_display, self->window);
 }
 
+void client_hilite(ObClient *self, gboolean hilite)
+{
+    if (self->demands_attention == hilite)
+        return; /* no change */
+
+    /* don't allow focused windows to hilite */
+    self->demands_attention = hilite && !client_focused(self);
+    if (self->demands_attention)
+        frame_flash_start(self->frame);
+    else
+        frame_flash_stop(self->frame);
+    client_change_state(self);
+}
+
 void client_set_desktop_recursive(ObClient *self,
                                   guint target, gboolean donthide)
 {
@@ -2578,14 +2663,23 @@ void client_set_desktop_recursive(ObClient *self,
 
     /* move all transients */
     for (it = self->transients; it; it = g_slist_next(it))
-        if (it->data != self) client_set_desktop_recursive(it->data,
-                                                           target, donthide);
+        if (it->data != self)
+            if (client_is_direct_child(self, it->data))
+                client_set_desktop_recursive(it->data, target, donthide);
 }
 
 void client_set_desktop(ObClient *self, guint target, gboolean donthide)
 {
-    client_set_desktop_recursive(client_search_top_transient(self),
-                                 target, donthide);
+    self = client_search_top_parent(self);
+    client_set_desktop_recursive(self, target, donthide);
+}
+
+gboolean client_is_direct_child(ObClient *parent, ObClient *child)
+{
+    while (child != parent &&
+           child->transient_for && child->transient_for != OB_TRAN_GROUP)
+        child = child->transient_for;
+    return child == parent;
 }
 
 ObClient *client_search_modal_child(ObClient *self)
@@ -2639,6 +2733,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
     gboolean max_vert = self->max_vert;
     gboolean modal = self->modal;
     gboolean iconic = self->iconic;
+    gboolean demands_attention = self->demands_attention;
     gint i;
 
     if (!(action == prop_atoms.net_wm_state_add ||
@@ -2688,6 +2783,10 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
             else if (state == prop_atoms.net_wm_state_below)
                 action = self->below ? prop_atoms.net_wm_state_remove :
                     prop_atoms.net_wm_state_add;
+            else if (state == prop_atoms.net_wm_state_demands_attention)
+                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)
                 action = undecorated ? prop_atoms.net_wm_state_remove :
                     prop_atoms.net_wm_state_add;
@@ -2716,6 +2815,8 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
             } else if (state == prop_atoms.net_wm_state_below) {
                 self->above = FALSE;
                 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) {
                 undecorated = TRUE;
             }
@@ -2741,6 +2842,8 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
                 self->above = FALSE;
             } else if (state == prop_atoms.net_wm_state_below) {
                 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) {
                 undecorated = FALSE;
             }
@@ -2780,16 +2883,17 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2)
     if (iconic != self->iconic)
         client_iconify(self, iconic, FALSE);
 
-    client_calc_layer(self);
+    if (demands_attention != self->demands_attention)
+        client_hilite(self, demands_attention);
+
     client_change_state(self); /* change the hint to reflect these changes */
 }
 
 ObClient *client_focus_target(ObClient *self)
 {
-    ObClient *child;
-     
-    /* if we have a modal child, then focus it, not us */
-    child = client_search_modal_child(client_search_top_transient(self));
+    ObClient *child = NULL;
+
+    child = client_search_modal_child(self);
     if (child) return child;
     return self;
 }
@@ -2841,6 +2945,8 @@ gboolean client_focus(ObClient *self)
         return FALSE;
     }
 
+    ob_debug("Focusing client \"%s\" at time %u\n", self->title, event_curtime);
+
     if (self->can_focus) {
         /* RevertToPointerRoot causes much more headache than RevertToNone, so
            I choose to use it always, hopefully to find errors quicker, if any
@@ -2893,46 +2999,55 @@ void client_unfocus(ObClient *self)
     }
 }
 
-void client_activate(ObClient *self, gboolean here, gboolean user)
+void client_activate(ObClient *self, gboolean here, gboolean user, Time time)
 {
     /* XXX do some stuff here if user is false to determine if we really want
-       to activate it or not (a parent or group member is currently active) */
-
-    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);
+       to activate it or not (a parent or group member is currently
+       active)?
+    */
+    ob_debug("Want to activate window 0x%x with time %u (last time %u), "
+             "source=%s\n",
+             self->window, time, client_last_user_time,
+             (user ? "user" : "application"));
+    if (!user && time && time < client_last_user_time)
+        client_hilite(self, TRUE);
+    else {
+        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);
+        client_focus(self);
 
-    /* we do this 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);
+        /* we do this 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_raise(ObClient *self)
 {
-    action_run_string("Raise", self);
+    action_run_string("Raise", self, CurrentTime);
 }
 
 void client_lower(ObClient *self)
 {
-    action_run_string("Lower", self);
+    action_run_string("Lower", self, CurrentTime);
 }
 
 gboolean client_focused(ObClient *self)
@@ -3129,40 +3244,29 @@ void client_set_undecorated(ObClient *self, gboolean undecorated)
     }
 }
 
-/* Determines which physical monitor a client is on by calculating the
-   area of the part of the client on each monitor.  The number of the
-   monitor containing the greatest area of the client is returned.*/
 guint client_monitor(ObClient *self)
 {
-    guint i;
-    guint most = 0;
-    guint mostv = 0;
-
-    for (i = 0; i < screen_num_monitors; ++i) {
-        Rect *area = screen_physical_area_monitor(i);
-        if (RECT_INTERSECTS_RECT(*area, self->frame->area)) {
-            Rect r;
-            guint v;
-
-            RECT_SET_INTERSECTION(r, *area, self->frame->area);
-            v = r.width * r.height;
+    return screen_find_monitor(&self->frame->area);
+}
 
-            if (v > mostv) {
-                mostv = v;
-                most = i;
-            }
-        }
-    }
-    return most;
+ObClient *client_search_top_parent(ObClient *self)
+{
+    while (self->transient_for && self->transient_for != OB_TRAN_GROUP)
+        self = self->transient_for;
+    return self;
 }
 
-ObClient *client_search_top_transient(ObClient *self)
+GSList *client_search_all_top_parents(ObClient *self)
 {
-    /* move up the transient chain as far as possible */
-    if (self->transient_for) {
-        if (self->transient_for != OB_TRAN_GROUP) {
-            return client_search_top_transient(self->transient_for);
-        } else {
+    GSList *ret = NULL;
+
+    /* move up the direct transient chain as far as possible */
+    while (self->transient_for && self->transient_for != OB_TRAN_GROUP)
+        self = self->transient_for;
+
+    if (!self->transient_for)
+        ret = g_slist_prepend(ret, self);
+    else {
             GSList *it;
 
             g_assert(self->group);
@@ -3170,16 +3274,15 @@ ObClient *client_search_top_transient(ObClient *self)
             for (it = self->group->members; it; it = g_slist_next(it)) {
                 ObClient *c = it->data;
 
-                /* checking transient_for prevents infinate loops! */
-                if (c != self && !c->transient_for)
-                    break;
+                if (!c->transient_for)
+                    ret = g_slist_prepend(ret, c);
             }
-            if (it)
-                return it->data;
-        }
+
+            if (ret == NULL) /* no group parents */
+                ret = g_slist_prepend(ret, self);
     }
 
-    return self;
+    return ret;
 }
 
 ObClient *client_search_focus_parent(ObClient *self)
This page took 0.041201 seconds and 4 git commands to generate.