/* This file is part of GNUnet. (C) 2010, 2012 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/fs/gnunet-fs-gtk.c * @brief Main function of gnunet-fs-gtk * @author Christian Grothoff */ #include "gnunet-fs-gtk.h" #include "gnunet-fs-gtk_common.h" #include "gnunet-fs-gtk_event-handler.h" /** * Should gnunet-fs-gtk start in tray mode? */ static int tray_only; /** * Handle to our main loop. */ static struct GNUNET_GTK_MainLoop *ml; /** * Handle for file-sharing operations. */ static struct GNUNET_FS_Handle *fs; /** * Return handle for file-sharing operations. * * @return NULL on error */ struct GNUNET_FS_Handle * GNUNET_FS_GTK_get_fs_handle () { return fs; } /** * Get our configuration. * * @return configuration handle */ const struct GNUNET_CONFIGURATION_Handle * GNUNET_FS_GTK_get_configuration () { return GNUNET_GTK_main_loop_get_configuration (ml); } /** * Get an object from the main window. * * @param name name of the object * @return NULL on error */ GObject * GNUNET_FS_GTK_get_main_window_object (const char *name) { return GNUNET_GTK_main_loop_get_object (ml, name); } /** * Return the list store with anonymity levels. * * @return the list store */ GtkTreeModel * GNUNET_FS_GTK_get_anonymity_level_list_store () { return GTK_TREE_MODEL (GNUNET_FS_GTK_get_main_window_object ("anonymity_level_liststore")); } /** * Obtains main window position and size before it's destroyed * and saves these into user's config file. * * @param main_window main window widget */ static void main_window_save_position (GtkWidget *main_window) { GdkWindow *main_window_gdk; gint window_x; gint window_y; gint window_width; gint window_height; int maximized; GdkWindowState window_state; struct GNUNET_CONFIGURATION_Handle *cfg; struct GNUNET_CONFIGURATION_Handle *cfgDefault; cfg = (struct GNUNET_CONFIGURATION_Handle *) GNUNET_GTK_main_loop_get_configuration (ml); main_window_gdk = gtk_widget_get_window (main_window); maximized = GNUNET_YES; if (NULL != main_window_gdk) { window_state = gdk_window_get_state (main_window_gdk); if (!(window_state & GDK_WINDOW_STATE_MAXIMIZED)) maximized = GNUNET_NO; } gtk_window_get_position (GTK_WINDOW (main_window), &window_x, &window_y); gtk_window_get_size (GTK_WINDOW (main_window), &window_width, &window_height); GNUNET_CONFIGURATION_set_value_number (cfg, "gnunet-gtk", "MAIN_WINDOW_X", window_x); GNUNET_CONFIGURATION_set_value_number (cfg, "gnunet-gtk", "MAIN_WINDOW_Y", window_y); GNUNET_CONFIGURATION_set_value_number (cfg, "gnunet-gtk", "MAIN_WINDOW_WIDTH", window_width); GNUNET_CONFIGURATION_set_value_number (cfg, "gnunet-gtk", "MAIN_WINDOW_HEIGHT", window_height); GNUNET_CONFIGURATION_set_value_string (cfg, "gnunet-gtk", "MAIN_WINDOW_MAXIMIZED", (maximized == GNUNET_YES) ? "YES" : "NO"); cfgDefault = GNUNET_CONFIGURATION_create (); (void) GNUNET_CONFIGURATION_load (cfgDefault, NULL); /* load defaults only */ GNUNET_CONFIGURATION_write_diffs (cfgDefault, cfg, GNUNET_GTK_main_loop_get_configuration_file (ml)); GNUNET_CONFIGURATION_destroy (cfgDefault); } /** * Task run on shutdown. * FIXME-STYLE: does this need to be a separate task!? * * @param cls NULL * @param tc scheduler context, unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { GNUNET_GTK_main_loop_quit (ml); if (fs != NULL) { GNUNET_FS_stop (fs); fs = NULL; } } /** * Callback invoked if the application is supposed to exit. * * @param object origin of the quit event, unused * @param user_data global builder instance, unused */ void GNUNET_GTK_quit_cb (GObject * object, gpointer user_data) { struct GNUNET_GTK_MainWindowContext *main_context = user_data; main_window_save_position (main_context->main_window); GNUNET_GTK_tray_icon_destroy (); GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &shutdown_task, NULL); GNUNET_free (main_context); } /** * Actual main function run right after GNUnet's scheduler * is initialized. Initializes up GTK and Glade. * * @param cls handle to the main loop ('struct GNUNET_GTK_MainLoop') * @param tc scheduler context, unused */ static void run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned long long dl_parallel, req_parallel, window_x, window_y, window_width, window_height; int maximized; struct GNUNET_GTK_MainWindowContext *main_context; main_context = GNUNET_malloc (sizeof (struct GNUNET_GTK_MainWindowContext)); ml = cls; /* setup main context */ if (GNUNET_OK != GNUNET_GTK_main_loop_build_window (cls, main_context)) { GNUNET_free (main_context); return; } main_context->builder = GNUNET_GTK_main_loop_get_builder (cls); main_context->cfg = GNUNET_GTK_main_loop_get_configuration (cls); main_context->search_ns_treestore = GTK_TREE_STORE (GNUNET_FS_GTK_get_main_window_object ("main_window_search_namespace_treestore")); main_context->main_window = GTK_WIDGET (GNUNET_FS_GTK_get_main_window_object ("GNUNET_GTK_main_window")); main_context->ns_selector_treeview = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object ("namespace_selector_treeview")); main_context->ns_selector_window = GTK_WIDGET (GNUNET_FS_GTK_get_main_window_object ("namespace_selector_window")); main_context->ns_dropdown_button = GTK_TOGGLE_BUTTON (GNUNET_FS_GTK_get_main_window_object ("main_window_search_namespace_dropdown_button")); main_context->search_ns_label = GTK_LABEL (GNUNET_FS_GTK_get_main_window_object ("main_window_search_selected_namespace_label")); main_context->search_entry = GTK_ENTRY (GNUNET_FS_GTK_get_main_window_object ("main_window_search_entry")); main_context->anonymity_combo = GTK_COMBO_BOX (GNUNET_FS_GTK_get_main_window_object ("main_window_search_anonymity_combobox")); main_context->anonymity_level_liststore = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object ("anonymity_level_liststore")); main_context->preview_image = GTK_IMAGE (GNUNET_FS_GTK_get_main_window_object ("GNUNET_GTK_main_window_preview_image")); main_context->md_liststore = GTK_LIST_STORE (GNUNET_FS_GTK_get_main_window_object ("GNUNET_GTK_meta_data_list_store")); main_context->md_treeview = GTK_TREE_VIEW (GNUNET_FS_GTK_get_main_window_object ("GNUNET_GTK_main_window_metadata_treeview")); main_context->ns_callback_registered = GNUNET_NO; GNUNET_GTK_set_icon_search_path (); GNUNET_GTK_setup_nls (); /* Make sure button class is realized */ g_type_class_unref (g_type_class_ref (GTK_TYPE_BUTTON)); /* GNUnet main window assumes that images on buttons are visible, * override the theme's gtkrc setting */ g_object_set (gtk_settings_get_default (), "gtk-button-images", TRUE, NULL); /* setup main window */ maximized = GNUNET_CONFIGURATION_get_value_yesno (main_context->cfg, "gnunet-gtk", "MAIN_WINDOW_MAXIMIZED"); if (GNUNET_SYSERR == maximized) maximized = GNUNET_YES; if ( (GNUNET_NO == maximized) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (main_context->cfg, "gnunet-gtk", "MAIN_WINDOW_X", &window_x)) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (main_context->cfg, "gnunet-gtk", "MAIN_WINDOW_Y", &window_y)) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (main_context->cfg, "gnunet-gtk", "MAIN_WINDOW_WIDTH", &window_width)) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (main_context->cfg, "gnunet-gtk", "MAIN_WINDOW_HEIGHT", &window_height)) ) { gtk_window_move (GTK_WINDOW (main_context->main_window), window_x, window_y); gtk_window_resize (GTK_WINDOW (main_context->main_window), window_width, window_height); } else { /* If anything is wrong - play safe and show it maximized */ gtk_window_maximize (GTK_WINDOW (main_context->main_window)); } /* Allow multiple selection in metadata view; */ /* FIXME-GTK3: this can be done within (modern versions of) glade */ gtk_tree_selection_set_mode (gtk_tree_view_get_selection (main_context->md_treeview), GTK_SELECTION_MULTIPLE); GNUNET_GTK_tray_icon_create (GTK_WINDOW (main_context->main_window), "gnunet-fs-gtk", "gnunet-fs-gtk"); /* FIXME: should these '1's be here? Maybe better to put them into * default config files? */ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (main_context->cfg, "gnunet-gtk", "MAX_PARALLEL_DOWNLOADS", &dl_parallel)) dl_parallel = 1; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (main_context->cfg, "gnunet-gtk", "MAX_PARALLEL_REQUESTS", &req_parallel)) req_parallel = 1; /* initialize file-sharing */ fs = GNUNET_FS_start (main_context->cfg, "gnunet-fs-gtk", &GNUNET_GTK_fs_event_handler, NULL, GNUNET_FS_FLAGS_NONE | GNUNET_FS_FLAGS_PERSISTENCE /* | GNUNET_FS_FLAGS_DO_PROBES */ , GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, (unsigned int) dl_parallel, GNUNET_FS_OPTIONS_REQUEST_PARALLELISM, (unsigned int) req_parallel, GNUNET_FS_OPTIONS_END); if (NULL == fs) { GNUNET_GTK_main_loop_quit (cls); GNUNET_free (main_context); return; } GNUNET_GTK_main_window_refresh_ns_list (main_context); /* make GUI visible */ if (!tray_only) { gtk_widget_show (main_context->main_window); gtk_window_present (GTK_WINDOW (main_context->main_window)); } } int main (int argc, char *const *argv) { static struct GNUNET_GETOPT_CommandLineOption options[] = { {'t', "tray", NULL, gettext_noop ("start in tray mode"), 0, &GNUNET_GETOPT_set_one, &tray_only}, GNUNET_GETOPT_OPTION_END }; if (GNUNET_OK != GNUNET_GTK_main_loop_start ("gnunet-fs-gtk", "GTK GUI for GNUnet", argc, argv, options, "gnunet_fs_gtk_main_window.glade", &run)) return 1; return 0; } /* end of gnunet-fs-gtk.c */