tenseleyflow/hyprkvm / e80de63

Browse files

fix: multi-monitor edge barriers and cursor positioning

Major fixes for edge barrier placement and cursor positioning in
multi-monitor setups:

- Calculate proper screen bounds (min_x, min_y, max_x, max_y) instead
of just max coordinates
- Fix handle_enter to use actual screen bounds for cursor placement
- Fix initiate_transfer to calculate edge-relative position correctly
with proper offset from screen origin
- Fix IPC Switch handler to use global screen bounds instead of
focused monitor dimensions
- Fix capture.rs output position matching to use explicit tracking
instead of checking for (0,0) coordinates
- Add direction negotiation in Hello handshake for automatic
bidirectional config sync
- Add systemd service file for daemon management
- Add GUI for machine layout configuration (iced-based)

The direction sync allows peers to automatically update their config
when the other machine changes direction, triggering a restart to
rebuild edge barriers.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
e80de63d626879114a9cf071b4e2224ced3a5fc9
Parents
d61acf2
Tree
c219d63

15 changed files

StatusFile+-
M Cargo.lock 4110 762
M Cargo.toml 3 0
M flake.nix 50 1
M hyprkvm-common/src/protocol/mod.rs 3 0
M hyprkvm-daemon/Cargo.toml 7 0
A hyprkvm-daemon/src/gui/app.rs 477 0
A hyprkvm-daemon/src/gui/canvas.rs 361 0
A hyprkvm-daemon/src/gui/messages.rs 50 0
A hyprkvm-daemon/src/gui/mod.rs 24 0
A hyprkvm-daemon/src/gui/state.rs 330 0
A hyprkvm-daemon/src/gui/theme.rs 55 0
M hyprkvm-daemon/src/input/capture.rs 7 4
M hyprkvm-daemon/src/main.rs 185 64
M hyprkvm-daemon/src/network/peer.rs 1 0
M hyprkvm-daemon/src/transfer/manager.rs 35 21
Cargo.lockmodified
5660 lines changed — click to load
@@ -2,6 +2,52 @@
22
 # It is not intended for manual editing.
33
 version = 4
44
 
5
+[[package]]
6
+name = "ab_glyph"
7
+version = "0.2.32"
8
+source = "registry+https://github.com/rust-lang/crates.io-index"
9
+checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2"
10
+dependencies = [
11
+ "ab_glyph_rasterizer",
12
+ "owned_ttf_parser",
13
+]
14
+
15
+[[package]]
16
+name = "ab_glyph_rasterizer"
17
+version = "0.1.10"
18
+source = "registry+https://github.com/rust-lang/crates.io-index"
19
+checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
20
+
21
+[[package]]
22
+name = "adler2"
23
+version = "2.0.1"
24
+source = "registry+https://github.com/rust-lang/crates.io-index"
25
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
26
+
27
+[[package]]
28
+name = "ahash"
29
+version = "0.7.8"
30
+source = "registry+https://github.com/rust-lang/crates.io-index"
31
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
32
+dependencies = [
33
+ "getrandom 0.2.16",
34
+ "once_cell",
35
+ "version_check",
36
+]
37
+
38
+[[package]]
39
+name = "ahash"
40
+version = "0.8.12"
41
+source = "registry+https://github.com/rust-lang/crates.io-index"
42
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
43
+dependencies = [
44
+ "cfg-if",
45
+ "getrandom 0.3.4",
46
+ "once_cell",
47
+ "version_check",
48
+ "zerocopy",
49
+]
50
+
551
 [[package]]
652
 name = "aho-corasick"
753
 version = "1.1.4"
@@ -11,6 +57,48 @@ dependencies = [
1157
  "memchr",
1258
 ]
1359
 
60
+[[package]]
61
+name = "allocator-api2"
62
+version = "0.2.21"
63
+source = "registry+https://github.com/rust-lang/crates.io-index"
64
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
65
+
66
+[[package]]
67
+name = "android-activity"
68
+version = "0.6.0"
69
+source = "registry+https://github.com/rust-lang/crates.io-index"
70
+checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046"
71
+dependencies = [
72
+ "android-properties",
73
+ "bitflags 2.10.0",
74
+ "cc",
75
+ "cesu8",
76
+ "jni",
77
+ "jni-sys",
78
+ "libc",
79
+ "log",
80
+ "ndk",
81
+ "ndk-context",
82
+ "ndk-sys 0.6.0+11769913",
83
+ "num_enum",
84
+ "thiserror 1.0.69",
85
+]
86
+
87
+[[package]]
88
+name = "android-properties"
89
+version = "0.2.2"
90
+source = "registry+https://github.com/rust-lang/crates.io-index"
91
+checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
92
+
93
+[[package]]
94
+name = "android_system_properties"
95
+version = "0.1.5"
96
+source = "registry+https://github.com/rust-lang/crates.io-index"
97
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
98
+dependencies = [
99
+ "libc",
100
+]
101
+
14102
 [[package]]
15103
 name = "anstream"
16104
 version = "0.6.21"
@@ -67,6 +155,190 @@ version = "1.0.100"
67155
 source = "registry+https://github.com/rust-lang/crates.io-index"
68156
 checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
69157
 
158
+[[package]]
159
+name = "approx"
160
+version = "0.5.1"
161
+source = "registry+https://github.com/rust-lang/crates.io-index"
162
+checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
163
+dependencies = [
164
+ "num-traits",
165
+]
166
+
167
+[[package]]
168
+name = "arrayref"
169
+version = "0.3.9"
170
+source = "registry+https://github.com/rust-lang/crates.io-index"
171
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
172
+
173
+[[package]]
174
+name = "arrayvec"
175
+version = "0.7.6"
176
+source = "registry+https://github.com/rust-lang/crates.io-index"
177
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
178
+
179
+[[package]]
180
+name = "as-raw-xcb-connection"
181
+version = "1.0.1"
182
+source = "registry+https://github.com/rust-lang/crates.io-index"
183
+checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
184
+
185
+[[package]]
186
+name = "ash"
187
+version = "0.37.3+1.3.251"
188
+source = "registry+https://github.com/rust-lang/crates.io-index"
189
+checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a"
190
+dependencies = [
191
+ "libloading 0.7.4",
192
+]
193
+
194
+[[package]]
195
+name = "async-broadcast"
196
+version = "0.7.2"
197
+source = "registry+https://github.com/rust-lang/crates.io-index"
198
+checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
199
+dependencies = [
200
+ "event-listener",
201
+ "event-listener-strategy",
202
+ "futures-core",
203
+ "pin-project-lite",
204
+]
205
+
206
+[[package]]
207
+name = "async-channel"
208
+version = "2.5.0"
209
+source = "registry+https://github.com/rust-lang/crates.io-index"
210
+checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
211
+dependencies = [
212
+ "concurrent-queue",
213
+ "event-listener-strategy",
214
+ "futures-core",
215
+ "pin-project-lite",
216
+]
217
+
218
+[[package]]
219
+name = "async-executor"
220
+version = "1.13.3"
221
+source = "registry+https://github.com/rust-lang/crates.io-index"
222
+checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8"
223
+dependencies = [
224
+ "async-task",
225
+ "concurrent-queue",
226
+ "fastrand",
227
+ "futures-lite",
228
+ "pin-project-lite",
229
+ "slab",
230
+]
231
+
232
+[[package]]
233
+name = "async-fs"
234
+version = "2.2.0"
235
+source = "registry+https://github.com/rust-lang/crates.io-index"
236
+checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5"
237
+dependencies = [
238
+ "async-lock",
239
+ "blocking",
240
+ "futures-lite",
241
+]
242
+
243
+[[package]]
244
+name = "async-io"
245
+version = "2.6.0"
246
+source = "registry+https://github.com/rust-lang/crates.io-index"
247
+checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
248
+dependencies = [
249
+ "autocfg",
250
+ "cfg-if",
251
+ "concurrent-queue",
252
+ "futures-io",
253
+ "futures-lite",
254
+ "parking",
255
+ "polling",
256
+ "rustix 1.1.3",
257
+ "slab",
258
+ "windows-sys 0.61.2",
259
+]
260
+
261
+[[package]]
262
+name = "async-lock"
263
+version = "3.4.2"
264
+source = "registry+https://github.com/rust-lang/crates.io-index"
265
+checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
266
+dependencies = [
267
+ "event-listener",
268
+ "event-listener-strategy",
269
+ "pin-project-lite",
270
+]
271
+
272
+[[package]]
273
+name = "async-process"
274
+version = "2.5.0"
275
+source = "registry+https://github.com/rust-lang/crates.io-index"
276
+checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
277
+dependencies = [
278
+ "async-channel",
279
+ "async-io",
280
+ "async-lock",
281
+ "async-signal",
282
+ "async-task",
283
+ "blocking",
284
+ "cfg-if",
285
+ "event-listener",
286
+ "futures-lite",
287
+ "rustix 1.1.3",
288
+]
289
+
290
+[[package]]
291
+name = "async-recursion"
292
+version = "1.1.1"
293
+source = "registry+https://github.com/rust-lang/crates.io-index"
294
+checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
295
+dependencies = [
296
+ "proc-macro2",
297
+ "quote",
298
+ "syn 2.0.113",
299
+]
300
+
301
+[[package]]
302
+name = "async-signal"
303
+version = "0.2.13"
304
+source = "registry+https://github.com/rust-lang/crates.io-index"
305
+checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c"
306
+dependencies = [
307
+ "async-io",
308
+ "async-lock",
309
+ "atomic-waker",
310
+ "cfg-if",
311
+ "futures-core",
312
+ "futures-io",
313
+ "rustix 1.1.3",
314
+ "signal-hook-registry",
315
+ "slab",
316
+ "windows-sys 0.61.2",
317
+]
318
+
319
+[[package]]
320
+name = "async-task"
321
+version = "4.7.1"
322
+source = "registry+https://github.com/rust-lang/crates.io-index"
323
+checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
324
+
325
+[[package]]
326
+name = "async-trait"
327
+version = "0.1.89"
328
+source = "registry+https://github.com/rust-lang/crates.io-index"
329
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
330
+dependencies = [
331
+ "proc-macro2",
332
+ "quote",
333
+ "syn 2.0.113",
334
+]
335
+
336
+[[package]]
337
+name = "atomic-waker"
338
+version = "1.1.2"
339
+source = "registry+https://github.com/rust-lang/crates.io-index"
340
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
341
+
70342
 [[package]]
71343
 name = "autocfg"
72344
 version = "1.5.0"
@@ -101,6 +373,21 @@ version = "0.22.1"
101373
 source = "registry+https://github.com/rust-lang/crates.io-index"
102374
 checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
103375
 
376
+[[package]]
377
+name = "bit-set"
378
+version = "0.5.3"
379
+source = "registry+https://github.com/rust-lang/crates.io-index"
380
+checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
381
+dependencies = [
382
+ "bit-vec",
383
+]
384
+
385
+[[package]]
386
+name = "bit-vec"
387
+version = "0.6.3"
388
+source = "registry+https://github.com/rust-lang/crates.io-index"
389
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
390
+
104391
 [[package]]
105392
 name = "bitflags"
106393
 version = "1.3.2"
@@ -125,6 +412,12 @@ dependencies = [
125412
  "wyz",
126413
 ]
127414
 
415
+[[package]]
416
+name = "block"
417
+version = "0.1.6"
418
+source = "registry+https://github.com/rust-lang/crates.io-index"
419
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
420
+
128421
 [[package]]
129422
 name = "block-buffer"
130423
 version = "0.10.4"
@@ -134,6 +427,40 @@ dependencies = [
134427
  "generic-array",
135428
 ]
136429
 
430
+[[package]]
431
+name = "block2"
432
+version = "0.5.1"
433
+source = "registry+https://github.com/rust-lang/crates.io-index"
434
+checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
435
+dependencies = [
436
+ "objc2 0.5.2",
437
+]
438
+
439
+[[package]]
440
+name = "blocking"
441
+version = "1.6.2"
442
+source = "registry+https://github.com/rust-lang/crates.io-index"
443
+checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21"
444
+dependencies = [
445
+ "async-channel",
446
+ "async-task",
447
+ "futures-io",
448
+ "futures-lite",
449
+ "piper",
450
+]
451
+
452
+[[package]]
453
+name = "bumpalo"
454
+version = "3.19.1"
455
+source = "registry+https://github.com/rust-lang/crates.io-index"
456
+checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
457
+
458
+[[package]]
459
+name = "by_address"
460
+version = "1.2.1"
461
+source = "registry+https://github.com/rust-lang/crates.io-index"
462
+checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
463
+
137464
 [[package]]
138465
 name = "bytemuck"
139466
 version = "1.24.0"
@@ -151,7 +478,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
151478
 dependencies = [
152479
  "proc-macro2",
153480
  "quote",
154
- "syn",
481
+ "syn 2.0.113",
155482
 ]
156483
 
157484
 [[package]]
@@ -174,18 +501,43 @@ dependencies = [
174501
  "thiserror 1.0.69",
175502
 ]
176503
 
504
+[[package]]
505
+name = "calloop"
506
+version = "0.14.3"
507
+source = "registry+https://github.com/rust-lang/crates.io-index"
508
+checksum = "cb9f6e1368bd4621d2c86baa7e37de77a938adf5221e5dd3d6133340101b309e"
509
+dependencies = [
510
+ "bitflags 2.10.0",
511
+ "polling",
512
+ "rustix 1.1.3",
513
+ "slab",
514
+ "tracing",
515
+]
516
+
177517
 [[package]]
178518
 name = "calloop-wayland-source"
179519
 version = "0.3.0"
180520
 source = "registry+https://github.com/rust-lang/crates.io-index"
181521
 checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20"
182522
 dependencies = [
183
- "calloop",
523
+ "calloop 0.13.0",
184524
  "rustix 0.38.44",
185525
  "wayland-backend",
186526
  "wayland-client",
187527
 ]
188528
 
529
+[[package]]
530
+name = "calloop-wayland-source"
531
+version = "0.4.1"
532
+source = "registry+https://github.com/rust-lang/crates.io-index"
533
+checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"
534
+dependencies = [
535
+ "calloop 0.14.3",
536
+ "rustix 1.1.3",
537
+ "wayland-backend",
538
+ "wayland-client",
539
+]
540
+
189541
 [[package]]
190542
 name = "cc"
191543
 version = "1.2.51"
@@ -198,12 +550,30 @@ dependencies = [
198550
  "shlex",
199551
 ]
200552
 
553
+[[package]]
554
+name = "cesu8"
555
+version = "1.1.0"
556
+source = "registry+https://github.com/rust-lang/crates.io-index"
557
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
558
+
201559
 [[package]]
202560
 name = "cfg-if"
203561
 version = "1.0.4"
204562
 source = "registry+https://github.com/rust-lang/crates.io-index"
205563
 checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
206564
 
565
+[[package]]
566
+name = "cfg_aliases"
567
+version = "0.1.1"
568
+source = "registry+https://github.com/rust-lang/crates.io-index"
569
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
570
+
571
+[[package]]
572
+name = "cfg_aliases"
573
+version = "0.2.1"
574
+source = "registry+https://github.com/rust-lang/crates.io-index"
575
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
576
+
207577
 [[package]]
208578
 name = "clap"
209579
 version = "4.5.54"
@@ -235,7 +605,7 @@ dependencies = [
235605
  "heck",
236606
  "proc-macro2",
237607
  "quote",
238
- "syn",
608
+ "syn 2.0.113",
239609
 ]
240610
 
241611
 [[package]]
@@ -245,1365 +615,4015 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
245615
 checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
246616
 
247617
 [[package]]
248
-name = "cmake"
249
-version = "0.1.57"
618
+name = "clipboard-win"
619
+version = "5.4.1"
250620
 source = "registry+https://github.com/rust-lang/crates.io-index"
251
-checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
621
+checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
252622
 dependencies = [
253
- "cc",
623
+ "error-code",
254624
 ]
255625
 
256626
 [[package]]
257
-name = "colorchoice"
258
-version = "1.0.4"
627
+name = "clipboard_macos"
628
+version = "0.1.1"
259629
 source = "registry+https://github.com/rust-lang/crates.io-index"
260
-checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
630
+checksum = "9b7f4aaa047ba3c3630b080bb9860894732ff23e2aee290a418909aa6d5df38f"
631
+dependencies = [
632
+ "objc2 0.5.2",
633
+ "objc2-app-kit",
634
+ "objc2-foundation 0.2.2",
635
+]
261636
 
262637
 [[package]]
263
-name = "concurrent-queue"
264
-version = "2.5.0"
638
+name = "clipboard_wayland"
639
+version = "0.2.2"
265640
 source = "registry+https://github.com/rust-lang/crates.io-index"
266
-checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
641
+checksum = "003f886bc4e2987729d10c1db3424e7f80809f3fc22dbc16c685738887cb37b8"
267642
 dependencies = [
268
- "crossbeam-utils",
643
+ "smithay-clipboard",
269644
 ]
270645
 
271646
 [[package]]
272
-name = "cpufeatures"
273
-version = "0.2.17"
647
+name = "clipboard_x11"
648
+version = "0.4.3"
274649
 source = "registry+https://github.com/rust-lang/crates.io-index"
275
-checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
650
+checksum = "bd63e33452ffdafd39924c4f05a5dd1e94db646c779c6bd59148a3d95fff5ad4"
276651
 dependencies = [
277
- "libc",
652
+ "thiserror 2.0.17",
653
+ "x11rb",
278654
 ]
279655
 
280656
 [[package]]
281
-name = "crossbeam-channel"
282
-version = "0.5.15"
657
+name = "cmake"
658
+version = "0.1.57"
283659
 source = "registry+https://github.com/rust-lang/crates.io-index"
284
-checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
660
+checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d"
285661
 dependencies = [
286
- "crossbeam-utils",
662
+ "cc",
287663
 ]
288664
 
289665
 [[package]]
290
-name = "crossbeam-utils"
291
-version = "0.8.21"
666
+name = "codespan-reporting"
667
+version = "0.11.1"
292668
 source = "registry+https://github.com/rust-lang/crates.io-index"
293
-checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
669
+checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
670
+dependencies = [
671
+ "termcolor",
672
+ "unicode-width",
673
+]
294674
 
295675
 [[package]]
296
-name = "crypto-common"
297
-version = "0.1.7"
676
+name = "colorchoice"
677
+version = "1.0.4"
298678
 source = "registry+https://github.com/rust-lang/crates.io-index"
299
-checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
679
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
680
+
681
+[[package]]
682
+name = "com"
683
+version = "0.6.0"
684
+source = "registry+https://github.com/rust-lang/crates.io-index"
685
+checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6"
300686
 dependencies = [
301
- "generic-array",
302
- "typenum",
687
+ "com_macros",
303688
 ]
304689
 
305690
 [[package]]
306
-name = "cursor-icon"
307
-version = "1.2.0"
691
+name = "com_macros"
692
+version = "0.6.0"
308693
 source = "registry+https://github.com/rust-lang/crates.io-index"
309
-checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
694
+checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5"
695
+dependencies = [
696
+ "com_macros_support",
697
+ "proc-macro2",
698
+ "syn 1.0.109",
699
+]
310700
 
311701
 [[package]]
312
-name = "deranged"
313
-version = "0.5.5"
702
+name = "com_macros_support"
703
+version = "0.6.0"
314704
 source = "registry+https://github.com/rust-lang/crates.io-index"
315
-checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
705
+checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c"
316706
 dependencies = [
317
- "powerfmt",
707
+ "proc-macro2",
708
+ "quote",
709
+ "syn 1.0.109",
318710
 ]
319711
 
320712
 [[package]]
321
-name = "digest"
322
-version = "0.10.7"
713
+name = "combine"
714
+version = "4.6.7"
323715
 source = "registry+https://github.com/rust-lang/crates.io-index"
324
-checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
716
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
325717
 dependencies = [
326
- "block-buffer",
327
- "crypto-common",
718
+ "bytes",
719
+ "memchr",
328720
 ]
329721
 
330722
 [[package]]
331
-name = "dirs"
332
-version = "5.0.1"
723
+name = "concurrent-queue"
724
+version = "2.5.0"
333725
 source = "registry+https://github.com/rust-lang/crates.io-index"
334
-checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
726
+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
335727
 dependencies = [
336
- "dirs-sys",
728
+ "crossbeam-utils",
337729
 ]
338730
 
339731
 [[package]]
340
-name = "dirs-sys"
341
-version = "0.4.1"
732
+name = "core-foundation"
733
+version = "0.9.4"
342734
 source = "registry+https://github.com/rust-lang/crates.io-index"
343
-checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
735
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
344736
 dependencies = [
737
+ "core-foundation-sys",
345738
  "libc",
346
- "option-ext",
347
- "redox_users",
348
- "windows-sys 0.48.0",
349739
 ]
350740
 
351741
 [[package]]
352
-name = "downcast-rs"
353
-version = "1.2.1"
742
+name = "core-foundation-sys"
743
+version = "0.8.7"
354744
 source = "registry+https://github.com/rust-lang/crates.io-index"
355
-checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
745
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
356746
 
357747
 [[package]]
358
-name = "dunce"
359
-version = "1.0.5"
748
+name = "core-graphics"
749
+version = "0.23.2"
360750
 source = "registry+https://github.com/rust-lang/crates.io-index"
361
-checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
751
+checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
752
+dependencies = [
753
+ "bitflags 1.3.2",
754
+ "core-foundation",
755
+ "core-graphics-types",
756
+ "foreign-types",
757
+ "libc",
758
+]
362759
 
363760
 [[package]]
364
-name = "equivalent"
365
-version = "1.0.2"
761
+name = "core-graphics-types"
762
+version = "0.1.3"
366763
 source = "registry+https://github.com/rust-lang/crates.io-index"
367
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
764
+checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
765
+dependencies = [
766
+ "bitflags 1.3.2",
767
+ "core-foundation",
768
+ "libc",
769
+]
368770
 
369771
 [[package]]
370
-name = "errno"
371
-version = "0.3.14"
772
+name = "cosmic-text"
773
+version = "0.12.1"
372774
 source = "registry+https://github.com/rust-lang/crates.io-index"
373
-checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
775
+checksum = "59fd57d82eb4bfe7ffa9b1cec0c05e2fd378155b47f255a67983cb4afe0e80c2"
374776
 dependencies = [
375
- "libc",
376
- "windows-sys 0.61.2",
777
+ "bitflags 2.10.0",
778
+ "fontdb",
779
+ "log",
780
+ "rangemap",
781
+ "rayon",
782
+ "rustc-hash 1.1.0",
783
+ "rustybuzz",
784
+ "self_cell",
785
+ "swash",
786
+ "sys-locale",
787
+ "ttf-parser 0.21.1",
788
+ "unicode-bidi",
789
+ "unicode-linebreak",
790
+ "unicode-script",
791
+ "unicode-segmentation",
377792
 ]
378793
 
379794
 [[package]]
380
-name = "evdev"
381
-version = "0.12.2"
795
+name = "cpufeatures"
796
+version = "0.2.17"
382797
 source = "registry+https://github.com/rust-lang/crates.io-index"
383
-checksum = "ab6055a93a963297befb0f4f6e18f314aec9767a4bbe88b151126df2433610a7"
798
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
384799
 dependencies = [
385
- "bitvec",
386
- "cfg-if",
387800
  "libc",
388
- "nix",
389
- "thiserror 1.0.69",
390801
 ]
391802
 
392803
 [[package]]
393
-name = "fastrand"
394
-version = "2.3.0"
804
+name = "crc32fast"
805
+version = "1.5.0"
395806
 source = "registry+https://github.com/rust-lang/crates.io-index"
396
-checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
807
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
808
+dependencies = [
809
+ "cfg-if",
810
+]
397811
 
398812
 [[package]]
399
-name = "find-msvc-tools"
400
-version = "0.1.6"
813
+name = "crossbeam-channel"
814
+version = "0.5.15"
401815
 source = "registry+https://github.com/rust-lang/crates.io-index"
402
-checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
816
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
817
+dependencies = [
818
+ "crossbeam-utils",
819
+]
403820
 
404821
 [[package]]
405
-name = "fixedbitset"
406
-version = "0.5.7"
822
+name = "crossbeam-deque"
823
+version = "0.8.6"
407824
 source = "registry+https://github.com/rust-lang/crates.io-index"
408
-checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
825
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
826
+dependencies = [
827
+ "crossbeam-epoch",
828
+ "crossbeam-utils",
829
+]
409830
 
410831
 [[package]]
411
-name = "foldhash"
412
-version = "0.1.5"
832
+name = "crossbeam-epoch"
833
+version = "0.9.18"
413834
 source = "registry+https://github.com/rust-lang/crates.io-index"
414
-checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
835
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
836
+dependencies = [
837
+ "crossbeam-utils",
838
+]
415839
 
416840
 [[package]]
417
-name = "fs_extra"
418
-version = "1.3.0"
841
+name = "crossbeam-utils"
842
+version = "0.8.21"
419843
 source = "registry+https://github.com/rust-lang/crates.io-index"
420
-checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
844
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
421845
 
422846
 [[package]]
423
-name = "funty"
424
-version = "2.0.0"
847
+name = "crunchy"
848
+version = "0.2.4"
425849
 source = "registry+https://github.com/rust-lang/crates.io-index"
426
-checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
850
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
427851
 
428852
 [[package]]
429
-name = "generic-array"
430
-version = "0.14.7"
853
+name = "crypto-common"
854
+version = "0.1.7"
431855
 source = "registry+https://github.com/rust-lang/crates.io-index"
432
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
856
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
433857
 dependencies = [
858
+ "generic-array",
434859
  "typenum",
435
- "version_check",
436860
 ]
437861
 
438862
 [[package]]
439
-name = "getrandom"
440
-version = "0.2.16"
863
+name = "ctor-lite"
864
+version = "0.1.0"
441865
 source = "registry+https://github.com/rust-lang/crates.io-index"
442
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
443
-dependencies = [
444
- "cfg-if",
445
- "libc",
446
- "wasi",
447
-]
866
+checksum = "1f791803201ab277ace03903de1594460708d2d54df6053f2d9e82f592b19e3b"
448867
 
449868
 [[package]]
450
-name = "getrandom"
451
-version = "0.3.4"
869
+name = "cursor-icon"
870
+version = "1.2.0"
452871
 source = "registry+https://github.com/rust-lang/crates.io-index"
453
-checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
454
-dependencies = [
455
- "cfg-if",
456
- "libc",
457
- "r-efi",
458
- "wasip2",
459
-]
872
+checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
460873
 
461874
 [[package]]
462
-name = "hashbrown"
463
-version = "0.15.5"
875
+name = "d3d12"
876
+version = "0.19.0"
464877
 source = "registry+https://github.com/rust-lang/crates.io-index"
465
-checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
878
+checksum = "3e3d747f100290a1ca24b752186f61f6637e1deffe3bf6320de6fcb29510a307"
466879
 dependencies = [
467
- "foldhash",
880
+ "bitflags 2.10.0",
881
+ "libloading 0.8.9",
882
+ "winapi",
468883
 ]
469884
 
470885
 [[package]]
471
-name = "hashbrown"
472
-version = "0.16.1"
886
+name = "dark-light"
887
+version = "1.1.1"
473888
 source = "registry+https://github.com/rust-lang/crates.io-index"
474
-checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
889
+checksum = "2a76fa97167fa740dcdbfe18e8895601e1bc36525f09b044e00916e717c03a3c"
890
+dependencies = [
891
+ "dconf_rs",
892
+ "detect-desktop-environment",
893
+ "dirs 4.0.0",
894
+ "objc",
895
+ "rust-ini",
896
+ "web-sys",
897
+ "winreg",
898
+ "zbus",
899
+]
475900
 
476901
 [[package]]
477
-name = "heck"
478
-version = "0.5.0"
902
+name = "dconf_rs"
903
+version = "0.3.0"
479904
 source = "registry+https://github.com/rust-lang/crates.io-index"
480
-checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
905
+checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b"
481906
 
482907
 [[package]]
483
-name = "hermit-abi"
484
-version = "0.5.2"
908
+name = "deranged"
909
+version = "0.5.5"
485910
 source = "registry+https://github.com/rust-lang/crates.io-index"
486
-checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
911
+checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
912
+dependencies = [
913
+ "powerfmt",
914
+]
487915
 
488916
 [[package]]
489
-name = "hex"
490
-version = "0.4.3"
917
+name = "detect-desktop-environment"
918
+version = "0.2.0"
491919
 source = "registry+https://github.com/rust-lang/crates.io-index"
492
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
920
+checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810"
493921
 
494922
 [[package]]
495
-name = "hostname"
496
-version = "0.4.2"
923
+name = "digest"
924
+version = "0.10.7"
497925
 source = "registry+https://github.com/rust-lang/crates.io-index"
498
-checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd"
926
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
499927
 dependencies = [
500
- "cfg-if",
501
- "libc",
502
- "windows-link",
928
+ "block-buffer",
929
+ "crypto-common",
503930
 ]
504931
 
505932
 [[package]]
506
-name = "hyprkvm-cli"
507
-version = "0.5.1"
933
+name = "dirs"
934
+version = "4.0.0"
935
+source = "registry+https://github.com/rust-lang/crates.io-index"
936
+checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
508937
 dependencies = [
509
- "anyhow",
510
- "clap",
511
- "hyprkvm-common",
512
- "serde",
513
- "serde_json",
514
- "tokio",
938
+ "dirs-sys 0.3.7",
515939
 ]
516940
 
517941
 [[package]]
518
-name = "hyprkvm-common"
519
-version = "0.5.1"
942
+name = "dirs"
943
+version = "5.0.1"
944
+source = "registry+https://github.com/rust-lang/crates.io-index"
945
+checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
520946
 dependencies = [
521
- "serde",
522
- "serde_json",
523
- "thiserror 1.0.69",
947
+ "dirs-sys 0.4.1",
524948
 ]
525949
 
526950
 [[package]]
527
-name = "hyprkvm-daemon"
528
-version = "0.5.1"
951
+name = "dirs-sys"
952
+version = "0.3.7"
953
+source = "registry+https://github.com/rust-lang/crates.io-index"
954
+checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
529955
 dependencies = [
530
- "anyhow",
531
- "base64",
532
- "bytes",
533
- "clap",
534
- "dirs",
535
- "evdev",
536
- "hex",
537
- "hostname",
538
- "hyprkvm-common",
539
- "rcgen",
540
- "rustix 0.38.44",
541
- "rustls",
542
- "rustls-pemfile",
543
- "serde",
544
- "serde_json",
545
- "sha2",
546
- "smithay-client-toolkit",
547
- "tempfile",
548
- "thiserror 1.0.69",
549
- "time",
550
- "tokio",
551
- "tokio-rustls",
552
- "toml",
553
- "tracing",
554
- "tracing-appender",
555
- "tracing-subscriber",
556
- "wayland-client",
557
- "wayland-protocols 0.31.2",
558
- "wayland-protocols-misc",
559
- "wayland-protocols-wlr",
560
- "wl-clipboard-rs",
956
+ "libc",
957
+ "redox_users",
958
+ "winapi",
561959
 ]
562960
 
563961
 [[package]]
564
-name = "indexmap"
565
-version = "2.12.1"
962
+name = "dirs-sys"
963
+version = "0.4.1"
566964
 source = "registry+https://github.com/rust-lang/crates.io-index"
567
-checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
965
+checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
568966
 dependencies = [
569
- "equivalent",
570
- "hashbrown 0.16.1",
967
+ "libc",
968
+ "option-ext",
969
+ "redox_users",
970
+ "windows-sys 0.48.0",
571971
 ]
572972
 
573973
 [[package]]
574
-name = "is_terminal_polyfill"
575
-version = "1.70.2"
974
+name = "dispatch"
975
+version = "0.2.0"
576976
 source = "registry+https://github.com/rust-lang/crates.io-index"
577
-checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
977
+checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
578978
 
579979
 [[package]]
580
-name = "itoa"
581
-version = "1.0.17"
980
+name = "dispatch2"
981
+version = "0.3.0"
582982
 source = "registry+https://github.com/rust-lang/crates.io-index"
583
-checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
983
+checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec"
984
+dependencies = [
985
+ "bitflags 2.10.0",
986
+ "objc2 0.6.3",
987
+]
584988
 
585989
 [[package]]
586
-name = "jobserver"
587
-version = "0.1.34"
990
+name = "dlib"
991
+version = "0.5.2"
588992
 source = "registry+https://github.com/rust-lang/crates.io-index"
589
-checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
993
+checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
590994
 dependencies = [
591
- "getrandom 0.3.4",
592
- "libc",
995
+ "libloading 0.8.9",
593996
 ]
594997
 
595998
 [[package]]
596
-name = "lazy_static"
597
-version = "1.5.0"
999
+name = "dlv-list"
1000
+version = "0.3.0"
5981001
 source = "registry+https://github.com/rust-lang/crates.io-index"
599
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
1002
+checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
6001003
 
6011004
 [[package]]
602
-name = "libc"
603
-version = "0.2.179"
1005
+name = "downcast-rs"
1006
+version = "1.2.1"
6041007
 source = "registry+https://github.com/rust-lang/crates.io-index"
605
-checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
1008
+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
6061009
 
6071010
 [[package]]
608
-name = "libredox"
609
-version = "0.1.12"
1011
+name = "dpi"
1012
+version = "0.1.2"
6101013
 source = "registry+https://github.com/rust-lang/crates.io-index"
611
-checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
1014
+checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
1015
+
1016
+[[package]]
1017
+name = "drm"
1018
+version = "0.14.1"
1019
+source = "registry+https://github.com/rust-lang/crates.io-index"
1020
+checksum = "80bc8c5c6c2941f70a55c15f8d9f00f9710ebda3ffda98075f996a0e6c92756f"
6121021
 dependencies = [
6131022
  "bitflags 2.10.0",
1023
+ "bytemuck",
1024
+ "drm-ffi",
1025
+ "drm-fourcc",
6141026
  "libc",
1027
+ "rustix 0.38.44",
6151028
 ]
