Merge pull request #287 from ZoiteChat/customize-all-keybinds

Customize all keybinds
This commit is contained in:
deepend-tildeclub
2026-06-10 16:22:52 -06:00
committed by GitHub
8 changed files with 464 additions and 90 deletions

View File

@@ -518,6 +518,7 @@ const struct prefs vars[] =
{"irc_conf_mode", P_OFFINT (hex_irc_conf_mode), TYPE_BOOL},
{"irc_extra_hilight", P_OFFSET (hex_irc_extra_hilight), TYPE_STR},
{"irc_hide_nickchange", P_OFFINT (hex_irc_hide_nickchange), TYPE_BOOL},
{"irc_hide_join_part_hostmask", P_OFFINT (hex_irc_hide_join_part_hostmask), TYPE_BOOL},
{"irc_hide_version", P_OFFINT (hex_irc_hide_version), TYPE_BOOL},
{"irc_hidehost", P_OFFINT (hex_irc_hidehost), TYPE_BOOL},
{"irc_id_ntext", P_OFFSET (hex_irc_id_ntext), TYPE_STR},

View File

@@ -1809,12 +1809,97 @@ format_event (session *sess, int index, char **args, char *o, gsize sizeofo, uns
o[0] = 0;
}
static char *
text_event_without_hostmask_format (const char *format, int host_arg)
{
char token[3];
const char *arg;
const char *open;
const char *close;
const char *start;
char *out;
gsize prefix_len;
g_snprintf (token, sizeof (token), "$%d", host_arg);
arg = strstr (format, token);
if (!arg)
return NULL;
open = arg;
while (open > format && *open != '(' && *open != '\n')
open--;
close = arg + strlen (token);
while (*close && *close != ')' && *close != '\n')
close++;
if (*open != '(' || *close != ')')
return NULL;
start = open;
if (start > format && start[-1] == ' ')
start--;
prefix_len = start - format;
out = g_malloc (prefix_len + strlen (close + 1) + 1);
memcpy (out, format, prefix_len);
strcpy (out + prefix_len, close + 1);
return out;
}
static void
display_event_string (session *sess, int event, char **args, char *format,
unsigned int stripcolor_args, time_t timestamp)
{
char *compiled;
char *saved;
char o[4096];
int max_arg;
if (pevt_build_string (format, &compiled, &max_arg) != 0)
return;
saved = pntevts[event];
pntevts[event] = compiled;
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
pntevts[event] = saved;
g_free (compiled);
if (o[0])
PrintTextTimeStamp (sess, o, timestamp);
}
static void
display_event (session *sess, int event, char **args,
unsigned int stripcolor_args, time_t timestamp)
{
char o[4096];
char *format;
char *host;
int host_arg;
if (prefs.hex_irc_hide_join_part_hostmask &&
(event == XP_TE_JOIN || event == XP_TE_PART || event == XP_TE_PARTREASON))
{
host_arg = event == XP_TE_JOIN ? 3 : 2;
format = text_event_without_hostmask_format (pntevts_text[event], host_arg);
if (format)
{
display_event_string (sess, event, args, format, stripcolor_args, timestamp);
g_free (format);
return;
}
host = args[host_arg];
args[host_arg] = "";
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
args[host_arg] = host;
}
else
{
format_event (sess, event, args, o, sizeof (o), stripcolor_args);
}
if (o[0])
PrintTextTimeStamp (sess, o, timestamp);
}

View File

@@ -188,6 +188,7 @@ struct zoitechatprefs
unsigned int hex_irc_conf_mode;
unsigned int hex_irc_hidehost;
unsigned int hex_irc_hide_nickchange;
unsigned int hex_irc_hide_join_part_hostmask;
unsigned int hex_irc_hide_version;
unsigned int hex_irc_invisible;
unsigned int hex_irc_logging;

View File

