]> git.decadent.org.uk Git - ion3.git/blob - libmainloop/hooks.c
[svn-upgrade] Integrating new upstream version, ion3 (20070203)
[ion3.git] / libmainloop / hooks.c
1 /*
2  * ion/mainloop/hooks.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <libtu/types.h>
13 #include <libtu/misc.h>
14 #include <libtu/dlist.h>
15 #include <libtu/output.h>
16 #include <libtu/rb.h>
17 #include <libtu/objp.h>
18 #include <libtu/locale.h>
19 #include <libextl/extl.h>
20 #include "hooks.h"
21
22
23 EXTL_EXPORT
24 IMPLCLASS(WHook, Obj, hook_deinit, NULL);
25
26 static Rb_node named_hooks=NULL;
27
28
29 /*{{{ Named hooks */
30
31
32 /* If hk==NULL to register, new is attempted to be created. */
33 WHook *mainloop_register_hook(const char *name, WHook *hk)
34 {
35     bool created=FALSE;
36     char *nnm;
37     
38     if(hk==NULL)
39         return NULL;
40     
41     if(named_hooks==NULL){
42         named_hooks=make_rb();
43         if(named_hooks==NULL)
44             return NULL;
45     }
46     
47     nnm=scopy(name);
48     
49     if(nnm==NULL)
50         return NULL;
51     
52     if(!rb_insert(named_hooks, nnm, hk)){
53         free(nnm);
54         destroy_obj((Obj*)hk);
55     }
56     
57     return hk;
58 }
59
60
61 WHook *mainloop_unregister_hook(const char *name, WHook *hk)
62 {
63     bool found=FALSE;
64     Rb_node node;
65
66     if(named_hooks==NULL)
67         return NULL;
68     
69     if(hk==NULL){
70         assert(name!=NULL);
71         node=rb_find_key_n(named_hooks, name, &found);
72     }else{
73         rb_traverse(node, named_hooks){
74             if((WHook*)rb_val(node)==hk){
75                 found=TRUE;
76                 break;
77             }
78         }
79     }
80
81     if(found){
82         hk=(WHook*)rb_val(node);
83         free((char*)node->k.key);
84         rb_delete_node(node);
85     }
86     
87     return hk;
88 }
89
90
91 /*EXTL_DOC
92  * Find named hook \var{name}.
93  */
94 EXTL_SAFE
95 EXTL_EXPORT
96 WHook *mainloop_get_hook(const char *name)
97 {
98     if(name==NULL)
99         return NULL;
100     
101     if(named_hooks!=NULL){
102         bool found=FALSE;
103         Rb_node node=rb_find_key_n(named_hooks, name, &found);
104         if(found)
105             return (WHook*)rb_val(node);
106     }
107     
108     return NULL;
109 }
110
111
112 /*}}}*/
113
114
115 /*{{{ Init/deinit */
116
117
118 static void destroy_item(WHook *hk, WHookItem *item)
119 {
120     if(item->fn==NULL)
121         extl_unref_fn(item->efn);
122     UNLINK_ITEM(hk->items, item, next, prev);
123     free(item);
124 }
125
126
127 static WHookItem *create_item(WHook *hk)
128 {
129     WHookItem *item=ALLOC(WHookItem);
130     if(item!=NULL){
131         LINK_ITEM_FIRST(hk->items, item, next, prev);
132         item->fn=NULL;
133         item->efn=extl_fn_none();
134     }
135     
136     return item;
137 }
138
139
140 bool hook_init(WHook *hk)
141 {
142     hk->items=NULL;
143     return TRUE;
144 }
145
146
147 WHook *create_hook()
148 {
149     CREATEOBJ_IMPL(WHook, hook, (p));
150 }
151
152
153 void hook_deinit(WHook *hk)
154 {
155     mainloop_unregister_hook(NULL, hk);
156     while(hk->items!=NULL)
157         destroy_item(hk, hk->items);
158 }
159
160
161 /*}}}*/
162
163
164 /*{{{ Find/add/remove */
165
166
167 WHookItem *hook_find(WHook *hk, WHookDummy *fn)
168 {
169     WHookItem *hi;
170     
171     for(hi=hk->items; hi!=NULL; hi=hi->next){
172         if(hi->fn==fn)
173             return hi;
174     }
175     
176     return NULL;
177 }
178
179
180 WHookItem *hook_find_extl(WHook *hk, ExtlFn efn)
181 {
182     WHookItem *hi;
183     
184     for(hi=hk->items; hi!=NULL; hi=hi->next){
185         if(extl_fn_eq(hi->efn, efn))
186             return hi;
187     }
188     
189     return NULL;
190 }
191
192
193 /*EXTL_DOC
194  * Is \var{fn} hooked to hook \var{hk}?
195  */
196 EXTL_SAFE
197 EXTL_EXPORT_MEMBER
198 bool hook_listed(WHook *hk, ExtlFn efn)
199 {
200     return hook_find_extl(hk, efn)!=NULL;
201 }
202
203
204 bool hook_add(WHook *hk, WHookDummy *fn)
205 {
206     WHookItem *item;
207     
208     if(hook_find(hk, fn))
209         return FALSE;
210     
211     item=create_item(hk);
212     if(item==NULL)
213         return FALSE;
214     item->fn=fn;
215     return TRUE;
216 }
217
218
219 /*EXTL_DOC
220  * Add \var{efn} to the list of functions to be called when the
221  * hook \var{hk} is triggered.
222  */
223 EXTL_EXPORT_AS(WHook, add)
224 bool hook_add_extl(WHook *hk, ExtlFn efn)
225 {
226     WHookItem *item;
227     
228     if(efn==extl_fn_none()){
229         warn(TR("No function given."));
230         return FALSE;
231     }
232
233     if(hook_find_extl(hk, efn))
234         return FALSE;
235     
236     item=create_item(hk);
237     
238     if(item==NULL)
239         return FALSE;
240     
241     item->efn=extl_ref_fn(efn);
242     
243     return TRUE;
244 }
245
246
247 bool hook_remove(WHook *hk, WHookDummy *fn)
248 {
249     WHookItem *item=hook_find(hk, fn);
250     if(item!=NULL)
251         destroy_item(hk, item);
252     return (item!=NULL);
253 }
254
255
256 /*EXTL_DOC
257  * Remove \var{efn} from the list of functions to be called when the 
258  * hook \var{hk} is triggered.
259  */
260 EXTL_EXPORT_AS(WHook, remove)
261 bool hook_remove_extl(WHook *hk, ExtlFn efn)
262 {
263     WHookItem *item=hook_find_extl(hk, efn);
264     if(item!=NULL)
265         destroy_item(hk, item);
266     return (item!=NULL);
267 }
268
269
270 /*}}}*/
271
272
273 /*{{{ Basic marshallers */
274
275
276 static bool marshall_v(WHookDummy *fn, void *param)
277 {
278     fn();
279     return TRUE;
280 }
281     
282
283 static bool marshall_extl_v(ExtlFn fn, void *param)
284 {
285     extl_call(fn, NULL, NULL);
286     return TRUE;
287 }
288
289
290 static bool marshall_o(WHookDummy *fn, void *param)
291 {
292     fn((Obj*)param);
293     return TRUE;
294 }
295     
296
297 static bool marshall_extl_o(ExtlFn fn, void *param)
298 {
299     return extl_call(fn, "o", NULL, (Obj*)param);
300 }
301
302
303 static bool marshall_p(WHookDummy *fn, void *param)
304 {
305     fn(param);
306     return TRUE;
307 }
308
309
310 static bool marshall_alt_v(bool (*fn)(), void *param)
311 {
312     return fn();
313 }
314     
315
316 static bool marshall_extl_alt_v(ExtlFn fn, void *param)
317 {
318     bool ret=FALSE;
319     extl_call(fn, NULL, "b", &ret);
320     return ret;
321 }
322
323
324 static bool marshall_alt_o(bool (*fn)(), void *param)
325 {
326     return fn((Obj*)param);
327 }
328     
329
330 static bool marshall_extl_alt_o(ExtlFn fn, void *param)
331 {
332     bool ret=FALSE;
333     extl_call(fn, "o", "b", (Obj*)param, &ret);
334     return ret;
335 }
336
337
338 static bool marshall_alt_p(bool (*fn)(), void *param)
339 {
340     return fn(param);
341 }
342
343
344 /*}}}*/
345
346
347 /*{{{ Call */
348
349
350 void hook_call(const WHook *hk, void *p,
351                WHookMarshall *m, WHookMarshallExtl *em)
352 {
353     WHookItem *hi, *next;
354     
355     for(hi=hk->items; hi!=NULL; hi=next){
356         next=hi->next;
357         if(hi->fn!=NULL)
358             m(hi->fn, p);
359         else if(em!=NULL)
360             em(hi->efn, p);
361     }
362 }
363
364
365 bool hook_call_alt(const WHook *hk, void *p,
366                    WHookMarshall *m, WHookMarshallExtl *em)
367 {
368     WHookItem *hi, *next;
369     bool ret=FALSE;
370     
371     for(hi=hk->items; hi!=NULL; hi=next){
372         next=hi->next;
373         if(hi->fn!=NULL)
374             ret=m(hi->fn, p);
375         else if(em!=NULL)
376             ret=em(hi->efn, p);
377         if(ret)
378             break;
379     }
380     
381     return ret;
382 }
383
384
385 void hook_call_v(const WHook *hk)
386 {
387     hook_call(hk, NULL, marshall_v, marshall_extl_v);
388 }
389
390
391 void hook_call_o(const WHook *hk, Obj *o)
392 {
393     hook_call(hk, o, marshall_o, marshall_extl_o);
394 }
395
396
397 void hook_call_p(const WHook *hk, void *p, WHookMarshallExtl *em)
398 {
399     hook_call(hk, p, marshall_p, em);
400 }
401
402
403 bool hook_call_alt_v(const WHook *hk)
404 {
405     return hook_call_alt(hk, NULL, (WHookMarshall*)marshall_alt_v, 
406                          (WHookMarshallExtl*)marshall_extl_alt_v);
407 }
408
409
410 bool hook_call_alt_o(const WHook *hk, Obj *o)
411 {
412     return hook_call_alt(hk, o, (WHookMarshall*)marshall_alt_o, 
413                          (WHookMarshallExtl*)marshall_extl_alt_o);
414 }
415
416
417 bool hook_call_alt_p(const WHook *hk, void *p, WHookMarshallExtl *em)
418 {
419     return hook_call_alt(hk, p, (WHookMarshall*)marshall_alt_p, em);
420 }
421
422
423 /*}}}*/
424
425
426