/src/irssi/subprojects/glib-2.74.7/glib/ghook.c
Line | Count | Source |
1 | | /* GLIB - Library of useful routines for C programming |
2 | | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | | * |
4 | | * GHook: Callback maintenance functions |
5 | | * Copyright (C) 1998 Tim Janik |
6 | | * |
7 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
8 | | * |
9 | | * This library is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | /* |
24 | | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
25 | | * file for a list of people on the GLib Team. See the ChangeLog |
26 | | * files for a list of changes. These files are distributed with |
27 | | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
28 | | */ |
29 | | |
30 | | /* |
31 | | * MT safe |
32 | | */ |
33 | | |
34 | | #include "config.h" |
35 | | |
36 | | #include "ghook.h" |
37 | | |
38 | | #include "gtestutils.h" |
39 | | #include "gslice.h" |
40 | | |
41 | | /** |
42 | | * SECTION:hooks |
43 | | * @title: Hook Functions |
44 | | * @short_description: support for manipulating lists of hook functions |
45 | | * |
46 | | * The #GHookList, #GHook and their related functions provide support for |
47 | | * lists of hook functions. Functions can be added and removed from the lists, |
48 | | * and the list of hook functions can be invoked. |
49 | | */ |
50 | | |
51 | | /** |
52 | | * GHookList: |
53 | | * @seq_id: the next free #GHook id |
54 | | * @hook_size: the size of the #GHookList elements, in bytes |
55 | | * @is_setup: 1 if the #GHookList has been initialized |
56 | | * @hooks: the first #GHook element in the list |
57 | | * @dummy3: unused |
58 | | * @finalize_hook: the function to call to finalize a #GHook element. |
59 | | * The default behaviour is to call the hooks @destroy function |
60 | | * @dummy: unused |
61 | | * |
62 | | * The #GHookList struct represents a list of hook functions. |
63 | | */ |
64 | | |
65 | | /** |
66 | | * GHookFinalizeFunc: |
67 | | * @hook_list: a #GHookList |
68 | | * @hook: the hook in @hook_list that gets finalized |
69 | | * |
70 | | * Defines the type of function to be called when a hook in a |
71 | | * list of hooks gets finalized. |
72 | | */ |
73 | | |
74 | | /** |
75 | | * GHookFlagMask: |
76 | | * @G_HOOK_FLAG_ACTIVE: set if the hook has not been destroyed |
77 | | * @G_HOOK_FLAG_IN_CALL: set if the hook is currently being run |
78 | | * @G_HOOK_FLAG_MASK: A mask covering all bits reserved for |
79 | | * hook flags; see %G_HOOK_FLAG_USER_SHIFT |
80 | | * |
81 | | * Flags used internally in the #GHook implementation. |
82 | | */ |
83 | | |
84 | | /** |
85 | | * G_HOOK_FLAGS: |
86 | | * @hook: a #GHook |
87 | | * |
88 | | * Gets the flags of a hook. |
89 | | */ |
90 | | |
91 | | /** |
92 | | * G_HOOK_FLAG_USER_SHIFT: |
93 | | * |
94 | | * The position of the first bit which is not reserved for internal |
95 | | * use be the #GHook implementation, i.e. |
96 | | * `1 << G_HOOK_FLAG_USER_SHIFT` is the first |
97 | | * bit which can be used for application-defined flags. |
98 | | */ |
99 | | |
100 | | /** |
101 | | * G_HOOK: |
102 | | * @hook: a pointer |
103 | | * |
104 | | * Casts a pointer to a `GHook*`. |
105 | | */ |
106 | | |
107 | | /** |
108 | | * G_HOOK_IS_VALID: |
109 | | * @hook: a #GHook |
110 | | * |
111 | | * Returns %TRUE if the #GHook is valid, i.e. it is in a #GHookList, |
112 | | * it is active and it has not been destroyed. |
113 | | * |
114 | | * Returns: %TRUE if the #GHook is valid |
115 | | */ |
116 | | |
117 | | /** |
118 | | * G_HOOK_ACTIVE: |
119 | | * @hook: a #GHook |
120 | | * |
121 | | * Returns %TRUE if the #GHook is active, which is normally the case |
122 | | * until the #GHook is destroyed. |
123 | | * |
124 | | * Returns: %TRUE if the #GHook is active |
125 | | */ |
126 | | |
127 | | /** |
128 | | * G_HOOK_IN_CALL: |
129 | | * @hook: a #GHook |
130 | | * |
131 | | * Returns %TRUE if the #GHook function is currently executing. |
132 | | * |
133 | | * Returns: %TRUE if the #GHook function is currently executing |
134 | | */ |
135 | | |
136 | | /** |
137 | | * G_HOOK_IS_UNLINKED: |
138 | | * @hook: a #GHook |
139 | | * |
140 | | * Returns %TRUE if the #GHook is not in a #GHookList. |
141 | | * |
142 | | * Returns: %TRUE if the #GHook is not in a #GHookList |
143 | | */ |
144 | | |
145 | | /** |
146 | | * GHook: |
147 | | * @data: data which is passed to func when this hook is invoked |
148 | | * @next: pointer to the next hook in the list |
149 | | * @prev: pointer to the previous hook in the list |
150 | | * @ref_count: the reference count of this hook |
151 | | * @hook_id: the id of this hook, which is unique within its list |
152 | | * @flags: flags which are set for this hook. See #GHookFlagMask for |
153 | | * predefined flags |
154 | | * @func: the function to call when this hook is invoked. The possible |
155 | | * signatures for this function are #GHookFunc and #GHookCheckFunc |
156 | | * @destroy: the default @finalize_hook function of a #GHookList calls |
157 | | * this member of the hook that is being finalized |
158 | | * |
159 | | * The #GHook struct represents a single hook function in a #GHookList. |
160 | | */ |
161 | | |
162 | | /** |
163 | | * GHookFunc: |
164 | | * @data: the data field of the #GHook is passed to the hook function here |
165 | | * |
166 | | * Defines the type of a hook function that can be invoked |
167 | | * by g_hook_list_invoke(). |
168 | | */ |
169 | | |
170 | | /** |
171 | | * GHookCheckFunc: |
172 | | * @data: the data field of the #GHook is passed to the hook function here |
173 | | * |
174 | | * Defines the type of a hook function that can be invoked |
175 | | * by g_hook_list_invoke_check(). |
176 | | * |
177 | | * Returns: %FALSE if the #GHook should be destroyed |
178 | | */ |
179 | | |
180 | | /* --- functions --- */ |
181 | | static void |
182 | | default_finalize_hook (GHookList *hook_list, |
183 | | GHook *hook) |
184 | 0 | { |
185 | 0 | GDestroyNotify destroy = hook->destroy; |
186 | |
|
187 | 0 | if (destroy) |
188 | 0 | { |
189 | 0 | hook->destroy = NULL; |
190 | 0 | destroy (hook->data); |
191 | 0 | } |
192 | 0 | } |
193 | | |
194 | | /** |
195 | | * g_hook_list_init: |
196 | | * @hook_list: a #GHookList |
197 | | * @hook_size: the size of each element in the #GHookList, |
198 | | * typically `sizeof (GHook)`. |
199 | | * |
200 | | * Initializes a #GHookList. |
201 | | * This must be called before the #GHookList is used. |
202 | | */ |
203 | | void |
204 | | g_hook_list_init (GHookList *hook_list, |
205 | | guint hook_size) |
206 | 0 | { |
207 | 0 | g_return_if_fail (hook_list != NULL); |
208 | 0 | g_return_if_fail (hook_size >= sizeof (GHook)); |
209 | | |
210 | 0 | hook_list->seq_id = 1; |
211 | 0 | hook_list->hook_size = hook_size; |
212 | 0 | hook_list->is_setup = TRUE; |
213 | 0 | hook_list->hooks = NULL; |
214 | 0 | hook_list->dummy3 = NULL; |
215 | 0 | hook_list->finalize_hook = default_finalize_hook; |
216 | 0 | hook_list->dummy[0] = NULL; |
217 | 0 | hook_list->dummy[1] = NULL; |
218 | 0 | } |
219 | | |
220 | | /** |
221 | | * g_hook_list_clear: |
222 | | * @hook_list: a #GHookList |
223 | | * |
224 | | * Removes all the #GHook elements from a #GHookList. |
225 | | */ |
226 | | void |
227 | | g_hook_list_clear (GHookList *hook_list) |
228 | 0 | { |
229 | 0 | g_return_if_fail (hook_list != NULL); |
230 | | |
231 | 0 | if (hook_list->is_setup) |
232 | 0 | { |
233 | 0 | GHook *hook; |
234 | | |
235 | 0 | hook_list->is_setup = FALSE; |
236 | | |
237 | 0 | hook = hook_list->hooks; |
238 | 0 | if (!hook) |
239 | 0 | { |
240 | | /* destroy hook_list->hook_memchunk */ |
241 | 0 | } |
242 | 0 | else |
243 | 0 | do |
244 | 0 | { |
245 | 0 | GHook *tmp; |
246 | | |
247 | 0 | g_hook_ref (hook_list, hook); |
248 | 0 | g_hook_destroy_link (hook_list, hook); |
249 | 0 | tmp = hook->next; |
250 | 0 | g_hook_unref (hook_list, hook); |
251 | 0 | hook = tmp; |
252 | 0 | } |
253 | 0 | while (hook); |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | | /** |
258 | | * g_hook_alloc: |
259 | | * @hook_list: a #GHookList |
260 | | * |
261 | | * Allocates space for a #GHook and initializes it. |
262 | | * |
263 | | * Returns: a new #GHook |
264 | | */ |
265 | | GHook* |
266 | | g_hook_alloc (GHookList *hook_list) |
267 | 0 | { |
268 | 0 | GHook *hook; |
269 | | |
270 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
271 | 0 | g_return_val_if_fail (hook_list->is_setup, NULL); |
272 | | |
273 | 0 | hook = g_slice_alloc0 (hook_list->hook_size); |
274 | 0 | hook->data = NULL; |
275 | 0 | hook->next = NULL; |
276 | 0 | hook->prev = NULL; |
277 | 0 | hook->flags = G_HOOK_FLAG_ACTIVE; |
278 | 0 | hook->ref_count = 0; |
279 | 0 | hook->hook_id = 0; |
280 | 0 | hook->func = NULL; |
281 | 0 | hook->destroy = NULL; |
282 | | |
283 | 0 | return hook; |
284 | 0 | } |
285 | | /** |
286 | | * g_hook_free: |
287 | | * @hook_list: a #GHookList |
288 | | * @hook: the #GHook to free |
289 | | * |
290 | | * Calls the #GHookList @finalize_hook function if it exists, |
291 | | * and frees the memory allocated for the #GHook. |
292 | | */ |
293 | | void |
294 | | g_hook_free (GHookList *hook_list, |
295 | | GHook *hook) |
296 | 0 | { |
297 | 0 | g_return_if_fail (hook_list != NULL); |
298 | 0 | g_return_if_fail (hook_list->is_setup); |
299 | 0 | g_return_if_fail (hook != NULL); |
300 | 0 | g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); |
301 | 0 | g_return_if_fail (!G_HOOK_IN_CALL (hook)); |
302 | | |
303 | 0 | if(hook_list->finalize_hook != NULL) |
304 | 0 | hook_list->finalize_hook (hook_list, hook); |
305 | 0 | g_slice_free1 (hook_list->hook_size, hook); |
306 | 0 | } |
307 | | |
308 | | /** |
309 | | * g_hook_destroy_link: |
310 | | * @hook_list: a #GHookList |
311 | | * @hook: the #GHook to remove |
312 | | * |
313 | | * Removes one #GHook from a #GHookList, marking it |
314 | | * inactive and calling g_hook_unref() on it. |
315 | | */ |
316 | | void |
317 | | g_hook_destroy_link (GHookList *hook_list, |
318 | | GHook *hook) |
319 | 0 | { |
320 | 0 | g_return_if_fail (hook_list != NULL); |
321 | 0 | g_return_if_fail (hook != NULL); |
322 | | |
323 | 0 | hook->flags &= ~G_HOOK_FLAG_ACTIVE; |
324 | 0 | if (hook->hook_id) |
325 | 0 | { |
326 | 0 | hook->hook_id = 0; |
327 | 0 | g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */ |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | /** |
332 | | * g_hook_destroy: |
333 | | * @hook_list: a #GHookList |
334 | | * @hook_id: a hook ID |
335 | | * |
336 | | * Destroys a #GHook, given its ID. |
337 | | * |
338 | | * Returns: %TRUE if the #GHook was found in the #GHookList and destroyed |
339 | | */ |
340 | | gboolean |
341 | | g_hook_destroy (GHookList *hook_list, |
342 | | gulong hook_id) |
343 | 0 | { |
344 | 0 | GHook *hook; |
345 | | |
346 | 0 | g_return_val_if_fail (hook_list != NULL, FALSE); |
347 | 0 | g_return_val_if_fail (hook_id > 0, FALSE); |
348 | | |
349 | 0 | hook = g_hook_get (hook_list, hook_id); |
350 | 0 | if (hook) |
351 | 0 | { |
352 | 0 | g_hook_destroy_link (hook_list, hook); |
353 | 0 | return TRUE; |
354 | 0 | } |
355 | | |
356 | 0 | return FALSE; |
357 | 0 | } |
358 | | |
359 | | /** |
360 | | * g_hook_unref: |
361 | | * @hook_list: a #GHookList |
362 | | * @hook: the #GHook to unref |
363 | | * |
364 | | * Decrements the reference count of a #GHook. |
365 | | * If the reference count falls to 0, the #GHook is removed |
366 | | * from the #GHookList and g_hook_free() is called to free it. |
367 | | */ |
368 | | void |
369 | | g_hook_unref (GHookList *hook_list, |
370 | | GHook *hook) |
371 | 0 | { |
372 | 0 | g_return_if_fail (hook_list != NULL); |
373 | 0 | g_return_if_fail (hook != NULL); |
374 | 0 | g_return_if_fail (hook->ref_count > 0); |
375 | | |
376 | 0 | hook->ref_count--; |
377 | 0 | if (!hook->ref_count) |
378 | 0 | { |
379 | 0 | g_return_if_fail (hook->hook_id == 0); |
380 | 0 | g_return_if_fail (!G_HOOK_IN_CALL (hook)); |
381 | | |
382 | 0 | if (hook->prev) |
383 | 0 | hook->prev->next = hook->next; |
384 | 0 | else |
385 | 0 | hook_list->hooks = hook->next; |
386 | 0 | if (hook->next) |
387 | 0 | { |
388 | 0 | hook->next->prev = hook->prev; |
389 | 0 | hook->next = NULL; |
390 | 0 | } |
391 | 0 | hook->prev = NULL; |
392 | |
|
393 | 0 | if (!hook_list->is_setup) |
394 | 0 | { |
395 | 0 | hook_list->is_setup = TRUE; |
396 | 0 | g_hook_free (hook_list, hook); |
397 | 0 | hook_list->is_setup = FALSE; |
398 | | |
399 | 0 | if (!hook_list->hooks) |
400 | 0 | { |
401 | | /* destroy hook_list->hook_memchunk */ |
402 | 0 | } |
403 | 0 | } |
404 | 0 | else |
405 | 0 | g_hook_free (hook_list, hook); |
406 | 0 | } |
407 | 0 | } |
408 | | |
409 | | /** |
410 | | * g_hook_ref: |
411 | | * @hook_list: a #GHookList |
412 | | * @hook: the #GHook to increment the reference count of |
413 | | * |
414 | | * Increments the reference count for a #GHook. |
415 | | * |
416 | | * Returns: the @hook that was passed in (since 2.6) |
417 | | */ |
418 | | GHook * |
419 | | g_hook_ref (GHookList *hook_list, |
420 | | GHook *hook) |
421 | 0 | { |
422 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
423 | 0 | g_return_val_if_fail (hook != NULL, NULL); |
424 | 0 | g_return_val_if_fail (hook->ref_count > 0, NULL); |
425 | | |
426 | 0 | hook->ref_count++; |
427 | |
|
428 | 0 | return hook; |
429 | 0 | } |
430 | | |
431 | | /** |
432 | | * g_hook_append: |
433 | | * @hook_list: a #GHookList |
434 | | * @hook: the #GHook to add to the end of @hook_list |
435 | | * |
436 | | * Appends a #GHook onto the end of a #GHookList. |
437 | | */ |
438 | | |
439 | | /** |
440 | | * g_hook_prepend: |
441 | | * @hook_list: a #GHookList |
442 | | * @hook: the #GHook to add to the start of @hook_list |
443 | | * |
444 | | * Prepends a #GHook on the start of a #GHookList. |
445 | | */ |
446 | | void |
447 | | g_hook_prepend (GHookList *hook_list, |
448 | | GHook *hook) |
449 | 0 | { |
450 | 0 | g_return_if_fail (hook_list != NULL); |
451 | | |
452 | 0 | g_hook_insert_before (hook_list, hook_list->hooks, hook); |
453 | 0 | } |
454 | | |
455 | | /** |
456 | | * g_hook_insert_before: |
457 | | * @hook_list: a #GHookList |
458 | | * @sibling: (nullable): the #GHook to insert the new #GHook before |
459 | | * @hook: the #GHook to insert |
460 | | * |
461 | | * Inserts a #GHook into a #GHookList, before a given #GHook. |
462 | | */ |
463 | | void |
464 | | g_hook_insert_before (GHookList *hook_list, |
465 | | GHook *sibling, |
466 | | GHook *hook) |
467 | 0 | { |
468 | 0 | g_return_if_fail (hook_list != NULL); |
469 | 0 | g_return_if_fail (hook_list->is_setup); |
470 | 0 | g_return_if_fail (hook != NULL); |
471 | 0 | g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); |
472 | 0 | g_return_if_fail (hook->ref_count == 0); |
473 | | |
474 | 0 | hook->hook_id = hook_list->seq_id++; |
475 | 0 | hook->ref_count = 1; /* counterpart to g_hook_destroy_link */ |
476 | | |
477 | 0 | if (sibling) |
478 | 0 | { |
479 | 0 | if (sibling->prev) |
480 | 0 | { |
481 | 0 | hook->prev = sibling->prev; |
482 | 0 | hook->prev->next = hook; |
483 | 0 | hook->next = sibling; |
484 | 0 | sibling->prev = hook; |
485 | 0 | } |
486 | 0 | else |
487 | 0 | { |
488 | 0 | hook_list->hooks = hook; |
489 | 0 | hook->next = sibling; |
490 | 0 | sibling->prev = hook; |
491 | 0 | } |
492 | 0 | } |
493 | 0 | else |
494 | 0 | { |
495 | 0 | if (hook_list->hooks) |
496 | 0 | { |
497 | 0 | sibling = hook_list->hooks; |
498 | 0 | while (sibling->next) |
499 | 0 | sibling = sibling->next; |
500 | 0 | hook->prev = sibling; |
501 | 0 | sibling->next = hook; |
502 | 0 | } |
503 | 0 | else |
504 | 0 | hook_list->hooks = hook; |
505 | 0 | } |
506 | 0 | } |
507 | | |
508 | | /** |
509 | | * g_hook_list_invoke: |
510 | | * @hook_list: a #GHookList |
511 | | * @may_recurse: %TRUE if functions which are already running |
512 | | * (e.g. in another thread) can be called. If set to %FALSE, |
513 | | * these are skipped |
514 | | * |
515 | | * Calls all of the #GHook functions in a #GHookList. |
516 | | */ |
517 | | void |
518 | | g_hook_list_invoke (GHookList *hook_list, |
519 | | gboolean may_recurse) |
520 | 0 | { |
521 | 0 | GHook *hook; |
522 | | |
523 | 0 | g_return_if_fail (hook_list != NULL); |
524 | 0 | g_return_if_fail (hook_list->is_setup); |
525 | | |
526 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
527 | 0 | while (hook) |
528 | 0 | { |
529 | 0 | GHookFunc func; |
530 | 0 | gboolean was_in_call; |
531 | | |
532 | 0 | func = (GHookFunc) hook->func; |
533 | | |
534 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
535 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
536 | 0 | func (hook->data); |
537 | 0 | if (!was_in_call) |
538 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
539 | | |
540 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | /** |
545 | | * g_hook_list_invoke_check: |
546 | | * @hook_list: a #GHookList |
547 | | * @may_recurse: %TRUE if functions which are already running |
548 | | * (e.g. in another thread) can be called. If set to %FALSE, |
549 | | * these are skipped |
550 | | * |
551 | | * Calls all of the #GHook functions in a #GHookList. |
552 | | * Any function which returns %FALSE is removed from the #GHookList. |
553 | | */ |
554 | | void |
555 | | g_hook_list_invoke_check (GHookList *hook_list, |
556 | | gboolean may_recurse) |
557 | 0 | { |
558 | 0 | GHook *hook; |
559 | | |
560 | 0 | g_return_if_fail (hook_list != NULL); |
561 | 0 | g_return_if_fail (hook_list->is_setup); |
562 | | |
563 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
564 | 0 | while (hook) |
565 | 0 | { |
566 | 0 | GHookCheckFunc func; |
567 | 0 | gboolean was_in_call; |
568 | 0 | gboolean need_destroy; |
569 | | |
570 | 0 | func = (GHookCheckFunc) hook->func; |
571 | | |
572 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
573 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
574 | 0 | need_destroy = !func (hook->data); |
575 | 0 | if (!was_in_call) |
576 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
577 | 0 | if (need_destroy) |
578 | 0 | g_hook_destroy_link (hook_list, hook); |
579 | | |
580 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
581 | 0 | } |
582 | 0 | } |
583 | | |
584 | | /** |
585 | | * GHookCheckMarshaller: |
586 | | * @hook: a #GHook |
587 | | * @user_data: user data |
588 | | * |
589 | | * Defines the type of function used by g_hook_list_marshal_check(). |
590 | | * |
591 | | * Returns: %FALSE if @hook should be destroyed |
592 | | */ |
593 | | |
594 | | /** |
595 | | * g_hook_list_marshal_check: |
596 | | * @hook_list: a #GHookList |
597 | | * @may_recurse: %TRUE if hooks which are currently running |
598 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
599 | | * these are skipped |
600 | | * @marshaller: the function to call for each #GHook |
601 | | * @marshal_data: data to pass to @marshaller |
602 | | * |
603 | | * Calls a function on each valid #GHook and destroys it if the |
604 | | * function returns %FALSE. |
605 | | */ |
606 | | void |
607 | | g_hook_list_marshal_check (GHookList *hook_list, |
608 | | gboolean may_recurse, |
609 | | GHookCheckMarshaller marshaller, |
610 | | gpointer data) |
611 | 0 | { |
612 | 0 | GHook *hook; |
613 | | |
614 | 0 | g_return_if_fail (hook_list != NULL); |
615 | 0 | g_return_if_fail (hook_list->is_setup); |
616 | 0 | g_return_if_fail (marshaller != NULL); |
617 | | |
618 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
619 | 0 | while (hook) |
620 | 0 | { |
621 | 0 | gboolean was_in_call; |
622 | 0 | gboolean need_destroy; |
623 | | |
624 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
625 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
626 | 0 | need_destroy = !marshaller (hook, data); |
627 | 0 | if (!was_in_call) |
628 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
629 | 0 | if (need_destroy) |
630 | 0 | g_hook_destroy_link (hook_list, hook); |
631 | | |
632 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
633 | 0 | } |
634 | 0 | } |
635 | | |
636 | | /** |
637 | | * GHookMarshaller: |
638 | | * @hook: a #GHook |
639 | | * @user_data: user data |
640 | | * |
641 | | * Defines the type of function used by g_hook_list_marshal(). |
642 | | */ |
643 | | |
644 | | /** |
645 | | * g_hook_list_marshal: |
646 | | * @hook_list: a #GHookList |
647 | | * @may_recurse: %TRUE if hooks which are currently running |
648 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
649 | | * these are skipped |
650 | | * @marshaller: the function to call for each #GHook |
651 | | * @marshal_data: data to pass to @marshaller |
652 | | * |
653 | | * Calls a function on each valid #GHook. |
654 | | */ |
655 | | void |
656 | | g_hook_list_marshal (GHookList *hook_list, |
657 | | gboolean may_recurse, |
658 | | GHookMarshaller marshaller, |
659 | | gpointer data) |
660 | 0 | { |
661 | 0 | GHook *hook; |
662 | | |
663 | 0 | g_return_if_fail (hook_list != NULL); |
664 | 0 | g_return_if_fail (hook_list->is_setup); |
665 | 0 | g_return_if_fail (marshaller != NULL); |
666 | | |
667 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
668 | 0 | while (hook) |
669 | 0 | { |
670 | 0 | gboolean was_in_call; |
671 | | |
672 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
673 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
674 | 0 | marshaller (hook, data); |
675 | 0 | if (!was_in_call) |
676 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
677 | | |
678 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
679 | 0 | } |
680 | 0 | } |
681 | | |
682 | | /** |
683 | | * g_hook_first_valid: |
684 | | * @hook_list: a #GHookList |
685 | | * @may_be_in_call: %TRUE if hooks which are currently running |
686 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
687 | | * these are skipped |
688 | | * |
689 | | * Returns the first #GHook in a #GHookList which has not been destroyed. |
690 | | * The reference count for the #GHook is incremented, so you must call |
691 | | * g_hook_unref() to restore it when no longer needed. (Or call |
692 | | * g_hook_next_valid() if you are stepping through the #GHookList.) |
693 | | * |
694 | | * Returns: the first valid #GHook, or %NULL if none are valid |
695 | | */ |
696 | | GHook* |
697 | | g_hook_first_valid (GHookList *hook_list, |
698 | | gboolean may_be_in_call) |
699 | 0 | { |
700 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
701 | | |
702 | 0 | if (hook_list->is_setup) |
703 | 0 | { |
704 | 0 | GHook *hook; |
705 | | |
706 | 0 | hook = hook_list->hooks; |
707 | 0 | if (hook) |
708 | 0 | { |
709 | 0 | g_hook_ref (hook_list, hook); |
710 | 0 | if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) |
711 | 0 | return hook; |
712 | 0 | else |
713 | 0 | return g_hook_next_valid (hook_list, hook, may_be_in_call); |
714 | 0 | } |
715 | 0 | } |
716 | | |
717 | 0 | return NULL; |
718 | 0 | } |
719 | | |
720 | | /** |
721 | | * g_hook_next_valid: |
722 | | * @hook_list: a #GHookList |
723 | | * @hook: the current #GHook |
724 | | * @may_be_in_call: %TRUE if hooks which are currently running |
725 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
726 | | * these are skipped |
727 | | * |
728 | | * Returns the next #GHook in a #GHookList which has not been destroyed. |
729 | | * The reference count for the #GHook is incremented, so you must call |
730 | | * g_hook_unref() to restore it when no longer needed. (Or continue to call |
731 | | * g_hook_next_valid() until %NULL is returned.) |
732 | | * |
733 | | * Returns: the next valid #GHook, or %NULL if none are valid |
734 | | */ |
735 | | GHook* |
736 | | g_hook_next_valid (GHookList *hook_list, |
737 | | GHook *hook, |
738 | | gboolean may_be_in_call) |
739 | 0 | { |
740 | 0 | GHook *ohook = hook; |
741 | |
|
742 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
743 | | |
744 | 0 | if (!hook) |
745 | 0 | return NULL; |
746 | | |
747 | 0 | hook = hook->next; |
748 | 0 | while (hook) |
749 | 0 | { |
750 | 0 | if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) |
751 | 0 | { |
752 | 0 | g_hook_ref (hook_list, hook); |
753 | 0 | g_hook_unref (hook_list, ohook); |
754 | | |
755 | 0 | return hook; |
756 | 0 | } |
757 | 0 | hook = hook->next; |
758 | 0 | } |
759 | 0 | g_hook_unref (hook_list, ohook); |
760 | |
|
761 | 0 | return NULL; |
762 | 0 | } |
763 | | |
764 | | /** |
765 | | * g_hook_get: |
766 | | * @hook_list: a #GHookList |
767 | | * @hook_id: a hook id |
768 | | * |
769 | | * Returns the #GHook with the given id, or %NULL if it is not found. |
770 | | * |
771 | | * Returns: the #GHook with the given id, or %NULL if it is not found |
772 | | */ |
773 | | GHook* |
774 | | g_hook_get (GHookList *hook_list, |
775 | | gulong hook_id) |
776 | 0 | { |
777 | 0 | GHook *hook; |
778 | | |
779 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
780 | 0 | g_return_val_if_fail (hook_id > 0, NULL); |
781 | | |
782 | 0 | hook = hook_list->hooks; |
783 | 0 | while (hook) |
784 | 0 | { |
785 | 0 | if (hook->hook_id == hook_id) |
786 | 0 | return hook; |
787 | 0 | hook = hook->next; |
788 | 0 | } |
789 | | |
790 | 0 | return NULL; |
791 | 0 | } |
792 | | |
793 | | /** |
794 | | * GHookFindFunc: |
795 | | * @hook: a #GHook |
796 | | * @user_data: user data passed to g_hook_find_func() |
797 | | * |
798 | | * Defines the type of the function passed to g_hook_find(). |
799 | | * |
800 | | * Returns: %TRUE if the required #GHook has been found |
801 | | */ |
802 | | |
803 | | /** |
804 | | * g_hook_find: |
805 | | * @hook_list: a #GHookList |
806 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
807 | | * should be skipped |
808 | | * @func: the function to call for each #GHook, which should return |
809 | | * %TRUE when the #GHook has been found |
810 | | * @data: the data to pass to @func |
811 | | * |
812 | | * Finds a #GHook in a #GHookList using the given function to |
813 | | * test for a match. |
814 | | * |
815 | | * Returns: the found #GHook or %NULL if no matching #GHook is found |
816 | | */ |
817 | | GHook* |
818 | | g_hook_find (GHookList *hook_list, |
819 | | gboolean need_valids, |
820 | | GHookFindFunc func, |
821 | | gpointer data) |
822 | 0 | { |
823 | 0 | GHook *hook; |
824 | | |
825 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
826 | 0 | g_return_val_if_fail (func != NULL, NULL); |
827 | | |
828 | 0 | hook = hook_list->hooks; |
829 | 0 | while (hook) |
830 | 0 | { |
831 | 0 | GHook *tmp; |
832 | | |
833 | | /* test only non-destroyed hooks */ |
834 | 0 | if (!hook->hook_id) |
835 | 0 | { |
836 | 0 | hook = hook->next; |
837 | 0 | continue; |
838 | 0 | } |
839 | | |
840 | 0 | g_hook_ref (hook_list, hook); |
841 | | |
842 | 0 | if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook))) |
843 | 0 | { |
844 | 0 | g_hook_unref (hook_list, hook); |
845 | | |
846 | 0 | return hook; |
847 | 0 | } |
848 | | |
849 | 0 | tmp = hook->next; |
850 | 0 | g_hook_unref (hook_list, hook); |
851 | 0 | hook = tmp; |
852 | 0 | } |
853 | | |
854 | 0 | return NULL; |
855 | 0 | } |
856 | | |
857 | | /** |
858 | | * g_hook_find_data: |
859 | | * @hook_list: a #GHookList |
860 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
861 | | * should be skipped |
862 | | * @data: the data to find |
863 | | * |
864 | | * Finds a #GHook in a #GHookList with the given data. |
865 | | * |
866 | | * Returns: the #GHook with the given @data or %NULL if no matching |
867 | | * #GHook is found |
868 | | */ |
869 | | GHook* |
870 | | g_hook_find_data (GHookList *hook_list, |
871 | | gboolean need_valids, |
872 | | gpointer data) |
873 | 0 | { |
874 | 0 | GHook *hook; |
875 | | |
876 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
877 | | |
878 | 0 | hook = hook_list->hooks; |
879 | 0 | while (hook) |
880 | 0 | { |
881 | | /* test only non-destroyed hooks */ |
882 | 0 | if (hook->data == data && |
883 | 0 | hook->hook_id && |
884 | 0 | (!need_valids || G_HOOK_ACTIVE (hook))) |
885 | 0 | return hook; |
886 | | |
887 | 0 | hook = hook->next; |
888 | 0 | } |
889 | | |
890 | 0 | return NULL; |
891 | 0 | } |
892 | | |
893 | | /** |
894 | | * g_hook_find_func: |
895 | | * @hook_list: a #GHookList |
896 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
897 | | * should be skipped |
898 | | * @func: the function to find |
899 | | * |
900 | | * Finds a #GHook in a #GHookList with the given function. |
901 | | * |
902 | | * Returns: the #GHook with the given @func or %NULL if no matching |
903 | | * #GHook is found |
904 | | */ |
905 | | GHook* |
906 | | g_hook_find_func (GHookList *hook_list, |
907 | | gboolean need_valids, |
908 | | gpointer func) |
909 | 0 | { |
910 | 0 | GHook *hook; |
911 | | |
912 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
913 | 0 | g_return_val_if_fail (func != NULL, NULL); |
914 | | |
915 | 0 | hook = hook_list->hooks; |
916 | 0 | while (hook) |
917 | 0 | { |
918 | | /* test only non-destroyed hooks */ |
919 | 0 | if (hook->func == func && |
920 | 0 | hook->hook_id && |
921 | 0 | (!need_valids || G_HOOK_ACTIVE (hook))) |
922 | 0 | return hook; |
923 | | |
924 | 0 | hook = hook->next; |
925 | 0 | } |
926 | | |
927 | 0 | return NULL; |
928 | 0 | } |
929 | | |
930 | | /** |
931 | | * g_hook_find_func_data: |
932 | | * @hook_list: a #GHookList |
933 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
934 | | * should be skipped |
935 | | * @func: (not nullable): the function to find |
936 | | * @data: the data to find |
937 | | * |
938 | | * Finds a #GHook in a #GHookList with the given function and data. |
939 | | * |
940 | | * Returns: the #GHook with the given @func and @data or %NULL if |
941 | | * no matching #GHook is found |
942 | | */ |
943 | | GHook* |
944 | | g_hook_find_func_data (GHookList *hook_list, |
945 | | gboolean need_valids, |
946 | | gpointer func, |
947 | | gpointer data) |
948 | 0 | { |
949 | 0 | GHook *hook; |
950 | | |
951 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
952 | 0 | g_return_val_if_fail (func != NULL, NULL); |
953 | | |
954 | 0 | hook = hook_list->hooks; |
955 | 0 | while (hook) |
956 | 0 | { |
957 | | /* test only non-destroyed hooks */ |
958 | 0 | if (hook->data == data && |
959 | 0 | hook->func == func && |
960 | 0 | hook->hook_id && |
961 | 0 | (!need_valids || G_HOOK_ACTIVE (hook))) |
962 | 0 | return hook; |
963 | | |
964 | 0 | hook = hook->next; |
965 | 0 | } |
966 | | |
967 | 0 | return NULL; |
968 | 0 | } |
969 | | |
970 | | /** |
971 | | * GHookCompareFunc: |
972 | | * @new_hook: the #GHook being inserted |
973 | | * @sibling: the #GHook to compare with @new_hook |
974 | | * |
975 | | * Defines the type of function used to compare #GHook elements in |
976 | | * g_hook_insert_sorted(). |
977 | | * |
978 | | * Returns: a value <= 0 if @new_hook should be before @sibling |
979 | | */ |
980 | | |
981 | | /** |
982 | | * g_hook_insert_sorted: |
983 | | * @hook_list: a #GHookList |
984 | | * @hook: the #GHook to insert |
985 | | * @func: the comparison function used to sort the #GHook elements |
986 | | * |
987 | | * Inserts a #GHook into a #GHookList, sorted by the given function. |
988 | | */ |
989 | | void |
990 | | g_hook_insert_sorted (GHookList *hook_list, |
991 | | GHook *hook, |
992 | | GHookCompareFunc func) |
993 | 0 | { |
994 | 0 | GHook *sibling; |
995 | | |
996 | 0 | g_return_if_fail (hook_list != NULL); |
997 | 0 | g_return_if_fail (hook_list->is_setup); |
998 | 0 | g_return_if_fail (hook != NULL); |
999 | 0 | g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); |
1000 | 0 | g_return_if_fail (hook->func != NULL); |
1001 | 0 | g_return_if_fail (func != NULL); |
1002 | | |
1003 | | /* first non-destroyed hook */ |
1004 | 0 | sibling = hook_list->hooks; |
1005 | 0 | while (sibling && !sibling->hook_id) |
1006 | 0 | sibling = sibling->next; |
1007 | | |
1008 | 0 | while (sibling) |
1009 | 0 | { |
1010 | 0 | GHook *tmp; |
1011 | | |
1012 | 0 | g_hook_ref (hook_list, sibling); |
1013 | 0 | if (func (hook, sibling) <= 0 && sibling->hook_id) |
1014 | 0 | { |
1015 | 0 | g_hook_unref (hook_list, sibling); |
1016 | 0 | break; |
1017 | 0 | } |
1018 | | |
1019 | | /* next non-destroyed hook */ |
1020 | 0 | tmp = sibling->next; |
1021 | 0 | while (tmp && !tmp->hook_id) |
1022 | 0 | tmp = tmp->next; |
1023 | |
|
1024 | 0 | g_hook_unref (hook_list, sibling); |
1025 | 0 | sibling = tmp; |
1026 | | |
1027 | 0 | } |
1028 | | |
1029 | 0 | g_hook_insert_before (hook_list, sibling, hook); |
1030 | 0 | } |
1031 | | |
1032 | | /** |
1033 | | * g_hook_compare_ids: |
1034 | | * @new_hook: a #GHook |
1035 | | * @sibling: a #GHook to compare with @new_hook |
1036 | | * |
1037 | | * Compares the ids of two #GHook elements, returning a negative value |
1038 | | * if the second id is greater than the first. |
1039 | | * |
1040 | | * Returns: a value <= 0 if the id of @sibling is >= the id of @new_hook |
1041 | | */ |
1042 | | gint |
1043 | | g_hook_compare_ids (GHook *new_hook, |
1044 | | GHook *sibling) |
1045 | 0 | { |
1046 | 0 | if (new_hook->hook_id < sibling->hook_id) |
1047 | 0 | return -1; |
1048 | 0 | else if (new_hook->hook_id > sibling->hook_id) |
1049 | 0 | return 1; |
1050 | | |
1051 | 0 | return 0; |
1052 | 0 | } |