From 9b8ca984f496d854af25df3570c1d42829cdc015 Mon Sep 17 00:00:00 2001 From: Asriel Camora Date: Sat, 1 Apr 2023 00:56:22 -0700 Subject: [PATCH] Big commit with lots of stuff --- .gitmodules | 3 + Cargo.lock | 165 +++++++++++++++++++++++--- app/Cargo.toml | 11 ++ app/build.rs | 53 +++++++-- app/resources/Sweet | 1 + app/resources/icon.ico | Bin 0 -> 20056 bytes app/resources/icon.svg | 122 +++++++++++++++++++ app/resources/main.blp | 79 +++++++++++- app/resources/main.css | 12 ++ app/resources/resources.gresource.xml | 4 +- app/src/main.rs | 52 ++++---- app/src/modules/mod.rs | 8 ++ app/src/modules/module.rs | 54 +++++++++ app/src/modules/theme_picker.rs | 65 ++++++++++ app/src/utils/dpi.rs | 19 +++ app/src/utils/mod.rs | 1 + app/src/widgets/application/imp.rs | 73 ++++++++++++ app/src/widgets/application/mod.rs | 28 +++++ app/src/widgets/mod.rs | 3 + 19 files changed, 701 insertions(+), 52 deletions(-) create mode 100644 .gitmodules create mode 160000 app/resources/Sweet create mode 100644 app/resources/icon.ico create mode 100644 app/resources/icon.svg create mode 100644 app/resources/main.css create mode 100644 app/src/modules/mod.rs create mode 100644 app/src/modules/module.rs create mode 100644 app/src/modules/theme_picker.rs create mode 100644 app/src/utils/dpi.rs create mode 100644 app/src/utils/mod.rs create mode 100644 app/src/widgets/application/imp.rs create mode 100644 app/src/widgets/application/mod.rs create mode 100644 app/src/widgets/mod.rs diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6eecee7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "app/resources/Sweet"] + path = app/resources/Sweet + url = https://github.com/WorkingRobot/Sweet.git diff --git a/Cargo.lock b/Cargo.lock index bd0534d..eed89a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,6 +165,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "embed-manifest" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ff574b0b0a794f8995383bb83f21f8f99214422cae791cb48d66da524b00f7" + [[package]] name = "encoding_rs" version = "0.8.32" @@ -373,6 +379,34 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gdk4-win32" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a79a5672b4b26ece3fc144c5be6c8d0ef2d84d37fed65002e5b1576fbc3ec00" +dependencies = [ + "gdk4", + "gdk4-win32-sys", + "gio", + "glib", + "libc", + "system-deps", + "windows 0.44.0", +] + +[[package]] +name = "gdk4-win32-sys" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2c1b84458185383da1d8877f812cccffd83a3cb42959d646e3e9a4ad0bc09ac" +dependencies = [ + "gdk-pixbuf-sys", + "gdk4-sys", + "glib-sys", + "libc", + "system-deps", +] + [[package]] name = "gio" version = "0.17.4" @@ -763,12 +797,16 @@ dependencies = [ name = "l4" version = "0.1.0" dependencies = [ + "embed-manifest", + "gdk4-win32", "glib-build-tools", "gtk4", "libadwaita", "libloading", "plugins_core", "walkdir", + "windows 0.47.0", + "winres", ] [[package]] @@ -1046,7 +1084,7 @@ dependencies = [ "rustc_version", "semver", "tokio", - "toml", + "toml 0.7.2", ] [[package]] @@ -1387,7 +1425,7 @@ dependencies = [ "cfg-expr", "heck", "pkg-config", - "toml", + "toml 0.7.2", "version-compare", ] @@ -1494,6 +1532,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.7.2" @@ -1749,19 +1796,37 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.44.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" +dependencies = [ + "windows-targets 0.42.1", +] + +[[package]] +name = "windows" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2649ff315bee4c98757f15dac226efe3d81927adbb6e882084bb1ee3e0c330a7" +dependencies = [ + "windows-targets 0.47.0", +] + [[package]] name = "windows-sys" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", ] [[package]] @@ -1770,7 +1835,7 @@ version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets", + "windows-targets 0.42.1", ] [[package]] @@ -1779,13 +1844,28 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", +] + +[[package]] +name = "windows-targets" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f8996d3f43b4b2d44327cd71b7b0efd1284ab60e6e9d0e8b630e18555d87d3e" +dependencies = [ + "windows_aarch64_gnullvm 0.47.0", + "windows_aarch64_msvc 0.47.0", + "windows_i686_gnu 0.47.0", + "windows_i686_msvc 0.47.0", + "windows_x86_64_gnu 0.47.0", + "windows_x86_64_gnullvm 0.47.0", + "windows_x86_64_msvc 0.47.0", ] [[package]] @@ -1794,42 +1874,84 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831d567d53d4f3cb1db332b68e6e2b6260228eb4d99a777d8b2e8ed794027c90" + [[package]] name = "windows_aarch64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +[[package]] +name = "windows_aarch64_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a42d54a417c60ce4f0e31661eed628f0fa5aca73448c093ec4d45fab4c51cdf" + [[package]] name = "windows_i686_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +[[package]] +name = "windows_i686_gnu" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1925beafdbb22201a53a483db861a5644123157c1c3cee83323a2ed565d71e3" + [[package]] name = "windows_i686_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +[[package]] +name = "windows_i686_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8ef8f2f1711b223947d9b69b596cf5a4e452c930fb58b6fc3fdae7d0ec6b31" + [[package]] name = "windows_x86_64_gnu" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +[[package]] +name = "windows_x86_64_gnu" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acaa0c2cf0d2ef99b61c308a0c3dbae430a51b7345dedec470bd8f53f5a3642" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a0628f71be1d11e17ca4a0e9e15b3a5180f6fbf1c2d55e3ba3f850378052c1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[package]] +name = "windows_x86_64_msvc" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d6e62c256dc6d40b8c8707df17df8d774e60e39db723675241e7c15e910bce7" + [[package]] name = "winnow" version = "0.3.5" @@ -1847,3 +1969,12 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "winres" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +dependencies = [ + "toml 0.5.11", +] diff --git a/app/Cargo.toml b/app/Cargo.toml index 6a2a932..9a6cbb3 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -3,11 +3,20 @@ name = "l4" version = "0.1.0" edition = "2021" +[package.metadata.winres] +OriginalFilename = "L4.exe" +ProductName = "L4" +FileDescription = "Launcher v4 or something" +LegalCopyright = "Copyright © 2023, Asriel Camora" +CompanyName = "WorkingRobot" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] libloading = "0.7.4" plugins_core = { path = "../plugins/core" } +gdk4-win32 = { version = "0.6.3", features = ["win32"] } +windows = { version = "0.47.0", features = ["Win32_UI_HiDpi", "Win32_Foundation"]} [dependencies.gtk] package = "gtk4" @@ -21,3 +30,5 @@ version = "0.3.1" [build-dependencies] glib-build-tools = "0.17.0" walkdir = "2.3.3" +embed-manifest = "1.3.1" +winres = "0.1.12" diff --git a/app/build.rs b/app/build.rs index e14c88e..d4fd5f1 100644 --- a/app/build.rs +++ b/app/build.rs @@ -1,5 +1,6 @@ -use std::process::Command; -use std::{env, path::Path}; +use embed_manifest::{embed_manifest, manifest::DpiAwareness, new_manifest}; +use std::process::{Command, Stdio}; +use std::{env, path::Path, path::PathBuf}; use walkdir::WalkDir; fn main() { @@ -8,6 +9,41 @@ fn main() { "resources/resources.gresource.xml", "L4.gresource", ); + + let out_dir = env::var("OUT_DIR").unwrap(); + for theme in &[ + "Sweet", + "Sweet-Ambar", + "Sweet-Ambar-Blue", + "Sweet-Dark", + "Sweet-Mars", + ] { + let mut from_path = PathBuf::new(); + from_path.push("resources"); + from_path.push("Sweet"); + from_path.push(theme); + from_path.set_extension("gresource"); + let mut to_path = PathBuf::new(); + to_path.push(out_dir.as_str()); + to_path.push(theme); + to_path.set_extension("gresource"); + std::fs::copy(&from_path, &to_path).unwrap(); + + println!("cargo:rerun-if-changed={}", &from_path.display()); + } + + if cfg!(target_os = "windows") { + embed_manifest( + new_manifest("WorkingRobot.L4").dpi_awareness(DpiAwareness::PerMonitorV2Only), + ) + .expect("Unable to embed manifest file"); + + let mut res = winres::WindowsResource::new(); + res.set_icon("resources/icon.ico") + .set("InternalName", "L4.EXE"); + res.compile().unwrap(); + } + println!("cargo:rerun-if-changed=build.rs"); } fn blueprint_batch_compile>(sources: &[P], input_dir: &str, output_dir: &str) { @@ -17,16 +53,19 @@ fn blueprint_batch_compile>(sources: &[P], input_dir: &str, outpu for source in sources { command.arg(source.as_ref()); - println!("cargo:rerun-if-changed={:?}", source.as_ref()); + println!("cargo:rerun-if-changed={}", source.as_ref().display()); } - let output = command.output().unwrap(); + let output = command + .stdout(Stdio::inherit()) + .stderr(Stdio::inherit()) + .output() + .unwrap(); assert!( output.status.success(), - "blueprint-compiler failed with exit status {} and stderr:\n{}", - output.status, - String::from_utf8_lossy(&output.stderr) + "blueprint-compiler failed with exit status {}", + output.status ) } diff --git a/app/resources/Sweet b/app/resources/Sweet new file mode 160000 index 0000000..ac1568c --- /dev/null +++ b/app/resources/Sweet @@ -0,0 +1 @@ +Subproject commit ac1568c63953feadc74fa80f20ba9d6639495b95 diff --git a/app/resources/icon.ico b/app/resources/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..49f723d1fe497b1286549d2fd99fc2f22fc18c60 GIT binary patch literal 20056 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 + + EGL2 + + + + image/svg+xml + + EGL2 + + + + + + + + + + + + + + + + + diff --git a/app/resources/main.blp b/app/resources/main.blp index 38f8bee..0e2b19a 100644 --- a/app/resources/main.blp +++ b/app/resources/main.blp @@ -1,6 +1,83 @@ using Gtk 4.0; using Adw 1; -Adw.ApplicationWindow window { +menu main-menu { + submenu { + label: _("_Filter"); + item { + label: _("_All"); + action: "win.filter"; + target: "All"; + } + + item { + label: _("_Open"); + action: "win.filter"; + target: "Open"; + } + + item { + label: _("_Done"); + action: "win.filter"; + target: "Done"; + } + } + + item { + label: _("_Remove Done Tasks"); + action: "win.remove-done-tasks"; + } + + item { + label: _("_Keyboard Shortcuts"); + action: "win.show-help-overlay"; + } +} + +ApplicationWindow window { + default-width: 650; + default-height: 550; + icon-name: "icon"; + + titlebar: HeaderBar { + decoration-layout: "icon:minimize,maximize,close"; + title-widget: StackSwitcher title { + stack: main-stack; + }; + + [start] + Label { + label: _("L4"); + } + }; + + Box { + orientation: vertical; + Stack main-stack { + StackPage page-games { + name: "games"; + title: _("Games"); + + child: Adw.StatusPage leaflet2 { + + }; + } + + StackPage { + name: "main"; + title: _("maintitle"); + child: Adw.StatusPage { + Box { + [start] + DropDown theme_dropdown { + model: StringList { + strings ["Sweet", "Dark", "Mars", "Ambar", "Blue"] + }; + } + } + }; + } + } + } } \ No newline at end of file diff --git a/app/resources/main.css b/app/resources/main.css new file mode 100644 index 0000000..9d9abb0 --- /dev/null +++ b/app/resources/main.css @@ -0,0 +1,12 @@ +headerbar entry, +headerbar spinbutton, +headerbar button, +headerbar separator { + margin-top: 0px; + margin-bottom: 0px; + font-weight: bold; +} + +headerbar { + min-height: 1.5em; +} \ No newline at end of file diff --git a/app/resources/resources.gresource.xml b/app/resources/resources.gresource.xml index adb1933..a81c70d 100644 --- a/app/resources/resources.gresource.xml +++ b/app/resources/resources.gresource.xml @@ -1,6 +1,8 @@ - main.ui + main.ui + icon.svg + main.css \ No newline at end of file diff --git a/app/src/main.rs b/app/src/main.rs index 06a9c62..edf76bf 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -1,35 +1,35 @@ +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +mod modules; +mod utils; +mod widgets; + use gtk::prelude::*; use gtk::{gio, glib}; -use window::Window; +use widgets::Application; -static APP_ID: &str = "org.gtk_rs.Todo5"; +static APP_ID: &str = "me.workingrobot.l4"; -// ANCHOR: main fn main() -> glib::ExitCode { - gio::resources_register_include!("L4.gresource").expect("Failed to register resources."); + //#[cfg(debug_assertions)] + // Cairo is enabled for faster launch times + //std::env::set_var("GSK_RENDERER", "cairo"); - // Create a new application - // 👇 changed - let app = adw::Application::builder().application_id(APP_ID).build(); + std::env::set_var("GTK_DEBUG", "interactive"); - // Connect to signals - app.connect_startup(setup_shortcuts); - app.connect_activate(build_ui); + gio::resources_register_include!("Sweet.gresource").expect("Failed to register theme"); + gio::resources_register_include!("Sweet-Ambar.gresource").expect("Failed to register theme"); + gio::resources_register_include!("Sweet-Ambar-Blue.gresource") + .expect("Failed to register theme"); + gio::resources_register_include!("Sweet-Dark.gresource").expect("Failed to register theme"); + gio::resources_register_include!("Sweet-Mars.gresource").expect("Failed to register theme"); + gio::resources_register_include!("L4.gresource").expect("Failed to register app resources"); - // Run the application - app.run() -} - -// 👇 changed -fn setup_shortcuts(app: &adw::Application) { - app.set_accels_for_action("win.filter('All')", &["a"]); - app.set_accels_for_action("win.filter('Open')", &["o"]); - app.set_accels_for_action("win.filter('Done')", &["d"]); -} - -// 👇 changed -fn build_ui(app: &adw::Application) { - // Create a new custom window and show it - let window = Window::new(app); - window.show(); + gtk::init().expect("Failed to initialize GTK"); + adw::init().expect("Failed to initialize LibAdwaita"); + + glib::set_application_name("L4"); + glib::set_program_name(Some("L4")); + + Application::new().with_application_id(APP_ID).run() } diff --git a/app/src/modules/mod.rs b/app/src/modules/mod.rs new file mode 100644 index 0000000..f7c55bc --- /dev/null +++ b/app/src/modules/mod.rs @@ -0,0 +1,8 @@ +mod module; +mod theme_picker; + +pub use module::Module; +pub use module::ModuleCtx; +pub use module::ModuleList; + +pub use theme_picker::ThemePicker; diff --git a/app/src/modules/module.rs b/app/src/modules/module.rs new file mode 100644 index 0000000..aee843b --- /dev/null +++ b/app/src/modules/module.rs @@ -0,0 +1,54 @@ +use gtk::prelude::*; +use gtk::Builder; +use gtk::{gdk, glib, IconTheme}; +use std::cell::RefCell; +use std::rc::Rc; + +pub trait ModuleCtx { + fn try_get_object>(&self, name: &'static str) -> Option; + + fn get_object>(&self, name: &'static str) -> T { + self.try_get_object(name) + .expect(format!("Failed to get object {}", name).as_str()) + } +} + +pub trait Module { + fn new(ctx: &impl ModuleCtx) -> Rc> + where + Self: Sized; +} + +pub struct ModuleList { + builder: Builder, + modules: Vec>>, +} + +impl ModuleCtx for ModuleList { + fn try_get_object>(&self, name: &'static str) -> Option { + self.builder.object(name) + } +} + +impl Default for ModuleList { + fn default() -> Self { + Self::new() + } +} + +impl ModuleList { + pub fn new() -> Self { + let display = gdk::Display::default().expect("Could not get a display"); + let icon_theme = IconTheme::for_display(&display); + icon_theme.add_resource_path("/me/workingrobot/l4"); + + Self { + builder: Builder::from_resource("/me/workingrobot/l4/main.ui"), + modules: vec![], + } + } + + pub fn add(&mut self) { + self.modules.push(T::new(self)); + } +} diff --git a/app/src/modules/theme_picker.rs b/app/src/modules/theme_picker.rs new file mode 100644 index 0000000..f19e5a9 --- /dev/null +++ b/app/src/modules/theme_picker.rs @@ -0,0 +1,65 @@ +use super::{Module, ModuleCtx}; +use gtk::gdk; +use std::cell::RefCell; +use std::rc::Rc; + +pub struct ThemePicker { + provider: gtk::CssProvider, +} + +impl ThemePicker { + fn set_theme(&self, theme_idx: u32) { + return; + let theme_name = match theme_idx { + 0 => "Sweet", + 1 => "Sweet-Dark", + 2 => "Sweet-Mars", + 3 => "Sweet-Ambar", + 4 => "Sweet-Ambar-Blue", + _ => todo!(), + }; + + self.provider.load_from_resource( + format!("/org/gtk/libgtk/theme/{theme_name}/gtk-dark.css").as_str(), + ); + } +} + +impl Module for ThemePicker { + fn new(ctx: &impl ModuleCtx) -> Rc> { + gtk::Settings::default() + .unwrap() + .set_gtk_theme_name(Some("Sweet-Dark")); + + let this = Self { + provider: gtk::CssProvider::new(), + }; + + let display = gdk::Display::default().expect("Could not get a display"); + this.provider.connect_parsing_error(|_, section, error| { + panic!("Could not parse css data ({} at {})", error, section); + }); + + #[allow(deprecated)] + // add_provider_for_display isn't actually deprecated, but the rest of StyleContext is + gtk::StyleContext::add_provider_for_display( + &display, + &this.provider, + gtk::STYLE_PROVIDER_PRIORITY_THEME, + ); + + this.set_theme(0); + + let this = Rc::new(RefCell::new(this)); + + let dropdown = ctx.get_object::("theme_dropdown"); + let this_clone = this.clone(); + dropdown.connect_selected_notify(move |drop| { + if drop.selected() != gtk::INVALID_LIST_POSITION { + this_clone.borrow().set_theme(drop.selected()); + } + }); + + this + } +} diff --git a/app/src/utils/dpi.rs b/app/src/utils/dpi.rs new file mode 100644 index 0000000..3354db5 --- /dev/null +++ b/app/src/utils/dpi.rs @@ -0,0 +1,19 @@ +use gdk4_win32::prelude::*; +use gdk4_win32::Win32Surface; +use gtk::{traits::NativeExt, Native}; +use windows::Win32::Foundation::HWND; +use windows::Win32::UI::HiDpi::GetDpiForWindow; + +pub trait UsesDpi: IsA { + fn get_dpi(&self) -> Option; +} + +impl UsesDpi for T +where + T: IsA, +{ + fn get_dpi(&self) -> Option { + let hwnd = HWND(self.surface().downcast_ref::()?.handle().0); + unsafe { Some(GetDpiForWindow(hwnd)) } + } +} diff --git a/app/src/utils/mod.rs b/app/src/utils/mod.rs new file mode 100644 index 0000000..b39b3ed --- /dev/null +++ b/app/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod dpi; diff --git a/app/src/widgets/application/imp.rs b/app/src/widgets/application/imp.rs new file mode 100644 index 0000000..2217592 --- /dev/null +++ b/app/src/widgets/application/imp.rs @@ -0,0 +1,73 @@ +use crate::modules::{ModuleCtx, ModuleList, ThemePicker}; + +use crate::utils::dpi::UsesDpi; +use adw::subclass::prelude::*; +use gtk::{gdk, glib, prelude::Cast, traits::GtkWindowExt}; +use std::cell::RefCell; +use std::rc::Rc; + +#[derive(Default)] +pub struct Application { + modules: Rc>, +} + +#[glib::object_subclass] +impl ObjectSubclass for Application { + const NAME: &'static str = "L4Application"; + type Type = super::Application; + type ParentType = adw::Application; +} + +impl ObjectImpl for Application {} + +impl ApplicationImpl for Application { + fn startup(&self) { + self.parent_startup(); + + let manager = adw::StyleManager::default(); + manager.set_color_scheme(adw::ColorScheme::ForceDark); + + let display = gdk::Display::default().expect("Could not get a display"); + + let provider = gtk::CssProvider::new(); + provider.connect_parsing_error(|_, section, error| { + panic!("Could not parse css data ({} at {})", error, section); + }); + provider.load_from_resource("/me/workingrobot/l4/main.css"); + + #[allow(deprecated)] + // add_provider_for_display isn't actually deprecated, but the rest of StyleContext is + gtk::StyleContext::add_provider_for_display( + &display, + &provider, + gtk::STYLE_PROVIDER_PRIORITY_APPLICATION, + ); + + let window = self + .modules + .borrow() + .get_object::("window"); + + window.set_application(Some(self.obj().upcast_ref::())); + } + + fn activate(&self) { + self.parent_activate(); + + let window = self + .modules + .borrow() + .get_object::("window"); + window.minimize(); + window.present(); + + let settings = gtk::Settings::default().expect("Could not get default settings"); + settings.set_gtk_xft_dpi(window.get_dpi().unwrap_or(96) as i32 * 1024); + + self.modules.borrow_mut().add::(); + } +} + +impl GtkApplicationImpl for Application {} + +impl AdwApplicationImpl for Application {} diff --git a/app/src/widgets/application/mod.rs b/app/src/widgets/application/mod.rs new file mode 100644 index 0000000..f849dbd --- /dev/null +++ b/app/src/widgets/application/mod.rs @@ -0,0 +1,28 @@ +mod imp; + +use glib::Object; +use gtk::{gio, glib}; + +glib::wrapper! { + pub struct Application(ObjectSubclass) + @extends adw::Application, gtk::Application, gio::Application, + @implements gio::ActionGroup, gio::ActionMap; +} + +impl Application { + pub fn new() -> Self { + Object::builder().build() + } + + pub fn with_application_id(&self, application_id: &str) -> Self { + Object::builder() + .property("application-id", application_id) + .build() + } +} + +impl Default for Application { + fn default() -> Self { + Self::new() + } +} diff --git a/app/src/widgets/mod.rs b/app/src/widgets/mod.rs new file mode 100644 index 0000000..68264e2 --- /dev/null +++ b/app/src/widgets/mod.rs @@ -0,0 +1,3 @@ +mod application; + +pub use application::Application;