merge r5742-5744 from trunk
authorDana Jansens <danakj@orodu.net>
Wed, 18 Apr 2007 19:25:45 +0000 (19:25 +0000)
committerDana Jansens <danakj@orodu.net>
Wed, 18 Apr 2007 19:25:45 +0000 (19:25 +0000)
Makefile.am
openbox/client.c
openbox/client.h
openbox/client_time_heap.c [new file with mode: 0644]
openbox/client_time_heap.h [new file with mode: 0644]
openbox/event.c
openbox/stacking.c

index 3a68ae62fdc5920e135cd0a9156a949713778a49..7e9e9363ade85819ef2cc1adb4ec9f66a68ed75c 100644 (file)
@@ -134,6 +134,8 @@ openbox_openbox_SOURCES = \
        openbox/action.h \
        openbox/client.c \
        openbox/client.h \
+       openbox/client_time_heap.c \
+       openbox/client_time_heap.h \
        openbox/client_list_menu.c \
        openbox/client_list_menu.h \
        openbox/client_list_combined_menu.c \
index 7f4cba2129003c14b2908bfbf798c29b5d575104..9d679738fee34f1523f72d488e9e6b6060e6acf1 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include "client.h"
+#include "client_time_heap.h"
 #include "debug.h"
 #include "startupnotify.h"
 #include "dock.h"
@@ -56,10 +57,10 @@ typedef struct
     gpointer data;
 } Destructor;
 
-GList         *client_list           = NULL;
+GList            *client_list        = NULL;
+ObClientTimeHeap *client_user_times  = 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);
@@ -84,11 +85,13 @@ void client_startup(gboolean reconfig)
 {
     if (reconfig) return;
 
+    client_user_times = client_time_heap_new();
     client_set_list();
 }
 
 void client_shutdown(gboolean reconfig)
 {
+    client_time_heap_free(client_user_times);
 }
 
 void client_add_destructor(ObClientDestructor func, gpointer data)
@@ -272,7 +275,7 @@ void client_manage(Window window)
     self->wmstate = WithdrawnState; /* make sure it gets updated first time */
     self->layer = -1;
     self->desktop = screen_num_desktops; /* always an invalid value */
-    self->user_time = client_last_user_time;
+    self->user_time = CurrentTime;
 
     client_get_all(self);
     /* per-app settings override stuff, and return the settings for other
@@ -405,7 +408,8 @@ void client_manage(Window window)
     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);
+                 self->window, self->user_time,
+                 client_time_heap_maximum(client_user_times));
 
         /* If a nothing at all, or a parent was focused, then focus this
            always
@@ -414,9 +418,10 @@ void client_manage(Window window)
             activate = TRUE;
         else
         {
+            guint32 last_time = client_time_heap_maximum(client_user_times);
             /* If time stamp is old, don't steal focus */
-            if (self->user_time &&
-                !event_time_after(self->user_time, client_last_user_time))
+            if (self->user_time && last_time &&
+                !event_time_after(self->user_time, last_time))
             {
                 activate = FALSE;
             }
@@ -436,7 +441,8 @@ void client_manage(Window window)
         } 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);
+                     self->title, self->user_time,
+                     client_time_heap_maximum(client_user_times));
             /* if the client isn't focused, then hilite it so the user
                knows it is there */
             client_hilite(self, TRUE);
@@ -538,6 +544,9 @@ void client_unmanage(ObClient *self)
     /* we dont want events no more */
     XSelectInput(ob_display, self->window, NoEventMask);
 
+    /* remove from the time heap */
+    client_time_heap_remove(client_user_times, self);
+
     client_list = g_list_remove(client_list, self);
     stacking_remove(self);
     g_hash_table_remove(window_map, &self->window);
@@ -949,7 +958,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);
+    client_update_user_time(self);
 }
 
 static void client_get_startup_id(ObClient *self)
@@ -1852,27 +1861,35 @@ void client_update_icons(ObClient *self)
         frame_adjust_icon(self->frame);
 }
 
-void client_update_user_time(ObClient *self, gboolean new_event)
+void client_update_user_time(ObClient *self)
 {
     guint32 time;
 
     if (PROP_GET32(self->window, net_wm_user_time, cardinal, &time)) {
-        self->user_time = time;
+        guint32 otime = self->user_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;
+        self->user_time = time;
+        /* adjust the time heap - windows with CurrentTime for their user_time
+           are not in the heap */
+        if (time == CurrentTime && otime != CurrentTime)
+            client_time_heap_remove(client_user_times, self);
+        else if (time != CurrentTime && otime == CurrentTime)
+            client_time_heap_add(client_user_times, self);
+        else if (time != CurrentTime && otime != CurrentTime) {
+            if (event_time_after(time, otime))
+                client_time_heap_increase_key(client_user_times, self);
+            else
+                client_time_heap_decrease_key(client_user_times, self);
+        }
 
         /*
         ob_debug("window %s user time %u\n", self->title, time);
-        ob_debug("last user time %u\n", client_last_user_time);
+        ob_debug("last user time %u\n", client_time_heap_maximum(client_user_times));
         */
     }
 }
