GNOME Bugzilla – Bug 1165
Handle late setting of adjustments in scrollable widgets
Last modified: 2015-06-23 11:30:54 UTC
When using a scrolled window widget (with a widget added with a viewport),
that has been realised, if new adjustments are set (with set_hadjustment()
and set_vadjustment()), then two display problems occur:
1. The X server is not informed of the new position of view on the
inserted widget, and thus sends exposure events for the wrong
part of the inserted widget.
2. The scroll bars are not redrawn correctly until they have been
unrealised and realised again.
The first problem is resolved as soon as the scroll bars are used;
things suddenly jump into the correct position. As far as I can tell
this is because only the callback from the scroll bars being adjusted
calls gdk_window_move() (which in turn informs the X server with
XWindowMove()). gdk_window_move() is not called by either
set_hadjustment() or set_vadjustment() (this is probably the best fix).
As a work around the scroll bars can be nudged (add one to the
adjustment current position, then take it off again); this is my current
work around and gives the correct display eventually (although some
unwanted redrawing is done -- this is noticeable in my instance because
the widget drawing code involves a lot of calculations and hence takes a
lot of time).
The second problem is resolved when, eg, the window is resized. As a
work around I've been turning the scroll bars off and then on again
(setting policy = NEVER, then setting policy = AUTOMATIC).
Unfortunately both the nudging and the scroll bar unrealising/realising
need to be done with the widget in the viewport realised which results
in extra redrawing. (The nudging, etc, does not take effect if the
inserted widget is not realised.)
Debian slink, with manually installed Glib 1.2.1, GTK+ 1.2.1, GTK-- 1.0.
Linux 2.2.1 kernel
Xfree86 X server (220.127.116.11a) (SVGA, for Matrox Millennium (I) card)
Using GTK-- C++ wrapper for GTK+, from C++ code, compiled with EGCS 1.1.1.
The problem appears in both 1.2.1 (which I've done most of my testing
on), and as far as I can tell in a very brief test in 1.2.2. The
1.2.1->1.2.2 patch doesn't indicate any changes in this area.
The GTK-- wrappers are simply calling the GTK+ functions directly (with
little other handling going on), and this and reading the GTK+ code are
the reason for thinking it is GTK+ not taking the correct steps.
Reproducing the bug:
Unfortunately I found these problems (and hacked around them) in the
middle of a large chunk of C++ code which I can't make available.
I also haven't yet had the time to write up a small sample program that
exhibits the problem.
As far as I can tell the problem can be repeated by:
1. Creating a scrolled window, with a suitable widget inside it that
reports on the expose events it is getting (I'm using a drawing
area), and set the scroll bar policies to AUTOMATIC.
2. Realise everything.
3. Giving the scrolled window new adjustments with a different range
(ie lower and upper) and a different value. (In my instance I'm
"zooming" so the range is normally 2-3 times as big, and the
position is scaled appropriately. But the problem seems to occur
irrespective of whether the adjustment range gets bigger or smaller.)
This should repeat the wrong-expose-events problem. The scroll bar
issue also seems to occur in the same manner, but is most obvious when
attempts at scrolling around result in scrollbars that will not "scroll"
even though based on the size of the view and the size of the widget
inside it, it should scroll. Resizing the window should "fix" this
(I realise it's a real pain not having example code that produces the
problem, and if you want to throw it back at me and say "provide an
example" then I'll do that. It just might take a while. Same with
------- Additional Comments From firstname.lastname@example.org 1999-05-05 12:06:32 ----
Subject: GTK+: Scrolled window: set new adjustments doesn't inform X server
From: Owen Taylor <email@example.com>
Cc: Ewen McNeill <firstname.lastname@example.org>
Date: 05 May 1999 12:06:32 -0400
An example program would in fact be most helpful here.
(Also, it would be preferred if it were straight
GTK+ as opposed to GTK--)
------- Additional Comments From email@example.com 1999-05-09 23:22:55 ----
Subject: Re: GTK+: Scrolled window: set new adjustments doesn't inform X server
From: Ewen McNeill <firstname.lastname@example.org>
Date: Mon, 10 May 1999 15:22:55 +1200
[This is a duplicate copy of a message that was bounced by the GTK
bug tracking service:
Hi. This is the qmail-send program at tirania.nuclecu.unam.mx.
I'm afraid I wasn't able to deliver your message to the following addresses.
This is a permanent error; I've given up. Sorry it didn't work out.
/ Unknown ticket service address owen taylor <email@example.com
Recognised addresses are:
/ General: Read # in Subject: Ticket # is NNNN:
Owen: I've BCC'd you on this message, in order to avoid confusing the
bug tracking service with your address, in case that was what had it
In message <firstname.lastname@example.org>, Owen Taylor writes:
>An example program would in fact be most helpful here.
>(Also, it would be preferred if it were straight GTK+ as opposed to GTK--)
One example, in GTK+ 1.2.1. The code is really hacked together but it
does show the problems that I reported in bug 1165, with one slight
variation: I've found it seems to be sufficient to hide/show the
_drawing_area_ (ie, contained widget) in order to get the scroll bars
drawn correctly again (previously I reported it was necessary to turn
the scroll bars off/on in the scrolled window).
The example code is loosely based on the scrolledwin demo example with
GTK+ 1.2.1, but has had bits hacked into it. It should compile with the
standard sort of Makefile for those examples, viz:
-=- cut here -=-
CC = gcc
$(CC) `gtk-config --cflags` -g scrolledwin.c -o scrolledwin `gtk-config
rm -f *.o scrolledwin
-=- cut here -=-
When compiled and run, the program displays a scrolled window containing
a drawing area, and a small control bar at the bottom. The drawing area
simply draws the position of the window in every so often across the
exposed area (makes it easy to tell what is being drawn).
The control bar contains:
1. An "adjust" button, used to set the scrolled window scroll bar
adjustments to random values (all less than 32767; an X limitation
which I haven't seen documented in the GTK docs)
2. Two checkboxes which can turn on and off the hacks I've been using:
"hide/show" -- will hide the drawing area and show it again in order
to force a repaint (I don't think this should be
necessary when the scrolled window works properly)
"nudge" -- nudges the scroll bar after setting adjustments
(done by setting the value to one more than prev
value), which forces flush of position update through
to the X server.
To see the problems I reported:
1. Compile and run the program.
Click on adjust without selecting any checkboxes.
Try the scroll bars. Note how they don't scroll any more!
2. Toggle the "hide/show" checkbox.
Click on adjust.
Note that the drawn area doesn't correspond with the area that
the scroll bars have been adjusted to.
Click on one of the scroll bars. Note how it suddenly springs
into the correct position. (For maximum effect click on the
move-by-1 arrow at the end of the scroll bar; a big jump for
moving by 1 :-) )
3. Toggle the "nudge" checkbox.
Click on "adjust".
Notice how it is now going to the correct place and redisplaying.
Situation 3 is how I believe it should behave without needing the
hide/show hack or the nudge scrollbar hack. The very act of setting the
adjustments should flush a new position thorugh to the X server.
Although doing this when they have to be set independently is possibly
unfortunate (if the widget is visible it could be double redrawn), but
it should be done at least once without any hacks required in the
If you've got any questions, etc, please feel free to get in touch.
Note that the code is a hack to demo the problem, and definitely leaks
memory, and has very poor style, because it was hacked together in a
hurry. But these shouldn't affect the thing being demonstrated.
Source code follows.
Tested with Debian Slink (2.1), with Linux 2.2.1 kernel, with Glib 1.2.1 and
GTK+ 1.2.1. C compiler is
ewen@pagoda:/src/local/niwa/libs/gtk-bugs $ gcc -v
Reading specs from /usr/lib/gcc-lib/i486-linux/18.104.22.168/specs
gcc version 22.214.171.124
Bugs also noted with GTK-- (C++ wrapper for GTK+) using GTK-- 1.0, Glib
1.2.1 and GTK+ 1.2.1, and with a very brief test of the program using
GTK-- appeared to be there with Glib 1.2.2 and GTK+ 1.2.2 (The patch to
GTK+ 1.2.2 didn't seem to affect files in the relevant areas.)
-=- cut here -=-
/* Demonstration of bug in GTK+ 1.2.1 with scrolling windows, and
* changing adjustments: (Reported as GTK bug 1165)
* 1. The X server is not informed of the new position of view on the
* inserted widget, and thus sends exposure events for the wrong
* part of the inserted widget until the scroll bars are adjusted.
* 2. The scroll bars are not redrawn correctly until they have been
* unrealised and realised again (or at least the drawing area
* hidden and shown).
* The "nudge scrollbar" toggle can be used to turn on and off the
* workaround for the first problem.
* The "show/hide" toggle can be used to turn on and off the workaround
* for the second problem.
* Hacked together by Ewen McNeill <email@example.com>, 1999/5/10,
* based on: scrolledwin example.
* NOTE: Quite a few of the bits in this code are just hacked together, with
* just enough to show what goes wrong, and it'll, eg, leak memory.
/* example-start scrolledwin scrolledwin.c */
static int show_expose = 2; /* 0 = don't; 1 = after config; 2 = always */
static GtkWidget *workaround_1_checkbox; /* Workaround one: hide/show */
static int workaround_1 = 0;
static GtkWidget *workaround_2_checkbox; /* Workaround two: nudge bar */
static int workaround_2 = 0;
static GtkWidget *scrolled_window; /* Scrolled window area */
static GtkWidget *drawing_area; /* Drawing area */
void destroy(GtkWidget *widget, gpointer data)
/* Set new adjustments for the window. We malloc the adjustments in
* order to ensure they won't get overwritten, but leak them afterwards
* for simplicity of this demo hack. (This shouldn't affect the bug.)
* The adjustments are set to random values in order to ensure they
* change each time around.
void new_adjustments(GtkWidget *widget, gpointer data)
int mx = (int)(rand()*1.0*32767.0/(RAND_MAX*1.0)); /* 0..32767 */
int my = (int)(rand()*1.0*32767.0/(RAND_MAX*1.0)); /* 0..32767 */
int px = (int)((rand()*1.0)*(mx*1.0)/(RAND_MAX*1.0)); /* 0..mx */
int py = (int)((rand()*1.0)*(my*1.0)/(RAND_MAX*1.0)); /* 0..my */
GtkAdjustment *x_adjust =
(GtkAdjustment *)gtk_adjustment_new(px, 0, mx, 1, 10, 300);
GtkAdjustment *y_adjust =
(GtkAdjustment *)gtk_adjustment_new(py, 0, my, 1, 10, 300);
GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(scrolled_window);
GtkDrawingArea *da = GTK_DRAWING_AREA(drawing_area);
printf("Adjusting X to %d/%d\n", px, mx);
printf("Adjusting Y to %d/%d\n", py, my);
gtk_drawing_area_size(da, mx, my);
/* Force a redraw (hide and show the drawing area) */
printf("Hiding and showing drawing area\n");
printf("Nudging scroll bar\n");
configure_event (GtkWidget *widget, GdkEventConfigure *event)
printf("Configuring for %dx%d\n", widget->allocation.width,
if (! show_expose)
show_expose = 1;
expose_event (GtkWidget *widget, GdkEventExpose *event)
int x, y;
int minx, miny;
int maxx, maxy;
fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
printf("Expose event for %d,%d, of size %dx%d\n",
if (show_expose < 2)
show_expose = 0;
/* Put some positioning kind of text into the window to show where
* we are in the window
minx = (event->area.x % 120 ? ((event->area.x/120)) * 120 : event->area.x);
miny = (event->area.y % 50 ? ((event->area.y/50)) * 50 : event->area.y);
maxx = event->area.x + event->area.width + 120;
maxy = event->area.y + event->area.height + 50;
for (y = miny; y < maxy; y+=50)
for (x = minx; x < maxx; x+=120)
sprintf(posstr, "%d,%d", x, y);
gdk_draw_text(widget->window, fixed_font, widget->style->black_gc,
x, y, posstr, strlen(posstr));
/* printf("Putting string [%s] at %d,%d\n", posstr, x, y); */
void toggle_workaround_1(GtkWidget *widget, gpointer data)
workaround_1 = !workaround_1;
printf("Show/Hide is now %s\n", workaround_1 ? "on" : "off");
void toggle_workaround_2(GtkWidget *widget, gpointer data)
workaround_2 = !workaround_2;
printf("Nudge Scrollbar is now %s\n", workaround_2 ? "on" : "off");
int main (int argc, char *argv)
static GtkWidget *window;
int i, j;
gtk_init (&argc, &argv);
/* Create the drawing area */
drawing_area = gtk_drawing_area_new ();
gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 600, 600);
/* Signals used to follow what is to be drawn */
gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
(GtkSignalFunc) expose_event, NULL);
(GtkSignalFunc) configure_event, NULL);
gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
/* Create a new dialog window for the scrolled window to be
* packed into. A dialog is just like a normal window except it has a
* vbox and a horizontal separator packed into it. It's just a shortcut
* for creating dialogs */
window = gtk_dialog_new ();
gtk_signal_connect (GTK_OBJECT (window), "destroy",
(GtkSignalFunc) destroy, NULL);
gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example");
gtk_container_set_border_width (GTK_CONTAINER (window), 0);
gtk_widget_set_usize(window, 300, 300);
/* create a new scrolled window. */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10);
/* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS.
* GTK_POLICY_AUTOMATIC will automatically decide whether you need
* scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars
* there. The first one is the horizontal scrollbar, the second,
* the vertical. */
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
/* The dialog window is created with a vbox packed into it. */
gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
TRUE, TRUE, 0);
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window
/* Add the control panel thingy to the bottom.
* We have an "adjust" button to activate the change, and some
* toggle flags to turn on and off the hacks that work around
* some of the problem.
button = gtk_button_new_with_label ("adjust");
gtk_signal_connect (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) new_adjustments, NULL);
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), hbox, TRUE,
workaround_1_checkbox = gtk_check_button_new_with_label("Hide/Show");
workaround_2_checkbox = gtk_check_button_new_with_label("Nudge");
workaround_1 = 0;
workaround_2 = 0;
gtk_box_pack_start(GTK_BOX(hbox), workaround_1_checkbox, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), workaround_2_checkbox, TRUE, TRUE, 0);
/* example-end */
-=- cut here -=-
------- Bug moved to this database by firstname.lastname@example.org 2001-01-27 14:46 -------
This bug was previously known as bug 1165 at http://bugs.gnome.org/
Originally filed under the gtk+ product and general component.
The original reporter (email@example.com) of this bug does not have an account here.
Reassigning to the exporter, firstname.lastname@example.org.
Reassigning to the default owner of the component, email@example.com.
The problem here is, simply, put, gtk_viewport_set_[hv]adjustment()
doesn't work after the widget is set up. This will be rather tricky
I'm moving this from the 1.2.9 milestone to the 2.0 milestone,
because it is quite hard to fix, and it's not clear that the
fix would be compatible with what people expect from 1.2.8.
All scrolled widgets need to be checked for this, not
I've made a bunch of changes now that make it behave as I
expect, though I not quite as is expected here. The thing
to realize is that for a GtkViewport, the only free variable
that can be controlled by the application is the value -
the lower/upper/max/page_size/step_size are all under the
control of the widget and are in units of pixels.
Fri Jun 6 16:25:44 2003 Owen Taylor <firstname.lastname@example.org>
* gtk/gtkviewport.c: Many fixes, along with extensive cleanups and
refactoring of code to reduce duplication; fixes include:
- gtk_viewport_realize(): Position the window correct from
values. (#110737, Michael Natterer)
- Remove some division-by-zero checks in places where there is no
longer division. (#110737)
- gtk_viewport_class_init: Make the hadjustment/vadjustment
G_PARAM_CONSTRUCT, so that there will always be adjustments, even
if gtk_viewport_new isn't used (#101135, Thomas Leonard).
- Switch over to encapsulated lazy-creation for hadjustment/
vadjustment; even with the CONSTRUCT property, we need this after
- When updating the adjustment, immediate set their values to
match the the current range of the viewport, and update the
viewport position to match the value of the new adjustments.
(Part of #1165)
"make it behave" == "make GtkViewport behave" - other scrolled
widgets still need to be fixed.
For discussion of the principles behind the changes.
I was the original bug reporter, back in 1999 (I've created a bugzilla account
just to be able to say this!).
In the interveening _five_ years I've seen dozens of reassignments of this bug
to yet another later version of GTK+ (and/or Gnome). I've long since ceased to
have anything to do with the project in which I encountered this bug (and that
project continues to work using the work around I came up with -- which is
described briefly above -- with some extra hacks to minimise the amount of
Perhaps it would be more honest to mark this bug "won't fix" at this point.
Or at least take me off the list of addresses notified of every deferrment of
this bug to a future release, as I really don't wish to receive a notification
of every single version that you have decided not to fix the bug in for yet more
Sorry, there's no way to take you off the Cc: list since you are the original
reporter. Maybe you can come up with a procmail rule or mail filter to discard
We've fixed this in *some* widgets now. It's still a legitimate TODO for
other widgets so WONTFIX'ing would be unfortunate.
Here is a list of scrollable widgets which still need to be fixed:
less important, since deprecated, are
Owens email linked above pretty clearly outlines what behaviour has to be
If this works, except for GtkCList and GtkText, shouldn't it have been closed?
I'd say so.
But does that work as expected now?
Matthias, can you confirm is this bug report is still relevant today?
My comment from 10 years ago does not say "this works, except for clist and text". But regardless, keeping this bug open for another 10 years is not going to make the world a better place.