/*
roxterm - VTE/GTK terminal emulator with tabs
Copyright (C) 2004-2015 Tony Houghton <h@realh.co.uk>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "defns.h"
#include <stdarg.h>
#include <string.h>
#include "menutree.h"
#include "shortcuts.h"
static char const *menutree_labels[MENUTREE_NUM_IDS];
static gboolean filled_labels = FALSE;
static GtkWidget *menutree_append_new_item_with_mnemonic(
GtkMenuShell *shell, const char *label)
{
GtkWidget *item = gtk_menu_item_new_with_mnemonic(label);
gtk_menu_shell_append(shell, item);
return item;
}
static char *strip_underscore(const char *in)
{
char *out = g_new(char, strlen(in) + 1);
int n, m;
for (n = 0, m = 0; in[n]; ++n)
{
if (in[n] != '_')
out[m++] = in[n];
}
out[m] = 0;
return out;
}
/* Builds a menu; va_list is a series of pairs of labels and IDs, terminated
* by a NULL label; use "_" for a separator, and MENUTREE_NULL_ID for any item
* you don't want stored in item_widgets */
static void menutree_build_shell_ap(MenuTree *menu_tree, GtkMenuShell *shell,
va_list ap)
{
char *label;
MenuTreeID id;
while ((label = va_arg(ap, char *)) != NULL)
{
GtkWidget *item = NULL;
id = va_arg(ap, MenuTreeID);
if (!strcmp(label, "_"))
{
item = gtk_separator_menu_item_new();
gtk_menu_shell_append(shell, item);
}
else
{
if (!filled_labels &&
id < MENUTREE_NUM_IDS && id != MENUTREE_NULL_ID)
{
menutree_labels[id] = label;
}
if (menu_tree->disable_shortcuts)
label = strip_underscore(label);
item = NULL;
switch (id)
{
case MENUTREE_VIEW_SHOW_MENUBAR:
case MENUTREE_VIEW_SHOW_TAB_BAR:
case MENUTREE_VIEW_FULLSCREEN:
item = gtk_check_menu_item_new_with_mnemonic(label);
gtk_menu_shell_append(shell, item);
break;
default:
item = menutree_append_new_item_with_mnemonic(shell, label);
break;
}
if (menu_tree->disable_shortcuts)
g_free(label);
}
if (id != MENUTREE_NULL_ID)
menu_tree->item_widgets[id] = item;
}
}
/* See above for description of variable args */
static void menutree_build_shell(MenuTree *menu_tree, GtkMenuShell * shell, ...)
{
va_list ap;
va_start(ap, shell);
menutree_build_shell_ap(menu_tree, shell, ap);
va_end(ap);
}
#define URI_MENU_ITEMS \
_("_SSH to host"), MENUTREE_SSH_HOST, \
_("_Open URL in browser"), MENUTREE_OPEN_IN_BROWSER, \
_("_Send email"), MENUTREE_OPEN_IN_MAILER, \
_("_Open file/directory in filer"), MENUTREE_OPEN_IN_FILER, \
_("_Copy address to clipboard"), MENUTREE_COPY_URI, \
_("_"), MENUTREE_URI_SEPARATOR
#define MENUTREE_SEARCH_ITEM _("_Search"), MENUTREE_SEARCH,
#define TOP_LEVEL_MENU_ITEMS \
_("_File"), MENUTREE_FILE, \
_("_Edit"), MENUTREE_EDIT, \
_("_View"), MENUTREE_VIEW, \
MENUTREE_SEARCH_ITEM \
_("_Preferences"), MENUTREE_PREFERENCES, \
_("Ta_bs"), MENUTREE_TABS, \
_("_Help"), MENUTREE_HELP
#define COPY_PASTE_MENU_ITEMS \
_("Select _All"), MENUTREE_EDIT_SELECT_ALL, \
_("_Copy"), MENUTREE_EDIT_COPY, \
_("_Paste"), MENUTREE_EDIT_PASTE, \
_("Cop_y & Paste"), MENUTREE_EDIT_COPY_AND_PASTE, \
"_", MENUTREE_NULL_ID
#define RESET_MENU_ITEMS \
_("_Reset"), MENUTREE_EDIT_RESET, \
_("Reset And C_lear"), MENUTREE_EDIT_RESET_AND_CLEAR
#define SHOW_MENU_BAR_ITEM \
_("Show Menu_bar"), MENUTREE_VIEW_SHOW_MENUBAR
#define ENC_INPUT_ITEMS \
_("C_haracter Encoding"), MENUTREE_PREFERENCES_CHARACTER_ENCODING
#define PREFS_ITEMS1 \
_("Select _Profile"), MENUTREE_PREFERENCES_SELECT_PROFILE, \
_("Select _Colour Scheme"), MENUTREE_PREFERENCES_SELECT_COLOUR_SCHEME, \
_("Select _Shortcuts Scheme"), MENUTREE_PREFERENCES_SELECT_SHORTCUTS, \
"_", MENUTREE_NULL_ID, \
_("_Edit Current Profile"), MENUTREE_PREFERENCES_EDIT_CURRENT_PROFILE, \
_("E_dit Current Colour Scheme"), \
MENUTREE_PREFERENCES_EDIT_CURRENT_COLOUR_SCHEME
#define PREFS_ITEMS2 \
"_", MENUTREE_NULL_ID, \
_("Configuration _Manager"), MENUTREE_PREFERENCES_CONFIG_MANAGER, \
"_", MENUTREE_NULL_ID, \
ENC_INPUT_ITEMS, \
NULL
GtkMenu *menutree_submenu_from_id(MenuTree *mtree, MenuTreeID id)
{
GtkWidget *item = menutree_get_widget_for_id(mtree, id);
return item ?
GTK_MENU(gtk_menu_item_get_submenu(GTK_MENU_ITEM(item))) : NULL;
}
static char *get_accel_path(Options *shortcuts, const char *branch_name)
{
return g_strjoin("/", ACCEL_PATH,
shortcuts_get_index_str(shortcuts), branch_name, NULL);
}
static void
menutree_set_accel_path_for_submenu(MenuTree *mtree, MenuTreeID id,
const char *menu_branch)
{
GtkMenu *menu = menutree_submenu_from_id(mtree, id);
char *accel_path;
if (!menu)
return;
accel_path = get_accel_path(mtree->shortcuts, menu_branch);
gtk_menu_set_accel_path(menu, accel_path);
g_free(accel_path);
gtk_menu_set_accel_group(menu, mtree->accel_group);
}
static void
menutree_set_accel_path_for_item(MenuTree * tree, MenuTreeID id,
const char *path_leaf)
{
GtkWidget *item = tree->item_widgets[id];
char *full_path;
if (!item)
return;
full_path = get_accel_path(tree->shortcuts, path_leaf);
gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), full_path);
g_free(full_path);
}
static void
menutree_set_accel_path_for_tab(MenuTree * tree, int tab)
{
char *leaf = NULL;
char *full_path = NULL;
if (!tree->tabs || tab >= 10)
return;
if (!tree->disable_tab_shortcuts && tree->ntabs != 1)
{
leaf = g_strdup_printf("Tabs/Select_Tab_%d", tab);
full_path = get_accel_path(tree->shortcuts, leaf);
}
shortcuts_enable_signal_handler(FALSE);
gtk_menu_item_set_accel_path(
GTK_MENU_ITEM(g_list_nth_data(tree->tabs, tab)),
full_path);
g_free(full_path);
g_free(leaf);
shortcuts_enable_signal_handler(TRUE);
}
static void menutree_apply_tab_shortcuts(MenuTree *mtree)
{
int n;
for (n = 0; n < mtree->ntabs; ++n)
menutree_set_accel_path_for_tab(mtree, n);
}
void menutree_apply_shortcuts(MenuTree *tree, Options *shortcuts)
{
GtkMenu *submenu;
char *accel_path;
tree->shortcuts = shortcuts;
shortcuts_enable_signal_handler(FALSE);
menutree_set_accel_path_for_submenu(tree, MENUTREE_FILE, "File");
menutree_set_accel_path_for_submenu(tree, MENUTREE_EDIT, "Edit");
menutree_set_accel_path_for_submenu(tree, MENUTREE_VIEW, "View");
menutree_set_accel_path_for_submenu(tree, MENUTREE_SEARCH, "Search");
menutree_set_accel_path_for_submenu(tree, MENUTREE_PREFERENCES,
"Preferences");
menutree_set_accel_path_for_submenu(tree, MENUTREE_HELP, "Help");
submenu = GTK_MENU(tree->new_win_profiles_menu);
if (submenu)
{
accel_path = get_accel_path(tree->shortcuts,
"File/New Window With Profile");
gtk_menu_set_accel_path(submenu, accel_path);
g_free(accel_path);
gtk_menu_set_accel_group(submenu, tree->accel_group);
}
submenu = GTK_MENU(tree->new_tab_profiles_menu);
if (submenu)
{
accel_path = get_accel_path(tree->shortcuts,
"File/New Tab With Profile");
gtk_menu_set_accel_path(submenu, accel_path);
g_free(accel_path);
gtk_menu_set_accel_group(submenu, tree->accel_group);
}
/* Tabs have shortcuts set dynamically so set paths
* for fixed items individually */
submenu = menutree_submenu_from_id(tree, MENUTREE_TABS);
if (submenu)
gtk_menu_set_accel_group(submenu, tree->accel_group);
menutree_set_accel_path_for_item(tree,
MENUTREE_FILE_NEW_WINDOW_WITH_PROFILE_HEADER,
"File/New Window With Profile/Profiles");
menutree_set_accel_path_for_item(tree,
MENUTREE_FILE_NEW_TAB_WITH_PROFILE_HEADER,
"File/New Tab With Profile/Profiles");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_DETACH_TAB,
"Tabs/Detach Tab");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_CLOSE_TAB,
"Tabs/Close Tab");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_CLOSE_OTHER_TABS,
"Tabs/Close Other Tabs");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_NAME_TAB,
"Tabs/Name Tab...");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_NEXT_TAB,
"Tabs/Next Tab");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_PREVIOUS_TAB,
"Tabs/Previous Tab");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_MOVE_TAB_LEFT,
"Tabs/Move Tab Left");
menutree_set_accel_path_for_item(tree, MENUTREE_TABS_MOVE_TAB_RIGHT,
"Tabs/Move Tab Right");
menutree_set_accel_path_for_submenu(tree, MENUTREE_HELP, "Help");
menutree_apply_tab_shortcuts(tree);
shortcuts_enable_signal_handler(TRUE);
}
#define MENUTREE_ENCODING_KEY "Encoding"
#define MENUTREE_ENCODING_NULL "NULL"
static GtkWidget *create_encoding_item(MenuTree *mtree,
const char *encoding_label, const char *encoding_data,
MenuTreeToggledHandler handler)
{
GtkWidget *item = gtk_radio_menu_item_new_with_label(mtree->encodings_group,
encoding_label);
g_object_set_data_full(G_OBJECT(item), MENUTREE_ENCODING_KEY,
g_strdup(encoding_data), g_free);
g_signal_connect(item, "toggled", G_CALLBACK(handler), mtree->user_data);
gtk_widget_show(item);
return item;
}
static GtkWidget *add_encoding(MenuTree *mtree, const char *encoding_label,
const char *encoding_data, MenuTreeToggledHandler handler)
{
GtkWidget *item = create_encoding_item(mtree,
encoding_label, encoding_data, handler);
gtk_menu_shell_append(GTK_MENU_SHELL(mtree->encodings), item);
mtree->encodings_group =
gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(item));
++mtree->n_encodings;
return item;
}
static void create_encodings_menu(MenuTree *mtree,
MenuTreeToggledHandler handler)
{
GtkWidget *item;
mtree->encodings = gtk_menu_new();
item = add_encoding(mtree, _("Default"), MENUTREE_ENCODING_NULL,
handler);
mtree->n_encodings = 0; /* "Default" doesn't count */
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
item = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(mtree->encodings), item);
gtk_widget_show(item);
gtk_widget_set_sensitive(mtree->item_widgets
[MENUTREE_PREFERENCES_CHARACTER_ENCODING], TRUE);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(mtree->item_widgets
[MENUTREE_PREFERENCES_CHARACTER_ENCODING]),
mtree->encodings);
}
void menutree_build_encodings_menu(MenuTree *mtree, char const **encodings,
MenuTreeToggledHandler handler)
{
/* We skip first item in list, "Default" */
if (encodings && encodings[1])
{
int n;
create_encodings_menu(mtree, handler);
for (n = 1; encodings[n]; ++n)
{
add_encoding(mtree, encodings[n], encodings[n], handler);
}
}
else
{
gtk_widget_set_sensitive(mtree->item_widgets
[MENUTREE_PREFERENCES_CHARACTER_ENCODING], FALSE);
}
}
const char *menutree_encoding_from_widget(GtkCheckMenuItem *item)
{
const char *encoding = g_object_get_data(G_OBJECT(item),
MENUTREE_ENCODING_KEY);
if (!strcmp(encoding, MENUTREE_ENCODING_NULL))
return NULL;
return encoding;
}
void menutree_add_encoding(MenuTree *mtree, const char *encoding,
MenuTreeToggledHandler handler)
{
if (!mtree->encodings)
{
create_encodings_menu(mtree, handler);
}
add_encoding(mtree, encoding, encoding, handler);
}
static GtkWidget *menutree_find_encoding(MenuTree *mtree,
const char *encoding, int *position)
{
GList *link;
int n = 0;
if (!position)
position = &n;
if (!mtree->encodings)
{
*position = -1;
return NULL;
}
link = gtk_container_get_children(GTK_CONTAINER(mtree->encodings));
if (!encoding)
{
if (mtree->encodings)
{
*position = 0;
return link->data;
}
}
while (++n, (link = g_list_next(link)) != NULL)
{
if (n == 1) continue; /* Skip separator */
if (!strcmp(menutree_encoding_from_widget(link->data), encoding))
{
*position = n;
return link->data;
}
}
g_critical(_("Encoding '%s' not found in menu"), encoding);
*position = -1;
return NULL;
}
void menutree_remove_encoding(MenuTree *mtree, const char *encoding)
{
GtkWidget *item = menutree_find_encoding(mtree, encoding, NULL);
if (item)
{
gtk_widget_destroy(item);
if (!--mtree->n_encodings)
{
gtk_widget_destroy(mtree->encodings);
mtree->encodings = NULL;
mtree->encodings_group = NULL;
gtk_widget_set_sensitive(mtree->item_widgets
[MENUTREE_PREFERENCES_CHARACTER_ENCODING], FALSE);
}
/* else... we never destroy first item in group, so it should be safe
* to leave encodings_group unchanged */
}
}
void menutree_change_encoding(MenuTree *mtree, const char *old_encoding,
const char *new_encoding, MenuTreeToggledHandler handler)
{
int position;
GtkWidget *item = menutree_find_encoding(mtree, old_encoding, &position);
if (item)
{
gboolean state =
gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(item));
gtk_widget_destroy(item);
item = create_encoding_item(mtree, new_encoding, new_encoding, handler);
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), state);
gtk_menu_shell_insert(GTK_MENU_SHELL(mtree->encodings), item, position);
}
}
void menutree_select_encoding(MenuTree *mtree, const char *encoding)
{
GtkWidget *item = menutree_find_encoding(mtree, encoding, NULL);
if (item)
{
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
}
}
/*
static void submenu_destroy_handler(GtkWidget *menu, gpointer handle)
{
g_debug("Destroying submenu %p", menu);
}
*/
/* Creates top-level menubar or popup menu with submenus */
static void menutree_build(MenuTree *menu_tree, Options *shortcuts,
GType menu_type)
{
GtkWidget *submenu;
menu_tree->top_level = menu_type == GTK_TYPE_MENU_BAR ?
gtk_menu_bar_new() : gtk_menu_new();
if (menu_type == GTK_TYPE_MENU_BAR)
{
menutree_build_shell(menu_tree, GTK_MENU_SHELL(menu_tree->top_level),
TOP_LEVEL_MENU_ITEMS, NULL);
}
else
{
menutree_build_shell(menu_tree, GTK_MENU_SHELL(menu_tree->top_level),
URI_MENU_ITEMS, TOP_LEVEL_MENU_ITEMS, NULL);
}
submenu = gtk_menu_new();
/*
g_debug("Creating File submenu %p", submenu);
g_signal_connect(submenu, "destroy",
G_CALLBACK(submenu_destroy_handler), NULL);
*/
menutree_build_shell(menu_tree, GTK_MENU_SHELL(submenu),
_("_New Window"), MENUTREE_FILE_NEW_WINDOW,
_("New _Tab"), MENUTREE_FILE_NEW_TAB,
_("New _Window With Profile"), MENUTREE_FILE_NEW_WINDOW_WITH_PROFILE,
_("New Tab With _Profile"), MENUTREE_FILE_NEW_TAB_WITH_PROFILE,
_("C_lose Tab"), MENUTREE_FILE_CLOSE_TAB,
_("_Close Window"), MENUTREE_FILE_CLOSE_WINDOW,
_("_Save Session..."), MENUTREE_FILE_SAVE_SESSION,
NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_FILE]), submenu);
menu_tree->new_win_profiles_menu = gtk_menu_new();
menutree_build_shell(menu_tree,
GTK_MENU_SHELL(menu_tree->new_win_profiles_menu),
_("Profiles"), MENUTREE_FILE_NEW_WINDOW_WITH_PROFILE_HEADER,
"_", MENUTREE_NULL_ID,
NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_FILE_NEW_WINDOW_WITH_PROFILE]),
menu_tree->new_win_profiles_menu);
menu_tree->new_tab_profiles_menu = gtk_menu_new();
menutree_build_shell(menu_tree,
GTK_MENU_SHELL(menu_tree->new_tab_profiles_menu),
_("Profiles"), MENUTREE_FILE_NEW_TAB_WITH_PROFILE_HEADER,
"_", MENUTREE_NULL_ID,
NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_FILE_NEW_TAB_WITH_PROFILE]),
menu_tree->new_tab_profiles_menu);
submenu = gtk_menu_new();
menutree_build_shell(menu_tree, GTK_MENU_SHELL(submenu),
COPY_PASTE_MENU_ITEMS,
_("_Set Window Title..."), MENUTREE_EDIT_SET_WINDOW_TITLE,
RESET_MENU_ITEMS,
"_", MENUTREE_NULL_ID,
_("Res_tart command"), MENUTREE_EDIT_RESPAWN,
NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_EDIT]), submenu);
submenu = gtk_menu_new();
menutree_build_shell(menu_tree, GTK_MENU_SHELL(submenu),
SHOW_MENU_BAR_ITEM,
_("_Always Show Tab Bar"), MENUTREE_VIEW_SHOW_TAB_BAR,
_("_Full Screen"), MENUTREE_VIEW_FULLSCREEN,
"_", MENUTREE_NULL_ID,
_("Zoom _In"), MENUTREE_VIEW_ZOOM_IN,
_("Zoom _Out"), MENUTREE_VIEW_ZOOM_OUT,
_("_Normal Size"), MENUTREE_VIEW_ZOOM_NORM,
"_", MENUTREE_NULL_ID,
_("Scroll _Up One Line"), MENUTREE_VIEW_SCROLL_UP,
_("Scroll _Down One Line"), MENUTREE_VIEW_SCROLL_DOWN,
_("Scroll Up One _Page"), MENUTREE_VIEW_SCROLL_PAGE_UP,
_("Scroll Do_wn One Page"), MENUTREE_VIEW_SCROLL_PAGE_DOWN,
_("Scroll Up One _Half Page"), MENUTREE_VIEW_SCROLL_HALF_PAGE_UP,
_("Scroll Down One Hal_f Page"), MENUTREE_VIEW_SCROLL_HALF_PAGE_DOWN,
_("Scroll To _Top"), MENUTREE_VIEW_SCROLL_TO_TOP,
_("Scroll To _Bottom"), MENUTREE_VIEW_SCROLL_TO_BOTTOM,
NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_VIEW]), submenu);
submenu = gtk_menu_new();
menutree_build_shell(menu_tree, GTK_MENU_SHELL(submenu),
_("_Find..."), MENUTREE_SEARCH_FIND,
_("Find _Next"), MENUTREE_SEARCH_FIND_NEXT,
_("Find _Previous"), MENUTREE_SEARCH_FIND_PREVIOUS,
NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_SEARCH]), submenu);
submenu = gtk_menu_new();
menutree_build_shell(menu_tree, GTK_MENU_SHELL(submenu),
PREFS_ITEMS1,
_("Edi_t Current Shortcuts Scheme"),
MENUTREE_PREFERENCES_EDIT_CURRENT_SHORTCUTS_SCHEME,
PREFS_ITEMS2);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_PREFERENCES]), submenu);
submenu = gtk_menu_new();
menutree_build_shell(menu_tree, GTK_MENU_SHELL(submenu),
_("_Detach Tab"), MENUTREE_TABS_DETACH_TAB,
_("_Close Tab"), MENUTREE_TABS_CLOSE_TAB,
_("Close _Other Tabs"), MENUTREE_TABS_CLOSE_OTHER_TABS,
_("Na_me Tab..."), MENUTREE_TABS_NAME_TAB,
"_", MENUTREE_NULL_ID,
_("_Previous Tab"), MENUTREE_TABS_PREVIOUS_TAB,
_("_Next Tab"), MENUTREE_TABS_NEXT_TAB,
"_", MENUTREE_NULL_ID,
_("Move Tab _Left"), MENUTREE_TABS_MOVE_TAB_LEFT,
_("Move Tab _Right"), MENUTREE_TABS_MOVE_TAB_RIGHT,
"_", MENUTREE_NULL_ID, NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_TABS]), submenu);
submenu = gtk_menu_new();
menutree_build_shell(menu_tree, GTK_MENU_SHELL(submenu),
_("Show _Manual"), MENUTREE_HELP_SHOW_MANUAL,
_("_About ROXTerm"), MENUTREE_HELP_ABOUT, NULL);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_tree->item_widgets
[MENUTREE_HELP]), submenu);
menutree_apply_shortcuts(menu_tree, shortcuts);
}
static void menutree_build_short_popup(MenuTree *menu_tree, Options *shortcuts,
GType menu_type)
{
(void) menu_type;
menu_tree->top_level = gtk_menu_new();
menutree_build_shell(menu_tree, GTK_MENU_SHELL(menu_tree->top_level),
URI_MENU_ITEMS,
COPY_PASTE_MENU_ITEMS,
RESET_MENU_ITEMS,
SHOW_MENU_BAR_ITEM,
ENC_INPUT_ITEMS,
NULL);
menutree_apply_shortcuts(menu_tree, shortcuts);
}
static void menutree_destroy(MenuTree * tree)
{
//g_debug("Destroying menu tree %p", tree);
if (tree->deleted_handler)
tree->deleted_handler(tree, tree->deleted_data);
if (tree->tabs)
g_list_free(tree->tabs);
g_free(tree);
}
static void menutree_destroy_widget_handler(GObject * obj, MenuTree * tree)
{
(void) obj;
//g_debug("Menu %p being destroyed", obj);
tree->top_level = NULL;
/* tree is no good any more so destroy it */
menutree_destroy(tree);
}
static MenuTree *menutree_new_common(Options *shortcuts,
GtkAccelGroup *accel_group,
GType menu_type,
void (*builder)(MenuTree *menu_tree, Options *shortcuts,
GType menu_type),
gboolean disable_shortcuts,
gboolean disable_tab_shortcuts, gpointer user_data)
{
MenuTree *tree = g_new0(MenuTree, 1);
int n;
for (n = 0; n < MENUTREE_NUM_IDS; ++n)
{
tree->item_widgets[n] = NULL;
}
tree->user_data = user_data;
tree->accel_group = accel_group;
tree->disable_shortcuts = disable_shortcuts;
tree->disable_tab_shortcuts = disable_tab_shortcuts;
builder(tree, shortcuts, menu_type);
g_signal_connect(tree->top_level,
"destroy", G_CALLBACK(menutree_destroy_widget_handler), tree);
gtk_widget_show_all(tree->top_level);
return tree;
}
MenuTree *menutree_new(Options *shortcuts, GtkAccelGroup *accel_group,
GType menu_type, gboolean disable_shortcuts,
gboolean disable_tab_shortcuts, gpointer user_data)
{
MenuTree *tree = NULL;
if (!filled_labels)
{
int n;
for (n = 0; n < MENUTREE_NUM_IDS; ++n)
menutree_labels[n] = NULL;
}
tree = menutree_new_common(shortcuts, accel_group, menu_type,
menutree_build, disable_shortcuts, disable_tab_shortcuts, user_data);
/*
g_debug("Created menu %p of type %s", tree->top_level,
menu_type == GTK_TYPE_MENU_BAR ? "bar" : "popup");
*/
filled_labels = TRUE;
return tree;
}
MenuTree *menutree_new_short_popup(Options *shortcuts,
GtkAccelGroup *accel_group, gboolean disable_shortcuts,
gpointer user_data)
{
MenuTree *tree = menutree_new_common(shortcuts, accel_group, GTK_TYPE_MENU,
menutree_build_short_popup, disable_shortcuts, FALSE, user_data);
//g_debug("Created short popup menu %p", tree->top_level);
return tree;
}
void menutree_delete(MenuTree * tree)
{
g_return_if_fail(tree != NULL);
if (tree->top_level)
{
gtk_widget_destroy(tree->top_level);
}
else
{
menutree_destroy(tree);
}
}
void
menutree_connect_destroyed(MenuTree * tree,
GCallback callback, gpointer user_data)
{
tree->deleted_handler = (void (*)(MenuTree *, gpointer)) callback;
tree->deleted_data = user_data;
}
void menutree_find_radio_group(GtkWidget *widget, gpointer data)
{
GSList **pgroup = data;
if (g_type_is_a(G_OBJECT_TYPE(G_OBJECT(widget)), GTK_TYPE_RADIO_MENU_ITEM))
*pgroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(widget));
}
inline static GtkMenuShell *menutree_get_submenu_at_id(MenuTree *tree, int id)
{
return GTK_MENU_SHELL(gtk_menu_item_get_submenu(
GTK_MENU_ITEM(tree->item_widgets[id])));
}
static void menutree_remove_tab_without_fixing_accels(MenuTree *tree,
GtkWidget *menu_item)
{
gtk_widget_destroy(menu_item);
tree->tabs = g_list_remove(tree->tabs, menu_item);
--tree->ntabs;
}
void menutree_remove_tab(MenuTree *tree, GtkWidget *menu_item)
{
menutree_remove_tab_without_fixing_accels(tree, menu_item);
menutree_apply_tab_shortcuts(tree);
}
static GtkWidget *menutree_tab_menu_item_new(GtkMenuShell *menu,
const char *title)
{
/* GtkCheckMenuItem is actually easier to manage than GtkRadioMenuItem due
* to difficulty of keeping track of group when deleting radio menu items
*/
GtkWidget *menu_item;
GSList *group = NULL;
gtk_container_foreach(GTK_CONTAINER(menu), menutree_find_radio_group,
&group);
menu_item = gtk_radio_menu_item_new_with_label(group, title);
gtk_widget_show(menu_item);
return menu_item;
}
GtkWidget *menutree_add_tab_at_position(MenuTree * tree, const char *title,
int position)
{
GtkMenuShell *submenu = menutree_get_submenu_at_id(tree, MENUTREE_TABS);
GtkWidget *menu_item = menutree_tab_menu_item_new(submenu, title);
if (position == -1)
{
gtk_menu_shell_append(submenu, menu_item);
tree->tabs = g_list_append(tree->tabs, menu_item);
position = tree->ntabs;
}
else
{
gtk_menu_shell_insert(submenu, menu_item,
position + MENUTREE_TABS_FIRST_DYNAMIC);
tree->tabs = g_list_insert(tree->tabs, menu_item, position);
}
++tree->ntabs;
menutree_apply_tab_shortcuts(tree);
return menu_item;
}
static void menu_item_change_label(GtkMenuItem *item, const char *label)
{
GtkWidget *inner_item = gtk_bin_get_child(GTK_BIN(item));
if (GTK_IS_LABEL(inner_item))
{
gtk_label_set_text_with_mnemonic(GTK_LABEL(inner_item), label);
}
else if (GTK_IS_CONTAINER(inner_item))
{
GList *link;
for (link = gtk_container_get_children(GTK_CONTAINER(inner_item));
link; link = g_list_next(link))
{
GtkWidget *child = link->data;
if (GTK_IS_LABEL(child))
{
gtk_label_set_text_with_mnemonic(GTK_LABEL(child), label);
return;
}
}
}
}
inline static void menutree_change_label(MenuTree *tree, MenuTreeID id,
const char *label)
{
menu_item_change_label(GTK_MENU_ITEM(menutree_get_widget_for_id(tree, id)),
label);
}
GtkWidget *menutree_change_tab_title(MenuTree * tree,
GtkWidget * menu_item, const char *title)
{
(void) tree;
menu_item_change_label(GTK_MENU_ITEM(menu_item), title);
return menu_item;
}
void menutree_change_move_tab_labels(MenuTree *tree)
{
menutree_change_label(tree, MENUTREE_TABS_MOVE_TAB_LEFT,
_("Move Tab _Up"));
menutree_change_label(tree, MENUTREE_TABS_MOVE_TAB_RIGHT,
_("Move Tab _Down"));
}
static void menutree_set_toggle(MenuTree *tree, MenuTreeID id, gboolean active)
{
GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM
(menutree_get_widget_for_id(tree, id));
if (active != gtk_check_menu_item_get_active(item))
{
gtk_check_menu_item_set_active(item, active);
}
}
void menutree_set_show_menu_bar_active(MenuTree *tree, gboolean active)
{
menutree_set_toggle(tree, MENUTREE_VIEW_SHOW_MENUBAR, active);
}
void menutree_set_show_tab_bar_active(MenuTree *tree, gboolean active)
{
menutree_set_toggle(tree, MENUTREE_VIEW_SHOW_TAB_BAR, active);
}
void menutree_set_fullscreen_active(MenuTree *tree, gboolean active)
{
menutree_set_toggle(tree, MENUTREE_VIEW_FULLSCREEN, active);
}
extern void multi_win_new_tab_action(gpointer win);
gulong menutree_named_signal_connect_data(MenuTree * tree, MenuTreeID id,
const char *signame, GCallback handler, gpointer user_data,
GConnectFlags flags)
{
GtkWidget *menu_item;
g_return_val_if_fail(tree, 0);
menu_item = menutree_get_widget_for_id(tree, id);
if (!menu_item)
return 0;
return g_signal_connect_data(menu_item, signame, handler, user_data,
NULL, flags);
}
void menutree_set_show_item(MenuTree * tree, MenuTreeID id, gboolean show)
{
GtkWidget *item = menutree_get_widget_for_id(tree, id);
if (show)
gtk_widget_show(item);
else
gtk_widget_hide(item);
}
void menutree_disable_shortcuts(MenuTree *tree, gboolean disable)
{
int n;
if (tree->disable_shortcuts == disable)
return;
tree->disable_shortcuts = disable;
for (n = 0; n < MENUTREE_NUM_IDS; ++n)
{
if (tree->item_widgets[n] && menutree_labels[n])
{
GtkWidget *child;
child = gtk_bin_get_child(GTK_BIN(tree->item_widgets[n]));
if (child && GTK_IS_LABEL(child))
{
if (disable)
{
char *stripped = strip_underscore(menutree_labels[n]);
gtk_label_set_text(GTK_LABEL(child), stripped);
g_free(stripped);
}
else
{
gtk_label_set_text_with_mnemonic(GTK_LABEL(child),
menutree_labels[n]);
}
}
}
}
}
void menutree_disable_tab_shortcuts(MenuTree *tree, gboolean disable)
{
if (tree->disable_tab_shortcuts == disable)
return;
tree->disable_tab_shortcuts = disable;
menutree_apply_tab_shortcuts(tree);
}
/* vi:set sw=4 ts=4 et cindent cino= */