GtkScrolledWindow: vertical `AUTOMATIC` scrollbar hides content

intended use of scrollbar […]
and when the scrollbar appears, it may cover a part of the text when text lines are long

Do I understand you correctly, that you think the intended behavior of scrollbars is to hide content ? :thinking:

I would say a scrollbar should generally* not cover the content below it. A scrollable area should work like a table with two columns: content in one column, scollbar in the other. If the scrollbar is AUTOMATIC then sometimes the second column has width=0. (this seemed to be the case for GTK2, btw.)

*exceptions are of course overlay scrollbar.

Below is a concrete example. The user searches for kanji. Each letter is added to the search history on the right (which is a vbox inside a GtkScrolledWindow)

That is what I have observed. I have just searched for the app where the invisible scrollbar was so invisible to me that I missed some widgets. It is the Gnome Shell 40 Tweaks app with Appearance tab. Scrollbar is invisible by default, so it is hard to guess that there are more widgets at the bottom of the window. And when I move the mouse pointer to the right border of the window, the scrollbar becomes visible, without shifting the widgets to the left in any way. For the Tweaks tool there is no covering of widgets, as the window has a wide right border.

You’re running with some random theme, so this may not apply.

The overall design of the scroll bars in GTK is to be overlaid on top of the scrollable content. That’s the intended behaviour, as the scroll bars are just meant to exist as indicators of where you are in the overall scrollable area. They can also be used as actual scroll bar controls, which is why they change shape on hover, but that’s mostly legacy at this point—considering that pointing devices either have smooth scrolling (touchpads and touchscreens) with incremental speed, or discrete scrolling (wheels). That’s also why there are no small button targets for “line” scrolling any more.

If your widget has content that should not be covered by overlaid scroll bars, you should add CSS or widget margin around the scrollable content. Most definitely, you should not mess with the size request of the scrolled window, as that has no bearing over the scroll bars.

You’re running with some random theme, so this may not apply.

I’m running Greybird on XUbuntu.

Given what you said, shouldn’t GTK_POLICY_ALWAYS follow the same logic then?

The appearance of the scroll bars don’t depend on the policy. The policy only controls the visibility of the scroll bar in relation to the scrollable content. ALWAYS means “show the scroll bars even if the scrollable content is entirely contained in the scrolled window allocation”. By default, that means that the scroll bars will stick on top of the content—which means if you set ALWAYS you’ll also have to compensate with your own margin/padding in a way that looks good for your UI. GTK can’t know what “looks good” for you.

As a side note: there’s really no reason why you should use ALWAYS instead of AUTOMATIC. The ALWAYS value existed because scroll bars appearing would resize the scrolled window and/or the content, back when scroll bars were not overlaid on top of the content. That’s why the default policy is AUTOMATIC.

which means if you set ALWAYS you’ll also have to compensate with your own margin/padding

That’s a very valuable insight!
Here on Gtk 3.24, ALWAYS policy reserves special space for the scrollbar - i.e. my expected behavior. But if I understand you right, that is merely a coincidence and I cannot count on that.

you’ll also have to compensate with your own margin/padding in a way that looks good for your UI

Can you tell me how I would style it so it won’t overlap with the content, then?

I’m playing around a little with the CSS, but I can’t get it to work. Even setting opacity of the scrollbar to 0 would leave an overlapping grey area (see picture).

image

edit: Maybe what you (two) meant was:

  1. The scrollbar is supposed to overlay.
  2. It’s the theme’s responsibility to make it properly.

However, this still leaves me puzzled on what’s happening in the screenshot above.

Have you considered using GtkScrollbar for the task itself, i.e. for scrolling the box with buttons? Then you have more control over the appearance, and would probably get the expected behaviour.

Have you considered using GtkScrollbar for the task itself

Yes, I’ve been working on this since yesterday. So far my solution seems to work well. For reference I post the code here.

static gboolean
adj_page_sizechanged (GtkAdjustment *adjustment,
                      GdkEvent      *unused,
                      GtkScrollbar  *scrollbar)
{
  gdouble maxValue = gtk_adjustment_get_upper (adjustment);
  gdouble maxSize = gtk_adjustment_get_page_size  (adjustment);

  gboolean show = (maxValue - maxSize >= 0.000001);
  g_object_set (scrollbar, "visible", show, NULL);
  return FALSE;
}



/**
 *  Creates a `automatic` scollbar for `widget`, that will never
 *  overlay (hide) the content of `widget`.
 *  The default behaviour in GTK is overlaying (and possibly hiding)
 *  the content.
 *
 **/