@@ -80,7 +80,7 @@ void key_action_tab_clean (void);
*/
/* Remember that the *number* of actions is this *plus* 1 --AGL */
#define KEY_MAX_ACTIONS 14
#define KEY_MAX_ACTIONS 16
struct key_binding
{
@@ -142,6 +142,13 @@ static int key_action_move_tab_family_right (GtkWidget * wid, GdkEventKey * evt,
static int key_action_put_history (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static int key_action_menu_shortcut (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static int key_action_reopen_closed_tab (GtkWidget * wid, GdkEventKey * evt,
char *d1, char *d2,
struct session *sess);
static GSList *keybind_list = NULL;
@@ -287,6 +294,10 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
N_("This command moves the current tab family to the right")},
{key_action_put_history, "Push input line into history",
N_("Push input line into history but doesn't send to server")},
{key_action_menu_shortcut, "Menu Shortcut",
N_("Runs one of the built-in menu shortcuts. Set Data 1 to: network-list, new-server-tab, new-server-window, close, quit, menu-toggle, user-list-toggle, fullscreen-toggle, away-toggle, reset-marker, move-marker, copy-selection, search-text, search-next, search-previous or contents.")},
{key_action_reopen_closed_tab, "Reopen Closed Tab",
N_("Reopens the most recently closed channel tab")},
};
#define default_kb_cfg \
@@ -329,7 +340,86 @@ static const struct key_action key_actions[KEY_MAX_ACTIONS + 1] = {
"ACCEL=<Alt>Right\nMove front tab right\nD1!\nD2!\n\n"\
"ACCEL=<Primary><Shift>Page_Up\nMove tab family left\nD1!\nD2!\n\n"\
"ACCEL=<Primary><Shift>Page_Down\nMove tab family right\nD1!\nD2!\n\n"\
"ACCEL=F9\nRun Command\nD1:/GUI MENU TOGGLE\nD2!\n\n"
"ACCEL=<Primary>s\nMenu Shortcut\nD1:network-list\nD2!\n\n"\
"ACCEL=<Primary>t\nMenu Shortcut\nD1:new-server-tab\nD2!\n\n"\
"ACCEL=<Primary>n\nMenu Shortcut\nD1:new-server-window\nD2!\n\n"\
"ACCEL=<Primary>w\nMenu Shortcut\nD1:close\nD2!\n\n"\
"ACCEL=<Primary>q\nMenu Shortcut\nD1:quit\nD2!\n\n"\
"ACCEL=<Primary>F9\nMenu Shortcut\nD1:menu-toggle\nD2!\n\n"\
"ACCEL=F7\nMenu Shortcut\nD1:user-list-toggle\nD2!\n\n"\
"ACCEL=F11\nMenu Shortcut\nD1:fullscreen-toggle\nD2!\n\n"\
"ACCEL=<Alt>a\nMenu Shortcut\nD1:away-toggle\nD2!\n\n"\
"ACCEL=<Primary>m\nMenu Shortcut\nD1:reset-marker\nD2!\n\n"\
"ACCEL=<Primary><Shift>M\nMenu Shortcut\nD1:move-marker\nD2!\n\n"\
"ACCEL=<Primary><Shift>C\nMenu Shortcut\nD1:copy-selection\nD2!\n\n"\
"ACCEL=<Primary>f\nMenu Shortcut\nD1:search-text\nD2!\n\n"\
"ACCEL=<Primary>g\nMenu Shortcut\nD1:search-next\nD2!\n\n"\
"ACCEL=<Primary><Shift>G\nMenu Shortcut\nD1:search-previous\nD2!\n\n"\
"ACCEL=F1\nMenu Shortcut\nD1:contents\nD2!\n\n"\
"ACCEL=<Primary><Shift>T\nReopen Closed Tab\nD1!\nD2!\n\n"
static gboolean
key_builtin_data_match (char *line, char *data)
{
if (line[2] == '!')
return data == NULL || data[0] == 0;
if (line[2] == ':')
return !strcmp (&line[3], data ? data : "");
return FALSE;
}
static gboolean
key_binding_is_builtin (struct key_binding *kb)
{
char *buf, *ibuf;
char *action;
int pnt = 0;
int state = 0;
gboolean match = FALSE;
gboolean d1_match = FALSE;
off_t size;
if (kb->action < 0 || kb->action > KEY_MAX_ACTIONS)
return FALSE;
action = key_actions[kb->action].name;
ibuf = g_strdup (default_kb_cfg);
size = strlen (default_kb_cfg);
while (buf_get_line (ibuf, &buf, &pnt, size))
{
if (strlen (buf) == 0)
continue;
switch (state)
{
case 0:
state = 1;
break;
case 1:
match = !strcmp (buf, action);
state = 2;
break;
case 2:
d1_match = match && key_builtin_data_match (buf, kb->data1);
state = 3;
break;
case 3:
if (d1_match && key_builtin_data_match (buf, kb->data2))
{
g_free (ibuf);
return TRUE;
}
state = 0;
break;
}
}
g_free (ibuf);
return FALSE;
}
void
key_init ()
@@ -443,28 +533,6 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
if (!list)
return FALSE;
current_sess = sess;
if ((evt->state & GDK_CONTROL_MASK) &&
!(evt->state & (GDK_MOD1_MASK | GDK_META_MASK)))
{
if (!(evt->state & GDK_SHIFT_MASK) &&
(evt->keyval == GDK_KEY_w || evt->keyval == GDK_KEY_W))
{
if (sess->type == SESS_CHANNEL)
{
fe_close_window (sess);
g_signal_stop_emission_by_name (G_OBJECT (wid), "key-press-event");
return 1;
}
}
if ((evt->state & GDK_SHIFT_MASK) &&
(evt->keyval == GDK_KEY_t || evt->keyval == GDK_KEY_T))
{
mg_reopen_closed_channel_tab ();
g_signal_stop_emission_by_name (G_OBJECT (wid), "key-press-event");
return 1;
}
}
if (plugin_emit_keypress (sess, evt->state, evt->keyval, gdk_keyval_to_unicode (evt->keyval)))
return 1;
@@ -508,6 +576,31 @@ key_handle_key_press (GtkWidget *wid, GdkEventKey *evt, session *sess)
return 0;
}
gboolean
key_get_menu_accel (const char *name, guint *keyval, GdkModifierType *mod)
{
struct key_binding *kb;
GSList *list;
if (!name)
return FALSE;
list = keybind_list;
while (list)
{
kb = (struct key_binding*)list->data;
if (kb->action >= 0 && kb->action <= KEY_MAX_ACTIONS && kb->keyval != 0 && !strcmp (key_actions[kb->action].name, "Menu Shortcut") && kb->data1 && !strcmp (kb->data1, name))
{
*keyval = kb->keyval;
*mod = kb->mod;
return TRUE;
}
list = g_slist_next (list);
}
return FALSE;
}
/* ***** GUI code here ******************* */
@@ -518,6 +611,7 @@ enum
ACTION_COLUMN,
D1_COLUMN,
D2_COLUMN,
CUSTOM_COLUMN,
N_COLUMNS
};
@@ -642,15 +736,31 @@ key_dialog_keypress (GtkWidget *wid, GdkEventKey *evt, gpointer userdata)
if (handled)
{
gboolean custom1, custom2;
sel = gtk_tree_view_get_selection (view);
gtk_tree_selection_get_selected (sel, &store, &iter1);
if (!gtk_tree_selection_get_selected (sel, &store, &iter1))
return FALSE;
path = gtk_tree_model_get_path (store, &iter1);
if (delta == 1)
gtk_tree_path_next (path);
else
gtk_tree_path_prev (path);
gtk_tree_model_get_iter (store, &iter2, path);
else if (!gtk_tree_path_prev (path))
{
gtk_tree_path_free (path);
return FALSE;
}
if (!gtk_tree_model_get_iter (store, &iter2, path))
{
gtk_tree_path_free (path);
return FALSE;
}
gtk_tree_path_free (path);
gtk_tree_model_get (store, &iter1, CUSTOM_COLUMN, &custom1, -1);
gtk_tree_model_get (store, &iter2, CUSTOM_COLUMN, &custom2, -1);
if (custom1 && custom2)
gtk_list_store_swap (GTK_LIST_STORE (store), &iter1, &iter2);
}
@@ -663,14 +773,23 @@ key_dialog_selection_changed (GtkTreeSelection *sel, gpointer userdata)
GtkTreeModel *model;
GtkTreeIter iter;
GtkXText *xtext;
GtkWidget *delete_button;
char *actiontext;
gboolean custom;
int action;
delete_button = g_object_get_data (G_OBJECT (key_dialog), "delete_button");
if (!gtk_tree_selection_get_selected (sel, &model, &iter) || model == NULL)
{
if (delete_button)
gtk_widget_set_sensitive (delete_button, FALSE);
return;
}
xtext = GTK_XTEXT (g_object_get_data (G_OBJECT (key_dialog), "xtext"));
gtk_tree_model_get (model, &iter, ACTION_COLUMN, &actiontext, -1);
gtk_tree_model_get (model, &iter, ACTION_COLUMN, &actiontext, CUSTOM_COLUMN, &custom, -1);
if (delete_button)
gtk_widget_set_sensitive (delete_button, custom);
if (actiontext)
{
@@ -745,7 +864,10 @@ key_dialog_save (GtkWidget *wid, gpointer userdata)
}
if (key_save_kbs () == 0)
{
menu_update_quit_accel ();
key_dialog_close (wid, NULL);
}
}
static void
@@ -758,6 +880,7 @@ key_dialog_add (GtkWidget *wid, gpointer userdata)
GtkTreePath *path;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter, CUSTOM_COLUMN, TRUE, -1);
/* make sure the new row is visible and selected */
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
@@ -774,9 +897,14 @@ key_dialog_delete (GtkWidget *wid, gpointer userdata)
GtkListStore *store = GTK_LIST_STORE (gtk_tree_view_get_model (view));
GtkTreeIter iter;
GtkTreePath *path;
gboolean custom;
if (gtkutil_treeview_get_selected (view, &iter, -1))
{
gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, CUSTOM_COLUMN, &custom, -1);
if (!custom)
return;
/* delete this row, select next one */
if (gtk_list_store_remove (store, &iter))
{
@@ -803,13 +931,13 @@ key_dialog_treeview_new (GtkWidget *box)
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_IN);
store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_STRING, G_TYPE_STRING);
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
g_return_val_if_fail (store != NULL, NULL);
view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (view), TRUE);
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (view), FALSE);
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), TRUE);
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view), FALSE);
g_signal_connect (G_OBJECT (view), "key-press-event",
G_CALLBACK (key_dialog_keypress), NULL);
@@ -880,6 +1008,7 @@ key_dialog_treeview_new (GtkWidget *box)
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view), ACTION_COLUMN,
"Action", render,
"text", ACTION_COLUMN,
"editable", CUSTOM_COLUMN,
NULL);
render = gtk_cell_renderer_text_new ();
@@ -890,6 +1019,7 @@ key_dialog_treeview_new (GtkWidget *box)
GTK_TREE_VIEW (view), D1_COLUMN,
"Data1", render,
"text", D1_COLUMN,
"editable", CUSTOM_COLUMN,
NULL);
render = gtk_cell_renderer_text_new ();
@@ -900,6 +1030,7 @@ key_dialog_treeview_new (GtkWidget *box)
GTK_TREE_VIEW (view), D2_COLUMN,
"Data2", render,
"text", D2_COLUMN,
"editable", CUSTOM_COLUMN,
NULL);
col = gtk_tree_view_get_column (GTK_TREE_VIEW (view), KEY_COLUMN);
@@ -945,7 +1076,8 @@ key_dialog_load (GtkListStore *store)
ACCEL_COLUMN, accel_text,
ACTION_COLUMN, key_actions[kb->action].name,
D1_COLUMN, kb->data1,
D2_COLUMN, kb->data2, -1);
D2_COLUMN, kb->data2,
CUSTOM_COLUMN, !key_binding_is_builtin (kb), -1);
g_free (accel_text);
g_free (label_text);
@@ -958,7 +1090,7 @@ void
key_dialog_show ()
{
GtkWidget *vbox, *box;
GtkWidget *view, *xtext;
GtkWidget *view, *xtext, *delete_button;
GtkListStore *store;
XTextColor xtext_palette[XTEXT_COLS];
char buf[128];
@@ -992,8 +1124,10 @@ key_dialog_show ()
gtkutil_button (box, ICON_FKEYS_NEW, NULL, key_dialog_add,
NULL, _("Add"));
gtkutil_button (box, ICON_FKEYS_DELETE, NULL, key_dialog_delete,
delete_button = gtkutil_button (box, ICON_FKEYS_DELETE, NULL, key_dialog_delete,
NULL, _("Delete"));
g_object_set_data (G_OBJECT (key_dialog), "delete_button", delete_button);
gtk_widget_set_sensitive (delete_button, FALSE);
gtkutil_button (box, ICON_FKEYS_CANCEL, NULL, key_dialog_close,
NULL, _("Cancel"));
gtkutil_button (box, ICON_FKEYS_SAVE, NULL, key_dialog_save,
@@ -1289,6 +1423,24 @@ key_action_handle_command (GtkWidget * wid, GdkEventKey * evt, char *d1,
return 0;
}
static int
key_action_menu_shortcut (GtkWidget * wid, GdkEventKey * evt, char *d1,
char *d2, struct session *sess)
{
if (menu_key_action (d1, evt->keyval, evt->state))
return 2;
return 0;
}
static int
key_action_reopen_closed_tab (GtkWidget * wid, GdkEventKey * evt, char *d1,
char *d2, struct session *sess)
{
mg_reopen_closed_channel_tab ();
return 2;
}
/*
* Check if the given session is inside the main window. This predicate
* is passed to lastact_getfirst() as a way to filter out detached sessions.

View File

@@ -35,5 +35,6 @@ int key_handle_key_press (GtkWidget * wid, GdkEventKey * evt, session *sess);
int key_action_insert (GtkWidget * wid, GdkEventKey * evt, char *d1, char *d2,
session *sess);
void key_check_replace_on_change (GtkEditable *editable, gpointer data);
gboolean key_get_menu_accel (const char *name, guint *keyval, GdkModifierType *mod);
#endif

View File

@@ -1755,44 +1755,6 @@ menu_change_layout (void)
}
}
void
menu_update_quit_accel (void)
{
GSList *list;
list = sess_list;
while (list)
{
session *sess = list->data;
session_gui *gui = sess->gui;
GtkWidget *item;
GtkAccelGroup *accel_group;
int enabled;
list = list->next;
if (!gui)
continue;
item = gui->menu_item[MENU_ID_QUIT];
if (!item)
continue;
enabled = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "zc-ctrlq-enabled"));
if (enabled == (int)prefs.hex_gui_ctrlq_quit)
continue;
accel_group = g_object_get_data (G_OBJECT (item), "zc-quit-accel-group");
if (!accel_group)
continue;
if (prefs.hex_gui_ctrlq_quit)
gtk_widget_add_accelerator (item, "activate", accel_group, GDK_KEY_q, STATE_CTRL, GTK_ACCEL_VISIBLE);
else
gtk_widget_remove_accelerator (item, accel_group, GDK_KEY_q, STATE_CTRL);
g_object_set_data (G_OBJECT (item), "zc-ctrlq-enabled", GINT_TO_POINTER (prefs.hex_gui_ctrlq_quit));
}
}
static void
menu_layout_cb (GtkWidget *item, gpointer none)
{
@@ -1939,13 +1901,13 @@ menu_about (GtkWidget *wid, gpointer sess)
static struct mymenu mymenu[] = {
{N_("_ZoiteChat"), 0, 0, M_NEWMENU, MENU_ID_ZOITECHAT, 0, 1},
{N_("Network Li_st"), menu_open_server_list, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_s},
{N_("Network Li_st"), menu_open_server_list, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_SEP, 0, 0, 0},
{N_("_New"), 0, 0, M_MENUSUB, 0, 0, 1},
{N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_t},
{N_("Server Tab"), menu_newserver_tab, 0, M_MENUITEM, 0, 0, 1},
{N_("Channel Tab"), menu_newchannel_tab, 0, M_MENUITEM, 0, 0, 1},
{N_("Server Window"), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_n},
{N_("Server Window"), menu_newserver_window, 0, M_MENUITEM, 0, 0, 1},
{N_("Channel Window"), menu_newchannel_window, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_END, 0, 0, 0},
{0, 0, 0, M_SEP, 0, 0, 0},
@@ -1957,13 +1919,13 @@ static struct mymenu mymenu[] = {
#define CLOSE_OFFSET (13)
{0, menu_close, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_SEP, 0, 0, 0},
{N_("_Quit"), menu_quit, 0, M_MENUITEM, MENU_ID_QUIT, 0, 1, GDK_KEY_q}, /* 15 */
{N_("_Quit"), menu_quit, 0, M_MENUITEM, MENU_ID_QUIT, 0, 1}, /* 15 */
{N_("_View"), 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_("_Menu Bar"), menu_bar_toggle_cb, 0, M_MENUTOG, MENU_ID_MENUBAR, 0, 1},
{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_("_User List"), menu_userlist_toggle, 0, M_MENUTOG, MENU_ID_USERLIST, 0, 1},
{N_("U_ser List 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},
@@ -1980,7 +1942,7 @@ static struct mymenu mymenu[] = {
{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_ ("_Fullscreen"), menu_fullscreen_toggle, 0, M_MENUTOG, MENU_ID_FULLSCREEN, 0, 1},
{N_("_Server"), 0, 0, M_NEWMENU, 0, 0, 1},
{N_("_Disconnect"), menu_disconnect, 0, M_MENUITEM, MENU_ID_DISCONNECT, 0, 1},
@@ -1989,7 +1951,7 @@ static struct mymenu mymenu[] = {
{N_("Channel _List"), menu_chanlist, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_SEP, 0, 0, 0},
#define AWAY_OFFSET (41)
{N_("Marked _Away"), menu_away_toggle, 0, M_MENUITEM, MENU_ID_AWAY, 0, 1, GDK_KEY_a},
{N_("Marked _Away"), menu_away_toggle, 0, M_MENUITEM, MENU_ID_AWAY, 0, 1},
{N_("_Usermenu"), 0, 0, M_NEWMENU, MENU_ID_USERMENU, 0, 1}, /* 40 */
@@ -2017,25 +1979,191 @@ static struct mymenu mymenu[] = {
{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_("Reset Marker Line"), menu_resetmarker, 0, M_MENUITEM, 0, 0, 1},
{N_("Move to Marker Line"), menu_movetomarker, 0, M_MENUITEM, 0, 0, 1},
{N_("_Copy Selection"), menu_copy_selection, 0, M_MENUITEM, 0, 0, 1},
{N_("C_lear Text"), menu_flushbuffer, 0, M_MENUITEM, 0, 0, 1},
{N_("Save Text" ELLIPSIS), menu_savebuffer, 0, M_MENUITEM, 0, 0, 1},
#define SEARCH_OFFSET (70)
{N_("Search"), 0, 0, M_MENUSUB, 0, 0, 1},
{N_("Search Text" ELLIPSIS), menu_search, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_f},
{N_("Search Next" ), menu_search_next, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_g},
{N_("Search Previous" ), menu_search_prev, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_G},
{N_("Search Text" ELLIPSIS), menu_search, 0, M_MENUITEM, 0, 0, 1},
{N_("Search Next" ), menu_search_next, 0, M_MENUITEM, 0, 0, 1},
{N_("Search Previous" ), menu_search_prev, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_END, 0, 0, 0},
{N_("_Help"), 0, 0, M_NEWMENU, 0, 0, 1}, /* 74 */
{N_("_Contents"), menu_docs, 0, M_MENUITEM, 0, 0, 1, GDK_KEY_F1},
{N_("_Contents"), menu_docs, 0, M_MENUITEM, 0, 0, 1},
{N_("_About"), menu_about, 0, M_MENUITEM, 0, 0, 1},
{0, 0, 0, M_END, 0, 0, 0},
};
static const char *
menu_get_key_action_name (int index)
{
switch (index)
{
case 1:
return "network-list";
case 4:
return "new-server-tab";
case 6:
return "new-server-window";
case CLOSE_OFFSET:
return "close";
case 15:
return "quit";
case MENUBAR_OFFSET:
return "menu-toggle";
case MENUBAR_OFFSET + 2:
return "user-list-toggle";
case 34:
return "fullscreen-toggle";
case AWAY_OFFSET:
return "away-toggle";
case 65:
return "reset-marker";
case 66:
return "move-marker";
case 67:
return "copy-selection";
case SEARCH_OFFSET + 1:
return "search-text";
case SEARCH_OFFSET + 2:
return "search-next";
case SEARCH_OFFSET + 3:
return "search-previous";
case 75:
return "contents";
}
return NULL;
}
static void
menu_add_keybinding_accel (GtkWidget *item, GtkAccelGroup *accel_group, const char *name)
{
guint keyval;
GdkModifierType mod;
if (!accel_group || !key_get_menu_accel (name, &keyval, &mod))
return;
if (!strcmp (name, "quit") && !prefs.hex_gui_ctrlq_quit && keyval == GDK_KEY_q && mod == STATE_CTRL)
return;
gtk_widget_add_accelerator (item, "activate", accel_group, keyval, mod, GTK_ACCEL_VISIBLE);
g_object_set_data (G_OBJECT (item), "zc-key-accel-key", GUINT_TO_POINTER (keyval));
g_object_set_data (G_OBJECT (item), "zc-key-accel-mod", GUINT_TO_POINTER (mod));
}
static void
menu_refresh_keybinding_accels (GtkWidget *widget, gpointer data)
{
GtkAccelGroup *accel_group = data;
const char *name;
guint keyval;
GdkModifierType mod;
GtkWidget *submenu;
GList *children, *list;
if (GTK_IS_MENU_ITEM (widget))
{
keyval = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "zc-key-accel-key"));
mod = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), "zc-key-accel-mod"));
if (keyval != 0)
{
gtk_widget_remove_accelerator (widget, accel_group, keyval, mod);
g_object_set_data (G_OBJECT (widget), "zc-key-accel-key", NULL);
g_object_set_data (G_OBJECT (widget), "zc-key-accel-mod", NULL);
}
name = g_object_get_data (G_OBJECT (widget), "zc-key-action");
menu_add_keybinding_accel (widget, accel_group, name);
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
if (submenu)
menu_refresh_keybinding_accels (submenu, data);
}
if (GTK_IS_CONTAINER (widget))
{
children = gtk_container_get_children (GTK_CONTAINER (widget));
for (list = children; list; list = g_list_next (list))
menu_refresh_keybinding_accels (list->data, data);
g_list_free (children);
}
}
void
menu_update_quit_accel (void)
{
session *sess;
GSList *list;
GtkAccelGroup *accel_group;
list = sess_list;
while (list)
{
sess = list->data;
if (sess && sess->gui && sess->gui->menu)
{
accel_group = g_object_get_data (G_OBJECT (sess->gui->menu), "accel");
if (accel_group)
menu_refresh_keybinding_accels (sess->gui->menu, accel_group);
}
list = g_slist_next (list);
}
}
gboolean
menu_key_action (const char *name, guint keyval, GdkModifierType state)
{
if (!name)
return FALSE;
if (!strcmp (name, "network-list"))
menu_open_server_list (NULL, NULL);
else if (!strcmp (name, "new-server-tab"))
menu_newserver_tab (NULL, NULL);
else if (!strcmp (name, "new-server-window"))
menu_newserver_window (NULL, NULL);
else if (!strcmp (name, "close"))
menu_close (NULL, NULL);
else if (!strcmp (name, "quit"))
{
if (!prefs.hex_gui_ctrlq_quit && keyval == GDK_KEY_q && (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) == STATE_CTRL)
return FALSE;
menu_quit (NULL, NULL);
}
else if (!strcmp (name, "menu-toggle"))
menu_bar_toggle_cb ();
else if (!strcmp (name, "user-list-toggle"))
menu_userlist_toggle (NULL, NULL);
else if (!strcmp (name, "fullscreen-toggle"))
menu_fullscreen_toggle (NULL, NULL);
else if (!strcmp (name, "away-toggle"))
menu_away_toggle (NULL, NULL);
else if (!strcmp (name, "reset-marker"))
menu_resetmarker (NULL, NULL);
else if (!strcmp (name, "move-marker"))
menu_movetomarker (NULL, NULL);
else if (!strcmp (name, "copy-selection"))
menu_copy_selection (NULL, NULL);
else if (!strcmp (name, "search-text"))
menu_search ();
else if (!strcmp (name, "search-next"))
menu_search_next (NULL);
else if (!strcmp (name, "search-previous"))
menu_search_prev (NULL);
else if (!strcmp (name, "contents"))
menu_docs (NULL, NULL);
else
return FALSE;
return TRUE;
}
void
menu_set_away (session_gui *gui, int away)
{
@@ -2641,6 +2769,8 @@ menu_create_main (void *accel_group, int bar, int away, int toplevel,
case M_MENUITEM:
item = gtk_menu_item_new_with_mnemonic (_(mymenu[i].text));
normalitem:
g_object_set_data (G_OBJECT (item), "zc-key-action", (gpointer) menu_get_key_action_name (i));
menu_add_keybinding_accel (item, accel_group, menu_get_key_action_name (i));
if (mymenu[i].key != 0 && !(mymenu[i].id == MENU_ID_QUIT && !prefs.hex_gui_ctrlq_quit))
gtk_widget_add_accelerator (item, "activate", accel_group,
mymenu[i].key,
@@ -2669,6 +2799,8 @@ normalitem:
case M_MENUTOG:
item = gtk_check_menu_item_new_with_mnemonic (_(mymenu[i].text));
togitem:
g_object_set_data (G_OBJECT (item), "zc-key-action", (gpointer) menu_get_key_action_name (i));
menu_add_keybinding_accel (item, accel_group, menu_get_key_action_name (i));
/* must avoid callback for Radio buttons */
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), mymenu[i].state);
/*gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),

View File

@@ -39,6 +39,7 @@ void menu_bar_toggle (void);
void menu_add_plugin_items (GtkWidget *menu, char *root, char *target);
void menu_change_layout (void);
void menu_update_quit_accel (void);
gboolean menu_key_action (const char *name, guint keyval, GdkModifierType state);
void menu_set_away (session_gui *gui, int away);
void menu_set_fullscreen (session_gui *gui, int fullscreen);

View File

@@ -546,6 +546,7 @@ static const setting general_settings[] =
{ST_TOGGLE, N_("WHOIS on notify"), P_OFFINTNL(hex_notify_whois_online), N_("Sends a /WHOIS when a user comes online in your notify list."), 0, 0},
{ST_TOGGLE, N_("Hide join and part messages"), P_OFFINTNL(hex_irc_conf_mode), N_("Hide channel join/part messages by default."), 0, 0},
{ST_TOGGLE, N_("Hide nick change messages"), P_OFFINTNL(hex_irc_hide_nickchange), 0, 0, 0},
{ST_TOGGLE, N_("Hide hostmasks in join and part messages"), P_OFFINTNL(hex_irc_hide_join_part_hostmask), 0, 0, 0},
{ST_TOGGLE, N_("Enable Ctrl+Q to quit"), P_OFFINTNL(hex_gui_ctrlq_quit), 0, 0, 0},
{ST_END, 0, 0, 0, 0, 0}