1 | /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ |
---|
2 | /* gnome-vfs-messages.c - Status message reporting for GNOME Virtual File |
---|
3 | System. |
---|
4 | |
---|
5 | Copyright (C) 1999 Free Software Foundation |
---|
6 | |
---|
7 | The Gnome Library is free software; you can redistribute it and/or |
---|
8 | modify it under the terms of the GNU Library General Public License as |
---|
9 | published by the Free Software Foundation; either version 2 of the |
---|
10 | License, or (at your option) any later version. |
---|
11 | |
---|
12 | The Gnome Library is distributed in the hope that it will be useful, |
---|
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
15 | Library General Public License for more details. |
---|
16 | |
---|
17 | You should have received a copy of the GNU Library General Public |
---|
18 | License along with the Gnome Library; see the file COPYING.LIB. If not, |
---|
19 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
20 | Boston, MA 02111-1307, USA. |
---|
21 | |
---|
22 | Author: Havoc Pennington <hp@redhat.com> */ |
---|
23 | |
---|
24 | #include "gnome-vfs-messages.h" |
---|
25 | |
---|
26 | #include <stdio.h> |
---|
27 | |
---|
28 | #ifdef G_THREADS_ENABLED |
---|
29 | #define MUTEX_LOCK(a) if ((a) != NULL) g_mutex_lock (a) |
---|
30 | #define MUTEX_UNLOCK(a) if ((a) != NULL) g_mutex_unlock (a) |
---|
31 | #else |
---|
32 | #define MUTEX_LOCK(a) |
---|
33 | #define MUTEX_UNLOCK(a) |
---|
34 | #endif |
---|
35 | |
---|
36 | static guint next_id = 1; |
---|
37 | |
---|
38 | G_LOCK_DEFINE_STATIC (next_id); |
---|
39 | |
---|
40 | typedef struct Callback Callback; |
---|
41 | |
---|
42 | struct Callback { |
---|
43 | GnomeVFSStatusCallback callback_func; |
---|
44 | gpointer user_data; |
---|
45 | GDestroyNotify notify_func; |
---|
46 | guint id; |
---|
47 | }; |
---|
48 | |
---|
49 | static Callback* |
---|
50 | callback_new (GnomeVFSStatusCallback callback_func, |
---|
51 | gpointer user_data, |
---|
52 | GDestroyNotify notify_func) |
---|
53 | { |
---|
54 | Callback *cb; |
---|
55 | |
---|
56 | cb = g_new(Callback, 1); |
---|
57 | |
---|
58 | cb->callback_func = callback_func; |
---|
59 | cb->user_data = user_data; |
---|
60 | cb->notify_func = notify_func; |
---|
61 | |
---|
62 | G_LOCK(next_id); |
---|
63 | cb->id = next_id; |
---|
64 | ++next_id; |
---|
65 | G_UNLOCK(next_id); |
---|
66 | |
---|
67 | return cb; |
---|
68 | } |
---|
69 | |
---|
70 | static void |
---|
71 | callback_destroy (Callback *cb) |
---|
72 | { |
---|
73 | if (cb->notify_func != NULL) { |
---|
74 | (* cb->notify_func) (cb->user_data); |
---|
75 | } |
---|
76 | |
---|
77 | g_free(cb); |
---|
78 | } |
---|
79 | |
---|
80 | static void |
---|
81 | callback_invoke (Callback *cb, const gchar* message) |
---|
82 | { |
---|
83 | if (cb->callback_func) { |
---|
84 | (* cb->callback_func) (message, cb->user_data); |
---|
85 | } |
---|
86 | } |
---|
87 | |
---|
88 | struct GnomeVFSMessageCallbacks { |
---|
89 | GSList *list; |
---|
90 | #ifdef G_THREADS_ENABLED |
---|
91 | GMutex *list_mutex; |
---|
92 | #endif |
---|
93 | }; |
---|
94 | |
---|
95 | GnomeVFSMessageCallbacks* |
---|
96 | gnome_vfs_message_callbacks_new (void) |
---|
97 | { |
---|
98 | GnomeVFSMessageCallbacks *cbs; |
---|
99 | |
---|
100 | cbs = g_new0(GnomeVFSMessageCallbacks, 1); |
---|
101 | |
---|
102 | #ifdef G_THREADS_ENABLED |
---|
103 | if (g_thread_supported ()) |
---|
104 | cbs->list_mutex = g_mutex_new (); |
---|
105 | else |
---|
106 | cbs->list_mutex = NULL; |
---|
107 | #endif |
---|
108 | |
---|
109 | return cbs; |
---|
110 | } |
---|
111 | |
---|
112 | void |
---|
113 | gnome_vfs_message_callbacks_destroy (GnomeVFSMessageCallbacks *cbs) |
---|
114 | { |
---|
115 | GSList *tmp; |
---|
116 | |
---|
117 | MUTEX_LOCK(cbs->list_mutex); |
---|
118 | |
---|
119 | tmp = cbs->list; |
---|
120 | |
---|
121 | while (tmp != NULL) { |
---|
122 | Callback *cb; |
---|
123 | |
---|
124 | cb = tmp->data; |
---|
125 | |
---|
126 | callback_destroy (cb); |
---|
127 | |
---|
128 | tmp = g_slist_next (tmp); |
---|
129 | } |
---|
130 | |
---|
131 | g_slist_free (cbs->list); |
---|
132 | |
---|
133 | MUTEX_UNLOCK(cbs->list_mutex); |
---|
134 | |
---|
135 | #ifdef G_THREADS_ENABLED |
---|
136 | if (cbs->list_mutex != NULL) |
---|
137 | g_mutex_free (cbs->list_mutex); |
---|
138 | #endif |
---|
139 | |
---|
140 | g_free(cbs); |
---|
141 | } |
---|
142 | |
---|
143 | guint |
---|
144 | gnome_vfs_message_callbacks_add (GnomeVFSMessageCallbacks *cbs, |
---|
145 | GnomeVFSStatusCallback callback, |
---|
146 | gpointer user_data) |
---|
147 | { |
---|
148 | return gnome_vfs_message_callbacks_add_full (cbs, callback, user_data, NULL); |
---|
149 | } |
---|
150 | |
---|
151 | guint |
---|
152 | gnome_vfs_message_callbacks_add_full (GnomeVFSMessageCallbacks *cbs, |
---|
153 | GnomeVFSStatusCallback callback, |
---|
154 | gpointer user_data, |
---|
155 | GDestroyNotify notify) |
---|
156 | { |
---|
157 | Callback *cb; |
---|
158 | |
---|
159 | cb = callback_new (callback, user_data, notify); |
---|
160 | |
---|
161 | MUTEX_LOCK(cbs->list_mutex); |
---|
162 | |
---|
163 | cbs->list = g_slist_prepend (cbs->list, cb); |
---|
164 | |
---|
165 | MUTEX_UNLOCK(cbs->list_mutex); |
---|
166 | |
---|
167 | return cb->id; |
---|
168 | } |
---|
169 | |
---|
170 | typedef gboolean (* MyGSListFilterFunc) (gpointer list_element, gpointer user_data); |
---|
171 | |
---|
172 | static GSList* |
---|
173 | my_g_slist_filter (GSList* list, MyGSListFilterFunc func, gpointer user_data) |
---|
174 | { |
---|
175 | GSList *iter; |
---|
176 | GSList *retval; |
---|
177 | |
---|
178 | retval = NULL; |
---|
179 | iter = list; |
---|
180 | |
---|
181 | while (iter != NULL) { |
---|
182 | GSList *freeme; |
---|
183 | |
---|
184 | if ((*func)(iter->data, user_data)) { |
---|
185 | retval = g_slist_prepend (retval, iter->data); |
---|
186 | } |
---|
187 | |
---|
188 | freeme = iter; |
---|
189 | iter = g_slist_next (iter); |
---|
190 | |
---|
191 | g_assert(freeme != NULL); |
---|
192 | |
---|
193 | /* Avoids using double the amount of space; glib can |
---|
194 | recycle these nodes into the new list */ |
---|
195 | g_slist_free_1 (freeme); |
---|
196 | } |
---|
197 | |
---|
198 | /* We assembled the nodes backward */ |
---|
199 | retval = g_slist_reverse (retval); |
---|
200 | |
---|
201 | return retval; |
---|
202 | } |
---|
203 | |
---|
204 | static gboolean |
---|
205 | callback_equal_predicate (gpointer callback, gpointer func) |
---|
206 | { |
---|
207 | return !(((Callback*)callback)->callback_func == |
---|
208 | ((GnomeVFSStatusCallback)func)); |
---|
209 | } |
---|
210 | |
---|
211 | static gboolean |
---|
212 | data_equal_predicate (gpointer callback, gpointer data) |
---|
213 | { |
---|
214 | return !(((Callback*)callback)->user_data == data); |
---|
215 | } |
---|
216 | |
---|
217 | struct func_and_data { |
---|
218 | GnomeVFSStatusCallback func; |
---|
219 | gpointer data; |
---|
220 | }; |
---|
221 | |
---|
222 | static gboolean |
---|
223 | all_equal_predicate (gpointer callback, gpointer func_and_data) |
---|
224 | { |
---|
225 | Callback *cb = callback; |
---|
226 | struct func_and_data* fd = func_and_data; |
---|
227 | |
---|
228 | return !(cb->callback_func == fd->func && cb->user_data == fd->data); |
---|
229 | } |
---|
230 | |
---|
231 | void gnome_vfs_message_callbacks_remove (GnomeVFSMessageCallbacks *cbs, |
---|
232 | guint num) |
---|
233 | { |
---|
234 | GSList *iter; |
---|
235 | |
---|
236 | MUTEX_LOCK(cbs->list_mutex); |
---|
237 | |
---|
238 | iter = cbs->list; |
---|
239 | |
---|
240 | while (iter != NULL) { |
---|
241 | Callback *cb; |
---|
242 | |
---|
243 | cb = iter->data; |
---|
244 | |
---|
245 | if (cb->id == num) |
---|
246 | break; |
---|
247 | |
---|
248 | iter = g_slist_next (iter); |
---|
249 | } |
---|
250 | |
---|
251 | if (iter) |
---|
252 | cbs->list = g_slist_remove(cbs->list, iter->data); |
---|
253 | else |
---|
254 | g_warning("status callback %u not found to remove", num); |
---|
255 | |
---|
256 | MUTEX_UNLOCK(cbs->list_mutex); |
---|
257 | } |
---|
258 | |
---|
259 | void |
---|
260 | gnome_vfs_message_callbacks_remove_by_func (GnomeVFSMessageCallbacks *cbs, |
---|
261 | GnomeVFSStatusCallback callback) |
---|
262 | { |
---|
263 | MUTEX_LOCK(cbs->list_mutex); |
---|
264 | cbs->list = my_g_slist_filter (cbs->list, callback_equal_predicate, callback); |
---|
265 | MUTEX_UNLOCK(cbs->list_mutex); |
---|
266 | } |
---|
267 | |
---|
268 | void |
---|
269 | gnome_vfs_message_callbacks_remove_by_data (GnomeVFSMessageCallbacks *cbs, |
---|
270 | gpointer user_data) |
---|
271 | { |
---|
272 | MUTEX_LOCK(cbs->list_mutex); |
---|
273 | cbs->list = my_g_slist_filter (cbs->list, data_equal_predicate, user_data); |
---|
274 | MUTEX_UNLOCK(cbs->list_mutex); |
---|
275 | } |
---|
276 | |
---|
277 | void |
---|
278 | gnome_vfs_message_callbacks_remove_by_func_and_data (GnomeVFSMessageCallbacks *cbs, |
---|
279 | GnomeVFSStatusCallback callback, |
---|
280 | gpointer user_data) |
---|
281 | { |
---|
282 | struct func_and_data fd; |
---|
283 | |
---|
284 | MUTEX_LOCK(cbs->list_mutex); |
---|
285 | |
---|
286 | fd.func = callback; |
---|
287 | fd.data = user_data; |
---|
288 | |
---|
289 | cbs->list = my_g_slist_filter (cbs->list, all_equal_predicate, &fd); |
---|
290 | |
---|
291 | MUTEX_UNLOCK(cbs->list_mutex); |
---|
292 | } |
---|
293 | |
---|
294 | void |
---|
295 | gnome_vfs_message_callbacks_emit (GnomeVFSMessageCallbacks *cbs, |
---|
296 | const gchar *message) |
---|
297 | { |
---|
298 | GSList *iter; |
---|
299 | |
---|
300 | MUTEX_LOCK(cbs->list_mutex); |
---|
301 | |
---|
302 | iter = cbs->list; |
---|
303 | |
---|
304 | while (iter != NULL) { |
---|
305 | Callback *cb; |
---|
306 | |
---|
307 | cb = iter->data; |
---|
308 | |
---|
309 | callback_invoke (cb, message); |
---|
310 | |
---|
311 | iter = g_slist_next (iter); |
---|
312 | } |
---|
313 | |
---|
314 | MUTEX_UNLOCK(cbs->list_mutex); |
---|
315 | } |
---|
316 | |
---|
317 | |
---|