From d52dbaa27bd63bba839d4c63208a1a17961e8bf3 Mon Sep 17 00:00:00 2001 From: Dave Patrick Caberto Date: Mon, 24 Jul 2023 11:19:50 +0800 Subject: [PATCH] refactor: drop app_settings util func --- src/application.rs | 46 ++++++++++++++++++------------------- src/preferences_window.rs | 48 ++++++++++++++++++++------------------- src/recording.rs | 3 +-- src/utils.rs | 33 +++++++++++++++++++-------- src/window.rs | 21 ++++++++++++----- 5 files changed, 87 insertions(+), 64 deletions(-) diff --git a/src/application.rs b/src/application.rs index 13d6a6eb1..160fd9a20 100644 --- a/src/application.rs +++ b/src/application.rs @@ -38,9 +38,17 @@ mod imp { fn activate(&self) { self.parent_activate(); - if let Some(window) = self.obj().main_window() { + let obj = self.obj(); + + if let Some(window) = self.window.get() { + let window = window.upgrade().unwrap(); window.present(); + return; } + + let window = Window::new(&obj); + self.window.set(window.downgrade()).unwrap(); + window.present(); } fn startup(&self) { @@ -87,18 +95,13 @@ impl Application { }) } - pub fn main_window(&self) -> Option { - let main_window = self - .imp() + pub fn window(&self) -> Window { + self.imp() .window - .get_or_init(|| Window::new(self).downgrade()) - .upgrade(); - - if main_window.is_none() { - tracing::warn!("Failed to upgrade WeakRef"); - } - - main_window + .get() + .expect("window must be initialized on activate") + .upgrade() + .unwrap() } pub fn send_record_success_notification(&self, recording_file: &gio::File) { @@ -119,9 +122,9 @@ impl Application { } pub fn present_preferences(&self) { - let window = PreferencesWindow::new(); + let window = PreferencesWindow::new(self.settings()); window.set_modal(true); - window.set_transient_for(self.main_window().as_ref()); + window.set_transient_for(Some(&self.window())); window.present(); } @@ -135,15 +138,13 @@ impl Application { async fn try_show_uri(&self, uri: &str) { if let Err(err) = gtk::FileLauncher::new(Some(&gio::File::for_uri(uri))) - .launch_future(self.main_window().as_ref()) + .launch_future(Some(&self.window())) .await { if !err.matches(gio::IOErrorEnum::Cancelled) { tracing::error!("Failed to launch default for uri `{}`: {:?}", uri, err); - if let Some(window) = self.main_window() { - window.present_error(&err.into()); - } + self.window().present_error(&err.into()); } } } @@ -169,7 +170,7 @@ impl Application { utils::spawn(async move { if let Err(err) = gtk::FileLauncher::new(Some(&gio::File::for_uri(&uri))) - .open_containing_folder_future(obj.main_window().as_ref()) + .open_containing_folder_future(Some(&obj.window())) .await { tracing::warn!("Failed to show items: {:?}", err); @@ -182,7 +183,7 @@ impl Application { let action_about = gio::SimpleAction::new("about", None); action_about.connect_activate(clone!(@weak self as obj => move |_, _| { - about::present_window(obj.main_window().as_ref()); + about::present_window(Some(&obj.window())); })); self.add_action(&action_about); @@ -194,13 +195,12 @@ impl Application { let action_quit = gio::SimpleAction::new("quit", None); action_quit.connect_activate(clone!(@weak self as obj => move |_, _| { - if let Some(window) = obj.main_window() { + if let Some(window) = obj.imp().window.get().and_then(|window| window.upgrade()) { if let Err(err) = window.close() { tracing::warn!("Failed to close window: {:?}", err); } - } else { - obj.quit(); } + obj.quit(); })); self.add_action(&action_quit); } diff --git a/src/preferences_window.rs b/src/preferences_window.rs index 83dd5fa19..2aca9ea78 100644 --- a/src/preferences_window.rs +++ b/src/preferences_window.rs @@ -5,9 +5,11 @@ use gtk::{ glib::{self, clone, closure}, pango, }; +use once_cell::unsync::OnceCell; use crate::{ profile::{self, BoxedProfile}, + settings::Settings, utils, }; @@ -15,9 +17,13 @@ mod imp { use super::*; use gtk::CompositeTemplate; - #[derive(Debug, Default, CompositeTemplate)] + #[derive(Debug, Default, glib::Properties, CompositeTemplate)] + #[properties(wrapper_type = super::PreferencesWindow)] #[template(resource = "/io/github/seadve/Kooha/ui/preferences-window.ui")] pub struct PreferencesWindow { + #[property(get, set, construct_only)] + pub(super) settings: OnceCell, + #[template_child] pub(super) framerate_button: TemplateChild, #[template_child] @@ -40,7 +46,7 @@ mod imp { klass.bind_template(); klass.install_action("preferences.select-saving-location", None, |obj, _, _| { - utils::app_settings().select_saving_location(obj); + obj.settings().select_saving_location(obj); }); } @@ -50,11 +56,13 @@ mod imp { } impl ObjectImpl for PreferencesWindow { + crate::derived_properties!(); + fn constructed(&self) { self.parent_constructed(); let obj = self.obj(); - let settings = utils::app_settings(); + let settings = obj.settings(); self.profile_row .set_factory(Some(&profile_row_factory(&self.profile_row, false))); @@ -117,12 +125,13 @@ mod imp { // Load last active profile first in `update_profile_row` before // connecting to the signal to avoid unnecessary updates. - self.profile_row.connect_selected_item_notify(|row| { - if let Some(item) = row.selected_item() { - let profile = item.downcast::().unwrap(); - utils::app_settings().set_profile(profile.get()); - } - }); + self.profile_row + .connect_selected_item_notify(clone!(@weak obj => move |row| { + if let Some(item) = row.selected_item() { + let profile = item.downcast::().unwrap(); + obj.settings().set_profile(profile.get()); + } + })); } } @@ -138,15 +147,14 @@ glib::wrapper! { } impl PreferencesWindow { - pub fn new() -> Self { - glib::Object::builder().build() + pub fn new(settings: &Settings) -> Self { + glib::Object::builder() + .property("settings", settings) + .build() } fn update_file_chooser_button(&self) { - let saving_location_display = utils::app_settings() - .saving_location() - .display() - .to_string(); + let saving_location_display = self.settings().saving_location().display().to_string(); if let Some(stripped) = saving_location_display.strip_prefix(&glib::home_dir().display().to_string()) @@ -162,7 +170,7 @@ impl PreferencesWindow { } fn update_profile_row(&self) { - let active_profile = utils::app_settings().profile(); + let active_profile = self.settings().profile(); let imp = self.imp(); let position = imp @@ -192,7 +200,7 @@ impl PreferencesWindow { fn update_framerate_warning(&self) { let imp = self.imp(); - let settings = utils::app_settings(); + let settings = self.settings(); imp.framerate_warning.set_visible( settings @@ -205,12 +213,6 @@ impl PreferencesWindow { } } -impl Default for PreferencesWindow { - fn default() -> Self { - Self::new() - } -} - fn profile_row_factory( profile_row: &adw::ComboRow, show_selected_indicator: bool, diff --git a/src/recording.rs b/src/recording.rs index 4304df02d..d27adb0a2 100644 --- a/src/recording.rs +++ b/src/recording.rs @@ -215,8 +215,7 @@ impl Recording { // select area if settings.capture_mode() == CaptureMode::Selection { let data = - AreaSelector::present(utils::app_instance().main_window().as_ref(), fd, &streams) - .await?; + AreaSelector::present(Some(&utils::app_instance().window()), fd, &streams).await?; pipeline_builder.select_area_data(data); } diff --git a/src/utils.rs b/src/utils.rs index b187ea367..c07069c38 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,10 +6,32 @@ use gtk::{ use std::{env, path::Path}; -use crate::{settings::Settings, Application}; +use crate::Application; const MAX_THREAD_COUNT: u32 = 64; +/// Generates the boilerplate for setting `glib::Properties`'s generated functions +/// to the implementation of the following methods of `ObjectImpl`: +/// * `properties()` +/// * `property()` +/// * `set_property()` +#[macro_export] +macro_rules! derived_properties { + () => { + fn properties() -> &'static [glib::ParamSpec] { + Self::derived_properties() + } + + fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value { + self.derived_property(id, pspec) + } + + fn set_property(&self, id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { + self.derived_set_property(id, value, pspec); + } + }; +} + /// Spawns a future in the default [`glib::MainContext`] pub fn spawn + 'static>(fut: F) { let ctx = glib::MainContext::default(); @@ -30,15 +52,6 @@ pub fn app_instance() -> Application { gio::Application::default().unwrap().downcast().unwrap() } -/// Get the global instance of `Settings`. -/// -/// # Panics -/// Panics if the application is not running or if this is -/// called on a non-main thread. -pub fn app_settings() -> Settings { - app_instance().settings().clone() -} - /// Whether the application is running in a flatpak sandbox. pub fn is_flatpak() -> bool { Path::new("/.flatpak-info").exists() diff --git a/src/window.rs b/src/window.rs index d6f97e6f5..ceab21c1e 100644 --- a/src/window.rs +++ b/src/window.rs @@ -78,7 +78,9 @@ mod imp { }); klass.install_action("win.forget-video-sources", None, move |_obj, _, _| { - utils::app_settings().set_screencast_restore_token(""); + utils::app_instance() + .settings() + .set_screencast_restore_token(""); }); } @@ -239,7 +241,9 @@ impl Window { imp.recording .replace(Some((recording.clone(), handler_ids))); - recording.start(Some(self), &utils::app_settings()).await; + recording + .start(Some(self), utils::app_instance().settings()) + .await; } fn toggle_pause(&self) -> Result<()> { @@ -378,14 +382,15 @@ impl Window { fn update_title_label(&self) { let imp = self.imp(); - match utils::app_settings().capture_mode() { + match utils::app_instance().settings().capture_mode() { CaptureMode::MonitorWindow => imp.title.set_title(&gettext("Normal")), CaptureMode::Selection => imp.title.set_title(&gettext("Selection")), } } fn update_audio_toggles_sensitivity(&self) { - let is_enabled = utils::app_settings() + let is_enabled = utils::app_instance() + .settings() .profile() .map_or(true, |profile| profile.supports_audio()); @@ -394,7 +399,10 @@ impl Window { } fn update_forget_video_sources_action(&self) { - let has_restore_token = !utils::app_settings().screencast_restore_token().is_empty(); + let has_restore_token = !utils::app_instance() + .settings() + .screencast_restore_token() + .is_empty(); self.imp() .forget_video_sources_revealer @@ -404,7 +412,8 @@ impl Window { } fn setup_settings(&self) { - let settings = utils::app_settings(); + let app = utils::app_instance(); + let settings = app.settings(); settings.connect_capture_mode_changed(clone!(@weak self as obj => move |_| { obj.update_title_label();