From 2251186b5bd164f1ad7707a428d0b6c91297f573 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 15 Feb 2005 11:57:43 +0000 Subject: r5409: - add a gtk events plugin - this is used in our gtk apps - make the main() functions of the gtk apps look more simular (we need to get rid of the globals in gregedit!) metze (This used to be commit 1051f9b32f4a5c69a1a6928e6849c8ada047032e) --- source4/gtk/common/gtk-smb.h | 3 + source4/gtk/common/gtk_events.c | 369 ++++++++++++++++++++++++++++++++++++++++ source4/gtk/config.mk | 3 +- source4/gtk/tools/gepdump.c | 11 +- source4/gtk/tools/gregedit.c | 48 +++--- source4/gtk/tools/gwcrontab.c | 4 +- source4/gtk/tools/gwsam.c | 5 +- 7 files changed, 407 insertions(+), 36 deletions(-) create mode 100644 source4/gtk/common/gtk_events.c diff --git a/source4/gtk/common/gtk-smb.h b/source4/gtk/common/gtk-smb.h index cbbd44698f..e85eb5be85 100644 --- a/source4/gtk/common/gtk-smb.h +++ b/source4/gtk/common/gtk-smb.h @@ -79,5 +79,8 @@ GtkWidget *gtk_select_domain_dialog_new (struct dcerpc_pipe *sam_pipe); GType gtk_select_domain_dialog_get_type (void); struct policy_handle gtk_select_domain_dialog_get_handle(GtkSelectDomainDialog *d); +int gtk_event_loop(void); +struct event_context; +struct event_context *gtk_event_context(void); #endif diff --git a/source4/gtk/common/gtk_events.c b/source4/gtk/common/gtk_events.c new file mode 100644 index 0000000000..faa99a780e --- /dev/null +++ b/source4/gtk/common/gtk_events.c @@ -0,0 +1,369 @@ +/* + Unix SMB/CIFS implementation. + + main select loop and event handling + + plugin for using a gtk application's event loop + + Copyright (C) Stefan Metzmacher 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "lib/events/events_internal.h" + +#include "gtk/common/select.h" + +/* as gtk_main() doesn't take a parameter nor return one, + we need to have a global event context structure for our + gtk-bases tools + */ +static struct event_context *gtk_event_context_global; + +static int gtk_event_context_destructor(void *ptr) +{ + gtk_event_context_global = NULL; + return 0; +} + +/* + create a gtk_event_context structure. +*/ +static int gtk_event_context_init(struct event_context *ev, void *private_data) +{ + talloc_set_destructor(ev, gtk_event_context_destructor); + return 0; +} + +struct gtk_fd_event { + BOOL running; + BOOL free_after_run; + GIOChannel *channel; + guint fd_id; +}; + +static gboolean gtk_event_fd_handler(GIOChannel *source, GIOCondition condition, gpointer data) +{ + struct fd_event *fde = talloc_get_type(data, struct fd_event); + struct gtk_fd_event *gtk_fd = talloc_get_type(fde->additional_data, + struct gtk_fd_event); + int flags = 0; + + if (condition & (G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP)) + flags |= EVENT_FD_READ; + if (condition & G_IO_OUT) + flags |= EVENT_FD_WRITE; + + gtk_fd->running = True; + fde->handler(fde->event_ctx, fde, flags, fde->private_data); + gtk_fd->running = False; + + if (gtk_fd->free_after_run) { + talloc_free(fde); + return gtk_false(); + } + + return gtk_true(); +} + +/* + destroy an fd_event +*/ +static int gtk_event_fd_destructor(void *ptr) +{ + struct fd_event *fde = talloc_get_type(ptr, struct fd_event); + struct gtk_fd_event *gtk_fd = talloc_get_type(fde->additional_data, + struct gtk_fd_event); + + if (gtk_fd->running) { + /* the event is running reject the talloc_free() + as it's done by the gtk_event_timed_handler() + */ + gtk_fd->free_after_run = True; + return -1; + } + + if (fde->flags) { + /* only if any flag is set we have really registered an event */ + g_source_remove(gtk_fd->fd_id); + } + g_io_channel_unref(gtk_fd->channel); + + return 0; +} + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +static struct fd_event *gtk_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) +{ + struct fd_event *fde; + struct gtk_fd_event *gtk_fd; + GIOChannel *channel; + guint fd_id = 0; + GIOCondition condition = 0; + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; + + gtk_fd = talloc(fde, struct gtk_fd_event); + if (gtk_fd == NULL) { + talloc_free(fde); + return NULL; + } + + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_data = gtk_fd; + + channel = g_io_channel_unix_new(fde->fd); + if (channel == NULL) { + talloc_free(fde); + return NULL; + } + + if (fde->flags & EVENT_FD_READ) + condition |= G_IO_IN; + if (fde->flags & EVENT_FD_WRITE) + condition |= G_IO_OUT; + + if (condition) { + /* only register the event when at least one flag is set + as condition == 0 means wait for any event and is not the same + as fde->flags == 0 ! + */ + fd_id = g_io_add_watch(channel, condition, gtk_event_fd_handler, fde); + } + + gtk_fd->running = False; + gtk_fd->free_after_run = False; + gtk_fd->channel = channel; + gtk_fd->fd_id = fd_id; + + talloc_set_destructor(fde, gtk_event_fd_destructor); + + return fde; +} + +/* + return the fd event flags +*/ +static uint16_t gtk_event_get_fd_flags(struct fd_event *fde) +{ + if (!fde) return 0; + + return fde->flags; +} + +/* + set the fd event flags +*/ +static void gtk_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + struct gtk_fd_event *gtk_fd = talloc_get_type(fde->additional_data, + struct gtk_fd_event); + GIOCondition condition = 0; + + if (!fde) return; + + if (fde->flags == flags) return; + + if (flags & EVENT_FD_READ) + condition |= G_IO_IN; + if (flags & EVENT_FD_WRITE) + condition |= G_IO_OUT; + + /* only register the event when at least one flag is set + as condition == 0 means wait for any event and is not the same + as fde->flags == 0 ! + */ + if (fde->flags) { + g_source_remove(gtk_fd->fd_id); + } + if (condition) { + gtk_fd->fd_id = g_io_add_watch(gtk_fd->channel, condition, gtk_event_fd_handler, fde); + } + + fde->flags = flags; +} + +struct gtk_timed_event { + BOOL running; + guint te_id; +}; + +static gboolean gtk_event_timed_handler(gpointer data) +{ + struct timed_event *te = talloc_get_type(data, struct timed_event); + struct gtk_timed_event *gtk_te = talloc_get_type(te->additional_data, + struct gtk_timed_event); + struct timeval t = timeval_current(); + + gtk_te->running = True; + te->handler(te->event_ctx, te, t, te->private_data); + gtk_te->running = False; + + talloc_free(te); + + /* return FALSE mean this event should be removed */ + return gtk_false(); +} + +/* + destroy a timed event +*/ +static int gtk_event_timed_destructor(void *ptr) +{ + struct timed_event *te = talloc_get_type(ptr, struct timed_event); + struct gtk_timed_event *gtk_te = talloc_get_type(te->additional_data, + struct gtk_timed_event); + + if (gtk_te->running) { + /* the event is running reject the talloc_free() + as it's done by the gtk_event_timed_handler() + */ + return -1; + } + + g_source_remove(gtk_te->te_id); + + return 0; +} + +/* + add a timed event + return NULL on failure (memory allocation error) +*/ +static struct timed_event *gtk_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) +{ + struct timed_event *te; + struct gtk_timed_event *gtk_te; + struct timeval cur_tv, diff_tv; + guint timeout; + + te = talloc(mem_ctx?mem_ctx:ev, struct timed_event); + if (te == NULL) return NULL; + + gtk_te = talloc(te, struct gtk_timed_event); + if (gtk_te == NULL) { + talloc_free(te); + return NULL; + } + + te->event_ctx = ev; + te->next_event = next_event; + te->handler = handler; + te->private_data = private_data; + te->additional_data = gtk_te; + + cur_tv = timeval_current(); + diff_tv = timeval_diff(&next_event, &cur_tv); + timeout = ((diff_tv.tv_usec+999)/1000)+(diff_tv.tv_sec*1000); + + gtk_te->te_id = g_timeout_add(timeout, gtk_event_timed_handler, te); + gtk_te->running = False; + + talloc_set_destructor(te, gtk_event_timed_destructor); + + return te; +} + +/* + do a single event loop +*/ +static int gtk_event_loop_once(struct event_context *ev) +{ + /* + * gtk_main_iteration () + * + * gboolean gtk_main_iteration (void); + * + * Runs a single iteration of the mainloop. If no events + * are waiting to be processed GTK+ will block until the + * next event is noticed. If you don't want to block look + * at gtk_main_iteration_do() or check if any events are + * pending with gtk_events_pending() first. + * + * Returns : TRUE if gtk_main_quit() has been called for the innermost mainloop. + */ + gboolean ret; + + ret = gtk_main_iteration(); + if (ret == gtk_true()) { + return -1; + } + + return 0; +} + +/* + return with 0 +*/ +static int gtk_event_loop_wait(struct event_context *ev) +{ + /* + * gtk_main () + * + * void gtk_main (void); + * + * Runs the main loop until gtk_main_quit() is called. + * You can nest calls to gtk_main(). In that case + * gtk_main_quit() will make the innermost invocation + * of the main loop return. + */ + gtk_main(); + return 0; +} + +static const struct event_ops gtk_event_ops = { + .context_init = gtk_event_context_init, + .add_fd = gtk_event_add_fd, + .get_fd_flags = gtk_event_get_fd_flags, + .set_fd_flags = gtk_event_set_fd_flags, + .add_timed = gtk_event_add_timed, + .loop_once = gtk_event_loop_once, + .loop_wait = gtk_event_loop_wait, +}; + +int gtk_event_loop(void) +{ + int ret; + + gtk_event_context_global = event_context_init_ops(NULL, >k_event_ops, NULL); + if (!gtk_event_context_global) return -1; + + ret = event_loop_wait(gtk_event_context_global); + + talloc_free(gtk_event_context_global); + + return ret; +} + +struct event_context *gtk_event_context(void) +{ + return gtk_event_context_global; +} diff --git a/source4/gtk/config.mk b/source4/gtk/config.mk index 72040c6882..0066583973 100644 --- a/source4/gtk/config.mk +++ b/source4/gtk/config.mk @@ -5,7 +5,8 @@ [SUBSYSTEM::GTKSMB] NOPROTO = YES INIT_OBJ_FILES = gtk/common/gtk-smb.o -ADD_OBJ_FILES = gtk/common/select.o +ADD_OBJ_FILES = gtk/common/select.o \ + gtk/common/gtk_events.o REQUIRED_SUBSYSTEMS = CHARSET LIBBASIC EXT_LIB_gtk RPC_NDR_SAMR # End SUBSYSTEM GTKSMB ############################## diff --git a/source4/gtk/tools/gepdump.c b/source4/gtk/tools/gepdump.c index 88cd9ff8b7..d445dd63cb 100644 --- a/source4/gtk/tools/gepdump.c +++ b/source4/gtk/tools/gepdump.c @@ -417,15 +417,16 @@ static GtkWidget* create_mainwindow (void) } -int main(int argc, char **argv) + int main(int argc, char **argv) { - gtk_init(&argc, &argv); gepdump_init_subsystems; lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); - setup_logging("gepdump", True); + setup_logging(argv[0], DEBUG_STDERR); + + gtk_init(&argc, &argv); mainwin = create_mainwindow(); gtk_widget_show_all(mainwin); - gtk_main(); - return 0; + + return gtk_event_loop(); } diff --git a/source4/gtk/tools/gregedit.c b/source4/gtk/tools/gregedit.c index 918ebd6945..9d0a87f2a7 100644 --- a/source4/gtk/tools/gregedit.c +++ b/source4/gtk/tools/gregedit.c @@ -660,7 +660,7 @@ gboolean on_key_activate(GtkTreeSelection *selection, return TRUE; } -static GtkWidget* create_mainwin (void) +static GtkWidget* create_mainwindow(void) { GtkWidget *vbox1; GtkWidget *menubar; @@ -955,43 +955,41 @@ static GtkWidget* create_savefilewin (void) return savefilewin; } +static int gregedit_load_defaults(void) +{ + WERROR error = reg_open_local(®istry); + if(!W_ERROR_IS_OK(error)) { + gtk_show_werror(mainwin, error); + return -1; + } + registry_load_root(); + + return 0; +} + int main(int argc, char *argv[]) { - poptContext pc; - WERROR error; - int opt; - struct poptOption long_options[] = { - POPT_AUTOHELP - POPT_TABLEEND - }; + int ret; gregedit_init_subsystems; - lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); + setup_logging(argv[0], DEBUG_STDERR); - gtk_init (&argc, &argv); mem_ctx = talloc_init("gregedit"); - pc = poptGetContext(argv[0], argc, (const char **) argv, long_options,0); + gtk_init(&argc, &argv); + mainwin = create_mainwindow(); + gtk_widget_show_all(mainwin); - while((opt = poptGetNextOpt(pc)) != -1) { - } + ret = gregedit_load_defaults(); + if (ret != 0) goto failed; - error = reg_open_local(®istry); - if(!W_ERROR_IS_OK(error)) { - gtk_show_werror(mainwin, error); - return -1; - } - mainwin = create_mainwin (); - registry_load_root(); - - gtk_widget_show_all (mainwin); - - gtk_main (); + ret = gtk_event_loop(); +failed: talloc_free(mem_ctx); - return 0; + return ret; } diff --git a/source4/gtk/tools/gwcrontab.c b/source4/gtk/tools/gwcrontab.c index 580bbc2ae3..69ef2d7965 100644 --- a/source4/gtk/tools/gwcrontab.c +++ b/source4/gtk/tools/gwcrontab.c @@ -501,11 +501,11 @@ static GtkWidget*create_new_job_dialog (void) gwcrontab_init_subsystems; lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); + setup_logging(argv[0], DEBUG_STDERR); gtk_init(&argc, &argv); mainwin = create_mainwindow(); gtk_widget_show_all(mainwin); - gtk_main(); - return 0; + return gtk_event_loop(); } diff --git a/source4/gtk/tools/gwsam.c b/source4/gtk/tools/gwsam.c index 7d9abde3d3..878440527e 100644 --- a/source4/gtk/tools/gwsam.c +++ b/source4/gtk/tools/gwsam.c @@ -420,13 +420,12 @@ create_mainwindow (void) gwsam_init_subsystems; lp_load(dyn_CONFIGFILE,True,False,False); load_interfaces(); - setup_logging("gwsam", True); + setup_logging(argv[0], DEBUG_STDERR); gtk_init(&argc, &argv); mainwin = create_mainwindow(); connect_sam(); gtk_widget_show_all(mainwin); - gtk_main(); - return 0; + return gtk_event_loop(); } -- cgit