6161029
 
6171030
 [[package]]
618
-name = "linux-raw-sys"
619
-version = "0.4.15"
1031
+name = "drm-ffi"
1032
+version = "0.9.0"
6201033
 source = "registry+https://github.com/rust-lang/crates.io-index"
621
-checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
1034
+checksum = "d8e41459d99a9b529845f6d2c909eb9adf3b6d2f82635ae40be8de0601726e8b"
1035
+dependencies = [
1036
+ "drm-sys",
1037
+ "rustix 0.38.44",
1038
+]
6221039
 
6231040
 [[package]]
624
-name = "linux-raw-sys"
625
-version = "0.11.0"
1041
+name = "drm-fourcc"
1042
+version = "2.2.0"
6261043
 source = "registry+https://github.com/rust-lang/crates.io-index"
627
-checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
1044
+checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
6281045
 
6291046
 [[package]]
630
-name = "lock_api"
631
-version = "0.4.14"
1047
+name = "drm-sys"
1048
+version = "0.8.0"
6321049
 source = "registry+https://github.com/rust-lang/crates.io-index"
633
-checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
1050
+checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c"
6341051
 dependencies = [
635
- "scopeguard",
1052
+ "libc",
1053
+ "linux-raw-sys 0.6.5",
6361054
 ]
6371055
 
6381056
 [[package]]
639
-name = "log"
640
-version = "0.4.29"
1057
+name = "dunce"
1058
+version = "1.0.5"
6411059
 source = "registry+https://github.com/rust-lang/crates.io-index"
642
-checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
1060
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
6431061
 
6441062
 [[package]]
645
-name = "matchers"
646
-version = "0.2.0"
1063
+name = "either"
1064
+version = "1.15.0"
6471065
 source = "registry+https://github.com/rust-lang/crates.io-index"
648
-checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
649
-dependencies = [
650
- "regex-automata",
651
-]
1066
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
6521067
 
6531068
 [[package]]
654
-name = "memchr"
655
-version = "2.7.6"
1069
+name = "endi"
1070
+version = "1.1.1"
6561071
 source = "registry+https://github.com/rust-lang/crates.io-index"
657
-checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
1072
+checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
6581073
 
6591074
 [[package]]
660
-name = "memmap2"
661
-version = "0.8.0"
1075
+name = "enumflags2"
1076
+version = "0.7.12"
6621077
 source = "registry+https://github.com/rust-lang/crates.io-index"
663
-checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
1078
+checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
6641079
 dependencies = [
665
- "libc",
1080
+ "enumflags2_derive",
1081
+ "serde",
6661082
 ]
6671083
 
6681084
 [[package]]
669
-name = "memmap2"
670
-version = "0.9.9"
1085
+name = "enumflags2_derive"
1086
+version = "0.7.12"
6711087
 source = "registry+https://github.com/rust-lang/crates.io-index"
672
-checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
1088
+checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
6731089
 dependencies = [
674
- "libc",
1090
+ "proc-macro2",
1091
+ "quote",
1092
+ "syn 2.0.113",
6751093
 ]
6761094
 
6771095
 [[package]]
678
-name = "memoffset"
679
-version = "0.6.5"
1096
+name = "equivalent"
1097
+version = "1.0.2"
6801098
 source = "registry+https://github.com/rust-lang/crates.io-index"
681
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
682
-dependencies = [
683
- "autocfg",
684
-]
1099
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
6851100
 
6861101
 [[package]]
687
-name = "mio"
688
-version = "1.1.1"
1102
+name = "errno"
1103
+version = "0.3.14"
6891104
 source = "registry+https://github.com/rust-lang/crates.io-index"
690
-checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
1105
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
6911106
 dependencies = [
6921107
  "libc",
693
- "wasi",
6941108
  "windows-sys 0.61.2",
6951109
 ]
6961110
 
6971111
 [[package]]
698
-name = "nix"
699
-version = "0.23.2"
1112
+name = "error-code"
1113
+version = "3.3.2"
7001114
 source = "registry+https://github.com/rust-lang/crates.io-index"
701
-checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
702
-dependencies = [
703
- "bitflags 1.3.2",
704
- "cc",
705
- "cfg-if",
706
- "libc",
707
- "memoffset",
708
-]
1115
+checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
7091116
 
7101117
 [[package]]
711
-name = "nom"
712
-version = "8.0.0"
1118
+name = "etagere"
1119
+version = "0.2.15"
7131120
 source = "registry+https://github.com/rust-lang/crates.io-index"
714
-checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
1121
+checksum = "fc89bf99e5dc15954a60f707c1e09d7540e5cd9af85fa75caa0b510bc08c5342"
7151122
 dependencies = [
716
- "memchr",
1123
+ "euclid",
1124
+ "svg_fmt",
7171125
 ]
7181126
 
7191127
 [[package]]
720
-name = "nu-ansi-term"
721
-version = "0.50.3"
1128
+name = "euclid"
1129
+version = "0.22.11"
7221130
 source = "registry+https://github.com/rust-lang/crates.io-index"
723
-checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
1131
+checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48"
7241132
 dependencies = [
725
- "windows-sys 0.61.2",
1133
+ "num-traits",
7261134
 ]
7271135
 
7281136
 [[package]]
729
-name = "num-conv"
730
-version = "0.1.0"
1137
+name = "evdev"
1138
+version = "0.12.2"
7311139
 source = "registry+https://github.com/rust-lang/crates.io-index"
732
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
1140
+checksum = "ab6055a93a963297befb0f4f6e18f314aec9767a4bbe88b151126df2433610a7"
1141
+dependencies = [
1142
+ "bitvec",
1143
+ "cfg-if",
1144
+ "libc",
1145
+ "nix 0.23.2",
1146
+ "thiserror 1.0.69",
1147
+]
7331148
 
7341149
 [[package]]
735
-name = "once_cell"
736
-version = "1.21.3"
1150
+name = "event-listener"
1151
+version = "5.4.1"
7371152
 source = "registry+https://github.com/rust-lang/crates.io-index"
738
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
1153
+checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
1154
+dependencies = [
1155
+ "concurrent-queue",
1156
+ "parking",
1157
+ "pin-project-lite",
1158
+]
7391159
 
7401160
 [[package]]
741
-name = "once_cell_polyfill"
742
-version = "1.70.2"
1161
+name = "event-listener-strategy"
1162
+version = "0.5.4"
7431163
 source = "registry+https://github.com/rust-lang/crates.io-index"
744
-checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
1164
+checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
1165
+dependencies = [
1166
+ "event-listener",
1167
+ "pin-project-lite",
1168
+]
7451169
 
7461170
 [[package]]
747
-name = "option-ext"
748
-version = "0.2.0"
1171
+name = "fast-srgb8"
1172
+version = "1.0.0"
7491173
 source = "registry+https://github.com/rust-lang/crates.io-index"
750
-checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
1174
+checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1"
7511175
 
7521176
 [[package]]
753
-name = "os_pipe"
754
-version = "1.2.3"
1177
+name = "fastrand"
1178
+version = "2.3.0"
7551179
 source = "registry+https://github.com/rust-lang/crates.io-index"
756
-checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
757
-dependencies = [
758
- "libc",
759
- "windows-sys 0.61.2",
760
-]
1180
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
7611181
 
7621182
 [[package]]
763
-name = "parking_lot"
764
-version = "0.12.5"
1183
+name = "fdeflate"
1184
+version = "0.3.7"
7651185
 source = "registry+https://github.com/rust-lang/crates.io-index"
766
-checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
1186
+checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c"
7671187
 dependencies = [
768
- "lock_api",
769
- "parking_lot_core",
1188
+ "simd-adler32",
7701189
 ]
7711190
 
7721191
 [[package]]
773
-name = "parking_lot_core"
774
-version = "0.9.12"
1192
+name = "find-msvc-tools"
1193
+version = "0.1.6"
7751194
 source = "registry+https://github.com/rust-lang/crates.io-index"
776
-checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
777
-dependencies = [
778
- "cfg-if",
779
- "libc",
780
- "redox_syscall",
781
- "smallvec",
782
- "windows-link",
783
-]
1195
+checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
7841196
 
7851197
 [[package]]
786
-name = "pem"
787
-version = "3.0.6"
1198
+name = "fixedbitset"
1199
+version = "0.5.7"
7881200
 source = "registry+https://github.com/rust-lang/crates.io-index"
789
-checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
790
-dependencies = [
791
- "base64",
792
- "serde_core",
793
-]
1201
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
7941202
 
7951203
 [[package]]
796
-name = "petgraph"
797
-version = "0.8.3"
1204
+name = "flate2"
1205
+version = "1.1.5"
7981206
 source = "registry+https://github.com/rust-lang/crates.io-index"
799
-checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
1207
+checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
8001208
 dependencies = [
801
- "fixedbitset",
802
- "hashbrown 0.15.5",
803
- "indexmap",
1209
+ "crc32fast",
1210
+ "miniz_oxide",
8041211
 ]
8051212
 
8061213
 [[package]]
807
-name = "pin-project-lite"
808
-version = "0.2.16"
1214
+name = "float_next_after"
1215
+version = "1.0.0"
8091216
 source = "registry+https://github.com/rust-lang/crates.io-index"
810
-checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
1217
+checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
8111218
 
8121219
 [[package]]
813
-name = "pkg-config"
814
-version = "0.3.32"
1220
+name = "foldhash"
1221
+version = "0.1.5"
8151222
 source = "registry+https://github.com/rust-lang/crates.io-index"
816
-checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
1223
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
8171224
 
8181225
 [[package]]
819
-name = "polling"
820
-version = "3.11.0"
1226
+name = "font-types"
1227
+version = "0.7.3"
8211228
 source = "registry+https://github.com/rust-lang/crates.io-index"
822
-checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
1229
+checksum = "b3971f9a5ca983419cdc386941ba3b9e1feba01a0ab888adf78739feb2798492"
8231230
 dependencies = [
824
- "cfg-if",
825
- "concurrent-queue",
826
- "hermit-abi",
827
- "pin-project-lite",
828
- "rustix 1.1.3",
829
- "windows-sys 0.61.2",
1231
+ "bytemuck",
8301232
 ]
8311233
 
8321234
 [[package]]
833
-name = "powerfmt"
834
-version = "0.2.0"
1235
+name = "fontconfig-parser"
1236
+version = "0.5.8"
8351237
 source = "registry+https://github.com/rust-lang/crates.io-index"
836
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
1238
+checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
1239
+dependencies = [
1240
+ "roxmltree",
1241
+]
8371242
 
8381243
 [[package]]
839
-name = "proc-macro2"
840
-version = "1.0.104"
1244
+name = "fontdb"
1245
+version = "0.16.2"
8411246
 source = "registry+https://github.com/rust-lang/crates.io-index"
842
-checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
1247
+checksum = "b0299020c3ef3f60f526a4f64ab4a3d4ce116b1acbf24cdd22da0068e5d81dc3"
8431248
 dependencies = [
844
- "unicode-ident",
1249
+ "fontconfig-parser",
1250
+ "log",
1251
+ "memmap2 0.9.9",
1252
+ "slotmap",
1253
+ "tinyvec",
1254
+ "ttf-parser 0.20.0",
8451255
 ]
8461256
 
8471257
 [[package]]
848
-name = "quick-xml"
849
-version = "0.38.4"
1258
+name = "foreign-types"
1259
+version = "0.5.0"
8501260
 source = "registry+https://github.com/rust-lang/crates.io-index"
851
-checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
1261
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
8521262
 dependencies = [
853
- "memchr",
1263
+ "foreign-types-macros",
1264
+ "foreign-types-shared",
8541265
 ]
8551266
 
8561267
 [[package]]
857
-name = "quote"
858
-version = "1.0.42"
1268
+name = "foreign-types-macros"
1269
+version = "0.2.3"
8591270
 source = "registry+https://github.com/rust-lang/crates.io-index"
860
-checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
1271
+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
8611272
 dependencies = [
8621273
  "proc-macro2",
1274
+ "quote",
1275
+ "syn 2.0.113",
8631276
 ]
8641277
 
8651278
 [[package]]
866
-name = "r-efi"
867
-version = "5.3.0"
1279
+name = "foreign-types-shared"
1280
+version = "0.3.1"
8681281
 source = "registry+https://github.com/rust-lang/crates.io-index"
869
-checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
1282
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
8701283
 
8711284
 [[package]]
872
-name = "radium"
873
-version = "0.7.0"
1285
+name = "fs_extra"
1286
+version = "1.3.0"
8741287
 source = "registry+https://github.com/rust-lang/crates.io-index"
875
-checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
1288
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
8761289
 
8771290
 [[package]]
878
-name = "rcgen"
879
-version = "0.13.2"
1291
+name = "funty"
1292
+version = "2.0.0"
8801293
 source = "registry+https://github.com/rust-lang/crates.io-index"
881
-checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
1294
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
1295
+
1296
+[[package]]
1297
+name = "futures"
1298
+version = "0.3.31"
1299
+source = "registry+https://github.com/rust-lang/crates.io-index"
1300
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
8821301
 dependencies = [
883
- "pem",
884
- "ring",
885
- "rustls-pki-types",
886
- "time",
887
- "yasna",
1302
+ "futures-channel",
1303
+ "futures-core",
1304
+ "futures-executor",
1305
+ "futures-io",
1306
+ "futures-sink",
1307
+ "futures-task",
1308
+ "futures-util",
8881309
 ]
8891310
 
8901311
 [[package]]
891
-name = "redox_syscall"
892
-version = "0.5.18"
1312
+name = "futures-channel"
1313
+version = "0.3.31"
8931314
 source = "registry+https://github.com/rust-lang/crates.io-index"
894
-checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
1315
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
8951316
 dependencies = [
896
- "bitflags 2.10.0",
1317
+ "futures-core",
1318
+ "futures-sink",
8971319
 ]
8981320
 
8991321
 [[package]]
900
-name = "redox_users"
901
-version = "0.4.6"
1322
+name = "futures-core"
1323
+version = "0.3.31"
9021324
 source = "registry+https://github.com/rust-lang/crates.io-index"
903
-checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
1325
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
1326
+
1327
+[[package]]
1328
+name = "futures-executor"
1329
+version = "0.3.31"
1330
+source = "registry+https://github.com/rust-lang/crates.io-index"
1331
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
9041332
 dependencies = [
905
- "getrandom 0.2.16",
906
- "libredox",
907
- "thiserror 1.0.69",
1333
+ "futures-core",
1334
+ "futures-task",
1335
+ "futures-util",
1336
+ "num_cpus",
9081337
 ]
9091338
 
9101339
 [[package]]
911
-name = "regex-automata"
912
-version = "0.4.13"
1340
+name = "futures-io"
1341
+version = "0.3.31"
9131342
 source = "registry+https://github.com/rust-lang/crates.io-index"
914
-checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
915
-dependencies = [
916
- "aho-corasick",
917
- "memchr",
918
- "regex-syntax",
919
-]
1343
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
9201344
 
9211345
 [[package]]
922
-name = "regex-syntax"
923
-version = "0.8.8"
1346
+name = "futures-lite"
1347
+version = "2.6.1"
9241348
 source = "registry+https://github.com/rust-lang/crates.io-index"
925
-checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
1349
+checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
1350
+dependencies = [
1351
+ "fastrand",
1352
+ "futures-core",
1353
+ "futures-io",
1354
+ "parking",
1355
+ "pin-project-lite",
1356
+]
9261357
 
9271358
 [[package]]
928
-name = "ring"
929
-version = "0.17.14"
1359
+name = "futures-macro"
1360
+version = "0.3.31"
9301361
 source = "registry+https://github.com/rust-lang/crates.io-index"
931
-checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
1362
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
9321363
 dependencies = [
933
- "cc",
934
- "cfg-if",
935
- "getrandom 0.2.16",
936
- "libc",
937
- "untrusted",
938
- "windows-sys 0.52.0",
1364
+ "proc-macro2",
1365
+ "quote",
1366
+ "syn 2.0.113",
9391367
 ]
9401368
 
9411369
 [[package]]
942
-name = "rustix"
943
-version = "0.38.44"
1370
+name = "futures-sink"
1371
+version = "0.3.31"
9441372
 source = "registry+https://github.com/rust-lang/crates.io-index"
945
-checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
1373
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
1374
+
1375
+[[package]]
1376
+name = "futures-task"
1377
+version = "0.3.31"
1378
+source = "registry+https://github.com/rust-lang/crates.io-index"
1379
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
1380
+
1381
+[[package]]
1382
+name = "futures-util"
1383
+version = "0.3.31"
1384
+source = "registry+https://github.com/rust-lang/crates.io-index"
1385
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
9461386
 dependencies = [
947
- "bitflags 2.10.0",
948
- "errno",
949
- "libc",
950
- "linux-raw-sys 0.4.15",
951
- "windows-sys 0.52.0",
1387
+ "futures-channel",
1388
+ "futures-core",
1389
+ "futures-io",
1390
+ "futures-macro",
1391
+ "futures-sink",
1392
+ "futures-task",
1393
+ "memchr",
1394
+ "pin-project-lite",
1395
+ "pin-utils",
1396
+ "slab",
9521397
 ]
9531398
 
9541399
 [[package]]
955
-name = "rustix"
956
-version = "1.1.3"
1400
+name = "generic-array"
1401
+version = "0.14.7"
9571402
 source = "registry+https://github.com/rust-lang/crates.io-index"
958
-checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
1403
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
9591404
 dependencies = [
960
- "bitflags 2.10.0",
961
- "errno",
962
- "libc",
963
- "linux-raw-sys 0.11.0",
964
- "windows-sys 0.61.2",
1405
+ "typenum",
1406
+ "version_check",
9651407
 ]
9661408
 
9671409
 [[package]]
968
-name = "rustls"
969
-version = "0.23.35"
1410
+name = "gethostname"
1411
+version = "1.1.0"
9701412
 source = "registry+https://github.com/rust-lang/crates.io-index"
971
-checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
1413
+checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
9721414
 dependencies = [
973
- "aws-lc-rs",
974
- "log",
975
- "once_cell",
976
- "rustls-pki-types",
977
- "rustls-webpki",
978
- "subtle",
979
- "zeroize",
1415
+ "rustix 1.1.3",
1416
+ "windows-link",
9801417
 ]
9811418
 
9821419
 [[package]]
983
-name = "rustls-pemfile"
984
-version = "2.2.0"
1420
+name = "getrandom"
1421
+version = "0.2.16"
9851422
 source = "registry+https://github.com/rust-lang/crates.io-index"
986
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
1423
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
9871424
 dependencies = [
988
- "rustls-pki-types",
1425
+ "cfg-if",
1426
+ "libc",
1427
+ "wasi",
9891428
 ]
9901429
 
9911430
 [[package]]
992
-name = "rustls-pki-types"
993
-version = "1.13.2"
1431
+name = "getrandom"
1432
+version = "0.3.4"
9941433
 source = "registry+https://github.com/rust-lang/crates.io-index"
995
-checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
1434
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
9961435
 dependencies = [
997
- "zeroize",
1436
+ "cfg-if",
1437
+ "libc",
1438
+ "r-efi",
1439
+ "wasip2",
9981440
 ]
9991441
 
10001442
 [[package]]
1001
-name = "rustls-webpki"
1002
-version = "0.103.8"
1443
+name = "gl_generator"
1444
+version = "0.14.0"
10031445
 source = "registry+https://github.com/rust-lang/crates.io-index"
1004
-checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
1446
+checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
10051447
 dependencies = [
1006
- "aws-lc-rs",
1007
- "ring",
1008
- "rustls-pki-types",
1009
- "untrusted",
1448
+ "khronos_api",
1449
+ "log",
1450
+ "xml-rs",
10101451
 ]
10111452
 
10121453
 [[package]]
1013
-name = "scopeguard"
1014
-version = "1.2.0"
1454
+name = "glam"
1455
+version = "0.25.0"
10151456
 source = "registry+https://github.com/rust-lang/crates.io-index"
1016
-checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
1457
+checksum = "151665d9be52f9bb40fc7966565d39666f2d1e69233571b71b87791c7e0528b3"
10171458
 
10181459
 [[package]]
1019
-name = "serde"
1020
-version = "1.0.228"
1460
+name = "glow"
1461
+version = "0.13.1"
10211462
 source = "registry+https://github.com/rust-lang/crates.io-index"
1022
-checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
1463
+checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
10231464
 dependencies = [
1024
- "serde_core",
1025
- "serde_derive",
1465
+ "js-sys",
1466
+ "slotmap",
1467
+ "wasm-bindgen",
1468
+ "web-sys",
10261469
 ]
10271470
 
10281471
 [[package]]
1029
-name = "serde_core"
1030
-version = "1.0.228"
1472
+name = "glutin_wgl_sys"
1473
+version = "0.5.0"
10311474
 source = "registry+https://github.com/rust-lang/crates.io-index"
1032
-checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
1475
+checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead"
10331476
 dependencies = [
1034
- "serde_derive",
1477
+ "gl_generator",
10351478
 ]
10361479
 
10371480
 [[package]]
1038
-name = "serde_derive"
1039
-version = "1.0.228"
1481
+name = "gpu-alloc"
1482
+version = "0.6.0"
10401483
 source = "registry+https://github.com/rust-lang/crates.io-index"
1041
-checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
1484
+checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
10421485
 dependencies = [
1043
- "proc-macro2",
1044
- "quote",
1045
- "syn",
1486
+ "bitflags 2.10.0",
1487
+ "gpu-alloc-types",
10461488
 ]
10471489
 
10481490
 [[package]]
1049
-name = "serde_json"
1050
-version = "1.0.148"
1491
+name = "gpu-alloc-types"
1492
+version = "0.3.0"
10511493
 source = "registry+https://github.com/rust-lang/crates.io-index"
1052
-checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
1494
+checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
10531495
 dependencies = [
1054
- "itoa",
1055
- "memchr",
1056
- "serde",
1057
- "serde_core",
1058
- "zmij",
1496
+ "bitflags 2.10.0",
10591497
 ]
10601498
 
10611499
 [[package]]
1062
-name = "serde_spanned"
1063
-version = "0.6.9"
1500
+name = "gpu-allocator"
1501
+version = "0.25.0"
10641502
 source = "registry+https://github.com/rust-lang/crates.io-index"
1065
-checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
1503
+checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884"
10661504
 dependencies = [
1067
- "serde",
1505
+ "log",
1506
+ "presser",
1507
+ "thiserror 1.0.69",
1508
+ "winapi",
1509
+ "windows",
10681510
 ]
10691511
 
10701512
 [[package]]
1071
-name = "sha2"
1072
-version = "0.10.9"
1513
+name = "gpu-descriptor"
1514
+version = "0.2.4"
10731515
 source = "registry+https://github.com/rust-lang/crates.io-index"
1074
-checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
1516
+checksum = "cc11df1ace8e7e564511f53af41f3e42ddc95b56fd07b3f4445d2a6048bc682c"
10751517
 dependencies = [
1076
- "cfg-if",
1077
- "cpufeatures",
1078
- "digest",
1518
+ "bitflags 2.10.0",
1519
+ "gpu-descriptor-types",
1520
+ "hashbrown 0.14.5",
10791521
 ]
10801522
 
10811523
 [[package]]
1082
-name = "sharded-slab"
1083
-version = "0.1.7"
1524
+name = "gpu-descriptor-types"
1525
+version = "0.1.2"
10841526
 source = "registry+https://github.com/rust-lang/crates.io-index"
1085
-checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
1527
+checksum = "6bf0b36e6f090b7e1d8a4b49c0cb81c1f8376f72198c65dd3ad9ff3556b8b78c"
10861528
 dependencies = [
1087
- "lazy_static",
1529
+ "bitflags 2.10.0",
10881530
 ]
10891531
 
10901532
 [[package]]
1091
-name = "shlex"
1092
-version = "1.3.0"
1533
+name = "guillotiere"
1534
+version = "0.6.2"
10931535
 source = "registry+https://github.com/rust-lang/crates.io-index"
1094
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1536
+checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782"
1537
+dependencies = [
1538
+ "euclid",
1539
+ "svg_fmt",
1540
+]
10951541
 
10961542
 [[package]]
1097
-name = "signal-hook-registry"
1098
-version = "1.4.8"
1543
+name = "half"
1544
+version = "2.7.1"
10991545
 source = "registry+https://github.com/rust-lang/crates.io-index"
1100
-checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
1546
+checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
11011547
 dependencies = [
1102
- "errno",
1103
- "libc",
1548
+ "cfg-if",
1549
+ "crunchy",
1550
+ "zerocopy",
11041551
 ]
11051552
 
11061553
 [[package]]
1107
-name = "slab"
1108
-version = "0.4.11"
1554
+name = "hashbrown"
1555
+version = "0.12.3"
11091556
 source = "registry+https://github.com/rust-lang/crates.io-index"
1110
-checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
1557
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
1558
+dependencies = [
1559
+ "ahash 0.7.8",
1560
+]
11111561
 
11121562
 [[package]]
1113
-name = "smallvec"
1114
-version = "1.15.1"
1563
+name = "hashbrown"
1564
+version = "0.14.5"
11151565
 source = "registry+https://github.com/rust-lang/crates.io-index"
1116
-checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
1566
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
1567
+dependencies = [
1568
+ "ahash 0.8.12",
1569
+ "allocator-api2",
1570
+]
11171571
 
11181572
 [[package]]
1119
-name = "smithay-client-toolkit"
1120
-version = "0.19.2"
1573
+name = "hashbrown"
1574
+version = "0.15.5"
11211575
 source = "registry+https://github.com/rust-lang/crates.io-index"
1122
-checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
1576
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
11231577
 dependencies = [
1124
- "bitflags 2.10.0",
1125
- "bytemuck",
1126
- "calloop",
1127
- "calloop-wayland-source",
1128
- "cursor-icon",
1129
- "libc",
1130
- "log",
1131
- "memmap2 0.9.9",
1132
- "pkg-config",
1133
- "rustix 0.38.44",
1134
- "thiserror 1.0.69",
1135
- "wayland-backend",
1136
- "wayland-client",
1137
- "wayland-csd-frame",
1138
- "wayland-cursor",
1139
- "wayland-protocols 0.32.10",
1140
- "wayland-protocols-wlr",
1141
- "wayland-scanner",
1142
- "xkbcommon",
1143
- "xkeysym",
1578
+ "foldhash",
11441579
 ]
11451580
 
11461581
 [[package]]
1147
-name = "socket2"
1148
-version = "0.6.1"
1582
+name = "hashbrown"
1583
+version = "0.16.1"
11491584
 source = "registry+https://github.com/rust-lang/crates.io-index"
1150
-checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
1585
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
1586
+
1587
+[[package]]
1588
+name = "hassle-rs"
1589
+version = "0.11.0"
1590
+source = "registry+https://github.com/rust-lang/crates.io-index"
1591
+checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890"
11511592
 dependencies = [
1593
+ "bitflags 2.10.0",
1594
+ "com",
11521595
  "libc",
1153
- "windows-sys 0.60.2",
1596
+ "libloading 0.8.9",
1597
+ "thiserror 1.0.69",
1598
+ "widestring",
1599
+ "winapi",
11541600
 ]
11551601
 
11561602
 [[package]]
1157
-name = "strsim"
1158
-version = "0.11.1"
1603
+name = "heck"
1604
+version = "0.5.0"
11591605
 source = "registry+https://github.com/rust-lang/crates.io-index"
1160
-checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
1606
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
11611607
 
11621608
 [[package]]
1163
-name = "subtle"
1164
-version = "2.6.1"
1609
+name = "hermit-abi"
1610
+version = "0.5.2"
11651611
 source = "registry+https://github.com/rust-lang/crates.io-index"
1166
-checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
1612
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
11671613
 
11681614
 [[package]]
1169
-name = "syn"
1170
-version = "2.0.113"
1615
+name = "hex"
1616
+version = "0.4.3"
11711617
 source = "registry+https://github.com/rust-lang/crates.io-index"
1172
-checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4"
1173
-dependencies = [
1174
- "proc-macro2",
1175
- "quote",
1176
- "unicode-ident",
1177
-]
1618
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
11781619
 
11791620
 [[package]]
1180
-name = "tap"
1181
-version = "1.0.1"
1621
+name = "hexf-parse"
1622
+version = "0.2.1"
11821623
 source = "registry+https://github.com/rust-lang/crates.io-index"
1183
-checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
1624
+checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
11841625
 
11851626
 [[package]]
1186
-name = "tempfile"
1187
-version = "3.24.0"
1627
+name = "hostname"
1628
+version = "0.4.2"
11881629
 source = "registry+https://github.com/rust-lang/crates.io-index"
1189
-checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
1630
+checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd"
11901631
 dependencies = [
1191
- "fastrand",
1192
- "getrandom 0.3.4",
1193
- "once_cell",
1194
- "rustix 1.1.3",
1195
- "windows-sys 0.61.2",
1632
+ "cfg-if",
1633
+ "libc",
1634
+ "windows-link",
11961635
 ]
11971636
 
11981637
 [[package]]
