changeset 21212:b65f1bff6412

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
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Wed, 03 Oct 2007 06:51:26 +0000
parents 5a12b881ac39
children 4d6828b8da3e
files finch/libgnt/gntmenu.c finch/libgnt/gntmenu.h finch/libgnt/gntmenuitem.c finch/libgnt/gntmenuitem.h finch/libgnt/gntstyle.c finch/libgnt/gntstyle.h finch/libgnt/gntwindow.c finch/libgnt/gntwindow.h finch/libgnt/gntwm.c
diffstat 9 files changed, 217 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- 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;
+}
+
--- 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 */
--- 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;
+}
+
--- 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 */
--- 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)
--- 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);
 
 /**
--- 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 <string.h>
 
+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;
+}
+
--- 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 *);
 
--- 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;
 }