diff --git a/.github/workflows/windows-msvc.yml b/.github/workflows/windows-msvc.yml index 19c4e039725b..7b04aa97f9f8 100644 --- a/.github/workflows/windows-msvc.yml +++ b/.github/workflows/windows-msvc.yml @@ -45,7 +45,7 @@ jobs: - name: Install pkgconfig-lite run: | - Invoke-WebRequest -Uri https://deac-fra.dl.sourceforge.net/project/pkgconfiglite/0.28-1/pkg-config-lite-0.28-1_bin-win32.zip -OutFile /pkg_config_lite.zip -MaximumRetryCount 5 + Invoke-WebRequest -UserAgent "Wget" -Uri https://downloads.sourceforge.net/project/pkgconfiglite/0.28-1/pkg-config-lite-0.28-1_bin-win32.zip -OutFile /pkg_config_lite.zip -MaximumRetryCount 5 Expand-Archive /pkg_config_lite.zip -DestinationPath C:\ ls C:\ ls C:\pkg-config-lite-0.28-1 diff --git a/Cargo.lock b/Cargo.lock index 91612444e4a8..330eec3d3061 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,7 +128,7 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cairo-rs" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "bitflags 2.5.0", "cairo-sys-rs", @@ -140,7 +140,7 @@ dependencies = [ [[package]] name = "cairo-sys-rs" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "glib-sys", "libc", @@ -392,7 +392,7 @@ dependencies = [ [[package]] name = "gdk-pixbuf" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "gdk-pixbuf-sys", "gio", @@ -403,7 +403,7 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "gio-sys", "glib-sys", @@ -552,7 +552,7 @@ checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "gio" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "futures-channel", "futures-core", @@ -569,7 +569,7 @@ dependencies = [ [[package]] name = "gio-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "glib-sys", "gobject-sys", @@ -618,7 +618,7 @@ dependencies = [ [[package]] name = "glib" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "bitflags 2.5.0", "futures-channel", @@ -639,7 +639,7 @@ dependencies = [ [[package]] name = "glib-macros" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "heck", "proc-macro-crate", @@ -651,7 +651,7 @@ dependencies = [ [[package]] name = "glib-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "libc", "system-deps", @@ -693,7 +693,7 @@ dependencies = [ [[package]] name = "gobject-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "glib-sys", "libc", @@ -703,7 +703,7 @@ dependencies = [ [[package]] name = "graphene-rs" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "glib", "graphene-sys", @@ -713,7 +713,7 @@ dependencies = [ [[package]] name = "graphene-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "glib-sys", "libc", @@ -1108,9 +1108,9 @@ checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" @@ -1184,7 +1184,7 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "pango" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "gio", "glib", @@ -1195,7 +1195,7 @@ dependencies = [ [[package]] name = "pango-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#2579e50c7677474152e0eba2dc78222cff30b4ca" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#dc97710becdf432e5a97e0b7c22d4d1daa8cfec6" dependencies = [ "glib-sys", "gobject-sys", @@ -2151,11 +2151,11 @@ dependencies = [ [[package]] name = "windows" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core 0.56.0", + "windows-core 0.57.0", "windows-targets 0.52.5", ] @@ -2170,9 +2170,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ "windows-implement", "windows-interface", @@ -2182,9 +2182,9 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", @@ -2193,9 +2193,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.56.0" +version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", diff --git a/examples/about_dialog/main.rs b/examples/about_dialog/main.rs index 8cbed0319151..0272580d70b6 100644 --- a/examples/about_dialog/main.rs +++ b/examples/about_dialog/main.rs @@ -27,20 +27,24 @@ fn main() { let bytes = glib::Bytes::from_static(LOGO_SVG); let logo = gdk::Texture::from_bytes(&bytes).expect("gtk-rs.svg to load"); - button.connect_clicked(glib::clone!(@weak window => move |_| { - let dialog = gtk::AboutDialog::builder() - .transient_for(&window) - .modal(true) - .program_name("About Dialog Example") - .version("0.1.0") - .website("https://gtk-rs.org") - .license_type(gtk::License::MitX11) - .authors(["Author 1", "Author 2"]) - .logo(&logo) - .build(); - - dialog.present(); - })); + button.connect_clicked(glib::clone!( + #[weak] + window, + move |_| { + let dialog = gtk::AboutDialog::builder() + .transient_for(&window) + .modal(true) + .program_name("About Dialog Example") + .version("0.1.0") + .website("https://gtk-rs.org") + .license_type(gtk::License::MitX11) + .authors(["Author 1", "Author 2"]) + .logo(&logo) + .build(); + + dialog.present(); + } + )); window.present(); }); diff --git a/examples/clipboard/main.rs b/examples/clipboard/main.rs index 7f6c3b759a60..b4e91c070166 100644 --- a/examples/clipboard/main.rs +++ b/examples/clipboard/main.rs @@ -54,23 +54,42 @@ fn build_ui(application: >k::Application) { text_container.append(&from_entry); let copy_btn = gtk::Button::with_label("Copy"); - copy_btn.connect_clicked(clone!(@weak clipboard, @weak from_entry => move |_btn| { - let text = from_entry.text(); - clipboard.set_text(&text); - })); + copy_btn.connect_clicked(clone!( + #[weak] + clipboard, + #[weak] + from_entry, + move |_btn| { + let text = from_entry.text(); + clipboard.set_text(&text); + } + )); text_container.append(©_btn); let into_entry = gtk::Entry::new(); text_container.append(&into_entry); let paste_btn = gtk::Button::with_label("Paste"); - paste_btn.connect_clicked(clone!(@weak clipboard, @weak into_entry => move |_btn| { - clipboard.read_text_async(gio::Cancellable::NONE, clone!(@weak into_entry => move|res| { - if let Ok(Some(text)) = res { - into_entry.set_text(&text); - } - })); - })); + paste_btn.connect_clicked(clone!( + #[weak] + clipboard, + #[weak] + into_entry, + move |_btn| { + clipboard.read_text_async( + gio::Cancellable::NONE, + clone!( + #[weak] + into_entry, + move |res| { + if let Ok(Some(text)) = res { + into_entry.set_text(&text); + } + } + ), + ); + } + )); text_container.append(&paste_btn); container.append(&text_container); @@ -100,10 +119,19 @@ fn build_ui(application: >k::Application) { .label("Copy") .valign(gtk::Align::Center) .build(); - copy_texture_btn.connect_clicked(clone!(@weak clipboard, @weak image_from => move |_btn| { - let texture = image_from.paintable().and_downcast::().unwrap(); - clipboard.set_texture(&texture); - })); + copy_texture_btn.connect_clicked(clone!( + #[weak] + clipboard, + #[weak] + image_from, + move |_btn| { + let texture = image_from + .paintable() + .and_downcast::() + .unwrap(); + clipboard.set_texture(&texture); + } + )); texture_container.append(©_texture_btn); let image_into = gtk::Image::builder() @@ -115,13 +143,24 @@ fn build_ui(application: >k::Application) { .label("Paste") .valign(gtk::Align::Center) .build(); - paste_texture_btn.connect_clicked(clone!(@weak clipboard => move |_btn| { - clipboard.read_texture_async(gio::Cancellable::NONE, clone!(@weak image_into => move |res| { - if let Ok(Some(texture)) = res { - image_into.set_paintable(Some(&texture)); - } - })); - })); + paste_texture_btn.connect_clicked(clone!( + #[weak] + clipboard, + move |_btn| { + clipboard.read_texture_async( + gio::Cancellable::NONE, + clone!( + #[weak] + image_into, + move |res| { + if let Ok(Some(texture)) = res { + image_into.set_paintable(Some(&texture)); + } + } + ), + ); + } + )); texture_container.append(&paste_texture_btn); container.append(&texture_container); diff --git a/examples/confetti_snapshot_animation/confetti_widget/mod.rs b/examples/confetti_snapshot_animation/confetti_widget/mod.rs index 0c686d298a3e..7fd02de499ea 100644 --- a/examples/confetti_snapshot_animation/confetti_widget/mod.rs +++ b/examples/confetti_snapshot_animation/confetti_widget/mod.rs @@ -27,17 +27,23 @@ impl ConfettiWidget { let frame_clock = self.frame_clock().unwrap(); exp.init_time(&frame_clock, duration); - frame_clock.connect_update(clone!(@weak self as this, @weak exp => move |clock| { - match exp.update(clock) { - ControlFlow::Continue => { - this.queue_draw(); - }, - ControlFlow::Break => { - this.imp().explosions.borrow_mut().remove(&exp); - clock.end_updating(); + frame_clock.connect_update(clone!( + #[weak(rename_to = this)] + self, + #[weak] + exp, + move |clock| { + match exp.update(clock) { + ControlFlow::Continue => { + this.queue_draw(); + } + ControlFlow::Break => { + this.imp().explosions.borrow_mut().remove(&exp); + clock.end_updating(); + } } } - })); + )); self.imp().explosions.borrow_mut().insert(exp.clone()); frame_clock.begin_updating(); exp diff --git a/examples/content_provider/main.rs b/examples/content_provider/main.rs index 3647aec2219f..4f20724175c5 100644 --- a/examples/content_provider/main.rs +++ b/examples/content_provider/main.rs @@ -17,15 +17,32 @@ fn on_activate(application: >k::Application) { // both GtkRootExt and GtkWidgetExt trait. let display = WidgetExt::display(&window); - window.connect_realize(glib::clone!(@weak display, @weak application => move |_| { - let provider = ContentProvider::default(); - display.clipboard().set_content(Some(&provider)).unwrap(); - glib::MainContext::default().spawn_local(glib::clone!(@weak display, @weak application => async move { - let text = display.clipboard().read_text_future().await.unwrap().unwrap(); - assert_eq!(text.as_str(), "Hello clipboard!"); - application.quit(); - })); - })); + window.connect_realize(glib::clone!( + #[weak] + display, + #[weak] + application, + move |_| { + let provider = ContentProvider::default(); + display.clipboard().set_content(Some(&provider)).unwrap(); + glib::MainContext::default().spawn_local(glib::clone!( + #[weak] + display, + #[weak] + application, + async move { + let text = display + .clipboard() + .read_text_future() + .await + .unwrap() + .unwrap(); + assert_eq!(text.as_str(), "Hello clipboard!"); + application.quit(); + } + )); + } + )); window.present(); } diff --git a/examples/custom_editable/custom_tag/imp.rs b/examples/custom_editable/custom_tag/imp.rs index 17b509ea1fc8..34a8b0833515 100644 --- a/examples/custom_editable/custom_tag/imp.rs +++ b/examples/custom_editable/custom_tag/imp.rs @@ -58,9 +58,13 @@ impl ObjectImpl for CustomTag { self.container.append(&self.label); let gesture = gtk::GestureClick::new(); - gesture.connect_released(clone!(@weak tag => move |_gesture, _n_press, _x, _y| { - tag.emit_by_name::<()>("clicked", &[]); - })); + gesture.connect_released(clone!( + #[weak] + tag, + move |_gesture, _n_press, _x, _y| { + tag.emit_by_name::<()>("clicked", &[]); + } + )); tag.add_controller(gesture); } @@ -98,9 +102,13 @@ impl CustomTag { .valign(gtk::Align::Center) .has_frame(false) .build(); - button.connect_clicked(clone!(@weak self as tag => move |_btn| { - tag.obj().emit_by_name::<()>("closed", &[]); - })); + button.connect_clicked(clone!( + #[weak(rename_to = tag)] + self, + move |_btn| { + tag.obj().emit_by_name::<()>("closed", &[]); + } + )); let icon = gtk::Image::from_icon_name("window-close-symbolic"); button.set_child(Some(&icon)); diff --git a/examples/custom_editable/main.rs b/examples/custom_editable/main.rs index 119a73a36a79..83cbc7e0cda0 100644 --- a/examples/custom_editable/main.rs +++ b/examples/custom_editable/main.rs @@ -48,18 +48,39 @@ fn build_ui(application: >k::Application) { let add_tag_button = gtk::Button::with_label("Add Tag"); add_tag_button.set_halign(gtk::Align::Center); - add_tag_button.connect_clicked(clone!(@weak editable => move |_btn| { - let tag = CustomTag::new("Blue"); - tag.connect_local_id(custom_tag::imp::CustomTag::signals()[0].signal_id(), None, false, clone!(@weak editable, @weak tag => @default-return None, move |_args| { - editable.remove_tag(&tag); - None - })); - tag.connect_local_id(custom_tag::imp::CustomTag::signals()[1].signal_id(), None, false, move |_args| { - println!("Tag clicked"); - None - }); - editable.add_tag(&tag); - })); + add_tag_button.connect_clicked(clone!( + #[weak] + editable, + move |_btn| { + let tag = CustomTag::new("Blue"); + tag.connect_local_id( + custom_tag::imp::CustomTag::signals()[0].signal_id(), + None, + false, + clone!( + #[weak] + editable, + #[weak] + tag, + #[upgrade_or_default] + move |_args| { + editable.remove_tag(&tag); + None + } + ), + ); + tag.connect_local_id( + custom_tag::imp::CustomTag::signals()[1].signal_id(), + None, + false, + move |_args| { + println!("Tag clicked"); + None + }, + ); + editable.add_tag(&tag); + } + )); horizontal_container.append(&add_tag_button); let show_spinner = gtk::CheckButton::builder() diff --git a/examples/custom_layout_manager/simple_widget/imp.rs b/examples/custom_layout_manager/simple_widget/imp.rs index d50b05574d1e..a6582dd53b71 100644 --- a/examples/custom_layout_manager/simple_widget/imp.rs +++ b/examples/custom_layout_manager/simple_widget/imp.rs @@ -33,9 +33,13 @@ impl ObjectImpl for SimpleWidget { let gesture = gtk::GestureClick::new(); // Trigger a transition on click let obj = self.obj(); - gesture.connect_pressed(clone!(@strong obj as this => move |_, _, _, _| { - this.do_transition(); - })); + gesture.connect_pressed(clone!( + #[weak(rename_to = this)] + obj, + move |_, _, _, _| { + this.do_transition(); + } + )); self.obj().add_controller(gesture); } diff --git a/examples/custom_layout_manager/simple_widget/mod.rs b/examples/custom_layout_manager/simple_widget/mod.rs index 222f99f056c5..974dd1c30acb 100644 --- a/examples/custom_layout_manager/simple_widget/mod.rs +++ b/examples/custom_layout_manager/simple_widget/mod.rs @@ -32,10 +32,12 @@ impl SimpleWidget { let start_time = std::time::Instant::now(); imp.start_time.replace(Some(start_time)); - let tick_id = - self.add_tick_callback(clone!(@weak self as this => @default-panic, move |_, _| { - this.transition() - })); + let tick_id = self.add_tick_callback(clone!( + #[weak(rename_to = this)] + self, + #[upgrade_or_panic] + move |_, _| this.transition() + )); imp.tick_id.replace(Some(tick_id)); } diff --git a/examples/custom_orientable/main.rs b/examples/custom_orientable/main.rs index ad14676cb733..acb178a8f876 100644 --- a/examples/custom_orientable/main.rs +++ b/examples/custom_orientable/main.rs @@ -13,13 +13,21 @@ fn main() -> glib::ExitCode { let orientable = CustomOrientable::default(); let button = gtk::Button::with_label("Switch orientation"); - button.connect_clicked(glib::clone!(@weak orientable => move |_| { - match orientable.orientation() { - gtk::Orientation::Horizontal => orientable.set_orientation(gtk::Orientation::Vertical), - gtk::Orientation::Vertical => orientable.set_orientation(gtk::Orientation::Horizontal), - _ => unreachable!(), - }; - })); + button.connect_clicked(glib::clone!( + #[weak] + orientable, + move |_| { + match orientable.orientation() { + gtk::Orientation::Horizontal => { + orientable.set_orientation(gtk::Orientation::Vertical) + } + gtk::Orientation::Vertical => { + orientable.set_orientation(gtk::Orientation::Horizontal) + } + _ => unreachable!(), + }; + } + )); orientable.set_halign(gtk::Align::Center); bx.append(&orientable); diff --git a/examples/dialog/main.rs b/examples/dialog/main.rs index 1d6cc8cf76c7..e5be7de93a1a 100644 --- a/examples/dialog/main.rs +++ b/examples/dialog/main.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use gtk::{ glib::{self, clone}, prelude::*, @@ -21,20 +19,20 @@ fn build_ui(application: >k::Application) { .valign(gtk::Align::Center) .build(); - let window = Rc::new( - gtk::ApplicationWindow::builder() - .application(application) - .title("Dialog Example") - .default_width(350) - .default_height(70) - .child(&button) - .visible(true) - .build(), - ); + let window = gtk::ApplicationWindow::builder() + .application(application) + .title("Dialog Example") + .default_width(350) + .default_height(70) + .child(&button) + .visible(true) + .build(); - button.connect_clicked(clone!(@strong window => + button.connect_clicked(clone!( + #[weak] + window, move |_| { - gtk::glib::MainContext::default().spawn_local(dialog(Rc::clone(&window))); + gtk::glib::MainContext::default().spawn_local(dialog(window.clone())); } )); @@ -46,14 +44,14 @@ fn build_ui(application: >k::Application) { }); } -async fn dialog>(window: Rc) { +async fn dialog>(window: W) { let question_dialog = gtk::AlertDialog::builder() .modal(true) .buttons(["Cancel", "Ok"]) .message("What is your answer?") .build(); - let answer = question_dialog.choose_future(Some(&*window)).await; + let answer = question_dialog.choose_future(Some(&window)).await; let info_dialog = gtk::AlertDialog::builder() .modal(true) @@ -61,5 +59,5 @@ async fn dialog>(window: Rc) { .detail(format!("Your answer: {answer:?}")) .build(); - info_dialog.show(Some(&*window)); + info_dialog.show(Some(&window)); } diff --git a/examples/entry_completion/main.rs b/examples/entry_completion/main.rs index 99129fc2767e..2bd8af0a34ae 100644 --- a/examples/entry_completion/main.rs +++ b/examples/entry_completion/main.rs @@ -13,11 +13,13 @@ fn main() -> glib::ExitCode { // When activated, shuts down the application let quit = gio::SimpleAction::new("quit", None); - quit.connect_activate( - glib::clone!(@weak application => move |_action, _parameter| { + quit.connect_activate(glib::clone!( + #[weak] + application, + move |_action, _parameter| { application.quit(); - }), - ); + } + )); application.set_accels_for_action("app.quit", &["Q"]); application.add_action(&quit); diff --git a/examples/gif_paintable/gif_paintable/mod.rs b/examples/gif_paintable/gif_paintable/mod.rs index 74d273673aab..bdcf572c9c16 100644 --- a/examples/gif_paintable/gif_paintable/mod.rs +++ b/examples/gif_paintable/gif_paintable/mod.rs @@ -80,10 +80,14 @@ impl GifPaintable { // setup a callback to this function once the frame has finished so that // we can play the next frame - let update_next_frame_callback = glib::clone!(@weak self as paintable => move || { - paintable.imp().timeout_source_id.take(); - paintable.setup_next_frame(); - }); + let update_next_frame_callback = glib::clone!( + #[weak(rename_to = paintable)] + self, + move || { + paintable.imp().timeout_source_id.take(); + paintable.setup_next_frame(); + } + ); let source_id = glib::timeout_add_local_once(next_frame.frame_duration, update_next_frame_callback); diff --git a/examples/grid_packing/main.rs b/examples/grid_packing/main.rs index 5f61d62e3673..2a30d71d5e5a 100644 --- a/examples/grid_packing/main.rs +++ b/examples/grid_packing/main.rs @@ -47,7 +47,11 @@ fn build_ui(application: >k::Application) { // Create the quit button and put it into the grid at (0, 1) let quit_button = gtk::Button::with_label("Quit"); - quit_button.connect_clicked(clone!(@weak window => move |_| window.destroy())); + quit_button.connect_clicked(clone!( + #[weak] + window, + move |_| window.destroy() + )); grid.attach(&quit_button, 0, 1, 2, 1); diff --git a/examples/gtk_builder/main.rs b/examples/gtk_builder/main.rs index fb8d07082447..eed46d22c12d 100644 --- a/examples/gtk_builder/main.rs +++ b/examples/gtk_builder/main.rs @@ -20,15 +20,19 @@ fn build_ui(application: >k::Application) { .object::("button") .expect("Couldn't get button"); - bigbutton.connect_clicked(glib::clone!(@weak window => move |_| { - gtk::AlertDialog::builder() - .modal(true) - .message("Thank you for trying this example") - .detail("You have pressed the button") - .buttons(["Ok"]) - .build() - .show(Some(&window)); - })); + bigbutton.connect_clicked(glib::clone!( + #[weak] + window, + move |_| { + gtk::AlertDialog::builder() + .modal(true) + .message("Thank you for trying this example") + .detail("You have pressed the button") + .buttons(["Ok"]) + .build() + .show(Some(&window)); + } + )); window.present(); } diff --git a/examples/list_box_model/list_box_row/imp.rs b/examples/list_box_model/list_box_row/imp.rs index ff74d00d817e..94d17a31b7fd 100644 --- a/examples/list_box_model/list_box_row/imp.rs +++ b/examples/list_box_model/list_box_row/imp.rs @@ -60,51 +60,67 @@ impl ObjectImpl for ListBoxRow { // When the edit button is clicked, a new modal dialog is created for editing // the corresponding row let edit_button = gtk::Button::with_label("Edit"); - edit_button.connect_clicked(clone!(@weak item, @weak obj => move |_| { - let parent_window = obj.root().and_downcast::(); - let dialog = gtk::Dialog::with_buttons( - Some("Edit Item"), - parent_window.as_ref(), - gtk::DialogFlags::MODAL, - &[("Close", gtk::ResponseType::Close)], - ); - dialog.set_default_response(gtk::ResponseType::Close); - dialog.connect_response(|dialog, _| dialog.close()); - - let content_area = dialog.content_area(); - - // Similarly to the label and spin button inside the listbox, the text entry - // and spin button in the edit dialog are connected via property bindings to - // the item. Any changes will be immediately reflected inside the item and - // by the listbox - let entry = gtk::Entry::new(); - item.bind_property("name", &entry, "text") - .sync_create().bidirectional() - .build(); - - // Activating the entry (enter) will send response `ResponseType::Close` to the dialog - entry.connect_activate(clone!(@weak dialog => move |_| { - dialog.response(gtk::ResponseType::Close); - })); - content_area.append(&entry); - - let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0); - item.bind_property("count", &spin_button, "value") - .sync_create().bidirectional() - .build(); - content_area.append(&spin_button); - - dialog.present() - })); + edit_button.connect_clicked(clone!( + #[weak] + item, + #[weak] + obj, + move |_| { + let parent_window = obj.root().and_downcast::(); + let dialog = gtk::Dialog::with_buttons( + Some("Edit Item"), + parent_window.as_ref(), + gtk::DialogFlags::MODAL, + &[("Close", gtk::ResponseType::Close)], + ); + dialog.set_default_response(gtk::ResponseType::Close); + dialog.connect_response(|dialog, _| dialog.close()); + + let content_area = dialog.content_area(); + + // Similarly to the label and spin button inside the listbox, the text entry + // and spin button in the edit dialog are connected via property bindings to + // the item. Any changes will be immediately reflected inside the item and + // by the listbox + let entry = gtk::Entry::new(); + item.bind_property("name", &entry, "text") + .sync_create() + .bidirectional() + .build(); + + // Activating the entry (enter) will send response `ResponseType::Close` to the dialog + entry.connect_activate(clone!( + #[weak] + dialog, + move |_| { + dialog.response(gtk::ResponseType::Close); + } + )); + content_area.append(&entry); + + let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0); + item.bind_property("count", &spin_button, "value") + .sync_create() + .bidirectional() + .build(); + content_area.append(&spin_button); + + dialog.present() + } + )); hbox.append(&edit_button); obj.set_child(Some(&hbox)); // When a row is activated (select + enter) we simply emit the clicked // signal on the corresponding edit button to open the edit dialog - obj.connect_activate(clone!(@weak edit_button => move |_| { - edit_button.emit_clicked(); - })); + obj.connect_activate(clone!( + #[weak] + edit_button, + move |_| { + edit_button.emit_clicked(); + } + )); } } diff --git a/examples/list_box_model/main.rs b/examples/list_box_model/main.rs index cb11b7ab017d..027999842b7b 100644 --- a/examples/list_box_model/main.rs +++ b/examples/list_box_model/main.rs @@ -47,13 +47,18 @@ fn build_ui(application: >k::Application) { let listbox = gtk::ListBox::new(); listbox.bind_model( Some(&model), - clone!(@weak window => @default-panic, move |item| { - ListBoxRow::new( - item.downcast_ref::() - .expect("RowData is of wrong type"), - ) - .upcast::() - }), + clone!( + #[weak] + window, + #[upgrade_or_panic] + move |item| { + ListBoxRow::new( + item.downcast_ref::() + .expect("RowData is of wrong type"), + ) + .upcast::() + } + ), ); let scrolled_window = gtk::ScrolledWindow::builder() @@ -72,32 +77,53 @@ fn build_ui(application: >k::Application) { // then add it to the model. Once added to the model, it will immediately // appear in the listbox UI let add_button = gtk::Button::with_label("Add"); - add_button.connect_clicked(clone!(@weak window, @weak model => move |_| { - let dialog = gtk::Dialog::with_buttons( - Some("Add Item"), - Some(&window), - gtk::DialogFlags::MODAL, - &[("Ok", gtk::ResponseType::Ok), ("Cancel", gtk::ResponseType::Cancel)], - ); - dialog.set_default_response(gtk::ResponseType::Ok); - let content_area = dialog.content_area(); - let entry = gtk::Entry::new(); - entry.connect_activate(clone!(@weak dialog => move |_| { - dialog.response(gtk::ResponseType::Ok); - })); - content_area.append(&entry); - let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0); - content_area.append(&spin_button); - dialog.connect_response(clone!(@weak model, @weak entry, @weak spin_button => move |dialog, resp| { - let text = entry.text(); - if !text.is_empty() && resp == gtk::ResponseType::Ok { - model.append(&RowData::new(&text, spin_button.value() as u32)); - } - dialog.close(); - })); - - dialog.present() - })); + add_button.connect_clicked(clone!( + #[weak] + window, + #[weak] + model, + move |_| { + let dialog = gtk::Dialog::with_buttons( + Some("Add Item"), + Some(&window), + gtk::DialogFlags::MODAL, + &[ + ("Ok", gtk::ResponseType::Ok), + ("Cancel", gtk::ResponseType::Cancel), + ], + ); + dialog.set_default_response(gtk::ResponseType::Ok); + let content_area = dialog.content_area(); + let entry = gtk::Entry::new(); + entry.connect_activate(clone!( + #[weak] + dialog, + move |_| { + dialog.response(gtk::ResponseType::Ok); + } + )); + content_area.append(&entry); + let spin_button = gtk::SpinButton::with_range(0.0, 100.0, 1.0); + content_area.append(&spin_button); + dialog.connect_response(clone!( + #[weak] + model, + #[weak] + entry, + #[weak] + spin_button, + move |dialog, resp| { + let text = entry.text(); + if !text.is_empty() && resp == gtk::ResponseType::Ok { + model.append(&RowData::new(&text, spin_button.value() as u32)); + } + dialog.close(); + } + )); + + dialog.present() + } + )); hbox.append(&add_button); @@ -105,14 +131,20 @@ fn build_ui(application: >k::Application) { // is at the index of the selected row. Also deleting from the // model is immediately reflected in the listbox. let delete_button = gtk::Button::with_label("Delete"); - delete_button.connect_clicked(clone!(@weak model, @weak listbox => move |_| { - let selected = listbox.selected_row(); - - if let Some(selected) = selected { - let idx = selected.index(); - model.remove(idx as u32); + delete_button.connect_clicked(clone!( + #[weak] + model, + #[weak] + listbox, + move |_| { + let selected = listbox.selected_row(); + + if let Some(selected) = selected { + let idx = selected.index(); + model.remove(idx as u32); + } } - })); + )); hbox.append(&delete_button); vbox.append(&hbox); diff --git a/examples/rotation_bin/main.rs b/examples/rotation_bin/main.rs index 9477f3d4b4c6..c2ba712873cf 100644 --- a/examples/rotation_bin/main.rs +++ b/examples/rotation_bin/main.rs @@ -60,12 +60,16 @@ fn build_ui(application: >k::Application) { let clockwise = gtk::Button::with_label("Rotate clockwise"); let counter_clockwise = gtk::Button::with_label("Rotate counter clockwise"); - clockwise.connect_clicked(clone!(@weak rotation_bin => move |_| { - rotation_bin.rotate_clockwise() - })); - counter_clockwise.connect_clicked(clone!(@weak rotation_bin => move |_| { - rotation_bin.rotate_counter_clockwise() - })); + clockwise.connect_clicked(clone!( + #[weak] + rotation_bin, + move |_| rotation_bin.rotate_clockwise() + )); + counter_clockwise.connect_clicked(clone!( + #[weak] + rotation_bin, + move |_| rotation_bin.rotate_counter_clockwise() + )); interactive_box.append(&clockwise); interactive_box.append(&counter_clockwise); @@ -75,18 +79,26 @@ fn build_ui(application: >k::Application) { let deg180 = gtk::Button::with_label("Reset rotation to 180 degrees"); let deg270 = gtk::Button::with_label("Reset rotation to 270 degrees"); - normal.connect_clicked(clone!(@weak rotation_bin => move |_| { - rotation_bin.set_rotation(Rotation::Normal) - })); - deg90.connect_clicked(clone!(@weak rotation_bin => move |_| { - rotation_bin.set_rotation(Rotation::Deg90) - })); - deg180.connect_clicked(clone!(@weak rotation_bin => move |_| { - rotation_bin.set_rotation(Rotation::Deg180) - })); - deg270.connect_clicked(clone!(@weak rotation_bin => move |_| { - rotation_bin.set_rotation(Rotation::Deg270) - })); + normal.connect_clicked(clone!( + #[weak] + rotation_bin, + move |_| rotation_bin.set_rotation(Rotation::Normal) + )); + deg90.connect_clicked(clone!( + #[weak] + rotation_bin, + move |_| rotation_bin.set_rotation(Rotation::Deg90) + )); + deg180.connect_clicked(clone!( + #[weak] + rotation_bin, + move |_| rotation_bin.set_rotation(Rotation::Deg180) + )); + deg270.connect_clicked(clone!( + #[weak] + rotation_bin, + move |_| rotation_bin.set_rotation(Rotation::Deg270) + )); grid.attach(&normal, 0, 1, 1, 1); grid.attach(°90, 1, 1, 1, 1); diff --git a/examples/scale/main.rs b/examples/scale/main.rs index 644713ce9f8a..af6713aa47b9 100644 --- a/examples/scale/main.rs +++ b/examples/scale/main.rs @@ -48,9 +48,13 @@ fn build_ui(application: >k::Application) { gtk::Scale::new(gtk::Orientation::Horizontal, Some(&horizontal_adjustment)); // Now if we want to take actions with the changed values of the scale, we'll have to implement a signal - horizontal_scale.connect_value_changed(clone!(@weak update_label => move |slider| { - update_label.set_text(&format!("Horizontal scale value: {:.2}", slider.value())); - })); + horizontal_scale.connect_value_changed(clone!( + #[weak] + update_label, + move |slider| { + update_label.set_text(&format!("Horizontal scale value: {:.2}", slider.value())); + } + )); // Now for the vertical scale let's use the builder let vertical_scale = gtk::Scale::builder() @@ -60,9 +64,13 @@ fn build_ui(application: >k::Application) { .build(); // To create a similar signal for the vertical scale - vertical_scale.connect_value_changed(clone!(@weak update_label => move |slider| { - update_label.set_text(&format!("Vertical scale value: {:.2}", slider.value())); - })); + vertical_scale.connect_value_changed(clone!( + #[weak] + update_label, + move |slider| { + update_label.set_text(&format!("Vertical scale value: {:.2}", slider.value())); + } + )); // To arrange everything in a presentable way we can use the grids let grid = gtk::Grid::builder() diff --git a/examples/search_bar/main.rs b/examples/search_bar/main.rs index 3bf6efac3218..3714aad74111 100644 --- a/examples/search_bar/main.rs +++ b/examples/search_bar/main.rs @@ -53,21 +53,33 @@ fn build_ui(application: >k::Application) { container.append(&label); - entry.connect_search_started(clone!(@weak search_button => move |_| { - search_button.set_active(true); - })); + entry.connect_search_started(clone!( + #[weak] + search_button, + move |_| { + search_button.set_active(true); + } + )); - entry.connect_stop_search(clone!(@weak search_button => move |_| { - search_button.set_active(false); - })); + entry.connect_stop_search(clone!( + #[weak] + search_button, + move |_| { + search_button.set_active(false); + } + )); - entry.connect_search_changed(clone!(@weak label => move |entry| { - if entry.text() != "" { - label.set_text(&entry.text()); - } else { - label.set_text("Type to start search"); + entry.connect_search_changed(clone!( + #[weak] + label, + move |entry| { + if entry.text() != "" { + label.set_text(&entry.text()); + } else { + label.set_text("Type to start search"); + } } - })); + )); window.present(); } diff --git a/examples/text_viewer/main.rs b/examples/text_viewer/main.rs index c769fa278a1e..ae31435f7b79 100644 --- a/examples/text_viewer/main.rs +++ b/examples/text_viewer/main.rs @@ -26,22 +26,27 @@ pub fn build_ui(application: >k::Application) { .object::("text_view") .expect("Couldn't get text_view"); - open_button.connect_clicked(glib::clone!(@weak window, @weak text_view => move |_| { - - let dialog = gtk::FileDialog::builder() - .title("Open File") - .accept_label("Open") - .build(); - - dialog.open(Some(&window), gio::Cancellable::NONE, move |file| { - if let Ok(file) = file { - let filename = file.path().expect("Couldn't get file path"); - let contents = read_to_string(filename).expect("Couldn't open file"); - - text_view.buffer().set_text(&contents); - } - }); - })); + open_button.connect_clicked(glib::clone!( + #[weak] + window, + #[weak] + text_view, + move |_| { + let dialog = gtk::FileDialog::builder() + .title("Open File") + .accept_label("Open") + .build(); + + dialog.open(Some(&window), gio::Cancellable::NONE, move |file| { + if let Ok(file) = file { + let filename = file.path().expect("Couldn't get file path"); + let contents = read_to_string(filename).expect("Couldn't open file"); + + text_view.buffer().set_text(&contents); + } + }); + } + )); window.present(); } diff --git a/examples/tokio_async_request/main.rs b/examples/tokio_async_request/main.rs index 10d6c9451ce7..c70ec095ddbb 100644 --- a/examples/tokio_async_request/main.rs +++ b/examples/tokio_async_request/main.rs @@ -53,11 +53,18 @@ fn main() -> glib::ExitCode { fn build_ui(app: &Application) { let (sender, receiver) = async_channel::bounded::, reqwest::Error>>(1); - runtime().spawn(clone!(@strong sender => async move { - let mut pokemon_client = PokemonClient::default(); - let pokemon_vec = pokemon_client.get_pokemon_list().await; - sender.send(pokemon_vec).await.expect("The channel needs to be open."); - })); + runtime().spawn(clone!( + #[strong] + sender, + async move { + let mut pokemon_client = PokemonClient::default(); + let pokemon_vec = pokemon_client.get_pokemon_list().await; + sender + .send(pokemon_vec) + .await + .expect("The channel needs to be open."); + } + )); let list_box = gtk::ListBox::builder().build(); let scrolled_window = gtk::ScrolledWindow::builder() @@ -69,10 +76,17 @@ fn build_ui(app: &Application) { scrolled_window.connect_edge_reached(move |_, position| { let mut pokemon_client = PokemonClient::default(); if gtk::PositionType::Bottom == position { - runtime().spawn(clone!(@strong sender => async move { - let pokemon_vec = pokemon_client.get_pokemon_list().await; - sender.send(pokemon_vec).await.expect("The channel needs to be open."); - })); + runtime().spawn(clone!( + #[strong] + sender, + async move { + let pokemon_vec = pokemon_client.get_pokemon_list().await; + sender + .send(pokemon_vec) + .await + .expect("The channel needs to be open."); + } + )); } }); diff --git a/examples/virtual_methods/main.rs b/examples/virtual_methods/main.rs index 084c9f1f7759..7cca1bf7e7d5 100644 --- a/examples/virtual_methods/main.rs +++ b/examples/virtual_methods/main.rs @@ -21,15 +21,23 @@ fn main() -> glib::ExitCode { base_button.connect_clicked(|b| { let ctx = glib::MainContext::default(); - ctx.spawn_local(clone!(@weak b => async move { - b.async_method().await.unwrap(); - })); + ctx.spawn_local(clone!( + #[weak] + b, + async move { + b.async_method().await.unwrap(); + } + )); }); derived_button.connect_clicked(|b| { let ctx = glib::MainContext::default(); - ctx.spawn_local(clone!(@weak b => async move { - b.async_method().await.unwrap(); - })); + ctx.spawn_local(clone!( + #[weak] + b, + async move { + b.async_method().await.unwrap(); + } + )); }); boxed.append(&base_button); diff --git a/gdk4-win32/Cargo.toml b/gdk4-win32/Cargo.toml index 4078b9dd205a..899fa1e06b4e 100644 --- a/gdk4-win32/Cargo.toml +++ b/gdk4-win32/Cargo.toml @@ -29,7 +29,7 @@ gio.workspace = true glib.workspace = true libc.workspace = true khronos-egl = {version = "6.0", optional = true} -windows = { version = "0.56", features = [ +windows = { version = "0.57", features = [ "Win32_Foundation", "Win32_UI_WindowsAndMessaging", ], optional = true } diff --git a/gtk4/src/dialog.rs b/gtk4/src/dialog.rs index 4c1405148801..1c3d8753d024 100644 --- a/gtk4/src/dialog.rs +++ b/gtk4/src/dialog.rs @@ -153,9 +153,13 @@ mod tests { #[test] async fn dialog_future() { let dialog = Dialog::new(); - glib::idle_add_local_once(glib::clone!(@strong dialog => move || { - dialog.response(ResponseType::Ok); - })); + glib::idle_add_local_once(glib::clone!( + #[strong] + dialog, + move || { + dialog.response(ResponseType::Ok); + } + )); let response = dialog.run_future().await; assert_eq!(response, ResponseType::Ok); } diff --git a/gtk4/src/subclass/widget.rs b/gtk4/src/subclass/widget.rs index 87c980319073..a771c73aeac5 100644 --- a/gtk4/src/subclass/widget.rs +++ b/gtk4/src/subclass/widget.rs @@ -913,9 +913,19 @@ pub unsafe trait WidgetClassExt: ClassStruct { let ctx = glib::MainContext::default(); let action_name = action_name.to_owned(); let parameter_type = parameter_type.map(ToOwned::to_owned); - ctx.spawn_local(glib::clone!(@strong this, @strong action_name, @strong parameter_type, @strong activate => async move { - activate(this, action_name, parameter_type).await; - })); + ctx.spawn_local(glib::clone!( + #[strong] + this, + #[strong] + action_name, + #[strong] + parameter_type, + #[strong] + activate, + async move { + activate(this, action_name, parameter_type).await; + } + )); }, ); }