diff --git a/src/application.rs b/src/application.rs index fe9fe3f2..31d7ddc1 100644 --- a/src/application.rs +++ b/src/application.rs @@ -52,10 +52,16 @@ mod imp { glib::timeout_add_seconds_local( 10, - clone!(@weak obj => @default-return glib::ControlFlow::Break, move || { - obj.tick(); - glib::ControlFlow::Continue - }), + clone!( + #[weak] + obj, + #[upgrade_or] + glib::ControlFlow::Break, + move || { + obj.tick(); + glib::ControlFlow::Continue + } + ), ); } } @@ -207,8 +213,12 @@ impl Application { let controller = gtk::EventControllerKey::new(); controller.connect_key_pressed(clone!( - @weak dialog => @default-return glib::Propagation::Stop, move |_, key, _, modifier| { - if key == gdk::Key::w && modifier == gdk::ModifierType::CONTROL_MASK{ + #[weak] + dialog, + #[upgrade_or] + glib::Propagation::Stop, + move |_, key, _, modifier| { + if key == gdk::Key::w && modifier == gdk::ModifierType::CONTROL_MASK { dialog.close(); } glib::Propagation::Proceed diff --git a/src/main.rs b/src/main.rs index bf188a0e..2a07971e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,22 +81,30 @@ fn main() { multi_log::MultiLogger::init(loggers, log_level).unwrap(); - glib::log_set_writer_func(clone!(@strong log_level => move |glib_log_level, fields| { - if (glib_log_level == glib::LogLevel::Debug && log_level >= log::Level::Debug ) - || (glib_log_level == glib::LogLevel::Info && log_level >= log::Level::Info) - || (glib_log_level == glib::LogLevel::Message && log_level >= log::Level::Info) - || (glib_log_level == glib::LogLevel::Warning && log_level >= log::Level::Warn) - || (glib_log_level == glib::LogLevel::Error && log_level >= log::Level::Error) - || (glib_log_level == glib::LogLevel::Critical && log_level >= log::Level::Error) - { - glib::log_writer_standard_streams(glib_log_level, fields); - glib::log_writer_journald(glib_log_level, fields); + glib::log_set_writer_func(clone!( + #[strong] + log_level, + move |glib_log_level, fields| { + if (glib_log_level == glib::LogLevel::Debug && log_level >= log::Level::Debug) + || (glib_log_level == glib::LogLevel::Info && log_level >= log::Level::Info) + || (glib_log_level == glib::LogLevel::Message + && log_level >= log::Level::Info) + || (glib_log_level == glib::LogLevel::Warning + && log_level >= log::Level::Warn) + || (glib_log_level == glib::LogLevel::Error + && log_level >= log::Level::Error) + || (glib_log_level == glib::LogLevel::Critical + && log_level >= log::Level::Error) + { + glib::log_writer_standard_streams(glib_log_level, fields); + glib::log_writer_journald(glib_log_level, fields); - glib::LogWriterOutput::Handled - } else { - glib::LogWriterOutput::Unhandled + glib::LogWriterOutput::Handled + } else { + glib::LogWriterOutput::Unhandled + } } - })); + )); adw::init().expect("Failed to init GTK/libadwaita"); sourceview5::init(); diff --git a/src/model/abstract_container_list.rs b/src/model/abstract_container_list.rs index 649a2542..3bdaac3b 100644 --- a/src/model/abstract_container_list.rs +++ b/src/model/abstract_container_list.rs @@ -84,14 +84,22 @@ impl AbstractContainerList { container.connect_notify_local( Some("status"), - clone!(@weak list => move |_, _| Self::notify_num_containers(&list)), + clone!( + #[weak] + list, + move |_, _| Self::notify_num_containers(&list) + ), ); container.connect_notify_local( Some("name"), - clone!(@weak list => move |container, _| { - list.container_name_changed(container); - }), + clone!( + #[weak] + list, + move |container, _| { + list.container_name_changed(container); + } + ), ); }); diff --git a/src/model/action.rs b/src/model/action.rs index e8d7916c..80d8b34d 100644 --- a/src/model/action.rs +++ b/src/model/action.rs @@ -141,20 +141,27 @@ impl Action { stream::Abortable::new(podman.images().prune(&opts), abort_registration).await } }, - clone!(@weak obj => move |result| if let Ok(result) = result { - let output = obj.output(); - let mut start_iter = output.start_iter(); - match result.as_ref() { - Ok(report) => { - output.insert(&mut start_iter, &serde_json::to_string_pretty(&report).unwrap()); - obj.set_state(State::Finished); - }, - Err(e) => { - output.insert(&mut start_iter, &e.to_string()); - obj.set_state(State::Failed); + clone!( + #[weak] + obj, + move |result| if let Ok(result) = result { + let output = obj.output(); + let mut start_iter = output.start_iter(); + match result.as_ref() { + Ok(report) => { + output.insert( + &mut start_iter, + &serde_json::to_string_pretty(&report).unwrap(), + ); + obj.set_state(State::Finished); + } + Err(e) => { + output.insert(&mut start_iter, &e.to_string()); + obj.set_state(State::Failed); + } } } - }), + ), ); obj @@ -179,14 +186,16 @@ impl Action { obj.set_state(State::Finished); } None => { - client - .image_list() - .connect_image_added(clone!(@weak obj => move |_, image| { + client.image_list().connect_image_added(clone!( + #[weak] + obj, + move |_, image| { if image.id() == image_id.as_str() { obj.set_artifact(image.upcast_ref()); obj.set_state(State::Finished); } - })); + } + )); } } }) @@ -215,39 +224,46 @@ impl Action { image, move |image| stream::Abortable::new(image.push(&opts), abort_registration).boxed(), clone!( - @weak obj => @default-return glib::ControlFlow::Break, - move |result: podman::Result| - { - match result.map_err(anyhow::Error::from).and_then(|line| { - serde_json::from_str::(&line).map_err(anyhow::Error::from) - }) { - Ok(report) => match report.stream { - Some(line) => { - obj.insert(&line); - glib::ControlFlow::Continue - } - None => { - if let Some(line) = report.error { - log::error!("Error on pushing image: {line}"); + #[weak] + obj, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + match result.map_err(anyhow::Error::from).and_then(|line| { + serde_json::from_str::(&line).map_err(anyhow::Error::from) + }) { + Ok(report) => match report.stream { + Some(line) => { obj.insert(&line); + glib::ControlFlow::Continue } + None => { + if let Some(line) = report.error { + log::error!("Error on pushing image: {line}"); + obj.insert(&line); + } + obj.set_state(State::Failed); + glib::ControlFlow::Break + } + }, + Err(e) => { + log::error!("Error on pushing image: {e}"); + obj.insert_line(&e.to_string()); obj.set_state(State::Failed); glib::ControlFlow::Break } - }, - Err(e) => { - log::error!("Error on pushing image: {e}"); - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); - glib::ControlFlow::Break } } - }), - clone!(@weak obj => move || { - if obj.state() != State::Failed { - obj.set_state(State::Finished); + ), + clone!( + #[weak] + obj, + move || { + if obj.state() != State::Failed { + obj.set_state(State::Finished); + } } - }), + ), ); obj @@ -278,48 +294,59 @@ impl Action { } }, clone!( - @weak obj, @weak client => @default-return glib::ControlFlow::Break, - move |result: podman::Result| - { - match result { - Ok(stream) => { - obj.insert(&stream.stream); - glib::ControlFlow::Continue + #[weak] + obj, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + match result { + Ok(stream) => { + obj.insert(&stream.stream); + glib::ControlFlow::Continue + } + Err(e) => { + log::error!("Error on building image: {e}"); + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); + glib::ControlFlow::Break + } } - Err(e) => { - log::error!("Error on building image: {e}"); - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); - glib::ControlFlow::Break - }, } - }), - clone!(@weak obj, @weak client => move || { - let output = obj.output(); - - let start = output.iter_at_line(0).unwrap(); - let mut end = output.iter_at_line(0).unwrap(); - end.forward_to_line_end(); - - let image_id = output.text(&start, &end, false).trim().to_owned(); - - match client.image_list().get_image(&image_id) { - Some(image) => { - obj.set_artifact(image.upcast_ref()); - obj.set_state(State::Finished); - } - None => { - client - .image_list() - .connect_image_added(clone!(@weak obj => move |_, image| { - if image.id() == image_id { - obj.set_artifact(image.upcast_ref()); - obj.set_state(State::Finished); + ), + clone!( + #[weak] + obj, + #[weak] + client, + move || { + let output = obj.output(); + + let start = output.iter_at_line(0).unwrap(); + let mut end = output.iter_at_line(0).unwrap(); + end.forward_to_line_end(); + + let image_id = output.text(&start, &end, false).trim().to_owned(); + + match client.image_list().get_image(&image_id) { + Some(image) => { + obj.set_artifact(image.upcast_ref()); + obj.set_state(State::Finished); + } + None => { + client.image_list().connect_image_added(clone!( + #[weak] + obj, + move |_, image| { + if image.id() == image_id { + obj.set_artifact(image.upcast_ref()); + obj.set_state(State::Finished); + } } - })); + )); + } } } - }), + ), ); obj @@ -345,20 +372,27 @@ impl Action { .await } }, - clone!(@weak obj => move |result| if let Ok(result) = result { - let output = obj.output(); - let mut start_iter = output.start_iter(); - match result.as_ref() { - Ok(report) => { - output.insert(&mut start_iter, &serde_json::to_string_pretty(&report).unwrap()); - obj.set_state(State::Finished); - }, - Err(e) => { - output.insert(&mut start_iter, &e.to_string()); - obj.set_state(State::Failed); + clone!( + #[weak] + obj, + move |result| if let Ok(result) = result { + let output = obj.output(); + let mut start_iter = output.start_iter(); + match result.as_ref() { + Ok(report) => { + output.insert( + &mut start_iter, + &serde_json::to_string_pretty(&report).unwrap(), + ); + obj.set_state(State::Finished); + } + Err(e) => { + output.insert(&mut start_iter, &e.to_string()); + obj.set_state(State::Failed); + } } } - }), + ), ); obj @@ -412,18 +446,22 @@ impl Action { utils::do_async( async move { stream::Abortable::new(api.commit(&opts), abort_registration).await }, - clone!(@weak obj => move |result| if let Ok(result) = result { - match result.as_ref() { - Ok(_) => { - obj.insert_line(&gettext("Finished")); - obj.set_state(State::Finished); - }, - Err(e) => { - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); + clone!( + #[weak] + obj, + move |result| if let Ok(result) = result { + match result.as_ref() { + Ok(_) => { + obj.insert_line(&gettext("Finished")); + obj.set_state(State::Finished); + } + Err(e) => { + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); + } } } - }), + ), ); obj @@ -494,56 +532,80 @@ impl Action { ) .await }, - clone!(@weak obj, @weak container => move |result| if let Ok(result) = result { - match result { - Ok(ar) => { - obj.insert_line(&gettext("Tar archive created")); - obj.insert_line(&gettext("Unwrapping tar archive…")); - - let abort_registration = obj.setup_abort_handle(); - utils::do_async( - stream::Abortable::new(ar.into_inner(), abort_registration), - clone!(@weak obj, @weak container => move |result| if let Ok(result) = result { - match result { - Ok(data) => { - obj.insert_line(&gettext("Tar archive unwrapped")); - obj.insert_line(&gettext("Copying files into container…")); - - let abort_registration = obj.setup_abort_handle(); - let api = container.api().unwrap(); - utils::do_async( - async move { - stream::Abortable::new( - api.copy_to(container_path, data.into()), - abort_registration - ).await - }, - clone!(@weak obj => move |result| match result { - Ok(_) => { - obj.insert_line(&gettext("Finished")); - obj.set_state(State::Finished); - } - Err(e) => { - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); - } - }), - ); - } - Err(e) => { - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); + clone!( + #[weak] + obj, + #[weak] + container, + move |result| if let Ok(result) = result { + match result { + Ok(ar) => { + obj.insert_line(&gettext("Tar archive created")); + obj.insert_line(&gettext("Unwrapping tar archive…")); + + let abort_registration = obj.setup_abort_handle(); + utils::do_async( + stream::Abortable::new(ar.into_inner(), abort_registration), + clone!( + #[weak] + obj, + #[weak] + container, + move |result| if let Ok(result) = result { + match result { + Ok(data) => { + obj.insert_line(&gettext("Tar archive unwrapped")); + obj.insert_line(&gettext( + "Copying files into container…", + )); + + let abort_registration = obj.setup_abort_handle(); + let api = container.api().unwrap(); + utils::do_async( + async move { + stream::Abortable::new( + api.copy_to( + container_path, + data.into(), + ), + abort_registration, + ) + .await + }, + clone!( + #[weak] + obj, + move |result| match result { + Ok(_) => { + obj.insert_line(&gettext( + "Finished", + )); + obj.set_state(State::Finished); + } + Err(e) => { + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); + } + } + ), + ); + } + Err(e) => { + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); + } + } } - } - }) - ); - } - Err(e) => { - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); + ), + ); + } + Err(e) => { + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); + } } } - }), + ), ); obj @@ -580,44 +642,60 @@ impl Action { .boxed() }, clone!( - @weak obj, - @strong buf - => @default-return glib::ControlFlow::Break, move |result: podman::Result>| - { - match result { - Ok(chunk) => { - let mut buf = buf.lock().unwrap(); - buf.extend(chunk); - obj.replace_last_line(&gettext!("Size: {}", glib::format_size(buf.len() as u64))); - glib::ControlFlow::Continue - } - Err(e) => { - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); - glib::ControlFlow::Break - } - } - }), - clone!(@weak obj => move || { - let mut buf_ = Vec::::new(); - mem::swap(&mut *buf.lock().unwrap(), &mut buf_); - - utils::do_async({ - let path = host_path.clone(); - async move { tokio::fs::write(path, buf_).await } - }, - clone!(@weak obj => move |result| match result { - Ok(_) => { - obj.insert_line(&gettext("Finished")); - obj.set_state(State::Finished); + #[weak] + obj, + #[strong] + buf, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result>| { + match result { + Ok(chunk) => { + let mut buf = buf.lock().unwrap(); + buf.extend(chunk); + obj.replace_last_line(&gettext!( + "Size: {}", + glib::format_size(buf.len() as u64) + )); + glib::ControlFlow::Continue } Err(e) => { obj.insert_line(&e.to_string()); obj.set_state(State::Failed); + glib::ControlFlow::Break } - }) - ); - }), + } + } + ), + clone!( + #[weak] + obj, + move || { + let mut buf_ = Vec::::new(); + mem::swap(&mut *buf.lock().unwrap(), &mut buf_); + + utils::do_async( + { + let path = host_path.clone(); + async move { tokio::fs::write(path, buf_).await } + }, + clone!( + #[weak] + obj, + move |result| match result { + Ok(_) => { + obj.insert_line(&gettext("Finished")); + obj.set_state(State::Finished); + } + Err(e) => { + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); + } + } + ), + ); + } + ), ); obj @@ -657,20 +735,27 @@ impl Action { let podman = client.podman(); async move { stream::Abortable::new(podman.pods().prune(), abort_registration).await } }, - clone!(@weak obj => move |result| if let Ok(result) = result { - let output = obj.output(); - let mut start_iter = output.start_iter(); - match result.as_ref() { - Ok(report) => { - output.insert(&mut start_iter, &serde_json::to_string_pretty(&report).unwrap()); - obj.set_state(State::Finished); - }, - Err(e) => { - output.insert(&mut start_iter, &e.to_string()); - obj.set_state(State::Failed); + clone!( + #[weak] + obj, + move |result| if let Ok(result) = result { + let output = obj.output(); + let mut start_iter = output.start_iter(); + match result.as_ref() { + Ok(report) => { + output.insert( + &mut start_iter, + &serde_json::to_string_pretty(&report).unwrap(), + ); + obj.set_state(State::Finished); + } + Err(e) => { + output.insert(&mut start_iter, &e.to_string()); + obj.set_state(State::Failed); + } } } - }), + ), ); obj @@ -693,36 +778,41 @@ impl Action { client.podman().images(), move |images| stream::Abortable::new(images.pull(&opts), abort_registration).boxed(), clone!( - @weak self as obj, @weak client => @default-return glib::ControlFlow::Break, - move |result: podman::Result| - { - match result { - Ok(report) => match report.error { - Some(error) => { - log::error!("Error on downloading image: {error}"); - obj.insert_line(&error); - obj.set_state(State::Failed); - glib::ControlFlow::Break - } - None => match report.stream { - Some(stream) => { - obj.insert(&stream); - glib::ControlFlow::Continue - } - None => { - op.clone()(obj, client, report); + #[weak(rename_to = obj)] + self, + #[weak] + client, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + match result { + Ok(report) => match report.error { + Some(error) => { + log::error!("Error on downloading image: {error}"); + obj.insert_line(&error); + obj.set_state(State::Failed); glib::ControlFlow::Break } + None => match report.stream { + Some(stream) => { + obj.insert(&stream); + glib::ControlFlow::Continue + } + None => { + op.clone()(obj, client, report); + glib::ControlFlow::Break + } + }, + }, + Err(e) => { + log::error!("Error on downloading image: {e}"); + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); + glib::ControlFlow::Break } } - Err(e) => { - log::error!("Error on downloading image: {e}"); - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); - glib::ControlFlow::Break - }, } - }), + ), ); self @@ -744,28 +834,37 @@ impl Action { .await } }, - clone!(@weak self as obj, @weak client => move |result| if let Ok(result) = result { - match result.map(|info| info.id) { - Ok(id) => { - match client.container_list().get_container(&id) { - Some(container) => { - obj.set_artifact(container.upcast_ref()); - obj.set_state(State::Finished); - } - None => { - client.container_list().connect_container_added( - clone!(@weak obj, @strong id => move |_, container| { - if container.id() == id.as_str() { - obj.set_artifact(container.upcast_ref()); - obj.set_state(State::Finished); + clone!( + #[weak(rename_to = obj)] + self, + #[weak] + client, + move |result| if let Ok(result) = result { + match result.map(|info| info.id) { + Ok(id) => { + match client.container_list().get_container(&id) { + Some(container) => { + obj.set_artifact(container.upcast_ref()); + obj.set_state(State::Finished); + } + None => { + client.container_list().connect_container_added(clone!( + #[weak] + obj, + #[strong] + id, + move |_, container| { + if container.id() == id.as_str() { + obj.set_artifact(container.upcast_ref()); + obj.set_state(State::Finished); + } } - }), - ); + )); + } } - } - if run { - crate::runtime().spawn({ + if run { + crate::runtime().spawn({ let podman = client.podman(); async move { podman @@ -775,15 +874,16 @@ impl Action { .await } }); + } + } + Err(e) => { + log::error!("Error on creating container: {e}"); + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); } - } - Err(e) => { - log::error!("Error on creating container: {e}"); - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); } } - }), + ), ); self @@ -799,33 +899,41 @@ impl Action { stream::Abortable::new(podman.pods().create(&opts), abort_registration).await } }, - clone!(@weak self as obj, @weak client => move |result| if let Ok(result) = result { - match result.map(|pod| pod.id().to_string()) { - Ok(id) => { - match client.pod_list().get_pod(&id) { + clone!( + #[weak(rename_to = obj)] + self, + #[weak] + client, + move |result| if let Ok(result) = result { + match result.map(|pod| pod.id().to_string()) { + Ok(id) => match client.pod_list().get_pod(&id) { Some(pod) => { obj.set_artifact(pod.upcast_ref()); obj.set_state(State::Finished); - }, + } None => { - client.pod_list().connect_pod_added( - clone!(@weak obj, @strong id => move |_, pod| { + client.pod_list().connect_pod_added(clone!( + #[weak] + obj, + #[strong] + id, + move |_, pod| { if pod.id() == id.as_str() { obj.set_artifact(pod.upcast_ref()); obj.set_state(State::Finished); } - }), - ); + } + )); } + }, + Err(e) => { + log::error!("Error on creating pod: {e}"); + obj.insert(&e.to_string()); + obj.set_state(State::Failed); } } - Err(e) => { - log::error!("Error on creating pod: {e}"); - obj.insert(&e.to_string()); - obj.set_state(State::Failed); - } } - }), + ), ); self @@ -851,33 +959,41 @@ impl Action { stream::Abortable::new(podman.volumes().create(&opts), abort_registration).await } }, - clone!(@weak obj, @weak client => move |result| if let Ok(result) = result { - match result.map(|response| response.name.unwrap_or_default()) { - Ok(name) => { - match client.volume_list().get_volume(&name) { + clone!( + #[weak] + obj, + #[weak] + client, + move |result| if let Ok(result) = result { + match result.map(|response| response.name.unwrap_or_default()) { + Ok(name) => match client.volume_list().get_volume(&name) { Some(volume) => { obj.set_artifact(volume.upcast_ref()); obj.set_state(State::Finished); } None => { - client.volume_list().connect_volume_added( - clone!(@weak obj, @strong name => move |_, volume| { + client.volume_list().connect_volume_added(clone!( + #[weak] + obj, + #[strong] + name, + move |_, volume| { if volume.inner().name == name { obj.set_artifact(volume.upcast_ref()); obj.set_state(State::Finished); } - }), - ); + } + )); } + }, + Err(e) => { + log::error!("Error on creating volume: {e}"); + obj.insert_line(&e.to_string()); + obj.set_state(State::Failed); } } - Err(e) => { - log::error!("Error on creating volume: {e}"); - obj.insert_line(&e.to_string()); - obj.set_state(State::Failed); - } } - }), + ), ); obj @@ -898,20 +1014,27 @@ impl Action { stream::Abortable::new(podman.volumes().prune(&opts), abort_registration).await } }, - clone!(@weak obj => move |result| if let Ok(result) = result { - let output = obj.output(); - let mut start_iter = output.start_iter(); - match result.as_ref() { - Ok(report) => { - output.insert(&mut start_iter, &serde_json::to_string_pretty(&report).unwrap()); - obj.set_state(State::Finished); - }, - Err(e) => { - output.insert(&mut start_iter, &e.to_string()); - obj.set_state(State::Failed); + clone!( + #[weak] + obj, + move |result| if let Ok(result) = result { + let output = obj.output(); + let mut start_iter = output.start_iter(); + match result.as_ref() { + Ok(report) => { + output.insert( + &mut start_iter, + &serde_json::to_string_pretty(&report).unwrap(), + ); + obj.set_state(State::Finished); + } + Err(e) => { + output.insert(&mut start_iter, &e.to_string()); + obj.set_state(State::Failed); + } } } - }), + ), ); obj diff --git a/src/model/action_list.rs b/src/model/action_list.rs index 7c8a0251..bf03dd40 100644 --- a/src/model/action_list.rs +++ b/src/model/action_list.rs @@ -366,7 +366,11 @@ impl ActionList { action.connect_notify_local( Some("state"), - clone!(@weak self as obj => move |_, _| obj.notify_num_states()), + clone!( + #[weak(rename_to = obj)] + self, + move |_, _| obj.notify_num_states() + ), ); self.items_changed(position as u32, 0, 1); diff --git a/src/model/client.rs b/src/model/client.rs index 0a975428..84a2f610 100644 --- a/src/model/client.rs +++ b/src/model/client.rs @@ -80,8 +80,10 @@ mod imp { let obj = &*self.obj(); - obj.image_list() - .connect_image_added(clone!(@weak obj => move |_, image| { + obj.image_list().connect_image_added(clone!( + #[weak] + obj, + move |_, image| { obj.container_list() .iter::() .map(|container| container.unwrap()) @@ -90,56 +92,74 @@ mod imp { container.set_image(Some(image)); image.container_list().add_container(&container); }); - })); + } + )); - obj.container_list() - .connect_container_added(clone!(@weak obj => move |_, container| { + obj.container_list().connect_container_added(clone!( + #[weak] + obj, + move |_, container| { let image = obj.image_list().get_image(container.image_id().as_str()); if let Some(ref image) = image { container.set_image(Some(image)); image.container_list().add_container(container); } - if let Some(pod) = container.pod_id().and_then(|id| obj.pod_list().get_pod(&id)) + if let Some(pod) = container + .pod_id() + .and_then(|id| obj.pod_list().get_pod(&id)) { container.set_pod(Some(&pod)); pod.container_list().add_container(container); } if !container.mounts().is_empty() { - container.inspect(clone!(@weak obj => move |result| { - if let Ok(container) = result { - container.data().unwrap().mounts().values().filter_map( - |mount| { - obj.volume_list() - .get_volume(mount.name.as_ref().unwrap()) - .map(|volume| (volume, mount)) - }, - ) - .for_each(|(volume, mount)| { - volume.container_list().add_container(&container); - - let container_volume_list = container.volume_list(); - container_volume_list.add_volume( - model::ContainerVolume::new( - &container_volume_list, - &volume, - mount.clone(), - ), - ); - }); + container.inspect(clone!( + #[weak] + obj, + move |result| { + if let Ok(container) = result { + container + .data() + .unwrap() + .mounts() + .values() + .filter_map(|mount| { + obj.volume_list() + .get_volume(mount.name.as_ref().unwrap()) + .map(|volume| (volume, mount)) + }) + .for_each(|(volume, mount)| { + volume.container_list().add_container(&container); + + let container_volume_list = container.volume_list(); + container_volume_list.add_volume( + model::ContainerVolume::new( + &container_volume_list, + &volume, + mount.clone(), + ), + ); + }); + } } - })); + )); } - })); - obj.container_list().connect_container_removed( - clone!(@weak obj => move |_, container| { + } + )); + obj.container_list().connect_container_removed(clone!( + #[weak] + obj, + move |_, container| { if let Some(image) = obj.image_list().get_image(container.image_id().as_str()) { - image.container_list().remove_container(container.id().as_str()); + image + .container_list() + .remove_container(container.id().as_str()); } if let Some(pod) = container.pod() { - pod.container_list().remove_container(container.id().as_str()); + pod.container_list() + .remove_container(container.id().as_str()); } container @@ -153,11 +173,13 @@ mod imp { .remove_container(container.id().as_str()); } }); - }), - ); + } + )); - obj.pod_list() - .connect_pod_added(clone!(@weak obj => move |_, pod| { + obj.pod_list().connect_pod_added(clone!( + #[weak] + obj, + move |_, pod| { obj.container_list() .iter::() .map(|container| container.unwrap()) @@ -166,11 +188,16 @@ mod imp { container.set_pod(Some(pod)); pod.container_list().add_container(&container); }); - })); - - obj.volume_list() - .connect_volume_added(clone!(@weak obj => move |_, volume| { - let container_list: Vec<_> = obj.container_list().iter::() + } + )); + + obj.volume_list().connect_volume_added(clone!( + #[weak] + obj, + move |_, volume| { + let container_list: Vec<_> = obj + .container_list() + .iter::() .map(|container| container.unwrap()) .filter(|container| !container.mounts().is_empty()) .collect(); @@ -182,14 +209,13 @@ mod imp { volume.set_searching_containers(true); let containers_left = Rc::new(AtomicUsize::new(container_list.len())); - container_list - .iter() - .for_each(|container| { - container.inspect(clone!( - @weak volume, - @strong containers_left - => move |result| - { + container_list.iter().for_each(|container| { + container.inspect(clone!( + #[weak] + volume, + #[strong] + containers_left, + move |result| { if let Ok(container) = result { if let Some(mount) = container.data().unwrap().mounts().values().find(|mount| { @@ -212,9 +238,11 @@ mod imp { if containers_left.fetch_sub(1, Ordering::Relaxed) == 1 { volume.set_searching_containers(false); } - })); - }); - })); + } + )); + }); + } + )); } } @@ -275,18 +303,22 @@ impl TryFrom<&model::Connection> for Client { utils::do_async( async move { podman.info().await }, - clone!(@weak obj => move |info| match info { - Ok(info) => { - obj.set_version(info.version.unwrap().version); - obj.set_cpus(info.host.unwrap().cpus); - } - Err(e) => { - log::error!("Error on retrieving podmnan info: {e}"); + clone!( + #[weak] + obj, + move |info| match info { + Ok(info) => { + obj.set_version(info.version.unwrap().version); + obj.set_cpus(info.host.unwrap().cpus); + } + Err(e) => { + log::error!("Error on retrieving podmnan info: {e}"); - obj.set_version(None); - obj.set_cpus(None); + obj.set_version(None); + obj.set_cpus(None); + } } - }), + ), ); obj @@ -316,40 +348,38 @@ impl Client { let podman = self.podman(); async move { podman.ping().await } }, - clone!(@weak self as obj => move |result| match result { - Ok(_) => { - obj.image_list().refresh({ - let err_op = err_op.clone(); - |_| err_op(ClientError::Images) - }); - obj.container_list().refresh( - None, - { + clone!( + #[weak(rename_to = obj)] + self, + move |result| match result { + Ok(_) => { + obj.image_list().refresh({ + let err_op = err_op.clone(); + |_| err_op(ClientError::Images) + }); + obj.container_list().refresh(None, { let err_op = err_op.clone(); |_| err_op(ClientError::Containers) - } - ); - obj.pod_list().refresh( - None, - { + }); + obj.pod_list().refresh(None, { let err_op = err_op.clone(); |_| err_op(ClientError::Pods) - } - ); - obj.volume_list().refresh({ - let err_op = err_op.clone(); - |_| err_op(ClientError::Volumes) - }); + }); + obj.volume_list().refresh({ + let err_op = err_op.clone(); + |_| err_op(ClientError::Volumes) + }); - op(); - obj.start_event_listener(err_op, finish_op); - obj.start_refresh_interval(); - } - Err(e) => { - log::error!("Could not connect to Podman: {e}"); - // No need to show a toast. The start service page is enough. + op(); + obj.start_event_listener(err_op, finish_op); + obj.start_refresh_interval(); + } + Err(e) => { + log::error!("Could not connect to Podman: {e}"); + // No need to show a toast. The start service page is enough. + } } - }), + ), ); } @@ -366,40 +396,43 @@ impl Client { .boxed() }, clone!( - @weak self as obj => @default-return glib::ControlFlow::Break, - move |result: podman::Result| - { - match result { - Ok(event) => { - log::debug!("Event: {event:?}"); - match event.typ.as_str() { - "image" => obj.image_list().handle_event(event, { - let err_op = err_op.clone(); - |_| err_op(ClientError::Images) - }), - "container" => obj.container_list().handle_event(event, { - let err_op = err_op.clone(); - |_| err_op(ClientError::Containers) - }), - "pod" => obj.pod_list().handle_event(event, { - let err_op = err_op.clone(); - |_| err_op(ClientError::Pods) - }), - "volume" => obj.volume_list().handle_event(event, { - let err_op = err_op.clone(); - |_| err_op(ClientError::Volumes) - }), - other => log::warn!("Unhandled event type: {other}"), + #[weak(rename_to = obj)] + self, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + match result { + Ok(event) => { + log::debug!("Event: {event:?}"); + match event.typ.as_str() { + "image" => obj.image_list().handle_event(event, { + let err_op = err_op.clone(); + |_| err_op(ClientError::Images) + }), + "container" => obj.container_list().handle_event(event, { + let err_op = err_op.clone(); + |_| err_op(ClientError::Containers) + }), + "pod" => obj.pod_list().handle_event(event, { + let err_op = err_op.clone(); + |_| err_op(ClientError::Pods) + }), + "volume" => obj.volume_list().handle_event(event, { + let err_op = err_op.clone(); + |_| err_op(ClientError::Volumes) + }), + other => log::warn!("Unhandled event type: {other}"), + } + glib::ControlFlow::Continue + } + Err(e) => { + log::error!("Stopping image event stream due to error: {e}"); + finish_op.clone()(e); + glib::ControlFlow::Break } - glib::ControlFlow::Continue - } - Err(e) => { - log::error!("Stopping image event stream due to error: {e}"); - finish_op.clone()(e); - glib::ControlFlow::Break } } - }), + ), ); } @@ -408,17 +441,23 @@ impl Client { fn start_refresh_interval(&self) { glib::timeout_add_seconds_local( SYNC_INTERVAL, - clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move || { - log::debug!("Syncing images, containers and pods"); + clone!( + #[weak(rename_to = obj)] + self, + #[upgrade_or] + glib::ControlFlow::Break, + move || { + log::debug!("Syncing images, containers and pods"); - obj.image_list().refresh(|_| {}); - obj.container_list().refresh(None, |_| {}); - obj.pod_list().refresh(None, |_| {}); + obj.image_list().refresh(|_| {}); + obj.container_list().refresh(None, |_| {}); + obj.pod_list().refresh(None, |_| {}); - log::debug!("Sleeping for {SYNC_INTERVAL} until next sync"); + log::debug!("Sleeping for {SYNC_INTERVAL} until next sync"); - glib::ControlFlow::Continue - }), + glib::ControlFlow::Continue + } + ), ); } } diff --git a/src/model/connection_manager.rs b/src/model/connection_manager.rs index 80abe73d..bc1212c7 100644 --- a/src/model/connection_manager.rs +++ b/src/model/connection_manager.rs @@ -182,7 +182,7 @@ impl ConnectionManager { file.write_all(&buf).await.map_err(anyhow::Error::from) }, - clone!(@weak self as obj => move |result| op(result)), + op, ); } @@ -218,27 +218,32 @@ impl ConnectionManager { let abort_registration = self.abort_registration(); async move { future::Abortable::new(podman.ping(), abort_registration).await } }, - clone!(@weak self as obj => move |result| { - if let Ok(result) = result { - match &result { - Ok(_) => { - let (position, _) = obj.imp() - .connections - .borrow_mut() - .insert_full(connection.uuid(), connection.clone()); - - obj.items_changed(position as u32, 0, 1); - - obj.set_client(Some(client)); - - obj.sync_to_disk(|_| {}); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Ok(result) = result { + match &result { + Ok(_) => { + let (position, _) = obj + .imp() + .connections + .borrow_mut() + .insert_full(connection.uuid(), connection.clone()); + + obj.items_changed(position as u32, 0, 1); + + obj.set_client(Some(client)); + + obj.sync_to_disk(|_| {}); + } + Err(e) => log::error!("Error on pinging connection: {e}"), } - Err(e) => log::error!("Error on pinging connection: {e}"), + op(result); } - op(result); + obj.set_creating_new_connection(false); } - obj.set_creating_new_connection(false); - }), + ), ); Ok(()) @@ -313,20 +318,24 @@ impl ConnectionManager { let abort_registration = self.abort_registration(); async move { future::Abortable::new(podman.ping(), abort_registration).await } }, - clone!(@weak self as obj => move |result| { - if let Ok(result) = result { - match result { - Ok(_) => { - obj.set_client(Some(client)); - } - Err(ref e) => { - log::error!("Failed to search for images: {}", e); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Ok(result) = result { + match result { + Ok(_) => { + obj.set_client(Some(client)); + } + Err(ref e) => { + log::error!("Failed to search for images: {}", e); + } } + op(result.map(|_| ()).map_err(anyhow::Error::from)); } - op(result.map(|_| ()).map_err(anyhow::Error::from)); + connection.set_connecting(false); } - connection.set_connecting(false); - }), + ), ); } diff --git a/src/model/container.rs b/src/model/container.rs index b0604e37..11431b77 100644 --- a/src/model/container.rs +++ b/src/model/container.rs @@ -332,13 +332,17 @@ impl Container { F: Fn(Result) + 'static, { if let Some(observers) = self.imp().inspection_observers.borrow().as_ref() { - observers.add(clone!(@weak self as obj => move |result| match result { - Ok(_) => op(Ok(obj)), - Err(e) => { - log::error!("Error on inspecting container '{}': {e}", obj.id()); - op(Err(e)); + observers.add(clone!( + #[weak(rename_to = obj)] + self, + move |result| match result { + Ok(_) => op(Ok(obj)), + Err(e) => { + log::error!("Error on inspecting container '{}': {e}", obj.id()); + op(Err(e)); + } } - })); + )); return; } @@ -348,22 +352,26 @@ impl Container { let container = self.api().unwrap(); async move { container.inspect().await } }, - clone!(@weak self as obj => move |result| { - let imp = obj.imp(); - - imp.inspection_observers.replace(None); - - match result { - Ok(data) => { - imp.set_data(data); - op(Ok(obj)); - }, - Err(e) => { - log::error!("Error on inspecting container '{}': {e}", obj.id()); - op(Err(e)); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + let imp = obj.imp(); + + imp.inspection_observers.replace(None); + + match result { + Ok(data) => { + imp.set_data(data); + op(Ok(obj)); + } + Err(e) => { + log::error!("Error on inspecting container '{}': {e}", obj.id()); + op(Err(e)); + } } } - }), + ), ); self.imp().inspection_observers.replace(Some(observers)); @@ -387,24 +395,22 @@ impl Container { utils::do_async( async move { fut_op(container).await }, - clone!(@weak self as obj => move |result| { - match &result { - Ok(_) => { - log::info!( - "Container <{}>: {name} has finished", - obj.id() - ); - } - Err(e) => { - log::error!( - "Container <{}>: Error while {name}: {e}", - obj.id(), - ); - obj.set_action_ongoing(false); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + match &result { + Ok(_) => { + log::info!("Container <{}>: {name} has finished", obj.id()); + } + Err(e) => { + log::error!("Container <{}>: Error while {name}: {e}", obj.id(),); + obj.set_action_ongoing(false); + } } + res_op(result) } - res_op(result) - }), + ), ); } } @@ -509,12 +515,16 @@ impl Container { ) .await }, - clone!(@weak self as obj => move |result| { - if result.is_err() { - obj.imp().set_to_be_deleted(false); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if result.is_err() { + obj.imp().set_to_be_deleted(false); + } + op(result) } - op(result) - }), + ), ); } diff --git a/src/model/container_list.rs b/src/model/container_list.rs index 64c681e4..04cf645c 100644 --- a/src/model/container_list.rs +++ b/src/model/container_list.rs @@ -121,39 +121,44 @@ mod imp { .boxed() }, clone!( - @weak obj => @default-return glib::ControlFlow::Break, - move |result: podman::Result| - { - match result - .map_err(anyhow::Error::from) - .and_then(|mut value| { - value - .as_object_mut() - .and_then(|object| object.remove("Stats")) - .ok_or_else(|| anyhow!("Field 'Stats' is not present")) - }) - .and_then(|value| { - serde_json::from_value::>(value) - .map_err(anyhow::Error::from) - }) { - Ok(stats) => { - stats.into_iter().for_each(|stat| { - if let Some(container) = - obj.get_container(stat.container_id.as_ref().unwrap()) - { - if container.status() == model::ContainerStatus::Running { - container.set_stats( - Some(model::BoxedContainerStats::from(stat)) - ); + #[weak] + obj, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + match result + .map_err(anyhow::Error::from) + .and_then(|mut value| { + value + .as_object_mut() + .and_then(|object| object.remove("Stats")) + .ok_or_else(|| anyhow!("Field 'Stats' is not present")) + }) + .and_then(|value| { + serde_json::from_value::>(value) + .map_err(anyhow::Error::from) + }) { + Ok(stats) => { + stats.into_iter().for_each(|stat| { + if let Some(container) = + obj.get_container(stat.container_id.as_ref().unwrap()) + { + if container.status() == model::ContainerStatus::Running { + container.set_stats(Some( + model::BoxedContainerStats::from(stat), + )); + } } - } - }); + }); + } + Err(e) => { + log::warn!("Error occurred on receiving stats stream element: {e}") + } } - Err(e) => log::warn!("Error occurred on receiving stats stream element: {e}"), - } - glib::ControlFlow::Continue - }), + glib::ControlFlow::Continue + } + ), ); } } @@ -305,30 +310,31 @@ impl ContainerList { .await } }, - clone!(@weak self as obj => move |result| { - match result { - Ok(list_containers) => { - if id.is_none() { - let to_remove = obj - .imp() - .list - .borrow() - .keys() - .filter(|id| { - !list_containers - .iter() - .any(|list_container| list_container.id.as_ref() == Some(id)) - }) - .cloned() - .collect::>(); - to_remove.iter().for_each(|id| { - obj.remove_container(id); - }); - } - - list_containers - .into_iter() - .for_each(|list_container| { + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + match result { + Ok(list_containers) => { + if id.is_none() { + let to_remove = obj + .imp() + .list + .borrow() + .keys() + .filter(|id| { + !list_containers.iter().any(|list_container| { + list_container.id.as_ref() == Some(id) + }) + }) + .cloned() + .collect::>(); + to_remove.iter().for_each(|id| { + obj.remove_container(id); + }); + } + + list_containers.into_iter().for_each(|list_container| { let index = obj.len(); let mut list = obj.imp().list.borrow_mut(); @@ -351,15 +357,16 @@ impl ContainerList { } }); } - Err(e) => { - log::error!("Error on retrieving containers: {}", e); - err_op(super::RefreshError); + Err(e) => { + log::error!("Error on retrieving containers: {}", e); + err_op(super::RefreshError); + } } + let imp = obj.imp(); + imp.set_listing(false); + imp.set_as_initialized(); } - let imp = obj.imp(); - imp.set_listing(false); - imp.set_as_initialized(); - }), + ), ); } diff --git a/src/model/image.rs b/src/model/image.rs index 7c3930fa..b42e52e2 100644 --- a/src/model/image.rs +++ b/src/model/image.rs @@ -202,13 +202,17 @@ impl Image { F: Fn(Result) + 'static, { if let Some(observers) = self.imp().inspection_observers.borrow().as_ref() { - observers.add(clone!(@weak self as obj => move |result| match result { - Ok(_) => op(Ok(obj)), - Err(e) => { - log::error!("Error on inspecting image '{}': {e}", obj.id()); - op(Err(e)); + observers.add(clone!( + #[weak(rename_to = obj)] + self, + move |result| match result { + Ok(_) => op(Ok(obj)), + Err(e) => { + log::error!("Error on inspecting image '{}': {e}", obj.id()); + op(Err(e)); + } } - })); + )); return; } @@ -218,22 +222,26 @@ impl Image { let image = self.api().unwrap(); async move { image.inspect().await } }, - clone!(@weak self as obj => move |result| { - let imp = obj.imp(); - - imp.inspection_observers.replace(None); - - match result { - Ok(data) => { - imp.set_data(model::ImageData::from(data)); - op(Ok(obj)); - }, - Err(e) => { - log::error!("Error on inspecting image '{}': {e}", obj.id()); - op(Err(e)); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + let imp = obj.imp(); + + imp.inspection_observers.replace(None); + + match result { + Ok(data) => { + imp.set_data(model::ImageData::from(data)); + op(Ok(obj)); + } + Err(e) => { + log::error!("Error on inspecting image '{}': {e}", obj.id()); + op(Err(e)); + } } } - }), + ), ); self.imp().inspection_observers.replace(Some(observers)); @@ -250,13 +258,17 @@ impl Image { utils::do_async( async move { image.remove().await }, - clone!(@weak self as obj => move |result| { - if let Err(ref e) = result { - obj.imp().set_to_be_deleted(false); - log::error!("Error on removing image: {}", e); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(ref e) = result { + obj.imp().set_to_be_deleted(false); + log::error!("Error on removing image: {}", e); + } + op(&obj, result); } - op(&obj, result); - }), + ), ); } } diff --git a/src/model/image_list.rs b/src/model/image_list.rs index 158714b2..9602f75c 100644 --- a/src/model/image_list.rs +++ b/src/model/image_list.rs @@ -229,57 +229,61 @@ impl ImageList { .await } }, - clone!(@weak self as obj => move |result| { - match result { - Ok(summaries) => { - let to_remove = obj - .imp() - .list - .borrow() - .keys() - .filter(|id| { - !summaries - .iter() - .any(|summary| summary.id.as_ref() == Some(id)) - }) - .cloned() - .collect::>(); - to_remove.iter().for_each(|id| { - obj.remove_image(id); - }); - - summaries.iter().for_each(|summary| { - let index = obj.len(); - - let mut list = obj.imp().list.borrow_mut(); - - match list.entry(summary.id.as_ref().unwrap().to_owned()) { - Entry::Vacant(e) => { - let image = model::Image::new(&obj, summary); - e.insert(image.clone()); - - drop(list); - - obj.items_changed(index, 0, 1); - obj.image_added(&image); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + match result { + Ok(summaries) => { + let to_remove = obj + .imp() + .list + .borrow() + .keys() + .filter(|id| { + !summaries + .iter() + .any(|summary| summary.id.as_ref() == Some(id)) + }) + .cloned() + .collect::>(); + to_remove.iter().for_each(|id| { + obj.remove_image(id); + }); + + summaries.iter().for_each(|summary| { + let index = obj.len(); + + let mut list = obj.imp().list.borrow_mut(); + + match list.entry(summary.id.as_ref().unwrap().to_owned()) { + Entry::Vacant(e) => { + let image = model::Image::new(&obj, summary); + e.insert(image.clone()); + + drop(list); + + obj.items_changed(index, 0, 1); + obj.image_added(&image); + } + Entry::Occupied(e) => { + let image = e.get().to_owned(); + drop(list); + image.update(summary); + } } - Entry::Occupied(e) => { - let image = e.get().to_owned(); - drop(list); - image.update(summary); - } - } - }); - } - Err(e) => { - log::error!("Error on retrieving images: {}", e); - err_op(super::RefreshError); + }); + } + Err(e) => { + log::error!("Error on retrieving images: {}", e); + err_op(super::RefreshError); + } } + let imp = obj.imp(); + imp.set_listing(false); + imp.set_as_initialized(); } - let imp = obj.imp(); - imp.set_listing(false); - imp.set_as_initialized(); - }), + ), ); } @@ -326,7 +330,11 @@ impl ImageList { self.notify_num_images(); image.connect_notify_local( Some("repo-tags"), - clone!(@weak self as obj => move |_, _| obj.notify_num_images()), + clone!( + #[weak(rename_to = obj)] + self, + move |_, _| obj.notify_num_images() + ), ); self.emit_by_name::<()>("image-added", &[image]); } diff --git a/src/model/pod.rs b/src/model/pod.rs index 5e41050e..3d9d63c9 100644 --- a/src/model/pod.rs +++ b/src/model/pod.rs @@ -144,14 +144,18 @@ mod imp { let obj = &*self.obj(); let handler_id_ref = Rc::new(RefCell::new(None)); - let handler_id = obj.container_list().connect_container_added( - clone!(@weak obj, @strong handler_id_ref => move |list, container| if container.is_infra() { + let handler_id = obj.container_list().connect_container_added(clone!( + #[weak] + obj, + #[strong] + handler_id_ref, + move |list, container| if container.is_infra() { list.disconnect(handler_id_ref.take().unwrap()); obj.imp().infra_container.set(Some(container)); obj.notify_infra_container(); - }), - ); + } + )); handler_id_ref.set(Some(handler_id)); } } @@ -223,13 +227,17 @@ impl Pod { F: Fn(Result) + 'static, { if let Some(observers) = self.imp().inspection_observers.borrow().as_ref() { - observers.add(clone!(@weak self as obj => move |result| match result { - Ok(_) => op(Ok(obj)), - Err(e) => { - log::error!("Error on inspecting pod '{}': {e}", obj.id()); - op(Err(e)); + observers.add(clone!( + #[weak(rename_to = obj)] + self, + move |result| match result { + Ok(_) => op(Ok(obj)), + Err(e) => { + log::error!("Error on inspecting pod '{}': {e}", obj.id()); + op(Err(e)); + } } - })); + )); return; } @@ -239,22 +247,26 @@ impl Pod { let pod = self.api().unwrap(); async move { pod.inspect().await } }, - clone!(@weak self as obj => move |result| { - let imp = obj.imp(); - - imp.inspection_observers.replace(None); - - match result { - Ok(data) => { - imp.set_data(model::PodData::from(data)); - op(Ok(obj)); - }, - Err(e) => { - log::error!("Error on inspecting pod '{}': {e}", obj.id()); - op(Err(e)); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + let imp = obj.imp(); + + imp.inspection_observers.replace(None); + + match result { + Ok(data) => { + imp.set_data(model::PodData::from(data)); + op(Ok(obj)); + } + Err(e) => { + log::error!("Error on inspecting pod '{}': {e}", obj.id()); + op(Err(e)); + } } } - }), + ), ); self.imp().inspection_observers.replace(Some(observers)); @@ -292,24 +304,22 @@ impl Pod { utils::do_async( async move { fut_op(pod).await }, - clone!(@weak self as obj => move |result| { - match &result { - Ok(_) => { - log::info!( - "Pod <{}>: {name} has finished", - obj.id() - ); - } - Err(e) => { - log::error!( - "Pod <{}>: Error while {name}: {e}", - obj.id(), - ); - obj.set_action_ongoing(false); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + match &result { + Ok(_) => { + log::info!("Pod <{}>: {name} has finished", obj.id()); + } + Err(e) => { + log::error!("Pod <{}>: Error while {name}: {e}", obj.id(),); + obj.set_action_ongoing(false); + } } + res_op(result) } - res_op(result) - }), + ), ); } } @@ -402,12 +412,16 @@ impl Pod { } .map(|_| ()) }, - clone!(@weak self as obj => move |result| { - if result.is_err() { - obj.imp().set_to_be_deleted(false); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if result.is_err() { + obj.imp().set_to_be_deleted(false); + } + op(result) } - op(result) - }), + ), ); } diff --git a/src/model/pod_list.rs b/src/model/pod_list.rs index bbbdb87b..d64e6eb8 100644 --- a/src/model/pod_list.rs +++ b/src/model/pod_list.rs @@ -225,30 +225,31 @@ impl PodList { .await } }, - clone!(@weak self as obj => move |result| { - match result { - Ok(list_pods) => { - if id.is_none() { - let to_remove = obj - .imp() - .list - .borrow() - .keys() - .filter(|id| { - !list_pods - .iter() - .any(|list_pod| list_pod.id.as_ref() == Some(id)) - }) - .cloned() - .collect::>(); - to_remove.iter().for_each(|id| { - obj.remove_pod(id); - }); - } - - list_pods - .into_iter() - .for_each(|report| { + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + match result { + Ok(list_pods) => { + if id.is_none() { + let to_remove = obj + .imp() + .list + .borrow() + .keys() + .filter(|id| { + !list_pods + .iter() + .any(|list_pod| list_pod.id.as_ref() == Some(id)) + }) + .cloned() + .collect::>(); + to_remove.iter().for_each(|id| { + obj.remove_pod(id); + }); + } + + list_pods.into_iter().for_each(|report| { let index = obj.len(); let mut list = obj.imp().list.borrow_mut(); @@ -270,16 +271,17 @@ impl PodList { } } }); + } + Err(e) => { + log::error!("Error on retrieving pods: {}", e); + err_op(super::RefreshError); + } } - Err(e) => { - log::error!("Error on retrieving pods: {}", e); - err_op(super::RefreshError); - } + let imp = obj.imp(); + imp.set_listing(false); + imp.set_as_initialized(); } - let imp = obj.imp(); - imp.set_listing(false); - imp.set_as_initialized(); - }), + ), ); } @@ -299,7 +301,11 @@ impl PodList { self.notify_num_pods(); pod.connect_notify_local( Some("status"), - clone!(@weak self as obj => move |_, _| obj.notify_num_pods()), + clone!( + #[weak(rename_to = obj)] + self, + move |_, _| obj.notify_num_pods() + ), ); self.emit_by_name::<()>("pod-added", &[pod]); } diff --git a/src/model/process_list.rs b/src/model/process_list.rs index c3bcfc58..3d466691 100644 --- a/src/model/process_list.rs +++ b/src/model/process_list.rs @@ -71,56 +71,64 @@ mod imp { utils::run_stream( processes_source, move |top_source| top_source.stream(), - clone!(@weak obj => @default-return glib::ControlFlow::Break, move |result: podman::Result| { - match result { - Ok(process_fields) => { - let to_remove = obj - .imp() - .list - .borrow() - .keys() - .filter(|pid| { - !process_fields - .iter() - .any(|process_field| &process_field[1] == *pid) - }) - .cloned() - .collect::>(); - to_remove.iter().for_each(|pid| { - obj.remove(pid); - }); - - process_fields.into_iter().for_each(|process_field| { - use indexmap::map::Entry; - - let mut list = obj.imp().list.borrow_mut(); - let index = list.len() as u32; - - match list.entry(process_field[1].clone()) { - Entry::Vacant(e) => { - let process = - model::Process::new(&obj, process_field.as_slice()); - e.insert(process.clone()); - - drop(list); - - obj.items_changed(index, 0, 1); + clone!( + #[weak] + obj, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + match result { + Ok(process_fields) => { + let to_remove = obj + .imp() + .list + .borrow() + .keys() + .filter(|pid| { + !process_fields + .iter() + .any(|process_field| &process_field[1] == *pid) + }) + .cloned() + .collect::>(); + to_remove.iter().for_each(|pid| { + obj.remove(pid); + }); + + process_fields.into_iter().for_each(|process_field| { + use indexmap::map::Entry; + + let mut list = obj.imp().list.borrow_mut(); + let index = list.len() as u32; + + match list.entry(process_field[1].clone()) { + Entry::Vacant(e) => { + let process = model::Process::new( + &obj, + process_field.as_slice(), + ); + e.insert(process.clone()); + + drop(list); + + obj.items_changed(index, 0, 1); + } + Entry::Occupied(e) => { + let process = e.get().clone(); + drop(list); + process.update(process_field.as_slice()); + } } - Entry::Occupied(e) => { - let process = e.get().clone(); - drop(list); - process.update(process_field.as_slice()); - } - } - }); + }); - obj.emit_by_name::<()>("updated", &[]); + obj.emit_by_name::<()>("updated", &[]); + } + Err(e) => log::warn!("Failed to read top stream element: {e}"), } - Err(e) => log::warn!("Failed to read top stream element: {e}"), - } - glib::ControlFlow::Continue - }), + glib::ControlFlow::Continue + } + ), ); } } diff --git a/src/model/selectable_list.rs b/src/model/selectable_list.rs index 580f43d3..196d81c4 100644 --- a/src/model/selectable_list.rs +++ b/src/model/selectable_list.rs @@ -48,14 +48,18 @@ glib::wrapper! { impl SelectableList { pub(super) fn bootstrap(list: &Self) { - list.connect_items_changed(|self_, position, _, added| { - self_.notify("num-selected"); + list.connect_items_changed(|obj, position, _, added| { + obj.notify("num-selected"); (position..position + added) - .map(|i| self_.item(i).unwrap()) + .map(|i| obj.item(i).unwrap()) .for_each(|item| { item.connect_notify_local( Some("selected"), - clone!(@weak self_ as obj => move |_, _| obj.notify("num-selected")), + clone!( + #[weak] + obj, + move |_, _| obj.notify("num-selected") + ), ); }); }); diff --git a/src/model/volume.rs b/src/model/volume.rs index 0009ece4..5d1e7438 100644 --- a/src/model/volume.rs +++ b/src/model/volume.rs @@ -68,11 +68,13 @@ mod imp { fn constructed(&self) { self.parent_constructed(); let obj = &*self.obj(); - obj.container_list().connect_items_changed( - clone!(@weak obj => move |_, _, _, _| if let Some(volume_list) = obj.volume_list() { + obj.container_list().connect_items_changed(clone!( + #[weak] + obj, + move |_, _, _, _| if let Some(volume_list) = obj.volume_list() { volume_list.notify_num_volumes(); - }), - ); + } + )); } } @@ -119,13 +121,17 @@ impl Volume { volume.delete().await } }, - clone!(@weak self as obj => move |result| { - if let Err(ref e) = result { - obj.imp().set_to_be_deleted(false); - log::error!("Error on removing volume: {}", e); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(ref e) = result { + obj.imp().set_to_be_deleted(false); + log::error!("Error on removing volume: {}", e); + } + op(&obj, result); } - op(&obj, result); - }), + ), ); } } diff --git a/src/model/volume_list.rs b/src/model/volume_list.rs index 7cbe0a33..67214219 100644 --- a/src/model/volume_list.rs +++ b/src/model/volume_list.rs @@ -209,50 +209,50 @@ impl VolumeList { .await } }, - clone!(@weak self as obj => move |result| { - match result { - Ok(volumes) => { - let imp = obj.imp(); - - let to_remove = imp - .list - .borrow() - .keys() - .filter(|name| { - !volumes - .iter() - .any(|volume| &volume.name == *name) - }) - .cloned() - .collect::>(); - to_remove.iter().for_each(|name| { - obj.remove_volume(name); - }); - - volumes.into_iter().for_each(|volume| { - let index = obj.len(); - - let mut list = imp.list.borrow_mut(); - if let Entry::Vacant(e) = list.entry(volume.name.clone()) { - let volume = model::Volume::new(&obj, volume); - e.insert(volume.clone()); - - drop(list); - - obj.items_changed(index, 0, 1); - obj.volume_added(&volume); - } - }); - } - Err(e) => { - log::error!("Error on retrieving volumes: {}", e); - err_op(super::RefreshError); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + match result { + Ok(volumes) => { + let imp = obj.imp(); + + let to_remove = imp + .list + .borrow() + .keys() + .filter(|name| !volumes.iter().any(|volume| &volume.name == *name)) + .cloned() + .collect::>(); + to_remove.iter().for_each(|name| { + obj.remove_volume(name); + }); + + volumes.into_iter().for_each(|volume| { + let index = obj.len(); + + let mut list = imp.list.borrow_mut(); + if let Entry::Vacant(e) = list.entry(volume.name.clone()) { + let volume = model::Volume::new(&obj, volume); + e.insert(volume.clone()); + + drop(list); + + obj.items_changed(index, 0, 1); + obj.volume_added(&volume); + } + }); + } + Err(e) => { + log::error!("Error on retrieving volumes: {}", e); + err_op(super::RefreshError); + } } + let imp = obj.imp(); + imp.set_listing(false); + imp.set_as_initialized(); } - let imp = obj.imp(); - imp.set_listing(false); - imp.set_as_initialized(); - }), + ), ); } diff --git a/src/utils.rs b/src/utils.rs index c57a35ee..c0c5bff2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -417,7 +417,11 @@ where { do_async( async move { request.send().await.and_then(|files| files.response()) }, - clone!(@weak widget => move |files| show_file_dialog(files, &widget, op)), + clone!( + #[weak] + widget, + move |files| show_file_dialog(files, &widget, op) + ), ); } @@ -427,7 +431,11 @@ where { do_async( async move { request.send().await.and_then(|files| files.response()) }, - clone!(@weak widget => move |files| show_file_dialog(files, &widget, op)), + clone!( + #[weak] + widget, + move |files| show_file_dialog(files, &widget, op) + ), ); } diff --git a/src/view/action_page.rs b/src/view/action_page.rs index 1cbbddf0..3eaa7075 100644 --- a/src/view/action_page.rs +++ b/src/view/action_page.rs @@ -77,7 +77,11 @@ mod imp { obj.update_state(&action); action.connect_notify_local( Some("state"), - clone!(@weak obj => move |action, _| obj.update_state(action)), + clone!( + #[weak] + obj, + move |action, _| obj.update_state(action) + ), ); self.status_page @@ -97,9 +101,15 @@ mod imp { obj.set_description(&action); glib::timeout_add_seconds_local( 1, - clone!(@weak obj, @weak action => @default-return glib::ControlFlow::Break, move || { - obj.set_description(&action) - }), + clone!( + #[weak] + obj, + #[weak] + action, + #[upgrade_or] + glib::ControlFlow::Break, + move || obj.set_description(&action) + ), ); } diff --git a/src/view/action_row.rs b/src/view/action_row.rs index 944d3d7d..45d82832 100644 --- a/src/view/action_row.rs +++ b/src/view/action_row.rs @@ -191,46 +191,71 @@ mod imp { let handler = action.connect_notify_local( Some("state"), - clone!(@weak obj => move |action, _| { - obj.set_state_label(action); - - if !matches!(action.state(), model::ActionState::Failed | model::ActionState::Finished) { - return; - } + clone!( + #[weak] + obj, + move |action, _| { + obj.set_state_label(action); + + if !matches!( + action.state(), + model::ActionState::Failed | model::ActionState::Finished + ) { + return; + } - let id = obj.imp().notification_id.get().unwrap().to_owned(); - let notification = if action.state() == model::ActionState::Failed { - ashpd::notification::Notification::new(&gettext("Failed Pods Action")) - .icon(ashpd::Icon::Names(vec!["computer-fail-symbolic".to_string()])) + let id = obj.imp().notification_id.get().unwrap().to_owned(); + let notification = if action.state() == model::ActionState::Failed { + ashpd::notification::Notification::new(&gettext( + "Failed Pods Action", + )) + .icon(ashpd::Icon::Names(vec![ + "computer-fail-symbolic".to_string() + ])) .priority(ashpd::notification::Priority::High) - } else { - ashpd::notification::Notification::new(&gettext("Finished Pods Action")) - .icon(ashpd::Icon::Names(vec!["checkbox-checked-symbolic".to_string()])) + } else { + ashpd::notification::Notification::new(&gettext( + "Finished Pods Action", + )) + .icon(ashpd::Icon::Names(vec![ + "checkbox-checked-symbolic".to_string() + ])) .priority(ashpd::notification::Priority::Low) + } + .body(action.description().as_ref()) + .default_action(""); + + crate::runtime().spawn(async move { + let _ = ashpd::notification::NotificationProxy::new() + .await + .unwrap() + .add_notification(&id, notification) + .await; + }); } - .body(action.description().as_ref()) - .default_action(""); - - crate::runtime().spawn(async move { - let _ = ashpd::notification::NotificationProxy::new().await.unwrap() - .add_notification(&id, notification) - .await; - }); - }), + ), ); self.handler.replace(Some(handler)); let timer = glib::timeout_add_seconds_local( 1, - clone!(@weak obj, @weak action => @default-return glib::ControlFlow::Break, move || { - let control_flow = obj.set_state_label(&action); - if control_flow.is_break() { - if let Some(timer) = obj.imp().timer.take() { - timer.remove(); + clone!( + #[weak] + obj, + #[weak] + action, + #[upgrade_or] + glib::ControlFlow::Break, + move || { + let control_flow = obj.set_state_label(&action); + if control_flow.is_break() { + if let Some(timer) = obj.imp().timer.take() { + timer.remove(); + } } + control_flow } - control_flow - }), + ), ); self.timer.replace(Some(timer)); } diff --git a/src/view/actions_sidebar.rs b/src/view/actions_sidebar.rs index 77d5c103..a832ee17 100644 --- a/src/view/actions_sidebar.rs +++ b/src/view/actions_sidebar.rs @@ -102,12 +102,16 @@ mod imp { action_list_can_clear_expr.clone().watch( Some(obj), - clone!(@weak obj => move || { - obj.action_set_enabled( - ACTIONS_OVERVIEW_ACTION_CLEAR_ACTIONS, - action_list_can_clear_expr.evaluate_as(Some(&obj)).unwrap() - ); - }), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTIONS_OVERVIEW_ACTION_CLEAR_ACTIONS, + action_list_can_clear_expr.evaluate_as(Some(&obj)).unwrap(), + ); + } + ), ); } diff --git a/src/view/connection_chooser_page.rs b/src/view/connection_chooser_page.rs index 2a31d6ac..2cb52004 100644 --- a/src/view/connection_chooser_page.rs +++ b/src/view/connection_chooser_page.rs @@ -100,13 +100,17 @@ mod imp { connection_manager.set_client_from( &connection.uuid(), - clone!(@weak obj => move |result| if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on establishing connection"), - &e.to_string(), - ); - }), + clone!( + #[weak] + obj, + move |result| if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on establishing connection"), + &e.to_string(), + ); + } + ), ); } } diff --git a/src/view/connection_creation_page.rs b/src/view/connection_creation_page.rs index 57c97b6e..972dad0e 100644 --- a/src/view/connection_creation_page.rs +++ b/src/view/connection_creation_page.rs @@ -126,7 +126,11 @@ mod imp { obj.update_actions(); obj.connection_manager().connect_notify_local( Some("connecting"), - clone!(@weak obj => move|_ ,_| obj.update_actions()), + clone!( + #[weak] + obj, + move |_, _| obj.update_actions() + ), ); self.unix_socket_url_row @@ -162,12 +166,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().name_entry_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.connect_button)); } @@ -260,10 +268,14 @@ impl ConnectionCreationPage { } else { None }, - clone!(@weak self as obj => move |result| match result { - Ok(_) => obj.activate_action("win.close", None).unwrap(), - Err(e) => obj.on_error(&e.to_string()), - }), + clone!( + #[weak(rename_to = obj)] + self, + move |result| match result { + Ok(_) => obj.activate_action("win.close", None).unwrap(), + Err(e) => obj.on_error(&e.to_string()), + } + ), ) { self.on_error(&e.to_string()); } diff --git a/src/view/connection_custom_info_page.rs b/src/view/connection_custom_info_page.rs index 554096d5..2843e176 100644 --- a/src/view/connection_custom_info_page.rs +++ b/src/view/connection_custom_info_page.rs @@ -86,9 +86,13 @@ mod imp { ); let style_manager = adw::StyleManager::default(); - style_manager.connect_dark_notify(clone!(@weak obj => move |style_manager| { - obj.imp().on_notify_dark(style_manager); - })); + style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.imp().on_notify_dark(style_manager); + } + )); self.on_notify_dark(&style_manager); } } diff --git a/src/view/connections_sidebar.rs b/src/view/connections_sidebar.rs index cc0de2ce..92962b36 100644 --- a/src/view/connections_sidebar.rs +++ b/src/view/connections_sidebar.rs @@ -98,13 +98,17 @@ mod imp { ) { connection_manager.set_client_from( &connection.uuid(), - clone!(@weak obj => move |result| if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on switching connection"), - &e.to_string(), - ); - }), + clone!( + #[weak] + obj, + move |result| if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on switching connection"), + &e.to_string(), + ); + } + ), ); } } diff --git a/src/view/container.rs b/src/view/container.rs index 090a78f3..712e7c16 100644 --- a/src/view/container.rs +++ b/src/view/container.rs @@ -62,14 +62,20 @@ pub(crate) fn rename(widget: >k::Widget, container: Option<&model::Container>) .extra_child(&container_renamer) .build(); - container.connect_deleted(clone!(@weak widget, @weak dialog => move |_| { - dialog.force_close(); - utils::show_error_toast( - &widget, - &gettext("Error renaming container"), - &gettext("Container has been deleted"), - ); - })); + container.connect_deleted(clone!( + #[weak] + widget, + #[weak] + dialog, + move |_| { + dialog.force_close(); + utils::show_error_toast( + &widget, + &gettext("Error renaming container"), + &gettext("Container has been deleted"), + ); + } + )); container .property_expression_weak("name") @@ -91,18 +97,30 @@ pub(crate) fn rename(widget: >k::Widget, container: Option<&model::Container>) dialog.connect_response( Some("rename"), - clone!(@weak widget, @weak container, @weak container_renamer => move |dialog, _| { - container.rename( - container_renamer.new_name(), - clone!(@weak widget, @weak dialog => move |result| if let Err(e) = result { - utils::show_error_toast( - &widget, - &gettext("Error renaming container"), - &e.to_string() - ); - }), - ); - }), + clone!( + #[weak] + widget, + #[weak] + container, + #[weak] + container_renamer, + move |_, _| { + container.rename( + container_renamer.new_name(), + clone!( + #[weak] + widget, + move |result| if let Err(e) = result { + utils::show_error_toast( + &widget, + &gettext("Error renaming container"), + &e.to_string(), + ); + } + ), + ); + } + ), ); dialog.present(Some(widget)); @@ -116,7 +134,7 @@ macro_rules! container_action { if let Some(container) = ::property::>(widget, "container") { container.$action( $($param,)* - glib::clone!(@weak widget => move |result| if let Err(e) = result { + glib::clone!(#[weak] widget, move |result| if let Err(e) = result { crate::utils::show_error_toast( &widget, &$error, diff --git a/src/view/container_card.rs b/src/view/container_card.rs index 301c25d2..ef27d654 100644 --- a/src/view/container_card.rs +++ b/src/view/container_card.rs @@ -192,10 +192,24 @@ mod imp { let pod_status_expr = pod_expr.chain_property::("status"); let stats_expr = container_expr.chain_property::("stats"); - status_expr.watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + status_expr.watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); container_expr .chain_property::("action-ongoing") - .watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + .watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); let css_classes = utils::css_classes(obj.upcast_ref()); status_expr @@ -458,28 +472,29 @@ mod imp { self.ports_pod_stack.set_visible_child_name("ports"); self.ports_flow_box.bind_model( Some(&container.ports()), - clone!(@weak obj => @default-panic, move |item| { - let port_mapping = - item.downcast_ref::().unwrap(); - - let label = gtk::Label::builder() - .css_classes([ - "status-badge-small", - "numeric", - ]) - .halign(gtk::Align::Center) - .valign(gtk::Align::Center) - .label(format!( - "{}/{}", - port_mapping.host_port(), - port_mapping.protocol() - )) - .build(); - - let css_classes = utils::css_classes(label.upcast_ref()); - super::ContainerCard::this_expression("container") - .chain_property::("status") - .chain_closure::>(closure!( + clone!( + #[weak] + obj, + #[upgrade_or_panic] + move |item| { + let port_mapping = + item.downcast_ref::().unwrap(); + + let label = gtk::Label::builder() + .css_classes(["status-badge-small", "numeric"]) + .halign(gtk::Align::Center) + .valign(gtk::Align::Center) + .label(format!( + "{}/{}", + port_mapping.host_port(), + port_mapping.protocol() + )) + .build(); + + let css_classes = utils::css_classes(label.upcast_ref()); + super::ContainerCard::this_expression("container") + .chain_property::("status") + .chain_closure::>(closure!( |_: super::ContainerCard, status: model::ContainerStatus| { css_classes .iter() @@ -490,14 +505,15 @@ mod imp { .collect::>() } )) - .bind(&label, "css-classes", Some(&obj)); - - gtk::FlowBoxChild::builder() - .halign(gtk::Align::Start) - .child(&label) - .build() - .upcast() - }), + .bind(&label, "css-classes", Some(&obj)); + + gtk::FlowBoxChild::builder() + .halign(gtk::Align::Start) + .child(&label) + .build() + .upcast() + } + ), ); } else { self.ports_pod_stack.set_visible_child_name("no-ports"); @@ -585,11 +601,19 @@ impl ContainerCard { percent_expr.watch( Some(self), - clone!(@weak self as obj, @weak progress_bar, @strong percent_expr => move || { - animation.set_value_from(progress_bar.fraction()); - animation.set_value_to(percent_expr.evaluate_as(Some(&obj)).unwrap_or(0.0)); - animation.play(); - }), + clone!( + #[weak(rename_to = obj)] + self, + #[weak] + progress_bar, + #[strong] + percent_expr, + move || { + animation.set_value_from(progress_bar.fraction()); + animation.set_value_to(percent_expr.evaluate_as(Some(&obj)).unwrap_or(0.0)); + animation.play(); + } + ), ); let classes = utils::css_classes(progress_bar.upcast_ref()); diff --git a/src/view/container_commit_page.rs b/src/view/container_commit_page.rs index 9937a807..7f0263c2 100644 --- a/src/view/container_commit_page.rs +++ b/src/view/container_commit_page.rs @@ -123,12 +123,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().author_entry_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.commit_button)); } @@ -151,9 +155,13 @@ mod imp { } if let Some(container) = value { - container.connect_deleted(clone!(@weak obj => move |_| { - obj.activate_action("win.close", None).unwrap(); - })); + container.connect_deleted(clone!( + #[weak] + obj, + move |_| { + obj.activate_action("win.close", None).unwrap(); + } + )); } self.container.set(value); @@ -187,32 +195,40 @@ impl ContainerCommitPage { .await .and_then(|user_info| user_info.response()) }, - clone!(@weak self as obj => move |user_info| { - match user_info { - Ok(user_info) => obj.imp().author_entry_row.set_text(user_info.name()), - Err(e) => { - if let ashpd::Error::Portal(ashpd::PortalError::Cancelled(_)) = e { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on fetching user name"), - &e.to_string(), - ); + clone!( + #[weak(rename_to = obj)] + self, + move |user_info| { + match user_info { + Ok(user_info) => obj.imp().author_entry_row.set_text(user_info.name()), + Err(e) => { + if let ashpd::Error::Portal(ashpd::PortalError::Cancelled(_)) = e { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on fetching user name"), + &e.to_string(), + ); + } } } } - }), + ), ); } pub(crate) fn add_change(&self) { let change = model::Value::default(); - change.connect_remove_request(clone!(@weak self as obj => move |change| { - let changes = obj.imp().changes(); - if let Some(pos) = changes.find(change) { - changes.remove(pos); + change.connect_remove_request(clone!( + #[weak(rename_to = obj)] + self, + move |change| { + let changes = obj.imp().changes(); + if let Some(pos) = changes.find(change) { + changes.remove(pos); + } } - })); + )); self.imp().changes().append(&change); } diff --git a/src/view/container_creation_page.rs b/src/view/container_creation_page.rs index baa3522b..df141134 100644 --- a/src/view/container_creation_page.rs +++ b/src/view/container_creation_page.rs @@ -251,12 +251,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().name_entry_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.create_button)); } @@ -428,10 +432,13 @@ impl ContainerCreationPage { image.disconnect(handler); } } - let handler = - image.connect_data_notify(clone!(@weak self as obj => move |image| { + let handler = image.connect_data_notify(clone!( + #[weak(rename_to = obj)] + self, + move |image| { obj.update_local_data(&image.data().unwrap().config()); - })); + } + )); let image_weak = glib::WeakRef::new(); image_weak.set(Some(&image)); imp.command_row_handler.replace(Some((handler, image_weak))); @@ -449,9 +456,13 @@ impl ContainerCreationPage { pub(crate) fn select_pod(&self) { if let Some(client) = self.client() { let pod_selection_page = view::PodSelectionPage::from(&client.pod_list()); - pod_selection_page.connect_pod_selected(clone!(@weak self as obj => move |_, pod| { - obj.set_pod(Some(&pod)); - })); + pod_selection_page.connect_pod_selected(clone!( + #[weak(rename_to = obj)] + self, + move |_, pod| { + obj.set_pod(Some(&pod)); + } + )); self.imp().navigation_view.push( &adw::NavigationPage::builder() .child(&pod_selection_page) @@ -713,11 +724,15 @@ fn bind_model( fn add_port_mapping(model: &gio::ListStore) -> model::PortMapping { let port_mapping = model::PortMapping::default(); - port_mapping.connect_remove_request(clone!(@weak model => move |port_mapping| { - if let Some(pos) = model.find(port_mapping) { - model.remove(pos); + port_mapping.connect_remove_request(clone!( + #[weak] + model, + move |port_mapping| { + if let Some(pos) = model.find(port_mapping) { + model.remove(pos); + } } - })); + )); model.append(&port_mapping); @@ -727,11 +742,15 @@ fn add_port_mapping(model: &gio::ListStore) -> model::PortMapping { fn add_mount(model: &gio::ListStore, client: &model::Client) -> model::Mount { let mount = model::Mount::from(client); - mount.connect_remove_request(clone!(@weak model => move |mount| { - if let Some(pos) = model.find(mount) { - model.remove(pos); + mount.connect_remove_request(clone!( + #[weak] + model, + move |mount| { + if let Some(pos) = model.find(mount) { + model.remove(pos); + } } - })); + )); model.append(&mount); mount @@ -740,11 +759,15 @@ fn add_mount(model: &gio::ListStore, client: &model::Client) -> model::Mount { fn add_value(model: &gio::ListStore) { let value = model::Value::default(); - value.connect_remove_request(clone!(@weak model => move |value| { - if let Some(pos) = model.find(value) { - model.remove(pos); + value.connect_remove_request(clone!( + #[weak] + model, + move |value| { + if let Some(pos) = model.find(value) { + model.remove(pos); + } } - })); + )); model.append(&value); } @@ -752,11 +775,15 @@ fn add_value(model: &gio::ListStore) { fn add_key_val(model: &gio::ListStore) { let entry = model::KeyVal::default(); - entry.connect_remove_request(clone!(@weak model => move |entry| { - if let Some(pos) = model.find(entry) { - model.remove(pos); + entry.connect_remove_request(clone!( + #[weak] + model, + move |entry| { + if let Some(pos) = model.find(entry) { + model.remove(pos); + } } - })); + )); model.append(&entry); } diff --git a/src/view/container_details_page.rs b/src/view/container_details_page.rs index a3b7431d..ff5d7a06 100644 --- a/src/view/container_details_page.rs +++ b/src/view/container_details_page.rs @@ -178,37 +178,64 @@ mod imp { })) .bind(&*self.resources, "visible", Some(obj)); - status_expr.watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + status_expr.watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); container_expr .chain_property::("action-ongoing") - .watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + .watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); container_expr .chain_property::("health_status") .watch( Some(obj), - clone!(@weak obj => move || { - obj.action_set_enabled( - ACTION_SHOW_HEALTH_DETAILS, - obj.container() - .as_ref() - .map(model::Container::health_status) - .map(|status| status != model::ContainerHealthStatus::Unconfigured) - .unwrap_or(false), - ); - }), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTION_SHOW_HEALTH_DETAILS, + obj.container() + .as_ref() + .map(model::Container::health_status) + .map(|status| { + status != model::ContainerHealthStatus::Unconfigured + }) + .unwrap_or(false), + ); + } + ), ); container_expr .chain_property::("image") .watch( Some(obj), - clone!(@weak obj => move || { - obj.action_set_enabled( - ACTION_SHOW_IMAGE_DETAILS, - obj.container().as_ref().and_then(model::Container::image).is_some() - ); - }), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTION_SHOW_IMAGE_DETAILS, + obj.container() + .as_ref() + .and_then(model::Container::image) + .is_some(), + ); + } + ), ); } @@ -231,14 +258,29 @@ mod imp { } if let Some(container) = value { - container.inspect(clone!(@weak obj => move |result| if let Err(e) = result { - utils::show_error_toast(obj.upcast_ref(), &gettext("Error on loading container details"), &e.to_string()); - })); - - let handler_id = container.connect_deleted(clone!(@weak obj => move |container| { - utils::show_toast(obj.upcast_ref(), gettext!("Container '{}' has been deleted", container.name())); - utils::navigation_view(obj.upcast_ref()).pop(); - })); + container.inspect(clone!( + #[weak] + obj, + move |result| if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on loading container details"), + &e.to_string(), + ); + } + )); + + let handler_id = container.connect_deleted(clone!( + #[weak] + obj, + move |container| { + utils::show_toast( + obj.upcast_ref(), + gettext!("Container '{}' has been deleted", container.name()), + ); + utils::navigation_view(obj.upcast_ref()).pop(); + } + )); self.handler_id.replace(Some(handler_id)); let sorter = gtk::StringSorter::new(Some( @@ -257,9 +299,11 @@ mod imp { }); obj.update_volumes_visibility(); - container.volume_list().connect_items_changed( - clone!(@weak obj => move |_, _, _, _| obj.update_volumes_visibility()), - ); + container.volume_list().connect_items_changed(clone!( + #[weak] + obj, + move |_, _, _, _| obj.update_volumes_visibility() + )); } self.container.set(value); diff --git a/src/view/container_files_get_page.rs b/src/view/container_files_get_page.rs index b25ae12a..eb7dd016 100644 --- a/src/view/container_files_get_page.rs +++ b/src/view/container_files_get_page.rs @@ -77,10 +77,13 @@ mod imp { let obj = self.obj(); obj.action_set_enabled(ACTION_GET, false); - self.host_path_row - .connect_subtitle_notify(clone!(@weak obj => move |row| { + self.host_path_row.connect_subtitle_notify(clone!( + #[weak] + obj, + move |row| { obj.action_set_enabled(ACTION_GET, row.subtitle().is_some()); - })); + } + )); } fn dispose(&self) { @@ -94,12 +97,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().container_path_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.get_button)); } @@ -117,9 +124,13 @@ mod imp { } if let Some(container) = value { - container.connect_deleted(clone!(@weak obj => move |_| { - obj.activate_action("win.close", None).unwrap(); - })); + container.connect_deleted(clone!( + #[weak] + obj, + move |_| { + obj.activate_action("win.close", None).unwrap(); + } + )); } self.container.set(value); @@ -152,13 +163,17 @@ impl ContainerFilesGetPage { utils::show_save_file_dialog( request, self.upcast_ref(), - clone!(@weak self as obj => move |files| { - let file = gio::File::for_uri(files.uris()[0].as_str()); - - if let Some(path) = file.path() { - obj.imp().host_path_row.set_subtitle(path.to_str().unwrap()); + clone!( + #[weak(rename_to = obj)] + self, + move |files| { + let file = gio::File::for_uri(files.uris()[0].as_str()); + + if let Some(path) = file.path() { + obj.imp().host_path_row.set_subtitle(path.to_str().unwrap()); + } } - }), + ), ) .await; } diff --git a/src/view/container_files_put_page.rs b/src/view/container_files_put_page.rs index 62139497..215453ce 100644 --- a/src/view/container_files_put_page.rs +++ b/src/view/container_files_put_page.rs @@ -88,10 +88,13 @@ mod imp { let obj = self.obj(); obj.action_set_enabled(ACTION_PUT, false); - self.host_path_row - .connect_subtitle_notify(clone!(@weak obj => move |row| { + self.host_path_row.connect_subtitle_notify(clone!( + #[weak] + obj, + move |row| { obj.action_set_enabled(ACTION_PUT, row.subtitle().is_some()); - })); + } + )); } fn dispose(&self) { @@ -105,12 +108,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().container_path_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.put_button)); } @@ -128,9 +135,13 @@ mod imp { } if let Some(container) = value { - container.connect_deleted(clone!(@weak obj => move |_| { - obj.activate_action("win.close", None).unwrap(); - })); + container.connect_deleted(clone!( + #[weak] + obj, + move |_| { + obj.activate_action("win.close", None).unwrap(); + } + )); } self.container.set(value); @@ -170,16 +181,20 @@ impl ContainerFilesPutPage { utils::show_open_file_dialog( request, self.upcast_ref(), - clone!(@weak self as obj => move |files| { - let file = gio::File::for_uri(files.uris()[0].as_str()); - - if let Some(path) = file.path() { - let imp = obj.imp(); - - imp.host_path_row.set_subtitle(path.to_str().unwrap()); - imp.directory.set(directory); + clone!( + #[weak(rename_to = obj)] + self, + move |files| { + let file = gio::File::for_uri(files.uris()[0].as_str()); + + if let Some(path) = file.path() { + let imp = obj.imp(); + + imp.host_path_row.set_subtitle(path.to_str().unwrap()); + imp.directory.set(directory); + } } - }), + ), ) .await; } diff --git a/src/view/container_health_check_page.rs b/src/view/container_health_check_page.rs index 60cb7342..1c83a8d3 100644 --- a/src/view/container_health_check_page.rs +++ b/src/view/container_health_check_page.rs @@ -85,22 +85,33 @@ mod imp { let data_expr = container_expr.chain_property::("data"); gtk::ClosureExpression::new::( - [&container_expr.chain_property::("status"), &health_status_expr], + [ + &container_expr.chain_property::("status"), + &health_status_expr, + ], closure!(|_: Self::Type, _: model::ContainerStatus, _: model::ContainerHealthStatus| false), ) - .watch(Some(obj), clone!(@weak obj => move || { - obj.action_set_enabled( - ACTION_RUN_HEALTH_COMMAND, - obj.container() - .map(|container| { - container.health_status() != model::ContainerHealthStatus::Unconfigured - && container.status() == model::ContainerStatus::Running - }) - .unwrap_or(false), - ); - })); + .watch( + Some(obj), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTION_RUN_HEALTH_COMMAND, + obj.container() + .map(|container| { + container.health_status() + != model::ContainerHealthStatus::Unconfigured + && container.status() == model::ContainerStatus::Running + }) + .unwrap_or(false), + ); + } + ), + ); health_status_expr .chain_closure::(closure!( @@ -123,31 +134,48 @@ mod imp { )) .bind(&*self.status_label, "css-classes", Some(obj)); - data_expr.watch(Some(obj), clone!(@weak obj => move || { - let model = obj - .container() - .as_ref() - .and_then(model::Container::data) - .as_ref() - .map(model::ContainerData::health_check_log_list); - - if let Some(ref model) = model { - obj.set_list_box_visibility(model.upcast_ref()); - model.connect_items_changed(clone!(@weak obj => move |model, _, _, _| { - obj.set_list_box_visibility(model.upcast_ref()); - })); - } - - let sort_model = gtk::SortListModel::new(model, Some(gtk::CustomSorter::new(|item1, item2| { - let log1 = item1.downcast_ref::().unwrap(); - let log2 = item2.downcast_ref::().unwrap(); - log2.start().cmp(&log1.start()).into() - }))); - - obj.imp().log_list_box.bind_model(Some(&sort_model), move |log| { - view::ContainerHealthCheckLogRow::from(log.downcast_ref().unwrap()).upcast() - }) - })); + data_expr.watch( + Some(obj), + clone!( + #[weak] + obj, + move || { + let model = obj + .container() + .as_ref() + .and_then(model::Container::data) + .as_ref() + .map(model::ContainerData::health_check_log_list); + + if let Some(ref model) = model { + obj.set_list_box_visibility(model.upcast_ref()); + model.connect_items_changed(clone!( + #[weak] + obj, + move |model, _, _, _| { + obj.set_list_box_visibility(model.upcast_ref()); + } + )); + } + + let sort_model = gtk::SortListModel::new( + model, + Some(gtk::CustomSorter::new(|item1, item2| { + let log1 = item1.downcast_ref::().unwrap(); + let log2 = item2.downcast_ref::().unwrap(); + log2.start().cmp(&log1.start()).into() + })), + ); + + obj.imp() + .log_list_box + .bind_model(Some(&sort_model), move |log| { + view::ContainerHealthCheckLogRow::from(log.downcast_ref().unwrap()) + .upcast() + }) + } + ), + ); } fn dispose(&self) { @@ -231,13 +259,17 @@ impl ContainerHealthCheckPage { if let Some(container) = self.container().as_ref().and_then(model::Container::api) { utils::do_async( async move { container.healthcheck().await }, - clone!(@weak self as obj => move |result| if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on running health check"), - &e.to_string() - ); - }), + clone!( + #[weak(rename_to = obj)] + self, + move |result| if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on running health check"), + &e.to_string(), + ); + } + ), ); } } diff --git a/src/view/container_log_page.rs b/src/view/container_log_page.rs index 57da93f4..c128971d 100644 --- a/src/view/container_log_page.rs +++ b/src/view/container_log_page.rs @@ -234,9 +234,13 @@ mod imp { let adw_style_manager = adw::StyleManager::default(); obj.on_notify_dark(&adw_style_manager); - adw_style_manager.connect_dark_notify(clone!(@weak obj => move |style_manager| { - obj.on_notify_dark(style_manager); - })); + adw_style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.on_notify_dark(style_manager); + } + )); ::gutter( &*self.scalable_text_view, @@ -260,15 +264,23 @@ mod imp { let adj = self.scrolled_window.vadjustment(); obj.on_adjustment_changed(&adj); - adj.connect_value_changed(clone!(@weak obj => move |adj| { - obj.on_adjustment_changed(adj); - })); - - adj.connect_upper_notify(clone!(@weak obj => move |_| { - if obj.sticky() || obj.imp().is_auto_scrolling.get() { - obj.scroll_down(); + adj.connect_value_changed(clone!( + #[weak] + obj, + move |adj| { + obj.on_adjustment_changed(adj); } - })); + )); + + adj.connect_upper_notify(clone!( + #[weak] + obj, + move |_| { + if obj.sticky() || obj.imp().is_auto_scrolling.get() { + obj.scroll_down(); + } + } + )); Self::Type::this_expression("container") .chain_property::("status") @@ -280,11 +292,15 @@ mod imp { if let Some(container) = obj.container() { container.connect_notify_local( Some("status"), - clone!(@weak obj => move |container, _| { - if container.status() == model::ContainerStatus::Running { - obj.follow_log(); + clone!( + #[weak] + obj, + move |container, _| { + if container.status() == model::ContainerStatus::Running { + obj.follow_log(); + } } - }), + ), ); } @@ -383,9 +399,13 @@ impl ContainerLogPage { let imp = self.imp(); imp.is_auto_scrolling.set(true); - glib::idle_add_local_once(clone!(@weak self as obj => move || { - obj.imp().scrolled_window.vadjustment().set_value(f64::MAX); - })); + glib::idle_add_local_once(clone!( + #[weak(rename_to = obj)] + self, + move || { + obj.imp().scrolled_window.vadjustment().set_value(f64::MAX); + } + )); } fn on_adjustment_changed(&self, adj: >k::Adjustment) { @@ -415,14 +435,24 @@ impl ContainerLogPage { .logs(&basic_opts_builder(false, true).tail("512").build()) .boxed() }, - clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move |result| { - obj.imp().stack.set_visible_child_name("loaded"); - obj.append_line(result, &mut perform) - }), - clone!(@weak self as obj => move || { - obj.imp().stack.set_visible_child_name("loaded"); - obj.follow_log(); - }), + clone!( + #[weak(rename_to = obj)] + self, + #[upgrade_or] + glib::ControlFlow::Break, + move |result| { + obj.imp().stack.set_visible_child_name("loaded"); + obj.append_line(result, &mut perform) + } + ), + clone!( + #[weak(rename_to = obj)] + self, + move || { + obj.imp().stack.set_visible_child_name("loaded"); + obj.follow_log(); + } + ), ); } } @@ -451,14 +481,20 @@ impl ContainerLogPage { utils::run_stream( container, move |container| container.logs(&opts.build()).boxed(), - clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move |result: podman::Result| { - if skip.load(Ordering::Relaxed) == 0 { - obj.append_line(result, &mut perform) - } else { - skip.fetch_sub(1, Ordering::Relaxed); - glib::ControlFlow::Continue + clone!( + #[weak(rename_to = obj)] + self, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + if skip.load(Ordering::Relaxed) == 0 { + obj.append_line(result, &mut perform) + } else { + skip.fetch_sub(1, Ordering::Relaxed); + glib::ControlFlow::Continue + } } - }), + ), ); } } @@ -539,28 +575,42 @@ impl ContainerLogPage { .logs(&basic_opts_builder(false, true).until(until).build()) .boxed() }, - clone!(@weak self as obj => @default-return glib::ControlFlow::Break, move |result| { - let imp = obj.imp(); - imp.fetch_lines_state.set(FetchLinesState::Fetching); - - match result { - Ok(line) => { - imp.fetched_lines.borrow_mut().push_back(Vec::from(line)); - glib::ControlFlow::Continue - } - Err(e) => { - log::warn!("Stopping container log stream due to error: {e}"); - glib::ControlFlow::Break + clone!( + #[weak(rename_to = obj)] + self, + #[upgrade_or] + glib::ControlFlow::Break, + move |result| { + let imp = obj.imp(); + imp.fetch_lines_state.set(FetchLinesState::Fetching); + + match result { + Ok(line) => { + imp.fetched_lines + .borrow_mut() + .push_back(Vec::from(line)); + glib::ControlFlow::Continue + } + Err(e) => { + log::warn!( + "Stopping container log stream due to error: {e}" + ); + glib::ControlFlow::Break + } } } - }), - clone!(@weak self as obj => move || { - let imp = obj.imp(); - imp.lines_loading_revealer.set_reveal_child(false); - imp.fetch_lines_state.set(FetchLinesState::Finished); - - obj.move_lines_to_buffer(); - }), + ), + clone!( + #[weak(rename_to = obj)] + self, + move || { + let imp = obj.imp(); + imp.lines_loading_revealer.set_reveal_child(false); + imp.fetch_lines_state.set(FetchLinesState::Finished); + + obj.move_lines_to_buffer(); + } + ), ); } } @@ -620,78 +670,92 @@ impl ContainerLogPage { utils::show_save_file_dialog( request, self.upcast_ref(), - clone!(@weak self as obj => move |files| { - obj.action_set_enabled(ACTION_SAVE_TO_FILE, false); - - let file = gio::File::for_uri(files.uris()[0].as_str()); - - if let Some(path) = file.path() { - let file = std::fs::OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(path) - .unwrap(); - - let mut writer = BufWriter::new(file); - let mut perform = PlainTextPerform::default(); - - let timestamps = files.choices()[0].1 == "true"; - - utils::run_stream_with_finish_handler( - container.api().unwrap(), - move |container| { - container - .logs(&basic_opts_builder(false, timestamps).build()) - .boxed() - }, - clone!( - @weak obj => @default-return glib::ControlFlow::Break, - move |result: podman::Result| - { - match result.map(Vec::from) { - Ok(line) => { - perform.decode(&line); - - let line = perform.move_out_buffer(); - if !line.is_empty() { - match writer - .write_all(line.as_bytes()) - .and_then(|_| writer.write_all(b"\n")) - { - Ok(_) => glib::ControlFlow::Continue, - Err(e) => { - log::warn!("Error on saving logs: {e}"); - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on saving logs"), - &e.to_string(), - ); - glib::ControlFlow::Break + clone!( + #[weak(rename_to = obj)] + self, + move |files| { + obj.action_set_enabled(ACTION_SAVE_TO_FILE, false); + + let file = gio::File::for_uri(files.uris()[0].as_str()); + + if let Some(path) = file.path() { + let file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + let mut writer = BufWriter::new(file); + let mut perform = PlainTextPerform::default(); + + let timestamps = files.choices()[0].1 == "true"; + + utils::run_stream_with_finish_handler( + container.api().unwrap(), + move |container| { + container + .logs(&basic_opts_builder(false, timestamps).build()) + .boxed() + }, + clone!( + #[weak] + obj, + #[upgrade_or] + glib::ControlFlow::Break, + move |result: podman::Result| { + match result.map(Vec::from) { + Ok(line) => { + perform.decode(&line); + + let line = perform.move_out_buffer(); + if !line.is_empty() { + match writer + .write_all(line.as_bytes()) + .and_then(|_| writer.write_all(b"\n")) + { + Ok(_) => glib::ControlFlow::Continue, + Err(e) => { + log::warn!("Error on saving logs: {e}"); + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on saving logs"), + &e.to_string(), + ); + glib::ControlFlow::Break + } + } + } else { + glib::ControlFlow::Continue } } - } else { - glib::ControlFlow::Continue + Err(e) => { + log::warn!("Error on retrieving logs: {e}"); + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on retrieving logs"), + &e.to_string(), + ); + glib::ControlFlow::Break + } } } - Err(e) => { - log::warn!("Error on retrieving logs: {e}"); - utils::show_error_toast( + ), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled(ACTION_SAVE_TO_FILE, true); + utils::show_toast( obj.upcast_ref(), - &gettext("Error on retrieving logs"), - &e.to_string(), + gettext("Log has been saved"), ); - glib::ControlFlow::Break } - } - }), - clone!(@weak obj => move || { - obj.action_set_enabled(ACTION_SAVE_TO_FILE, true); - utils::show_toast(obj.upcast_ref(), gettext("Log has been saved")); - }), - ); + ), + ); + } } - }), + ), ) .await; } @@ -708,17 +772,33 @@ impl ContainerLogPage { pub(crate) fn start_or_resume_container(&self) { if let Some(container) = self.container() { if container.can_start() { - container.start(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast(obj.upcast_ref(), &gettext("Error starting container"), &e.to_string()); + container.start(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error starting container"), + &e.to_string(), + ); + } } - })); + )); } else if container.can_resume() { - container.resume(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast(obj.upcast_ref(), &gettext("Error resuming container"), &e.to_string()); + container.resume(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error resuming container"), + &e.to_string(), + ); + } } - })); + )); } } } diff --git a/src/view/container_menu_button.rs b/src/view/container_menu_button.rs index 870b0d29..6fd33348 100644 --- a/src/view/container_menu_button.rs +++ b/src/view/container_menu_button.rs @@ -109,7 +109,14 @@ mod imp { container_expr .chain_property::("status") - .watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + .watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); } fn dispose(&self) { diff --git a/src/view/container_properties_group.rs b/src/view/container_properties_group.rs index b88e4331..cf9461a9 100644 --- a/src/view/container_properties_group.rs +++ b/src/view/container_properties_group.rs @@ -141,107 +141,116 @@ mod imp { port_bindings_expr.watch( Some(obj), - clone!(@weak obj, @to-owned port_bindings_expr => move || { - let imp = obj.imp(); - - imp.port_bindings_label.set_label(""); - utils::ChildIter::from(imp.port_bindings_row.upcast_ref()) - .filter(|child| child.is::()) - .for_each(|child| imp.port_bindings_row.remove(&child)); - - let port_bindings: Option = - port_bindings_expr.evaluate_as(Some(&obj)); - - if let Some(port_bindings) = port_bindings { - let client = obj - .container() - .unwrap() - .container_list() - .unwrap() - .client() - .unwrap(); - let connection = client.connection(); - - imp.port_bindings_label.set_label(&port_bindings.len().to_string()); - - port_bindings - .iter() - .flat_map(|(container_port, hosts)| { - hosts - .as_deref() - .unwrap_or_default() - .iter() - .map(move |host| (container_port, host)) - }) - .map(|(container_port, host)| { - let host_ip = host.host_ip.as_deref().unwrap_or(""); - let host = format!( - "{}:{}", - if host_ip.is_empty() { - if connection.is_remote() { - let url = connection.url(); - let host_with_port = url.split_once("://").unwrap().1; - - Cow::Owned( - host_with_port - .split_once(':') - .map(|(host, _)| host) - .unwrap_or(host_with_port) - .to_string() - ) + clone!( + #[weak] + obj, + #[to_owned] + port_bindings_expr, + move || { + let imp = obj.imp(); + + imp.port_bindings_label.set_label(""); + utils::ChildIter::from(imp.port_bindings_row.upcast_ref()) + .filter(|child| child.is::()) + .for_each(|child| imp.port_bindings_row.remove(&child)); + + let port_bindings: Option = + port_bindings_expr.evaluate_as(Some(&obj)); + + if let Some(port_bindings) = port_bindings { + let client = obj + .container() + .unwrap() + .container_list() + .unwrap() + .client() + .unwrap(); + let connection = client.connection(); + + imp.port_bindings_label + .set_label(&port_bindings.len().to_string()); + + port_bindings + .iter() + .flat_map(|(container_port, hosts)| { + hosts + .as_deref() + .unwrap_or_default() + .iter() + .map(move |host| (container_port, host)) + }) + .map(|(container_port, host)| { + let host_ip = host.host_ip.as_deref().unwrap_or(""); + let host = format!( + "{}:{}", + if host_ip.is_empty() { + if connection.is_remote() { + let url = connection.url(); + let host_with_port = + url.split_once("://").unwrap().1; + + Cow::Owned( + host_with_port + .split_once(':') + .map(|(host, _)| host) + .unwrap_or(host_with_port) + .to_string(), + ) + } else { + Cow::Borrowed("127.0.0.1") + } } else { - Cow::Borrowed("127.0.0.1") - } - } else { - Cow::Borrowed(host_ip) - }, - host.host_port.as_deref().unwrap_or("0") - ); - - let box_ = gtk::CenterBox::builder() - .margin_top(12) - .margin_end(12) - .margin_bottom(12) - .margin_start(12) - .build(); - - box_.set_start_widget(Some( - >k::Label::builder() - .label(format!("{host}")) - .hexpand(true) - .selectable(true) - .use_markup(true) - .wrap(true) - .wrap_mode(pango::WrapMode::WordChar) - .xalign(0.0) - .build(), - )); - box_.set_center_widget(Some( - >k::Image::builder() - .icon_name("arrow1-right-symbolic") - .margin_start(15) + Cow::Borrowed(host_ip) + }, + host.host_port.as_deref().unwrap_or("0") + ); + + let box_ = gtk::CenterBox::builder() + .margin_top(12) .margin_end(12) + .margin_bottom(12) + .margin_start(12) + .build(); + + box_.set_start_widget(Some( + >k::Label::builder() + .label(format!("{host}")) + .hexpand(true) + .selectable(true) + .use_markup(true) + .wrap(true) + .wrap_mode(pango::WrapMode::WordChar) + .xalign(0.0) + .build(), + )); + box_.set_center_widget(Some( + >k::Image::builder() + .icon_name("arrow1-right-symbolic") + .margin_start(15) + .margin_end(12) + .build(), + )); + box_.set_end_widget(Some( + >k::Label::builder() + .label(container_port) + .css_classes(vec!["dim-label".to_string()]) + .hexpand(true) + .selectable(true) + .wrap(true) + .wrap_mode(pango::WrapMode::WordChar) + .xalign(1.0) + .build(), + )); + + gtk::ListBoxRow::builder() + .activatable(false) + .child(&box_) .build() - )); - box_.set_end_widget(Some(>k::Label::builder() - .label(container_port) - .css_classes(vec!["dim-label".to_string()]) - .hexpand(true) - .selectable(true) - .wrap(true) - .wrap_mode(pango::WrapMode::WordChar) - .xalign(1.0) - .build() - )); - - gtk::ListBoxRow::builder() - .activatable(false) - .child(&box_) - .build() - }) - .for_each(|row| imp.port_bindings_row.add_row(&row)); + }) + .for_each(|row| imp.port_bindings_row.add_row(&row)); + } } - }), + ), ); #[rustfmt::skip] diff --git a/src/view/container_renamer.rs b/src/view/container_renamer.rs index 7373ce0b..7cbeecca 100644 --- a/src/view/container_renamer.rs +++ b/src/view/container_renamer.rs @@ -80,12 +80,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().entry_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); } } } diff --git a/src/view/container_resources.rs b/src/view/container_resources.rs index 5c21005f..b37129b8 100644 --- a/src/view/container_resources.rs +++ b/src/view/container_resources.rs @@ -238,11 +238,19 @@ impl ContainerResources { percent_expr.watch( Some(self), - clone!(@weak self as obj, @weak progress_bar, @strong percent_expr => move || { - animation.set_value_from(progress_bar.fraction()); - animation.set_value_to(percent_expr.evaluate_as(Some(&obj)).unwrap_or(0.0)); - animation.play(); - }), + clone!( + #[weak(rename_to = obj)] + self, + #[weak] + progress_bar, + #[strong] + percent_expr, + move || { + animation.set_value_from(progress_bar.fraction()); + animation.set_value_to(percent_expr.evaluate_as(Some(&obj)).unwrap_or(0.0)); + animation.play(); + } + ), ); let classes = utils::css_classes(progress_bar.upcast_ref()); diff --git a/src/view/container_row.rs b/src/view/container_row.rs index 90420fea..0453e3b0 100644 --- a/src/view/container_row.rs +++ b/src/view/container_row.rs @@ -230,11 +230,19 @@ impl ContainerRow { perc_expr.watch( Some(self), - clone!(@weak self as obj, @weak progress_bar, @strong perc_expr => move || { - animation.set_value_from(progress_bar.percentage()); - animation.set_value_to(perc_expr.evaluate_as(Some(&obj)).unwrap_or(0.0)); - animation.play(); - }), + clone!( + #[weak(rename_to = obj)] + self, + #[weak] + progress_bar, + #[strong] + perc_expr, + move || { + animation.set_value_from(progress_bar.percentage()); + animation.set_value_to(perc_expr.evaluate_as(Some(&obj)).unwrap_or(0.0)); + animation.play(); + } + ), ); } diff --git a/src/view/container_terminal.rs b/src/view/container_terminal.rs index 884a71f6..7b411f57 100644 --- a/src/view/container_terminal.rs +++ b/src/view/container_terminal.rs @@ -184,30 +184,41 @@ mod imp { status_expr.watch( Some(obj), - clone!(@weak obj => move || { - obj.action_set_enabled( - ACTION_START_OR_RESUME, - match obj - .container() - .filter(|container| container.status() == model::ContainerStatus::Running) - { - Some(container) => { - obj.setup_tty_connection(&container); - false - } - None => true, - }, - ); - }), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTION_START_OR_RESUME, + match obj.container().filter(|container| { + container.status() == model::ContainerStatus::Running + }) { + Some(container) => { + obj.setup_tty_connection(&container); + false + } + None => true, + }, + ); + } + ), ); self.on_terminal_selection_changed(); - adw::StyleManager::default().connect_dark_notify(clone!(@weak obj => move |_| { - glib::idle_add_local_once(clone!(@weak obj => move || { - obj.imp().on_notify_dark(); - })); - })); + adw::StyleManager::default().connect_dark_notify(clone!( + #[weak] + obj, + move |_| { + glib::idle_add_local_once(clone!( + #[weak] + obj, + move || { + obj.imp().on_notify_dark(); + } + )); + } + )); self.on_notify_dark(); } @@ -383,11 +394,15 @@ impl ContainerTerminal { let (tx_output, mut rx_output) = tokio::sync::mpsc::channel::>(5); - glib::spawn_future_local(clone!(@weak self as obj => async move { - while let Some(buf) = rx_output.recv().await { - obj.imp().terminal.feed(&buf); + glib::spawn_future_local(clone!( + #[weak(rename_to = obj)] + self, + async move { + while let Some(buf) = rx_output.recv().await { + obj.imp().terminal.feed(&buf); + } } - })); + )); let (tx_input, mut rx_input) = tokio::sync::mpsc::unbounded_channel::(); imp.tx_input.replace(Some(tx_input.clone())); @@ -462,22 +477,26 @@ impl ContainerTerminal { Ok(()) }, - clone!(@weak self as obj => move |result: podman::Result<_>| { - if result.is_err() { - utils::show_error_toast( - gio::Application::default() - .unwrap() - .downcast::() - .unwrap() - .main_window() - .toast_overlay() - .upcast_ref(), - &gettext("Terminal error"), - &gettext("'/bin/sh' not found"), - ); + clone!( + #[weak(rename_to = obj)] + self, + move |result: podman::Result<_>| { + if result.is_err() { + utils::show_error_toast( + gio::Application::default() + .unwrap() + .downcast::() + .unwrap() + .main_window() + .toast_overlay() + .upcast_ref(), + &gettext("Terminal error"), + &gettext("'/bin/sh' not found"), + ); + } + obj.emit_by_name::<()>("terminated", &[]); } - obj.emit_by_name::<()>("terminated", &[]); - }), + ), ); } @@ -512,12 +531,13 @@ impl ContainerTerminal { if let Some(display) = gdk::Display::default() { display.clipboard().read_text_async( gio::Cancellable::NONE, - clone!(@weak self as obj => move |result| if let Some(text) = result - .ok() - .flatten() - { - obj.imp().terminal.paste_text(text.as_str()); - }), + clone!( + #[weak(rename_to = obj)] + self, + move |result| if let Some(text) = result.ok().flatten() { + obj.imp().terminal.paste_text(text.as_str()); + } + ), ); } } diff --git a/src/view/container_volume_row.rs b/src/view/container_volume_row.rs index 0538f97a..71258217 100644 --- a/src/view/container_volume_row.rs +++ b/src/view/container_volume_row.rs @@ -123,15 +123,27 @@ mod imp { container_list_expr.bind(&*self.containers_count_bar, "container-list", Some(obj)); let style_manager = adw::StyleManager::default(); - style_manager.connect_dark_notify(clone!(@weak obj => move |style_manager| { - obj.imp().set_path_label(style_manager); - })); - style_manager.connect_accent_color_notify(clone!(@weak obj => move |style_manager| { - obj.imp().set_path_label(style_manager); - })); - style_manager.connect_high_contrast_notify(clone!(@weak obj => move |style_manager| { - obj.imp().set_path_label(style_manager); - })); + style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.imp().set_path_label(style_manager); + } + )); + style_manager.connect_accent_color_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.imp().set_path_label(style_manager); + } + )); + style_manager.connect_high_contrast_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.imp().set_path_label(style_manager); + } + )); self.set_path_label(&style_manager); } } diff --git a/src/view/containers_group.rs b/src/view/containers_group.rs index a1b95ca8..8f996268 100644 --- a/src/view/containers_group.rs +++ b/src/view/containers_group.rs @@ -89,12 +89,20 @@ mod imp { } if let Some(list) = value { - list.connect_container_name_changed(clone!(@weak obj => move |_, _| { - glib::timeout_add_seconds_local_once( - 1, - clone!(@weak obj => move || obj.update_sorter()), - ); - })); + list.connect_container_name_changed(clone!( + #[weak] + obj, + move |_, _| { + glib::timeout_add_seconds_local_once( + 1, + clone!( + #[weak] + obj, + move || obj.update_sorter() + ), + ); + } + )); let model = gtk::SortListModel::new(Some(list.to_owned()), self.sorter.get().cloned()); diff --git a/src/view/containers_panel.rs b/src/view/containers_panel.rs index 04ec4cb3..e88fb880 100644 --- a/src/view/containers_panel.rs +++ b/src/view/containers_panel.rs @@ -261,16 +261,19 @@ mod imp { not_selection_mode_expr.bind(&self.search_bar.get(), "visible", Some(obj)); - let search_filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let search_filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = &*obj.imp().search_term.borrow(); if term.is_empty() { true } else { let container = item.downcast_ref::().unwrap(); - container - .name().to_lowercase().contains(term) + container.name().to_lowercase().contains(term) || container.id().contains(term) || container .image_name() @@ -278,14 +281,17 @@ mod imp { .unwrap_or(false) || container.image_id().contains(term) } - })); + } + )); let state_filter = gtk::AnyFilter::new(); - state_filter.append(gtk::CustomFilter::new( - clone!(@weak obj => @default-return false, move |_| { - !obj.show_only_running_containers() - }), - )); + state_filter.append(gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |_| !obj.show_only_running_containers() + ))); state_filter.append(gtk::BoolFilter::new(Some( model::Container::this_expression("status").chain_closure::(closure!( |_: model::Container, status: model::ContainerStatus| status @@ -377,29 +383,41 @@ mod imp { if let Some(container_list) = value { container_list.connect_notify_local( Some("num-selected"), - clone!(@weak obj => move |list, _| { - ACTIONS_SELECTION - .iter() - .for_each(|action_name| { + clone!( + #[weak] + obj, + move |list, _| { + ACTIONS_SELECTION.iter().for_each(|action_name| { obj.action_set_enabled(action_name, list.num_selected() > 0); - }); - }), + }); + } + ), ); container_list.connect_notify_local( Some("running"), - clone!(@weak obj => move |_, _| { - obj.imp().update_filter(gtk::FilterChange::Different) - }), + clone!( + #[weak] + obj, + move |_, _| obj.imp().update_filter(gtk::FilterChange::Different) + ), ); - container_list.connect_container_name_changed(clone!(@weak obj => move |_, _| { - obj.imp().update_filter(gtk::FilterChange::Different); - glib::timeout_add_seconds_local_once( - 1, - clone!(@weak obj => move || obj.imp().update_sorter()), - ); - })); + container_list.connect_container_name_changed(clone!( + #[weak] + obj, + move |_, _| { + obj.imp().update_filter(gtk::FilterChange::Different); + glib::timeout_add_seconds_local_once( + 1, + clone!( + #[weak] + obj, + move || obj.imp().update_sorter() + ), + ); + } + )); let model = gtk::SortListModel::new( Some(gtk::FilterListModel::new( @@ -419,15 +437,23 @@ mod imp { self.filter_stack .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); - model.connect_items_changed(clone!(@weak obj => move |model, _, removed, _| { - obj.imp() - .filter_stack - .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); + model.connect_items_changed(clone!( + #[weak] + obj, + move |model, _, removed, _| { + obj.imp() + .filter_stack + .set_visible_child_name(if model.n_items() > 0 { + "list" + } else { + "empty" + }); - if removed > 0 { - obj.deselect_hidden_containers(model.upcast_ref()); + if removed > 0 { + obj.deselect_hidden_containers(model.upcast_ref()); + } } - })); + )); } self.container_list.set(value); @@ -547,19 +573,23 @@ impl ContainersPanel { .for_each(|container| { container.stop( force, - clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &if force { - gettext("Error on killing container") - } else { - gettext("Error on stopping container") - }, - &e.to_string(), - ); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &if force { + gettext("Error on killing container") + } else { + gettext("Error on stopping container") + }, + &e.to_string(), + ); + } } - }), + ), ); }); list.set_selection_mode(false); @@ -575,15 +605,19 @@ impl ContainersPanel { .for_each(|container| { container.restart( false, - clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on restarting container"), - &e.to_string(), - ); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on restarting container"), + &e.to_string(), + ); + } } - }), + ), ); }); list.set_selection_mode(false); @@ -597,26 +631,34 @@ impl ContainersPanel { .map(|obj| obj.downcast_ref::().unwrap()) .for_each(|container| match container.status() { model::ContainerStatus::Paused => { - container.resume(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on resuming container"), - &e.to_string(), - ); + container.resume(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on resuming container"), + &e.to_string(), + ); + } } - })); + )); } other if other != model::ContainerStatus::Running => { - container.start(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on starting container"), - &e.to_string(), - ); + container.start(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on starting container"), + &e.to_string(), + ); + } } - })); + )); } _ => (), }); @@ -631,15 +673,19 @@ impl ContainersPanel { .map(|obj| obj.downcast_ref::().unwrap()) .filter(|container| matches!(container.status(), model::ContainerStatus::Running)) .for_each(|container| { - container.pause(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on pausing container"), - &e.to_string(), - ); + container.pause(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on pausing container"), + &e.to_string(), + ); + } } - })); + )); }); list.set_selection_mode(false); } @@ -672,27 +718,36 @@ impl ContainersPanel { dialog.connect_response( None, - clone!(@weak self as obj => move |_, response| if response == "delete" { - if let Some(list) = obj.container_list() { - list - .selected_items() - .iter() - .map(|obj| obj.downcast_ref::().unwrap()) - .for_each(|container| - { - container.delete(true, clone!(@weak obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on deleting container"), - &e.to_string(), + clone!( + #[weak(rename_to = obj)] + self, + move |_, response| if response == "delete" { + if let Some(list) = obj.container_list() { + list.selected_items() + .iter() + .map(|obj| obj.downcast_ref::().unwrap()) + .for_each(|container| { + container.delete( + true, + clone!( + #[weak] + obj, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on deleting container"), + &e.to_string(), + ); + } + } + ), ); - } - })); - }); - list.set_selection_mode(false); + }); + list.set_selection_mode(false); + } } - }), + ), ); dialog.present(Some(self)); diff --git a/src/view/image.rs b/src/view/image.rs index be70e1ad..63578a64 100644 --- a/src/view/image.rs +++ b/src/view/image.rs @@ -32,11 +32,17 @@ pub(crate) fn delete_image_show_confirmation(widget: >k::Widget, image: Option dialog.choose( widget, gio::Cancellable::NONE, - clone!(@weak widget, @weak image => move |response| { - if response == "delete" { - delete_image(&widget, &image); + clone!( + #[weak] + widget, + #[weak] + image, + move |response| { + if response == "delete" { + delete_image(&widget, &image); + } } - }), + ), ); } None => delete_image(widget, &image), @@ -45,16 +51,20 @@ pub(crate) fn delete_image_show_confirmation(widget: >k::Widget, image: Option } pub(crate) fn delete_image(widget: >k::Widget, image: &model::Image) { - image.delete(clone!(@weak widget => move |image, result| { - if let Err(e) = result { - utils::show_error_toast( - &widget, - // Translators: The "{}" is a placeholder for the image id. - &gettext!("Error on deleting image '{}'", image.id()), - &e.to_string(), - ); + image.delete(clone!( + #[weak] + widget, + move |image, result| { + if let Err(e) = result { + utils::show_error_toast( + &widget, + // Translators: The "{}" is a placeholder for the image id. + &gettext!("Error on deleting image '{}'", image.id()), + &e.to_string(), + ); + } } - })); + )); } pub(crate) fn create_container(widget: >k::Widget, image: Option) { diff --git a/src/view/image_build_page.rs b/src/view/image_build_page.rs index 7d4e2391..a6959531 100644 --- a/src/view/image_build_page.rs +++ b/src/view/image_build_page.rs @@ -134,12 +134,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().tag_entry_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.build_button)); } @@ -199,15 +203,19 @@ impl ImageBuildPage { utils::show_open_file_dialog( request, self.upcast_ref(), - clone!(@weak self as obj => move |files| { - let file = gio::File::for_uri(files.uris()[0].as_str()); - - if let Some(path) = file.path() { - obj.imp() - .context_dir_row - .set_subtitle(path.to_str().unwrap()); + clone!( + #[weak(rename_to = obj)] + self, + move |files| { + let file = gio::File::for_uri(files.uris()[0].as_str()); + + if let Some(path) = file.path() { + obj.imp() + .context_dir_row + .set_subtitle(path.to_str().unwrap()); + } } - }), + ), ) .await; } @@ -215,12 +223,16 @@ impl ImageBuildPage { fn add_label(&self) { let label = model::KeyVal::default(); - label.connect_remove_request(clone!(@weak self as obj => move |label| { - let labels = obj.imp().labels(); - if let Some(pos) = labels.find(label) { - labels.remove(pos); + label.connect_remove_request(clone!( + #[weak(rename_to = obj)] + self, + move |label| { + let labels = obj.imp().labels(); + if let Some(pos) = labels.find(label) { + labels.remove(pos); + } } - })); + )); self.imp().labels().append(&label); } diff --git a/src/view/image_details_page.rs b/src/view/image_details_page.rs index 17fa1d83..ebcdb55d 100644 --- a/src/view/image_details_page.rs +++ b/src/view/image_details_page.rs @@ -128,12 +128,18 @@ mod imp { .chain_property::("to-be-deleted") .watch( Some(obj), - clone!(@weak obj => move || { - obj.action_set_enabled( - ACTION_DELETE_IMAGE, - obj.image().map(|image| !image.to_be_deleted()).unwrap_or(false), - ); - }), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTION_DELETE_IMAGE, + obj.image() + .map(|image| !image.to_be_deleted()) + .unwrap_or(false), + ); + } + ), ); data_expr @@ -271,14 +277,29 @@ mod imp { if let Some(image) = value { self.window_title .set_subtitle(&utils::format_id(&image.id())); - image.inspect(clone!(@weak obj => move |result| if let Err(e) = result { - utils::show_error_toast(obj.upcast_ref(), &gettext("Error on loading image details"), &e.to_string()); - })); - - let handler_id = image.connect_deleted(clone!(@weak obj => move |image| { - utils::show_toast(obj.upcast_ref(), gettext!("Image '{}' has been deleted", image.id())); - utils::navigation_view(obj.upcast_ref()).pop(); - })); + image.inspect(clone!( + #[weak] + obj, + move |result| if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on loading image details"), + &e.to_string(), + ); + } + )); + + let handler_id = image.connect_deleted(clone!( + #[weak] + obj, + move |image| { + utils::show_toast( + obj.upcast_ref(), + gettext!("Image '{}' has been deleted", image.id()), + ); + utils::navigation_view(obj.upcast_ref()).pop(); + } + )); self.handler_id.replace(Some(handler_id)); let model = gtk::SortListModel::new( diff --git a/src/view/image_history_page.rs b/src/view/image_history_page.rs index c0256cf2..9beb2cbb 100644 --- a/src/view/image_history_page.rs +++ b/src/view/image_history_page.rs @@ -69,127 +69,133 @@ impl From<&model::Image> for ImageHistoryPage { let api = image.api().unwrap(); async move { api.history().await } }, - clone!(@weak obj => move |result| { - let imp = obj.imp(); - - match result { - Ok(entries) => { - let len = entries.len() as u32; - - imp.preferences_group.set_description(Some(&format!( - "{}, {}", - ngettext!("{} entry", "{} entries", len, len,), - gettext!( - "{} in total", - glib::format_size( - entries - .iter() - .filter_map(|item| item.size) - .map(|size| size as u64) - .sum() - ), - ) - ))); - - entries.into_iter().for_each(|entry| { - let row = adw::ExpanderRow::builder() - .title( - entry - .id - .as_deref() - .map(utils::format_id) - .unwrap_or_else(|| gettext("")), + clone!( + #[weak] + obj, + move |result| { + let imp = obj.imp(); + + match result { + Ok(entries) => { + let len = entries.len() as u32; + + imp.preferences_group.set_description(Some(&format!( + "{}, {}", + ngettext!("{} entry", "{} entries", len, len,), + gettext!( + "{} in total", + glib::format_size( + entries + .iter() + .filter_map(|item| item.size) + .map(|size| size as u64) + .sum() + ), ) - .subtitle( - entry - .created - .map(|created| { - glib::DateTime::from_unix_local(created) - .unwrap() - .format( - // Translators: This is a date time format (https://valadoc.org/glib-2.0/GLib.DateTime.format.html) - &gettext("%x %X"), - ) - .unwrap() - .to_string() - }) - .unwrap_or_else(|| gettext("Unknown Date")), - ) - .use_markup(false) - .build(); + ))); - row.add_action( - >k::Label::builder() - .label( + entries.into_iter().for_each(|entry| { + let row = adw::ExpanderRow::builder() + .title( entry - .size - .map(|size| String::from(glib::format_size(size as u64))) - .unwrap_or_else(|| gettext("Unknown size")), + .id + .as_deref() + .map(utils::format_id) + .unwrap_or_else(|| gettext("")), ) - .css_classes(vec!["dim-label".to_string()]) - .build(), - ); - - if let Some(created_by) = entry.created_by { - let box_ = gtk::Box::builder() - .orientation(gtk::Orientation::Vertical) - .spacing(9) - .margin_top(9) - .margin_end(12) - .margin_bottom(9) - .margin_start(12) + .subtitle( + entry + .created + .map(|created| { + glib::DateTime::from_unix_local(created) + .unwrap() + .format( + // Translators: This is a date time format (https://valadoc.org/glib-2.0/GLib.DateTime.format.html) + &gettext("%x %X"), + ) + .unwrap() + .to_string() + }) + .unwrap_or_else(|| gettext("Unknown Date")), + ) + .use_markup(false) .build(); - box_.append( - >k::Label::builder() - .label(gettext("Created by")) - .xalign(0.0) - .css_classes(vec!["heading".to_string()]) - .build(), - ); - box_.append( + + row.add_action( >k::Label::builder() - .label(created_by) - .single_line_mode(false) - .xalign(0.0) - .wrap(true) - .wrap_mode(pango::WrapMode::WordChar) - .selectable(true) + .label( + entry + .size + .map(|size| { + String::from(glib::format_size(size as u64)) + }) + .unwrap_or_else(|| gettext("Unknown size")), + ) + .css_classes(vec!["dim-label".to_string()]) .build(), ); - row.add_row( - &adw::PreferencesRow::builder() - .activatable(false) - .child(&box_) - .build(), - ); - } - if let Some(comment) = entry.comment { - if !comment.is_empty() { - row.add_row(&property_row(&gettext("Comment"), &comment)); + if let Some(created_by) = entry.created_by { + let box_ = gtk::Box::builder() + .orientation(gtk::Orientation::Vertical) + .spacing(9) + .margin_top(9) + .margin_end(12) + .margin_bottom(9) + .margin_start(12) + .build(); + box_.append( + >k::Label::builder() + .label(gettext("Created by")) + .xalign(0.0) + .css_classes(vec!["heading".to_string()]) + .build(), + ); + box_.append( + >k::Label::builder() + .label(created_by) + .single_line_mode(false) + .xalign(0.0) + .wrap(true) + .wrap_mode(pango::WrapMode::WordChar) + .selectable(true) + .build(), + ); + + row.add_row( + &adw::PreferencesRow::builder() + .activatable(false) + .child(&box_) + .build(), + ); + } + if let Some(comment) = entry.comment { + if !comment.is_empty() { + row.add_row(&property_row(&gettext("Comment"), &comment)); + } + } + if let Some(tags) = entry.tags { + row.add_row(&property_row(&gettext("Tags"), &tags.join(", "))); } - } - if let Some(tags) = entry.tags { - row.add_row(&property_row(&gettext("Tags"), &tags.join(", "))); - } - imp.preferences_group.add(&row); - }); + imp.preferences_group.add(&row); + }); - imp.stack.set_visible_child_name("loaded"); - } - Err(e) => { - log::error!("Error on retrieving history: {e}"); - - imp.spinner.set_visible(false); - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on retrieving history"), - &e.to_string() - ); + imp.stack.set_visible_child_name("loaded"); + } + Err(e) => { + log::error!("Error on retrieving history: {e}"); + + imp.spinner.set_visible(false); + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on retrieving history"), + &e.to_string(), + ); + } } } - }), + ), ); obj diff --git a/src/view/image_menu_button.rs b/src/view/image_menu_button.rs index ec92d89e..69f21d99 100644 --- a/src/view/image_menu_button.rs +++ b/src/view/image_menu_button.rs @@ -83,12 +83,18 @@ mod imp { to_be_deleted_expr.watch( Some(obj), - clone!(@weak obj => move || { - obj.action_set_enabled( - ACTION_DELETE_IMAGE, - obj.image().map(|image| !image.to_be_deleted()).unwrap_or(false) - ); - }), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTION_DELETE_IMAGE, + obj.image() + .map(|image| !image.to_be_deleted()) + .unwrap_or(false), + ); + } + ), ); } diff --git a/src/view/image_row.rs b/src/view/image_row.rs index dfeaa219..e76bf5ea 100644 --- a/src/view/image_row.rs +++ b/src/view/image_row.rs @@ -130,9 +130,13 @@ mod imp { obj.action_set_enabled("image.show-details", !image.to_be_deleted()); image.connect_notify_local( Some("to-be-deleted"), - clone!(@weak obj => move|image, _| { - obj.action_set_enabled("image.show-details", !image.to_be_deleted()); - }), + clone!( + #[weak] + obj, + move |image, _| { + obj.action_set_enabled("image.show-details", !image.to_be_deleted()); + } + ), ); } } diff --git a/src/view/image_search_page.rs b/src/view/image_search_page.rs index 841459d4..4f5d0444 100644 --- a/src/view/image_search_page.rs +++ b/src/view/image_search_page.rs @@ -190,41 +190,52 @@ mod imp { .await } }, - clone!(@weak obj => move |result| if let Ok(responses) = result { - match responses { - Ok(responses) => { - let imp = obj.imp(); - - if responses.is_empty() { - obj.action_set_enabled(ACTION_SELECT, false); - - imp.search_stack.set_visible_child_name("nothing"); - imp.no_results_status_page.set_title(&gettext!("No Results For {}", term)); - - } else { - obj.action_set_enabled(ACTION_SELECT, true); - - responses.into_iter().for_each(|response| { - imp.search_results() - .append(&model::ImageSearchResponse::from(response)); - }); - imp.selection.set_selected(0); - imp.search_stack.set_visible_child_name("results"); - - glib::idle_add_local_once(clone!(@weak obj => move || { - obj.imp().scrolled_window.emit_scroll_child(gtk::ScrollType::Start, false); - })); + clone!( + #[weak] + obj, + move |result| if let Ok(responses) = result { + match responses { + Ok(responses) => { + let imp = obj.imp(); + + if responses.is_empty() { + obj.action_set_enabled(ACTION_SELECT, false); + + imp.search_stack.set_visible_child_name("nothing"); + imp.no_results_status_page + .set_title(&gettext!("No Results For {}", term)); + } else { + obj.action_set_enabled(ACTION_SELECT, true); + + responses.into_iter().for_each(|response| { + imp.search_results() + .append(&model::ImageSearchResponse::from(response)); + }); + imp.selection.set_selected(0); + imp.search_stack.set_visible_child_name("results"); + + glib::idle_add_local_once(clone!( + #[weak] + obj, + move || { + obj.imp() + .scrolled_window + .emit_scroll_child(gtk::ScrollType::Start, false); + } + )); + } + } + Err(e) => { + log::error!("Failed to search for images: {}", e); + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Failed to search for images"), + &e.to_string(), + ); } - } - Err(e) => { - log::error!("Failed to search for images: {}", e); - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Failed to search for images"), - &e.to_string()); } } - }), + ), ); } @@ -320,10 +331,14 @@ impl ImageSearchPage { let page = view::RepoTagSelectionPage::new(&client, &image, &self.action_button_name()); - page.connect_image_selected(clone!(@weak self as obj => move |_, image| { - obj.imp().navigation_view.pop(); - obj.emit_by_name::<()>("image-selected", &[image]); - })); + page.connect_image_selected(clone!( + #[weak(rename_to = obj)] + self, + move |_, image| { + obj.imp().navigation_view.pop(); + obj.emit_by_name::<()>("image-selected", &[image]); + } + )); self.imp() .navigation_view diff --git a/src/view/image_selection_combo_row.rs b/src/view/image_selection_combo_row.rs index 6a3dbf22..03aee41d 100644 --- a/src/view/image_selection_combo_row.rs +++ b/src/view/image_selection_combo_row.rs @@ -132,11 +132,13 @@ impl ImageSelectionComboRow { pub(crate) fn select_image(&self) { if let Some(client) = self.client() { let image_selection_page = view::ImageSelectionPage::from(&client.image_list()); - image_selection_page.connect_image_selected( - clone!(@weak self as obj => move |_, image| { + image_selection_page.connect_image_selected(clone!( + #[weak(rename_to = obj)] + self, + move |_, image| { obj.set_image(Some(image)); - }), - ); + } + )); utils::navigation_view(self.upcast_ref()).push( &adw::NavigationPage::builder() .child(&image_selection_page) @@ -149,13 +151,17 @@ impl ImageSelectionComboRow { if let Some(client) = self.client() { let image_search_page = view::ImageSearchPage::new(&client, &gettext("Select"), false); - image_search_page.connect_image_selected(clone!(@weak self as obj => move |_, image| { - obj.activate_action("navigation.pop", None).unwrap(); - - obj.set_image(Option::::None); - obj.set_mode(ImageSelectionMode::Remote); - obj.set_subtitle(image); - })); + image_search_page.connect_image_selected(clone!( + #[weak(rename_to = obj)] + self, + move |_, image| { + obj.activate_action("navigation.pop", None).unwrap(); + + obj.set_image(Option::::None); + obj.set_mode(ImageSelectionMode::Remote); + obj.set_subtitle(image); + } + )); utils::navigation_view(self.upcast_ref()).push( &adw::NavigationPage::builder() .child(&image_search_page) diff --git a/src/view/image_selection_page.rs b/src/view/image_selection_page.rs index 74f45124..23e0b1fd 100644 --- a/src/view/image_selection_page.rs +++ b/src/view/image_selection_page.rs @@ -118,8 +118,12 @@ mod imp { self.filter_entry.set_key_capture_widget(Some(obj)); - let filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = obj.imp().filter_entry.text().to_lowercase(); let image = item.downcast_ref::().unwrap(); @@ -128,13 +132,16 @@ mod imp { .get(0) .map(|repo_tag| repo_tag.full().contains(&term)) .unwrap_or_else(|| image.id().contains(&term)) - })); + } + )); self.filter.set(filter.upcast()).unwrap(); self.list_view.remove_css_class("view"); - self.selection - .connect_items_changed(clone!(@weak obj => move |selection, _, _, _| { + self.selection.connect_items_changed(clone!( + #[weak] + obj, + move |selection, _, _, _| { obj.imp() .images_stack .set_visible_child_name(if selection.n_items() > 0 { @@ -142,7 +149,8 @@ mod imp { } else { "empty" }); - })); + } + )); } fn dispose(&self) { @@ -274,9 +282,13 @@ mod imp { let model = gtk::SingleSelection::new(Some(model)); - model.connect_selected_item_notify(clone!(@weak obj => move |selection| { - obj.action_set_enabled(ACTION_SELECT, selection.selected_item().is_some()); - })); + model.connect_selected_item_notify(clone!( + #[weak] + obj, + move |selection| { + obj.action_set_enabled(ACTION_SELECT, selection.selected_item().is_some()); + } + )); self.selection.set_model(Some(&model)); diff --git a/src/view/images_panel.rs b/src/view/images_panel.rs index 0ba764b6..0b9a740a 100644 --- a/src/view/images_panel.rs +++ b/src/view/images_panel.rs @@ -234,23 +234,34 @@ mod imp { not_selection_mode_expr.bind(&self.search_bar.get(), "visible", Some(obj)); - let search_filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let search_filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let image = item.downcast_ref::().unwrap(); let term = &*obj.imp().search_term.borrow(); image.id().contains(term) || image.repo_tags().contains(term) - })); + } + )); - let state_filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let state_filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { !obj.hide_intermediate_images() - || item - .downcast_ref::() - .unwrap() - .repo_tags() - .n_items() > 0 - })); + || item + .downcast_ref::() + .unwrap() + .repo_tags() + .n_items() + > 0 + } + )); let filter = gtk::EveryFilter::new(); filter.append(search_filter); @@ -326,11 +337,15 @@ mod imp { value.connect_notify_local( Some("intermediates"), - clone!(@weak obj => move |_ ,_| { - let imp = obj.imp(); - imp.update_filter(gtk::FilterChange::Different); - imp.update_sorter(); - }), + clone!( + #[weak] + obj, + move |_, _| { + let imp = obj.imp(); + imp.update_filter(gtk::FilterChange::Different); + imp.update_sorter(); + } + ), ); let model = gtk::SortListModel::new( @@ -347,22 +362,30 @@ mod imp { self.filter_stack .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); - model.connect_items_changed(clone!(@weak obj => move |model, _, removed, _| { - obj.imp() - .filter_stack - .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); - - if removed > 0 { - obj.deselect_hidden_images(model.upcast_ref()); + model.connect_items_changed(clone!( + #[weak] + obj, + move |model, _, removed, _| { + obj.imp() + .filter_stack + .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); + + if removed > 0 { + obj.deselect_hidden_images(model.upcast_ref()); + } } - })); + )); obj.action_set_enabled(ACTION_DELETE_SELECTION, false); value.connect_notify_local( Some("num-selected"), - clone!(@weak obj => move |list, _| { - obj.action_set_enabled(ACTION_DELETE_SELECTION, list.num_selected() > 0); - }), + clone!( + #[weak] + obj, + move |list, _| { + obj.action_set_enabled(ACTION_DELETE_SELECTION, list.num_selected() > 0); + } + ), ); self.image_list.set(Some(value)); @@ -495,27 +518,37 @@ impl ImagesPanel { dialog.connect_response( None, - clone!(@weak self as obj => move |_, response| if response == "delete" { - if let Some(list) = obj.image_list() { - list - .selected_items() - .iter().map(|obj| obj.downcast_ref::().unwrap()) - .for_each(|image| - { - image.delete(clone!(@weak obj => move |image, result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - // Translators: The first "{}" is a placeholder for the image id, the second is for an error message. - &gettext!("Error on deleting image '{}'", image.id()), - &e.to_string() - ); - } - })); - }); - list.set_selection_mode(false); + clone!( + #[weak(rename_to = obj)] + self, + move |_, response| if response == "delete" { + if let Some(list) = obj.image_list() { + list.selected_items() + .iter() + .map(|obj| obj.downcast_ref::().unwrap()) + .for_each(|image| { + image.delete(clone!( + #[weak] + obj, + move |image, result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + // Translators: The first "{}" is a placeholder for the image id, the second is for an error message. + &gettext!( + "Error on deleting image '{}'", + image.id() + ), + &e.to_string(), + ); + } + } + )); + }); + list.set_selection_mode(false); + } } - }), + ), ); dialog.present(Some(self)); diff --git a/src/view/info_panel.rs b/src/view/info_panel.rs index 2f0741d3..9dc55ca5 100644 --- a/src/view/info_panel.rs +++ b/src/view/info_panel.rs @@ -143,160 +143,196 @@ impl InfoPanel { let podman = client.podman(); async move { podman.info().await } }, - clone!(@weak self as obj => move |result| { - let imp = obj.imp(); - - obj.action_set_enabled(ACTION_REFRESH, true); - - match result { - Ok(info) => { - imp.stack.set_visible_child_name("content"); - - // Version - let version = info.version.as_ref(); - imp.version_api_version_row.set_value(&utils::format_option( - version.and_then(|version| version.api_version.as_ref()), - )); - imp.version_built_time_row - .set_value(&utils::format_option(version.and_then(|v| v.built.and_then(|t| - glib::DateTime::from_unix_local(t).ok().map(|d| { - d.format( - // Translators: This is a date time format (https://valadoc.org/glib-2.0/GLib.DateTime.format.html) - &gettext("%x %X"), - ) - .unwrap() - }) - )))); - imp.version_git_commit_row - .set_value(&utils::format_option(version.and_then(|v| v.git_commit.as_ref().and_then(|s| { - if s.is_empty() { - None - } else { - Some(s) - } - })))); - imp.version_go_version_row.set_value(&utils::format_option( - version.and_then(|v| v.go_version.as_ref()) - )); - imp.version_os_arch_row.set_value(&utils::format_option( - version.and_then(|v| v.os_arch.as_ref()) - )); - imp.version_version_row.set_value(&utils::format_option( - version.and_then(|v| v.version.as_ref()) - )); - - // Store - let store = info.store.as_ref(); - let container_store = store.and_then(|s| s.container_store.as_ref()); - imp.store_config_file_row.set_value(&utils::format_option( - store.and_then(|v| v.config_file.as_ref()), - )); - imp.store_container_store_label - .set_label(&utils::format_option( - container_store.and_then(|c| c.number.map(|n| { - // Translators: "{}" is a placeholder for a cardinal numbers. - ngettext!("{} Container", "{} Containers", n as u32, n) - }) - ))); - imp.store_container_store_paused_row - .set_value(&utils::format_option(container_store.and_then(|s| s - .paused - .as_ref() - .map(i64::to_string) - ))); - imp.store_container_store_running_row - .set_value(&utils::format_option(container_store.and_then(|s| s - .running - .as_ref() - .map(i64::to_string) - ))); - imp.store_container_store_stopped_row - .set_value(&utils::format_option(container_store.and_then(|s| s - .stopped - .as_ref() - .map(i64::to_string) - ))); - imp.store_graph_driver_name_row - .set_value(&utils::format_option( - store.and_then(|s| s.graph_driver_name.as_ref()) + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + let imp = obj.imp(); + + obj.action_set_enabled(ACTION_REFRESH, true); + + match result { + Ok(info) => { + imp.stack.set_visible_child_name("content"); + + // Version + let version = info.version.as_ref(); + imp.version_api_version_row.set_value(&utils::format_option( + version.and_then(|version| version.api_version.as_ref()), )); - - let graph_options = store.and_then(|s| s.graph_options.as_ref()); - imp.store_graph_options_label - .set_label(&utils::format_option( - graph_options.as_ref().map(|o| { - let len = o.as_object().unwrap().len(); - // Translators: "{}" is a placeholder for a cardinal number. - ngettext!("{} Option", "{} Options", len as u32, len) - }) + imp.version_built_time_row.set_value(&utils::format_option( + version.and_then(|v| { + v.built.and_then(|t| { + glib::DateTime::from_unix_local(t).ok().map(|d| { + d.format( + // Translators: This is a date time format (https://valadoc.org/glib-2.0/GLib.DateTime.format.html) + &gettext("%x %X"), + ) + .unwrap() + }) + }) + }), )); - - let mut store_graph_options_rows = - imp.store_graph_options_rows.borrow_mut(); - while let Some(row) = store_graph_options_rows.pop() { - imp.store_graph_options_row.remove(&row); - } - - if let Some(graph_options) = store.and_then(|s| s.graph_options.as_ref()) { - graph_options.as_object().unwrap().iter().for_each(|(k, v)| { - let row = widget::PropertyRow::default(); - row.set_key(k); - row.set_value(&v.to_string()); - - imp.store_graph_options_row.add_row(&row); - store_graph_options_rows.push(row); - }); - } - - imp.store_graph_root_row.set_value(&utils::format_option( - store.and_then(|s| s.graph_root.as_ref()) - )); - imp.store_graph_status_label - .set_label(&utils::format_option( - store.and_then(|s| s.graph_status.as_ref().map(|s| { - // Translators: "{}" is placeholders for a cardinal number. - ngettext!("{} State", "{} States", s.len() as u32, s.len()) - })) + imp.version_git_commit_row.set_value(&utils::format_option( + version.and_then(|v| { + v.git_commit.as_ref().and_then(|s| { + if s.is_empty() { + None + } else { + Some(s) + } + }) + }), + )); + imp.version_go_version_row.set_value(&utils::format_option( + version.and_then(|v| v.go_version.as_ref()), + )); + imp.version_os_arch_row.set_value(&utils::format_option( + version.and_then(|v| v.os_arch.as_ref()), + )); + imp.version_version_row.set_value(&utils::format_option( + version.and_then(|v| v.version.as_ref()), )); - let mut store_graph_status_rows = imp.store_graph_status_rows.borrow_mut(); - while let Some(row) = store_graph_status_rows.pop() { - imp.store_graph_status_row.remove(&row); + // Store + let store = info.store.as_ref(); + let container_store = + store.and_then(|s| s.container_store.as_ref()); + imp.store_config_file_row.set_value(&utils::format_option( + store.and_then(|v| v.config_file.as_ref()), + )); + imp.store_container_store_label + .set_label(&utils::format_option(container_store.and_then( + |c| { + c.number.map(|n| { + // Translators: "{}" is a placeholder for a cardinal numbers. + ngettext!( + "{} Container", + "{} Containers", + n as u32, + n + ) + }) + }, + ))); + imp.store_container_store_paused_row.set_value( + &utils::format_option( + container_store + .and_then(|s| s.paused.as_ref().map(i64::to_string)), + ), + ); + imp.store_container_store_running_row.set_value( + &utils::format_option( + container_store + .and_then(|s| s.running.as_ref().map(i64::to_string)), + ), + ); + imp.store_container_store_stopped_row.set_value( + &utils::format_option( + container_store + .and_then(|s| s.stopped.as_ref().map(i64::to_string)), + ), + ); + imp.store_graph_driver_name_row + .set_value(&utils::format_option( + store.and_then(|s| s.graph_driver_name.as_ref()), + )); + + let graph_options = store.and_then(|s| s.graph_options.as_ref()); + imp.store_graph_options_label + .set_label(&utils::format_option(graph_options.as_ref().map( + |o| { + let len = o.as_object().unwrap().len(); + // Translators: "{}" is a placeholder for a cardinal number. + ngettext!("{} Option", "{} Options", len as u32, len) + }, + ))); + + let mut store_graph_options_rows = + imp.store_graph_options_rows.borrow_mut(); + while let Some(row) = store_graph_options_rows.pop() { + imp.store_graph_options_row.remove(&row); + } + + if let Some(graph_options) = + store.and_then(|s| s.graph_options.as_ref()) + { + graph_options + .as_object() + .unwrap() + .iter() + .for_each(|(k, v)| { + let row = widget::PropertyRow::default(); + row.set_key(k); + row.set_value(&v.to_string()); + + imp.store_graph_options_row.add_row(&row); + store_graph_options_rows.push(row); + }); + } + + imp.store_graph_root_row.set_value(&utils::format_option( + store.and_then(|s| s.graph_root.as_ref()), + )); + imp.store_graph_status_label + .set_label(&utils::format_option(store.and_then(|s| { + s.graph_status.as_ref().map(|s| { + // Translators: "{}" is placeholders for a cardinal number. + ngettext!( + "{} State", + "{} States", + s.len() as u32, + s.len() + ) + }) + }))); + + let mut store_graph_status_rows = + imp.store_graph_status_rows.borrow_mut(); + while let Some(row) = store_graph_status_rows.pop() { + imp.store_graph_status_row.remove(&row); + } + + if let Some(graph_status) = + store.and_then(|s| s.graph_status.as_ref()) + { + graph_status.iter().for_each(|(k, v)| { + let row = widget::PropertyRow::default(); + row.set_key(k); + row.set_value(v); + + imp.store_graph_status_row.add_row(&row); + store_graph_status_rows.push(row); + }); + } + imp.store_image_store_row.set_value(&utils::format_option( + store.and_then(|s| s.image_store.as_ref()).and_then(|s| { + s.number.map(|n| { + // Translators: "{}" is placeholders for a cardinal number. + ngettext!("{} Image", "{} Images", n as u32, n) + }) + }), + )); + imp.store_run_root_row.set_value(&utils::format_option( + store.and_then(|s| s.run_root.as_ref()), + )); + imp.store_volume_path_row.set_value(&utils::format_option( + store.and_then(|s| s.volume_path.as_ref()), + )); } - - if let Some(graph_status) = store.and_then(|s| s.graph_status.as_ref()) - { - graph_status.iter().for_each(|(k, v)| { - let row = widget::PropertyRow::default(); - row.set_key(k); - row.set_value(v); - - imp.store_graph_status_row.add_row(&row); - store_graph_status_rows.push(row); - }); + Err(e) => { + imp.stack.set_visible_child_name("error"); + + log::error!("Failed to retrieve host info: {e}"); + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on retrieving info"), + &e.to_string(), + ); } - imp.store_image_store_row - .set_value(&utils::format_option( - store.and_then(|s| s.image_store.as_ref()).and_then(|s| s.number.map(|n| { - // Translators: "{}" is placeholders for a cardinal number. - ngettext!("{} Image", "{} Images", n as u32, n) - }) - ))); - imp.store_run_root_row.set_value(&utils::format_option( - store.and_then(|s| s.run_root.as_ref()) - )); - imp.store_volume_path_row.set_value(&utils::format_option( - store.and_then(|s| s.volume_path.as_ref()) - )); - } - Err(e) => { - imp.stack.set_visible_child_name("error"); - - log::error!("Failed to retrieve host info: {e}"); - utils::show_error_toast(obj.upcast_ref(), &gettext("Error on retrieving info"), &e.to_string()); } } - }), + ), ); } } diff --git a/src/view/mount_row.rs b/src/view/mount_row.rs index f2d9bfce..e7506650 100644 --- a/src/view/mount_row.rs +++ b/src/view/mount_row.rs @@ -321,14 +321,16 @@ impl MountRow { pub(crate) fn select_volume(&self) { if let Some(client) = self.mount().and_then(|mount| mount.client()) { let volume_selection_page = view::VolumeSelectionPage::from(&client.volume_list()); - volume_selection_page.connect_volume_selected( - clone!(@weak self as obj => move |_, volume| { + volume_selection_page.connect_volume_selected(clone!( + #[weak(rename_to = obj)] + self, + move |_, volume| { if let Some(mount) = obj.mount() { mount.set_volume(Some(volume)); obj.action_set_enabled(ACTION_CLEAR_VOLUME, true); } - }), - ); + } + )); utils::navigation_view(self.upcast_ref()).push( &adw::NavigationPage::builder() .child(&volume_selection_page) diff --git a/src/view/pod.rs b/src/view/pod.rs index 94682e70..236d116e 100644 --- a/src/view/pod.rs +++ b/src/view/pod.rs @@ -27,7 +27,7 @@ macro_rules! pod_action { if let Some(pod) = ::property::>(widget, "pod") { pod.$action( $($param,)* - glib::clone!(@weak widget => move |result| if let Err(e) = result { + glib::clone!(#[weak] widget, move |result| if let Err(e) = result { crate::utils::show_error_toast(&widget, &$error, &e.to_string()); }), ); @@ -70,11 +70,15 @@ pub(crate) fn show_delete_confirmation_dialog(widget: >k::Widget) { dialog.choose( widget, gio::Cancellable::NONE, - clone!(@weak widget, @weak pod => move |response| { - if response == "delete" { - delete(&widget); + clone!( + #[weak] + widget, + move |response| { + if response == "delete" { + delete(&widget); + } } - }), + ), ); } None => delete(widget), diff --git a/src/view/pod_creation_page.rs b/src/view/pod_creation_page.rs index 052d4546..89661c36 100644 --- a/src/view/pod_creation_page.rs +++ b/src/view/pod_creation_page.rs @@ -227,12 +227,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().name_entry_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.create_button)); } @@ -559,12 +563,15 @@ impl PodCreationPage { image.disconnect(handler); } } - let handler = - image.connect_data_notify(clone!(@weak self as obj => move |image| { + let handler = image.connect_data_notify(clone!( + #[weak(rename_to = obj)] + self, + move |image| { obj.imp().infra_command_entry_row.set_text( - &image.data().unwrap().config().cmd().unwrap_or_default() + &image.data().unwrap().config().cmd().unwrap_or_default(), ); - })); + } + )); let image_weak = glib::WeakRef::new(); image_weak.set(Some(&image)); imp.command_row_handler.replace(Some((handler, image_weak))); @@ -605,11 +612,15 @@ fn bind_model( fn add_key_val(model: &gio::ListStore) { let entry = model::KeyVal::default(); - entry.connect_remove_request(clone!(@weak model => move |entry| { - if let Some(pos) = model.find(entry) { - model.remove(pos); + entry.connect_remove_request(clone!( + #[weak] + model, + move |entry| { + if let Some(pos) = model.find(entry) { + model.remove(pos); + } } - })); + )); model.append(&entry); } @@ -617,11 +628,15 @@ fn add_key_val(model: &gio::ListStore) { fn add_value(model: &gio::ListStore) { let value = model::Value::default(); - value.connect_remove_request(clone!(@weak model => move |value| { - if let Some(pos) = model.find(value) { - model.remove(pos); + value.connect_remove_request(clone!( + #[weak] + model, + move |value| { + if let Some(pos) = model.find(value) { + model.remove(pos); + } } - })); + )); model.append(&value); } @@ -629,11 +644,15 @@ fn add_value(model: &gio::ListStore) { fn add_port_mapping(model: &gio::ListStore) -> model::PortMapping { let port_mapping = model::PortMapping::default(); - port_mapping.connect_remove_request(clone!(@weak model => move |port_mapping| { - if let Some(pos) = model.find(port_mapping) { - model.remove(pos); + port_mapping.connect_remove_request(clone!( + #[weak] + model, + move |port_mapping| { + if let Some(pos) = model.find(port_mapping) { + model.remove(pos); + } } - })); + )); model.append(&port_mapping); @@ -643,11 +662,15 @@ fn add_port_mapping(model: &gio::ListStore) -> model::PortMapping { fn add_device(model: &gio::ListStore) { let device = model::Device::default(); - device.connect_remove_request(clone!(@weak model => move |device| { - if let Some(pos) = model.find(device) { - model.remove(pos); + device.connect_remove_request(clone!( + #[weak] + model, + move |device| { + if let Some(pos) = model.find(device) { + model.remove(pos); + } } - })); + )); model.append(&device); } diff --git a/src/view/pod_details_page.rs b/src/view/pod_details_page.rs index 70c2747d..9f8eddfa 100644 --- a/src/view/pod_details_page.rs +++ b/src/view/pod_details_page.rs @@ -198,10 +198,24 @@ mod imp { )) .bind(&*self.hostname_row, "visible", Some(obj)); - status_expr.watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + status_expr.watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); pod_expr .chain_property::("action-ongoing") - .watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + .watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); } fn dispose(&self) { @@ -225,14 +239,29 @@ mod imp { if let Some(pod) = value { self.window_title.set_subtitle(&pod.name()); - pod.inspect(clone!(@weak obj => move |result| if let Err(e) = result { - utils::show_error_toast(obj.upcast_ref(), &gettext("Error on loading pod data"), &e.to_string()); - })); - - let handler_id = pod.connect_deleted(clone!(@weak obj => move |pod| { - utils::show_toast(obj.upcast_ref(), gettext!("Pod '{}' has been deleted", pod.name())); - utils::navigation_view(obj.upcast_ref()).pop(); - })); + pod.inspect(clone!( + #[weak] + obj, + move |result| if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on loading pod data"), + &e.to_string(), + ); + } + )); + + let handler_id = pod.connect_deleted(clone!( + #[weak] + obj, + move |pod| { + utils::show_toast( + obj.upcast_ref(), + gettext!("Pod '{}' has been deleted", pod.name()), + ); + utils::navigation_view(obj.upcast_ref()).pop(); + } + )); self.handler_id.replace(Some(handler_id)); } diff --git a/src/view/pod_menu_button.rs b/src/view/pod_menu_button.rs index 3d0ddf21..cc8f45d4 100644 --- a/src/view/pod_menu_button.rs +++ b/src/view/pod_menu_button.rs @@ -107,9 +107,14 @@ mod imp { })) .bind(&*self.menu_button, "sensitive", Some(obj)); - pod_expr - .chain_property::("status") - .watch(Some(obj), clone!(@weak obj => move || obj.update_actions())); + pod_expr.chain_property::("status").watch( + Some(obj), + clone!( + #[weak] + obj, + move || obj.update_actions() + ), + ); } fn dispose(&self) { diff --git a/src/view/pod_row.rs b/src/view/pod_row.rs index 501a79b8..053cbc19 100644 --- a/src/view/pod_row.rs +++ b/src/view/pod_row.rs @@ -174,14 +174,18 @@ mod imp { Some(container) => self.setup_ports(&container), None => { let handler_id_ref = Rc::new(RefCell::new(None)); - let handler_id = pod.connect_infra_container_notify( - clone!(@weak obj, @strong handler_id_ref => move |pod| { + let handler_id = pod.connect_infra_container_notify(clone!( + #[weak] + obj, + #[strong] + handler_id_ref, + move |pod| { if let Some(container) = pod.infra_container() { pod.disconnect(handler_id_ref.take().unwrap()); obj.imp().setup_ports(&container); } - }), - ); + } + )); handler_id_ref.set(Some(handler_id)); } } @@ -198,45 +202,46 @@ mod imp { self.ports_flow_box.bind_model( Some(&container.ports()), - clone!(@weak obj => @default-panic, move |item| { - let port_mapping = - item.downcast_ref::().unwrap(); - - let label = gtk::Label::builder() - .css_classes([ - "status-badge-small", - "numeric", - ]) - .halign(gtk::Align::Center) - .label(format!( - "{}/{}", - port_mapping.host_port(), - port_mapping.protocol() - )) - .build(); - - let css_classes = utils::css_classes(label.upcast_ref()); - super::PodRow::this_expression("pod") - .chain_property::("status") - .chain_closure::>(closure!( - |_: super::PodRow, status: model::PodStatus| { - css_classes - .iter() - .cloned() - .chain(Some(String::from( - super::super::pod_status_css_class(status) - ))) - .collect::>() - } - )) - .bind(&label, "css-classes", Some(&obj)); - - gtk::FlowBoxChild::builder() - .halign(gtk::Align::Start) - .child(&label) - .build() - .upcast() - }), + clone!( + #[weak] + obj, + #[upgrade_or_panic] + move |item| { + let port_mapping = item.downcast_ref::().unwrap(); + + let label = gtk::Label::builder() + .css_classes(["status-badge-small", "numeric"]) + .halign(gtk::Align::Center) + .label(format!( + "{}/{}", + port_mapping.host_port(), + port_mapping.protocol() + )) + .build(); + + let css_classes = utils::css_classes(label.upcast_ref()); + super::PodRow::this_expression("pod") + .chain_property::("status") + .chain_closure::>(closure!( + |_: super::PodRow, status: model::PodStatus| { + css_classes + .iter() + .cloned() + .chain(Some(String::from( + super::super::pod_status_css_class(status), + ))) + .collect::>() + } + )) + .bind(&label, "css-classes", Some(&obj)); + + gtk::FlowBoxChild::builder() + .halign(gtk::Align::Start) + .child(&label) + .build() + .upcast() + } + ), ); } } diff --git a/src/view/pod_selection_page.rs b/src/view/pod_selection_page.rs index 63e968e3..39469d97 100644 --- a/src/view/pod_selection_page.rs +++ b/src/view/pod_selection_page.rs @@ -123,19 +123,26 @@ mod imp { self.filter_entry.set_key_capture_widget(Some(obj)); - let filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = obj.imp().filter_entry.text().to_lowercase(); let pod = item.downcast_ref::().unwrap(); pod.name().to_lowercase().contains(&term) - })); + } + )); self.filter.set(filter.upcast()).unwrap(); self.list_view.remove_css_class("view"); - self.selection - .connect_items_changed(clone!(@weak obj => move |selection, _, _, _| { + self.selection.connect_items_changed(clone!( + #[weak] + obj, + move |selection, _, _, _| { obj.imp() .pods_stack .set_visible_child_name(if selection.n_items() > 0 { @@ -143,7 +150,8 @@ mod imp { } else { "empty" }); - })); + } + )); } fn dispose(&self) { @@ -251,9 +259,13 @@ mod imp { let model = gtk::SingleSelection::new(Some(model)); - model.connect_selected_item_notify(clone!(@weak obj => move |selection| { - obj.action_set_enabled(ACTION_SELECT, selection.selected_item().is_some()); - })); + model.connect_selected_item_notify(clone!( + #[weak] + obj, + move |selection| { + obj.action_set_enabled(ACTION_SELECT, selection.selected_item().is_some()); + } + )); self.selection.set_model(Some(&model)); diff --git a/src/view/pods_panel.rs b/src/view/pods_panel.rs index b1b2d6ca..7cfdb4df 100644 --- a/src/view/pods_panel.rs +++ b/src/view/pods_panel.rs @@ -253,24 +253,31 @@ mod imp { ))) .bind(&self.selected_pods_button.get(), "label", Some(obj)); - let search_filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let search_filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = &*obj.imp().search_term.borrow(); item.downcast_ref::() .unwrap() .name() .to_lowercase() .contains(term) - })); + } + )); not_selection_mode_expr.bind(&self.search_bar.get(), "visible", Some(obj)); let state_filter = gtk::AnyFilter::new(); - state_filter.append(gtk::CustomFilter::new( - clone!(@weak obj => @default-return false, move |_| { - !obj.show_only_running_pods() - }), - )); + state_filter.append(gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |_| !obj.show_only_running_pods() + ))); state_filter.append(gtk::BoolFilter::new(Some( model::Pod::this_expression("status").chain_closure::(closure!( |_: model::Pod, status: model::PodStatus| status == model::PodStatus::Running @@ -336,9 +343,13 @@ mod imp { value.connect_notify_local( Some("running"), - clone!(@weak obj => move |_ ,_| { - obj.imp().update_filter(gtk::FilterChange::Different); - }), + clone!( + #[weak] + obj, + move |_, _| { + obj.imp().update_filter(gtk::FilterChange::Different); + } + ), ); let model = gtk::SortListModel::new( @@ -355,28 +366,34 @@ mod imp { self.filter_stack .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); - model.connect_items_changed(clone!(@weak obj => move |model, _, removed, _| { - obj.imp() - .filter_stack - .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); - - if removed > 0 { - obj.deselect_hidden_pods(model.upcast_ref()); + model.connect_items_changed(clone!( + #[weak] + obj, + move |model, _, removed, _| { + obj.imp() + .filter_stack + .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); + + if removed > 0 { + obj.deselect_hidden_pods(model.upcast_ref()); + } } - })); + )); ACTIONS_SELECTION .iter() .for_each(|action_name| obj.action_set_enabled(action_name, false)); value.connect_notify_local( Some("num-selected"), - clone!(@weak obj => move |list, _| { - ACTIONS_SELECTION - .iter() - .for_each(|action_name| { + clone!( + #[weak] + obj, + move |list, _| { + ACTIONS_SELECTION.iter().for_each(|action_name| { obj.action_set_enabled(action_name, list.num_selected() > 0); - }); - }), + }); + } + ), ); self.pod_list.set(Some(value)); @@ -471,26 +488,34 @@ impl PodsPanel { .map(|obj| obj.downcast_ref::().unwrap()) .for_each(|pod| match pod.status() { model::PodStatus::Paused => { - pod.resume(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on resuming pod"), - &e.to_string(), - ); + pod.resume(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on resuming pod"), + &e.to_string(), + ); + } } - })); + )); } other if other != model::PodStatus::Running => { - pod.start(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on starting pod"), - &e.to_string(), - ); + pod.start(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on starting pod"), + &e.to_string(), + ); + } } - })); + )); } _ => (), }); @@ -507,19 +532,23 @@ impl PodsPanel { .for_each(|pod| { pod.stop( force, - clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &if force { - gettext("Error on killing pod") - } else { - gettext("Error on stopping pod") - }, - &e.to_string(), - ); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &if force { + gettext("Error on killing pod") + } else { + gettext("Error on stopping pod") + }, + &e.to_string(), + ); + } } - }), + ), ); }); list.set_selection_mode(false); @@ -533,15 +562,19 @@ impl PodsPanel { .map(|obj| obj.downcast_ref::().unwrap()) .filter(|pod| matches!(pod.status(), model::PodStatus::Running)) .for_each(|pod| { - pod.pause(clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on stopping pod"), - &e.to_string(), - ); + pod.pause(clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on stopping pod"), + &e.to_string(), + ); + } } - })); + )); }); list.set_selection_mode(false); } @@ -556,15 +589,19 @@ impl PodsPanel { .for_each(|pod| { pod.restart( false, - clone!(@weak self as obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on restarting pod"), - &e.to_string(), - ); + clone!( + #[weak(rename_to = obj)] + self, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on restarting pod"), + &e.to_string(), + ); + } } - }), + ), ); }); list.set_selection_mode(false); @@ -591,26 +628,36 @@ impl PodsPanel { dialog.connect_response( None, - clone!(@weak self as obj => move |_, response| if response == "delete" { - if let Some(list) = obj.pod_list() { - list - .selected_items() - .iter().map(|obj| obj.downcast_ref::().unwrap()) - .for_each(|pod| - { - pod.delete(true, clone!(@weak obj => move |result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on deleting pod"), - &e.to_string(), + clone!( + #[weak(rename_to = obj)] + self, + move |_, response| if response == "delete" { + if let Some(list) = obj.pod_list() { + list.selected_items() + .iter() + .map(|obj| obj.downcast_ref::().unwrap()) + .for_each(|pod| { + pod.delete( + true, + clone!( + #[weak] + obj, + move |result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on deleting pod"), + &e.to_string(), + ); + } + } + ), ); - } - })); - }); - list.set_selection_mode(false); + }); + list.set_selection_mode(false); + } } - }), + ), ); dialog.present(Some(self)); diff --git a/src/view/repo_tag_add_dialog.rs b/src/view/repo_tag_add_dialog.rs index 8027c5f8..d6bafc02 100644 --- a/src/view/repo_tag_add_dialog.rs +++ b/src/view/repo_tag_add_dialog.rs @@ -88,10 +88,14 @@ mod imp { ) .await }, - clone!(@weak obj => move |result| match result { - Ok(_) => obj.force_close(), - Err(e) => obj.set_error(&e.to_string()), - }), + clone!( + #[weak] + obj, + move |result| match result { + Ok(_) => obj.force_close(), + Err(e) => obj.set_error(&e.to_string()), + } + ), ); } None => { diff --git a/src/view/repo_tag_push_page.rs b/src/view/repo_tag_push_page.rs index 97cfd6b2..46f05e71 100644 --- a/src/view/repo_tag_push_page.rs +++ b/src/view/repo_tag_push_page.rs @@ -97,15 +97,18 @@ mod imp { let obj = &*self.obj(); - self.password_toggle_button - .connect_active_notify(clone!(@weak obj => move |button| { + self.password_toggle_button.connect_active_notify(clone!( + #[weak] + obj, + move |button| { let is_active = button.is_active(); - let imp = obj. imp(); + let imp = obj.imp(); imp.username_entry_row.set_visible(is_active); imp.password_entry_row.set_visible(is_active); imp.token_entry_row.set_visible(!is_active); - })); + } + )); if let Some(repo_tag) = obj.repo_tag() { self.window_title.set_subtitle(&repo_tag.full()); @@ -139,40 +142,47 @@ mod imp { Err(e) => Some(Err(e)), } }, - clone!(@weak obj => move |maybe| { - let imp = obj.imp(); - - imp.login_group.set_sensitive(true); - - if let Some(result) = maybe { - match result { - Ok(auth) => { - imp.login_switch.set_active(true); - imp.save_credentials_switch_row.set_active(true); - - match auth { - RegistryAuth::Password { username, password } => { - imp.password_toggle_button.set_active(true); - imp.username_entry_row.set_text(&username); - imp.password_entry_row.set_text(&password); - } - RegistryAuth::Token(token) => { - imp.token_toggle_button.set_active(true); - imp.token_entry_row.set_text(&token); + clone!( + #[weak] + obj, + move |maybe| { + let imp = obj.imp(); + + imp.login_group.set_sensitive(true); + + if let Some(result) = maybe { + match result { + Ok(auth) => { + imp.login_switch.set_active(true); + imp.save_credentials_switch_row.set_active(true); + + match auth { + RegistryAuth::Password { + username, + password, + } => { + imp.password_toggle_button.set_active(true); + imp.username_entry_row.set_text(&username); + imp.password_entry_row.set_text(&password); + } + RegistryAuth::Token(token) => { + imp.token_toggle_button.set_active(true); + imp.token_entry_row.set_text(&token); + } } } - } - Err(e) => { - log::error!("Error on accessing keyring: {e}"); - utils::show_error_toast( - imp.toast_overlay.upcast_ref(), - &gettext("Error on accessing keyring"), - &e.to_string() - ); + Err(e) => { + log::error!("Error on accessing keyring: {e}"); + utils::show_error_toast( + imp.toast_overlay.upcast_ref(), + &gettext("Error on accessing keyring"), + &e.to_string(), + ); + } } } } - }), + ), ); } None => self.login_group.set_sensitive(true), diff --git a/src/view/repo_tag_row.rs b/src/view/repo_tag_row.rs index bda0ea03..713bde0d 100644 --- a/src/view/repo_tag_row.rs +++ b/src/view/repo_tag_row.rs @@ -72,22 +72,40 @@ mod imp { let obj = &*self.obj(); let style_manager = adw::StyleManager::default(); - style_manager.connect_dark_notify(clone!(@weak obj => move |style_manager| { - obj.set_label(style_manager); - })); - style_manager.connect_high_contrast_notify(clone!(@weak obj => move |style_manager| { - obj.set_label(style_manager); - })); - style_manager.connect_accent_color_notify(clone!(@weak obj => move |style_manager| { - obj.set_label(style_manager); - })); + style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.set_label(style_manager); + } + )); + style_manager.connect_high_contrast_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.set_label(style_manager); + } + )); + style_manager.connect_accent_color_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.set_label(style_manager); + } + )); if let Some(repo_tag) = obj.repo_tag() { repo_tag.connect_notify_local( Some("to-be-deleted"), - clone!(@weak obj, @weak style_manager => move |_, _| { - obj.set_label(&style_manager); - }), + clone!( + #[weak] + obj, + #[weak] + style_manager, + move |_, _| { + obj.set_label(&style_manager); + } + ), ); } @@ -202,17 +220,21 @@ impl RepoTagRow { ) .await }, - clone!(@weak self as obj => move |result| if let Err(e) = result { - if let Some(repo_tag) = obj.repo_tag() { - repo_tag.set_to_be_deleted(false); + clone!( + #[weak(rename_to = obj)] + self, + move |result| if let Err(e) = result { + if let Some(repo_tag) = obj.repo_tag() { + repo_tag.set_to_be_deleted(false); + } + log::warn!("Error on untagging image: {e}"); + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error on untagging image"), + &e.to_string(), + ); } - log::warn!("Error on untagging image: {e}"); - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error on untagging image"), - &e.to_string() - ); - }), + ), ); } } diff --git a/src/view/repo_tag_selection_page.rs b/src/view/repo_tag_selection_page.rs index f4aaf934..e940eded 100644 --- a/src/view/repo_tag_selection_page.rs +++ b/src/view/repo_tag_selection_page.rs @@ -132,42 +132,56 @@ mod imp { .await } }, - clone!(@weak obj => move |result| if let Ok(responses) = result { - match responses { - Ok(responses) => { - let imp = obj.imp(); - - obj.action_set_enabled(ACTION_SELECT, true); - - responses.into_iter().for_each(|response| { - obj - .imp() - .search_results() - .append(&model::ImageSearchResponse::from(response)); - }); - - imp.selection.set_selected(0); - imp.search_stack.set_visible_child_name("results"); - - glib::idle_add_local_once(clone!(@weak obj => move || { - obj.imp().scrolled_window.emit_scroll_child(gtk::ScrollType::Start, false); - })); - } - Err(e) => { - log::error!("Failed to search for images: {}", e); - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Failed to search for images"), - &e.to_string()); + clone!( + #[weak] + obj, + move |result| if let Ok(responses) = result { + match responses { + Ok(responses) => { + let imp = obj.imp(); + + obj.action_set_enabled(ACTION_SELECT, true); + + responses.into_iter().for_each(|response| { + obj.imp() + .search_results() + .append(&model::ImageSearchResponse::from(response)); + }); + + imp.selection.set_selected(0); + imp.search_stack.set_visible_child_name("results"); + + glib::idle_add_local_once(clone!( + #[weak] + obj, + move || { + obj.imp() + .scrolled_window + .emit_scroll_child(gtk::ScrollType::Start, false); + } + )); + } + Err(e) => { + log::error!("Failed to search for images: {}", e); + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Failed to search for images"), + &e.to_string(), + ); + } } } - }), + ), ); self.filter_entry.set_key_capture_widget(Some(obj)); - let filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let text = obj.imp().filter_entry.text(); let mut terms = text.split_ascii_whitespace(); let tag = item @@ -176,7 +190,8 @@ mod imp { .tag() .unwrap(); terms.all(|term| tag.contains(&term.to_ascii_lowercase())) - })); + } + )); self.filter.set(filter.clone().upcast()).unwrap(); let filter_list_model = gtk::FilterListModel::new(Some(self.search_results().to_owned()), Some(filter)); diff --git a/src/view/repo_tag_simple_row.rs b/src/view/repo_tag_simple_row.rs index 113e1bdf..5fea6b53 100644 --- a/src/view/repo_tag_simple_row.rs +++ b/src/view/repo_tag_simple_row.rs @@ -54,15 +54,27 @@ mod imp { let obj = &*self.obj(); let style_manager = adw::StyleManager::default(); - style_manager.connect_dark_notify(clone!(@weak obj => move |style_manager| { - obj.set_label(style_manager); - })); - style_manager.connect_accent_color_notify(clone!(@weak obj => move |style_manager| { - obj.set_label(style_manager); - })); - style_manager.connect_high_contrast_notify(clone!(@weak obj => move |style_manager| { - obj.set_label(style_manager); - })); + style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.set_label(style_manager); + } + )); + style_manager.connect_accent_color_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.set_label(style_manager); + } + )); + style_manager.connect_high_contrast_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.set_label(style_manager); + } + )); obj.set_label(&style_manager); } diff --git a/src/view/scalable_text_view_page.rs b/src/view/scalable_text_view_page.rs index 0bc3ee50..bec7a1bb 100644 --- a/src/view/scalable_text_view_page.rs +++ b/src/view/scalable_text_view_page.rs @@ -194,9 +194,13 @@ mod imp { let adw_style_manager = adw::StyleManager::default(); self.on_notify_dark(&adw_style_manager); - adw_style_manager.connect_dark_notify(clone!(@weak obj => move |style_manager| { - obj.imp().on_notify_dark(style_manager); - })); + adw_style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |style_manager| { + obj.imp().on_notify_dark(style_manager); + } + )); } fn dispose(&self) { @@ -334,7 +338,11 @@ impl From for ScalableTextViewPage { serde_json::to_string_pretty(&data).map_err(anyhow::Error::from) }) }, - clone!(@weak obj => move |result| obj.init(result, Mode::Inspect)), + clone!( + #[weak] + obj, + move |result| obj.init(result, Mode::Inspect) + ), ); } Entity::Container { container, mode } => { @@ -356,7 +364,11 @@ impl From for ScalableTextViewPage { .map_err(anyhow::Error::from), } }, - clone!(@weak obj => move |result| obj.init(result, mode)), + clone!( + #[weak] + obj, + move |result| obj.init(result, mode) + ), ); } Entity::Pod { pod, mode } => { @@ -378,7 +390,11 @@ impl From for ScalableTextViewPage { .map_err(anyhow::Error::from), } }, - clone!(@weak obj => move |result| obj.init(result, mode)), + clone!( + #[weak] + obj, + move |result| obj.init(result, mode) + ), ); } Entity::Volume(volume) => { @@ -430,30 +446,42 @@ impl ScalableTextViewPage { utils::show_save_file_dialog( request, self.upcast_ref(), - clone!(@weak self as obj => move |files| { - let file = gio::File::for_uri(files.uris()[0].as_str()); - - if let Some(path) = file.path() { - let file = std::fs::OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(path) - .unwrap(); - - let buffer = &*obj.imp().source_buffer; - let text = buffer.text(&buffer.start_iter(), &buffer.end_iter(), false); - - glib::MainContext::default().spawn_local(clone!(@weak obj => async move { - if let Err((msg, _)) = gio::WriteOutputStream::new(file) - .write_all_future(text, glib::Priority::default()) - .await - { - utils::show_error_toast(obj.upcast_ref(), &gettext("Error"), &msg); - } - })); + clone!( + #[weak(rename_to = obj)] + self, + move |files| { + let file = gio::File::for_uri(files.uris()[0].as_str()); + + if let Some(path) = file.path() { + let file = std::fs::OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path) + .unwrap(); + + let buffer = &*obj.imp().source_buffer; + let text = buffer.text(&buffer.start_iter(), &buffer.end_iter(), false); + + glib::MainContext::default().spawn_local(clone!( + #[weak] + obj, + async move { + if let Err((msg, _)) = gio::WriteOutputStream::new(file) + .write_all_future(text, glib::Priority::default()) + .await + { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error"), + &msg, + ); + } + } + )); + } } - }), + ), ) .await; } diff --git a/src/view/search_panel.rs b/src/view/search_panel.rs index 053d1717..f7aacbbf 100644 --- a/src/view/search_panel.rs +++ b/src/view/search_panel.rs @@ -85,15 +85,18 @@ mod imp { let obj = &*self.obj(); - let filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = obj.imp().search_entry.text().to_lowercase(); if term.is_empty() { false } else if let Some(container) = item.downcast_ref::() { - container - .name().to_lowercase().contains(&term) + container.name().to_lowercase().contains(&term) || container.id().contains(&term) || container .image_name() @@ -109,7 +112,8 @@ mod imp { } else { unreachable!(); } - })); + } + )); let sorter = gtk::CustomSorter::new(|obj1, obj2| { if let Some(container1) = obj1.downcast_ref::() { @@ -211,17 +215,25 @@ mod imp { &self.volumes_model, ); - client.container_list().connect_container_name_changed( - clone!(@weak obj => move |_, _| { - glib::timeout_add_seconds_local_once( - 1, - clone!(@weak obj => move || { - obj.update_filter(); - obj.update_sorter(); - }), - ); - }), - ); + client + .container_list() + .connect_container_name_changed(clone!( + #[weak] + obj, + move |_, _| { + glib::timeout_add_seconds_local_once( + 1, + clone!( + #[weak] + obj, + move || { + obj.update_filter(); + obj.update_sorter(); + } + ), + ); + } + )); } self.client.set(value); @@ -257,9 +269,11 @@ impl SearchPanel { 0, 6, ); - model.connect_items_changed( - clone!(@weak self as obj => move |_, _, _, _| obj.update_view()), - ); + model.connect_items_changed(clone!( + #[weak(rename_to = obj)] + self, + move |_, _, _, _| obj.update_view() + )); list_box.bind_model(Some(&model), move |item| { create_widget_func(item.downcast_ref().unwrap()) }); diff --git a/src/view/top_page.rs b/src/view/top_page.rs index 04442131..b4c0ba19 100644 --- a/src/view/top_page.rs +++ b/src/view/top_page.rs @@ -211,26 +211,34 @@ mod imp { let expr_watches = Rc::new(RefCell::new(HashMap::new())); let factory = gtk::SignalListItemFactory::new(); - factory.connect_setup(clone!(@weak expr_watches => move |_, list_item| { - let label = gtk::Label::builder().halign(halign).build(); - if matches!( - property_type, - PropertyType::Integer - | PropertyType::Float - | PropertyType::Elapsed - | PropertyType::CpuTime - ) { - label.add_css_class("numeric"); - } - list_item - .downcast_ref::() - .unwrap() - .set_child(Some(&label)); + factory.connect_setup(clone!( + #[weak] + expr_watches, + move |_, list_item| { + let label = gtk::Label::builder().halign(halign).build(); + if matches!( + property_type, + PropertyType::Integer + | PropertyType::Float + | PropertyType::Elapsed + | PropertyType::CpuTime + ) { + label.add_css_class("numeric"); + } + list_item + .downcast_ref::() + .unwrap() + .set_child(Some(&label)); - expr_watches.borrow_mut().insert(label, None); - })); - factory.connect_bind( - clone!(@strong display_expr, @strong expr_watches => move |_, list_item| { + expr_watches.borrow_mut().insert(label, None); + } + )); + factory.connect_bind(clone!( + #[strong] + display_expr, + #[strong] + expr_watches, + move |_, list_item| { let list_item = list_item.downcast_ref::().unwrap(); let process = list_item @@ -242,24 +250,28 @@ mod imp { let label = list_item.child().and_downcast::().unwrap(); let expr_watch = display_expr.bind(&label, "label", Some(&process)); *expr_watches.borrow_mut().get_mut(&label).unwrap() = Some(expr_watch); - }), - ); - - factory.connect_unbind(clone!(@weak expr_watches => move |_, list_item| { - let label = list_item - .downcast_ref::() - .unwrap() - .child() - .and_downcast::() - .unwrap(); - expr_watches - .borrow() - .get(&label) - .unwrap() - .as_ref() - .unwrap() - .unwatch(); - })); + } + )); + + factory.connect_unbind(clone!( + #[weak] + expr_watches, + move |_, list_item| { + let label = list_item + .downcast_ref::() + .unwrap() + .child() + .and_downcast::() + .unwrap(); + expr_watches + .borrow() + .get(&label) + .unwrap() + .as_ref() + .unwrap() + .unwatch(); + } + )); factory.connect_teardown(move |_, list_item| { let label = list_item @@ -305,28 +317,34 @@ mod imp { .unwrap(); let sorter = self.column_view.sorter().unwrap(); - model.connect_updated(clone!(@weak sorter => move |_| { - sorter.changed(gtk::SorterChange::Different); - })); - - let filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + model.connect_updated(clone!( + #[weak] + sorter, + move |_| { + sorter.changed(gtk::SorterChange::Different); + } + )); + + let filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = &*obj.imp().search_term.borrow(); if term.is_empty() { true } else { let process = item.downcast_ref::().unwrap(); - process - .user().to_lowercase().contains(term) - || process - .tty().to_lowercase().contains(term) - || process - .command().to_lowercase().contains(term) + process.user().to_lowercase().contains(term) + || process.tty().to_lowercase().contains(term) + || process.command().to_lowercase().contains(term) || process.pid().to_string().contains(term) || process.ppid().to_string().contains(term) } - })); + } + )); let filter_list_model = gtk::FilterListModel::new(Some(model), Some(filter.clone())); self.filter.set(filter.upcast()).unwrap(); @@ -345,19 +363,24 @@ mod imp { action_bar.set_revealed(false); self.toolbar_view.add_bottom_bar(&action_bar); - selection_model.connect_items_changed( - clone!(@weak action_bar => move |model, _, removed, _| { + selection_model.connect_items_changed(clone!( + #[weak] + action_bar, + move |model, _, removed, _| { if removed > 0 { action_bar.set_revealed(model.selection().size() > 0); } - }), - ); - selection_model.connect_selection_changed( - clone!(@weak action_bar => move |model, position, _| { - action_bar - .set_revealed(model.is_selected(position) || model.selection().size() > 0); - }), - ); + } + )); + selection_model.connect_selection_changed(clone!( + #[weak] + action_bar, + move |model, position, _| { + action_bar.set_revealed( + model.is_selected(position) || model.selection().size() > 0, + ); + } + )); self.action_bar.set(action_bar).unwrap(); } @@ -501,13 +524,17 @@ impl TopPage { Err(err_output) } }, - clone!(@weak self as obj => move |result| if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext("Error"), - e.trim() - ); - }), + clone!( + #[weak(rename_to = obj)] + self, + move |result| if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext("Error"), + e.trim(), + ); + } + ), ) } None => utils::show_error_toast( diff --git a/src/view/volume.rs b/src/view/volume.rs index 732d3c7b..2997f82f 100644 --- a/src/view/volume.rs +++ b/src/view/volume.rs @@ -32,11 +32,17 @@ pub(crate) fn delete_volume_show_confirmation(widget: >k::Widget, volume: Opti dialog.choose( widget, gio::Cancellable::NONE, - clone!(@weak widget, @weak volume => move |response| { - if response == "delete" { - delete_volume(&widget, &volume, true); + clone!( + #[weak] + widget, + #[weak] + volume, + move |response| { + if response == "delete" { + delete_volume(&widget, &volume, true); + } } - }), + ), ); } None => delete_volume(widget, &volume, false), @@ -47,16 +53,20 @@ pub(crate) fn delete_volume_show_confirmation(widget: >k::Widget, volume: Opti fn delete_volume(widget: >k::Widget, volume: &model::Volume, force: bool) { volume.delete( force, - clone!(@weak widget => move |volume, result| { - if let Err(e) = result { - utils::show_error_toast( - &widget, - // Translators: The "{}" is a placeholder for the volume name. - &gettext!("Error on deleting volume '{}'", &volume.inner().name), - &e.to_string(), - ); + clone!( + #[weak] + widget, + move |volume, result| { + if let Err(e) = result { + utils::show_error_toast( + &widget, + // Translators: The "{}" is a placeholder for the volume name. + &gettext!("Error on deleting volume '{}'", &volume.inner().name), + &e.to_string(), + ); + } } - }), + ), ); } diff --git a/src/view/volume_creation_page.rs b/src/view/volume_creation_page.rs index dd54e2a9..6e042e31 100644 --- a/src/view/volume_creation_page.rs +++ b/src/view/volume_creation_page.rs @@ -77,12 +77,16 @@ mod imp { let widget = &*self.obj(); - glib::idle_add_local( - clone!(@weak widget => @default-return glib::ControlFlow::Break, move || { + glib::idle_add_local(clone!( + #[weak] + widget, + #[upgrade_or] + glib::ControlFlow::Break, + move || { widget.imp().name_entry_row.grab_focus(); glib::ControlFlow::Break - }), - ); + } + )); utils::root(widget.upcast_ref()).set_default_widget(Some(&*self.create_button)); } diff --git a/src/view/volume_details_page.rs b/src/view/volume_details_page.rs index 528df0bc..e0144bbf 100644 --- a/src/view/volume_details_page.rs +++ b/src/view/volume_details_page.rs @@ -101,12 +101,18 @@ mod imp { .chain_property::("to-be-deleted") .watch( Some(obj), - clone!(@weak obj => move || { - obj.action_set_enabled( - ACTION_DELETE_VOLUME, - obj.volume().map(|volume| !volume.to_be_deleted()).unwrap_or(false), - ); - }), + clone!( + #[weak] + obj, + move || { + obj.action_set_enabled( + ACTION_DELETE_VOLUME, + obj.volume() + .map(|volume| !volume.to_be_deleted()) + .unwrap_or(false), + ); + } + ), ); volume_inner_expr @@ -173,10 +179,17 @@ mod imp { self.window_title .set_subtitle(&utils::format_volume_name(&volume.inner().name)); - let handler_id = volume.connect_deleted(clone!(@weak obj => move |volume| { - utils::show_toast(obj.upcast_ref(), gettext!("Volume '{}' has been deleted", volume.inner().name)); - utils::navigation_view(obj.upcast_ref()).pop(); - })); + let handler_id = volume.connect_deleted(clone!( + #[weak] + obj, + move |volume| { + utils::show_toast( + obj.upcast_ref(), + gettext!("Volume '{}' has been deleted", volume.inner().name), + ); + utils::navigation_view(obj.upcast_ref()).pop(); + } + )); self.handler_id.replace(Some(handler_id)); } diff --git a/src/view/volume_row.rs b/src/view/volume_row.rs index b314ab23..4528909a 100644 --- a/src/view/volume_row.rs +++ b/src/view/volume_row.rs @@ -193,21 +193,33 @@ mod imp { volume_to_be_deleted_expr.watch( Some(obj), - clone!(@weak obj, @strong volume_to_be_deleted_expr => move || { - obj.action_set_enabled( - ACTION_DELETE_VOLUME, - !volume_to_be_deleted_expr.evaluate_as::(Some(&obj)).unwrap() - ); - }), + clone!( + #[weak] + obj, + #[strong] + volume_to_be_deleted_expr, + move || { + obj.action_set_enabled( + ACTION_DELETE_VOLUME, + !volume_to_be_deleted_expr + .evaluate_as::(Some(&obj)) + .unwrap(), + ); + } + ), ); if let Some(volume) = obj.volume() { obj.action_set_enabled("volume.show-details", !volume.to_be_deleted()); volume.connect_notify_local( Some("to-be-deleted"), - clone!(@weak obj => move|volume, _| { - obj.action_set_enabled("volume.show-details", !volume.to_be_deleted()); - }), + clone!( + #[weak] + obj, + move |volume, _| { + obj.action_set_enabled("volume.show-details", !volume.to_be_deleted()); + } + ), ); } } diff --git a/src/view/volume_selection_page.rs b/src/view/volume_selection_page.rs index ab1e79a2..4cc24611 100644 --- a/src/view/volume_selection_page.rs +++ b/src/view/volume_selection_page.rs @@ -123,19 +123,26 @@ mod imp { self.filter_entry.set_key_capture_widget(Some(obj)); - let filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = obj.imp().filter_entry.text().to_lowercase(); let volume = item.downcast_ref::().unwrap(); volume.inner().name.to_lowercase().contains(&term) - })); + } + )); self.filter.set(filter.upcast()).unwrap(); self.list_view.remove_css_class("view"); - self.selection - .connect_items_changed(clone!(@weak obj => move |selection, _, _, _| { + self.selection.connect_items_changed(clone!( + #[weak] + obj, + move |selection, _, _, _| { obj.imp() .volumes_stack .set_visible_child_name(if selection.n_items() > 0 { @@ -143,7 +150,8 @@ mod imp { } else { "empty" }); - })); + } + )); } fn dispose(&self) { @@ -254,9 +262,13 @@ mod imp { let model = gtk::SingleSelection::new(Some(model)); - model.connect_selected_item_notify(clone!(@weak obj => move |selection| { - obj.action_set_enabled(ACTION_SELECT, selection.selected_item().is_some()); - })); + model.connect_selected_item_notify(clone!( + #[weak] + obj, + move |selection| { + obj.action_set_enabled(ACTION_SELECT, selection.selected_item().is_some()); + } + )); self.selection.set_model(Some(&model)); diff --git a/src/view/volumes_panel.rs b/src/view/volumes_panel.rs index 3a8b28b3..ef57266e 100644 --- a/src/view/volumes_panel.rs +++ b/src/view/volumes_panel.rs @@ -221,8 +221,12 @@ mod imp { not_selection_mode_expr.bind(&self.search_bar.get(), "visible", Some(obj)); - let search_filter = - gtk::CustomFilter::new(clone!(@weak obj => @default-return false, move |item| { + let search_filter = gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |item| { let term = &*obj.imp().search_term.borrow(); item.downcast_ref::() .unwrap() @@ -230,14 +234,17 @@ mod imp { .name .to_lowercase() .contains(term) - })); + } + )); let state_filter = gtk::AnyFilter::new(); - state_filter.append(gtk::CustomFilter::new( - clone!(@weak obj => @default-return false, move |_| { - !obj.show_only_used_volumes() - }), - )); + state_filter.append(gtk::CustomFilter::new(clone!( + #[weak] + obj, + #[upgrade_or] + false, + move |_| !obj.show_only_used_volumes() + ))); state_filter.append(gtk::BoolFilter::new(Some( model::Volume::this_expression("container-list") .chain_property::("len") @@ -310,16 +317,27 @@ mod imp { if let Some(volume_list) = value { volume_list.connect_notify_local( Some("num-selected"), - clone!(@weak obj => move |list, _| { - obj.action_set_enabled(ACTION_DELETE_SELECTION, list.num_selected() > 0); - }), + clone!( + #[weak] + obj, + move |list, _| { + obj.action_set_enabled( + ACTION_DELETE_SELECTION, + list.num_selected() > 0, + ); + } + ), ); volume_list.connect_notify_local( Some("used"), - clone!(@weak obj => move |_, _| { - obj.imp().update_filter(gtk::FilterChange::Different); - }), + clone!( + #[weak] + obj, + move |_, _| { + obj.imp().update_filter(gtk::FilterChange::Different); + } + ), ); let model = gtk::SortListModel::new( @@ -336,15 +354,23 @@ mod imp { self.filter_stack .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); - model.connect_items_changed(clone!(@weak obj => move |model, _, removed, _| { - obj.imp() - .filter_stack - .set_visible_child_name(if model.n_items() > 0 { "list" } else { "empty" }); + model.connect_items_changed(clone!( + #[weak] + obj, + move |model, _, removed, _| { + obj.imp() + .filter_stack + .set_visible_child_name(if model.n_items() > 0 { + "list" + } else { + "empty" + }); - if removed > 0 { - obj.deselect_hidden_volumes(model.upcast_ref()); + if removed > 0 { + obj.deselect_hidden_volumes(model.upcast_ref()); + } } - })); + )); } self.volume_list.set(value); @@ -464,31 +490,40 @@ impl VolumesPanel { dialog.connect_response( None, - clone!(@weak self as obj => move |_, response| if response == "delete" { - if let Some(list) = obj.volume_list() { - list - .selected_items() - .iter() - .map(|obj| obj.downcast_ref::().unwrap()) - .for_each(|volume| - { - volume.delete(true, clone!(@weak obj => move |volume, result| { - if let Err(e) = result { - utils::show_error_toast( - obj.upcast_ref(), - &gettext!( - "Error on deleting volume '{}'", - volume.inner().name + clone!( + #[weak(rename_to = obj)] + self, + move |_, response| if response == "delete" { + if let Some(list) = obj.volume_list() { + list.selected_items() + .iter() + .map(|obj| obj.downcast_ref::().unwrap()) + .for_each(|volume| { + volume.delete( + true, + clone!( + #[weak] + obj, + move |volume, result| { + if let Err(e) = result { + utils::show_error_toast( + obj.upcast_ref(), + &gettext!( + "Error on deleting volume '{}'", + volume.inner().name + ), + &e.to_string(), + ); + } + } ), - &e.to_string() ); - } - })); - }); - list.set_selection_mode(false); - obj.emit_by_name::<()>("exit-selection-mode", &[]); + }); + list.set_selection_mode(false); + obj.emit_by_name::<()>("exit-selection-mode", &[]); + } } - }), + ), ); dialog.present(Some(self)); diff --git a/src/view/window.rs b/src/view/window.rs index edb72cfb..2217c39f 100644 --- a/src/view/window.rs +++ b/src/view/window.rs @@ -105,7 +105,11 @@ mod imp { let controller = gtk::EventControllerKey::new(); controller.connect_key_pressed(clone!( - @weak shortcuts => @default-return glib::Propagation::Stop, move |_, key, _, modifier| { + #[weak] + shortcuts, + #[upgrade_or] + glib::Propagation::Stop, + move |_, key, _, modifier| { if key == gdk::Key::w && modifier == gdk::ModifierType::CONTROL_MASK { shortcuts.close(); } @@ -129,32 +133,50 @@ mod imp { obj.maximize(); } - self.connection_manager.connect_items_changed( - clone!(@weak obj => move |connection_manager, _, _, _| { + self.connection_manager.connect_items_changed(clone!( + #[weak] + obj, + move |connection_manager, _, _, _| { if connection_manager.n_items() == 0 { obj.imp().main_stack.set_visible_child_name("welcome"); } - }), - ); + } + )); - self.connection_manager.connect_client_notify( - clone!(@weak obj => move |manager| match manager.client() { + self.connection_manager.connect_client_notify(clone!( + #[weak] + obj, + move |manager| match manager.client() { Some(client) => client.check_service( - clone!(@weak obj, @weak client => move || { - obj - .imp() - .main_stack - .set_visible_child_full("client", gtk::StackTransitionType::None); - }), - clone!(@weak obj => move |e| obj.client_err_op(e)), - clone!(@weak obj, @weak manager => move |e| { - utils::show_error_toast( - obj.imp().toast_overlay.upcast_ref(), - "Connection lost", - &e.to_string() - ); - manager.unset_client(); - }), + clone!( + #[weak] + obj, + move || { + obj.imp().main_stack.set_visible_child_full( + "client", + gtk::StackTransitionType::None, + ); + } + ), + clone!( + #[weak] + obj, + move |e| obj.client_err_op(e) + ), + clone!( + #[weak] + obj, + #[weak] + manager, + move |e| { + utils::show_error_toast( + obj.imp().toast_overlay.upcast_ref(), + "Connection lost", + &e.to_string(), + ); + manager.unset_client(); + } + ), ), None => { obj.imp().main_stack.set_visible_child_full( @@ -163,17 +185,19 @@ mod imp { } else { "welcome" }, - gtk::StackTransitionType::Crossfade + gtk::StackTransitionType::Crossfade, ); } - }), - ); + } + )); - self.connection_manager.setup( - clone!(@weak obj => move |result| if let Err(e) = result { + self.connection_manager.setup(clone!( + #[weak] + obj, + move |result| if let Err(e) = result { obj.on_connection_manager_setup_error(e); - }), - ); + } + )); } } diff --git a/src/widget/circular_progress_bar.rs b/src/widget/circular_progress_bar.rs index 0ab0bd56..6a0fbc68 100644 --- a/src/widget/circular_progress_bar.rs +++ b/src/widget/circular_progress_bar.rs @@ -84,9 +84,16 @@ mod imp { let obj = &*self.obj(); let adw_style_manager = adw::StyleManager::default(); - adw_style_manager - .connect_high_contrast_notify(clone!(@weak obj => move |_| obj.queue_draw())); - adw_style_manager.connect_dark_notify(clone!(@weak obj => move |_| obj.queue_draw())); + adw_style_manager.connect_high_contrast_notify(clone!( + #[weak] + obj, + move |_| obj.queue_draw() + )); + adw_style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |_| obj.queue_draw() + )); } fn dispose(&self) { diff --git a/src/widget/date_time_row.rs b/src/widget/date_time_row.rs index 9aed2cf3..b9ab10da 100644 --- a/src/widget/date_time_row.rs +++ b/src/widget/date_time_row.rs @@ -80,9 +80,13 @@ mod imp { obj.load_time_format(); self.desktop_settings.connect_changed( Some("clock-format"), - clone!(@weak obj => move |_, _| { - obj.load_time_format(); - }), + clone!( + #[weak] + obj, + move |_, _| { + obj.load_time_format(); + } + ), ); gtk::ClosureExpression::new::( diff --git a/src/widget/source_view_search_widget.rs b/src/widget/source_view_search_widget.rs index 957a3b0c..aea8a93a 100644 --- a/src/widget/source_view_search_widget.rs +++ b/src/widget/source_view_search_widget.rs @@ -149,13 +149,15 @@ mod imp { Some(&self.search_settings), ); - search_context.connect_occurrences_count_notify(clone!(@weak obj => move |ctx| { - obj.imp().search_entry.set_info(& - gettext!( - "0 of {}", - ctx.occurrences_count(), - )); - })); + search_context.connect_occurrences_count_notify(clone!( + #[weak] + obj, + move |ctx| { + obj.imp() + .search_entry + .set_info(&gettext!("0 of {}", ctx.occurrences_count(),)); + } + )); self.search_context.replace(Some(search_context)); } diff --git a/src/widget/spinner.rs b/src/widget/spinner.rs index 277888c5..295de8f6 100644 --- a/src/widget/spinner.rs +++ b/src/widget/spinner.rs @@ -83,10 +83,14 @@ mod imp { let obj = &*self.obj(); - let target = adw::CallbackAnimationTarget::new(clone!(@weak obj => move |value| { - obj.imp().animation_value.set(value as f32); - obj.queue_draw(); - })); + let target = adw::CallbackAnimationTarget::new(clone!( + #[weak] + obj, + move |value| { + obj.imp().animation_value.set(value as f32); + obj.queue_draw(); + } + )); let animation = adw::TimedAnimation::builder() .widget(obj) .target(&target) @@ -99,9 +103,16 @@ mod imp { self.animation.set(animation).unwrap(); let adw_style_manager = adw::StyleManager::default(); - adw_style_manager - .connect_high_contrast_notify(clone!(@weak obj => move |_| obj.queue_draw())); - adw_style_manager.connect_dark_notify(clone!(@weak obj => move |_| obj.queue_draw())); + adw_style_manager.connect_high_contrast_notify(clone!( + #[weak] + obj, + move |_| obj.queue_draw() + )); + adw_style_manager.connect_dark_notify(clone!( + #[weak] + obj, + move |_| obj.queue_draw() + )); } fn dispose(&self) {