X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkmenubar.c;h=d337d712ae4f7ed2a1b09c0874f801c1fec035c4;hb=67f5e595a796a8321d6dc7737c58476564998c07;hp=da116d48334f3a4a085cffab95d56fbcba672668;hpb=923fcaa9283e4203a22c65ec48d8a5f499cc78d5;p=~andy%2Fgtk diff --git a/gtk/gtkmenubar.c b/gtk/gtkmenubar.c index da116d483..d337d712a 100644 --- a/gtk/gtkmenubar.c +++ b/gtk/gtkmenubar.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 . */ /* @@ -48,13 +46,11 @@ #include "gtksettings.h" #include "gtksizerequest.h" #include "gtkwindow.h" +#include "gtkcontainerprivate.h" #include "gtkintl.h" #include "gtkprivate.h" #include "gtktypebuiltins.h" -#define BORDER_SPACING 0 -#define DEFAULT_IPADDING 1 - /* Properties */ enum { PROP_0, @@ -83,6 +79,14 @@ static void gtk_menu_bar_get_preferred_width (GtkWidget *widget, static void gtk_menu_bar_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural); +static void gtk_menu_bar_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum, + gint *natural); +static void gtk_menu_bar_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum, + gint *natural); static void gtk_menu_bar_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gint gtk_menu_bar_draw (GtkWidget *widget, @@ -115,10 +119,14 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) widget_class->get_preferred_width = gtk_menu_bar_get_preferred_width; widget_class->get_preferred_height = gtk_menu_bar_get_preferred_height; + widget_class->get_preferred_width_for_height = gtk_menu_bar_get_preferred_width_for_height; + widget_class->get_preferred_height_for_width = gtk_menu_bar_get_preferred_height_for_width; widget_class->size_allocate = gtk_menu_bar_size_allocate; widget_class->draw = gtk_menu_bar_draw; widget_class->hierarchy_changed = gtk_menu_bar_hierarchy_changed; + gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_MENU_BAR); + menu_shell_class->submenu_placement = GTK_TOP_BOTTOM; menu_shell_class->get_popup_delay = gtk_menu_bar_get_popup_delay; menu_shell_class->move_current = gtk_menu_bar_move_current; @@ -208,14 +216,24 @@ gtk_menu_bar_class_init (GtkMenuBarClass *class) GTK_SHADOW_OUT, GTK_PARAM_READABLE)); + /** + * GtkMenuBar:internal-padding: + * + * Amount of border space between the menubar shadow and the menu items + * + * 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 ("internal-padding", P_("Internal padding"), P_("Amount of border space between the menubar shadow and the menu items"), 0, G_MAXINT, - DEFAULT_IPADDING, - GTK_PARAM_READABLE)); + 0, + GTK_PARAM_READABLE | + G_PARAM_DEPRECATED)); g_type_class_add_private (gobject_class, sizeof (GtkMenuBarPrivate)); } @@ -290,9 +308,29 @@ gtk_menu_bar_get_property (GObject *object, } } +static void +get_preferred_size_for_size (GtkWidget *widget, + GtkOrientation orientation, + gint size, + gint *minimum, + gint *natural) +{ + if (orientation == GTK_ORIENTATION_HORIZONTAL) + if (size < 0) + gtk_widget_get_preferred_width (widget, minimum, natural); + else + gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural); + else + if (size < 0) + gtk_widget_get_preferred_height (widget, minimum, natural); + else + gtk_widget_get_preferred_height_for_width (widget, size, minimum, natural); +} + static void gtk_menu_bar_size_request (GtkWidget *widget, GtkOrientation orientation, + gint size, gint *minimum, gint *natural) { @@ -301,11 +339,15 @@ gtk_menu_bar_size_request (GtkWidget *widget, GtkMenuShell *menu_shell; GtkWidget *child; GList *children; - GtkRequisition child_requisition; - gint ipadding; guint border_width; - gboolean use_toggle_size; - gint size = 0; + gboolean use_toggle_size, use_maximize; + gint child_minimum, child_natural; + GtkStyleContext *context; + GtkBorder border; + GtkStateFlags flags; + + *minimum = 0; + *natural = 0; menu_bar = GTK_MENU_BAR (widget); menu_shell = GTK_MENU_SHELL (widget); @@ -319,6 +361,12 @@ gtk_menu_bar_size_request (GtkWidget *widget, else use_toggle_size = (orientation == GTK_ORIENTATION_VERTICAL); + if (priv->pack_direction == GTK_PACK_DIRECTION_LTR || + priv->pack_direction == GTK_PACK_DIRECTION_RTL) + use_maximize = (orientation == GTK_ORIENTATION_VERTICAL); + else + use_maximize = (orientation == GTK_ORIENTATION_HORIZONTAL); + while (children) { child = children->data; @@ -326,7 +374,7 @@ gtk_menu_bar_size_request (GtkWidget *widget, if (gtk_widget_get_visible (child)) { - gtk_widget_get_preferred_size (child, &child_requisition, NULL); + get_preferred_size_for_size (child, orientation, size, &child_minimum, &child_natural); if (use_toggle_size) { @@ -335,52 +383,57 @@ gtk_menu_bar_size_request (GtkWidget *widget, gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size); - child_requisition.width += toggle_size; - child_requisition.height += toggle_size; + child_minimum += toggle_size; + child_natural += toggle_size; } - if (priv->pack_direction == GTK_PACK_DIRECTION_LTR || - priv->pack_direction == GTK_PACK_DIRECTION_RTL) + if (use_maximize) { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - size += child_requisition.width; - else - size = MAX (size, child_requisition.height); + *minimum = MAX (*minimum, child_minimum); + *natural = MAX (*natural, child_natural); } else { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - size = MAX (size, child_requisition.width); - else - size += child_requisition.height; + *minimum += child_minimum; + *natural += child_natural; } } } - gtk_widget_style_get (widget, "internal-padding", &ipadding, NULL); + context = gtk_widget_get_style_context (widget); + flags = gtk_widget_get_state_flags (widget); + gtk_style_context_get_padding (context, flags, &border); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + *minimum += border.left + border.right; + *natural += border.left + border.right; + } + else + { + *minimum += border.top + border.bottom; + *natural += border.top + border.bottom; + } border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_bar)); - size += (border_width + ipadding + BORDER_SPACING) * 2; + *minimum += border_width * 2; + *natural += border_width * 2; if (get_shadow_type (menu_bar) != GTK_SHADOW_NONE) { - GtkStyleContext *context; - GtkBorder *border; - - context = gtk_widget_get_style_context (widget); - - gtk_style_context_get (context, 0, - "border-width", &border, - NULL); + gtk_style_context_get_border (context, flags, &border); if (orientation == GTK_ORIENTATION_HORIZONTAL) - size += border->left + border->right; + { + *minimum += border.left + border.right; + *natural += border.left + border.right; + } else - size += border->top + border->bottom; - gtk_border_free (border); + { + *minimum += border.top + border.bottom; + *natural += border.top + border.bottom; + } } - - *minimum = *natural = size; } static void @@ -388,7 +441,7 @@ gtk_menu_bar_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural) { - gtk_menu_bar_size_request (widget, GTK_ORIENTATION_HORIZONTAL, minimum, natural); + gtk_menu_bar_size_request (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural); } static void @@ -396,7 +449,25 @@ gtk_menu_bar_get_preferred_height (GtkWidget *widget, gint *minimum, gint *natural) { - gtk_menu_bar_size_request (widget, GTK_ORIENTATION_VERTICAL, minimum, natural); + gtk_menu_bar_size_request (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural); +} + +static void +gtk_menu_bar_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum, + gint *natural) +{ + gtk_menu_bar_size_request (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural); +} + +static void +gtk_menu_bar_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum, + gint *natural) +{ + gtk_menu_bar_size_request (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural); } static void @@ -408,13 +479,11 @@ gtk_menu_bar_size_allocate (GtkWidget *widget, GtkMenuBarPrivate *priv; GtkWidget *child; GList *children; - GtkAllocation child_allocation; - GtkRequisition child_requisition; - guint offset; - GtkTextDirection direction; - gint ltr_x, ltr_y; - gint ipadding; + GtkAllocation remaining_space; guint border_width; + GArray *requested_sizes; + gint toggle_size; + guint i; g_return_if_fail (GTK_IS_MENU_BAR (widget)); g_return_if_fail (allocation != NULL); @@ -423,8 +492,6 @@ gtk_menu_bar_size_allocate (GtkWidget *widget, menu_shell = GTK_MENU_SHELL (widget); priv = menu_bar->priv; - direction = gtk_widget_get_direction (widget); - gtk_widget_set_allocation (widget, allocation); if (gtk_widget_get_realized (widget)) @@ -432,136 +499,148 @@ gtk_menu_bar_size_allocate (GtkWidget *widget, allocation->x, allocation->y, allocation->width, allocation->height); - gtk_widget_style_get (widget, "internal-padding", &ipadding, NULL); - if (menu_shell->priv->children) { + GtkStyleContext *context; + GtkStateFlags flags; + GtkBorder border; + + context = gtk_widget_get_style_context (widget); + flags = gtk_widget_get_state_flags (widget); + gtk_style_context_get_padding (context, flags, &border); + border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_bar)); - child_allocation.x = (border_width + - ipadding + - BORDER_SPACING); - child_allocation.y = (border_width + - BORDER_SPACING); - - if (get_shadow_type (menu_bar) != GTK_SHADOW_NONE) - { - GtkStyleContext *context; - GtkBorder *border; - context = gtk_widget_get_style_context (widget); - gtk_style_context_get (context, 0, - "border-width", &border, - NULL); + remaining_space.x = (border_width + border.left); + remaining_space.y = (border_width + border.top); + remaining_space.width = allocation->width - + 2 * (border_width) - border.left - border.right; + remaining_space.height = allocation->height - + 2 * (border_width) - border.top - border.bottom; - child_allocation.x += border->left; - child_allocation.y += border->top; + if (get_shadow_type (menu_bar) != GTK_SHADOW_NONE) + { + gtk_style_context_get_border (context, flags, &border); - gtk_border_free (border); + remaining_space.x += border.left; + remaining_space.y += border.top; + remaining_space.width -= border.left + border.right; + remaining_space.height -= border.top + border.bottom; } + requested_sizes = g_array_new (FALSE, FALSE, sizeof (GtkRequestedSize)); + if (priv->pack_direction == GTK_PACK_DIRECTION_LTR || priv->pack_direction == GTK_PACK_DIRECTION_RTL) { - child_allocation.height = MAX (1, (gint)allocation->height - child_allocation.y * 2); - - offset = child_allocation.x; /* Window edge to menubar start */ - ltr_x = child_allocation.x; + int size = remaining_space.width; + gboolean ltr = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) == (priv->pack_direction == GTK_PACK_DIRECTION_LTR); - children = menu_shell->priv->children; - while (children) + for (children = menu_shell->priv->children; children; children = children->next) { - gint toggle_size; - + GtkRequestedSize request; child = children->data; - children = children->next; - + + if (!gtk_widget_get_visible (child)) + continue; + + request.data = child; + gtk_widget_get_preferred_width_for_height (child, + remaining_space.height, + &request.minimum_size, + &request.natural_size); gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size); - gtk_widget_get_preferred_size (child, &child_requisition, NULL); - - if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR || - priv->child_pack_direction == GTK_PACK_DIRECTION_RTL) - child_requisition.width += toggle_size; - else - child_requisition.height += toggle_size; - - /* Support for the right justified help menu */ - if (children == NULL && - GTK_IS_MENU_ITEM (child) && - GTK_MENU_ITEM (child)->priv->right_justify) - { - ltr_x = allocation->width - - child_requisition.width - offset; - } - if (gtk_widget_get_visible (child)) - { - if ((direction == GTK_TEXT_DIR_LTR) == (priv->pack_direction == GTK_PACK_DIRECTION_LTR)) - child_allocation.x = ltr_x; - else - child_allocation.x = allocation->width - - child_requisition.width - ltr_x; - - child_allocation.width = child_requisition.width; - - gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child), - toggle_size); - gtk_widget_size_allocate (child, &child_allocation); - - ltr_x += child_allocation.width; - } - } + request.minimum_size += toggle_size; + request.natural_size += toggle_size; + + gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child), toggle_size); + + g_array_append_val (requested_sizes, request); + + size -= request.minimum_size; + } + + size = gtk_distribute_natural_allocation (size, + requested_sizes->len, + (GtkRequestedSize *) requested_sizes->data); + + for (i = 0; i < requested_sizes->len; i++) + { + GtkAllocation child_allocation = remaining_space; + GtkRequestedSize *request = &g_array_index (requested_sizes, GtkRequestedSize, i); + + child_allocation.width = request->minimum_size; + remaining_space.width -= request->minimum_size; + + if (i + 1 == requested_sizes->len && GTK_IS_MENU_ITEM (request->data) && + GTK_MENU_ITEM (request->data)->priv->right_justify) + ltr = !ltr; + + if (ltr) + remaining_space.x += request->minimum_size; + else + child_allocation.x += remaining_space.width; + + gtk_widget_size_allocate (request->data, &child_allocation); + } } else { - child_allocation.width = MAX (1, (gint)allocation->width - child_allocation.x * 2); - - offset = child_allocation.y; /* Window edge to menubar start */ - ltr_y = child_allocation.y; + int size = remaining_space.height; + gboolean ttb = (priv->pack_direction == GTK_PACK_DIRECTION_TTB); - children = menu_shell->priv->children; - while (children) + for (children = menu_shell->priv->children; children; children = children->next) { - gint toggle_size; - + GtkRequestedSize request; child = children->data; - children = children->next; - + + if (!gtk_widget_get_visible (child)) + continue; + + request.data = child; + gtk_widget_get_preferred_height_for_width (child, + remaining_space.width, + &request.minimum_size, + &request.natural_size); gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size); - gtk_widget_get_preferred_size (child, &child_requisition, NULL); - - if (priv->child_pack_direction == GTK_PACK_DIRECTION_LTR || - priv->child_pack_direction == GTK_PACK_DIRECTION_RTL) - child_requisition.width += toggle_size; - else - child_requisition.height += toggle_size; - - /* Support for the right justified help menu */ - if (children == NULL && - GTK_IS_MENU_ITEM (child) && - GTK_MENU_ITEM (child)->priv->right_justify) - { - ltr_y = allocation->height - - child_requisition.height - offset; - } - if (gtk_widget_get_visible (child)) - { - if ((direction == GTK_TEXT_DIR_LTR) == - (priv->pack_direction == GTK_PACK_DIRECTION_TTB)) - child_allocation.y = ltr_y; - else - child_allocation.y = allocation->height - - child_requisition.height - ltr_y; - child_allocation.height = child_requisition.height; - - gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child), - toggle_size); - gtk_widget_size_allocate (child, &child_allocation); - - ltr_y += child_allocation.height; - } - } + request.minimum_size += toggle_size; + request.natural_size += toggle_size; + + gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child), toggle_size); + + g_array_append_val (requested_sizes, request); + + size -= request.minimum_size; + } + + size = gtk_distribute_natural_allocation (size, + requested_sizes->len, + (GtkRequestedSize *) requested_sizes->data); + + for (i = 0; i < requested_sizes->len; i++) + { + GtkAllocation child_allocation = remaining_space; + GtkRequestedSize *request = &g_array_index (requested_sizes, GtkRequestedSize, i); + + child_allocation.height = request->minimum_size; + remaining_space.height -= request->minimum_size; + + if (i + 1 == requested_sizes->len && GTK_IS_MENU_ITEM (request->data) && + GTK_MENU_ITEM (request->data)->priv->right_justify) + ttb = !ttb; + + if (ttb) + remaining_space.y += request->minimum_size; + else + child_allocation.y += remaining_space.height; + + gtk_widget_size_allocate (request->data, &child_allocation); + } } + + g_array_free (requested_sizes, TRUE); } } @@ -570,25 +649,21 @@ gtk_menu_bar_draw (GtkWidget *widget, cairo_t *cr) { GtkStyleContext *context; - GtkStateFlags state; int border; border = 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_set_state (context, state); + gtk_render_background (context, cr, + border, border, + gtk_widget_get_allocated_width (widget) - border * 2, + gtk_widget_get_allocated_height (widget) - border * 2); if (get_shadow_type (GTK_MENU_BAR (widget)) != GTK_SHADOW_NONE) - gtk_render_background (context, cr, - border, border, - gtk_widget_get_allocated_width (widget) - border * 2, - gtk_widget_get_allocated_height (widget) - border * 2); - - gtk_render_frame (context, cr, - border, border, - gtk_widget_get_allocated_width (widget) - border * 2, - gtk_widget_get_allocated_height (widget) - border * 2); + gtk_render_frame (context, cr, + border, border, + gtk_widget_get_allocated_width (widget) - border * 2, + gtk_widget_get_allocated_height (widget) - border * 2); GTK_WIDGET_CLASS (gtk_menu_bar_parent_class)->draw (widget, cr); @@ -981,3 +1056,32 @@ gtk_menu_bar_set_child_pack_direction (GtkMenuBar *menubar, g_object_notify (G_OBJECT (menubar), "child-pack-direction"); } } + +/** + * gtk_menu_bar_new_from_model: + * @model: a #GMenuModel + * + * Creates a new #GtkMenuBar and populates it with menu items + * and submenus according to @model. + * + * The created menu items are connected to actions found in the + * #GtkApplicationWindow to which the menu bar belongs - typically + * by means of being contained within the #GtkApplicationWindows + * widget hierarchy. + * + * Returns: a new #GtkMenuBar + * + * Since: 3.4 + */ +GtkWidget * +gtk_menu_bar_new_from_model (GMenuModel *model) +{ + GtkWidget *menubar; + + g_return_val_if_fail (G_IS_MENU_MODEL (model), NULL); + + menubar = gtk_menu_bar_new (); + gtk_menu_shell_bind_model (GTK_MENU_SHELL (menubar), model, NULL, FALSE); + + return menubar; +}