GtkNotebook tab does not expand to fit child widget

I am dealing with a strange problem and am hoping that someone can point me in the right direction.

I am sub-classing GtkNotebook to create my own widget, which uses complex tab labels. Instead of just a simple label, the widget tree that I have in the tab is the following:

GtkBox
    GtkOverlay
          GtkStack
                GtkLabel
                GtkProgressBar
          GtkEventBox
                GtkLabel
    GtkButton

The title of the tab is held by the GtkLabel child of the GtkEventBox and the GtkEvenBox is used to detect the mouse clicks on the label so tabs can be switched.

This all seems to work find, albeit it being a bit complex, with one exception - tabs with title text that is long are getting the title GtkLabel cut off instead of being resized to fit the label. From my tracking with GTK_DEBUG=interactive, it seems that the culprit is the GtkStack widget. At least, that is the deepest child, which has any effect on the overall tab title size when it’s changed manually. Changing the size of its children has no effect (by “size”, I mean the “[height/width]-request” property).

Can someone help me understand why parent widgets are not getting resized so the tab title is fully visible?

Anyone have an idea?

Thank you.

And when you use a plain label it is not cut off? Because from my memory, these tabs may have some fixed maximum size, and whenever label is longer, it is cut?

Yes, when using a plain label it’s not cut off. When using a plain label, the size of the tabs adjust to match the length of the longest lable.

Well, my first attempt would be to apply

https://developer.gnome.org/gtk3/stable/GtkWidget.html#gtk-widget-set-hexpand

on the involved child widgets. I used that function in

for the Scrollbars when moving from old GtkTable to new GtkGrid.

Thank you for the suggestion. I had already tried this with GTK_DEBUG=interactive but it doesn’t seem to work. Even if I set the [h|v]expand property of all of the widgets from the GtkOverlay down, there are still tabs that have their text cut off.

Hi, any pointers? Still struggling with this.

Thank you.

As no one has a great idea, the solution is quiet obvious:

  • Make a minimal example that we can test, preferable in C, not in a too exotic language

  • Divide the problem in simpler units – your original example is too nested

  • Try with different gtk version, maybe also with gtk4, and on different platforms

  • looks into gtk sources

  • hire a dev

  • avoid that GUI construct

  • use another GUI toolkit

  • avoid GUI coding at all, as it can be frustrating when it has unsolvable bugs

And yes, I know that is hard. But your goal is a bit exotic. (And I have still no solution for my problem with srollbars and drawingarea, have also spent many hours on it.)

As requested, here is the example (using Python):

#!/usr/bin/python
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, Gdk

class MyNotebook(Gtk.Notebook):
    def do_insert_page(self, child, label, menu, position):
        if self.props.tab_pos == Gtk.PositionType.LEFT:
            label.set_angle(90)
            tab_box = Gtk.VBox(2)
        elif self.props.tab_pos == Gtk.PositionType.RIGHT:
            label.set_angle(-90)
            tab_box = Gtk.Vbox(2)
        else:
            tab_box = Gtk.HBox(2)

        close_button = Gtk.Button.new_from_icon_name("window-close",
                                                     Gtk.IconSize.SMALL_TOOLBAR)

        overlay = Gtk.Overlay()
        overlay.add_overlay(label)

        if self.props.tab_pos == Gtk.PositionType.LEFT:
            tab_box.pack_start(close_button, False, False, 0)
            tab_box.pack_end(overlay, True, True, 0)
        else:
            tab_box.pack_start(overlay, True, True, 0);
            tab_box.pack_end(close_button, False, False, 0)

        tab_box.show_all()

        if not menu:
            menu = Gtk.Label(label.get_text())
        return Gtk.Notebook.do_insert_page(self, child, tab_box, menu, position)

