491 lines
15 KiB
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");
|
|
+ }
|
|
+}
|
|
|