2 Unix SMB/CIFS implementation.
4 main select loop and event handling
6 plugin for using a gtk application's event loop
8 Copyright (C) Stefan Metzmacher 2005
9 Copyright (C) Jelmer Vernooij 2009
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34 #include "tevent_internal.h"
36 #include "common/select.h"
38 /* as gtk_main() doesn't take a parameter nor return one,
39 we need to have a global event context structure for our
42 static struct tevent_context *gtk_event_context_global;
44 static int gtk_event_context_destructor(struct tevent_context *ev)
46 gtk_event_context_global = NULL;
51 create a gtk_event_context structure.
53 static int gtk_event_context_init(struct tevent_context *ev)
55 talloc_set_destructor(ev, gtk_event_context_destructor);
59 struct gtk_tevent_fd {
66 static gboolean gtk_event_fd_handler(GIOChannel *source, GIOCondition condition, gpointer data)
68 struct tevent_fd *fde = talloc_get_type(data, struct tevent_fd);
69 struct gtk_tevent_fd *gtk_fd = talloc_get_type(fde->additional_data,
70 struct gtk_tevent_fd);
73 if (condition & (G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP))
74 flags |= TEVENT_FD_READ;
75 if (condition & G_IO_OUT)
76 flags |= TEVENT_FD_WRITE;
78 gtk_fd->running = true;
79 fde->handler(fde->event_ctx, fde, flags, fde->private_data);
80 gtk_fd->running = false;
82 if (gtk_fd->free_after_run) {
93 static int gtk_event_fd_destructor(struct tevent_fd *fde)
95 struct gtk_tevent_fd *gtk_fd = talloc_get_type(fde->additional_data,
96 struct gtk_tevent_fd);
98 if (gtk_fd->running) {
99 /* the event is running reject the talloc_free()
100 as it's done by the gtk_event_timed_handler()
102 gtk_fd->free_after_run = true;
107 /* only if any flag is set we have really registered an event */
108 g_source_remove(gtk_fd->fd_id);
110 g_io_channel_unref(gtk_fd->channel);
117 return NULL on failure (memory allocation error)
119 static struct tevent_fd *gtk_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
120 int fd, uint16_t flags,
121 tevent_fd_handler_t handler,
123 const char *handler_location,
124 const char *location)
126 struct tevent_fd *fde;
127 struct gtk_tevent_fd *gtk_fd;
130 GIOCondition condition = 0;
132 fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
133 if (!fde) return NULL;
135 gtk_fd = talloc(fde, struct gtk_tevent_fd);
136 if (gtk_fd == NULL) {
144 fde->handler = handler;
145 fde->private_data = private_data;
146 fde->additional_flags = 0;
147 fde->additional_data = gtk_fd;
149 channel = g_io_channel_unix_new(fde->fd);
150 if (channel == NULL) {
155 if (fde->flags & TEVENT_FD_READ)
156 condition |= (G_IO_IN | G_IO_ERR | G_IO_HUP);
157 if (fde->flags & TEVENT_FD_WRITE)
158 condition |= G_IO_OUT;
161 /* only register the event when at least one flag is set
162 as condition == 0 means wait for any event and is not the same
165 fd_id = g_io_add_watch(channel, condition, gtk_event_fd_handler, fde);
168 gtk_fd->running = false;
169 gtk_fd->free_after_run = false;
170 gtk_fd->channel = channel;
171 gtk_fd->fd_id = fd_id;
173 talloc_set_destructor(fde, gtk_event_fd_destructor);
179 return the fd event flags
181 static uint16_t gtk_event_get_fd_flags(struct tevent_fd *fde)
187 set the fd event flags
189 static void gtk_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
191 struct gtk_tevent_fd *gtk_fd = talloc_get_type(fde->additional_data,
192 struct gtk_tevent_fd);
193 GIOCondition condition = 0;
195 if (fde->flags == flags) return;
197 if (flags & TEVENT_FD_READ)
198 condition |= (G_IO_IN | G_IO_ERR | G_IO_HUP);
199 if (flags & TEVENT_FD_WRITE)
200 condition |= G_IO_OUT;
202 /* only register the event when at least one flag is set
203 as condition == 0 means wait for any event and is not the same
207 g_source_remove(gtk_fd->fd_id);
210 gtk_fd->fd_id = g_io_add_watch(gtk_fd->channel, condition, gtk_event_fd_handler, fde);
216 struct gtk_tevent_timer {
221 destroy a timed event
223 static int gtk_event_timed_destructor(struct tevent_timer *te)
225 struct gtk_tevent_timer *gtk_te = talloc_get_type(te->additional_data,
226 struct gtk_tevent_timer);
228 g_source_remove(gtk_te->te_id);
233 static int gtk_event_timed_deny_destructor(struct tevent_timer *te)
238 static gboolean gtk_event_timed_handler(gpointer data)
240 struct tevent_timer *te = talloc_get_type(data, struct tevent_timer);
241 struct timeval t = timeval_current();
243 /* deny the handler to free the event */
244 talloc_set_destructor(te, gtk_event_timed_deny_destructor);
245 te->handler(te->event_ctx, te, t, te->private_data);
247 talloc_set_destructor(te, gtk_event_timed_destructor);
250 /* return FALSE mean this event should be removed */
256 return NULL on failure (memory allocation error)
258 static struct tevent_timer *gtk_event_add_timer(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
259 struct timeval next_event,
260 tevent_timer_handler_t handler,
262 const char *handler_name,
263 const char *location)
265 struct tevent_timer *te;
266 struct gtk_tevent_timer *gtk_te;
267 struct timeval cur_tv, diff_tv;
270 te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
271 if (te == NULL) return NULL;
273 gtk_te = talloc(te, struct gtk_tevent_timer);
274 if (gtk_te == NULL) {
280 te->next_event = next_event;
281 te->handler = handler;
282 te->private_data = private_data;
283 te->additional_data = gtk_te;
285 cur_tv = timeval_current();
286 diff_tv = timeval_until(&cur_tv, &next_event);
287 timeout = ((diff_tv.tv_usec+999)/1000)+(diff_tv.tv_sec*1000);
289 gtk_te->te_id = g_timeout_add(timeout, gtk_event_timed_handler, te);
291 talloc_set_destructor(te, gtk_event_timed_destructor);
297 do a single event loop
300 static int gtk_event_loop_once(struct tevent_context *ev,
301 const char *location)
304 * gtk_main_iteration ()
306 * gboolean gtk_main_iteration (void);
308 * Runs a single iteration of the mainloop. If no events
309 * are waiting to be processed GTK+ will block until the
310 * next event is noticed. If you don't want to block look
311 * at gtk_main_iteration_do() or check if any events are
312 * pending with gtk_events_pending() first.
314 * Returns : TRUE if gtk_main_quit() has been called for the innermost mainloop.
318 ret = gtk_main_iteration();
319 if (ret == gtk_true()) {
330 static int gtk_event_loop_wait(struct tevent_context *ev,
331 const char *location)
336 * void gtk_main (void);
338 * Runs the main loop until gtk_main_quit() is called.
339 * You can nest calls to gtk_main(). In that case
340 * gtk_main_quit() will make the innermost invocation
341 * of the main loop return.
347 static const struct tevent_ops gtk_event_ops = {
348 .context_init = gtk_event_context_init,
349 .add_fd = gtk_event_add_fd,
350 .get_fd_flags = gtk_event_get_fd_flags,
351 .set_fd_flags = gtk_event_set_fd_flags,
352 .add_timer = gtk_event_add_timer,
353 .loop_once = gtk_event_loop_once,
354 .loop_wait = gtk_event_loop_wait,
357 int gtk_event_loop(void)
361 tevent_register_backend("gtk", >k_event_ops);
363 gtk_event_context_global = tevent_context_init_byname(NULL, "gtk");
364 if (!gtk_event_context_global) return -1;
366 ret = tevent_loop_wait(gtk_event_context_global);
368 talloc_free(gtk_event_context_global);
373 struct tevent_context *gtk_event_context(void)
375 return gtk_event_context_global;