class App:
    def __init__(self):
        window = Gtk.Window()
        window.connect("destroy", self.on_window_destroy)
        notebook = MyNotebook()

        label = Gtk.Label("This is a test page with a very long tab title")
        button = Gtk.Button("Button 1")
        notebook.append_page(button, label)

        label = Gtk.Label("Short Label")
        button = Gtk.Button("Button 2")
        notebook.append_page(button, label)

        window.add(notebook)
        window.show_all()

    def on_window_destroy(self, window):
        Gtk.main_quit()

if __name__ == "__main__":
    app = App()
    Gtk.main()

Running this should produce a window with a notebook with two tabs where the tab labels are cut off. As requested, I’ve removed some of the complexity by not adding anything to the overlay widget.

An interesting example :slight_smile:

I did a short test, works but tabs are tiny. (And I have to admit that I do not fully understand the code yet, have to read more about overlays…)

My idea was to use

https://developer.gnome.org/gtk3/stable/GtkNotebook.html#GtkNotebook--c-tab-expand

which is FALSE by default, so we can hope it may make a difference.

I tried to set it to TRUE, but it was not working for me. But maybe I did it wrong, as I have not much experience with Python. You may try that yourself.

Other idea was to replace the GtkLabel in the tab with another simple widget, to test if other widgets expand better than labels. GtkLabels may be special in some kind, as they have these ellipsize behaviour.

Can not really help you, sorry.

Hi,

Tried that with no effect. What is even more interesting is that I can’t even click on the “Close” button. It behaves as if the Gtk.Overlay is the top widget in the tab and is top of the button preventing it from receiving events.

It would be great if some Devs jump in with some pointers.

Thank you

Just as I said that, I think I figured it out. By replacing overlay.add_overlay(label) with overlay.add(label), it all works.

So, it appears that the base overlay widget is the on that determines the size of the overlay. Overlayed widgets’ size is based on that.

Great. I wish all that would be better documented. It can be really hard to figure such things out, and this low traffic forum often does not help much, as ebassi is not always available, and I think he can not know all.

I was going to suggest you that now with the fine example code you could ask at stackoverflow, because that one has much more visitors. But luckily this issue is solved now.

Please post the working code example here, so that we can remember…

Well, I was too early with my declaration. As it turns out, the issue is not solved.

The same happens with any overlayed widged as with the original label. Any overlayed widget is not made to fit within the size of the main child but rather gets cut off.

At this point, a dev is required as this seems like a bug to me. Effectively, one has to guarantee that the main child widget of a GtkOverlay is bigger (or the same size) as any of the overlayed widgets.

To be fair, the idea of shoving a GtkOverlay inside a tab-widget spot sounds pretty weird to me to begin with.

Anyway, since you have an example, feel free to open an issue.

It isn’t a bug.
It makes no sense to have any overlaying children that are as big as the main child. If all of the main widget is hidden behind another widget, then it’s pointless to put that main widget on the screen, in the first place!

GtkOverlay’s purpose is to allow a widget to obscure only a part of another widget. Therefore, all overlaying children must be smaller than the main child. An application programmer must make them smaller if it’s needed. (Only the programmer can know how much smaller. Only that one can know how much of the main widget that one wants to stay visible.)

Thank you for your response.

I am not sure that I agree with your point. According to the documentation of the “get-child-position” signal emitted by a GtkOverlay widget, the child alignment can be GTK_ALIGN_FILL, in which case, the child widget can be full height/width.

Furthermore, it doesn’t even make sense to have such a restriction. If a widget can partially block the main widget, why can’t it fully block the main widget. I get the “why show it at all” argument but consider that the overlay widget might not “block” the main widget.

For example, in my application the overlayed widget is a GtkStack, which has a empty label and a progress bar. Then I switch which part of the GtkStack is show, creating the appearance that the tab label has a progress bar that shows some activity. In this case, the main widget (the tab title label) is not really hidden.

So, I still maintain that this is a bug. If nothing else, it’s a documentation bug, although, not in my mind. I might be able to work around it using the “gtk-child-position” signal but the natural behavior definitely does not follow my expected behavior.

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