GTK+ is not thread safe. You should only use GTK+ and GDK from the thread gtk_init() and gtk_main() were called on. This is usually referred to as the “main thread”.
Signals on GTK+ and GDK types, as well as non-signal callbacks, are emitted in the main thread.
We need a way to enforce this invariant and it's not enough to make every widget !Send because a constructor could be called from any thread.
It can be done statically by having some !Send object that represents the GTK runtime (or the default MainContext) and making every constructor take a reference to this object:
let gtk = Gtk::new();
let button = Button::new(>k);
We're guaranteed that GTK callbacks (but not all callbacks possible under GLib) happen on the same thread so don't need extra checking there.
To avoid the usability hit of passing an extra argument to each constructor it might be possible to add methods on the Gtk struct to achieve something like
let button1 = gtk.button().new();
let button2 = gtk.button().with_label("Hello");
Here gtk.button() returns a ButtonBuilder or a ButtonFactory that supports all the constructors of a button.
It may actually be possible to make each widget have only one constructor (living under the Gtk struct) and refactor the others into setters (possibly allowing method chaining), so this example would look like
let button1 = gtk.button();
let button2 = gtk.button().set_label("Hello");
All of this can be sidestepped by doing runtime checks but it doesn't seem very Rust-y.
The Gtk struct doesn't need to contain all those constructors as inherent methods (that would be pretty ugly). Each widget module can make a trait like ButtonFactory and implement it for the Gtk struct.
https://developer.gnome.org/gdk3/stable/gdk3-Threads.html#gdk3-Threads.description
We need a way to enforce this invariant and it's not enough to make every widget
!Send
because a constructor could be called from any thread.It can be done statically by having some
!Send
object that represents the GTK runtime (or the default MainContext) and making every constructor take a reference to this object:We're guaranteed that GTK callbacks (but not all callbacks possible under GLib) happen on the same thread so don't need extra checking there.
To avoid the usability hit of passing an extra argument to each constructor it might be possible to add methods on the
Gtk
struct to achieve something likeHere
gtk.button()
returns aButtonBuilder
or aButtonFactory
that supports all the constructors of a button.It may actually be possible to make each widget have only one constructor (living under the
Gtk
struct) and refactor the others into setters (possibly allowing method chaining), so this example would look likeAll of this can be sidestepped by doing runtime checks but it doesn't seem very Rust-y.