Skip to content

Commit 281e2a8

Browse files
committed
book(main_event_loop): add custom struct mutation example
1 parent 6d48eb1 commit 281e2a8

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use glib::clone;
2+
use gtk::{Application, ApplicationWindow, Button, glib};
3+
use gtk::{gio, prelude::*};
4+
5+
use std::{
6+
sync::{Arc, Mutex},
7+
thread,
8+
time::Duration,
9+
};
10+
11+
const APP_ID: &str = "org.gtk_rs.MainEventLoop10";
12+
13+
fn main() -> glib::ExitCode {
14+
// Create a new application
15+
let app = Application::builder().application_id(APP_ID).build();
16+
17+
// Connect to "activate" signal of `app`
18+
app.connect_activate(build_ui);
19+
20+
// Run the application
21+
app.run()
22+
}
23+
24+
struct DemoStruct {
25+
text: String,
26+
}
27+
28+
impl DemoStruct {
29+
fn mutate(&mut self, string: String) {
30+
self.text = string.to_string();
31+
}
32+
}
33+
34+
fn build_ui(app: &Application) {
35+
// Create a button
36+
let button = Button::builder()
37+
.label("START")
38+
.margin_top(12)
39+
.margin_bottom(12)
40+
.margin_start(12)
41+
.margin_end(12)
42+
.build();
43+
44+
let (sender, receiver) = async_channel::bounded(1);
45+
// ANCHOR: callback
46+
//
47+
// Wrap the new structure in Arc/Mutext
48+
let demo_struct = Arc::new(Mutex::new(DemoStruct {
49+
text: "Start".to_string(),
50+
}));
51+
52+
// Connect to "clicked" signal of `button`
53+
button.connect_clicked(move |moved_button| {
54+
let sender = sender.clone();
55+
// Get mutable reference to the structure
56+
let arc_struct = Arc::clone(&demo_struct);
57+
58+
moved_button.set_label("Working");
59+
60+
gio::spawn_blocking(move || {
61+
let three_seconds = Duration::from_secs(3);
62+
thread::sleep(three_seconds);
63+
// Mutate the string on another thread
64+
arc_struct
65+
.lock()
66+
.unwrap()
67+
.mutate("Mutated on another thread".to_string());
68+
// Send the structe back
69+
sender.send_blocking(arc_struct).unwrap();
70+
});
71+
});
72+
73+
glib::spawn_future_local(clone!(
74+
#[weak]
75+
button,
76+
async move {
77+
while let Ok(mutated_struct) = receiver.recv().await {
78+
// Set the label using the string from the received structure
79+
button.set_label(&mutated_struct.lock().unwrap().text);
80+
}
81+
}
82+
));
83+
// ANCHOR_END: callback
84+
//
85+
// Create a window
86+
let window = ApplicationWindow::builder()
87+
.application(app)
88+
.title("My GTK App")
89+
.child(&button)
90+
.build();
91+
92+
// Present window
93+
window.present();
94+
}

book/src/main_event_loop.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,14 @@ If you decide to share it, you user name will be printed on the console.
241241

242242
If you have a custom structure that needs to perform its function on a separate thread to avoid blocking, Rust's [Arc](https://doc.rust-lang.org/std/sync/struct.Arc.html) and [Mutex](https://doc.rust-lang.org/std/sync/struct.Mutex.html) are required for safe data transport. `Mutex` (mutual exclusion) allows data access from another thread while guaranteeing exclusivity of the request call. To request data from another thread, `lock()` is called on the `Mutext` to signal the attempt. But Rust's ownership system does not allow `Mutext` data to be safely exchanged between threads. To perform data transfer between threads, you need to utilize Rust's `Arc` structure. These `Arc`s (Atomic Reference Counting) are safe to share between the application threads. But keep in mind that this safety comes with the price and will affect the performance. In some cases it is cheaper to run operations on a single thread without spending resources on locks and reference counting.
243243

244+
Lets mutate the `text` string of the `DemoStruct` structure in another thread:
245+
246+
Filename: <a class=file-link href="https://github.com/gtk-rs/gtk4-rs/blob/main/book/listings/main_event_loop/10/main.rs">listings/main_event_loop/10/main.rs</a>
247+
248+
```rust
249+
{{#rustdoc_include ../listings/main_event_loop/10/main.rs:callback}}
250+
```
251+
244252
## Tokio
245253

246254
[`tokio`](https://docs.rs/tokio/latest/tokio/) is Rust's most popular asynchronous platform.

0 commit comments

Comments
 (0)