Hi;

On 24 March 2015 at 14:43, Sergei Naumov <vo...@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]
_______________________________________________
gtk-app-devel-list mailing list
gtk-app-devel-list@gnome.org
https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list

Reply via email to