*/
#include "config.h"
+
+#include "gtkcontainer.h"
+
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
-#include "gtkcontainer.h"
#include "gtkbuildable.h"
#include "gtkbuilderprivate.h"
#include "gtkprivate.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
+#include "gtksizerequest.h"
#include "gtkwindow.h"
#include "gtkintl.h"
#include "gtktoolbar.h"
#include <gobject/gobjectnotifyqueue.c>
#include <gobject/gvaluecollector.h>
-struct _GtkContainerPriv
+struct _GtkContainerPrivate
{
GtkWidget *focus_child;
gpointer client_data);
static void gtk_container_show_all (GtkWidget *widget);
static void gtk_container_hide_all (GtkWidget *widget);
-static gint gtk_container_expose (GtkWidget *widget,
- GdkEventExpose *event);
+static gint gtk_container_draw (GtkWidget *widget,
+ cairo_t *cr);
static void gtk_container_map (GtkWidget *widget);
static void gtk_container_unmap (GtkWidget *widget);
+static void gtk_container_adjust_size_request (GtkWidget *widget,
+ GtkOrientation orientation,
+ gint for_size,
+ gint *minimum_size,
+ gint *natural_size);
+static void gtk_container_adjust_size_allocation (GtkWidget *widget,
+ GtkAllocation *allocation);
static gchar* gtk_container_child_default_composite_name (GtkContainer *container,
GtkWidget *child);
widget_class->show_all = gtk_container_show_all;
widget_class->hide_all = gtk_container_hide_all;
- widget_class->expose_event = gtk_container_expose;
+ widget_class->draw = gtk_container_draw;
widget_class->map = gtk_container_map;
widget_class->unmap = gtk_container_unmap;
widget_class->focus = gtk_container_focus;
-
+
+ widget_class->adjust_size_request = gtk_container_adjust_size_request;
+ widget_class->adjust_size_allocation = gtk_container_adjust_size_allocation;
+
class->add = gtk_container_add_unimplemented;
class->remove = gtk_container_remove_unimplemented;
class->check_resize = gtk_container_real_check_resize;
G_TYPE_NONE, 1,
GTK_TYPE_WIDGET);
- g_type_class_add_private (class, sizeof (GtkContainerPriv));
+ g_type_class_add_private (class, sizeof (GtkContainerPrivate));
}
static void
static void
gtk_container_init (GtkContainer *container)
{
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
container->priv = G_TYPE_INSTANCE_GET_PRIVATE (container,
GTK_TYPE_CONTAINER,
- GtkContainerPriv);
+ GtkContainerPrivate);
priv = container->priv;
priv->focus_child = NULL;
gtk_container_destroy (GtkObject *object)
{
GtkContainer *container = GTK_CONTAINER (object);
- GtkContainerPriv *priv = container->priv;
+ GtkContainerPrivate *priv = container->priv;
if (GTK_CONTAINER_RESIZE_PENDING (container))
_gtk_container_dequeue_resize_handler (container);
+ if (priv->focus_child)
+ {
+ g_object_unref (priv->focus_child);
+ priv->focus_child = NULL;
+ }
+
/* do this before walking child widgets, to avoid
* removing children from focus chain one by one.
*/
GParamSpec *pspec)
{
GtkContainer *container = GTK_CONTAINER (object);
- GtkContainerPriv *priv = container->priv;
+ GtkContainerPrivate *priv = container->priv;
switch (prop_id)
{
gtk_container_set_border_width (GtkContainer *container,
guint border_width)
{
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
g_return_if_fail (GTK_IS_CONTAINER (container));
{
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (GTK_IS_WIDGET (widget));
-
- /* When using the deprecated API of the toolbar, it is possible
- * to legitimately call this function with a widget that is not
- * a direct child of the container.
- */
- g_return_if_fail (GTK_IS_TOOLBAR (container) ||
- gtk_widget_get_parent (widget) == GTK_WIDGET (container));
+ g_return_if_fail (gtk_widget_get_parent (widget) == GTK_WIDGET (container));
g_signal_emit (container, container_signals[REMOVE], 0, widget);
}
gtk_container_set_resize_mode (GtkContainer *container,
GtkResizeMode resize_mode)
{
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (resize_mode <= GTK_RESIZE_IMMEDIATE);
void
_gtk_container_queue_resize (GtkContainer *container)
{
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
GtkContainer *resize_container;
GtkWidget *parent;
GtkWidget *widget;
while (TRUE)
{
GTK_PRIVATE_SET_FLAG (widget, GTK_ALLOC_NEEDED);
- GTK_PRIVATE_SET_FLAG (widget, GTK_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_WIDTH_REQUEST_NEEDED);
GTK_PRIVATE_SET_FLAG (widget, GTK_HEIGHT_REQUEST_NEEDED);
GtkWidget *widget = GTK_WIDGET (container);
GtkAllocation allocation;
GtkRequisition requisition;
-
- gtk_widget_size_request (widget, &requisition);
+
+ gtk_widget_get_preferred_size (widget,
+ &requisition, NULL);
gtk_widget_get_allocation (widget, &allocation);
if (requisition.width > allocation.width ||
gtk_widget_set_allocation (widget, &allocation);
}
+static void
+gtk_container_adjust_size_request (GtkWidget *widget,
+ GtkOrientation orientation,
+ gint for_size,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ GtkContainer *container;
+
+ container = GTK_CONTAINER (widget);
+
+ if (GTK_CONTAINER_GET_CLASS (widget)->handle_border_width)
+ {
+ int border_width;
+
+ border_width = container->priv->border_width;
+
+ *minimum_size += border_width * 2;
+ *natural_size += border_width * 2;
+ }
+
+ /* chain up last so gtk_widget_set_size_request() values
+ * will have a chance to overwrite our border width.
+ */
+ parent_class->adjust_size_request (widget, orientation, for_size,
+ minimum_size, natural_size);
+}
+
+static void
+gtk_container_adjust_size_allocation (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ GtkContainer *container;
+ int border_width;
+
+ container = GTK_CONTAINER (widget);
+
+ parent_class->adjust_size_allocation (widget, allocation);
+
+ if (!GTK_CONTAINER_GET_CLASS (widget)->handle_border_width)
+ return;
+
+ border_width = container->priv->border_width;
+
+ allocation->width -= border_width * 2;
+ allocation->height -= border_width * 2;
+
+ /* If we get a pathological too-small allocation to hold
+ * even the border width, leave all allocation to the actual
+ * widget, and leave x,y unchanged. (GtkWidget's min size is
+ * 1x1 if you're wondering why <1 and not <0)
+ *
+ * As long as we have space, set x,y properly.
+ */
+
+ if (allocation->width < 1)
+ {
+ allocation->width += border_width * 2;
+ }
+ else
+ {
+ allocation->x += border_width;
+ }
+
+ if (allocation->height < 1)
+ {
+ allocation->height += border_width * 2;
+ }
+ else
+ {
+ allocation->y += border_width;
+ }
+}
+
+/**
+ * gtk_container_class_handle_border_width:
+ * @klass: the class struct of a #GtkContainer subclass
+ *
+ * Modifies a subclass of #GtkContainerClass to automatically add and
+ * remove the border-width setting on GtkContainer. This allows the
+ * subclass to ignore the border width in its size request and
+ * allocate methods. The intent is for a subclass to invoke this
+ * in its class_init function.
+ *
+ * gtk_container_class_handle_border_width() is necessary because it
+ * would break API too badly to make this behavior the default. So
+ * subclasses must "opt in" to the parent class handling border_width
+ * for them.
+ */
+void
+gtk_container_class_handle_border_width (GtkContainerClass *klass)
+{
+ g_return_if_fail (GTK_IS_CONTAINER_CLASS (klass));
+
+ klass->handle_border_width = TRUE;
+}
+
/**
* gtk_container_forall:
* @container: a #GtkContainer
/**
* gtk_container_foreach:
* @container: a #GtkContainer
- * @callback: a callback
+ * @callback: (scope call): a callback
* @callback_data: callback user data
*
* Invokes @callback on each non-internal child of @container. See
* This function emits the GtkContainer::set_focus_child signal of
* @container. Implementations of #GtkContainer can override the
* default behaviour by overriding the class closure of this signal.
+ *
+ * This is function is mostly meant to be used by widgets. Applications can use
+ * gtk_widget_grab_focus() to manualy set the focus to a specific widget.
*/
void
gtk_container_set_focus_child (GtkContainer *container,
* gtk_container_get_focus_child:
* @container: a #GtkContainer
*
- * Returns the current focus child widget inside @container.
+ * Returns the current focus child widget inside @container. This is not the
+ * currently focused widget. That can be obtained by calling
+ * gtk_window_get_focus().
*
- * Returns: The child widget which has the focus
- * inside @container, or %NULL if none is set.
+ * Returns: The child widget which will recieve the focus inside @container when
+ * the @conatiner is focussed, or %NULL if none is set.
*
* Since: 2.14
**/
gtk_container_real_set_focus_child (GtkContainer *container,
GtkWidget *child)
{
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
GList *sorted_children;
gint return_val;
GtkContainer *container;
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
{
GtkWidget *widget = GTK_WIDGET (container);
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+ GtkWidget *old_focus;
- if (GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget)
+ if (GTK_IS_WINDOW (toplevel))
{
- GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget;
-
- return get_allocation_coords (container, old_focus, old_focus_rect);
+ old_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
+ if (old_focus)
+ return get_allocation_coords (container, old_focus, old_focus_rect);
}
- else
- return FALSE;
+
+ return FALSE;
}
typedef struct _CompareInfo CompareInfo;
GList *children,
GtkDirectionType direction)
{
- GtkContainerPriv *priv = container->priv;
+ GtkContainerPrivate *priv = container->priv;
GtkWidget *focus_child;
GtkWidget *child;
}
/**
- * gtk_container_set_focus_chain:
+ * gtk_container_set_focus_chain:
* @container: a #GtkContainer
- * @focusable_widgets: the new focus chain
+ * @focusable_widgets: (transfer none) (element-type GtkWidget):
+ * the new focus chain
*
* Sets a focus chain, overriding the one computed automatically by GTK+.
*
{
GList *chain;
GList *tmp_list;
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
g_return_if_fail (GTK_IS_CONTAINER (container));
gtk_container_get_focus_chain (GtkContainer *container,
GList **focus_chain)
{
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
g_return_val_if_fail (GTK_IS_CONTAINER (container), FALSE);
void
gtk_container_unset_focus_chain (GtkContainer *container)
{
- GtkContainerPriv *priv;
+ GtkContainerPrivate *priv;
g_return_if_fail (GTK_IS_CONTAINER (container));
static void
-gtk_container_expose_child (GtkWidget *child,
- gpointer client_data)
+gtk_container_draw_child (GtkWidget *child,
+ gpointer client_data)
{
struct {
GtkWidget *container;
- GdkEventExpose *event;
+ cairo_t *cr;
} *data = client_data;
- gtk_container_propagate_expose (GTK_CONTAINER (data->container),
- child,
- data->event);
+ gtk_container_propagate_draw (GTK_CONTAINER (data->container),
+ child,
+ data->cr);
}
static gint
-gtk_container_expose (GtkWidget *widget,
- GdkEventExpose *event)
+gtk_container_draw (GtkWidget *widget,
+ cairo_t *cr)
{
struct {
GtkWidget *container;
- GdkEventExpose *event;
+ cairo_t *cr;
} data;
- g_return_val_if_fail (GTK_IS_CONTAINER (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
+ data.container = widget;
+ data.cr = cr;
- if (gtk_widget_is_drawable (widget))
- {
- data.container = widget;
- data.event = event;
-
- gtk_container_forall (GTK_CONTAINER (widget),
- gtk_container_expose_child,
- &data);
- }
+ gtk_container_forall (GTK_CONTAINER (widget),
+ gtk_container_draw_child,
+ &data);
return FALSE;
}
}
/**
- * gtk_container_propagate_expose:
+ * gtk_container_propagate_draw:
* @container: a #GtkContainer
* @child: a child of @container
- * @event: a expose event sent to container
+ * @cr: Cairo context as passed to the container. If you want to use @cr
+ * in container's draw function, consider using cairo_save() and
+ * cairo_restore() before calling this function.
*
- * When a container receives an expose event, it must send synthetic
- * expose events to all children that don't have their own #GdkWindows.
- * This function provides a convenient way of doing this. A container,
- * when it receives an expose event, calls gtk_container_propagate_expose()
- * once for each child, passing in the event the container received.
+ * When a container receives a call to the draw function, it must send
+ * synthetic #GtkWidget::draw calls to all children that don't have their
+ * own #GdkWindows. This function provides a convenient way of doing this.
+ * A container, when it receives a call to its #GtkWidget::draw function,
+ * calls gtk_container_propagate_draw() once for each child, passing in
+ * the @cr the container received.
*
- * gtk_container_propagate_expose() takes care of deciding whether
- * an expose event needs to be sent to the child, intersecting
- * the event's area with the child area, and sending the event.
+ * gtk_container_propagate_draw() takes care of translating the origin of @cr,
+ * and deciding whether the draw needs to be sent to the child. It is a
+ * convenient and optimized way of getting the same effect as calling
+ * gtk_widget_draw() on the child directly.
*
- * In most cases, a container can simply either simply inherit the
- * #GtkWidget::expose implementation from #GtkContainer, or, do some drawing
- * and then chain to the ::expose implementation from #GtkContainer.
+ * In most cases, a container can simply either inherit the
+ * #GtkWidget::draw implementation from #GtkContainer, or do some drawing
+ * and then chain to the ::draw implementation from #GtkContainer.
**/
void
-gtk_container_propagate_expose (GtkContainer *container,
- GtkWidget *child,
- GdkEventExpose *event)
+gtk_container_propagate_draw (GtkContainer *container,
+ GtkWidget *child,
+ cairo_t *cr)
{
- GdkEvent *child_event;
+ GdkEventExpose *event;
+ GtkAllocation allocation;
+ GdkWindow *window, *w;
+ int x, y;
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (GTK_IS_WIDGET (child));
- g_return_if_fail (event != NULL);
+ g_return_if_fail (cr != NULL);
g_assert (gtk_widget_get_parent (child) == GTK_WIDGET (container));
- if (gtk_widget_is_drawable (child) &&
- !gtk_widget_get_has_window (child) &&
- gtk_widget_get_window (child) == event->window)
+ event = _gtk_cairo_get_event (cr);
+ if (event)
{
- child_event = gdk_event_new (GDK_EXPOSE);
- child_event->expose = *event;
- g_object_ref (child_event->expose.window);
+ if (gtk_widget_get_has_window (child) ||
+ gtk_widget_get_window (child) != event->window)
+ return;
+ }
- child_event->expose.region = gtk_widget_region_intersect (child, event->region);
- if (!cairo_region_is_empty (child_event->expose.region))
- {
- cairo_region_get_extents (child_event->expose.region, &child_event->expose.area);
- gtk_widget_send_expose (child, child_event);
- }
- gdk_event_free (child_event);
+ cairo_save (cr);
+
+ /* translate coordinates. Ugly business, that. */
+ if (!gtk_widget_get_has_window (GTK_WIDGET (container)))
+ {
+ gtk_widget_get_allocation (GTK_WIDGET (container), &allocation);
+ x = -allocation.x;
+ y = -allocation.y;
+ }
+ else
+ {
+ x = 0;
+ y = 0;
+ }
+
+ window = gtk_widget_get_window (GTK_WIDGET (container));
+
+ for (w = gtk_widget_get_window (child); w && w != window; w = gdk_window_get_parent (w))
+ {
+ int wx, wy;
+ gdk_window_get_position (w, &wx, &wy);
+ x += wx;
+ y += wy;
+ }
+
+ if (w == NULL)
+ {
+ x = 0;
+ y = 0;
}
+
+ if (!gtk_widget_get_has_window (child))
+ {
+ gtk_widget_get_allocation (child, &allocation);
+ x += allocation.x;
+ y += allocation.y;
+ }
+
+ cairo_translate (cr, x, y);
+
+ _gtk_widget_draw_internal (child, cr, TRUE);
+
+ cairo_restore (cr);
}
gboolean