Coverage Report

Created: 2026-08-31 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}