Layout stale after adding widgets to GtkContainer, resolves on window resize

I’m struggling with an issue when I rearrange the hierarchy of widgets in a GtkWindow, to add a menu bar. There is more details in the stackoverflow post, but hopefully there are some more helpful people here.

My first guess would be that a call of gtk_widget_hide() may help, somewhere before show() call.

But maybe you should just add your menu from the beginning and hide() it when needed?

Does gtkmm code generally looks that ugly? cast and all that? I think I would even prefer plain C then.

That’s definitely not gtkmm

I’ve tried hiding a bunch of the widgets before restructuring the hierarchy and it made no difference.

Ya it’s ugly, depending on the namespace clashes I have to use the GtkCast (my own cast macro) instead of the C cast’s given by the GTK headers. But in this case the C casts work so I removed all the GtkCast uses here.

As I posted in the stackoverflow question I’ve found a “work around” that’ll have to do for the moment. After adding the GtkBox to the GtkWindow I send a signal:

GdkRectangle allocation = Wnd->GetClient();
g_signal_emit_by_name(G_OBJECT(vbox), "size-allocate", GTK_WIDGET(vbox), &allocation, NULL, NULL);

And that manages to trick the box into refreshing the layout of it’s child widgets. And the menu and root widget show up in the right place automatically.

Don’t do that, ever.

At most, you should call gtk_widget_queue_resize(), but that should happen automatically, which makes me think you’re really doing something else in your code than just adding stuff to the window. Likely, you’re blocking the main loop somewhere else, or are returning from a signal handler and telling the toolkit that you handled the event and preventing the default handler to run.

Don’t do that ever

why? What bad things ™ would happen?

I tried gtk_widget_queue_resize and it didn’t have any effect, the program went back to the old behaviour of not showing the menu till a window resize. I’m assuming that you mean I should pass the GtkBox to gtk_widget_queue_resize?

I agree, it’s probably something I’m doing elsewhere in the code. The most obvious place would be the custom LgiWidget code which comprises the widget called Wnd->_Root in this example. It’s a non standard widget that I wrote to wrap GTK stuff for my cross platform code. And it’s recently been ported from GTK2 so a bunch of stuff in there is me just figuring out who to write a custom GTK3 widget, and is probably badly written. Maybe something in the function lgi_widget_size_allocate(…)?

First of all, you must not emit signals by calling g_signal_emit() unless you’re the one calling g_signal_new()unless the signal is defined as G_SIGNAL_ACTION. This is true for all GObject signals. Since the size-allocate signal is installed by the GtkWidget class, it means you cannot emit it.

As to why: the size-allocate signal is coupled with the GtkWidgetClass.size_allocate virtual function, which is an internal detail of how widgets work; it has to happen within the layout phase of the frame, and it has to be called by the container widget on each and every child, recursively; there are constraints on when and how that function must be called, and it has to happen with a valid rectangle associated with the position and size computed by the parent widget. Widgets might size child windowing system surfaces; allocate data; and change input regions. You’re passing a random rectangle, and expect things to work.

I don’t even know what Wnd->GetClient(); even is.

Your code example on StackOverflow—which you should have at least copied here, to avoid going on SO—does not tell the whole story on what you’re trying to achieve. The screenshot seems to indicate that you’re trying to embed some other UI control into your GTK application, which is questionable at best.

You will need to provide more context on what you’re doing.

You should drop GTK2 support: it makes the code messy and masks issues. GTK2 is in deep maintenance mode; it’s unsupported, and won’t be released any more after GTK4 is released; and GTK3 has been released and stable longer than the whole GTK2 release cycle.

For instance, you have a block for GTK3 and one of GTK2 in your size_allocate function, but in the GTK2 block you’re still testing for GTK3, which simply cannot happen.

Your GTK3 code just moves the child window around, but child windows in GTK3 are not needed; if you want to detect input events, you should use a GDK_INPUT_ONLY window, not a GDK_WINDOW_CHILD.

On top of that, you’re mixing type system API from GTK1 (gtk_type_unique()) with GTK2, so it means you’re literally calling API that has been deprecated for nearly 20 years, making the code base even more messy.

The real problem, though, is that you’re calling gtk_widget_size_allocate() inside the map() implementation, when that should not happen; gtk_widget_size_allocate() should only ever be used inside a size_allocate() implementation. You’re forcing an allocation on map, which is not what map() is for.

GTK3 has a well-defined sequence of steps performed in each frame; additionally, like GTK1 and GTK2 before it, it has a well-defined sequence of events that go from widget construction to its appearance on screen:

  1. widgets are set to be visible by the user with gtk_widget_show()
  2. widgets are realized, either recursively on their first frame, or explicitly via gtk_widget_realize(); the widget implementation is responsible for creating windowing system resources, like a GdkWindow
  3. widgets are mapped
  4. widgets are laid out, through a size negotiation phase that flows from the top-level widget to leaf widgets in the graph; first, the graph is traversed to ask the preferred size, recursively; then the graph is traversed to assign a size and position, recursively
  5. widgets are drawn

All of this happens in a sequence; going out of sequence was possible in GTK1 and GTK2 because every step was done separately and things could happen out of order, but it’s not recommended in GTK3 where the ordering is strictly guaranteed—unless, of course, you know what you’re doing and you’re forcing something to happen because of weird backward compatibility issue.

This is why you shouldn’t port GTK code from 2 to 3 side by side; you should write GTK3 code to generate an equivalent end result, not as a search-and-replace exercise. Trying to support both GTK2 and GTK3 within the same code base will end up looking like the latter, and will lead to bugs. Stop doing that, and start from a base widget class provided by GTK3 instead of subclassing GtkContainer directly. My strong suggestion is to inherit from GtkBin, without overriding anything; you’re likely not going to need a child window, and you’re likely not going to need anything except being able to pack a child into your root widget. If you do need a child window for input events, override realize() to create it, and unrealize() to destroy it; and override size_allocate() to move/resize it using the allocation’s rectangle and make sure to chain up to the parent class.

I’m completely on board with removing the GTK2 code, it’d really only there for reference. I don’t compile it anymore.

The problem with your comments is that there is a lot of useful information in there but if I try and read the docs I can’t find a lot of those rules about what to do and not do. The API docs are very terse and don’t cover the detail I need. And because I’m doing things that most people don’t need to do I’m flying blind. I will go through all your comments in detail and rewrite as best I can. May take some time.

That’s my entire point: you should not use GTK2 code as reference for GTK3. If GTK2 could be simply replaced with GTK3, we wouldn’t have needed to make a whole new API-incompatible release.

You have to look at the end result of the GTK2 code—the UI and its behaviour—and then write GTK3 code to achieve the same.

I’m very doubtful you’re doing incredibly special things—but typically this means you need to understand the toolkit a lot better than just reading the API reference. You’ll have to read the source code of the toolkit itself.

As I said, my strong suggestion is to not subclass GtkContainer at all, and not do most of the things you’re doing in your class. Reuse one of the existing base classes provided by GTK itself.

Whether of not this qualifies as “special” IDK, but basically I’m using GTK as a layer between my apps and X windows so I don’t have to write Xlib code. I don’t want to use many GTK containers or buttons or anything, because all of that is in the cross platform layer above GTK. That is not the usual way of doing things, it’s more like WxWidgets or QT using GTK under the hood.

I’m not subclassing the GtkContainer. Just the GtkWidget.

That’s not what GTK is for, and the toolkit will resist your attempts at doing something like this.

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