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