X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtklayout.c;h=1f636b1288e9956bb37ad614005d43eb557e6357;hb=70c01bbe859829f84e2a7f7ab9c3c03f59b4447b;hp=784cf73f0b20fa392ebea87f8b654be132df5606;hpb=a425e6b5c21e4cfebc6c9aa0b7c5cd277face8a6;p=~andy%2Fgtk diff --git a/gtk/gtklayout.c b/gtk/gtklayout.c index 784cf73f0..1f636b128 100644 --- a/gtk/gtklayout.c +++ b/gtk/gtklayout.c @@ -2,16 +2,16 @@ * 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 Library General Public + * 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 - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public + * 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. @@ -21,66 +21,111 @@ * 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 "gdk/gdkx.h" - - -static void gtk_layout_class_init (GtkLayoutClass *class); -static void gtk_layout_init (GtkLayout *layout); - -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 void gtk_layout_draw (GtkWidget *widget, - GdkRectangle *area); -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_realize_child (GtkLayout *layout, - GtkLayoutChild *child); -static void gtk_layout_position_child (GtkLayout *layout, - GtkLayoutChild *child, - gboolean force_allocate); -static void gtk_layout_position_children (GtkLayout *layout); - -static void gtk_layout_expose_area (GtkLayout *layout, - gint x, - gint y, - gint width, - gint height); -static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment, - GtkLayout *layout); -static GdkFilterReturn gtk_layout_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data); -static GdkFilterReturn gtk_layout_main_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data); - -static gboolean gtk_layout_gravity_works (void); -static void gtk_layout_set_static_gravity (GdkWindow *win, - gboolean op); +#include "gtkprivate.h" +#include "gtkintl.h" +#include "gtkmarshalers.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 GObject *gtk_layout_constructor (GType type, + guint n_properties, + GObjectConstructParam *properties); +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 void gtk_layout_style_set (GtkWidget *widget, + GtkStyle *old_style); + +static void gtk_layout_set_adjustment_upper (GtkAdjustment *adj, + gdouble upper, + gboolean always_emit_changed); static GtkWidgetClass *parent_class = NULL; -static gboolean gravity_works; /* Public interface */ +/** + * gtk_layout_new: + * @hadjustment: horizontal scroll adjustment, or %NULL + * @vadjustment: vertical scroll adjustment, or %NULL + * + * Creates a new #GtkLayout. Unless you have a specific adjustment + * you'd like the layout to use for scrolling, pass %NULL for + * @hadjustment and @vadjustment. + * + * Return value: a new #GtkLayout + **/ GtkWidget* gtk_layout_new (GtkAdjustment *hadjustment, @@ -88,30 +133,61 @@ gtk_layout_new (GtkAdjustment *hadjustment, { GtkLayout *layout; - layout = gtk_type_new (gtk_layout_get_type()); - - gtk_layout_set_adjustments (layout, hadjustment, vadjustment); + layout = g_object_new (GTK_TYPE_LAYOUT, + "hadjustment", hadjustment, + "vadjustment", vadjustment, + NULL); return GTK_WIDGET (layout); } +/** + * gtk_layout_get_hadjustment: + * @layout: a #GtkLayout + * + * This function should only be called after the layout has been + * placed in a #GtkScrolledWindow or otherwise configured for + * scrolling. It returns the #GtkAdjustment used for communication + * between the horizontal scrollbar and @layout. + * + * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details. + * + * Return value: horizontal scroll adjustment + **/ GtkAdjustment* gtk_layout_get_hadjustment (GtkLayout *layout) { - g_return_val_if_fail (layout != NULL, NULL); g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL); return layout->hadjustment; } +/** + * gtk_layout_get_vadjustment: + * @layout: a #GtkLayout + * + * This function should only be called after the layout has been + * placed in a #GtkScrolledWindow or otherwise configured for + * scrolling. It returns the #GtkAdjustment used for communication + * between the vertical scrollbar and @layout. + * + * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details. + * + * Return value: vertical scroll adjustment + **/ GtkAdjustment* gtk_layout_get_vadjustment (GtkLayout *layout) { - g_return_val_if_fail (layout != NULL, NULL); g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL); return layout->vadjustment; } +static GtkAdjustment * +new_default_adjustment (void) +{ + return GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)); +} + static void gtk_layout_set_adjustments (GtkLayout *layout, GtkAdjustment *hadj, @@ -119,17 +195,16 @@ gtk_layout_set_adjustments (GtkLayout *layout, { gboolean need_adjust = FALSE; - g_return_if_fail (layout != NULL); 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)); + else if (layout->hadjustment) + hadj = new_default_adjustment (); 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)); + else if (layout->vadjustment) + vadj = new_default_adjustment (); if (layout->hadjustment && (layout->hadjustment != hadj)) { @@ -148,6 +223,7 @@ gtk_layout_set_adjustments (GtkLayout *layout, layout->hadjustment = hadj; gtk_object_ref (GTK_OBJECT (layout->hadjustment)); gtk_object_sink (GTK_OBJECT (layout->hadjustment)); + gtk_layout_set_adjustment_upper (layout->hadjustment, layout->width, FALSE); gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed", (GtkSignalFunc) gtk_layout_adjustment_changed, @@ -160,6 +236,7 @@ gtk_layout_set_adjustments (GtkLayout *layout, layout->vadjustment = vadj; gtk_object_ref (GTK_OBJECT (layout->vadjustment)); gtk_object_sink (GTK_OBJECT (layout->vadjustment)); + gtk_layout_set_adjustment_upper (layout->vadjustment, layout->height, FALSE); gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed", (GtkSignalFunc) gtk_layout_adjustment_changed, @@ -167,32 +244,95 @@ gtk_layout_set_adjustments (GtkLayout *layout, need_adjust = TRUE; } - if (need_adjust) + /* vadj or hadj can be NULL while constructing; don't emit a signal + then */ + if (need_adjust && vadj && hadj) 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); +} + +/** + * gtk_layout_set_hadjustment: + * @layout: a #GtkLayout + * @adjustment: new scroll adjustment + * + * Sets the horizontal scroll adjustment for the layout. + * + * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details. + * + **/ void gtk_layout_set_hadjustment (GtkLayout *layout, GtkAdjustment *adjustment) { - g_return_if_fail (layout != NULL); g_return_if_fail (GTK_IS_LAYOUT (layout)); gtk_layout_set_adjustments (layout, adjustment, layout->vadjustment); + g_object_notify (G_OBJECT (layout), "hadjustment"); } - +/** + * gtk_layout_set_vadjustment: + * @layout: a #GtkLayout + * @adjustment: new scroll adjustment + * + * Sets the vertical scroll adjustment for the layout. + * + * See #GtkScrolledWindow, #GtkScrollbar, #GtkAdjustment for details. + * + **/ void gtk_layout_set_vadjustment (GtkLayout *layout, GtkAdjustment *adjustment) { - g_return_if_fail (layout != NULL); 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; +} +/** + * gtk_layout_put: + * @layout: a #GtkLayout + * @child_widget: child widget + * @x: X position of child widget + * @y: Y position of child widget + * + * Adds @child_widget to @layout, at position (@x,@y). + * @layout becomes the new parent container of @child_widget. + * + **/ void gtk_layout_put (GtkLayout *layout, GtkWidget *child_widget, @@ -201,122 +341,234 @@ gtk_layout_put (GtkLayout *layout, { GtkLayoutChild *child; - g_return_if_fail (layout != NULL); 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->window = NULL; child->x = x; child->y = y; - child->widget->requisition.width = 0; - child->widget->requisition.height = 0; - child->mapped = FALSE; 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_size_request (child->widget, &child->widget->requisition); + gtk_widget_freeze_child_notify (widget); - if (GTK_WIDGET_REALIZED (layout) && - !GTK_WIDGET_REALIZED (child_widget)) - gtk_layout_realize_child (layout, child); + 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_layout_position_child (layout, child, TRUE); + gtk_widget_thaw_child_notify (widget); + + if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_VISIBLE (layout)) + gtk_widget_queue_resize (GTK_WIDGET (widget)); } +/** + * gtk_layout_move: + * @layout: a #GtkLayout + * @child_widget: a current child of @layout + * @x: X position to move to + * @y: Y position to move to + * + * Moves a current child of @layout to a new position. + * + **/ void gtk_layout_move (GtkLayout *layout, GtkWidget *child_widget, gint x, gint y) { - GList *tmp_list; - GtkLayoutChild *child; - - g_return_if_fail (layout != NULL); 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)); - tmp_list = layout->children; - while (tmp_list) + gtk_layout_move_internal (layout, child_widget, TRUE, x, TRUE, y); +} + +static void +gtk_layout_set_adjustment_upper (GtkAdjustment *adj, + gdouble upper, + gboolean always_emit_changed) +{ + gboolean changed = FALSE; + gboolean value_changed = FALSE; + + gdouble min = MAX (0., upper - adj->page_size); + + if (upper != adj->upper) { - child = tmp_list->data; - if (child->widget == child_widget) - { - child->x = x; - child->y = y; - - gtk_layout_position_child (layout, child, TRUE); - return; - } - tmp_list = tmp_list->next; + adj->upper = upper; + changed = TRUE; + } + + if (adj->value > min) + { + adj->value = min; + value_changed = TRUE; } + + if (changed || always_emit_changed) + gtk_signal_emit_by_name (GTK_OBJECT (adj), "changed"); + if (value_changed) + gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed"); } +/** + * gtk_layout_set_size: + * @layout: a #GtkLayout + * @width: width of entire scrollable area + * @height: height of entire scrollable area + * + * Sets the size of the scrollable area of the layout. + * + **/ void gtk_layout_set_size (GtkLayout *layout, guint width, guint height) { - g_return_if_fail (layout != NULL); + GtkWidget *widget; + g_return_if_fail (GTK_IS_LAYOUT (layout)); - layout->width = width; - layout->height = height; + widget = GTK_WIDGET (layout); + + g_object_freeze_notify (G_OBJECT (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"); + } + g_object_thaw_notify (G_OBJECT (layout)); + + if (layout->hadjustment) + gtk_layout_set_adjustment_upper (layout->hadjustment, layout->width, FALSE); + if (layout->vadjustment) + gtk_layout_set_adjustment_upper (layout->vadjustment, layout->height, FALSE); + + 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); + } +} - layout->hadjustment->upper = layout->width; - gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); +/** + * 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)); - layout->vadjustment->upper = layout->height; - gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); + if (width) + *width = layout->width; + if (height) + *height = layout->height; } +/** + * gtk_layout_freeze: + * @layout: a #GtkLayout + * + * This is a deprecated function, it doesn't do anything useful. + **/ void gtk_layout_freeze (GtkLayout *layout) { - g_return_if_fail (layout != NULL); g_return_if_fail (GTK_IS_LAYOUT (layout)); - layout->frozen = TRUE; + layout->freeze_count++; } +/** + * gtk_layout_thaw: + * @layout: a #GtkLayout + * + * This is a deprecated function, it doesn't do anything useful. + **/ void gtk_layout_thaw (GtkLayout *layout) { - g_return_if_fail (layout != NULL); g_return_if_fail (GTK_IS_LAYOUT (layout)); - if (!layout->frozen) - return; - - layout->frozen = FALSE; - gtk_layout_position_children (layout); - gtk_widget_draw (GTK_WIDGET (layout), NULL); + if (layout->freeze_count) + if (!(--layout->freeze_count)) + gtk_widget_draw (GTK_WIDGET (layout), NULL); } /* Basic Object handling procedures */ -guint +GtkType gtk_layout_get_type (void) { - static guint layout_type = 0; + static GtkType layout_type = 0; if (!layout_type) { - GtkTypeInfo layout_info = + static const GTypeInfo layout_info = { - "GtkLayout", - sizeof (GtkLayout), sizeof (GtkLayoutClass), - (GtkClassInitFunc) gtk_layout_class_init, - (GtkObjectInitFunc) gtk_layout_init, - (GtkArgSetFunc) NULL, - (GtkArgGetFunc) NULL, + 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 = gtk_type_unique (gtk_container_get_type (), &layout_info); + layout_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkLayout", &layout_info, 0); } return layout_type; @@ -325,38 +577,212 @@ gtk_layout_get_type (void) 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_container_get_type ()); - + 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; + gobject_class->constructor = gtk_layout_constructor; + + 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->draw = gtk_layout_draw; widget_class->expose_event = gtk_layout_expose; + widget_class->style_set = gtk_layout_style_set; + + container_class->remove = gtk_layout_remove; + container_class->forall = gtk_layout_forall; + + class->set_scroll_adjustments = gtk_layout_set_adjustments; - widget_class->scroll_adjustments_signal = - gtk_signal_new ("scroll_adjustments", + widget_class->set_scroll_adjustments_signal = + gtk_signal_new ("set_scroll_adjustments", GTK_RUN_LAST, - object_class->type, - GTK_SIGNAL_OFFSET (GtkLayoutClass, scroll_adjustments), - gtk_marshal_NONE__POINTER_POINTER, + 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); +} - gravity_works = gtk_layout_gravity_works (); +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, layout->hadjustment); + break; + case PROP_VADJUSTMENT: + g_value_set_object (value, 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; + } +} - container_class->remove = gtk_layout_remove; - container_class->forall = gtk_layout_forall; +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; + } +} - class->scroll_adjustments = gtk_layout_set_adjustments; +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 @@ -372,10 +798,35 @@ gtk_layout_init (GtkLayout *layout) layout->bin_window = NULL; - layout->configure_serial = 0; layout->scroll_x = 0; layout->scroll_y = 0; layout->visibility = GDK_VISIBILITY_PARTIAL; + + layout->freeze_count = 0; +} + +static GObject * +gtk_layout_constructor (GType type, + guint n_properties, + GObjectConstructParam *properties) +{ + GtkLayout *layout; + GObject *object; + GtkAdjustment *hadj, *vadj; + + object = G_OBJECT_CLASS (parent_class)->constructor (type, + n_properties, + properties); + + layout = GTK_LAYOUT (object); + + hadj = layout->hadjustment ? layout->hadjustment : new_default_adjustment (); + vadj = layout->vadjustment ? layout->vadjustment : new_default_adjustment (); + + if (!layout->hadjustment || !layout->vadjustment) + gtk_layout_set_adjustments (layout, hadj, vadj); + + return object; } /* Widget methods @@ -389,7 +840,6 @@ gtk_layout_realize (GtkWidget *widget) GdkWindowAttr attributes; gint attributes_mask; - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_LAYOUT (widget)); layout = GTK_LAYOUT (widget); @@ -411,33 +861,40 @@ gtk_layout_realize (GtkWidget *widget) &attributes, attributes_mask); gdk_window_set_user_data (widget->window, widget); - attributes.x = 0; - attributes.y = 0; - attributes.event_mask = gtk_widget_get_events (widget); + attributes.x = - layout->hadjustment->value, + attributes.y = - layout->vadjustment->value; + 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); - if (gravity_works) - gtk_layout_set_static_gravity (layout->bin_window, TRUE); - 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); - gdk_window_add_filter (widget->window, gtk_layout_main_filter, layout); - gdk_window_add_filter (layout->bin_window, gtk_layout_filter, layout); - tmp_list = layout->children; while (tmp_list) { GtkLayoutChild *child = tmp_list->data; - - if (GTK_WIDGET_VISIBLE (child->widget)) - gtk_layout_realize_child (layout, child); - tmp_list = tmp_list->next; + + gtk_widget_set_parent_window (child->widget, layout->bin_window); + } +} + +static void +gtk_layout_style_set (GtkWidget *widget, GtkStyle *old_style) +{ + if (GTK_WIDGET_CLASS (parent_class)->style_set) + (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, old_style); + + if (GTK_WIDGET_REALIZED (widget)) + { + gtk_style_set_background (widget->style, GTK_LAYOUT (widget)->bin_window, GTK_STATE_NORMAL); } } @@ -447,75 +904,44 @@ gtk_layout_map (GtkWidget *widget) GList *tmp_list; GtkLayout *layout; - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_LAYOUT (widget)); layout = GTK_LAYOUT (widget); GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); - gdk_window_show (widget->window); - gdk_window_show (layout->bin_window); - tmp_list = layout->children; while (tmp_list) { GtkLayoutChild *child = tmp_list->data; + tmp_list = tmp_list->next; - if (child->mapped && GTK_WIDGET_VISIBLE (child->widget)) + if (GTK_WIDGET_VISIBLE (child->widget)) { if (!GTK_WIDGET_MAPPED (child->widget)) gtk_widget_map (child->widget); - - if (child->window) - gdk_window_show (child->window); } - - tmp_list = tmp_list->next; } - + + gdk_window_show (layout->bin_window); + gdk_window_show (widget->window); } static void gtk_layout_unrealize (GtkWidget *widget) { - GList *tmp_list; GtkLayout *layout; - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_LAYOUT (widget)); layout = GTK_LAYOUT (widget); - tmp_list = layout->children; - gdk_window_set_user_data (layout->bin_window, NULL); gdk_window_destroy (layout->bin_window); layout->bin_window = NULL; - while (tmp_list) - { - GtkLayoutChild *child = tmp_list->data; - - if (child->window) - { - gdk_window_set_user_data (child->window, NULL); - gdk_window_destroy (child->window); - } - - tmp_list = tmp_list->next; - } -} - -static void -gtk_layout_draw (GtkWidget *widget, GdkRectangle *area) -{ - GtkLayout *layout; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_LAYOUT (widget)); - - layout = GTK_LAYOUT (widget); + if (GTK_WIDGET_CLASS (parent_class)->unrealize) + (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } static void @@ -525,19 +951,23 @@ gtk_layout_size_request (GtkWidget *widget, GList *tmp_list; GtkLayout *layout; - g_return_if_fail (widget != NULL); 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; - gtk_widget_size_request (child->widget, &child->widget->requisition); + GtkRequisition child_requisition; tmp_list = tmp_list->next; + + gtk_widget_size_request (child->widget, &child_requisition); } } @@ -548,7 +978,6 @@ gtk_layout_size_allocate (GtkWidget *widget, GList *tmp_list; GtkLayout *layout; - g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_LAYOUT (widget)); widget->allocation = *allocation; @@ -560,9 +989,9 @@ gtk_layout_size_allocate (GtkWidget *widget, while (tmp_list) { GtkLayoutChild *child = tmp_list->data; - gtk_layout_position_child (layout, child, TRUE); - tmp_list = tmp_list->next; + + gtk_layout_allocate_child (layout, child); } if (GTK_WIDGET_REALIZED (widget)) @@ -570,44 +999,38 @@ gtk_layout_size_allocate (GtkWidget *widget, gdk_window_move_resize (widget->window, allocation->x, allocation->y, allocation->width, allocation->height); - gdk_window_move_resize (GTK_LAYOUT(widget)->bin_window, - 0, 0, - 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; - gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); + layout->hadjustment->page_increment = allocation->width * 0.9; + layout->hadjustment->lower = 0; + /* set_adjustment_upper() emits ::changed */ + gtk_layout_set_adjustment_upper (layout->hadjustment, MAX (allocation->width, layout->width), TRUE); layout->vadjustment->page_size = allocation->height; - layout->vadjustment->page_increment = allocation->height / 2; - gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); + layout->vadjustment->page_increment = allocation->height * 0.9; + layout->vadjustment->lower = 0; + layout->vadjustment->upper = MAX (allocation->height, layout->height); + gtk_layout_set_adjustment_upper (layout->vadjustment, MAX (allocation->height, layout->height), TRUE); } static gint gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event) { - GList *tmp_list; GtkLayout *layout; - g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_LAYOUT (widget), FALSE); layout = GTK_LAYOUT (widget); - if (event->window == layout->bin_window) + if (event->window != layout->bin_window) return FALSE; - tmp_list = layout->children; - while (tmp_list) - { - GtkLayoutChild *child = tmp_list->data; - - if (event->window == child->window) - return gtk_widget_event (child->widget, (GdkEvent *)event); - - tmp_list = tmp_list->next; - } + (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event); return FALSE; } @@ -620,9 +1043,8 @@ gtk_layout_remove (GtkContainer *container, { GList *tmp_list; GtkLayout *layout; - GtkLayoutChild *child; + GtkLayoutChild *child = NULL; - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_LAYOUT (container)); layout = GTK_LAYOUT (container); @@ -638,15 +1060,6 @@ gtk_layout_remove (GtkContainer *container, if (tmp_list) { - if (child->window) - { - /* FIXME: This will cause problems for reparenting NO_WINDOW - * widgets out of a GtkLayout - */ - gdk_window_set_user_data (child->window, NULL); - gdk_window_destroy (child->window); - } - gtk_widget_unparent (widget); layout->children = g_list_remove_link (layout->children, tmp_list); @@ -665,7 +1078,6 @@ gtk_layout_forall (GtkContainer *container, GtkLayoutChild *child; GList *tmp_list; - g_return_if_fail (container != NULL); g_return_if_fail (GTK_IS_LAYOUT (container)); g_return_if_fail (callback != NULL); @@ -685,536 +1097,40 @@ gtk_layout_forall (GtkContainer *container, */ static void -gtk_layout_realize_child (GtkLayout *layout, - GtkLayoutChild *child) +gtk_layout_allocate_child (GtkLayout *layout, + GtkLayoutChild *child) { - GtkWidget *widget; - gint attributes_mask; - - widget = GTK_WIDGET (layout); - - if (GTK_WIDGET_NO_WINDOW (child->widget)) - { - GdkWindowAttr attributes; - - gint x = child->x - layout->xoffset; - gint y = child->y - layout->xoffset; - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = x; - attributes.y = y; - attributes.width = child->widget->requisition.width; - attributes.height = child->widget->requisition.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - attributes.event_mask = GDK_EXPOSURE_MASK; - - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - child->window = gdk_window_new (layout->bin_window, - &attributes, attributes_mask); - gdk_window_set_user_data (child->window, widget); - - if (child->window) - gtk_style_set_background (widget->style, - child->window, - GTK_STATE_NORMAL); - } - - gtk_widget_set_parent_window (child->widget, - child->window ? child->window : layout->bin_window); - - gtk_widget_realize (child->widget); + 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; - if (gravity_works) - gtk_layout_set_static_gravity (child->window ? child->window : child->widget->window, TRUE); + gtk_widget_size_allocate (child->widget, &allocation); } -static void -gtk_layout_position_child (GtkLayout *layout, - GtkLayoutChild *child, - gboolean force_allocate) -{ - gint x; - gint y; - - x = child->x - layout->xoffset; - y = child->y - layout->yoffset; - - if ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && - (y >= G_MINSHORT) && (y <= G_MAXSHORT)) - { - if (!child->mapped) - { - child->mapped = TRUE; - - if (GTK_WIDGET_MAPPED (layout) && - GTK_WIDGET_VISIBLE (child->widget)) - { - if (child->window) - gdk_window_show (child->window); - if (!GTK_WIDGET_MAPPED (child->widget)) - gtk_widget_map (child->widget); - - child->mapped = TRUE; - force_allocate = TRUE; - } - } - - if (force_allocate) - { - GtkAllocation allocation; - - if (GTK_WIDGET_NO_WINDOW (child->widget)) - { - if (child->window) - { - gdk_window_move_resize (child->window, - x, y, - child->widget->requisition.width, - child->widget->requisition.height); - } - - allocation.x = 0; - allocation.y = 0; - } - else - { - allocation.x = x; - allocation.y = y; - } - - allocation.width = child->widget->requisition.width; - allocation.height = child->widget->requisition.height; - - gtk_widget_size_allocate (child->widget, &allocation); - } - } - else - { - if (child->mapped) - { - child->mapped = FALSE; - if (child->window) - gdk_window_hide (child->window); - else if (GTK_WIDGET_MAPPED (child->widget)) - gtk_widget_unmap (child->widget); - } - } -} - -static void -gtk_layout_position_children (GtkLayout *layout) -{ - GList *tmp_list; - - tmp_list = layout->children; - while (tmp_list) - { - gtk_layout_position_child (layout, tmp_list->data, FALSE); - - tmp_list = tmp_list->next; - } -} - /* Callbacks */ -/* Send a synthetic expose event to the widget - */ -static void -gtk_layout_expose_area (GtkLayout *layout, - gint x, gint y, gint width, gint height) -{ - if (layout->visibility == GDK_VISIBILITY_UNOBSCURED) - { - GdkEventExpose event; - - event.type = GDK_EXPOSE; - event.send_event = TRUE; - event.window = layout->bin_window; - event.count = 0; - - event.area.x = x; - event.area.y = y; - event.area.width = width; - event.area.height = height; - - gdk_window_ref (event.window); - gtk_widget_event (GTK_WIDGET (layout), (GdkEvent *)&event); - gdk_window_unref (event.window); - } -} - -/* This function is used to find events to process while scrolling - * Removing the GravityNotify events is a bit of a hack - currently - * GTK uses a lot of time processing them as GtkEventOther - a - * feature that is obsolete and will be removed. Until then... - */ - -static Bool -gtk_layout_expose_predicate (Display *display, - XEvent *xevent, - XPointer arg) -{ - if ((xevent->type == Expose) || (xevent->type == GravityNotify) || - ((xevent->xany.window == *(Window *)arg) && - (xevent->type == ConfigureNotify))) - return True; - else - return False; -} - -/* This is the main routine to do the scrolling. Scrolling is - * done by "Guffaw" scrolling, as in the Mozilla XFE, with - * a few modifications. - * - * The main improvement is that we keep track of whether we - * are obscured or not. If not, we ignore the generated expose - * events and instead do the exposes ourself, without having - * to wait for a roundtrip to the server. This also provides - * a limited form of expose-event compression, since we do - * the affected area as one big chunk. - * - * Real expose event compression, as in the XFE, could be added - * here. It would help opaque drags over the region, and the - * obscured case. - * - * Code needs to be added here to do the scrolling on machines - * that don't have working WindowGravity. That could be done - * - * - XCopyArea and move the windows, and accept trailing the - * background color. (Since it is only a fallback method) - * - XmHTML style. As above, but turn off expose events when - * not obscured and do the exposures ourself. - * - gzilla-style. Move the window continuously, and reset - * every 32768 pixels - */ - static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment, GtkLayout *layout) { GtkWidget *widget; - XEvent xevent; - - gint dx, dy; widget = GTK_WIDGET (layout); - dx = (gint)layout->hadjustment->value - layout->xoffset; - dy = (gint)layout->vadjustment->value - layout->yoffset; - - layout->xoffset = (gint)layout->hadjustment->value; - layout->yoffset = (gint)layout->vadjustment->value; - - if (layout->frozen) + if (layout->freeze_count) return; - if (!GTK_WIDGET_MAPPED (layout)) - { - gtk_layout_position_children (layout); - return; - } - - if (dx > 0) - { - if (gravity_works) - { - gdk_window_resize (layout->bin_window, - widget->allocation.width + dx, - widget->allocation.height); - gdk_window_move (layout->bin_window, -dx, 0); - gdk_window_move_resize (layout->bin_window, - 0, 0, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - - gtk_layout_expose_area (layout, - widget->allocation.width - dx, - 0, - dx, - widget->allocation.height); - } - else if (dx < 0) - { - if (gravity_works) - { - gdk_window_move_resize (layout->bin_window, - dx, 0, - widget->allocation.width - dx, - widget->allocation.height); - gdk_window_move (layout->bin_window, 0, 0); - gdk_window_resize (layout->bin_window, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - - gtk_layout_expose_area (layout, - 0, - 0, - -dx, - widget->allocation.height); - } - - if (dy > 0) - { - if (gravity_works) - { - gdk_window_resize (layout->bin_window, - widget->allocation.width, - widget->allocation.height + dy); - gdk_window_move (layout->bin_window, 0, -dy); - gdk_window_move_resize (layout->bin_window, - 0, 0, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - - gtk_layout_expose_area (layout, - 0, - widget->allocation.height - dy, - widget->allocation.width, - dy); - } - else if (dy < 0) - { - if (gravity_works) - { - gdk_window_move_resize (layout->bin_window, - 0, dy, - widget->allocation.width, - widget->allocation.height - dy); - gdk_window_move (layout->bin_window, 0, 0); - gdk_window_resize (layout->bin_window, - widget->allocation.width, - widget->allocation.height); - } - else - { - /* FIXME */ - } - gtk_layout_expose_area (layout, - 0, - 0, - widget->allocation.height, - -dy); - } - - gtk_layout_position_children (layout); - - /* We have to make sure that all exposes from this scroll get - * processed before we scroll again, or the expose events will - * have invalid coordinates. - * - * We also do expose events for other windows, since otherwise - * their updating will fall behind the scrolling - * - * This also avoids a problem in pre-1.0 GTK where filters don't - * have access to configure events that were compressed. - */ - - gdk_flush(); - while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (layout->bin_window), - &xevent, - gtk_layout_expose_predicate, - (XPointer)&GDK_WINDOW_XWINDOW (layout->bin_window))) + if (GTK_WIDGET_REALIZED (layout)) { - GdkEvent event; - GtkWidget *event_widget; - - if ((xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window)) && - (gtk_layout_filter (&xevent, &event, layout) == GDK_FILTER_REMOVE)) - continue; + gdk_window_move (layout->bin_window, + - layout->hadjustment->value, + - layout->vadjustment->value); - if (xevent.type == Expose) - { - event.expose.window = gdk_window_lookup (xevent.xany.window); - gdk_window_get_user_data (event.expose.window, - (gpointer *)&event_widget); - - if (event_widget) - { - event.expose.type = GDK_EXPOSE; - event.expose.area.x = xevent.xexpose.x; - event.expose.area.y = xevent.xexpose.y; - event.expose.area.width = xevent.xexpose.width; - event.expose.area.height = xevent.xexpose.height; - event.expose.count = xevent.xexpose.count; - - gdk_window_ref (event.expose.window); - gtk_widget_event (event_widget, &event); - gdk_window_unref (event.expose.window); - } - } + gdk_window_process_updates (layout->bin_window, TRUE); } } - -/* The main event filter. Actually, we probably don't really need - * to install this as a filter at all, since we are calling it - * directly above in the expose-handling hack. But in case scrollbars - * are fixed up in some manner... - * - * This routine identifies expose events that are generated when - * we've temporarily moved the bin_window_origin, and translates - * them or discards them, depending on whether we are obscured - * or not. - */ -static GdkFilterReturn -gtk_layout_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data) -{ - XEvent *xevent; - GtkLayout *layout; - - xevent = (XEvent *)gdk_xevent; - layout = GTK_LAYOUT (data); - - switch (xevent->type) - { - case Expose: - if (xevent->xexpose.serial == layout->configure_serial) - { - if (layout->visibility == GDK_VISIBILITY_UNOBSCURED) - return GDK_FILTER_REMOVE; - else - { - xevent->xexpose.x += layout->scroll_x; - xevent->xexpose.y += layout->scroll_y; - - break; - } - } - break; - - case ConfigureNotify: - if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0)) - { - layout->configure_serial = xevent->xconfigure.serial; - layout->scroll_x = xevent->xconfigure.x; - layout->scroll_y = xevent->xconfigure.y; - } - break; - } - - return GDK_FILTER_CONTINUE; -} - -/* Although GDK does have a GDK_VISIBILITY_NOTIFY event, - * there is no corresponding event in GTK, so we have - * to get the events from a filter - */ -static GdkFilterReturn -gtk_layout_main_filter (GdkXEvent *gdk_xevent, - GdkEvent *event, - gpointer data) -{ - XEvent *xevent; - GtkLayout *layout; - - xevent = (XEvent *)gdk_xevent; - layout = GTK_LAYOUT (data); - - if (xevent->type == VisibilityNotify) - { - switch (xevent->xvisibility.state) - { - case VisibilityFullyObscured: - layout->visibility = GDK_VISIBILITY_FULLY_OBSCURED; - break; - - case VisibilityPartiallyObscured: - layout->visibility = GDK_VISIBILITY_PARTIAL; - break; - - case VisibilityUnobscured: - layout->visibility = GDK_VISIBILITY_UNOBSCURED; - break; - } - - return GDK_FILTER_REMOVE; - } - - - return GDK_FILTER_CONTINUE; -} - -/* Routines to set the window gravity, and check whether it is - * functional. Extra capabilities need to be added to GDK, so - * we don't have to use Xlib here. - */ -static void -gtk_layout_set_static_gravity (GdkWindow *win, gboolean on) -{ - XSetWindowAttributes xattributes; - - xattributes.win_gravity = on ? StaticGravity : NorthWestGravity; - xattributes.bit_gravity = on ? StaticGravity : NorthWestGravity; - - XChangeWindowAttributes (GDK_WINDOW_XDISPLAY (win), - GDK_WINDOW_XWINDOW (win), - CWBitGravity | CWWinGravity, - &xattributes); -} - -static gboolean -gtk_layout_gravity_works (void) -{ - GdkWindowAttr attr; - - GdkWindow *parent; - GdkWindow *child; - gint y; - - /* This particular server apparently has a bug so that the test - * works but the actual code crashes it - */ - if ((!strcmp (XServerVendor (GDK_DISPLAY()), "Sun Microsystems, Inc.")) && - (VendorRelease (GDK_DISPLAY()) == 3400)) - return FALSE; - - attr.window_type = GDK_WINDOW_TEMP; - attr.wclass = GDK_INPUT_OUTPUT; - attr.x = 0; - attr.y = 0; - attr.width = 100; - attr.height = 100; - attr.event_mask = 0; - - parent = gdk_window_new (NULL, &attr, GDK_WA_X | GDK_WA_Y); - - attr.window_type = GDK_WINDOW_CHILD; - child = gdk_window_new (parent, &attr, GDK_WA_X | GDK_WA_Y); - - gtk_layout_set_static_gravity (parent, TRUE); - gtk_layout_set_static_gravity (child, TRUE); - - gdk_window_resize (parent, 100, 110); - gdk_window_move (parent, 0, -10); - gdk_window_move_resize (parent, 0, 0, 100, 100); - - gdk_window_resize (parent, 100, 110); - gdk_window_move (parent, 0, -10); - gdk_window_move_resize (parent, 0, 0, 100, 100); - - gdk_window_get_geometry (child, NULL, &y, NULL, NULL, NULL); - - gdk_window_destroy (parent); - gdk_window_destroy (child); - - return (y == -20); -} -