1199
-name = "thiserror"
1200
-version = "1.0.69"
1201
-source = "registry+https://github.com/rust-lang/crates.io-index"
1202
-checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
1638
+name = "hyprkvm-cli"
1639
+version = "0.5.1"
12031640
 dependencies = [
1204
- "thiserror-impl 1.0.69",
1205
-]
1206
-
1641
+ "anyhow",
1642
+ "clap",
1643
+ "hyprkvm-common",
1644
+ "serde",
1645
+ "serde_json",
1646
+ "tokio",
1647
+]
1648
+
1649
+[[package]]
1650
+name = "hyprkvm-common"
1651
+version = "0.5.1"
1652
+dependencies = [
1653
+ "serde",
1654
+ "serde_json",
1655
+ "thiserror 1.0.69",
1656
+]
1657
+
1658
+[[package]]
1659
+name = "hyprkvm-daemon"
1660
+version = "0.5.1"
1661
+dependencies = [
1662
+ "anyhow",
1663
+ "base64",
1664
+ "bytes",
1665
+ "clap",
1666
+ "dirs 5.0.1",
1667
+ "evdev",
1668
+ "hex",
1669
+ "hostname",
1670
+ "hyprkvm-common",
1671
+ "iced",
1672
+ "rcgen",
1673
+ "rustix 0.38.44",
1674
+ "rustls",
1675
+ "rustls-pemfile",
1676
+ "serde",
1677
+ "serde_json",
1678
+ "sha2",
1679
+ "smithay-client-toolkit 0.19.2",
1680
+ "tempfile",
1681
+ "thiserror 1.0.69",
1682
+ "time",
1683
+ "tokio",
1684
+ "tokio-rustls",
1685
+ "toml",
1686
+ "tracing",
1687
+ "tracing-appender",
1688
+ "tracing-subscriber",
1689
+ "wayland-client",
1690
+ "wayland-protocols 0.31.2",
1691
+ "wayland-protocols-misc",
1692
+ "wayland-protocols-wlr",
1693
+ "wl-clipboard-rs",
1694
+]
1695
+
1696
+[[package]]
1697
+name = "iced"
1698
+version = "0.13.1"
1699
+source = "registry+https://github.com/rust-lang/crates.io-index"
1700
+checksum = "88acfabc84ec077eaf9ede3457ffa3a104626d79022a9bf7f296093b1d60c73f"
1701
+dependencies = [
1702
+ "iced_core",
1703
+ "iced_futures",
1704
+ "iced_renderer",
1705
+ "iced_widget",
1706
+ "iced_winit",
1707
+ "thiserror 1.0.69",
1708
+]
1709
+
1710
+[[package]]
1711
+name = "iced_core"
1712
+version = "0.13.2"
1713
+source = "registry+https://github.com/rust-lang/crates.io-index"
1714
+checksum = "0013a238275494641bf8f1732a23a808196540dc67b22ff97099c044ae4c8a1c"
1715
+dependencies = [
1716
+ "bitflags 2.10.0",
1717
+ "bytes",
1718
+ "dark-light",
1719
+ "glam",
1720
+ "log",
1721
+ "num-traits",
1722
+ "once_cell",
1723
+ "palette",
1724
+ "rustc-hash 2.1.1",
1725
+ "smol_str",
1726
+ "thiserror 1.0.69",
1727
+ "web-time",
1728
+]
1729
+
1730
+[[package]]
1731
+name = "iced_futures"
1732
+version = "0.13.2"
1733
+source = "registry+https://github.com/rust-lang/crates.io-index"
1734
+checksum = "0c04a6745ba2e80f32cf01e034fd00d853aa4f4cd8b91888099cb7aaee0d5d7c"
1735
+dependencies = [
1736
+ "futures",
1737
+ "iced_core",
1738
+ "log",
1739
+ "rustc-hash 2.1.1",
1740
+ "tokio",
1741
+ "wasm-bindgen-futures",
1742
+ "wasm-timer",
1743
+]
1744
+
1745
+[[package]]
1746
+name = "iced_glyphon"
1747
+version = "0.6.0"
1748
+source = "registry+https://github.com/rust-lang/crates.io-index"
1749
+checksum = "41c3bb56f1820ca252bc1d0994ece33d233a55657c0c263ea7cb16895adbde82"
1750
+dependencies = [
1751
+ "cosmic-text",
1752
+ "etagere",
1753
+ "lru",
1754
+ "rustc-hash 2.1.1",
1755
+ "wgpu",
1756
+]
1757
+
1758
+[[package]]
1759
+name = "iced_graphics"
1760
+version = "0.13.0"
1761
+source = "registry+https://github.com/rust-lang/crates.io-index"
1762
+checksum = "ba25a18cfa6d5cc160aca7e1b34f73ccdff21680fa8702168c09739767b6c66f"
1763
+dependencies = [
1764
+ "bitflags 2.10.0",
1765
+ "bytemuck",
1766
+ "cosmic-text",
1767
+ "half",
1768
+ "iced_core",
1769
+ "iced_futures",
1770
+ "log",
1771
+ "lyon_path",
1772
+ "once_cell",
1773
+ "raw-window-handle",
1774
+ "rustc-hash 2.1.1",
1775
+ "thiserror 1.0.69",
1776
+ "unicode-segmentation",
1777
+]
1778
+
1779
+[[package]]
1780
+name = "iced_renderer"
1781
+version = "0.13.0"
1782
+source = "registry+https://github.com/rust-lang/crates.io-index"
1783
+checksum = "73558208059f9e622df2bf434e044ee2f838ce75201a023cf0ca3e1244f46c2a"
1784
+dependencies = [
1785
+ "iced_graphics",
1786
+ "iced_tiny_skia",
1787
+ "iced_wgpu",
1788
+ "log",
1789
+ "thiserror 1.0.69",
1790
+]
1791
+
1792
+[[package]]
1793
+name = "iced_runtime"
1794
+version = "0.13.2"
1795
+source = "registry+https://github.com/rust-lang/crates.io-index"
1796
+checksum = "348b5b2c61c934d88ca3b0ed1ed913291e923d086a66fa288ce9669da9ef62b5"
1797
+dependencies = [
1798
+ "bytes",
1799
+ "iced_core",
1800
+ "iced_futures",
1801
+ "raw-window-handle",
1802
+ "thiserror 1.0.69",
1803
+]
1804
+
1805
+[[package]]
1806
+name = "iced_tiny_skia"
1807
+version = "0.13.0"
1808
+source = "registry+https://github.com/rust-lang/crates.io-index"
1809
+checksum = "c625d368284fcc43b0b36b176f76eff1abebe7959dd58bd8ce6897d641962a50"
1810
+dependencies = [
1811
+ "bytemuck",
1812
+ "cosmic-text",
1813
+ "iced_graphics",
1814
+ "kurbo",
1815
+ "log",
1816
+ "rustc-hash 2.1.1",
1817
+ "softbuffer",
1818
+ "tiny-skia",
1819
+]
1820
+
1821
+[[package]]
1822
+name = "iced_wgpu"
1823
+version = "0.13.5"
1824
+source = "registry+https://github.com/rust-lang/crates.io-index"
1825
+checksum = "15708887133671d2bcc6c1d01d1f176f43a64d6cdc3b2bf893396c3ee498295f"
1826
+dependencies = [
1827
+ "bitflags 2.10.0",
1828
+ "bytemuck",
1829
+ "futures",
1830
+ "glam",
1831
+ "guillotiere",
1832
+ "iced_glyphon",
1833
+ "iced_graphics",
1834
+ "log",
1835
+ "lyon",
1836
+ "once_cell",
1837
+ "rustc-hash 2.1.1",
1838
+ "thiserror 1.0.69",
1839
+ "wgpu",
1840
+]
1841
+
1842
+[[package]]
1843
+name = "iced_widget"
1844
+version = "0.13.4"
1845
+source = "registry+https://github.com/rust-lang/crates.io-index"
1846
+checksum = "81429e1b950b0e4bca65be4c4278fea6678ea782030a411778f26fa9f8983e1d"
1847
+dependencies = [
1848
+ "iced_renderer",
1849
+ "iced_runtime",
1850
+ "num-traits",
1851
+ "once_cell",
1852
+ "rustc-hash 2.1.1",
1853
+ "thiserror 1.0.69",
1854
+ "unicode-segmentation",
1855
+]
1856
+
1857
+[[package]]
1858
+name = "iced_winit"
1859
+version = "0.13.0"
1860
+source = "registry+https://github.com/rust-lang/crates.io-index"
1861
+checksum = "f44cd4e1c594b6334f409282937bf972ba14d31fedf03c23aa595d982a2fda28"
1862
+dependencies = [
1863
+ "iced_futures",
1864
+ "iced_graphics",
1865
+ "iced_runtime",
1866
+ "log",
1867
+ "rustc-hash 2.1.1",
1868
+ "thiserror 1.0.69",
1869
+ "tracing",
1870
+ "wasm-bindgen-futures",
1871
+ "web-sys",
1872
+ "winapi",
1873
+ "window_clipboard",
1874
+ "winit",
1875
+]
1876
+
1877
+[[package]]
1878
+name = "indexmap"
1879
+version = "2.12.1"
1880
+source = "registry+https://github.com/rust-lang/crates.io-index"
1881
+checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
1882
+dependencies = [
1883
+ "equivalent",
1884
+ "hashbrown 0.16.1",
1885
+]
1886
+
1887
+[[package]]
1888
+name = "instant"
1889
+version = "0.1.13"
1890
+source = "registry+https://github.com/rust-lang/crates.io-index"
1891
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
1892
+dependencies = [
1893
+ "cfg-if",
1894
+]
1895
+
1896
+[[package]]
1897
+name = "is_terminal_polyfill"
1898
+version = "1.70.2"
1899
+source = "registry+https://github.com/rust-lang/crates.io-index"
1900
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
1901
+
1902
+[[package]]
1903
+name = "itoa"
1904
+version = "1.0.17"
1905
+source = "registry+https://github.com/rust-lang/crates.io-index"
1906
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
1907
+
1908
+[[package]]
1909
+name = "jni"
1910
+version = "0.21.1"
1911
+source = "registry+https://github.com/rust-lang/crates.io-index"
1912
+checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97"
1913
+dependencies = [
1914
+ "cesu8",
1915
+ "cfg-if",
1916
+ "combine",
1917
+ "jni-sys",
1918
+ "log",
1919
+ "thiserror 1.0.69",
1920
+ "walkdir",
1921
+ "windows-sys 0.45.0",
1922
+]
1923
+
1924
+[[package]]
1925
+name = "jni-sys"
1926
+version = "0.3.0"
1927
+source = "registry+https://github.com/rust-lang/crates.io-index"
1928
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
1929
+
1930
+[[package]]
1931
+name = "jobserver"
1932
+version = "0.1.34"
1933
+source = "registry+https://github.com/rust-lang/crates.io-index"
1934
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
1935
+dependencies = [
1936
+ "getrandom 0.3.4",
1937
+ "libc",
1938
+]
1939
+
1940
+[[package]]
1941
+name = "js-sys"
1942
+version = "0.3.83"
1943
+source = "registry+https://github.com/rust-lang/crates.io-index"
1944
+checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
1945
+dependencies = [
1946
+ "once_cell",
1947
+ "wasm-bindgen",
1948
+]
1949
+
1950
+[[package]]
1951
+name = "khronos-egl"
1952
+version = "6.0.0"
1953
+source = "registry+https://github.com/rust-lang/crates.io-index"
1954
+checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76"
1955
+dependencies = [
1956
+ "libc",
1957
+ "libloading 0.8.9",
1958
+ "pkg-config",
1959
+]
1960
+
1961
+[[package]]
1962
+name = "khronos_api"
1963
+version = "3.1.0"
1964
+source = "registry+https://github.com/rust-lang/crates.io-index"
1965
+checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
1966
+
1967
+[[package]]
1968
+name = "kurbo"
1969
+version = "0.10.4"
1970
+source = "registry+https://github.com/rust-lang/crates.io-index"
1971
+checksum = "1618d4ebd923e97d67e7cd363d80aef35fe961005cbbbb3d2dad8bdd1bc63440"
1972
+dependencies = [
1973
+ "arrayvec",
1974
+ "smallvec",
1975
+]
1976
+
1977
+[[package]]
1978
+name = "lazy_static"
1979
+version = "1.5.0"
1980
+source = "registry+https://github.com/rust-lang/crates.io-index"
1981
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
1982
+
1983
+[[package]]
1984
+name = "libc"
1985
+version = "0.2.179"
1986
+source = "registry+https://github.com/rust-lang/crates.io-index"
1987
+checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
1988
+
1989
+[[package]]
1990
+name = "libloading"
1991
+version = "0.7.4"
1992
+source = "registry+https://github.com/rust-lang/crates.io-index"
1993
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
1994
+dependencies = [
1995
+ "cfg-if",
1996
+ "winapi",
1997
+]
1998
+
1999
+[[package]]
2000
+name = "libloading"
2001
+version = "0.8.9"
2002
+source = "registry+https://github.com/rust-lang/crates.io-index"
2003
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
2004
+dependencies = [
2005
+ "cfg-if",
2006
+ "windows-link",
2007
+]
2008
+
2009
+[[package]]
2010
+name = "libm"
2011
+version = "0.2.15"
2012
+source = "registry+https://github.com/rust-lang/crates.io-index"
2013
+checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
2014
+
2015
+[[package]]
2016
+name = "libredox"
2017
+version = "0.1.12"
2018
+source = "registry+https://github.com/rust-lang/crates.io-index"
2019
+checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
2020
+dependencies = [
2021
+ "bitflags 2.10.0",
2022
+ "libc",
2023
+ "redox_syscall 0.7.0",
2024
+]
2025
+
2026
+[[package]]
2027
+name = "linux-raw-sys"
2028
+version = "0.4.15"
2029
+source = "registry+https://github.com/rust-lang/crates.io-index"
2030
+checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
2031
+
2032
+[[package]]
2033
+name = "linux-raw-sys"
2034
+version = "0.6.5"
2035
+source = "registry+https://github.com/rust-lang/crates.io-index"
2036
+checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
2037
+
2038
+[[package]]
2039
+name = "linux-raw-sys"
2040
+version = "0.11.0"
2041
+source = "registry+https://github.com/rust-lang/crates.io-index"
2042
+checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
2043
+
2044
+[[package]]
2045
+name = "lock_api"
2046
+version = "0.4.14"
2047
+source = "registry+https://github.com/rust-lang/crates.io-index"
2048
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
2049
+dependencies = [
2050
+ "scopeguard",
2051
+]
2052
+
2053
+[[package]]
2054
+name = "log"
2055
+version = "0.4.29"
2056
+source = "registry+https://github.com/rust-lang/crates.io-index"
2057
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
2058
+
2059
+[[package]]
2060
+name = "lru"
2061
+version = "0.12.5"
2062
+source = "registry+https://github.com/rust-lang/crates.io-index"
2063
+checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
2064
+
2065
+[[package]]
2066
+name = "lyon"
2067
+version = "1.0.16"
2068
+source = "registry+https://github.com/rust-lang/crates.io-index"
2069
+checksum = "dbcb7d54d54c8937364c9d41902d066656817dce1e03a44e5533afebd1ef4352"
2070
+dependencies = [
2071
+ "lyon_algorithms",
2072
+ "lyon_tessellation",
2073
+]
2074
+
2075
+[[package]]
2076
+name = "lyon_algorithms"
2077
+version = "1.0.16"
2078
+source = "registry+https://github.com/rust-lang/crates.io-index"
2079
+checksum = "f4c0829e28c4f336396f250d850c3987e16ce6db057ffe047ce0dd54aab6b647"
2080
+dependencies = [
2081
+ "lyon_path",
2082
+ "num-traits",
2083
+]
2084
+
2085
+[[package]]
2086
+name = "lyon_geom"
2087
+version = "1.0.18"
2088
+source = "registry+https://github.com/rust-lang/crates.io-index"
2089
+checksum = "e260b6de923e6e47adfedf6243013a7a874684165a6a277594ee3906021b2343"
2090
+dependencies = [
2091
+ "arrayvec",
2092
+ "euclid",
2093
+ "num-traits",
2094
+]
2095
+
2096
+[[package]]
2097
+name = "lyon_path"
2098
+version = "1.0.16"
2099
+source = "registry+https://github.com/rust-lang/crates.io-index"
2100
+checksum = "1aeca86bcfd632a15984ba029b539ffb811e0a70bf55e814ef8b0f54f506fdeb"
2101
+dependencies = [
2102
+ "lyon_geom",
2103
+ "num-traits",
2104
+]
2105
+
2106
+[[package]]
2107
+name = "lyon_tessellation"
2108
+version = "1.0.16"
2109
+source = "registry+https://github.com/rust-lang/crates.io-index"
2110
+checksum = "f3f586142e1280335b1bc89539f7c97dd80f08fc43e9ab1b74ef0a42b04aa353"
2111
+dependencies = [
2112
+ "float_next_after",
2113
+ "lyon_path",
2114
+ "num-traits",
2115
+]
2116
+
2117
+[[package]]
2118
+name = "malloc_buf"
2119
+version = "0.0.6"
2120
+source = "registry+https://github.com/rust-lang/crates.io-index"
2121
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
2122
+dependencies = [
2123
+ "libc",
2124
+]
2125
+
2126
+[[package]]
2127
+name = "matchers"
2128
+version = "0.2.0"
2129
+source = "registry+https://github.com/rust-lang/crates.io-index"
2130
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
2131
+dependencies = [
2132
+ "regex-automata",
2133
+]
2134
+
2135
+[[package]]
2136
+name = "memchr"
2137
+version = "2.7.6"
2138
+source = "registry+https://github.com/rust-lang/crates.io-index"
2139
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
2140
+
2141
+[[package]]
2142
+name = "memmap2"
2143
+version = "0.8.0"
2144
+source = "registry+https://github.com/rust-lang/crates.io-index"
2145
+checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed"
2146
+dependencies = [
2147
+ "libc",
2148
+]
2149
+
2150
+[[package]]
2151
+name = "memmap2"
2152
+version = "0.9.9"
2153
+source = "registry+https://github.com/rust-lang/crates.io-index"
2154
+checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
2155
+dependencies = [
2156
+ "libc",
2157
+]
2158
+
2159
+[[package]]
2160
+name = "memoffset"
2161
+version = "0.6.5"
2162
+source = "registry+https://github.com/rust-lang/crates.io-index"
2163
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
2164
+dependencies = [
2165
+ "autocfg",
2166
+]
2167
+
2168
+[[package]]
2169
+name = "memoffset"
2170
+version = "0.9.1"
2171
+source = "registry+https://github.com/rust-lang/crates.io-index"
2172
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
2173
+dependencies = [
2174
+ "autocfg",
2175
+]
2176
+
2177
+[[package]]
2178
+name = "metal"
2179
+version = "0.27.0"
2180
+source = "registry+https://github.com/rust-lang/crates.io-index"
2181
+checksum = "c43f73953f8cbe511f021b58f18c3ce1c3d1ae13fe953293e13345bf83217f25"
2182
+dependencies = [
2183
+ "bitflags 2.10.0",
2184
+ "block",
2185
+ "core-graphics-types",
2186
+ "foreign-types",
2187
+ "log",
2188
+ "objc",
2189
+ "paste",
2190
+]
2191
+
2192
+[[package]]
2193
+name = "miniz_oxide"
2194
+version = "0.8.9"
2195
+source = "registry+https://github.com/rust-lang/crates.io-index"
2196
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
2197
+dependencies = [
2198
+ "adler2",
2199
+ "simd-adler32",
2200
+]
2201
+
2202
+[[package]]
2203
+name = "mio"
2204
+version = "1.1.1"
2205
+source = "registry+https://github.com/rust-lang/crates.io-index"
2206
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
2207
+dependencies = [
2208
+ "libc",
2209
+ "wasi",
2210
+ "windows-sys 0.61.2",
2211
+]
2212
+
2213
+[[package]]
2214
+name = "naga"
2215
+version = "0.19.2"
2216
+source = "registry+https://github.com/rust-lang/crates.io-index"
2217
+checksum = "50e3524642f53d9af419ab5e8dd29d3ba155708267667c2f3f06c88c9e130843"
2218
+dependencies = [
2219
+ "bit-set",
2220
+ "bitflags 2.10.0",
2221
+ "codespan-reporting",
2222
+ "hexf-parse",
2223
+ "indexmap",
2224
+ "log",
2225
+ "num-traits",
2226
+ "rustc-hash 1.1.0",
2227
+ "spirv",
2228
+ "termcolor",
2229
+ "thiserror 1.0.69",
2230
+ "unicode-xid",
2231
+]
2232
+
2233
+[[package]]
2234
+name = "ndk"
2235
+version = "0.9.0"
2236
+source = "registry+https://github.com/rust-lang/crates.io-index"
2237
+checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4"
2238
+dependencies = [
2239
+ "bitflags 2.10.0",
2240
+ "jni-sys",
2241
+ "log",
2242
+ "ndk-sys 0.6.0+11769913",
2243
+ "num_enum",
2244
+ "raw-window-handle",
2245
+ "thiserror 1.0.69",
2246
+]
2247
+
2248
+[[package]]
2249
+name = "ndk-context"
2250
+version = "0.1.1"
2251
+source = "registry+https://github.com/rust-lang/crates.io-index"
2252
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
2253
+
2254
+[[package]]
2255
+name = "ndk-sys"
2256
+version = "0.5.0+25.2.9519653"
2257
+source = "registry+https://github.com/rust-lang/crates.io-index"
2258
+checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691"
2259
+dependencies = [
2260
+ "jni-sys",
2261
+]
2262
+
2263
+[[package]]
2264
+name = "ndk-sys"
2265
+version = "0.6.0+11769913"
2266
+source = "registry+https://github.com/rust-lang/crates.io-index"
2267
+checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873"
2268
+dependencies = [
2269
+ "jni-sys",
2270
+]
2271
+
2272
+[[package]]
2273
+name = "nix"
2274
+version = "0.23.2"
2275
+source = "registry+https://github.com/rust-lang/crates.io-index"
2276
+checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
2277
+dependencies = [
2278
+ "bitflags 1.3.2",
2279
+ "cc",
2280
+ "cfg-if",
2281
+ "libc",
2282
+ "memoffset 0.6.5",
2283
+]
2284
+
2285
+[[package]]
2286
+name = "nix"
2287
+version = "0.29.0"
2288
+source = "registry+https://github.com/rust-lang/crates.io-index"
2289
+checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
2290
+dependencies = [
2291
+ "bitflags 2.10.0",
2292
+ "cfg-if",
2293
+ "cfg_aliases 0.2.1",
2294
+ "libc",
2295
+ "memoffset 0.9.1",
2296
+]
2297
+
2298
+[[package]]
2299
+name = "nom"
2300
+version = "8.0.0"
2301
+source = "registry+https://github.com/rust-lang/crates.io-index"
2302
+checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
2303
+dependencies = [
2304
+ "memchr",
2305
+]
2306
+
2307
+[[package]]
2308
+name = "nu-ansi-term"
2309
+version = "0.50.3"
2310
+source = "registry+https://github.com/rust-lang/crates.io-index"
2311
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
2312
+dependencies = [
2313
+ "windows-sys 0.61.2",
2314
+]
2315
+
2316
+[[package]]
2317
+name = "num-conv"
2318
+version = "0.1.0"
2319
+source = "registry+https://github.com/rust-lang/crates.io-index"
2320
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
2321
+
2322
+[[package]]
2323
+name = "num-traits"
2324
+version = "0.2.19"
2325
+source = "registry+https://github.com/rust-lang/crates.io-index"
2326
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
2327
+dependencies = [
2328
+ "autocfg",
2329
+ "libm",
2330
+]
2331
+
2332
+[[package]]
2333
+name = "num_cpus"
2334
+version = "1.17.0"
2335
+source = "registry+https://github.com/rust-lang/crates.io-index"
2336
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
2337
+dependencies = [
2338
+ "hermit-abi",
2339
+ "libc",
2340
+]
2341
+
2342
+[[package]]
2343
+name = "num_enum"
2344
+version = "0.7.5"
2345
+source = "registry+https://github.com/rust-lang/crates.io-index"
2346
+checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c"
2347
+dependencies = [
2348
+ "num_enum_derive",
2349
+ "rustversion",
2350
+]
2351
+
2352
+[[package]]
2353
+name = "num_enum_derive"
2354
+version = "0.7.5"
2355
+source = "registry+https://github.com/rust-lang/crates.io-index"
2356
+checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7"
2357
+dependencies = [
2358
+ "proc-macro-crate",
2359
+ "proc-macro2",
2360
+ "quote",
2361
+ "syn 2.0.113",
2362
+]
2363
+
2364
+[[package]]
2365
+name = "objc"
2366
+version = "0.2.7"
2367
+source = "registry+https://github.com/rust-lang/crates.io-index"
2368
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
2369
+dependencies = [
2370
+ "malloc_buf",
2371
+ "objc_exception",
2372
+]
2373
+
2374
+[[package]]
2375
+name = "objc-sys"
2376
+version = "0.3.5"
2377
+source = "registry+https://github.com/rust-lang/crates.io-index"
2378
+checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
2379
+
2380
+[[package]]
2381
+name = "objc2"
2382
+version = "0.5.2"
2383
+source = "registry+https://github.com/rust-lang/crates.io-index"
2384
+checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
2385
+dependencies = [
2386
+ "objc-sys",
2387
+ "objc2-encode",
2388
+]
2389
+
2390
+[[package]]
2391
+name = "objc2"
2392
+version = "0.6.3"
2393
+source = "registry+https://github.com/rust-lang/crates.io-index"
2394
+checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05"
2395
+dependencies = [
2396
+ "objc2-encode",
2397
+]
2398
+
2399
+[[package]]
2400
+name = "objc2-app-kit"
2401
+version = "0.2.2"
2402
+source = "registry+https://github.com/rust-lang/crates.io-index"
2403
+checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
2404
+dependencies = [
2405
+ "bitflags 2.10.0",
2406
+ "block2",
2407
+ "libc",
2408
+ "objc2 0.5.2",
2409
+ "objc2-core-data",
2410
+ "objc2-core-image",
2411
+ "objc2-foundation 0.2.2",
2412
+ "objc2-quartz-core 0.2.2",
2413
+]
2414
+
2415
+[[package]]
2416
+name = "objc2-cloud-kit"
2417
+version = "0.2.2"
2418
+source = "registry+https://github.com/rust-lang/crates.io-index"
2419
+checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
2420
+dependencies = [
2421
+ "bitflags 2.10.0",
2422
+ "block2",
2423
+ "objc2 0.5.2",
2424
+ "objc2-core-location",
2425
+ "objc2-foundation 0.2.2",
2426
+]
2427
+
2428
+[[package]]
2429
+name = "objc2-contacts"
2430
+version = "0.2.2"
2431
+source = "registry+https://github.com/rust-lang/crates.io-index"
2432
+checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
2433
+dependencies = [
2434
+ "block2",
2435
+ "objc2 0.5.2",
2436
+ "objc2-foundation 0.2.2",
2437
+]
2438
+
2439
+[[package]]
2440
+name = "objc2-core-data"
2441
+version = "0.2.2"
2442
+source = "registry+https://github.com/rust-lang/crates.io-index"
2443
+checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
2444
+dependencies = [
2445
+ "bitflags 2.10.0",
2446
+ "block2",
2447
+ "objc2 0.5.2",
2448
+ "objc2-foundation 0.2.2",
2449
+]
2450
+
2451
+[[package]]
2452
+name = "objc2-core-foundation"
2453
+version = "0.3.2"
2454
+source = "registry+https://github.com/rust-lang/crates.io-index"
2455
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
2456
+dependencies = [
2457
+ "bitflags 2.10.0",
2458
+ "dispatch2",
2459
+ "objc2 0.6.3",
2460
+]
2461
+
2462
+[[package]]
2463
+name = "objc2-core-graphics"
2464
+version = "0.3.2"
2465
+source = "registry+https://github.com/rust-lang/crates.io-index"
2466
+checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807"
2467
+dependencies = [
2468
+ "bitflags 2.10.0",
2469
+ "dispatch2",
2470
+ "objc2 0.6.3",
2471
+ "objc2-core-foundation",
2472
+ "objc2-io-surface",
2473
+]
2474
+
2475
+[[package]]
2476
+name = "objc2-core-image"
2477
+version = "0.2.2"
2478
+source = "registry+https://github.com/rust-lang/crates.io-index"
2479
+checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
2480
+dependencies = [
2481
+ "block2",
2482
+ "objc2 0.5.2",
2483
+ "objc2-foundation 0.2.2",
2484
+ "objc2-metal",
2485
+]
2486
+
2487
+[[package]]
2488
+name = "objc2-core-location"
2489
+version = "0.2.2"
2490
+source = "registry+https://github.com/rust-lang/crates.io-index"
2491
+checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
2492
+dependencies = [
2493
+ "block2",
2494
+ "objc2 0.5.2",
2495
+ "objc2-contacts",
2496
+ "objc2-foundation 0.2.2",
2497
+]
2498
+
2499
+[[package]]
2500
+name = "objc2-encode"
2501
+version = "4.1.0"
2502
+source = "registry+https://github.com/rust-lang/crates.io-index"
2503
+checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33"
2504
+
2505
+[[package]]
2506
+name = "objc2-foundation"
2507
+version = "0.2.2"
2508
+source = "registry+https://github.com/rust-lang/crates.io-index"
2509
+checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
2510
+dependencies = [
2511
+ "bitflags 2.10.0",
2512
+ "block2",
2513
+ "dispatch",
2514
+ "libc",
2515
+ "objc2 0.5.2",
2516
+]
2517
+
2518
+[[package]]
2519
+name = "objc2-foundation"
2520
+version = "0.3.2"
2521
+source = "registry+https://github.com/rust-lang/crates.io-index"
2522
+checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
2523
+dependencies = [
2524
+ "bitflags 2.10.0",
2525
+ "objc2 0.6.3",
2526
+ "objc2-core-foundation",
2527
+]
2528
+
2529
+[[package]]
2530
+name = "objc2-io-surface"
2531
+version = "0.3.2"
2532
+source = "registry+https://github.com/rust-lang/crates.io-index"
2533
+checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d"
2534
+dependencies = [
2535
+ "bitflags 2.10.0",
2536
+ "objc2 0.6.3",
2537
+ "objc2-core-foundation",
2538
+]
2539
+
2540
+[[package]]
2541
+name = "objc2-link-presentation"
2542
+version = "0.2.2"
2543
+source = "registry+https://github.com/rust-lang/crates.io-index"
2544
+checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
2545
+dependencies = [
2546
+ "block2",
2547
+ "objc2 0.5.2",
2548
+ "objc2-app-kit",
2549
+ "objc2-foundation 0.2.2",
2550
+]
2551
+
2552
+[[package]]
2553
+name = "objc2-metal"
2554
+version = "0.2.2"
2555
+source = "registry+https://github.com/rust-lang/crates.io-index"
2556
+checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
2557
+dependencies = [
2558
+ "bitflags 2.10.0",
2559
+ "block2",
2560
+ "objc2 0.5.2",
2561
+ "objc2-foundation 0.2.2",
2562
+]
2563
+
2564
+[[package]]
2565
+name = "objc2-quartz-core"
2566
+version = "0.2.2"
2567
+source = "registry+https://github.com/rust-lang/crates.io-index"
2568
+checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
2569
+dependencies = [
2570
+ "bitflags 2.10.0",
2571
+ "block2",
2572
+ "objc2 0.5.2",
2573
+ "objc2-foundation 0.2.2",
2574
+ "objc2-metal",
2575
+]
2576
+
2577
+[[package]]
2578
+name = "objc2-quartz-core"
2579
+version = "0.3.2"
2580
+source = "registry+https://github.com/rust-lang/crates.io-index"
2581
+checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f"
2582
+dependencies = [
2583
+ "bitflags 2.10.0",
2584
+ "objc2 0.6.3",
2585
+ "objc2-core-foundation",
2586
+ "objc2-foundation 0.3.2",
2587
+]
2588
+
2589
+[[package]]
2590
+name = "objc2-symbols"
2591
+version = "0.2.2"
2592
+source = "registry+https://github.com/rust-lang/crates.io-index"
2593
+checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
2594
+dependencies = [
2595
+ "objc2 0.5.2",
2596
+ "objc2-foundation 0.2.2",
2597
+]
2598
+
2599
+[[package]]
2600
+name = "objc2-ui-kit"
2601
+version = "0.2.2"
2602
+source = "registry+https://github.com/rust-lang/crates.io-index"
2603
+checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
2604
+dependencies = [
2605
+ "bitflags 2.10.0",
2606
+ "block2",
2607
+ "objc2 0.5.2",
2608
+ "objc2-cloud-kit",
2609
+ "objc2-core-data",
2610
+ "objc2-core-image",
2611
+ "objc2-core-location",
2612
+ "objc2-foundation 0.2.2",
2613
+ "objc2-link-presentation",
2614
+ "objc2-quartz-core 0.2.2",
2615
+ "objc2-symbols",
2616
+ "objc2-uniform-type-identifiers",
2617
+ "objc2-user-notifications",
2618
+]
2619
+
2620
+[[package]]
2621
+name = "objc2-uniform-type-identifiers"
2622
+version = "0.2.2"
2623
+source = "registry+https://github.com/rust-lang/crates.io-index"
2624
+checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
2625
+dependencies = [
2626
+ "block2",
2627
+ "objc2 0.5.2",
2628
+ "objc2-foundation 0.2.2",
2629
+]
2630
+
2631
+[[package]]
2632
+name = "objc2-user-notifications"
2633
+version = "0.2.2"
2634
+source = "registry+https://github.com/rust-lang/crates.io-index"
2635
+checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
2636
+dependencies = [
2637
+ "bitflags 2.10.0",
2638
+ "block2",
2639
+ "objc2 0.5.2",
2640
+ "objc2-core-location",
2641
+ "objc2-foundation 0.2.2",
2642
+]
2643
+
2644
+[[package]]
2645
+name = "objc_exception"
2646
+version = "0.1.2"
2647
+source = "registry+https://github.com/rust-lang/crates.io-index"
2648
+checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4"
2649
+dependencies = [
2650
+ "cc",
2651
+]
2652
+
2653
+[[package]]
2654
+name = "once_cell"
2655
+version = "1.21.3"
2656
+source = "registry+https://github.com/rust-lang/crates.io-index"
2657
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
2658
+
2659
+[[package]]
2660
+name = "once_cell_polyfill"
2661
+version = "1.70.2"
2662
+source = "registry+https://github.com/rust-lang/crates.io-index"
2663
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
2664
+
2665
+[[package]]
2666
+name = "option-ext"
2667
+version = "0.2.0"
2668
+source = "registry+https://github.com/rust-lang/crates.io-index"
2669
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
2670
+
2671
+[[package]]
2672
+name = "orbclient"
2673
+version = "0.3.50"
2674
+source = "registry+https://github.com/rust-lang/crates.io-index"
2675
+checksum = "52ad2c6bae700b7aa5d1cc30c59bdd3a1c180b09dbaea51e2ae2b8e1cf211fdd"
2676
+dependencies = [
2677
+ "libc",
2678
+ "libredox",
2679
+]
2680
+
2681
+[[package]]
2682
+name = "ordered-multimap"
2683
+version = "0.4.3"
2684
+source = "registry+https://github.com/rust-lang/crates.io-index"
2685
+checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
2686
+dependencies = [
2687
+ "dlv-list",
2688
+ "hashbrown 0.12.3",
2689
+]
2690
+
2691
+[[package]]
2692
+name = "ordered-stream"
2693
+version = "0.2.0"
2694
+source = "registry+https://github.com/rust-lang/crates.io-index"
2695
+checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
2696
+dependencies = [
2697
+ "futures-core",
2698
+ "pin-project-lite",
2699
+]
2700
+
2701
+[[package]]
2702
+name = "os_pipe"
2703
+version = "1.2.3"
2704
+source = "registry+https://github.com/rust-lang/crates.io-index"
2705
+checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967"
2706
+dependencies = [
2707
+ "libc",
2708
+ "windows-sys 0.61.2",
2709
+]
2710
+
2711
+[[package]]
2712
+name = "owned_ttf_parser"
2713
+version = "0.25.1"
2714
+source = "registry+https://github.com/rust-lang/crates.io-index"
2715
+checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b"
2716
+dependencies = [
2717
+ "ttf-parser 0.25.1",
2718
+]
2719
+
2720
+[[package]]
2721
+name = "palette"
2722
+version = "0.7.6"
2723
+source = "registry+https://github.com/rust-lang/crates.io-index"
2724
+checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6"
2725
+dependencies = [
2726
+ "approx",
2727
+ "fast-srgb8",
2728
+ "palette_derive",
2729
+ "phf",
2730
+]
2731
+
2732
+[[package]]
2733
+name = "palette_derive"
2734
+version = "0.7.6"
2735
+source = "registry+https://github.com/rust-lang/crates.io-index"
2736
+checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30"
2737
+dependencies = [
2738
+ "by_address",
2739
+ "proc-macro2",
2740
+ "quote",
2741
+ "syn 2.0.113",
2742
+]
2743
+
2744
+[[package]]
2745
+name = "parking"
2746
+version = "2.2.1"
2747
+source = "registry+https://github.com/rust-lang/crates.io-index"
2748
+checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
2749
+
2750
+[[package]]
2751
+name = "parking_lot"
2752
+version = "0.11.2"
2753
+source = "registry+https://github.com/rust-lang/crates.io-index"
2754
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
2755
+dependencies = [
2756
+ "instant",
2757
+ "lock_api",
2758
+ "parking_lot_core 0.8.6",
2759
+]
2760
+
2761
+[[package]]
2762
+name = "parking_lot"
2763
+version = "0.12.5"
2764
+source = "registry+https://github.com/rust-lang/crates.io-index"
2765
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
2766
+dependencies = [
2767
+ "lock_api",
2768
+ "parking_lot_core 0.9.12",
2769
+]
2770
+
2771
+[[package]]
2772
+name = "parking_lot_core"
2773
+version = "0.8.6"
2774
+source = "registry+https://github.com/rust-lang/crates.io-index"
2775
+checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
2776
+dependencies = [
2777
+ "cfg-if",
2778
+ "instant",
2779
+ "libc",
2780
+ "redox_syscall 0.2.16",
2781
+ "smallvec",
2782
+ "winapi",
2783
+]
2784
+
2785
+[[package]]
2786
+name = "parking_lot_core"
2787
+version = "0.9.12"
2788
+source = "registry+https://github.com/rust-lang/crates.io-index"
2789
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
2790
+dependencies = [
2791
+ "cfg-if",
2792
+ "libc",
2793
+ "redox_syscall 0.5.18",
2794
+ "smallvec",
2795
+ "windows-link",
2796
+]
2797
+
2798
+[[package]]
2799
+name = "paste"
2800
+version = "1.0.15"
2801
+source = "registry+https://github.com/rust-lang/crates.io-index"
2802
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
2803
+
2804
+[[package]]
2805
+name = "pem"
2806
+version = "3.0.6"
2807
+source = "registry+https://github.com/rust-lang/crates.io-index"
2808
+checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
2809
+dependencies = [
2810
+ "base64",
2811
+ "serde_core",
2812
+]
2813
+
2814
+[[package]]
2815
+name = "percent-encoding"
2816
+version = "2.3.2"
2817
+source = "registry+https://github.com/rust-lang/crates.io-index"
2818
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
2819
+
2820
+[[package]]
2821
+name = "petgraph"
2822
+version = "0.8.3"
2823
+source = "registry+https://github.com/rust-lang/crates.io-index"
2824
+checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455"
2825
+dependencies = [
2826
+ "fixedbitset",
2827
+ "hashbrown 0.15.5",
2828
+ "indexmap",
2829
+]
2830
+
2831
+[[package]]
2832
+name = "phf"
2833
+version = "0.11.3"
2834
+source = "registry+https://github.com/rust-lang/crates.io-index"
2835
+checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078"
2836
+dependencies = [
2837
+ "phf_macros",
2838
+ "phf_shared",
2839
+]
2840
+
2841
+[[package]]
2842
+name = "phf_generator"
2843
+version = "0.11.3"
2844
+source = "registry+https://github.com/rust-lang/crates.io-index"
2845
+checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
2846
+dependencies = [
2847
+ "phf_shared",
2848
+ "rand",
2849
+]
2850
+
2851
+[[package]]
2852
+name = "phf_macros"
2853
+version = "0.11.3"
2854
+source = "registry+https://github.com/rust-lang/crates.io-index"
2855
+checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216"
2856
+dependencies = [
2857
+ "phf_generator",
2858
+ "phf_shared",
2859
+ "proc-macro2",
2860
+ "quote",
2861
+ "syn 2.0.113",
2862
+]
2863
+
2864
+[[package]]
2865
+name = "phf_shared"
2866
+version = "0.11.3"
2867
+source = "registry+https://github.com/rust-lang/crates.io-index"
2868
+checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
2869
+dependencies = [
2870
+ "siphasher",
2871
+]
2872
+
2873
+[[package]]
2874
+name = "pin-project"
2875
+version = "1.1.10"
2876
+source = "registry+https://github.com/rust-lang/crates.io-index"
2877
+checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
2878
+dependencies = [
2879
+ "pin-project-internal",
2880
+]
2881
+
2882
+[[package]]
2883
+name = "pin-project-internal"
2884
+version = "1.1.10"
2885
+source = "registry+https://github.com/rust-lang/crates.io-index"
2886
+checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
2887
+dependencies = [
2888
+ "proc-macro2",
2889
+ "quote",
2890
+ "syn 2.0.113",
2891
+]
2892
+
2893
+[[package]]
2894
+name = "pin-project-lite"
2895
+version = "0.2.16"
2896
+source = "registry+https://github.com/rust-lang/crates.io-index"
2897
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
2898
+
2899
+[[package]]
2900
+name = "pin-utils"
2901
+version = "0.1.0"
2902
+source = "registry+https://github.com/rust-lang/crates.io-index"
2903
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
2904
+
2905
+[[package]]
2906
+name = "piper"
2907
+version = "0.2.4"
2908
+source = "registry+https://github.com/rust-lang/crates.io-index"
2909
+checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
2910
+dependencies = [
2911
+ "atomic-waker",
2912
+ "fastrand",
2913
+ "futures-io",
2914
+]
2915
+
2916
+[[package]]
2917
+name = "pkg-config"
2918
+version = "0.3.32"
2919
+source = "registry+https://github.com/rust-lang/crates.io-index"
2920
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
2921
+
2922
+[[package]]
2923
+name = "png"
2924
+version = "0.17.16"
2925
+source = "registry+https://github.com/rust-lang/crates.io-index"
2926
+checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
2927
+dependencies = [
2928
+ "bitflags 1.3.2",
2929
+ "crc32fast",
2930
+ "fdeflate",
2931
+ "flate2",
2932
+ "miniz_oxide",
2933
+]
2934
+
2935
+[[package]]
2936
+name = "polling"
2937
+version = "3.11.0"
2938
+source = "registry+https://github.com/rust-lang/crates.io-index"
2939
+checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
2940
+dependencies = [
2941
+ "cfg-if",
2942
+ "concurrent-queue",
2943
+ "hermit-abi",
2944
+ "pin-project-lite",
2945
+ "rustix 1.1.3",
2946
+ "windows-sys 0.61.2",
2947
+]
2948
+
2949
+[[package]]
2950
+name = "powerfmt"
2951
+version = "0.2.0"
2952
+source = "registry+https://github.com/rust-lang/crates.io-index"
2953
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
2954
+
2955
+[[package]]
2956
+name = "ppv-lite86"
2957
+version = "0.2.21"
2958
+source = "registry+https://github.com/rust-lang/crates.io-index"
2959
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
2960
+dependencies = [
2961
+ "zerocopy",
2962
+]
2963
+
2964
+[[package]]
2965
+name = "presser"
2966
+version = "0.3.1"
2967
+source = "registry+https://github.com/rust-lang/crates.io-index"
2968
+checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa"
2969
+
2970
+[[package]]
2971
+name = "proc-macro-crate"
2972
+version = "3.4.0"
2973
+source = "registry+https://github.com/rust-lang/crates.io-index"
2974
+checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
2975
+dependencies = [
2976
+ "toml_edit 0.23.10+spec-1.0.0",
2977
+]
2978
+
2979
+[[package]]
2980
+name = "proc-macro2"
2981
+version = "1.0.104"
2982
+source = "registry+https://github.com/rust-lang/crates.io-index"
2983
+checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0"
2984
+dependencies = [
2985
+ "unicode-ident",
2986
+]
2987
+
2988
+[[package]]
2989
+name = "profiling"
2990
+version = "1.0.17"
2991
+source = "registry+https://github.com/rust-lang/crates.io-index"
2992
+checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
2993
+
2994
+[[package]]
2995
+name = "quick-xml"
2996
+version = "0.38.4"
2997
+source = "registry+https://github.com/rust-lang/crates.io-index"
2998
+checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
2999
+dependencies = [
3000
+ "memchr",
3001
+]
3002
+
3003
+[[package]]
3004
+name = "quote"
3005
+version = "1.0.42"
3006
+source = "registry+https://github.com/rust-lang/crates.io-index"
3007
+checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
3008
+dependencies = [
3009
+ "proc-macro2",
3010
+]
3011
+
3012
+[[package]]
3013
+name = "r-efi"
3014
+version = "5.3.0"
3015
+source = "registry+https://github.com/rust-lang/crates.io-index"
3016
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
3017
+
3018
+[[package]]
3019
+name = "radium"
3020
+version = "0.7.0"
3021
+source = "registry+https://github.com/rust-lang/crates.io-index"
3022
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
3023
+
3024
+[[package]]
3025
+name = "rand"
3026
+version = "0.8.5"
3027
+source = "registry+https://github.com/rust-lang/crates.io-index"
3028
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
3029
+dependencies = [
3030
+ "libc",
3031
+ "rand_chacha",
3032
+ "rand_core",
3033
+]
3034
+
3035
+[[package]]
3036
+name = "rand_chacha"
3037
+version = "0.3.1"
3038
+source = "registry+https://github.com/rust-lang/crates.io-index"
3039
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
3040
+dependencies = [
3041
+ "ppv-lite86",
3042
+ "rand_core",
3043
+]
3044
+
3045
+[[package]]
3046
+name = "rand_core"
3047
+version = "0.6.4"
3048
+source = "registry+https://github.com/rust-lang/crates.io-index"
3049
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
3050
+dependencies = [
3051
+ "getrandom 0.2.16",
3052
+]
3053
+
3054
+[[package]]
3055
+name = "range-alloc"
3056
+version = "0.1.4"
3057
+source = "registry+https://github.com/rust-lang/crates.io-index"
3058
+checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde"
3059
+
3060
+[[package]]
3061
+name = "rangemap"
3062
+version = "1.7.1"
3063
+source = "registry+https://github.com/rust-lang/crates.io-index"
3064
+checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68"
3065
+
3066
+[[package]]
3067
+name = "raw-window-handle"
3068
+version = "0.6.2"
3069
+source = "registry+https://github.com/rust-lang/crates.io-index"
3070
+checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
3071
+
3072
+[[package]]
3073
+name = "rayon"
3074
+version = "1.11.0"
3075
+source = "registry+https://github.com/rust-lang/crates.io-index"
3076
+checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
3077
+dependencies = [
3078
+ "either",
3079
+ "rayon-core",
3080
+]
3081
+
3082
+[[package]]
3083
+name = "rayon-core"
3084
+version = "1.13.0"
3085
+source = "registry+https://github.com/rust-lang/crates.io-index"
3086
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
3087
+dependencies = [
3088
+ "crossbeam-deque",
3089
+ "crossbeam-utils",
3090
+]
3091
+
3092
+[[package]]
3093
+name = "rcgen"
3094
+version = "0.13.2"
3095
+source = "registry+https://github.com/rust-lang/crates.io-index"
3096
+checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2"
3097
+dependencies = [
3098
+ "pem",
3099
+ "ring",
3100
+ "rustls-pki-types",
3101
+ "time",
3102
+ "yasna",
3103
+]
3104
+
3105
+[[package]]
3106
+name = "read-fonts"
3107
+version = "0.22.7"
3108
+source = "registry+https://github.com/rust-lang/crates.io-index"
3109
+checksum = "69aacb76b5c29acfb7f90155d39759a29496aebb49395830e928a9703d2eec2f"
3110
+dependencies = [
3111
+ "bytemuck",
3112
+ "font-types",
3113
+]
3114
+
3115
+[[package]]
3116
+name = "redox_syscall"
3117
+version = "0.2.16"
3118
+source = "registry+https://github.com/rust-lang/crates.io-index"
3119
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
3120
+dependencies = [
3121
+ "bitflags 1.3.2",
3122
+]
3123
+
3124
+[[package]]
3125
+name = "redox_syscall"
3126
+version = "0.4.1"
3127
+source = "registry+https://github.com/rust-lang/crates.io-index"
3128
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
3129
+dependencies = [
3130
+ "bitflags 1.3.2",
3131
+]
3132
+
3133
+[[package]]
3134
+name = "redox_syscall"
3135
+version = "0.5.18"
3136
+source = "registry+https://github.com/rust-lang/crates.io-index"
3137
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
3138
+dependencies = [
3139
+ "bitflags 2.10.0",
3140
+]
3141
+
3142
+[[package]]
3143
+name = "redox_syscall"
3144
+version = "0.7.0"
3145
+source = "registry+https://github.com/rust-lang/crates.io-index"
3146
+checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
3147
+dependencies = [
3148
+ "bitflags 2.10.0",
3149
+]
3150
+
3151
+[[package]]
3152
+name = "redox_users"
3153
+version = "0.4.6"
3154
+source = "registry+https://github.com/rust-lang/crates.io-index"
3155
+checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
3156
+dependencies = [
3157
+ "getrandom 0.2.16",
3158
+ "libredox",
3159
+ "thiserror 1.0.69",
3160
+]
3161
+
3162
+[[package]]
3163
+name = "regex-automata"
3164
+version = "0.4.13"
3165
+source = "registry+https://github.com/rust-lang/crates.io-index"
3166
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
3167
+dependencies = [
3168
+ "aho-corasick",
3169
+ "memchr",
3170
+ "regex-syntax",
3171
+]
3172
+
3173
+[[package]]
3174
+name = "regex-syntax"
3175
+version = "0.8.8"
3176
+source = "registry+https://github.com/rust-lang/crates.io-index"
3177
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
3178
+
3179
+[[package]]
3180
+name = "renderdoc-sys"
3181
+version = "1.1.0"
3182
+source = "registry+https://github.com/rust-lang/crates.io-index"
3183
+checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832"
3184
+
3185
+[[package]]
3186
+name = "ring"
3187
+version = "0.17.14"
3188
+source = "registry+https://github.com/rust-lang/crates.io-index"
3189
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
3190
+dependencies = [
3191
+ "cc",
3192
+ "cfg-if",
3193
+ "getrandom 0.2.16",
3194
+ "libc",
3195
+ "untrusted",
3196
+ "windows-sys 0.52.0",
3197
+]
3198
+
3199
+[[package]]
3200
+name = "roxmltree"
3201
+version = "0.20.0"
3202
+source = "registry+https://github.com/rust-lang/crates.io-index"
3203
+checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
3204
+
3205
+[[package]]
3206
+name = "rust-ini"
3207
+version = "0.18.0"
3208
+source = "registry+https://github.com/rust-lang/crates.io-index"
3209
+checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
3210
+dependencies = [
3211
+ "cfg-if",
3212
+ "ordered-multimap",
3213
+]
3214
+
3215
+[[package]]
3216
+name = "rustc-hash"
3217
+version = "1.1.0"
3218
+source = "registry+https://github.com/rust-lang/crates.io-index"
3219
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
3220
+
3221
+[[package]]
3222
+name = "rustc-hash"
3223
+version = "2.1.1"
3224
+source = "registry+https://github.com/rust-lang/crates.io-index"
3225
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
3226
+
3227
+[[package]]
3228
+name = "rustix"
3229
+version = "0.38.44"
3230
+source = "registry+https://github.com/rust-lang/crates.io-index"
3231
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
3232
+dependencies = [
3233
+ "bitflags 2.10.0",
3234
+ "errno",
3235
+ "libc",
3236
+ "linux-raw-sys 0.4.15",
3237
+ "windows-sys 0.52.0",
3238
+]
3239
+
3240
+[[package]]
3241
+name = "rustix"
3242
+version = "1.1.3"
3243
+source = "registry+https://github.com/rust-lang/crates.io-index"
3244
+checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
3245
+dependencies = [
3246
+ "bitflags 2.10.0",
3247
+ "errno",
3248
+ "libc",
3249
+ "linux-raw-sys 0.11.0",
3250
+ "windows-sys 0.61.2",
3251
+]
3252
+
3253
+[[package]]
3254
+name = "rustls"
3255
+version = "0.23.35"
3256
+source = "registry+https://github.com/rust-lang/crates.io-index"
3257
+checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
3258
+dependencies = [
3259
+ "aws-lc-rs",
3260
+ "log",
3261
+ "once_cell",
3262
+ "rustls-pki-types",
3263
+ "rustls-webpki",
3264
+ "subtle",
3265
+ "zeroize",
3266
+]
3267
+
3268
+[[package]]
3269
+name = "rustls-pemfile"
3270
+version = "2.2.0"
3271
+source = "registry+https://github.com/rust-lang/crates.io-index"
3272
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
3273
+dependencies = [
3274
+ "rustls-pki-types",
3275
+]
3276
+
3277
+[[package]]
3278
+name = "rustls-pki-types"
3279
+version = "1.13.2"
3280
+source = "registry+https://github.com/rust-lang/crates.io-index"
3281
+checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
3282
+dependencies = [
3283
+ "zeroize",
3284
+]
3285
+
3286
+[[package]]
3287
+name = "rustls-webpki"
3288
+version = "0.103.8"
3289
+source = "registry+https://github.com/rust-lang/crates.io-index"
3290
+checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52"
3291
+dependencies = [
3292
+ "aws-lc-rs",
3293
+ "ring",
3294
+ "rustls-pki-types",
3295
+ "untrusted",
3296
+]
3297
+
3298
+[[package]]
3299
+name = "rustversion"
3300
+version = "1.0.22"
3301
+source = "registry+https://github.com/rust-lang/crates.io-index"
3302
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
3303
+
3304
+[[package]]
3305
+name = "rustybuzz"
3306
+version = "0.14.1"
3307
+source = "registry+https://github.com/rust-lang/crates.io-index"
3308
+checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c"
3309
+dependencies = [
3310
+ "bitflags 2.10.0",
3311
+ "bytemuck",
3312
+ "libm",
3313
+ "smallvec",
3314
+ "ttf-parser 0.21.1",
3315
+ "unicode-bidi-mirroring",
3316
+ "unicode-ccc",
3317
+ "unicode-properties",
3318
+ "unicode-script",
3319
+]
3320
+
3321
+[[package]]
3322
+name = "same-file"
3323
+version = "1.0.6"
3324
+source = "registry+https://github.com/rust-lang/crates.io-index"
3325
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
3326
+dependencies = [
3327
+ "winapi-util",
3328
+]
3329
+
3330
+[[package]]
3331
+name = "scoped-tls"
3332
+version = "1.0.1"
3333
+source = "registry+https://github.com/rust-lang/crates.io-index"
3334
+checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
3335
+
3336
+[[package]]
3337
+name = "scopeguard"
3338
+version = "1.2.0"
3339
+source = "registry+https://github.com/rust-lang/crates.io-index"
3340
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
3341
+
3342
+[[package]]
3343
+name = "sctk-adwaita"
3344
+version = "0.10.1"
3345
+source = "registry+https://github.com/rust-lang/crates.io-index"
3346
+checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec"
3347
+dependencies = [
3348
+ "ab_glyph",
3349
+ "log",
3350
+ "memmap2 0.9.9",
3351
+ "smithay-client-toolkit 0.19.2",
3352
+ "tiny-skia",
3353
+]
3354
+
3355
+[[package]]
3356
+name = "self_cell"
3357
+version = "1.2.2"
3358
+source = "registry+https://github.com/rust-lang/crates.io-index"
3359
+checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89"
3360
+
3361
+[[package]]
3362
+name = "serde"
3363
+version = "1.0.228"
3364
+source = "registry+https://github.com/rust-lang/crates.io-index"
3365
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
3366
+dependencies = [
3367
+ "serde_core",
3368
+ "serde_derive",
3369
+]
3370
+
3371
+[[package]]
3372
+name = "serde_core"
3373
+version = "1.0.228"
3374
+source = "registry+https://github.com/rust-lang/crates.io-index"
3375
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
3376
+dependencies = [
3377
+ "serde_derive",
3378
+]
3379
+
3380
+[[package]]
3381
+name = "serde_derive"
3382
+version = "1.0.228"
3383
+source = "registry+https://github.com/rust-lang/crates.io-index"
3384
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
3385
+dependencies = [
3386
+ "proc-macro2",
3387
+ "quote",
3388
+ "syn 2.0.113",
3389
+]
3390
+
3391
+[[package]]
3392
+name = "serde_json"
3393
+version = "1.0.148"
3394
+source = "registry+https://github.com/rust-lang/crates.io-index"
3395
+checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da"
3396
+dependencies = [
3397
+ "itoa",
3398
+ "memchr",
3399
+ "serde",
3400
+ "serde_core",
3401
+ "zmij",
3402
+]
3403
+
3404
+[[package]]
3405
+name = "serde_repr"
3406
+version = "0.1.20"
3407
+source = "registry+https://github.com/rust-lang/crates.io-index"
3408
+checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
3409
+dependencies = [
3410
+ "proc-macro2",
3411
+ "quote",
3412
+ "syn 2.0.113",
3413
+]
3414
+
3415
+[[package]]
3416
+name = "serde_spanned"
3417
+version = "0.6.9"
3418
+source = "registry+https://github.com/rust-lang/crates.io-index"
3419
+checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
3420
+dependencies = [
3421
+ "serde",
3422
+]
3423
+
3424
+[[package]]
3425
+name = "sha1"
3426
+version = "0.10.6"
3427
+source = "registry+https://github.com/rust-lang/crates.io-index"
3428
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
3429
+dependencies = [
3430
+ "cfg-if",
3431
+ "cpufeatures",
3432
+ "digest",
3433
+]
3434
+
3435
+[[package]]
3436
+name = "sha2"
3437
+version = "0.10.9"
3438
+source = "registry+https://github.com/rust-lang/crates.io-index"
3439
+checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
3440
+dependencies = [
3441
+ "cfg-if",
3442
+ "cpufeatures",
3443
+ "digest",
3444
+]
3445
+
3446
+[[package]]
3447
+name = "sharded-slab"
3448
+version = "0.1.7"
3449
+source = "registry+https://github.com/rust-lang/crates.io-index"
3450
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
3451
+dependencies = [
3452
+ "lazy_static",
3453
+]
3454
+
3455
+[[package]]
3456
+name = "shlex"
3457
+version = "1.3.0"
3458
+source = "registry+https://github.com/rust-lang/crates.io-index"
3459
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
3460
+
3461
+[[package]]
3462
+name = "signal-hook-registry"
3463
+version = "1.4.8"
3464
+source = "registry+https://github.com/rust-lang/crates.io-index"
3465
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
3466
+dependencies = [
3467
+ "errno",
3468
+ "libc",
3469
+]
3470
+
3471
+[[package]]
3472
+name = "simd-adler32"
3473
+version = "0.3.8"
3474
+source = "registry+https://github.com/rust-lang/crates.io-index"
3475
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
3476
+
3477
+[[package]]
3478
+name = "siphasher"
3479
+version = "1.0.1"
3480
+source = "registry+https://github.com/rust-lang/crates.io-index"
3481
+checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
3482
+
3483
+[[package]]
3484
+name = "skrifa"
3485
+version = "0.22.3"
3486
+source = "registry+https://github.com/rust-lang/crates.io-index"
3487
+checksum = "8e1c44ad1f6c5bdd4eefed8326711b7dbda9ea45dfd36068c427d332aa382cbe"
3488
+dependencies = [
3489
+ "bytemuck",
3490
+ "read-fonts",
3491
+]
3492
+
3493
+[[package]]
3494
+name = "slab"
3495
+version = "0.4.11"
3496
+source = "registry+https://github.com/rust-lang/crates.io-index"
3497
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
3498
+
3499
+[[package]]
3500
+name = "slotmap"
3501
+version = "1.1.1"
3502
+source = "registry+https://github.com/rust-lang/crates.io-index"
3503
+checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038"
3504
+dependencies = [
3505
+ "version_check",
3506
+]
3507
+
3508
+[[package]]
3509
+name = "smallvec"
3510
+version = "1.15.1"
3511
+source = "registry+https://github.com/rust-lang/crates.io-index"
3512
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
3513
+
3514
+[[package]]
3515
+name = "smithay-client-toolkit"
3516
+version = "0.19.2"
3517
+source = "registry+https://github.com/rust-lang/crates.io-index"
3518
+checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016"
3519
+dependencies = [
3520
+ "bitflags 2.10.0",
3521
+ "bytemuck",
3522
+ "calloop 0.13.0",
3523
+ "calloop-wayland-source 0.3.0",
3524
+ "cursor-icon",
3525
+ "libc",
3526
+ "log",
3527
+ "memmap2 0.9.9",
3528
+ "pkg-config",
3529
+ "rustix 0.38.44",
3530
+ "thiserror 1.0.69",
3531
+ "wayland-backend",
3532
+ "wayland-client",
3533
+ "wayland-csd-frame",
3534
+ "wayland-cursor",
3535
+ "wayland-protocols 0.32.10",
3536
+ "wayland-protocols-wlr",
3537
+ "wayland-scanner",
3538
+ "xkbcommon",
3539
+ "xkeysym",
3540
+]
3541
+
3542
+[[package]]
3543
+name = "smithay-client-toolkit"
3544
+version = "0.20.0"
3545
+source = "registry+https://github.com/rust-lang/crates.io-index"
3546
+checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0"
3547
+dependencies = [
3548
+ "bitflags 2.10.0",
3549
+ "calloop 0.14.3",
3550
+ "calloop-wayland-source 0.4.1",
3551
+ "cursor-icon",
3552
+ "libc",
3553
+ "log",
3554
+ "memmap2 0.9.9",
3555
+ "rustix 1.1.3",
3556
+ "thiserror 2.0.17",
3557
+ "wayland-backend",
3558
+ "wayland-client",
3559
+ "wayland-csd-frame",
3560
+ "wayland-cursor",
3561
+ "wayland-protocols 0.32.10",
3562
+ "wayland-protocols-experimental",
3563
+ "wayland-protocols-misc",
3564
+ "wayland-protocols-wlr",
3565
+ "wayland-scanner",
3566
+ "xkeysym",
3567
+]
3568
+
3569
+[[package]]
3570
+name = "smithay-clipboard"
3571
+version = "0.7.3"
3572
+source = "registry+https://github.com/rust-lang/crates.io-index"
3573
+checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226"
3574
+dependencies = [
3575
+ "libc",
3576
+ "smithay-client-toolkit 0.20.0",
3577
+ "wayland-backend",
3578
+]
3579
+
3580
+[[package]]
3581
+name = "smol_str"
3582
+version = "0.2.2"
3583
+source = "registry+https://github.com/rust-lang/crates.io-index"
3584
+checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead"
3585
+dependencies = [
3586
+ "serde",
3587
+]
3588
+
3589
+[[package]]
3590
+name = "socket2"
3591
+version = "0.6.1"
3592
+source = "registry+https://github.com/rust-lang/crates.io-index"
3593
+checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
3594
+dependencies = [
3595
+ "libc",
3596
+ "windows-sys 0.60.2",
3597
+]
3598
+
3599
+[[package]]
3600
+name = "softbuffer"
3601
+version = "0.4.8"
3602
+source = "registry+https://github.com/rust-lang/crates.io-index"
3603
+checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3"
3604
+dependencies = [
3605
+ "as-raw-xcb-connection",
3606
+ "bytemuck",
3607
+ "drm",
3608
+ "fastrand",
3609
+ "js-sys",
3610
+ "memmap2 0.9.9",
3611
+ "ndk",
3612
+ "objc2 0.6.3",
3613
+ "objc2-core-foundation",
3614
+ "objc2-core-graphics",
3615
+ "objc2-foundation 0.3.2",
3616
+ "objc2-quartz-core 0.3.2",
3617
+ "raw-window-handle",
3618
+ "redox_syscall 0.5.18",
3619
+ "rustix 1.1.3",
3620
+ "tiny-xlib",
3621
+ "tracing",
3622
+ "wasm-bindgen",
3623
+ "wayland-backend",
3624
+ "wayland-client",
3625
+ "wayland-sys",
3626
+ "web-sys",
3627
+ "windows-sys 0.61.2",
3628
+ "x11rb",
3629
+]
3630
+
3631
+[[package]]
3632
+name = "spirv"
3633
+version = "0.3.0+sdk-1.3.268.0"
3634
+source = "registry+https://github.com/rust-lang/crates.io-index"
3635
+checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
3636
+dependencies = [
3637
+ "bitflags 2.10.0",
3638
+]
3639
+
3640
+[[package]]
3641
+name = "static_assertions"
3642
+version = "1.1.0"
3643
+source = "registry+https://github.com/rust-lang/crates.io-index"
3644
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
3645
+
3646
+[[package]]
3647
+name = "strict-num"
3648
+version = "0.1.1"
3649
+source = "registry+https://github.com/rust-lang/crates.io-index"
3650
+checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731"
3651
+
3652
+[[package]]
3653
+name = "strsim"
3654
+version = "0.11.1"
3655
+source = "registry+https://github.com/rust-lang/crates.io-index"
3656
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
3657
+
3658
+[[package]]
3659
+name = "subtle"
3660
+version = "2.6.1"
3661
+source = "registry+https://github.com/rust-lang/crates.io-index"
3662
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
3663
+
3664
+[[package]]
3665
+name = "svg_fmt"
3666
+version = "0.4.5"
3667
+source = "registry+https://github.com/rust-lang/crates.io-index"
3668
+checksum = "0193cc4331cfd2f3d2011ef287590868599a2f33c3e69bc22c1a3d3acf9e02fb"
3669
+
3670
+[[package]]
3671
+name = "swash"
3672
+version = "0.1.19"
3673
+source = "registry+https://github.com/rust-lang/crates.io-index"
3674
+checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2"
3675
+dependencies = [
3676
+ "skrifa",
3677
+ "yazi",
3678
+ "zeno",
3679
+]
3680
+
3681
+[[package]]
3682
+name = "syn"
3683
+version = "1.0.109"
3684
+source = "registry+https://github.com/rust-lang/crates.io-index"
3685
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
3686
+dependencies = [
3687
+ "proc-macro2",
3688
+ "quote",
3689
+ "unicode-ident",
3690
+]
3691
+
3692
+[[package]]
3693
+name = "syn"
3694
+version = "2.0.113"
3695
+source = "registry+https://github.com/rust-lang/crates.io-index"
3696
+checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4"
3697
+dependencies = [
3698
+ "proc-macro2",
3699
+ "quote",
3700
+ "unicode-ident",
3701
+]
3702
+
3703
+[[package]]
3704
+name = "sys-locale"
3705
+version = "0.3.2"
3706
+source = "registry+https://github.com/rust-lang/crates.io-index"
3707
+checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
3708
+dependencies = [
3709
+ "libc",
3710
+]
3711
+
3712
+[[package]]
3713
+name = "tap"
3714
+version = "1.0.1"
3715
+source = "registry+https://github.com/rust-lang/crates.io-index"
3716
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
3717
+
3718
+[[package]]
3719
+name = "tempfile"
3720
+version = "3.24.0"
3721
+source = "registry+https://github.com/rust-lang/crates.io-index"
3722
+checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
3723
+dependencies = [
3724
+ "fastrand",
3725
+ "getrandom 0.3.4",
3726
+ "once_cell",
3727
+ "rustix 1.1.3",
3728
+ "windows-sys 0.61.2",
3729
+]
3730
+
3731
+[[package]]
3732
+name = "termcolor"
3733
+version = "1.4.1"
3734
+source = "registry+https://github.com/rust-lang/crates.io-index"
3735
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
3736
+dependencies = [
3737
+ "winapi-util",
3738
+]
3739
+
3740
+[[package]]
3741
+name = "thiserror"
3742
+version = "1.0.69"
3743
+source = "registry+https://github.com/rust-lang/crates.io-index"
3744
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
3745
+dependencies = [
3746
+ "thiserror-impl 1.0.69",
3747
+]
3748
+
3749
+[[package]]
3750
+name = "thiserror"
3751
+version = "2.0.17"
3752
+source = "registry+https://github.com/rust-lang/crates.io-index"
3753
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
3754
+dependencies = [
3755
+ "thiserror-impl 2.0.17",
3756
+]
3757
+
3758
+[[package]]
3759
+name = "thiserror-impl"
3760
+version = "1.0.69"
3761
+source = "registry+https://github.com/rust-lang/crates.io-index"
3762
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
3763
+dependencies = [
3764
+ "proc-macro2",
3765
+ "quote",
3766
+ "syn 2.0.113",
3767
+]
3768
+
3769
+[[package]]
3770
+name = "thiserror-impl"
3771
+version = "2.0.17"
3772
+source = "registry+https://github.com/rust-lang/crates.io-index"
3773
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
3774
+dependencies = [
3775
+ "proc-macro2",
3776
+ "quote",
3777
+ "syn 2.0.113",
3778
+]
3779
+
3780
+[[package]]
3781
+name = "thread_local"
3782
+version = "1.1.9"
3783
+source = "registry+https://github.com/rust-lang/crates.io-index"
3784
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
3785
+dependencies = [
3786
+ "cfg-if",
3787
+]
3788
+
3789
+[[package]]
3790
+name = "time"
3791
+version = "0.3.44"
3792
+source = "registry+https://github.com/rust-lang/crates.io-index"
3793
+checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
3794
+dependencies = [
3795
+ "deranged",
3796
+ "itoa",
3797
+ "num-conv",
3798
+ "powerfmt",
3799
+ "serde",
3800
+ "time-core",
3801
+ "time-macros",
3802
+]
3803
+
3804
+[[package]]
3805
+name = "time-core"
3806
+version = "0.1.6"
3807
+source = "registry+https://github.com/rust-lang/crates.io-index"
3808
+checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
3809
+
3810
+[[package]]
3811
+name = "time-macros"
3812
+version = "0.2.24"
3813
+source = "registry+https://github.com/rust-lang/crates.io-index"
3814
+checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
3815
+dependencies = [
3816
+ "num-conv",
3817
+ "time-core",
3818
+]
3819
+
3820
+[[package]]
3821
+name = "tiny-skia"
3822
+version = "0.11.4"
3823
+source = "registry+https://github.com/rust-lang/crates.io-index"
3824
+checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab"
3825
+dependencies = [
3826
+ "arrayref",
3827
+ "arrayvec",
3828
+ "bytemuck",
3829
+ "cfg-if",
3830
+ "log",
3831
+ "png",
3832
+ "tiny-skia-path",
3833
+]
3834
+
3835
+[[package]]
3836
+name = "tiny-skia-path"
3837
+version = "0.11.4"
3838
+source = "registry+https://github.com/rust-lang/crates.io-index"
3839
+checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93"
3840
+dependencies = [
3841
+ "arrayref",
3842
+ "bytemuck",
3843
+ "strict-num",
3844
+]
3845
+
3846
+[[package]]
3847
+name = "tiny-xlib"
3848
+version = "0.2.4"
3849
+source = "registry+https://github.com/rust-lang/crates.io-index"
3850
+checksum = "0324504befd01cab6e0c994f34b2ffa257849ee019d3fb3b64fb2c858887d89e"
3851
+dependencies = [
3852
+ "as-raw-xcb-connection",
3853
+ "ctor-lite",
3854
+ "libloading 0.8.9",
3855
+ "pkg-config",
3856
+ "tracing",
3857
+]
3858
+
12073859
 [[package]]
