Re: gtk_widget_draw()

On Tue, 2010-08-17 at 17:28 +0200, Benjamin Otte wrote:
> On Mon, Aug 16, 2010 at 11:23 PM, Alexander Larsson <alexl redhat com> wrote:
> > [...]
> >
> > However, the next step, getting rid of the wrappers/impls and
> > restructuring the window class hierarchy is not really right
> > imho. Having impls be a separate object type is quite nice for CSW, it
> > models pretty well the situation where GdkWindow are the client side
> > things, and GdkWindowImpls are the native part that GdkWindows draw
> > in, etc. It also matches the dynamic status of "nativeness". I.e. a
> > window can get a native window when needed rather than having to do
> > this upfront. If nativeness was encoded in the typesystem things like
> > that just wouldn't work.
> >
> The biggest problem for me when reading the GdkWindow code is that I
> have no idea what a window is. So I have a hard time understanding the
> code and if what it does is sane.

Yeah, this is simultaneously very simple and very hard to explain. The
simple version is "its behaves like if there was a X window there,
except some minor changes". Of course, the hard version includes having
to read the full Xlib specification and knowing all the minor historic
ways that gdk arbitrarily differs from the X behavior.

Clearly this is not a great setup. I definitely would not propose
something like this were we to start over with a new toolkit. However,
its what we have, and even minor changes to the semantics (like tiny
event ordering issues or minute grab event property differences) cause
weird and very hard to track down bugs. I know, I had to track them all

Additionally, while GdkWindows are complex and underdocumented they are
not really something that most users of Gtk+ ever touch, which limits
the problem. 

> - Does a GdkWindow mirror a window provided by the windowing system?
> Obviously no, because offscreen windows do not own a windowing system
> window and csw windows do grab onto the native parent's window. So the
> relationship between GdkWindows and X Windows is 1:N (where N can be
> 0).
> - Does a GdkWindow have a matching Cairo surface? Well, kinda, but csw
> windows share the surface with of the native window, so when drawing
> to it, we need to clip before we draw.

This is one of the major deficiencies with csw actually. I requested
sub-surface support in cairo multiple times and got positive feedback,
but it just hasn't happened yet. Ideally we should use that so that we
can avoid hacks like gdk_cairo_reset_clip().

> - Is a GdkWindow an implementation detail or available in the public
> API? Again, it depends. If you have a GdkWindowImplFoo, it's private,
> otherwise it's public. Can I even call the same (internal or public)
> functions on these two types of windows?

All GdkWindows visible to external parties are public API. The impls are
internal stuff that behave in somewhat weird ways, but again, this is
not something normal people see.

> - Does a GdkWindow describe a window hierarchy? Again, kinda. Mostly
> you can restack and reparent windows fine, but stuffing a toplevel
> into an offscreen window does not work at all.

With offscreen windows its more like a forest than a tree, with the
limit that no window with a native window can be a child of an

> - What's a GdkWindowType? When I restack a TOPLEVEL into a CHILD, will
> it change type? Should it?

I think it does now, at least if CHILD goes to TOPLEVEL. I dunno what
the perfect behaviour would be. In a GdkToplevel world such a reparent
operation would have to just fail. But what if the reparenting happens
anyway? For instance when the parent GtkSocket X window dies and your
GtkPlug becomes a toplevel?

> - Who's responsible for what? Who decides when to repaint a window? Is
> it the same for offscreen windows? Who creates damage events?
> - Can windows be translucent? Should they be?

Right now they are typically not, but you can enable the optional
composite feature to make them translucent. This is sort of a hack that
was added to do some features that can now be done with offscreen widget

> - Is a GdkWindow the only way to get enter/leave events to widgets? Do
> widget authors know these thing?

GdkWindows are the main source of events, without them you never get any
events. The features that windows give are:

 * Something you can render on and display
 * Invalid region tracking (internal and from the window system)
 * Implicit clipping based on the "environment" of the window
 * Easy scrolling of window hierarchies
 * Event generation

> - What do we do with event masks? I learned yesterday that widgets
> without EXPOSURE_MASK don't get their background cleared. Is that
> documented? Or should that even be the case? Do we even need event
> masks?

They should get the background of the GdkWindow cleared, but of course
there will be no expose event so any widget-specific background will not
be drawn.

> - Shoud every widget have its own window now that we have lightweight
> client-side windows? Or should almost no widget have a window because
> we can synthethically create all the events widgets need? Do we have a
> list for widget authors somewhere for when they want to create their
> own window?