@@ -3067,16 +3084,21 @@ static void client_unfocus(ObClient *self)
 
 void client_activate(ObClient *self, gboolean here, gboolean user)
 {
+    guint32 last_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)?
     */
     ob_debug("Want to activate window 0x%x with time %u (last time %u), "
              "source=%s\n",
-             self->window, event_curtime, client_last_user_time,
+             self->window, event_curtime,
+             client_time_heap_maximum(client_user_times),
              (user ? "user" : "application"));
-    if (!user && event_curtime &&
-        !event_time_after(event_curtime, client_last_user_time))
+
+    last_time = client_time_heap_maximum(client_user_times);
+    if (!user && event_curtime && last_time &&
+        !event_time_after(event_curtime, last_time))
     {
         client_hilite(self, TRUE);
     } else {
index 1c4a2b1fc5c4b796835dc296301fcf780da30223..bb1d4c9f15d5ca2b9aad35aaff2fdeb85143fb8e 100644 (file)
@@ -2,7 +2,7 @@
 
    client.h 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
@@ -32,6 +32,7 @@
 struct _ObFrame;
 struct _ObGroup;
 struct _ObSessionState;
+struct _ObClientTimeHeap;
 
 typedef struct _ObClient      ObClient;
 typedef struct _ObClientIcon  ObClientIcon;
@@ -300,6 +301,7 @@ struct _ObAppSettings
 };
 
 extern GList *client_list;
+extern struct _ObClientTimeHeap *client_user_times;
 
 void client_startup(gboolean reconfig);
 void client_shutdown(gboolean reconfig);
@@ -559,7 +561,7 @@ void client_update_strut(ObClient *self);
 /*! Updates the window's icons */
 void client_update_icons(ObClient *self);
 /*! Updates the window's user time */