GtkWidget *
gtkx_scrollable_widget_vertical_new (GtkWidget     *widget,
                                     GtkAdjustment *adjustment_nullable)
{
  GtkWidget *root = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);

  // setup adjustment
  GtkAdjustment * adj_v = adjustment_nullable;
  if (NULL == adj_v)
    adj_v = gtk_adjustment_new (0,0,100,1,10,10);

  // setup scrollbar
  {
    GtkWidget * scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, adj_v);
    g_signal_connect(adj_v, "notify::page-size", G_CALLBACK (adj_page_sizechanged), scrollbar);
    gtk_box_pack_end (GTK_BOX (root), scrollbar, FALSE, FALSE, 0);
  }


  // setup scrollable area
  {
    GtkWidget * scrolled_window = gtk_scrolled_window_new (NULL, adj_v);
    gtk_container_add (GTK_CONTAINER (scrolled_window), widget);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
                                  GTK_POLICY_NEVER, GTK_POLICY_EXTERNAL);
    gtk_box_pack_start (GTK_BOX (root), scrolled_window, TRUE, TRUE, 0);
  }


  return root;
}

Is it necessary to use the GtkScrolledWindow? What about making the box with buttons scrollable by inserting it into GtkViewport? Then you have less overhead.

However, I am not sure what will happen to the touch abilities then, because the documentation says: “GtkScrolledWindow has built-in support for touch devices.” This means that GtkViewport lacks this.

Well, using a Scrolled Window with an external scrollbar is much easier to program than using a GtkViewport (or at least was for me).

Btw, I think I’ve found a bug in GTK using the method above: c - GTK: hide and show a widget in a GtkBox show's the widget underneath the GtkBox - Stack Overflow

All that is very ugly. Adding more buttons by user activity is ugly, using still the legacy program style with the gtk_init() is ugly, dozens of lines of ugly C code just to show some buttons is ugly, and the screenshot pictures look ugly too – is it Windows? Such type of code has generally the high risk to not work properly for new GTK versions, and then nobody wants to touch the code to fix it. I have seen some examples of code like that in the last two decades – I would have not even been able to fix it. Well I guess you are doing what you like to do, regarding your user name, but I would have just asked someone skilled how to do it before writing more than a few lines of code or spending more than a few minutes on that all. And what do you hope for by cross posting to stack overflow. Mr. Bassi is already here.

Yes, unrelated, not helpful, but no insult intended. But I can tell my impression, which was confirmed by some of your other recent posts – closing the app when user clicks elsewhere and such. I got the impression that you just try to do strange things to confuse users and make them angry.

For your task of needing a variable, increasing number of buttons, I was just thinking of using a GtkComboboxText or a GtkListBox instead? A PopOver or HamburgerMenu may be an option maybe. A long list of Buttons wastes a lot of space, and with a scrollbar user experience is bad.

1 Like

For your Stackoverflow code example, I would guess that the reason for the strange behaviour may be your

g_object_set (scrollbar, "visible", show, NULL);

Maybe try instead

https://gnome.pages.gitlab.gnome.org/gtk/gtk4/method.Widget.hide.html

Other solutions may be to add the ScrollBar widget only when needed, or maybe use a GtkGrid as outer container.

It is definitely a theme issue because that code works fine on my Linux Mint 20.1 with its default theme.

This baffles me!
How can this be theme related?
I’m using Greybird (default on XUbuntu). Setting it to Adwaita has a milding effect on the behavior. It also seems important how big the window is in relation to the button.
Here a video:
https://youtu.be/upk9caJ51xU

I got the impression that you just try to do strange things to confuse users and make them angry.

Indeed, behavior without context might seem strange. I mostly try to abstract the problem away from my specific use case to 1) prevent comments on unrelated things and 2) reduce the amount of background information other users need to read in order to understand the problem.

Apart from that, strange behavior like with the scroll bar stays strange behavior. Yes, I might (or might not) use a ComboBox instead. But,

  1. that wouldn’t solve the actual existing problem at hand.
  2. It would lead to other edge case problems I would have with that solution (this is just a representative. There is no need to justify it, as it is only a represetative.

At the begin, I also found it strange, what you wanted to get. But we can express the intend in a more general/abstract way:

A collection of clickable elements that needs more space than it can occupy on the screen (and whose size can be changed dynamically at run time). In fact, we have lots of such cases in an application and several different ways to get the intended result.

What about your unanswered July-question, the GtkListBox probably offers what you wanted. The widget emits two different signals: if an element is selected and if an element is activated (= clicked; even if it was already selected).

1 Like

A collection of clickable elements that needs more space than it can occupy on the screen (and whose size can be changed dynamically at run time). In fact, we have lots of such cases in an application and several different ways to get the intended result.

Thank you very much for this abstraction of the problem. I’d like to add it to my first post, but unfortunately I can’t edit it.

What about your unanswered July-question, the GtkListBox probably offers what you wanted.

I’m not really sure which question you’re referring to, but as for this problem, GtkListBox did not help orI’m using it wrong - I couldn’t get it to scroll automatically so I still had to put it inside a ScrolledWindow, whicht triggers the problematic behavior again.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.