X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtksizegroup.c;h=e31dfa84eb1755b30b53f228eeff280941a16989;hb=5e2c23214564f7dcc687fa8467020eeb6b9407a9;hp=10d2c43b861c598460df5ea0c1e084e28f7f4a45;hpb=6f5687c1e305e1d2eab3764caedc7487bf7ea470;p=~andy%2Fgtk diff --git a/gtk/gtksizegroup.c b/gtk/gtksizegroup.c index 10d2c43b8..e31dfa84e 100644 --- a/gtk/gtksizegroup.c +++ b/gtk/gtksizegroup.c @@ -13,17 +13,110 @@ * 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 . */ -#include +#include "config.h" +#include + +#include "gtkbuildable.h" #include "gtkcontainer.h" #include "gtkintl.h" +#include "gtktypebuiltins.h" #include "gtkprivate.h" -#include "gtksizegroup.h" -#include "gtkalias.h" +#include "gtksizegroup-private.h" +#include "gtksizerequestcacheprivate.h" +#include "gtkwidgetprivate.h" +#include "gtkcontainerprivate.h" + + +/** + * SECTION:gtksizegroup + * @Short_description: Grouping widgets so they request the same size + * @Title: GtkSizeGroup + * + * #GtkSizeGroup provides a mechanism for grouping a number of widgets + * together so they all request the same amount of space. This is + * typically useful when you want a column of widgets to have the same + * size, but you can't use a #GtkGrid widget. + * + * In detail, the size requested for each widget in a #GtkSizeGroup is + * the maximum of the sizes that would have been requested for each + * widget in the size group if they were not in the size group. The mode + * of the size group (see gtk_size_group_set_mode()) determines whether + * this applies to the horizontal size, the vertical size, or both sizes. + * + * Note that size groups only affect the amount of space requested, not + * the size that the widgets finally receive. If you want the widgets in + * a #GtkSizeGroup to actually be the same size, you need to pack them in + * such a way that they get the size they request and not more. For + * example, if you are packing your widgets into a table, you would not + * include the %GTK_FILL flag. + * + * #GtkSizeGroup objects are referenced by each widget in the size group, + * so once you have added all widgets to a #GtkSizeGroup, you can drop + * the initial reference to the size group with g_object_unref(). If the + * widgets in the size group are subsequently destroyed, then they will + * be removed from the size group and drop their references on the size + * group; when all widgets have been removed, the size group will be + * freed. + * + * Widgets can be part of multiple size groups; GTK+ will compute the + * horizontal size of a widget from the horizontal requisition of all + * widgets that can be reached from the widget by a chain of size groups + * of type %GTK_SIZE_GROUP_HORIZONTAL or %GTK_SIZE_GROUP_BOTH, and the + * vertical size from the vertical requisition of all widgets that can be + * reached from the widget by a chain of size groups of type + * %GTK_SIZE_GROUP_VERTICAL or %GTK_SIZE_GROUP_BOTH. + * + * Note that only non-contextual sizes of every widget are ever consulted + * by size groups (since size groups have no knowledge of what size a widget + * will be allocated in one dimension, it cannot derive how much height + * a widget will receive for a given width). When grouping widgets that + * trade height for width in mode %GTK_SIZE_GROUP_VERTICAL or %GTK_SIZE_GROUP_BOTH: + * the height for the minimum width will be the requested height for all + * widgets in the group. The same is of course true when horizontally grouping + * width for height widgets. + * + * Widgets that trade height-for-width should set a reasonably large minimum width + * by way of #GtkLabel:width-chars for instance. Widgets with static sizes as well + * as widgets that grow (such as ellipsizing text) need no such considerations. + * + * + * GtkSizeGroup as GtkBuildable + * + * Size groups can be specified in a UI definition by placing an + * <object> element with class="GtkSizeGroup" + * somewhere in the UI definition. The widgets that belong to the + * size group are specified by a <widgets> element that may + * contain multiple <widget> elements, one for each member + * of the size group. The name attribute gives the id of the widget. + * + * + * A UI definition fragment with GtkSizeGroup + * + * GTK_SIZE_GROUP_HORIZONTAL + * + * + * + * + * + * ]]> + * + * + * + */ + + +struct _GtkSizeGroupPrivate +{ + GSList *widgets; + + guint8 mode; + + guint ignore_hidden : 1; +}; enum { PROP_0, @@ -40,194 +133,181 @@ static void gtk_size_group_get_property (GObject *object, GValue *value, GParamSpec *pspec); -static void add_group_to_closure (GtkSizeGroup *group, - GtkSizeGroupMode mode, - GSList **groups, - GSList **widgets); -static void add_widget_to_closure (GtkWidget *widget, - GtkSizeGroupMode mode, - GSList **groups, - GSList **widgets); - -static GQuark size_groups_quark; -static const gchar size_groups_tag[] = "gtk-size-groups"; - -static GSList * -get_size_groups (GtkWidget *widget) -{ - if (!size_groups_quark) - size_groups_quark = g_quark_from_static_string (size_groups_tag); - - return g_object_get_qdata (G_OBJECT (widget), size_groups_quark); -} +/* GtkBuildable */ +static void gtk_size_group_buildable_init (GtkBuildableIface *iface); +static gboolean gtk_size_group_buildable_custom_tag_start (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + GMarkupParser *parser, + gpointer *data); +static void gtk_size_group_buildable_custom_finished (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer user_data); + +G_STATIC_ASSERT (GTK_SIZE_GROUP_HORIZONTAL == (1 << GTK_ORIENTATION_HORIZONTAL)); +G_STATIC_ASSERT (GTK_SIZE_GROUP_VERTICAL == (1 << GTK_ORIENTATION_VERTICAL)); +G_STATIC_ASSERT (GTK_SIZE_GROUP_BOTH == (GTK_SIZE_GROUP_HORIZONTAL | GTK_SIZE_GROUP_VERTICAL)); static void -set_size_groups (GtkWidget *widget, - GSList *groups) +add_widget_to_closure (GHashTable *widgets, + GHashTable *groups, + GtkWidget *widget, + GtkOrientation orientation) { - if (!size_groups_quark) - size_groups_quark = g_quark_from_static_string (size_groups_tag); + GSList *tmp_groups, *tmp_widgets; + gboolean hidden; - g_object_set_qdata (G_OBJECT (widget), size_groups_quark, groups); -} + if (g_hash_table_lookup (widgets, widget)) + return; -static void -add_group_to_closure (GtkSizeGroup *group, - GtkSizeGroupMode mode, - GSList **groups, - GSList **widgets) -{ - GSList *tmp_widgets; - - *groups = g_slist_prepend (*groups, group); + g_hash_table_add (widgets, widget); + hidden = !gtk_widget_is_visible (widget); - tmp_widgets = group->widgets; - while (tmp_widgets) + for (tmp_groups = _gtk_widget_get_sizegroups (widget); tmp_groups; tmp_groups = tmp_groups->next) { - GtkWidget *tmp_widget = tmp_widgets->data; - - if (!g_slist_find (*widgets, tmp_widget)) - add_widget_to_closure (tmp_widget, mode, groups, widgets); - - tmp_widgets = tmp_widgets->next; - } -} + GtkSizeGroup *tmp_group = tmp_groups->data; + GtkSizeGroupPrivate *tmp_priv = tmp_group->priv; -static void -add_widget_to_closure (GtkWidget *widget, - GtkSizeGroupMode mode, - GSList **groups, - GSList **widgets) -{ - GSList *tmp_groups; + if (g_hash_table_lookup (groups, tmp_group)) + continue; - *widgets = g_slist_prepend (*widgets, widget); + if (tmp_priv->ignore_hidden && hidden) + continue; - tmp_groups = get_size_groups (widget); - while (tmp_groups) - { - GtkSizeGroup *tmp_group = tmp_groups->data; - - if ((tmp_group->mode == GTK_SIZE_GROUP_BOTH || tmp_group->mode == mode) && - !g_slist_find (*groups, tmp_group)) - add_group_to_closure (tmp_group, mode, groups, widgets); + if (!(tmp_priv->mode & (1 << orientation))) + continue; + + g_hash_table_add (groups, tmp_group); - tmp_groups = tmp_groups->next; + for (tmp_widgets = tmp_priv->widgets; tmp_widgets; tmp_widgets = tmp_widgets->next) + add_widget_to_closure (widgets, groups, tmp_widgets->data, orientation); } } -static void -real_queue_resize (GtkWidget *widget) +GHashTable * +_gtk_size_group_get_widget_peers (GtkWidget *for_widget, + GtkOrientation orientation) { - GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED); - GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED); - - if (widget->parent) - _gtk_container_queue_resize (GTK_CONTAINER (widget->parent)); - else if (GTK_WIDGET_TOPLEVEL (widget) && GTK_IS_CONTAINER (widget)) - _gtk_container_queue_resize (GTK_CONTAINER (widget)); -} + GHashTable *widgets, *groups; + widgets = g_hash_table_new (g_direct_hash, g_direct_equal); + groups = g_hash_table_new (g_direct_hash, g_direct_equal); + + add_widget_to_closure (widgets, groups, for_widget, orientation); + + g_hash_table_unref (groups); + + return widgets; +} + static void -reset_group_sizes (GSList *groups) +real_queue_resize (GtkWidget *widget, + GtkQueueResizeFlags flags) { - GSList *tmp_list = groups; - while (tmp_list) - { - GtkSizeGroup *tmp_group = tmp_list->data; + GtkWidget *container; - tmp_group->have_width = FALSE; - tmp_group->have_height = FALSE; - - tmp_list = tmp_list->next; + _gtk_widget_set_alloc_needed (widget, TRUE); + _gtk_size_request_cache_clear (_gtk_widget_peek_request_cache (widget)); + + container = gtk_widget_get_parent (widget); + if (!container && + gtk_widget_is_toplevel (widget) && GTK_IS_CONTAINER (widget)) + container = widget; + + if (container) + { + if (flags & GTK_QUEUE_RESIZE_INVALIDATE_ONLY) + _gtk_container_resize_invalidate (GTK_CONTAINER (container)); + else + _gtk_container_queue_resize (GTK_CONTAINER (container)); } } static void -queue_resize_on_widget (GtkWidget *widget, - gboolean check_siblings) +queue_resize_on_widget (GtkWidget *widget, + gboolean check_siblings, + GtkQueueResizeFlags flags) { GtkWidget *parent = widget; - GSList *tmp_list; while (parent) { GSList *widget_groups; - GSList *groups; - GSList *widgets; + GHashTable *widgets; + GHashTableIter iter; + gpointer current; if (widget == parent && !check_siblings) { - real_queue_resize (widget); - parent = parent->parent; + real_queue_resize (widget, flags); + parent = gtk_widget_get_parent (parent); continue; } - widget_groups = get_size_groups (parent); + widget_groups = _gtk_widget_get_sizegroups (parent); if (!widget_groups) { if (widget == parent) - real_queue_resize (widget); + real_queue_resize (widget, flags); - parent = parent->parent; + parent = gtk_widget_get_parent (parent); continue; } - groups = NULL; - widgets = NULL; - - add_widget_to_closure (parent, GTK_SIZE_GROUP_HORIZONTAL, &groups, &widgets); - reset_group_sizes (groups); - - tmp_list = widgets; - while (tmp_list) + widgets = _gtk_size_group_get_widget_peers (parent, GTK_ORIENTATION_HORIZONTAL); + + g_hash_table_iter_init (&iter, widgets); + while (g_hash_table_iter_next (&iter, ¤t, NULL)) { - if (tmp_list->data == parent) + if (current == parent) { if (widget == parent) - real_queue_resize (parent); + real_queue_resize (parent, flags); } + else if (current == widget) + { + g_warning ("A container and its child are part of this SizeGroup"); + } else - queue_resize_on_widget (tmp_list->data, FALSE); - - tmp_list = tmp_list->next; + queue_resize_on_widget (current, FALSE, flags); } - g_slist_free (widgets); - g_slist_free (groups); - - groups = NULL; - widgets = NULL; - - add_widget_to_closure (parent, GTK_SIZE_GROUP_VERTICAL, &groups, &widgets); - reset_group_sizes (groups); - - tmp_list = widgets; - while (tmp_list) + g_hash_table_destroy (widgets); + + widgets = _gtk_size_group_get_widget_peers (parent, GTK_ORIENTATION_VERTICAL); + + g_hash_table_iter_init (&iter, widgets); + while (g_hash_table_iter_next (&iter, ¤t, NULL)) { - if (tmp_list->data == parent) + if (current == parent) { if (widget == parent) - real_queue_resize (parent); + real_queue_resize (parent, flags); } + else if (current == widget) + { + g_warning ("A container and its child are part of this SizeGroup"); + } else - queue_resize_on_widget (tmp_list->data, FALSE); - - tmp_list = tmp_list->next; + queue_resize_on_widget (current, FALSE, flags); } - g_slist_free (widgets); - g_slist_free (groups); - - parent = parent->parent; + g_hash_table_destroy (widgets); + + parent = gtk_widget_get_parent (parent); } } static void -queue_resize_on_group (GtkSizeGroup *size_group) +queue_resize_on_group (GtkSizeGroup *size_group) { - if (size_group->widgets) - queue_resize_on_widget (size_group->widgets->data, TRUE); + GtkSizeGroupPrivate *priv = size_group->priv; + + if (priv->widgets) + queue_resize_on_widget (priv->widgets->data, TRUE, 0); } static void @@ -245,13 +325,12 @@ gtk_size_group_class_init (GtkSizeGroupClass *klass) P_("The directions in which the size group affects the requested sizes" " of its component widgets"), GTK_TYPE_SIZE_GROUP_MODE, - GTK_SIZE_GROUP_HORIZONTAL, - GTK_PARAM_READWRITE)); + GTK_SIZE_GROUP_HORIZONTAL, GTK_PARAM_READWRITE)); /** * GtkSizeGroup:ignore-hidden: * - * If %TRUE, hidden widgets are ignored when determining + * If %TRUE, unmapped widgets are ignored when determining * the size of the group. * * Since: 2.8 @@ -260,49 +339,40 @@ gtk_size_group_class_init (GtkSizeGroupClass *klass) PROP_IGNORE_HIDDEN, g_param_spec_boolean ("ignore-hidden", P_("Ignore hidden"), - P_("If TRUE, hidden widgets are ignored " + P_("If TRUE, unmapped widgets are ignored " "when determining the size of the group"), FALSE, GTK_PARAM_READWRITE)); + + g_type_class_add_private (klass, sizeof (GtkSizeGroupPrivate)); } static void gtk_size_group_init (GtkSizeGroup *size_group) { - size_group->widgets = NULL; - size_group->mode = GTK_SIZE_GROUP_HORIZONTAL; - size_group->have_width = 0; - size_group->have_height = 0; - size_group->ignore_hidden = 0; -} + GtkSizeGroupPrivate *priv; -GType -gtk_size_group_get_type (void) -{ - static GType size_group_type = 0; + size_group->priv = G_TYPE_INSTANCE_GET_PRIVATE (size_group, + GTK_TYPE_SIZE_GROUP, + GtkSizeGroupPrivate); + priv = size_group->priv; - if (!size_group_type) - { - static const GTypeInfo size_group_info = - { - sizeof (GtkSizeGroupClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_size_group_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GtkSizeGroup), - 16, /* n_preallocs */ - (GInstanceInitFunc) gtk_size_group_init, - }; - - size_group_type = g_type_register_static (G_TYPE_OBJECT, "GtkSizeGroup", - &size_group_info, 0); - } + priv->widgets = NULL; + priv->mode = GTK_SIZE_GROUP_HORIZONTAL; + priv->ignore_hidden = FALSE; +} - return size_group_type; +static void +gtk_size_group_buildable_init (GtkBuildableIface *iface) +{ + iface->custom_tag_start = gtk_size_group_buildable_custom_tag_start; + iface->custom_finished = gtk_size_group_buildable_custom_finished; } +G_DEFINE_TYPE_WITH_CODE (GtkSizeGroup, gtk_size_group, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, + gtk_size_group_buildable_init)) + static void gtk_size_group_set_property (GObject *object, guint prop_id, @@ -332,14 +402,15 @@ gtk_size_group_get_property (GObject *object, GParamSpec *pspec) { GtkSizeGroup *size_group = GTK_SIZE_GROUP (object); + GtkSizeGroupPrivate *priv = size_group->priv; switch (prop_id) { case PROP_MODE: - g_value_set_enum (value, size_group->mode); + g_value_set_enum (value, priv->mode); break; case PROP_IGNORE_HIDDEN: - g_value_set_boolean (value, size_group->ignore_hidden); + g_value_set_boolean (value, priv->ignore_hidden); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -356,11 +427,12 @@ gtk_size_group_get_property (GObject *object, * Return value: a newly created #GtkSizeGroup **/ GtkSizeGroup * -gtk_size_group_new (GtkSizeGroupMode mode) +gtk_size_group_new (GtkSizeGroupMode mode) { GtkSizeGroup *size_group = g_object_new (GTK_TYPE_SIZE_GROUP, NULL); + GtkSizeGroupPrivate *priv = size_group->priv; - size_group->mode = mode; + priv->mode = mode; return size_group; } @@ -372,23 +444,27 @@ gtk_size_group_new (GtkSizeGroupMode mode) * * Sets the #GtkSizeGroupMode of the size group. The mode of the size * group determines whether the widgets in the size group should - * all have the same horizontal requisition (%GTK_SIZE_GROUP_MODE_HORIZONTAL) - * all have the same vertical requisition (%GTK_SIZE_GROUP_MODE_VERTICAL), + * all have the same horizontal requisition (%GTK_SIZE_GROUP_HORIZONTAL) + * all have the same vertical requisition (%GTK_SIZE_GROUP_VERTICAL), * or should all have the same requisition in both directions - * (%GTK_SIZE_GROUP_MODE_BOTH). + * (%GTK_SIZE_GROUP_BOTH). **/ void gtk_size_group_set_mode (GtkSizeGroup *size_group, GtkSizeGroupMode mode) { + GtkSizeGroupPrivate *priv; + g_return_if_fail (GTK_IS_SIZE_GROUP (size_group)); - if (size_group->mode != mode) + priv = size_group->priv; + + if (priv->mode != mode) { - if (size_group->mode != GTK_SIZE_GROUP_NONE) + if (priv->mode != GTK_SIZE_GROUP_NONE) queue_resize_on_group (size_group); - size_group->mode = mode; - if (size_group->mode != GTK_SIZE_GROUP_NONE) + priv->mode = mode; + if (priv->mode != GTK_SIZE_GROUP_NONE) queue_resize_on_group (size_group); g_object_notify (G_OBJECT (size_group), "mode"); @@ -408,16 +484,16 @@ gtk_size_group_get_mode (GtkSizeGroup *size_group) { g_return_val_if_fail (GTK_IS_SIZE_GROUP (size_group), GTK_SIZE_GROUP_BOTH); - return size_group->mode; + return size_group->priv->mode; } /** * gtk_size_group_set_ignore_hidden: * @size_group: a #GtkSizeGroup - * @ignore_hidden: whether hidden widgets should be ignored + * @ignore_hidden: whether unmapped widgets should be ignored * when calculating the size * - * Sets whether invisible widgets should be ignored when + * Sets whether unmapped widgets should be ignored when * calculating the size. * * Since: 2.8 @@ -426,13 +502,17 @@ void gtk_size_group_set_ignore_hidden (GtkSizeGroup *size_group, gboolean ignore_hidden) { + GtkSizeGroupPrivate *priv; + g_return_if_fail (GTK_IS_SIZE_GROUP (size_group)); - + + priv = size_group->priv; + ignore_hidden = ignore_hidden != FALSE; - if (size_group->ignore_hidden != ignore_hidden) + if (priv->ignore_hidden != ignore_hidden) { - size_group->ignore_hidden = ignore_hidden; + priv->ignore_hidden = ignore_hidden; g_object_notify (G_OBJECT (size_group), "ignore-hidden"); } @@ -453,7 +533,7 @@ gtk_size_group_get_ignore_hidden (GtkSizeGroup *size_group) { g_return_val_if_fail (GTK_IS_SIZE_GROUP (size_group), FALSE); - return size_group->ignore_hidden; + return size_group->priv->ignore_hidden; } static void @@ -473,24 +553,29 @@ gtk_size_group_widget_destroyed (GtkWidget *widget, * and the requisition of the other widgets in the size group. * Whether this applies horizontally, vertically, or in both directions * depends on the mode of the size group. See gtk_size_group_set_mode(). - **/ + * + * When the widget is destroyed or no longer referenced elsewhere, it will + * be removed from the size group. + */ void gtk_size_group_add_widget (GtkSizeGroup *size_group, GtkWidget *widget) { + GtkSizeGroupPrivate *priv; GSList *groups; g_return_if_fail (GTK_IS_SIZE_GROUP (size_group)); g_return_if_fail (GTK_IS_WIDGET (widget)); - - groups = get_size_groups (widget); + + priv = size_group->priv; + + groups = _gtk_widget_get_sizegroups (widget); if (!g_slist_find (groups, size_group)) { - groups = g_slist_prepend (groups, size_group); - set_size_groups (widget, groups); + _gtk_widget_add_sizegroup (widget, size_group); - size_group->widgets = g_slist_prepend (size_group->widgets, widget); + priv->widgets = g_slist_prepend (priv->widgets, widget); g_signal_connect (widget, "destroy", G_CALLBACK (gtk_size_group_widget_destroyed), @@ -504,273 +589,158 @@ gtk_size_group_add_widget (GtkSizeGroup *size_group, /** * gtk_size_group_remove_widget: - * @size_group: a #GtkSizeGrup + * @size_group: a #GtkSizeGroup * @widget: the #GtkWidget to remove * * Removes a widget from a #GtkSizeGroup. **/ void -gtk_size_group_remove_widget (GtkSizeGroup *size_group, - GtkWidget *widget) +gtk_size_group_remove_widget (GtkSizeGroup *size_group, + GtkWidget *widget) { - GSList *groups; + GtkSizeGroupPrivate *priv; g_return_if_fail (GTK_IS_SIZE_GROUP (size_group)); g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (g_slist_find (size_group->widgets, widget)); + + priv = size_group->priv; + + g_return_if_fail (g_slist_find (priv->widgets, widget)); g_signal_handlers_disconnect_by_func (widget, gtk_size_group_widget_destroyed, size_group); - groups = get_size_groups (widget); - groups = g_slist_remove (groups, size_group); - set_size_groups (widget, groups); + _gtk_widget_remove_sizegroup (widget, size_group); - size_group->widgets = g_slist_remove (size_group->widgets, widget); + priv->widgets = g_slist_remove (priv->widgets, widget); queue_resize_on_group (size_group); gtk_widget_queue_resize (widget); g_object_unref (size_group); } -static gint -get_base_dimension (GtkWidget *widget, - GtkSizeGroupMode mode) +/** + * gtk_size_group_get_widgets: + * @size_group: a #GtkSizeGroup + * + * Returns the list of widgets associated with @size_group. + * + * Return value: (element-type GtkWidget) (transfer none): a #GSList of + * widgets. The list is owned by GTK+ and should not be modified. + * + * Since: 2.10 + **/ +GSList * +gtk_size_group_get_widgets (GtkSizeGroup *size_group) { - GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE); - - if (mode == GTK_SIZE_GROUP_HORIZONTAL) - { - if (aux_info && aux_info->width > 0) - return aux_info->width; - else - return widget->requisition.width; - } - else - { - if (aux_info && aux_info->height > 0) - return aux_info->height; - else - return widget->requisition.height; - } + return size_group->priv->widgets; } -static void -do_size_request (GtkWidget *widget) +/** + * _gtk_size_group_queue_resize: + * @widget: a #GtkWidget + * + * Queue a resize on a widget, and on all other widgets grouped with this widget. + **/ +void +_gtk_size_group_queue_resize (GtkWidget *widget, + GtkQueueResizeFlags flags) { - if (GTK_WIDGET_REQUEST_NEEDED (widget)) - { - gtk_widget_ensure_style (widget); - GTK_PRIVATE_UNSET_FLAG (widget, GTK_REQUEST_NEEDED); - g_signal_emit_by_name (widget, - "size_request", - &widget->requisition); - } + queue_resize_on_widget (widget, TRUE, flags); } -static gint -compute_base_dimension (GtkWidget *widget, - GtkSizeGroupMode mode) -{ - do_size_request (widget); +typedef struct { + GObject *object; + GSList *items; +} GSListSubParserData; - return get_base_dimension (widget, mode); -} - -static gint -compute_dimension (GtkWidget *widget, - GtkSizeGroupMode mode) +static void +size_group_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **names, + const gchar **values, + gpointer user_data, + GError **error) { - GSList *widgets = NULL; - GSList *groups = NULL; - GSList *tmp_list; - gint result = 0; - - add_widget_to_closure (widget, mode, &groups, &widgets); - - g_slist_foreach (widgets, (GFunc)g_object_ref, NULL); - - if (!groups) - { - result = compute_base_dimension (widget, mode); - } + guint i; + GSListSubParserData *data = (GSListSubParserData*)user_data; + + if (strcmp (element_name, "widget") == 0) + for (i = 0; names[i]; i++) + if (strcmp (names[i], "name") == 0) + data->items = g_slist_prepend (data->items, g_strdup (values[i])); + else if (strcmp (element_name, "widgets") == 0) + return; else - { - GtkSizeGroup *group = groups->data; - - if (mode == GTK_SIZE_GROUP_HORIZONTAL && group->have_width) - result = group->requisition.width; - else if (mode == GTK_SIZE_GROUP_VERTICAL && group->have_height) - result = group->requisition.height; - else - { - tmp_list = widgets; - while (tmp_list) - { - GtkWidget *tmp_widget = tmp_list->data; - - gint dimension = compute_base_dimension (tmp_widget, mode); - - if (GTK_WIDGET_VISIBLE (tmp_widget) || !group->ignore_hidden) - { - if (dimension > result) - result = dimension; - } - - tmp_list = tmp_list->next; - } - - tmp_list = groups; - while (tmp_list) - { - GtkSizeGroup *tmp_group = tmp_list->data; - - if (mode == GTK_SIZE_GROUP_HORIZONTAL) - { - tmp_group->have_width = TRUE; - tmp_group->requisition.width = result; - } - else - { - tmp_group->have_height = TRUE; - tmp_group->requisition.height = result; - } - - tmp_list = tmp_list->next; - } - } - } + g_warning ("Unsupported type tag for GtkSizeGroup: %s\n", + element_name); - g_slist_foreach (widgets, (GFunc)g_object_unref, NULL); - - g_slist_free (widgets); - g_slist_free (groups); - - return result; } -static gint -get_dimension (GtkWidget *widget, - GtkSizeGroupMode mode) +static const GMarkupParser size_group_parser = + { + size_group_start_element + }; + +static gboolean +gtk_size_group_buildable_custom_tag_start (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + GMarkupParser *parser, + gpointer *data) { - GSList *widgets = NULL; - GSList *groups = NULL; - gint result = 0; + GSListSubParserData *parser_data; - add_widget_to_closure (widget, mode, &groups, &widgets); + if (child) + return FALSE; - if (!groups) - { - result = get_base_dimension (widget, mode); - } - else + if (strcmp (tagname, "widgets") == 0) { - GtkSizeGroup *group = groups->data; + parser_data = g_slice_new0 (GSListSubParserData); + parser_data->items = NULL; + parser_data->object = G_OBJECT (buildable); - if (mode == GTK_SIZE_GROUP_HORIZONTAL && group->have_width) - result = group->requisition.width; - else if (mode == GTK_SIZE_GROUP_VERTICAL && group->have_height) - result = group->requisition.height; + *parser = size_group_parser; + *data = parser_data; + return TRUE; } - g_slist_free (widgets); - g_slist_free (groups); - - return result; + return FALSE; } static void -get_fast_child_requisition (GtkWidget *widget, - GtkRequisition *requisition) +gtk_size_group_buildable_custom_finished (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *tagname, + gpointer user_data) { - GtkWidgetAuxInfo *aux_info = _gtk_widget_get_aux_info (widget, FALSE); - - *requisition = widget->requisition; - - if (aux_info) - { - if (aux_info->width > 0) - requisition->width = aux_info->width; - if (aux_info && aux_info->height > 0) - requisition->height = aux_info->height; - } -} + GSList *l; + GSListSubParserData *data; + GObject *object; -/** - * _gtk_size_group_get_child_requisition: - * @widget: a #GtkWidget - * @requisition: location to store computed requisition. - * - * Retrieve the "child requisition" of the widget, taking account grouping - * of the widget's requisition with other widgets. - **/ -void -_gtk_size_group_get_child_requisition (GtkWidget *widget, - GtkRequisition *requisition) -{ - if (requisition) - { - if (get_size_groups (widget)) - { - requisition->width = get_dimension (widget, GTK_SIZE_GROUP_HORIZONTAL); - requisition->height = get_dimension (widget, GTK_SIZE_GROUP_VERTICAL); - - /* Only do the full computation if we actually have size groups */ - } - else - get_fast_child_requisition (widget, requisition); - } -} - -/** - * _gtk_size_group_compute_requisition: - * @widget: a #GtkWidget - * @requisition: location to store computed requisition. - * - * Compute the requisition of a widget taking into account grouping of - * the widget's requisition with other widgets. - **/ -void -_gtk_size_group_compute_requisition (GtkWidget *widget, - GtkRequisition *requisition) -{ - gint width; - gint height; + if (strcmp (tagname, "widgets")) + return; + + data = (GSListSubParserData*)user_data; + data->items = g_slist_reverse (data->items); - if (get_size_groups (widget)) + for (l = data->items; l; l = l->next) { - /* Only do the full computation if we actually have size groups */ - - width = compute_dimension (widget, GTK_SIZE_GROUP_HORIZONTAL); - height = compute_dimension (widget, GTK_SIZE_GROUP_VERTICAL); - - if (requisition) + object = gtk_builder_get_object (builder, l->data); + if (!object) { - requisition->width = width; - requisition->height = height; + g_warning ("Unknown object %s specified in sizegroup %s", + (const gchar*)l->data, + gtk_buildable_get_name (GTK_BUILDABLE (data->object))); + continue; } + gtk_size_group_add_widget (GTK_SIZE_GROUP (data->object), + GTK_WIDGET (object)); + g_free (l->data); } - else - { - do_size_request (widget); - - if (requisition) - get_fast_child_requisition (widget, requisition); - } + g_slist_free (data->items); + g_slice_free (GSListSubParserData, data); } - -/** - * _gtk_size_group_queue_resize: - * @widget: a #GtkWidget - * - * Queue a resize on a widget, and on all other widgets grouped with this widget. - **/ -void -_gtk_size_group_queue_resize (GtkWidget *widget) -{ - queue_resize_on_widget (widget, TRUE); -} - -#define __GTK_SIZE_GROUP_C__ -#include "gtkaliasdef.c"