1208
-name = "thiserror"
1209
-version = "2.0.17"
3860
+name = "tinyvec"
3861
+version = "1.10.0"
12103862
 source = "registry+https://github.com/rust-lang/crates.io-index"
1211
-checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
3863
+checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
12123864
 dependencies = [
1213
- "thiserror-impl 2.0.17",
3865
+ "tinyvec_macros",
12143866
 ]
12153867
 
12163868
 [[package]]
1217
-name = "thiserror-impl"
1218
-version = "1.0.69"
3869
+name = "tinyvec_macros"
3870
+version = "0.1.1"
12193871
 source = "registry+https://github.com/rust-lang/crates.io-index"
1220
-checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
3872
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
3873
+
3874
+[[package]]
3875
+name = "tokio"
3876
+version = "1.49.0"
3877
+source = "registry+https://github.com/rust-lang/crates.io-index"
3878
+checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
3879
+dependencies = [
3880
+ "bytes",
3881
+ "libc",
3882
+ "mio",
3883
+ "parking_lot 0.12.5",
3884
+ "pin-project-lite",
3885
+ "signal-hook-registry",
3886
+ "socket2",
3887
+ "tokio-macros",
3888
+ "windows-sys 0.61.2",
3889
+]
3890
+
3891
+[[package]]
3892
+name = "tokio-macros"
3893
+version = "2.6.0"
3894
+source = "registry+https://github.com/rust-lang/crates.io-index"
3895
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
12213896
 dependencies = [
12223897
  "proc-macro2",
12233898
  "quote",
1224
- "syn",
3899
+ "syn 2.0.113",
12253900
 ]
