1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 client_set.c for the Openbox window manager
4 Copyright (c) 2011 Dana Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
19 #include "client_set.h"
31 static void client_destroyed(ObClient *client, ObClientSet *set)
33 g_hash_table_remove(set->h, &client->window);
36 static void client_set_create_hash(ObClientSet *set)
38 set->h = g_hash_table_new(g_int_hash, g_int_equal);
39 client_add_destroy_notify((ObClientCallback)client_destroyed, set);
42 static void client_set_destroy_hash(ObClientSet *set)
44 g_hash_table_unref(set->h);
45 client_remove_destroy_notify_data(
46 (ObClientCallback)client_destroyed, set);
50 ObClientSet* client_set_empty(void)
54 set = g_slice_new(ObClientSet);
60 ObClientSet* client_set_single(ObClient *c)
64 set = client_set_empty();
66 client_set_create_hash(set);
67 g_hash_table_insert(set->h, &c->window, c);
72 /*! Returns a new set of clients with all possible client in it.*/
73 ObClientSet* client_set_all(void)
77 if (!client_list) return NULL;
78 set = g_slice_new(ObClientSet);
84 static void foreach_clone(gpointer k, gpointer v, gpointer u)
88 g_hash_table_insert(seth, &c->window, c);
91 ObClientSet* client_set_clone(const ObClientSet *a)
96 set = g_slice_new(ObClientSet);
98 if (!a->h) set->h = NULL;
100 client_set_create_hash(set);
101 g_hash_table_foreach(a->h, foreach_clone, set->h);
106 void client_set_destroy(ObClientSet *set)
111 client_remove_destroy_notify_data(
112 (ObClientCallback)client_destroyed, set);
113 g_hash_table_destroy(set->h);
116 g_slice_free(ObClientSet, set);
120 static void foreach_union(gpointer k, gpointer v, gpointer u)
123 g_hash_table_insert(set, k, v); /* add everything in the other set */
126 /* Returns a new set which contains all clients in either @a or @b. The sets
127 @a and @b are considered freed once passed to this function.
129 ObClientSet* client_set_union(ObClientSet *a, ObClientSet *b)
131 g_return_val_if_fail(a != NULL, NULL);
132 g_return_val_if_fail(b != NULL, NULL);
137 client_set_destroy(b);
141 client_set_destroy(a);
145 client_set_destroy(a);
149 client_set_destroy(b);
153 g_hash_table_foreach(b->h, foreach_union, a->h);
154 client_set_destroy(b);
158 static gboolean foreach_intersection(gpointer k, gpointer v, gpointer u)
161 return !g_hash_table_lookup(set, k); /* remove if not in the other set */
164 /* Returns a new set which contains all clients in both @a and @b. The sets
165 @a and @b are considered freed once passed to this function.
167 ObClientSet* client_set_intersection(ObClientSet *a, ObClientSet *b)
169 g_return_val_if_fail(a != NULL, NULL);
170 g_return_val_if_fail(b != NULL, NULL);
175 client_set_destroy(a);
179 client_set_destroy(b);
183 client_set_destroy(b);
187 client_set_destroy(a);
191 g_hash_table_foreach_remove(a->h, foreach_intersection, b->h);
192 client_set_destroy(b);
196 static gboolean reduce_minus(struct _ObClient *c, gpointer data)
198 ObClientSet *b = data;
199 return client_set_contains(b, c);
202 ObClientSet* client_set_minus(ObClientSet *a, ObClientSet *b)
204 g_return_val_if_fail(a != NULL, NULL);
205 g_return_val_if_fail(b != NULL, NULL);
209 client_set_destroy_hash(a);
214 client_set_destroy(a);
215 b->all = FALSE; /* make empty */
219 client_set_destroy(b);
223 client_set_destroy(b);
227 return client_set_reduce(a, reduce_minus, b);
230 struct ObClientSetForeachReduce {
231 ObClientSetReduceFunc f;
235 static gboolean foreach_reduce(gpointer k, gpointer v, gpointer u)
238 struct ObClientSetForeachReduce *d = u;
239 return d->f(c, d->data);
242 static gboolean func_invert(struct _ObClient *c, gpointer data)
244 struct ObClientSetForeachReduce *d = data;
245 return !d->f(c, d->data);
248 ObClientSet* client_set_reduce(ObClientSet *set, ObClientSetReduceFunc f,
251 struct ObClientSetForeachReduce d;
253 g_return_val_if_fail(set != NULL, NULL);
254 g_return_val_if_fail(f != NULL, NULL);
257 struct ObClientSetForeachReduce d;
259 /* use set expansion on an empty set rather than building a full set
260 and then removing stuff. but we're given a reduce function.
261 so when reduce says TRUE, we want to add (expand) it.
262 we use func_invert() to do this.
264 set->all = FALSE; /* make it empty */
267 return client_set_expand(set, func_invert, &d);
270 if (!set->h) return set; /* already empty */
274 g_hash_table_foreach_remove(set->h, foreach_reduce, &d);
275 if (g_hash_table_size(set->h) == 0)
276 client_set_destroy_hash(set);
280 ObClientSet* client_set_expand(ObClientSet *set, ObClientSetExpandFunc f,
286 g_return_val_if_fail(set != NULL, NULL);
287 g_return_val_if_fail(f != NULL, NULL);
289 if (set->all) return set; /* already full */
292 for (it = client_list; it; it = g_list_next(it)) {
293 ObClient *c = it->data;
294 if (!set->h || !g_hash_table_lookup(set->h, &c->window))
297 client_set_create_hash(set);
298 g_hash_table_insert(set->h, &c->window, c);
302 if (g_hash_table_size(set->h) == avail) {
303 client_set_destroy_hash(set);
309 gboolean client_set_is_empty(const ObClientSet *set)
311 if (set->all) return client_list == NULL;
312 else return set->h == NULL;
315 gboolean client_set_test_boolean(const ObClientSet *set)
317 if (set->all) return TRUE;
318 else return set->h != NULL;
321 gboolean client_set_contains(const ObClientSet *set, struct _ObClient *c)
323 if (!c) return FALSE;
324 if (set->all) return TRUE;
325 if (!set->h) return FALSE;
326 return g_hash_table_lookup(set->h, &c->window) != NULL;
331 ObClientSetForeachFunc foreach;
332 ObClientSetRunFunc run;
334 const struct _ObActionListRun *run;
337 } ObClientSetForeachData;
339 void foreach_func(gpointer k, gpointer v, gpointer u)
341 ObClientSetForeachData *const d = u;
342 if (!d->running) return;
343 d->running = d->func.foreach((ObClient*)v, d->data);
346 void client_set_foreach(const ObClientSet *set, ObClientSetForeachFunc func,
349 g_return_if_fail(set != NULL);
353 for (it = client_list; it; it = g_list_next(it))
354 func(it->data, data);
357 ObClientSetForeachData d;
358 d.func.foreach = func;
361 g_hash_table_foreach(set->h, foreach_func, &d);
365 void run_func(gpointer k, gpointer v, gpointer u)
367 ObClientSetForeachData *const d = u;
368 if (!d->running) return;
369 d->running = d->func.run((ObClient*)v, d->run, d->data);
372 void client_set_run(const ObClientSet *set, const struct _ObActionListRun *run,
373 ObClientSetRunFunc func, gpointer data)
375 g_return_if_fail(set != NULL);
379 for (it = client_list; it; it = g_list_next(it))
380 func(it->data, run, data);
383 ObClientSetForeachData d;
388 g_hash_table_foreach(set->h, run_func, &d);
392 guint client_set_size(const ObClientSet *set)
399 return g_hash_table_size(set->h);
402 GList *client_set_get_all(const ObClientSet *set)
405 return g_list_copy(client_list);
409 return g_hash_table_get_values(set->h);