r8875: Rename timeval_diff to timeval_until and revert the arguments. timeval_diff is
[samba.git] / source / gtk / common / gtk_events.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    main select loop and event handling
5    
6    plugin for using a gtk application's event loop
7
8    Copyright (C) Stefan Metzmacher 2005
9    
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 #include "includes.h"
26 #include "lib/events/events.h"
27 #include "lib/events/events_internal.h"
28
29 #include "gtk/common/select.h"
30
31 /* as gtk_main() doesn't take a parameter nor return one,
32    we need to have a global event context structure for our
33    gtk-bases tools
34  */
35 static struct event_context *gtk_event_context_global;
36
37 static int gtk_event_context_destructor(void *ptr)
38 {
39         gtk_event_context_global = NULL;
40         return 0;
41 }
42
43 /*
44   create a gtk_event_context structure.
45 */
46 static int gtk_event_context_init(struct event_context *ev, void *private_data)
47 {
48         talloc_set_destructor(ev, gtk_event_context_destructor);
49         return 0;
50 }
51
52 struct gtk_fd_event {
53         BOOL running;
54         BOOL free_after_run;
55         GIOChannel *channel;
56         guint fd_id;
57 };
58
59 static gboolean gtk_event_fd_handler(GIOChannel *source, GIOCondition condition, gpointer data)
60 {
61         struct fd_event *fde = talloc_get_type(data, struct fd_event);
62         struct gtk_fd_event *gtk_fd = talloc_get_type(fde->additional_data,
63                                                       struct gtk_fd_event);
64         int flags = 0;
65
66         if (condition & (G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP))
67                 flags |= EVENT_FD_READ;
68         if (condition & G_IO_OUT)
69                 flags |= EVENT_FD_WRITE;
70
71         gtk_fd->running = True;
72         fde->handler(fde->event_ctx, fde, flags, fde->private_data);
73         gtk_fd->running = False;
74
75         if (gtk_fd->free_after_run) {
76                 talloc_free(fde);
77                 return gtk_false();
78         }
79
80         return gtk_true();
81 }
82
83 /*
84   destroy an fd_event
85 */
86 static int gtk_event_fd_destructor(void *ptr)
87 {
88         struct fd_event *fde = talloc_get_type(ptr, struct fd_event);
89         struct gtk_fd_event *gtk_fd = talloc_get_type(fde->additional_data,
90                                                       struct gtk_fd_event);
91
92         if (gtk_fd->running) {
93                 /* the event is running reject the talloc_free()
94                    as it's done by the gtk_event_timed_handler()
95                  */
96                 gtk_fd->free_after_run = True;
97                 return -1;
98         }
99
100         if (fde->flags) {
101                 /* only if any flag is set we have really registered an event */
102                 g_source_remove(gtk_fd->fd_id);
103         }
104         g_io_channel_unref(gtk_fd->channel);
105
106         return 0;
107 }
108
109 /*
110   add a fd based event
111   return NULL on failure (memory allocation error)
112 */
113 static struct fd_event *gtk_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx,
114                                          int fd, uint16_t flags,
115                                          event_fd_handler_t handler,
116                                          void *private_data)
117 {
118         struct fd_event *fde;
119         struct gtk_fd_event *gtk_fd;
120         GIOChannel *channel;
121         guint fd_id = 0;
122         GIOCondition condition = 0;
123
124         fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event);
125         if (!fde) return NULL;
126
127         gtk_fd = talloc(fde, struct gtk_fd_event);
128         if (gtk_fd == NULL) {
129                 talloc_free(fde);
130                 return NULL;
131         }
132
133         fde->event_ctx          = ev;
134         fde->fd                 = fd;
135         fde->flags              = flags;
136         fde->handler            = handler;
137         fde->private_data       = private_data;
138         fde->additional_data    = gtk_fd;
139
140         channel = g_io_channel_unix_new(fde->fd);
141         if (channel == NULL) {
142                 talloc_free(fde);
143                 return NULL;
144         }
145
146         if (fde->flags & EVENT_FD_READ)
147                 condition |= G_IO_IN;
148         if (fde->flags & EVENT_FD_WRITE)
149                 condition |= G_IO_OUT;
150
151         if (condition) {
152                 /* only register the event when at least one flag is set
153                    as condition == 0 means wait for any event and is not the same
154                    as fde->flags == 0 !
155                 */
156                 fd_id = g_io_add_watch(channel, condition, gtk_event_fd_handler, fde);
157         }
158
159         gtk_fd->running         = False;
160         gtk_fd->free_after_run  = False;
161         gtk_fd->channel         = channel;
162         gtk_fd->fd_id           = fd_id;
163
164         talloc_set_destructor(fde, gtk_event_fd_destructor);
165
166         return fde;
167 }
168
169 /*
170   return the fd event flags
171 */
172 static uint16_t gtk_event_get_fd_flags(struct fd_event *fde)
173 {
174         if (!fde) return 0;
175
176         return fde->flags;
177 }
178
179 /*
180   set the fd event flags
181 */
182 static void gtk_event_set_fd_flags(struct fd_event *fde, uint16_t flags)
183 {
184         struct gtk_fd_event *gtk_fd = talloc_get_type(fde->additional_data,
185                                                       struct gtk_fd_event);
186         GIOCondition condition = 0;
187
188         if (!fde) return;
189
190         if (fde->flags == flags) return;
191
192         if (flags & EVENT_FD_READ)
193                 condition |= G_IO_IN;
194         if (flags & EVENT_FD_WRITE)
195                 condition |= G_IO_OUT;
196
197         /* only register the event when at least one flag is set
198            as condition == 0 means wait for any event and is not the same
199            as fde->flags == 0 !
200         */
201         if (fde->flags) {
202                 g_source_remove(gtk_fd->fd_id);
203         }
204         if (condition) {
205                 gtk_fd->fd_id = g_io_add_watch(gtk_fd->channel, condition, gtk_event_fd_handler, fde);
206         }
207
208         fde->flags = flags;
209 }
210
211 struct gtk_timed_event {
212         BOOL running;
213         guint te_id;
214 };
215
216 static gboolean gtk_event_timed_handler(gpointer data)
217 {
218         struct timed_event *te = talloc_get_type(data, struct timed_event);
219         struct gtk_timed_event *gtk_te = talloc_get_type(te->additional_data,
220                                                          struct gtk_timed_event);
221         struct timeval t = timeval_current();
222
223         gtk_te->running = True;
224         te->handler(te->event_ctx, te, t, te->private_data);
225         gtk_te->running = False;
226
227         talloc_free(te);
228
229         /* return FALSE mean this event should be removed */
230         return gtk_false();
231 }
232
233 /*
234   destroy a timed event
235 */
236 static int gtk_event_timed_destructor(void *ptr)
237 {
238         struct timed_event *te = talloc_get_type(ptr, struct timed_event);
239         struct gtk_timed_event *gtk_te = talloc_get_type(te->additional_data,
240                                                          struct gtk_timed_event);
241
242         if (gtk_te->running) {
243                 /* the event is running reject the talloc_free()
244                    as it's done by the gtk_event_timed_handler()
245                  */
246                 return -1;
247         }
248
249         g_source_remove(gtk_te->te_id);
250
251         return 0;
252 }
253
254 /*
255   add a timed event
256   return NULL on failure (memory allocation error)
257 */
258 static struct timed_event *gtk_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx,
259                                                struct timeval next_event, 
260                                                event_timed_handler_t handler, 
261                                                void *private_data) 
262 {
263         struct timed_event *te;
264         struct gtk_timed_event *gtk_te;
265         struct timeval cur_tv, diff_tv;
266         guint timeout;
267
268         te = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
269         if (te == NULL) return NULL;
270
271         gtk_te = talloc(te, struct gtk_timed_event);
272         if (gtk_te == NULL) {
273                 talloc_free(te);
274                 return NULL;
275         }
276
277         te->event_ctx           = ev;
278         te->next_event          = next_event;
279         te->handler             = handler;
280         te->private_data        = private_data;
281         te->additional_data     = gtk_te;
282
283         cur_tv                  = timeval_current();
284         diff_tv                 = timeval_until(&cur_tv, &next_event);
285         timeout                 = ((diff_tv.tv_usec+999)/1000)+(diff_tv.tv_sec*1000);
286
287         gtk_te->te_id           = g_timeout_add(timeout, gtk_event_timed_handler, te);
288         gtk_te->running         = False;
289
290         talloc_set_destructor(te, gtk_event_timed_destructor);
291
292         return te;
293 }
294
295 /*
296   do a single event loop
297 */
298 static int gtk_event_loop_once(struct event_context *ev)
299 {
300         /*
301          * gtk_main_iteration ()
302          *
303          * gboolean    gtk_main_iteration              (void);
304          *
305          * Runs a single iteration of the mainloop. If no events 
306          * are waiting to be processed GTK+ will block until the
307          * next event is noticed. If you don't want to block look
308          * at gtk_main_iteration_do() or check if any events are
309          * pending with gtk_events_pending() first.
310          * 
311          * Returns :    TRUE if gtk_main_quit() has been called for the innermost mainloop.
312          */
313         gboolean ret;
314
315         ret = gtk_main_iteration();
316         if (ret == gtk_true()) {
317                 return -1;
318         }
319
320         return 0;
321 }
322
323 /*
324   return with 0
325 */
326 static int gtk_event_loop_wait(struct event_context *ev)
327 {
328         /*
329          * gtk_main ()
330          * 
331          * void        gtk_main                        (void);
332          * 
333          * Runs the main loop until gtk_main_quit() is called.
334          * You can nest calls to gtk_main(). In that case
335          * gtk_main_quit() will make the innermost invocation
336          * of the main loop return. 
337          */
338         gtk_main();
339         return 0;
340 }
341
342 static const struct event_ops gtk_event_ops = {
343         .context_init   = gtk_event_context_init,
344         .add_fd         = gtk_event_add_fd,
345         .get_fd_flags   = gtk_event_get_fd_flags,
346         .set_fd_flags   = gtk_event_set_fd_flags,
347         .add_timed      = gtk_event_add_timed,
348         .loop_once      = gtk_event_loop_once,
349         .loop_wait      = gtk_event_loop_wait,
350 };
351
352 int gtk_event_loop(void)
353 {
354         int ret;
355
356         gtk_event_context_global = event_context_init_ops(NULL, &gtk_event_ops, NULL);
357         if (!gtk_event_context_global) return -1;
358
359         ret = event_loop_wait(gtk_event_context_global);
360
361         talloc_free(gtk_event_context_global);
362
363         return ret;
364 }
365
366 struct event_context *gtk_event_context(void)
367 {
368         return gtk_event_context_global;
369 }