2 * ion/libmainloop/defer.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
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.
12 /* This file contains routines for deferred execution of potentially
13 * dangerous actions. They're called upon returning to the main
17 #include <libtu/obj.h>
18 #include <libtu/objp.h>
19 #include <libtu/types.h>
20 #include <libtu/misc.h>
21 #include <libtu/dlist.h>
22 #include <libtu/output.h>
23 #include <libtu/locale.h>
27 DECLSTRUCT(WDeferred){
29 WDeferredAction *action;
31 WDeferred *next, *prev;
36 static WDeferred *deferred=NULL;
41 /* To avoid allocating memory all the time, we use a small
42 * buffer that should be able to contain the small expected
43 * number of simultaneous deferred actions.
45 static WDeferred dbuf[N_DBUF];
46 static int dbuf_used=0;
49 static WDeferred *alloc_defer()
53 /* Keeping it simple -- this naive loop should do it
56 for(i=0; i<N_DBUF; i++){
57 if(!dbuf_used&(1<<i)){
62 return ALLOC(WDeferred);
66 static void free_defer(WDeferred *d)
68 if(d>=dbuf && d<dbuf+N_DBUF){
69 dbuf_used&=~1<<((d-dbuf)/sizeof(WDeferred));
76 static void defer_watch_handler(Watch *w, Obj *obj)
78 WDeferred *d=(WDeferred*)w;
80 UNLINK_ITEM(*(WDeferred**)(d->list), d, next, prev);
84 warn(TR("Object destroyed while deferred actions are still pending."));
88 bool mainloop_defer_action_on_list(Obj *obj, WDeferredAction *action,
102 d->fn=extl_fn_none();
105 watch_setup(&(d->watch), obj, defer_watch_handler);
107 LINK_ITEM(*list, d, next, prev);
113 bool mainloop_defer_action(Obj *obj, WDeferredAction *action)
115 return mainloop_defer_action_on_list(obj, action, &deferred);
119 bool mainloop_defer_destroy(Obj *obj)
121 if(OBJ_IS_BEING_DESTROYED(obj))
124 return mainloop_defer_action(obj, destroy_obj);
128 bool mainloop_defer_extl_on_list(ExtlFn fn, WDeferred **list)
141 d->fn=extl_ref_fn(fn);
143 watch_init(&(d->watch));
145 LINK_ITEM(*list, d, next, prev);
152 * Defer execution of \var{fn} until the main loop.
155 EXTL_EXPORT_AS(mainloop, defer)
156 bool mainloop_defer_extl(ExtlFn fn)
158 return mainloop_defer_extl_on_list(fn, &deferred);
162 static void do_execute(WDeferred *d)
164 Obj *obj=d->watch.obj;
165 WDeferredAction *a=d->action;
168 watch_reset(&(d->watch));
174 }else if(fn!=extl_fn_none()){
175 extl_call(fn, NULL, NULL);
181 void mainloop_execute_deferred_on_list(WDeferred **list)
184 void (*action)(Obj*);
188 UNLINK_ITEM(*list, d, next, prev);
194 void mainloop_execute_deferred()
196 mainloop_execute_deferred_on_list(&deferred);