...it seems like just getting your toplevel from the window system and drawing / managing everything else on your own would be less of a hassle in a cross-platform setting.
In a world where the lowest common denominator is a window system where there are only top-level windows that are just canvases, you'd be right. But things haven't worked that way for a long time.
The biggest thing any window system that goes beyond tiling has to deal with is overlap. It has to to be aware of where the windows are and how they're stacked to decide where to send input and where to place and clip output. Once that problem is solved, subwindows per widget aren't a problem because the same set of rules is applied to a deeper stack. With the window system able handle it, there's no reason for every client to duplicate that effort, even if it is in a library somewhere. Every window system of any significance that came to life in the last 30+ years has adopted this model and toolkits like GTK+ take advantage of the fact that X, Windows and Quartz all use it.
On the client side, unique windows per interface component makes a lot of sense, too. Instead of being left on your own to figure out what part of your code needs to service that mouse click you got at (280, 192) in your main window, you get an identifier for the window where it landed that can be used to match it with a widget and coordinates relative to its boundaries. Your interface components only have to understand themselves (dimensions, text color, text content, etc.) and don't know or care what's going on anywhere else.
Having invented parts of that wheel myself once or twice in the 1980s, I can tell you from experience that it's a lot of work, and I'm much happier letting the window system take care of it.