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