Drawing
Three GTK widgets draw for themselves. The drawing area is the plain one: a blank box, a size and a callback, and everything on screen is what the callback painted. The GL area is the same idea with a GPU behind it. Graphics offload draws nothing at all — it hands its one child to the compositor untouched, which is cheaper than compositing a texture per frame.
The fourth, the drag icon, draws nothing either, and for the opposite reason: it is not a widget an application builds at all but one that belongs to a drag operation and dies with it.
What none of them have is styling. Their CSS nodes carry no rule in libadwaita’s stylesheet, so what you see here is geometry, not a theme.
Drawing Area
Section titled “Drawing Area”A blank widget you paint on. It has no visual properties at all — what you see is
whatever set_draw_func drew, and the draw function is called with the widget’s
allocation, so it has to be ready for a size it did not choose.
content-width and content-height are the minimum and the natural size in one: a parent may hand the area more room than it asked for, but never less. At 0 — the default — the area has no intrinsic size at all and fills whatever box it is put in, which is why an area with both at 0 and no size request disappears.
The draw function is called again whenever the area is drawn: when it first comes on
screen, when its size changes, when something covers it, and when you ask for it with
queue_draw(). That is the whole contract — repaint from the function, never
incrementally.
GL Area
Section titled “GL Area”The same idea with a GPU behind it. auto-render says whether ::render is emitted
every time the widget draws, has-depth-buffer and has-stencil-buffer decide what
the framebuffer has in it, and allowed-apis is a set — gl gles (the default),
gles or gl — not a choice.
The two signals are the whole contract, and their order is the part applications get
wrong. ::resize arrives with the device-pixel viewport (logical size × scale
factor) before the first ::render and before every later one, so a program that
sets up its projection there cannot draw into a viewport nobody told it about.
The render flag is cleared after ::render, so queue_render() from inside the
handler queues its frame and loses its flag — one render, not a loop. Nothing redraws on
its own either way: auto-render decides whether a draw you asked for ends in
::render, and animating means asking, from a tick callback.
One property refuses to change late. allowed-apis is read when the context is created,
so GTK refuses a write to a realized area — and the browser replica does the same, putting
the attribute back rather than starting a second context.
Drag Icon
Section titled “Drag Icon”The fourth widget on this page is the one no application builds. A GtkDragIcon belongs
to a drag operation: get_for_drag(drag) returns the icon that drag is using, creating it if
there is none, and GTK destroys it when the drag ends. Its own docs say the rest — drag
icons do not allow user input — and the class makes it true in init, which calls
gtk_widget_set_can_target (self, FALSE).
There is exactly one property, child, and it does the whole job: set_child unparents
the previous child, parents the new one, shows the icon and notifies. Its size is the child’s
preferred size, which is why an icon is exactly as big as what it carries.
What makes the widget interesting is create_widget_for_value, which is what a
GtkDragSource calls to decide what a drag shows. It answers for six kinds of value: a
string is a GtkLabel, a GdkRGBA is a colour swatch, a GdkPaintable and a GFile are
GtkImages at the large size, a GtkTextBuffer is a painted GtkPicture of its selection,
a GskRenderNode is an image of its bounds — and NULL for anything else. The hotspot is
the other half of a drag icon’s setup: set_from_paintable calls
gdk_drag_set_hotspot (drag, hot_x, hot_y) and aligns that point of the paintable with the
cursor’s.
Graphics Offload
Section titled “Graphics Offload”A wrapper that draws nothing itself: it hands its one child to the compositor as it is, skipping the texture round-trip a frequently changing child would otherwise pay on every frame. It is worth it for video and nothing else, and GTK falls back to normal rendering whenever it cannot — there is no failure mode to handle.
enabled says whether the attempt is made at all (enabled from the start, disabled to opt out). black-background paints black over the whole allocation before the child, which is what letterboxing needs: an aspect ratio that does not match the screen leaves bars, and the property makes them black in CSS rather than in an application’s own drawing code.
What the widget will not do is the list worth reading before you reach for it: a rounded corner that clips the content, a transform more complex than a translation and a scale, a filter such as opacity or grayscale, and translucent content all rule offload out. An offloaded child is best kept bare.