Fix expand/reduce in the full or empty set cases.
authorDana Jansens <danakj@orodu.net>
Tue, 2 Aug 2011 17:31:23 +0000 (13:31 -0400)
committerDana Jansens <danakj@orodu.net>
Sun, 16 Oct 2011 22:55:15 +0000 (18:55 -0400)
openbox/client_set.c
openbox/client_set.h

index 6b86b9795d4d2c48fdd1e697c6356e2b02a8a01f..ab6085646b6ec4e15647a3ae58f1fbac02deb852 100644 (file)
@@ -163,6 +163,12 @@ static gboolean foreach_reduce(gpointer k, gpointer v, gpointer u)
     return d->f(c, d->data);
 }
 
+static gboolean func_invert(struct _ObClient *c, gpointer data)
+{
+    struct ObClientSetForeachReduce *d = data;
+    return !d->f(c, d->data);
+}
+
 ObClientSet* client_set_reduce(ObClientSet *set, ObClientSetReduceFunc f,
                                gpointer data)
 {
@@ -171,6 +177,22 @@ ObClientSet* client_set_reduce(ObClientSet *set, ObClientSetReduceFunc f,
     g_return_val_if_fail(set != NULL, NULL);
     g_return_val_if_fail(f != NULL, NULL);
 
+    if (set->all) {
+        struct ObClientSetForeachReduce *d;
+
+        /* use set expansion on an empty set rather than building a full set
+           and then removing stuff.  but we're given a reduce function.
+           so when reduce says TRUE, we want to add (expand) it.
+           we use func_invert() to do this.
+        */
+        set->all = FALSE; /* make it empty */
+        d.f = f;
+        d.data = data;
+        return client_set_expand(set, func_invert, &d);
+    }
+
+    if (!set->h) return set; /* already empty */
+
     d.f = f;
     d.data = data;
     g_hash_table_foreach_remove(set->h, foreach_reduce, &d);
@@ -185,10 +207,14 @@ ObClientSet* client_set_expand(ObClientSet *set, ObClientSetExpandFunc f,
                                gpointer data)
 {
     GList *it;
+    gint avail;
 
     g_return_val_if_fail(set != NULL, NULL);
     g_return_val_if_fail(f != NULL, NULL);
 
+    if (set->all) return set; /* already full */
+
+    avail = 0;
     for (it = client_list; it; it = g_list_next(it)) {
         ObClient *c = it->data;
         if (!set->h || !g_hash_table_lookup(set->h, &c->window))
@@ -197,6 +223,12 @@ ObClientSet* client_set_expand(ObClientSet *set, ObClientSetExpandFunc f,
                     set->h = g_hash_table_new(g_int_hash, g_int_equal);
                 g_hash_table_insert(set->h, &c->window, c);
             }
+        ++avail;
+    }
+    if (g_hash_table_size(set->h) == avail) {
+        g_hash_table_destroy(set->h);
+        set->h = NULL;
+        set->all = TRUE;
     }
     return set;
 }
index 6e930019f39f6cc540d3056687ea41bc9dd20adf..8d35ab3a615ca5550df16ee72c2458320c566627 100644 (file)
@@ -30,7 +30,7 @@ ObClientSet* client_set_empty(void);
 /*! Returns a new set of clients with a single client in it.
   The client is the currently targeted window. */
 ObClientSet* client_set_single(void);
-/*! Returns a new set of clients with all possible client in it.*/
+/*! Returns a new set of clients with all possible clients in it. */
 ObClientSet* client_set_all(void);
 
 void client_set_destroy(ObClientSet *set);