From b8f3a5bb5416dacfc738cc67ba117afb21218c17 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Fri, 29 Jul 2011 16:00:02 -0400 Subject: [PATCH] Add ObClientSet data type. It holds a set of clients ! The sets can be modified by union and intersection, and can have clients added or removed with a test callback function. They use a GHashTable underneath. --- Makefile.am | 2 + openbox/client_set.c | 144 +++++++++++++++++++++++++++++++++++++++++++ openbox/client_set.h | 55 +++++++++++++++++ 3 files changed, 201 insertions(+) create mode 100644 openbox/client_set.c create mode 100644 openbox/client_set.h diff --git a/Makefile.am b/Makefile.am index d92253f9..3ca51665 100644 --- a/Makefile.am +++ b/Makefile.am @@ -256,6 +256,8 @@ openbox_openbox_SOURCES = \ openbox/client_list_combined_menu.h \ openbox/client_menu.c \ openbox/client_menu.h \ + openbox/client_set.c \ + openbox/client_set.h \ openbox/config.c \ openbox/config.h \ openbox/debug.c \ diff --git a/openbox/client_set.c b/openbox/client_set.c new file mode 100644 index 00000000..9f70e7cb --- /dev/null +++ b/openbox/client_set.c @@ -0,0 +1,144 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + client_set.c for the Openbox window manager + Copyright (c) 2011 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_set.h" +#include "client.h" +#include "event.h" + +#include + +void client_destroyed(ObClient *client, ObClientSet *set); + +struct _ObClientSet { + GHashTable *h; +}; + +static ObClientSet* empty_set(void) +{ + ObClientSet *set; + + set = g_slice_new(ObClientSet); + set->h = g_hash_table_new(g_int_hash, g_int_equal); + client_add_destroy_notify((ObClientCallback)client_destroyed, set); + return set; +} + +ObClientSet* client_set_single(void) +{ + struct _ObClient *c; + ObClientSet *set; + + c = event_current_target(); + if (!c) return NULL; + set = empty_set(); + g_hash_table_insert(set->h, &c->window, c); + return set; +} + +/*! Returns a new set of clients with all possible client in it.*/ +ObClientSet* client_set_all(void) +{ + ObClientSet *set; + GList *it; + + if (!client_list) return NULL; + set = g_slice_new(ObClientSet); + set->h = g_hash_table_new(g_int_hash, g_int_equal); + for (it = client_list; it; it = g_list_next(it)) { + ObClient *c = it->data; + g_hash_table_insert(set->h, &c->window, c); + } + client_add_destroy_notify((ObClientCallback)client_destroyed, set); + return set; +} + +void client_destroyed(ObClient *client, ObClientSet *set) +{ + g_hash_table_remove(set->h, &client->window); +} + +void client_set_destroy(ObClientSet *set) +{ + client_remove_destroy_notify_data((ObClientCallback)client_destroyed, set); + g_hash_table_destroy(set->h); + g_slice_free(ObClientSet, set); +} + +static void foreach_union(gpointer k, gpointer v, gpointer u) +{ + GHashTable *set = u; + g_hash_table_insert(set, k, v); /* add everything in the other 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. +*/ +ObClientSet* client_set_union(ObClientSet *a, ObClientSet *b) +{ + g_hash_table_foreach(b->h, foreach_union, a->h); + client_set_destroy(b); + return a; +} + +static gboolean foreach_intersection(gpointer k, gpointer v, gpointer u) +{ + GHashTable *set = u; + return !g_hash_table_lookup(set, k); /* remove if not in the other set */ +} + +/* 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) +{ + g_hash_table_foreach_remove(a->h, foreach_intersection, b->h); + client_set_destroy(b); + return a; +} + +static gboolean foreach_reduce(gpointer k, gpointer v, gpointer u) +{ + ObClient *c = v; + ObClientSetReduceFunc f = u; + return f(c); +} + +ObClientSet* client_set_reduce(ObClientSet *set, ObClientSetReduceFunc f) +{ + g_hash_table_foreach_remove(set->h, foreach_reduce, f); + if (g_hash_table_size(set->h) > 0) + return set; + client_set_destroy(set); + return NULL; +} + +ObClientSet* client_set_expand(ObClientSet *set, ObClientSetExpandFunc f) +{ + GList *it; + + for (it = client_list; it; it = g_list_next(it)) { + ObClient *c = it->data; + if (!set || !g_hash_table_lookup(set->h, &c->window)) { + if (f(c)) { + if (!set) set = empty_set(); + g_hash_table_insert(set->h, &c->window, c); + } + } + } + return set; +} diff --git a/openbox/client_set.h b/openbox/client_set.h new file mode 100644 index 00000000..efdf2002 --- /dev/null +++ b/openbox/client_set.h @@ -0,0 +1,55 @@ +/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + client_set.h for the Openbox window manager + Copyright (c) 2011 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 + +struct _ObClient; + +/*! A set of ObClients. An empty set is always a NULL pointer. */ +typedef struct _ObClientSet ObClientSet; + +typedef gboolean (*ObClientSetReduceFunc)(struct _ObClient *c); +typedef gboolean (*ObClientSetExpandFunc)(struct _ObClient *c); + +/*! 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.*/ +ObClientSet* client_set_all(void); + +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. +*/ +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. +*/ +ObClientSet* client_set_intersection(ObClientSet *a, ObClientSet *b); + +/*! Reduce a set of clients. The function @f is called for each client + currently in the set. For each client that it returns TRUE, the client will + be removed from the set. */ +ObClientSet* client_set_reduce(ObClientSet *set, ObClientSetReduceFunc f); + +/*! Expand a set of clients. The function @f is called for each client + not currently in the set. For each client that it returns TRUE, the client + will be added to the set. */ +ObClientSet* client_set_expand(ObClientSet *set, ObClientSetExpandFunc f); -- 2.34.1