From 14724626395882260fc73ae008a9df4fe7cbd877 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Wed, 27 Jan 1999 18:21:20 +0000 Subject: Use floor() instead of truncating to integer values so we get translation Wed Jan 20 11:19:00 1999 Owen Taylor * 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. --- gdk/gdk.h | 5 ++ gdk/gdkprivate.h | 1 + gdk/gdkwindow.c | 168 +++++++++++++++++++++++++++++++++++++++++++++--- gdk/x11/gdkwindow-x11.c | 168 +++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 326 insertions(+), 16 deletions(-) (limited to 'gdk') diff --git a/gdk/gdk.h b/gdk/gdk.h index e3030b3bc..bae3ebb87 100644 --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -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; +} -- cgit v1.2.1