From a6f9f83141ef81a7cd817c8b677f7be4a82a5227 Mon Sep 17 00:00:00 2001
From: Brage Fuglseth <91388039+bragefuglseth@users.noreply.github.com>
Date: Mon, 23 Dec 2024 02:06:37 +0100
Subject: [PATCH] Add Discord RPC support
If someone has Discord and Keypunch open at the same time, their
Keypunch activity will now show up in Discord using its rich presence
API. For some reason, Builder doesn't like the new folder access
requirements, so I've added a new one that grants access to the specific
folders needed to do this.
---
Cargo.lock | 575 +++-
Cargo.toml | 1 +
....bragefuglseth.Keypunch.DiscordAccess.json | 86 +
data/discord-rpc-artwork.svg | 2392 +++++++++++++++++
src/application.rs | 11 +-
src/discord_rpc.rs | 145 +
src/main.rs | 2 +
src/session_enums.rs | 69 +
src/text_generation.rs | 2 +-
src/widgets/window.rs | 53 +-
src/widgets/window/session.rs | 36 +
src/widgets/window/ui_state.rs | 42 +-
12 files changed, 3236 insertions(+), 178 deletions(-)
create mode 100644 build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json
create mode 100644 data/discord-rpc-artwork.svg
create mode 100644 src/discord_rpc.rs
create mode 100644 src/session_enums.rs
diff --git a/Cargo.lock b/Cargo.lock
index dd0d352..9f7524e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,9 +19,9 @@ dependencies = [
[[package]]
name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
@@ -41,11 +41,17 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+[[package]]
+name = "bytes"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
+
[[package]]
name = "cairo-rs"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8a0ea147c94108c9613235388f540e4d14c327f7081c9e471fc8ee8a2533e69"
+checksum = "ae50b5510d86cf96ac2370e66d8dc960882f3df179d6a5a1e52bd94a1416c0f7"
dependencies = [
"bitflags",
"cairo-sys-rs",
@@ -55,9 +61,9 @@ dependencies = [
[[package]]
name = "cairo-sys-rs"
-version = "0.20.0"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "428290f914b9b86089f60f5d8a9f6e440508e1bcff23b25afd51502b0a2da88f"
+checksum = "f18b6bb8e43c7eb0f2aac7976afe0c61b6f5fc2ab7bc4c139537ea56c92290df"
dependencies = [
"glib-sys",
"libc",
@@ -66,18 +72,18 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.1.21"
+version = "1.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0"
+checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-expr"
-version = "0.16.0"
+version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "345c78335be0624ed29012dc10c49102196c6882c12dde65d9f35b02da2aada8"
+checksum = "8d4ba6e40bd1184518716a6e1a781bf9160e286d219ccdb8ab2612e74cfe4789"
dependencies = [
"smallvec",
"target-lexicon",
@@ -89,6 +95,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
[[package]]
name = "crc32fast"
version = "1.4.2"
@@ -98,11 +110,20 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
+dependencies = [
+ "crossbeam-utils",
+]
+
[[package]]
name = "crossbeam-deque"
-version = "0.8.5"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
@@ -119,9 +140,32 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.20"
+version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "discord-presence"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff5c60b76a2455bad4e7eef0f8a9eca0c450c112c64a7b38ef24f569f4f4f88c"
+dependencies = [
+ "byteorder",
+ "bytes",
+ "cfg-if",
+ "crossbeam-channel",
+ "named_pipe",
+ "num-derive",
+ "num-traits",
+ "parking_lot",
+ "paste",
+ "quork",
+ "serde",
+ "serde_json",
+ "thiserror 2.0.9",
+ "tracing",
+ "uuid",
+]
[[package]]
name = "either"
@@ -153,9 +197,9 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.33"
+version = "1.0.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
+checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -163,24 +207,24 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
]
[[package]]
name = "futures-core"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
name = "futures-executor"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
dependencies = [
"futures-core",
"futures-task",
@@ -189,15 +233,15 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
[[package]]
name = "futures-macro"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
@@ -206,15 +250,15 @@ dependencies = [
[[package]]
name = "futures-task"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
[[package]]
name = "futures-util"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
"futures-core",
"futures-macro",
@@ -226,9 +270,9 @@ dependencies = [
[[package]]
name = "gdk-pixbuf"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8730751991b97419fc3f0c2dca2c9e45b48edf46e48e0f965964ecf33889812f"
+checksum = "b6efc7705f7863d37b12ad6974cbb310d35d054f5108cdc1e69037742f573c4c"
dependencies = [
"gdk-pixbuf-sys",
"gio",
@@ -238,9 +282,9 @@ dependencies = [
[[package]]
name = "gdk-pixbuf-sys"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ffbf649fd5b1c8c0f0feeb015b7533c3ef92da2887fb95ddd338bc2b1644a7c"
+checksum = "67f2587c9202bf997476bbba6aaed4f78a11538a2567df002a5f57f5331d0b5c"
dependencies = [
"gio-sys",
"glib-sys",
@@ -251,9 +295,9 @@ dependencies = [
[[package]]
name = "gdk4"
-version = "0.9.0"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b7d7237c1487ed4b300aac7744efcbf1319e12d60d7afcd6f505414bd5b5dea"
+checksum = "d0196720118f880f71fe7da971eff58cc43a89c9cf73f46076b7cb1e60889b15"
dependencies = [
"cairo-rs",
"gdk-pixbuf",
@@ -266,9 +310,9 @@ dependencies = [
[[package]]
name = "gdk4-sys"
-version = "0.9.0"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a67576c8ec012156d7f680e201a807b4432a77babb3157e0555e990ab6bcd878"
+checksum = "60b0e1340bd15e7a78810cf39fed9e5d85f0a8f80b1d999d384ca17dcc452b60"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
@@ -304,9 +348,9 @@ dependencies = [
[[package]]
name = "gettext-rs"
-version = "0.7.1"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a6716b8a0db461a2720b850ba1623e5b69e4b1aa0224cf5e1fb23a0fe49e65c"
+checksum = "a44e92f7dc08430aca7ed55de161253a22276dfd69c5526e5c5e95d1f7cf338a"
dependencies = [
"gettext-sys",
"locale_config",
@@ -324,9 +368,9 @@ dependencies = [
[[package]]
name = "gio"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcacaa37401cad0a95aadd266bc39c72a131d454fc012f6dfd217f891d76cc52"
+checksum = "a517657589a174be9f60c667f1fec8b7ac82ed5db4ebf56cf073a3b5955d8e2e"
dependencies = [
"futures-channel",
"futures-core",
@@ -341,22 +385,22 @@ dependencies = [
[[package]]
name = "gio-sys"
-version = "0.20.1"
+version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5237611e97e9b86ab5768adc3eef853ae713ea797aa3835404acdfacffc9fb38"
+checksum = "8446d9b475730ebef81802c1738d972db42fde1c5a36a627ebc4d665fc87db04"
dependencies = [
"glib-sys",
"gobject-sys",
"libc",
"system-deps",
- "windows-sys 0.52.0",
+ "windows-sys",
]
[[package]]
name = "glib"
-version = "0.20.3"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95648aac01b75503000bb3bcaa5ec7a7a2dd61e43636b8b1814854de94dd80e4"
+checksum = "f969edf089188d821a30cde713b6f9eb08b20c63fc2e584aba2892a7984a8cc0"
dependencies = [
"bitflags",
"futures-channel",
@@ -375,9 +419,9 @@ dependencies = [
[[package]]
name = "glib-macros"
-version = "0.20.3"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302f1d633c9cdef4350330e7b68fd8016e2834bb106c93fdf9789fcde753c1ab"
+checksum = "715601f8f02e71baef9c1f94a657a9a77c192aea6097cf9ae7e5e177cd8cde68"
dependencies = [
"heck",
"proc-macro-crate",
@@ -388,9 +432,9 @@ dependencies = [
[[package]]
name = "glib-sys"
-version = "0.20.2"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92eee4531c1c9abba945d19378b205031b5890e1f99c319ba0503b6e0c06a163"
+checksum = "b360ff0f90d71de99095f79c526a5888c9c92fc9ee1b19da06c6f5e75f0c2a53"
dependencies = [
"libc",
"system-deps",
@@ -398,9 +442,9 @@ dependencies = [
[[package]]
name = "gobject-sys"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa3d1dcd8a1eb2e7c22be3d5e792b14b186f3524f79b25631730f9a8c169d49a"
+checksum = "67a56235e971a63bfd75abb13ef70064e1346388723422a68580d8a6fbac6423"
dependencies = [
"glib-sys",
"libc",
@@ -409,9 +453,9 @@ dependencies = [
[[package]]
name = "graphene-rs"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80aac87f74e81c0e13433e892a047237abdc37945c86887f5eed905038356e69"
+checksum = "f39d3bcd2e24fd9c2874a56f277b72c03e728de9bdc95a8d4ef4c962f10ced98"
dependencies = [
"glib",
"graphene-sys",
@@ -420,9 +464,9 @@ dependencies = [
[[package]]
name = "graphene-sys"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc2f91ecd32989efad60326cc20a8fb252bd2852239a08e4e70cde8c100de9ca"
+checksum = "11a68d39515bf340e879b72cecd4a25c1332557757ada6e8aba8654b4b81d23a"
dependencies = [
"glib-sys",
"libc",
@@ -432,9 +476,9 @@ dependencies = [
[[package]]
name = "gsk4"
-version = "0.9.0"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3cf2091e1af185b347b3450817d93dea6fe435df7abd4c2cd7fb5bcb4cfda8"
+checksum = "32b9188db0a6219e708b6b6e7225718e459def664023dbddb8395ca1486d8102"
dependencies = [
"cairo-rs",
"gdk4",
@@ -447,9 +491,9 @@ dependencies = [
[[package]]
name = "gsk4-sys"
-version = "0.9.0"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aa69614a26d8760c186c3690f1b0fbb917572ca23ef83137445770ceddf8cde"
+checksum = "bca10fc65d68528a548efa3d8747934adcbe7058b73695c9a7f43a25352fce14"
dependencies = [
"cairo-sys-rs",
"gdk4-sys",
@@ -463,9 +507,9 @@ dependencies = [
[[package]]
name = "gtk4"
-version = "0.9.1"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4fe572bf318e5dbc6f5a2f8a25d853f1ae3f42768c0b08af6ca20a18f4057e1"
+checksum = "b697ff938136625f6acf75f01951220f47a45adcf0060ee55b4671cf734dac44"
dependencies = [
"cairo-rs",
"field-offset",
@@ -484,9 +528,9 @@ dependencies = [
[[package]]
name = "gtk4-macros"
-version = "0.9.1"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e7b362c8fccd2712297903717d65d30defdab2b509bc9d209cbe5ffb9fabaf"
+checksum = "0ed1786c4703dd196baf7e103525ce0cf579b3a63a0570fe653b7ee6bac33999"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -496,9 +540,9 @@ dependencies = [
[[package]]
name = "gtk4-sys"
-version = "0.9.0"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1114a207af8ada02cf4658a76692f4190f06f093380d5be07e3ca8b43aa7c666"
+checksum = "3af4b680cee5d2f786a2f91f1c77e95ecf2254522f0ca4edf3a2dce6cb35cecf"
dependencies = [
"cairo-sys-rs",
"gdk-pixbuf-sys",
@@ -542,9 +586,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.14.5"
+version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]]
name = "heck"
@@ -558,7 +602,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f249c6dcfe2e8403f0e309da6f6b552dcfb607b094b5038db0709f8010fa4ea0"
dependencies = [
- "gettext-rs 0.7.1",
+ "gettext-rs 0.7.2",
"quote",
]
@@ -583,9 +627,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "2.5.0"
+version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
dependencies = [
"equivalent",
"hashbrown",
@@ -593,14 +637,15 @@ dependencies = [
[[package]]
name = "itoa"
-version = "1.0.11"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "keypunch"
version = "0.1.0"
dependencies = [
+ "discord-presence",
"gettext-rs 0.6.0",
"gtk4",
"gvdb-macros",
@@ -623,9 +668,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libadwaita"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ff9c222b5c783729de45185f07b2fec2d43a7f9c63961e777d3667e20443878"
+checksum = "8611ee9fb85e7606c362b513afcaf5b59853f79e4d98caaaf581d99465014247"
dependencies = [
"gdk4",
"gio",
@@ -638,9 +683,9 @@ dependencies = [
[[package]]
name = "libadwaita-sys"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c44d8bdbad31d6639e1f20cc9c1424f1a8e02d751fc28d44659bf743fb9eca6"
+checksum = "b099a223560118d4d4fa04b6d23f3ea5b7171fe1d83dfb7e6b45b54cdfc83af9"
dependencies = [
"gdk4-sys",
"gio-sys",
@@ -654,9 +699,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.158"
+version = "0.2.169"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
[[package]]
name = "litrs"
@@ -680,6 +725,16 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
[[package]]
name = "malloc_buf"
version = "0.0.6"
@@ -706,13 +761,54 @@ dependencies = [
[[package]]
name = "miniz_oxide"
-version = "0.8.0"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
+checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
dependencies = [
"adler2",
]
+[[package]]
+name = "named_pipe"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad9c443cce91fc3e12f017290db75dde490d685cdaaf508d7159d7cf41f0eb2b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "nix"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
[[package]]
name = "objc"
version = "0.2.7"
@@ -742,11 +838,17 @@ dependencies = [
"objc",
]
+[[package]]
+name = "once_cell"
+version = "1.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+
[[package]]
name = "pango"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5764e5a174a5a0ec054fe5962ce6d4fc7052e2d0dcc23bbc77202b40a4a403d3"
+checksum = "9e89bd74250a03a05cec047b43465469102af803be2bf5e5a1088f8b8455e087"
dependencies = [
"gio",
"glib",
@@ -756,9 +858,9 @@ dependencies = [
[[package]]
name = "pango-sys"
-version = "0.20.1"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd317e1de76b14b3d3efe05518c08b360327f1ab7fec150473a89ffcad4b072d"
+checksum = "71787e0019b499a5eda889279e4adb455a4f3fdd6870cd5ab7f4a5aa25df6699"
dependencies = [
"glib-sys",
"gobject-sys",
@@ -766,11 +868,40 @@ dependencies = [
"system-deps",
]
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
[[package]]
name = "pin-project-lite"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
[[package]]
name = "pin-utils"
@@ -780,9 +911,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
-version = "0.3.30"
+version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "ppv-lite86"
@@ -802,25 +933,74 @@ dependencies = [
"toml_edit",
]
+[[package]]
+name = "proc-macro-error-attr2"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+]
+
+[[package]]
+name = "proc-macro-error2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802"
+dependencies = [
+ "proc-macro-error-attr2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
-version = "0.36.1"
+version = "0.36.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc"
+checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe"
dependencies = [
"memchr",
"serde",
]
+[[package]]
+name = "quork"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b223192745155c4f425d5c0ac0f5e18ae8a58721ebccb5f9709d18009af108ee"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "nix",
+ "quork-proc",
+ "thiserror 1.0.69",
+ "windows",
+]
+
+[[package]]
+name = "quork-proc"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5deb881b55a330d22f00f08963b89b240553c2d88841fa35f100858e552eb73"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro-error2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "quote"
version = "1.0.37"
@@ -880,11 +1060,20 @@ dependencies = [
"crossbeam-utils",
]
+[[package]]
+name = "redox_syscall"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
+dependencies = [
+ "bitflags",
+]
+
[[package]]
name = "regex"
-version = "1.10.6"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@@ -894,9 +1083,9 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.7"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -905,9 +1094,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc_version"
@@ -920,9 +1109,9 @@ dependencies = [
[[package]]
name = "rustversion"
-version = "1.0.17"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
[[package]]
name = "ryu"
@@ -939,26 +1128,32 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
[[package]]
name = "semver"
-version = "1.0.23"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
[[package]]
name = "serde"
-version = "1.0.210"
+version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.210"
+version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
dependencies = [
"proc-macro2",
"quote",
@@ -967,9 +1162,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.128"
+version = "1.0.134"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
dependencies = [
"itoa",
"memchr",
@@ -979,9 +1174,9 @@ dependencies = [
[[package]]
name = "serde_spanned"
-version = "0.6.7"
+version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
dependencies = [
"serde",
]
@@ -1034,9 +1229,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.77"
+version = "2.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035"
dependencies = [
"proc-macro2",
"quote",
@@ -1045,9 +1240,9 @@ dependencies = [
[[package]]
name = "system-deps"
-version = "7.0.2"
+version = "7.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "070a0a5e7da2d24be457809c4b3baa57a835fd2829ad8b86f9a049052fe71031"
+checksum = "66d23aaf9f331227789a99e8de4c91bf46703add012bdfd45fdecdfb2975a005"
dependencies = [
"cfg-expr",
"heck",
@@ -1064,9 +1259,49 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "temp-dir"
-version = "0.1.13"
+version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f227968ec00f0e5322f9b8173c7a0cbcff6181a0a5b28e9892491c286277231"
+checksum = "bc1ee6eef34f12f765cb94725905c6312b6610ab2b0940889cfe58dae7bc3c72"
+
+[[package]]
+name = "thiserror"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
+dependencies = [
+ "thiserror-impl 1.0.69",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc"
+dependencies = [
+ "thiserror-impl 2.0.9",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
[[package]]
name = "toml"
@@ -1091,9 +1326,9 @@ dependencies = [
[[package]]
name = "toml_edit"
-version = "0.22.21"
+version = "0.22.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
dependencies = [
"indexmap",
"serde",
@@ -1102,11 +1337,42 @@ dependencies = [
"winnow",
]
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+dependencies = [
+ "once_cell",
+]
+
[[package]]
name = "unicode-ident"
-version = "1.0.13"
+version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
+checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "unicode-segmentation"
@@ -1120,6 +1386,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc"
+[[package]]
+name = "uuid"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
+dependencies = [
+ "getrandom",
+]
+
[[package]]
name = "version-compare"
version = "0.2.0"
@@ -1164,7 +1439,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys",
]
[[package]]
@@ -1174,10 +1449,54 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
-name = "windows-sys"
-version = "0.52.0"
+name = "windows"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
+dependencies = [
+ "windows-core",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-result",
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-result"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets",
]
@@ -1257,9 +1576,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
-version = "0.6.18"
+version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
dependencies = [
"memchr",
]
diff --git a/Cargo.toml b/Cargo.toml
index 52ce02f..51113b2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
+discord-presence = "1.4.1"
gettext-rs = { version = "0.6", features = ["gettext-system"] }
gvdb-macros = "0.1.12"
i18n-format = "0.2.0"
diff --git a/build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json b/build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json
new file mode 100644
index 0000000..1b7d83a
--- /dev/null
+++ b/build-aux/dev.bragefuglseth.Keypunch.DiscordAccess.json
@@ -0,0 +1,86 @@
+{
+ "id" : "dev.bragefuglseth.Keypunch.Devel",
+ "runtime" : "org.gnome.Platform",
+ "runtime-version" : "master",
+ "sdk" : "org.gnome.Sdk",
+ "sdk-extensions" : [
+ {
+ "id" : "org.freedesktop.Sdk.Extension.rust-stable",
+ "version" : "24.08"
+ }
+ ],
+ "command" : "keypunch-wrapper.sh",
+ "finish-args" : [
+ "--share=network",
+ "--share=ipc",
+ "--socket=fallback-x11",
+ "--device=dri",
+ "--socket=wayland",
+ "--filesystem=xdg-run/app/com.discordapp.Discord:create",
+ "--env=RUST_BACKTRACE=1"
+ ],
+ "build-options" : {
+ "append-path" : "/usr/lib/sdk/rust-stable/bin",
+ "build-args" : [
+ "--share=network"
+ ],
+ "env" : {
+ "RUST_BACKTRACE" : "1",
+ "RUST_LOG" : "keypunch=debug"
+ }
+ },
+ "cleanup" : [
+ "/include",
+ "/lib/pkgconfig",
+ "/man",
+ "/share/doc",
+ "/share/gtk-doc",
+ "/share/man",
+ "/share/pkgconfig",
+ "*.la",
+ "*.a"
+ ],
+ "modules" : [
+ {
+ "name": "blueprint-compiler",
+ "buildsystem": "meson",
+ "cleanup": ["*"],
+ "sources": [
+ {
+ "type": "git",
+ "url": "https://gitlab.gnome.org/jwestman/blueprint-compiler",
+ "tag": "v0.14.0"
+ }
+ ]
+ },
+ {
+ "name" : "keypunch-wrapper",
+ "buildsystem" : "simple",
+ "build-commands" : [
+ "install -Dm755 keypunch-wrapper.sh /app/bin/keypunch-wrapper.sh"
+ ],
+ "sources" : [
+ {
+ "type" : "script",
+ "dest-filename" : "keypunch-wrapper.sh",
+ "commands" : [
+ "for i in {0..9}; do\ntest -S $XDG_RUNTIME_DIR/discord-ipc-$i || ln -sf {app/com.discordapp.Discord,$XDG_RUNTIME_DIR}/discord-ipc-$i;\ndone",
+ "keypunch"
+ ]
+ }
+ ]
+ },
+ {
+ "name" : "keypunch",
+ "builddir" : true,
+ "buildsystem" : "meson",
+ "run-tests" : true,
+ "sources" : [
+ {
+ "type" : "dir",
+ "path" : ".."
+ }
+ ]
+ }
+ ]
+}
diff --git a/data/discord-rpc-artwork.svg b/data/discord-rpc-artwork.svg
new file mode 100644
index 0000000..5ba944f
--- /dev/null
+++ b/data/discord-rpc-artwork.svg
@@ -0,0 +1,2392 @@
+
+
+
+
diff --git a/src/application.rs b/src/application.rs
index 8357e9e..7ebf413 100644
--- a/src/application.rs
+++ b/src/application.rs
@@ -18,6 +18,7 @@
* SPDX-License-Identifier: GPL-3.0-or-later
*/
+use crate::discord_rpc::RpcWrapper;
use adw::subclass::prelude::*;
use gtk::prelude::*;
use gtk::{gio, glib};
@@ -27,8 +28,10 @@ use crate::widgets::KpWindow;
mod imp {
use super::*;
- #[derive(Debug, Default)]
- pub struct KpApplication {}
+ #[derive(Default)]
+ pub struct KpApplication {
+ pub discord_rpc: RpcWrapper,
+ }
#[glib::object_subclass]
impl ObjectSubclass for KpApplication {
@@ -95,4 +98,8 @@ impl KpApplication {
self.add_action_entries(actions);
}
+
+ pub fn discord_rpc(&self) -> &RpcWrapper {
+ &self.imp().discord_rpc
+ }
}
diff --git a/src/discord_rpc.rs b/src/discord_rpc.rs
new file mode 100644
index 0000000..a894d25
--- /dev/null
+++ b/src/discord_rpc.rs
@@ -0,0 +1,145 @@
+use crate::session_enums::*;
+use discord_presence::models::rich_presence::Activity;
+use discord_presence::Client;
+use std::sync::mpsc;
+use std::sync::mpsc::Sender;
+use std::thread;
+use std::time::SystemTime;
+
+const DISCORD_CLIENT_ID: u64 = 1320106636743802923;
+
+enum RpcMessage {
+ SendStored,
+ Change(SessionType, SessionDuration, PresenceState),
+ UpdateStats(f64, f64),
+}
+
+pub struct RpcWrapper {
+ sender: Sender,
+}
+
+impl Default for RpcWrapper {
+ fn default() -> Self {
+ let (sender, receiver) = mpsc::channel();
+
+ let sender_clone = sender.clone();
+
+ thread::spawn(move || {
+ let start_time = SystemTime::now()
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .ok()
+ .map(|d| d.as_millis() as u64);
+
+ let mut stored_activity = Activity::new();
+ let mut stored_stats: Option<(f64, f64)> = None; // WPM & accuracy
+
+ let mut client = Client::new(DISCORD_CLIENT_ID);
+
+ client
+ .on_connected(move |_ctx| {
+ sender_clone
+ .send(RpcMessage::SendStored)
+ .expect("channel exists until app shuts down");
+ })
+ .persist();
+
+ client.start();
+
+ for msg in receiver.iter() {
+ if let RpcMessage::Change(session_type, duration, state) = msg {
+ let details_string = match session_type {
+ SessionType::Simple => format!("Simple, {}", duration.english_string()),
+ SessionType::Advanced => format!("Advanced, {}", duration.english_string()),
+ SessionType::Custom => "Custom text".to_string(),
+ };
+
+ stored_activity = Activity::new()
+ .state(state.english_string())
+ .details(details_string);
+ } else if let RpcMessage::UpdateStats(wpm, accuracy) = msg {
+ stored_stats = Some((wpm, accuracy));
+ }
+
+ if let Some(time) = start_time {
+ stored_activity = stored_activity.timestamps(|t| t.start(time));
+ }
+
+ if let Some((wpm, accuracy)) = stored_stats {
+ let display_accuracy = (accuracy * 100.).floor() as usize;
+
+ stored_activity = stored_activity.assets(|a| {
+ a.large_image("main")
+ .large_text("Keypunch")
+ .small_image(wpm_to_image(wpm))
+ .small_text(format!(
+ "{:.0} WPM, {:.0}% correctness",
+ wpm.floor(), display_accuracy
+ ))
+ });
+ } else {
+ stored_activity =
+ stored_activity.assets(|a| a.large_image("main").large_text("Keypunch"));
+ };
+
+ let _ = client.set_activity(|mut a| {
+ a.clone_from(&stored_activity);
+ a
+ });
+ }
+ });
+
+ RpcWrapper { sender }
+ }
+}
+
+impl RpcWrapper {
+ pub fn set_activity(
+ &self,
+ session_type: SessionType,
+ duration: SessionDuration,
+ state: PresenceState,
+ ) {
+ self.sender
+ .send(RpcMessage::Change(session_type, duration, state))
+ .expect("channel exists until app shuts down");
+ }
+
+ pub fn set_stats(&self, wpm: f64, accuracy: f64) {
+ self.sender
+ .send(RpcMessage::UpdateStats(wpm, accuracy))
+ .expect("channel exists until app shuts down");
+ }
+}
+
+fn wpm_to_image(wpm: f64) -> &'static str {
+ const WPM_IMAGES: &'static [(f64, &'static str)] = &[
+ (10., "0-wpm"),
+ (20., "10-wpm"),
+ (30., "20-wpm"),
+ (40., "30-wpm"),
+ (50., "40-wpm"),
+ (60., "50-wpm"),
+ (70., "60-wpm"),
+ (80., "70-wpm"),
+ (90., "80-wpm"),
+ (100., "90-wpm"),
+ (110., "100-wpm"),
+ (120., "110-wpm"),
+ (130., "120-wpm"),
+ (140., "130-wpm"),
+ (150., "140-wpm"),
+ (160., "150-wpm"),
+ (170., "160-wpm"),
+ (180., "170-wpm"),
+ (190., "180-wpm"),
+ (200., "190-wpm"),
+ ];
+
+ for (threshold, image) in WPM_IMAGES {
+ if wpm < *threshold {
+ return image;
+ }
+ }
+
+ "200-wpm"
+}
diff --git a/src/main.rs b/src/main.rs
index 5a96b19..6645e18 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,6 +20,8 @@
mod application;
mod config;
+mod discord_rpc;
+mod session_enums;
mod text_generation;
mod text_utils;
mod widgets;
diff --git a/src/session_enums.rs b/src/session_enums.rs
new file mode 100644
index 0000000..46e4862
--- /dev/null
+++ b/src/session_enums.rs
@@ -0,0 +1,69 @@
+use gettextrs::gettext;
+use strum_macros::{Display as EnumDisplay, EnumIter, EnumString};
+
+#[derive(Clone, Copy, Default, PartialEq, EnumString, EnumDisplay, EnumIter)]
+pub enum SessionType {
+ #[default]
+ Simple,
+ Advanced,
+ Custom,
+}
+
+impl SessionType {
+ pub fn ui_string(&self) -> String {
+ match self {
+ SessionType::Simple => gettext("Simple"),
+ SessionType::Advanced => gettext("Advanced"),
+ SessionType::Custom => gettext("Custom"),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Default, PartialEq, EnumString, EnumDisplay, EnumIter)]
+pub enum SessionDuration {
+ #[default]
+ Sec15,
+ Sec30,
+ Min1,
+ Min5,
+ Min10,
+}
+
+impl SessionDuration {
+ pub fn ui_string(&self) -> String {
+ match self {
+ SessionDuration::Sec15 => gettext("15 seconds"),
+ SessionDuration::Sec30 => gettext("30 seconds"),
+ SessionDuration::Min1 => gettext("1 minute"),
+ SessionDuration::Min5 => gettext("5 minutes"),
+ SessionDuration::Min10 => gettext("10 minutes"),
+ }
+ }
+
+ pub fn english_string(&self) -> &str {
+ match self {
+ SessionDuration::Sec15 => "15 seconds",
+ SessionDuration::Sec30 => "30 seconds",
+ SessionDuration::Min1 => "1 minute",
+ SessionDuration::Min5 => "5 minutes",
+ SessionDuration::Min10 => "10 minutes",
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub enum PresenceState {
+ Ready,
+ Typing,
+ Results,
+}
+
+impl PresenceState {
+ pub fn english_string(&self) -> &str {
+ match self {
+ PresenceState::Ready => "Ready to start",
+ PresenceState::Typing => "Typing",
+ PresenceState::Results => "Viewing results",
+ }
+ }
+}
diff --git a/src/text_generation.rs b/src/text_generation.rs
index e7ae0a8..3893516 100644
--- a/src/text_generation.rs
+++ b/src/text_generation.rs
@@ -264,7 +264,7 @@ pub fn advanced(language: Language) -> String {
" ",
GENERIC_PUNCTUATION,
WESTERN_ARABIC_NUMERALS,
- )
+ ),
}
}
diff --git a/src/widgets/window.rs b/src/widgets/window.rs
index 91e697e..5247a61 100644
--- a/src/widgets/window.rs
+++ b/src/widgets/window.rs
@@ -25,6 +25,7 @@ mod settings;
mod ui_state;
use crate::config::APP_ID;
+use crate::session_enums::*;
use crate::text_generation::Language;
use crate::widgets::{KpResultsView, KpTextView};
use adw::prelude::*;
@@ -33,47 +34,6 @@ use gettextrs::gettext;
use gtk::{gio, glib};
use std::cell::{Cell, OnceCell, RefCell};
use std::time::{Duration, Instant};
-use strum_macros::{Display as EnumDisplay, EnumIter, EnumString};
-
-#[derive(Clone, Copy, Default, PartialEq, EnumString, EnumDisplay, EnumIter)]
-pub enum SessionType {
- #[default]
- Simple,
- Advanced,
- Custom,
-}
-
-impl SessionType {
- pub fn ui_string(&self) -> String {
- match self {
- SessionType::Simple => gettext("Simple"),
- SessionType::Advanced => gettext("Advanced"),
- SessionType::Custom => gettext("Custom"),
- }
- }
-}
-
-#[derive(Copy, Clone, Default, PartialEq, EnumString, EnumDisplay, EnumIter)]
-pub enum SessionDuration {
- #[default]
- Sec15,
- Sec30,
- Min1,
- Min5,
- Min10,
-}
-
-impl SessionDuration {
- pub fn ui_string(&self) -> String {
- match self {
- SessionDuration::Sec15 => gettext("15 seconds"),
- SessionDuration::Sec30 => gettext("30 seconds"),
- SessionDuration::Min1 => gettext("1 minute"),
- SessionDuration::Min5 => gettext("5 minutes"),
- SessionDuration::Min10 => gettext("10 minutes"),
- }
- }
-}
mod imp {
use super::*;
@@ -186,8 +146,6 @@ mod imp {
self.setup_continue_button();
self.setup_ui_hiding();
self.show_cursor();
-
- self.ready();
}
}
impl WidgetImpl for KpWindow {}
@@ -264,9 +222,12 @@ glib::wrapper! {
impl KpWindow {
pub fn new>(application: &P) -> Self {
- glib::Object::builder()
+ let obj: KpWindow = glib::Object::builder()
.property("application", application)
- .build()
+ .build();
+
+ obj.imp().ready();
+
+ obj
}
}
-
diff --git a/src/widgets/window/session.rs b/src/widgets/window/session.rs
index 0fb04bf..0013eac 100644
--- a/src/widgets/window/session.rs
+++ b/src/widgets/window/session.rs
@@ -1,4 +1,5 @@
use super::*;
+use crate::application::KpApplication;
use crate::text_generation;
use crate::text_utils::{calculate_accuracy, calculate_wpm, process_custom_text, GraphemeState};
use crate::widgets::{KpCustomTextDialog, KpTextLanguageDialog};
@@ -150,6 +151,19 @@ impl imp::KpWindow {
self.text_view.set_original_text(&new_original);
self.secondary_config_stack
.set_visible_child(&config_widget);
+
+ // Discord IPC
+ self.obj()
+ .application()
+ .expect("ready() isn't called before window has been paired with application")
+ .downcast_ref::()
+ .unwrap()
+ .discord_rpc()
+ .set_activity(
+ self.session_type.get(),
+ self.duration.get(),
+ PresenceState::Ready,
+ );
}
pub(super) fn update_time(&self) {
@@ -161,6 +175,19 @@ impl imp::KpWindow {
self.settings()
.set_string("session-duration", &selected.to_string())
.unwrap();
+
+ // Discord IPC
+ self.obj()
+ .application()
+ .expect("ready() isn't called before window has been paired with application")
+ .downcast_ref::()
+ .unwrap()
+ .discord_rpc()
+ .set_activity(
+ self.session_type.get(),
+ self.duration.get(),
+ PresenceState::Ready,
+ );
}
pub(super) fn show_text_language_dialog(&self) {
@@ -473,6 +500,15 @@ impl imp::KpWindow {
}
),
);
+
+ // Discord IPC
+ self.obj()
+ .application()
+ .expect("ready() isn't called before window has been paired with application")
+ .downcast_ref::()
+ .unwrap()
+ .discord_rpc()
+ .set_stats(wpm, accuracy);
}
}
diff --git a/src/widgets/window/ui_state.rs b/src/widgets/window/ui_state.rs
index 0212609..9d4a255 100644
--- a/src/widgets/window/ui_state.rs
+++ b/src/widgets/window/ui_state.rs
@@ -1,4 +1,5 @@
use super::*;
+use crate::application::KpApplication;
impl imp::KpWindow {
pub(super) fn setup_stop_button(&self) {
@@ -105,6 +106,19 @@ impl imp::KpWindow {
self.obj().action_set_enabled("win.cancel-session", false);
self.obj().remove_css_class("hide-controls");
+ // Discord IPC
+ self.obj()
+ .application()
+ .expect("ready() isn't called before window has been paired with application")
+ .downcast_ref::()
+ .unwrap()
+ .discord_rpc()
+ .set_activity(
+ self.session_type.get(),
+ self.duration.get(),
+ PresenceState::Ready,
+ );
+
self.end_existing_inhibit();
}
@@ -133,7 +147,7 @@ impl imp::KpWindow {
imp.stop_button.set_opacity(1.);
}
}
- )
+ ),
);
match self.session_type.get() {
@@ -146,6 +160,19 @@ impl imp::KpWindow {
self.obj().action_set_enabled("win.cancel-session", true);
self.obj().add_css_class("hide-controls");
+ // Discord IPC
+ self.obj()
+ .application()
+ .expect("ready() isn't called before window has been paired with application")
+ .downcast_ref::()
+ .unwrap()
+ .discord_rpc()
+ .set_activity(
+ self.session_type.get(),
+ self.duration.get(),
+ PresenceState::Typing,
+ );
+
// Translators: This is shown as a warning by GNOME Shell before logging out or shutting off the system in the middle of a typing session, alongside Keypunch's name and icon
self.inhibit_session(&gettext("Ongoing typing session"))
}
@@ -167,6 +194,19 @@ impl imp::KpWindow {
self.obj().action_set_enabled("win.cancel-session", false);
self.end_existing_inhibit();
+
+ // Discord IPC
+ self.obj()
+ .application()
+ .expect("ready() isn't called before window has been paired with application")
+ .downcast_ref::()
+ .unwrap()
+ .discord_rpc()
+ .set_activity(
+ self.session_type.get(),
+ self.duration.get(),
+ PresenceState::Results,
+ );
}
pub(super) fn hide_cursor(&self) {