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