diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5600faa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true +[*] +indent_style = space +end_of_line = lf +trim_trailing_whitespace = true +insert_final_newline = true +charset = utf-8 + +[*.{build,css,doap,scss,ui,xml,xml.in,xml.in.in,yaml,yml}] +indent_size = 2 + +[*.{json,py,rs}] +indent_size = 4 + +[*.{c,h,h.in}] +indent_size = 2 +max_line_length = 80 + +[NEWS] +indent_size = 2 +max_line_length = 72 diff --git a/.gitignore b/.gitignore index ea8c4bf..1a3a73a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,14 @@ -/target +target/ +build/ +_build/ +builddir/ +build-aux/app +build-aux/.flatpak-builder/ +src/config.rs +*.ui.in~ +*.ui~ +.flatpak/ +vendor +flatpak_app/ +.flatpak-builder/ +recompile/ diff --git a/Cargo.lock b/Cargo.lock index ce51cce..2b65e7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,32 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + [[package]] name = "anyhow" version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -21,10 +41,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "cairo-rs" -version = "0.15.6" +name = "block" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b14c80d8d1a02fa6d914b9d1afeeca9bc34257f8300d9696e1e331ae114223" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "cairo-rs" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "bitflags", "cairo-sys-rs", @@ -35,15 +60,20 @@ dependencies = [ [[package]] name = "cairo-sys-rs" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "glib-sys", "libc", "system-deps", ] +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-expr" version = "0.10.2" @@ -53,6 +83,25 @@ dependencies = [ "smallvec", ] +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + [[package]] name = "field-offset" version = "0.3.4" @@ -95,6 +144,17 @@ version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-task" version = "0.3.21" @@ -108,6 +168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-core", + "futures-macro", "futures-task", "pin-project-lite", "pin-utils", @@ -116,9 +177,8 @@ dependencies = [ [[package]] name = "gdk-pixbuf" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8750501d75f318c2ec0314701bc8403901303210def80bafd13f6b6059a3f45" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "bitflags", "gdk-pixbuf-sys", @@ -129,9 +189,8 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413424d9818621fa3cfc8a3a915cdb89a7c3c507d56761b4ec83a9a98e587171" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "gio-sys", "glib-sys", @@ -142,9 +201,8 @@ dependencies = [ [[package]] name = "gdk4" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9df40006277ff44538fe758400fc671146f6f2665978b6b57d2408db3c2becf" +version = "0.5.0" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#f8a6597a7bf3014758b8efe007f593b27d501dbf" dependencies = [ "bitflags", "cairo-rs", @@ -158,9 +216,8 @@ dependencies = [ [[package]] name = "gdk4-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48a39e34abe35ee2cf54a1e29dd983accecd113ad30bdead5050418fa92f2a1b" +version = "0.5.0" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#f8a6597a7bf3014758b8efe007f593b27d501dbf" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -174,10 +231,29 @@ dependencies = [ ] [[package]] -name = "gio" -version = "0.15.6" +name = "gettext-rs" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96efd8a1c00d890f6b45671916e165b5e43ccec61957d443aff6d7e44f62d348" +checksum = "e49ea8a8fad198aaa1f9655a2524b64b70eb06b2f3ff37da407566c93054f364" +dependencies = [ + "gettext-sys", + "locale_config", +] + +[[package]] +name = "gettext-sys" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa9e06ab9e7514cc9ae668ea3b71ea1536259d767dff0289ac23ad134f99929" +dependencies = [ + "cc", + "temp-dir", +] + +[[package]] +name = "gio" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "bitflags", "futures-channel", @@ -192,9 +268,8 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0fa5052773f5a56b8ae47dab09d040f5d9ce1311f4f99006e16e9a08269296" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "glib-sys", "gobject-sys", @@ -205,15 +280,15 @@ dependencies = [ [[package]] name = "glib" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa570813c504bdf7539a9400180c2dd4b789a819556fb86da7226d7d1b037b49" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "bitflags", "futures-channel", "futures-core", "futures-executor", "futures-task", + "futures-util", "glib-macros", "glib-sys", "gobject-sys", @@ -225,9 +300,8 @@ dependencies = [ [[package]] name = "glib-macros" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41bfd8d227dead0829ac142454e97531b93f576d0805d779c42bfd799c65c572" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "anyhow", "heck", @@ -240,9 +314,8 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4366377bd56697de8aaee24e673c575d2694d72e7756324ded2b0428829a7b8" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "libc", "system-deps", @@ -250,9 +323,8 @@ dependencies = [ [[package]] name = "gobject-sys" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6859463843c20cf3837e3a9069b6ab2051aeeadf4c899d33344f4aea83189a" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "glib-sys", "libc", @@ -261,9 +333,8 @@ dependencies = [ [[package]] name = "graphene-rs" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c54f9fbbeefdb62c99f892dfca35f83991e2cb5b46a8dc2a715e58612f85570" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "glib", "graphene-sys", @@ -272,9 +343,8 @@ dependencies = [ [[package]] name = "graphene-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f311acb023cf7af5537f35de028e03706136eead7f25a31e8fd26f5011e0b3" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "glib-sys", "libc", @@ -284,9 +354,8 @@ dependencies = [ [[package]] name = "gsk4" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf63d454e2f75abd92ee6de0ac9fc5aaf1018cd9c458aaf9de296c5cbab6bb9" +version = "0.5.0" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#f8a6597a7bf3014758b8efe007f593b27d501dbf" dependencies = [ "bitflags", "cairo-rs", @@ -300,9 +369,8 @@ dependencies = [ [[package]] name = "gsk4-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31d21d7ce02ba261bb24c50c4ab238a10b41a2c97c32afffae29471b7cca69b" +version = "0.5.0" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#f8a6597a7bf3014758b8efe007f593b27d501dbf" dependencies = [ "cairo-sys-rs", "gdk4-sys", @@ -316,9 +384,8 @@ dependencies = [ [[package]] name = "gtk4" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e841556e3fe55d8a43ada76b7b08a5f65570bbdfe3b8f72c333053b8832c626" +version = "0.5.0" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#f8a6597a7bf3014758b8efe007f593b27d501dbf" dependencies = [ "bitflags", "cairo-rs", @@ -339,9 +406,8 @@ dependencies = [ [[package]] name = "gtk4-macros" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573db42bb64973a4d5f718b73caa7204285a1a665308a23b11723d0ee56ec305" +version = "0.5.0" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#f8a6597a7bf3014758b8efe007f593b27d501dbf" dependencies = [ "anyhow", "proc-macro-crate", @@ -353,9 +419,8 @@ dependencies = [ [[package]] name = "gtk4-sys" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47c075e8f795c38f6e9a47b51a73eab77b325f83c0154979ed4d4245c36490d" +version = "0.5.0" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#f8a6597a7bf3014758b8efe007f593b27d501dbf" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -377,10 +442,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" [[package]] -name = "libadwaita" -version = "0.1.0" +name = "hermit-abi" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4b1d54d907dfa5d6663fdf4bdbe46c34747258b85c787adbf66187ccbaac81" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + +[[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.1.0-alpha-6" +source = "git+https://gitlab.gnome.org/World/Rust/libadwaita-rs.git?rev=e9ca4b59f2d3774c3ecfbb87828f9c6325fd59f9#e9ca4b59f2d3774c3ecfbb87828f9c6325fd59f9" dependencies = [ "gdk-pixbuf", "gdk4", @@ -395,9 +483,8 @@ dependencies = [ [[package]] name = "libadwaita-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f18b6ac4cadd252a89f5cba0a5a4e99836131795d6fad37b859ac79e8cb7d2c8" +version = "0.1.0-alpha-6" +source = "git+https://gitlab.gnome.org/World/Rust/libadwaita-rs.git?rev=e9ca4b59f2d3774c3ecfbb87828f9c6325fd59f9#e9ca4b59f2d3774c3ecfbb87828f9c6325fd59f9" dependencies = [ "gdk4-sys", "gio-sys", @@ -414,6 +501,43 @@ version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +[[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 = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[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.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "memoffset" version = "0.6.5" @@ -427,7 +551,41 @@ dependencies = [ name = "mutiny" version = "0.1.0" dependencies = [ + "gettext-rs", + "gtk4", "libadwaita", + "log", + "once_cell", + "pretty_env_logger", +] + +[[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]] @@ -438,9 +596,8 @@ checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" [[package]] name = "pango" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c7420fc01a390ec200da7395b64d705f5d82fe03e5d0708aee422c46538be7" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "bitflags", "glib", @@ -451,9 +608,8 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7022c2fb88cd2d9d55e1a708a8c53a3ae8678234c4a54bf623400aeb7f31fac2" +version = "0.16.0" +source = "git+https://github.com/gtk-rs/gtk-rs-core#e06623f4ab5e4395216ce2d4040da7137572be39" dependencies = [ "glib-sys", "gobject-sys", @@ -488,6 +644,16 @@ version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "proc-macro-crate" version = "1.1.3" @@ -531,6 +697,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.15" @@ -540,6 +712,23 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "rustc_version" version = "0.3.3" @@ -609,6 +798,21 @@ dependencies = [ "version-compare", ] +[[package]] +name = "temp-dir" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab" + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -678,6 +882,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index c11f4f8..f6c1608 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,13 @@ [package] +edition = "2021" name = "mutiny" version = "0.1.0" -edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies.adw] -package = "libadwaita" -version = "0.1.0" +[dependencies] +adw = {package = "libadwaita", rev = "e9ca4b59f2d3774c3ecfbb87828f9c6325fd59f9", git = "https://gitlab.gnome.org/World/Rust/libadwaita-rs.git"} +gettext-rs = {version = "0.7", features = ["gettext-system"]} +gtk = {package = "gtk4", git = "https://github.com/gtk-rs/gtk4-rs.git"} +log = "0.4" +once_cell = "1.9" +pretty_env_logger = "0.4" diff --git a/build-aux/chat.revolt.Mutiny.Devel.json b/build-aux/chat.revolt.Mutiny.Devel.json new file mode 100644 index 0000000..376b120 --- /dev/null +++ b/build-aux/chat.revolt.Mutiny.Devel.json @@ -0,0 +1,45 @@ +{ + "app-id": "chat.revolt.Mutiny.Devel", + "runtime": "org.gnome.Platform", + "runtime-version": "master", + "sdk": "org.gnome.Sdk", + "sdk-extensions": [ + "org.freedesktop.Sdk.Extension.rust-stable" + ], + "command": "mutiny", + "finish-args": [ + "--socket=fallback-x11", + "--socket=wayland", + "--device=dri", + "--share=network", + "--env=RUST_LOG=mutiny=debug", + "--env=G_MESSAGES_DEBUG=none", + "--env=RUST_BACKTRACE=1" + ], + "build-options": { + "append-path": "/usr/lib/sdk/rust-stable/bin", + "build-args": [ + "--share=network" + ], + "test-args": [ + "--socket=x11", + "--share=network" + ] + }, + "modules": [ + { + "name": "mutiny", + "buildsystem": "meson", + "run-tests": true, + "config-opts": [ + "-Dprofile=development" + ], + "sources": [ + { + "type": "dir", + "path": "../" + } + ] + } + ] +} diff --git a/build-aux/dist-vendor.sh b/build-aux/dist-vendor.sh new file mode 100644 index 0000000..be73278 --- /dev/null +++ b/build-aux/dist-vendor.sh @@ -0,0 +1,10 @@ +#!/bin/bash +export DIST="$1" +export SOURCE_ROOT="$2" + +cd "$SOURCE_ROOT" +mkdir "$DIST"/.cargo +cargo vendor | sed 's/^directory = ".*"/directory = "vendor"/g' > $DIST/.cargo/config +# Move vendor into dist tarball directory +mv vendor "$DIST" + diff --git a/data/chat.revolt.Mutiny.desktop.in.in b/data/chat.revolt.Mutiny.desktop.in.in new file mode 100644 index 0000000..bf81e7a --- /dev/null +++ b/data/chat.revolt.Mutiny.desktop.in.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Name=Mutiny +Comment=Revolt Client +Type=Application +Exec=mutiny +Terminal=false +Categories=Network;InstantMessaging +Keywords=Revolt;Chat +# Translators: Do NOT translate or transliterate this text (this is an icon file name)! +Icon=@icon@ +StartupNotify=true diff --git a/data/chat.revolt.Mutiny.gschema.xml.in b/data/chat.revolt.Mutiny.gschema.xml.in new file mode 100644 index 0000000..0910bc4 --- /dev/null +++ b/data/chat.revolt.Mutiny.gschema.xml.in @@ -0,0 +1,20 @@ + + + + + 600 + Default window width + Default window width + + + 400 + Default window height + Default window height + + + false + Default window maximized behaviour + + + + diff --git a/data/chat.revolt.Mutiny.metainfo.xml.in.in b/data/chat.revolt.Mutiny.metainfo.xml.in.in new file mode 100644 index 0000000..5cae7fa --- /dev/null +++ b/data/chat.revolt.Mutiny.metainfo.xml.in.in @@ -0,0 +1,42 @@ + + + + @app-id@ + CC0 + + + Mutiny + Write a GTK + Rust application + + A boilerplate template for GTK + Rust. It uses Meson as a build system and has flatpak support by default. + + + + https://gitlab.gnome.org/bilelmoussaoui/mutiny/raw/master/data/resources/screenshots/screenshot1.png + Main window + + + https://github.com/revoltchat/mutiny + https://github.com/revoltchat/mutiny/issues + + moderate + moderate + moderate + intense + + + + + + + ModernToolkit + HiDpiIcon + + Revolt + hello@revolt.chat + @gettext-package@ + @app-id@.desktop + diff --git a/data/icons/chat.revolt.gtk.Mutiny-symbolic.svg b/data/icons/chat.revolt.Mutiny-symbolic.svg similarity index 100% rename from data/icons/chat.revolt.gtk.Mutiny-symbolic.svg rename to data/icons/chat.revolt.Mutiny-symbolic.svg diff --git a/data/icons/chat.revolt.gtk.Mutiny.Devel.svg b/data/icons/chat.revolt.Mutiny.Devel.svg similarity index 100% rename from data/icons/chat.revolt.gtk.Mutiny.Devel.svg rename to data/icons/chat.revolt.Mutiny.Devel.svg diff --git a/data/icons/chat.revolt.gtk.Mutiny.svg b/data/icons/chat.revolt.Mutiny.svg similarity index 100% rename from data/icons/chat.revolt.gtk.Mutiny.svg rename to data/icons/chat.revolt.Mutiny.svg diff --git a/data/icons/meson.build b/data/icons/meson.build new file mode 100644 index 0000000..2ab86e9 --- /dev/null +++ b/data/icons/meson.build @@ -0,0 +1,10 @@ +install_data( + '@0@.svg'.format(application_id), + install_dir: iconsdir / 'hicolor' / 'scalable' / 'apps' +) + +install_data( + '@0@-symbolic.svg'.format(base_id), + install_dir: iconsdir / 'hicolor' / 'symbolic' / 'apps', + rename: '@0@-symbolic.svg'.format(application_id) +) diff --git a/data/meson.build b/data/meson.build new file mode 100644 index 0000000..5643b60 --- /dev/null +++ b/data/meson.build @@ -0,0 +1,76 @@ +subdir('icons') +subdir('resources') +# Desktop file +desktop_conf = configuration_data() +desktop_conf.set('icon', application_id) +desktop_file = i18n.merge_file( + type: 'desktop', + input: configure_file( + input: '@0@.desktop.in.in'.format(base_id), + output: '@BASENAME@', + configuration: desktop_conf + ), + output: '@0@.desktop'.format(application_id), + po_dir: podir, + install: true, + install_dir: datadir / 'applications' +) +# Validate Desktop file +if desktop_file_validate.found() + test( + 'validate-desktop', + desktop_file_validate, + args: [ + desktop_file.full_path() + ], + depends: desktop_file, + ) +endif + +# Appdata +appdata_conf = configuration_data() +appdata_conf.set('app-id', application_id) +appdata_conf.set('gettext-package', gettext_package) +appdata_file = i18n.merge_file( + input: configure_file( + input: '@0@.metainfo.xml.in.in'.format(base_id), + output: '@BASENAME@', + configuration: appdata_conf + ), + output: '@0@.metainfo.xml'.format(application_id), + po_dir: podir, + install: true, + install_dir: datadir / 'metainfo' +) +# Validate Appdata +if appstream_util.found() + test( + 'validate-appdata', appstream_util, + args: [ + 'validate', '--nonet', appdata_file.full_path() + ], + depends: appdata_file, + ) +endif + +# GSchema +gschema_conf = configuration_data() +gschema_conf.set('app-id', application_id) +gschema_conf.set('gettext-package', gettext_package) +configure_file( + input: '@0@.gschema.xml.in'.format(base_id), + output: '@0@.gschema.xml'.format(application_id), + configuration: gschema_conf, + install: true, + install_dir: datadir / 'glib-2.0' / 'schemas' +) + +# Validata GSchema +if glib_compile_schemas.found() + test( + 'validate-gschema', glib_compile_schemas, + args: [ + '--strict', '--dry-run', meson.current_build_dir() + ], + ) +endif diff --git a/data/resources/meson.build b/data/resources/meson.build new file mode 100644 index 0000000..604e1b2 --- /dev/null +++ b/data/resources/meson.build @@ -0,0 +1,9 @@ +# Resources +resources = gnome.compile_resources( + 'resources', + 'resources.gresource.xml', + gresource_bundle: true, + source_dir: meson.current_build_dir(), + install: true, + install_dir: pkgdatadir, +) diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml new file mode 100644 index 0000000..09be358 --- /dev/null +++ b/data/resources/resources.gresource.xml @@ -0,0 +1,8 @@ + + + + + ui/shortcuts.ui + ui/window.ui + + diff --git a/data/resources/screenshots/screenshot1.png b/data/resources/screenshots/screenshot1.png new file mode 100644 index 0000000..173b6be Binary files /dev/null and b/data/resources/screenshots/screenshot1.png differ diff --git a/data/resources/ui/shortcuts.ui b/data/resources/ui/shortcuts.ui new file mode 100644 index 0000000..ef12f02 --- /dev/null +++ b/data/resources/ui/shortcuts.ui @@ -0,0 +1,29 @@ + + + + True + + + shortcuts + 10 + + + General + + + Show Shortcuts + win.show-help-overlay + + + + + Quit + app.quit + + + + + + + + diff --git a/data/resources/ui/window.ui b/data/resources/ui/window.ui new file mode 100644 index 0000000..239a221 --- /dev/null +++ b/data/resources/ui/window.ui @@ -0,0 +1,48 @@ + + + + + + _Preferences + app.preferences + + + _Keyboard Shortcuts + win.show-help-overlay + + + _About Mutiny + app.about + + + + + + + vertical + + + + + Mutiny + + + + + open-menu-symbolic + primary_menu + + + + + + + Hello world! + True + True + + + + + + diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..1974ef4 --- /dev/null +++ b/meson.build @@ -0,0 +1,71 @@ +project( + 'mutiny', + 'rust', + version: '0.0.1', + meson_version: '>= 0.59', + # license: MIT, +) + +i18n = import('i18n') +gnome = import('gnome') + +base_id = 'chat.revolt.Mutiny' + +dependency('glib-2.0', version: '>= 2.66') +dependency('gio-2.0', version: '>= 2.66') +dependency('gtk4', version: '>= 4.0.0') + +glib_compile_resources = find_program('glib-compile-resources', required: true) +glib_compile_schemas = find_program('glib-compile-schemas', required: true) +desktop_file_validate = find_program('desktop-file-validate', required: false) +appstream_util = find_program('appstream-util', required: false) +cargo = find_program('cargo', required: true) + +version = meson.project_version() + +prefix = get_option('prefix') +bindir = prefix / get_option('bindir') +localedir = prefix / get_option('localedir') + +datadir = prefix / get_option('datadir') +pkgdatadir = datadir / meson.project_name() +iconsdir = datadir / 'icons' +podir = meson.project_source_root() / 'po' +gettext_package = meson.project_name() + +if get_option('profile') == 'development' + profile = 'Devel' + vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD').stdout().strip() + if vcs_tag == '' + version_suffix = '-devel' + else + version_suffix = '-@0@'.format(vcs_tag) + endif + application_id = '@0@.@1@'.format(base_id, profile) +else + profile = '' + version_suffix = '' + application_id = base_id +endif + +meson.add_dist_script( + 'build-aux/dist-vendor.sh', + meson.project_build_root() / 'meson-dist' / meson.project_name() + '-' + version, + meson.project_source_root() +) + +if get_option('profile') == 'development' + # Setup pre-commit hook for ensuring coding style is always consistent + message('Setting up git pre-commit hook..') + run_command('cp', '-f', 'hooks/pre-commit.hook', '.git/hooks/pre-commit') +endif + +subdir('data') +subdir('po') +subdir('src') + +gnome.post_install( + gtk_update_icon_cache: true, + glib_compile_schemas: true, + update_desktop_database: true, +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..2e02821 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,10 @@ +option( + 'profile', + type: 'combo', + choices: [ + 'default', + 'development' + ], + value: 'default', + description: 'The build profile for Mutiny. One of "default" or "development".' +) diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..e69de29 diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..9b44e61 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,6 @@ +data/chat.revolt.Mutiny.desktop.in.in +data/chat.revolt.Mutiny.gschema.xml.in +data/chat.revolt.Mutiny.metainfo.xml.in.in +data/resources/ui/shortcuts.ui +data/resources/ui/window.ui +src/application.rs diff --git a/po/meson.build b/po/meson.build new file mode 100644 index 0000000..57d1266 --- /dev/null +++ b/po/meson.build @@ -0,0 +1 @@ +i18n.gettext(gettext_package, preset: 'glib') diff --git a/src/application.rs b/src/application.rs new file mode 100644 index 0000000..60ae9a7 --- /dev/null +++ b/src/application.rs @@ -0,0 +1,141 @@ +use gettextrs::gettext; +use log::{debug, info}; + +use adw::subclass::prelude::*; +use glib::clone; +use gtk::prelude::*; +use gtk::subclass::prelude::*; +use gtk::{gio, glib}; + +use crate::config::{APP_ID, PKGDATADIR, PROFILE, VERSION}; +use crate::window::MutinyAppWindow; + +mod imp { + use super::*; + use glib::WeakRef; + use once_cell::sync::OnceCell; + + #[derive(Debug, Default)] + pub struct MutinyApp { + pub window: OnceCell>, + } + + #[glib::object_subclass] + impl ObjectSubclass for MutinyApp { + const NAME: &'static str = "MutinyApp"; + type Type = super::MutinyApp; + type ParentType = adw::Application; + } + + impl ObjectImpl for MutinyApp {} + + impl ApplicationImpl for MutinyApp { + fn activate(&self, app: &Self::Type) { + debug!("GtkApplication::activate"); + self.parent_activate(app); + + if let Some(window) = self.window.get() { + let window = window.upgrade().unwrap(); + window.present(); + return; + } + + let window = MutinyAppWindow::new(app); + self.window + .set(window.downgrade()) + .expect("Window already set."); + + app.main_window().present(); + } + + fn startup(&self, app: &Self::Type) { + debug!("GtkApplication::startup"); + self.parent_startup(app); + + // Set icons for shell + gtk::Window::set_default_icon_name(APP_ID); + + app.setup_gactions(); + app.setup_accels(); + } + } + + impl GtkApplicationImpl for MutinyApp {} + impl AdwApplicationImpl for MutinyApp {} +} + +glib::wrapper! { + pub struct MutinyApp(ObjectSubclass) + @extends gio::Application, gtk::Application, adw::Application, + @implements gio::ActionMap, gio::ActionGroup; +} + +impl MutinyApp { + pub fn new() -> Self { + glib::Object::new(&[ + ("application-id", &Some(APP_ID)), + ("flags", &gio::ApplicationFlags::empty()), + ("resource-base-path", &Some("/chat/revolt/Mutiny/")), + ]) + .expect("Application initialization failed...") + } + + fn main_window(&self) -> MutinyAppWindow { + self.imp().window.get().unwrap().upgrade().unwrap() + } + + fn setup_gactions(&self) { + // Quit + let action_quit = gio::SimpleAction::new("quit", None); + action_quit.connect_activate(clone!(@weak self as app => move |_, _| { + // This is needed to trigger the delete event and saving the window state + app.main_window().close(); + app.quit(); + })); + self.add_action(&action_quit); + + // About + let action_about = gio::SimpleAction::new("about", None); + action_about.connect_activate(clone!(@weak self as app => move |_, _| { + app.show_about_dialog(); + })); + self.add_action(&action_about); + } + + // Sets up keyboard shortcuts + fn setup_accels(&self) { + self.set_accels_for_action("app.quit", &["q"]); + } + + fn show_about_dialog(&self) { + let dialog = gtk::AboutDialog::builder() + .logo_icon_name(APP_ID) + // Insert your license of choice here + // .license_type(gtk::License::MitX11) + // Insert your website here + // .website("https://gitlab.gnome.org/bilelmoussaoui/mutiny/") + .version(VERSION) + .transient_for(&self.main_window()) + .translator_credits(&gettext("translator-credits")) + .modal(true) + .authors(vec!["Revolt".into()]) + .artists(vec!["Revolt".into()]) + .build(); + + dialog.present(); + } + + pub fn run(&self) { + info!("Mutiny ({})", APP_ID); + info!("Version: {} ({})", VERSION, PROFILE); + info!("Datadir: {}", PKGDATADIR); + + ApplicationExtManual::run(self); + } +} + +impl Default for MutinyApp { + fn default() -> Self { + Self::new() + } +} diff --git a/src/config.rs.in b/src/config.rs.in new file mode 100644 index 0000000..699897f --- /dev/null +++ b/src/config.rs.in @@ -0,0 +1,7 @@ +pub const APP_ID: &str = @APP_ID@; +pub const GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@; +pub const LOCALEDIR: &str = @LOCALEDIR@; +pub const PKGDATADIR: &str = @PKGDATADIR@; +pub const PROFILE: &str = @PROFILE@; +pub const RESOURCES_FILE: &str = concat!(@PKGDATADIR@, "/resources.gresource"); +pub const VERSION: &str = @VERSION@; diff --git a/src/main.rs b/src/main.rs index cb5678f..ba84b35 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,92 +1,28 @@ -use adw::{prelude::*, Avatar}; +mod application; +#[rustfmt::skip] +mod config; +mod window; -use adw::{ActionRow, ApplicationWindow, HeaderBar}; -use adw::gtk::{Application, Box, ListBox, Orientation}; +use gettextrs::{gettext, LocaleCategory}; +use gtk::{gio, glib}; + +use self::application::MutinyApp; +use self::config::{GETTEXT_PACKAGE, LOCALEDIR, RESOURCES_FILE}; fn main() { - // Configure a new GTK4 application. - let application = Application::builder() - .application_id("chat.revolt.Mutiny") - .build(); + // Initialize logger + pretty_env_logger::init(); - // Configure Adwaita on start. - application.connect_startup(|_| { - adw::init(); - }); + // Prepare i18n + gettextrs::setlocale(LocaleCategory::LcAll, ""); + gettextrs::bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR).expect("Unable to bind the text domain"); + gettextrs::textdomain(GETTEXT_PACKAGE).expect("Unable to switch to the text domain"); - // Once the application is ready, build the UI. - application.connect_activate(|app| { - // This is our main Window frame. - let frame = Box::new(Orientation::Vertical, 0); + glib::set_application_name(&gettext("Mutiny")); - // Add the header bar, not included by default. - frame.append( - &HeaderBar::builder() - .title_widget(&adw::WindowTitle::new("Mutiny", "")) - .build(), - ); + let res = gio::Resource::load(RESOURCES_FILE).expect("Could not load gresource file"); + gio::resources_register(&res); - // Add the main content. - frame.append(&{ - let panels = Box::builder() - .orientation(Orientation::Horizontal) - .margin_top(16) - .margin_start(16) - .build(); - - // Some stuff on the left. - panels.append(&{ - let servers_or_something = Box::new(Orientation::Vertical, 24); - - servers_or_something.append(&Avatar::new(64, Some("deez nuts"), true)); - servers_or_something.append(&Avatar::new(64, Some("hm yes aaa"), true)); - servers_or_something.append(&Avatar::new(64, Some("abc def"), true)); - servers_or_something.append(&Avatar::new(64, Some("aaaa"), true)); - - servers_or_something - }); - - // This is the default content from the Adwaita demo code. - panels.append(&{ - let list = ListBox::builder() - .margin_top(32) - .margin_end(32) - .margin_bottom(32) - .margin_start(32) - .css_classes(vec![String::from("content")]) - .build(); - - list.append(&{ - let row = ActionRow::builder() - .activatable(true) - .selectable(false) - .title("Click me") - .build(); - - row.connect_activated(|_| { - eprintln!("Clicked!"); - }); - - row - }); - - list - }); - - panels - }); - - // Construct the Window. - let window = ApplicationWindow::builder() - .application(app) - .default_width(350) - .content(&frame) - .build(); - - // Display the Window. - window.show(); - }); - - // Run the GTK application. - application.run(); + let app = MutinyApp::new(); + app.run(); } diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..d99036d --- /dev/null +++ b/src/meson.build @@ -0,0 +1,52 @@ +global_conf = configuration_data() +global_conf.set_quoted('APP_ID', application_id) +global_conf.set_quoted('PKGDATADIR', pkgdatadir) +global_conf.set_quoted('PROFILE', profile) +global_conf.set_quoted('VERSION', version + version_suffix) +global_conf.set_quoted('GETTEXT_PACKAGE', gettext_package) +global_conf.set_quoted('LOCALEDIR', localedir) +config = configure_file( + input: 'config.rs.in', + output: 'config.rs', + configuration: global_conf +) +# Copy the config.rs output to the source directory. +run_command( + 'cp', + meson.project_build_root() / 'src' / 'config.rs', + meson.project_source_root() / 'src' / 'config.rs', + check: true +) + +cargo_options = [ '--manifest-path', meson.project_source_root() / 'Cargo.toml' ] +cargo_options += [ '--target-dir', meson.project_build_root() / 'src' ] + +if get_option('profile') == 'default' + cargo_options += [ '--release' ] + rust_target = 'release' + message('Building in release mode') +else + rust_target = 'debug' + message('Building in debug mode') +endif + +cargo_env = [ 'CARGO_HOME=' + meson.project_build_root() / 'cargo-home' ] + +cargo_build = custom_target( + 'cargo-build', + build_by_default: true, + build_always_stale: true, + output: meson.project_name(), + console: true, + install: true, + install_dir: bindir, + depends: resources, + command: [ + 'env', + cargo_env, + cargo, 'build', + cargo_options, + '&&', + 'cp', 'src' / rust_target / meson.project_name(), '@OUTPUT@', + ] +) diff --git a/src/window.rs b/src/window.rs new file mode 100644 index 0000000..1117457 --- /dev/null +++ b/src/window.rs @@ -0,0 +1,116 @@ +use adw::subclass::prelude::*; +use gtk::prelude::*; +use gtk::subclass::prelude::*; +use gtk::{gio, glib}; + +use crate::application::MutinyApp; +use crate::config::{APP_ID, PROFILE}; + +mod imp { + use super::*; + + use gtk::CompositeTemplate; + + #[derive(Debug, CompositeTemplate)] + #[template(resource = "/chat/revolt/Mutiny/ui/window.ui")] + pub struct MutinyAppWindow { + #[template_child] + pub headerbar: TemplateChild, + pub settings: gio::Settings, + } + + impl Default for MutinyAppWindow { + fn default() -> Self { + Self { + headerbar: TemplateChild::default(), + settings: gio::Settings::new(APP_ID), + } + } + } + + #[glib::object_subclass] + impl ObjectSubclass for MutinyAppWindow { + const NAME: &'static str = "MutinyAppWindow"; + type Type = super::MutinyAppWindow; + type ParentType = adw::ApplicationWindow; + + fn class_init(klass: &mut Self::Class) { + Self::bind_template(klass); + } + + // You must call `Widget`'s `init_template()` within `instance_init()`. + fn instance_init(obj: &glib::subclass::InitializingObject) { + obj.init_template(); + } + } + + impl ObjectImpl for MutinyAppWindow { + fn constructed(&self, obj: &Self::Type) { + self.parent_constructed(obj); + + // Devel Profile + if PROFILE == "Devel" { + obj.add_css_class("devel"); + } + + // Load latest window state + obj.load_window_size(); + } + } + + impl WidgetImpl for MutinyAppWindow {} + impl WindowImpl for MutinyAppWindow { + // Save window state on delete event + fn close_request(&self, window: &Self::Type) -> gtk::Inhibit { + if let Err(err) = window.save_window_size() { + log::warn!("Failed to save window state, {}", &err); + } + + // Pass close request on to the parent + self.parent_close_request(window) + } + } + + impl ApplicationWindowImpl for MutinyAppWindow {} + impl AdwApplicationWindowImpl for MutinyAppWindow {} +} + +glib::wrapper! { + pub struct MutinyAppWindow(ObjectSubclass) + @extends gtk::Widget, gtk::Window, gtk::ApplicationWindow, + @implements gio::ActionMap, gio::ActionGroup, gtk::Root; +} + +impl MutinyAppWindow { + pub fn new(app: &MutinyApp) -> Self { + glib::Object::new(&[("application", app)]).expect("Failed to create MutinyAppWindow") + } + + fn save_window_size(&self) -> Result<(), glib::BoolError> { + let imp = self.imp(); + + let (width, height) = self.default_size(); + + imp.settings.set_int("window-width", width)?; + imp.settings.set_int("window-height", height)?; + + imp.settings + .set_boolean("is-maximized", self.is_maximized())?; + + Ok(()) + } + + fn load_window_size(&self) { + let imp = self.imp(); + + let width = imp.settings.int("window-width"); + let height = imp.settings.int("window-height"); + let is_maximized = imp.settings.boolean("is-maximized"); + + self.set_default_size(width, height); + + if is_maximized { + self.maximize(); + } + } +}
A boilerplate template for GTK + Rust. It uses Meson as a build system and has flatpak support by default.