Make the window list plugin's menu react to keypresses. The proper way to do this is to use the 'activate' signal, but since the 'button-release-event' is used instead, we need to use the keypress events. We use 'key-press-event' to avoid beeps from GTK when keypresses which we do want are received, and 'key-release-event' to actually perform the actions. Some use of idle callbacks is needed else things just don't work properly: workspace switches don't happen and the window is moved to the current workspace, for example. Signed-off-by: Darren Salt diff -u plugins/windowlist/windowlist.c plugins/windowlist/windowlist.c --- plugins/windowlist/windowlist.c 2006-07-31 20:43:05.000000000 +0100 +++ plugins/windowlist/windowlist.c (working copy) @@ -37,6 +37,8 @@ #include #endif +#include + #include #include @@ -200,6 +202,104 @@ } static gboolean +menulist_goto_window_idle (NetkWindow *window) +{ + netk_window_activate (window); + return FALSE; +} + +static gboolean +menulist_goto_workspace_window_idle (NetkWindow *window) +{ + netk_workspace_activate(netk_window_get_workspace(window)); + g_idle_add ((GSourceFunc) menulist_goto_window_idle, window); + return FALSE; +} + +static gboolean +menulist_goto_workspace_idle (NetkWorkspace *workspace) +{ + netk_workspace_activate (workspace); + return FALSE; +} + +static gboolean +menulist_key_event (GtkWidget *menu, + GdkEventKey *ev, + gpointer data) +{ + gboolean force_deactivate; + GtkWidget *item = (GTK_MENU_SHELL(menu))->active_menu_item; + NetkWindow *window = item ? g_object_get_data(G_OBJECT(item), "window") : NULL; + guint state = ev->state & 0xFF; + + switch (ev->keyval) + { + default: + return FALSE; + + case GDK_Menu: + state = state ? 0x100 : 0x101; + /* fall through */ + + case GDK_Return: + case GDK_KP_Enter: + force_deactivate = TRUE; + break; + + case GDK_space: + case GDK_KP_Space: + force_deactivate = FALSE; + break; + } + + if (!window) + switch (state) + { + default: + return FALSE; + + case 0: + if (data) + { + NetkWorkspace *workspace = g_object_get_data(G_OBJECT(item), "workspace"); + gtk_menu_shell_activate_item (GTK_MENU_SHELL (menu), item, force_deactivate); + g_idle_add ((GSourceFunc) menulist_goto_workspace_idle, workspace); + } + break; + } + else + switch (state) + { + default: + return FALSE; + + case 0: + if (data) + { + gtk_menu_shell_activate_item (GTK_MENU_SHELL (menu), item, force_deactivate); + g_idle_add ((GSourceFunc) menulist_goto_workspace_window_idle, window); + } + break; + + case GDK_SHIFT_MASK: + if (data) + { + gtk_menu_shell_activate_item (GTK_MENU_SHELL (menu), item, force_deactivate); + g_idle_add ((GSourceFunc) menulist_goto_window_idle, window); + } + break; + + case GDK_CONTROL_MASK: + case 0x101: + popup_action_menu (item, window); + break; + } + + return TRUE; +} + +static gboolean menulist_add_screen (GtkWidget *mi, GdkEventButton *ev, Windowlist *wl) @@ -433,7 +533,8 @@ g_free (ws_label); g_signal_connect (mi, "button-release-event", G_CALLBACK (menulist_goto_workspace), netk_workspace); - + g_object_set_data(G_OBJECT(mi), "workspace", netk_workspace); + /* Apply layout */ if (netk_workspace == active_workspace) gtk_widget_modify_font (gtk_bin_get_child (GTK_BIN (mi)), bold); @@ -506,6 +607,8 @@ g_signal_connect(G_OBJECT(mi), "destroy", G_CALLBACK(mi_destroyed), window); + + g_object_set_data(G_OBJECT(mi), "window", window); } if (i < wscount-1) @@ -514,6 +617,11 @@ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); } } + /* keypress handling is needed to avoid unwanted beeping... */ + g_signal_connect (G_OBJECT(menu), "key-press-event", + G_CALLBACK (menulist_key_event), NULL); + g_signal_connect (G_OBJECT(menu), "key-release-event", + G_CALLBACK (menulist_key_event), menu); pango_font_description_free(italic); pango_font_description_free(bold);