/* X-Chat * Copyright (C) 1998-2007 Peter Zelezny. * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #ifdef WIN32 #include #include #else #include #endif #include "fe-gtk.h" #include #include "../common/hexchat.h" #include "../common/hexchatc.h" #include "../common/cfgfiles.h" #include "../common/outbound.h" #include "../common/ignore.h" #include "../common/fe.h" #include "../common/server.h" #include "../common/servlist.h" #include "../common/notify.h" #include "../common/util.h" #include "../common/text.h" #include "xtext.h" #include "ascii.h" #include "banlist.h" #include "chanlist.h" #include "editlist.h" #include "fkeys.h" #include "gtkutil.h" #include "maingui.h" #include "notifygui.h" #include "pixmaps.h" #include "rawlog.h" #include "palette.h" #include "plugingui.h" #include "search.h" #include "textgui.h" #include "urlgrab.h" #include "userlistgui.h" #include "menu.h" #include "servlistgui.h" static GSList *submenu_list; enum { M_MENUITEM, M_NEWMENU, M_END, M_SEP, M_MENUTOG, M_MENURADIO, M_MENUSTOCK, M_MENUPIX, M_MENUSUB }; struct mymenu { char *text; void *callback; char *image; unsigned char type; /* M_XXX */ unsigned char id; /* MENU_ID_XXX (menu.h) */ unsigned char state; /* ticked or not? */ unsigned char sensitive; /* shaded out? */ guint key; /* GDK_KEY_x */ }; #define XCMENU_DOLIST 1 #define XCMENU_SHADED 1 #define XCMENU_MARKUP 2 #define XCMENU_MNEMONIC 4 /* execute a userlistbutton/popupmenu command */ static void nick_command (session * sess, char *cmd) { if (*cmd == '!') hexchat_exec (cmd + 1); else handle_command (sess, cmd, TRUE); } /* fill in the %a %s %n etc and execute the command */ void nick_command_parse (session *sess, char *cmd, char *nick, char *allnick) { char *buf; char *host = _("Host unknown"); char *account = _("Account unknown"); struct User *user; int len; /* if (sess->type == SESS_DIALOG) { buf = (char *)(GTK_ENTRY (sess->gui->topic_entry)->text); buf = strrchr (buf, '@'); if (buf) host = buf + 1; } else*/ { user = userlist_find (sess, nick); if (user) { if (user->hostname) host = strchr (user->hostname, '@') + 1; if (user->account) account = user->account; } } /* this can't overflow, since popup->cmd is only 256 */ len = strlen (cmd) + strlen (nick) + strlen (allnick) + 512; buf = g_malloc (len); auto_insert (buf, len, cmd, 0, 0, allnick, sess->channel, "", server_get_network (sess->server, TRUE), host, sess->server->nick, nick, account); nick_command (sess, buf); g_free (buf); } /* userlist button has been clicked */ void userlist_button_cb (GtkWidget * button, char *cmd) { int i, num_sel, using_allnicks = FALSE; char **nicks, *allnicks; char *nick = NULL; session *sess; sess = current_sess; if (strstr (cmd, "%a")) using_allnicks = TRUE; if (sess->type == SESS_DIALOG) { /* fake a selection */ nicks = g_new (char *, 2); nicks[0] = g_strdup (sess->channel); nicks[1] = NULL; num_sel = 1; } else { /* find number of selected rows */ nicks = userlist_selection_list (sess->gui->user_tree, &num_sel); if (num_sel < 1) { nick_command_parse (sess, cmd, "", ""); g_free (nicks); return; } } /* create "allnicks" string */ allnicks = g_malloc (((NICKLEN + 1) * num_sel) + 1); *allnicks = 0; i = 0; while (nicks[i]) { if (i > 0) strcat (allnicks, " "); strcat (allnicks, nicks[i]); if (!nick) nick = nicks[0]; /* if not using "%a", execute the command once for each nickname */ if (!using_allnicks) nick_command_parse (sess, cmd, nicks[i], ""); i++; } if (using_allnicks) { if (!nick) nick = ""; nick_command_parse (sess, cmd, nick, allnicks); } while (num_sel) { num_sel--; g_free (nicks[num_sel]); } g_free (nicks); g_free (allnicks); } /* a popup-menu-item has been selected */ static void popup_menu_cb (GtkWidget * item, char *cmd) { char *nick; /* the userdata is set in menu_quick_item() */ nick = g_object_get_data (G_OBJECT (item), "u"); if (!nick) /* userlist popup menu */ { /* treat it just like a userlist button */ userlist_button_cb (NULL, cmd); return; } if (!current_sess) /* for url grabber window */ nick_command_parse (sess_list->data, cmd, nick, nick); else nick_command_parse (current_sess, cmd, nick, nick); } GtkWidget * menu_toggle_item (char *label, GtkWidget *menu, void *callback, void *userdata, int state) { GtkWidget *item; item = gtk_check_menu_item_new_with_mnemonic (label); gtk_check_menu_item_set_active ((GtkCheckMenuItem*)item, state); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback), userdata); gtk_widget_show (item); return item; } GtkWidget * menu_quick_item (char *cmd, char *label, GtkWidget * menu, int flags, gpointer userdata, char *icon) { GtkWidget *img, *item; char *path; if (!label) item = gtk_menu_item_new (); else { if (icon) { /*if (flags & XCMENU_MARKUP) item = gtk_image_menu_item_new_with_markup (label); else*/ item = gtk_image_menu_item_new_with_mnemonic (label); img = NULL; if (access (icon, R_OK) == 0) /* try fullpath */ img = gtk_image_new_from_file (icon); else { /* try relative to */ path = g_build_filename (get_xdir (), icon, NULL); if (access (path, R_OK) == 0) img = gtk_image_new_from_file (path); else img = gtk_image_new_from_stock (icon, GTK_ICON_SIZE_MENU); g_free (path); } if (img) gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img); } else { if (flags & XCMENU_MARKUP) { item = gtk_menu_item_new_with_label (""); if (flags & XCMENU_MNEMONIC) gtk_label_set_markup_with_mnemonic (GTK_LABEL (GTK_BIN (item)->child), label); else gtk_label_set_markup (GTK_LABEL (GTK_BIN (item)->child), label); } else { if (flags & XCMENU_MNEMONIC) item = gtk_menu_item_new_with_mnemonic (label); else item = gtk_menu_item_new_with_label (label); } } } gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_object_set_data (G_OBJECT (item), "u", userdata); if (cmd) g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (popup_menu_cb), cmd); if (flags & XCMENU_SHADED) gtk_widget_set_sensitive (GTK_WIDGET (item), FALSE); gtk_widget_show_all (item); return item; } static void menu_quick_item_with_callback (void *callback, char *label, GtkWidget * menu, void *arg) { GtkWidget *item; item = gtk_menu_item_new_with_label (label); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback), arg); gtk_widget_show (item); } GtkWidget * menu_quick_sub (char *name, GtkWidget *menu, GtkWidget **sub_item_ret, int flags, int pos) { GtkWidget *sub_menu; GtkWidget *sub_item; if (!name) return menu; /* Code to add a submenu */ sub_menu = gtk_menu_new (); if (flags & XCMENU_MARKUP) { sub_item = gtk_menu_item_new_with_label (""); gtk_label_set_markup (GTK_LABEL (GTK_BIN (sub_item)->child), name); } else { if (flags & XCMENU_MNEMONIC) sub_item = gtk_menu_item_new_with_mnemonic (name); else sub_item = gtk_menu_item_new_with_label (name); } gtk_menu_shell_insert (GTK_MENU_SHELL (menu), sub_item, pos); gtk_widget_show (sub_item); gtk_menu_item_set_submenu (GTK_MENU_ITEM (sub_item), sub_menu); if (sub_item_ret) *sub_item_ret = sub_item; if (flags & XCMENU_DOLIST) /* We create a new element in the list */ submenu_list = g_slist_prepend (submenu_list, sub_menu); return sub_menu; } static GtkWidget * menu_quick_endsub (void) { /* Just delete the first element in the linked list pointed to by first */ if (submenu_list) submenu_list = g_slist_remove (submenu_list, submenu_list->data); if (submenu_list) return (submenu_list->data); else return NULL; } static void toggle_cb (GtkWidget *item, char *pref_name) { char buf[256]; if (GTK_CHECK_MENU_ITEM (item)->active) g_snprintf (buf, sizeof (buf), "set %s 1", pref_name); else g_snprintf (buf, sizeof (buf), "set %s 0", pref_name); handle_command (current_sess, buf, FALSE); } static int is_in_path (char *cmd) { char *orig = g_strdup (cmd + 1); /* 1st char is "!" */ char *prog = orig; char **argv; int argc; /* special-case these default entries. */ /* 123456789012345678 */ if (strncmp (prog, "gnome-terminal -x ", 18) == 0) /* don't check for gnome-terminal, but the thing it's executing! */ prog += 18; if (g_shell_parse_argv (prog, &argc, &argv, NULL)) { char *path = g_find_program_in_path (argv[0]); g_strfreev (argv); if (path) { g_free (path); g_free (orig); return 1; } } g_free (orig); return 0; } /* syntax: "LABEL~ICON~STUFF~ADDED~LATER~" */ static void menu_extract_icon (char *name, char **label, char **icon) { char *p = name; char *start = NULL; char *end = NULL; while (*p) { if (*p == '~') { /* escape \~ */ if (p == name || p[-1] != '\\') { if (!start) start = p + 1; else if (!end) end = p + 1; } } p++; } if (!end) end = p; if (start && start != end) { *label = g_strndup (name, (start - name) - 1); *icon = g_strndup (start, (end - start) - 1); } else { *label = g_strdup (name); *icon = NULL; } } /* append items to "me
// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