12263901
 
12273902
 [[package]]
1228
-name = "thiserror-impl"
1229
-version = "2.0.17"
3903
+name = "tokio-rustls"
3904
+version = "0.26.4"
12303905
 source = "registry+https://github.com/rust-lang/crates.io-index"
1231
-checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
3906
+checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
3907
+dependencies = [
3908
+ "rustls",
3909
+ "tokio",
3910
+]
3911
+
3912
+[[package]]
3913
+name = "toml"
3914
+version = "0.8.23"
3915
+source = "registry+https://github.com/rust-lang/crates.io-index"
3916
+checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
3917
+dependencies = [
3918
+ "serde",
3919
+ "serde_spanned",
3920
+ "toml_datetime 0.6.11",
3921
+ "toml_edit 0.22.27",
3922
+]
3923
+
3924
+[[package]]
3925
+name = "toml_datetime"
3926
+version = "0.6.11"
3927
+source = "registry+https://github.com/rust-lang/crates.io-index"
3928
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
3929
+dependencies = [
3930
+ "serde",
3931
+]
3932
+
3933
+[[package]]
3934
+name = "toml_datetime"
3935
+version = "0.7.5+spec-1.1.0"
3936
+source = "registry+https://github.com/rust-lang/crates.io-index"
3937
+checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
3938
+dependencies = [
3939
+ "serde_core",
3940
+]
3941
+
3942
+[[package]]
3943
+name = "toml_edit"
3944
+version = "0.22.27"
3945
+source = "registry+https://github.com/rust-lang/crates.io-index"
3946
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
3947
+dependencies = [
3948
+ "indexmap",
3949
+ "serde",
3950
+ "serde_spanned",
3951
+ "toml_datetime 0.6.11",
3952
+ "toml_write",
3953
+ "winnow",
3954
+]
3955
+
3956
+[[package]]
3957
+name = "toml_edit"
3958
+version = "0.23.10+spec-1.0.0"
3959
+source = "registry+https://github.com/rust-lang/crates.io-index"
3960
+checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
3961
+dependencies = [
3962
+ "indexmap",
3963
+ "toml_datetime 0.7.5+spec-1.1.0",
3964
+ "toml_parser",
3965
+ "winnow",
3966
+]
3967
+
3968
+[[package]]
3969
+name = "toml_parser"
3970
+version = "1.0.6+spec-1.1.0"
3971
+source = "registry+https://github.com/rust-lang/crates.io-index"
3972
+checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
3973
+dependencies = [
3974
+ "winnow",
3975
+]
3976
+
3977
+[[package]]
3978
+name = "toml_write"
3979
+version = "0.1.2"
3980
+source = "registry+https://github.com/rust-lang/crates.io-index"
3981
+checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
3982
+
3983
+[[package]]
3984
+name = "tracing"
3985
+version = "0.1.44"
3986
+source = "registry+https://github.com/rust-lang/crates.io-index"
3987
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
3988
+dependencies = [
3989
+ "log",
3990
+ "pin-project-lite",
3991
+ "tracing-attributes",
3992
+ "tracing-core",
3993
+]
3994
+
3995
+[[package]]
3996
+name = "tracing-appender"
3997
+version = "0.2.4"
3998
+source = "registry+https://github.com/rust-lang/crates.io-index"
3999
+checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf"
4000
+dependencies = [
4001
+ "crossbeam-channel",
4002
+ "thiserror 2.0.17",
4003
+ "time",
4004
+ "tracing-subscriber",
4005
+]
4006
+
4007
+[[package]]
4008
+name = "tracing-attributes"
4009
+version = "0.1.31"
4010
+source = "registry+https://github.com/rust-lang/crates.io-index"
4011
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
12324012
 dependencies = [
12334013
  "proc-macro2",
12344014
  "quote",
1235
- "syn",
4015
+ "syn 2.0.113",
12364016
 ]
12374017
 
12384018
 [[package]]
1239
-name = "thread_local"
1240
-version = "1.1.9"
4019
+name = "tracing-core"
4020
+version = "0.1.36"
12414021
 source = "registry+https://github.com/rust-lang/crates.io-index"
1242
-checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
4022
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
12434023
 dependencies = [
1244
- "cfg-if",
4024
+ "once_cell",
4025
+ "valuable",
4026
+]
4027
+
4028
+[[package]]
4029
+name = "tracing-log"
4030
+version = "0.2.0"
4031
+source = "registry+https://github.com/rust-lang/crates.io-index"
4032
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
4033
+dependencies = [
4034
+ "log",
4035
+ "once_cell",
4036
+ "tracing-core",
4037
+]
4038
+
4039
+[[package]]
4040
+name = "tracing-subscriber"
4041
+version = "0.3.22"
4042
+source = "registry+https://github.com/rust-lang/crates.io-index"
4043
+checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
4044
+dependencies = [
4045
+ "matchers",
4046
+ "nu-ansi-term",
4047
+ "once_cell",
4048
+ "regex-automata",
4049
+ "sharded-slab",
4050
+ "smallvec",
4051
+ "thread_local",
4052
+ "tracing",
4053
+ "tracing-core",
4054
+ "tracing-log",
4055
+]
4056
+
4057
+[[package]]
4058
+name = "tree_magic_mini"
4059
+version = "3.2.2"
4060
+source = "registry+https://github.com/rust-lang/crates.io-index"
4061
+checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6"
4062
+dependencies = [
4063
+ "memchr",
4064
+ "nom",
4065
+ "petgraph",
4066
+]
4067
+
4068
+[[package]]
4069
+name = "ttf-parser"
4070
+version = "0.20.0"
4071
+source = "registry+https://github.com/rust-lang/crates.io-index"
4072
+checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4"
4073
+
4074
+[[package]]
4075
+name = "ttf-parser"
4076
+version = "0.21.1"
4077
+source = "registry+https://github.com/rust-lang/crates.io-index"
4078
+checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8"
4079
+
4080
+[[package]]
4081
+name = "ttf-parser"
4082
+version = "0.25.1"
4083
+source = "registry+https://github.com/rust-lang/crates.io-index"
4084
+checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
4085
+
4086
+[[package]]
4087
+name = "typenum"
4088
+version = "1.19.0"
4089
+source = "registry+https://github.com/rust-lang/crates.io-index"
4090
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
4091
+
4092
+[[package]]
4093
+name = "uds_windows"
4094
+version = "1.1.0"
4095
+source = "registry+https://github.com/rust-lang/crates.io-index"
4096
+checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
4097
+dependencies = [
4098
+ "memoffset 0.9.1",
4099
+ "tempfile",
4100
+ "winapi",
12454101
 ]
12464102
 
12474103
 [[package]]
1248
-name = "time"
1249
-version = "0.3.44"
4104
+name = "unicode-bidi"
4105
+version = "0.3.18"
4106
+source = "registry+https://github.com/rust-lang/crates.io-index"
4107
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
4108
+
4109
+[[package]]
4110
+name = "unicode-bidi-mirroring"
4111
+version = "0.2.0"
4112
+source = "registry+https://github.com/rust-lang/crates.io-index"
4113
+checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86"
4114
+
4115
+[[package]]
4116
+name = "unicode-ccc"
4117
+version = "0.2.0"
4118
+source = "registry+https://github.com/rust-lang/crates.io-index"
4119
+checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656"
4120
+
4121
+[[package]]
4122
+name = "unicode-ident"
4123
+version = "1.0.22"
4124
+source = "registry+https://github.com/rust-lang/crates.io-index"
4125
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
4126
+
4127
+[[package]]
4128
+name = "unicode-linebreak"
4129
+version = "0.1.5"
4130
+source = "registry+https://github.com/rust-lang/crates.io-index"
4131
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
4132
+
4133
+[[package]]
4134
+name = "unicode-properties"
4135
+version = "0.1.4"
4136
+source = "registry+https://github.com/rust-lang/crates.io-index"
4137
+checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
4138
+
4139
+[[package]]
4140
+name = "unicode-script"
4141
+version = "0.5.8"
4142
+source = "registry+https://github.com/rust-lang/crates.io-index"
4143
+checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee"
4144
+
4145
+[[package]]
4146
+name = "unicode-segmentation"
4147
+version = "1.12.0"
4148
+source = "registry+https://github.com/rust-lang/crates.io-index"
4149
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
4150
+
4151
+[[package]]
4152
+name = "unicode-width"
4153
+version = "0.1.14"
4154
+source = "registry+https://github.com/rust-lang/crates.io-index"
4155
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
4156
+
4157
+[[package]]
4158
+name = "unicode-xid"
4159
+version = "0.2.6"
4160
+source = "registry+https://github.com/rust-lang/crates.io-index"
4161
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
4162
+
4163
+[[package]]
4164
+name = "untrusted"
4165
+version = "0.9.0"
4166
+source = "registry+https://github.com/rust-lang/crates.io-index"
4167
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
4168
+
4169
+[[package]]
4170
+name = "utf8parse"
4171
+version = "0.2.2"
4172
+source = "registry+https://github.com/rust-lang/crates.io-index"
4173
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
4174
+
4175
+[[package]]
4176
+name = "valuable"
4177
+version = "0.1.1"
4178
+source = "registry+https://github.com/rust-lang/crates.io-index"
4179
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
4180
+
4181
+[[package]]
4182
+name = "version_check"
4183
+version = "0.9.5"
4184
+source = "registry+https://github.com/rust-lang/crates.io-index"
4185
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
4186
+
4187
+[[package]]
4188
+name = "walkdir"
4189
+version = "2.5.0"
12504190
 source = "registry+https://github.com/rust-lang/crates.io-index"
1251
-checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
4191
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
12524192
 dependencies = [
1253
- "deranged",
1254
- "itoa",
1255
- "num-conv",
1256
- "powerfmt",
1257
- "serde",
1258
- "time-core",
1259
- "time-macros",
4193
+ "same-file",
4194
+ "winapi-util",
12604195
 ]
12614196
 
12624197
 [[package]]
1263
-name = "time-core"
1264
-version = "0.1.6"
4198
+name = "wasi"
4199
+version = "0.11.1+wasi-snapshot-preview1"
12654200
 source = "registry+https://github.com/rust-lang/crates.io-index"
1266
-checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
4201
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
12674202
 
12684203
 [[package]]
1269
-name = "time-macros"
1270
-version = "0.2.24"
4204
+name = "wasip2"
4205
+version = "1.0.1+wasi-0.2.4"
12714206
 source = "registry+https://github.com/rust-lang/crates.io-index"
1272
-checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
4207
+checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
12734208
 dependencies = [
1274
- "num-conv",
1275
- "time-core",
4209
+ "wit-bindgen",
12764210
 ]
12774211
 
12784212
 [[package]]
1279
-name = "tokio"
1280
-version = "1.49.0"
4213
+name = "wasm-bindgen"
4214
+version = "0.2.106"
12814215
 source = "registry+https://github.com/rust-lang/crates.io-index"
1282
-checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
4216
+checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
12834217
 dependencies = [
1284
- "bytes",
1285
- "libc",
1286
- "mio",
1287
- "parking_lot",
1288
- "pin-project-lite",
1289
- "signal-hook-registry",
1290
- "socket2",
1291
- "tokio-macros",
1292
- "windows-sys 0.61.2",
4218
+ "cfg-if",
4219
+ "once_cell",
4220
+ "rustversion",
4221
+ "wasm-bindgen-macro",
4222
+ "wasm-bindgen-shared",
12934223
 ]
12944224
 
12954225
 [[package]]
1296
-name = "tokio-macros"
1297
-version = "2.6.0"
4226
+name = "wasm-bindgen-futures"
4227
+version = "0.4.56"
12984228
 source = "registry+https://github.com/rust-lang/crates.io-index"
1299
-checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
4229
+checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
13004230
 dependencies = [
1301
- "proc-macro2",
1302
- "quote",
1303
- "syn",
4231
+ "cfg-if",
4232
+ "js-sys",
4233
+ "once_cell",
4234
+ "wasm-bindgen",
4235
+ "web-sys",
13044236
 ]
13054237
 
13064238
 [[package]]
1307
-name = "tokio-rustls"
1308
-version = "0.26.4"
4239
+name = "wasm-bindgen-macro"
4240
+version = "0.2.106"
13094241
 source = "registry+https://github.com/rust-lang/crates.io-index"
1310
-checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
4242
+checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
13114243
 dependencies = [
1312
- "rustls",
1313
- "tokio",
4244
+ "quote",
4245
+ "wasm-bindgen-macro-support",
13144246
 ]
13154247
 
13164248
 [[package]]
1317
-name = "toml"
1318
-version = "0.8.23"
4249
+name = "wasm-bindgen-macro-support"
4250
+version = "0.2.106"
13194251
 source = "registry+https://github.com/rust-lang/crates.io-index"
1320
-checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
4252
+checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
13214253
 dependencies = [
1322
- "serde",
1323
- "serde_spanned",
1324
- "toml_datetime",
1325
- "toml_edit",
4254
+ "bumpalo",
4255
+ "proc-macro2",
4256
+ "quote",
4257
+ "syn 2.0.113",
4258
+ "wasm-bindgen-shared",
13264259
 ]
13274260
 
13284261
 [[package]]
1329
-name = "toml_datetime"
1330
-version = "0.6.11"
4262
+name = "wasm-bindgen-shared"
4263
+version = "0.2.106"
13314264
 source = "registry+https://github.com/rust-lang/crates.io-index"
1332
-checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
4265
+checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
13334266
 dependencies = [
1334
- "serde",
4267
+ "unicode-ident",
13354268
 ]
13364269
 
13374270
 [[package]]
1338
-name = "toml_edit"
1339
-version = "0.22.27"
4271
+name = "wasm-timer"
4272
+version = "0.2.5"
13404273
 source = "registry+https://github.com/rust-lang/crates.io-index"
1341
-checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
4274
+checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
13424275
 dependencies = [
1343
- "indexmap",
1344
- "serde",
1345
- "serde_spanned",
1346
- "toml_datetime",
1347
- "toml_write",
1348
- "winnow",
4276
+ "futures",
4277
+ "js-sys",
4278
+ "parking_lot 0.11.2",
4279
+ "pin-utils",
4280
+ "wasm-bindgen",
4281
+ "wasm-bindgen-futures",
4282
+ "web-sys",
13494283
 ]
13504284
 
13514285
 [[package]]
1352
-name = "toml_write"
1353
-version = "0.1.2"
4286
+name = "wayland-backend"
4287
+version = "0.3.12"
13544288
 source = "registry+https://github.com/rust-lang/crates.io-index"
1355
-checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
4289
+checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9"
4290
+dependencies = [
4291
+ "cc",
4292
+ "downcast-rs",
4293
+ "rustix 1.1.3",
4294
+ "scoped-tls",
4295
+ "smallvec",
4296
+ "wayland-sys",
4297
+]
13564298
 
13574299
 [[package]]
1358
-name = "tracing"
1359
-version = "0.1.44"
4300
+name = "wayland-client"
4301
+version = "0.31.12"
13604302
 source = "registry+https://github.com/rust-lang/crates.io-index"
1361
-checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
4303
+checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec"
13624304
 dependencies = [
1363
- "pin-project-lite",
1364
- "tracing-attributes",
1365
- "tracing-core",
4305
+ "bitflags 2.10.0",
4306
+ "rustix 1.1.3",
4307
+ "wayland-backend",
4308
+ "wayland-scanner",
13664309
 ]
13674310
 
13684311
 [[package]]
1369
-name = "tracing-appender"
1370
-version = "0.2.4"
4312
+name = "wayland-csd-frame"
4313
+version = "0.3.0"
13714314
 source = "registry+https://github.com/rust-lang/crates.io-index"
1372
-checksum = "786d480bce6247ab75f005b14ae1624ad978d3029d9113f0a22fa1ac773faeaf"
4315
+checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
13734316
 dependencies = [
1374
- "crossbeam-channel",
1375
- "thiserror 2.0.17",
1376
- "time",
1377
- "tracing-subscriber",
4317
+ "bitflags 2.10.0",
4318
+ "cursor-icon",
4319
+ "wayland-backend",
13784320
 ]
13794321
 
13804322
 [[package]]
1381
-name = "tracing-attributes"
1382
-version = "0.1.31"
4323
+name = "wayland-cursor"
4324
+version = "0.31.12"
13834325
 source = "registry+https://github.com/rust-lang/crates.io-index"
1384
-checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
4326
+checksum = "5864c4b5b6064b06b1e8b74ead4a98a6c45a285fe7a0e784d24735f011fdb078"
13854327
 dependencies = [
1386
- "proc-macro2",
1387
- "quote",
1388
- "syn",
4328
+ "rustix 1.1.3",
4329
+ "wayland-client",
4330
+ "xcursor",
13894331
 ]
13904332
 
13914333
 [[package]]
1392
-name = "tracing-core"
1393
-version = "0.1.36"
4334
+name = "wayland-protocols"
4335
+version = "0.31.2"
13944336
 source = "registry+https://github.com/rust-lang/crates.io-index"
1395
-checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
4337
+checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
13964338
 dependencies = [
1397
- "once_cell",
1398
- "valuable",
4339
+ "bitflags 2.10.0",
4340
+ "wayland-backend",
4341
+ "wayland-client",
4342
+ "wayland-scanner",
13994343
 ]
14004344
 
14014345
 [[package]]
1402
-name = "tracing-log"
1403
-version = "0.2.0"
4346
+name = "wayland-protocols"
4347
+version = "0.32.10"
14044348
 source = "registry+https://github.com/rust-lang/crates.io-index"
1405
-checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
4349
+checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3"
14064350
 dependencies = [
1407
- "log",
1408
- "once_cell",
1409
- "tracing-core",
4351
+ "bitflags 2.10.0",
4352
+ "wayland-backend",
4353
+ "wayland-client",
4354
+ "wayland-scanner",
14104355
 ]
14114356
 
14124357
 [[package]]
1413
-name = "tracing-subscriber"
1414
-version = "0.3.22"
4358
+name = "wayland-protocols-experimental"
4359
+version = "20250721.0.1"
14154360
 source = "registry+https://github.com/rust-lang/crates.io-index"
1416
-checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
4361
+checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1"
14174362
 dependencies = [
1418
- "matchers",
1419
- "nu-ansi-term",
1420
- "once_cell",
1421
- "regex-automata",
1422
- "sharded-slab",
1423
- "smallvec",
1424
- "thread_local",
1425
- "tracing",
1426
- "tracing-core",
1427
- "tracing-log",
4363
+ "bitflags 2.10.0",
4364
+ "wayland-backend",
4365
+ "wayland-client",
4366
+ "wayland-protocols 0.32.10",
4367
+ "wayland-scanner",
14284368
 ]
14294369
 
14304370
 [[package]]
1431
-name = "tree_magic_mini"
1432
-version = "3.2.2"
4371
+name = "wayland-protocols-misc"
4372
+version = "0.3.10"
14334373
 source = "registry+https://github.com/rust-lang/crates.io-index"
1434
-checksum = "b8765b90061cba6c22b5831f675da109ae5561588290f9fa2317adab2714d5a6"
4374
+checksum = "791c58fdeec5406aa37169dd815327d1e47f334219b523444bc26d70ceb4c34e"
14354375
 dependencies = [
1436
- "memchr",
1437
- "nom",
1438
- "petgraph",
4376
+ "bitflags 2.10.0",
4377
+ "wayland-backend",
4378
+ "wayland-client",
4379
+ "wayland-protocols 0.32.10",
4380
+ "wayland-scanner",
14394381
 ]
14404382
 
14414383
 [[package]]
1442
-name = "typenum"
1443
-version = "1.19.0"
4384
+name = "wayland-protocols-plasma"
4385
+version = "0.3.10"
14444386
 source = "registry+https://github.com/rust-lang/crates.io-index"
1445
-checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
4387
+checksum = "aa98634619300a535a9a97f338aed9a5ff1e01a461943e8346ff4ae26007306b"
4388
+dependencies = [
4389
+ "bitflags 2.10.0",
4390
+ "wayland-backend",
4391
+ "wayland-client",
4392
+ "wayland-protocols 0.32.10",
4393
+ "wayland-scanner",
4394
+]
14464395
 
14474396
 [[package]]
1448
-name = "unicode-ident"
1449
-version = "1.0.22"
4397
+name = "wayland-protocols-wlr"
4398
+version = "0.3.10"
14504399
 source = "registry+https://github.com/rust-lang/crates.io-index"
1451
-checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
4400
+checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3"
4401
+dependencies = [
4402
+ "bitflags 2.10.0",
4403
+ "wayland-backend",
4404
+ "wayland-client",
4405
+ "wayland-protocols 0.32.10",
4406
+ "wayland-scanner",
4407
+]
14524408
 
14534409
 [[package]]
1454
-name = "untrusted"
1455
-version = "0.9.0"
4410
+name = "wayland-scanner"
4411
+version = "0.31.8"
14564412
 source = "registry+https://github.com/rust-lang/crates.io-index"
1457
-checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
4413
+checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3"
4414
+dependencies = [
4415
+ "proc-macro2",
4416
+ "quick-xml",
4417
+ "quote",
4418
+]
14584419
 
14594420
 [[package]]
1460
-name = "utf8parse"
1461
-version = "0.2.2"
4421
+name = "wayland-sys"
4422
+version = "0.31.8"
14624423
 source = "registry+https://github.com/rust-lang/crates.io-index"
1463
-checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
4424
+checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd"
4425
+dependencies = [
4426
+ "dlib",
4427
+ "log",
4428
+ "once_cell",
4429
+ "pkg-config",
4430
+]
14644431
 
14654432
 [[package]]
1466
-name = "valuable"
1467
-version = "0.1.1"
4433
+name = "web-sys"
4434
+version = "0.3.83"
14684435
 source = "registry+https://github.com/rust-lang/crates.io-index"
1469
-checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
4436
+checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
4437
+dependencies = [
4438
+ "js-sys",
4439
+ "wasm-bindgen",
4440
+]
14704441
 
14714442
 [[package]]
1472
-name = "version_check"
1473
-version = "0.9.5"
4443
+name = "web-time"
4444
+version = "1.1.0"
14744445
 source = "registry+https://github.com/rust-lang/crates.io-index"
1475
-checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
4446
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
4447
+dependencies = [
4448
+ "js-sys",
4449
+ "wasm-bindgen",
4450
+]
14764451
 
14774452
 [[package]]
1478
-name = "wasi"
1479
-version = "0.11.1+wasi-snapshot-preview1"
4453
+name = "wgpu"
4454
+version = "0.19.4"
14804455
 source = "registry+https://github.com/rust-lang/crates.io-index"
1481
-checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
4456
+checksum = "cbd7311dbd2abcfebaabf1841a2824ed7c8be443a0f29166e5d3c6a53a762c01"
4457
+dependencies = [
4458
+ "arrayvec",
4459
+ "cfg-if",
4460
+ "cfg_aliases 0.1.1",
4461
+ "js-sys",
4462
+ "log",
4463
+ "naga",
4464
+ "parking_lot 0.12.5",
4465
+ "profiling",
4466
+ "raw-window-handle",
4467
+ "smallvec",
4468
+ "static_assertions",
4469
+ "wasm-bindgen",
4470
+ "wasm-bindgen-futures",
4471
+ "web-sys",
4472
+ "wgpu-core",
4473
+ "wgpu-hal",
4474
+ "wgpu-types",
4475
+]
14824476
 
14834477
 [[package]]
1484
-name = "wasip2"
1485
-version = "1.0.1+wasi-0.2.4"
4478
+name = "wgpu-core"
4479
+version = "0.19.4"
14864480
 source = "registry+https://github.com/rust-lang/crates.io-index"
1487
-checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
4481
+checksum = "28b94525fc99ba9e5c9a9e24764f2bc29bad0911a7446c12f446a8277369bf3a"
14884482
 dependencies = [
1489
- "wit-bindgen",
4483
+ "arrayvec",
4484
+ "bit-vec",
4485
+ "bitflags 2.10.0",
4486
+ "cfg_aliases 0.1.1",
4487
+ "codespan-reporting",
4488
+ "indexmap",
4489
+ "log",
4490
+ "naga",
4491
+ "once_cell",
4492
+ "parking_lot 0.12.5",
4493
+ "profiling",
4494
+ "raw-window-handle",
4495
+ "rustc-hash 1.1.0",
4496
+ "smallvec",
4497
+ "thiserror 1.0.69",
4498
+ "web-sys",
4499
+ "wgpu-hal",
4500
+ "wgpu-types",
14904501
 ]
14914502
 
14924503
 [[package]]
1493
-name = "wayland-backend"
1494
-version = "0.3.12"
4504
+name = "wgpu-hal"
4505
+version = "0.19.5"
14954506
 source = "registry+https://github.com/rust-lang/crates.io-index"
1496
-checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9"
4507
+checksum = "bfabcfc55fd86611a855816326b2d54c3b2fd7972c27ce414291562650552703"
14974508
 dependencies = [
1498
- "cc",
1499
- "downcast-rs",
1500
- "rustix 1.1.3",
4509
+ "android_system_properties",
4510
+ "arrayvec",
4511
+ "ash",
4512
+ "bit-set",
4513
+ "bitflags 2.10.0",
4514
+ "block",
4515
+ "cfg_aliases 0.1.1",
4516
+ "core-graphics-types",
4517
+ "d3d12",
4518
+ "glow",
4519
+ "glutin_wgl_sys",
4520
+ "gpu-alloc",
4521
+ "gpu-allocator",
4522
+ "gpu-descriptor",
4523
+ "hassle-rs",
4524
+ "js-sys",
4525
+ "khronos-egl",
4526
+ "libc",
4527
+ "libloading 0.8.9",
4528
+ "log",
4529
+ "metal",
4530
+ "naga",
4531
+ "ndk-sys 0.5.0+25.2.9519653",
4532
+ "objc",
4533
+ "once_cell",
4534
+ "parking_lot 0.12.5",
4535
+ "profiling",
4536
+ "range-alloc",
4537
+ "raw-window-handle",
4538
+ "renderdoc-sys",
4539
+ "rustc-hash 1.1.0",
15014540
  "smallvec",
1502
- "wayland-sys",
4541
+ "thiserror 1.0.69",
4542
+ "wasm-bindgen",
4543
+ "web-sys",
4544
+ "wgpu-types",
4545
+ "winapi",
15034546
 ]
15044547
 
15054548
 [[package]]
1506
-name = "wayland-client"
1507
-version = "0.31.12"
4549
+name = "wgpu-types"
4550
+version = "0.19.2"
15084551
 source = "registry+https://github.com/rust-lang/crates.io-index"
1509
-checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec"
4552
+checksum = "b671ff9fb03f78b46ff176494ee1ebe7d603393f42664be55b64dc8d53969805"
15104553
 dependencies = [
15114554
  "bitflags 2.10.0",
1512
- "rustix 1.1.3",
1513
- "wayland-backend",
1514
- "wayland-scanner",
4555
+ "js-sys",
4556
+ "web-sys",
15154557
 ]
15164558
 
15174559
 [[package]]
1518
-name = "wayland-csd-frame"
1519
-version = "0.3.0"
4560
+name = "widestring"
4561
+version = "1.2.1"
15204562
 source = "registry+https://github.com/rust-lang/crates.io-index"
1521
-checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"
1522
-dependencies = [
1523
- "bitflags 2.10.0",
1524
- "cursor-icon",
1525
- "wayland-backend",
1526
-]
4563
+checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
15274564
 
15284565
 [[package]]
1529
-name = "wayland-cursor"
1530
-version = "0.31.12"
4566
+name = "winapi"
4567
+version = "0.3.9"
15314568
 source = "registry+https://github.com/rust-lang/crates.io-index"
1532
-checksum = "5864c4b5b6064b06b1e8b74ead4a98a6c45a285fe7a0e784d24735f011fdb078"
4569
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
15334570
 dependencies = [
1534
- "rustix 1.1.3",
1535
- "wayland-client",
1536
- "xcursor",
4571
+ "winapi-i686-pc-windows-gnu",
4572
+ "winapi-x86_64-pc-windows-gnu",
15374573
 ]
15384574
 
15394575
 [[package]]
1540
-name = "wayland-protocols"
1541
-version = "0.31.2"
4576
+name = "winapi-i686-pc-windows-gnu"
4577
+version = "0.4.0"
15424578
 source = "registry+https://github.com/rust-lang/crates.io-index"
1543
-checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
1544
-dependencies = [
1545
- "bitflags 2.10.0",
1546
- "wayland-backend",
1547
- "wayland-client",
1548
- "wayland-scanner",
1549
-]
4579
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
15504580
 
15514581
 [[package]]
1552
-name = "wayland-protocols"
1553
-version = "0.32.10"
4582
+name = "winapi-util"
4583
+version = "0.1.11"
15544584
 source = "registry+https://github.com/rust-lang/crates.io-index"
1555
-checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3"
4585
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
15564586
 dependencies = [
1557
- "bitflags 2.10.0",
1558
- "wayland-backend",
1559
- "wayland-client",
1560
- "wayland-scanner",
4587
+ "windows-sys 0.61.2",
15614588
 ]
15624589
 
15634590
 [[package]]
1564
-name = "wayland-protocols-misc"
1565
-version = "0.3.10"
4591
+name = "winapi-x86_64-pc-windows-gnu"
4592
+version = "0.4.0"
15664593
 source = "registry+https://github.com/rust-lang/crates.io-index"
1567
-checksum = "791c58fdeec5406aa37169dd815327d1e47f334219b523444bc26d70ceb4c34e"
1568
-dependencies = [
1569
- "bitflags 2.10.0",
1570
- "wayland-backend",
1571
- "wayland-client",
1572
- "wayland-protocols 0.32.10",
1573
- "wayland-scanner",
1574
-]
4594
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
15754595
 
15764596
 [[package]]
1577
-name = "wayland-protocols-wlr"
1578
-version = "0.3.10"
4597
+name = "window_clipboard"
4598
+version = "0.4.1"
15794599
 source = "registry+https://github.com/rust-lang/crates.io-index"
1580
-checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3"
4600
+checksum = "f6d692d46038c433f9daee7ad8757e002a4248c20b0a3fbc991d99521d3bcb6d"
15814601
 dependencies = [
1582
- "bitflags 2.10.0",
1583
- "wayland-backend",
1584
- "wayland-client",
1585
- "wayland-protocols 0.32.10",
1586
- "wayland-scanner",
4602
+ "clipboard-win",
4603
+ "clipboard_macos",
4604
+ "clipboard_wayland",
4605
+ "clipboard_x11",
4606
+ "raw-window-handle",
4607
+ "thiserror 1.0.69",
15874608
 ]
15884609
 
15894610
 [[package]]
1590
-name = "wayland-scanner"
1591
-version = "0.31.8"
4611
+name = "windows"
4612
+version = "0.52.0"
15924613
 source = "registry+https://github.com/rust-lang/crates.io-index"
1593
-checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3"
4614
+checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
15944615
 dependencies = [
1595
- "proc-macro2",
1596
- "quick-xml",
1597
- "quote",
4616
+ "windows-core",
4617
+ "windows-targets 0.52.6",
15984618
 ]
15994619
 
16004620
 [[package]]
1601
-name = "wayland-sys"
1602
-version = "0.31.8"
4621
+name = "windows-core"
4622
+version = "0.52.0"
16034623
 source = "registry+https://github.com/rust-lang/crates.io-index"
1604
-checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd"
4624
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
16054625
 dependencies = [
1606
- "pkg-config",
4626
+ "windows-targets 0.52.6",
16074627
 ]
16084628
 
16094629
 [[package]]
@@ -1612,6 +4632,15 @@ version = "0.2.1"
16124632
 source = "registry+https://github.com/rust-lang/crates.io-index"
16134633
 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
16144634
 
4635
+[[package]]
4636
+name = "windows-sys"
4637
+version = "0.45.0"
4638
+source = "registry+https://github.com/rust-lang/crates.io-index"
4639
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
4640
+dependencies = [
4641
+ "windows-targets 0.42.2",
4642
+]
4643
+
16154644
 [[package]]
16164645
 name = "windows-sys"
16174646
 version = "0.48.0"
@@ -1630,6 +4659,15 @@ dependencies = [
16304659
  "windows-targets 0.52.6",
16314660
 ]
16324661
 
