]> icculus.org git repositories - dana/openbox.git/blob - openbox/client_set.c
Make empty ObClientSet objects not hold a hash table.
[dana/openbox.git] / openbox / client_set.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    client_set.c for the Openbox window manager
4    Copyright (c) 2011        Dana Jansens
5
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.
10
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.
15
16    See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "client_set.h"
20 #include "client.h"
21 #include "event.h"
22
23 #include <glib.h>
24
25 struct _ObClientSet {
26     gboolean all;
27     GHashTable *h;
28 };
29
30 static void client_destroyed(ObClient *client, ObClientSet *set)
31 {
32     g_hash_table_remove(set->h, &client->window);
33 }
34
35 ObClientSet* client_set_empty(void)
36 {
37     ObClientSet *set;
38
39     set = g_slice_new(ObClientSet);
40     set->all = FALSE;
41     set->h = NULL;
42     client_add_destroy_notify((ObClientCallback)client_destroyed, set);
43     return set;
44 }
45
46 ObClientSet* client_set_single(void)
47 {
48     struct _ObClient *c;
49     ObClientSet *set;
50
51     c = event_current_target();
52     if (!c) return NULL;
53     set = g_slice_new(ObClientSet);
54     set->all = FALSE;
55     set->h = g_hash_table_new(g_int_hash, g_int_equal);
56     g_hash_table_insert(set->h, &c->window, c);
57     return set;
58 }
59
60 /*! Returns a new set of clients with all possible client in it.*/
61 ObClientSet* client_set_all(void)
62 {
63     ObClientSet *set;
64
65     if (!client_list) return NULL;
66     set = g_slice_new(ObClientSet);
67     set->all = TRUE;
68     set->h = NULL;
69     return set;
70 }
71
72 void client_set_destroy(ObClientSet *set)
73 {
74     if (!set->all) {
75         client_remove_destroy_notify_data((ObClientCallback)client_destroyed,
76                                           set);
77         if (set->h) g_hash_table_destroy(set->h);
78     }
79     g_slice_free(ObClientSet, set);
80 }
81
82 static void foreach_union(gpointer k, gpointer v, gpointer u)
83 {
84     GHashTable *set = u;
85     g_hash_table_insert(set, k, v); /* add everything in the other set */
86 }
87
88 /* Returns a new set which contains all clients in either @a or @b.  The sets
89    @a and @b are considered freed once passed to this function.
90 */
91 ObClientSet* client_set_union(ObClientSet *a, ObClientSet *b)
92 {
93     g_return_val_if_fail(a != NULL, NULL);
94     g_return_val_if_fail(b != NULL, NULL);
95
96     if (a->all) {
97         client_set_destroy(b);
98         return a;
99     }
100     if (b->all) {
101         client_set_destroy(a);
102         return b;
103     }
104     if (!a->h) {
105         client_set_destroy(a);
106         return b;
107     }
108     if (!b->h) {
109         client_set_destroy(b);
110         return a;
111     }
112
113     g_hash_table_foreach(b->h, foreach_union, a->h);
114     client_set_destroy(b);
115     return a;
116 }
117
118 static gboolean foreach_intersection(gpointer k, gpointer v, gpointer u)
119 {
120     GHashTable *set = u;
121     return !g_hash_table_lookup(set, k); /* remove if not in the other set */
122 }
123
124 /* Returns a new set which contains all clients in both @a and @b.  The sets
125    @a and @b are considered freed once passed to this function.
126 */
127 ObClientSet* client_set_intersection(ObClientSet *a, ObClientSet *b)
128 {
129     g_return_val_if_fail(a != NULL, NULL);
130     g_return_val_if_fail(b != NULL, NULL);
131
132     if (a->all) {
133         client_set_destroy(a);
134         return b;
135     }
136     if (b->all) {
137         client_set_destroy(b);
138         return a;
139     }
140     if (!a->h) {
141         client_set_destroy(b);
142         return a;
143     }
144     if (!b->h) {
145         client_set_destroy(a);
146         return b;
147     }
148
149     g_hash_table_foreach_remove(a->h, foreach_intersection, b->h);
150     client_set_destroy(b);
151     return a;
152 }
153
154 struct ObClientSetForeachReduce {
155     ObClientSetReduceFunc f;
156     gpointer data;
157 };
158
159 static gboolean foreach_reduce(gpointer k, gpointer v, gpointer u)
160 {
161     ObClient *c = v;
162     struct ObClientSetForeachReduce *d = u;
163     return d->f(c, d->data);
164 }
165
166 ObClientSet* client_set_reduce(ObClientSet *set, ObClientSetReduceFunc f,
167                                gpointer data)
168 {
169     struct ObClientSetForeachReduce d;
170
171     g_return_val_if_fail(set != NULL, NULL);
172     g_return_val_if_fail(f != NULL, NULL);
173
174     d.f = f;
175     d.data = data;
176     g_hash_table_foreach_remove(set->h, foreach_reduce, &d);
177     if (g_hash_table_size(set->h) == 0) {
178         g_hash_table_destroy(set->h);
179         set->h = NULL;
180     }
181     return set;
182 }
183
184 ObClientSet* client_set_expand(ObClientSet *set, ObClientSetExpandFunc f,
185                                gpointer data)
186 {
187     GList *it;
188
189     g_return_val_if_fail(set != NULL, NULL);
190     g_return_val_if_fail(f != NULL, NULL);
191
192     for (it = client_list; it; it = g_list_next(it)) {
193         ObClient *c = it->data;
194         if (!set->h || !g_hash_table_lookup(set->h, &c->window))
195             if (f(c, data)) {
196                 if (!set->h)
197                     set->h = g_hash_table_new(g_int_hash, g_int_equal);
198                 g_hash_table_insert(set->h, &c->window, c);
199             }
200     }
201     return set;
202 }
203
204 gboolean client_set_is_empty(ObClientSet *set)
205 {
206     if (set->all) return client_list == NULL;
207     else return set->h == NULL;
208 }
209
210 gboolean client_set_test_boolean(ObClientSet *set)
211 {
212     if (set->all) return TRUE;
213     else return set->h != NULL;
214 }
215