generic-poky/openembedded/packages/gtk+/gtk+-2.6.4-1.osso7/gtkmenushell.c.diff

491 lines
15 KiB
Diff

--- gtk+-2.6.4/gtk/gtkmenushell.c 2005-02-09 18:46:54.000000000 +0200
+++ gtk+-2.6.4/gtk/gtkmenushell.c 2005-04-06 16:19:36.999913520 +0300
@@ -39,6 +39,8 @@
#include "gtkmnemonichash.h"
#include "gtktearoffmenuitem.h"
#include "gtkwindow.h"
+#include "gtkprivate.h"
+#include "gtkintl.h"
#define MENU_SHELL_TIMEOUT 500
@@ -52,6 +54,11 @@
LAST_SIGNAL
};
+enum {
+ PROP_0,
+ PROP_TAKE_FOCUS
+};
+
typedef void (*GtkMenuShellSignal1) (GtkObject *object,
GtkMenuDirectionType arg1,
gpointer data);
@@ -122,10 +129,20 @@
{
GtkMnemonicHash *mnemonic_hash;
GtkKeyHash *key_hash;
+ gboolean activated_submenu;
+ 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,
@@ -176,7 +193,6 @@
static GtkContainerClass *parent_class = NULL;
static guint menu_shell_signals[LAST_SIGNAL] = { 0 };
-
GType
gtk_menu_shell_get_type (void)
{
@@ -220,6 +236,8 @@
container_class = (GtkContainerClass*) 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;
@@ -299,9 +317,15 @@
binding_set = gtk_binding_set_by_class (klass);
+/* Hildon : The following binding is commented out
+ * because we want the Escape key to only exit the
+ * currently opened submenu. Therefore, the handling
+ * of esc-key will be moved to gtkmenuitem.c */
+/*
gtk_binding_entry_add_signal (binding_set,
GDK_Escape, 0,
"cancel", 0);
+*/
gtk_binding_entry_add_signal (binding_set,
GDK_Return, 0,
"activate_current", 1,
@@ -330,7 +354,23 @@
GDK_F10, GDK_SHIFT_MASK,
"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,
+ G_PARAM_READWRITE));
+
g_type_class_add_private (object_class, sizeof (GtkMenuShellPrivate));
}
@@ -356,6 +396,46 @@
priv->mnemonic_hash = NULL;
priv->key_hash = NULL;
+ priv->take_focus = TRUE;
+ priv->activated_submenu = FALSE;
+}
+
+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
@@ -470,6 +550,7 @@
gtk_menu_shell_button_press (GtkWidget *widget,
GdkEventButton *event)
{
+ GtkMenuShellPrivate *priv;
GtkMenuShell *menu_shell;
GtkWidget *menu_item;
@@ -479,7 +560,22 @@
if (event->type != GDK_BUTTON_PRESS)
return FALSE;
+ priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
+
menu_shell = GTK_MENU_SHELL (widget);
+ menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent*) event);
+
+ if (menu_shell->active && menu_item &&
+ (menu_shell->active_menu_item == menu_item) &&
+ _gtk_menu_item_is_selectable (menu_item) &&
+ GTK_MENU_ITEM (menu_item)->submenu != NULL &&
+ !GTK_WIDGET_VISIBLE (GTK_MENU_ITEM (menu_item)->submenu))
+ {
+ /* Hildon : We want to be able to activate submenu items. */
+ gtk_menu_shell_activate_item (menu_shell, menu_item, FALSE);
+
+ priv->activated_submenu = TRUE;
+ }
if (menu_shell->parent_menu_shell)
{
@@ -491,30 +587,29 @@
menu_shell->button = event->button;
- menu_item = gtk_menu_shell_get_item (menu_shell, (GdkEvent *)event);
-
if (menu_item && _gtk_menu_item_is_selectable (menu_item))
- {
- if ((menu_item->parent == widget) &&
- (menu_item != menu_shell->active_menu_item))
- {
- if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
- {
- menu_shell->activate_time = event->time;
- }
+ {
+
+ if ((menu_item->parent == widget) &&
+ (menu_item != menu_shell->active_menu_item))
+ {
+ if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
+ {
+ menu_shell->activate_time = event->time;
+ }
- gtk_menu_shell_select_item (menu_shell, menu_item);
- }
- }
+ gtk_menu_shell_select_item (menu_shell, menu_item);
+ }
+ }
}
else
{
widget = gtk_get_event_widget ((GdkEvent*) event);
if (widget == GTK_WIDGET (menu_shell))
- {
- gtk_menu_shell_deactivate (menu_shell);
- g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
- }
+ {
+ gtk_menu_shell_deactivate (menu_shell);
+ g_signal_emit (menu_shell, menu_shell_signals[SELECTION_DONE], 0);
+ }
}
return TRUE;
@@ -524,13 +619,20 @@
gtk_menu_shell_button_release (GtkWidget *widget,
GdkEventButton *event)
{
+ GtkMenuShellPrivate *priv;
GtkMenuShell *menu_shell;
GtkWidget *menu_item;
gint deactivate;
+ gboolean activated_submenu;
g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
+ priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
+
+ activated_submenu = priv->activated_submenu;
+ priv->activated_submenu = FALSE;
+
menu_shell = GTK_MENU_SHELL (widget);
if (menu_shell->active)
{
@@ -556,11 +658,11 @@
gtk_menu_shell_activate_item (menu_shell, menu_item, TRUE);
return TRUE;
}
- else if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement != GTK_TOP_BOTTOM)
- {
- gtk_menu_item_select (GTK_MENU_ITEM (menu_item));
- return TRUE;
- }
+ else if (!activated_submenu)
+ {
+ /* popdown the submenu if we didn't pop it up in this click */
+ _gtk_menu_item_popdown_submenu (menu_item);
+ }
}
else if (menu_item &&
!_gtk_menu_item_is_selectable (menu_item) &&
@@ -630,12 +732,14 @@
gtk_menu_shell_enter_notify (GtkWidget *widget,
GdkEventCrossing *event)
{
+ GtkMenuShellPrivate *priv;
GtkMenuShell *menu_shell;
GtkWidget *menu_item;
g_return_val_if_fail (GTK_IS_MENU_SHELL (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
+ priv = GTK_MENU_SHELL_GET_PRIVATE (widget);
menu_shell = GTK_MENU_SHELL (widget);
if (menu_shell->active)
@@ -658,6 +762,17 @@
(GTK_WIDGET_STATE (menu_item) != GTK_STATE_PRELIGHT))
{
gtk_menu_shell_select_item (menu_shell, menu_item);
+
+ /* If the pen is down, and there is a submenu that is not
+ * yet visible, activate it */
+ if ((event->state & GDK_BUTTON1_MASK) &&
+ GTK_MENU_ITEM (menu_item)->submenu != NULL &&
+ !GTK_WIDGET_VISIBLE (GTK_MENU_ITEM (menu_item)->submenu))
+ {
+ gtk_menu_shell_activate_item (menu_shell, menu_item, FALSE);
+
+ priv->activated_submenu = TRUE;
+ }
}
}
else if (menu_shell->parent_menu_shell)
@@ -887,8 +1002,14 @@
/* This allows the bizarre radio buttons-with-submenus-display-history
* behavior
*/
+ /* Hildon modification. We probably won't have those
+ * bizarre radio buttons-with-submenus so we don't
+ * need this. Also, this functionality interferes with
+ * other functionality. */
+/*
if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu)
gtk_widget_activate (menu_shell->active_menu_item);
+*/
}
void
@@ -919,7 +1040,9 @@
g_object_ref (menu_shell);
- if (deactivate)
+ /* We don't want to deactivate if we're activating
+ * a submenu item. */
+ if ((deactivate) && (GTK_MENU_ITEM (menu_item)->submenu == NULL))
{
GtkMenuShell *parent_menu_shell = menu_shell;
@@ -965,29 +1088,30 @@
if (distance > 0)
{
+ /*Hildon: selection no longer wraps around at the
+ *bottom of the menu*/
+
node = node->next;
- while (node != start_node &&
- (!node || !_gtk_menu_item_is_selectable (node->data)))
+ while (node && node != start_node &&
+ !_gtk_menu_item_is_selectable (node->data))
{
- if (!node)
- node = menu_shell->children;
- else
node = node->next;
}
}
else
{
+ /*Hildon: selection no longer wraps around at the top
+ *of the menu*/
+
node = node->prev;
- while (node != start_node &&
- (!node || !_gtk_menu_item_is_selectable (node->data)))
+ while (node && node != start_node &&
+ !_gtk_menu_item_is_selectable (node->data))
{
- if (!node)
- node = g_list_last (menu_shell->children);
- else
node = node->prev;
}
}
+ /*note: gtk_menu_shell_select_item won't select non-selectable items*/
if (node)
gtk_menu_shell_select_item (menu_shell, node->data);
}
@@ -1119,6 +1243,16 @@
switch (direction)
{
case GTK_MENU_DIR_PARENT:
+
+ if(!parent_menu_shell || GTK_IS_MENU_BAR(parent_menu_shell))
+ break;
+
+ /* hildon-modification - menu should be closed when returning from submenu.
+ * WARNING: This function is from GtkMenu, which normally
+ * shouldn't be called from GtkMenuShell, but currently
+ * there are no better alternatives. */
+ gtk_menu_popdown (GTK_MENU (menu_shell));
+
if (parent_menu_shell)
{
if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
@@ -1151,10 +1285,14 @@
_gtk_menu_item_is_selectable (menu_shell->active_menu_item) &&
GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu)
{
+ /* Hildon-modification -- submenu is not opened automatically but needs to be explicitly opened*/
+ g_signal_emit (G_OBJECT (menu_shell), menu_shell_signals[ACTIVATE_CURRENT], 0, (gint) FALSE);
+
if (gtk_menu_shell_select_submenu_first (menu_shell))
break;
}
+#if 0
/* Try to find a menu running the opposite direction */
while (parent_menu_shell &&
(GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
@@ -1173,6 +1311,7 @@
gtk_menu_shell_move_selected (parent_menu_shell, 1);
gtk_menu_shell_select_submenu_first (parent_menu_shell);
}
+#endif
break;
case GTK_MENU_DIR_PREV:
@@ -1197,8 +1336,8 @@
gtk_real_menu_shell_activate_current (GtkMenuShell *menu_shell,
gboolean force_hide)
{
- if (menu_shell->active_menu_item &&
- _gtk_menu_item_is_selectable (menu_shell->active_menu_item))
+ if (menu_shell->active_menu_item)/* &&
+ _gtk_menu_item_is_selectable (menu_shell->active_menu_item)) */
{
if (GTK_MENU_ITEM (menu_shell->active_menu_item)->submenu == NULL)
@@ -1390,4 +1529,73 @@
keyval, target);
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");
+ }
+}