From 2b5395f628dc6e1e9fb922261ba417c6f7816118 Mon Sep 17 00:00:00 2001 From: keifufu Date: Sat, 12 Aug 2023 03:05:25 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + Cargo.lock | 1234 +++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 11 + README.md | 16 + rustfmt.toml | 1 + src/config.yaml | 14 + src/main.rs | 314 ++++++++++++ 7 files changed, 1591 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 rustfmt.toml create mode 100644 src/config.yaml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..f743f76 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1234 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anyhow" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" + +[[package]] +name = "atk" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39991bc421ddf72f70159011b323ff49b0f783cc676a7287c59453da2e2531cf" +dependencies = [ + "atk-sys", + "bitflags", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ad703eb64dc058024f0e57ccfa069e15a413b98dbd50a1a950e743b7f11148" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "cairo-rs" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3125b15ec28b84c238f6f476c6034016a5f6cc0221cb514ca46c532139fc97d" +dependencies = [ + "bitflags", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48f4af05fabdcfa9658178e1326efa061853f040ce7d72e33af6885196f421" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "cfg-expr" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types 0.5.0", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" +dependencies = [ + "bitflags", + "block", + "core-foundation", + "core-graphics-types", + "foreign-types 0.3.2", + "libc", + "objc", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "core-graphics" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" +dependencies = [ + "bitflags", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +dependencies = [ + "bitflags", + "core-foundation", + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cute-borders" +version = "0.1.0" +dependencies = [ + "lazy_static", + "serde", + "serde_yaml", + "tray-icon", + "winapi", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "gdk" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9cb33da481c6c040404a11f8212d193889e9b435db2c14fd86987f630d3ce1" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3578c60dee9d029ad86593ed88cb40f35c1b83360e12498d055022385dd9a05" +dependencies = [ + "bitflags", + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3092cf797a5f1210479ea38070d9ae8a5b8e9f8f1be9f32f4643c529c7d70016" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76354f97a913e55b984759a997b693aa7dc71068c9e98bcce51aa167a0a5c5a" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gio" +version = "0.16.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a1c84b4534a290a29160ef5c6eff2a9c95833111472e824fc5cb78b513dd092" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror", +] + +[[package]] +name = "gio-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b693b8e39d042a95547fc258a7b07349b1f0b48f4b2fa3108ba3c51c0b5229" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16aa2475c9debed5a32832cb5ff2af5a3f9e1ab9e69df58eaadc1ab2004d6eba" +dependencies = [ + "bitflags", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "once_cell", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1a9325847aa46f1e96ffea37611b9d51fc4827e67f79e7de502a297560a67b" +dependencies = [ + "anyhow", + "heck", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "glib-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61a4f46316d06bfa33a7ac22df6f0524c8be58e3db2d9ca99ccb1f357b62a65" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3520bb9c07ae2a12c7f2fbb24d4efc11231c8146a86956413fb1a79bb760a0f1" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4d3507d43908c866c805f74c9dd593c0ce7ba5c38e576e41846639cdcd4bee6" +dependencies = [ + "atk", + "bitflags", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "once_cell", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b5f8946685d5fe44497007786600c2f368ff6b1e61a16251c89f72a97520a3" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "096eb63c6fedf03bafe65e5924595785eaf1bcb7200dac0f2cbe9c9738f05ad8" +dependencies = [ + "anyhow", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "keyboard-types" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7668b7cff6a51fe61cdde64cd27c8a220786f399501b57ebe36f7d8112fd68" +dependencies = [ + "bitflags", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libappindicator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e1edfdc9b0853358306c6dfb4b77c79c779174256fe93d80c0b5ebca451a2f" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08fcb2bea89cee9613982501ec83eaa2d09256b24540ae463c52a28906163918" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libxdo" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00333b8756a3d28e78def82067a377de7fa61b24909000aeaa2b446a948d14db" +dependencies = [ + "libxdo-sys", +] + +[[package]] +name = "libxdo-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212" +dependencies = [ + "libc", + "x11", +] + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "muda" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e33f46fb20f85553edb85e30a6a5231567f4103276ccdb5a2050613d253b1d" +dependencies = [ + "cocoa", + "crossbeam-channel", + "gdk", + "gdk-pixbuf", + "gtk", + "keyboard-types", + "libxdo", + "objc", + "once_cell", + "png", + "thiserror", + "windows-sys", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "pango" +version = "0.16.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdff66b271861037b89d028656184059e03b0b6ccb36003820be19f7200b1e94" +dependencies = [ + "bitflags", + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e134909a9a293e04d2cc31928aa95679c5e4df954d0b85483159bd20d8f047f" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "png" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall", + "thiserror", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + +[[package]] +name = "serde" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-deps" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "target-lexicon" +version = "0.12.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" + +[[package]] +name = "thiserror" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.28", +] + +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tray-icon" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b0e5bec13da15e62330e9bcf8b9fd42489b5acfe29ac8fec7ed659dbee21d9" +dependencies = [ + "cocoa", + "core-graphics", + "crossbeam-channel", + "dirs-next", + "libappindicator", + "muda", + "objc", + "once_cell", + "png", + "thiserror", + "windows-sys", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +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", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5504cc7644f4b593cbc05c4a55bf9bd4e94b867c3c0bd440934174d50482427d" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b505a34 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "cute-borders" +version = "0.1.0" +edition = "2021" + +[dependencies] +lazy_static = "1.4.0" +serde = "1.0.183" +serde_yaml = "0.9.25" +tray-icon = "0.8.1" +winapi = { version = "0.3.9", features = ["winuser", "dwmapi", "wincon", "shellapi"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..4d72430 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# cute borders + +idk, description? only works on win11 + +## Preview + +soon + +## Settings + +soon + +# TODO + +- tray icon (currently fucking invisible) +- run_at_startup diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..6f2e075 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +tab_spaces = 2 \ No newline at end of file diff --git a/src/config.yaml b/src/config.yaml new file mode 100644 index 0000000..5190802 --- /dev/null +++ b/src/config.yaml @@ -0,0 +1,14 @@ +run_at_startup: false +window_rules: + - match: "Global" + active_border_color: "#c6a0f6" + inactive_border_color: "#ffffff" + # Example rules + - match: "Title" + contains: "Mozilla Firefox" + active_border_color: "#c6a0f6" + inactive_border_color: "#fffff" + - match: "Class" + contains: "MozillaWindowClass" + active_border_color: "#c6a0f6" + inactive_border_color: "#ffffff" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..9160345 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,314 @@ +#![windows_subsystem = "windows"] + +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use std::ffi::c_ulong; +use std::ffi::OsString; +use std::fs; +use std::io::Write; +use std::os::windows::prelude::OsStringExt; +use std::path::Path; +use std::sync::Mutex; +use tray_icon::menu::Menu; +use tray_icon::menu::MenuEvent; +use tray_icon::menu::MenuId; +use tray_icon::menu::MenuItemBuilder; +use tray_icon::TrayIconBuilder; +use winapi::ctypes::c_int; +use winapi::ctypes::c_void; +use winapi::shared::minwindef::{BOOL, DWORD, LPARAM}; +use winapi::shared::windef::{HWINEVENTHOOK__, HWND}; +use winapi::um::dwmapi::DwmSetWindowAttribute; +use winapi::um::winuser::EnumWindows; +use winapi::um::winuser::GetClassNameW; +use winapi::um::winuser::GetWindowTextLengthW; +use winapi::um::winuser::GetWindowTextW; +use winapi::um::winuser::WS_EX_TOOLWINDOW; +use winapi::um::winuser::{ + DispatchMessageW, GetForegroundWindow, GetMessageW, IsWindowVisible, SetWinEventHook, + TranslateMessage, UnhookWinEvent, EVENT_OBJECT_CREATE, EVENT_OBJECT_DESTROY, + EVENT_SYSTEM_FOREGROUND, GWL_EXSTYLE, WINEVENT_OUTOFCONTEXT, +}; + +const DWMWA_BORDER_COLOR: u32 = 34; +const DWMWA_COLOR_DEFAULT: u32 = 0xFFFFFFFF; +const DEFAULT_CONFIG: &str = include_str!("config.yaml"); +lazy_static! { + static ref CONFIG: Mutex = Mutex::new(Config::read()); +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +// Maybe support Process later. +// Getting the process name seems annoying. +enum RuleMatch { + Global, + Title, + Class, +} + +#[derive(Debug, Serialize, Deserialize)] +struct WindowRule { + #[serde(rename = "match")] + rule_match: RuleMatch, + contains: Option, + active_border_color: String, + inactive_border_color: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Config { + run_at_startup: bool, + window_rules: Vec, +} + +impl Config { + fn read() -> Self { + let user_profile = + std::env::var("USERPROFILE").expect("USERPROFILE environment variable not found"); + let config_dir = format!("{}\\.cuteborders", user_profile); + let config_file = format!("{}\\config.yaml", config_dir); + + if !Path::new(&config_dir).exists() { + fs::create_dir(&config_dir).expect("Failed to create directory"); + } + + if !Path::new(&config_file).exists() { + let mut file = fs::File::create(&config_file).expect("Failed to create config file"); + file + .write_all(DEFAULT_CONFIG.as_bytes()) + .expect("Failed to write to config file"); + } + + let contents = fs::read_to_string(&config_file).expect("Failed to read config"); + + let config: Config = serde_yaml::from_str(contents.as_str()).expect("Failed to parse config"); + config + } + fn reload() { + let mut config = CONFIG.lock().unwrap(); + *config = Self::read(); + } +} + +fn main() { + unsafe { + let create_hook = SetWinEventHook( + EVENT_OBJECT_CREATE, + EVENT_OBJECT_DESTROY, + std::ptr::null_mut(), + Some(create_window_event), + 0, + 0, + WINEVENT_OUTOFCONTEXT, + ); + + let foreground_hook = SetWinEventHook( + EVENT_SYSTEM_FOREGROUND, + EVENT_SYSTEM_FOREGROUND, + std::ptr::null_mut(), + Some(foreground_event), + 0, + 0, + WINEVENT_OUTOFCONTEXT, + ); + + if create_hook.is_null() || foreground_hook.is_null() { + panic!("Error setting up hooks"); + } + + let tray_menu = Menu::with_items(&[ + &MenuItemBuilder::new() + .text("Reload config") + .enabled(true) + .id(MenuId::new("1")) + .build(), + &MenuItemBuilder::new() + .text("Exit") + .enabled(true) + .id(MenuId::new("2")) + .build(), + ]) + .unwrap(); + #[allow(unused_variables)] + let tray_icon = TrayIconBuilder::new() + .with_menu(Box::new(tray_menu)) + .with_menu_on_left_click(true) + .build() + .unwrap(); + + MenuEvent::set_event_handler(Some(|event: MenuEvent| { + if event.id == MenuId::new("1") { + Config::reload(); + apply_colors(false); + } else if event.id == MenuId::new("2") { + apply_colors(true); + std::process::exit(0); + } + })); + + let mut msg = std::mem::zeroed(); + while GetMessageW(&mut msg, std::ptr::null_mut(), 0, 0) != 0 { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + UnhookWinEvent(create_hook); + UnhookWinEvent(foreground_hook); + apply_colors(true); + } +} + +unsafe extern "system" fn create_window_event( + _h_win_event_hook: *mut HWINEVENTHOOK__, + event: DWORD, + _hwnd: HWND, + _id_object: i32, + _id_child: i32, + _id_event_thread: DWORD, + _dwms_event_time: DWORD, +) { + if event == EVENT_OBJECT_CREATE || event == EVENT_OBJECT_DESTROY { + apply_colors(false); + } +} + +unsafe extern "system" fn foreground_event( + _h_win_event_hook: *mut HWINEVENTHOOK__, + _event: DWORD, + _hwnd: HWND, + _id_object: i32, + _id_child: i32, + _id_event_thread: DWORD, + _dwms_event_time: DWORD, +) { + apply_colors(false); +} + +fn get_colors_for_window(_hwnd: HWND, title: String, class: String, reset: bool) -> (u32, u32) { + if reset { + return (DWMWA_COLOR_DEFAULT, DWMWA_COLOR_DEFAULT); + } + + let config = CONFIG.lock().unwrap(); + let mut color_active = DWMWA_COLOR_DEFAULT; + let mut color_inactive = DWMWA_COLOR_DEFAULT; + + for rule in config.window_rules.iter() { + match rule.rule_match { + RuleMatch::Global => { + color_active = hex_to_colorref(&rule.active_border_color).expect("Failed to convert hex"); + color_inactive = + hex_to_colorref(&rule.inactive_border_color).expect("Failed to convert hex"); + } + RuleMatch::Title => { + if let Some(contains_str) = &rule.contains { + if title.to_lowercase().contains(&contains_str.to_lowercase()) { + color_active = + hex_to_colorref(&rule.active_border_color).expect("Failed to convert hex"); + color_inactive = + hex_to_colorref(&rule.inactive_border_color).expect("Failed to convert hex"); + break; + } + } else { + panic!("Expected 'rule.contains' to be Some(value)"); + } + } + RuleMatch::Class => { + if let Some(contains_str) = &rule.contains { + if class.to_lowercase().contains(&contains_str.to_lowercase()) { + color_active = + hex_to_colorref(&rule.active_border_color).expect("Failed to convert hex"); + color_inactive = + hex_to_colorref(&rule.inactive_border_color).expect("Failed to convert hex"); + break; + } + } else { + panic!("Expected 'rule.contains' to be Some(value)"); + } + } + } + } + + (color_active, color_inactive) +} + +fn apply_colors(reset: bool) { + let mut visible_windows: Vec<(HWND, String, String)> = Vec::new(); + unsafe { + EnumWindows( + Some(enum_windows_callback), + &mut visible_windows as *mut _ as LPARAM, + ); + } + + for (hwnd, title, class) in visible_windows { + let (color_active, color_inactive) = get_colors_for_window(hwnd, title, class, reset); + unsafe { + let active = GetForegroundWindow(); + + if active == hwnd { + DwmSetWindowAttribute( + hwnd, + DWMWA_BORDER_COLOR, + &color_active as *const _ as *const c_void, + std::mem::size_of::() as u32, + ); + } else { + DwmSetWindowAttribute( + hwnd, + DWMWA_BORDER_COLOR, + &color_inactive as *const _ as *const c_void, + std::mem::size_of::() as u32, + ); + } + } + } +} + +unsafe extern "system" fn enum_windows_callback(hwnd: HWND, lparam: LPARAM) -> BOOL { + if IsWindowVisible(hwnd) != 0 { + let mut title_buffer: [u16; 512] = [0; 512]; + let text_length = GetWindowTextLengthW(hwnd) + 1; + if text_length > 0 { + GetWindowTextW(hwnd, title_buffer.as_mut_ptr(), text_length as c_int); + } + let title = OsString::from_wide(&title_buffer) + .to_string_lossy() + .into_owned(); + + let ex_style = winapi::um::winuser::GetWindowLongW(hwnd, GWL_EXSTYLE) as c_int; + + let mut class_buffer: [u16; 256] = [0; 256]; + let result = GetClassNameW(hwnd, class_buffer.as_mut_ptr(), class_buffer.len() as c_int); + let mut class_name = String::new(); + if result > 0 { + class_name = OsString::from_wide(&class_buffer) + .to_string_lossy() + .into_owned(); + } + + // Exclude certain window styles like WS_EX_TOOLWINDOW + if ex_style & (WS_EX_TOOLWINDOW as i32) == 0 { + let visible_windows: &mut Vec<(HWND, String, String)> = + &mut *(lparam as *mut Vec<(HWND, String, String)>); + visible_windows.push((hwnd, title, class_name)); + } + } + + 1 +} + +fn hex_to_colorref(hex: &str) -> Option { + if hex.len() != 7 || !hex.starts_with('#') { + return None; // Invalid format + } + + let r = u8::from_str_radix(&hex[1..3], 16); + let g = u8::from_str_radix(&hex[3..5], 16); + let b = u8::from_str_radix(&hex[5..7], 16); + + match (r, g, b) { + (Ok(r), Ok(g), Ok(b)) => Some((b as u32) << 16 | (g as u32) << 8 | r as u32), + _ => None, // Invalid component values + } +}