From 72d9f8e21ad699a9791dae72acd26cb840f638f2 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Tue, 2 Aug 2011 14:45:21 -0400 Subject: [PATCH] Add a means to duplicate ObClientSet and fix destroy notifications. - set the destroy notification when making a set with a single window, not when making an empty set. - always add/remove the destroy notification when creating/destroying the hash table --- openbox/client_set.c | 61 ++++++++++++++++++++++++++++++++++---------- openbox/client_set.h | 15 ++++++----- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/openbox/client_set.c b/openbox/client_set.c index a949ed99..f2970939 100644 --- a/openbox/client_set.c +++ b/openbox/client_set.c @@ -33,6 +33,20 @@ static void client_destroyed(ObClient *client, ObClientSet *set) g_hash_table_remove(set->h, &client->window); } +static void client_set_create_hash(ObClientSet *set) +{ + set->h = g_hash_table_new(g_int_hash, g_int_equal); + client_add_destroy_notify((ObClientCallback)client_destroyed, set); +} + +static void client_set_destroy_hash(ObClientSet *set) +{ + g_hash_table_unref(set->h); + client_remove_destroy_notify_data( + (ObClientCallback)client_destroyed, set); + set->h = NULL; +} + ObClientSet* client_set_empty(void) { ObClientSet *set; @@ -40,7 +54,6 @@ ObClientSet* client_set_empty(void) set = g_slice_new(ObClientSet); set->all = FALSE; set->h = NULL; - client_add_destroy_notify((ObClientCallback)client_destroyed, set); return set; } @@ -51,7 +64,7 @@ ObClientSet* client_set_single(ObClient *c) if (!c) return NULL; set = g_slice_new(ObClientSet); set->all = FALSE; - set->h = g_hash_table_new(g_int_hash, g_int_equal); + client_set_create_hash(set); g_hash_table_insert(set->h, &c->window, c); return set; } @@ -68,13 +81,37 @@ ObClientSet* client_set_all(void) return set; } +static void foreach_clone(gpointer k, gpointer v, gpointer u) +{ + ObClient *c = v; + GHashTable *seth = u; + g_hash_table_insert(seth, &c->window, c); +} + +ObClientSet* client_set_clone(ObClientSet *a) +{ + ObClientSet *set; + + if (!a) return NULL; + set = g_slice_new(ObClientSet); + set->all = a->all; + if (!a->h) set->h = NULL; + else { + client_set_create_hash(set); + g_hash_table_foreach(a->h, foreach_clone, set->h); + } + return set; +} + void client_set_destroy(ObClientSet *set) { if (set) { if (!set->all) { - client_remove_destroy_notify_data( - (ObClientCallback)client_destroyed, set); - if (set->h) g_hash_table_destroy(set->h); + if (set->h) { + client_remove_destroy_notify_data( + (ObClientCallback)client_destroyed, set); + g_hash_table_destroy(set->h); + } } g_slice_free(ObClientSet, set); } @@ -168,7 +205,8 @@ ObClientSet* client_set_minus(ObClientSet *a, ObClientSet *b) g_return_val_if_fail(b != NULL, NULL); if (a == b) { - if (a->h) g_hash_table_unref(a->h); + if (a->h) + client_set_destroy_hash(a); a->all = FALSE; return a; } @@ -234,10 +272,8 @@ ObClientSet* client_set_reduce(ObClientSet *set, ObClientSetReduceFunc f, d.f = f; d.data = data; g_hash_table_foreach_remove(set->h, foreach_reduce, &d); - if (g_hash_table_size(set->h) == 0) { - g_hash_table_unref(set->h); - set->h = NULL; - } + if (g_hash_table_size(set->h) == 0) + client_set_destroy_hash(set); return set; } @@ -258,14 +294,13 @@ ObClientSet* client_set_expand(ObClientSet *set, ObClientSetExpandFunc f, if (!set->h || !g_hash_table_lookup(set->h, &c->window)) if (f(c, data)) { if (!set->h) - set->h = g_hash_table_new(g_int_hash, g_int_equal); + client_set_create_hash(set); g_hash_table_insert(set->h, &c->window, c); } ++avail; } if (g_hash_table_size(set->h) == avail) { - g_hash_table_unref(set->h); - set->h = NULL; + client_set_destroy_hash(set); set->all = TRUE; } return set; diff --git a/openbox/client_set.h b/openbox/client_set.h index 2ec50716..33474493 100644 --- a/openbox/client_set.h +++ b/openbox/client_set.h @@ -32,20 +32,23 @@ ObClientSet* client_set_single(struct _ObClient *c); /*! Returns a new set of clients with all possible clients in it. */ ObClientSet* client_set_all(void); +/*! Returns an identical set to @a. */ +ObClientSet* client_set_clone(ObClientSet *a); + void client_set_destroy(ObClientSet *set); -/* Returns a new set which contains all clients in either @a or @b. The sets - @a and @b are considered freed once passed to this function. +/*! Returns a new set which contains all clients in either @a or @b. The sets + @a and @b are considered freed once passed to this function. */ ObClientSet* client_set_union(ObClientSet *a, ObClientSet *b); -/* Returns a new set which contains all clients in both @a and @b. The sets - @a and @b are considered freed once passed to this function. +/*! Returns a new set which contains all clients in both @a and @b. The sets + @a and @b are considered freed once passed to this function. */ ObClientSet* client_set_intersection(ObClientSet *a, ObClientSet *b); -/* Returns a new set which contains all clients in @a but not in @b. The sets - @a and @b are considered freed once passed to this function. +/*! Returns a new set which contains all clients in @a but not in @b. The sets + @a and @b are considered freed once passed to this function. */ ObClientSet* client_set_minus(ObClientSet *a, ObClientSet *b); -- 2.34.1