diff options
-rw-r--r-- | ChangeLog | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 40 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 40 | ||||
-rw-r--r-- | gdk/gdk.h | 5 | ||||
-rw-r--r-- | gdk/gdkprivate.h | 1 | ||||
-rw-r--r-- | gdk/gdkwindow.c | 168 | ||||
-rw-r--r-- | gdk/x11/gdkwindow-x11.c | 168 | ||||
-rw-r--r-- | gtk/gtklabel.c | 15 | ||||
-rw-r--r-- | gtk/gtklayout.c | 475 | ||||
-rw-r--r-- | gtk/gtklayout.h | 29 | ||||
-rw-r--r-- | gtk/gtkprivate.h | 4 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 41 | ||||
-rw-r--r-- | gtk/testgtk.c | 10 | ||||
-rw-r--r-- | tests/testgtk.c | 10 |
18 files changed, 895 insertions, 311 deletions
@@ -1,3 +1,43 @@ +Wed Jan 20 11:19:00 1999 Owen Taylor <otaylor@redhat.com> + + * gtk/gtklabel.c: Use floor() instead of truncating + to integer values so we get translation invariance. + + * gtk/gtklayout.c (gtk_layout_size_allocate): Set upper + and lower values for adjustments in size_allocate(). + + * gdk/gdkwindow.c gdk/gdk.h gdk/gdkprivate.h: New + function gdk_window_set_static_gravities() to set + up a window for guffaw scrolling. + + * gdk/gdkwindow.c (gdk_window_internal_destroy): Set flags + indicating destroyed state before cleanup. + + * gtk/gtkprivate.h gtk/gtkwidget.c: Add a new + private flag IS_OFFSCREEN. If set, this indicates + to GTK+ that the widget is not to be considered + viewable regardless of its map state. Queued draws + on offscreen widgets are suppressed. + + Added new function static gtk_widget_is_offscreen() to + check this flag on a widget and its ancestors. + + * gtk/gtklayout.[ch]: Major revisions. + + - Use gdk_window_set_static_gravities to set static gravity + on all child windows, and thus avoid having to create a window + for NO_WINDOW children. + + - Adjust allocations of children as we scroll them + so queued draws work correctly. + + - Don't allocate our children directly in a put() + or move(); just queue a resize() like every other + widget. + + * gtk/testgtk.c: Make the arrows on the scrollbars + work, create a larger and more demanding test. + Wed Jan 27 09:19:07 1999 Tim Janik <timj@gtk.org> * gdk/gdkcolor.c (gdk_colormap_unref): assert ref_count>0. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index dfe5b34ce..0e49fdab4 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,43 @@ +Wed Jan 20 11:19:00 1999 Owen Taylor <otaylor@redhat.com> + + * gtk/gtklabel.c: Use floor() instead of truncating + to integer values so we get translation invariance. + + * gtk/gtklayout.c (gtk_layout_size_allocate): Set upper + and lower values for adjustments in size_allocate(). + + * gdk/gdkwindow.c gdk/gdk.h gdk/gdkprivate.h: New + function gdk_window_set_static_gravities() to set + up a window for guffaw scrolling. + + * gdk/gdkwindow.c (gdk_window_internal_destroy): Set flags + indicating destroyed state before cleanup. + + * gtk/gtkprivate.h gtk/gtkwidget.c: Add a new + private flag IS_OFFSCREEN. If set, this indicates + to GTK+ that the widget is not to be considered + viewable regardless of its map state. Queued draws + on offscreen widgets are suppressed. + + Added new function static gtk_widget_is_offscreen() to + check this flag on a widget and its ancestors. + + * gtk/gtklayout.[ch]: Major revisions. + + - Use gdk_window_set_static_gravities to set static gravity + on all child windows, and thus avoid having to create a window + for NO_WINDOW children. + + - Adjust allocations of children as we scroll them + so queued draws work correctly. + + - Don't allocate our children directly in a put() + or move(); just queue a resize() like every other + widget. + + * gtk/testgtk.c: Make the arrows on the scrollbars + work, create a larger and more demanding test. + Wed Jan 27 09:19:07 1999 Tim Janik <timj@gtk.org> * gdk/gdkcolor.c (gdk_colormap_unref): assert ref_count>0. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index dfe5b34ce..0e49fdab4 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,43 @@ +Wed Jan 20 11:19:00 1999 Owen Taylor <otaylor@redhat.com> + + * gtk/gtklabel.c: Use floor() instead of truncating + to integer values so we get translation invariance. + + * gtk/gtklayout.c (gtk_layout_size_allocate): Set upper + and lower values for adjustments in size_allocate(). + + * gdk/gdkwindow.c gdk/gdk.h gdk/gdkprivate.h: New + function gdk_window_set_static_gravities() to set + up a window for guffaw scrolling. + + * gdk/gdkwindow.c (gdk_window_internal_destroy): Set flags + indicating destroyed state before cleanup. + + * gtk/gtkprivate.h gtk/gtkwidget.c: Add a new + private flag IS_OFFSCREEN. If set, this indicates + to GTK+ that the widget is not to be considered + viewable regardless of its map state. Queued draws + on offscreen widgets are suppressed. + + Added new function static gtk_widget_is_offscreen() to + check this flag on a widget and its ancestors. + + * gtk/gtklayout.[ch]: Major revisions. + + - Use gdk_window_set_static_gravities to set static gravity + on all child windows, and thus avoid having to create a window + for NO_WINDOW children. + + - Adjust allocations of children as we scroll them + so queued draws work correctly. + + - Don't allocate our children directly in a put() + or move(); just queue a resize() like every other + widget. + + * gtk/testgtk.c: Make the arrows on the scrollbars + work, create a larger and more demanding test. + Wed Jan 27 09:19:07 1999 Tim Janik <timj@gtk.org> * gdk/gdkcolor.c (gdk_colormap_unref): assert ref_count>0. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index dfe5b34ce..0e49fdab4 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,43 @@ +Wed Jan 20 11:19:00 1999 Owen Taylor <otaylor@redhat.com> + + * gtk/gtklabel.c: Use floor() instead of truncating + to integer values so we get translation invariance. + + * gtk/gtklayout.c (gtk_layout_size_allocate): Set upper + and lower values for adjustments in size_allocate(). + + * gdk/gdkwindow.c gdk/gdk.h gdk/gdkprivate.h: New + function gdk_window_set_static_gravities() to set + up a window for guffaw scrolling. + + * gdk/gdkwindow.c (gdk_window_internal_destroy): Set flags + indicating destroyed state before cleanup. + + * gtk/gtkprivate.h gtk/gtkwidget.c: Add a new + private flag IS_OFFSCREEN. If set, this indicates + to GTK+ that the widget is not to be considered + viewable regardless of its map state. Queued draws + on offscreen widgets are suppressed. + + Added new function static gtk_widget_is_offscreen() to + check this flag on a widget and its ancestors. + + * gtk/gtklayout.[ch]: Major revisions. + + - Use gdk_window_set_static_gravities to set static gravity + on all child windows, and thus avoid having to create a window + for NO_WINDOW children. + + - Adjust allocations of children as we scroll them + so queued draws work correctly. + + - Don't allocate our children directly in a put() + or move(); just queue a resize() like every other + widget. + + * gtk/testgtk.c: Make the arrows on the scrollbars + work, create a larger and more demanding test. + Wed Jan 27 09:19:07 1999 Tim Janik <timj@gtk.org> * gdk/gdkcolor.c (gdk_colormap_unref): assert ref_count>0. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index dfe5b34ce..0e49fdab4 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,43 @@ +Wed Jan 20 11:19:00 1999 Owen Taylor <otaylor@redhat.com> + + * gtk/gtklabel.c: Use floor() instead of truncating + to integer values so we get translation invariance. + + * gtk/gtklayout.c (gtk_layout_size_allocate): Set upper + and lower values for adjustments in size_allocate(). + + * gdk/gdkwindow.c gdk/gdk.h gdk/gdkprivate.h: New + function gdk_window_set_static_gravities() to set + up a window for guffaw scrolling. + + * gdk/gdkwindow.c (gdk_window_internal_destroy): Set flags + indicating destroyed state before cleanup. + + * gtk/gtkprivate.h gtk/gtkwidget.c: Add a new + private flag IS_OFFSCREEN. If set, this indicates + to GTK+ that the widget is not to be considered + viewable regardless of its map state. Queued draws + on offscreen widgets are suppressed. + + Added new function static gtk_widget_is_offscreen() to + check this flag on a widget and its ancestors. + + * gtk/gtklayout.[ch]: Major revisions. + + - Use gdk_window_set_static_gravities to set static gravity + on all child windows, and thus avoid having to create a window + for NO_WINDOW children. + + - Adjust allocations of children as we scroll them + so queued draws work correctly. + + - Don't allocate our children directly in a put() + or move(); just queue a resize() like every other + widget. + + * gtk/testgtk.c: Make the arrows on the scrollbars + work, create a larger and more demanding test. + Wed Jan 27 09:19:07 1999 Tim Janik <timj@gtk.org> * gdk/gdkcolor.c (gdk_colormap_unref): assert ref_count>0. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index dfe5b34ce..0e49fdab4 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,43 @@ +Wed Jan 20 11:19:00 1999 Owen Taylor <otaylor@redhat.com> + + * gtk/gtklabel.c: Use floor() instead of truncating + to integer values so we get translation invariance. + + * gtk/gtklayout.c (gtk_layout_size_allocate): Set upper + and lower values for adjustments in size_allocate(). + + * gdk/gdkwindow.c gdk/gdk.h gdk/gdkprivate.h: New + function gdk_window_set_static_gravities() to set + up a window for guffaw scrolling. + + * gdk/gdkwindow.c (gdk_window_internal_destroy): Set flags + indicating destroyed state before cleanup. + + * gtk/gtkprivate.h gtk/gtkwidget.c: Add a new + private flag IS_OFFSCREEN. If set, this indicates + to GTK+ that the widget is not to be considered + viewable regardless of its map state. Queued draws + on offscreen widgets are suppressed. + + Added new function static gtk_widget_is_offscreen() to + check this flag on a widget and its ancestors. + + * gtk/gtklayout.[ch]: Major revisions. + + - Use gdk_window_set_static_gravities to set static gravity + on all child windows, and thus avoid having to create a window + for NO_WINDOW children. + + - Adjust allocations of children as we scroll them + so queued draws work correctly. + + - Don't allocate our children directly in a put() + or move(); just queue a resize() like every other + widget. + + * gtk/testgtk.c: Make the arrows on the scrollbars + work, create a larger and more demanding test. + Wed Jan 27 09:19:07 1999 Tim Janik <timj@gtk.org> * gdk/gdkcolor.c (gdk_colormap_unref): assert ref_count>0. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index dfe5b34ce..0e49fdab4 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,43 @@ +Wed Jan 20 11:19:00 1999 Owen Taylor <otaylor@redhat.com> + + * gtk/gtklabel.c: Use floor() instead of truncating + to integer values so we get translation invariance. + + * gtk/gtklayout.c (gtk_layout_size_allocate): Set upper + and lower values for adjustments in size_allocate(). + + * gdk/gdkwindow.c gdk/gdk.h gdk/gdkprivate.h: New + function gdk_window_set_static_gravities() to set + up a window for guffaw scrolling. + + * gdk/gdkwindow.c (gdk_window_internal_destroy): Set flags + indicating destroyed state before cleanup. + + * gtk/gtkprivate.h gtk/gtkwidget.c: Add a new + private flag IS_OFFSCREEN. If set, this indicates + to GTK+ that the widget is not to be considered + viewable regardless of its map state. Queued draws + on offscreen widgets are suppressed. + + Added new function static gtk_widget_is_offscreen() to + check this flag on a widget and its ancestors. + + * gtk/gtklayout.[ch]: Major revisions. + + - Use gdk_window_set_static_gravities to set static gravity + on all child windows, and thus avoid having to create a window + for NO_WINDOW children. + + - Adjust allocations of children as we scroll them + so queued draws work correctly. + + - Don't allocate our children directly in a put() + or move(); just queue a resize() like every other + widget. + + * gtk/testgtk.c: Make the arrows on the scrollbars + work, create a larger and more demanding test. + Wed Jan 27 09:19:07 1999 Tim Janik <timj@gtk.org> * gdk/gdkcolor.c (gdk_colormap_unref): assert ref_count>0. @@ -227,6 +227,11 @@ void gdk_window_merge_child_shapes (GdkWindow *window); gboolean gdk_window_is_visible (GdkWindow *window); gboolean gdk_window_is_viewable (GdkWindow *window); +/* Set static bit gravity on the parent, and static + * window gravity on all children. + */ +gboolean gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static); /* * The following function adds a global filter for all client * messages of type message_type diff --git a/gdk/gdkprivate.h b/gdk/gdkprivate.h index 42b6a5ea4..00232970b 100644 --- a/gdk/gdkprivate.h +++ b/gdk/gdkprivate.h @@ -64,6 +64,7 @@ struct _GdkWindowPrivate guint ref_count; guint destroyed : 2; guint mapped : 1; + guint guffaw_gravity : 1; gint extension_events; diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 7cdde55dc..601c74894 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -69,6 +69,10 @@ const int gdk_event_mask_table[20] = }; const int gdk_nevent_masks = sizeof(gdk_event_mask_table)/sizeof(int); +/* Forward declarations */ +static gboolean gdk_window_gravity_works (void); +static void gdk_window_set_static_win_gravity (GdkWindow *window, + gboolean on); static gboolean gdk_window_have_shape_ext (void); /* internal function created for and used by gdk_window_xid_at_coords */ @@ -274,12 +278,10 @@ gdk_window_new (GdkWindow *parent, private->parent = parent; - if (parent_private) - parent_private->children = g_list_prepend (parent_private->children, window); - private->xdisplay = parent_display; private->destroyed = FALSE; private->mapped = FALSE; + private->guffaw_gravity = FALSE; private->resize_count = 0; private->ref_count = 1; xattributes_mask = 0; @@ -322,13 +324,21 @@ gdk_window_new (GdkWindow *parent, if (xattributes.event_mask) xattributes_mask |= CWEventMask; - if(attributes_mask & GDK_WA_NOREDIR) { - xattributes.override_redirect = + if (attributes_mask & GDK_WA_NOREDIR) + { + xattributes.override_redirect = (attributes->override_redirect == FALSE)?False:True; - xattributes_mask |= CWOverrideRedirect; - } else + xattributes_mask |= CWOverrideRedirect; + } + else xattributes.override_redirect = False; + if (parent_private && parent_private->guffaw_gravity) + { + xattributes.win_gravity = StaticGravity; + xattributes_mask |= CWWinGravity; + } + if (attributes->wclass == GDK_INPUT_OUTPUT) { class = InputOutput; @@ -409,6 +419,9 @@ gdk_window_new (GdkWindow *parent, (attributes->cursor) : NULL)); + if (parent_private) + parent_private->children = g_list_prepend (parent_private->children, window); + switch (private->window_type) { case GDK_WINDOW_DIALOG: @@ -523,6 +536,7 @@ gdk_window_foreign_new (guint32 anid) private->window_type = GDK_WINDOW_FOREIGN; private->destroyed = FALSE; private->mapped = (attrs.map_state != IsUnmapped); + private->guffaw_gravity = FALSE; private->extension_events = 0; private->colormap = NULL; @@ -877,8 +891,13 @@ gdk_window_reparent (GdkWindow *window, if (old_parent_private) old_parent_private->children = g_list_remove (old_parent_private->children, window); - parent_private->children = g_list_prepend (parent_private->children, window); + + if ((old_parent_private && + (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) || + (!old_parent_private && parent_private->guffaw_gravity)) + gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity); + parent_private->children = g_list_prepend (parent_private->children, window); } void @@ -2547,3 +2566,136 @@ gdk_drawable_set_data (GdkDrawable *drawable, { g_dataset_set_data_full (drawable, key, data, destroy_func); } + + +/* Support for windows that can be guffaw-scrolled + * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt) + */ + +static gboolean +gdk_window_gravity_works (void) +{ + enum { UNKNOWN, NO, YES }; + static gint gravity_works = UNKNOWN; + + if (gravity_works == UNKNOWN) + { + 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)) + { + gravity_works = NO; + 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); + + gdk_window_set_static_win_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); + + gravity_works = ((y == -20) ? YES : NO); + } + + return (gravity_works == YES); +} + +static void +gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + XSetWindowAttributes xattributes; + + g_return_if_fail (window != NULL); + + xattributes.bit_gravity = on ? StaticGravity : ForgetGravity; + XChangeWindowAttributes (private->xdisplay, + private->xwindow, + CWBitGravity, &xattributes); +} + +static void +gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + XSetWindowAttributes xattributes; + + g_return_if_fail (window != NULL); + + xattributes.win_gravity = on ? StaticGravity : NorthWestGravity; + + XChangeWindowAttributes (private->xdisplay, + private->xwindow, + CWWinGravity, &xattributes); +} + +/************************************************************* + * gdk_window_set_static_gravities: + * Set the bit gravity of the given window to static, + * and flag it so all children get static subwindow + * gravity. + * arguments: + * window: window for which to set static gravity + * use_static: Whether to turn static gravity on or off. + * results: + * Does the XServer support static gravity? + *************************************************************/ + +gboolean +gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GList *tmp_list; + + g_return_val_if_fail (window != NULL, FALSE); + + if (!use_static == !private->guffaw_gravity) + return TRUE; + + if (use_static && !gdk_window_gravity_works ()) + return FALSE; + + private->guffaw_gravity = use_static; + + gdk_window_set_static_bit_gravity (window, use_static); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_set_static_win_gravity (window, use_static); + + tmp_list = tmp_list->next; + } + + return TRUE; +} diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index 7cdde55dc..601c74894 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -69,6 +69,10 @@ const int gdk_event_mask_table[20] = }; const int gdk_nevent_masks = sizeof(gdk_event_mask_table)/sizeof(int); +/* Forward declarations */ +static gboolean gdk_window_gravity_works (void); +static void gdk_window_set_static_win_gravity (GdkWindow *window, + gboolean on); static gboolean gdk_window_have_shape_ext (void); /* internal function created for and used by gdk_window_xid_at_coords */ @@ -274,12 +278,10 @@ gdk_window_new (GdkWindow *parent, private->parent = parent; - if (parent_private) - parent_private->children = g_list_prepend (parent_private->children, window); - private->xdisplay = parent_display; private->destroyed = FALSE; private->mapped = FALSE; + private->guffaw_gravity = FALSE; private->resize_count = 0; private->ref_count = 1; xattributes_mask = 0; @@ -322,13 +324,21 @@ gdk_window_new (GdkWindow *parent, if (xattributes.event_mask) xattributes_mask |= CWEventMask; - if(attributes_mask & GDK_WA_NOREDIR) { - xattributes.override_redirect = + if (attributes_mask & GDK_WA_NOREDIR) + { + xattributes.override_redirect = (attributes->override_redirect == FALSE)?False:True; - xattributes_mask |= CWOverrideRedirect; - } else + xattributes_mask |= CWOverrideRedirect; + } + else xattributes.override_redirect = False; + if (parent_private && parent_private->guffaw_gravity) + { + xattributes.win_gravity = StaticGravity; + xattributes_mask |= CWWinGravity; + } + if (attributes->wclass == GDK_INPUT_OUTPUT) { class = InputOutput; @@ -409,6 +419,9 @@ gdk_window_new (GdkWindow *parent, (attributes->cursor) : NULL)); + if (parent_private) + parent_private->children = g_list_prepend (parent_private->children, window); + switch (private->window_type) { case GDK_WINDOW_DIALOG: @@ -523,6 +536,7 @@ gdk_window_foreign_new (guint32 anid) private->window_type = GDK_WINDOW_FOREIGN; private->destroyed = FALSE; private->mapped = (attrs.map_state != IsUnmapped); + private->guffaw_gravity = FALSE; private->extension_events = 0; private->colormap = NULL; @@ -877,8 +891,13 @@ gdk_window_reparent (GdkWindow *window, if (old_parent_private) old_parent_private->children = g_list_remove (old_parent_private->children, window); - parent_private->children = g_list_prepend (parent_private->children, window); + + if ((old_parent_private && + (!old_parent_private->guffaw_gravity != !parent_private->guffaw_gravity)) || + (!old_parent_private && parent_private->guffaw_gravity)) + gdk_window_set_static_win_gravity (window, parent_private->guffaw_gravity); + parent_private->children = g_list_prepend (parent_private->children, window); } void @@ -2547,3 +2566,136 @@ gdk_drawable_set_data (GdkDrawable *drawable, { g_dataset_set_data_full (drawable, key, data, destroy_func); } + + +/* Support for windows that can be guffaw-scrolled + * (See http://www.gtk.org/~otaylor/whitepapers/guffaw-scrolling.txt) + */ + +static gboolean +gdk_window_gravity_works (void) +{ + enum { UNKNOWN, NO, YES }; + static gint gravity_works = UNKNOWN; + + if (gravity_works == UNKNOWN) + { + 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)) + { + gravity_works = NO; + 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); + + gdk_window_set_static_win_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); + + gravity_works = ((y == -20) ? YES : NO); + } + + return (gravity_works == YES); +} + +static void +gdk_window_set_static_bit_gravity (GdkWindow *window, gboolean on) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + XSetWindowAttributes xattributes; + + g_return_if_fail (window != NULL); + + xattributes.bit_gravity = on ? StaticGravity : ForgetGravity; + XChangeWindowAttributes (private->xdisplay, + private->xwindow, + CWBitGravity, &xattributes); +} + +static void +gdk_window_set_static_win_gravity (GdkWindow *window, gboolean on) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + XSetWindowAttributes xattributes; + + g_return_if_fail (window != NULL); + + xattributes.win_gravity = on ? StaticGravity : NorthWestGravity; + + XChangeWindowAttributes (private->xdisplay, + private->xwindow, + CWWinGravity, &xattributes); +} + +/************************************************************* + * gdk_window_set_static_gravities: + * Set the bit gravity of the given window to static, + * and flag it so all children get static subwindow + * gravity. + * arguments: + * window: window for which to set static gravity + * use_static: Whether to turn static gravity on or off. + * results: + * Does the XServer support static gravity? + *************************************************************/ + +gboolean +gdk_window_set_static_gravities (GdkWindow *window, + gboolean use_static) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)window; + GList *tmp_list; + + g_return_val_if_fail (window != NULL, FALSE); + + if (!use_static == !private->guffaw_gravity) + return TRUE; + + if (use_static && !gdk_window_gravity_works ()) + return FALSE; + + private->guffaw_gravity = use_static; + + gdk_window_set_static_bit_gravity (window, use_static); + + tmp_list = private->children; + while (tmp_list) + { + gdk_window_set_static_win_gravity (window, use_static); + + tmp_list = tmp_list->next; + } + + return TRUE; +} diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c index e32efbac3..7c3fc744e 100644 --- a/gtk/gtklabel.c +++ b/gtk/gtklabel.c @@ -15,6 +15,7 @@ * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include <math.h> #include <string.h> #include "gtklabel.h" #include "gdk/gdkkeysyms.h" @@ -926,14 +927,14 @@ gtk_label_expose (GtkWidget *widget, gdk_gc_set_clip_rectangle (widget->style->white_gc, &event->area); gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state], &event->area); - x = widget->allocation.x + misc->xpad + - (widget->allocation.width - label->max_width - 2 * misc->xpad) - * misc->xalign + 0.5; + x = floor (widget->allocation.x + misc->xpad + + ((widget->allocation.width - label->max_width - 2 * misc->xpad) + * misc->xalign) + 0.5); - y = (widget->allocation.y - + (widget->allocation.height - - widget->requisition.height) * misc->yalign - + misc->ypad + 0.5); + y = floor (widget->allocation.y + + (widget->allocation.height + - widget->requisition.height) * misc->yalign + + misc->ypad + 0.5); for (word = label->words; word; word = word->next) { gchar save = word->beginning[word->length]; diff --git a/gtk/gtklayout.c b/gtk/gtklayout.c index e9c90ebd4..5aeace76b 100644 --- a/gtk/gtklayout.c +++ b/gtk/gtklayout.c @@ -23,8 +23,25 @@ #include "gtklayout.h" #include "gtksignal.h" +#include "gtkprivate.h" #include "gdk/gdkx.h" +typedef struct _GtkLayoutAdjData GtkLayoutAdjData; +typedef struct _GtkLayoutChild GtkLayoutChild; + +struct _GtkLayoutAdjData { + gint dx; + gint dy; +}; + +struct _GtkLayoutChild { + GtkWidget *widget; + gint x; + gint y; +}; + +#define IS_ONSCREEN(x,y) ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && \ + (y >= G_MINSHORT) && (y <= G_MAXSHORT)) static void gtk_layout_class_init (GtkLayoutClass *class); static void gtk_layout_init (GtkLayout *layout); @@ -51,13 +68,20 @@ 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); + GtkLayoutChild *child); +static void gtk_layout_allocate_child (GtkLayout *layout, + GtkLayoutChild *child); static void gtk_layout_position_children (GtkLayout *layout); +static void gtk_layout_adjust_allocations_recurse (GtkWidget *widget, + gpointer cb_data); +static void gtk_layout_adjust_allocations (GtkLayout *layout, + gint dx, + gint dy); + + + static void gtk_layout_expose_area (GtkLayout *layout, gint x, gint y, @@ -74,10 +98,18 @@ static GdkFilterReturn gtk_layout_main_filter (GdkXEvent *gdk_xevent, static gboolean gtk_layout_gravity_works (void); static void gtk_layout_set_static_gravity (GdkWindow *win, - gboolean op); + gboolean is_parent, + gboolean on); + +static void gtk_layout_add_child_cb (GdkWindow *parent, + GdkWindow *child, + gpointer data); +static void gtk_layout_remove_child_cb (GdkWindow *parent, + GdkWindow *child, + gpointer data); + static GtkWidgetClass *parent_class = NULL; -static gboolean gravity_works; /* Public interface */ @@ -209,24 +241,33 @@ gtk_layout_put (GtkLayout *layout, 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); gtk_widget_set_parent (child_widget, GTK_WIDGET (layout)); + if (GTK_WIDGET_REALIZED (layout)) + gtk_widget_set_parent_window (child->widget, layout->bin_window); - gtk_widget_size_request (child->widget, &child->widget->requisition); - - if (GTK_WIDGET_REALIZED (layout) && - !GTK_WIDGET_REALIZED (child_widget)) - gtk_layout_realize_child (layout, child); + if (!IS_ONSCREEN (x, y)) + GTK_PRIVATE_SET_FLAG (child_widget, GTK_IS_OFFSCREEN); - gtk_layout_position_child (layout, child, TRUE); + if (GTK_WIDGET_VISIBLE (layout)) + { + if (GTK_WIDGET_REALIZED (layout) && + !GTK_WIDGET_REALIZED (child_widget)) + gtk_widget_realize (child_widget); + + if (GTK_WIDGET_MAPPED (layout) && + !GTK_WIDGET_MAPPED (child_widget)) + gtk_widget_map (child_widget); + } + + if (GTK_WIDGET_VISIBLE (child_widget) && GTK_WIDGET_VISIBLE (layout)) + gtk_widget_queue_resize (child_widget); } void @@ -245,15 +286,18 @@ gtk_layout_move (GtkLayout *layout, while (tmp_list) { child = tmp_list->data; + tmp_list = tmp_list->next; + if (child->widget == child_widget) { child->x = x; child->y = y; - - gtk_layout_position_child (layout, child, TRUE); + + if (GTK_WIDGET_VISIBLE (child_widget) && GTK_WIDGET_VISIBLE (layout)) + gtk_widget_queue_resize (child_widget); + return; } - tmp_list = tmp_list->next; } } @@ -353,8 +397,6 @@ gtk_layout_class_init (GtkLayoutClass *class) gtk_marshal_NONE__POINTER_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT); - gravity_works = gtk_layout_gravity_works (); - container_class->remove = gtk_layout_remove; container_class->forall = gtk_layout_forall; @@ -417,15 +459,13 @@ gtk_layout_realize (GtkWidget *widget) attributes.x = 0; attributes.y = 0; - attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask = GDK_EXPOSURE_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); @@ -433,15 +473,15 @@ gtk_layout_realize (GtkWidget *widget) gdk_window_add_filter (widget->window, gtk_layout_main_filter, layout); gdk_window_add_filter (layout->bin_window, gtk_layout_filter, layout); + layout->gravity_works = gdk_window_set_static_gravities (layout->bin_window, TRUE); + 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); } } @@ -462,17 +502,14 @@ gtk_layout_map (GtkWidget *widget) 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)) + if (!GTK_WIDGET_MAPPED (child->widget) && + !GTK_WIDGET_IS_OFFSCREEN (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); @@ -482,7 +519,6 @@ gtk_layout_map (GtkWidget *widget) static void gtk_layout_unrealize (GtkWidget *widget) { - GList *tmp_list; GtkLayout *layout; g_return_if_fail (widget != NULL); @@ -490,41 +526,14 @@ gtk_layout_unrealize (GtkWidget *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); - child->window = NULL; - } - - tmp_list = tmp_list->next; - } - if (GTK_WIDGET_CLASS (parent_class)->unrealize) (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } -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); -} - static void gtk_layout_size_request (GtkWidget *widget, GtkRequisition *requisition) @@ -545,9 +554,9 @@ gtk_layout_size_request (GtkWidget *widget, while (tmp_list) { GtkLayoutChild *child = tmp_list->data; - gtk_widget_size_request (child->widget, &child->widget->requisition); - tmp_list = tmp_list->next; + + gtk_widget_size_request (child->widget, &child->widget->requisition); } } @@ -570,9 +579,10 @@ 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_position_child (layout, child); + gtk_layout_allocate_child (layout, child); } if (GTK_WIDGET_REALIZED (widget)) @@ -587,36 +597,73 @@ gtk_layout_size_allocate (GtkWidget *widget, layout->hadjustment->page_size = allocation->width; layout->hadjustment->page_increment = allocation->width / 2; + layout->hadjustment->lower = 0; + layout->hadjustment->upper = 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 = layout->height; gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); } +static void +gtk_layout_draw (GtkWidget *widget, GdkRectangle *area) +{ + GList *tmp_list; + GtkLayout *layout; + GdkRectangle child_area; + + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_LAYOUT (widget)); + + layout = GTK_LAYOUT (widget); + + /* We don't have any way of telling themes about this properly, + * so we just assume a background pixmap + */ + if (!GTK_WIDGET_APP_PAINTABLE (widget)) + gdk_window_clear_area (layout->bin_window, + area->x, area->y, area->width, area->height); + + tmp_list = layout->children; + while (tmp_list) + { + GtkLayoutChild *child = tmp_list->data; + tmp_list = tmp_list->next; + + if (gtk_widget_intersect (child->widget, area, &child_area)) + gtk_widget_draw (child->widget, &child_area); + } +} + static gint gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event) { GList *tmp_list; GtkLayout *layout; + GdkEventExpose child_event; 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; + + child_event = *event; + if (GTK_WIDGET_DRAWABLE (child->widget) && + GTK_WIDGET_NO_WINDOW (child->widget) && + gtk_widget_intersect (child->widget, &event->area, &child_event.area)) + gtk_widget_event (child->widget, (GdkEvent*) &child_event); } return FALSE; @@ -648,21 +695,14 @@ 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); g_list_free_1 (tmp_list); g_free (child); } + + GTK_PRIVATE_UNSET_FLAG (widget, GTK_IS_OFFSCREEN); } static void @@ -695,125 +735,52 @@ gtk_layout_forall (GtkContainer *container, */ static void -gtk_layout_realize_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); - - if (gravity_works) - gtk_layout_set_static_gravity (child->window ? child->window : child->widget->window, TRUE); -} - -static void gtk_layout_position_child (GtkLayout *layout, - GtkLayoutChild *child, - gboolean force_allocate) + GtkLayoutChild *child) { 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 (IS_ONSCREEN (x,y)) { - if (!child->mapped) + if (GTK_WIDGET_MAPPED (layout) && + GTK_WIDGET_VISIBLE (child->widget)) { - 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 (!GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_map (child->widget); } - - 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); - } + if (GTK_WIDGET_IS_OFFSCREEN (child->widget)) + GTK_PRIVATE_UNSET_FLAG (child->widget, GTK_IS_OFFSCREEN); } 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); - } + if (!GTK_WIDGET_IS_OFFSCREEN (child->widget)) + GTK_PRIVATE_SET_FLAG (child->widget, GTK_IS_OFFSCREEN); + + if (GTK_WIDGET_MAPPED (child->widget)) + gtk_widget_unmap (child->widget); } } static void +gtk_layout_allocate_child (GtkLayout *layout, + GtkLayoutChild *child) +{ + GtkAllocation allocation; + + allocation.x = child->x - layout->xoffset; + allocation.y = child->y - layout->yoffset; + allocation.width = child->widget->requisition.width; + allocation.height = child->widget->requisition.height; + + gtk_widget_size_allocate (child->widget, &allocation); +} + +static void gtk_layout_position_children (GtkLayout *layout) { GList *tmp_list; @@ -821,9 +788,54 @@ gtk_layout_position_children (GtkLayout *layout) tmp_list = layout->children; while (tmp_list) { - gtk_layout_position_child (layout, tmp_list->data, FALSE); + GtkLayoutChild *child = tmp_list->data; + tmp_list = tmp_list->next; + + gtk_layout_position_child (layout, child); + } +} + +static void +gtk_layout_adjust_allocations_recurse (GtkWidget *widget, + gpointer cb_data) +{ + GtkLayoutAdjData *data = cb_data; + widget->allocation.x += data->dx; + widget->allocation.y += data->dy; + + if (GTK_WIDGET_NO_WINDOW (widget) && + GTK_IS_CONTAINER (widget)) + gtk_container_forall (GTK_CONTAINER (widget), + gtk_layout_adjust_allocations_recurse, + cb_data); +} + +static void +gtk_layout_adjust_allocations (GtkLayout *layout, + gint dx, + gint dy) +{ + GList *tmp_list; + GtkLayoutAdjData data; + + data.dx = dx; + data.dy = dy; + + tmp_list = layout->children; + while (tmp_list) + { + GtkLayoutChild *child = tmp_list->data; tmp_list = tmp_list->next; + + child->widget->allocation.x += dx; + child->widget->allocation.y += dy; + + if (GTK_WIDGET_NO_WINDOW (child->widget) && + GTK_IS_CONTAINER (child->widget)) + gtk_container_forall (GTK_CONTAINER (child->widget), + gtk_layout_adjust_allocations_recurse, + &data); } } @@ -856,9 +868,6 @@ gtk_layout_expose_area (GtkLayout *layout, } /* 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 @@ -866,7 +875,7 @@ gtk_layout_expose_predicate (Display *display, XEvent *xevent, XPointer arg) { - if ((xevent->type == Expose) || (xevent->type == GravityNotify) || + if ((xevent->type == Expose) || ((xevent->xany.window == *(Window *)arg) && (xevent->type == ConfigureNotify))) return True; @@ -926,9 +935,11 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, return; } + gtk_layout_adjust_allocations (layout, -dx, -dy); + if (dx > 0) { - if (gravity_works) + if (layout->gravity_works) { gdk_window_resize (layout->bin_window, widget->allocation.width + dx, @@ -945,14 +956,14 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, } gtk_layout_expose_area (layout, - widget->allocation.width - dx, + MAX ((gint)widget->allocation.width - dx, 0), 0, - dx, + MIN (dx, widget->allocation.width), widget->allocation.height); } else if (dx < 0) { - if (gravity_works) + if (layout->gravity_works) { gdk_window_move_resize (layout->bin_window, dx, 0, @@ -971,13 +982,13 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, gtk_layout_expose_area (layout, 0, 0, - -dx, + MIN (-dx, widget->allocation.width), widget->allocation.height); } if (dy > 0) { - if (gravity_works) + if (layout->gravity_works) { gdk_window_resize (layout->bin_window, widget->allocation.width, @@ -995,13 +1006,13 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, gtk_layout_expose_area (layout, 0, - widget->allocation.height - dy, + MAX ((gint)widget->allocation.height - dy, 0), widget->allocation.width, - dy); + MIN (dy, widget->allocation.width)); } else if (dy < 0) { - if (gravity_works) + if (layout->gravity_works) { gdk_window_move_resize (layout->bin_window, 0, dy, @@ -1020,7 +1031,7 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, 0, 0, widget->allocation.height, - -dy); + MIN (-dy, (gint)widget->allocation.width)); } gtk_layout_position_children (layout); @@ -1037,6 +1048,7 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, */ gdk_flush(); + g_print ("==== %d =====\n", XPending(GDK_DISPLAY())); while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (layout->bin_window), &xevent, gtk_layout_expose_predicate, @@ -1045,6 +1057,8 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, GdkEvent event; GtkWidget *event_widget; + g_print ("#"); + if ((xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window)) && (gtk_layout_filter (&xevent, &event, layout) == GDK_FILTER_REMOVE)) continue; @@ -1070,6 +1084,7 @@ gtk_layout_adjustment_changed (GtkAdjustment *adjustment, } } } + g_print ("\n"); } /* The main event filter. Actually, we probably don't really need @@ -1111,7 +1126,7 @@ gtk_layout_filter (GdkXEvent *gdk_xevent, break; case ConfigureNotify: - if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0)) + if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0)) { layout->configure_serial = xevent->xconfigure.serial; layout->scroll_x = xevent->xconfigure.x; @@ -1162,69 +1177,3 @@ gtk_layout_main_filter (GdkXEvent *gdk_xevent, 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); -} - diff --git a/gtk/gtklayout.h b/gtk/gtklayout.h index c7ca1d5ff..862da8b69 100644 --- a/gtk/gtklayout.h +++ b/gtk/gtklayout.h @@ -40,15 +40,6 @@ extern "C" { typedef struct _GtkLayout GtkLayout; typedef struct _GtkLayoutClass GtkLayoutClass; -typedef struct _GtkLayoutChild GtkLayoutChild; - -struct _GtkLayoutChild { - GtkWidget *widget; - GdkWindow *window; /* For NO_WINDOW widgets */ - gint x; - gint y; - gboolean mapped : 1; -}; struct _GtkLayout { GtkContainer container; @@ -72,6 +63,8 @@ struct _GtkLayout { gint scroll_y; guint freeze_count; + + guint gravity_works : 1; }; struct _GtkLayoutClass { @@ -99,13 +92,6 @@ void gtk_layout_set_size (GtkLayout *layout, guint width, guint height); -/* These disable and enable moving and repainting the scrolling window of the GtkLayout, - * respectively. If you want to update the layout's offsets but do not want it to - * repaint itself, you should use these functions. - */ -void gtk_layout_freeze (GtkLayout *layout); -void gtk_layout_thaw (GtkLayout *layout); - GtkAdjustment* gtk_layout_get_hadjustment (GtkLayout *layout); GtkAdjustment* gtk_layout_get_vadjustment (GtkLayout *layout); void gtk_layout_set_hadjustment (GtkLayout *layout, @@ -113,6 +99,17 @@ void gtk_layout_set_hadjustment (GtkLayout *layout, void gtk_layout_set_vadjustment (GtkLayout *layout, GtkAdjustment *adjustment); +/* These disable and enable moving and repainting the scrolling window + * of the GtkLayout, respectively. If you want to update the layout's + * offsets but do not want it to repaint itself, you should use these + * functions. + * + * - I don't understand these are supposed to work, so I suspect + * - they don't now. OWT 1/20/98 + */ +void gtk_layout_freeze (GtkLayout *layout); +void gtk_layout_thaw (GtkLayout *layout); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h index a71cd7316..221c207b0 100644 --- a/gtk/gtkprivate.h +++ b/gtk/gtkprivate.h @@ -39,7 +39,8 @@ typedef enum PRIVATE_GTK_RESIZE_NEEDED = 1 << 3, PRIVATE_GTK_LEAVE_PENDING = 1 << 4, PRIVATE_GTK_HAS_SHAPE_MASK = 1 << 5, - PRIVATE_GTK_IN_REPARENT = 1 << 6 + PRIVATE_GTK_IN_REPARENT = 1 << 6, + PRIVATE_GTK_IS_OFFSCREEN = 1 << 7 } GtkPrivateFlags; /* Macros for extracting a widgets private_flags from GtkWidget. @@ -52,6 +53,7 @@ typedef enum #define GTK_WIDGET_LEAVE_PENDING(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_LEAVE_PENDING) != 0) #define GTK_WIDGET_HAS_SHAPE_MASK(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_HAS_SHAPE_MASK) != 0) #define GTK_WIDGET_IN_REPARENT(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_IN_REPARENT) != 0) +#define GTK_WIDGET_IS_OFFSCREEN(obj) ((GTK_PRIVATE_FLAGS (obj) & PRIVATE_GTK_IS_OFFSCREEN) != 0) /* Macros for setting and clearing private widget flags. * we use a preprocessor string concatenation here for a clear diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index b00272d14..138dcf771 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -172,6 +172,8 @@ static void gtk_widget_set_style_internal (GtkWidget *widget, static void gtk_widget_set_style_recurse (GtkWidget *widget, gpointer client_data); +static gboolean gtk_widget_is_offscreen (GtkWidget *widget); + static GtkWidgetAuxInfo* gtk_widget_aux_info_new (void); static void gtk_widget_aux_info_destroy (GtkWidgetAuxInfo *aux_info); @@ -1214,8 +1216,13 @@ gtk_widget_queue_clear_child (GtkWidget *widget) { GtkWidget *parent; + /* We check for GTK_WIDGET_IS_OFFSCREEN (widget), + * and queue_clear_area(parent...) will check the rest of + * way up the tree with gtk_widget_is_offscreen (parent) + */ parent = widget->parent; - if (parent && GTK_WIDGET_DRAWABLE (parent)) + if (parent && GTK_WIDGET_DRAWABLE (parent) && + !GTK_WIDGET_IS_OFFSCREEN (widget)) gtk_widget_queue_clear_area (parent, widget->allocation.x, widget->allocation.y, @@ -1800,7 +1807,8 @@ gtk_widget_queue_draw_area (GtkWidget *widget, g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); - if (widget->window && gdk_window_is_viewable (widget->window)) + if (widget->window && gdk_window_is_viewable (widget->window) && + !gtk_widget_is_offscreen (widget)) gtk_widget_queue_draw_data (widget, x, y, width, height, NULL); } @@ -1810,7 +1818,8 @@ gtk_widget_queue_draw (GtkWidget *widget) g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); - if (widget->window && gdk_window_is_viewable (widget->window)) + if (widget->window && gdk_window_is_viewable (widget->window) && + !gtk_widget_is_offscreen (widget)) gtk_widget_queue_draw_data (widget, 0, 0, -1, -1, NULL); } @@ -1826,7 +1835,8 @@ gtk_widget_queue_clear_area (GtkWidget *widget, g_return_if_fail (widget != NULL); g_return_if_fail (GTK_IS_WIDGET (widget)); - if (!(widget->window && gdk_window_is_viewable (widget->window))) + if (!(widget->window && gdk_window_is_viewable (widget->window)) || + gtk_widget_is_offscreen (widget)) return; /* Find the correct widget */ @@ -4587,6 +4597,29 @@ gtk_widget_propagate_state (GtkWidget *widget, } } +/************************************************************* + * gtk_widget_is_offscreen: + * Check if a widget is "offscreen" + * arguments: + * widget: a widget + * results: + * TRUE if the widget or any of ancestors has the + * PRIVATE_GTK_WIDGET_IS_OFFSCREEN set. + *************************************************************/ + +static gboolean +gtk_widget_is_offscreen (GtkWidget *widget) +{ + while (widget) + { + if (GTK_WIDGET_IS_OFFSCREEN (widget)) + return TRUE; + widget = widget->parent; + } + + return FALSE; +} + /***************************************** * gtk_widget_aux_info_new: * diff --git a/gtk/testgtk.c b/gtk/testgtk.c index 2c14f8079..d76e0666a 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -8284,12 +8284,18 @@ void create_layout (void) layout = gtk_layout_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (scrolledwindow), layout); + + /* We set step sizes here since GtkLayout does not set + * them itself. + */ + GTK_LAYOUT (layout)->hadjustment->step_increment = 10.0; + GTK_LAYOUT (layout)->vadjustment->step_increment = 10.0; gtk_widget_set_events (layout, GDK_EXPOSURE_MASK); gtk_signal_connect (GTK_OBJECT (layout), "expose_event", GTK_SIGNAL_FUNC (layout_expose_handler), NULL); - gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 64000); + gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 128000); for (i=0 ; i < 16 ; i++) for (j=0 ; j < 16 ; j++) @@ -8304,7 +8310,7 @@ void create_layout (void) j*100, i*100); } - for (i=16; i < 640; i++) + for (i=16; i < 1280; i++) { sprintf(buf, "Button %d, %d", i, 0); if (i % 2) diff --git a/tests/testgtk.c b/tests/testgtk.c index 2c14f8079..d76e0666a 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -8284,12 +8284,18 @@ void create_layout (void) layout = gtk_layout_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (scrolledwindow), layout); + + /* We set step sizes here since GtkLayout does not set + * them itself. + */ + GTK_LAYOUT (layout)->hadjustment->step_increment = 10.0; + GTK_LAYOUT (layout)->vadjustment->step_increment = 10.0; gtk_widget_set_events (layout, GDK_EXPOSURE_MASK); gtk_signal_connect (GTK_OBJECT (layout), "expose_event", GTK_SIGNAL_FUNC (layout_expose_handler), NULL); - gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 64000); + gtk_layout_set_size (GTK_LAYOUT (layout), 1600, 128000); for (i=0 ; i < 16 ; i++) for (j=0 ; j < 16 ; j++) @@ -8304,7 +8310,7 @@ void create_layout (void) j*100, i*100); } - for (i=16; i < 640; i++) + for (i=16; i < 1280; i++) { sprintf(buf, "Button %d, %d", i, 0); if (i % 2) |