Skip to content

Commit 878b909

Browse files
authored
Merge pull request #2081 from sdroege/0.9-backports
0.9 backports
2 parents 20d14bd + 3e720cc commit 878b909

File tree

9 files changed

+568
-403
lines changed

9 files changed

+568
-403
lines changed

Cargo.lock

Lines changed: 477 additions & 331 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

book/src/g_object_memory_management.md

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ With our first example, we have window with a single button.
77
Every button click should increment an integer `number` by one.
88

99
```rust ,no_run,compile_fail
10-
#use gtk::prelude::*;
11-
#use gtk::{self, glib, Application, ApplicationWindow, Button};
10+
# use gtk::prelude::*;
11+
# use gtk::{self, glib, Application, ApplicationWindow, Button};
1212
#
13-
#const APP_ID: &str = "org.gtk_rs.GObjectMemoryManagement0";
13+
# const APP_ID: &str = "org.gtk_rs.GObjectMemoryManagement0";
1414
#
1515
// DOES NOT COMPILE!
1616
fn main() -> glib::ExitCode {
@@ -72,7 +72,7 @@ note: function requires argument type to outlive `'static`
7272
help: to force the closure to take ownership of `number` (and any other referenced variables), use the `move` keyword
7373
|
7474
32 | button_increase.connect_clicked(move |_| number += 1);
75-
|
75+
|
7676
```
7777

7878
Our closure only borrows `number`.
@@ -81,31 +81,31 @@ The compiler also suggests how to fix this.
8181
By adding the `move` keyword in front of the closure, `number` will be moved into the closure.
8282

8383
```rust ,no_run,compile_fail
84-
#use gtk::prelude::*;
85-
#use gtk::{self, glib, Application, ApplicationWindow, Button};
84+
# use gtk::prelude::*;
85+
# use gtk::{self, glib, Application, ApplicationWindow, Button};
8686
#
87-
#const APP_ID: &str = "org.gtk_rs.GObjectMemoryManagement0";
87+
# const APP_ID: &str = "org.gtk_rs.GObjectMemoryManagement0";
8888
#
89-
#fn main() -> glib::ExitCode {
90-
# // Create a new application
91-
# let app = Application::builder().application_id(APP_ID).build();
89+
# fn main() -> glib::ExitCode {
90+
# // Create a new application
91+
# let app = Application::builder().application_id(APP_ID).build();
9292
#
93-
# // Connect to "activate" signal of `app`
94-
# app.connect_activate(build_ui);
93+
# // Connect to "activate" signal of `app`
94+
# app.connect_activate(build_ui);
9595
#
96-
# // Run the application
97-
# app.run()
98-
#}
96+
# // Run the application
97+
# app.run()
98+
# }
9999
#
100-
#fn build_ui(application: &Application) {
101-
# // Create two buttons
102-
# let button_increase = Button::builder()
103-
# .label("Increase")
104-
# .margin_top(12)
105-
# .margin_bottom(12)
106-
# .margin_start(12)
107-
# .margin_end(12)
108-
# .build();
100+
# fn build_ui(application: &Application) {
101+
# // Create two buttons
102+
# let button_increase = Button::builder()
103+
# .label("Increase")
104+
# .margin_top(12)
105+
# .margin_bottom(12)
106+
# .margin_start(12)
107+
# .margin_end(12)
108+
# .build();
109109
#
110110
// DOES NOT COMPILE!
111111
// A mutable integer
@@ -124,7 +124,7 @@ By adding the `move` keyword in front of the closure, `number` will be moved int
124124
#
125125
# // Present the window
126126
# window.present();
127-
#}
127+
# }
128128
```
129129

130130
This still leaves the following error message:
@@ -169,7 +169,6 @@ That is exactly what the [`std::rc::Rc`](https://doc.rust-lang.org/std/rc/struct
169169
If we want to modify the content of our [`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html),
170170
we can again use the [`Cell`](https://doc.rust-lang.org/std/cell/struct.Cell.html) type.
171171

172-
173172
Filename: <a class=file-link href="https://github.com/gtk-rs/gtk4-rs/blob/main/book/listings/g_object_memory_management/2/main.rs">listings/g_object_memory_management/2/main.rs</a>
174173

175174
```rust

book/src/main_event_loop.md

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,13 @@ We can't even move the window.
2626
The `sleep` call is an artificial example,
2727
but frequently, we want to run a slightly longer operation in one go.
2828

29-
3029
<div style="text-align:center">
3130
<video autoplay muted loop>
3231
<source src="vid/main_event_loop_1.webm" type="video/webm">
3332
<p>A video which shows that after pressing the button, the window can still be moved</p>
3433
</video>
3534
</div>
3635

37-
3836
## How to Avoid Blocking the Main Loop
3937

4038
In order to avoid blocking the main loop, we can spawn a new task with [`gio::spawn_blocking`](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/gio/fn.spawn_blocking.html) and let the operation run on the thread pool.
@@ -56,7 +54,6 @@ This is not necessarily what we want.
5654
</video>
5755
</div>
5856

59-
6057
> If you come from another language than Rust, you might be uncomfortable with the thought of running tasks in separate threads before even looking at other options.
6158
> Luckily, Rust's safety guarantees allow you to stop worrying about the nasty bugs that concurrency tends to bring.
6259
@@ -123,12 +120,12 @@ But why did we not do the same thing with our multithreaded example?
123120

124121
```rust ,no_run,compile_fail
125122
# use std::{thread, time::Duration};
126-
#
123+
#
127124
# use glib::{clone, MainContext, PRIORITY_DEFAULT};
128125
# use gtk::{glib, gio};
129126
# use gtk::prelude::*;
130127
# use gtk::{Application, ApplicationWindow, Button};
131-
#
128+
#
132129
# fn main() {
133130
# // Create a new application
134131
# let app = Application::builder()
@@ -137,21 +134,21 @@ But why did we not do the same thing with our multithreaded example?
137134
#
138135
# // Connect to "activate" signal
139136
# app.connect_activate(build_ui);
140-
#
137+
#
141138
# // Get command-line arguments
142139
# let args: Vec<String> = args().collect();
143140
# // Run the application
144141
# app.run(&args);
145142
# }
146-
#
143+
#
147144
# // When the application is launched…
148145
# fn build_ui(application: &Application) {
149146
# // Create a window
150147
# let window = ApplicationWindow::builder()
151148
# .application(application)
152149
# .title("My GTK App")
153150
# .build();
154-
#
151+
#
155152
# // Create a button
156153
# let button = Button::builder()
157154
# .label("Press me!")
@@ -160,7 +157,7 @@ But why did we not do the same thing with our multithreaded example?
160157
# .margin_start(12)
161158
# .margin_end(12)
162159
# .build();
163-
#
160+
#
164161
// DOES NOT COMPILE!
165162
// Connect to "clicked" signal of `button`
166163
button.connect_clicked(move |button| {
@@ -175,7 +172,7 @@ But why did we not do the same thing with our multithreaded example?
175172
button.set_sensitive(true);
176173
});
177174
});
178-
#
175+
#
179176
# // Add button
180177
# window.set_child(Some(&button));
181178
# window.present();
@@ -213,11 +210,11 @@ Filename: <a class=file-link href="https://github.com/gtk-rs/gtk4-rs/blob/main/b
213210
Asynchronous functions from the `glib` ecosystem can always be spawned on the `glib` main loop.
214211
Typically, crates depending on `async-std` or `smol` work as well.
215212
Let us take `ashpd` for example which allows sandboxed applications to interact with the desktop.
216-
Per default it depends on `async-std`.
213+
It can be configured to depend on `async-std`.
217214
We can add it to our dependencies by running the following command.
218215