4662
+[[package]]
4663
+name = "windows-sys"
4664
+version = "0.59.0"
4665
+source = "registry+https://github.com/rust-lang/crates.io-index"
4666
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
4667
+dependencies = [
4668
+ "windows-targets 0.52.6",
4669
+]
4670
+
16334671
 [[package]]
16344672
 name = "windows-sys"
16354673
 version = "0.60.2"
@@ -1648,6 +4686,21 @@ dependencies = [
16484686
  "windows-link",
16494687
 ]
16504688
 
4689
+[[package]]
4690
+name = "windows-targets"
4691
+version = "0.42.2"
4692
+source = "registry+https://github.com/rust-lang/crates.io-index"
4693
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
4694
+dependencies = [
4695
+ "windows_aarch64_gnullvm 0.42.2",
4696
+ "windows_aarch64_msvc 0.42.2",
4697
+ "windows_i686_gnu 0.42.2",
4698
+ "windows_i686_msvc 0.42.2",
4699
+ "windows_x86_64_gnu 0.42.2",
4700
+ "windows_x86_64_gnullvm 0.42.2",
4701
+ "windows_x86_64_msvc 0.42.2",
4702
+]
4703
+
16514704
 [[package]]
16524705
 name = "windows-targets"
16534706
 version = "0.48.5"
@@ -1696,6 +4749,12 @@ dependencies = [
16964749
  "windows_x86_64_msvc 0.53.1",
16974750
 ]
16984751
 
4752
+[[package]]
4753
+name = "windows_aarch64_gnullvm"
4754
+version = "0.42.2"
4755
+source = "registry+https://github.com/rust-lang/crates.io-index"
4756
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
4757
+
16994758
 [[package]]
17004759
 name = "windows_aarch64_gnullvm"
17014760
 version = "0.48.5"
@@ -1714,6 +4773,12 @@ version = "0.53.1"
17144773
 source = "registry+https://github.com/rust-lang/crates.io-index"
17154774
 checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
17164775
 
4776
+[[package]]
4777
+name = "windows_aarch64_msvc"
4778
+version = "0.42.2"
4779
+source = "registry+https://github.com/rust-lang/crates.io-index"
4780
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
4781
+
17174782
 [[package]]
17184783
 name = "windows_aarch64_msvc"
17194784
 version = "0.48.5"
@@ -1732,6 +4797,12 @@ version = "0.53.1"
17324797
 source = "registry+https://github.com/rust-lang/crates.io-index"
17334798
 checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
17344799
 
4800
+[[package]]
4801
+name = "windows_i686_gnu"
4802
+version = "0.42.2"
4803
+source = "registry+https://github.com/rust-lang/crates.io-index"
4804
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
4805
+
17354806
 [[package]]
17364807
 name = "windows_i686_gnu"
17374808
 version = "0.48.5"
@@ -1762,6 +4833,12 @@ version = "0.53.1"
17624833
 source = "registry+https://github.com/rust-lang/crates.io-index"
17634834
 checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
17644835
 
4836
+[[package]]
4837
+name = "windows_i686_msvc"
4838
+version = "0.42.2"
4839
+source = "registry+https://github.com/rust-lang/crates.io-index"
4840
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
4841
+
17654842
 [[package]]
17664843
 name = "windows_i686_msvc"
17674844
 version = "0.48.5"
@@ -1780,6 +4857,12 @@ version = "0.53.1"
17804857
 source = "registry+https://github.com/rust-lang/crates.io-index"
17814858
 checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
17824859
 
4860
+[[package]]
4861
+name = "windows_x86_64_gnu"
4862
+version = "0.42.2"
4863
+source = "registry+https://github.com/rust-lang/crates.io-index"
4864
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
4865
+
17834866
 [[package]]
17844867
 name = "windows_x86_64_gnu"
17854868
 version = "0.48.5"
@@ -1798,6 +4881,12 @@ version = "0.53.1"
17984881
 source = "registry+https://github.com/rust-lang/crates.io-index"
17994882
 checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
18004883
 
4884
+[[package]]
4885
+name = "windows_x86_64_gnullvm"
4886
+version = "0.42.2"
4887
+source = "registry+https://github.com/rust-lang/crates.io-index"
4888
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
4889
+
18014890
 [[package]]
18024891
 name = "windows_x86_64_gnullvm"
18034892
 version = "0.48.5"
@@ -1816,6 +4905,12 @@ version = "0.53.1"
18164905
 source = "registry+https://github.com/rust-lang/crates.io-index"
18174906
 checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
18184907
 
4908
+[[package]]
4909
+name = "windows_x86_64_msvc"
4910
+version = "0.42.2"
4911
+source = "registry+https://github.com/rust-lang/crates.io-index"
4912
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
4913
+
18194914
 [[package]]
18204915
 name = "windows_x86_64_msvc"
18214916
 version = "0.48.5"
@@ -1834,6 +4929,58 @@ version = "0.53.1"
18344929
 source = "registry+https://github.com/rust-lang/crates.io-index"
18354930
 checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
18364931
 
4932
+[[package]]
4933
+name = "winit"
4934
+version = "0.30.12"
4935
+source = "registry+https://github.com/rust-lang/crates.io-index"
4936
+checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732"
4937
+dependencies = [
4938
+ "ahash 0.8.12",
4939
+ "android-activity",
4940
+ "atomic-waker",
4941
+ "bitflags 2.10.0",
4942
+ "block2",
4943
+ "bytemuck",
4944
+ "calloop 0.13.0",
4945
+ "cfg_aliases 0.2.1",
4946
+ "concurrent-queue",
4947
+ "core-foundation",
4948
+ "core-graphics",
4949
+ "cursor-icon",
4950
+ "dpi",
4951
+ "js-sys",
4952
+ "libc",
4953
+ "memmap2 0.9.9",
4954
+ "ndk",
4955
+ "objc2 0.5.2",
4956
+ "objc2-app-kit",
4957
+ "objc2-foundation 0.2.2",
4958
+ "objc2-ui-kit",
4959
+ "orbclient",
4960
+ "percent-encoding",
4961
+ "pin-project",
4962
+ "raw-window-handle",
4963
+ "redox_syscall 0.4.1",
4964
+ "rustix 0.38.44",
4965
+ "sctk-adwaita",
4966
+ "smithay-client-toolkit 0.19.2",
4967
+ "smol_str",
4968
+ "tracing",
4969
+ "unicode-segmentation",
4970
+ "wasm-bindgen",
4971
+ "wasm-bindgen-futures",
4972
+ "wayland-backend",
4973
+ "wayland-client",
4974
+ "wayland-protocols 0.32.10",
4975
+ "wayland-protocols-plasma",
4976
+ "web-sys",
4977
+ "web-time",
4978
+ "windows-sys 0.52.0",
4979
+ "x11-dl",
4980
+ "x11rb",
4981
+ "xkbcommon-dl",
4982
+]
4983
+
18374984
 [[package]]
18384985
 name = "winnow"
18394986
 version = "0.7.14"
@@ -1843,6 +4990,15 @@ dependencies = [
18434990
  "memchr",
18444991
 ]
18454992
 
4993
+[[package]]
4994
+name = "winreg"
4995
+version = "0.10.1"
4996
+source = "registry+https://github.com/rust-lang/crates.io-index"
4997
+checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
4998
+dependencies = [
4999
+ "winapi",
5000
+]
5001
+
18465002
 [[package]]
18475003
 name = "wit-bindgen"
18485004
 version = "0.46.0"
@@ -1876,12 +5032,54 @@ dependencies = [
18765032
  "tap",
18775033
 ]
18785034
 
5035
+[[package]]
5036
+name = "x11-dl"
5037
+version = "2.21.0"
5038
+source = "registry+https://github.com/rust-lang/crates.io-index"
5039
+checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
5040
+dependencies = [
5041
+ "libc",
5042
+ "once_cell",
5043
+ "pkg-config",
5044
+]
5045
+
5046
+[[package]]
5047
+name = "x11rb"
5048
+version = "0.13.2"
5049
+source = "registry+https://github.com/rust-lang/crates.io-index"
5050
+checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
5051
+dependencies = [
5052
+ "as-raw-xcb-connection",
5053
+ "gethostname",
5054
+ "libc",
5055
+ "libloading 0.8.9",
5056
+ "once_cell",
5057
+ "rustix 1.1.3",
5058
+ "x11rb-protocol",
5059
+]
5060
+
5061
+[[package]]
5062
+name = "x11rb-protocol"
5063
+version = "0.13.2"
5064
+source = "registry+https://github.com/rust-lang/crates.io-index"
5065
+checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
5066
+
18795067
 [[package]]
18805068
 name = "xcursor"
18815069
 version = "0.3.10"
18825070
 source = "registry+https://github.com/rust-lang/crates.io-index"
18835071
 checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"
18845072
 
5073
+[[package]]
5074
+name = "xdg-home"
5075
+version = "1.3.0"
5076
+source = "registry+https://github.com/rust-lang/crates.io-index"
5077
+checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6"
5078
+dependencies = [
5079
+ "libc",
5080
+ "windows-sys 0.59.0",
5081
+]
5082
+
18855083
 [[package]]
18865084
 name = "xkbcommon"
18875085
 version = "0.7.0"
@@ -1893,6 +5091,19 @@ dependencies = [
18935091
  "xkeysym",
18945092
 ]
18955093
 
5094
+[[package]]
5095
+name = "xkbcommon-dl"
5096
+version = "0.4.2"
5097
+source = "registry+https://github.com/rust-lang/crates.io-index"
5098
+checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5"
5099
+dependencies = [
5100
+ "bitflags 2.10.0",
5101
+ "dlib",
5102
+ "log",
5103
+ "once_cell",
5104
+ "xkeysym",
5105
+]
5106
+
18965107
 [[package]]
18975108
 name = "xkeysym"
18985109
 version = "0.2.1"
@@ -1902,6 +5113,12 @@ dependencies = [
19025113
  "bytemuck",
19035114
 ]
19045115
 
5116
+[[package]]
5117
+name = "xml-rs"
5118
+version = "0.8.28"
5119
+source = "registry+https://github.com/rust-lang/crates.io-index"
5120
+checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
5121
+
19055122
 [[package]]
19065123
 name = "yasna"
19075124
 version = "0.5.2"
@@ -1911,6 +5128,100 @@ dependencies = [
19115128
  "time",
19125129
 ]
19135130
 
5131
+[[package]]
5132
+name = "yazi"
5133
+version = "0.1.6"
5134
+source = "registry+https://github.com/rust-lang/crates.io-index"
5135
+checksum = "c94451ac9513335b5e23d7a8a2b61a7102398b8cca5160829d313e84c9d98be1"
5136
+
5137
+[[package]]
5138
+name = "zbus"
5139
+version = "4.4.0"
5140
+source = "registry+https://github.com/rust-lang/crates.io-index"
5141
+checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725"
5142
+dependencies = [
5143
+ "async-broadcast",
5144
+ "async-executor",
5145
+ "async-fs",
5146
+ "async-io",
5147
+ "async-lock",
5148
+ "async-process",
5149
+ "async-recursion",
5150
+ "async-task",
5151
+ "async-trait",
5152
+ "blocking",
5153
+ "enumflags2",
5154
+ "event-listener",
5155
+ "futures-core",
5156
+ "futures-sink",
5157
+ "futures-util",
5158
+ "hex",
5159
+ "nix 0.29.0",
5160
+ "ordered-stream",
5161
+ "rand",
5162
+ "serde",
5163
+ "serde_repr",
5164
+ "sha1",
5165
+ "static_assertions",
5166
+ "tracing",
5167
+ "uds_windows",
5168
+ "windows-sys 0.52.0",
5169
+ "xdg-home",
5170
+ "zbus_macros",
5171
+ "zbus_names",
5172
+ "zvariant",
5173
+]
5174
+
5175
+[[package]]
5176
+name = "zbus_macros"
5177
+version = "4.4.0"
5178
+source = "registry+https://github.com/rust-lang/crates.io-index"
5179
+checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e"
5180
+dependencies = [
5181
+ "proc-macro-crate",
5182
+ "proc-macro2",
5183
+ "quote",
5184
+ "syn 2.0.113",
5185
+ "zvariant_utils",
5186
+]
5187
+
5188
+[[package]]
5189
+name = "zbus_names"
5190
+version = "3.0.0"
5191
+source = "registry+https://github.com/rust-lang/crates.io-index"
5192
+checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c"
5193
+dependencies = [
5194
+ "serde",
5195
+ "static_assertions",
5196
+ "zvariant",
5197
+]
5198
+
5199
+[[package]]
5200
+name = "zeno"
5201
+version = "0.2.3"
5202
+source = "registry+https://github.com/rust-lang/crates.io-index"
5203
+checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697"
5204
+
5205
+[[package]]
5206
+name = "zerocopy"
5207
+version = "0.8.31"
5208
+source = "registry+https://github.com/rust-lang/crates.io-index"
5209
+checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3"
5210
+dependencies = [
5211
+ "zerocopy-derive",
5212
+]
5213
+
5214
+[[package]]
5215
+name = "zerocopy-derive"
5216
+version = "0.8.31"
5217
+source = "registry+https://github.com/rust-lang/crates.io-index"
5218
+checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a"
5219
+dependencies = [
5220
+ "proc-macro2",
5221
+ "quote",
5222
+ "syn 2.0.113",
5223
+]
5224
+
19145225
 [[package]]
19155226
 name = "zeroize"
19165227
 version = "1.8.2"
@@ -1922,3 +5233,40 @@ name = "zmij"
19225233
 version = "1.0.9"
19235234
 source = "registry+https://github.com/rust-lang/crates.io-index"
19245235
 checksum = "4ee2a72b10d087f75fb2e1c2c7343e308fe6970527c22a41caf8372e165ff5c1"
5236
+
5237
+[[package]]
5238
+name = "zvariant"
5239
+version = "4.2.0"
5240
+source = "registry+https://github.com/rust-lang/crates.io-index"
5241
+checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe"
5242
+dependencies = [
5243
+ "endi",
5244
+ "enumflags2",
5245
+ "serde",
5246
+ "static_assertions",
5247
+ "zvariant_derive",
5248
+]
5249
+
5250
+[[package]]
5251
+name = "zvariant_derive"
5252
+version = "4.2.0"
5253
+source = "registry+https://github.com/rust-lang/crates.io-index"
5254
+checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449"
5255
+dependencies = [
5256
+ "proc-macro-crate",
5257
+ "proc-macro2",
5258
+ "quote",
5259
+ "syn 2.0.113",
5260
+ "zvariant_utils",
5261
+]
5262
+
5263
+[[package]]
5264
+name = "zvariant_utils"
5265
+version = "2.1.0"
5266
+source = "registry+https://github.com/rust-lang/crates.io-index"
5267
+checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340"
5268
+dependencies = [
5269
+ "proc-macro2",
5270
+ "quote",
5271
+ "syn 2.0.113",
5272
+]
Cargo.tomlmodified
@@ -61,5 +61,8 @@ wl-clipboard-rs = "0.9"
61
 hex = "0.4"
61
 hex = "0.4"
62
 base64 = "0.22"
62
 base64 = "0.22"
63
 
63
 
64
+# GUI (optional)
65
+iced = { version = "0.13", features = ["canvas", "tokio", "tiny-skia"] }
66
+
64
 # Internal crates
67
 # Internal crates
65
 hyprkvm-common = { path = "hyprkvm-common" }
68
 hyprkvm-common = { path = "hyprkvm-common" }
flake.nixmodified
@@ -34,6 +34,14 @@
34
 
34
 
35
           # TLS
35
           # TLS
36
           openssl
36
           openssl
37
+
38
+          # GUI (Iced) dependencies
39
+          vulkan-loader
40
+          libGL
41
+          xorg.libX11
42
+          xorg.libXcursor
43
+          xorg.libXrandr
44
+          xorg.libXi
37
         ];
45
         ];
38
 
46
 
39
         rustToolchain = pkgs.rust-bin.stable.latest.default.override {
47
         rustToolchain = pkgs.rust-bin.stable.latest.default.override {
@@ -53,6 +61,9 @@
53
           # For wayland-scanner
61
           # For wayland-scanner
54
           WAYLAND_PROTOCOLS = "${pkgs.wayland-protocols}/share/wayland-protocols";
62
           WAYLAND_PROTOCOLS = "${pkgs.wayland-protocols}/share/wayland-protocols";
55
 
63
 
64
+          # Graphics library paths for GUI
65
+          LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath libDeps;
66
+
56
           shellHook = ''
67
           shellHook = ''
57
             echo "HyprKVM development shell"
68
             echo "HyprKVM development shell"
58
             echo "Rust: $(rustc --version)"
69
             echo "Rust: $(rustc --version)"
@@ -61,7 +72,7 @@
61
           '';
72
           '';
62
         };
73
         };
63
 
74
 
64
-        # Package
75
+        # Package (without GUI for smaller binary)
65
         packages.default = pkgs.rustPlatform.buildRustPackage {
76
         packages.default = pkgs.rustPlatform.buildRustPackage {
66
           pname = "hyprkvm";
77
           pname = "hyprkvm";
67
           version = "0.5.1";
78
           version = "0.5.1";
@@ -90,6 +101,44 @@
90
             mainProgram = "hyprkvm";
101
             mainProgram = "hyprkvm";
91
           };
102
           };
92
         };
103
         };
104
+
105
+        # Package with GUI support
106
+        packages.gui = pkgs.rustPlatform.buildRustPackage {
107
+          pname = "hyprkvm";
108
+          version = "0.5.1";
109
+          src = ./.;
110
+
111
+          cargoLock = {
112
+            lockFile = ./Cargo.lock;
113
+          };
114
+
115
+          nativeBuildInputs = buildDeps ++ [ pkgs.makeWrapper ];
116
+          buildInputs = libDeps;
117
+
118
+          # Build with GUI feature
119
+          buildFeatures = [ "gui" ];
120
+
121
+          # Wrap binary to include graphics library paths
122
+          postInstall = ''
123
+            wrapProgram $out/bin/hyprkvm \
124
+              --prefix LD_LIBRARY_PATH : ${pkgs.lib.makeLibraryPath libDeps}
125
+          '';
126
+
127
+          meta = with pkgs.lib; {
128
+            description = "Hyprland-native software KVM switch (with GUI)";
129
+            longDescription = ''
130
+              HyprKVM enables seamless keyboard/mouse control transfer between
131
+              Linux machines running Hyprland. Move past your last workspace
132
+              to switch to another machine.
133
+
134
+              This package includes the GUI configuration tool.
135
+            '';
136
+            homepage = "https://github.com/tenseleyFlow/hyprKVM";
137
+            license = licenses.mit;
138
+            platforms = platforms.linux;
139
+            mainProgram = "hyprkvm";
140
+          };
141
+        };
93
       }
142
       }
94
     );
143
     );
95
 }
144
 }
hyprkvm-common/src/protocol/mod.rsmodified
@@ -54,6 +54,9 @@ pub struct HelloPayload {
54
     pub machine_name: String,
54
     pub machine_name: String,
55
     /// Supported capabilities
55
     /// Supported capabilities
56
     pub capabilities: Vec<String>,
56
     pub capabilities: Vec<String>,
57
+    /// Direction the sender has configured for the recipient (peer uses opposite)
58
+    #[serde(default, skip_serializing_if = "Option::is_none")]
59
+    pub my_direction_for_you: Option<crate::Direction>,
57
 }
60
 }
58
 
61
 
59
 #[derive(Debug, Clone, Serialize, Deserialize)]
62
 #[derive(Debug, Clone, Serialize, Deserialize)]
hyprkvm-daemon/Cargo.tomlmodified
@@ -10,6 +10,10 @@ description = "HyprKVM daemon - Hyprland-native software KVM switch"
10
 name = "hyprkvm"
10
 name = "hyprkvm"
11
 path = "src/main.rs"
11
 path = "src/main.rs"
12
 
12
 
13
+[features]
14
+default = ["gui"]
15
+gui = ["iced"]
16
+
13
 [dependencies]
17
 [dependencies]
14
 hyprkvm-common = { workspace = true }
18
 hyprkvm-common = { workspace = true }
15
 
19
 
@@ -62,5 +66,8 @@ wl-clipboard-rs = { workspace = true }
62
 hex = { workspace = true }
66
 hex = { workspace = true }
63
 base64 = { workspace = true }
67
 base64 = { workspace = true }
64
 
68
 
69
+# GUI (optional)
70
+iced = { workspace = true, optional = true }
71
+
65
 [dev-dependencies]
72
 [dev-dependencies]
66
 tempfile = "3"
73
 tempfile = "3"
