* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+/**
+ * SECTION:gtkmenushell
+ * @Title: GtkMenuShell
+ * @Short_description: A base class for menu objects
+ *
+ * A #GtkMenuShell is the abstract base class used to derive the
+ * #GtkMenu and #GtkMenuBar subclasses.
+ *
+ * A #GtkMenuShell is a container of #GtkMenuItem objects arranged
+ * in a list which can be navigated, selected, and activated by the
+ * user to perform application functions. A #GtkMenuItem can have a
+ * submenu associated with it, allowing for nested hierarchical menus.
+ */
#include "config.h"
#include "gtkbindings.h"
#include "gtkmenushellprivate.h"
#include "gtkmenuprivate.h"
#include "gtkmnemonichash.h"
-#include "gtktearoffmenuitem.h"
#include "gtkwindow.h"
#include "gtkprivate.h"
+#include "gtkmain.h"
#include "gtkintl.h"
+#include "gtktypebuiltins.h"
+
+#include "deprecated/gtktearoffmenuitem.h"
+
+#include "a11y/gtkmenushellaccessible.h"
+
#define MENU_SHELL_TIMEOUT 500
CANCEL,
CYCLE_FOCUS,
MOVE_SELECTED,
+ INSERT,
LAST_SIGNAL
};
klass->insert = gtk_menu_shell_real_insert;
klass->move_selected = gtk_menu_shell_real_move_selected;
+ /**
+ * GtkMenuShell::deactivate:
+ * @menushell: the object which received the signal
+ *
+ * This signal is emitted when a menu shell is deactivated.
+ */
menu_shell_signals[DEACTIVATE] =
g_signal_new (I_("deactivate"),
G_OBJECT_CLASS_TYPE (object_class),
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+ /**
+ * GtkMenuShell::selection-done:
+ * @menushell: the object which received the signal
+ *
+ * This signal is emitted when a selection has been
+ * completed within a menu shell.
+ */
menu_shell_signals[SELECTION_DONE] =
g_signal_new (I_("selection-done"),
G_OBJECT_CLASS_TYPE (object_class),
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+ /**
+ * GtkMenuShell::move-current:
+ * @menushell: the object which received the signal
+ * @direction: the direction to move
+ *
+ * An keybinding signal which moves the current menu item
+ * in the direction specified by @direction.
+ */
menu_shell_signals[MOVE_CURRENT] =
g_signal_new (I_("move-current"),
G_OBJECT_CLASS_TYPE (object_class),
G_TYPE_NONE, 1,
GTK_TYPE_MENU_DIRECTION_TYPE);
+ /**
+ * GtkMenuShell::activate-current:
+ * @menushell: the object which received the signal
+ * @force_hide: if %TRUE, hide the menu after activating the menu item
+ *
+ * An action signal that activates the current menu item within
+ * the menu shell.
+ */
menu_shell_signals[ACTIVATE_CURRENT] =
g_signal_new (I_("activate-current"),
G_OBJECT_CLASS_TYPE (object_class),
G_TYPE_NONE, 1,
G_TYPE_BOOLEAN);
+ /**
+ * GtkMenuShell::cancel:
+ * @menushell: the object which received the signal
+ *
+ * An action signal which cancels the selection within the menu shell.
+ * Causes the #GtkMenuShell::selection-done signal to be emitted.
+ */
menu_shell_signals[CANCEL] =
g_signal_new (I_("cancel"),
G_OBJECT_CLASS_TYPE (object_class),
_gtk_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+ /**
+ * GtkMenuShell::cycle-focus:
+ * @menushell: the object which received the signal
+ * @direction: the direction to cycle in
+ *
+ * A keybinding signal which moves the focus in the
+ * given @direction.
+ */
menu_shell_signals[CYCLE_FOCUS] =
g_signal_new_class_handler (I_("cycle-focus"),
G_OBJECT_CLASS_TYPE (object_class),
G_TYPE_BOOLEAN, 1,
G_TYPE_INT);
+ /**
+ * GtkMenuShell::insert:
+ * @menu_shell: the object on which the signal is emitted
+ * @child: the #GtkMenuItem that is being inserted
+ * @position: the position at which the insert occurs
+ *
+ * The ::insert signal is emitted when a new #GtkMenuItem is added to
+ * a #GtkMenuShell. A separate signal is used instead of
+ * GtkContainer::add because of the need for an additional position
+ * parameter.
+ *
+ * The inverse of this signal is the GtkContainer::removed signal.
+ *
+ * Since: 3.2
+ **/
+ menu_shell_signals[INSERT] =
+ g_signal_new (I_("insert"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GtkMenuShellClass, insert),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT_INT,
+ G_TYPE_NONE, 2, GTK_TYPE_WIDGET, G_TYPE_INT);
+
+
binding_set = gtk_binding_set_by_class (klass);
gtk_binding_entry_add_signal (binding_set,
GDK_KEY_Escape, 0,
TRUE,
GTK_PARAM_READWRITE));
+ gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_MENU_SHELL_ACCESSIBLE);
+
g_type_class_add_private (object_class, sizeof (GtkMenuShellPrivate));
}
G_OBJECT_CLASS (gtk_menu_shell_parent_class)->dispose (object);
}
+/**
+ * gtk_menu_shell_append:
+ * @menu_shell: a #GtkMenuShell
+ * @child: The #GtkMenuItem to add
+ *
+ * Adds a new #GtkMenuItem to the end of the menu shell's
+ * item list.
+ */
void
gtk_menu_shell_append (GtkMenuShell *menu_shell,
GtkWidget *child)
gtk_menu_shell_insert (menu_shell, child, -1);
}
+/**
+ * gtk_menu_shell_prepend:
+ * @menu_shell: a #GtkMenuShell
+ * @child: The #GtkMenuItem to add
+ *
+ * Adds a new #GtkMenuItem to the beginning of the menu shell's
+ * item list.
+ */
void
gtk_menu_shell_prepend (GtkMenuShell *menu_shell,
GtkWidget *child)
gtk_menu_shell_insert (menu_shell, child, 0);
}
+/**
+ * gtk_menu_shell_insert:
+ * @menu_shell: a #GtkMenuShell
+ * @child: The #GtkMenuItem to add
+ * @position: The position in the item list where @child
+ * is added. Positions are numbered from 0 to n-1
+ *
+ * Adds a new #GtkMenuItem to the menu shell's item list
+ * at the position indicated by @position.
+ */
void
gtk_menu_shell_insert (GtkMenuShell *menu_shell,
GtkWidget *child,
gint position)
{
- GtkMenuShellClass *class;
-
g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
g_return_if_fail (GTK_IS_MENU_ITEM (child));
- class = GTK_MENU_SHELL_GET_CLASS (menu_shell);
-
- if (class->insert)
- class->insert (menu_shell, child, position);
+ g_signal_emit (menu_shell, menu_shell_signals[INSERT], 0, child, position);
}
static void
gtk_widget_set_parent (child, GTK_WIDGET (menu_shell));
}
+/**
+ * gtk_menu_shell_deactivate:
+ * @menu_shell: a #GtkMenuShell
+ *
+ * Deactivates the menu shell.
+ *
+ * Typically this results in the menu shell being erased
+ * from the screen.
+ */
void
gtk_menu_shell_deactivate (GtkMenuShell *menu_shell)
{
g_return_if_fail (GTK_IS_MENU_SHELL (menu_shell));
- g_signal_emit (menu_shell, menu_shell_signals[DEACTIVATE], 0);
+ if (menu_shell->priv->active)
+ g_signal_emit (menu_shell, menu_shell_signals[DEACTIVATE], 0);
}
static void
GdkWindow *window;
GdkWindowAttr attributes;
gint attributes_mask;
+ GtkStyleContext *context;
gtk_widget_set_realized (widget, TRUE);
window = gdk_window_new (gtk_widget_get_parent_window (widget),
&attributes, attributes_mask);
gtk_widget_set_window (widget, window);
- gdk_window_set_user_data (window, widget);
+ gtk_widget_register_window (widget, window);
- gtk_widget_style_attach (widget);
- gtk_style_set_background (gtk_widget_get_style (widget), window, GTK_STATE_NORMAL);
+ context = gtk_widget_get_style_context (widget);
+ gtk_style_context_set_background (context, window);
}
-void
-_gtk_menu_shell_activate (GtkMenuShell *menu_shell)
+static void
+gtk_menu_shell_activate (GtkMenuShell *menu_shell)
{
GtkMenuShellPrivate *priv = menu_shell->priv;
gtk_widget_get_parent (menu_item) == widget &&
menu_item != priv->active_menu_item)
{
- _gtk_menu_shell_activate (menu_shell);
+ gtk_menu_shell_activate (menu_shell);
priv->button = event->button;
if (GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement == GTK_TOP_BOTTOM)
if (event->detail != GDK_NOTIFY_INFERIOR)
{
- if (gtk_widget_get_state (menu_item) != GTK_STATE_PRELIGHT)
+ if ((gtk_widget_get_state_flags (menu_item) & GTK_STATE_FLAG_PRELIGHT) == 0)
gtk_menu_shell_select_item (menu_shell, menu_item);
/* If any mouse button is down, and there is a submenu
if (!gtk_widget_get_visible (GTK_MENU_ITEM (menu_item)->priv->submenu))
{
- gboolean touchscreen_mode;
+ GdkDevice *source_device;
- g_object_get (gtk_widget_get_settings (widget),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
+ source_device = gdk_event_get_source_device ((GdkEvent *) event);
- if (touchscreen_mode)
+ if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)
_gtk_menu_item_popup_submenu (menu_item, TRUE);
}
}
GdkEventCrossing *event)
{
if (event->mode == GDK_CROSSING_GTK_GRAB ||
- event->mode == GDK_CROSSING_GTK_GRAB ||
+ event->mode == GDK_CROSSING_GTK_UNGRAB ||
event->mode == GDK_CROSSING_STATE_CHANGED)
return TRUE;
(menu_item->priv->submenu == NULL))
{
if ((event->detail != GDK_NOTIFY_INFERIOR) &&
- (gtk_widget_get_state (GTK_WIDGET (menu_item)) != GTK_STATE_NORMAL))
+ (gtk_widget_get_state_flags (GTK_WIDGET (menu_item)) & GTK_STATE_FLAG_PRELIGHT) != 0)
{
gtk_menu_shell_deselect (menu_shell);
}
if (priv->active)
{
-
priv->button = 0;
priv->active = FALSE;
priv->activate_time = 0;
/* Handlers for action signals */
+/**
+ * gtk_menu_shell_select_item:
+ * @menu_shell: a #GtkMenuShell
+ * @menu_item: The #GtkMenuItem to select
+ *
+ * Selects the menu item from the menu shell.
+ */
void
gtk_menu_shell_select_item (GtkMenuShell *menu_shell,
GtkWidget *menu_item)
return;
}
+ gtk_menu_shell_activate (menu_shell);
+
priv->active_menu_item = menu_item;
if (pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT)
_gtk_menu_item_set_placement (GTK_MENU_ITEM (priv->active_menu_item),
gtk_widget_activate (priv->active_menu_item);
}
+/**
+ * gtk_menu_shell_deselect:
+ * @menu_shell: a #GtkMenuShell
+ *
+ * Deselects the currently selected item from the menu shell,
+ * if any.
+ */
void
gtk_menu_shell_deselect (GtkMenuShell *menu_shell)
{
}
}
+/**
+ * gtk_menu_shell_activate_item:
+ * @menu_shell: a #GtkMenuShell
+ * @menu_item: the #GtkMenuItem to activate
+ * @force_deactivate: if %TRUE, force the deactivation of the
+ * menu shell after the menu item is activated
+ *
+ * Activates the menu item within the menu shell.
+ */
void
gtk_menu_shell_activate_item (GtkMenuShell *menu_shell,
GtkWidget *menu_item,
GtkMenuShellPrivate *priv = menu_shell->priv;
GtkMenuShell *parent_menu_shell = NULL;
gboolean had_selection;
- gboolean touchscreen_mode;
priv->in_unselectable_item = FALSE;
had_selection = priv->active_menu_item != NULL;
- g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_shell)),
- "gtk-touchscreen-mode", &touchscreen_mode,
- NULL);
-
if (priv->parent_menu_shell)
parent_menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
switch (direction)
{
case GTK_MENU_DIR_PARENT:
- if (touchscreen_mode &&
- priv->active_menu_item &&
- GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu &&
- gtk_widget_get_visible (GTK_MENU_ITEM (priv->active_menu_item)->priv->submenu))
- {
- /* if we are on a menu item that has an open submenu but the
- * focus is not in that submenu (e.g. because it's empty or
- * has only insensitive items), close that submenu instead of
- * running into the code below which would close *this* menu.
- */
- _gtk_menu_item_popdown_submenu (priv->active_menu_item);
- _gtk_menu_shell_update_mnemonics (menu_shell);
- }
- else if (parent_menu_shell)
+ if (parent_menu_shell)
{
- if (touchscreen_mode)
- {
- /* close menu when returning from submenu. */
- _gtk_menu_item_popdown_submenu (GTK_MENU (menu_shell)->priv->parent_menu_item);
- _gtk_menu_shell_update_mnemonics (parent_menu_shell);
- break;
- }
-
if (GTK_MENU_SHELL_GET_CLASS (parent_menu_shell)->submenu_placement ==
GTK_MENU_SHELL_GET_CLASS (menu_shell)->submenu_placement)
gtk_menu_shell_deselect (menu_shell);
gtk_real_menu_shell_cycle_focus (GtkMenuShell *menu_shell,
GtkDirectionType dir)
{
- GtkMenuShellPrivate *priv = menu_shell->priv;
-
while (menu_shell && !GTK_IS_MENU_BAR (menu_shell))
{
- if (priv->parent_menu_shell)
- menu_shell = GTK_MENU_SHELL (priv->parent_menu_shell);
+ if (menu_shell->priv->parent_menu_shell)
+ menu_shell = GTK_MENU_SHELL (menu_shell->priv->parent_menu_shell);
else
menu_shell = NULL;
}
event->group);
if (entries)
- result = _gtk_mnemonic_hash_activate (mnemonic_hash,
- GPOINTER_TO_UINT (entries->data));
+ {
+ result = _gtk_mnemonic_hash_activate (mnemonic_hash,
+ GPOINTER_TO_UINT (entries->data));
+ g_slist_free (entries);
+ }
return result;
}
*
* Gets the currently selected item.
*
- * Returns: the currently selected item
+ * Returns: (transfer none): the currently selected item
*
* Since: 3.0
*/
* The parent menu shell of a submenu is the #GtkMenu or #GtkMenuBar
* from which it was opened up.
*
- * Returns: the parent #GtkMenuShell
+ * Returns: (transfer none): the parent #GtkMenuShell
*
* Since: 3.0
*/