X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkmenuitem.c;h=73c2545dcbd32243d399b27eb8f521e8f2e8754e;hb=HEAD;hp=5bd093c181f19af8c89eecd20402e18afc8dc7cf;hpb=6f6c81e527d54cc84e4b8b55bd26a4fdb6f566d9;p=~andy%2Fgtk diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index 5bd093c18..73c2545dc 100644 --- a/gtk/gtkmenuitem.c +++ b/gtk/gtkmenuitem.c @@ -12,9 +12,7 @@ * 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 . */ /* @@ -25,26 +23,59 @@ */ #include "config.h" + #include #include "gtkaccellabel.h" #include "gtkmain.h" #include "gtkmarshalers.h" -#include "gtkmenu.h" +#include "gtkmenuprivate.h" +#include "gtkmenushellprivate.h" +#include "gtkmenuitemprivate.h" #include "gtkmenubar.h" #include "gtkmenuprivate.h" #include "gtkseparatormenuitem.h" #include "gtkprivate.h" #include "gtkbuildable.h" #include "gtkactivatable.h" -#include "gtksizerequest.h" +#include "gtkwidgetprivate.h" #include "gtkintl.h" +#include "gtksettings.h" +#include "gtktypebuiltins.h" +#include "a11y/gtkmenuitemaccessible.h" +#include "deprecated/gtktearoffmenuitem.h" +/** + * SECTION:gtkmenuitem + * @Short_description: The widget used for item in menus + * @Title: GtkMenuItem + * @See_also: #GtkBin, #GtkMenuShell + * + * The #GtkMenuItem widget and the derived widgets are the only valid + * childs for menus. Their function is to correctly handle highlighting, + * alignment, events and submenus. + * + * As it derives from #GtkBin it can hold any valid child widget, altough + * only a few are really useful. + * + * + * GtkMenuItem as GtkBuildable + * The GtkMenuItem implementation of the GtkBuildable interface + * supports adding a submenu by specifying "submenu" as the "type" + * attribute of a <child> element. + * + * A UI definition fragment with submenus + * + * + * + * + * + * ]]> + * + * + */ -typedef struct { - GtkAction *action; - gboolean use_action_appearance; -} GtkMenuItemPrivate; enum { ACTIVATE, @@ -66,22 +97,25 @@ enum { /* activatable properties */ PROP_ACTIVATABLE_RELATED_ACTION, - PROP_ACTIVATABLE_USE_ACTION_APPEARANCE + PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, + + PROP_ACTION_NAME, + PROP_ACTION_TARGET }; static void gtk_menu_item_dispose (GObject *object); static void gtk_menu_item_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); + guint prop_id, + const GValue *value, + GParamSpec *pspec); static void gtk_menu_item_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void gtk_menu_item_destroy (GtkObject *object); + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gtk_menu_item_destroy (GtkWidget *widget); static void gtk_menu_item_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); + GtkAllocation *allocation); static void gtk_menu_item_realize (GtkWidget *widget); static void gtk_menu_item_unrealize (GtkWidget *widget); static void gtk_menu_item_map (GtkWidget *widget); @@ -93,7 +127,7 @@ static gboolean gtk_menu_item_leave (GtkWidget *widget, static gboolean gtk_menu_item_draw (GtkWidget *widget, cairo_t *cr); static void gtk_menu_item_parent_set (GtkWidget *widget, - GtkWidget *previous_parent); + GtkWidget *previous_parent); static void gtk_real_menu_item_select (GtkMenuItem *item); @@ -101,96 +135,138 @@ static void gtk_real_menu_item_deselect (GtkMenuItem *item); static void gtk_real_menu_item_activate (GtkMenuItem *item); static void gtk_real_menu_item_activate_item (GtkMenuItem *item); static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item, - gint *requisition); + gint *requisition); static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item, - gint allocation); + gint allocation); static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget, - gboolean group_cycling); + gboolean group_cycling); static void gtk_menu_item_ensure_label (GtkMenuItem *menu_item); static gint gtk_menu_item_popup_timeout (gpointer data); static void gtk_menu_item_position_menu (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data); + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data); static void gtk_menu_item_show_all (GtkWidget *widget); -static void gtk_menu_item_hide_all (GtkWidget *widget); static void gtk_menu_item_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget, - guint signal_id); + guint signal_id); static void gtk_real_menu_item_set_label (GtkMenuItem *menu_item, - const gchar *label); -static G_CONST_RETURN gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item); - -static void gtk_menu_item_size_request_init (GtkSizeRequestIface *iface); -static void gtk_menu_item_get_width (GtkSizeRequest *widget, - gint *minimum_size, - gint *natural_size); -static void gtk_menu_item_get_height (GtkSizeRequest *widget, - gint *minimum_size, - gint *natural_size); -static void gtk_menu_item_get_height_for_width (GtkSizeRequest *widget, - gint for_size, - gint *minimum_size, - gint *natural_size); + const gchar *label); +static const gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item); + +static void gtk_menu_item_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_menu_item_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size); +static void gtk_menu_item_get_preferred_height_for_width (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size); static void gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface); static void gtk_menu_item_buildable_add_child (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const gchar *type); + GtkBuilder *builder, + GObject *child, + const gchar *type); static void gtk_menu_item_buildable_custom_finished(GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const gchar *tagname, - gpointer user_data); + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer user_data); +static void gtk_menu_item_actionable_interface_init (GtkActionableInterface *iface); static void gtk_menu_item_activatable_interface_init (GtkActivatableIface *iface); static void gtk_menu_item_update (GtkActivatable *activatable, - GtkAction *action, - const gchar *property_name); + GtkAction *action, + const gchar *property_name); static void gtk_menu_item_sync_action_properties (GtkActivatable *activatable, - GtkAction *action); + GtkAction *action); static void gtk_menu_item_set_related_action (GtkMenuItem *menu_item, - GtkAction *action); + GtkAction *action); static void gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item, - gboolean use_appearance); - + gboolean use_appearance); static guint menu_item_signals[LAST_SIGNAL] = { 0 }; static GtkBuildableIface *parent_buildable_iface; G_DEFINE_TYPE_WITH_CODE (GtkMenuItem, gtk_menu_item, GTK_TYPE_BIN, - G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, - gtk_menu_item_buildable_interface_init) - G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE, - gtk_menu_item_activatable_interface_init) - G_IMPLEMENT_INTERFACE (GTK_TYPE_SIZE_REQUEST, - gtk_menu_item_size_request_init)) + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, + gtk_menu_item_buildable_interface_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE, + gtk_menu_item_activatable_interface_init) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, + gtk_menu_item_actionable_interface_init)) + +static void +gtk_menu_item_set_action_name (GtkActionable *actionable, + const gchar *action_name) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable); -#define GET_PRIVATE(object) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((object), GTK_TYPE_MENU_ITEM, GtkMenuItemPrivate)) + if (!menu_item->priv->action_helper) + menu_item->priv->action_helper = gtk_action_helper_new (actionable); + + gtk_action_helper_set_action_name (menu_item->priv->action_helper, action_name); +} + +static void +gtk_menu_item_set_action_target_value (GtkActionable *actionable, + GVariant *action_target) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable); + + if (!menu_item->priv->action_helper) + menu_item->priv->action_helper = gtk_action_helper_new (actionable); + + gtk_action_helper_set_action_target_value (menu_item->priv->action_helper, action_target); +} + +static const gchar * +gtk_menu_item_get_action_name (GtkActionable *actionable) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable); + + return gtk_action_helper_get_action_name (menu_item->priv->action_helper); +} + +static GVariant * +gtk_menu_item_get_action_target_value (GtkActionable *actionable) +{ + GtkMenuItem *menu_item = GTK_MENU_ITEM (actionable); + + return gtk_action_helper_get_action_target_value (menu_item->priv->action_helper); +} + +static void +gtk_menu_item_actionable_interface_init (GtkActionableInterface *iface) +{ + iface->set_action_name = gtk_menu_item_set_action_name; + iface->get_action_name = gtk_menu_item_get_action_name; + iface->set_action_target_value = gtk_menu_item_set_action_target_value; + iface->get_action_target_value = gtk_menu_item_get_action_target_value; +} static void gtk_menu_item_class_init (GtkMenuItemClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass); - gobject_class->dispose = gtk_menu_item_dispose; + gobject_class->dispose = gtk_menu_item_dispose; gobject_class->set_property = gtk_menu_item_set_property; gobject_class->get_property = gtk_menu_item_get_property; - object_class->destroy = gtk_menu_item_destroy; - + widget_class->destroy = gtk_menu_item_destroy; widget_class->size_allocate = gtk_menu_item_size_allocate; widget_class->draw = gtk_menu_item_draw; widget_class->realize = gtk_menu_item_realize; @@ -200,62 +276,80 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) widget_class->enter_notify_event = gtk_menu_item_enter; widget_class->leave_notify_event = gtk_menu_item_leave; widget_class->show_all = gtk_menu_item_show_all; - widget_class->hide_all = gtk_menu_item_hide_all; widget_class->mnemonic_activate = gtk_menu_item_mnemonic_activate; widget_class->parent_set = gtk_menu_item_parent_set; widget_class->can_activate_accel = gtk_menu_item_can_activate_accel; - + widget_class->get_preferred_width = gtk_menu_item_get_preferred_width; + widget_class->get_preferred_height = gtk_menu_item_get_preferred_height; + widget_class->get_preferred_height_for_width = gtk_menu_item_get_preferred_height_for_width; + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_MENU_ITEM_ACCESSIBLE); + container_class->forall = gtk_menu_item_forall; - klass->activate = gtk_real_menu_item_activate; - klass->activate_item = gtk_real_menu_item_activate_item; - klass->toggle_size_request = gtk_real_menu_item_toggle_size_request; + klass->activate = gtk_real_menu_item_activate; + klass->activate_item = gtk_real_menu_item_activate_item; + klass->toggle_size_request = gtk_real_menu_item_toggle_size_request; klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate; - klass->set_label = gtk_real_menu_item_set_label; - klass->get_label = gtk_real_menu_item_get_label; - klass->select = gtk_real_menu_item_select; - klass->deselect = gtk_real_menu_item_deselect; + klass->set_label = gtk_real_menu_item_set_label; + klass->get_label = gtk_real_menu_item_get_label; + klass->select = gtk_real_menu_item_select; + klass->deselect = gtk_real_menu_item_deselect; klass->hide_on_activate = TRUE; + /** + * GtkMenuItem::activate: + * @menuitem: the object which received the signal. + * + * Emitted when the item is activated. + */ menu_item_signals[ACTIVATE] = g_signal_new (I_("activate"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GtkMenuItemClass, activate), - NULL, NULL, - _gtk_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GtkMenuItemClass, activate), + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); widget_class->activate_signal = menu_item_signals[ACTIVATE]; + /** + * GtkMenuItem::activate-item: + * @menuitem: the object which received the signal. + * + * Emitted when the item is activated, but also if the menu item has a + * submenu. For normal applications, the relevant signal is + * #GtkMenuItem::activate. + */ menu_item_signals[ACTIVATE_ITEM] = g_signal_new (I_("activate-item"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkMenuItemClass, activate_item), - NULL, NULL, - _gtk_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkMenuItemClass, activate_item), + NULL, NULL, + _gtk_marshal_VOID__VOID, + G_TYPE_NONE, 0); menu_item_signals[TOGGLE_SIZE_REQUEST] = g_signal_new (I_("toggle-size-request"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request), - NULL, NULL, - _gtk_marshal_VOID__POINTER, - G_TYPE_NONE, 1, - G_TYPE_POINTER); + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_request), + NULL, NULL, + _gtk_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); menu_item_signals[TOGGLE_SIZE_ALLOCATE] = g_signal_new (I_("toggle-size-allocate"), - G_OBJECT_CLASS_TYPE (gobject_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate), - NULL, NULL, - _gtk_marshal_VOID__INT, - G_TYPE_NONE, 1, - G_TYPE_INT); + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GtkMenuItemClass, toggle_size_allocate), + NULL, NULL, + _gtk_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); menu_item_signals[SELECT] = g_signal_new (I_("select"), @@ -278,25 +372,26 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) /** * GtkMenuItem:right-justified: * - * Sets whether the menu item appears justified at the right side of a menu bar. + * Sets whether the menu item appears justified + * at the right side of a menu bar. * * Since: 2.14 - **/ + */ g_object_class_install_property (gobject_class, PROP_RIGHT_JUSTIFIED, g_param_spec_boolean ("right-justified", P_("Right Justified"), P_("Sets whether the menu item appears justified at the right side of a menu bar"), FALSE, - GTK_PARAM_READWRITE)); + GTK_PARAM_READWRITE | G_PARAM_DEPRECATED)); /** * GtkMenuItem:submenu: * - * The submenu attached to the menu item, or NULL if it has none. + * The submenu attached to the menu item, or %NULL if it has none. * * Since: 2.12 - **/ + */ g_object_class_install_property (gobject_class, PROP_SUBMENU, g_param_spec_object ("submenu", @@ -304,7 +399,6 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) P_("The submenu attached to the menu item, or NULL if it has none"), GTK_TYPE_MENU, GTK_PARAM_READWRITE)); - /** * GtkMenuItem:accel-path: @@ -314,7 +408,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) * identified and saved to persistant storage. * * Since: 2.14 - **/ + */ g_object_class_install_property (gobject_class, PROP_ACCEL_PATH, g_param_spec_string ("accel-path", @@ -329,70 +423,83 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) * The text for the child label. * * Since: 2.16 - **/ + */ g_object_class_install_property (gobject_class, PROP_LABEL, g_param_spec_string ("label", - P_("Label"), - P_("The text for the child label"), - "", - GTK_PARAM_READWRITE)); + P_("Label"), + P_("The text for the child label"), + "", + GTK_PARAM_READWRITE)); /** * GtkMenuItem:use-underline: * - * %TRUE if underlines in the text indicate mnemonics + * %TRUE if underlines in the text indicate mnemonics. * * Since: 2.16 - **/ + */ g_object_class_install_property (gobject_class, PROP_USE_UNDERLINE, g_param_spec_boolean ("use-underline", - P_("Use underline"), - P_("If set, an underline in the text indicates " - "the next character should be used for the " - "mnemonic accelerator key"), - FALSE, - GTK_PARAM_READWRITE)); + P_("Use underline"), + P_("If set, an underline in the text indicates " + "the next character should be used for the " + "mnemonic accelerator key"), + FALSE, + GTK_PARAM_READWRITE)); g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action"); g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance"); + g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name"); + g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target"); + gtk_widget_class_install_style_property_parser (widget_class, - g_param_spec_enum ("selected-shadow-type", - "Selected Shadow Type", - "Shadow type when item is selected", - GTK_TYPE_SHADOW_TYPE, - GTK_SHADOW_NONE, - GTK_PARAM_READABLE), - gtk_rc_property_parse_enum); + g_param_spec_enum ("selected-shadow-type", + "Selected Shadow Type", + "Shadow type when item is selected", + GTK_TYPE_SHADOW_TYPE, + GTK_SHADOW_NONE, + GTK_PARAM_READABLE), + gtk_rc_property_parse_enum); + /** + * GtkMenuItem:horizontal-padding: + * + * Padding to left and right of the menu item. + * + * Deprecated: 3.8: use the standard padding CSS property (through objects + * like #GtkStyleContext and #GtkCssProvider); the value of this style + * property is ignored. + */ gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("horizontal-padding", - "Horizontal Padding", - "Padding to left and right of the menu item", - 0, - G_MAXINT, - 3, - GTK_PARAM_READABLE)); + g_param_spec_int ("horizontal-padding", + "Horizontal Padding", + "Padding to left and right of the menu item", + 0, + G_MAXINT, + 0, + GTK_PARAM_READABLE | + G_PARAM_DEPRECATED)); gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("toggle-spacing", - "Icon Spacing", - "Space between icon and label", - 0, - G_MAXINT, - 5, - GTK_PARAM_READABLE)); + g_param_spec_int ("toggle-spacing", + "Icon Spacing", + "Space between icon and label", + 0, + G_MAXINT, + 5, + GTK_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("arrow-spacing", - "Arrow Spacing", - "Space between label and arrow", - 0, - G_MAXINT, - 10, - GTK_PARAM_READABLE)); + g_param_spec_int ("arrow-spacing", + "Arrow Spacing", + "Space between label and arrow", + 0, + G_MAXINT, + 10, + GTK_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, g_param_spec_float ("arrow-scaling", @@ -407,7 +514,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) * The minimum desired width of the menu item in characters. * * Since: 2.14 - **/ + */ gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("width-chars", P_("Width in Characters"), @@ -415,95 +522,137 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) 0, G_MAXINT, 12, GTK_PARAM_READABLE)); - g_type_class_add_private (object_class, sizeof (GtkMenuItemPrivate)); + g_type_class_add_private (klass, sizeof (GtkMenuItemPrivate)); } static void gtk_menu_item_init (GtkMenuItem *menu_item) { - GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + GtkStyleContext *context; + GtkMenuItemPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (menu_item, + GTK_TYPE_MENU_ITEM, + GtkMenuItemPrivate); + menu_item->priv = priv; gtk_widget_set_has_window (GTK_WIDGET (menu_item), FALSE); priv->action = NULL; priv->use_action_appearance = TRUE; - menu_item->submenu = NULL; - menu_item->toggle_size = 0; - menu_item->accelerator_width = 0; - menu_item->show_submenu_indicator = FALSE; + menu_item->priv->submenu = NULL; + menu_item->priv->toggle_size = 0; + menu_item->priv->accelerator_width = 0; if (gtk_widget_get_direction (GTK_WIDGET (menu_item)) == GTK_TEXT_DIR_RTL) - menu_item->submenu_direction = GTK_DIRECTION_LEFT; + priv->submenu_direction = GTK_DIRECTION_LEFT; else - menu_item->submenu_direction = GTK_DIRECTION_RIGHT; - menu_item->submenu_placement = GTK_TOP_BOTTOM; - menu_item->right_justify = FALSE; + priv->submenu_direction = GTK_DIRECTION_RIGHT; + priv->submenu_placement = GTK_TOP_BOTTOM; + priv->right_justify = FALSE; + priv->use_action_appearance = TRUE; + priv->timer = 0; + priv->action = NULL; - menu_item->timer = 0; + context = gtk_widget_get_style_context (GTK_WIDGET (menu_item)); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUITEM); } +/** + * gtk_menu_item_new: + * + * Creates a new #GtkMenuItem. + * + * Returns: the newly created #GtkMenuItem + */ GtkWidget* gtk_menu_item_new (void) { return g_object_new (GTK_TYPE_MENU_ITEM, NULL); } +/** + * gtk_menu_item_new_with_label: + * @label: the text for the label + * + * Creates a new #GtkMenuItem whose child is a #GtkLabel. + * + * Returns: the newly created #GtkMenuItem + */ GtkWidget* gtk_menu_item_new_with_label (const gchar *label) { - return g_object_new (GTK_TYPE_MENU_ITEM, - "label", label, - NULL); + return g_object_new (GTK_TYPE_MENU_ITEM, + "label", label, + NULL); } /** * gtk_menu_item_new_with_mnemonic: * @label: The text of the button, with an underscore in front of the - * mnemonic character - * @returns: a new #GtkMenuItem + * mnemonic character * - * Creates a new #GtkMenuItem containing a label. The label - * will be created using gtk_label_new_with_mnemonic(), so underscores - * in @label indicate the mnemonic for the menu item. - **/ + * Creates a new #GtkMenuItem containing a label. + * + * The label will be created using gtk_label_new_with_mnemonic(), + * so underscores in @label indicate the mnemonic for the menu item. + * + * Returns: a new #GtkMenuItem + */ GtkWidget* gtk_menu_item_new_with_mnemonic (const gchar *label) { - return g_object_new (GTK_TYPE_MENU_ITEM, - "use-underline", TRUE, - "label", label, - NULL); + return g_object_new (GTK_TYPE_MENU_ITEM, + "use-underline", TRUE, + "label", label, + NULL); } static void gtk_menu_item_dispose (GObject *object) { GtkMenuItem *menu_item = GTK_MENU_ITEM (object); - GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + GtkMenuItemPrivate *priv = menu_item->priv; + + g_clear_object (&priv->action_helper); if (priv->action) { gtk_action_disconnect_accelerator (priv->action); gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), NULL); - priv->action = NULL; } G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object); } -static void +static void +gtk_menu_item_do_set_right_justified (GtkMenuItem *menu_item, + gboolean right_justified) +{ + GtkMenuItemPrivate *priv = menu_item->priv; + + right_justified = right_justified != FALSE; + + if (priv->right_justify != right_justified) + { + priv->right_justify = right_justified; + gtk_widget_queue_resize (GTK_WIDGET (menu_item)); + } +} + +static void gtk_menu_item_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) + guint prop_id, + const GValue *value, + GParamSpec *pspec) { GtkMenuItem *menu_item = GTK_MENU_ITEM (object); - + switch (prop_id) { case PROP_RIGHT_JUSTIFIED: - gtk_menu_item_set_right_justified (menu_item, g_value_get_boolean (value)); + gtk_menu_item_do_set_right_justified (menu_item, g_value_get_boolean (value)); break; case PROP_SUBMENU: gtk_menu_item_set_submenu (menu_item, g_value_get_object (value)); @@ -523,25 +672,31 @@ gtk_menu_item_set_property (GObject *object, case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: gtk_menu_item_set_use_action_appearance (menu_item, g_value_get_boolean (value)); break; + case PROP_ACTION_NAME: + gtk_menu_item_set_action_name (GTK_ACTIONABLE (menu_item), g_value_get_string (value)); + break; + case PROP_ACTION_TARGET: + gtk_menu_item_set_action_target_value (GTK_ACTIONABLE (menu_item), g_value_get_variant (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -static void +static void gtk_menu_item_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) + guint prop_id, + GValue *value, + GParamSpec *pspec) { GtkMenuItem *menu_item = GTK_MENU_ITEM (object); - GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); - + GtkMenuItemPrivate *priv = menu_item->priv; + switch (prop_id) { case PROP_RIGHT_JUSTIFIED: - g_value_set_boolean (value, gtk_menu_item_get_right_justified (menu_item)); + g_value_set_boolean (value, menu_item->priv->right_justify); break; case PROP_SUBMENU: g_value_set_object (value, gtk_menu_item_get_submenu (menu_item)); @@ -561,6 +716,12 @@ gtk_menu_item_get_property (GObject *object, case PROP_ACTIVATABLE_USE_ACTION_APPEARANCE: g_value_set_boolean (value, priv->use_action_appearance); break; + case PROP_ACTION_NAME: + g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper)); + break; + case PROP_ACTION_TARGET: + g_value_set_variant (value, gtk_action_helper_get_action_target_value (priv->action_helper)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -568,59 +729,68 @@ gtk_menu_item_get_property (GObject *object, } static void -gtk_menu_item_destroy (GtkObject *object) +gtk_menu_item_destroy (GtkWidget *widget) { - GtkMenuItem *menu_item = GTK_MENU_ITEM (object); + GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; - if (menu_item->submenu) - gtk_widget_destroy (menu_item->submenu); + if (priv->submenu) + gtk_widget_destroy (priv->submenu); - GTK_OBJECT_CLASS (gtk_menu_item_parent_class)->destroy (object); + GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->destroy (widget); } static void gtk_menu_item_detacher (GtkWidget *widget, - GtkMenu *menu) + GtkMenu *menu) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; - g_return_if_fail (menu_item->submenu == (GtkWidget*) menu); + g_return_if_fail (priv->submenu == (GtkWidget*) menu); - menu_item->submenu = NULL; + priv->submenu = NULL; } static void get_arrow_size (GtkWidget *widget, - GtkWidget *child, - gint *size) + GtkWidget *child, + gint *size, + gint *spacing) { PangoContext *context; PangoFontMetrics *metrics; gfloat arrow_scaling; - + gint arrow_spacing; + g_assert (size); gtk_widget_style_get (widget, - "arrow-scaling", &arrow_scaling, - NULL); - + "arrow-scaling", &arrow_scaling, + "arrow-spacing", &arrow_spacing, + NULL); + + if (spacing != NULL) + *spacing = arrow_spacing; + context = gtk_widget_get_pango_context (child); - metrics = pango_context_get_metrics (context, - gtk_widget_get_style (child)->font_desc, - pango_context_get_language (context)); - + + metrics = pango_context_get_metrics (context, + pango_context_get_font_description (context), + pango_context_get_language (context)); + *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + - pango_font_metrics_get_descent (metrics))); - + pango_font_metrics_get_descent (metrics))); + pango_font_metrics_unref (metrics); - + *size = *size * arrow_scaling; } static void gtk_menu_item_accel_width_foreach (GtkWidget *widget, - gpointer data) + gpointer data) { guint *width = data; @@ -633,8 +803,8 @@ gtk_menu_item_accel_width_foreach (GtkWidget *widget, } else if (GTK_IS_CONTAINER (widget)) gtk_container_foreach (GTK_CONTAINER (widget), - gtk_menu_item_accel_width_foreach, - data); + gtk_menu_item_accel_width_foreach, + data); } static gint @@ -646,9 +816,10 @@ get_minimum_width (GtkWidget *widget) gint width_chars; context = gtk_widget_get_pango_context (widget); + metrics = pango_context_get_metrics (context, - gtk_widget_get_style (widget)->font_desc, - pango_context_get_language (context)); + pango_context_get_font_description (context), + pango_context_get_language (context)); width = pango_font_metrics_get_approximate_char_width (metrics); @@ -659,100 +830,67 @@ get_minimum_width (GtkWidget *widget) return PANGO_PIXELS (width_chars * width); } -static void -gtk_menu_item_size_request_init (GtkSizeRequestIface *iface) -{ - iface->get_width = gtk_menu_item_get_width; - iface->get_height = gtk_menu_item_get_height; - iface->get_height_for_width = gtk_menu_item_get_height_for_width; -} - -static void -gtk_menu_item_get_width (GtkSizeRequest *request, - gint *minimum_size, - gint *natural_size) +static void +gtk_menu_item_get_preferred_width (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) { - GtkMenuItem *menu_item; + GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; GtkBin *bin; - GtkWidget *child, *widget = GTK_WIDGET (request); + GtkWidget *child; GtkWidget *parent; guint accel_width; - guint horizontal_padding; guint border_width; - GtkPackDirection pack_dir; - GtkPackDirection child_pack_dir; gint min_width, nat_width; + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder padding; min_width = nat_width = 0; - - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); - bin = GTK_BIN (widget); - menu_item = GTK_MENU_ITEM (widget); parent = gtk_widget_get_parent (widget); - if (GTK_IS_MENU_BAR (parent)) - { - pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent)); - child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent)); - } - else - { - pack_dir = GTK_PACK_DIRECTION_LTR; - child_pack_dir = GTK_PACK_DIRECTION_LTR; - } - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - min_width = (border_width + gtk_widget_get_style (widget)->xthickness) * 2; - - if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) && - (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL)) - min_width += 2 * horizontal_padding; + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_padding (context, state, &padding); + min_width = (border_width * 2) + padding.left + padding.right; nat_width = min_width; child = gtk_bin_get_child (bin); if (child != NULL && gtk_widget_get_visible (child)) { + GtkMenuItemPrivate *priv = menu_item->priv; gint child_min, child_nat; - gtk_size_request_get_width (GTK_SIZE_REQUEST (child), &child_min, &child_nat); + gtk_widget_get_preferred_width (child, &child_min, &child_nat); - if (menu_item->submenu && menu_item->show_submenu_indicator) + if ((menu_item->priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator) { - guint arrow_spacing; - gint arrow_size; - - gtk_widget_style_get (widget, - "arrow-spacing", &arrow_spacing, - NULL); - - get_arrow_size (widget, child, &arrow_size); + gint arrow_spacing, arrow_size; - min_width += arrow_size; - min_width += arrow_spacing; + get_arrow_size (widget, child, &arrow_size, &arrow_spacing); - min_width = MAX (min_width, get_minimum_width (widget)); - - nat_width = min_width; - } + min_width += arrow_size; + min_width += arrow_spacing; + min_width = MAX (min_width, get_minimum_width (widget)); + nat_width = min_width; + } min_width += child_min; nat_width += child_nat; - - } accel_width = 0; gtk_container_foreach (GTK_CONTAINER (menu_item), - gtk_menu_item_accel_width_foreach, - &accel_width); - menu_item->accelerator_width = accel_width; + gtk_menu_item_accel_width_foreach, + &accel_width); + priv->accelerator_width = accel_width; if (minimum_size) *minimum_size = min_width; @@ -761,52 +899,42 @@ gtk_menu_item_get_width (GtkSizeRequest *request, *natural_size = nat_width; } -static void -gtk_menu_item_get_height (GtkSizeRequest *request, - gint *minimum_size, - gint *natural_size) +static void +gtk_menu_item_real_get_height (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) { - GtkMenuItem *menu_item; + GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; GtkBin *bin; - GtkStyle *style; - GtkWidget *child, *widget = GTK_WIDGET (request); + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder padding; + GtkWidget *child; GtkWidget *parent; guint accel_width; - guint horizontal_padding; guint border_width; - GtkPackDirection pack_dir; - GtkPackDirection child_pack_dir; - gint min_height, nat_height; + gint min_height, nat_height; + gint avail_size = 0; min_height = nat_height = 0; - style = gtk_widget_get_style (widget); + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_padding (context, state, &padding); - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); - bin = GTK_BIN (widget); - menu_item = GTK_MENU_ITEM (widget); parent = gtk_widget_get_parent (widget); - if (GTK_IS_MENU_BAR (parent)) - { - pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent)); - child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent)); - } - else - { - pack_dir = GTK_PACK_DIRECTION_LTR; - child_pack_dir = GTK_PACK_DIRECTION_LTR; - } - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - min_height = (border_width + style->ythickness) * 2; + min_height = (border_width * 2) + padding.top + padding.bottom; - if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) && - (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT)) - min_height += 2 * horizontal_padding; + if (for_size != -1) + { + avail_size = for_size; + avail_size -= (border_width * 2) + padding.left + padding.right; + } nat_height = min_height; @@ -815,21 +943,29 @@ gtk_menu_item_get_height (GtkSizeRequest *request, if (child != NULL && gtk_widget_get_visible (child)) { gint child_min, child_nat; - - gtk_size_request_get_height (GTK_SIZE_REQUEST (child), &child_min, &child_nat); + gint arrow_size = 0, arrow_spacing = 0; - min_height += child_min; - nat_height += child_nat; + if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator) + get_arrow_size (widget, child, &arrow_size, &arrow_spacing); - if (menu_item->submenu && menu_item->show_submenu_indicator) - { - gint arrow_size; + if (for_size != -1) + { + avail_size -= (arrow_size + arrow_spacing); + gtk_widget_get_preferred_height_for_width (child, + avail_size, + &child_min, + &child_nat); + } + else + { + gtk_widget_get_preferred_height (child, &child_min, &child_nat); + } - get_arrow_size (widget, child, &arrow_size); + min_height += child_min; + nat_height += child_nat; - min_height = MAX (min_height, arrow_size); - nat_height = MAX (nat_height, arrow_size); - } + min_height = MAX (min_height, arrow_size); + nat_height = MAX (nat_height, arrow_size); } else /* separator item */ { @@ -842,18 +978,27 @@ gtk_menu_item_get_height (GtkSizeRequest *request, NULL); if (wide_separators) - min_height += separator_height + style->ythickness; + { + min_height += separator_height; + nat_height += separator_height; + } else - min_height += style->ythickness * 2; - - nat_height = min_height; + { + /* force odd, so that we can have the same space above and + * below the line. + */ + if (min_height % 2 == 0) + min_height += 1; + if (nat_height % 2 == 0) + nat_height += 1; + } } accel_width = 0; gtk_container_foreach (GTK_CONTAINER (menu_item), - gtk_menu_item_accel_width_foreach, - &accel_width); - menu_item->accelerator_width = accel_width; + gtk_menu_item_accel_width_foreach, + &accel_width); + priv->accelerator_width = accel_width; if (minimum_size) *minimum_size = min_height; @@ -863,118 +1008,20 @@ gtk_menu_item_get_height (GtkSizeRequest *request, } static void -gtk_menu_item_get_height_for_width (GtkSizeRequest *request, - gint for_size, - gint *minimum_size, - gint *natural_size) +gtk_menu_item_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) { - GtkMenuItem *menu_item; - GtkBin *bin; - GtkStyle *style; - GtkWidget *child, *widget = GTK_WIDGET (request); - GtkWidget *parent; - guint horizontal_padding; - guint border_width; - GtkPackDirection pack_dir; - GtkPackDirection child_pack_dir; - gint min_height, nat_height; - gint avail_size; - - min_height = nat_height = 0; - - style = gtk_widget_get_style (widget); - - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); - - bin = GTK_BIN (widget); - menu_item = GTK_MENU_ITEM (widget); - parent = gtk_widget_get_parent (widget); - - if (GTK_IS_MENU_BAR (parent)) - { - pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent)); - child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent)); - } - else - { - pack_dir = GTK_PACK_DIRECTION_LTR; - child_pack_dir = GTK_PACK_DIRECTION_LTR; - } - - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - min_height = (border_width + style->ythickness) * 2; - - avail_size = for_size; - avail_size -= (border_width + style->xthickness) * 2; - - if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) && - (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT)) - min_height += 2 * horizontal_padding; - - if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) && - (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL)) - avail_size -= 2 * horizontal_padding; - - nat_height = min_height; - - child = gtk_bin_get_child (bin); - - if (child != NULL && gtk_widget_get_visible (child)) - { - gint child_min, child_nat; - gint arrow_size = 0; - - if (menu_item->submenu && menu_item->show_submenu_indicator) - { - - guint arrow_spacing; - - gtk_widget_style_get (widget, - "arrow-spacing", &arrow_spacing, - NULL); - - get_arrow_size (widget, child, &arrow_size); - - avail_size -= arrow_size; - avail_size -= arrow_spacing; - } - - gtk_size_request_get_height_for_width (GTK_SIZE_REQUEST (child), avail_size, &child_min, &child_nat); - - min_height += child_min; - nat_height += child_nat; - - if (menu_item->submenu && menu_item->show_submenu_indicator) - { - min_height = MAX (min_height, arrow_size); - nat_height = MAX (nat_height, arrow_size); - } - } - else /* separator item */ - { - gboolean wide_separators; - gint separator_height; - - gtk_widget_style_get (widget, - "wide-separators", &wide_separators, - "separator-height", &separator_height, - NULL); - - if (wide_separators) - min_height += separator_height + style->ythickness; - else - min_height += style->ythickness * 2; - - nat_height = min_height; - } - - if (minimum_size) - *minimum_size = min_height; + gtk_menu_item_real_get_height (widget, -1, minimum_size, natural_size); +} - if (natural_size) - *natural_size = nat_height; +static void +gtk_menu_item_get_preferred_height_for_width (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) +{ + gtk_menu_item_real_get_height (widget, for_size, minimum_size, natural_size); } static void @@ -987,24 +1034,24 @@ gtk_menu_item_buildable_interface_init (GtkBuildableIface *iface) static void gtk_menu_item_buildable_add_child (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const gchar *type) + GtkBuilder *builder, + GObject *child, + const gchar *type) { if (type && strcmp (type, "submenu") == 0) - gtk_menu_item_set_submenu (GTK_MENU_ITEM (buildable), - GTK_WIDGET (child)); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (buildable), + GTK_WIDGET (child)); else parent_buildable_iface->add_child (buildable, builder, child, type); } -static void -gtk_menu_item_buildable_custom_finished (GtkBuildable *buildable, - GtkBuilder *builder, - GObject *child, - const gchar *tagname, - gpointer user_data) +static void +gtk_menu_item_buildable_custom_finished (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer user_data) { GtkWidget *toplevel; @@ -1015,21 +1062,21 @@ gtk_menu_item_buildable_custom_finished (GtkBuildable *buildable, menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (GTK_WIDGET (buildable))); if (menu_shell) - { - while (GTK_IS_MENU (menu_shell) && - (attach = gtk_menu_get_attach_widget (GTK_MENU (menu_shell))) != NULL) - menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (attach)); - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu_shell)); - } + { + while (GTK_IS_MENU (menu_shell) && + (attach = gtk_menu_get_attach_widget (GTK_MENU (menu_shell))) != NULL) + menu_shell = GTK_MENU_SHELL (gtk_widget_get_parent (attach)); + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu_shell)); + } else - { - /* Fall back to something ... */ - toplevel = gtk_widget_get_toplevel (GTK_WIDGET (buildable)); + { + /* Fall back to something ... */ + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (buildable)); - g_warning ("found a GtkMenuItem '%s' without a parent GtkMenuShell, assigned accelerators wont work.", - gtk_buildable_get_name (buildable)); - } + g_warning ("found a GtkMenuItem '%s' without a parent GtkMenuShell, assigned accelerators wont work.", + gtk_buildable_get_name (buildable)); + } /* Feed the correct toplevel to the GtkWidget accelerator parsing code */ _gtk_widget_buildable_finish_accelerator (GTK_WIDGET (buildable), toplevel, user_data); @@ -1062,34 +1109,77 @@ activatable_update_label (GtkMenuItem *menu_item, GtkAction *action) } } -gboolean _gtk_menu_is_empty (GtkWidget *menu); +/* + * gtk_menu_is_empty: + * @menu: (allow-none): a #GtkMenu or %NULL + * + * Determines whether @menu is empty. A menu is considered empty if it + * the only visible children are tearoff menu items or "filler" menu + * items which were inserted to mark the menu as empty. + * + * This function is used by #GtkAction. + * + * Return value: whether @menu is empty. + **/ +static gboolean +gtk_menu_is_empty (GtkWidget *menu) +{ + GList *children, *cur; + gboolean result = TRUE; + + g_return_val_if_fail (menu == NULL || GTK_IS_MENU (menu), TRUE); + + if (!menu) + return FALSE; + + children = gtk_container_get_children (GTK_CONTAINER (menu)); + + cur = children; + while (cur) + { + if (gtk_widget_get_visible (cur->data)) + { + if (!GTK_IS_TEAROFF_MENU_ITEM (cur->data) && + !g_object_get_data (cur->data, "gtk-empty-menu-item")) + { + result = FALSE; + break; + } + } + cur = cur->next; + } + g_list_free (children); + + return result; +} + static void gtk_menu_item_update (GtkActivatable *activatable, - GtkAction *action, - const gchar *property_name) + GtkAction *action, + const gchar *property_name) { GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable); - GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + GtkMenuItemPrivate *priv = menu_item->priv; if (strcmp (property_name, "visible") == 0) - _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item), - _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item))); + _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item), + gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item))); else if (strcmp (property_name, "sensitive") == 0) gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action)); else if (priv->use_action_appearance) { if (strcmp (property_name, "label") == 0) - activatable_update_label (menu_item, action); + activatable_update_label (menu_item, action); } } static void gtk_menu_item_sync_action_properties (GtkActivatable *activatable, - GtkAction *action) + GtkAction *action) { GtkMenuItem *menu_item = GTK_MENU_ITEM (activatable); - GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + GtkMenuItemPrivate *priv = menu_item->priv; GtkWidget *label; if (!priv->use_action_appearance || !action) @@ -1104,7 +1194,7 @@ gtk_menu_item_sync_action_properties (GtkActivatable *activatable, return; _gtk_action_sync_menu_visible (action, GTK_WIDGET (menu_item), - _gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item))); + gtk_menu_is_empty (gtk_menu_item_get_submenu (menu_item))); gtk_widget_set_sensitive (GTK_WIDGET (menu_item), gtk_action_is_sensitive (action)); @@ -1112,15 +1202,18 @@ gtk_menu_item_sync_action_properties (GtkActivatable *activatable, { label = gtk_bin_get_child (GTK_BIN (menu_item)); - /* make sure label is a label */ + /* make sure label is a label, deleting it otherwise */ if (label && !GTK_IS_LABEL (label)) - { - gtk_container_remove (GTK_CONTAINER (menu_item), label); - label = NULL; - } - + { + gtk_container_remove (GTK_CONTAINER (menu_item), label); + label = NULL; + } + /* Make sure that menu_item has a label and that any + * accelerators are set */ gtk_menu_item_ensure_label (menu_item); gtk_menu_item_set_use_underline (menu_item, TRUE); + /* Make label point to the menu_item's label */ + label = gtk_bin_get_child (GTK_BIN (menu_item)); if (GTK_IS_ACCEL_LABEL (label) && gtk_action_get_accel_path (action)) { @@ -1135,28 +1228,28 @@ gtk_menu_item_sync_action_properties (GtkActivatable *activatable, static void gtk_menu_item_set_related_action (GtkMenuItem *menu_item, - GtkAction *action) + GtkAction *action) { - GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + GtkMenuItemPrivate *priv = menu_item->priv; if (priv->action == action) return; if (priv->action) { - gtk_action_disconnect_accelerator (priv->action); + gtk_action_disconnect_accelerator (priv->action); } if (action) { - const gchar *accel_path; - - accel_path = gtk_action_get_accel_path (action); - if (accel_path) - { - gtk_action_connect_accelerator (action); - gtk_menu_item_set_accel_path (menu_item, accel_path); - } + const gchar *accel_path; + + accel_path = gtk_action_get_accel_path (action); + if (accel_path) + { + gtk_action_connect_accelerator (action); + gtk_menu_item_set_accel_path (menu_item, accel_path); + } } gtk_activatable_do_set_related_action (GTK_ACTIVATABLE (menu_item), action); @@ -1166,15 +1259,15 @@ gtk_menu_item_set_related_action (GtkMenuItem *menu_item, static void gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item, - gboolean use_appearance) + gboolean use_appearance) { - GtkMenuItemPrivate *priv = GET_PRIVATE (menu_item); + GtkMenuItemPrivate *priv = menu_item->priv; if (priv->use_action_appearance != use_appearance) { - priv->use_action_appearance = use_appearance; + priv->use_action_appearance = use_appearance; - gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (menu_item), priv->action); + gtk_activatable_sync_action_properties (GTK_ACTIVATABLE (menu_item), priv->action); } } @@ -1186,29 +1279,31 @@ gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item, * * Sets or replaces the menu item's submenu, or removes it when a %NULL * submenu is passed. - **/ + */ void gtk_menu_item_set_submenu (GtkMenuItem *menu_item, - GtkWidget *submenu) + GtkWidget *submenu) { + GtkMenuItemPrivate *priv = menu_item->priv; + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); g_return_if_fail (submenu == NULL || GTK_IS_MENU (submenu)); - - if (menu_item->submenu != submenu) + + if (priv->submenu != submenu) { - if (menu_item->submenu) - gtk_menu_detach (GTK_MENU (menu_item->submenu)); + if (priv->submenu) + gtk_menu_detach (GTK_MENU (priv->submenu)); if (submenu) - { - menu_item->submenu = submenu; - gtk_menu_attach_to_widget (GTK_MENU (submenu), - GTK_WIDGET (menu_item), - gtk_menu_item_detacher); - } + { + priv->submenu = submenu; + gtk_menu_attach_to_widget (GTK_MENU (submenu), + GTK_WIDGET (menu_item), + gtk_menu_item_detacher); + } if (gtk_widget_get_parent (GTK_WIDGET (menu_item))) - gtk_widget_queue_resize (GTK_WIDGET (menu_item)); + gtk_widget_queue_resize (GTK_WIDGET (menu_item)); g_object_notify (G_OBJECT (menu_item), "submenu"); } @@ -1221,26 +1316,26 @@ gtk_menu_item_set_submenu (GtkMenuItem *menu_item, * Gets the submenu underneath this menu item, if any. * See gtk_menu_item_set_submenu(). * - * Return value: (transfer none): submenu for this menu item, or %NULL if none. - **/ + * Return value: (transfer none): submenu for this menu item, or %NULL if none + */ GtkWidget * gtk_menu_item_get_submenu (GtkMenuItem *menu_item) { g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL); - return menu_item->submenu; + return menu_item->priv->submenu; } void _gtk_menu_item_set_placement (GtkMenuItem *menu_item, - GtkSubmenuPlacement placement); + GtkSubmenuPlacement placement); void _gtk_menu_item_set_placement (GtkMenuItem *menu_item, - GtkSubmenuPlacement placement) + GtkSubmenuPlacement placement) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); - menu_item->submenu_placement = placement; + menu_item->priv->submenu_placement = placement; } void @@ -1260,11 +1355,18 @@ gtk_menu_item_select (GtkMenuItem *menu_item) { GtkMenu *menu = GTK_MENU (parent); - if (menu->parent_menu_item) - gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item)); + if (menu->priv->parent_menu_item) + gtk_widget_queue_draw (GTK_WIDGET (menu->priv->parent_menu_item)); } } +/** + * gtk_menu_item_deselect: + * @menu_item: the menu item + * + * Emits the #GtkMenuItem::deselect signal on the given item. Behaves + * exactly like #gtk_item_deselect. + */ void gtk_menu_item_deselect (GtkMenuItem *menu_item) { @@ -1282,11 +1384,17 @@ gtk_menu_item_deselect (GtkMenuItem *menu_item) { GtkMenu *menu = GTK_MENU (parent); - if (menu->parent_menu_item) - gtk_widget_queue_draw (GTK_WIDGET (menu->parent_menu_item)); + if (menu->priv->parent_menu_item) + gtk_widget_queue_draw (GTK_WIDGET (menu->priv->parent_menu_item)); } } +/** + * gtk_menu_item_activate: + * @menu_item: the menu item + * + * Emits the #GtkMenuItem::activate signal on the given item + */ void gtk_menu_item_activate (GtkMenuItem *menu_item) { @@ -1295,18 +1403,32 @@ gtk_menu_item_activate (GtkMenuItem *menu_item) g_signal_emit (menu_item, menu_item_signals[ACTIVATE], 0); } +/** + * gtk_menu_item_toggle_size_request: + * @menu_item: the menu item + * @requisition: the requisition to use as signal data. + * + * Emits the #GtkMenuItem::toggle-size-request signal on the given item. + */ void gtk_menu_item_toggle_size_request (GtkMenuItem *menu_item, - gint *requisition) + gint *requisition) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); g_signal_emit (menu_item, menu_item_signals[TOGGLE_SIZE_REQUEST], 0, requisition); } +/** + * gtk_menu_item_toggle_size_allocate: + * @menu_item: the menu item. + * @allocation: the allocation to use as signal data. + * + * Emits the #GtkMenuItem::toggle-size-allocate signal on the given item. + */ void gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item, - gint allocation) + gint allocation) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); @@ -1315,13 +1437,13 @@ gtk_menu_item_toggle_size_allocate (GtkMenuItem *menu_item, static void gtk_menu_item_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) + GtkAllocation *allocation) { - GtkMenuItem *menu_item; + GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; GtkBin *bin; GtkAllocation child_allocation; GtkTextDirection direction; - GtkPackDirection pack_dir; GtkPackDirection child_pack_dir; GtkWidget *child; GtkWidget *parent; @@ -1329,20 +1451,17 @@ gtk_menu_item_size_allocate (GtkWidget *widget, g_return_if_fail (GTK_IS_MENU_ITEM (widget)); g_return_if_fail (allocation != NULL); - menu_item = GTK_MENU_ITEM (widget); bin = GTK_BIN (widget); - + direction = gtk_widget_get_direction (widget); parent = gtk_widget_get_parent (widget); if (GTK_IS_MENU_BAR (parent)) { - pack_dir = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (parent)); child_pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent)); } else { - pack_dir = GTK_PACK_DIRECTION_LTR; child_pack_dir = GTK_PACK_DIRECTION_LTR; } @@ -1351,76 +1470,73 @@ gtk_menu_item_size_allocate (GtkWidget *widget, child = gtk_bin_get_child (bin); if (child) { - GtkRequisition child_requisition; - GtkStyle *style; - guint horizontal_padding; + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder padding; guint border_width; - style = gtk_widget_get_style (widget); - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + gtk_style_context_get_padding (context, state, &padding); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - child_allocation.x = border_width + style->xthickness; - child_allocation.y = border_width + style->ythickness; - - if ((pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL) && - (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL)) - child_allocation.x += horizontal_padding; - else if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) && - (child_pack_dir == GTK_PACK_DIRECTION_TTB || child_pack_dir == GTK_PACK_DIRECTION_BTT)) - child_allocation.y += horizontal_padding; + child_allocation.x = border_width + padding.left; + child_allocation.y = border_width + padding.top; - child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2); - child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2); + child_allocation.width = allocation->width - (border_width * 2) - + padding.left - padding.right; + child_allocation.height = allocation->height - (border_width * 2) - + padding.top - padding.bottom; if (child_pack_dir == GTK_PACK_DIRECTION_LTR || - child_pack_dir == GTK_PACK_DIRECTION_RTL) - { - if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL)) - child_allocation.x += GTK_MENU_ITEM (widget)->toggle_size; - child_allocation.width -= GTK_MENU_ITEM (widget)->toggle_size; - } + child_pack_dir == GTK_PACK_DIRECTION_RTL) + { + if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_RTL)) + child_allocation.x += priv->toggle_size; + child_allocation.width -= priv->toggle_size; + } else - { - if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT)) - child_allocation.y += GTK_MENU_ITEM (widget)->toggle_size; - child_allocation.height -= GTK_MENU_ITEM (widget)->toggle_size; - } + { + if ((direction == GTK_TEXT_DIR_LTR) == (child_pack_dir != GTK_PACK_DIRECTION_BTT)) + child_allocation.y += priv->toggle_size; + child_allocation.height -= priv->toggle_size; + } child_allocation.x += allocation->x; child_allocation.y += allocation->y; - gtk_size_request_get_size (GTK_SIZE_REQUEST (child), - &child_requisition, NULL); - if (menu_item->submenu && menu_item->show_submenu_indicator) + if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator) { + gint arrow_spacing, arrow_size; + + get_arrow_size (widget, child, &arrow_size, &arrow_spacing); + if (direction == GTK_TEXT_DIR_RTL) - child_allocation.x += child_requisition.height; - child_allocation.width -= child_requisition.height; + child_allocation.x += arrow_size + arrow_spacing; + child_allocation.width -= arrow_size + arrow_spacing; } if (child_allocation.width < 1) - child_allocation.width = 1; + child_allocation.width = 1; gtk_widget_size_allocate (child, &child_allocation); } if (gtk_widget_get_realized (widget)) - gdk_window_move_resize (menu_item->event_window, + gdk_window_move_resize (priv->event_window, allocation->x, allocation->y, allocation->width, allocation->height); - if (menu_item->submenu) - gtk_menu_reposition (GTK_MENU (menu_item->submenu)); + if (priv->submenu) + gtk_menu_reposition (GTK_MENU (priv->submenu)); } static void gtk_menu_item_realize (GtkWidget *widget) { - GtkAllocation allocation; GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; + GtkAllocation allocation; GdkWindow *window; GdkWindowAttr attributes; gint attributes_mask; @@ -1440,29 +1556,28 @@ gtk_menu_item_realize (GtkWidget *widget) attributes.window_type = GDK_WINDOW_CHILD; attributes.wclass = GDK_INPUT_ONLY; attributes.event_mask = (gtk_widget_get_events (widget) | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_POINTER_MOTION_MASK); + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_POINTER_MOTION_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y; - menu_item->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gdk_window_set_user_data (menu_item->event_window, widget); - - gtk_widget_style_attach (widget); + priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gtk_widget_register_window (widget, priv->event_window); } static void gtk_menu_item_unrealize (GtkWidget *widget) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; - gdk_window_set_user_data (menu_item->event_window, NULL); - gdk_window_destroy (menu_item->event_window); - menu_item->event_window = NULL; + gtk_widget_unregister_window (widget, priv->event_window); + gdk_window_destroy (priv->event_window); + priv->event_window = NULL; GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unrealize (widget); } @@ -1471,18 +1586,20 @@ static void gtk_menu_item_map (GtkWidget *widget) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); - + GtkMenuItemPrivate *priv = menu_item->priv; + GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->map (widget); - gdk_window_show (menu_item->event_window); + gdk_window_show (priv->event_window); } static void gtk_menu_item_unmap (GtkWidget *widget) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); - - gdk_window_hide (menu_item->event_window); + GtkMenuItemPrivate *priv = menu_item->priv; + + gdk_window_hide (priv->event_window); GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->unmap (widget); } @@ -1510,17 +1627,16 @@ gtk_menu_item_draw (GtkWidget *widget, cairo_t *cr) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); - GtkStateType state_type; - GtkShadowType shadow_type, selected_shadow_type; - GtkStyle *style; - GtkWidget *child; - GdkWindow *window; + GtkMenuItemPrivate *priv = menu_item->priv; + GtkStateFlags state; + GtkStyleContext *context; + GtkBorder padding; + GtkWidget *child, *parent; gint x, y, w, h, width, height; guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - state_type = gtk_widget_get_state (widget); - style = gtk_widget_get_style (widget); - window = gtk_widget_get_window (widget); + state = gtk_widget_get_state_flags (widget); + context = gtk_widget_get_style_context (widget); width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); @@ -1530,86 +1646,59 @@ gtk_menu_item_draw (GtkWidget *widget, h = height - border_width * 2; child = gtk_bin_get_child (GTK_BIN (menu_item)); - - if (child && state_type == GTK_STATE_PRELIGHT) - { - gtk_widget_style_get (widget, - "selected-shadow-type", &selected_shadow_type, - NULL); - gtk_cairo_paint_box (style, - cr, - GTK_STATE_PRELIGHT, - selected_shadow_type, - widget, "menuitem", - x, y, w, h); - } + parent = gtk_widget_get_parent (widget); + + gtk_style_context_get_padding (context, state, &padding); - if (menu_item->submenu && menu_item->show_submenu_indicator) + gtk_render_background (context, cr, x, y, w, h); + gtk_render_frame (context, cr, x, y, w, h); + + if (priv->submenu && !GTK_IS_MENU_BAR (parent)) { gint arrow_x, arrow_y; gint arrow_size; - guint horizontal_padding; GtkTextDirection direction; - GtkArrowType arrow_type; + gdouble angle; direction = gtk_widget_get_direction (widget); - - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); - - get_arrow_size (widget, child, &arrow_size); - - shadow_type = GTK_SHADOW_OUT; - if (state_type == GTK_STATE_PRELIGHT) - shadow_type = GTK_SHADOW_IN; + get_arrow_size (widget, child, &arrow_size, NULL); if (direction == GTK_TEXT_DIR_LTR) { - arrow_x = x + w - horizontal_padding - arrow_size; - arrow_type = GTK_ARROW_RIGHT; + arrow_x = x + w - arrow_size; + angle = G_PI / 2; } else { - arrow_x = x + horizontal_padding; - arrow_type = GTK_ARROW_LEFT; + arrow_x = x; + angle = (3 * G_PI) / 2; } arrow_y = y + (h - arrow_size) / 2; - gtk_cairo_paint_arrow (style, cr, - state_type, shadow_type, - widget, "menuitem", - arrow_type, TRUE, - arrow_x, arrow_y, - arrow_size, arrow_size); + gtk_render_arrow (context, cr, angle, arrow_x, arrow_y, arrow_size); } else if (!child) { gboolean wide_separators; gint separator_height; - guint horizontal_padding; gtk_widget_style_get (widget, "wide-separators", &wide_separators, "separator-height", &separator_height, - "horizontal-padding", &horizontal_padding, NULL); - if (wide_separators) - gtk_cairo_paint_box (style, cr, - GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, - widget, "hseparator", - horizontal_padding + style->xthickness, - (height - separator_height - style->ythickness) / 2, - width - 2 * (horizontal_padding + style->xthickness), - separator_height); + gtk_render_frame (context, cr, + x + padding.left, + y + padding.top, + w - padding.left - padding.right, + separator_height); else - gtk_cairo_paint_hline (style, cr, - GTK_STATE_NORMAL, widget, "menuitem", - horizontal_padding + style->xthickness, - width - horizontal_padding - style->xthickness - 1, - (height - style->ythickness) / 2); + gtk_render_line (context, cr, + x + padding.left, + y + padding.top, + x + w - padding.right - 1, + y + padding.top); } GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->draw (widget, cr); @@ -1617,40 +1706,58 @@ gtk_menu_item_draw (GtkWidget *widget, return FALSE; } +/** + * gtk_menu_item_select: + * @menu_item: the menu item + * + * Emits the #GtkMenuItem::select signal on the given item. Behaves + * exactly like #gtk_item_select. + */ static void gtk_real_menu_item_select (GtkMenuItem *menu_item) { - gboolean touchscreen_mode; + GtkMenuItemPrivate *priv = menu_item->priv; + GdkDevice *source_device = NULL; + GdkEvent *current_event; - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); + current_event = gtk_get_current_event (); - if (!touchscreen_mode && - menu_item->submenu && - (!gtk_widget_get_mapped (menu_item->submenu) || - GTK_MENU (menu_item->submenu)->tearoff_active)) + if (current_event) + { + source_device = gdk_event_get_source_device (current_event); + gdk_event_free (current_event); + } + + if ((!source_device || + gdk_device_get_source (source_device) != GDK_SOURCE_TOUCHSCREEN) && + priv->submenu && + (!gtk_widget_get_mapped (priv->submenu) || + GTK_MENU (priv->submenu)->priv->tearoff_active)) { _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item), TRUE); } - gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT); + gtk_widget_set_state_flags (GTK_WIDGET (menu_item), + GTK_STATE_FLAG_PRELIGHT, FALSE); gtk_widget_queue_draw (GTK_WIDGET (menu_item)); } static void gtk_real_menu_item_deselect (GtkMenuItem *menu_item) { - if (menu_item->submenu) + GtkMenuItemPrivate *priv = menu_item->priv; + + if (priv->submenu) _gtk_menu_item_popdown_submenu (GTK_WIDGET (menu_item)); - gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL); + gtk_widget_unset_state_flags (GTK_WIDGET (menu_item), + GTK_STATE_FLAG_PRELIGHT); gtk_widget_queue_draw (GTK_WIDGET (menu_item)); } static gboolean gtk_menu_item_mnemonic_activate (GtkWidget *widget, - gboolean group_cycling) + gboolean group_cycling) { GtkWidget *parent; @@ -1662,23 +1769,23 @@ gtk_menu_item_mnemonic_activate (GtkWidget *widget, if (group_cycling && parent && GTK_IS_MENU_SHELL (parent) && - GTK_MENU_SHELL (parent)->active) + GTK_MENU_SHELL (parent)->priv->active) { - gtk_menu_shell_select_item (GTK_MENU_SHELL (parent), - widget); + gtk_menu_shell_select_item (GTK_MENU_SHELL (parent), widget); } else g_signal_emit (widget, menu_item_signals[ACTIVATE_ITEM], 0); - + return TRUE; } -static void +static void gtk_real_menu_item_activate (GtkMenuItem *menu_item) { - GtkMenuItemPrivate *priv; + GtkMenuItemPrivate *priv = menu_item->priv; - priv = GET_PRIVATE (menu_item); + if (priv->action_helper) + gtk_action_helper_activate (priv->action_helper); if (priv->action) gtk_action_activate (priv->action); @@ -1688,13 +1795,10 @@ gtk_real_menu_item_activate (GtkMenuItem *menu_item) static void gtk_real_menu_item_activate_item (GtkMenuItem *menu_item) { - GtkMenuItemPrivate *priv; + GtkMenuItemPrivate *priv = menu_item->priv; GtkWidget *parent; GtkWidget *widget; - g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); - - priv = GET_PRIVATE (menu_item); widget = GTK_WIDGET (menu_item); parent = gtk_widget_get_parent (widget); @@ -1702,24 +1806,21 @@ gtk_real_menu_item_activate_item (GtkMenuItem *menu_item) { GtkMenuShell *menu_shell = GTK_MENU_SHELL (parent); - if (menu_item->submenu == NULL) - gtk_menu_shell_activate_item (menu_shell, - widget, TRUE); + if (priv->submenu == NULL) + gtk_menu_shell_activate_item (menu_shell, widget, TRUE); else - { - _gtk_menu_shell_activate (menu_shell); - - gtk_menu_shell_select_item (menu_shell, widget); - _gtk_menu_item_popup_submenu (widget, FALSE); + { + gtk_menu_shell_select_item (menu_shell, widget); + _gtk_menu_item_popup_submenu (widget, FALSE); - gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE); - } + gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->submenu), TRUE); + } } } static void gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item, - gint *requisition) + gint *requisition) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); @@ -1728,16 +1829,16 @@ gtk_real_menu_item_toggle_size_request (GtkMenuItem *menu_item, static void gtk_real_menu_item_toggle_size_allocate (GtkMenuItem *menu_item, - gint allocation) + gint allocation) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); - menu_item->toggle_size = allocation; + menu_item->priv->toggle_size = allocation; } static void gtk_real_menu_item_set_label (GtkMenuItem *menu_item, - const gchar *label) + const gchar *label) { GtkWidget *child; @@ -1747,12 +1848,12 @@ gtk_real_menu_item_set_label (GtkMenuItem *menu_item, if (GTK_IS_LABEL (child)) { gtk_label_set_label (GTK_LABEL (child), label ? label : ""); - + g_object_notify (G_OBJECT (menu_item), "label"); } } -static G_CONST_RETURN gchar * +static const gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item) { GtkWidget *child; @@ -1777,18 +1878,18 @@ gtk_menu_item_real_popup_submenu (GtkWidget *widget, gboolean remember_exact_time) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; GtkWidget *parent; parent = gtk_widget_get_parent (widget); - if (gtk_widget_is_sensitive (menu_item->submenu) && parent) + if (gtk_widget_is_sensitive (priv->submenu) && parent) { gboolean take_focus; GtkMenuPositionFunc menu_position_func; take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (parent)); - gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu), - take_focus); + gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (priv->submenu), take_focus); if (remember_exact_time) { @@ -1796,13 +1897,13 @@ gtk_menu_item_real_popup_submenu (GtkWidget *widget, g_get_current_time (popup_time); - g_object_set_data_full (G_OBJECT (menu_item->submenu), + g_object_set_data_full (G_OBJECT (priv->submenu), "gtk-menu-exact-popup-time", popup_time, (GDestroyNotify) free_timeval); } else { - g_object_set_data (G_OBJECT (menu_item->submenu), + g_object_set_data (G_OBJECT (priv->submenu), "gtk-menu-exact-popup-time", NULL); } @@ -1817,12 +1918,12 @@ gtk_menu_item_real_popup_submenu (GtkWidget *widget, else menu_position_func = NULL; - gtk_menu_popup (GTK_MENU (menu_item->submenu), + gtk_menu_popup (GTK_MENU (priv->submenu), parent, widget, menu_position_func, menu_item, - GTK_MENU_SHELL (parent)->button, + GTK_MENU_SHELL (parent)->priv->button, 0); } @@ -1835,24 +1936,23 @@ gtk_menu_item_real_popup_submenu (GtkWidget *widget, static gint gtk_menu_item_popup_timeout (gpointer data) { - GtkMenuItem *menu_item; + GtkMenuItem *menu_item = GTK_MENU_ITEM (data); + GtkMenuItemPrivate *priv = menu_item->priv; GtkWidget *parent; - - menu_item = GTK_MENU_ITEM (data); parent = gtk_widget_get_parent (GTK_WIDGET (menu_item)); - if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->active) || - (GTK_IS_MENU (parent) && GTK_MENU (parent)->torn_off)) + if ((GTK_IS_MENU_SHELL (parent) && GTK_MENU_SHELL (parent)->priv->active) || + (GTK_IS_MENU (parent) && GTK_MENU (parent)->priv->torn_off)) { gtk_menu_item_real_popup_submenu (GTK_WIDGET (menu_item), TRUE); - if (menu_item->timer_from_keypress && menu_item->submenu) - GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE; + if (priv->timer_from_keypress && priv->submenu) + GTK_MENU_SHELL (priv->submenu)->priv->ignore_enter = TRUE; } - menu_item->timer = 0; + priv->timer = 0; - return FALSE; + return FALSE; } static gint @@ -1870,8 +1970,8 @@ get_popup_delay (GtkWidget *widget) gint popup_delay; g_object_get (gtk_widget_get_settings (widget), - "gtk-menu-popup-delay", &popup_delay, - NULL); + "gtk-menu-popup-delay", &popup_delay, + NULL); return popup_delay; } @@ -1882,11 +1982,12 @@ _gtk_menu_item_popup_submenu (GtkWidget *widget, gboolean with_delay) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; - if (menu_item->timer) + if (priv->timer) { - g_source_remove (menu_item->timer); - menu_item->timer = 0; + g_source_remove (priv->timer); + priv->timer = 0; with_delay = FALSE; } @@ -1895,22 +1996,22 @@ _gtk_menu_item_popup_submenu (GtkWidget *widget, gint popup_delay = get_popup_delay (widget); if (popup_delay > 0) - { - GdkEvent *event = gtk_get_current_event (); + { + GdkEvent *event = gtk_get_current_event (); - menu_item->timer = gdk_threads_add_timeout (popup_delay, - gtk_menu_item_popup_timeout, - menu_item); + priv->timer = gdk_threads_add_timeout (popup_delay, + gtk_menu_item_popup_timeout, + menu_item); - if (event && - event->type != GDK_BUTTON_PRESS && - event->type != GDK_ENTER_NOTIFY) - menu_item->timer_from_keypress = TRUE; - else - menu_item->timer_from_keypress = FALSE; + if (event && + event->type != GDK_BUTTON_PRESS && + event->type != GDK_ENTER_NOTIFY) + priv->timer_from_keypress = TRUE; + else + priv->timer_from_keypress = FALSE; - if (event) - gdk_event_free (event); + if (event) + gdk_event_free (event); return; } @@ -1922,22 +2023,21 @@ _gtk_menu_item_popup_submenu (GtkWidget *widget, void _gtk_menu_item_popdown_submenu (GtkWidget *widget) { - GtkMenuItem *menu_item; - - menu_item = GTK_MENU_ITEM (widget); + GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; - if (menu_item->submenu) + if (priv->submenu) { - g_object_set_data (G_OBJECT (menu_item->submenu), + g_object_set_data (G_OBJECT (priv->submenu), "gtk-menu-exact-popup-time", NULL); - if (menu_item->timer) + if (priv->timer) { - g_source_remove (menu_item->timer); - menu_item->timer = 0; + g_source_remove (priv->timer); + priv->timer = 0; } else - gtk_menu_popdown (GTK_MENU (menu_item->submenu)); + gtk_menu_popdown (GTK_MENU (priv->submenu)); gtk_widget_queue_draw (widget); } @@ -1945,36 +2045,38 @@ _gtk_menu_item_popdown_submenu (GtkWidget *widget) static void get_offsets (GtkMenu *menu, - gint *horizontal_offset, - gint *vertical_offset) + gint *horizontal_offset, + gint *vertical_offset) { - gint vertical_padding; - gint horizontal_padding; - + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder padding; + gtk_widget_style_get (GTK_WIDGET (menu), - "horizontal-offset", horizontal_offset, - "vertical-offset", vertical_offset, - "horizontal-padding", &horizontal_padding, - "vertical-padding", &vertical_padding, - NULL); + "horizontal-offset", horizontal_offset, + "vertical-offset", vertical_offset, + NULL); + + context = gtk_widget_get_style_context (GTK_WIDGET (menu)); + state = gtk_widget_get_state_flags (GTK_WIDGET (menu)); + gtk_style_context_get_padding (context, state, &padding); - *vertical_offset -= gtk_widget_get_style (GTK_WIDGET (menu))->ythickness; - *vertical_offset -= vertical_padding; - *horizontal_offset += horizontal_padding; + *vertical_offset -= padding.top; + *horizontal_offset += padding.left; } static void gtk_menu_item_position_menu (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data) + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data) { + GtkMenuItem *menu_item = GTK_MENU_ITEM (user_data); + GtkMenuItemPrivate *priv = menu_item->priv; GtkAllocation allocation; - GtkMenuItem *menu_item; GtkWidget *widget; GtkMenuItem *parent_menu_item; - GtkRequisition requisition; GtkWidget *parent; GdkScreen *screen; gint twidth, theight; @@ -1984,14 +2086,15 @@ gtk_menu_item_position_menu (GtkMenu *menu, gint monitor_num; gint horizontal_offset; gint vertical_offset; - gint parent_xthickness; gint available_left, available_right; + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder parent_padding; g_return_if_fail (menu != NULL); g_return_if_fail (x != NULL); g_return_if_fail (y != NULL); - menu_item = GTK_MENU_ITEM (user_data); widget = GTK_WIDGET (user_data); if (push_in) @@ -1999,18 +2102,16 @@ gtk_menu_item_position_menu (GtkMenu *menu, direction = gtk_widget_get_direction (widget); - gtk_size_request_get_size (GTK_SIZE_REQUEST (menu), &requisition, NULL); - twidth = requisition.width; - theight = requisition.height; + twidth = gtk_widget_get_allocated_width (GTK_WIDGET (menu)); + theight = gtk_widget_get_allocated_height (GTK_WIDGET (menu)); screen = gtk_widget_get_screen (GTK_WIDGET (menu)); - monitor_num = gdk_screen_get_monitor_at_window (screen, menu_item->event_window); + monitor_num = gdk_screen_get_monitor_at_window (screen, priv->event_window); if (monitor_num < 0) monitor_num = 0; - gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); - if (!gdk_window_get_origin (gtk_widget_get_window (widget), - &tx, &ty)) + if (!gdk_window_get_origin (gtk_widget_get_window (widget), &tx, &ty)) { g_warning ("Menu not on screen"); return; @@ -2027,89 +2128,77 @@ gtk_menu_item_position_menu (GtkMenu *menu, available_right = monitor.x + monitor.width - (tx + allocation.width); parent = gtk_widget_get_parent (widget); - if (GTK_IS_MENU_BAR (parent)) - { - menu_item->from_menubar = TRUE; - } - else if (GTK_IS_MENU (parent)) - { - if (GTK_MENU (parent)->parent_menu_item) - menu_item->from_menubar = GTK_MENU_ITEM (GTK_MENU (parent)->parent_menu_item)->from_menubar; - else - menu_item->from_menubar = FALSE; - } - else - { - menu_item->from_menubar = FALSE; - } - - switch (menu_item->submenu_placement) + priv->from_menubar = GTK_IS_MENU_BAR (parent); + + switch (priv->submenu_placement) { case GTK_TOP_BOTTOM: if (direction == GTK_TEXT_DIR_LTR) - menu_item->submenu_direction = GTK_DIRECTION_RIGHT; - else - { - menu_item->submenu_direction = GTK_DIRECTION_LEFT; - tx += allocation.width - twidth; - } + priv->submenu_direction = GTK_DIRECTION_RIGHT; + else + { + priv->submenu_direction = GTK_DIRECTION_LEFT; + tx += allocation.width - twidth; + } if ((ty + allocation.height + theight) <= monitor.y + monitor.height) - ty += allocation.height; + ty += allocation.height; else if ((ty - theight) >= monitor.y) - ty -= theight; + ty -= theight; else if (monitor.y + monitor.height - (ty + allocation.height) > ty) - ty += allocation.height; + ty += allocation.height; else - ty -= theight; + ty -= theight; break; case GTK_LEFT_RIGHT: if (GTK_IS_MENU (parent)) - parent_menu_item = GTK_MENU_ITEM (GTK_MENU (parent)->parent_menu_item); + parent_menu_item = GTK_MENU_ITEM (GTK_MENU (parent)->priv->parent_menu_item); else - parent_menu_item = NULL; + parent_menu_item = NULL; - parent_xthickness = gtk_widget_get_style (parent)->xthickness; + context = gtk_widget_get_style_context (parent); + state = gtk_widget_get_state_flags (parent); + gtk_style_context_get_padding (context, state, &parent_padding); - if (parent_menu_item && !GTK_MENU (parent)->torn_off) - { - menu_item->submenu_direction = parent_menu_item->submenu_direction; - } + if (parent_menu_item && !GTK_MENU (parent)->priv->torn_off) + { + priv->submenu_direction = parent_menu_item->priv->submenu_direction; + } else - { - if (direction == GTK_TEXT_DIR_LTR) - menu_item->submenu_direction = GTK_DIRECTION_RIGHT; - else - menu_item->submenu_direction = GTK_DIRECTION_LEFT; - } + { + if (direction == GTK_TEXT_DIR_LTR) + priv->submenu_direction = GTK_DIRECTION_RIGHT; + else + priv->submenu_direction = GTK_DIRECTION_LEFT; + } - switch (menu_item->submenu_direction) - { - case GTK_DIRECTION_LEFT: - if (tx - twidth - parent_xthickness - horizontal_offset >= monitor.x || - available_left >= available_right) - tx -= twidth + parent_xthickness + horizontal_offset; - else - { - menu_item->submenu_direction = GTK_DIRECTION_RIGHT; - tx += allocation.width + parent_xthickness + horizontal_offset; - } - break; - - case GTK_DIRECTION_RIGHT: - if (tx + allocation.width + parent_xthickness + horizontal_offset + twidth <= monitor.x + monitor.width || - available_right >= available_left) - tx += allocation.width + parent_xthickness + horizontal_offset; - else - { - menu_item->submenu_direction = GTK_DIRECTION_LEFT; - tx -= twidth + parent_xthickness + horizontal_offset; - } - break; - } + switch (priv->submenu_direction) + { + case GTK_DIRECTION_LEFT: + if (tx - twidth - parent_padding.left - horizontal_offset >= monitor.x || + available_left >= available_right) + tx -= twidth + parent_padding.left + horizontal_offset; + else + { + priv->submenu_direction = GTK_DIRECTION_RIGHT; + tx += allocation.width + parent_padding.right + horizontal_offset; + } + break; + + case GTK_DIRECTION_RIGHT: + if (tx + allocation.width + parent_padding.right + horizontal_offset + twidth <= monitor.x + monitor.width || + available_right >= available_left) + tx += allocation.width + parent_padding.right + horizontal_offset; + else + { + priv->submenu_direction = GTK_DIRECTION_LEFT; + tx -= twidth + parent_padding.left + horizontal_offset; + } + break; + } ty += vertical_offset; - + /* If the height of the menu doesn't fit we move it upward. */ ty = CLAMP (ty, monitor.y, MAX (monitor.y, monitor.y + monitor.height - theight)); break; @@ -2123,100 +2212,80 @@ gtk_menu_item_position_menu (GtkMenu *menu, gtk_menu_set_monitor (menu, monitor_num); - if (!gtk_widget_get_visible (menu->toplevel)) + if (!gtk_widget_get_visible (menu->priv->toplevel)) { - gtk_window_set_type_hint (GTK_WINDOW (menu->toplevel), menu_item->from_menubar? - GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU); + gtk_window_set_type_hint (GTK_WINDOW (menu->priv->toplevel), priv->from_menubar? + GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU : GDK_WINDOW_TYPE_HINT_POPUP_MENU); } } /** * gtk_menu_item_set_right_justified: * @menu_item: a #GtkMenuItem. - * @right_justified: if %TRUE the menu item will appear at the - * far right if added to a menu bar. - * + * @right_justified: if %TRUE the menu item will appear at the + * far right if added to a menu bar + * * Sets whether the menu item appears justified at the right - * side of a menu bar. This was traditionally done for "Help" menu - * items, but is now considered a bad idea. (If the widget + * side of a menu bar. This was traditionally done for "Help" + * menu items, but is now considered a bad idea. (If the widget * layout is reversed for a right-to-left language like Hebrew * or Arabic, right-justified-menu-items appear at the left.) + * + * Deprecated: 3.2: If you insist on using it, use + * gtk_widget_set_hexpand() and gtk_widget_set_halign(). **/ void gtk_menu_item_set_right_justified (GtkMenuItem *menu_item, - gboolean right_justified) + gboolean right_justified) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); - right_justified = right_justified != FALSE; - - if (right_justified != menu_item->right_justify) - { - menu_item->right_justify = right_justified; - gtk_widget_queue_resize (GTK_WIDGET (menu_item)); - } + gtk_menu_item_do_set_right_justified (menu_item, right_justified); } /** * gtk_menu_item_get_right_justified: * @menu_item: a #GtkMenuItem - * + * * Gets whether the menu item appears justified at the right * side of the menu bar. - * + * * Return value: %TRUE if the menu item will appear at the * far right if added to a menu bar. + * + * Deprecated: 3.2: See gtk_menu_item_set_right_justified() **/ gboolean gtk_menu_item_get_right_justified (GtkMenuItem *menu_item) { g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE); - - return menu_item->right_justify; + + return menu_item->priv->right_justify; } static void gtk_menu_item_show_all (GtkWidget *widget) { - GtkMenuItem *menu_item; - - g_return_if_fail (GTK_IS_MENU_ITEM (widget)); - - menu_item = GTK_MENU_ITEM (widget); + GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); + GtkMenuItemPrivate *priv = menu_item->priv; /* show children including submenu */ - if (menu_item->submenu) - gtk_widget_show_all (menu_item->submenu); + if (priv->submenu) + gtk_widget_show_all (priv->submenu); gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_show_all, NULL); gtk_widget_show (widget); } -static void -gtk_menu_item_hide_all (GtkWidget *widget) -{ - GtkMenuItem *menu_item; - - g_return_if_fail (GTK_IS_MENU_ITEM (widget)); - - gtk_widget_hide (widget); - - menu_item = GTK_MENU_ITEM (widget); - - /* hide children including submenu */ - gtk_container_foreach (GTK_CONTAINER (widget), (GtkCallback) gtk_widget_hide_all, NULL); - if (menu_item->submenu) - gtk_widget_hide_all (menu_item->submenu); -} - static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget, - guint signal_id) + guint signal_id) { GtkWidget *parent; parent = gtk_widget_get_parent (widget); + /* Chain to the parent GtkMenu for further checks */ return (gtk_widget_is_sensitive (widget) && gtk_widget_get_visible (widget) && parent && gtk_widget_can_activate_accel (parent, signal_id)); @@ -2224,28 +2293,28 @@ gtk_menu_item_can_activate_accel (GtkWidget *widget, static void gtk_menu_item_accel_name_foreach (GtkWidget *widget, - gpointer data) + gpointer data) { const gchar **path_p = data; if (!*path_p) { if (GTK_IS_LABEL (widget)) - { - *path_p = gtk_label_get_text (GTK_LABEL (widget)); - if (*path_p && (*path_p)[0] == 0) - *path_p = NULL; - } + { + *path_p = gtk_label_get_text (GTK_LABEL (widget)); + if (*path_p && (*path_p)[0] == 0) + *path_p = NULL; + } else if (GTK_IS_CONTAINER (widget)) - gtk_container_foreach (GTK_CONTAINER (widget), - gtk_menu_item_accel_name_foreach, - data); + gtk_container_foreach (GTK_CONTAINER (widget), + gtk_menu_item_accel_name_foreach, + data); } } static void gtk_menu_item_parent_set (GtkWidget *widget, - GtkWidget *previous_parent) + GtkWidget *previous_parent) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); GtkMenu *menu; @@ -2256,9 +2325,9 @@ gtk_menu_item_parent_set (GtkWidget *widget, if (menu) _gtk_menu_item_refresh_accel_path (menu_item, - menu->accel_path, - menu->accel_group, - TRUE); + menu->priv->accel_path, + menu->priv->accel_group, + TRUE); if (GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set) GTK_WIDGET_CLASS (gtk_menu_item_parent_class)->parent_set (widget, previous_parent); @@ -2266,10 +2335,11 @@ gtk_menu_item_parent_set (GtkWidget *widget, void _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item, - const gchar *prefix, - GtkAccelGroup *accel_group, - gboolean group_changed) + const gchar *prefix, + GtkAccelGroup *accel_group, + gboolean group_changed) { + GtkMenuItemPrivate *priv = menu_item->priv; const gchar *path; GtkWidget *widget; @@ -2285,72 +2355,74 @@ _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item, } path = _gtk_widget_get_accel_path (widget, NULL); - if (!path) /* no active accel_path yet */ + if (!path) /* no active accel_path yet */ { - path = menu_item->accel_path; + path = priv->accel_path; if (!path && prefix) - { - const gchar *postfix = NULL; + { + const gchar *postfix = NULL; gchar *new_path; - /* try to construct one from label text */ - gtk_container_foreach (GTK_CONTAINER (menu_item), - gtk_menu_item_accel_name_foreach, - &postfix); + /* try to construct one from label text */ + gtk_container_foreach (GTK_CONTAINER (menu_item), + gtk_menu_item_accel_name_foreach, + &postfix); if (postfix) { new_path = g_strconcat (prefix, "/", postfix, NULL); - path = menu_item->accel_path = (char*)g_intern_string (new_path); + path = priv->accel_path = (char*)g_intern_string (new_path); g_free (new_path); } - } + } if (path) - gtk_widget_set_accel_path (widget, path, accel_group); + gtk_widget_set_accel_path (widget, path, accel_group); } - else if (group_changed) /* reinstall accelerators */ + else if (group_changed) /* reinstall accelerators */ gtk_widget_set_accel_path (widget, path, accel_group); } /** - * gtk_menu_item_set_accel_path + * gtk_menu_item_set_accel_path: * @menu_item: a valid #GtkMenuItem - * @accel_path: (allow-none): accelerator path, corresponding to this menu item's - * functionality, or %NULL to unset the current path. + * @accel_path: (allow-none): accelerator path, corresponding to this menu + * item's functionality, or %NULL to unset the current path. * - * Set the accelerator path on @menu_item, through which runtime changes of the - * menu item's accelerator caused by the user can be identified and saved to - * persistant storage (see gtk_accel_map_save() on this). - * To setup a default accelerator for this menu item, call - * gtk_accel_map_add_entry() with the same @accel_path. - * See also gtk_accel_map_add_entry() on the specifics of accelerator paths, - * and gtk_menu_set_accel_path() for a more convenient variant of this function. + * Set the accelerator path on @menu_item, through which runtime + * changes of the menu item's accelerator caused by the user can be + * identified and saved to persistent storage (see gtk_accel_map_save() + * on this). To set up a default accelerator for this menu item, call + * gtk_accel_map_add_entry() with the same @accel_path. See also + * gtk_accel_map_add_entry() on the specifics of accelerator paths, + * and gtk_menu_set_accel_path() for a more convenient variant of + * this function. * - * This function is basically a convenience wrapper that handles calling - * gtk_widget_set_accel_path() with the appropriate accelerator group for - * the menu item. + * This function is basically a convenience wrapper that handles + * calling gtk_widget_set_accel_path() with the appropriate accelerator + * group for the menu item. * * Note that you do need to set an accelerator on the parent menu with * gtk_menu_set_accel_group() for this to work. * - * Note that @accel_path string will be stored in a #GQuark. Therefore, if you - * pass a static string, you can save some memory by interning it first with - * g_intern_static_string(). + * Note that @accel_path string will be stored in a #GQuark. + * Therefore, if you pass a static string, you can save some memory + * by interning it first with g_intern_static_string(). */ void gtk_menu_item_set_accel_path (GtkMenuItem *menu_item, - const gchar *accel_path) + const gchar *accel_path) { + GtkMenuItemPrivate *priv = menu_item->priv; GtkWidget *parent; GtkWidget *widget; g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); g_return_if_fail (accel_path == NULL || - (accel_path[0] == '<' && strchr (accel_path, '/'))); + (accel_path[0] == '<' && strchr (accel_path, '/'))); widget = GTK_WIDGET (menu_item); /* store new path */ - menu_item->accel_path = (char*)g_intern_string (accel_path); + priv->accel_path = (char*)g_intern_string (accel_path); /* forget accelerators associated with old path */ gtk_widget_set_accel_path (widget, NULL, NULL); @@ -2361,40 +2433,40 @@ gtk_menu_item_set_accel_path (GtkMenuItem *menu_item, { GtkMenu *menu = GTK_MENU (parent); - if (menu->accel_group) - _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget), - NULL, - menu->accel_group, - FALSE); + if (menu->priv->accel_group) + _gtk_menu_item_refresh_accel_path (GTK_MENU_ITEM (widget), + NULL, + menu->priv->accel_group, + FALSE); } } /** - * gtk_menu_item_get_accel_path + * gtk_menu_item_get_accel_path: * @menu_item: a valid #GtkMenuItem * * Retrieve the accelerator path that was previously set on @menu_item. * * See gtk_menu_item_set_accel_path() for details. * - * Returns: the accelerator path corresponding to this menu item's - * functionality, or %NULL if not set + * Returns: the accelerator path corresponding to this menu + * item's functionality, or %NULL if not set * * Since: 2.14 */ -G_CONST_RETURN gchar * +const gchar * gtk_menu_item_get_accel_path (GtkMenuItem *menu_item) { g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL); - return menu_item->accel_path; + return menu_item->priv->accel_path; } static void gtk_menu_item_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) { GtkWidget *child; @@ -2430,8 +2502,8 @@ gtk_menu_item_ensure_label (GtkMenuItem *menu_item) gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5); gtk_container_add (GTK_CONTAINER (menu_item), accel_label); - gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), - GTK_WIDGET (menu_item)); + gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), + GTK_WIDGET (menu_item)); gtk_widget_show (accel_label); } } @@ -2444,10 +2516,10 @@ gtk_menu_item_ensure_label (GtkMenuItem *menu_item) * Sets @text on the @menu_item label * * Since: 2.16 - **/ + */ void gtk_menu_item_set_label (GtkMenuItem *menu_item, - const gchar *label) + const gchar *label) { g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); @@ -2464,8 +2536,8 @@ gtk_menu_item_set_label (GtkMenuItem *menu_item, * string used by the label, and must not be modified. * * Since: 2.16 - **/ -G_CONST_RETURN gchar * + */ +const gchar * gtk_menu_item_get_label (GtkMenuItem *menu_item) { g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), NULL); @@ -2476,16 +2548,16 @@ gtk_menu_item_get_label (GtkMenuItem *menu_item) /** * gtk_menu_item_set_use_underline: * @menu_item: a #GtkMenuItem - * @setting: %TRUE if underlines in the text indicate mnemonics + * @setting: %TRUE if underlines in the text indicate mnemonics * - * If true, an underline in the text indicates the next character should be - * used for the mnemonic accelerator key. + * If true, an underline in the text indicates the next character + * should be used for the mnemonic accelerator key. * * Since: 2.16 - **/ + */ void gtk_menu_item_set_use_underline (GtkMenuItem *menu_item, - gboolean setting) + gboolean setting) { GtkWidget *child; @@ -2506,14 +2578,14 @@ gtk_menu_item_set_use_underline (GtkMenuItem *menu_item, * gtk_menu_item_get_use_underline: * @menu_item: a #GtkMenuItem * - * Checks if an underline in the text indicates the next character should be - * used for the mnemonic accelerator key. + * Checks if an underline in the text indicates the next character + * should be used for the mnemonic accelerator key. * - * Return value: %TRUE if an embedded underline in the label indicates - * the mnemonic accelerator key. + * Return value: %TRUE if an embedded underline in the label + * indicates the mnemonic accelerator key. * * Since: 2.16 - **/ + */ gboolean gtk_menu_item_get_use_underline (GtkMenuItem *menu_item) { @@ -2529,3 +2601,55 @@ gtk_menu_item_get_use_underline (GtkMenuItem *menu_item) return FALSE; } + +/** + * gtk_menu_item_set_reserve_indicator: + * @menu_item: a #GtkMenuItem + * @reserve: the new value + * + * Sets whether the @menu_item should reserve space for + * the submenu indicator, regardless if it actually has + * a submenu or not. + * + * There should be little need for applications to call + * this functions. + * + * Since: 3.0 + */ +void +gtk_menu_item_set_reserve_indicator (GtkMenuItem *menu_item, + gboolean reserve) +{ + GtkMenuItemPrivate *priv; + + g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); + + priv = menu_item->priv; + + if (priv->reserve_indicator != reserve) + { + priv->reserve_indicator = reserve; + gtk_widget_queue_resize (GTK_WIDGET (menu_item)); + } +} + +/** + * gtk_menu_item_get_reserve_indicator: + * @menu_item: a #GtkMenuItem + * + * Returns whether the @menu_item reserves space for + * the submenu indicator, regardless if it has a submenu + * or not. + * + * Returns: %TRUE if @menu_item always reserves space for the + * submenu indicator + * + * Since: 3.0 + */ +gboolean +gtk_menu_item_get_reserve_indicator (GtkMenuItem *menu_item) +{ + g_return_val_if_fail (GTK_IS_MENU_ITEM (menu_item), FALSE); + + return menu_item->priv->reserve_indicator; +}