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 Receiver
once, store an Option<Receiver>
and take().unwrap()
it in build_ui()
, you will need a mutable reference to MyData
for that.
If you cannot provide a mutable reference (which I believe is the case with GTK), you can store a Cell<Option<Receiver>>
, and take().unwrap()
it. This only requires a shared reference, as Cell
has interior mutability.