I am new to rust and GTK. I'd like to create a glib::MainContext::channel() pair prior to initializing my gtk::Application. I believe this can be thought of exactly like a std::sync::mpsc. And while I can create the rx/tx channel pair and save it, I'm not sure how to pass the Receiver into the gtk::Application::connect_activate() signal handler so that I can .attach() it.
For example, I've modified this sample:
struct MyData {
ready_tx: glib::Sender<i32>,
//ready_rx: glib::Receiver<i32>,
}
fn setup() -> MyData {
let (ready_tx, ready_rx) = glib::MainContext::channel(glib::Priority::default());
MyData {
ready_tx,
//ready_rx,
}
}
fn main() {
let data = setup();
//
// Setup other threads by cloning data.sender
//
let application = gtk::Application::new(
Some("com.github.gtk-rs.examples.cairo_threads"),
Default::default(),
);
application.connect_activate(move |app| {
build_ui(&app, &data)
});
application.run();
}
fn build_ui(application: >k::Application, data: &MyData) {
...
data.ready_rx.attach( {
...
});
}
The above compiles and runs (ignoring the stubbed out build_ui) but has an obvious issue: ready_tx isn't actually included.
Doing so results in a "move occurs because data.ready_rx has type glib::Receiver<i32>, which does not implement the Copy trait'" inside build_ui().
I want the ownership of the Receiver<i32> to transit from the setup() function, up to main, and eventually be consumed by the build_ui() function, but I'm not sure how to get there or what I'm missing. I'm not sure why Copy is needed and I know I can't .clone() the Receiver.
Any ideas?
I want to do this because I need to setup some additional threads first that will need references to the Sender well before I initialize the GTK GUI. I haven't found any good examples of creating a glib::MainContext::channel() pair outside of the build_ui() function.
Is there another approach I should consider?
UPDATE:
Thanks to @chayim-friedman's answer, the following modifications to the posted code does what I need:
use std::cell::Cell;
struct MyData {
ready_tx: glib::Sender<i32>,
ready_rx: Cell<Option<glib::Receiver<i32>>>,
}
fn setup() -> MyData {
let (ready_tx, ready_rx) = glib::MainContext::channel(glib::Priority::default());
MyData {
ready_tx,
ready_rx: Cell::new(Some(read_rx)),
}
}
fn main() {
let mut data = setup();
//
// Setup other threads by cloning data.sender
//
let application = gtk::Application::new(
Some("com.github.gtk-rs.examples.cairo_threads"),
Default::default(),
);
application.connect_activate(move |app| {
build_ui(&app, &data)
});
application.run();
}
fn build_ui(application: >k::Application, data: &MyData) {
...
data.ready_rx.take().unwrap().attach( {
...
});
}
If you only need the
Receiveronce, store anOption<Receiver>andtake().unwrap()it inbuild_ui(), you will need a mutable reference toMyDatafor that.If you cannot provide a mutable reference (which I believe is the case with GTK), you can store a
Cell<Option<Receiver>>, andtake().unwrap()it. This only requires a shared reference, asCellhas interior mutability.