Re: Drawing Area issues ( continued, with example )



On 11 October 2017 at 19:34, Eric Cashon via gtk-perl-list
<gtk-perl-list gnome org> wrote:

I think there's some confusion, here, about the role of a GdkWindow
and rendering…

This is something that I have had some trouble with at the app level. In
GTK3, how drawing is done, has changed a bit between minor versions in GTK3.
In order to get CSS, transparency, OpenGL and modern drawing techniques
working well,,, things have changed. Here is an article about container
windows. I have always considered containers not to have windows to draw on
but that may not be true anymore.

https://blog.gtk.org/2017/05/24/container-secrets/

Widgets do not need windows to draw any more. It hasn't been true for
years, even if the transition happened during the 3.x API series.

A GdkWindow itself doesn't mean that a real windowing system surface
is used to render its contents; this has been true since the 2.x days.

A GtkWidget has a GdkWindow for rendering *only* if
Gtk.Widget.set_has_window() is called with `TRUE`; additionally, a
GtkWidget can add more GdkWindows for separate rendering and input
handling, assuming it calls Gtk.Widget.register_window(), to let the
toolkit know.

Rendering starts from the top-level, and each widget will be
traversed, with the draw() virtual function being called with a Cairo
context. The nature of the Cairo context is entirely inconsequential,
so you should *never* assume anything about its state. You're only
supposed to draw your widget using the allocated size as the size of
the surface; if you want to make sure to avoid overdraw, in case
you're not using widgets but you're rendering your own objects, you
can also query the size of the clip, and avoid rendering things
outside of that region.

I wrote a blog post about how GTK+ renders last year, for the development blog:

  https://blog.gtk.org/2016/06/15/drawing-in-gtk/

Some widgets might use the background window. For example a label or even a
plug inside a socket. You can always try a GtkEventBox if you need a window
to draw on behind a widget if it doesn't have it's own window.

You can also use Gtk.DrawingArea and call Gtk.Widget.set_has_window();
the drawing area widget will then create a GdkWindow for you inside
its realize() implementation.

A GtkDrawingArea has it's own window to draw on.

No, it really doesn't.

Of course, unless you call Gtk.Widget.set_has_window(), which is not
the default. The default behaviour of GtkDrawingArea, in GTK+ 3.22, is
to use the parent's window. In a typical GTK application, this means
it'll render on the top-level window, which ideally should be the only
native windowing system surface in use for rendering.

Incidentally, for GTK+ 4.0 we're cleaning up this mess, and the only
windowing system surface for both rendering and input will be the one
created by GtkWindow; everything else will render on that, and input
will be handled by the GTK widget hierarchy.

If you put a drawing area
over the main window and draw on both with transparency you can see this.

This is not really correct.

Transparency is done via opacity groups in Cairo and GTK; if a widget
has a different opacity than its parent, and its parent also has a
different opacity than 1.0, it'll be rendered into an intermediate
surface, and then composited at the parent's opacity, to avoid
blending errors.

How GTK draws the layout using cairo and the compositor might be a different
argument though. Cairo contexts are the same.

Yes, the Cairo context is the same because the Cairo context is
propagated through the widget hierarchy, assuming that the surface
used as the target is the same. That's how we can implement
semi-transparent widgets, or how we can do things like border shadows
in CSS. This is also why it's fundamental to always draw using the
Cairo context given to you by GTK itself, and never call
gdk_cairo_create(). If you want to draw into an intermediate surface
you should create your own Cairo surface, render into it, and then use
that surface as the source on the Cairo context inside the draw()
implementation.

Ciao,
 Emmanuele.

-- 
https://www.bassi.io
[@] ebassi [@gmail.com]


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