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