diff options
author | Michael Natterer <mitch@gimp.org> | 2005-03-31 17:02:19 +0000 |
---|---|---|
committer | Michael Natterer <mitch@src.gnome.org> | 2005-03-31 17:02:19 +0000 |
commit | 91cb92c01882f7a3b1014c594908873fc18a936c (patch) | |
tree | e18e289edfbd0dd442fac1df3d3c4439223b29da | |
parent | 420878b21e654c49ade3b5670aed281beaeb2508 (diff) | |
download | gtk+-91cb92c01882f7a3b1014c594908873fc18a936c.tar.gz |
Allow to pop up menus without grabbing the keyboard. Useful for stuff like
2005-03-31 Michael Natterer <mitch@gimp.org>
Allow to pop up menus without grabbing the keyboard. Useful for
stuff like virtual keyboards. Fixes bug #159890
* gtk/gtk.symbols
* gtk/gtkmenushell.[ch]: added boolean property "take-focus"
and public API gtk_menu_shell_set/get_take_focus().
* gtk/gtkmenu.c (gtk_menu_popup)
(popup_grab_on_window): don't grab the keyboard if take_focus
is FALSE.
* gtk/gtkmenuitem.c (_gtk_menu_item_popup_submen): propagate the
parent menu_shell's take_focus property to the submenu which is
about to be popped up.
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 17 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 17 | ||||
-rw-r--r-- | gtk/gtk.symbols | 2 | ||||
-rw-r--r-- | gtk/gtkmenu.c | 21 | ||||
-rw-r--r-- | gtk/gtkmenuitem.c | 22 | ||||
-rw-r--r-- | gtk/gtkmenushell.c | 145 | ||||
-rw-r--r-- | gtk/gtkmenushell.h | 16 |
8 files changed, 237 insertions, 20 deletions
@@ -1,3 +1,20 @@ +2005-03-31 Michael Natterer <mitch@gimp.org> + + Allow to pop up menus without grabbing the keyboard. Useful for + stuff like virtual keyboards. Fixes bug #159890 + + * gtk/gtk.symbols + * gtk/gtkmenushell.[ch]: added boolean property "take-focus" + and public API gtk_menu_shell_set/get_take_focus(). + + * gtk/gtkmenu.c (gtk_menu_popup) + (popup_grab_on_window): don't grab the keyboard if take_focus + is FALSE. + + * gtk/gtkmenuitem.c (_gtk_menu_item_popup_submen): propagate the + parent menu_shell's take_focus property to the submenu which is + about to be popped up. + 2005-03-30 Federico Mena Quintero <federico@ximian.com> Merged from gtk-2-6: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index fce692ad17..d41547d3ac 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,20 @@ +2005-03-31 Michael Natterer <mitch@gimp.org> + + Allow to pop up menus without grabbing the keyboard. Useful for + stuff like virtual keyboards. Fixes bug #159890 + + * gtk/gtk.symbols + * gtk/gtkmenushell.[ch]: added boolean property "take-focus" + and public API gtk_menu_shell_set/get_take_focus(). + + * gtk/gtkmenu.c (gtk_menu_popup) + (popup_grab_on_window): don't grab the keyboard if take_focus + is FALSE. + + * gtk/gtkmenuitem.c (_gtk_menu_item_popup_submen): propagate the + parent menu_shell's take_focus property to the submenu which is + about to be popped up. + 2005-03-30 Federico Mena Quintero <federico@ximian.com> Merged from gtk-2-6: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index fce692ad17..d41547d3ac 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,20 @@ +2005-03-31 Michael Natterer <mitch@gimp.org> + + Allow to pop up menus without grabbing the keyboard. Useful for + stuff like virtual keyboards. Fixes bug #159890 + + * gtk/gtk.symbols + * gtk/gtkmenushell.[ch]: added boolean property "take-focus" + and public API gtk_menu_shell_set/get_take_focus(). + + * gtk/gtkmenu.c (gtk_menu_popup) + (popup_grab_on_window): don't grab the keyboard if take_focus + is FALSE. + + * gtk/gtkmenuitem.c (_gtk_menu_item_popup_submen): propagate the + parent menu_shell's take_focus property to the submenu which is + about to be popped up. + 2005-03-30 Federico Mena Quintero <federico@ximian.com> Merged from gtk-2-6: diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols index 05d4a5f3ba..4bee95dd78 100644 --- a/gtk/gtk.symbols +++ b/gtk/gtk.symbols @@ -2128,6 +2128,8 @@ gtk_menu_shell_insert gtk_menu_shell_prepend gtk_menu_shell_select_first gtk_menu_shell_select_item +gtk_menu_shell_set_take_focus +gtk_menu_shell_get_take_focus #endif #endif diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 31a9c360b8..2dfa0c22af 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -1221,7 +1221,8 @@ gtk_menu_tearoff_bg_copy (GtkMenu *menu) static gboolean popup_grab_on_window (GdkWindow *window, - guint32 activate_time) + guint32 activate_time, + gboolean grab_keyboard) { if ((gdk_pointer_grab (window, TRUE, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | @@ -1229,7 +1230,8 @@ popup_grab_on_window (GdkWindow *window, GDK_POINTER_MOTION_MASK, NULL, NULL, activate_time) == 0)) { - if (gdk_keyboard_grab (window, TRUE, + if (!grab_keyboard || + gdk_keyboard_grab (window, TRUE, activate_time) == 0) return TRUE; else @@ -1283,13 +1285,15 @@ gtk_menu_popup (GtkMenu *menu, GtkWidget *parent; GdkEvent *current_event; GtkMenuShell *menu_shell; - GtkMenuPrivate *priv = gtk_menu_get_private (menu); + gboolean grab_keyboard; + GtkMenuPrivate *priv; g_return_if_fail (GTK_IS_MENU (menu)); widget = GTK_WIDGET (menu); menu_shell = GTK_MENU_SHELL (menu); - + priv = gtk_menu_get_private (menu); + menu_shell->parent_menu_shell = parent_menu_shell; priv->seen_item_enter = FALSE; @@ -1334,9 +1338,12 @@ gtk_menu_popup (GtkMenu *menu, * probably could just leave the grab on the other window, with a * little reorganization of the code in gtkmenu*). */ + grab_keyboard = gtk_menu_shell_get_take_focus (menu_shell); + gtk_window_set_accept_focus (GTK_WINDOW (menu->toplevel), grab_keyboard); + if (xgrab_shell && xgrab_shell != widget) { - if (popup_grab_on_window (xgrab_shell->window, activate_time)) + if (popup_grab_on_window (xgrab_shell->window, activate_time, grab_keyboard)) GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE; } else @@ -1345,7 +1352,7 @@ gtk_menu_popup (GtkMenu *menu, xgrab_shell = widget; transfer_window = menu_grab_transfer_window_get (menu); - if (popup_grab_on_window (transfer_window, activate_time)) + if (popup_grab_on_window (transfer_window, activate_time, grab_keyboard)) GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE; } @@ -1437,7 +1444,7 @@ gtk_menu_popup (GtkMenu *menu, gtk_widget_show (menu->toplevel); if (xgrab_shell == widget) - popup_grab_on_window (widget->window, activate_time); /* Should always succeed */ + popup_grab_on_window (widget->window, activate_time, grab_keyboard); /* Should always succeed */ gtk_grab_add (GTK_WIDGET (menu)); } diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index c9e5e3a6dc..433cc41022 100644 --- a/gtk/gtkmenuitem.c +++ b/gtk/gtkmenuitem.c @@ -1054,13 +1054,21 @@ _gtk_menu_item_popup_submenu (GtkWidget *widget) menu_item->timer = 0; if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu)) - gtk_menu_popup (GTK_MENU (menu_item->submenu), - widget->parent, - widget, - gtk_menu_item_position_menu, - menu_item, - GTK_MENU_SHELL (widget->parent)->button, - 0); + { + gboolean take_focus; + + take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent)); + gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu), + take_focus); + + gtk_menu_popup (GTK_MENU (menu_item->submenu), + widget->parent, + widget, + gtk_menu_item_position_menu, + menu_item, + GTK_MENU_SHELL (widget->parent)->button, + 0); + } } static void diff --git a/gtk/gtkmenushell.c b/gtk/gtkmenushell.c index f2986ddede..1534bbed02 100644 --- a/gtk/gtkmenushell.c +++ b/gtk/gtkmenushell.c @@ -38,6 +38,8 @@ #include "gtkmnemonichash.h" #include "gtktearoffmenuitem.h" #include "gtkwindow.h" +#include "gtkprivate.h" +#include "gtkintl.h" #include "gtkalias.h" #define MENU_SHELL_TIMEOUT 500 @@ -57,6 +59,11 @@ enum { LAST_SIGNAL }; +enum { + PROP_0, + PROP_TAKE_FOCUS +}; + typedef void (*GtkMenuShellSignal1) (GtkObject *object, GtkMenuDirectionType arg1, gpointer data); @@ -131,10 +138,20 @@ struct _GtkMenuShellPrivate { GtkMnemonicHash *mnemonic_hash; GtkKeyHash *key_hash; + + gboolean take_focus; }; static void gtk_menu_shell_class_init (GtkMenuShellClass *klass); static void gtk_menu_shell_init (GtkMenuShell *menu_shell); +static void gtk_menu_shell_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_menu_shell_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); static void gtk_menu_shell_realize (GtkWidget *widget); static void gtk_menu_shell_finalize (GObject *object); static gint gtk_menu_shell_button_press (GtkWidget *widget, @@ -230,6 +247,8 @@ gtk_menu_shell_class_init (GtkMenuShellClass *klass) parent_class = g_type_class_peek_parent (klass); + object_class->set_property = gtk_menu_shell_set_property; + object_class->get_property = gtk_menu_shell_get_property; object_class->finalize = gtk_menu_shell_finalize; widget_class->realize = gtk_menu_shell_realize; @@ -340,6 +359,23 @@ gtk_menu_shell_class_init (GtkMenuShellClass *klass) "cycle_focus", 1, GTK_TYPE_DIRECTION_TYPE, GTK_DIR_TAB_BACKWARD); + /** + * GtkMenuShell:take-focus: + * + * A boolean that determines whether the menu and its submenus grab the + * keyboard focus. See gtk_menu_shell_set_take_focus() and + * gtk_menu_shell_get_take_focus(). + * + * Since: 2.8 + **/ + g_object_class_install_property (object_class, + PROP_TAKE_FOCUS, + g_param_spec_boolean ("take-focus", + P_("Take Focus"), + P_("A boolean that determines whether the menu grabs the keyboard focus"), + TRUE, + GTK_PARAM_READWRITE)); + g_type_class_add_private (object_class, sizeof (GtkMenuShellPrivate)); } @@ -365,6 +401,45 @@ gtk_menu_shell_init (GtkMenuShell *menu_shell) priv->mnemonic_hash = NULL; priv->key_hash = NULL; + priv->take_focus = TRUE; +} + +static void +gtk_menu_shell_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkMenuShell *menu_shell = GTK_MENU_SHELL (object); + + switch (prop_id) + { + case PROP_TAKE_FOCUS: + gtk_menu_shell_set_take_focus (menu_shell, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gtk_menu_shell_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkMenuShell *menu_shell = GTK_MENU_SHELL (object); + + switch (prop_id) + { + case PROP_TAKE_FOCUS: + g_value_set_boolean (value, gtk_menu_shell_get_take_focus (menu_shell)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } } static void @@ -1388,5 +1463,75 @@ _gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell, gtk_menu_shell_reset_key_hash (menu_shell); } +/** + * gtk_menu_shell_get_take_focus: + * @menu: a #GtkMenuShell + * + * @returns: %TRUE if the menu_shell will take the keyboard focus on popup. + * + * Since: 2.8 + **/ +gboolean +gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell) +{ + GtkMenuShellPrivate *priv; + + g_return_val_if_fail (GTK_IS_MENU_SHELL (menu_shell), FALSE); + + priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell); + + return priv->take_focus; +} + +/** + * gtk_menu_shell_set_take_focus: + * @menu: a #GtkMenuShell + * @take_focus: %TRUE if the menu_shell should take the keyboard focus on popup. + * + * If @take_focus is %TRUE (the default) the menu will take the keyboard focus + * so that it will receive all keyboard events which is needed to enable + * keyboard navigation in menus. + * + * Setting @take_focus to %FALSE is useful only for special applications + * like virtual keyboard implementations which should not take keyboard + * focus. + * + * The @take_focus state of a menu or menu bar is automatically propagated + * to submenus whenever a submenu is popped up, so you don't have to worry + * about recursively setting it for your entire menu hierarchy. Only when + * programmatically picking a submenu and popping it up manually, the + * @take_focus property of the submenu needs to be set explicitely. + * + * Note that setting it to %FALSE has side-effects: + * + * If the focus is in some other app, it keeps the focus and keynav in + * the menu doesn't work. Consequently, keynav on the menu will only + * work if the focus is on some toplevel owned by the onscreen keyboard. + * + * To avoid confusing the user, menus with @take_focus set to %FALSE + * should not display mnemonics or accelerators, since it cannot be + * guaranteed that they will work. + * + * See also gdk_keyboard_grab() + * + * Since: 2.8 + **/ +void +gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell, + gboolean take_focus) +{ + GtkMenuShellPrivate *priv; + + g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell)); + + priv = GTK_MENU_SHELL_GET_PRIVATE (menu_shell); + + if (priv->take_focus != take_focus) + { + priv->take_focus = take_focus; + g_object_notify (G_OBJECT (menu_shell), "take-focus"); + } +} + #define __GTK_MENU_SHELL_C__ #include "gtkaliasdef.c" diff --git a/gtk/gtkmenushell.h b/gtk/gtkmenushell.h index a0b48f4317..9a4b3a0147 100644 --- a/gtk/gtkmenushell.h +++ b/gtk/gtkmenushell.h @@ -115,12 +115,16 @@ void _gtk_menu_shell_activate (GtkMenuShell *menu_shell); gint _gtk_menu_shell_get_popup_delay (GtkMenuShell *menu_shell); void gtk_menu_shell_cancel (GtkMenuShell *menu_shell); -void _gtk_menu_shell_add_mnemonic (GtkMenuShell *menu_shell, - guint keyval, - GtkWidget *target); -void _gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell, - guint keyval, - GtkWidget *target); +void _gtk_menu_shell_add_mnemonic (GtkMenuShell *menu_shell, + guint keyval, + GtkWidget *target); +void _gtk_menu_shell_remove_mnemonic (GtkMenuShell *menu_shell, + guint keyval, + GtkWidget *target); + +gboolean gtk_menu_shell_get_take_focus (GtkMenuShell *menu_shell); +void gtk_menu_shell_set_take_focus (GtkMenuShell *menu_shell, + gboolean take_focus); G_END_DECLS |