Re: API changes, GTK 3.21 to 3.22, need advice to replace lost capability



Hi;

your question has been answered multiple times on this mailing list; I
know, because usually I'm the one answering it.

If you look in the archives, you'll probably even find code examples.

On 24 January 2017 at 21:12,  <kornelix posteo de> wrote:

My application code writes extensively to GdkWindow objects using cairo
and cairo with pixbufs. This is often done directly on the window,
outside of draw events, usually in mouse events.

I see now that this is not recommended, however I have done this up to
now in hundreds of places without problems, and the performance is
great.

The issue why this is not recommended is not just performance: GTK
cannot guarantee in any way that what you draw directly on a windowing
system surface is going to be rendered on screen. Additionally,
"performance is great" in this kind of design implies that your CPU is
being kept a lot busier than necessary, which impacts the overall
performance of the system and the power consumption.

I cannot imagine showing lines being drawn or areas painted in
real time if I must queue draw events and let them run for every tiny
change. Maybe this is feasible and fast enough, but would require a
total redesign and maybe months of work.

What I am missing is cairo_t * gdk_cairo_create(GdkWindow *) which is
deprecated and replaced with gdk_window_begin_draw_frame() and
gdk_drawing_context_get_cairo_context().

The deprecation assumes you're literally implementing a toolkit based
on GDK, and you need to render your content.

If you're using GTK, the recommendation is, as it's always been since
GTK+ 3.0, to create your own Cairo surfaces and draw on them wherever
you want — then use them as the source surface on the Cairo context
provided you by the GtkWidget::draw virtual function/signal handler.

In the past, using gdk_cairo_create(), I created a cairo context
wherever in the code I needed, and destroyed it when done.

You can use gdk_window_create_similar_surface() or
gdk_window_create_similar_image_surface(), and then call
cairo_create() to obtain a Cairo context. After you finished drawing
on the Cairo context, use cairo_destroy().

During the GtkWidget::draw call, use the surface you created with
cairo_set_source_surface().

This is how well-behaved GTK+ 3 widgets should be written if they
require out-of-frame rendering — for instance due to caching or due to
threaded rendering. You *only* render of the Cairo context of a
GtkWidget (i.e. on the nearest GdkWindow in the hierarchy, which
typically is the top-level one) from within the emission of the
GtkWidget::draw. Anything else you wish to draw will need its own
surface.

There are
times when a mouse event function is re-entered while still busy,
because new mouse events happen during execution and sometimes functions
are called that iterate the main loop. Creating and destroying parallel
cairo contexts was not a problem up to now, apparently.

It's always been a problem. There's no safety or ordering guarantee,
and what you do on your widget may be cleared or cause continuous
submissions.

This is no longer possible, because only one drawing context can be
defined for a GdkWindow, and there is no way to find out if a GdkWindow
already has one or not. You can go from a GdkDrawingContext to a
matching GdkWindow, but not the other way around. Is there a way?

No.

Also, If a drawing context is created for a GdkWindow, what happens if
there is a draw event and the window is repainted? I presume the created
drawing context is now invalid, or GTK will fail when creating the
automatic new drawing context for the draw event because another context
already exists. It also seems that if the window is resized, the drawing
context becomes invalid because the size of the drawing region is fixed
by the call to gdk_window_begin_draw_frame().

Yes. There is no re-entrance in frame based drawing. Every frame is
its own atomic bloc.

Am I right to think that the new API has a performance advantage in that
the backing store is only as large as the pre-declared drawing region?
(presuming the extra code to calculate a minimum region before each set
of window draws).

The new API is just a way to deprecate out of frame rendering on
GdkWindow. It's, internally, implemented exactly in the same way as
the old API.

This work is mostly in preparation of what we wanted to achieve with
GTK+ 4.0, which is dropping immediate-mode rendering of widgets in
favour of a retained scene graph and render commands.

Ciao,
 Emmanuele.

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


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