Re: Re: Getting a Cairo context



Hi;

On 24 March 2015 at 14:43, Sergei Naumov <vomus rambler ru> wrote:

The idiomatic way is to create a surface either using
gdk_window_create_similar_surface(), or
gdk_window_create_similar_image_surface(), which will take care of
giving you the most appropriate surface for the platform you're using.

You can usually do that from the main thread context, after realizing
the widget in order to obtain its GdkWindow; you keep the surface
inside your widget instance data, and draw on it from the thread you
create for rendering. At the end of the thread, you queue a redraw on
the widget, and then you use the surface as the source for rendering
on the cairo_t* that the ::draw signal gives to you.


Do I understand this correctly that what you are saying is as follows?

1) create a surface in the main gtk thread

You can only use the GDK and GTK+ API from the same thread that called
gtk_init/gtk_main, so if you want to use
gdk_window_create_similar_surface() you will have to call the function
from the main thread; you can create a Cairo image surface from the
thread you spawn for drawing, and then pass the surface to the main
thread, but in general it's easier if only a single thread is
responsible for creating and destroying resources.

2) make this surface global across threads

No. You attach this drawing surface to the instance of your widget,
and you pass your widget as a pointer to the drawing thread. You will
need the widget pointer in any case, because you have to schedule a
widget redraw from the thread by using something like
gdk_threads_add_idle() or g_main_context_invoke().

3) draw whatever on the surface

From the thread, yes. As long as only one thread at a time accesses
the Cairo surface, you should be safe.

4) bind something to a "draw" signal that redraws

That's the only way to make it work. You *cannot* use GTK API from
different threads.

In short:

  1. create the widget instance
  2. realize it
  3. create a similar Cairo surface from the GdkWindow of the widget
  4. store Cairo surface on the widget instance; you can use a
subclass or g_object_set_data(), with a preference for the former
  5. connect a callback to/override the class closure of the ::draw signal
    a. in the draw signal handler, you take the surface and use it a
source to draw on the cairo_t given to you; you can use a boolean flag
to know whether or not the contents of the surface are okay to use
  6. fire off a thread, and pass the pointer to widget to the thread function
  7. inside the thread function, draw on the surface
  8. at the end of the thread, schedule a redraw in the main thread
    a. use gdk_threads_add_idle() with a callback and pass the widget
pointer as the data
    b. from within the callback, set the boolean flag that tells the
::draw callback to use the surface as a source, and call
gtk_widget_queue_draw()

It's safe to draw on Cairo surfaces from different threads, assuming
only a thread at a time does it; it's not safe to use GTK API from
different threads, though. That's why you can create a surface from
the main thread, and draw on it in a separate thread — as long as you
ensure that all the operations involving GTK happen on the main
thread.

Ciao,
 Emmanuele.

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


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