use adw::prelude::*; use adw::subclass::prelude::*; use gtk::gio; use std::cell::OnceCell; use crate::config::{APP_ID, VERSION}; use crate::window::DriftwoodWindow; mod imp { use super::*; pub struct DriftwoodApplication { pub settings: OnceCell, } impl Default for DriftwoodApplication { fn default() -> Self { Self { settings: OnceCell::new(), } } } #[glib::object_subclass] impl ObjectSubclass for DriftwoodApplication { const NAME: &'static str = "DriftwoodApplication"; type Type = super::DriftwoodApplication; type ParentType = adw::Application; } impl ObjectImpl for DriftwoodApplication {} impl ApplicationImpl for DriftwoodApplication { fn startup(&self) { self.parent_startup(); let app = self.obj(); app.setup_css(); app.setup_theme(); app.setup_actions(); } fn activate(&self) { self.parent_activate(); let app = self.obj(); // Present existing window or create a new one if let Some(window) = app.active_window() { window.present(); } else { let window = DriftwoodWindow::new(&*app); window.present(); } } } impl GtkApplicationImpl for DriftwoodApplication {} impl AdwApplicationImpl for DriftwoodApplication {} } glib::wrapper! { pub struct DriftwoodApplication(ObjectSubclass) @extends adw::Application, gtk::Application, gio::Application, @implements gio::ActionGroup, gio::ActionMap; } impl DriftwoodApplication { pub fn new(app_id: &str, flags: &gio::ApplicationFlags) -> Self { glib::Object::builder() .property("application-id", app_id) .property("flags", flags) .build() } fn setup_css(&self) { let provider = gtk::CssProvider::new(); provider.load_from_resource("/app/driftwood/Driftwood/style.css"); gtk::style_context_add_provider_for_display( >k::gdk::Display::default().expect("Could not get default display"), &provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION, ); } fn setup_theme(&self) { let settings = gio::Settings::new(APP_ID); Self::apply_color_scheme(&settings); settings.connect_changed(Some("color-scheme"), |settings, _| { Self::apply_color_scheme(settings); }); // Store settings on the imp struct so it stays alive // (otherwise the connect_changed signal gets dropped) self.imp() .settings .set(settings) .expect("Theme settings already initialized"); } fn apply_color_scheme(settings: &gio::Settings) { let value = settings.string("color-scheme"); let scheme = match value.as_str() { "force-light" => adw::ColorScheme::ForceLight, "force-dark" => adw::ColorScheme::ForceDark, _ => adw::ColorScheme::Default, }; adw::StyleManager::default().set_color_scheme(scheme); } fn setup_actions(&self) { // Quit action (Ctrl+Q) let quit_action = gio::ActionEntry::builder("quit") .activate(|app: &Self, _, _| { if let Some(window) = app.active_window() { window.close(); } app.quit(); }) .build(); // About action let about_action = gio::ActionEntry::builder("about") .activate(|app: &Self, _, _| { app.show_about_dialog(); }) .build(); self.add_action_entries([quit_action, about_action]); self.set_accels_for_action("app.quit", &["q"]); } fn show_about_dialog(&self) { let dialog = adw::AboutDialog::builder() .application_name("Driftwood") .application_icon(APP_ID) .version(VERSION) .developer_name("Driftwood Contributors") .license_type(gtk::License::Gpl30) .comments("A modern AppImage manager for GNOME desktops") .website("https://github.com/driftwood-app/driftwood") .build(); dialog.present(self.active_window().as_ref()); } }