Coverage Report

Created: 2025-07-01 07:09

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