219216
```
220-
cargo add ashpd --features gtk4
217+
cargo add ashpd --no-default-features --features "gtk4 async-std"
221218
```
222219

223220
You need to use a Linux desktop environment in order to run the following example locally.
@@ -281,32 +278,32 @@ Doing this will block one of the runtime's threads with the GLib main loop, whic
281278
Instead, we bind [`tokio::runtime::Runtime`](https://docs.rs/tokio/latest/tokio/runtime/struct.Runtime.html) to a static variable.
282279

283280
```rust
284-
#use std::sync::OnceLock;
281+
# use std::sync::OnceLock;
285282
#
286-
#use glib::clone;
287-
#use gtk::glib;
288-
#use gtk::prelude::*;
289-
#use gtk::{Application, ApplicationWindow, Button};
290-
#use tokio::runtime::Runtime;
283+
# use glib::clone;
284+
# use gtk::glib;
285+
# use gtk::prelude::*;
286+
# use gtk::{Application, ApplicationWindow, Button};
287+
# use tokio::runtime::Runtime;
291288
#
292-
#const APP_ID: &str = "org.gtk_rs.MainEventLoop0";
289+
# const APP_ID: &str = "org.gtk_rs.MainEventLoop0";
293290
#
294291
// DOES NOT COMPILE!
295292
static RUNTIME: Runtime =
296293
Runtime::new().expect("Setting up tokio runtime needs to succeed.");
297294
#
298-
#fn main() -> glib::ExitCode {
299-
# // Create a new application
300-
# let app = Application::builder().application_id(APP_ID).build();
295+
# fn main() -> glib::ExitCode {
296+
# // Create a new application
297+
# let app = Application::builder().application_id(APP_ID).build();
301298
#
302-
# // Connect to "activate" signal of `app`
303-
# app.connect_activate(build_ui);
299+
# // Connect to "activate" signal of `app`
300+
# app.connect_activate(build_ui);
304301
#
305-
# // Run the application
306-
# app.run()
307-
#}
302+
# // Run the application
303+
# app.run()
304+
# }
308305
#
309-
#fn build_ui(app: &Application) {
306+
# fn build_ui(app: &Application) {
310307
# // Create a button
311308
# let button = Button::builder()
312309
# .label("Press me!")
@@ -347,7 +344,7 @@ static RUNTIME: Runtime =
347344
#
348345
# // Present window
349346
# window.present();
350-
#}
347+
# }
351348
```
352349

353350
Unfortunately, this doesn't compile.
@@ -362,7 +359,6 @@ consider wrapping this expression in `Lazy::new(|| ...)` from the `once_cell` cr
362359
We could follow the advice directly, but the standard library also provides solutions for that.
363360
With [`std::sync::OnceLock`](https://doc.rust-lang.org/stable/std/sync/struct.OnceLock.html) we can initialize the static with the const function `OnceLock::new()` and initialize it the first time our function `runtime` is called.
364361

365-
366362
Filename: <a class=file-link href="https://github.com/gtk-rs/gtk4-rs/blob/main/book/listings/main_event_loop/9/main.rs">listings/main_event_loop/9/main.rs</a>
367363

368364
```rust
@@ -391,12 +387,12 @@ cargo remove tokio reqwest ashpd
391387

392388
How to find out whether you can spawn an `async` task on the `glib` main loop?
393389
`glib` should be able to spawn the task when the called functions come from libraries that either:
390+
394391
- come from the `glib` ecosystem,
395392
- don't depend on a runtime but only on the `futures` family of crates (`futures-io`, `futures-core` etc),
396393
- depend on the `async-std` or `smol` runtimes, or
397394
- have cargo features that let them depend on `async-std`/`smol` instead of `tokio`.
398395

399-
400396
## Conclusion
401397

402398
You don't want to block the main thread long enough that it is noticeable by the user.
@@ -408,7 +404,7 @@ That means you have to run the task in a separate thread and let it send results
408404

409405
If your task is [IO bound](https://en.wikipedia.org/wiki/I/O_bound), the answer depends on the crates at your disposal and the type of work to be done.
410406

411-
- Light I/O work with functions from crates using `glib`, `smol`, `async-std` or the `futures` trait family can be spawned on the main loop. This way, you can often avoid synchronization via channels.
407+
- Light I/O work with functions from crates using `glib`, `smol`, `async-std` or the `futures` trait family can be spawned on the main loop. This way, you can often avoid synchronization via channels.
412408
- Heavy I/O work might still benefit from running in a separate thread / an async executor to avoid saturating the main loop. If you are unsure, benchmarking is advised.
413409

414410
If the best crate for the job relies on `tokio`, you will have to spawn it with the tokio runtime and communicate via channels.

gtk4/Gir.toml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ generate = [
103103
"Gtk.EditableProperties",
104104
"Gtk.EmojiChooser",
105105
"Gtk.EntryIconPosition",
106-
"Gtk.EventController",
107106
"Gtk.EventControllerFocus",
108107
"Gtk.EventControllerMotion",
109108
"Gtk.EventControllerScrollFlags",
@@ -544,6 +543,9 @@ status = "generate"
544543
name = "accelerator_parse"
545544
manual = true # to make use of gdk::Key
546545
[[object.function]]
546+
name = "disable_portals"
547+
assertion = "not-initialized"
548+
[[object.function]]
547549
name = "disable_setlocale"
548550
assertion = "not-initialized"
549551
[[object.function]]
@@ -1173,6 +1175,14 @@ status = "generate"
11731175
rename = "entry"
11741176
manual = true # upcast to Entry
11751177

1178+
[[object]]
1179+
name = "Gtk.EventController"
1180+
status = "generate"
1181+
manual_traits = ["EventControllerExtManual"]
1182+
[[object.function]]
1183+
name = "set_static_name"
1184+
manual = true # to make use of a static lifetimed string
1185+
11761186
[[object]]
11771187
name = "Gtk.EventControllerKey"
11781188
status = "generate"

gtk4/src/auto/event_controller.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -147,18 +147,6 @@ pub trait EventControllerExt: IsA<EventController> + sealed::Sealed + 'static {
147147
}
148148
}
149149

150-
#[cfg(feature = "v4_8")]
151-
#[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
152-
#[doc(alias = "gtk_event_controller_set_static_name")]
153-
fn set_static_name(&self, name: Option<&str>) {
154-
unsafe {
155-
ffi::gtk_event_controller_set_static_name(
156-
self.as_ref().to_glib_none().0,
157-
name.to_glib_none().0,
158-
);
159-
}
160-
}
161-
162150
#[doc(alias = "name")]
163151
fn connect_name_notify<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
164152
unsafe extern "C" fn notify_name_trampoline<

gtk4/src/auto/functions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ pub fn check_version(
3939
#[cfg_attr(docsrs, doc(cfg(feature = "v4_18")))]
4040
#[doc(alias = "gtk_disable_portals")]
4141
pub fn disable_portals() {
42-
assert_initialized_main_thread!();
42+
assert_not_initialized!();
4343
unsafe {
4444
ffi::gtk_disable_portals();
4545
}

gtk4/src/event_controller.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
#[cfg(feature = "v4_8")]
4+
use glib::translate::*;
5+
6+
#[cfg(feature = "v4_8")]
7+
use crate::ffi;
8+
use crate::{prelude::*, EventController};
9+
10+
pub trait EventControllerExtManual: IsA<EventController> + 'static {
11+
#[cfg(feature = "v4_8")]
12+
#[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
13+
#[doc(alias = "gtk_event_controller_set_static_name")]
14+
fn set_static_name(&self, name: Option<&'static glib::GStr>) {
15+
unsafe {
16+
ffi::gtk_event_controller_set_static_name(
17+
self.as_ref().to_glib_none().0,
18+
name.to_glib_none().0,
19+
);
20+
}
21+
}
22+
}
23+
24+
impl<O: IsA<EventController>> EventControllerExtManual for O {}

gtk4/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ mod entry;
139139
mod entry_buffer;
140140
mod entry_completion;
141141
mod enums;
142+
mod event_controller;
142143
mod event_controller_key;
143144
mod expression_watch;
144145
mod file_chooser;

gtk4/src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub use crate::{
2121
editable::EditableExtManual,
2222
entry::EntryExtManual,
2323
entry_buffer::EntryBufferExtManual,
24+
event_controller::EventControllerExtManual,
2425
expression::{GObjectPropertyExpressionExt, IsExpression},
2526
file_chooser::FileChooserExtManual,
2627
font_chooser::FontChooserExtManual,

0 commit comments

Comments
 (0)