Most widgets are already no-window widgets and have no windows, at least
no input-output windows. Some do have input-only windows for events

> > Similarly a problem is encoding things like toplevel/subwindowness in
> > the typesystem (i.e. GdkSubwindow or GdkToplevel). A subwindow is a
> > subwindow purely based on where its in the hierarchy, which is easily
> > changed with gdk_window_reparent. This means windows can go from
> > toplevels and back at runtime.
> >
> But there are operations that do not make sense at all on a
> non-toplevel window. Like setting the icon or the title. And I'd argue
> that it's confusing for widget implementors that they need to think
> about this stuff when creating a window for their widget.
> For offscreen windows, a lot more of the window operations don't make sense.

Is it actually confusing though? Do you think widget authors ever tried
to make a child window fullscreen or set its icon?

We could do lots of contortions in the implementation side to somehow
enforce the dynamic aspects of toplevelness into static types. However,
the inherent problems in this means weird things will still shine
through here and there, and it'll be quite some work. The question in my
mind is more "is it worth it, based on the amount of confusion"?

> > Secondly, while I think your description of a no-exposes cairo_t-only
> > rendering system sounds very nice I fear that it is to simple to
> > handle everything a full featured toolkit will meet in
> > practice. People will want to put all kinds of weird stuff inside a Gtk
> > window, including things like: OpenGL rendered stuff, Xv magic,
> > socket/plug X embedding, embedding things like a flash plugin or old
> > motif plugins in a browser, etc. There is just no way you can take
> > things like these and put them transformed on a pdf surface. We have
> > to expose a more "raw" expose system.
> >
> We can have a very simple solution to most of these problems I
> believe. Something like:
> gboolean gdk_cairo_is_system_repaint (cairo_t *cr);
> That function would return TRUE if the cairo_t was created by GDK for
> repainting and FALSE if it just was a random call to
> gtk_widget_paint().

But if it is a system repaint, how would we do the drawing if we only
have a cairo_t?

> Also, for the xv and OpenGL cases you outlined, you probably want to
> create an X window outside of GDK (you definitely want in GStreamer,
> and I'm prettty sure I'd want to for GL, too) and handle it manually.
> In that case it's not GDK's responsibility to get something drawn. And
> it would be up to the widgets to draw it when doing a non-system
> draw() call.

I'm not sure what you mean by outside. But you want to create a
GdkWindow and ensure it has a native window, then get the XID and use
that to set up a gl context and render. However, you still need
GdkWindow to put it in the right place in the window hierarchy, to get
events (including exposure, but also input, enter/leave), etc. You
definitely don't want to do anything but the rendering using raw X stuff
as it will mix very badly with the rest of the apps use of gtk.

> > Now, say you have a complex dialog with lots of widgetry (and no
> > native subwindows). The only thing in the update region is the area of
> > two buttons, at the bottom of the window (maybe you moused over
> > them). How do we repaint this?
> >
> So here's pseudocode for the important functions for redraw handling
> that exist in my mind. There's probably some corner cases that we need
> to think about, but in general, i think it works.
> def expose_event (native_window, invalid_region):
>   cairo_create (get_surface (native_window));
>   cairo_clip (invalid_region)
>   cairo_push_group() /* for double-buffering */
>   render_window(native_window)
>   cairo_pop_group_to_source()
>   cairo_set_operator(SOURCE)
>   cairo_paint()
> def render_window (native_window, cr):
>   foreach (subwindow of native_window):
>     cairo_save()
>     cairo_clip(get_region (subwindow))
>     if (! everything_clipped ()):
>       cairo_translate(subwindow.x,subwindow.y)

I think you forgot a render_window() recursion here.

>       gtk_widget_draw (get_widget (subwindow))
>     cairo_restore()

> def gtk_widget_draw(widget, cr):
>   cairo_save ()
>   cairo_clip (widget.allocation)
>   if (! everything_clipped ()):
>     widget->class->draw ()
>   cairo_restore ()

This is mostly like my version, but using cairo_clip for the region
work. Nice.

 Alexander Larsson                                            Red Hat, Inc 
       alexl redhat com            alexander larsson gmail com 
He's an obese sweet-toothed filmmaker with nothing left to lose. She's a 
sarcastic blonde pearl diver with a birthmark shaped like Liberty's torch. 
They fight crime! 

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]