# HG changeset patch # User Sadrul Habib Chowdhury # Date 1191394286 0 # Node ID b65f1bff6412c1d1f845544a0997027ab4920b3a # Parent 5a12b881ac399fff481d651553f0a1adc75b23fa Allow binding key-shortcuts to menuitems. For example, to bind ctrl+m to the 'Options -> Send IM...' menu, you would add: [buddylist::menu] c-m = send-im in ~/.gntrc diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntmenu.c --- a/finch/libgnt/gntmenu.c Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntmenu.c Wed Oct 03 06:51:26 2007 +0000 @@ -459,3 +459,33 @@ menu->list = g_list_append(menu->list, item); } +GntMenuItem *gnt_menu_get_item(GntMenu *menu, const char *id) +{ + GntMenuItem *item = NULL; + GList *iter = menu->list; + + if (!id || !*id) + return NULL; + + for (; iter; iter = iter->next) { + GntMenu *sub; + item = iter->data; + sub = gnt_menuitem_get_submenu(item); + if (sub) { + item = gnt_menu_get_item(sub, id); + if (item) + break; + } else { + const char *itid = gnt_menuitem_get_id(item); + if (itid && strcmp(itid, id) == 0) + break; + } + item = NULL; + } + + if (item) + menuitem_activate(menu, item); + + return item; +} + diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntmenu.h --- a/finch/libgnt/gntmenu.h Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntmenu.h Wed Oct 03 06:51:26 2007 +0000 @@ -86,27 +86,37 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return The GType for GntMenu. */ GType gnt_menu_get_gtype(void); /** - * - * @param type + * Create a new menu. * - * @return + * @param type The type of the menu, whether it's a toplevel menu or a popup menu. + * + * @return The newly created menu. */ GntWidget * gnt_menu_new(GntMenuType type); /** - * - * @param menu - * @param item + * Add an item to the menu. + * + * @param menu The menu. + * @param item The item to add to the menu. */ void gnt_menu_add_item(GntMenu *menu, GntMenuItem *item); +/** + * Get the GntMenuItem with the given ID. + * + * @param menu The menu. + * @param id The ID for an item. + * + * @return The menuitem with the given ID, or @c NULL. + */ +GntMenuItem *gnt_menu_get_item(GntMenu *menu, const char *id); + G_END_DECLS #endif /* GNT_MENU_H */ diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntmenuitem.c --- a/finch/libgnt/gntmenuitem.c Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntmenuitem.c Wed Oct 03 06:51:26 2007 +0000 @@ -33,6 +33,7 @@ item->text = NULL; if (item->submenu) gnt_widget_destroy(GNT_WIDGET(item->submenu)); + g_free(item->priv.id); parent_class->dispose(obj); } @@ -104,6 +105,11 @@ item->submenu = menu; } +GntMenu *gnt_menuitem_get_submenu(GntMenuItem *item) +{ + return item->submenu; +} + void gnt_menuitem_set_trigger(GntMenuItem *item, char trigger) { item->priv.trigger = trigger; @@ -114,3 +120,14 @@ return item->priv.trigger; } +void gnt_menuitem_set_id(GntMenuItem *item, const char *id) +{ + g_free(item->priv.id); + item->priv.id = g_strdup(id); +} + +const char * gnt_menuitem_get_id(GntMenuItem *item) +{ + return item->priv.id; +} + diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntmenuitem.h --- a/finch/libgnt/gntmenuitem.h Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntmenuitem.h Wed Oct 03 06:51:26 2007 +0000 @@ -53,6 +53,7 @@ int x; int y; char trigger; + char *id; }; typedef void (*GntMenuItemCallback)(GntMenuItem *item, gpointer data); @@ -86,36 +87,46 @@ G_BEGIN_DECLS /** - * - * - * @return + * @return GType for GntMenuItem. */ GType gnt_menuitem_get_gtype(void); /** - * - * @param text + * Create a new menuitem. * - * @return + * @param text Label for the menuitem. + * + * @return The newly created menuitem. */ GntMenuItem * gnt_menuitem_new(const char *text); /** - * - * @param item - * @param callback - * @param data + * Set a callback function for a menuitem. + * + * @param item The menuitem. + * @param callback The callback function. + * @param data Data to send to the callback function. */ void gnt_menuitem_set_callback(GntMenuItem *item, GntMenuItemCallback callback, gpointer data); /** - * - * @param item - * @param menu + * Set a submenu for a menuitem. A menuitem with a submenu cannot have a callback. + * + * @param item The menuitem. + * @param menu The submenu. */ void gnt_menuitem_set_submenu(GntMenuItem *item, GntMenu *menu); /** + * Get the submenu for a menuitem. + * + * @param item The menuitem. + * + * @return The submenu, or @c NULL. + */ +GntMenu *gnt_menuitem_get_submenu(GntMenuItem *item); + +/** * Set a trigger key for the item. * * @param item The menuitem @@ -134,6 +145,23 @@ */ char gnt_menuitem_get_trigger(GntMenuItem *item); +/** + * Set an ID for the menuitem. + * + * @param item The menuitem. + * @param id The ID for the menuitem. + */ +void gnt_menuitem_set_id(GntMenuItem *item, const char *id); + +/** + * Get the ID of the menuitem. + * + * @param item The menuitem. + * + * @return The ID for the menuitem. + */ +const char * gnt_menuitem_get_id(GntMenuItem *item); + G_END_DECLS #endif /* GNT_MENUITEM_H */ diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntstyle.c --- a/finch/libgnt/gntstyle.c Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntstyle.c Wed Oct 03 06:51:26 2007 +0000 @@ -227,6 +227,65 @@ #endif } +gboolean gnt_style_read_menu_accels(const char *name, GHashTable *table) +{ +#if GLIB_CHECK_VERSION(2,6,0) + char *kname; + GError *error = NULL; + gboolean ret = FALSE; + + kname = g_strdup_printf("%s::menu", name); + + if (g_key_file_has_group(gkfile, kname)) + { + gsize len = 0; + char **keys; + + keys = g_key_file_get_keys(gkfile, kname, &len, &error); + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + g_free(kname); + return ret; + } + + while (len--) + { + char *key, *menuid; + + key = g_strdup(keys[len]); + menuid = g_key_file_get_string(gkfile, kname, keys[len], &error); + + if (error) + { + g_printerr("GntStyle: %s\n", error->message); + g_error_free(error); + error = NULL; + } + else + { + const char *keycode = parse_key(key); + if (keycode == NULL) { + g_printerr("GntStyle: Invalid key-binding %s\n", key); + } else { + ret = TRUE; + g_hash_table_replace(table, g_strdup(keycode), menuid); + menuid = NULL; + } + } + g_free(key); + g_free(menuid); + } + g_strfreev(keys); + } + + g_free(kname); + return ret; +#endif + return FALSE; +} + void gnt_styles_get_keyremaps(GType type, GHashTable *hash) { #if GLIB_CHECK_VERSION(2,6,0) diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntstyle.h --- a/finch/libgnt/gntstyle.h Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntstyle.h Wed Oct 03 06:51:26 2007 +0000 @@ -89,6 +89,16 @@ */ void gnt_style_read_actions(GType type, GntBindableClass *klass); +/* + * Read menu-accels from ~/.gntrc + * + * @param name The name of the window. + * @param table The hastable to store the accel information. + * + * @return @c TRUE if some accels were read, @c FALSE otherwise. + */ +gboolean gnt_style_read_menu_accels(const char *name, GHashTable *table); + void gnt_style_read_workspaces(GntWM *wm); /** diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntwindow.c --- a/finch/libgnt/gntwindow.c Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntwindow.c Wed Oct 03 06:51:26 2007 +0000 @@ -25,6 +25,11 @@ #include +struct _GntWindowPriv +{ + GHashTable *accels; /* key => menuitem-id */ +}; + enum { SIG_WORKSPACE_HIDE, @@ -55,6 +60,10 @@ GntWindow *window = GNT_WINDOW(widget); if (window->menu) gnt_widget_destroy(GNT_WIDGET(window->menu)); + if (window->priv) { + g_hash_table_destroy(window->priv->accels); + g_free(window->priv); + } org_destroy(widget); } @@ -98,8 +107,11 @@ gnt_window_init(GTypeInstance *instance, gpointer class) { GntWidget *widget = GNT_WIDGET(instance); + GntWindow *win = GNT_WINDOW(widget); GNT_WIDGET_UNSET_FLAGS(widget, GNT_WIDGET_NO_BORDER | GNT_WIDGET_NO_SHADOW); GNT_WIDGET_SET_FLAGS(widget, GNT_WIDGET_CAN_TAKE_FOCUS); + win->priv = g_new0(GntWindowPriv, 1); + win->priv->accels = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); GNTDEBUG; } @@ -170,8 +182,23 @@ void gnt_window_set_menu(GntWindow *window, GntMenu *menu) { /* If a menu already existed, then destroy that first. */ + const char *name = gnt_widget_get_name(GNT_WIDGET(window)); if (window->menu) gnt_widget_destroy(GNT_WIDGET(window->menu)); window->menu = menu; + if (name && window->priv) { + if (!gnt_style_read_menu_accels(name, window->priv->accels)) { + g_hash_table_destroy(window->priv->accels); + g_free(window->priv); + window->priv = NULL; + } + } } +const char * gnt_window_get_accel_item(GntWindow *window, const char *key) +{ + if (window->priv) + return g_hash_table_lookup(window->priv->accels, key); + return NULL; +} + diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntwindow.h --- a/finch/libgnt/gntwindow.h Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntwindow.h Wed Oct 03 06:51:26 2007 +0000 @@ -52,6 +52,7 @@ { GntBox parent; GntMenu *menu; + GntWindowPriv *priv; }; struct _GntWindowClass @@ -99,6 +100,8 @@ */ void gnt_window_set_menu(GntWindow *window, GntMenu *menu); +const char * gnt_window_get_accel_item(GntWindow *window, const char *key); + void gnt_window_workspace_hiding(GntWindow *); void gnt_window_workspace_showing(GntWindow *); diff -r 5a12b881ac39 -r b65f1bff6412 finch/libgnt/gntwm.c --- a/finch/libgnt/gntwm.c Wed Oct 03 05:42:31 2007 +0000 +++ b/finch/libgnt/gntwm.c Wed Oct 03 06:51:26 2007 +0000 @@ -1853,8 +1853,17 @@ ret = gnt_widget_key_pressed(GNT_WIDGET(wm->menu), keys); else if (wm->_list.window) ret = gnt_widget_key_pressed(wm->_list.window, keys); - else if (wm->cws->ordered) - ret = gnt_widget_key_pressed(GNT_WIDGET(wm->cws->ordered->data), keys); + else if (wm->cws->ordered) { + GntWidget *win = wm->cws->ordered->data; + GntMenu *menu = GNT_WINDOW(win)->menu; + if (menu) { + const char *id = gnt_window_get_accel_item(GNT_WINDOW(win), keys); + if (id) + ret = (gnt_menu_get_item(menu, id) != NULL); + } + if (!ret) + ret = gnt_widget_key_pressed(win, keys); + } return ret; }