-void client_update_user_time(ObClient *self, gboolean new_event);
+void client_update_user_time(ObClient *self);
 
 /*! Set up what decor should be shown on the window and what functions should
   be allowed (ObClient::decorations and ObClient::functions).
diff --git a/openbox/client_time_heap.c b/openbox/client_time_heap.c
new file mode 100644 (file)
index 0000000..1adefdd
--- /dev/null
@@ -0,0 +1,158 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+   
+   client_time_heap.c for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   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
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#include "client_time_heap.h"
+#include "client.h"
+
+#include <X11/Xlib.h>
+
+/* Helper functions for the heap */
+
+#define isroot(n) (n == 0)
+#define parent(n) ((n-1)/2)
+#define right(n) ((n+1)*2)
+#define left(n) (right(n)-1)
+#define exists(n) (n < h->nodes->len)
+#define key(n) (((ObClient*)h->nodes->pdata[n])->user_time)
+
+static inline void swap(ObClientTimeHeap *h, guint a, guint b)
+{
+    gpointer c;
+
+    g_assert(a < h->nodes->len);
+    g_assert(b < h->nodes->len);
+
+    c = h->nodes->pdata[a];
+    h->nodes->pdata[a] = h->nodes->pdata[b];
+    h->nodes->pdata[b] = c;
+}
+
+static inline void heapify(ObClientTimeHeap *h, guint n)
+{
+    g_assert(exists(n));
+
+    /* fix up the heap, move it down below keys it's smaller than */
+    while ((exists(left(n)) && key(n) < key(left(n))) ||
+           (exists(right(n)) && key(n) < key(right(n))))
+    {
+        if (exists(left(n)) && exists(right(n)))
+            if (key(left(n)) > key(right(n))) {
+                swap(h, n, left(n));
+                n = left(n);
+            } else {
+                swap(h, n, right(n));
+                n = right(n);
+            }
+        else {
+            /* its impossible in this structure to have a right child but no
+               left child */
+            swap(h, n, left(n));
+            n = left(n);
+        }
+    }
+}
+
+ObClientTimeHeap* client_time_heap_new()
+{
+    ObClientTimeHeap *h = g_new0(ObClientTimeHeap, 1);
+    h->nodes = g_ptr_array_new();
+    return h;
+}
+
+void client_time_heap_free(ObClientTimeHeap *h)
+{
+    if (h != NULL) {
+        /* all the clients should be removed before the heap is destroyed. */
+        g_assert(h->nodes->len == 0);
+        g_ptr_array_free(h->nodes, TRUE);
+        g_free(h);
+    }
+}
+
+guint32 client_time_heap_maximum(ObClientTimeHeap *h)
+{
+    if (h->nodes->len == 0)
+        return CurrentTime;
+    else
+        return key(0);
+}
+
+
+void client_time_heap_add(ObClientTimeHeap *h, ObClient *c)
+{
+    guint n;
+
+    /* insert it as the last leaf */
+    g_ptr_array_add(h->nodes, c);
+    n = h->nodes->len - 1;
+
+    /* move it up to its proper place */
+    while (!isroot(n) && key(n) > key(parent(n))) {
+        swap(h, n, parent(n));
+        n = parent(n);
+    }
+}
+
+void client_time_heap_remove(ObClientTimeHeap *h, ObClient *c)
+{
+    /* find the client */
+    guint n;
+    for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n);
+
+    /* if the client is in the heap */
+    if (n < h->nodes->len) {
+        /* move it to a leaf and delete it from the heap */
+        swap(h, n, h->nodes->len-1);
+        g_ptr_array_remove_index(h->nodes, h->nodes->len-1);
+
+        /* move the swapped leaf down to its proper place if it wasn't just
+           deleted */
+        if (exists(n))
+            heapify(h, n);
+    }
+}
+
+void client_time_heap_decrease_key(ObClientTimeHeap *h, ObClient *c)
+{
+    /* find the client */
+    guint n;
+    for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n);
+
+    /* if the client is in the heap */
+    if (n < h->nodes->len) {
+        /* move it down to its proper place */
+        heapify(h, n);
+    }
+}
+
+void client_time_heap_increase_key(ObClientTimeHeap *h, ObClient *c)
+{
+    /* find the client */
+    guint n;
+    for (n = 0; h->nodes->pdata[n] != c && n < h->nodes->len; ++n);
+
+    /* if the client is in the heap */
+    if (n < h->nodes->len) {
+        /* move it up to its proper place */
+        while (!isroot(n) && key(n) > key(parent(n))) {
+            swap(h, n, parent(n));
+            n = parent(n);
+        }
+    }
+}
diff --git a/openbox/client_time_heap.h b/openbox/client_time_heap.h
new file mode 100644 (file)
index 0000000..e57de5f
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
+
+   client_time_heap.h for the Openbox window manager
+   Copyright (c) 2006        Mikael Magnusson
+   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
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   See the COPYING file for a copy of the GNU General Public License.
+*/
+
+#ifndef __client_time_heap_h
+#define __client_time_heap_h
+
+#include <glib.h>
+
+struct _ObClient *client;
+
+typedef struct _ObClientTimeHeap     ObClientTimeHeap;
+typedef struct _ObClientTimeHeapNode ObClientTimeHeapNode;
+
+/*! A min-heap of the clients based on their user_time as the key */
+struct _ObClientTimeHeap
+{
+    /* The nodes in the heap */
+    GPtrArray *nodes;
+};
+
+ObClientTimeHeap* client_time_heap_new          ();
+void              client_time_heap_free         (ObClientTimeHeap *h);
+
+guint32           client_time_heap_maximum      (ObClientTimeHeap *h);
+
+void              client_time_heap_add          (ObClientTimeHeap *h,
+                                                 struct _ObClient *c);
+void              client_time_heap_remove       (ObClientTimeHeap *h,
+                                                 struct _ObClient *c);
+void              client_time_heap_decrease_key (ObClientTimeHeap *h,
+                                                 struct _ObClient *c);
+void              client_time_heap_increase_key (ObClientTimeHeap *h,
+                                                 struct _ObClient *c);
+
+#endif
index 7dfcc0c70d91e527f1a979aae83600bd4da4561c..a2f0ef6adc2fa8555229a93de6c1d431f3e61b2d 100644 (file)
@@ -1163,7 +1163,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
             client_update_icons(client);
         }
         else if (msgtype == prop_atoms.net_wm_user_time) {
-            client_update_user_time(client, TRUE);
+            client_update_user_time(client);
         }
         else if (msgtype == prop_atoms.sm_client_id) {
             client_update_sm_client_id(client);
@@ -1378,6 +1378,9 @@ void event_ignore_queued_enters()
 
 gboolean event_time_after(Time t1, Time t2)
 {
+    g_assert(t1 != CurrentTime);
+    g_assert(t2 != CurrentTime);
+
     /*
       Timestamp values wrap around (after about 49.7 days). The server, given
       its current time is represented by timestamp T, always interprets
index cb8eaf31a996fd72c29dce49d01dd275be80d908..f3173c4d55e83cd35605f94421d4cfa4e3391432 100644 (file)
@@ -408,8 +408,10 @@ void stacking_add_nonintrusive(ObWindow *win)
         }
     }
     if (!it_below) {
-        /* out of ideas, just add it normally... */
-        stacking_add(win);
+        /* there is no window to put this directly above, so put it at the
+           bottom */
+        stacking_list = g_list_prepend(stacking_list, win);
+        stacking_lower(win);
     } else {
         /* make sure it's not in the wrong layer though ! */
         for (; it_below; it_below = g_list_next(it_below))