// NOTE: Do not modify the contents of this file.  If this class is regenerated by
//  Microsoft Visual C++, your modifications will be overwritten.


#include "stdafx.h"
#include "wmpsettings.h"


/////////////////////////////////////////////////////////////////////////////
// CWMPSettings properties

/////////////////////////////////////////////////////////////////////////////
// CWMPSettings operations

BOOL CWMPSettings::GetIsAvailable(LPCTSTR bstrItem)
{
	BOOL result;
	static BYTE parms[] =
		VTS_BSTR;
	InvokeHelper(0x71, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, parms,
		bstrItem);
	return result;
}

BOOL CWMPSettings::GetAutoStart()
{
	BOOL result;
	InvokeHelper(0x65, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetAutoStart(BOOL bNewValue)
{
	static BYTE parms[] =
		VTS_BOOL;
	InvokeHelper(0x65, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 bNewValue);
}

CString CWMPSettings::GetBaseURL()
{
	CString result;
	InvokeHelper(0x6c, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetBaseURL(LPCTSTR lpszNewValue)
{
	static BYTE parms[] =
		VTS_BSTR;
	InvokeHelper(0x6c, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 lpszNewValue);
}

CString CWMPSettings::GetDefaultFrame()
{
	CString result;
	InvokeHelper(0x6d, DISPATCH_PROPERTYGET, VT_BSTR, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetDefaultFrame(LPCTSTR lpszNewValue)
{
	static BYTE parms[] =
		VTS_BSTR;
	InvokeHelper(0x6d, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 lpszNewValue);
}

BOOL CWMPSettings::GetInvokeURLs()
{
	BOOL result;
	InvokeHelper(0x67, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetInvokeURLs(BOOL bNewValue)
{
	static BYTE parms[] =
		VTS_BOOL;
	InvokeHelper(0x67, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 bNewValue);
}

BOOL CWMPSettings::GetMute()
{
	BOOL result;
	InvokeHelper(0x68, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetMute(BOOL bNewValue)
{
	static BYTE parms[] =
		VTS_BOOL;
	InvokeHelper(0x68, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 bNewValue);
}

long CWMPSettings::GetPlayCount()
{
	long result;
	InvokeHelper(0x69, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetPlayCount(long nNewValue)
{
	static BYTE parms[] =
		VTS_I4;
	InvokeHelper(0x69, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 nNewValue);
}

double CWMPSettings::GetRate()
{
	double result;
	InvokeHelper(0x6a, DISPATCH_PROPERTYGET, VT_R8, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetRate(double newValue)
{
	static BYTE parms[] =
		VTS_R8;
	InvokeHelper(0x6a, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 newValue);
}

long CWMPSettings::GetBalance()
{
	long result;
	InvokeHelper(0x66, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetBalance(long nNewValue)
{
	static BYTE parms[] =
		VTS_I4;
	InvokeHelper(0x66, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 nNewValue);
}

long CWMPSettings::GetVolume()
{
	long result;
	InvokeHelper(0x6b, DISPATCH_PROPERTYGET, VT_I4, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetVolume(long nNewValue)
{
	static BYTE parms[] =
		VTS_I4;
	InvokeHelper(0x6b, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 nNewValue);
}

BOOL CWMPSettings::getMode(LPCTSTR bstrMode)
{
	BOOL result;
	static BYTE parms[] =
		VTS_BSTR;
	InvokeHelper(0x6e, DISPATCH_METHOD, VT_BOOL, (void*)&result, parms,
		bstrMode);
	return result;
}

void CWMPSettings::setMode(LPCTSTR bstrMode, BOOL varfMode)
{
	static BYTE parms[] =
		VTS_BSTR VTS_BOOL;
	InvokeHelper(0x6f, DISPATCH_METHOD, VT_EMPTY, NULL, parms,
		 bstrMode, varfMode);
}

BOOL CWMPSettings::GetEnableErrorDialogs()
{
	BOOL result;
	InvokeHelper(0x70, DISPATCH_PROPERTYGET, VT_BOOL, (void*)&result, NULL);
	return result;
}

void CWMPSettings::SetEnableErrorDialogs(BOOL bNewValue)
{
	static BYTE parms[] =
		VTS_BOOL;
	InvokeHelper(0x70, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, parms,
		 bNewValue);
}
0, 0, M_NEWMENU, 0, 0, 1}, #define MENUBAR_OFFSET (17) {N_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1, GDK_KEY_F9}, {N_("_Topic Bar"), menu_topicbar_toggle, 0, M_MENUTOG, MENU_ID_TOPICBAR, 0, 1}, {N_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1, GDK_KEY_F7}, {N_("U_serlist Buttons"), menu_ulbuttons_toggle, 0, M_MENUTOG, MENU_ID_ULBUTTONS, 0, 1}, {N_("M_ode Buttons"), menu_cmbuttons_toggle, 0, M_MENUTOG, MENU_ID_MODEBUTTONS, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("_Channel Switcher"), 0, 0, M_MENUSUB, 0, 0, 1}, /* 23 */ #define TABS_OFFSET (24) {N_("_Tabs"), menu_layout_cb, 0, M_MENURADIO, MENU_ID_LAYOUT_TABS, 0, 1}, {N_("T_ree"), 0, 0, M_MENURADIO, MENU_ID_LAYOUT_TREE, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, {N_("_Network Meters"), 0, 0, M_MENUSUB, 0, 0, 1}, /* 27 */ #define METRE_OFFSET (28) {N_("Off"), menu_metres_off, 0, M_MENURADIO, 0, 0, 1}, {N_("Graph"), menu_metres_graph, 0, M_MENURADIO, 0, 0, 1}, {N_("Text"), menu_metres_text, 0, M_MENURADIO, 0, 0, 1}, {N_("Both"), menu_metres_both, 0, M_MENURADIO, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, /* 32 */ { 0, 0, 0, M_SEP, 0, 0, 0 }, {N_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1, GDK_KEY_F11}, {N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1}, {N_("_Disconnect"), menu_disconnect, GTK_STOCK_DISCONNECT, M_MENUSTOCK, MENU_ID_DISCONNECT, 0, 1}, {N_("_Reconnect"), menu_reconnect, GTK_STOCK_CONNECT, M_MENUSTOCK, MENU_ID_RECONNECT, 0, 1}, {N_("_Join a Channel..."), menu_join, GTK_STOCK_JUMP_TO, M_MENUSTOCK, MENU_ID_JOIN, 0, 1}, {N_("_List of Channels..."), menu_chanlist, GTK_STOCK_INDEX, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, #define AWAY_OFFSET (41) {N_("Marked _Away"), menu_away, 0, M_MENUTOG, MENU_ID_AWAY, 0, 1, GDK_KEY_a}, {N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 40 */ {N_("S_ettings"), 0, 0, M_NEWMENU, 0, 0, 1}, {N_("_Preferences"), menu_settings, GTK_STOCK_PREFERENCES, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("Auto Replace..."), menu_rpopup, 0, M_MENUITEM, 0, 0, 1}, {N_("CTCP Replies..."), menu_ctcpguiopen, 0, M_MENUITEM, 0, 0, 1}, {N_("Dialog Buttons..."), menu_dlgbuttons, 0, M_MENUITEM, 0, 0, 1}, {N_("Keyboard Shortcuts..."), menu_keypopup, 0, M_MENUITEM, 0, 0, 1}, {N_("Text Events..."), menu_evtpopup, 0, M_MENUITEM, 0, 0, 1}, {N_("URL Handlers..."), menu_urlhandlers, 0, M_MENUITEM, 0, 0, 1}, {N_("User Commands..."), menu_usercommands, 0, M_MENUITEM, 0, 0, 1}, {N_("Userlist Buttons..."), menu_ulbuttons, 0, M_MENUITEM, 0, 0, 1}, {N_("Userlist Popup..."), menu_ulpopup, 0, M_MENUITEM, 0, 0, 1}, /* 52 */ {N_("_Window"), 0, 0, M_NEWMENU, 0, 0, 1}, {N_("_Ban List..."), menu_banlist, 0, M_MENUITEM, 0, 0, 1}, {N_("Character Chart..."), ascii_open, 0, M_MENUITEM, 0, 0, 1}, {N_("Direct Chat..."), menu_dcc_chat_win, 0, M_MENUITEM, 0, 0, 1}, {N_("File _Transfers..."), menu_dcc_win, 0, M_MENUITEM, 0, 0, 1}, {N_("Friends List..."), notify_opengui, 0, M_MENUITEM, 0, 0, 1}, {N_("Ignore List..."), ignore_gui_open, 0, M_MENUITEM, 0, 0, 1}, {N_("_Plugins and Scripts..."), menu_pluginlist, 0, M_MENUITEM, 0, 0, 1}, {N_("_Raw Log..."), menu_rawlog, 0, M_MENUITEM, 0, 0, 1}, /* 61 */ {N_("URL Grabber..."), url_opengui, 0, M_MENUITEM, 0, 0, 1}, {0, 0, 0, M_SEP, 0, 0, 0}, {N_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_m}, {N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_M}, {N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_C}, {N_("C_lear Text"), menu_flushbuffer, GTK_STOCK_CLEAR, M_MENUSTOCK, 0, 0, 1}, {N_("Save Text..."), menu_savebuffer, GTK_STOCK_SAVE, M_MENUSTOCK, 0, 0, 1}, #define SEARCH_OFFSET (70) {N_("Search"), 0, GTK_STOCK_JUSTIFY_LEFT, M_MENUSUB, 0, 0, 1}, {N_("Search Text..."), menu_search, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_f}, {N_("Search Next" ), menu_search_next, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_g}, {N_("Search Previous" ), menu_search_prev, GTK_STOCK_FIND, M_MENUSTOCK, 0, 0, 1, GDK_KEY_G}, {0, 0, 0, M_END, 0, 0, 0}, {N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */ {N_("_Contents"), menu_docs, GTK_STOCK_HELP, M_MENUSTOCK, 0, 0, 1, GDK_KEY_F1}, {N_("_About"), menu_about, GTK_STOCK_ABOUT, M_MENUSTOCK, 0, 0, 1}, {0, 0, 0, M_END, 0, 0, 0}, }; void menu_set_away (session_gui *gui, int away) { GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (gui->menu_item[MENU_ID_AWAY]); g_signal_handlers_block_by_func (G_OBJECT (item), menu_away, NULL); gtk_check_menu_item_set_active (item, away); g_signal_handlers_unblock_by_func (G_OBJECT (item), menu_away, NULL); } void menu_set_fullscreen (session_gui *gui, int full) { GtkCheckMenuItem *item = GTK_CHECK_MENU_ITEM (gui->menu_item[MENU_ID_FULLSCREEN]); g_signal_handlers_block_by_func (G_OBJECT (item), menu_fullscreen_toggle, NULL); gtk_check_menu_item_set_active (item, full); g_signal_handlers_unblock_by_func (G_OBJECT (item), menu_fullscreen_toggle, NULL); } GtkWidget * create_icon_menu (char *labeltext, void *stock_name, int is_stock) { GtkWidget *item, *img; if (is_stock) img = gtk_image_new_from_stock (stock_name, GTK_ICON_SIZE_MENU); else img = gtk_image_new_from_pixbuf (*((GdkPixbuf **)stock_name)); item = gtk_image_menu_item_new_with_mnemonic (labeltext); gtk_image_menu_item_set_image ((GtkImageMenuItem *)item, img); gtk_widget_show (img); return item; } /* Override the default GTK2.4 handler, which would make menu bindings not work when the menu-bar is hidden. */ static gboolean menu_canacaccel (GtkWidget *widget, guint signal_id, gpointer user_data) { /* GTK2.2 behaviour */ return gtk_widget_is_sensitive (widget); } /* === STUFF FOR /MENU === */ static GtkMenuItem * menu_find_item (GtkWidget *menu, char *name) { GList *items = ((GtkMenuShell *) menu)->children; GtkMenuItem *item; GtkWidget *child; const char *labeltext; while (items) { item = items->data; child = GTK_BIN (item)->child; if (child) /* separators arn't labels, skip them */ { labeltext = g_object_get_data (G_OBJECT (item), "name"); if (!labeltext) labeltext = gtk_label_get_text (GTK_LABEL (child)); if (!menu_streq (labeltext, name, 1)) return item; } else if (name == NULL) { return item; } items = items->next; } return NULL; } static GtkWidget * menu_find_path (GtkWidget *menu, char *path) { GtkMenuItem *item; char *s; char name[128]; int len; /* grab the next part of the path */ s = strchr (path, '/'); len = s - path; if (!s) len = strlen (path); len = MIN (len, sizeof (name) - 1); memcpy (name, path, len); name[len] = 0; item = menu_find_item (menu, name); if (!item) return NULL; menu = gtk_menu_item_get_submenu (item); if (!menu) return NULL; path += len; if (*path == 0) return menu; return menu_find_path (menu, path + 1); } static GtkWidget * menu_find (GtkWidget *menu, char *path, char *label) { GtkWidget *item = NULL; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) item = (GtkWidget *)menu_find_item (menu, label); return item; } static void menu_foreach_gui (menu_entry *me, void (*callback) (GtkWidget *, menu_entry *, char *)) { GSList *list = sess_list; int tabdone = FALSE; session *sess; if (!me->is_main) return; /* not main menu */ while (list) { sess = list->data; /* do it only once for tab sessions, since they share a GUI */ if (!sess->gui->is_tab || !tabdone) { callback (sess->gui->menu, me, NULL); if (sess->gui->is_tab) tabdone = TRUE; } list = list->next; } } static void menu_update_cb (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item; item = menu_find (menu, me->path, me->label); if (item) { gtk_widget_set_sensitive (item, me->enable); /* must do it without triggering the callback */ if (GTK_IS_CHECK_MENU_ITEM (item)) GTK_CHECK_MENU_ITEM (item)->active = me->state; } } /* radio state changed via mouse click */ static void menu_radio_cb (GtkCheckMenuItem *item, menu_entry *me) { me->state = 0; if (item->active) me->state = 1; /* update the state, incase this was changed via right-click. */ /* This will update all other windows and menu bars */ menu_foreach_gui (me, menu_update_cb); if (me->state && me->cmd) handle_command (current_sess, me->cmd, FALSE); } /* toggle state changed via mouse click */ static void menu_toggle_cb (GtkCheckMenuItem *item, menu_entry *me) { me->state = 0; if (item->active) me->state = 1; /* update the state, incase this was changed via right-click. */ /* This will update all other windows and menu bars */ menu_foreach_gui (me, menu_update_cb); if (me->state) handle_command (current_sess, me->cmd, FALSE); else handle_command (current_sess, me->ucmd, FALSE); } static GtkWidget * menu_radio_item (char *label, GtkWidget *menu, void *callback, void *userdata, int state, char *groupname) { GtkWidget *item; GtkMenuItem *parent; GSList *grouplist = NULL; parent = menu_find_item (menu, groupname); if (parent) grouplist = gtk_radio_menu_item_get_group ((GtkRadioMenuItem *)parent); item = gtk_radio_menu_item_new_with_label (grouplist, label); gtk_check_menu_item_set_active ((GtkCheckMenuItem*)item, state); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (callback), userdata); gtk_widget_show (item); return item; } static void menu_reorder (GtkMenu *menu, GtkWidget *item, int pos) { if (pos == 0xffff) /* outbound.c uses this default */ return; if (pos < 0) /* position offset from end/bottom */ gtk_menu_reorder_child (menu, item, (g_list_length (GTK_MENU_SHELL (menu)->children) + pos) - 1); else gtk_menu_reorder_child (menu, item, pos); } static GtkWidget * menu_add_radio (GtkWidget *menu, menu_entry *me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { item = menu_radio_item (me->label, menu, menu_radio_cb, me, me->state, me->group); menu_reorder (GTK_MENU (menu), item, me->pos); } return item; } static GtkWidget * menu_add_toggle (GtkWidget *menu, menu_entry *me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { item = menu_toggle_item (me->label, menu, menu_toggle_cb, me, me->state); menu_reorder (GTK_MENU (menu), item, me->pos); } return item; } static GtkWidget * menu_add_item (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { item = menu_quick_item (me->cmd, me->label, menu, me->markup ? XCMENU_MARKUP|XCMENU_MNEMONIC : XCMENU_MNEMONIC, target, me->icon); menu_reorder (GTK_MENU (menu), item, me->pos); } return item; } static GtkWidget * menu_add_sub (GtkWidget *menu, menu_entry *me) { GtkWidget *item = NULL; char *path = me->path + me->root_offset; int pos; if (path[0] != 0) menu = menu_find_path (menu, path); if (menu) { pos = me->pos; if (pos < 0) /* position offset from end/bottom */ pos = g_list_length (GTK_MENU_SHELL (menu)->children) + pos; menu_quick_sub (me->label, menu, &item, me->markup ? XCMENU_MARKUP|XCMENU_MNEMONIC : XCMENU_MNEMONIC, pos); } return item; } static void menu_del_cb (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item = menu_find (menu, me->path + me->root_offset, me->label); if (item) gtk_widget_destroy (item); } static void menu_add_cb (GtkWidget *menu, menu_entry *me, char *target) { GtkWidget *item; GtkAccelGroup *accel_group; if (me->group) /* have a group name? Must be a radio item */ item = menu_add_radio (menu, me); else if (me->ucmd) /* have unselect-cmd? Must be a toggle item */ item = menu_add_toggle (menu, me); else if (me->cmd || !me->label) /* label=NULL for separators */ item = menu_add_item (menu, me, target); else item = menu_add_sub (menu, me); if (item) { gtk_widget_set_sensitive (item, me->enable); if (me->key) { accel_group = g_object_get_data (G_OBJECT (menu), "accel"); if (accel_group) /* popup menus don't have them */ gtk_widget_add_accelerator (item, "activate", accel_group, me->key, me->modifier, GTK_ACCEL_VISIBLE); } } } char * fe_menu_add (menu_entry *me) { char *text; menu_foreach_gui (me, menu_add_cb); if (!me->markup) return NULL; if (!pango_parse_markup (me->label, -1, 0, NULL, &text, NULL, NULL)) return NULL; /* return the label with markup stripped */ return text; } void fe_menu_del (menu_entry *me) { menu_foreach_gui (me, menu_del_cb); } void fe_menu_update (menu_entry *me) { menu_foreach_gui (me, menu_update_cb); } /* used to add custom menus to the right-click menu */ static void menu_add_plugin_mainmenu_items (GtkWidget *menu) { GSList *list; menu_entry *me; list = menu_list; /* outbound.c */ while (list) { me = list->data; if (me->is_main) menu_add_cb (menu, me, NULL); list = list->next; } } void menu_add_plugin_items (GtkWidget *menu, char *root, char *target) { GSList *list; menu_entry *me; list = menu_list; /* outbound.c */ while (list) { me = list->data; if (!me->is_main && !strncmp (me->path, root + 1, root[0])) menu_add_cb (menu, me, target); list = list->next; } } /* === END STUFF FOR /MENU === */ GtkWidget * menu_create_main (void *accel_group, int bar, int away, int toplevel, GtkWidget **menu_widgets) { int i = 0; GtkWidget *item; GtkWidget *menu = 0; GtkWidget *menu_item = 0; GtkWidget *menu_bar; GtkWidget *usermenu = 0; GtkWidget *submenu = 0; int close_mask = STATE_CTRL; int away_mask = STATE_ALT; char *key_theme = NULL; GtkSettings *settings; GSList *group = NULL; #ifdef HAVE_GTK_MAC int appmenu_offset = 1; /* 0 is for about */ #endif if (bar) { menu_bar = gtk_menu_bar_new (); #ifdef HAVE_GTK_MAC gtkosx_application_set_menu_bar (osx_app, GTK_MENU_SHELL (menu_bar)); #endif } else menu_bar = gtk_menu_new (); /* /MENU needs to know this later */ g_object_set_data (G_OBJECT (menu_bar), "accel", accel_group); g_signal_connect (G_OBJECT (menu_bar), "can-activate-accel", G_CALLBACK (menu_canacaccel), 0); /* set the initial state of toggles */ mymenu[MENUBAR_OFFSET].state = !prefs.hex_gui_hide_menu; mymenu[MENUBAR_OFFSET+1].state = prefs.hex_gui_topicbar; mymenu[MENUBAR_OFFSET+2].state = !prefs.hex_gui_ulist_hide; mymenu[MENUBAR_OFFSET+3].state = prefs.hex_gui_ulist_buttons; mymenu[MENUBAR_OFFSET+4].state = prefs.hex_gui_mode_buttons; mymenu[AWAY_OFFSET].state = away; switch (prefs.hex_gui_tab_layout) { case 0: mymenu[TABS_OFFSET].state = 1; mymenu[TABS_OFFSET+1].state = 0; break; default: mymenu[TABS_OFFSET].state = 0; mymenu[TABS_OFFSET+1].state = 1; } mymenu[METRE_OFFSET].state = 0; mymenu[METRE_OFFSET+1].state = 0; mymenu[METRE_OFFSET+2].state = 0; mymenu[METRE_OFFSET+3].state = 0; switch (prefs.hex_gui_lagometer) { case 0: mymenu[METRE_OFFSET].state = 1; break; case 1: mymenu[METRE_OFFSET+1].state = 1; break; case 2: mymenu[METRE_OFFSET+2].state = 1; break; default: mymenu[METRE_OFFSET+3].state = 1; } /* change Close binding to ctrl-shift-w when using emacs keys */ settings = gtk_widget_get_settings (menu_bar); if (settings) { g_object_get (settings, "gtk-key-theme-name", &key_theme, NULL); if (key_theme) { if (!g_ascii_strcasecmp (key_theme, "Emacs")) { close_mask = STATE_SHIFT | STATE_CTRL; mymenu[SEARCH_OFFSET].key = 0; } g_free (key_theme); } } /* Away binding to ctrl-alt-a if the _Help menu conflicts (FR/PT/IT) */ { char *help = _("_Help"); char *under = strchr (help, '_'); if (under && (under[1] == 'a' || under[1] == 'A')) away_mask = STATE_ALT | STATE_CTRL; } if (!toplevel) { mymenu[DETACH_OFFSET].text = N_("_Detach"); mymenu[CLOSE_OFFSET].text = N_("_Close"); } else { mymenu[DETACH_OFFSET].text = N_("_Attach"); mymenu[CLOSE_OFFSET].text = N_("_Close"); } while (1) { item = NULL; if (mymenu[i].id == MENU_ID_USERMENU && !prefs.hex_gui_usermenu) { i++; continue; } switch (mymenu[i].type) { case M_NEWMENU: if (menu) gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu); item = menu = gtk_menu_new (); if (mymenu[i].id == MENU_ID_USERMENU) usermenu = menu; menu_item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text)); /* record the English name for /menu */ g_object_set_data (G_OBJECT (menu_item), "name", mymenu[i].text); #ifdef HAVE_GTK_MAC /* Added to app menu, see below */ if (!bar || mymenu[i].id != MENU_ID_HEXCHAT) #endif gtk_menu_shell_append (GTK_MENU_SHELL (menu_bar), menu_item); gtk_widget_show (menu_item); break; case M_MENUPIX: item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, FALSE); goto normalitem; case M_MENUSTOCK: item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE); goto normalitem; case M_MENUITEM: item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text)); normalitem: if (mymenu[i].key != 0) gtk_widget_add_accelerator (item, "activate", accel_group, mymenu[i].key, mymenu[i].key == GDK_KEY_F1 ? 0 : mymenu[i].key == GDK_KEY_w ? close_mask : (g_ascii_isupper (mymenu[i].key)) ? STATE_SHIFT | STATE_CTRL : STATE_CTRL, GTK_ACCEL_VISIBLE); if (mymenu[i].callback) g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (mymenu[i].callback), 0); if (submenu) gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item); else gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); break; case M_MENUTOG: item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text)); togitem: /* must avoid callback for Radio buttons */ GTK_CHECK_MENU_ITEM (item)->active = mymenu[i].state; /*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state);*/ if (mymenu[i].key != 0) gtk_widget_add_accelerator (item, "activate", accel_group, mymenu[i].key, mymenu[i].id == MENU_ID_FULLSCREEN ? 0 : mymenu[i].id == MENU_ID_AWAY ? away_mask : STATE_CTRL, GTK_ACCEL_VISIBLE); if (mymenu[i].callback) g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (mymenu[i].callback), NULL); if (submenu) gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item); else gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); gtk_widget_set_sensitive (item, mymenu[i].sensitive); break; case M_MENURADIO: item = gtk_radio_menu_item_new_with_mnemonic (group, _(mymenu[i].text)); group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item)); goto togitem; case M_SEP: item = gtk_menu_item_new (); gtk_widget_set_sensitive (item, FALSE); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); break; case M_MENUSUB: group = NULL; submenu = gtk_menu_new (); item = create_icon_menu (_(mymenu[i].text), mymenu[i].image, TRUE); /* record the English name for /menu */ g_object_set_data (G_OBJECT (item), "name", mymenu[i].text); gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), submenu); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); break; /*case M_END:*/ default: if (!submenu) { if (menu) { gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), menu); menu_add_plugin_mainmenu_items (menu_bar); } if (usermenu) usermenu_create (usermenu); return (menu_bar); } submenu = NULL; } /* record this GtkWidget * so it's state might be changed later */ if (mymenu[i].id != 0 && menu_widgets) /* this ends up in sess->gui->menu_item[MENU_ID_XXX] */ menu_widgets[mymenu[i].id] = item; #ifdef HAVE_GTK_MAC /* We want HexChat to be the app menu, not including Quit or HexChat itself */ if (bar && item && i <= CLOSE_OFFSET + 1 && mymenu[i].id != MENU_ID_HEXCHAT) { if (!submenu || mymenu[i].type == M_MENUSUB) gtkosx_application_insert_app_menu_item (osx_app, item, appmenu_offset++); } #endif i++; } }