/* This file is part of GNUnet (C) 2003, 2004, 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet 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, or (at your option) any later version. GNUnet 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 GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/common/helper.c * @brief This file contains some GUI helper functions * @author Igor Wronsky * @author Christian Grothoff */ #include "platform.h" #include "gnunetgtk_common.h" #include "../core/eggtrayicon.h" #include #include #include #include #define HELPER_DEBUG GNUNET_NO #ifdef WITH_LIBNOTIFY #include #endif #ifdef WITH_LIBGKSU2 /* Not used because libgksu2 headers have broken depends in Debian And this is not really needed #include */ gboolean gksu_run (gchar * command_line, GError ** error); #endif typedef struct { struct GNUNET_Semaphore *sem; void *args; GNUNET_ThreadMainFunction func; int destroyed; void *rval; } SaveCall; typedef struct Plugin { struct Plugin *next; char *name; void *library; } Plugin; static GladeXML *mainXML; static GtkIconFactory *iconFactory; #if GTK_CHECK_VERSION(2,10,0) static GtkStatusIcon *trayIcon; #endif static char *gladeFile; static GdkWindowState main_window_state; /** * the main thread */ static struct GNUNET_ThreadHandle *mainThread; static SaveCall **psc; static unsigned int pscCount; static struct GNUNET_Mutex *sclock; static int saveCallsUp; static Plugin *plugin; static void *shutdown_function; static struct GNUNET_GC_Configuration *cfg; static struct GNUNET_CronManager *cron; struct GNUNET_CronManager * GNUNET_GTK_get_cron_manager () { return cron; } static gboolean saveCallWrapper (gpointer data) { SaveCall *call = data; int i; /* clearly, we are no longer pending, so remove from psc */ if (call->sem != NULL) { GNUNET_mutex_lock (sclock); for (i = 0; i < pscCount; i++) { if (psc[i] == call) { psc[i] = psc[pscCount - 1]; break; } } GNUNET_GE_ASSERT (NULL, i != pscCount); GNUNET_array_grow (psc, pscCount, pscCount - 1); GNUNET_mutex_unlock (sclock); } call->rval = call->func (call->args); if (call->sem != NULL) GNUNET_semaphore_up (call->sem); return FALSE; } /** * Call a callback function from the mainloop/main thread ("SaveCall"). * Since GTK doesn't work with multi-threaded applications under Windows, * all GTK operations have to be done in the main thread */ void * GNUNET_GTK_save_call (GNUNET_ThreadMainFunction func, void *args) { SaveCall call; GNUNET_mutex_lock (sclock); if ((saveCallsUp == GNUNET_NO) || (!GNUNET_thread_test_self (mainThread))) { GNUNET_GE_ASSERT(NULL, saveCallsUp != GNUNET_SYSERR); call.args = args; call.func = func; call.sem = GNUNET_semaphore_create (0); call.destroyed = 0; call.rval = NULL; GNUNET_array_grow (psc, pscCount, pscCount + 1); psc[pscCount - 1] = &call; gtk_idle_add (&saveCallWrapper, &call); GNUNET_mutex_unlock (sclock); GNUNET_thread_stop_sleep (mainThread); GNUNET_semaphore_down (call.sem, GNUNET_YES); GNUNET_semaphore_destroy (call.sem); return call.rval; } else { GNUNET_mutex_unlock (sclock); return func (args); } } /** * Simple accessor method. */ const char * GNUNET_GTK_get_glade_filename () { return gladeFile; } /** * Simple accessor method. */ GladeXML * GNUNET_GTK_get_main_glade_XML () { return mainXML; } /** * Simple accessor method. */ GtkIconFactory * GNUNET_GTK_get_iconFactory () { return iconFactory; } /** * Simple accessor method. */ #if GTK_CHECK_VERSION(2,10,0) GtkStatusIcon * GNUNET_GTK_get_trayIcon () { return trayIcon; } #endif static void connector (const gchar * handler_name, GObject * object, const gchar * signal_name, const gchar * signal_data, GObject * connect_object, gboolean after, gpointer user_data) { GModule *module; GladeXML *xml = user_data; Plugin *plug; void *method; plug = plugin; method = NULL; while (plug != NULL) { method = GNUNET_plugin_resolve_function (plug->library, handler_name, GNUNET_NO); if (method != NULL) break; plug = plug->next; } if (0 == strcmp (handler_name, "gnunet_gtk_main_quit")) method = shutdown_function; if (method == NULL) { module = g_module_open (NULL, 0); if ((module == NULL) || (TRUE != g_module_symbol (module, handler_name, &method))) { GNUNET_GE_LOG (NULL, GNUNET_GE_WARNING | GNUNET_GE_DEVELOPER | GNUNET_GE_IMMEDIATE, _("Failed to find handler for `%s'\n"), handler_name); g_module_close (module); return; } g_module_close (module); } glade_xml_signal_connect (xml, handler_name, (GCallback) method); } void GNUNET_GTK_connect_glade_with_plugins (GladeXML * xml) { glade_xml_signal_autoconnect_full (xml, &connector, xml); } typedef void (*InitCall) (struct GNUNET_GE_Context * ectx, struct GNUNET_GC_Configuration * cfg); typedef void (*PlainCall) (void); static void loadPlugin (const char *name) { Plugin *p; struct GNUNET_PluginHandle *lib; InitCall init; lib = GNUNET_plugin_load (NULL, "libgnunetgtkmodule_", name); if (lib == NULL) return; p = GNUNET_malloc (sizeof (Plugin)); p->name = GNUNET_strdup (name); p->next = plugin; p->library = lib; plugin = p; init = GNUNET_plugin_resolve_function (lib, "init_", GNUNET_NO); if (init != NULL) init (NULL, cfg); } static void loadPlugins (const char *names) { char *dup; char *next; const char *pos; if (names == NULL) return; dup = GNUNET_strdup (names); next = dup; do { while (*next == ' ') next++; pos = next; while ((*next != '\0') && (*next != ' ')) next++; if (*next == '\0') { next = NULL; /* terminate! */ } else { *next = '\0'; /* add 0-termination for pos */ next++; } if (strlen (pos) > 0) loadPlugin (pos); } while (next != NULL); GNUNET_free (dup); } static void * unloadPlugin (void *p) { PlainCall done; Plugin *plug = (Plugin *) p; done = GNUNET_plugin_resolve_function (plug->library, "done_", GNUNET_NO); if (done != NULL) done (); GNUNET_plugin_unload (plug->library); GNUNET_free (plug->name); GNUNET_free (plug); return NULL; } void GNUNET_GTK_initialize_common_library (struct GNUNET_GC_Configuration *c, void *callback) { char *load; char *path; char *filename; cfg = c; shutdown_function = callback; sclock = GNUNET_mutex_create (GNUNET_YES); mainThread = GNUNET_thread_get_self (); saveCallsUp = GNUNET_YES; cron = GNUNET_cron_create (NULL); /* load the interface */ path = GNUNET_get_installation_path (GNUNET_IPK_DATADIR); filename = GNUNET_malloc (strlen (path) + strlen ("/../gnunet-gtk/gnunet-gtk.glade") + 2); strcpy (filename, path); GNUNET_free (path); strcat (filename, "/../gnunet-gtk/gnunet-gtk.glade"); #if MINGW gladeFile = GNUNET_malloc (_MAX_PATH + 1); plibc_conv_to_win_path (filename, gladeFile); #else gladeFile = GNUNET_strdup (filename); #endif GNUNET_free (filename); mainXML = glade_xml_new (gladeFile, "mainWindow", PACKAGE_NAME); if (mainXML == NULL) GNUNET_GE_DIE_STRERROR_FILE (NULL, GNUNET_GE_FATAL | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE, "glade_xml_new", gladeFile); iconFactory = gtk_icon_factory_new (); gtk_icon_factory_add_default (iconFactory); #if GTK_CHECK_VERSION (2,10,0) trayIcon = gtk_status_icon_new (); #endif initTrayIcon (); /* load the plugins */ GNUNET_GC_get_configuration_value_string (cfg, "GNUNET-GTK", "PLUGINS", "about daemon fs stats", &load); loadPlugins (load); GNUNET_free (load); GNUNET_GTK_connect_glade_with_plugins (mainXML); GNUNET_cron_start (cron); } void GNUNET_GTK_shutdown_plugins () { int i; GNUNET_cron_stop (cron); /* unload the plugins */ while (plugin != NULL) { Plugin *next; next = plugin->next; unloadPlugin (plugin); plugin = next; } UNREF (mainXML); mainXML = NULL; GNUNET_free (gladeFile); gladeFile = NULL; saveCallsUp = GNUNET_NO; GNUNET_mutex_lock (sclock); for (i = 0; i < pscCount; i++) psc[i]->func (psc[i]); i = pscCount; GNUNET_mutex_unlock (sclock); /* wait until all PSC-jobs have left the GNUNET_GTK_save_call method before destroying the mutex! */ while (i != 0) { GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS); GNUNET_mutex_lock (sclock); i = pscCount; GNUNET_mutex_unlock (sclock); } saveCallsUp = GNUNET_SYSERR; } void GNUNET_GTK_shutdown_common_library () { GNUNET_cron_destroy (cron); GNUNET_thread_release_self (mainThread); GNUNET_mutex_destroy (sclock); } struct rwsc_closure { struct GNUNET_Semaphore *sig; GNUNET_ThreadMainFunction realMain; void *arg; }; static void * shutdownCode (void *arg) { struct rwsc_closure *cls = arg; void *ret; ret = cls->realMain (cls->arg); GNUNET_semaphore_up (cls->sig); GNUNET_thread_stop_sleep (mainThread); return ret; } void * GNUNET_GTK_run_with_save_calls (GNUNET_ThreadMainFunction cb, void *arg) { struct GNUNET_ThreadHandle *doneThread; void *retval; struct rwsc_closure cls; int i; cls.sig = GNUNET_semaphore_create (0); cls.realMain = cb; cls.arg = arg; doneThread = GNUNET_thread_create (&shutdownCode, &cls, 64 * 1024); if (doneThread == NULL) GNUNET_GE_DIE_STRERROR (NULL, GNUNET_GE_FATAL | GNUNET_GE_ADMIN | GNUNET_GE_BULK, "pthread_create"); if (!GNUNET_thread_test_self (mainThread)) { /* another thread will run the save calls */ GNUNET_semaphore_down (cls.sig, GNUNET_YES); } else { i = 0; while (GNUNET_SYSERR == GNUNET_semaphore_down (cls.sig, GNUNET_NO)) { if (i == -1) GNUNET_thread_sleep (50 * GNUNET_CRON_MILLISECONDS); GNUNET_mutex_lock (sclock); if (pscCount > 0) { i = GNUNET_random_u32 (GNUNET_RANDOM_QUALITY_WEAK, pscCount); if (TRUE == g_idle_remove_by_data (psc[i])) saveCallWrapper (psc[i]); } else { i = -1; } GNUNET_mutex_unlock (sclock); } } GNUNET_thread_join (doneThread, &retval); GNUNET_semaphore_destroy (cls.sig); return retval; } /* * Update the status bar indicator and the status icon * about daemon and connexions status. */ void GNUNET_GTK_display_daemon_status (GNUNET_GTK_STATUS status, unsigned long long peers) { static gboolean once = TRUE; static int last_status = GNUNET_GTK_STATUS_UNKNOWN; unsigned long long last_peers = 0; char *label; static GtkWidget *statusConnexionsLabel; static GtkWidget *statusConnexionsPic; #if GTK_CHECK_VERSION (2,10,0) static GtkStatusIcon *trayIcon; #endif if (once) { statusConnexionsLabel = glade_xml_get_widget (GNUNET_GTK_get_main_glade_XML (), "statusConnexionsLabel"); statusConnexionsPic = glade_xml_get_widget (GNUNET_GTK_get_main_glade_XML (), "statusConnexionsPic"); #if GTK_CHECK_VERSION (2,10,0) GtkIconSet *iconSet; GtkIconSource *iconSource; char *iconPath; char *finalPath; char *instDir; char *dataDir; trayIcon = GNUNET_GTK_get_trayIcon (); instDir = GNUNET_get_installation_path (GNUNET_IPK_DATADIR); dataDir = g_strconcat (instDir, "/../gnunet-gtk/", NULL); #if MINGW finalPath = GNUNET_malloc (_MAX_PATH + 1); plibc_conv_to_win_path (dataDir, finalPath); #else finalPath = GNUNET_strdup (dataDir); #endif GNUNET_free (instDir); g_free (dataDir); iconSource = gtk_icon_source_new (); iconSet = gtk_icon_set_new (); iconPath = g_strconcat (finalPath, "gnunet-gtk-status-connected.svg", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_set_add_source (iconSet, iconSource); iconPath = g_build_filename (instDir, "..", "gnunet-gtk", "gnunet-gtk-status-connected.png", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_source_set_size_wildcarded (iconSource, FALSE); gtk_icon_set_add_source (iconSet, iconSource); gtk_icon_factory_add (GNUNET_GTK_get_iconFactory (), "gnunet-gtk-status-connected", iconSet); gtk_icon_set_unref (iconSet); iconSet = gtk_icon_set_new (); iconPath = g_strconcat (finalPath, "gnunet-gtk-status-unknown.svg", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_source_set_size_wildcarded (iconSource, TRUE); gtk_icon_set_add_source (iconSet, iconSource); iconPath = g_strconcat (finalPath, "gnunet-gtk-status-unknown.png", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_source_set_size_wildcarded (iconSource, FALSE); gtk_icon_set_add_source (iconSet, iconSource); gtk_icon_factory_add (GNUNET_GTK_get_iconFactory (), "gnunet-gtk-status-unknown", iconSet); gtk_icon_set_unref (iconSet); iconSet = gtk_icon_set_new (); iconPath = g_strconcat (finalPath, "gnunet-gtk-status-nodaemon.svg", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_source_set_size_wildcarded (iconSource, TRUE); gtk_icon_set_add_source (iconSet, iconSource); iconPath = g_strconcat (finalPath, "gnunet-gtk-status-nodaemon.png", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_source_set_size_wildcarded (iconSource, FALSE); gtk_icon_set_add_source (iconSet, iconSource); gtk_icon_factory_add (GNUNET_GTK_get_iconFactory (), "gnunet-gtk-status-nodaemon", iconSet); gtk_icon_set_unref (iconSet); iconSet = gtk_icon_set_new (); iconPath = g_strconcat (finalPath, "gnunet-gtk-status-disconnected.svg", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_source_set_size_wildcarded (iconSource, TRUE); gtk_icon_set_add_source (iconSet, iconSource); iconPath = g_strconcat (finalPath, "gnunet-gtk-status-disconnected.png", NULL); gtk_icon_source_set_filename (iconSource, iconPath); g_free (iconPath); gtk_icon_source_set_size_wildcarded (iconSource, FALSE); gtk_icon_set_add_source (iconSet, iconSource); gtk_icon_factory_add (GNUNET_GTK_get_iconFactory (), "gnunet-gtk-status-disconnected", iconSet); gtk_icon_set_unref (iconSet); gtk_icon_source_free (iconSource); GNUNET_free (finalPath); #endif once = FALSE; } if (status == last_status && peers == last_peers) return; switch (status) { case GNUNET_GTK_STATUS_CONNECTED : GNUNET_GE_BREAK (NULL, peers > 0); if (peers == 1) { gtk_label_set_text (GTK_LABEL (statusConnexionsLabel), _("Connected to 1 peer")); #if GTK_CHECK_VERSION (2,10,0) gtk_status_icon_set_tooltip (trayIcon, _("GNUnet - Connected to 1 peer")); #endif } else { label = g_strdup_printf (_("Connected to %Lu peers"), peers); gtk_label_set_text (GTK_LABEL (statusConnexionsLabel), label); g_free (label); #if GTK_CHECK_VERSION (2,10,0) label = g_strdup_printf (_("GNUnet - Connected to %Lu peers"), peers); gtk_status_icon_set_tooltip (trayIcon, label); g_free (label); #endif } #if GTK_CHECK_VERSION (2,10,0) gtk_status_icon_set_from_stock (trayIcon, "gnunet-gtk-status-connected"); #endif gtk_image_set_from_stock (GTK_IMAGE (statusConnexionsPic), GTK_STOCK_NETWORK, 1); break; case GNUNET_GTK_STATUS_DISCONNECTED : gtk_label_set_markup (GTK_LABEL (statusConnexionsLabel), _("Disconnected")); gtk_image_set_from_stock (GTK_IMAGE (statusConnexionsPic), GTK_STOCK_DISCONNECT, 1); #if GTK_CHECK_VERSION (2,10,0) gtk_status_icon_set_tooltip (trayIcon, _("GNUnet - Disconnected")); gtk_status_icon_set_from_stock (trayIcon, "gnunet-gtk-status-disconnected"); #endif break; case GNUNET_GTK_STATUS_DAEMONUP : gtk_label_set_markup (GTK_LABEL (statusConnexionsLabel), _("Daemon running")); gtk_image_set_from_stock (GTK_IMAGE (statusConnexionsPic), GTK_STOCK_EXECUTE, 1); #if GTK_CHECK_VERSION (2,10,0) gtk_status_icon_set_tooltip (trayIcon, _("GNUnet - Daemon running")); gtk_status_icon_set_from_icon_name (trayIcon, "gnunet-gtk"); #endif break; case GNUNET_GTK_STATUS_NODAEMON : gtk_label_set_markup (GTK_LABEL (statusConnexionsLabel), _("Daemon not running")); gtk_image_set_from_stock (GTK_IMAGE (statusConnexionsPic), GTK_STOCK_NO, 1); #if GTK_CHECK_VERSION (2,10,0) gtk_status_icon_set_tooltip (trayIcon, _("GNUnet - Daemon not running")); gtk_status_icon_set_from_stock (trayIcon, "gnunet-gtk-status-nodaemon"); #endif break; default : /* GNUNET_GTK_STATUS_UNKNOWN */ GNUNET_GTK_add_log_entry (_ ("WARNING: Failed to obtain connection statistics from gnunetd.\n")); gtk_label_set_text (GTK_LABEL (statusConnexionsLabel), _("Unknown status")); gtk_image_set_from_stock (GTK_IMAGE (statusConnexionsPic), GTK_STOCK_DIALOG_ERROR, 1); #if GTK_CHECK_VERSION (2,10,0) gtk_status_icon_set_tooltip (trayIcon, _("Unknown status")); gtk_status_icon_set_from_stock (trayIcon, "gnunet-gtk-status-unknown"); #endif break; } last_status = status; last_peers = peers; } /** * Simple glue to libnotify, and others? * */ void GNUNET_GTK_notify (int type, const char *message, ...) { #ifdef WITH_LIBNOTIFY static int once; char *msg; size_t size; va_list arg; GtkWidget *root; NotifyNotification *libnotify; NotifyUrgency libnotify_urgency = NOTIFY_URGENCY_NORMAL; long libnotify_expire_timeout = NOTIFY_EXPIRES_DEFAULT; if (!notify_is_initted ()) { if (once == 1) return; if (!notify_init ("gnunet-gtk")) { once = 1; GNUNET_GE_LOG (NULL, GNUNET_GE_WARNING | GNUNET_GE_BULK | GNUNET_GE_USER | GNUNET_GE_ADMIN, _("Could not initialize libnotify\n")); return; } } root = glade_xml_get_widget (GNUNET_GTK_get_main_glade_XML (), "mainWindow"); if (gtk_window_is_active (GTK_WINDOW (root)) == FALSE) { if (type == GNUNET_GTK_NOTIFY_LEVEL_LOW) libnotify_urgency = NOTIFY_URGENCY_LOW; else if (type == GNUNET_GTK_NOTIFY_LEVEL_NORMAL) libnotify_urgency = NOTIFY_URGENCY_NORMAL; else libnotify_urgency = NOTIFY_URGENCY_CRITICAL; va_start (arg, message); size = vsnprintf (NULL, 0, message, arg); va_end (arg); msg = GNUNET_malloc (size + 1); va_start (arg, message); vsnprintf (msg, size, message, arg); va_end (arg); libnotify = notify_notification_new ("gnunet-gtk", msg, PACKAGE_DATA "/gnunet-gtk/gnunet-gtk-notify.png", NULL); GNUNET_free (msg); notify_notification_set_timeout (libnotify, libnotify_expire_timeout); notify_notification_set_urgency (libnotify, libnotify_urgency); if (!notify_notification_show (libnotify, NULL)) { once = 1; GNUNET_GE_LOG (NULL, GNUNET_GE_WARNING | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_BULK, _("Could not send notification via libnotify\n")); } g_object_unref (G_OBJECT (libnotify)); notify_uninit (); } #endif } /** * Validate that a string is a Utf-8 string. * If validation fails, msg is freed and a valid * Utf-8 string is returned. */ char * GNUNET_GTK_validate_utf8 (char *msg) { const gchar *end; char *ret; gsize send; end = NULL; if (TRUE == g_utf8_validate (msg, -1, &end)) return msg; /* hope that it is ISO8859-1 */ ret = g_convert_with_fallback (msg, -1, "UTF-8", "ISO8859-1", ".", NULL, &send, NULL); GNUNET_free (msg); msg = GNUNET_strdup (ret); g_free (ret); GNUNET_GE_BREAK (NULL, TRUE == g_utf8_validate (msg, -1, &end)); return msg; } /** * Gtk callback to save the main window state (tray icon use) */ void GNUNET_GTK_save_main_window_state (GtkWidget * main_window, GdkEventWindowState * event, gpointer user_data) { main_window_state = (*event).new_window_state; return; } /** * Get the last main window state when restoring (tray icon use) */ GdkWindowState GNUNET_GTK_get_main_window_state () { return main_window_state; } /** * Start gnunet-setup, asking for a password if needed */ gboolean GNUNET_GTK_run_gnunet_setup (gchar * conffile, gboolean run_wizard) { GtkWidget *mainWindow; GtkWidget *messageDialog; GError *gerror = NULL; char *error_message = NULL; if (0 == ACCESS (conffile, W_OK)) { if (run_wizard) { char *argv[] = { "gnunet-setup", "-d", "wizard-gtk", "-c", conffile, NULL }; g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN, NULL, NULL, NULL, &gerror); } else { char *argv[] = { "gnunet-setup", "-d", "gconfig", "-c", conffile, NULL }; g_spawn_async (NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN, NULL, NULL, NULL, &gerror); } if (gerror) { error_message = GNUNET_strdup (gerror->message); g_error_free (gerror); } } else #ifndef WITH_LIBGKSU2 { error_message = GNUNET_strdup (_ ("You don't have rights to write to the provided configuration file.")); } #else { char *commandline; if (run_wizard) { commandline = g_strconcat ("gnunet-setup -d wizard-gtk -c ", conffile, NULL); gksu_run (commandline, &gerror); } else { commandline = g_strconcat ("gnunet-setup -d gconfig -c ", conffile, NULL); gksu_run (commandline, &gerror); } GNUNET_free (commandline); if (gerror) { error_message = GNUNET_strdup (gerror->message); g_error_free (gerror); } } #endif if (error_message) { mainWindow = glade_xml_get_widget (GNUNET_GTK_get_main_glade_XML (), "mainWindow"); messageDialog = gtk_message_dialog_new (GTK_WINDOW (mainWindow), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, _ ("Failed to run the configuration tool (gnunet-setup): %s"), error_message); gtk_dialog_run (GTK_DIALOG (messageDialog)); gtk_widget_destroy (messageDialog); GNUNET_free (error_message); return FALSE; } return TRUE; } GtkWidget * GNUNET_GTK_extract_main_widget_from_window (GladeXML * xml, const char *windowName) { GtkContainer *window; GtkWidget *ret; window = GTK_CONTAINER (glade_xml_get_widget (xml, windowName)); ret = gtk_bin_get_child (GTK_BIN (window)); gtk_widget_ref (ret); gtk_container_remove (window, ret); gtk_widget_destroy (GTK_WIDGET (window)); return ret; } /* end of helper.c */