diff --git a/.gitignore b/.gitignore
index 11c6ec9..dc886ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,4 @@ xcuserdata
target/
.DS_STORE
-.idea/
\ No newline at end of file
+.idea/
diff --git a/burrow-gtk/Cargo.lock b/burrow-gtk/Cargo.lock
new file mode 100644
index 0000000..4e87651
--- /dev/null
+++ b/burrow-gtk/Cargo.lock
@@ -0,0 +1,897 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
+
+[[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 = "burrow-gtk"
+version = "0.1.0"
+dependencies = [
+ "gettext-rs",
+ "gtk4",
+ "libadwaita",
+]
+
+[[package]]
+name = "cairo-rs"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a"
+dependencies = [
+ "bitflags",
+ "cairo-sys-rs",
+ "glib",
+ "libc",
+ "once_cell",
+ "thiserror",
+]
+
+[[package]]
+name = "cairo-sys-rs"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "691d0c66b1fb4881be80a760cb8fe76ea97218312f9dfe2c9cc0f496ca279cb1"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+
+[[package]]
+name = "cfg-expr"
+version = "0.15.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "215c0072ecc28f92eeb0eea38ba63ddfcb65c2828c46311d646f1a3ff5f9841c"
+dependencies = [
+ "smallvec",
+ "target-lexicon",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
+
+[[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 = "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.22",
+]
+
+[[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-pixbuf"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "695d6bc846438c5708b07007537b9274d883373dd30858ca881d7d71b5540717"
+dependencies = [
+ "bitflags",
+ "gdk-pixbuf-sys",
+ "gio",
+ "glib",
+ "libc",
+ "once_cell",
+]
+
+[[package]]
+name = "gdk-pixbuf-sys"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9285ec3c113c66d7d0ab5676599176f1f42f4944ca1b581852215bf5694870cb"
+dependencies = [
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gdk4"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3abf96408a26e3eddf881a7f893a1e111767137136e347745e8ea6ed12731ff"
+dependencies = [
+ "bitflags",
+ "cairo-rs",
+ "gdk-pixbuf",
+ "gdk4-sys",
+ "gio",
+ "glib",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gdk4-sys"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc92aa1608c089c49393d014c38ac0390d01e4841e1fedaa75dbcef77aaed64"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "pango-sys",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gettext-rs"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e49ea8a8fad198aaa1f9655a2524b64b70eb06b2f3ff37da407566c93054f364"
+dependencies = [
+ "gettext-sys",
+ "locale_config",
+]
+
+[[package]]
+name = "gettext-sys"
+version = "0.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c63ce2e00f56a206778276704bbe38564c8695249fdc8f354b4ef71c57c3839d"
+dependencies = [
+ "cc",
+ "temp-dir",
+]
+
+[[package]]
+name = "gio"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6973e92937cf98689b6a054a9e56c657ed4ff76de925e36fc331a15f0c5d30a"
+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.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ccf87c30a12c469b6d958950f6a9c09f2be20b7773f7e70d20b867fdf2628c3"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+ "winapi",
+]
+
+[[package]]
+name = "glib"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3fad45ba8d4d2cea612b432717e834f48031cd8853c8aaf43b2c79fec8d144b"
+dependencies = [
+ "bitflags",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-task",
+ "futures-util",
+ "gio-sys",
+ "glib-macros",
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "memchr",
+ "once_cell",
+ "smallvec",
+ "thiserror",
+]
+
+[[package]]
+name = "glib-macros"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eca5c79337338391f1ab8058d6698125034ce8ef31b72a442437fa6c8580de26"
+dependencies = [
+ "anyhow",
+ "heck",
+ "proc-macro-crate",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "glib-sys"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d80aa6ea7bba0baac79222204aa786a6293078c210abe69ef1336911d4bdc4f0"
+dependencies = [
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "gobject-sys"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd34c3317740a6358ec04572c1bcfd3ac0b5b6529275fae255b237b314bb8062"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "graphene-rs"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "def4bb01265b59ed548b05455040d272d989b3012c42d4c1bbd39083cb9b40d9"
+dependencies = [
+ "glib",
+ "graphene-sys",
+ "libc",
+]
+
+[[package]]
+name = "graphene-sys"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1856fc817e6a6675e36cea0bd9a3afe296f5d9709d1e2d3182803ac77f0ab21d"
+dependencies = [
+ "glib-sys",
+ "libc",
+ "pkg-config",
+ "system-deps",
+]
+
+[[package]]
+name = "gsk4"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f01ef44fa7cac15e2da9978529383e6bee03e570ba5bf7036b4c10a15cc3a3c"
+dependencies = [
+ "bitflags",
+ "cairo-rs",
+ "gdk4",
+ "glib",
+ "graphene-rs",
+ "gsk4-sys",
+ "libc",
+ "pango",
+]
+
+[[package]]
+name = "gsk4-sys"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c07a84fb4dcf1323d29435aa85e2f5f58bef564342bef06775ec7bd0da1f01b0"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk4-sys",
+ "glib-sys",
+ "gobject-sys",
+ "graphene-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "gtk4"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b28a32a04cd75cef14a0983f8b0c669e0fe152a0a7725accdeb594e2c764c88b"
+dependencies = [
+ "bitflags",
+ "cairo-rs",
+ "field-offset",
+ "futures-channel",
+ "gdk-pixbuf",
+ "gdk4",
+ "gio",
+ "glib",
+ "graphene-rs",
+ "gsk4",
+ "gtk4-macros",
+ "gtk4-sys",
+ "libc",
+ "once_cell",
+ "pango",
+]
+
+[[package]]
+name = "gtk4-macros"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a4d6b61570f76d3ee542d984da443b1cd69b6105264c61afec3abed08c2500f"
+dependencies = [
+ "anyhow",
+ "proc-macro-crate",
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "gtk4-sys"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f8283f707b07e019e76c7f2934bdd4180c277e08aa93f4c0d8dd07b7a34e22f"
+dependencies = [
+ "cairo-sys-rs",
+ "gdk-pixbuf-sys",
+ "gdk4-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "graphene-sys",
+ "gsk4-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[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 = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libadwaita"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1c4efd2020a4fcedbad2c4a97de97bf6045e5dc49d61d5a5d0cfd753db60700"
+dependencies = [
+ "bitflags",
+ "futures-channel",
+ "gdk-pixbuf",
+ "gdk4",
+ "gio",
+ "glib",
+ "gtk4",
+ "libadwaita-sys",
+ "libc",
+ "once_cell",
+ "pango",
+]
+
+[[package]]
+name = "libadwaita-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0727b85b4fe2b1bed5ac90df6343de15cbf8118bfb96d7c3cc1512681a4b34ac"
+dependencies = [
+ "gdk4-sys",
+ "gio-sys",
+ "glib-sys",
+ "gobject-sys",
+ "gtk4-sys",
+ "libc",
+ "pango-sys",
+ "system-deps",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.147"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
+
+[[package]]
+name = "locale_config"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d2c35b16f4483f6c26f0e4e9550717a2f6575bcd6f12a53ff0c490a94a6934"
+dependencies = [
+ "lazy_static",
+ "objc",
+ "objc-foundation",
+ "regex",
+ "winapi",
+]
+
+[[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 = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+]
+
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
+[[package]]
+name = "objc_id"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+dependencies = [
+ "objc",
+]
+
+[[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.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35be456fc620e61f62dff7ff70fbd54dcbaf0a4b920c0f16de1107c47d921d48"
+dependencies = [
+ "bitflags",
+ "gio",
+ "glib",
+ "libc",
+ "once_cell",
+ "pango-sys",
+]
+
+[[package]]
+name = "pango-sys"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3da69f9f3850b0d8990d462f8c709561975e95f689c1cdf0fecdebde78b35195"
+dependencies = [
+ "glib-sys",
+ "gobject-sys",
+ "libc",
+ "system-deps",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+
+[[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 = "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.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+
+[[package]]
+name = "serde"
+version = "1.0.164"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+dependencies = [
+ "serde",
+]
+
+[[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.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[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.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
+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.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1c7f239eb94671427157bd93b3694320f3668d4e1eff08c7285366fd777fac"
+
+[[package]]
+name = "temp-dir"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab"
+
+[[package]]
+name = "thiserror"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.22",
+]
+
+[[package]]
+name = "toml"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240"
+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.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+
+[[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 = "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 = "winnow"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448"
+dependencies = [
+ "memchr",
+]
diff --git a/burrow-gtk/Cargo.toml b/burrow-gtk/Cargo.toml
new file mode 100644
index 0000000..7243745
--- /dev/null
+++ b/burrow-gtk/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "burrow-gtk"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+gettext-rs = { version = "0.7", features = ["gettext-system"] }
+gtk = { version = "0.6", package = "gtk4" }
+
+[dependencies.adw]
+package = "libadwaita"
+version = "0.3"
+features = ["v1_2"]
diff --git a/burrow-gtk/README.md b/burrow-gtk/README.md
new file mode 100644
index 0000000..93c1d95
--- /dev/null
+++ b/burrow-gtk/README.md
@@ -0,0 +1,3 @@
+# burrow-gtk
+
+A description of this project.
diff --git a/burrow-gtk/com.hackclub.Burrow.json b/burrow-gtk/com.hackclub.Burrow.json
new file mode 100644
index 0000000..081096b
--- /dev/null
+++ b/burrow-gtk/com.hackclub.Burrow.json
@@ -0,0 +1,51 @@
+{
+ "app-id" : "com.hackclub.Burrow",
+ "runtime" : "org.gnome.Platform",
+ "runtime-version" : "44",
+ "sdk" : "org.gnome.Sdk",
+ "sdk-extensions" : [
+ "org.freedesktop.Sdk.Extension.rust-stable"
+ ],
+ "command" : "burrow-gtk",
+ "finish-args" : [
+ "--share=network",
+ "--share=ipc",
+ "--socket=fallback-x11",
+ "--device=dri",
+ "--socket=wayland"
+ ],
+ "build-options" : {
+ "append-path" : "/usr/lib/sdk/rust-stable/bin",
+ "build-args" : [
+ "--share=network"
+ ],
+ "env" : {
+ "RUST_BACKTRACE" : "1",
+ "RUST_LOG" : "burrow-gtk=debug"
+ }
+ },
+ "cleanup" : [
+ "/include",
+ "/lib/pkgconfig",
+ "/man",
+ "/share/doc",
+ "/share/gtk-doc",
+ "/share/man",
+ "/share/pkgconfig",
+ "*.la",
+ "*.a"
+ ],
+ "modules" : [
+ {
+ "name" : "burrow-gtk",
+ "builddir" : true,
+ "buildsystem" : "meson",
+ "sources" : [
+ {
+ "type" : "git",
+ "url" : "file:///var/home/reesericci/Code"
+ }
+ ]
+ }
+ ]
+}
diff --git a/burrow-gtk/data/com.hackclub.Burrow.appdata.xml.in b/burrow-gtk/data/com.hackclub.Burrow.appdata.xml.in
new file mode 100644
index 0000000..cbee29f
--- /dev/null
+++ b/burrow-gtk/data/com.hackclub.Burrow.appdata.xml.in
@@ -0,0 +1,8 @@
+
+
+ com.hackclub.Burrow.desktop
+ GPL-3.0-or-later
+
+ No description
+
+
diff --git a/burrow-gtk/data/com.hackclub.Burrow.desktop.in b/burrow-gtk/data/com.hackclub.Burrow.desktop.in
new file mode 100644
index 0000000..024d14e
--- /dev/null
+++ b/burrow-gtk/data/com.hackclub.Burrow.desktop.in
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Name=burrow-gtk
+Exec=burrow-gtk
+Icon=com.hackclub.Burrow
+Terminal=false
+Type=Application
+Categories=GTK;Network
+StartupNotify=true
diff --git a/burrow-gtk/data/com.hackclub.Burrow.gschema.xml b/burrow-gtk/data/com.hackclub.Burrow.gschema.xml
new file mode 100644
index 0000000..7121dfb
--- /dev/null
+++ b/burrow-gtk/data/com.hackclub.Burrow.gschema.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/burrow-gtk/data/icons/hicolor/scalable/apps/com.hackclub.Burrow.svg b/burrow-gtk/data/icons/hicolor/scalable/apps/com.hackclub.Burrow.svg
new file mode 100644
index 0000000..a74c4df
--- /dev/null
+++ b/burrow-gtk/data/icons/hicolor/scalable/apps/com.hackclub.Burrow.svg
@@ -0,0 +1,130 @@
+
+
diff --git a/burrow-gtk/data/icons/hicolor/symbolic/apps/com.hackclub.Burrow-symbolic.svg b/burrow-gtk/data/icons/hicolor/symbolic/apps/com.hackclub.Burrow-symbolic.svg
new file mode 100644
index 0000000..0444828
--- /dev/null
+++ b/burrow-gtk/data/icons/hicolor/symbolic/apps/com.hackclub.Burrow-symbolic.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/burrow-gtk/data/icons/meson.build b/burrow-gtk/data/icons/meson.build
new file mode 100644
index 0000000..4ee9744
--- /dev/null
+++ b/burrow-gtk/data/icons/meson.build
@@ -0,0 +1,13 @@
+application_id = 'com.hackclub.Burrow'
+
+scalable_dir = join_paths('hicolor', 'scalable', 'apps')
+install_data(
+ join_paths(scalable_dir, ('@0@.svg').format(application_id)),
+ install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir)
+)
+
+symbolic_dir = join_paths('hicolor', 'symbolic', 'apps')
+install_data(
+ join_paths(symbolic_dir, ('@0@-symbolic.svg').format(application_id)),
+ install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir)
+)
diff --git a/burrow-gtk/data/meson.build b/burrow-gtk/data/meson.build
new file mode 100644
index 0000000..4cca4a4
--- /dev/null
+++ b/burrow-gtk/data/meson.build
@@ -0,0 +1,39 @@
+desktop_file = i18n.merge_file(
+ input: 'com.hackclub.Burrow.desktop.in',
+ output: 'com.hackclub.Burrow.desktop',
+ type: 'desktop',
+ po_dir: '../po',
+ install: true,
+ install_dir: join_paths(get_option('datadir'), 'applications')
+)
+
+desktop_utils = find_program('desktop-file-validate', required: false)
+if desktop_utils.found()
+ test('Validate desktop file', desktop_utils, args: [desktop_file])
+endif
+
+appstream_file = i18n.merge_file(
+ input: 'com.hackclub.Burrow.appdata.xml.in',
+ output: 'com.hackclub.Burrow.appdata.xml',
+ po_dir: '../po',
+ install: true,
+ install_dir: join_paths(get_option('datadir'), 'appdata')
+)
+
+appstream_util = find_program('appstream-util', required: false)
+if appstream_util.found()
+ test('Validate appstream file', appstream_util, args: ['validate', appstream_file])
+endif
+
+install_data('com.hackclub.Burrow.gschema.xml',
+ install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
+)
+
+compile_schemas = find_program('glib-compile-schemas', required: false)
+if compile_schemas.found()
+ test('Validate schema file',
+ compile_schemas,
+ args: ['--strict', '--dry-run', meson.current_source_dir()])
+endif
+
+subdir('icons')
diff --git a/burrow-gtk/meson.build b/burrow-gtk/meson.build
new file mode 100644
index 0000000..3e9a026
--- /dev/null
+++ b/burrow-gtk/meson.build
@@ -0,0 +1,20 @@
+project('burrow-gtk', 'rust',
+ version: '0.1.0',
+ meson_version: '>= 0.62.0',
+ default_options: [ 'warning_level=2', 'werror=false', ],
+)
+
+i18n = import('i18n')
+gnome = import('gnome')
+
+
+
+subdir('data')
+subdir('src')
+subdir('po')
+
+gnome.post_install(
+ glib_compile_schemas: true,
+ gtk_update_icon_cache: true,
+ update_desktop_database: true,
+)
diff --git a/burrow-gtk/po/LINGUAS b/burrow-gtk/po/LINGUAS
new file mode 100644
index 0000000..e69de29
diff --git a/burrow-gtk/po/POTFILES b/burrow-gtk/po/POTFILES
new file mode 100644
index 0000000..d1acb5a
--- /dev/null
+++ b/burrow-gtk/po/POTFILES
@@ -0,0 +1,4 @@
+data/com.hackclub.Burrow.desktop.in
+data/com.hackclub.Burrow.appdata.xml.in
+data/com.hackclub.Burrow.gschema.xml
+src/window.ui
diff --git a/burrow-gtk/po/meson.build b/burrow-gtk/po/meson.build
new file mode 100644
index 0000000..4b239a8
--- /dev/null
+++ b/burrow-gtk/po/meson.build
@@ -0,0 +1 @@
+i18n.gettext('burrow-gtk', preset: 'glib')
diff --git a/burrow-gtk/src/application.rs b/burrow-gtk/src/application.rs
new file mode 100644
index 0000000..f511bae
--- /dev/null
+++ b/burrow-gtk/src/application.rs
@@ -0,0 +1,92 @@
+use gtk::prelude::*;
+use adw::subclass::prelude::*;
+use gtk::{gio, glib};
+
+use crate::config::VERSION;
+use crate::BurrowGtkWindow;
+
+mod imp {
+ use super::*;
+
+ #[derive(Debug, Default)]
+ pub struct BurrowGtkApplication {}
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for BurrowGtkApplication {
+ const NAME: &'static str = "BurrowGtkApplication";
+ type Type = super::BurrowGtkApplication;
+ type ParentType = adw::Application;
+ }
+
+ impl ObjectImpl for BurrowGtkApplication {
+ fn constructed(&self) {
+ self.parent_constructed();
+ let obj = self.obj();
+ obj.setup_gactions();
+ obj.set_accels_for_action("app.quit", &["q"]);
+ }
+ }
+
+ impl ApplicationImpl for BurrowGtkApplication {
+ // We connect to the activate callback to create a window when the application
+ // has been launched. Additionally, this callback notifies us when the user
+ // tries to launch a "second instance" of the application. When they try
+ // to do that, we'll just present any existing window.
+ fn activate(&self) {
+ let application = self.obj();
+ // Get the current window or create one if necessary
+ let window = if let Some(window) = application.active_window() {
+ window
+ } else {
+ let window = BurrowGtkWindow::new(&*application);
+ window.upcast()
+ };
+
+ // Ask the window manager/compositor to present the window
+ window.present();
+ }
+ }
+
+ impl GtkApplicationImpl for BurrowGtkApplication {}
+ impl AdwApplicationImpl for BurrowGtkApplication {}
+}
+
+glib::wrapper! {
+ pub struct BurrowGtkApplication(ObjectSubclass)
+ @extends gio::Application, gtk::Application, adw::Application,
+ @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl BurrowGtkApplication {
+ pub fn new(application_id: &str, flags: &gio::ApplicationFlags) -> Self {
+ glib::Object::builder()
+ .property("application-id", application_id)
+ .property("flags", flags)
+ .build()
+ }
+
+ fn setup_gactions(&self) {
+ let quit_action = gio::ActionEntry::builder("quit")
+ .activate(move |app: &Self, _, _| app.quit())
+ .build();
+ let about_action = gio::ActionEntry::builder("about")
+ .activate(move |app: &Self, _, _| app.show_about())
+ .build();
+ self.add_action_entries([quit_action, about_action]);
+ }
+
+ fn show_about(&self) {
+ let window = self.active_window().unwrap();
+ let about = adw::AboutWindow::builder()
+ .transient_for(&window)
+ .application_name("burrow-gtk")
+ .application_icon("com.hackclub.Burrow")
+ .developer_name("Hack Club")
+ .version(VERSION)
+ .developers(vec!["Hack Club"])
+ .copyright("© 2023 The Hack Foundation")
+ .build();
+
+ about.present();
+ }
+}
diff --git a/burrow-gtk/src/burrow-gtk.gresource.xml b/burrow-gtk/src/burrow-gtk.gresource.xml
new file mode 100644
index 0000000..23a5a82
--- /dev/null
+++ b/burrow-gtk/src/burrow-gtk.gresource.xml
@@ -0,0 +1,7 @@
+
+
+
+ window.ui
+ gtk/help-overlay.ui
+
+
diff --git a/burrow-gtk/src/config.rs b/burrow-gtk/src/config.rs
new file mode 100644
index 0000000..73ce81e
--- /dev/null
+++ b/burrow-gtk/src/config.rs
@@ -0,0 +1,4 @@
+pub static VERSION: &str = "0.1.0";
+pub static GETTEXT_PACKAGE: &str = "burrow-gtk";
+pub static LOCALEDIR: &str = "/app/share/locale";
+pub static PKGDATADIR: &str = "/app/share/burrow-gtk";
diff --git a/burrow-gtk/src/config.rs.in b/burrow-gtk/src/config.rs.in
new file mode 100644
index 0000000..1a24858
--- /dev/null
+++ b/burrow-gtk/src/config.rs.in
@@ -0,0 +1,4 @@
+pub static VERSION: &str = @VERSION@;
+pub static GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
+pub static LOCALEDIR: &str = @LOCALEDIR@;
+pub static PKGDATADIR: &str = @PKGDATADIR@;
diff --git a/burrow-gtk/src/gtk/help-overlay.blp b/burrow-gtk/src/gtk/help-overlay.blp
new file mode 100644
index 0000000..90ee78f
--- /dev/null
+++ b/burrow-gtk/src/gtk/help-overlay.blp
@@ -0,0 +1,24 @@
+using Gtk 4.0;
+
+ShortcutsWindow help_overlay {
+ modal: true;
+
+ ShortcutsSection {
+ section-name: "shortcuts";
+ max-height: 10;
+
+ ShortcutsGroup {
+ title: C_("shortcut window", "General");
+
+ ShortcutsShortcut {
+ title: C_("shortcut window", "Show Shortcuts");
+ action-name: "win.show-help-overlay";
+ }
+
+ ShortcutsShortcut {
+ title: C_("shortcut window", "Quit");
+ action-name: "app.quit";
+ }
+ }
+ }
+}
diff --git a/burrow-gtk/src/main.rs b/burrow-gtk/src/main.rs
new file mode 100644
index 0000000..6ccd23b
--- /dev/null
+++ b/burrow-gtk/src/main.rs
@@ -0,0 +1,35 @@
+mod application;
+mod config;
+mod window;
+
+use self::application::BurrowGtkApplication;
+use self::window::BurrowGtkWindow;
+
+use config::{GETTEXT_PACKAGE, LOCALEDIR, PKGDATADIR};
+use gettextrs::{bind_textdomain_codeset, bindtextdomain, textdomain};
+use gtk::{gio, glib};
+use gtk::prelude::*;
+
+fn main() -> glib::ExitCode {
+ // Set up gettext translations
+ bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain");
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8")
+ .expect("Unable to set the text domain encoding");
+ textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain");
+
+ // Load resources
+ let resources = gio::Resource::load(PKGDATADIR.to_owned() + "/burrow-gtk.gresource")
+ .expect("Could not load resources");
+ gio::resources_register(&resources);
+
+ // Create a new GtkApplication. The application manages our main loop,
+ // application windows, integration with the window manager/compositor, and
+ // desktop features such as file opening and single-instance applications.
+ let app = BurrowGtkApplication::new("com.hackclub.Burrow", &gio::ApplicationFlags::empty());
+
+ // Run the application. This function will block until the application
+ // exits. Upon return, we have our exit code to return to the shell. (This
+ // is the code you see when you do `echo $?` after running a command in a
+ // terminal.
+ app.run()
+}
diff --git a/burrow-gtk/src/meson.build b/burrow-gtk/src/meson.build
new file mode 100644
index 0000000..15ec34b
--- /dev/null
+++ b/burrow-gtk/src/meson.build
@@ -0,0 +1,67 @@
+pkgdatadir = join_paths(get_option('prefix'), get_option('datadir'), meson.project_name())
+gnome = import('gnome')
+
+
+blueprints = custom_target('blueprints',
+ input: files(
+ 'gtk/help-overlay.blp',
+ 'window.blp',
+ ),
+ output: '.',
+ command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
+)
+
+gnome.compile_resources('burrow-gtk',
+ 'burrow-gtk.gresource.xml',
+ gresource_bundle: true,
+ install: true,
+ install_dir: pkgdatadir,
+ dependencies: blueprints
+)
+
+conf = configuration_data()
+conf.set_quoted('VERSION', meson.project_version())
+conf.set_quoted('GETTEXT_PACKAGE', 'burrow-gtk')
+conf.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
+conf.set_quoted('PKGDATADIR', pkgdatadir)
+
+configure_file(
+ input: 'config.rs.in',
+ output: 'config.rs',
+ configuration: conf
+)
+
+# Copy the config.rs output to the source directory.
+run_command(
+ 'cp',
+ join_paths(meson.project_build_root(), 'src', 'config.rs'),
+ join_paths(meson.project_source_root(), 'src', 'config.rs'),
+ check: true
+)
+
+cargo_bin = find_program('cargo')
+cargo_opt = [ '--manifest-path', meson.project_source_root() / 'Cargo.toml' ]
+cargo_opt += [ '--target-dir', meson.project_build_root() / 'src' ]
+cargo_env = [ 'CARGO_HOME=' + meson.project_build_root() / 'cargo-home' ]
+
+if get_option('buildtype') == 'release'
+ cargo_options += [ '--release' ]
+ rust_target = 'release'
+else
+ rust_target = 'debug'
+endif
+
+cargo_build = custom_target(
+ 'cargo-build',
+ build_by_default: true,
+ build_always_stale: true,
+ output: meson.project_name(),
+ console: true,
+ install: true,
+ install_dir: get_option('bindir'),
+ command: [
+ 'env', cargo_env,
+ cargo_bin, 'build',
+ cargo_opt, '&&', 'cp', 'src' / rust_target / meson.project_name(), '@OUTPUT@',
+ ]
+)
diff --git a/burrow-gtk/src/window.blp b/burrow-gtk/src/window.blp
new file mode 100644
index 0000000..6f3534a
--- /dev/null
+++ b/burrow-gtk/src/window.blp
@@ -0,0 +1,48 @@
+using Gtk 4.0;
+using Adw 1;
+
+template BurrowGtkWindow : Adw.ApplicationWindow {
+ default-width: 600;
+ default-height: 400;
+
+ Box {
+ orientation: vertical;
+
+ HeaderBar header_bar {
+ [end]
+ MenuButton {
+ icon-name: "open-menu-symbolic";
+ menu-model: primary_menu;
+ }
+ }
+
+ Label label {
+ label: "Burrow GNOME";
+
+ vexpand: true;
+
+ styles [
+ "title-1",
+ ]
+ }
+ }
+}
+
+menu primary_menu {
+ section {
+ item {
+ label: _("_Preferences");
+ action: "app.preferences";
+ }
+
+ item {
+ label: _("_Keyboard Shortcuts");
+ action: "win.show-help-overlay";
+ }
+
+ item {
+ label: _("_About Burrow-gtk");
+ action: "app.about";
+ }
+ }
+}
diff --git a/burrow-gtk/src/window.rs b/burrow-gtk/src/window.rs
new file mode 100644
index 0000000..4a51ef0
--- /dev/null
+++ b/burrow-gtk/src/window.rs
@@ -0,0 +1,51 @@
+use gtk::prelude::*;
+use adw::subclass::prelude::*;
+use gtk::{gio, glib};
+
+mod imp {
+ use super::*;
+
+ #[derive(Debug, Default, gtk::CompositeTemplate)]
+ #[template(resource = "/com/hackclub/Burrow/window.ui")]
+ pub struct BurrowGtkWindow {
+ // Template widgets
+ #[template_child]
+ pub header_bar: TemplateChild,
+ #[template_child]
+ pub label: TemplateChild,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for BurrowGtkWindow {
+ const NAME: &'static str = "BurrowGtkWindow";
+ type Type = super::BurrowGtkWindow;
+ type ParentType = adw::ApplicationWindow;
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.bind_template();
+ }
+
+ fn instance_init(obj: &glib::subclass::InitializingObject) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for BurrowGtkWindow {}
+ impl WidgetImpl for BurrowGtkWindow {}
+ impl WindowImpl for BurrowGtkWindow {}
+ impl ApplicationWindowImpl for BurrowGtkWindow {}
+ impl AdwApplicationWindowImpl for BurrowGtkWindow {}
+}
+
+glib::wrapper! {
+ pub struct BurrowGtkWindow(ObjectSubclass)
+ @extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, adw::ApplicationWindow, @implements gio::ActionGroup, gio::ActionMap;
+}
+
+impl BurrowGtkWindow {
+ pub fn new>(application: &P) -> Self {
+ glib::Object::builder()
+ .property("application", application)
+ .build()
+ }
+}
diff --git a/burrow-gtk/subprojects/blueprint-compiler.wrap b/burrow-gtk/subprojects/blueprint-compiler.wrap
new file mode 100644
index 0000000..6e6ee32
--- /dev/null
+++ b/burrow-gtk/subprojects/blueprint-compiler.wrap
@@ -0,0 +1,8 @@
+[wrap-git]
+directory = blueprint-compiler
+url = https://gitlab.gnome.org/jwestman/blueprint-compiler.git
+revision = main
+depth = 1
+
+[provide]
+program_names = blueprint-compiler
\ No newline at end of file