source: trunk/third/glib2/glib/ghook.c @ 18159

Revision 18159, 13.6 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18158, which included commits to RCS files with non-trunk default branches.
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 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, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
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 "glib.h"
37
38
39/* --- defines --- */
40#define G_HOOKS_PREALLOC        (16)
41
42
43/* --- functions --- */
44static void
45default_finalize_hook (GHookList *hook_list,
46                       GHook     *hook)
47{
48  GDestroyNotify destroy = hook->destroy;
49
50  if (destroy)
51    {
52      hook->destroy = NULL;
53      destroy (hook->data);
54    }
55}
56
57void
58g_hook_list_init (GHookList *hook_list,
59                  guint      hook_size)
60{
61  g_return_if_fail (hook_list != NULL);
62  g_return_if_fail (hook_size >= sizeof (GHook));
63  g_return_if_fail (hook_size < 65536);
64 
65  hook_list->seq_id = 1;
66  hook_list->hook_size = hook_size;
67  hook_list->is_setup = TRUE;
68  hook_list->hooks = NULL;
69  hook_list->hook_memchunk = g_mem_chunk_new ("GHook Memchunk",
70                                              hook_size,
71                                              hook_size * G_HOOKS_PREALLOC,
72                                              G_ALLOC_AND_FREE);
73  hook_list->finalize_hook = default_finalize_hook;
74  hook_list->dummy[0] = NULL;
75  hook_list->dummy[1] = NULL;
76}
77
78void
79g_hook_list_clear (GHookList *hook_list)
80{
81  g_return_if_fail (hook_list != NULL);
82 
83  if (hook_list->is_setup)
84    {
85      GHook *hook;
86     
87      hook_list->is_setup = FALSE;
88     
89      hook = hook_list->hooks;
90      if (!hook)
91        {
92          g_mem_chunk_destroy (hook_list->hook_memchunk);
93          hook_list->hook_memchunk = NULL;
94        }
95      else
96        do
97          {
98            GHook *tmp;
99           
100            g_hook_ref (hook_list, hook);
101            g_hook_destroy_link (hook_list, hook);
102            tmp = hook->next;
103            g_hook_unref (hook_list, hook);
104            hook = tmp;
105          }
106        while (hook);
107      if (hook_list->hook_memchunk)
108        g_warning (G_STRLOC ": failed to clear hooklist, unconsolidated references on hooks left");
109    }
110}
111
112GHook*
113g_hook_alloc (GHookList *hook_list)
114{
115  GHook *hook;
116 
117  g_return_val_if_fail (hook_list != NULL, NULL);
118  g_return_val_if_fail (hook_list->is_setup, NULL);
119 
120  hook = g_chunk_new0 (GHook, hook_list->hook_memchunk);
121  hook->data = NULL;
122  hook->next = NULL;
123  hook->prev = NULL;
124  hook->flags = G_HOOK_FLAG_ACTIVE;
125  hook->ref_count = 0;
126  hook->hook_id = 0;
127  hook->func = NULL;
128  hook->destroy = NULL;
129 
130  return hook;
131}
132
133void
134g_hook_free (GHookList *hook_list,
135             GHook     *hook)
136{
137  g_return_if_fail (hook_list != NULL);
138  g_return_if_fail (hook_list->is_setup);
139  g_return_if_fail (hook != NULL);
140  g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
141  g_return_if_fail (!G_HOOK_IN_CALL (hook));
142
143  hook_list->finalize_hook (hook_list, hook);
144  g_chunk_free (hook, hook_list->hook_memchunk);
145}
146
147void
148g_hook_destroy_link (GHookList *hook_list,
149                     GHook     *hook)
150{
151  g_return_if_fail (hook_list != NULL);
152  g_return_if_fail (hook != NULL);
153
154  hook->flags &= ~G_HOOK_FLAG_ACTIVE;
155  if (hook->hook_id)
156    {
157      hook->hook_id = 0;
158      g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */
159    }
160}
161
162gboolean
163g_hook_destroy (GHookList   *hook_list,
164                gulong       hook_id)
165{
166  GHook *hook;
167 
168  g_return_val_if_fail (hook_list != NULL, FALSE);
169  g_return_val_if_fail (hook_id > 0, FALSE);
170 
171  hook = g_hook_get (hook_list, hook_id);
172  if (hook)
173    {
174      g_hook_destroy_link (hook_list, hook);
175      return TRUE;
176    }
177 
178  return FALSE;
179}
180
181void
182g_hook_unref (GHookList *hook_list,
183              GHook     *hook)
184{
185  g_return_if_fail (hook_list != NULL);
186  g_return_if_fail (hook_list->hook_memchunk != NULL);
187  g_return_if_fail (hook != NULL);
188  g_return_if_fail (hook->ref_count > 0);
189 
190  hook->ref_count--;
191  if (!hook->ref_count)
192    {
193      g_return_if_fail (hook->hook_id == 0);
194      g_return_if_fail (!G_HOOK_IN_CALL (hook));
195
196      if (hook->prev)
197        hook->prev->next = hook->next;
198      else
199        hook_list->hooks = hook->next;
200      if (hook->next)
201        {
202          hook->next->prev = hook->prev;
203          hook->next = NULL;
204        }
205      hook->prev = NULL;
206
207      if (!hook_list->is_setup)
208        {
209          hook_list->is_setup = TRUE;
210          g_hook_free (hook_list, hook);
211          hook_list->is_setup = FALSE;
212     
213          if (!hook_list->hooks)
214            {
215              g_mem_chunk_destroy (hook_list->hook_memchunk);
216              hook_list->hook_memchunk = NULL;
217            }
218        }
219      else
220        g_hook_free (hook_list, hook);
221    }
222}
223
224void
225g_hook_ref (GHookList *hook_list,
226            GHook     *hook)
227{
228  g_return_if_fail (hook_list != NULL);
229  g_return_if_fail (hook != NULL);
230  g_return_if_fail (hook->ref_count > 0);
231 
232  hook->ref_count++;
233}
234
235void
236g_hook_prepend (GHookList *hook_list,
237                GHook     *hook)
238{
239  g_return_if_fail (hook_list != NULL);
240 
241  g_hook_insert_before (hook_list, hook_list->hooks, hook);
242}
243
244void
245g_hook_insert_before (GHookList *hook_list,
246                      GHook     *sibling,
247                      GHook     *hook)
248{
249  g_return_if_fail (hook_list != NULL);
250  g_return_if_fail (hook_list->is_setup);
251  g_return_if_fail (hook != NULL);
252  g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
253  g_return_if_fail (hook->ref_count == 0);
254 
255  hook->hook_id = hook_list->seq_id++;
256  hook->ref_count = 1; /* counterpart to g_hook_destroy_link */
257 
258  if (sibling)
259    {
260      if (sibling->prev)
261        {
262          hook->prev = sibling->prev;
263          hook->prev->next = hook;
264          hook->next = sibling;
265          sibling->prev = hook;
266        }
267      else
268        {
269          hook_list->hooks = hook;
270          hook->next = sibling;
271          sibling->prev = hook;
272        }
273    }
274  else
275    {
276      if (hook_list->hooks)
277        {
278          sibling = hook_list->hooks;
279          while (sibling->next)
280            sibling = sibling->next;
281          hook->prev = sibling;
282          sibling->next = hook;
283        }
284      else
285        hook_list->hooks = hook;
286    }
287}
288
289void
290g_hook_list_invoke (GHookList *hook_list,
291                    gboolean   may_recurse)
292{
293  GHook *hook;
294 
295  g_return_if_fail (hook_list != NULL);
296  g_return_if_fail (hook_list->is_setup);
297
298  hook = g_hook_first_valid (hook_list, may_recurse);
299  while (hook)
300    {
301      GHookFunc func;
302      gboolean was_in_call;
303     
304      func = (GHookFunc) hook->func;
305     
306      was_in_call = G_HOOK_IN_CALL (hook);
307      hook->flags |= G_HOOK_FLAG_IN_CALL;
308      func (hook->data);
309      if (!was_in_call)
310        hook->flags &= ~G_HOOK_FLAG_IN_CALL;
311     
312      hook = g_hook_next_valid (hook_list, hook, may_recurse);
313    }
314}
315
316void
317g_hook_list_invoke_check (GHookList *hook_list,
318                          gboolean   may_recurse)
319{
320  GHook *hook;
321 
322  g_return_if_fail (hook_list != NULL);
323  g_return_if_fail (hook_list->is_setup);
324 
325  hook = g_hook_first_valid (hook_list, may_recurse);
326  while (hook)
327    {
328      GHookCheckFunc func;
329      gboolean was_in_call;
330      gboolean need_destroy;
331     
332      func = (GHookCheckFunc) hook->func;
333     
334      was_in_call = G_HOOK_IN_CALL (hook);
335      hook->flags |= G_HOOK_FLAG_IN_CALL;
336      need_destroy = !func (hook->data);
337      if (!was_in_call)
338        hook->flags &= ~G_HOOK_FLAG_IN_CALL;
339      if (need_destroy)
340        g_hook_destroy_link (hook_list, hook);
341     
342      hook = g_hook_next_valid (hook_list, hook, may_recurse);
343    }
344}
345
346void
347g_hook_list_marshal_check (GHookList           *hook_list,
348                           gboolean             may_recurse,
349                           GHookCheckMarshaller marshaller,
350                           gpointer             data)
351{
352  GHook *hook;
353 
354  g_return_if_fail (hook_list != NULL);
355  g_return_if_fail (hook_list->is_setup);
356  g_return_if_fail (marshaller != NULL);
357 
358  hook = g_hook_first_valid (hook_list, may_recurse);
359  while (hook)
360    {
361      gboolean was_in_call;
362      gboolean need_destroy;
363     
364      was_in_call = G_HOOK_IN_CALL (hook);
365      hook->flags |= G_HOOK_FLAG_IN_CALL;
366      need_destroy = !marshaller (hook, data);
367      if (!was_in_call)
368        hook->flags &= ~G_HOOK_FLAG_IN_CALL;
369      if (need_destroy)
370        g_hook_destroy_link (hook_list, hook);
371     
372      hook = g_hook_next_valid (hook_list, hook, may_recurse);
373    }
374}
375
376void
377g_hook_list_marshal (GHookList               *hook_list,
378                     gboolean                 may_recurse,
379                     GHookMarshaller          marshaller,
380                     gpointer                 data)
381{
382  GHook *hook;
383 
384  g_return_if_fail (hook_list != NULL);
385  g_return_if_fail (hook_list->is_setup);
386  g_return_if_fail (marshaller != NULL);
387 
388  hook = g_hook_first_valid (hook_list, may_recurse);
389  while (hook)
390    {
391      gboolean was_in_call;
392     
393      was_in_call = G_HOOK_IN_CALL (hook);
394      hook->flags |= G_HOOK_FLAG_IN_CALL;
395      marshaller (hook, data);
396      if (!was_in_call)
397        hook->flags &= ~G_HOOK_FLAG_IN_CALL;
398     
399      hook = g_hook_next_valid (hook_list, hook, may_recurse);
400    }
401}
402
403GHook*
404g_hook_first_valid (GHookList *hook_list,
405                    gboolean   may_be_in_call)
406{
407  g_return_val_if_fail (hook_list != NULL, NULL);
408 
409  if (hook_list->is_setup)
410    {
411      GHook *hook;
412     
413      hook = hook_list->hooks;
414      if (hook)
415        {
416          g_hook_ref (hook_list, hook);
417          if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
418            return hook;
419          else
420            return g_hook_next_valid (hook_list, hook, may_be_in_call);
421        }
422    }
423 
424  return NULL;
425}
426
427GHook*
428g_hook_next_valid (GHookList *hook_list,
429                   GHook     *hook,
430                   gboolean   may_be_in_call)
431{
432  GHook *ohook = hook;
433
434  g_return_val_if_fail (hook_list != NULL, NULL);
435
436  if (!hook)
437    return NULL;
438 
439  hook = hook->next;
440  while (hook)
441    {
442      if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook)))
443        {
444          g_hook_ref (hook_list, hook);
445          g_hook_unref (hook_list, ohook);
446         
447          return hook;
448        }
449      hook = hook->next;
450    }
451  g_hook_unref (hook_list, ohook);
452
453  return NULL;
454}
455
456GHook*
457g_hook_get (GHookList *hook_list,
458            gulong     hook_id)
459{
460  GHook *hook;
461 
462  g_return_val_if_fail (hook_list != NULL, NULL);
463  g_return_val_if_fail (hook_id > 0, NULL);
464 
465  hook = hook_list->hooks;
466  while (hook)
467    {
468      if (hook->hook_id == hook_id)
469        return hook;
470      hook = hook->next;
471    }
472 
473  return NULL;
474}
475
476GHook*
477g_hook_find (GHookList    *hook_list,
478             gboolean      need_valids,
479             GHookFindFunc func,
480             gpointer      data)
481{
482  GHook *hook;
483 
484  g_return_val_if_fail (hook_list != NULL, NULL);
485  g_return_val_if_fail (func != NULL, NULL);
486 
487  hook = hook_list->hooks;
488  while (hook)
489    {
490      GHook *tmp;
491
492      /* test only non-destroyed hooks */
493      if (!hook->hook_id)
494        {
495          hook = hook->next;
496          continue;
497        }
498     
499      g_hook_ref (hook_list, hook);
500     
501      if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook)))
502        {
503          g_hook_unref (hook_list, hook);
504         
505          return hook;
506        }
507
508      tmp = hook->next;
509      g_hook_unref (hook_list, hook);
510      hook = tmp;
511    }
512 
513  return NULL;
514}
515
516GHook*
517g_hook_find_data (GHookList *hook_list,
518                  gboolean   need_valids,
519                  gpointer   data)
520{
521  GHook *hook;
522 
523  g_return_val_if_fail (hook_list != NULL, NULL);
524 
525  hook = hook_list->hooks;
526  while (hook)
527    {
528      /* test only non-destroyed hooks */
529      if (hook->data == data &&
530          hook->hook_id &&
531          (!need_valids || G_HOOK_ACTIVE (hook)))
532        return hook;
533
534      hook = hook->next;
535    }
536 
537  return NULL;
538}
539
540GHook*
541g_hook_find_func (GHookList *hook_list,
542                  gboolean   need_valids,
543                  gpointer   func)
544{
545  GHook *hook;
546 
547  g_return_val_if_fail (hook_list != NULL, NULL);
548  g_return_val_if_fail (func != NULL, NULL);
549 
550  hook = hook_list->hooks;
551  while (hook)
552    {
553      /* test only non-destroyed hooks */
554      if (hook->func == func &&
555          hook->hook_id &&
556          (!need_valids || G_HOOK_ACTIVE (hook)))
557        return hook;
558
559      hook = hook->next;
560    }
561 
562  return NULL;
563}
564
565GHook*
566g_hook_find_func_data (GHookList *hook_list,
567                       gboolean   need_valids,
568                       gpointer   func,
569                       gpointer   data)
570{
571  GHook *hook;
572 
573  g_return_val_if_fail (hook_list != NULL, NULL);
574  g_return_val_if_fail (func != NULL, NULL);
575 
576  hook = hook_list->hooks;
577  while (hook)
578    {
579      /* test only non-destroyed hooks */
580      if (hook->data == data &&
581          hook->func == func &&
582          hook->hook_id &&
583          (!need_valids || G_HOOK_ACTIVE (hook)))
584        return hook;
585
586      hook = hook->next;
587    }
588 
589  return NULL;
590}
591
592void
593g_hook_insert_sorted (GHookList       *hook_list,
594                      GHook           *hook,
595                      GHookCompareFunc func)
596{
597  GHook *sibling;
598 
599  g_return_if_fail (hook_list != NULL);
600  g_return_if_fail (hook_list->is_setup);
601  g_return_if_fail (hook != NULL);
602  g_return_if_fail (G_HOOK_IS_UNLINKED (hook));
603  g_return_if_fail (hook->func != NULL);
604  g_return_if_fail (func != NULL);
605
606  /* first non-destroyed hook */
607  sibling = hook_list->hooks;
608  while (sibling && !sibling->hook_id)
609    sibling = sibling->next;
610 
611  while (sibling)
612    {
613      GHook *tmp;
614     
615      g_hook_ref (hook_list, sibling);
616      if (func (hook, sibling) <= 0 && sibling->hook_id)
617        {
618          g_hook_unref (hook_list, sibling);
619          break;
620        }
621
622      /* next non-destroyed hook */
623      tmp = sibling->next;
624      while (tmp && !tmp->hook_id)
625        tmp = tmp->next;
626
627      g_hook_unref (hook_list, sibling);
628      sibling = tmp;
629    }
630 
631  g_hook_insert_before (hook_list, sibling, hook);
632}
633
634gint
635g_hook_compare_ids (GHook *new_hook,
636                    GHook *sibling)
637{
638  if (new_hook->hook_id < sibling->hook_id)
639    return -1;
640  else if (new_hook->hook_id > sibling->hook_id)
641    return 1;
642 
643  return 0;
644}
Note: See TracBrowser for help on using the repository browser.