hyprkvm-daemon/src/gui/app.rsadded
@@ -0,0 +1,477 @@
1
+//! Main Iced Application implementation
2
+
3
+use iced::widget::{button, column, container, row, text, text_input, Space};
4
+use iced::{Element, Length, Task};
5
+use std::path::PathBuf;
6
+
7
+use super::canvas::machine_canvas;
8
+use super::messages::{CanvasEvent, Message};
9
+use super::state::GuiState;
10
+use super::theme;
11
+use crate::config::Config;
12
+
13
+/// The main HyprKVM GUI application
14
+pub struct HyprKvmGui {
15
+    state: GuiState,
16
+}
17
+
18
+impl HyprKvmGui {
19
+    /// Create a new GUI from a config path
20
+    pub fn new(config_path: PathBuf) -> (Self, Task<Message>) {
21
+        // Load config or use default
22
+        let config = Config::load(&config_path).unwrap_or_else(|e| {
23
+            tracing::warn!("Failed to load config: {}, using defaults", e);
24
+            Config::default()
25
+        });
26
+
27
+        let state = GuiState::from_config(config_path, config);
28
+
29
+        (Self { state }, Task::none())
30
+    }
31
+
32
+    /// Update state based on message
33
+    pub fn update(&mut self, message: Message) -> Task<Message> {
34
+        match message {
35
+            Message::CanvasEvent(event) => self.handle_canvas_event(event),
36
+            Message::AddMachine => {
37
+                self.state.show_add_modal = true;
38
+                self.state.new_machine = Default::default();
39
+                Task::none()
40
+            }
41
+            Message::CancelAddMachine => {
42
+                self.state.show_add_modal = false;
43
+                Task::none()
44
+            }
45
+            Message::ConfirmAddMachine => {
46
+                self.confirm_add_machine();
47
+                Task::none()
48
+            }
49
+            Message::RemoveMachine(idx) => {
50
+                if self.state.remove_machine(idx) {
51
+                    self.save_and_reload()
52
+                } else {
53
+                    Task::none()
54
+                }
55
+            }
56
+            Message::UpdateNewMachineName(name) => {
57
+                self.state.new_machine.name = name;
58
+                Task::none()
59
+            }
60
+            Message::UpdateNewMachineAddress(address) => {
61
+                self.state.new_machine.address = address;
62
+                Task::none()
63
+            }
64
+            Message::SelectNewMachinePosition(pos) => {
65
+                // Add machine at the selected position
66
+                let name = self.state.new_machine.name.clone();
67
+                let address = self.state.new_machine.address.clone();
68
+                match self.state.add_machine(name, address, pos) {
69
+                    Ok(()) => {
70
+                        self.state.show_add_modal = false;
71
+                        self.save_and_reload()
72
+                    }
73
+                    Err(e) => {
74
+                        self.state.error = Some(e);
75
+                        Task::none()
76
+                    }
77
+                }
78
+            }
79
+            Message::SaveConfig => self.save_and_reload(),
80
+            Message::ReloadDaemon => {
81
+                self.reload_daemon();
82
+                Task::none()
83
+            }
84
+            Message::RestartDaemon => {
85
+                self.restart_daemon();
86
+                Task::none()
87
+            }
88
+            Message::ConfigSaved(result) => {
89
+                if let Err(e) = result {
90
+                    self.state.error = Some(format!("Failed to save config: {}", e));
91
+                }
92
+                Task::none()
93
+            }
94
+            Message::DaemonReloaded(result) => {
95
+                if let Err(e) = result {
96
+                    self.state.error = Some(format!("Failed to reload daemon: {}", e));
97
+                }
98
+                Task::none()
99
+            }
100
+            Message::StatusUpdate(statuses) => {
101
+                for (name, status) in statuses {
102
+                    for machine in &mut self.state.machines {
103
+                        if machine.name == name {
104
+                            machine.status = status;
105
+                        }
106
+                    }
107
+                }
108
+                Task::none()
109
+            }
110
+            Message::ClearError => {
111
+                self.state.error = None;
112
+                Task::none()
113
+            }
114
+            Message::ClearSuccess => {
115
+                self.state.success = None;
116
+                Task::none()
117
+            }
118
+        }
119
+    }
120
+
121
+    fn handle_canvas_event(&mut self, event: CanvasEvent) -> Task<Message> {
122
+        match event {
123
+            CanvasEvent::MachinePressed(idx) => {
124
+                // Don't drag self machine
125
+                if !self.state.machines[idx].is_self {
126
+                    self.state.drag.start(idx);
127
+                }
128
+                Task::none()
129
+            }
130
+            CanvasEvent::MouseMoved(pos, snap_target) => {
131
+                self.state.drag.update(pos);
132
+                self.state.drag.snap_target = snap_target;
133
+                Task::none()
134
+            }
135
+            CanvasEvent::MouseReleased => {
136
+                if let Some((idx, snap_target)) = self.state.drag.end() {
137
+                    if let Some(new_pos) = snap_target {
138
+                        if self.state.move_machine(idx, new_pos) {
139
+                            return self.save_and_reload();
140
+                        }
141
+                    }
142
+                }
143
+                Task::none()
144
+            }
145
+            CanvasEvent::MouseEntered | CanvasEvent::MouseExited => Task::none(),
146
+        }
147
+    }
148
+
149
+    fn confirm_add_machine(&mut self) {
150
+        // Find first available position
151
+        let available = self.state.available_positions();
152
+        if available.is_empty() {
153
+            self.state.error = Some("No available positions".to_string());
154
+            return;
155
+        }
156
+
157
+        let name = self.state.new_machine.name.clone();
158
+        let address = self.state.new_machine.address.clone();
159
+
160
+        if name.is_empty() || address.is_empty() {
161
+            self.state.error = Some("Name and address are required".to_string());
162
+            return;
163
+        }
164
+
165
+        // Use first available position
166
+        let pos = available[0];
167
+
168
+        match self.state.add_machine(name, address, pos) {
169
+            Ok(()) => {
170
+                self.state.show_add_modal = false;
171
+            }
172
+            Err(e) => {
173
+                self.state.error = Some(e);
174
+            }
175
+        }
176
+    }
177
+
178
+    fn save_and_reload(&mut self) -> Task<Message> {
179
+        // Save config
180
+        if let Err(e) = self.state.save_config() {
181
+            self.state.error = Some(format!("Failed to save: {}", e));
182
+            return Task::none();
183
+        }
184
+
185
+        // Reload daemon via IPC
186
+        self.reload_daemon();
187
+        Task::none()
188
+    }
189
+
190
+    fn reload_daemon(&mut self) {
191
+        use std::io::{BufRead, BufReader, Write};
192
+        use std::os::unix::net::UnixStream;
193
+
194
+        let socket_path = crate::ipc::socket_path();
195
+
196
+        match UnixStream::connect(&socket_path) {
197
+            Ok(mut stream) => {
198
+                // Send reload request (format: {"type": "reload"})
199
+                if writeln!(stream, r#"{{"type":"reload"}}"#).is_err() {
200
+                    self.state.error = Some("Failed to send reload".to_string());
201
+                    return;
202
+                }
203
+                stream.flush().ok();
204
+
205
+                // Set read timeout
206
+                stream
207
+                    .set_read_timeout(Some(std::time::Duration::from_secs(2)))
208
+                    .ok();
209
+
210
+                // Read response
211
+                let mut reader = BufReader::new(&stream);
212
+                let mut response = String::new();
213
+                if reader.read_line(&mut response).is_ok() {
214
+                    if response.contains("Error") {
215
+                        self.state.error = Some("Failed to reload daemon".to_string());
216
+                        self.state.needs_restart = false;
217
+                    } else if response.contains("restart required") {
218
+                        self.state.error = Some("Direction changed - restart required".to_string());
219
+                        self.state.needs_restart = true;
220
+                    } else {
221
+                        self.state.success = Some("Config saved & applied".to_string());
222
+                        self.state.needs_restart = false;
223
+                    }
224
+                } else {
225
+                    self.state.success = Some("Config saved".to_string());
226
+                    self.state.needs_restart = false;
227
+                }
228
+            }
229
+            Err(_) => {
230
+                // Daemon not running - just show config saved
231
+                self.state.success = Some("Config saved (daemon not running)".to_string());
232
+                self.state.needs_restart = false;
233
+            }
234
+        }
235
+    }
236
+
237
+    fn restart_daemon(&mut self) {
238
+        use std::io::{BufRead, BufReader, Write};
239
+        use std::os::unix::net::UnixStream;
240
+        use std::process::Command;
241
+
242
+        let socket_path = crate::ipc::socket_path();
243
+
244
+        // First, try to shutdown the running daemon
245
+        if let Ok(mut stream) = UnixStream::connect(&socket_path) {
246
+            // Send shutdown request
247
+            if writeln!(stream, r#"{{"type":"shutdown"}}"#).is_ok() {
248
+                stream.flush().ok();
249
+                // Wait for response
250
+                stream.set_read_timeout(Some(std::time::Duration::from_secs(2))).ok();
251
+                let mut reader = BufReader::new(&stream);
252
+                let mut response = String::new();
253
+                let _ = reader.read_line(&mut response);
254
+            }
255
+            // Give daemon time to shutdown
256
+            std::thread::sleep(std::time::Duration::from_millis(500));
257
+        }
258
+
259
+        // Now spawn a new daemon process
260
+        let exe = std::env::current_exe().unwrap_or_else(|_| "hyprkvm".into());
261
+        match Command::new(&exe)
262
+            .arg("daemon")
263
+            .stdin(std::process::Stdio::null())
264
+            .stdout(std::process::Stdio::null())
265
+            .stderr(std::process::Stdio::null())
266
+            .spawn()
267
+        {
268
+            Ok(_) => {
269
+                // Wait a moment for daemon to start
270
+                std::thread::sleep(std::time::Duration::from_millis(500));
271
+                self.state.error = None;
272
+                self.state.needs_restart = false;
273
+                self.state.success = Some("Daemon restarted".to_string());
274
+            }
275
+            Err(e) => {
276
+                self.state.error = Some(format!("Failed to start daemon: {}", e));
277
+                self.state.needs_restart = false;
278
+            }
279
+        }
280
+    }
281
+
282
+    /// Build the view
283
+    pub fn view(&self) -> Element<'_, Message> {
284
+        // Toolbar
285
+        let toolbar = self.toolbar_view();
286
+
287
+        // Main canvas
288
+        let canvas = machine_canvas(
289
+            self.state.machines.clone(),
290
+            self.state.drag.clone(),
291
+            self.state.available_positions(),
292
+        );
293
+
294
+        // Notification banners
295
+        let error_banner = self.error_banner();
296
+        let success_banner = self.success_banner();
297
+
298
+        // Add machine modal (if showing)
299
+        let content: Element<Message> = if self.state.show_add_modal {
300
+            let modal = self.add_machine_modal();
301
+            // Overlay modal on canvas
302
+            container(
303
+                column![toolbar, error_banner, success_banner, container(modal).center_x(Length::Fill).center_y(Length::Fill)]
304
+                    .spacing(0),
305
+            )
306
+            .width(Length::Fill)
307
+            .height(Length::Fill)
308
+            .into()
309
+        } else {
310
+            column![toolbar, error_banner, success_banner, canvas]
311
+                .spacing(0)
312
+                .width(Length::Fill)
313
+                .height(Length::Fill)
314
+                .into()
315
+        };
316
+
317
+        container(content)
318
+            .width(Length::Fill)
319
+            .height(Length::Fill)
320
+            .style(|_theme| container::Style {
321
+                background: Some(theme::BACKGROUND.into()),
322
+                ..Default::default()
323
+            })
324
+            .into()
325
+    }
326
+
327
+    fn toolbar_view(&self) -> Element<'_, Message> {
328
+        let add_btn = button(text("+").size(20))
329
+            .padding([5, 15])
330
+            .on_press(Message::AddMachine);
331
+
332
+        let title = text("HyprKVM").size(18);
333
+
334
+        let save_btn = button(text("Save"))
335
+            .padding([5, 10])
336
+            .on_press(Message::SaveConfig);
337
+
338
+        container(
339
+            row![add_btn, Space::with_width(Length::Fill), title, Space::with_width(Length::Fill), save_btn]
340
+                .spacing(10)
341
+                .padding(10),
342
+        )
343
+        .width(Length::Fill)
344
+        .style(|_theme| container::Style {
345
+            background: Some(iced::Color::from_rgb(0.95, 0.93, 0.91).into()),
346
+            ..Default::default()
347
+        })
348
+        .into()
349
+    }
350
+
351
+    fn error_banner(&self) -> Element<'_, Message> {
352
+        if let Some(ref error) = self.state.error {
353
+            let mut row_content = row![
354
+                text(error).style(|_theme| text::Style {
355
+                    color: Some(theme::STATUS_DISCONNECTED)
356
+                }),
357
+                Space::with_width(Length::Fill)
358
+            ];
359
+
360
+            // Add restart button if restart is needed
361
+            if self.state.needs_restart {
362
+                row_content = row_content.push(
363
+                    button(text("Restart Daemon"))
364
+                        .padding([5, 10])
365
+                        .on_press(Message::RestartDaemon)
366
+                );
367
+                row_content = row_content.push(Space::with_width(10));
368
+            }
369
+
370
+            row_content = row_content.push(button(text("x")).on_press(Message::ClearError));
371
+
372
+            container(row_content.padding(10))
373
+                .width(Length::Fill)
374
+                .style(|_theme| container::Style {
375
+                    background: Some(iced::Color::from_rgba(1.0, 0.9, 0.9, 1.0).into()),
376
+                    ..Default::default()
377
+                })
378
+                .into()
379
+        } else {
380
+            Space::with_height(0).into()
381
+        }
382
+    }
383
+
384
+    fn success_banner(&self) -> Element<'_, Message> {
385
+        if let Some(ref msg) = self.state.success {
386
+            container(
387
+                row![
388
+                    text(msg).style(|_theme| text::Style {
389
+                        color: Some(theme::STATUS_CONNECTED)
390
+                    }),
391
+                    Space::with_width(Length::Fill),
392
+                    button(text("x")).on_press(Message::ClearSuccess)
393
+                ]
394
+                .padding(10),
395
+            )
396
+            .width(Length::Fill)
397
+            .style(|_theme| container::Style {
398
+                background: Some(iced::Color::from_rgba(0.9, 1.0, 0.9, 1.0).into()),
399
+                ..Default::default()
400
+            })
401
+            .into()
402
+        } else {
403
+            Space::with_height(0).into()
404
+        }
405
+    }
406
+
407
+    fn add_machine_modal(&self) -> Element<'_, Message> {
408
+        let available = self.state.available_positions();
409
+
410
+        // Position buttons
411
+        let position_buttons: Vec<Element<Message>> = available
412
+            .iter()
413
+            .map(|&pos| {
414
+                let label = pos.to_direction().map(|d| format!("{}", d)).unwrap_or_default();
415
+                button(text(label))
416
+                    .padding([8, 16])
417
+                    .on_press(Message::SelectNewMachinePosition(pos))
418
+                    .into()
419
+            })
420
+            .collect();
421
+
422
+        let position_row = row(position_buttons).spacing(10);
423
+
424
+        container(
425
+            column![
426
+                text("Add Machine").size(20),
427
+                Space::with_height(20),
428
+                text("Name:"),
429
+                text_input("Machine name", &self.state.new_machine.name)
430
+                    .on_input(Message::UpdateNewMachineName)
431
+                    .padding(8),
432
+                Space::with_height(10),
433
+                text("Address:"),
434
+                text_input("192.168.1.100:24850", &self.state.new_machine.address)
435
+                    .on_input(Message::UpdateNewMachineAddress)
436
+                    .padding(8),
437
+                Space::with_height(20),
438
+                text("Position:"),
439
+                position_row,
440
+                Space::with_height(20),
441
+                row![
442
+                    button(text("Cancel")).on_press(Message::CancelAddMachine),
443
+                    Space::with_width(10),
444
+                    button(text("Add")).on_press(Message::ConfirmAddMachine)
445
+                ]
446
+            ]
447
+            .spacing(5)
448
+            .padding(30),
449
+        )
450
+        .style(|_theme| container::Style {
451
+            background: Some(iced::Color::WHITE.into()),
452
+            border: iced::Border {
453
+                color: iced::Color::from_rgb(0.8, 0.8, 0.8),
454
+                width: 1.0,
455
+                radius: 8.0.into(),
456
+            },
457
+            shadow: iced::Shadow {
458
+                color: iced::Color::from_rgba(0.0, 0.0, 0.0, 0.2),
459
+                offset: iced::Vector::new(0.0, 2.0),
460
+                blur_radius: 10.0,
461
+            },
462
+            ..Default::default()
463
+        })
464
+        .width(Length::Fixed(400.0))
465
+        .into()
466
+    }
467
+
468
+    /// Window title
469
+    pub fn title(&self) -> String {
470
+        format!("HyprKVM - {}", self.state.config.machines.self_name)
471
+    }
472
+
473
+    /// Theme
474
+    pub fn theme(&self) -> iced::Theme {
475
+        iced::Theme::Light
476
+    }
477
+}
hyprkvm-daemon/src/gui/canvas.rsadded
@@ -0,0 +1,361 @@
1
+//! Canvas rendering for machine grid
2
+
3
+use iced::widget::canvas::{self, Cache, Canvas, Event, Frame, Geometry, Path, Stroke, Text};
4
+use iced::mouse;
5
+use iced::{Color, Point, Rectangle, Renderer, Size, Theme};
6
+
7
+use super::messages::{CanvasEvent, Message};
8
+use super::state::{ConnectionStatus, DragState, GridPos, MachineNode};
9
+use super::theme;
10
+
11
+/// The machine grid canvas program
12
+pub struct MachineGrid {
13
+    /// All machines to render
14
+    machines: Vec<MachineNode>,
15
+    /// Current drag state
16
+    drag: DragState,
17
+    /// Available snap positions
18
+    available_positions: Vec<GridPos>,
19
+    /// Render cache
20
+    cache: Cache,
21
+}
22
+
23
+impl MachineGrid {
24
+    pub fn new(
25
+        machines: Vec<MachineNode>,
26
+        drag: DragState,
27
+        available_positions: Vec<GridPos>,
28
+    ) -> Self {
29
+        Self {
30
+            machines,
31
+            drag,
32
+            available_positions,
33
+            cache: Cache::new(),
34
+        }
35
+    }
36
+
37
+    /// Convert grid position to canvas coordinates
38
+    fn grid_to_canvas(&self, pos: GridPos, bounds: &Rectangle) -> Point {
39
+        let center = Point::new(bounds.width / 2.0, bounds.height / 2.0);
40
+        Point::new(
41
+            center.x + (pos.x as f32 * theme::GRID_SPACING_H),
42
+            center.y + (pos.y as f32 * theme::GRID_SPACING_V),
43
+        )
44
+    }
45
+
46
+    /// Convert canvas coordinates to nearest grid position
47
+    fn canvas_to_grid(&self, point: Point, bounds: &Rectangle) -> GridPos {
48
+        let center = Point::new(bounds.width / 2.0, bounds.height / 2.0);
49
+        let relative = Point::new(point.x - center.x, point.y - center.y);
50
+
51
+        GridPos {
52
+            x: (relative.x / theme::GRID_SPACING_H).round() as i32,
53
+            y: (relative.y / theme::GRID_SPACING_V).round() as i32,
54
+        }
55
+    }
56
+
57
+    /// Find machine at canvas position
58
+    fn machine_at_position(&self, point: Point, bounds: &Rectangle) -> Option<usize> {
59
+        for (idx, machine) in self.machines.iter().enumerate() {
60
+            let machine_center = self.grid_to_canvas(machine.grid_pos, bounds);
61
+            let rect = Rectangle::new(
62
+                Point::new(
63
+                    machine_center.x - theme::MACHINE_WIDTH / 2.0,
64
+                    machine_center.y - theme::MACHINE_HEIGHT / 2.0,
65
+                ),
66
+                Size::new(theme::MACHINE_WIDTH, theme::MACHINE_HEIGHT),
67
+            );
68
+
69
+            if rect.contains(point) {
70
+                return Some(idx);
71
+            }
72
+        }
73
+        None
74
+    }
75
+
76
+    /// Find snap target near cursor position
77
+    fn find_snap_target(&self, point: Point, bounds: &Rectangle) -> Option<GridPos> {
78
+        for &pos in &self.available_positions {
79
+            let target = self.grid_to_canvas(pos, bounds);
80
+            let distance = ((point.x - target.x).powi(2) + (point.y - target.y).powi(2)).sqrt();
81
+
82
+            if distance < theme::SNAP_RADIUS {
83
+                return Some(pos);
84
+            }
85
+        }
86
+        None
87
+    }
88
+
89
+    /// Draw a machine rectangle
90
+    fn draw_machine(&self, frame: &mut Frame, machine: &MachineNode, center: Point, dragging: bool) {
91
+        let half_w = theme::MACHINE_WIDTH / 2.0;
92
+        let half_h = theme::MACHINE_HEIGHT / 2.0;
93
+
94
+        // Machine background
95
+        let bg_color = if machine.is_self {
96
+            theme::MACHINE_SELF
97
+        } else {
98
+            theme::MACHINE_NEIGHBOR
99
+        };
100
+
101
+        // Apply opacity if dragging
102
+        let bg_color = if dragging {
103
+            Color::from_rgba(bg_color.r, bg_color.g, bg_color.b, 0.6)
104
+        } else {
105
+            bg_color
106
+        };
107
+
108
+        let rect = Path::rectangle(
109
+            Point::new(center.x - half_w, center.y - half_h),
110
+            Size::new(theme::MACHINE_WIDTH, theme::MACHINE_HEIGHT),
111
+        );
112
+
113
+        frame.fill(&rect, bg_color);
114
+
115
+        // Status indicator (small circle in corner)
116
+        if !machine.is_self {
117
+            let status_color = match machine.status {
118
+                ConnectionStatus::Connected => theme::STATUS_CONNECTED,
119
+                ConnectionStatus::Connecting => theme::STATUS_CONNECTING,
120
+                ConnectionStatus::Disconnected => theme::STATUS_DISCONNECTED,
121
+            };
122
+
123
+            let status_pos = Point::new(center.x + half_w - 12.0, center.y - half_h + 12.0);
124
+            let status_circle = Path::circle(status_pos, 6.0);
125
+            frame.fill(&status_circle, status_color);
126
+        }
127
+
128
+        // Machine name
129
+        let name_text = Text {
130
+            content: machine.name.clone(),
131
+            position: Point::new(center.x, center.y - 10.0),
132
+            color: theme::TEXT_LIGHT,
133
+            size: iced::Pixels(16.0),
134
+            horizontal_alignment: iced::alignment::Horizontal::Center,
135
+            vertical_alignment: iced::alignment::Vertical::Center,
136
+            ..Default::default()
137
+        };
138
+        frame.fill_text(name_text);
139
+
140
+        // Address (for neighbors)
141
+        if !machine.is_self && !machine.address.is_empty() {
142
+            let addr_text = Text {
143
+                content: machine.address.clone(),
144
+                position: Point::new(center.x, center.y + 15.0),
145
+                color: Color::from_rgba(1.0, 1.0, 1.0, 0.7),
146
+                size: iced::Pixels(11.0),
147
+                horizontal_alignment: iced::alignment::Horizontal::Center,
148
+                vertical_alignment: iced::alignment::Vertical::Center,
149
+                ..Default::default()
150
+            };
151
+            frame.fill_text(addr_text);
152
+        }
153
+
154
+        // Self label
155
+        if machine.is_self {
156
+            let self_text = Text {
157
+                content: "(this machine)".to_string(),
158
+                position: Point::new(center.x, center.y + 15.0),
159
+                color: Color::from_rgba(1.0, 1.0, 1.0, 0.7),
160
+                size: iced::Pixels(11.0),
161
+                horizontal_alignment: iced::alignment::Horizontal::Center,
162
+                vertical_alignment: iced::alignment::Vertical::Center,
163
+                ..Default::default()
164
+            };
165
+            frame.fill_text(self_text);
166
+        }
167
+    }
168
+
169
+    /// Draw a snap target indicator
170
+    fn draw_snap_target(&self, frame: &mut Frame, center: Point, highlighted: bool) {
171
+        let half_w = theme::MACHINE_WIDTH / 2.0;
172
+        let half_h = theme::MACHINE_HEIGHT / 2.0;
173
+
174
+        let color = if highlighted {
175
+            theme::SNAP_HIGHLIGHT
176
+        } else {
177
+            Color::from_rgba(0.5, 0.5, 0.5, 0.15)
178
+        };
179
+
180
+        let rect = Path::rectangle(
181
+            Point::new(center.x - half_w, center.y - half_h),
182
+            Size::new(theme::MACHINE_WIDTH, theme::MACHINE_HEIGHT),
183
+        );
184
+
185
+        frame.fill(&rect, color);
186
+
187
+        // Dashed border
188
+        let stroke = Stroke::default()
189
+            .with_color(Color::from_rgba(0.5, 0.5, 0.5, 0.4))
190
+            .with_width(2.0);
191
+
192
+        frame.stroke(&rect, stroke);
193
+
194
+        // Direction label
195
+        if let Some(direction) = (GridPos {
196
+            x: ((center.x - frame.size().width / 2.0) / theme::GRID_SPACING_H).round() as i32,
197
+            y: ((center.y - frame.size().height / 2.0) / theme::GRID_SPACING_V).round() as i32,
198
+        })
199
+        .to_direction()
200
+        {
201
+            let label = Text {
202
+                content: format!("{}", direction),
203
+                position: center,
204
+                color: Color::from_rgba(0.4, 0.4, 0.4, 0.6),
205
+                size: iced::Pixels(14.0),
206
+                horizontal_alignment: iced::alignment::Horizontal::Center,
207
+                vertical_alignment: iced::alignment::Vertical::Center,
208
+                ..Default::default()
209
+            };
210
+            frame.fill_text(label);
211
+        }
212
+    }
213
+}
214
+
215
+impl canvas::Program<Message> for MachineGrid {
216
+    type State = ();
217
+
218
+    fn update(
219
+        &self,
220
+        _state: &mut Self::State,
221
+        event: Event,
222
+        bounds: Rectangle,
223
+        cursor: mouse::Cursor,
224
+    ) -> (canvas::event::Status, Option<Message>) {
225
+        let cursor_position = cursor.position_in(bounds);
226
+
227
+        match event {
228
+            Event::Mouse(mouse_event) => match mouse_event {
229
+                mouse::Event::ButtonPressed(mouse::Button::Left) => {
230
+                    if let Some(pos) = cursor_position {
231
+                        if let Some(idx) = self.machine_at_position(pos, &bounds) {
232
+                            // Don't allow dragging self
233
+                            if !self.machines[idx].is_self {
234
+                                return (
235
+                                    canvas::event::Status::Captured,
236
+                                    Some(Message::CanvasEvent(CanvasEvent::MachinePressed(idx))),
237
+                                );
238
+                            }
239
+                        }
240
+                    }
241
+                }
242
+                mouse::Event::ButtonReleased(mouse::Button::Left) => {
243
+                    if self.drag.is_dragging() {
244
+                        return (
245
+                            canvas::event::Status::Captured,
246
+                            Some(Message::CanvasEvent(CanvasEvent::MouseReleased)),
247
+                        );
248
+                    }
249
+                }
250
+                mouse::Event::CursorMoved { .. } => {
251
+                    if self.drag.is_dragging() {
252
+                        if let Some(pos) = cursor_position {
253
+                            // Calculate snap target
254
+                            let snap_target = self.find_snap_target(pos, &bounds);
255
+                            return (
256
+                                canvas::event::Status::Captured,
257
+                                Some(Message::CanvasEvent(CanvasEvent::MouseMoved(pos, snap_target))),
258
+                            );
259
+                        }
260
+                    }
261
+                }
262
+                _ => {}
263
+            },
264
+            _ => {}
265
+        }
266
+
267
+        (canvas::event::Status::Ignored, None)
268
+    }
269
+
270
+    fn draw(
271
+        &self,
272
+        _state: &Self::State,
273
+        renderer: &Renderer,
274
+        _theme: &Theme,
275
+        bounds: Rectangle,
276
+        _cursor: mouse::Cursor,
277
+    ) -> Vec<Geometry> {
278
+        let geometry = self.cache.draw(renderer, bounds.size(), |frame| {
279
+            // Background
280
+            frame.fill_rectangle(
281
+                Point::ORIGIN,
282
+                frame.size(),
283
+                theme::BACKGROUND,
284
+            );
285
+
286
+            // Draw connection dots between self and each neighbor
287
+            let self_center = self.grid_to_canvas(GridPos::origin(), &bounds);
288
+            for machine in &self.machines {
289
+                if !machine.is_self {
290
+                    let neighbor_center = self.grid_to_canvas(machine.grid_pos, &bounds);
291
+                    // Calculate midpoint between self and neighbor
292
+                    let mid = Point::new(
293
+                        (self_center.x + neighbor_center.x) / 2.0,
294
+                        (self_center.y + neighbor_center.y) / 2.0,
295
+                    );
296
+                    // Draw connection dot
297
+                    let dot = Path::circle(mid, theme::CONNECTION_DOT_RADIUS);
298
+                    frame.fill(&dot, theme::CONNECTION_DOT);
299
+                }
300
+            }
301
+
302
+            // Draw available snap positions
303
+            for &pos in &self.available_positions {
304
+                let target_center = self.grid_to_canvas(pos, &bounds);
305
+                let highlighted = self.drag.snap_target == Some(pos);
306
+                self.draw_snap_target(frame, target_center, highlighted);
307
+            }
308
+
309
+            // Draw machines (except the one being dragged)
310
+            for (idx, machine) in self.machines.iter().enumerate() {
311
+                let is_being_dragged = self.drag.dragging == Some(idx);
312
+                if !is_being_dragged {
313
+                    let center = self.grid_to_canvas(machine.grid_pos, &bounds);
314
+                    self.draw_machine(frame, machine, center, false);
315
+                }
316
+            }
317
+
318
+            // Draw dragged machine at cursor position
319
+            if let Some(drag_idx) = self.drag.dragging {
320
+                if let Some(cursor_pos) = self.drag.cursor_pos {
321
+                    let machine = &self.machines[drag_idx];
322
+                    self.draw_machine(frame, machine, cursor_pos, true);
323
+                }
324
+            }
325
+        });
326
+
327
+        vec![geometry]
328
+    }
329
+
330
+    fn mouse_interaction(
331
+        &self,
332
+        _state: &Self::State,
333
+        bounds: Rectangle,
334
+        cursor: mouse::Cursor,
335
+    ) -> mouse::Interaction {
336
+        if self.drag.is_dragging() {
337
+            return mouse::Interaction::Grabbing;
338
+        }
339
+
340
+        if let Some(pos) = cursor.position_in(bounds) {
341
+            if let Some(idx) = self.machine_at_position(pos, &bounds) {
342
+                if !self.machines[idx].is_self {
343
+                    return mouse::Interaction::Grab;
344
+                }
345
+            }
346
+        }
347
+
348
+        mouse::Interaction::default()
349
+    }
350
+}
351
+
352
+/// Create the canvas widget
353
+pub fn machine_canvas(
354
+    machines: Vec<MachineNode>,
355
+    drag: DragState,
356
+    available_positions: Vec<GridPos>,
357
+) -> Canvas<MachineGrid, Message> {
358
+    Canvas::new(MachineGrid::new(machines, drag, available_positions))
359
+        .width(iced::Length::Fill)
360
+        .height(iced::Length::Fill)
361
+}
hyprkvm-daemon/src/gui/messages.rsadded
@@ -0,0 +1,50 @@
1
+//! GUI message types
2
+
3
+use super::state::GridPos;
4
+
5
+/// All messages that can be sent in the GUI
6
+#[derive(Debug, Clone)]
7
+pub enum Message {
8
+    // Canvas interactions
9
+    CanvasEvent(CanvasEvent),
10
+
11
+    // Machine CRUD
12
+    AddMachine,
13
+    RemoveMachine(usize),
14
+    CancelAddMachine,
15
+    ConfirmAddMachine,
16
+
17
+    // Form updates
18
+    UpdateNewMachineName(String),
19
+    UpdateNewMachineAddress(String),
20
+    SelectNewMachinePosition(GridPos),
21
+
22
+    // Config operations
23
+    SaveConfig,
24
+    ReloadDaemon,
25
+    RestartDaemon,
26
+    ConfigSaved(Result<(), String>),
27
+    DaemonReloaded(Result<(), String>),
28
+
29
+    // Status updates
30
+    StatusUpdate(Vec<(String, super::state::ConnectionStatus)>),
31
+
32
+    // Notifications
33
+    ClearError,
34
+    ClearSuccess,
35
+}
36
+
37
+/// Canvas-specific events
38
+#[derive(Debug, Clone)]
39
+pub enum CanvasEvent {
40
+    /// Mouse pressed on a machine
41
+    MachinePressed(usize),
42
+    /// Mouse released (potentially on a snap target)
43
+    MouseReleased,
44
+    /// Mouse moved during drag, with calculated snap target
45
+    MouseMoved(iced::Point, Option<super::state::GridPos>),
46
+    /// Mouse entered canvas bounds
47
+    MouseEntered,
48
+    /// Mouse left canvas bounds
49
+    MouseExited,
50
+}
hyprkvm-daemon/src/gui/mod.rsadded
@@ -0,0 +1,24 @@
1
+//! HyprKVM GUI module
2
+//!
3
+//! Provides a visual interface for configuring machine neighbors.
4
+
5
+mod app;
6
+mod canvas;
7
+mod messages;
8
+mod state;
9
+mod theme;
10
+
11
+use std::path::Path;
12
+
13
+use app::HyprKvmGui;
14
+
15
+/// Run the GUI application
16
+pub fn run_gui(config_path: &Path) -> anyhow::Result<()> {
17
+    let config_path = config_path.to_path_buf();
18
+
19
+    iced::application("HyprKVM", HyprKvmGui::update, HyprKvmGui::view)
20
+        .window_size(iced::Size::new(800.0, 600.0))
21
+        .antialiasing(true)
22
+        .run_with(move || HyprKvmGui::new(config_path.clone()))
23
+        .map_err(|e| anyhow::anyhow!("GUI error: {}", e))
24
+}
hyprkvm-daemon/src/gui/state.rsadded
@@ -0,0 +1,330 @@
1
+//! GUI state management
2
+
3
+#![allow(dead_code)]
4
+
5
+use hyprkvm_common::Direction;
6
+use crate::config::{Config, NeighborConfig};
7
+use std::path::PathBuf;
8
+
9
+/// Grid position in the visual layout
10
+/// Self machine is always at (0, 0)
11
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12
+pub struct GridPos {
13
+    pub x: i32,
14
+    pub y: i32,
15
+}
16
+
17
+impl GridPos {
18
+    pub fn origin() -> Self {
19
+        Self { x: 0, y: 0 }
20
+    }
21
+
22
+    pub fn from_direction(direction: Direction) -> Self {
23
+        match direction {
24
+            Direction::Left => Self { x: -1, y: 0 },
25
+            Direction::Right => Self { x: 1, y: 0 },
26
+            Direction::Up => Self { x: 0, y: -1 },
27
+            Direction::Down => Self { x: 0, y: 1 },
28
+        }
29
+    }
30
+
31
+    pub fn to_direction(&self) -> Option<Direction> {
32
+        match (self.x, self.y) {
33
+            (-1, 0) => Some(Direction::Left),
34
+            (1, 0) => Some(Direction::Right),
35
+            (0, -1) => Some(Direction::Up),
36
+            (0, 1) => Some(Direction::Down),
37
+            _ => None, // Origin or invalid position
38
+        }
39
+    }
40
+
41
+    /// Check if this is a valid neighbor position (adjacent to origin)
42
+    pub fn is_valid_neighbor(&self) -> bool {
43
+        self.to_direction().is_some()
44
+    }
45
+}
46
+
47
+/// Connection status for a machine
48
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
49
+pub enum ConnectionStatus {
50
+    #[default]
51
+    Disconnected,
52
+    Connecting,
53
+    Connected,
54
+}
55
+
56
+/// Visual representation of a machine in the GUI
57
+#[derive(Debug, Clone)]
58
+pub struct MachineNode {
59
+    /// Machine name
60
+    pub name: String,
61
+    /// Network address (empty for self)
62
+    pub address: String,
63
+    /// Position on the visual grid
64
+    pub grid_pos: GridPos,
65
+    /// Connection status
66
+    pub status: ConnectionStatus,
67
+    /// Is this the local machine?
68
+    pub is_self: bool,
69
+    /// Original neighbor index in config (None for self)
70
+    pub config_index: Option<usize>,
71
+}
72
+
73
+impl MachineNode {
74
+    pub fn new_self(name: String) -> Self {
75
+        Self {
76
+            name,
77
+            address: String::new(),
78
+            grid_pos: GridPos::origin(),
79
+            status: ConnectionStatus::Connected, // Self is always connected
80
+            is_self: true,
81
+            config_index: None,
82
+        }
83
+    }
84
+
85
+    pub fn new_neighbor(
86
+        name: String,
87
+        address: String,
88
+        direction: Direction,
89
+        config_index: usize,
90
+    ) -> Self {
91
+        Self {
92
+            name,
93
+            address,
94
+            grid_pos: GridPos::from_direction(direction),
95
+            status: ConnectionStatus::Disconnected,
96
+            is_self: false,
97
+            config_index: Some(config_index),
98
+        }
99
+    }
100
+}
101
+
102
+/// Drag state for machine repositioning
103
+#[derive(Debug, Clone, Default)]
104
+pub struct DragState {
105
+    /// Index of machine being dragged (None if not dragging)
106
+    pub dragging: Option<usize>,
107
+    /// Current cursor position during drag
108
+    pub cursor_pos: Option<iced::Point>,
109
+    /// Snap target (if cursor is near a valid position)
110
+    pub snap_target: Option<GridPos>,
111
+}
112
+
113
+impl DragState {
114
+    pub fn is_dragging(&self) -> bool {
115
+        self.dragging.is_some()
116
+    }
117
+
118
+    pub fn start(&mut self, machine_index: usize) {
119
+        self.dragging = Some(machine_index);
120
+        self.cursor_pos = None;
121
+        self.snap_target = None;
122
+    }
123
+
124
+    pub fn update(&mut self, cursor: iced::Point) {
125
+        self.cursor_pos = Some(cursor);
126
+    }
127
+
128
+    pub fn end(&mut self) -> Option<(usize, Option<GridPos>)> {
129
+        let result = self.dragging.map(|idx| (idx, self.snap_target));
130
+        self.dragging = None;
131
+        self.cursor_pos = None;
132
+        self.snap_target = None;
133
+        result
134
+    }
135
+}
136
+
137
+/// Main GUI state
138
+#[derive(Debug)]
139
+pub struct GuiState {
140
+    /// Path to config file
141
+    pub config_path: PathBuf,
142
+    /// Current configuration
143
+    pub config: Config,
144
+    /// Machine nodes for rendering
145
+    pub machines: Vec<MachineNode>,
146
+    /// Drag state
147
+    pub drag: DragState,
148
+    /// Error message to display
149
+    pub error: Option<String>,
150
+    /// Success message to display (auto-dismisses)
151
+    pub success: Option<String>,
152
+    /// Whether daemon restart is needed (shows restart button)
153
+    pub needs_restart: bool,
154
+    /// Show add machine modal
155
+    pub show_add_modal: bool,
156
+    /// New machine form data
157
+    pub new_machine: NewMachineForm,
158
+}
159
+
160
+/// Form data for adding a new machine
161
+#[derive(Debug, Clone, Default)]
162
+pub struct NewMachineForm {
163
+    pub name: String,
164
+    pub address: String,
165
+}
166
+
167
+impl GuiState {
168
+    /// Create state from config
169
+    pub fn from_config(config_path: PathBuf, config: Config) -> Self {
170
+        let mut machines = Vec::new();
171
+
172
+        // Add self machine at origin
173
+        machines.push(MachineNode::new_self(config.machines.self_name.clone()));
174
+
175
+        // Add neighbors at their positions
176
+        for (idx, neighbor) in config.machines.neighbors.iter().enumerate() {
177
+            machines.push(MachineNode::new_neighbor(
178
+                neighbor.name.clone(),
179
+                neighbor.address.to_string(),
180
+                neighbor.direction,
181
+                idx,
182
+            ));
183
+        }
184
+
185
+        Self {
186
+            config_path,
187
+            config,
188
+            machines,
189
+            drag: DragState::default(),
190
+            error: None,
191
+            success: None,
192
+            needs_restart: false,
193
+            show_add_modal: false,
194
+            new_machine: NewMachineForm::default(),
195
+        }
196
+    }
197
+
198
+    /// Find machine at grid position
199
+    pub fn machine_at(&self, pos: GridPos) -> Option<usize> {
200
+        self.machines.iter().position(|m| m.grid_pos == pos)
201
+    }
202
+
203
+    /// Get available neighbor positions (not occupied, excluding dragged machine)
204
+    pub fn available_positions(&self) -> Vec<GridPos> {
205
+        let occupied: std::collections::HashSet<_> = self.machines
206
+            .iter()
207
+            .enumerate()
208
+            .filter(|(idx, _)| Some(*idx) != self.drag.dragging) // Exclude dragged machine
209
+            .map(|(_, m)| m.grid_pos)
210
+            .collect();
211
+
212
+        [
213
+            GridPos { x: -1, y: 0 },
214
+            GridPos { x: 1, y: 0 },
215
+            GridPos { x: 0, y: -1 },
216
+            GridPos { x: 0, y: 1 },
217
+        ]
218
+        .into_iter()
219
+        .filter(|pos| !occupied.contains(pos))
220
+        .collect()
221
+    }
222
+
223
+    /// Move a machine to a new position
224
+    pub fn move_machine(&mut self, machine_idx: usize, new_pos: GridPos) -> bool {
225
+        // Can't move self
226
+        if self.machines[machine_idx].is_self {
227
+            return false;
228
+        }
229
+
230
+        // Check if position is valid
231
+        if !new_pos.is_valid_neighbor() {
232
+            return false;
233
+        }
234
+
235
+        // Check if position is occupied by another machine (not the one being moved)
236
+        if let Some(occupant_idx) = self.machine_at(new_pos) {
237
+            if occupant_idx != machine_idx {
238
+                return false;
239
+            }
240
+            // Same position - no need to update
241
+            return true;
242
+        }
243
+
244
+        // Update the machine position
245
+        self.machines[machine_idx].grid_pos = new_pos;
246
+
247
+        // Update config
248
+        if let Some(config_idx) = self.machines[machine_idx].config_index {
249
+            if let Some(direction) = new_pos.to_direction() {
250
+                self.config.machines.neighbors[config_idx].direction = direction;
251
+            }
252
+        }
253
+
254
+        true
255
+    }
256
+
257
+    /// Add a new neighbor machine
258
+    pub fn add_machine(&mut self, name: String, address: String, pos: GridPos) -> Result<(), String> {
259
+        // Validate position
260
+        let direction = pos.to_direction().ok_or("Invalid position")?;
261
+
262
+        // Check if position is occupied
263
+        if self.machine_at(pos).is_some() {
264
+            return Err("Position already occupied".to_string());
265
+        }
266
+
267
+        // Parse address
268
+        let socket_addr: std::net::SocketAddr = address
269
+            .parse()
270
+            .map_err(|e| format!("Invalid address: {}", e))?;
271
+
272
+        // Add to config
273
+        let config_idx = self.config.machines.neighbors.len();
274
+        self.config.machines.neighbors.push(NeighborConfig {
275
+            name: name.clone(),
276
+            direction,
277
+            address: socket_addr,
278
+            fingerprint: None,
279
+            tls: None,
280
+        });
281
+
282
+        // Add to machines list
283
+        self.machines.push(MachineNode::new_neighbor(
284
+            name,
285
+            address,
286
+            direction,
287
+            config_idx,
288
+        ));
289
+
290
+        Ok(())
291
+    }
292
+
293
+    /// Remove a neighbor machine
294
+    pub fn remove_machine(&mut self, machine_idx: usize) -> bool {
295
+        // Can't remove self
296
+        if machine_idx == 0 || self.machines[machine_idx].is_self {
297
+            return false;
298
+        }
299
+
300
+        // Get config index before removal
301
+        let config_idx = match self.machines[machine_idx].config_index {
302
+            Some(idx) => idx,
303
+            None => return false,
304
+        };
305
+
306
+        // Remove from machines
307
+        self.machines.remove(machine_idx);
308
+
309
+        // Remove from config
310
+        self.config.machines.neighbors.remove(config_idx);
311
+
312
+        // Update config indices for remaining machines
313
+        for machine in &mut self.machines {
314
+            if let Some(idx) = machine.config_index {
315
+                if idx > config_idx {
316
+                    machine.config_index = Some(idx - 1);
317
+                }
318
+            }
319
+        }
320
+
321
+        true
322
+    }
323
+
324
+    /// Save config to file
325
+    pub fn save_config(&mut self) -> Result<(), String> {
326
+        self.config
327
+            .save(&self.config_path)
328
+            .map_err(|e| e.to_string())
329
+    }
330
+}
hyprkvm-daemon/src/gui/theme.rsadded
@@ -0,0 +1,55 @@
1
+//! Color theme constants for HyprKVM GUI
2
+
3
+#![allow(dead_code)]
4
+
5
+use iced::Color;
6
+
7
+/// Warm off-white background
8
+pub const BACKGROUND: Color = Color::from_rgb(0.961, 0.949, 0.941); // #F5F2F0
9
+
10
+/// Rich purple for neighbor machines
11
+pub const MACHINE_NEIGHBOR: Color = Color::from_rgb(0.549, 0.361, 0.820); // #8C5CD1
12
+
13
+/// Darker purple for self machine
14
+pub const MACHINE_SELF: Color = Color::from_rgb(0.439, 0.220, 0.722); // #7038B8
15
+
16
+/// Green for connected status
17
+pub const STATUS_CONNECTED: Color = Color::from_rgb(0.302, 0.690, 0.310); // #4DB04F
18
+
19
+/// Amber for connecting status
20
+pub const STATUS_CONNECTING: Color = Color::from_rgb(1.0, 0.761, 0.031); // #FFC208
21
+
22
+/// Red for disconnected status
23
+pub const STATUS_DISCONNECTED: Color = Color::from_rgb(0.914, 0.302, 0.239); // #E94D3D
24
+
25
+/// Snap highlight (purple at 30% opacity)
26
+pub const SNAP_HIGHLIGHT: Color = Color::from_rgba(0.549, 0.361, 0.820, 0.3);
27
+
28
+/// Text color (dark gray)
29
+pub const TEXT_PRIMARY: Color = Color::from_rgb(0.2, 0.2, 0.2);
30
+
31
+/// Text color (light, for on purple backgrounds)
32
+pub const TEXT_LIGHT: Color = Color::from_rgb(1.0, 1.0, 1.0);
33
+
34
+/// Grid line color (light gray)
35
+pub const GRID_LINE: Color = Color::from_rgba(0.6, 0.6, 0.6, 0.3);
36
+
37
+/// Machine rectangle dimensions
38
+pub const MACHINE_WIDTH: f32 = 160.0;
39
+pub const MACHINE_HEIGHT: f32 = 100.0;
40
+
41
+/// Gap between machines (same in both directions for equidistant spacing)
42
+pub const MACHINE_GAP: f32 = 24.0;
43
+
44
+/// Grid cell spacing (horizontal: width + gap, vertical: height + gap)
45
+pub const GRID_SPACING_H: f32 = MACHINE_WIDTH + MACHINE_GAP;   // 184
46
+pub const GRID_SPACING_V: f32 = MACHINE_HEIGHT + MACHINE_GAP;  // 124
47
+
48
+/// Snap radius for drag operations
49
+pub const SNAP_RADIUS: f32 = 50.0;
50
+
51
+/// Connection dot radius
52
+pub const CONNECTION_DOT_RADIUS: f32 = 4.0;
53
+
54
+/// Connection dot color (subtle gray)
55
+pub const CONNECTION_DOT: Color = Color::from_rgba(0.5, 0.5, 0.5, 0.5);
hyprkvm-daemon/src/input/capture.rsmodified
@@ -128,9 +128,10 @@ impl EdgeCaptureState {
128
         // Logical size = physical size / scale
128
         // Logical size = physical size / scale
129
 
129
 
130
         let mut used_monitors: Vec<bool> = vec![false; self.config.monitors.len()];
130
         let mut used_monitors: Vec<bool> = vec![false; self.config.monitors.len()];
131
+        let mut assigned_outputs: Vec<bool> = vec![false; self.outputs.len()];
131
 
132
 
132
         // First pass: try to find unique matches
133
         // First pass: try to find unique matches
133
-        for out in &mut self.outputs {
134
+        for (out_idx, out) in self.outputs.iter_mut().enumerate() {
134
             // Find monitors that could match this output size (considering possible scales)
135
             // Find monitors that could match this output size (considering possible scales)
135
             let mut candidates: Vec<usize> = Vec::new();
136
             let mut candidates: Vec<usize> = Vec::new();
136
             for (i, mon) in self.config.monitors.iter().enumerate() {
137
             for (i, mon) in self.config.monitors.iter().enumerate() {
@@ -162,6 +163,7 @@ impl EdgeCaptureState {
162
                 out.x = mon.x;
163
                 out.x = mon.x;
163
                 out.y = mon.y;
164
                 out.y = mon.y;
164
                 used_monitors[i] = true;
165
                 used_monitors[i] = true;
166
+                assigned_outputs[out_idx] = true;
165
             } else if candidates.len() > 1 {
167
             } else if candidates.len() > 1 {
166
                 tracing::debug!("Multiple candidates for output {}x{}: {:?}",
168
                 tracing::debug!("Multiple candidates for output {}x{}: {:?}",
167
                     out.width, out.height,
169
                     out.width, out.height,
@@ -170,9 +172,9 @@ impl EdgeCaptureState {
170
         }
172
         }
171
 
173
 
172
         // Second pass: assign remaining outputs to remaining monitors by order
174
         // Second pass: assign remaining outputs to remaining monitors by order
173
-        for out in &mut self.outputs {
175
+        for (out_idx, out) in self.outputs.iter_mut().enumerate() {
174
-            if out.x != 0 || out.y != 0 {
176
+            if assigned_outputs[out_idx] {
175
-                continue; // Already assigned
177
+                continue; // Already assigned in first pass
176
             }
178
             }
177
             // Find first unused monitor that could match
179
             // Find first unused monitor that could match
178
             for (i, mon) in self.config.monitors.iter().enumerate() {
180
             for (i, mon) in self.config.monitors.iter().enumerate() {
@@ -192,6 +194,7 @@ impl EdgeCaptureState {
192
                     out.x = mon.x;
194
                     out.x = mon.x;
193
                     out.y = mon.y;
195
                     out.y = mon.y;
194
                     used_monitors[i] = true;
196
                     used_monitors[i] = true;
197
+                    assigned_outputs[out_idx] = true;
195
                     break;
198
                     break;
196
                 }
199
                 }
197
             }
200
             }
hyprkvm-daemon/src/main.rsmodified
@@ -12,6 +12,8 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
12
 
12
 
13
 mod clipboard;
13
 mod clipboard;
14
 mod config;
14
 mod config;
15
+#[cfg(feature = "gui")]
16
+mod gui;
15
 mod hyprland;
17
 mod hyprland;
16
 mod input;
18
 mod input;
17
 mod ipc;
19
 mod ipc;
@@ -82,6 +84,10 @@ enum Commands {
82
         #[command(subcommand)]
84
         #[command(subcommand)]
83
         action: ConfigAction,
85
         action: ConfigAction,
84
     },
86
     },
87
+
88
+    /// Launch the graphical configuration interface
89
+    #[cfg(feature = "gui")]
90
+    Gui,
85
 }
91
 }
86
 
92
 
87
 #[derive(Subcommand)]
93
 #[derive(Subcommand)]
@@ -92,8 +98,7 @@ enum ConfigAction {
92
     Reload,
98
     Reload,
93
 }
99
 }
94
 
100
 
95
-#[tokio::main]
101
+fn main() -> anyhow::Result<()> {
96
-async fn main() -> anyhow::Result<()> {
97
     let cli = Cli::parse();
102
     let cli = Cli::parse();
98
 
103
 
99
     // Set up logging with dual output (stderr + file)
104
     // Set up logging with dual output (stderr + file)
@@ -131,10 +136,7 @@ async fn main() -> anyhow::Result<()> {
131
         );
136
         );
132
     subscriber.init();
137
     subscriber.init();
133
 
138
 
134
-    // Keep the guard alive for the duration of the program
139
+    // Load configuration path
135
-    // (it's moved into the async context below)
136
-
137
-    // Load configuration
138
     let config_path = cli.config.unwrap_or_else(|| {
140
     let config_path = cli.config.unwrap_or_else(|| {
139
         dirs::config_dir()
141
         dirs::config_dir()
140
             .unwrap_or_else(|| std::path::PathBuf::from("."))
142
             .unwrap_or_else(|| std::path::PathBuf::from("."))
@@ -142,24 +144,39 @@ async fn main() -> anyhow::Result<()> {
142
             .join("hyprkvm.toml")
144
             .join("hyprkvm.toml")
143
     });
145
     });
144
 
146
 
145
-    match cli.command {
147
+    // Handle GUI command outside of async runtime (Iced manages its own runtime)
146
-        Commands::Daemon => {
148
+    #[cfg(feature = "gui")]
147
-            info!("Starting HyprKVM daemon...");
149
+    if matches!(cli.command, Commands::Gui) {
148
-            run_daemon(&config_path).await
150
+        info!("Starting HyprKVM GUI...");
149
-        }
151
+        return gui::run_gui(&config_path);
150
-        Commands::Status => {
151
-            show_status().await
152
-        }
153
-        Commands::Move { direction } => {
154
-            handle_move(&direction).await
155
-        }
156
-        Commands::Config { action } => {
157
-            match action {
158
-                ConfigAction::Show => show_config(&config_path),
159
-                ConfigAction::Reload => reload_config().await,
160
-            }
161
-        }
162
     }
152
     }
153
+
154
+    // Run async commands in tokio runtime
155
+    tokio::runtime::Builder::new_multi_thread()
156
+        .enable_all()
157
+        .build()?
158
+        .block_on(async {
159
+            match cli.command {
160
+                Commands::Daemon => {
161
+                    info!("Starting HyprKVM daemon...");
162
+                    run_daemon(&config_path).await
163
+                }
164
+                Commands::Status => {
165
+                    show_status().await
166
+                }
167
+                Commands::Move { direction } => {
168
+                    handle_move(&direction).await
169
+                }
170
+                Commands::Config { action } => {
171
+                    match action {
172
+                        ConfigAction::Show => show_config(&config_path),
173
+                        ConfigAction::Reload => reload_config().await,
174
+                    }
175
+                }
176
+                #[cfg(feature = "gui")]
177
+                Commands::Gui => unreachable!("GUI handled above"),
178
+            }
179
+        })
163
 }
180
 }
164
 
181
 
165
 async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
182
 async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
@@ -171,7 +188,7 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
171
     use hyprkvm_common::protocol::{Message, HelloPayload, PROTOCOL_VERSION};
188
     use hyprkvm_common::protocol::{Message, HelloPayload, PROTOCOL_VERSION};
172
 
189
 
173
     // Load or create default config
190
     // Load or create default config
174
-    let config = match Config::load(config_path) {
191
+    let mut config = match Config::load(config_path) {
175
         Ok(cfg) => cfg,
192
         Ok(cfg) => cfg,
176
         Err(e) => {
193
         Err(e) => {
177
             tracing::warn!("Failed to load config: {e}, using defaults");
194
             tracing::warn!("Failed to load config: {e}, using defaults");
@@ -200,9 +217,15 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
200
         info!("  {} at ({}, {}) {}x{}", mon.name, mon.x, mon.y, mon.width, mon.height);
217
         info!("  {} at ({}, {}) {}x{}", mon.name, mon.x, mon.y, mon.width, mon.height);
201
     }
218
     }
202
 
219
 
203
-    // Calculate screen bounds
220
+    // Calculate screen bounds (supports negative coordinates and multi-monitor layouts)
204
-    let screen_width: u32 = monitors.iter().map(|m| m.x as u32 + m.width).max().unwrap_or(1920);
221
+    let screen_min_x: i32 = monitors.iter().map(|m| m.x).min().unwrap_or(0);
205
-    let screen_height: u32 = monitors.iter().map(|m| m.y as u32 + m.height).max().unwrap_or(1080);
222
+    let screen_min_y: i32 = monitors.iter().map(|m| m.y).min().unwrap_or(0);
223
+    let screen_max_x: i32 = monitors.iter().map(|m| m.x + m.width as i32).max().unwrap_or(1920);
224
+    let screen_max_y: i32 = monitors.iter().map(|m| m.y + m.height as i32).max().unwrap_or(1080);
225
+    let screen_width: u32 = (screen_max_x - screen_min_x) as u32;
226
+    let screen_height: u32 = (screen_max_y - screen_min_y) as u32;
227
+    info!("Screen bounds: ({}, {}) to ({}, {}), dimensions: {}x{}",
228
+          screen_min_x, screen_min_y, screen_max_x, screen_max_y, screen_width, screen_height);
206
 
229
 
207
     // Determine which edges have network neighbors
230
     // Determine which edges have network neighbors
208
     let mut enabled_edges = Vec::new();
231
     let mut enabled_edges = Vec::new();
@@ -333,12 +356,17 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
333
     };
356
     };
334
     info!("Listening for connections on {} (TLS: {})", server.local_addr(), tls_enabled);
357
     info!("Listening for connections on {} (TLS: {})", server.local_addr(), tls_enabled);
335
 
358
 
359
+    // Channel for signaling config changes that require restart
360
+    let (restart_tx, mut restart_rx) = tokio::sync::mpsc::channel::<String>(1);
361
+
336
     // Spawn task to accept incoming connections
362
     // Spawn task to accept incoming connections
337
     let machine_name = config.machines.self_name.clone();
363
     let machine_name = config.machines.self_name.clone();
338
     let neighbors_for_accept = config.machines.neighbors.clone();
364
     let neighbors_for_accept = config.machines.neighbors.clone();
339
     let peers_for_accept = peers.clone();
365
     let peers_for_accept = peers.clone();
340
     let known_hosts_for_accept = known_hosts.clone();
366
     let known_hosts_for_accept = known_hosts.clone();
341
     let known_hosts_path_for_accept = known_hosts_path.clone();
367
     let known_hosts_path_for_accept = known_hosts_path.clone();
368
+    let config_path_for_accept = config_path.to_path_buf();
369
+    let restart_tx_for_accept = restart_tx.clone();
342
     let accept_handle = tokio::spawn(async move {
370
     let accept_handle = tokio::spawn(async move {
343
         loop {
371
         loop {
344
             match server.accept().await {
372
             match server.accept().await {
@@ -393,11 +421,67 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
393
                                 continue;
421
                                 continue;
394
                             }
422
                             }
395
 
423
 
396
-                            // Determine direction based on peer's machine name
424
+                            // Determine direction: use opposite of what peer told us, or fall back to config
397
-                            let direction = neighbors_for_accept
425
+                            let direction = if let Some(peer_dir) = hello.my_direction_for_you {
398
-                                .iter()
426
+                                // Peer says "I have you as X", so we store them as opposite(X)
399
-                                .find(|n| n.name == hello.machine_name)
427
+                                Some(peer_dir.opposite())
400
-                                .map(|n| n.direction);
428
+                            } else {
429
+                                // Legacy: look up in our config
430
+                                neighbors_for_accept
431
+                                    .iter()
432
+                                    .find(|n| n.name == hello.machine_name)
433
+                                    .map(|n| n.direction)
434
+                            };
435
+
436
+                            // Check if we need to update our config due to direction change
437
+                            if let Some(peer_dir) = hello.my_direction_for_you {
438
+                                let new_dir = peer_dir.opposite();
439
+                                let existing = neighbors_for_accept
440
+                                    .iter()
441
+                                    .find(|n| n.name == hello.machine_name);
442
+
443
+                                let needs_update = match existing {
444
+                                    Some(n) => n.direction != new_dir,
445
+                                    None => true, // Peer not in our config - could add them
446
+                                };
447
+
448
+                                if needs_update {
449
+                                    if let Some(existing_neighbor) = existing {
450
+                                        info!(
451
+                                            "Direction mismatch for {}: our config says {:?}, peer says we should be {:?}",
452
+                                            hello.machine_name, existing_neighbor.direction, new_dir
453
+                                        );
454
+
455
+                                        // Load, update, and save config
456
+                                        match Config::load(&config_path_for_accept) {
457
+                                            Ok(mut cfg) => {
458
+                                                // Find and update the neighbor's direction
459
+                                                for neighbor in &mut cfg.machines.neighbors {
460
+                                                    if neighbor.name == hello.machine_name {
461
+                                                        info!("Updating {} direction: {:?} -> {:?}",
462
+                                                              neighbor.name, neighbor.direction, new_dir);
463
+                                                        neighbor.direction = new_dir;
464
+                                                        break;
465
+                                                    }
466
+                                                }
467
+
468
+                                                // Save updated config
469
+                                                if let Err(e) = cfg.save(&config_path_for_accept) {
470
+                                                    tracing::error!("Failed to save updated config: {}", e);
471
+                                                } else {
472
+                                                    info!("Config updated with new direction, signaling restart...");
473
+                                                    let _ = restart_tx_for_accept.try_send(
474
+                                                        format!("Direction changed for {}", hello.machine_name)
475
+                                                    );
476
+                                                }
477
+                                            }
478
+                                            Err(e) => {
479
+                                                tracing::error!("Failed to load config for update: {}", e);
480
+                                            }
481
+                                        }
482
+                                    }
483
+                                }
484
+                            }
401
 
485
 
402
                             if let Some(dir) = direction {
486
                             if let Some(dir) = direction {
403
                                 let mut peers = peers_for_accept.write().await;
487
                                 let mut peers = peers_for_accept.write().await;
@@ -405,12 +489,13 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
405
                                     info!("Already have connection for {:?}, dropping incoming from {}", dir, hello.machine_name);
489
                                     info!("Already have connection for {:?}, dropping incoming from {}", dir, hello.machine_name);
406
                                     // Drop the incoming connection, keep the existing one
490
                                     // Drop the incoming connection, keep the existing one
407
                                 } else {
491
                                 } else {
408
-                                    info!("Storing incoming connection from {} as {:?}", hello.machine_name, dir);
492
+                                    info!("Storing incoming connection from {} as {:?} (peer claimed {:?})",
493
+                                          hello.machine_name, dir, hello.my_direction_for_you);
409
                                     peers.insert(dir, conn);
494
                                     peers.insert(dir, conn);
410
                                 }
495
                                 }
411
                             } else {
496
                             } else {
412
                                 tracing::warn!(
497
                                 tracing::warn!(
413
-                                    "Unknown peer '{}' connected - not in neighbors list",
498
+                                    "Unknown peer '{}' connected - not in neighbors list and no direction provided",
414
                                     hello.machine_name
499
                                     hello.machine_name
415
                                 );
500
                                 );
416
                                 // Connection will be dropped
501
                                 // Connection will be dropped
@@ -479,11 +564,13 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
479
 
564
 
480
                 match conn_result {
565
                 match conn_result {
481
                     Ok(mut conn) => {
566
                     Ok(mut conn) => {
482
-                        // Send Hello
567
+                        // Send Hello with our direction for this peer
568
+                        // Peer will use the opposite direction to store us
483
                         let hello = Message::Hello(HelloPayload {
569
                         let hello = Message::Hello(HelloPayload {
484
                             protocol_version: PROTOCOL_VERSION,
570
                             protocol_version: PROTOCOL_VERSION,
485
                             machine_name: machine_name.clone(),
571
                             machine_name: machine_name.clone(),
486
                             capabilities: vec![],
572
                             capabilities: vec![],
573
+                            my_direction_for_you: Some(direction),
487
                         });
574
                         });
488
 
575
 
489
                         if let Err(e) = conn.send(&hello).await {
576
                         if let Err(e) = conn.send(&hello).await {
@@ -858,8 +945,10 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
858
                                     if let Err(e) = transfer_manager.initiate_transfer(
945
                                     if let Err(e) = transfer_manager.initiate_transfer(
859
                                         direction,
946
                                         direction,
860
                                         cursor_pos,
947
                                         cursor_pos,
861
-                                        screen_height,
948
+                                        screen_min_x,
862
-                                        screen_width,
949
+                                        screen_min_y,
950
+                                        screen_max_x,
951
+                                        screen_max_y,
863
                                         true, // keyboard-initiated (recovery hotkey)
952
                                         true, // keyboard-initiated (recovery hotkey)
864
                                     ).await {
953
                                     ).await {
865
                                         tracing::error!("Failed to initiate transfer from recovery hotkey: {}", e);
954
                                         tracing::error!("Failed to initiate transfer from recovery hotkey: {}", e);
@@ -943,8 +1032,10 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
943
                             if let Err(e) = transfer_manager.initiate_transfer(
1032
                             if let Err(e) = transfer_manager.initiate_transfer(
944
                                 direction,
1033
                                 direction,
945
                                 edge_event.position,
1034
                                 edge_event.position,
946
-                                screen_height,
1035
+                                screen_min_x,
947
-                                screen_width,
1036
+                                screen_min_y,
1037
+                                screen_max_x,
1038
+                                screen_max_y,
948
                                 false, // not keyboard-initiated (mouse edge)
1039
                                 false, // not keyboard-initiated (mouse edge)
949
                             ).await {
1040
                             ).await {
950
                                 tracing::warn!("Failed to initiate transfer: {}", e);
1041
                                 tracing::warn!("Failed to initiate transfer: {}", e);
@@ -1046,8 +1137,10 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
1046
                                                         if let Err(e) = transfer_manager.initiate_transfer(
1137
                                                         if let Err(e) = transfer_manager.initiate_transfer(
1047
                                                             edge_dir,
1138
                                                             edge_dir,
1048
                                                             (cx, cy),
1139
                                                             (cx, cy),
1049
-                                                            screen_height,
1140
+                                                            screen_min_x,
1050
-                                                            screen_width,
1141
+                                                            screen_min_y,
1142
+                                                            screen_max_x,
1143
+                                                            screen_max_y,
1051
                                                             false, // not keyboard-initiated (cursor edge)
1144
                                                             false, // not keyboard-initiated (cursor edge)
1052
                                                         ).await {
1145
                                                         ).await {
1053
                                                             tracing::warn!("Failed to initiate transfer: {}", e);
1146
                                                             tracing::warn!("Failed to initiate transfer: {}", e);
@@ -1127,8 +1220,10 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
1127
                                         match transfer_manager.handle_enter(
1220
                                         match transfer_manager.handle_enter(
1128
                                             direction,
1221
                                             direction,
1129
                                             payload,
1222
                                             payload,
1130
-                                            screen_width,
1223
+                                            screen_min_x,
1131
-                                            screen_height,
1224
+                                            screen_min_y,
1225
+                                            screen_max_x,
1226
+                                            screen_max_y,
1132
                                         ).await {
1227
                                         ).await {
1133
                                             Ok(pos) => {
1228
                                             Ok(pos) => {
1134
                                                 info!("Positioned cursor at {:?}", pos);
1229
                                                 info!("Positioned cursor at {:?}", pos);
@@ -1575,8 +1670,10 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
1575
                                         if let Err(e) = transfer_manager.initiate_transfer(
1670
                                         if let Err(e) = transfer_manager.initiate_transfer(
1576
                                             direction,
1671
                                             direction,
1577
                                             cursor_pos,
1672
                                             cursor_pos,
1578
-                                            screen_height,
1673
+                                            screen_min_x,
1579
-                                            screen_width,
1674
+                                            screen_min_y,
1675
+                                            screen_max_x,
1676
+                                            screen_max_y,
1580
                                             true, // keyboard-initiated (IPC Move from keybind)
1677
                                             true, // keyboard-initiated (IPC Move from keybind)
1581
                                         ).await {
1678
                                         ).await {
1582
                                             IpcResponse::Error { message: format!("Transfer failed: {}", e) }
1679
                                             IpcResponse::Error { message: format!("Transfer failed: {}", e) }
@@ -1598,8 +1695,10 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
1598
                                     if let Err(e) = transfer_manager.initiate_transfer(
1695
                                     if let Err(e) = transfer_manager.initiate_transfer(
1599
                                         direction,
1696
                                         direction,
1600
                                         cursor_pos,
1697
                                         cursor_pos,
1601
-                                        screen_height,
1698
+                                        screen_min_x,
1602
-                                        screen_width,
1699
+                                        screen_min_y,
1700
+                                        screen_max_x,
1701
+                                        screen_max_y,
1603
                                         true, // keyboard-initiated (IPC Move from keybind)
1702
                                         true, // keyboard-initiated (IPC Move from keybind)
1604
                                     ).await {
1703
                                     ).await {
1605
                                         IpcResponse::Error { message: format!("Transfer failed: {}", e) }
1704
                                         IpcResponse::Error { message: format!("Transfer failed: {}", e) }
@@ -1778,24 +1877,14 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
1778
                                 if peers_guard.get(&dir).is_some() {
1877
                                 if peers_guard.get(&dir).is_some() {
1779
                                     drop(peers_guard);
1878
                                     drop(peers_guard);
1780
 
1879
 
1781
-                                    // Get cursor position and screen size from Hyprland
1880
+                                    // Get cursor position (use center of total screen)
1782
-                                    let (cursor_pos, screen_width, screen_height) = match hypr_client.monitors().await {
1881
+                                    let cursor_pos = hypr_client.cursor_pos().await
1783
-                                        Ok(monitors) => {
1882
+                                        .map(|c| (c.x, c.y))
1784
-                                            if let Some(focused) = monitors.iter().find(|m| m.focused) {
1883
+                                        .unwrap_or(((screen_min_x + screen_max_x) / 2, (screen_min_y + screen_max_y) / 2));
1785
-                                                // Use center of screen as cursor position for switch
1786
-                                                let cx = focused.x + focused.width as i32 / 2;
1787
-                                                let cy = focused.y + focused.height as i32 / 2;
1788
-                                                ((cx, cy), focused.width, focused.height)
1789
-                                            } else {
1790
-                                                ((0, 0), 1920, 1080) // Fallback
1791
-                                            }
1792
-                                        }
1793
-                                        Err(_) => ((0, 0), 1920, 1080), // Fallback
1794
-                                    };
1795
 
1884
 
1796
                                     // Initiate transfer (CLI-initiated, not keyboard)
1885
                                     // Initiate transfer (CLI-initiated, not keyboard)
1797
                                     info!("IPC Switch: calling initiate_transfer");
1886
                                     info!("IPC Switch: calling initiate_transfer");
1798
-                                    match transfer_manager.initiate_transfer(dir, cursor_pos, screen_height, screen_width, false).await {
1887
+                                    match transfer_manager.initiate_transfer(dir, cursor_pos, screen_min_x, screen_min_y, screen_max_x, screen_max_y, false).await {
1799
                                         Ok(()) => {
1888
                                         Ok(()) => {
1800
                                             let machine_name = config.machines.neighbors
1889
                                             let machine_name = config.machines.neighbors
1801
                                                 .iter()
1890
                                                 .iter()
@@ -1928,11 +2017,12 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
1928
 
2017
 
1929
                                     match conn_result {
2018
                                     match conn_result {
1930
                                         Ok(mut conn) => {
2019
                                         Ok(mut conn) => {
1931
-                                            // Send Hello
2020
+                                            // Send Hello with direction for peer sync
1932
                                             let hello = Message::Hello(HelloPayload {
2021
                                             let hello = Message::Hello(HelloPayload {
1933
                                                 protocol_version: PROTOCOL_VERSION,
2022
                                                 protocol_version: PROTOCOL_VERSION,
1934
                                                 machine_name,
2023
                                                 machine_name,
1935
                                                 capabilities: vec![],
2024
                                                 capabilities: vec![],
2025
+                                                my_direction_for_you: Some(direction),
1936
                                             });
2026
                                             });
1937
                                             if let Err(e) = conn.send(&hello).await {
2027
                                             if let Err(e) = conn.send(&hello).await {
1938
                                                 tracing::error!("Reconnect: failed to send Hello: {}", e);
2028
                                                 tracing::error!("Reconnect: failed to send Hello: {}", e);
@@ -2013,6 +2103,27 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
2013
                                     needs_restart = true;
2103
                                     needs_restart = true;
2014
                                 }
2104
                                 }
2015
 
2105
 
2106
+                                // Check for direction changes (requires restart for edge barriers)
2107
+                                for new_neighbor in &new_config.machines.neighbors {
2108
+                                    if let Some(old_neighbor) = config.machines.neighbors
2109
+                                        .iter()
2110
+                                        .find(|n| n.name == new_neighbor.name)
2111
+                                    {
2112
+                                        if old_neighbor.direction != new_neighbor.direction {
2113
+                                            changes.push(format!(
2114
+                                                "neighbor '{}' direction: {:?} -> {:?} (requires restart)",
2115
+                                                new_neighbor.name, old_neighbor.direction, new_neighbor.direction
2116
+                                            ));
2117
+                                            needs_restart = true;
2118
+                                        }
2119
+                                    }
2120
+                                }
2121
+
2122
+                                // Apply the new config (only if no restart needed)
2123
+                                if !needs_restart {
2124
+                                    config = new_config;
2125
+                                }
2126
+
2016
                                 if changes.is_empty() {
2127
                                 if changes.is_empty() {
2017
                                     IpcResponse::Ok {
2128
                                     IpcResponse::Ok {
2018
                                         message: "Config unchanged".to_string(),
2129
                                         message: "Config unchanged".to_string(),
@@ -2020,7 +2131,7 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
2020
                                 } else if needs_restart {
2131
                                 } else if needs_restart {
2021
                                     IpcResponse::Ok {
2132
                                     IpcResponse::Ok {
2022
                                         message: format!(
2133
                                         message: format!(
2023
-                                            "Config changes detected (restart required):\n  - {}",
2134
+                                            "Config saved (restart required to apply):\n  - {}",
2024
                                             changes.join("\n  - ")
2135
                                             changes.join("\n  - ")
2025
                                         ),
2136
                                         ),
2026
                                     }
2137
                                     }
@@ -2105,6 +2216,16 @@ async fn run_daemon(config_path: &std::path::Path) -> anyhow::Result<()> {
2105
                 let _ = response_tx.send(response);
2216
                 let _ = response_tx.send(response);
2106
             }
2217
             }
2107
 
2218
 
2219
+            // Handle restart signal from direction change
2220
+            Some(reason) = restart_rx.recv() => {
2221
+                info!("Restart required: {}", reason);
2222
+                info!("Exiting to allow restart with updated config...");
2223
+                accept_handle.abort();
2224
+                // Exit with code 75 (EX_TEMPFAIL) to signal that we need to restart
2225
+                // This allows systemd or the GUI to restart us
2226
+                std::process::exit(75);
2227
+            }
2228
+
2108
             // Shutdown (Ctrl+C or IPC request)
2229
             // Shutdown (Ctrl+C or IPC request)
2109
             _ = tokio::signal::ctrl_c() => {
2230
             _ = tokio::signal::ctrl_c() => {
2110
                 info!("Shutting down (Ctrl+C)...");
2231
                 info!("Shutting down (Ctrl+C)...");
hyprkvm-daemon/src/network/peer.rsmodified
@@ -43,6 +43,7 @@ impl Peer {
43
             protocol_version: PROTOCOL_VERSION,
43
             protocol_version: PROTOCOL_VERSION,
44
             machine_name: our_name.to_string(),
44
             machine_name: our_name.to_string(),
45
             capabilities: our_capabilities.to_vec(),
45
             capabilities: our_capabilities.to_vec(),
46
+            my_direction_for_you: None, // Direction not known in this context
46
         });
47
         });
47
 
48
 
48
         conn.send(&hello).await?;
49
         conn.send(&hello).await?;
hyprkvm-daemon/src/transfer/manager.rsmodified
@@ -116,8 +116,10 @@ impl TransferManager {
116
         &self,
116
         &self,
117
         direction: Direction,
117
         direction: Direction,
118
         cursor_pos: (i32, i32),
118
         cursor_pos: (i32, i32),
119
-        screen_height: u32,
119
+        screen_min_x: i32,
120
-        screen_width: u32,
120
+        screen_min_y: i32,
121
+        screen_max_x: i32,
122
+        screen_max_y: i32,
121
         keyboard_initiated: bool,
123
         keyboard_initiated: bool,
122
     ) -> Result<(), TransferError> {
124
     ) -> Result<(), TransferError> {
123
         let mut state = self.state.write().await;
125
         let mut state = self.state.write().await;
@@ -137,15 +139,20 @@ impl TransferManager {
137
 
139
 
138
         let transfer_id = self.next_transfer_id();
140
         let transfer_id = self.next_transfer_id();
139
 
141
 
140
-        // Calculate edge-relative cursor position
142
+        // Calculate edge-relative cursor position (0.0-1.0 along the edge)
143
+        let screen_width = (screen_max_x - screen_min_x) as f64;
144
+        let screen_height = (screen_max_y - screen_min_y) as f64;
145
+
141
         let edge_relative = match direction {
146
         let edge_relative = match direction {
142
             Direction::Left | Direction::Right => {
147
             Direction::Left | Direction::Right => {
143
-                cursor_pos.1 as f64 / screen_height as f64
148
+                // Y position relative to screen height
149
+                (cursor_pos.1 - screen_min_y) as f64 / screen_height
144
             }
150
             }
145
             Direction::Up | Direction::Down => {
151
             Direction::Up | Direction::Down => {
146
-                cursor_pos.0 as f64 / screen_width as f64
152
+                // X position relative to screen width
153
+                (cursor_pos.0 - screen_min_x) as f64 / screen_width
147
             }
154
             }
148
-        };
155
+        }.clamp(0.0, 1.0); // Ensure within valid range
149
 
156
 
150
         tracing::info!(
157
         tracing::info!(
151
             "Initiating transfer to {:?}, transfer_id={}",
158
             "Initiating transfer to {:?}, transfer_id={}",
@@ -250,8 +257,10 @@ impl TransferManager {
250
         &self,
257
         &self,
251
         from_direction: Direction,
258
         from_direction: Direction,
252
         payload: EnterPayload,
259
         payload: EnterPayload,
253
-        screen_width: u32,
260
+        screen_min_x: i32,
254
-        screen_height: u32,
261
+        screen_min_y: i32,
262
+        screen_max_x: i32,
263
+        screen_max_y: i32,
255
     ) -> Result<(i32, i32), TransferError> {
264
     ) -> Result<(i32, i32), TransferError> {
256
         let mut state = self.state.write().await;
265
         let mut state = self.state.write().await;
257
 
266
 
@@ -276,29 +285,34 @@ impl TransferManager {
276
             }
285
             }
277
         }
286
         }
278
 
287
 
279
-        // Calculate actual cursor position
288
+        // Calculate actual cursor position using proper screen bounds
289
+        let screen_width = (screen_max_x - screen_min_x) as f64;
290
+        let screen_height = (screen_max_y - screen_min_y) as f64;
291
+
280
         let cursor_pos = match payload.cursor_pos {
292
         let cursor_pos = match payload.cursor_pos {
281
             CursorEntryPos::EdgeRelative(rel) => {
293
             CursorEntryPos::EdgeRelative(rel) => {
282
-                // Entry is from the perspective of the sender
294
+                // from_direction indicates which edge the cursor enters from
283
-                // So if they say "from_direction = Right", they're to our right
295
+                // e.g., from_direction=Left means cursor enters at our left edge
284
-                // and we should position cursor at our right edge
285
                 match from_direction {
296
                 match from_direction {
286
                     Direction::Left => {
297
                     Direction::Left => {
287
-                        // They're to our left, cursor enters from left edge
298
+                        // Cursor enters from left edge
288
-                        let y = (rel * screen_height as f64) as i32;
299
+                        let y = screen_min_y + (rel * screen_height) as i32;
289
-                        (0, y)
300
+                        (screen_min_x, y)
290
                     }
301
                     }
291
                     Direction::Right => {
302
                     Direction::Right => {
292
-                        let y = (rel * screen_height as f64) as i32;
303
+                        // Cursor enters from right edge
293
-                        (screen_width as i32 - 1, y)
304
+                        let y = screen_min_y + (rel * screen_height) as i32;
305
+                        (screen_max_x - 1, y)
294
                     }
306
                     }
295
                     Direction::Up => {
307
                     Direction::Up => {
296
-                        let x = (rel * screen_width as f64) as i32;
308
+                        // Cursor enters from top edge
297
-                        (x, 0)
309
+                        let x = screen_min_x + (rel * screen_width) as i32;
310
+                        (x, screen_min_y)
298
                     }
311
                     }
299
                     Direction::Down => {
312
                     Direction::Down => {
300
-                        let x = (rel * screen_width as f64) as i32;
313
+                        // Cursor enters from bottom edge
301
-                        (x, screen_height as i32 - 1)
314
+                        let x = screen_min_x + (rel * screen_width) as i32;
315
+                        (x, screen_max_y - 1)
302
                     }
316
                     }
303
                 }
317
                 }
304
             }
318
             }