summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Natterer <mitch@gimp.org>2005-03-31 17:02:19 +0000
committerMichael Natterer <mitch@src.gnome.org>2005-03-31 17:02:19 +0000
commit91cb92c01882f7a3b1014c594908873fc18a936c (patch)
treee18e289edfbd0dd442fac1df3d3c4439223b29da
parent420878b21e654c49ade3b5670aed281beaeb2508 (diff)
downloadgtk+-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--ChangeLog17
-rw-r--r--ChangeLog.pre-2-1017
-rw-r--r--ChangeLog.pre-2-817
-rw-r--r--gtk/gtk.symbols2
-rw-r--r--gtk/gtkmenu.c21
-rw-r--r--gtk/gtkmenuitem.c22
-rw-r--r--gtk/gtkmenushell.c145
-rw-r--r--gtk/gtkmenushell.h16
8 files changed, 237 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index fce692ad17..d41547d3ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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