some time ago I asked this question (how to position a child widget Q: custom GtkOverlay's child (GtkRevealer) position) and haven’t found a clear solution.
To get around I’ve set only x,y coordinates (not touching other measurements), it works in most cases. But sometimes there’s garbage in allocation rectangle (Gtk.Overlay::get-child-position) and returned width/height by gtk_widget_get_width()/.._height() are 0, that prevent to calculate any of preferred coordinates.
Is there a more clear way to position a child widget?
In that case, just return FALSE from the callback.
Personally, with gtk4, when I need to position a widget on top of another one at specific coordinates, I stopped using GtkOverlay and instead just use a simple custom widget that just overrides the Gtk.Widget.size_allocate virtual method, and from there call Gtk.Widget.size_allocate on each children with their respective position inside my custom widget.
In that case, just return FALSE from the callback.
it doesn’t work in all cases with GTK4, for example on xfce4 session with next get_child_position(GtkOverlay* self, GtkWidget* widget, GdkRectangle *allocation, gpointer user_data) callback:
I see that I can translate x,y position with this GskTransform. The widget width/height and surrounding coordinates are unknown beforehand. All together it becomes a bit messy.
To clarify a bit what I’m trying to achieve:
there’s two draggable with DnD widgets in overlay, initially they’re needed to position relatively to the left-top corner (the first widget) and relatively to the right-top corner (the second one). To calculate their positions I’ve used overlay’s get_child_position() callback to calculate it there, using (1) size of surrounding frame (from GdkRectangle *allocation), (2) child widget size (data returned by gtk_widget_measure()), and (3) known beforehand x0, y0 relatively to a correspondent corner.
It’s calculated easily if I have data in GdkRectangle allocation and it’s there in most cases at get_child_position() calls. Rarely on some OSes it’s not known, it’s the case.
There’s an example when it works, DnD elements in red squares are a legend on the first snapshot and control-buttons on the second, that are initially needed to position.
I would personally do something like this (Python code):
import sys
import gi
gi.require_version('Gdk', '4.0')
gi.require_version('Gtk', '4.0')
from gi.repository import Gdk, Gtk
class MyOverlay(Gtk.Widget):
def __init__(self):
super().__init__()
self.child = Gtk.DrawingArea(content_width=400, content_height=300)
self.overlay = Gtk.Label(label="Hello!")
self.child.set_parent(self)
self.overlay.set_parent(self)
def do_dispose(self):
self.child.unparent()
self.overlay.unparent()
Gtk.Widget.do_dispose(self)
def do_measure(self, orientation, for_size):
# We only care of the main child. If the overlay is too big it will be cropped
return self.child.measure(orientation, for_size)
def do_size_allocate(self, width, height, baseline):
rect = Gdk.Rectangle()
# The main child is given the full allocation
rect.x, rect.y, rect.width, rect.height = 0, 0, width, height
self.child.size_allocate(rect, baseline)
# The overlay will be allocated with minimum size, at (100, 50) offset
min_w, nat_w, min_b, nat_b = self.overlay.measure(Gtk.Orientation.HORIZONTAL, -1)
min_h, nat_h, min_b, nat_b = self.overlay.measure(Gtk.Orientation.VERTICAL, -1)
rect.x, rect.y, rect.width, rect.height = 100, 50, min_w, min_h
self.overlay.size_allocate(rect, baseline)
class MyAppWindow(Gtk.ApplicationWindow):
def __init__(self):
super().__init__()
self.set_child(MyOverlay())
self.present()
class MyApp(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self)
self.connect('activate', self.on_activate)
def on_activate(self, app):
self.add_window(MyAppWindow())
if __name__ == '__main__':
sys.exit(MyApp().run(sys.argv))
@gwillems
Now I got this approach.
More or less it plays the same role as a GtkOverlay. In case if it’s positioned from the right side, full allocation size needs to be known. I’ll compare it to cases when I couldn’t get that size with get_child_position().
Certainly it is an option to GtkOverlay/get_child_position().
Thank you.