X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/50b4f4deb41f7509efe5292f89500ec5186d8c70..a2352a7ddb9fe8136c587190aa5d926f18baed79:/src/toolbar.c?ds=sidebyside diff --git a/src/toolbar.c b/src/toolbar.c index 0ecdaed6..1f14fc27 100644 --- a/src/toolbar.c +++ b/src/toolbar.c @@ -1,8 +1,10 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ /* - * toolbar.c - this file is part of Geany, a fast and lightweight IDE + * toolbar.c - this file was part of Geany (v1.24.1), a fast and lightweight IDE * * Copyright 2009-2012 Enrico Tröger * Copyright 2009-2012 Nick Treleaven + * Copyright 2014 Rob Norris * * 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 @@ -25,557 +27,614 @@ */ /* Utility functions to create the toolbar */ -#include "geany.h" -#include "support.h" -#include "ui_utils.h" -#include "toolbar.h" -#include "callbacks.h" -#include "utils.h" -#include "dialogs.h" -#include "document.h" -#include "build.h" -#include "main.h" -#include "geanymenubuttonaction.h" -#include "geanyentryaction.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include "toolbar.h" +#include "dir.h" +#include "ui_util.h" +#include "util.h" #include +#include #include +#include + +#include "preferences.h" + + +struct _VikToolbarClass +{ + GObjectClass object_class; +}; + +struct _VikToolbar { + GObject obj; + GtkWidget *widget; + GtkUIManager *uim; + guint merge_id; + GtkActionGroup *group_actions; + GtkActionGroup *group_toggles; + GtkActionGroup *group_tools; + GtkActionGroup *group_modes; + GSList *list_of_actions; + GSList *list_of_toggles; + GSList *list_of_tools; + GSList *list_of_modes; +}; + +G_DEFINE_TYPE (VikToolbar, vik_toolbar, G_TYPE_OBJECT) + +static void vik_toolbar_class_init (VikToolbarClass *klass) +{ +} + +static void vik_toolbar_init (VikToolbar *vtb) +{ + vtb->widget = NULL; + vtb->merge_id = 0; + vtb->list_of_actions = NULL; + vtb->list_of_toggles = NULL; + vtb->list_of_tools = NULL; + vtb->list_of_modes = NULL; +} +VikToolbar *vik_toolbar_new () +{ + VikToolbar *vtb = (VikToolbar *)g_object_new(vik_toolbar_get_type(), NULL); + return vtb; +} -GeanyToolbarPrefs toolbar_prefs; -static GtkUIManager *uim; -static GtkActionGroup *group; -static GSList *plugin_items = NULL; - -/* Available toolbar actions - * Fields: name, stock_id, label, accelerator, tooltip, callback */ -static const GtkActionEntry ui_entries[] = { - /* custom actions defined in toolbar_init(): "New", "Open", "SearchEntry", "GotoEntry", "Build" */ - { "Save", GTK_STOCK_SAVE, NULL, NULL, N_("Save the current file"), G_CALLBACK(on_toolbutton_save_clicked) }, - { "SaveAs", GTK_STOCK_SAVE_AS, NULL, NULL, N_("Save as"), G_CALLBACK(on_save_as1_activate) }, - { "SaveAll", GEANY_STOCK_SAVE_ALL, NULL, NULL, N_("Save all open files"), G_CALLBACK(on_save_all1_activate) }, - { "Reload", GTK_STOCK_REVERT_TO_SAVED, NULL, NULL, N_("Reload the current file from disk"), G_CALLBACK(on_toolbutton_reload_clicked) }, - { "Close", GTK_STOCK_CLOSE, NULL, NULL, N_("Close the current file"), G_CALLBACK(on_toolbutton_close_clicked) }, - { "CloseAll", GEANY_STOCK_CLOSE_ALL, NULL, NULL, N_("Close all open files"), G_CALLBACK(on_toolbutton_close_all_clicked) }, - { "Cut", GTK_STOCK_CUT, NULL, NULL, N_("Cut the current selection"), G_CALLBACK(on_cut1_activate) }, - { "Copy", GTK_STOCK_COPY, NULL, NULL, N_("Copy the current selection"), G_CALLBACK(on_copy1_activate) }, - { "Paste", GTK_STOCK_PASTE, NULL, NULL, N_("Paste the contents of the clipboard"), G_CALLBACK(on_paste1_activate) }, - { "Delete", GTK_STOCK_DELETE, NULL, NULL, N_("Delete the current selection"), G_CALLBACK(on_delete1_activate) }, - { "Undo", GTK_STOCK_UNDO, NULL, NULL, N_("Undo the last modification"), G_CALLBACK(on_undo1_activate) }, - { "Redo", GTK_STOCK_REDO, NULL, NULL, N_("Redo the last modification"), G_CALLBACK(on_redo1_activate) }, - { "NavBack", GTK_STOCK_GO_BACK, NULL, NULL, N_("Navigate back a location"), G_CALLBACK(on_back_activate) }, - { "NavFor", GTK_STOCK_GO_FORWARD, NULL, NULL, N_("Navigate forward a location"), G_CALLBACK(on_forward_activate) }, - { "Compile", GTK_STOCK_CONVERT, N_("Compile"), NULL, N_("Compile the current file"), G_CALLBACK(on_toolbutton_compile_clicked) }, - { "Run", GTK_STOCK_EXECUTE, NULL, NULL, N_("Run or view the current file"), G_CALLBACK(on_toolbutton_run_clicked) }, - { "Color", GTK_STOCK_SELECT_COLOR, N_("Color Chooser"), NULL, N_("Open a color chooser dialog, to interactively pick colors from a palette"), G_CALLBACK(on_show_color_chooser1_activate) }, - { "ZoomIn", GTK_STOCK_ZOOM_IN, NULL, NULL, N_("Zoom in the text"), G_CALLBACK(on_zoom_in1_activate) }, - { "ZoomOut", GTK_STOCK_ZOOM_OUT, NULL, NULL, N_("Zoom out the text"), G_CALLBACK(on_zoom_out1_activate) }, - { "UnIndent", GTK_STOCK_UNINDENT, NULL, NULL, N_("Decrease indentation"), G_CALLBACK(on_menu_decrease_indent1_activate) }, - { "Indent", GTK_STOCK_INDENT, NULL, NULL, N_("Increase indentation"), G_CALLBACK(on_menu_increase_indent1_activate) }, - { "Search", GTK_STOCK_FIND, NULL, NULL, N_("Find the entered text in the current file"), G_CALLBACK(on_toolbutton_search_clicked) }, - { "Goto", GTK_STOCK_JUMP_TO, NULL, NULL, N_("Jump to the entered line number"), G_CALLBACK(on_toolbutton_goto_clicked) }, - { "Preferences", GTK_STOCK_PREFERENCES, NULL, NULL, N_("Show the preferences dialog"), G_CALLBACK(on_toolbutton_preferences_clicked) }, - { "Quit", GTK_STOCK_QUIT, NULL, NULL, N_("Quit Geany"), G_CALLBACK(on_toolbutton_quit_clicked) }, - { "Print", GTK_STOCK_PRINT, NULL, NULL, N_("Print document"), G_CALLBACK(on_print1_activate) }, - { "Replace", GTK_STOCK_FIND_AND_REPLACE, NULL, NULL, N_("Replace text in the current document"), G_CALLBACK(on_replace1_activate) } +#define TOOLBAR_PARAMS_GROUP_KEY "toolbar" +#define TOOLBAR_PARAMS_NAMESPACE "toolbar." + +static gchar *params_icon_size[] = { N_("System Default"), N_("Small"), N_("Medium"), N_("Large"), NULL }; +static gchar *params_icon_style[] = { N_("System Default"), N_("Icons Only"), N_("Text Only"), N_("Icons and Text"), NULL }; + +typedef struct { + VikToolbar *vtb; + GtkWindow *parent; + GtkWidget *vbox; + GtkWidget *hbox; + ReloadCB *reload_cb; + gpointer user_data; +} config_t; + +static config_t extra_widget_data; + +static VikLayerParam prefs[] = { + { VIK_LAYER_NUM_TYPES, TOOLBAR_PARAMS_NAMESPACE "append_to_menu", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Append to Menu:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, + N_("Pack the toolbar to the main menu to save vertical space"), NULL, NULL, NULL }, + { VIK_LAYER_NUM_TYPES, TOOLBAR_PARAMS_NAMESPACE "icon_size", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Icon Size:"), VIK_LAYER_WIDGET_COMBOBOX, params_icon_size, NULL, + NULL, NULL, NULL, NULL }, + { VIK_LAYER_NUM_TYPES, TOOLBAR_PARAMS_NAMESPACE "icon_style", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Icon Style:"), VIK_LAYER_WIDGET_COMBOBOX, params_icon_style, NULL, + NULL, NULL, NULL, NULL }, + { VIK_LAYER_NUM_TYPES, TOOLBAR_PARAMS_NAMESPACE "NOTSAVED1", VIK_LAYER_PARAM_PTR, VIK_LAYER_GROUP_NONE, N_("Customize:"), VIK_LAYER_WIDGET_BUTTON, N_("Customize Buttons"), NULL, + NULL, NULL, NULL, NULL }, }; -static const guint ui_entries_n = G_N_ELEMENTS(ui_entries); - - -/* fallback UI definition */ -static const gchar *toolbar_markup = -"" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" -""; +// Global storage to enable freeing upon closure +static GHashTable *signal_data; +static GSList *toggle_overrides = NULL; + +// Forward declaration +void toolbar_configure (VikToolbar *vtb, GtkWidget *toolbar, GtkWindow *parent, GtkWidget *vbox, GtkWidget *hbox, ReloadCB reload_cb, gpointer user_data); + +void toolbar_configure_cb(void) +{ + // Values not known at prefs initialization. + // So trying to pass these values via the UI builder is not possible currently. + // ATM cheat via internal values - although this doesn't work properly for multiple Windows... + toolbar_configure ( extra_widget_data.vtb, + extra_widget_data.vtb->widget, + extra_widget_data.parent, + extra_widget_data.vbox, + extra_widget_data.hbox, + extra_widget_data.reload_cb, + extra_widget_data.user_data ); +} + +/** + * a_toolbar_init: + * + * Initialize stuff for the toolbar. + */ +void a_toolbar_init (void) +{ + // Preferences + a_preferences_register_group ( TOOLBAR_PARAMS_GROUP_KEY, _("Toolbar") ); + + guint i = 0; + VikLayerParamData tmp; + tmp.b = FALSE; + a_preferences_register (&prefs[i++], tmp, TOOLBAR_PARAMS_GROUP_KEY); + tmp.u = 0; + a_preferences_register (&prefs[i++], tmp, TOOLBAR_PARAMS_GROUP_KEY); +#ifdef WINDOWS + tmp.u = 1; // Small Icons for Windows by default as 'System Defaults' is more GNOME Theme driven. +#else + tmp.u = 0; +#endif + a_preferences_register (&prefs[i++], tmp, TOOLBAR_PARAMS_GROUP_KEY); + tmp.ptr = toolbar_configure_cb; + a_preferences_register (&prefs[i++], tmp, TOOLBAR_PARAMS_GROUP_KEY); + + // Signal data hash + signal_data = g_hash_table_new_full ( g_direct_hash, g_direct_equal, NULL, g_free ); +} + +/** + * a_toolbar_uninit: + * + * Uninitialize toolbar related stuff. + */ +void a_toolbar_uninit ( void ) +{ + g_hash_table_destroy ( signal_data ); + g_slist_foreach ( toggle_overrides, (GFunc)g_free, NULL ); + g_slist_free ( toggle_overrides ); +} + +static gboolean prefs_get_append_to_menu (void) +{ + return a_preferences_get(TOOLBAR_PARAMS_NAMESPACE "append_to_menu")->b; +} + +static guint prefs_get_icon_size (void) +{ + return a_preferences_get(TOOLBAR_PARAMS_NAMESPACE "icon_size")->b; +} + +static guint prefs_get_icon_style (void) +{ + return a_preferences_get(TOOLBAR_PARAMS_NAMESPACE "icon_style")->b; +} /* Note: The returned widget pointer is only valid until the toolbar is reloaded. So, either * update the widget pointer in this case (i.e. request it again) or better use * toolbar_get_action_by_name() instead. The action objects will remain the same even when the * toolbar is reloaded. */ -GtkWidget *toolbar_get_widget_by_name(const gchar *name) +GtkWidget *toolbar_get_widget_by_name(VikToolbar *vtb, const gchar *name) { GtkWidget *widget; gchar *path; g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail(VIK_IS_TOOLBAR(vtb), NULL); - path = g_strconcat("/ui/GeanyToolbar/", name, NULL); - widget = gtk_ui_manager_get_widget(uim, path); + path = g_strconcat("/ui/MainToolbar/", name, NULL); + widget = gtk_ui_manager_get_widget(vtb->uim, path); g_free(path); return widget; } - -/* Note: The returned widget pointer is only valid until the toolbar is reloaded. See - * toolbar_get_widget_by_name for details(). */ -GtkWidget *toolbar_get_widget_child_by_name(const gchar *name) +static GtkAction *get_action ( VikToolbar *vtb, const gchar *name ) { - GtkWidget *widget = toolbar_get_widget_by_name(name); - - if (G_LIKELY(widget != NULL)) - return gtk_bin_get_child(GTK_BIN(widget)); - else - return NULL; + // Try all groups + GtkAction *action = gtk_action_group_get_action (vtb->group_actions, name); + if ( !action ) + action = gtk_action_group_get_action (vtb->group_tools, name); + if ( !action ) + action = gtk_action_group_get_action (vtb->group_toggles, name); + if ( !action ) + action = gtk_action_group_get_action (vtb->group_modes, name); + return action; } - -GtkAction *toolbar_get_action_by_name(const gchar *name) +/** + * toolbar_get_action_by_name: + * + * Find an action in the specified toolbar via the action name + */ +GtkAction *toolbar_get_action_by_name(VikToolbar *vtb, const gchar *name) { g_return_val_if_fail(name != NULL, NULL); + g_return_val_if_fail(VIK_IS_TOOLBAR(vtb), NULL); - return gtk_action_group_get_action(group, name); + return get_action(vtb,name); } +/** + * toolbar_action_tool_entry_register: + * + * Register a tool button in the specified toolbar + * Only one of these tools can be active at a time (hence it is a GtkRadioActionEntry) + */ +void toolbar_action_tool_entry_register(VikToolbar *vtb, GtkRadioActionEntry *action) +{ + g_return_if_fail(VIK_IS_TOOLBAR(vtb)); + g_return_if_fail(action != NULL); + vtb->list_of_tools = g_slist_append(vtb->list_of_tools, action); +} -static void toolbar_item_destroy_cb(GtkWidget *widget, G_GNUC_UNUSED gpointer data) +/** + * toolbar_action_mode_entry_register: + * + * Register a drawing projection mode button in the specified toolbar + * Only one of these modes can be active at a time (hence it is a GtkRadioActionEntry) + */ +void toolbar_action_mode_entry_register(VikToolbar *vtb, GtkRadioActionEntry *action) { - plugin_items = g_slist_remove(plugin_items, widget); + g_return_if_fail(VIK_IS_TOOLBAR(vtb)); + g_return_if_fail(action != NULL); + vtb->list_of_modes = g_slist_append(vtb->list_of_modes, action); } +/** + * toolbar_action_toggle_entry_register: + * + * Register a toggle button in the specified toolbar with the specified callback + * Used in preventing circluar callbacks of a toolbar toggle event calling the menu toggle event + * (that then calls toolbar callback and so on and so on...) + * The toggle action must be given a pointer to a function that is used on the callback for toolbar only + * (that must offer a way to have a finite call chain!) + */ +void toolbar_action_toggle_entry_register(VikToolbar *vtb, GtkToggleActionEntry *action, gpointer callback) +{ + g_return_if_fail(VIK_IS_TOOLBAR(vtb)); + g_return_if_fail(action != NULL); + + GtkToggleActionEntry *myaction = g_malloc (sizeof (GtkToggleActionEntry) ); + memcpy ( myaction, action, sizeof (GtkToggleActionEntry) ); + // Overwrite with specific callback + myaction->callback = callback; + vtb->list_of_toggles = g_slist_append(vtb->list_of_toggles, myaction); -void toolbar_item_ref(GtkToolItem *item) + // Store override so it can be freed upon toolbar destruction + toggle_overrides = g_slist_append ( toggle_overrides, myaction ); +} + +/** + * toolbar_action_entry_register: + * + * Register a standard action button in the specified toolbar + */ +void toolbar_action_entry_register(VikToolbar *vtb, GtkActionEntry *action) { - g_return_if_fail(item != NULL); + g_return_if_fail(VIK_IS_TOOLBAR(vtb)); + g_return_if_fail(action != NULL); + vtb->list_of_actions = g_slist_append(vtb->list_of_actions, action); +} - plugin_items = g_slist_append(plugin_items, item); - g_signal_connect(item, "destroy", G_CALLBACK(toolbar_item_destroy_cb), NULL); +static void configure_cb (GtkWidget *widget, gpointer user_data) +{ + config_t *data = (config_t*)user_data; + toolbar_configure ( data->vtb, data->vtb->widget, data->parent, data->vbox, data->hbox, data->reload_cb, data->user_data); } +static gboolean toolbar_popup_menu (GtkWidget *widget, GdkEventButton *event, gpointer user_data) +{ + // Only display menu on right button clicks + if (event->button == 3) { + GtkWidget *tmenu; + tmenu = gtk_menu_new(); + GtkWidget *item = gtk_menu_item_new_with_mnemonic ( _("_Customize") ); + g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(configure_cb), user_data ); + gtk_menu_shell_append ( GTK_MENU_SHELL(tmenu), item ); + gtk_menu_popup ( GTK_MENU(tmenu), NULL, NULL, NULL, NULL, event->button, event->time ); + gtk_widget_show_all ( GTK_WIDGET(tmenu) ); + g_object_ref_sink (tmenu); + return TRUE; + } + return FALSE; +} -static GtkWidget *toolbar_reload(const gchar *markup) +/* sets the icon style of the toolbar */ +static void toolbar_set_icon_style (GtkWidget *toolbar) { - gint i; - GSList *l; - GtkWidget *entry; - GError *error = NULL; - gchar *filename; - static guint merge_id = 0; - GtkWidget *toolbar_new_file_menu = NULL; - GtkWidget *toolbar_recent_files_menu = NULL; - GtkWidget *toolbar_build_menu = NULL; + gint icon_style = prefs_get_icon_style(); - /* Cleanup old toolbar */ - if (merge_id > 0) - { - /* ref plugins toolbar items to keep them after we destroyed the toolbar */ - foreach_slist(l, plugin_items) - { - g_object_ref(l->data); - gtk_container_remove(GTK_CONTAINER(main_widgets.toolbar), GTK_WIDGET(l->data)); - } - /* ref and hold the submenus of the New, Open and Build toolbar items */ - toolbar_new_file_menu = geany_menu_button_action_get_menu( - GEANY_MENU_BUTTON_ACTION(gtk_action_group_get_action(group, "New"))); - g_object_ref(toolbar_new_file_menu); - toolbar_recent_files_menu = geany_menu_button_action_get_menu( - GEANY_MENU_BUTTON_ACTION(gtk_action_group_get_action(group, "Open"))); - g_object_ref(toolbar_recent_files_menu); - toolbar_build_menu = geany_menu_button_action_get_menu( - GEANY_MENU_BUTTON_ACTION(gtk_action_group_get_action(group, "Build"))); - g_object_ref(toolbar_build_menu); + if (icon_style == 0) + icon_style = ui_get_gtk_settings_integer("gtk-toolbar-style", GTK_TOOLBAR_ICONS); + else + // Adjust to enum GtkToolbarStyle + icon_style--; - /* Get rid of it! */ - gtk_widget_destroy(main_widgets.toolbar); + gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), icon_style); +} - gtk_ui_manager_remove_ui(uim, merge_id); - gtk_ui_manager_ensure_update(uim); - } - if (markup != NULL) - { - merge_id = gtk_ui_manager_add_ui_from_string(uim, markup, -1, &error); +/* sets the icon size of the toolbar */ +static void toolbar_set_icon_size (GtkWidget *toolbar) +{ + gint icon_size = prefs_get_icon_size(); + + if ( icon_size == 0 ) + icon_size = ui_get_gtk_settings_integer("gtk-toolbar-icon-size", GTK_ICON_SIZE_SMALL_TOOLBAR); + else { + // Adjust to enum GtkIconSize + if ( icon_size == 1 ) + icon_size = GTK_ICON_SIZE_SMALL_TOOLBAR; + else if ( icon_size == 2 ) + icon_size = GTK_ICON_SIZE_LARGE_TOOLBAR; + else if ( icon_size == 3 ) + icon_size = GTK_ICON_SIZE_DND; } - else - { - /* Load the toolbar UI XML file from disk (first from config dir, then try data dir) */ - filename = g_build_filename(app->configdir, "ui_toolbar.xml", NULL); - merge_id = gtk_ui_manager_add_ui_from_file(uim, filename, &error); - if (merge_id == 0) - { - if (! g_error_matches(error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) - geany_debug("Loading user toolbar UI definition failed (%s).", error->message); - g_error_free(error); - error = NULL; - SETPTR(filename, g_build_filename(app->datadir, "ui_toolbar.xml", NULL)); - merge_id = gtk_ui_manager_add_ui_from_file(uim, filename, &error); - } - g_free(filename); - } - if (error != NULL) - { - geany_debug("UI creation failed, using internal fallback definition. Error message: %s", - error->message); - g_error_free(error); - /* finally load the internally defined markup as fallback */ - merge_id = gtk_ui_manager_add_ui_from_string(uim, toolbar_markup, -1, NULL); + gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), icon_size); +} + +/** + * toolbar_apply_settings: + * @vbox: Potential vertical container for the specified toolbar + * @hbox: Potential horizontal container for the specified toolbar + * @Reset: Specify if the toolbar should be reparented + * (when called externally this should always be TRUE) + * + * Updates the specified toolbar with current setting values + */ +void toolbar_apply_settings(VikToolbar *vtb, + GtkWidget *vbox, + GtkWidget *hbox, + gboolean reset) +{ + g_return_if_fail(VIK_IS_TOOLBAR(vtb)); + + if ( reset ) { + g_object_ref (vtb->widget); // ensure not deleted when removed + // Try both places it could be + if ( gtk_widget_get_parent (vtb->widget) == hbox ) + gtk_container_remove(GTK_CONTAINER(hbox), vtb->widget ); + if ( gtk_widget_get_parent (vtb->widget) == vbox ) + gtk_container_remove(GTK_CONTAINER(vbox), vtb->widget ); } - main_widgets.toolbar = gtk_ui_manager_get_widget(uim, "/ui/GeanyToolbar"); - ui_init_toolbar_widgets(); + + toolbar_set_icon_style(vtb->widget); + toolbar_set_icon_size(vtb->widget); /* add the toolbar again to the main window */ - if (toolbar_prefs.append_to_menu) + // Use reorder to ensure toolbar always comes after the menu + if (prefs_get_append_to_menu()) { - GtkWidget *hbox_menubar = ui_lookup_widget(main_widgets.window, "hbox_menubar"); - gtk_box_pack_start(GTK_BOX(hbox_menubar), main_widgets.toolbar, TRUE, TRUE, 0); - gtk_box_reorder_child(GTK_BOX(hbox_menubar), main_widgets.toolbar, 1); + if ( hbox ) { + gtk_box_pack_start(GTK_BOX(hbox), vtb->widget, TRUE, TRUE, 0); + gtk_box_reorder_child(GTK_BOX(hbox), vtb->widget, 1); + } } else { - GtkWidget *box = ui_lookup_widget(main_widgets.window, "vbox1"); - - gtk_box_pack_start(GTK_BOX(box), main_widgets.toolbar, FALSE, FALSE, 0); - gtk_box_reorder_child(GTK_BOX(box), main_widgets.toolbar, 1); + if ( vbox ) { + gtk_box_pack_start(GTK_BOX(vbox), vtb->widget, FALSE, TRUE, 0); + gtk_box_reorder_child(GTK_BOX(vbox), vtb->widget, 1); + } } - gtk_widget_show(main_widgets.toolbar); +} + +/** + * toolbar_get_widget: + * + */ +GtkWidget* toolbar_get_widget(VikToolbar *vtb) +{ + g_return_val_if_fail(VIK_IS_TOOLBAR(vtb), NULL); + return vtb->widget; +} - /* re-add und unref the plugin toolbar items */ - i = toolbar_get_insert_position(); - foreach_slist(l, plugin_items) +#include "toolbar.xml.h" +static void toolbar_reload ( VikToolbar *vtb, + const gchar *markup, + GtkWindow *parent, + GtkWidget *vbox, + GtkWidget *hbox, + ReloadCB reload_cb, + gpointer user_data ) +{ + GError *error = NULL; + g_debug ( "%s: %d", __FUNCTION__, g_hash_table_size(signal_data) ); + + /* Cleanup old toolbar */ + if (vtb->merge_id > 0) { - gtk_toolbar_insert(GTK_TOOLBAR(main_widgets.toolbar), l->data, i); - g_object_unref(l->data); - i++; + /* Get rid of it! */ + gtk_widget_destroy(vtb->widget); + + gtk_ui_manager_remove_ui(vtb->uim, vtb->merge_id); + gtk_ui_manager_ensure_update(vtb->uim); + + g_hash_table_remove ( signal_data, vtb ); } - /* re-add und unref the submenus of menu toolbar items */ - if (toolbar_new_file_menu != NULL) + + if (markup != NULL) { - geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION( - gtk_action_group_get_action(group, "New")), toolbar_new_file_menu); - g_object_unref(toolbar_new_file_menu); + vtb->merge_id = gtk_ui_manager_add_ui_from_string(vtb->uim, markup, -1, &error); } - if (toolbar_recent_files_menu != NULL) + else { - geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION( - gtk_action_group_get_action(group, "Open")), toolbar_recent_files_menu); - g_object_unref(toolbar_recent_files_menu); + gchar *filename = NULL; + /* Load the toolbar UI XML file from disk */ + // Consider using a_get_viking_data_path() first + filename = g_build_filename (a_get_viking_dir(), "ui_toolbar.xml", NULL); + vtb->merge_id = gtk_ui_manager_add_ui_from_file(vtb->uim, filename, &error); + g_free(filename); } - if (toolbar_build_menu != NULL) + if (error != NULL) { - geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION( - gtk_action_group_get_action(group, "Build")), toolbar_build_menu); - g_object_unref(toolbar_build_menu); + g_debug("UI creation failed, using internal fallback definition. Error message: %s", error->message); + g_error_free(error); + error = NULL; + + /* finally load the internally defined markup as fallback */ + vtb->merge_id = gtk_ui_manager_add_ui_from_string(vtb->uim, toolbar_xml, -1, &error); + if (error) { + // Abort - this should only happen if you're missing around with the code + g_error("Internal UI creation failed. Error message: %s", error->message); + } + } + vtb->widget = gtk_ui_manager_get_widget(vtb->uim, "/ui/MainToolbar"); /* update button states */ - if (main_status.main_window_realized) - { - GeanyDocument *doc = document_get_current(); - gboolean doc_changed = (doc != NULL) ? doc->changed : FALSE; + reload_cb ( vtb->group_actions, user_data ); - ui_document_buttons_update(); - ui_save_buttons_toggle(doc_changed); /* update save all */ - ui_update_popup_reundo_items(doc); + toolbar_apply_settings(vtb, vbox, hbox, FALSE); - toolbar_apply_settings(); - } + gtk_widget_show(vtb->widget); /* Signals */ - g_signal_connect(main_widgets.toolbar, "button-press-event", - G_CALLBACK(toolbar_popup_menu), NULL); - g_signal_connect(main_widgets.toolbar, "key-press-event", - G_CALLBACK(on_escape_key_press_event), NULL); + config_t *data = g_malloc(sizeof(config_t)); + data->vtb = vtb; + data->parent = parent; + data->vbox = vbox; + data->hbox = hbox; + data->reload_cb = reload_cb; + data->user_data = user_data; + + // Store data in a hash so it can be freed when the toolbar is reconfigured + g_hash_table_insert (signal_data, vtb, data); + + g_signal_connect(vtb->widget, "button-press-event", G_CALLBACK(toolbar_popup_menu), data); /* We don't need to disconnect those signals as this is done automatically when the entry * widgets are destroyed, happens when the toolbar itself is destroyed. */ - entry = toolbar_get_widget_child_by_name("SearchEntry"); - if (entry != NULL) - g_signal_connect(entry, "motion-notify-event", G_CALLBACK(on_motion_event), NULL); - entry = toolbar_get_widget_child_by_name("GotoEntry"); - if (entry != NULL) - g_signal_connect(entry, "motion-notify-event", G_CALLBACK(on_motion_event), NULL); - - return main_widgets.toolbar; } - static void toolbar_notify_style_cb(GObject *object, GParamSpec *arg1, gpointer data) { const gchar *arg_name = g_param_spec_get_name(arg1); gint value; - if (toolbar_prefs.use_gtk_default_style && utils_str_equal(arg_name, "gtk-toolbar-style")) + if (prefs_get_icon_style() == 0 && !g_strcmp0(arg_name, "gtk-toolbar-style")) { - value = ui_get_gtk_settings_integer(arg_name, toolbar_prefs.icon_style); - gtk_toolbar_set_style(GTK_TOOLBAR(main_widgets.toolbar), value); + value = ui_get_gtk_settings_integer(arg_name, GTK_TOOLBAR_ICONS); + if ( GTK_IS_TOOLBAR (data) ) + gtk_toolbar_set_style(GTK_TOOLBAR(data), value); } - else if (toolbar_prefs.use_gtk_default_icon && utils_str_equal(arg_name, "gtk-toolbar-size")) + else if (prefs_get_icon_size() == 0 && !g_strcmp0(arg_name, "gtk-toolbar-size")) { - value = ui_get_gtk_settings_integer(arg_name, toolbar_prefs.icon_size); - gtk_toolbar_set_icon_size(GTK_TOOLBAR(main_widgets.toolbar), value); + value = ui_get_gtk_settings_integer(arg_name, GTK_ICON_SIZE_SMALL_TOOLBAR); + if ( GTK_IS_TOOLBAR (data) ) + gtk_toolbar_set_icon_size(GTK_TOOLBAR(data), value); } } - -GtkWidget *toolbar_init(void) +/** + * toolbar_init: + * + * Initialize the specified toolbar using the given values + */ +void toolbar_init (VikToolbar *vtb, + GtkWindow *parent, + GtkWidget *vbox, + GtkWidget *hbox, + ToolCB tool_cb, + ReloadCB reload_cb, + gpointer user_data) { - GtkWidget *toolbar; - GtkAction *action_new; - GtkAction *action_open; - GtkAction *action_build; - GtkAction *action_searchentry; - GtkAction *action_gotoentry; - GtkSettings *gtk_settings; - - uim = gtk_ui_manager_new(); - group = gtk_action_group_new("GeanyToolbar"); - - gtk_action_group_set_translation_domain(group, GETTEXT_PACKAGE); - gtk_action_group_add_actions(group, ui_entries, ui_entries_n, NULL); - - /* Create our custom actions */ - action_new = geany_menu_button_action_new( - "New", NULL, - _("Create a new file"), - _("Create a new file from a template"), - GTK_STOCK_NEW); - g_signal_connect(action_new, "button-clicked", G_CALLBACK(on_toolbutton_new_clicked), NULL); - gtk_action_group_add_action(group, action_new); - - action_open = geany_menu_button_action_new( - "Open", NULL, - _("Open an existing file"), - _("Open a recent file"), - GTK_STOCK_OPEN); - g_signal_connect(action_open, "button-clicked", G_CALLBACK(on_toolbutton_open_clicked), NULL); - gtk_action_group_add_action(group, action_open); - - action_build = geany_menu_button_action_new( - "Build", NULL, - _("Build the current file"), - _("Choose more build actions"), - GEANY_STOCK_BUILD); - g_signal_connect(action_build, "button-clicked", - G_CALLBACK(build_toolbutton_build_clicked), NULL); - gtk_action_group_add_action(group, action_build); - - action_searchentry = geany_entry_action_new( - "SearchEntry", _("Search Field"), _("Find the entered text in the current file"), FALSE); - g_signal_connect(action_searchentry, "entry-activate", - G_CALLBACK(on_toolbar_search_entry_activate), GINT_TO_POINTER(FALSE)); - g_signal_connect(action_searchentry, "entry-activate-backward", - G_CALLBACK(on_toolbar_search_entry_activate), GINT_TO_POINTER(TRUE)); - g_signal_connect(action_searchentry, "entry-changed", - G_CALLBACK(on_toolbar_search_entry_changed), NULL); - gtk_action_group_add_action(group, action_searchentry); - - action_gotoentry = geany_entry_action_new( - "GotoEntry", _("Goto Field"), _("Jump to the entered line number"), TRUE); - g_signal_connect(action_gotoentry, "entry-activate", - G_CALLBACK(on_toolbutton_goto_entry_activate), NULL); - gtk_action_group_add_action(group, action_gotoentry); - - gtk_ui_manager_insert_action_group(uim, group, 0); - - toolbar = toolbar_reload(NULL); -#if GTK_CHECK_VERSION(3, 0, 0) - gtk_style_context_add_class(gtk_widget_get_style_context(toolbar), "primary-toolbar"); -#endif - - gtk_settings = gtk_widget_get_settings(GTK_WIDGET(toolbar)); - if (gtk_settings != NULL) - { - g_signal_connect(gtk_settings, "notify::gtk-toolbar-style", - G_CALLBACK(toolbar_notify_style_cb), NULL); + vtb->uim = gtk_ui_manager_new(); + + vtb->group_actions = gtk_action_group_new("MainToolbar"); + gtk_action_group_set_translation_domain(vtb->group_actions, GETTEXT_PACKAGE); + GtkActionEntry *actions = NULL; + GSList *gl; + gint nn = 0; + foreach_slist(gl, vtb->list_of_actions) { + GtkActionEntry *action = gl->data; + actions = g_renew(GtkActionEntry, actions, nn+1); + actions[nn] = *action; + nn++; } - - return toolbar; -} - - -void toolbar_update_ui(void) -{ - static GtkWidget *hbox_menubar = NULL; - static GtkWidget *menubar = NULL; - GtkWidget *menubar_toolbar_separator = NULL; - GtkWidget *parent; - GtkToolItem *first_item; - - if (menubar == NULL) - { /* cache widget pointers */ - hbox_menubar = ui_lookup_widget(main_widgets.window, "hbox_menubar"); - menubar = ui_lookup_widget(main_widgets.window, "menubar1"); + gtk_action_group_add_actions(vtb->group_actions, actions, nn, user_data); + gtk_ui_manager_insert_action_group(vtb->uim, vtb->group_actions, 0); + + vtb->group_toggles = gtk_action_group_new("UIItems"); + gtk_action_group_set_translation_domain(vtb->group_toggles, GETTEXT_PACKAGE); + GtkToggleActionEntry *toggle_actions = NULL; + nn = 0; + foreach_slist(gl, vtb->list_of_toggles) { + GtkToggleActionEntry *action = gl->data; + toggle_actions = g_renew(GtkToggleActionEntry, toggle_actions, nn+1); + toggle_actions[nn] = *action; + nn++; } - /* the separator between the menubar and the toolbar */ - first_item = gtk_toolbar_get_nth_item(GTK_TOOLBAR(main_widgets.toolbar), 0); - if (first_item != NULL && GTK_IS_SEPARATOR_TOOL_ITEM(first_item)) - { - gtk_widget_destroy(GTK_WIDGET(first_item)); + gtk_action_group_add_toggle_actions(vtb->group_toggles, toggle_actions, nn, user_data); + gtk_ui_manager_insert_action_group(vtb->uim, vtb->group_toggles, 0); + + vtb->group_tools = gtk_action_group_new("ToolItems"); + gtk_action_group_set_translation_domain(vtb->group_tools, GETTEXT_PACKAGE); + + GtkRadioActionEntry *tool_actions = NULL; + nn = 0; + foreach_slist(gl, vtb->list_of_tools) { + GtkRadioActionEntry *action = gl->data; + tool_actions = g_renew(GtkRadioActionEntry, tool_actions, nn+1); + tool_actions[nn] = *action; + tool_actions[nn].value = nn; + nn++; } - - parent = gtk_widget_get_parent(main_widgets.toolbar); - - if (toolbar_prefs.append_to_menu) - { - if (parent != NULL) - { - if (parent != hbox_menubar) - { /* here we manually 'reparent' the toolbar, gtk_widget_reparent() doesn't - * like to do it */ - g_object_ref(main_widgets.toolbar); - - gtk_container_remove(GTK_CONTAINER(parent), main_widgets.toolbar); - gtk_box_pack_start(GTK_BOX(hbox_menubar), main_widgets.toolbar, TRUE, TRUE, 0); - gtk_box_reorder_child(GTK_BOX(hbox_menubar), main_widgets.toolbar, 1); - - g_object_unref(main_widgets.toolbar); - } - } - else - gtk_box_pack_start(GTK_BOX(hbox_menubar), main_widgets.toolbar, TRUE, TRUE, 0); - - /* the separator between the menubar and the toolbar */ - menubar_toolbar_separator = GTK_WIDGET(gtk_separator_tool_item_new()); - gtk_widget_show(menubar_toolbar_separator); - gtk_toolbar_insert(GTK_TOOLBAR(main_widgets.toolbar), - GTK_TOOL_ITEM(menubar_toolbar_separator), 0); + gtk_action_group_add_radio_actions(vtb->group_tools, tool_actions, nn, 0, G_CALLBACK(tool_cb), user_data); + gtk_ui_manager_insert_action_group(vtb->uim, vtb->group_tools, 0); + + vtb->group_modes = gtk_action_group_new("ModeItems"); + gtk_action_group_set_translation_domain(vtb->group_modes, GETTEXT_PACKAGE); + + GtkRadioActionEntry *mode_actions = NULL; + nn = 0; + foreach_slist(gl, vtb->list_of_modes) { + GtkRadioActionEntry *action = gl->data; + mode_actions = g_renew(GtkRadioActionEntry, mode_actions, nn+1); + mode_actions[nn] = *action; + mode_actions[nn].value = nn; + nn++; } - else - { - GtkWidget *box = ui_lookup_widget(main_widgets.window, "vbox1"); + gtk_action_group_add_radio_actions(vtb->group_modes, mode_actions, nn, 0, G_CALLBACK(tool_cb), user_data); + gtk_ui_manager_insert_action_group(vtb->uim, vtb->group_modes, 0); - if (parent != NULL) - { - if (parent != box) - { - g_object_ref(main_widgets.toolbar); + toolbar_reload(vtb, NULL, parent, vbox, hbox, reload_cb, user_data); - gtk_container_remove(GTK_CONTAINER(parent), main_widgets.toolbar); - gtk_box_pack_start(GTK_BOX(box), main_widgets.toolbar, FALSE, FALSE, 0); - gtk_box_reorder_child(GTK_BOX(box), main_widgets.toolbar, 1); +#if GTK_CHECK_VERSION(3, 0, 0) + gtk_style_context_add_class(gtk_widget_get_style_context(vtb->widget), "primary-toolbar"); +#endif - g_object_unref(main_widgets.toolbar); - } - } - else - { - gtk_box_pack_start(GTK_BOX(box), main_widgets.toolbar, FALSE, FALSE, 0); - gtk_box_reorder_child(GTK_BOX(box), main_widgets.toolbar, 1); - } + GtkSettings *gtk_settings = gtk_widget_get_settings(vtb->widget); + if (gtk_settings != NULL) + { + g_signal_connect(gtk_settings, "notify::gtk-toolbar-style", + G_CALLBACK(toolbar_notify_style_cb), vtb->widget); } - /* we need to adjust the packing flags for the menubar to expand it if it is alone in the - * hbox and not expand it if the toolbar is appended */ - gtk_box_set_child_packing(GTK_BOX(hbox_menubar), menubar, - ! (toolbar_prefs.visible && toolbar_prefs.append_to_menu), TRUE, 0, GTK_PACK_START); -} + extra_widget_data.vtb = vtb; + extra_widget_data.parent = parent; + extra_widget_data.vbox = vbox; + extra_widget_data.reload_cb = reload_cb; + extra_widget_data.user_data = user_data; +} -/* Returns the position for adding new toolbar items. The returned position can be used - * to add new toolbar items with @c gtk_toolbar_insert(). The toolbar object can be accessed - * with @a geany->main_widgets->toolbar. - * The position is always the last one before the Quit button or the very last position if the - * Quit button is not the last toolbar item. +/** + * toolbar_action_set_sensitive: * - * @return The position for new toolbar items. + * Set sensitivity of a particular action */ -gint toolbar_get_insert_position(void) +void toolbar_action_set_sensitive (VikToolbar *vtb, const gchar *name, gboolean sensitive) { - GtkWidget *quit = toolbar_get_widget_by_name("Quit"); - gint quit_pos = -1, pos; - - if (quit != NULL) - quit_pos = gtk_toolbar_get_item_index(GTK_TOOLBAR(main_widgets.toolbar), GTK_TOOL_ITEM(quit)); - - pos = gtk_toolbar_get_n_items(GTK_TOOLBAR(main_widgets.toolbar)); - if (quit_pos == (pos - 1)) - { - /* if the toolbar item before the quit button is a separator, insert new items before */ - if (GTK_IS_SEPARATOR_TOOL_ITEM(gtk_toolbar_get_nth_item( - GTK_TOOLBAR(main_widgets.toolbar), quit_pos - 1))) - { - return quit_pos - 1; - } - /* else return the position of the quit button to insert new items before */ - return quit_pos; - } - - return pos; + g_return_if_fail(VIK_IS_TOOLBAR(vtb)); + g_return_if_fail(name != NULL); + // Try all groups + GtkAction *action = get_action ( vtb, name ); + if ( action ) + g_object_set ( action, "sensitive", sensitive, NULL); } - -void toolbar_finalize(void) +/** + * vik_toolbar_finalize: + * + * Memory cleanups upon toolbar destruction + */ +void vik_toolbar_finalize ( VikToolbar *vtb ) { - GeanyMenubuttonAction *open_action = GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("Open")); - g_object_unref(geany_menu_button_action_get_menu(open_action)); - geany_menu_button_action_set_menu(open_action, NULL); + g_hash_table_remove ( signal_data, vtb ); /* unref'ing the GtkUIManager object will destroy all its widgets unless they were ref'ed */ - g_object_unref(uim); - g_object_unref(group); - - g_slist_free(plugin_items); -} - - -void toolbar_show_hide(void) -{ - ignore_callback = TRUE; - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( - ui_lookup_widget(main_widgets.window, "menu_show_toolbar1")), toolbar_prefs.visible); - ui_widget_show_hide(main_widgets.toolbar, toolbar_prefs.visible); - ignore_callback = FALSE; -} - - -/* sets the icon style of the toolbar */ -static void toolbar_set_icon_style(void) -{ - gint icon_style; - - icon_style = toolbar_prefs.icon_style; - - if (toolbar_prefs.use_gtk_default_style) - icon_style = ui_get_gtk_settings_integer("gtk-toolbar-style", toolbar_prefs.icon_style); - - gtk_toolbar_set_style(GTK_TOOLBAR(main_widgets.toolbar), icon_style); -} - - -/* sets the icon size of the toolbar */ -static void toolbar_set_icon_size(void) -{ - gint icon_size; - - icon_size = toolbar_prefs.icon_size; - - if (toolbar_prefs.use_gtk_default_icon) - icon_size = ui_get_gtk_settings_integer("gtk-toolbar-icon-size", toolbar_prefs.icon_size); - - gtk_toolbar_set_icon_size(GTK_TOOLBAR(main_widgets.toolbar), icon_size); -} - - -void toolbar_apply_settings(void) -{ - toolbar_set_icon_style(); - toolbar_set_icon_size(); + g_object_unref(vtb->uim); + g_object_unref(vtb->group_actions); + g_object_unref(vtb->group_tools); + g_object_unref(vtb->group_toggles); + g_object_unref(vtb->group_modes); + + g_slist_free(vtb->list_of_actions); + g_slist_free(vtb->list_of_tools); + g_slist_free(vtb->list_of_toggles); + g_slist_free(vtb->list_of_modes); } @@ -595,11 +654,13 @@ typedef struct GtkTreeViewDropPosition last_drag_pos; GtkWidget *drag_source; + + config_t config; } TBEditorWidget; static const GtkTargetEntry tb_editor_dnd_targets[] = { - { "GEANY_TB_EDITOR_ROW", 0, 0 } + { "VIKING_TB_EDITOR_ROW", 0, 0 } }; static const gint tb_editor_dnd_targets_len = G_N_ELEMENTS(tb_editor_dnd_targets); @@ -620,12 +681,12 @@ static void tb_editor_handler_start_element(GMarkupParseContext *context, const GSList **actions = data; /* This is very basic parsing, stripped down any error checking, requires a valid UI markup. */ - if (utils_str_equal(element_name, "separator")) + if (!g_strcmp0(element_name, "separator")) *actions = g_slist_append(*actions, g_strdup(TB_EDITOR_SEPARATOR)); for (i = 0; attribute_names[i] != NULL; i++) { - if (utils_str_equal(attribute_names[i], "action")) + if (!g_strcmp0(attribute_names[i], "action")) { *actions = g_slist_append(*actions, g_strdup(attribute_values[i])); } @@ -652,30 +713,29 @@ static GSList *tb_editor_parse_ui(const gchar *buffer, gssize length, GError **e } -static void tb_editor_set_item_values(const gchar *name, GtkListStore *store, GtkTreeIter *iter) +static void tb_editor_set_item_values(VikToolbar *vtb, const gchar *name, GtkListStore *store, GtkTreeIter *iter) { gchar *icon = NULL; gchar *label = NULL; gchar *label_clean = NULL; - GtkAction *action; - action = gtk_action_group_get_action(group, name); - if (action == NULL) - { - if (utils_str_equal(name, TB_EDITOR_SEPARATOR)) + // Tries all action groups + GtkAction *action = get_action ( vtb, name ); + + if (action == NULL) { + if (!g_strcmp0(name, TB_EDITOR_SEPARATOR)) label_clean = g_strdup(TB_EDITOR_SEPARATOR_LABEL); else return; } - else - { + if (action != NULL) { g_object_get(action, "icon-name", &icon, NULL); if (icon == NULL) g_object_get(action, "stock-id", &icon, NULL); g_object_get(action, "label", &label, NULL); if (label != NULL) - label_clean = utils_str_remove_chars(g_strdup(label), "_"); + label_clean = util_str_remove_chars(g_strdup(label), "_"); } gtk_list_store_set(store, iter, @@ -722,10 +782,10 @@ static void tb_editor_btn_remove_clicked_cb(GtkWidget *button, TBEditorWidget *t if (gtk_list_store_remove(tbw->store_used, &iter_used)) gtk_tree_selection_select_iter(selection_used, &iter_used); - if (! utils_str_equal(action_name, TB_EDITOR_SEPARATOR)) + if (g_strcmp0(action_name, TB_EDITOR_SEPARATOR)) { gtk_list_store_append(tbw->store_available, &iter_new); - tb_editor_set_item_values(action_name, tbw->store_available, &iter_new); + tb_editor_set_item_values(tbw->config.vtb, action_name, tbw->store_available, &iter_new); tb_editor_scroll_to_iter(tbw->tree_available, &iter_new); } @@ -746,7 +806,7 @@ static void tb_editor_btn_add_clicked_cb(GtkWidget *button, TBEditorWidget *tbw) { gtk_tree_model_get(model_available, &iter_available, TB_EDITOR_COL_ACTION, &action_name, -1); - if (! utils_str_equal(action_name, TB_EDITOR_SEPARATOR)) + if (g_strcmp0(action_name, TB_EDITOR_SEPARATOR)) { if (gtk_list_store_remove(tbw->store_available, &iter_available)) gtk_tree_selection_select_iter(selection_available, &iter_available); @@ -758,7 +818,7 @@ static void tb_editor_btn_add_clicked_cb(GtkWidget *button, TBEditorWidget *tbw) else gtk_list_store_append(tbw->store_used, &iter_new); - tb_editor_set_item_values(action_name, tbw->store_used, &iter_new); + tb_editor_set_item_values(tbw->config.vtb, action_name, tbw->store_used, &iter_new); tb_editor_scroll_to_iter(tbw->tree_used, &iter_new); g_free(action_name); @@ -767,7 +827,7 @@ static void tb_editor_btn_add_clicked_cb(GtkWidget *button, TBEditorWidget *tbw) static gboolean tb_editor_drag_motion_cb(GtkWidget *widget, GdkDragContext *drag_context, - gint x, gint y, guint ltime, TBEditorWidget *tbw) + gint x, gint y, guint ltime, TBEditorWidget *tbw) { if (tbw->last_drag_path != NULL) gtk_tree_path_free(tbw->last_drag_path); @@ -779,8 +839,8 @@ static gboolean tb_editor_drag_motion_cb(GtkWidget *widget, GdkDragContext *drag static void tb_editor_drag_data_get_cb(GtkWidget *widget, GdkDragContext *context, - GtkSelectionData *data, guint info, guint ltime, - TBEditorWidget *tbw) + GtkSelectionData *data, guint info, guint ltime, + TBEditorWidget *tbw) { GtkTreeIter iter; GtkTreeSelection *selection; @@ -821,7 +881,7 @@ static void tb_editor_drag_data_rcvd_cb(GtkWidget *widget, GdkDragContext *conte gchar *text = NULL; text = (gchar*) gtk_selection_data_get_data(data); - is_sep = utils_str_equal(text, TB_EDITOR_SEPARATOR); + is_sep = !g_strcmp0(text, TB_EDITOR_SEPARATOR); /* If the source of the action is equal to the target, we do just re-order and so need * to delete the separator to get it moved, not just copied. */ if (is_sep && widget == tbw->drag_source) @@ -850,7 +910,7 @@ static void tb_editor_drag_data_rcvd_cb(GtkWidget *widget, GdkDragContext *conte else gtk_list_store_append(store, &iter); - tb_editor_set_item_values(text, store, &iter); + tb_editor_set_item_values(tbw->config.vtb, text, store, &iter); tb_editor_scroll_to_iter(tree, &iter); } if (tree != tbw->tree_used || ! is_sep) @@ -864,13 +924,13 @@ static void tb_editor_drag_data_rcvd_cb(GtkWidget *widget, GdkDragContext *conte static gboolean tb_editor_foreach_used(GtkTreeModel *model, GtkTreePath *path, - GtkTreeIter *iter, gpointer data) + GtkTreeIter *iter, gpointer data) { gchar *action_name; gtk_tree_model_get(model, iter, TB_EDITOR_COL_ACTION, &action_name, -1); - if (utils_str_equal(action_name, TB_EDITOR_SEPARATOR)) + if (!g_strcmp0(action_name, TB_EDITOR_SEPARATOR)) g_string_append_printf(data, "\t\t\n"); else if (G_LIKELY(!EMPTY(action_name))) g_string_append_printf(data, "\t\t\n", action_name); @@ -884,27 +944,32 @@ static void tb_editor_write_markup(TBEditorWidget *tbw) { /* must be the first tag, otherwise gtk_ui_manager_add_ui_from_string() will fail. */ const gchar *template = "\n\n\ -\t\n"; - gchar *filename; +Generally one should use the toolbar editor in Viking rather than editing this file.\n\n\ +For manual changes to this file to take effect, you need to restart Viking.\n-->\n\ +\t\n"; GString *str = g_string_new(template); gtk_tree_model_foreach(GTK_TREE_MODEL(tbw->store_used), tb_editor_foreach_used, str); - g_string_append(str, "\n\t\n\n"); + g_string_append(str, "\t\n\n"); - toolbar_reload(str->str); + toolbar_reload(tbw->config.vtb, + str->str, + tbw->config.parent, + tbw->config.vbox, + tbw->config.hbox, + tbw->config.reload_cb, + tbw->config.user_data); - filename = g_build_filename(app->configdir, "ui_toolbar.xml", NULL); - utils_write_file(filename, str->str); + // ATM always save the toolbar when changed + gchar *filename = g_build_filename(a_get_viking_dir (), "ui_toolbar.xml", NULL); + GError *error = NULL; + if (! g_file_set_contents(filename, str->str, -1, &error)) { + g_warning ("%s: could not write to file %s (%s)", __FUNCTION__, filename, error->message); + g_error_free(error); + } g_free(filename); g_string_free(str, TRUE); @@ -925,24 +990,25 @@ static void tb_editor_available_items_deleted_cb(GtkTreeModel *model, GtkTreePat } -static TBEditorWidget *tb_editor_create_dialog(GtkWindow *parent) +static TBEditorWidget *tb_editor_create_dialog(VikToolbar *vtb, GtkWindow *parent, GtkWidget *toolbar, GtkWidget *vbox, GtkWidget *menu_hbox, ReloadCB reload_cb, gpointer user_data) { - GtkWidget *dialog, *vbox, *hbox, *vbox_buttons, *button_add, *button_remove; + GtkWidget *dialog, *hbox, *vbox_buttons, *button_add, *button_remove; GtkWidget *swin_available, *swin_used, *tree_available, *tree_used, *label; GtkCellRenderer *text_renderer, *icon_renderer; GtkTreeViewColumn *column; - TBEditorWidget *tbw = g_new(TBEditorWidget, 1); - if (parent == NULL) - parent = GTK_WINDOW(main_widgets.window); + if (parent == NULL) { + g_warning ( "No parent" ); + return NULL; + } + + TBEditorWidget *tbw = g_new(TBEditorWidget, 1); dialog = gtk_dialog_new_with_buttons(_("Customize Toolbar"), - parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); - vbox = ui_dialog_vbox_new(GTK_DIALOG(dialog)); - gtk_box_set_spacing(GTK_BOX(vbox), 6); - gtk_widget_set_name(dialog, "GeanyDialog"); + GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); + gtk_widget_set_name(dialog, "VikingDialog"); gtk_window_set_default_size(GTK_WINDOW(dialog), -1, 400); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE); @@ -951,6 +1017,13 @@ static TBEditorWidget *tb_editor_create_dialog(GtkWindow *parent) tbw->store_used = gtk_list_store_new(TB_EDITOR_COLS_MAX, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + tbw->config.vtb = vtb; + tbw->config.parent = parent; + tbw->config.vbox = vbox; + tbw->config.hbox = menu_hbox; + tbw->config.reload_cb = reload_cb; + tbw->config.user_data = user_data; + label = gtk_label_new( _("Select items to be displayed on the toolbar. Items can be reordered by drag and drop.")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); @@ -1039,10 +1112,10 @@ static TBEditorWidget *tb_editor_create_dialog(GtkWindow *parent) gtk_box_pack_start(GTK_BOX(hbox), vbox_buttons, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), swin_used, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 6); - gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), label, FALSE, FALSE, 6); + gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, TRUE, TRUE, 0); - gtk_widget_show_all(vbox); + gtk_widget_show_all(dialog); g_object_unref(tbw->store_available); g_object_unref(tbw->store_used); @@ -1056,8 +1129,11 @@ static TBEditorWidget *tb_editor_create_dialog(GtkWindow *parent) return tbw; } - -void toolbar_configure(GtkWindow *parent) +/** + * toolbar_configure: + * + */ +void toolbar_configure (VikToolbar *vtb, GtkWidget *toolbar, GtkWindow *parent, GtkWidget *vbox, GtkWidget *hbox, ReloadCB reload_cb, gpointer user_data) { gchar *markup; const gchar *name; @@ -1068,15 +1144,18 @@ void toolbar_configure(GtkWindow *parent) TBEditorWidget *tbw; /* read the current active toolbar items */ - markup = gtk_ui_manager_get_ui(uim); + markup = gtk_ui_manager_get_ui(vtb->uim); used_items = tb_editor_parse_ui(markup, -1, NULL); g_free(markup); /* get all available actions */ - all_items = gtk_action_group_list_actions(group); + all_items = gtk_action_group_list_actions(vtb->group_actions); + all_items = g_list_concat ( all_items, gtk_action_group_list_actions(vtb->group_toggles) ); + all_items = g_list_concat ( all_items, gtk_action_group_list_actions(vtb->group_tools) ); + all_items = g_list_concat ( all_items, gtk_action_group_list_actions(vtb->group_modes) ); /* create the GUI */ - tbw = tb_editor_create_dialog(parent); + tbw = tb_editor_create_dialog(vtb, parent, toolbar, vbox, hbox, reload_cb, user_data); /* fill the stores */ gtk_list_store_insert_with_values(tbw->store_available, NULL, -1, @@ -1089,13 +1168,13 @@ void toolbar_configure(GtkWindow *parent) if (g_slist_find_custom(used_items, name, (GCompareFunc) strcmp) == NULL) { gtk_list_store_append(tbw->store_available, &iter); - tb_editor_set_item_values(name, tbw->store_available, &iter); + tb_editor_set_item_values(vtb, name, tbw->store_available, &iter); } } foreach_slist(sl, used_items) { gtk_list_store_append(tbw->store_used, &iter); - tb_editor_set_item_values(sl->data, tbw->store_used, &iter); + tb_editor_set_item_values(vtb, sl->data, tbw->store_used, &iter); } /* select first item */ path = gtk_tree_path_new_from_string("0");