
2001-08-07 Havoc Pennington <hp@pobox.com> * gtk/gtkfilesel.c (open_ref_dir): fix a typo. * gtk/gtkplug.c (gtk_plug_init): remove setting of auto_shrink; some fixage is needed here, but nothing simple. Owen understands it. ;-) * gtk/gtkwindow.h, gtk/gtkwindow.c: Rework code and API for window sizing and positioning. Also, fix bug in compute_geometry_hints (width/height confusion for setting min size). (gtk_window_move): new function (gtk_window_resize): new function (gtk_window_get_size): new function (gtk_window_get_position): new function (gtk_window_parse_geometry): new function * gtk/gtkwidget.c (gtk_widget_set_size_request): new function (gtk_widget_get_size_request): new function (gtk_widget_get_usize): delete, that was a short-lived function ;-) (gtk_widget_set_usize): deprecate (gtk_widget_set_uposition): deprecate, make it a trivial gtk_window_move() wrapper (gtk_widget_class_init): remove x/y/width/height properties, add width_request height_request * demos/*: update to avoid deprecated functions * gtk/gtklayout.c: add x/y child properties * gtk/gtkfixed.c: add x/y child properties, and get rid of uses of "gint16" * tests/testgtk.c (create_window_sizing): lots of tweaks to window sizing test * gdk/x11/gdkevents-x11.c (gdk_event_translate): Ensure that configure events on toplevel windows are always in root window coordinates, following ICCCM spec that all synthetic events are in root window coords already, while real events are in parent window coords. Previously the code assumed that coords of 0,0 were parent window coords, which was really broken. * gtk/gtkcontainer.c (gtk_container_get_focus_chain): fix warning * gdk/gdkwindow.h (GdkWindowHints): add GDK_HINT_USER_POS and GDK_HINT_USER_SIZE so we can set USSize and USPosition hints in gtk_window_parse_geometry() * gdk/x11/gdkwindow-x11.c (gdk_window_set_geometry_hints): support new USER_POS USER_SIZE hints
972 lines
27 KiB
C
972 lines
27 KiB
C
/* GTK - The GIMP Toolkit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* 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.
|
|
*
|
|
* GtkLayout: Widget for scrolling of arbitrary-sized areas.
|
|
*
|
|
* Copyright Owen Taylor, 1998
|
|
*/
|
|
|
|
/*
|
|
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
|
|
* file for a list of people on the GTK+ Team. See the ChangeLog
|
|
* files for a list of changes. These files are distributed with
|
|
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
|
*/
|
|
|
|
#include "gdkconfig.h"
|
|
|
|
#include "gtklayout.h"
|
|
#include "gtksignal.h"
|
|
#include "gtkprivate.h"
|
|
#include "gtkintl.h"
|
|
|
|
typedef struct _GtkLayoutChild GtkLayoutChild;
|
|
|
|
struct _GtkLayoutChild {
|
|
GtkWidget *widget;
|
|
gint x;
|
|
gint y;
|
|
};
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_HADJUSTMENT,
|
|
PROP_VADJUSTMENT,
|
|
PROP_WIDTH,
|
|
PROP_HEIGHT
|
|
};
|
|
|
|
enum {
|
|
CHILD_PROP_0,
|
|
CHILD_PROP_X,
|
|
CHILD_PROP_Y
|
|
};
|
|
|
|
static void gtk_layout_class_init (GtkLayoutClass *class);
|
|
static void gtk_layout_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gtk_layout_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gtk_layout_init (GtkLayout *layout);
|
|
static void gtk_layout_finalize (GObject *object);
|
|
static void gtk_layout_realize (GtkWidget *widget);
|
|
static void gtk_layout_unrealize (GtkWidget *widget);
|
|
static void gtk_layout_map (GtkWidget *widget);
|
|
static void gtk_layout_size_request (GtkWidget *widget,
|
|
GtkRequisition *requisition);
|
|
static void gtk_layout_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation);
|
|
static gint gtk_layout_expose (GtkWidget *widget,
|
|
GdkEventExpose *event);
|
|
static void gtk_layout_remove (GtkContainer *container,
|
|
GtkWidget *widget);
|
|
static void gtk_layout_forall (GtkContainer *container,
|
|
gboolean include_internals,
|
|
GtkCallback callback,
|
|
gpointer callback_data);
|
|
static void gtk_layout_set_adjustments (GtkLayout *layout,
|
|
GtkAdjustment *hadj,
|
|
GtkAdjustment *vadj);
|
|
static void gtk_layout_set_child_property (GtkContainer *container,
|
|
GtkWidget *child,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gtk_layout_get_child_property (GtkContainer *container,
|
|
GtkWidget *child,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gtk_layout_allocate_child (GtkLayout *layout,
|
|
GtkLayoutChild *child);
|
|
static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
|
|
GtkLayout *layout);
|
|
|
|
|
|
static GtkWidgetClass *parent_class = NULL;
|
|
|
|
/* Public interface
|
|
*/
|
|
|
|
GtkWidget*
|
|
gtk_layout_new (GtkAdjustment *hadjustment,
|
|
GtkAdjustment *vadjustment)
|
|
{
|
|
GtkLayout *layout;
|
|
|
|
layout = gtk_type_new (GTK_TYPE_LAYOUT);
|
|
|
|
gtk_layout_set_adjustments (layout, hadjustment, vadjustment);
|
|
|
|
return GTK_WIDGET (layout);
|
|
}
|
|
|
|
GtkAdjustment*
|
|
gtk_layout_get_hadjustment (GtkLayout *layout)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
|
|
|
|
return layout->hadjustment;
|
|
}
|
|
GtkAdjustment*
|
|
gtk_layout_get_vadjustment (GtkLayout *layout)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
|
|
|
|
return layout->vadjustment;
|
|
}
|
|
|
|
static void
|
|
gtk_layout_set_adjustments (GtkLayout *layout,
|
|
GtkAdjustment *hadj,
|
|
GtkAdjustment *vadj)
|
|
{
|
|
gboolean need_adjust = FALSE;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
|
|
if (hadj)
|
|
g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
|
|
else
|
|
hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
|
|
if (vadj)
|
|
g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
|
|
else
|
|
vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
|
|
|
|
if (layout->hadjustment && (layout->hadjustment != hadj))
|
|
{
|
|
gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout);
|
|
gtk_object_unref (GTK_OBJECT (layout->hadjustment));
|
|
}
|
|
|
|
if (layout->vadjustment && (layout->vadjustment != vadj))
|
|
{
|
|
gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout);
|
|
gtk_object_unref (GTK_OBJECT (layout->vadjustment));
|
|
}
|
|
|
|
if (layout->hadjustment != hadj)
|
|
{
|
|
layout->hadjustment = hadj;
|
|
gtk_object_ref (GTK_OBJECT (layout->hadjustment));
|
|
gtk_object_sink (GTK_OBJECT (layout->hadjustment));
|
|
|
|
gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed",
|
|
(GtkSignalFunc) gtk_layout_adjustment_changed,
|
|
layout);
|
|
need_adjust = TRUE;
|
|
}
|
|
|
|
if (layout->vadjustment != vadj)
|
|
{
|
|
layout->vadjustment = vadj;
|
|
gtk_object_ref (GTK_OBJECT (layout->vadjustment));
|
|
gtk_object_sink (GTK_OBJECT (layout->vadjustment));
|
|
|
|
gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed",
|
|
(GtkSignalFunc) gtk_layout_adjustment_changed,
|
|
layout);
|
|
need_adjust = TRUE;
|
|
}
|
|
|
|
if (need_adjust)
|
|
gtk_layout_adjustment_changed (NULL, layout);
|
|
}
|
|
|
|
static void
|
|
gtk_layout_finalize (GObject *object)
|
|
{
|
|
GtkLayout *layout = GTK_LAYOUT (object);
|
|
|
|
gtk_object_unref (GTK_OBJECT (layout->hadjustment));
|
|
gtk_object_unref (GTK_OBJECT (layout->vadjustment));
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
void
|
|
gtk_layout_set_hadjustment (GtkLayout *layout,
|
|
GtkAdjustment *adjustment)
|
|
{
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
|
|
gtk_layout_set_adjustments (layout, adjustment, layout->vadjustment);
|
|
g_object_notify (G_OBJECT (layout), "hadjustment");
|
|
}
|
|
|
|
|
|
void
|
|
gtk_layout_set_vadjustment (GtkLayout *layout,
|
|
GtkAdjustment *adjustment)
|
|
{
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
|
|
gtk_layout_set_adjustments (layout, layout->hadjustment, adjustment);
|
|
g_object_notify (G_OBJECT (layout), "vadjustment");
|
|
}
|
|
|
|
static GtkLayoutChild*
|
|
get_child (GtkLayout *layout,
|
|
GtkWidget *widget)
|
|
{
|
|
GList *children;
|
|
|
|
children = layout->children;
|
|
while (children)
|
|
{
|
|
GtkLayoutChild *child;
|
|
|
|
child = children->data;
|
|
children = children->next;
|
|
|
|
if (child->widget == widget)
|
|
return child;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
gtk_layout_put (GtkLayout *layout,
|
|
GtkWidget *child_widget,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
GtkLayoutChild *child;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
g_return_if_fail (GTK_IS_WIDGET (child_widget));
|
|
|
|
child = g_new (GtkLayoutChild, 1);
|
|
|
|
child->widget = child_widget;
|
|
child->x = x;
|
|
child->y = y;
|
|
|
|
layout->children = g_list_append (layout->children, child);
|
|
|
|
if (GTK_WIDGET_REALIZED (layout))
|
|
gtk_widget_set_parent_window (child->widget, layout->bin_window);
|
|
|
|
gtk_widget_set_parent (child_widget, GTK_WIDGET (layout));
|
|
}
|
|
|
|
static void
|
|
gtk_layout_move_internal (GtkLayout *layout,
|
|
GtkWidget *widget,
|
|
gboolean change_x,
|
|
gint x,
|
|
gboolean change_y,
|
|
gint y)
|
|
{
|
|
GtkLayoutChild *child;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
g_return_if_fail (GTK_IS_WIDGET (widget));
|
|
g_return_if_fail (widget->parent == GTK_WIDGET (layout));
|
|
|
|
child = get_child (layout, widget);
|
|
|
|
g_assert (child);
|
|
|
|
gtk_widget_freeze_child_notify (widget);
|
|
|
|
if (change_x)
|
|
{
|
|
child->x = x;
|
|
gtk_widget_child_notify (widget, "x");
|
|
}
|
|
|
|
if (change_y)
|
|
{
|
|
child->y = y;
|
|
gtk_widget_child_notify (widget, "y");
|
|
}
|
|
|
|
gtk_widget_thaw_child_notify (widget);
|
|
|
|
if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (layout))
|
|
gtk_widget_queue_resize (GTK_WIDGET (layout));
|
|
}
|
|
|
|
void
|
|
gtk_layout_move (GtkLayout *layout,
|
|
GtkWidget *child_widget,
|
|
gint x,
|
|
gint y)
|
|
{
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
g_return_if_fail (GTK_IS_WIDGET (child_widget));
|
|
g_return_if_fail (child_widget->parent == GTK_WIDGET (layout));
|
|
|
|
gtk_layout_move_internal (layout, child_widget, TRUE, x, TRUE, y);
|
|
}
|
|
|
|
static void
|
|
gtk_layout_set_adjustment_upper (GtkAdjustment *adj,
|
|
gdouble upper)
|
|
{
|
|
if (upper != adj->upper)
|
|
{
|
|
gdouble min = MAX (0., upper - adj->page_size);
|
|
gboolean value_changed = FALSE;
|
|
|
|
adj->upper = upper;
|
|
|
|
if (adj->value > min)
|
|
{
|
|
adj->value = min;
|
|
value_changed = TRUE;
|
|
}
|
|
|
|
gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed");
|
|
if (value_changed)
|
|
gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_layout_set_size (GtkLayout *layout,
|
|
guint width,
|
|
guint height)
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
|
|
widget = GTK_WIDGET (layout);
|
|
|
|
if (width != layout->width)
|
|
{
|
|
layout->width = width;
|
|
g_object_notify (G_OBJECT (layout), "width");
|
|
}
|
|
if (height != layout->height)
|
|
{
|
|
layout->height = height;
|
|
g_object_notify (G_OBJECT (layout), "height");
|
|
}
|
|
|
|
gtk_layout_set_adjustment_upper (layout->hadjustment, layout->width);
|
|
gtk_layout_set_adjustment_upper (layout->vadjustment, layout->height);
|
|
|
|
if (GTK_WIDGET_REALIZED (layout))
|
|
{
|
|
width = MAX (width, widget->allocation.width);
|
|
height = MAX (height, widget->allocation.height);
|
|
gdk_window_resize (layout->bin_window, width, height);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gtk_layout_get_size:
|
|
* @layout: a #GtkLayout
|
|
* @width: location to store the width set on @layout, or %NULL
|
|
* @height: location to store the height set on @layout, or %NULL
|
|
*
|
|
* Gets the size that has been set on the layout, and that determines
|
|
* the total extents of the layout's scrollbar area. See
|
|
* gtk_layout_set_size ().
|
|
**/
|
|
void
|
|
gtk_layout_get_size (GtkLayout *layout,
|
|
guint *width,
|
|
guint *height)
|
|
{
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
|
|
if (width)
|
|
*width = layout->width;
|
|
if (height)
|
|
*height = layout->height;
|
|
}
|
|
|
|
void
|
|
gtk_layout_freeze (GtkLayout *layout)
|
|
{
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
|
|
layout->freeze_count++;
|
|
}
|
|
|
|
void
|
|
gtk_layout_thaw (GtkLayout *layout)
|
|
{
|
|
g_return_if_fail (GTK_IS_LAYOUT (layout));
|
|
|
|
if (layout->freeze_count)
|
|
if (!(--layout->freeze_count))
|
|
gtk_widget_draw (GTK_WIDGET (layout), NULL);
|
|
}
|
|
|
|
/* Basic Object handling procedures
|
|
*/
|
|
GtkType
|
|
gtk_layout_get_type (void)
|
|
{
|
|
static GtkType layout_type = 0;
|
|
|
|
if (!layout_type)
|
|
{
|
|
static const GTypeInfo layout_info =
|
|
{
|
|
sizeof (GtkLayoutClass),
|
|
NULL, /* base_init */
|
|
NULL, /* base_finalize */
|
|
(GClassInitFunc) gtk_layout_class_init,
|
|
NULL, /* class_finalize */
|
|
NULL, /* class_data */
|
|
sizeof (GtkLayout),
|
|
16, /* n_preallocs */
|
|
(GInstanceInitFunc) gtk_layout_init,
|
|
};
|
|
|
|
layout_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkLayout", &layout_info, 0);
|
|
}
|
|
|
|
return layout_type;
|
|
}
|
|
|
|
static void
|
|
gtk_layout_class_init (GtkLayoutClass *class)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GtkObjectClass *object_class;
|
|
GtkWidgetClass *widget_class;
|
|
GtkContainerClass *container_class;
|
|
|
|
gobject_class = (GObjectClass*) class;
|
|
object_class = (GtkObjectClass*) class;
|
|
widget_class = (GtkWidgetClass*) class;
|
|
container_class = (GtkContainerClass*) class;
|
|
|
|
parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
|
|
|
|
gobject_class->set_property = gtk_layout_set_property;
|
|
gobject_class->get_property = gtk_layout_get_property;
|
|
gobject_class->finalize = gtk_layout_finalize;
|
|
|
|
container_class->set_child_property = gtk_layout_set_child_property;
|
|
container_class->get_child_property = gtk_layout_get_child_property;
|
|
|
|
gtk_container_class_install_child_property (container_class,
|
|
CHILD_PROP_X,
|
|
g_param_spec_int ("x",
|
|
_("X position"),
|
|
_("X position of child widget"),
|
|
G_MININT,
|
|
G_MAXINT,
|
|
0,
|
|
G_PARAM_READWRITE));
|
|
|
|
gtk_container_class_install_child_property (container_class,
|
|
CHILD_PROP_Y,
|
|
g_param_spec_int ("y",
|
|
_("Y position"),
|
|
_("Y position of child widget"),
|
|
G_MININT,
|
|
G_MAXINT,
|
|
0,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_HADJUSTMENT,
|
|
g_param_spec_object ("hadjustment",
|
|
_("Horizontal adjustment"),
|
|
_("The GtkAdjustment for the horizontal position."),
|
|
GTK_TYPE_ADJUSTMENT,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_VADJUSTMENT,
|
|
g_param_spec_object ("vadjustment",
|
|
_("Vertical adjustment"),
|
|
_("The GtkAdjustment for the vertical position."),
|
|
GTK_TYPE_ADJUSTMENT,
|
|
G_PARAM_READWRITE));
|
|
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_WIDTH,
|
|
g_param_spec_uint ("width",
|
|
_("Width"),
|
|
_("The width of the layout."),
|
|
0,
|
|
G_MAXINT,
|
|
100,
|
|
G_PARAM_READWRITE));
|
|
g_object_class_install_property (gobject_class,
|
|
PROP_HEIGHT,
|
|
g_param_spec_uint ("height",
|
|
_("Height"),
|
|
_("The height of the layout."),
|
|
0,
|
|
G_MAXINT,
|
|
100,
|
|
G_PARAM_READWRITE));
|
|
widget_class->realize = gtk_layout_realize;
|
|
widget_class->unrealize = gtk_layout_unrealize;
|
|
widget_class->map = gtk_layout_map;
|
|
widget_class->size_request = gtk_layout_size_request;
|
|
widget_class->size_allocate = gtk_layout_size_allocate;
|
|
widget_class->expose_event = gtk_layout_expose;
|
|
|
|
container_class->remove = gtk_layout_remove;
|
|
container_class->forall = gtk_layout_forall;
|
|
|
|
class->set_scroll_adjustments = gtk_layout_set_adjustments;
|
|
|
|
widget_class->set_scroll_adjustments_signal =
|
|
gtk_signal_new ("set_scroll_adjustments",
|
|
GTK_RUN_LAST,
|
|
GTK_CLASS_TYPE (object_class),
|
|
GTK_SIGNAL_OFFSET (GtkLayoutClass, set_scroll_adjustments),
|
|
gtk_marshal_VOID__OBJECT_OBJECT,
|
|
GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
|
|
}
|
|
|
|
static void
|
|
gtk_layout_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkLayout *layout = GTK_LAYOUT (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_HADJUSTMENT:
|
|
g_value_set_object (value, G_OBJECT (layout->hadjustment));
|
|
break;
|
|
case PROP_VADJUSTMENT:
|
|
g_value_set_object (value, G_OBJECT (layout->vadjustment));
|
|
break;
|
|
case PROP_WIDTH:
|
|
g_value_set_uint (value, layout->width);
|
|
break;
|
|
case PROP_HEIGHT:
|
|
g_value_set_uint (value, layout->height);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_layout_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkLayout *layout = GTK_LAYOUT (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_HADJUSTMENT:
|
|
gtk_layout_set_hadjustment (layout,
|
|
(GtkAdjustment*) g_value_get_object (value));
|
|
break;
|
|
case PROP_VADJUSTMENT:
|
|
gtk_layout_set_vadjustment (layout,
|
|
(GtkAdjustment*) g_value_get_object (value));
|
|
break;
|
|
case PROP_WIDTH:
|
|
gtk_layout_set_size (layout, g_value_get_uint (value),
|
|
layout->height);
|
|
break;
|
|
case PROP_HEIGHT:
|
|
gtk_layout_set_size (layout, layout->width,
|
|
g_value_get_uint (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_layout_set_child_property (GtkContainer *container,
|
|
GtkWidget *child,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (property_id)
|
|
{
|
|
case CHILD_PROP_X:
|
|
gtk_layout_move_internal (GTK_LAYOUT (container),
|
|
child,
|
|
TRUE, g_value_get_int (value),
|
|
FALSE, 0);
|
|
break;
|
|
case CHILD_PROP_Y:
|
|
gtk_layout_move_internal (GTK_LAYOUT (container),
|
|
child,
|
|
FALSE, 0,
|
|
TRUE, g_value_get_int (value));
|
|
break;
|
|
default:
|
|
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_layout_get_child_property (GtkContainer *container,
|
|
GtkWidget *child,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkLayoutChild *layout_child;
|
|
|
|
layout_child = get_child (GTK_LAYOUT (container), child);
|
|
|
|
switch (property_id)
|
|
{
|
|
case CHILD_PROP_X:
|
|
g_value_set_int (value, layout_child->x);
|
|
break;
|
|
case CHILD_PROP_Y:
|
|
g_value_set_int (value, layout_child->y);
|
|
break;
|
|
default:
|
|
GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_layout_init (GtkLayout *layout)
|
|
{
|
|
layout->children = NULL;
|
|
|
|
layout->width = 100;
|
|
layout->height = 100;
|
|
|
|
layout->hadjustment = NULL;
|
|
layout->vadjustment = NULL;
|
|
|
|
layout->bin_window = NULL;
|
|
|
|
layout->scroll_x = 0;
|
|
layout->scroll_y = 0;
|
|
layout->visibility = GDK_VISIBILITY_PARTIAL;
|
|
|
|
layout->freeze_count = 0;
|
|
}
|
|
|
|
/* Widget methods
|
|
*/
|
|
|
|
static void
|
|
gtk_layout_realize (GtkWidget *widget)
|
|
{
|
|
GList *tmp_list;
|
|
GtkLayout *layout;
|
|
GdkWindowAttr attributes;
|
|
gint attributes_mask;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (widget));
|
|
|
|
layout = GTK_LAYOUT (widget);
|
|
GTK_WIDGET_SET_FLAGS (layout, GTK_REALIZED);
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.x = widget->allocation.x;
|
|
attributes.y = widget->allocation.y;
|
|
attributes.width = widget->allocation.width;
|
|
attributes.height = widget->allocation.height;
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
attributes.colormap = gtk_widget_get_colormap (widget);
|
|
attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
|
|
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
|
|
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
|
|
&attributes, attributes_mask);
|
|
gdk_window_set_user_data (widget->window, widget);
|
|
|
|
attributes.x = 0;
|
|
attributes.y = 0;
|
|
attributes.width = MAX (layout->width, widget->allocation.width);
|
|
attributes.height = MAX (layout->height, widget->allocation.height);
|
|
attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK |
|
|
gtk_widget_get_events (widget);
|
|
|
|
layout->bin_window = gdk_window_new (widget->window,
|
|
&attributes, attributes_mask);
|
|
gdk_window_set_user_data (layout->bin_window, widget);
|
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window);
|
|
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
|
|
gtk_style_set_background (widget->style, layout->bin_window, GTK_STATE_NORMAL);
|
|
|
|
tmp_list = layout->children;
|
|
while (tmp_list)
|
|
{
|
|
GtkLayoutChild *child = tmp_list->data;
|
|
tmp_list = tmp_list->next;
|
|
|
|
gtk_widget_set_parent_window (child->widget, layout->bin_window);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_layout_map (GtkWidget *widget)
|
|
{
|
|
GList *tmp_list;
|
|
GtkLayout *layout;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (widget));
|
|
|
|
layout = GTK_LAYOUT (widget);
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
|
|
|
|
tmp_list = layout->children;
|
|
while (tmp_list)
|
|
{
|
|
GtkLayoutChild *child = tmp_list->data;
|
|
tmp_list = tmp_list->next;
|
|
|
|
if (GTK_WIDGET_VISIBLE (child->widget))
|
|
{
|
|
if (!GTK_WIDGET_MAPPED (child->widget))
|
|
gtk_widget_map (child->widget);
|
|
}
|
|
}
|
|
|
|
gdk_window_show (layout->bin_window);
|
|
gdk_window_show (widget->window);
|
|
}
|
|
|
|
static void
|
|
gtk_layout_unrealize (GtkWidget *widget)
|
|
{
|
|
GtkLayout *layout;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (widget));
|
|
|
|
layout = GTK_LAYOUT (widget);
|
|
|
|
gdk_window_set_user_data (layout->bin_window, NULL);
|
|
gdk_window_destroy (layout->bin_window);
|
|
layout->bin_window = NULL;
|
|
|
|
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
|
|
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
|
|
}
|
|
|
|
static void
|
|
gtk_layout_size_request (GtkWidget *widget,
|
|
GtkRequisition *requisition)
|
|
{
|
|
GList *tmp_list;
|
|
GtkLayout *layout;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (widget));
|
|
|
|
layout = GTK_LAYOUT (widget);
|
|
|
|
requisition->width = 0;
|
|
requisition->height = 0;
|
|
|
|
tmp_list = layout->children;
|
|
|
|
while (tmp_list)
|
|
{
|
|
GtkLayoutChild *child = tmp_list->data;
|
|
GtkRequisition child_requisition;
|
|
|
|
tmp_list = tmp_list->next;
|
|
|
|
gtk_widget_size_request (child->widget, &child_requisition);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_layout_size_allocate (GtkWidget *widget,
|
|
GtkAllocation *allocation)
|
|
{
|
|
GList *tmp_list;
|
|
GtkLayout *layout;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (widget));
|
|
|
|
widget->allocation = *allocation;
|
|
|
|
layout = GTK_LAYOUT (widget);
|
|
|
|
tmp_list = layout->children;
|
|
|
|
while (tmp_list)
|
|
{
|
|
GtkLayoutChild *child = tmp_list->data;
|
|
tmp_list = tmp_list->next;
|
|
|
|
gtk_layout_allocate_child (layout, child);
|
|
}
|
|
|
|
if (GTK_WIDGET_REALIZED (widget))
|
|
{
|
|
gdk_window_move_resize (widget->window,
|
|
allocation->x, allocation->y,
|
|
allocation->width, allocation->height);
|
|
|
|
gdk_window_resize (layout->bin_window,
|
|
MAX (layout->width, allocation->width),
|
|
MAX (layout->height, allocation->height));
|
|
}
|
|
|
|
layout->hadjustment->page_size = allocation->width;
|
|
layout->hadjustment->page_increment = allocation->width / 2;
|
|
layout->hadjustment->lower = 0;
|
|
layout->hadjustment->upper = MAX (allocation->width, layout->width);
|
|
gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
|
|
|
|
layout->vadjustment->page_size = allocation->height;
|
|
layout->vadjustment->page_increment = allocation->height / 2;
|
|
layout->vadjustment->lower = 0;
|
|
layout->vadjustment->upper = MAX (allocation->height, layout->height);
|
|
gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
|
|
}
|
|
|
|
static gint
|
|
gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event)
|
|
{
|
|
GtkLayout *layout;
|
|
|
|
g_return_val_if_fail (GTK_IS_LAYOUT (widget), FALSE);
|
|
|
|
layout = GTK_LAYOUT (widget);
|
|
|
|
if (event->window != layout->bin_window)
|
|
return FALSE;
|
|
|
|
(* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/* Container method
|
|
*/
|
|
static void
|
|
gtk_layout_remove (GtkContainer *container,
|
|
GtkWidget *widget)
|
|
{
|
|
GList *tmp_list;
|
|
GtkLayout *layout;
|
|
GtkLayoutChild *child = NULL;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (container));
|
|
|
|
layout = GTK_LAYOUT (container);
|
|
|
|
tmp_list = layout->children;
|
|
while (tmp_list)
|
|
{
|
|
child = tmp_list->data;
|
|
if (child->widget == widget)
|
|
break;
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
|
|
if (tmp_list)
|
|
{
|
|
gtk_widget_unparent (widget);
|
|
|
|
layout->children = g_list_remove_link (layout->children, tmp_list);
|
|
g_list_free_1 (tmp_list);
|
|
g_free (child);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_layout_forall (GtkContainer *container,
|
|
gboolean include_internals,
|
|
GtkCallback callback,
|
|
gpointer callback_data)
|
|
{
|
|
GtkLayout *layout;
|
|
GtkLayoutChild *child;
|
|
GList *tmp_list;
|
|
|
|
g_return_if_fail (GTK_IS_LAYOUT (container));
|
|
g_return_if_fail (callback != NULL);
|
|
|
|
layout = GTK_LAYOUT (container);
|
|
|
|
tmp_list = layout->children;
|
|
while (tmp_list)
|
|
{
|
|
child = tmp_list->data;
|
|
tmp_list = tmp_list->next;
|
|
|
|
(* callback) (child->widget, callback_data);
|
|
}
|
|
}
|
|
|
|
/* Operations on children
|
|
*/
|
|
|
|
static void
|
|
gtk_layout_allocate_child (GtkLayout *layout,
|
|
GtkLayoutChild *child)
|
|
{
|
|
GtkAllocation allocation;
|
|
GtkRequisition requisition;
|
|
|
|
allocation.x = child->x;
|
|
allocation.y = child->y;
|
|
gtk_widget_get_child_requisition (child->widget, &requisition);
|
|
allocation.width = requisition.width;
|
|
allocation.height = requisition.height;
|
|
|
|
gtk_widget_size_allocate (child->widget, &allocation);
|
|
}
|
|
|
|
/* Callbacks */
|
|
|
|
static void
|
|
gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
|
|
GtkLayout *layout)
|
|
{
|
|
GtkWidget *widget;
|
|
|
|
widget = GTK_WIDGET (layout);
|
|
|
|
if (layout->freeze_count)
|
|
return;
|
|
|
|
if (GTK_WIDGET_REALIZED (layout))
|
|
{
|
|
gdk_window_move (layout->bin_window,
|
|
- layout->hadjustment->value,
|
|
- layout->vadjustment->value);
|
|
|
|
gdk_window_process_updates (layout->bin_window, TRUE);
|
|
}
|
|
}
|