X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkmenuitem.c;h=73c2545dcbd32243d399b27eb8f521e8f2e8754e;hb=bbf915118bd3ff3a871a8c8014514352037f6d10;hp=6194ee567e77016814ded880385808aa2f20b2fd;hpb=d4add8cefa6fa5c29bdb50f18e31cbfbfb38cc2b;p=~andy%2Fgtk diff --git a/gtk/gtkmenuitem.c b/gtk/gtkmenuitem.c index 6194ee567..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 . */ /* @@ -40,8 +38,43 @@ #include "gtkprivate.h" #include "gtkbuildable.h" #include "gtkactivatable.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 + * + * + * + * + * + * ]]> + * + * + */ enum { @@ -64,7 +97,10 @@ enum { /* activatable properties */ PROP_ACTIVATABLE_RELATED_ACTION, - PROP_ACTIVATABLE_USE_ACTION_APPEARANCE + PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, + + PROP_ACTION_NAME, + PROP_ACTION_TARGET }; @@ -122,7 +158,7 @@ static gboolean gtk_menu_item_can_activate_accel (GtkWidget *widget, 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 const gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item); static void gtk_menu_item_get_preferred_width (GtkWidget *widget, gint *minimum_size, @@ -146,6 +182,7 @@ static void gtk_menu_item_buildable_custom_finished(GtkBuildable *buildab 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, @@ -157,7 +194,6 @@ static void gtk_menu_item_set_related_action (GtkMenuItem *menu static void gtk_menu_item_set_use_action_appearance (GtkMenuItem *menu_item, gboolean use_appearance); - static guint menu_item_signals[LAST_SIGNAL] = { 0 }; static GtkBuildableIface *parent_buildable_iface; @@ -166,8 +202,58 @@ 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)) + 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); + + 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) @@ -197,6 +283,8 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) 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; @@ -210,6 +298,12 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) 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), @@ -220,6 +314,14 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) 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), @@ -281,7 +383,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) 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: @@ -350,6 +452,9 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) 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", @@ -359,14 +464,24 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) 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)); + 0, + GTK_PARAM_READABLE | + G_PARAM_DEPRECATED)); gtk_widget_class_install_style_property (widget_class, g_param_spec_int ("toggle-spacing", @@ -413,6 +528,7 @@ gtk_menu_item_class_init (GtkMenuItemClass *klass) static void gtk_menu_item_init (GtkMenuItem *menu_item) { + GtkStyleContext *context; GtkMenuItemPrivate *priv; priv = G_TYPE_INSTANCE_GET_PRIVATE (menu_item, @@ -437,14 +553,32 @@ gtk_menu_item_init (GtkMenuItem *menu_item) priv->use_action_appearance = TRUE; priv->timer = 0; priv->action = NULL; + + 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) { @@ -481,6 +615,8 @@ gtk_menu_item_dispose (GObject *object) GtkMenuItem *menu_item = GTK_MENU_ITEM (object); GtkMenuItemPrivate *priv = menu_item->priv; + g_clear_object (&priv->action_helper); + if (priv->action) { gtk_action_disconnect_accelerator (priv->action); @@ -490,6 +626,21 @@ gtk_menu_item_dispose (GObject *object) G_OBJECT_CLASS (gtk_menu_item_parent_class)->dispose (object); } +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, @@ -501,7 +652,7 @@ gtk_menu_item_set_property (GObject *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)); @@ -521,6 +672,12 @@ 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; @@ -539,7 +696,7 @@ gtk_menu_item_get_property (GObject *object, 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)); @@ -559,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; @@ -592,26 +755,28 @@ gtk_menu_item_detacher (GtkWidget *widget, static void get_arrow_size (GtkWidget *widget, GtkWidget *child, - gint *size) + gint *size, + gint *spacing) { - GtkStyleContext *style_context; - GtkStateFlags state; PangoContext *context; PangoFontMetrics *metrics; gfloat arrow_scaling; + gint arrow_spacing; g_assert (size); gtk_widget_style_get (widget, "arrow-scaling", &arrow_scaling, + "arrow-spacing", &arrow_spacing, NULL); + if (spacing != NULL) + *spacing = arrow_spacing; + context = gtk_widget_get_pango_context (child); - style_context = gtk_widget_get_style_context (child); - state = gtk_widget_get_state_flags (child); metrics = pango_context_get_metrics (context, - gtk_style_context_get_font (style_context, state), + pango_context_get_font_description (context), pango_context_get_language (context)); *size = (PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) + @@ -645,19 +810,15 @@ gtk_menu_item_accel_width_foreach (GtkWidget *widget, static gint get_minimum_width (GtkWidget *widget) { - GtkStyleContext *style_context; - GtkStateFlags state; PangoContext *context; PangoFontMetrics *metrics; gint width; gint width_chars; context = gtk_widget_get_pango_context (widget); - style_context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); metrics = pango_context_get_metrics (context, - gtk_style_context_get_font (style_context, state), + pango_context_get_font_description (context), pango_context_get_language (context)); width = pango_font_metrics_get_approximate_char_width (metrics); @@ -680,51 +841,25 @@ gtk_menu_item_get_preferred_width (GtkWidget *widget, 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, border; + GtkBorder padding; min_width = nat_width = 0; - - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); - bin = GTK_BIN (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)); context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); gtk_style_context_get_padding (context, state, &padding); - gtk_style_context_get_border (context, state, &border); - - min_width = (border_width * 2) + padding.left + padding.right + - border.left + border.right; - - 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; + 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)) @@ -736,20 +871,9 @@ gtk_menu_item_get_preferred_width (GtkWidget *widget, 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; - gtk_widget_style_get (widget, - "arrow-spacing", &arrow_spacing, - NULL); - - get_arrow_size (widget, child, &arrow_size); + get_arrow_size (widget, child, &arrow_size, &arrow_spacing); min_width += arrow_size; min_width += arrow_spacing; @@ -776,56 +900,41 @@ gtk_menu_item_get_preferred_width (GtkWidget *widget, } static void -gtk_menu_item_get_preferred_height (GtkWidget *widget, - gint *minimum_size, - gint *natural_size) +gtk_menu_item_real_get_height (GtkWidget *widget, + gint for_size, + gint *minimum_size, + gint *natural_size) { GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); GtkMenuItemPrivate *priv = menu_item->priv; GtkBin *bin; GtkStyleContext *context; GtkStateFlags state; - GtkBorder padding, border; + 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; context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); gtk_style_context_get_padding (context, state, &padding); - gtk_style_context_get_border (context, state, &border); - - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); bin = GTK_BIN (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 * 2) + padding.top + padding.bottom + border.top + border.bottom; + 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; @@ -833,23 +942,30 @@ gtk_menu_item_get_preferred_height (GtkWidget *widget, if (child != NULL && gtk_widget_get_visible (child)) { - GtkMenuItemPrivate *priv = menu_item->priv; gint child_min, child_nat; + gint arrow_size = 0, arrow_spacing = 0; - gtk_widget_get_preferred_height (child, &child_min, &child_nat); + if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator) + get_arrow_size (widget, child, &arrow_size, &arrow_spacing); + + 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); + } min_height += child_min; nat_height += child_nat; - if ((menu_item->priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator) - { - gint arrow_size; - - get_arrow_size (widget, child, &arrow_size); - - 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 */ { @@ -862,11 +978,20 @@ gtk_menu_item_get_preferred_height (GtkWidget *widget, NULL); if (wide_separators) - min_height += separator_height + padding.top + border.top; + { + min_height += separator_height; + nat_height += separator_height; + } else - min_height += padding.top + padding.bottom + border.top + border.bottom; - - 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; @@ -882,126 +1007,21 @@ gtk_menu_item_get_preferred_height (GtkWidget *widget, *natural_size = nat_height; } +static void +gtk_menu_item_get_preferred_height (GtkWidget *widget, + gint *minimum_size, + gint *natural_size) +{ + gtk_menu_item_real_get_height (widget, -1, minimum_size, natural_size); +} + static void gtk_menu_item_get_preferred_height_for_width (GtkWidget *widget, gint for_size, gint *minimum_size, gint *natural_size) { - GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); - GtkMenuItemPrivate *priv = menu_item->priv; - GtkBin *bin; - GtkStyleContext *context; - GtkStateFlags state; - GtkBorder padding, border; - GtkWidget *child; - 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; - - context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - gtk_style_context_get_padding (context, state, &padding); - gtk_style_context_get_border (context, state, &border); - - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); - - bin = GTK_BIN (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 * 2) + padding.top + padding.bottom + border.top + border.bottom; - - avail_size = for_size; - avail_size -= (border_width * 2) + padding.left + padding.right + border.left + border.right; - - 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 ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_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_widget_get_preferred_height_for_width (child, - avail_size, - &child_min, - &child_nat); - - min_height += child_min; - nat_height += child_nat; - - if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_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 + padding.top + border.top; - else - min_height += padding.top + padding.bottom + border.top + border.bottom; - - nat_height = min_height; - } - - if (minimum_size) - *minimum_size = min_height; - - if (natural_size) - *natural_size = nat_height; + gtk_menu_item_real_get_height (widget, for_size, minimum_size, natural_size); } static void @@ -1089,7 +1109,50 @@ 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, @@ -1101,7 +1164,7 @@ gtk_menu_item_update (GtkActivatable *activatable, 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_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) @@ -1131,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)); @@ -1297,6 +1360,13 @@ gtk_menu_item_select (GtkMenuItem *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) { @@ -1319,6 +1389,12 @@ gtk_menu_item_deselect (GtkMenuItem *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) { @@ -1327,6 +1403,13 @@ 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) @@ -1336,6 +1419,13 @@ gtk_menu_item_toggle_size_request (GtkMenuItem *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) @@ -1354,7 +1444,6 @@ gtk_menu_item_size_allocate (GtkWidget *widget, GtkBin *bin; GtkAllocation child_allocation; GtkTextDirection direction; - GtkPackDirection pack_dir; GtkPackDirection child_pack_dir; GtkWidget *child; GtkWidget *parent; @@ -1369,12 +1458,10 @@ gtk_menu_item_size_allocate (GtkWidget *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; } @@ -1385,40 +1472,21 @@ gtk_menu_item_size_allocate (GtkWidget *widget, { GtkStyleContext *context; GtkStateFlags state; - GtkBorder padding, border; - guint horizontal_padding; + GtkBorder padding; guint border_width; context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); gtk_style_context_get_padding (context, state, &padding); - gtk_style_context_get_border (context, state, &border); - - gtk_widget_style_get (widget, - "horizontal-padding", &horizontal_padding, - NULL); border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - child_allocation.x = border_width + padding.left + border.left; - child_allocation.y = border_width + padding.top + border.top; + child_allocation.x = border_width + padding.left; + child_allocation.y = border_width + padding.top; child_allocation.width = allocation->width - (border_width * 2) - - padding.left - padding.right - border.left - border.right; + padding.left - padding.right; child_allocation.height = allocation->height - (border_width * 2) - - padding.top - padding.bottom - border.top - border.bottom; - - 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; - child_allocation.width -= 2 * 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.height -= 2 * horizontal_padding; - } + padding.top - padding.bottom; if (child_pack_dir == GTK_PACK_DIRECTION_LTR || child_pack_dir == GTK_PACK_DIRECTION_RTL) @@ -1439,14 +1507,9 @@ gtk_menu_item_size_allocate (GtkWidget *widget, if ((priv->submenu && !GTK_IS_MENU_BAR (parent)) || priv->reserve_indicator) { - guint arrow_spacing; - gint arrow_size; + gint arrow_spacing, arrow_size; - gtk_widget_style_get (widget, - "arrow-spacing", &arrow_spacing, - NULL); - - get_arrow_size (widget, child, &arrow_size); + get_arrow_size (widget, child, &arrow_size, &arrow_spacing); if (direction == GTK_TEXT_DIR_RTL) child_allocation.x += arrow_size + arrow_spacing; @@ -1503,7 +1566,7 @@ gtk_menu_item_realize (GtkWidget *widget) priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->event_window, widget); + gtk_widget_register_window (widget, priv->event_window); } static void @@ -1512,7 +1575,7 @@ gtk_menu_item_unrealize (GtkWidget *widget) GtkMenuItem *menu_item = GTK_MENU_ITEM (widget); GtkMenuItemPrivate *priv = menu_item->priv; - gdk_window_set_user_data (priv->event_window, NULL); + gtk_widget_unregister_window (widget, priv->event_window); gdk_window_destroy (priv->event_window); priv->event_window = NULL; @@ -1585,41 +1648,29 @@ gtk_menu_item_draw (GtkWidget *widget, child = gtk_bin_get_child (GTK_BIN (menu_item)); parent = gtk_widget_get_parent (widget); - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - gtk_style_context_get_padding (context, state, &padding); - if (child && (state & GTK_STATE_FLAG_PRELIGHT)) - { - gtk_render_background (context, cr, x, y, w, h); - gtk_render_frame (context, cr, x, y, w, h); - } + 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; 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); + get_arrow_size (widget, child, &arrow_size, NULL); if (direction == GTK_TEXT_DIR_LTR) { - arrow_x = x + w - horizontal_padding - arrow_size; + arrow_x = x + w - arrow_size; angle = G_PI / 2; } else { - arrow_x = x + horizontal_padding; + arrow_x = x; angle = (3 * G_PI) / 2; } @@ -1631,45 +1682,55 @@ gtk_menu_item_draw (GtkWidget *widget, { 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_render_frame (context, cr, - horizontal_padding + padding.left, - (height - separator_height - padding.top) / 2, - width - (2 * horizontal_padding) - padding.left - padding.right, + x + padding.left, + y + padding.top, + w - padding.left - padding.right, separator_height); else gtk_render_line (context, cr, - horizontal_padding + padding.left, - (height - padding.top) / 2, - width - horizontal_padding - padding.right - 1, - (height - padding.top) / 2); + 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); - gtk_style_context_restore (context); - 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) { GtkMenuItemPrivate *priv = menu_item->priv; - gboolean touchscreen_mode; + GdkDevice *source_device = NULL; + GdkEvent *current_event; + + current_event = gtk_get_current_event (); - g_object_get (gtk_widget_get_settings (GTK_WIDGET (menu_item)), - "gtk-touchscreen-mode", &touchscreen_mode, - NULL); + if (current_event) + { + source_device = gdk_event_get_source_device (current_event); + gdk_event_free (current_event); + } - if (!touchscreen_mode && priv->submenu && + 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)) { @@ -1723,6 +1784,9 @@ gtk_real_menu_item_activate (GtkMenuItem *menu_item) { GtkMenuItemPrivate *priv = menu_item->priv; + if (priv->action_helper) + gtk_action_helper_activate (priv->action_helper); + if (priv->action) gtk_action_activate (priv->action); } @@ -1746,8 +1810,6 @@ gtk_real_menu_item_activate_item (GtkMenuItem *menu_item) 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); @@ -1791,7 +1853,7 @@ gtk_real_menu_item_set_label (GtkMenuItem *menu_item, } } -static G_CONST_RETURN gchar * +static const gchar * gtk_real_menu_item_get_label (GtkMenuItem *menu_item) { GtkWidget *child; @@ -1986,8 +2048,6 @@ get_offsets (GtkMenu *menu, gint *horizontal_offset, gint *vertical_offset) { - gint vertical_padding; - gint horizontal_padding; GtkStyleContext *context; GtkStateFlags state; GtkBorder padding; @@ -1995,8 +2055,6 @@ get_offsets (GtkMenu *menu, gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", horizontal_offset, "vertical-offset", vertical_offset, - "horizontal-padding", &horizontal_padding, - "vertical-padding", &vertical_padding, NULL); context = gtk_widget_get_style_context (GTK_WIDGET (menu)); @@ -2004,8 +2062,7 @@ get_offsets (GtkMenu *menu, gtk_style_context_get_padding (context, state, &padding); *vertical_offset -= padding.top; - *vertical_offset -= vertical_padding; - *horizontal_offset += horizontal_padding; + *horizontal_offset += padding.left; } static void @@ -2020,7 +2077,6 @@ gtk_menu_item_position_menu (GtkMenu *menu, GtkAllocation allocation; GtkWidget *widget; GtkMenuItem *parent_menu_item; - GtkRequisition requisition; GtkWidget *parent; GdkScreen *screen; gint twidth, theight; @@ -2046,15 +2102,14 @@ gtk_menu_item_position_menu (GtkMenu *menu, direction = gtk_widget_get_direction (widget); - gtk_widget_get_preferred_size (GTK_WIDGET (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, 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)) { @@ -2073,21 +2128,7 @@ 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)) - { - priv->from_menubar = TRUE; - } - else if (GTK_IS_MENU (parent)) - { - if (GTK_MENU (parent)->priv->parent_menu_item) - priv->from_menubar = GTK_MENU_ITEM (GTK_MENU (parent)->priv->parent_menu_item)->priv->from_menubar; - else - priv->from_menubar = FALSE; - } - else - { - priv->from_menubar = FALSE; - } + priv->from_menubar = GTK_IS_MENU_BAR (parent); switch (priv->submenu_placement) { @@ -2189,22 +2230,17 @@ gtk_menu_item_position_menu (GtkMenu *menu, * 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) { - GtkMenuItemPrivate *priv = menu_item->priv; - g_return_if_fail (GTK_IS_MENU_ITEM (menu_item)); - right_justified = right_justified != FALSE; - - if (priv->right_justify != right_justified) - { - priv->right_justify = right_justified; - gtk_widget_queue_resize (GTK_WIDGET (menu_item)); - } + gtk_menu_item_do_set_right_justified (menu_item, right_justified); } /** @@ -2216,6 +2252,8 @@ gtk_menu_item_set_right_justified (GtkMenuItem *menu_item, * * 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) @@ -2344,7 +2382,7 @@ _gtk_menu_item_refresh_accel_path (GtkMenuItem *menu_item, } /** - * 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. @@ -2404,7 +2442,7 @@ gtk_menu_item_set_accel_path (GtkMenuItem *menu_item, } /** - * 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. @@ -2416,7 +2454,7 @@ gtk_menu_item_set_accel_path (GtkMenuItem *menu_item, * * 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); @@ -2499,7 +2537,7 @@ gtk_menu_item_set_label (GtkMenuItem *menu_item, * * 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);