diff --git a/book/listings/actions/1/main.rs b/book/listings/actions/1/main.rs index 6f14b7c4bc6d..32d44e85a962 100644 --- a/book/listings/actions/1/main.rs +++ b/book/listings/actions/1/main.rs @@ -1,5 +1,4 @@ -use gio::SimpleAction; -use glib::clone; +use gio::ActionEntry; use gtk::prelude::*; use gtk::{gio, glib, Application, ApplicationWindow}; @@ -31,11 +30,12 @@ fn build_ui(app: &Application) { .build(); // Add action "close" to `window` taking no parameter - let action_close = SimpleAction::new("close", None); - action_close.connect_activate(clone!(@weak window => move |_, _| { - window.close(); - })); - window.add_action(&action_close); + let action_close = ActionEntry::builder("close") + .activate(|window: &ApplicationWindow, _, _| { + window.close(); + }) + .build(); + window.add_action_entries([action_close]); // Present window window.present(); diff --git a/book/listings/actions/2/main.rs b/book/listings/actions/2/main.rs index fdc3f8df3e97..150bb172be45 100644 --- a/book/listings/actions/2/main.rs +++ b/book/listings/actions/2/main.rs @@ -1,10 +1,9 @@ -use gio::SimpleAction; +use gio::ActionEntry; use glib::clone; use gtk::gio::SimpleActionGroup; use gtk::prelude::*; use gtk::{gio, glib, Application, ApplicationWindow}; -// ANCHOR: main const APP_ID: &str = "org.gtk_rs.Actions2"; fn main() -> glib::ExitCode { @@ -13,14 +12,14 @@ fn main() -> glib::ExitCode { // Connect to "activate" signal of `app` app.connect_activate(build_ui); - - // Set keyboard accelerator to trigger "win.close". - app.set_accels_for_action("win.close", &["W"]); + // ANCHOR: accel + // Set keyboard accelerator to trigger "custom-group.close". + app.set_accels_for_action("custom-group.close", &["W"]); + // ANCHOR_END: accel // Run the application app.run() } -// ANCHOR_END: main // ANCHOR: build_ui fn build_ui(app: &Application) { @@ -32,17 +31,17 @@ fn build_ui(app: &Application) { .build(); // Add action "close" to `window` taking no parameter - let action_close = SimpleAction::new("close", None); - action_close.connect_activate(clone!(@weak window => move |_, _| { - window.close(); - })); - window.add_action(&action_close); + let action_close = ActionEntry::builder("close") + .activate(clone!(@weak window => move |_, _, _| { + window.close(); + })) + .build(); // ANCHOR: action_group // Create a new action group and add actions to it let actions = SimpleActionGroup::new(); - window.insert_action_group("win", Some(&actions)); - actions.add_action(&action_close); + actions.add_action_entries([action_close]); + window.insert_action_group("custom-group", Some(&actions)); // ANCHOR_END: action_group // Present window diff --git a/book/listings/actions/3/main.rs b/book/listings/actions/3/main.rs index 0a30d6319d55..5b8654c29112 100644 --- a/book/listings/actions/3/main.rs +++ b/book/listings/actions/3/main.rs @@ -1,5 +1,4 @@ -use gio::SimpleAction; -use glib::clone; +use gio::ActionEntry; use gtk::prelude::*; use gtk::{ gio, glib, Align, Application, ApplicationWindow, Button, Label, Orientation, @@ -59,33 +58,32 @@ fn build_ui(app: &Application) { .build(); // Add action "count" to `window` taking an integer as parameter - let action_count = SimpleAction::new_stateful( - "count", - Some(&i32::static_variant_type()), - &original_state.to_variant(), - ); - action_count.connect_activate(clone!(@weak label => move |action, parameter| { - // Get state - let mut state = action - .state() - .expect("Could not get state.") - .get::() - .expect("The variant needs to be of type `i32`."); + let action_count = ActionEntry::builder("count") + .parameter_type(Some(&i32::static_variant_type())) + .state(original_state.to_variant()) + .activate(move |_, action, parameter| { + // Get state + let mut state = action + .state() + .expect("Could not get state.") + .get::() + .expect("The variant needs to be of type `i32`."); - // Get parameter - let parameter = parameter - .expect("Could not get parameter.") - .get::() - .expect("The variant needs to be of type `i32`."); + // Get parameter + let parameter = parameter + .expect("Could not get parameter.") + .get::() + .expect("The variant needs to be of type `i32`."); - // Increase state by parameter and store state - state += parameter; - action.set_state(&state.to_variant()); + // Increase state by parameter and store state + state += parameter; + action.set_state(&state.to_variant()); - // Update label with new state - label.set_label(&format!("Counter: {state}")); - })); - window.add_action(&action_count); + // Update label with new state + label.set_label(&format!("Counter: {state}")); + }) + .build(); + window.add_action_entries([action_count]); // Present window window.present(); diff --git a/book/listings/actions/4/main.rs b/book/listings/actions/4/main.rs index de23d3e4a568..3aa1522439f8 100644 --- a/book/listings/actions/4/main.rs +++ b/book/listings/actions/4/main.rs @@ -1,5 +1,4 @@ -use gio::SimpleAction; -use glib::clone; +use gio::ActionEntry; use gtk::prelude::*; use gtk::{ gio, glib, Align, Application, ApplicationWindow, Button, Label, Orientation, @@ -55,34 +54,32 @@ fn build_ui(app: &Application) { .build(); // Add action "count" to `window` taking an integer as parameter - let action_count = SimpleAction::new_stateful( - "count", - Some(&i32::static_variant_type()), - &original_state.to_variant(), - ); - action_count.connect_activate(clone!(@weak label => move |action, parameter| { - // Get state - let mut state = action - .state() - .expect("Could not get state.") - .get::() - .expect("The value needs to be of type `i32`."); + let action_count = ActionEntry::builder("count") + .parameter_type(Some(&i32::static_variant_type())) + .state(original_state.to_variant()) + .activate(move |_, action, parameter| { + // Get state + let mut state = action + .state() + .expect("Could not get state.") + .get::() + .expect("The variant needs to be of type `i32`."); - // Get parameter - let parameter = parameter - .expect("Could not get parameter.") - .get::() - .expect("The value needs to be of type `i32`."); + // Get parameter + let parameter = parameter + .expect("Could not get parameter.") + .get::() + .expect("The variant needs to be of type `i32`."); - // Increase state by parameter and save state - state += parameter; - action.set_state(&state.to_variant()); + // Increase state by parameter and store state + state += parameter; + action.set_state(&state.to_variant()); - // Update label with new state - label.set_label(&format!("Counter: {state}")); - })); - - window.add_action(&action_count); + // Update label with new state + label.set_label(&format!("Counter: {state}")); + }) + .build(); + window.add_action_entries([action_count]); // Present window window.present(); diff --git a/book/listings/actions/5/window/mod.rs b/book/listings/actions/5/window/mod.rs index 8d3ca104e134..7dba0d7a79ee 100644 --- a/book/listings/actions/5/window/mod.rs +++ b/book/listings/actions/5/window/mod.rs @@ -1,7 +1,7 @@ mod imp; -use gio::SimpleAction; -use glib::{clone, Object}; +use gio::ActionEntry; +use glib::Object; use gtk::prelude::*; use gtk::subclass::prelude::*; use gtk::{gio, glib, Application}; @@ -21,38 +21,34 @@ impl Window { } fn setup_actions(&self) { - let label = self.imp().label.get(); - // Add stateful action "count" to `window` taking an integer as parameter let original_state = 0; - let action_count = SimpleAction::new_stateful( - "count", - Some(&i32::static_variant_type()), - &original_state.to_variant(), - ); - - action_count.connect_activate(clone!(@weak label => move |action, parameter| { - // Get state - let mut state = action - .state() - .expect("Could not get state.") - .get::() - .expect("The value needs to be of type `i32`."); - - // Get parameter - let parameter = parameter - .expect("Could not get parameter.") - .get::() - .expect("The value needs to be of type `i32`."); - - // Increase state by parameter and save state - state += parameter; - action.set_state(&state.to_variant()); - - // Update label with new state - label.set_label(&format!("Counter: {state}")); - })); - self.add_action(&action_count); + let action_count = ActionEntry::builder("count") + .parameter_type(Some(&i32::static_variant_type())) + .state(original_state.to_variant()) + .activate(move |window: &Self, action, parameter| { + // Get state + let mut state = action + .state() + .expect("Could not get state.") + .get::() + .expect("The variant needs to be of type `i32`."); + + // Get parameter + let parameter = parameter + .expect("Could not get parameter.") + .get::() + .expect("The variant needs to be of type `i32`."); + + // Increase state by parameter and store state + state += parameter; + action.set_state(&state.to_variant()); + + // Update label with new state + window.imp().label.set_label(&format!("Counter: {state}")); + }) + .build(); + self.add_action_entries([action_count]); } } // ANCHOR_END: impl_window diff --git a/book/listings/actions/6/window/mod.rs b/book/listings/actions/6/window/mod.rs index ccba724398e0..f1889afdd21a 100644 --- a/book/listings/actions/6/window/mod.rs +++ b/book/listings/actions/6/window/mod.rs @@ -1,7 +1,7 @@ mod imp; -use gio::{PropertyAction, SimpleAction}; -use glib::{clone, Object}; +use gio::{ActionEntry, PropertyAction}; +use glib::Object; use gtk::prelude::*; use gtk::subclass::prelude::*; use gtk::{gio, glib, Application, Orientation}; @@ -21,40 +21,33 @@ impl Window { // ANCHOR: setup_actions fn setup_actions(&self) { - // Get state - let label = self.imp().label.get(); - // Add stateful action "count" to `window` taking an integer as parameter let original_state = 0; - let action_count = SimpleAction::new_stateful( - "count", - Some(&i32::static_variant_type()), - &original_state.to_variant(), - ); - - action_count.connect_activate(clone!(@weak label => move |action, parameter| { - // Get state - let mut state = action - .state() - .expect("Could not get state.") - .get::() - .expect("The value needs to be of type `i32`."); + let action_count = ActionEntry::builder("count") + .parameter_type(Some(&i32::static_variant_type())) + .state(original_state.to_variant()) + .activate(move |window: &Self, action, parameter| { + // Get state + let mut state = action + .state() + .expect("Could not get state.") + .get::() + .expect("The variant needs to be of type `i32`."); - // Get parameter - let parameter = parameter - .expect("Could not get parameter.") - .get::() - .expect("The value needs to be of type `i32`."); - - // Increase state by parameter and save state - state += parameter; - action.set_state(&state.to_variant()); + // Get parameter + let parameter = parameter + .expect("Could not get parameter.") + .get::() + .expect("The variant needs to be of type `i32`."); - // Update label with new state - label.set_label(&format!("Counter: {state}")); - })); - self.add_action(&action_count); + // Increase state by parameter and store state + state += parameter; + action.set_state(&state.to_variant()); + // Update label with new state + window.imp().label.set_label(&format!("Counter: {state}")); + }) + .build(); // ANCHOR: action_button_frame // Add property action "button-frame" to `window` let button = self.imp().button.get(); @@ -64,17 +57,11 @@ impl Window { // ANCHOR_END: action_button_frame // ANCHOR: action_orientation - // Add stateful action "orientation" to `window` taking a string as parameter - let gtk_box = self.imp().gtk_box.get(); - let action_orientation = SimpleAction::new_stateful( - "orientation", - Some(&String::static_variant_type()), - &"Vertical".to_variant(), - ); - - action_orientation.connect_activate(clone!(@weak gtk_box => - move |action, parameter| { + let action_orientation = ActionEntry::builder("orientation") + .parameter_type(Some(&String::static_variant_type())) + .state("Vertical".to_variant()) + .activate(move |window: &Self, action, parameter| { // Get parameter let parameter = parameter .expect("Could not get parameter.") @@ -84,14 +71,15 @@ impl Window { let orientation = match parameter.as_str() { "Horizontal" => Orientation::Horizontal, "Vertical" => Orientation::Vertical, - _ => unreachable!() + _ => unreachable!(), }; // Set orientation and save state - gtk_box.set_orientation(orientation); + window.imp().gtk_box.set_orientation(orientation); action.set_state(¶meter.to_variant()); - })); - self.add_action(&action_orientation); + }) + .build(); + self.add_action_entries([action_count, action_orientation]); //ANCHOR_END: action_orientation } // ANCHOR_END: setup_actions diff --git a/book/listings/actions/7/resources/window.ui b/book/listings/actions/7/resources/window.ui index 246ae20adde4..f41fe12bc97e 100644 --- a/book/listings/actions/7/resources/window.ui +++ b/book/listings/actions/7/resources/window.ui @@ -3,7 +3,7 @@ _Close window - win.close + window.close _Toggle button frame diff --git a/book/listings/actions/7/window/mod.rs b/book/listings/actions/7/window/mod.rs index e5a5a887b1cb..4a1f9ae006eb 100644 --- a/book/listings/actions/7/window/mod.rs +++ b/book/listings/actions/7/window/mod.rs @@ -1,7 +1,7 @@ mod imp; -use gio::{Settings, SimpleAction}; -use glib::{clone, Object}; +use gio::{ActionEntry, Settings}; +use glib::Object; use gtk::prelude::*; use gtk::subclass::prelude::*; use gtk::{gio, glib, Application, Orientation}; @@ -39,47 +39,34 @@ impl Window { // ANCHOR_END: settings fn setup_actions(&self) { - // Get state - let label = self.imp().label.get(); - // Add stateful action "count" to `window` taking an integer as parameter let original_state = 0; - let action_count = SimpleAction::new_stateful( - "count", - Some(&i32::static_variant_type()), - &original_state.to_variant(), - ); - - action_count.connect_activate(clone!(@weak label => move |action, parameter| { - // Get state - let mut state = action - .state() - .expect("Could not get state.") - .get::() - .expect("The variant needs to be of type `i32`."); - - // Get parameter - let parameter = parameter - .expect("Could not get parameter.") - .get::() - .expect("The variant needs to be of type `i32`."); - - // Increase state by parameter and save state - state += parameter; - action.set_state(&state.to_variant()); - - // Update label with new state - label.set_label(&format!("Counter: {state}")); - })); - self.add_action(&action_count); - - // Add action "close" to `window` taking no parameter - let action_close = SimpleAction::new("close", None); - - action_close.connect_activate(clone!(@weak self as window => move |_, _| { - window.close(); - })); - self.add_action(&action_close); + let action_count = ActionEntry::builder("count") + .parameter_type(Some(&i32::static_variant_type())) + .state(original_state.to_variant()) + .activate(move |window: &Self, action, parameter| { + // Get state + let mut state = action + .state() + .expect("Could not get state.") + .get::() + .expect("The variant needs to be of type `i32`."); + + // Get parameter + let parameter = parameter + .expect("Could not get parameter.") + .get::() + .expect("The variant needs to be of type `i32`."); + + // Increase state by parameter and store state + state += parameter; + action.set_state(&state.to_variant()); + + // Update label with new state + window.imp().label.set_label(&format!("Counter: {state}")); + }) + .build(); + self.add_action_entries([action_count]); // ANCHOR: settings_create_actions // Create action from key "button-frame" and add to action group "win" @@ -94,8 +81,6 @@ impl Window { // ANCHOR: bind_settings fn bind_settings(&self) { - // Get state - // Bind setting "button-frame" to "has-frame" property of `button` let button = self.imp().button.get(); self.settings() diff --git a/book/listings/todo/2/window/mod.rs b/book/listings/todo/2/window/mod.rs index a0583179beb2..610a67360350 100644 --- a/book/listings/todo/2/window/mod.rs +++ b/book/listings/todo/2/window/mod.rs @@ -57,8 +57,6 @@ impl Window { // ANCHOR: filter fn filter(&self) -> Option { - // Get state - // Get filter_state from settings let filter_state: String = self.settings().get("filter"); @@ -226,10 +224,8 @@ impl Window { self.add_action(&action_filter); // Create action to remove done tasks and add to action group "win" - let action_remove_done_tasks = - gio::SimpleAction::new("remove-done-tasks", None); - action_remove_done_tasks.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_remove_done_tasks = gio::ActionEntry::builder("remove-done-tasks") + .activate(move |window: &Self, _, _| { let tasks = window.tasks(); let mut position = 0; while let Some(item) = tasks.item(position) { @@ -244,9 +240,9 @@ impl Window { position += 1; } } - }), - ); - self.add_action(&action_remove_done_tasks); + }) + .build(); + self.add_action_entries([action_remove_done_tasks]); } // ANCHOR_END: setup_actions } diff --git a/book/listings/todo/3/window/mod.rs b/book/listings/todo/3/window/mod.rs index 01a3c73d4b11..ca1bec27eda2 100644 --- a/book/listings/todo/3/window/mod.rs +++ b/book/listings/todo/3/window/mod.rs @@ -54,8 +54,6 @@ impl Window { } fn filter(&self) -> Option { - // Get state - // Get filter state from settings let filter_state: String = self.settings().get("filter"); @@ -215,10 +213,8 @@ impl Window { self.add_action(&action_filter); // Create action to remove done tasks and add to action group "win" - let action_remove_done_tasks = - gio::SimpleAction::new("remove-done-tasks", None); - action_remove_done_tasks.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_remove_done_tasks = gio::ActionEntry::builder("remove-done-tasks") + .activate(move |window: &Self, _, _| { let tasks = window.tasks(); let mut position = 0; while let Some(item) = tasks.item(position) { @@ -233,8 +229,8 @@ impl Window { position += 1; } } - }), - ); - self.add_action(&action_remove_done_tasks); + }) + .build(); + self.add_action_entries([action_remove_done_tasks]); } } diff --git a/book/listings/todo/4/window/mod.rs b/book/listings/todo/4/window/mod.rs index ead2bc7da805..732da8353fcd 100644 --- a/book/listings/todo/4/window/mod.rs +++ b/book/listings/todo/4/window/mod.rs @@ -212,10 +212,8 @@ impl Window { self.add_action(&action_filter); // Create action to remove done tasks and add to action group "win" - let action_remove_done_tasks = - gio::SimpleAction::new("remove-done-tasks", None); - action_remove_done_tasks.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_remove_done_tasks = gio::ActionEntry::builder("remove-done-tasks") + .activate(move |window: &Self, _, _| { let tasks = window.tasks(); let mut position = 0; while let Some(item) = tasks.item(position) { @@ -230,8 +228,8 @@ impl Window { position += 1; } } - }), - ); - self.add_action(&action_remove_done_tasks); + }) + .build(); + self.add_action_entries([action_remove_done_tasks]); } } diff --git a/book/listings/todo/5/window/mod.rs b/book/listings/todo/5/window/mod.rs index e11a56e1afdb..d49a82e35306 100644 --- a/book/listings/todo/5/window/mod.rs +++ b/book/listings/todo/5/window/mod.rs @@ -213,10 +213,8 @@ impl Window { self.add_action(&action_filter); // Create action to remove done tasks and add to action group "win" - let action_remove_done_tasks = - gio::SimpleAction::new("remove-done-tasks", None); - action_remove_done_tasks.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_remove_done_tasks = gio::ActionEntry::builder("remove-done-tasks") + .activate(move |window: &Self, _, _| { let tasks = window.tasks(); let mut position = 0; while let Some(item) = tasks.item(position) { @@ -231,8 +229,8 @@ impl Window { position += 1; } } - }), - ); - self.add_action(&action_remove_done_tasks); + }) + .build(); + self.add_action_entries([action_remove_done_tasks]); } } diff --git a/book/listings/todo/6/window/mod.rs b/book/listings/todo/6/window/mod.rs index 284b56cbb78c..c73fe63fb5aa 100644 --- a/book/listings/todo/6/window/mod.rs +++ b/book/listings/todo/6/window/mod.rs @@ -213,10 +213,8 @@ impl Window { self.add_action(&action_filter); // Create action to remove done tasks and add to action group "win" - let action_remove_done_tasks = - gio::SimpleAction::new("remove-done-tasks", None); - action_remove_done_tasks.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_remove_done_tasks = gio::ActionEntry::builder("remove-done-tasks") + .activate(move |window: &Self, _, _| { let tasks = window.tasks(); let mut position = 0; while let Some(item) = tasks.item(position) { @@ -231,8 +229,8 @@ impl Window { position += 1; } } - }), - ); - self.add_action(&action_remove_done_tasks); + }) + .build(); + self.add_action_entries([action_remove_done_tasks]); } } diff --git a/book/listings/todo/7/window/mod.rs b/book/listings/todo/7/window/mod.rs index 76cdd83ae3b5..bf9194576f47 100644 --- a/book/listings/todo/7/window/mod.rs +++ b/book/listings/todo/7/window/mod.rs @@ -216,10 +216,8 @@ impl Window { self.add_action(&action_filter); // Create action to remove done tasks and add to action group "win" - let action_remove_done_tasks = - gio::SimpleAction::new("remove-done-tasks", None); - action_remove_done_tasks.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_remove_done_tasks = gio::ActionEntry::builder("remove-done-tasks") + .activate(move |window: &Self, _, _| { let tasks = window.tasks(); let mut position = 0; while let Some(item) = tasks.item(position) { @@ -234,8 +232,8 @@ impl Window { position += 1; } } - }), - ); - self.add_action(&action_remove_done_tasks); + }) + .build(); + self.add_action_entries([action_remove_done_tasks]); } } diff --git a/book/listings/todo/8/window/mod.rs b/book/listings/todo/8/window/mod.rs index b2120f546932..944a541bf8f5 100644 --- a/book/listings/todo/8/window/mod.rs +++ b/book/listings/todo/8/window/mod.rs @@ -363,10 +363,8 @@ impl Window { self.add_action(&action_filter); // Create action to remove done tasks and add to action group "win" - let action_remove_done_tasks = - gio::SimpleAction::new("remove-done-tasks", None); - action_remove_done_tasks.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_remove_done_tasks = gio::ActionEntry::builder("remove-done-tasks") + .activate(move |window: &Self, _, _| { let tasks = window.tasks(); let mut position = 0; while let Some(item) = tasks.item(position) { @@ -381,19 +379,17 @@ impl Window { position += 1; } } - }), - ); - self.add_action(&action_remove_done_tasks); + }) + .build(); // ANCHOR: setup_actions // Create action to create new collection and add to action group "win" - let action_new_collection = gio::SimpleAction::new("new-collection", None); - action_new_collection.connect_activate( - clone!(@weak self as window => move |_, _| { + let action_new_collection = gio::ActionEntry::builder("new-collection") + .activate(move |window: &Self, _, _| { window.new_collection(); - }), - ); - self.add_action(&action_new_collection); + }) + .build(); + self.add_action_entries([action_remove_done_tasks, action_new_collection]); // ANCHOR_END: setup_actions } diff --git a/book/src/actions.md b/book/src/actions.md index 48676f9cea1a..194630c8aaf4 100644 --- a/book/src/actions.md +++ b/book/src/actions.md @@ -13,8 +13,9 @@ Filename: listings/actions/1/main.rs @@ -33,18 +34,29 @@ The answer is that it is so common to add actions to windows and applications th - "app" for actions global to the application, and - "win" for actions tied to an application window. -If that had not been the case, we would have to add the action group manually via [`gio::SimpleActionGroup`](https://gtk-rs.org/gtk-rs-core/stable/latest/docs/gio/struct.SimpleActionGroup.html). +We can add an action group to any widget via the method [`insert_action_group`](https://gtk-rs.org/gtk4-rs/stable/latest/docs/gtk4/prelude/trait.WidgetExt.html#method.insert_action_group). +Let's add our action to the action group "custom-group" and add the group then to our window. +The action entry isn't specific to our window anymore, the first parameter of the "activate" callback is of type `SimpleActionGroup` instead of `ApplicationWindow`. +This means we have to clone `window` into the closure. Filename: listings/actions/2/main.rs ```rust -{{#rustdoc_include ../listings/actions/2/main.rs:action_group}} +{{#rustdoc_include ../listings/actions/2/main.rs:build_ui}} ``` -Also, if we had multiple instances of the same windows we would expect that only the currently focused window will be closed when activating "win.close". +If we bind the accelerator to "custom-group.close", it works just as before. + +Filename: listings/actions/2/main.rs + +```rust +{{#rustdoc_include ../listings/actions/2/main.rs:accel}} +``` + +Also, if we had multiple instances of the same windows, we would expect that only the currently focused window will be closed when activating "win.close". And indeed, the "win.close" will be dispatched to the currently focused window. However, that also means that we actually define one action per window instance. -If we want to have a single globally accessible action instead, we call `add_action` on our application instead. +If we want to have a single globally accessible action instead, we call `add_action_entries` on our application instead. > Adding "win.close" was useful as a simple example. > However, in the future we will use the pre-defined ["window.close"](https://gtk-rs.org/gtk4-rs/stable/latest/docs/gtk4/struct.Window.html#actions) action which does exactly the same thing. @@ -61,7 +73,7 @@ Filename: listings/actions/7/window/mod.rs @@ -297,5 +309,5 @@ Filename: