Desktop notification when a render or Render all ends while unfocused (notify-rust; Tim t1025u)
@@ -629,6 +629,12 @@ version = "1.2.0"
629
629
source = "registry+https://github.com/rust-lang/crates.io-index"
630
630
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
631
631
632
[[package]]
633
name = "deranged"
634
version = "0.5.9"
635
source = "registry+https://github.com/rust-lang/crates.io-index"
636
checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e"
637
632
638
[[package]]
633
639
name = "dispatch"
634
640
version = "0.2.0"
@@ -1242,7 +1248,7 @@ dependencies = [
1242
1248
"presser",
1243
1249
"thiserror 1.0.69",
1244
1250
"winapi",
1245
"windows",
1251
"windows 0.52.0",
1246
1252
]
1247
1253
1248
1254
[[package]]
@@ -1623,6 +1629,20 @@ version = "0.4.35"
1623
1629
source = "registry+https://github.com/rust-lang/crates.io-index"
1624
1630
checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c"
1625
1631
1632
[[package]]
1633
name = "mac-notification-sys"
1634
version = "0.6.15"
1635
source = "registry+https://github.com/rust-lang/crates.io-index"
1636
checksum = "fd604973958ddcc11b561193c0fb96ba146506ef2f231ef2e7c35fd2cbc9beca"
1637
dependencies = [
1638
"cc",
1639
"log",
1640
"objc2 0.6.5",
1641
"objc2-foundation 0.3.2",
1642
"time",
1643
"uuid",
1644
]
1645
1626
1646
[[package]]
1627
1647
name = "malloc_buf"
1628
1648
version = "0.0.6"
@@ -1767,6 +1787,26 @@ version = "0.2.0"
1767
1787
source = "registry+https://github.com/rust-lang/crates.io-index"
1768
1788
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
1769
1789
1790
[[package]]
1791
name = "notify-rust"
1792
version = "4.18.2"
1793
source = "registry+https://github.com/rust-lang/crates.io-index"
1794
checksum = "4587364a9a0074333429b3df75a30a205340c56a536ca3eb6ca0e59b87bbf8af"
1795
dependencies = [
1796
"futures-lite",
1797
"log",
1798
"mac-notification-sys",
1799
"serde",
1800
"tauri-winrt-notification",
1801
"zbus",
1802
]
1803
1804
[[package]]
1805
name = "num-conv"
1806
version = "0.2.2"
1807
source = "registry+https://github.com/rust-lang/crates.io-index"
1808
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
1809
1770
1810
[[package]]
1771
1811
name = "num-traits"
1772
1812
version = "0.2.19"
@@ -1972,6 +2012,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1972
2012
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
1973
2013
dependencies = [
1974
2014
"bitflags 2.13.2",
2015
"block2 0.6.2",
2016
"libc",
1975
2017
"objc2 0.6.5",
1976
2018
"objc2-core-foundation",
1977
2019
]
@@ -2123,6 +2165,7 @@ dependencies = [
2123
2165
"glow 0.14.2",
2124
2166
"gltf",
2125
2167
"libloading",
2168
"notify-rust",
2126
2169
"png",
2127
2170
"rfd",
2128
2171
"serde",
@@ -2265,6 +2308,12 @@ dependencies = [
2265
2308
"zerovec",
2266
2309
]
2267
2310
2311
[[package]]
2312
name = "powerfmt"
2313
version = "0.2.1"
2314
source = "registry+https://github.com/rust-lang/crates.io-index"
2315
checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958"
2316
2268
2317
[[package]]
2269
2318
name = "ppv-lite86"
2270
2319
version = "0.2.21"
@@ -2771,6 +2820,17 @@ dependencies = [
2771
2820
"syn 3.0.9",
2772
2821
]
2773
2822
2823
[[package]]
2824
name = "tauri-winrt-notification"
2825
version = "0.8.1"
2826
source = "registry+https://github.com/rust-lang/crates.io-index"
2827
checksum = "f37a6c354fd28fc9e322ed9bd47e3959576dad28c9d58ea1cf888cce1c7ccb36"
2828
dependencies = [
2829
"thiserror 2.0.21",
2830
"windows 0.62.2",
2831
"windows-version",
2832
]
2833
2774
2834
[[package]]
2775
2835
name = "tempfile"
2776
2836
version = "3.27.0"
@@ -2833,6 +2893,25 @@ dependencies = [
2833
2893
"syn 3.0.9",
2834
2894
]
2835
2895
2896
[[package]]
2897
name = "time"
2898
version = "0.3.55"
2899
source = "registry+https://github.com/rust-lang/crates.io-index"
2900
checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"
2901
dependencies = [
2902
"deranged",
2903
"num-conv",
2904
"powerfmt",
2905
"serde_core",
2906
"time-core",
2907
]
2908
2909
[[package]]
2910
name = "time-core"
2911
version = "0.1.9"
2912
source = "registry+https://github.com/rust-lang/crates.io-index"
2913
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
2914
2836
2915
[[package]]
2837
2916
name = "tinystr"
2838
2917
version = "0.8.5"
@@ -3043,6 +3122,7 @@ version = "1.29.0"
3043
3122
source = "registry+https://github.com/rust-lang/crates.io-index"
3044
3123
checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514"
3045
3124
dependencies = [
3125
"getrandom 0.4.3",
3046
3126
"js-sys",
3047
3127
"serde_core",
3048
3128
"wasm-bindgen",
@@ -3443,10 +3523,31 @@ version = "0.52.0"
3443
3523
source = "registry+https://github.com/rust-lang/crates.io-index"
3444
3524
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
3445
3525
dependencies = [
3446
"windows-core",
3526
"windows-core 0.52.0",
3447
3527
"windows-targets",
3448
3528
]
3449
3529
3530
[[package]]
3531
name = "windows"
3532
version = "0.62.2"
3533
source = "registry+https://github.com/rust-lang/crates.io-index"
3534
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
3535
dependencies = [
3536
"windows-collections",
3537
"windows-core 0.62.2",
3538
"windows-future",
3539
"windows-numerics",
3540
]
3541
3542
[[package]]
3543
name = "windows-collections"
3544
version = "0.3.2"
3545
source = "registry+https://github.com/rust-lang/crates.io-index"
3546
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
3547
dependencies = [
3548
"windows-core 0.62.2",
3549
]
3550
3450
3551
[[package]]
3451
3552
name = "windows-core"
3452
3553
version = "0.52.0"
@@ -3456,12 +3557,86 @@ dependencies = [
3456
3557
"windows-targets",
3457
3558
]
3458
3559
3560
[[package]]
3561
name = "windows-core"
3562
version = "0.62.2"
3563
source = "registry+https://github.com/rust-lang/crates.io-index"
3564
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
3565
dependencies = [
3566
"windows-implement",
3567
"windows-interface",
3568
"windows-link",
3569
"windows-result",
3570
"windows-strings",
3571
]
3572
3573
[[package]]
3574
name = "windows-future"
3575
version = "0.3.2"
3576
source = "registry+https://github.com/rust-lang/crates.io-index"
3577
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
3578
dependencies = [
3579
"windows-core 0.62.2",
3580
"windows-link",
3581
"windows-threading",
3582
]
3583
3584
[[package]]
3585
name = "windows-implement"
3586
version = "0.60.2"
3587
source = "registry+https://github.com/rust-lang/crates.io-index"
3588
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
3589
dependencies = [
3590
"proc-macro2",
3591
"quote",
3592
"syn 2.0.119",
3593
]
3594
3595
[[package]]
3596
name = "windows-interface"
3597
version = "0.59.3"
3598
source = "registry+https://github.com/rust-lang/crates.io-index"
3599
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
3600
dependencies = [
3601
"proc-macro2",
3602
"quote",
3603
"syn 2.0.119",
3604
]
3605
3459
3606
[[package]]
3460
3607
name = "windows-link"
3461
3608
version = "0.2.1"
3462
3609
source = "registry+https://github.com/rust-lang/crates.io-index"
3463
3610
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
3464
3611
3612
[[package]]
3613
name = "windows-numerics"
3614
version = "0.3.1"
3615
source = "registry+https://github.com/rust-lang/crates.io-index"
3616
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
3617
dependencies = [
3618
"windows-core 0.62.2",
3619
"windows-link",
3620
]
3621
3622
[[package]]
3623
name = "windows-result"
3624
version = "0.4.1"
3625
source = "registry+https://github.com/rust-lang/crates.io-index"
3626
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
3627
dependencies = [
3628
"windows-link",
3629
]
3630
3631
[[package]]
3632
name = "windows-strings"
3633
version = "0.5.1"
3634
source = "registry+https://github.com/rust-lang/crates.io-index"
3635
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
3636
dependencies = [
3637
"windows-link",
3638
]
3639
3465
3640
[[package]]
3466
3641
name = "windows-sys"
3467
3642
version = "0.52.0"
@@ -3505,6 +3680,24 @@ dependencies = [
3505
3680
"windows_x86_64_msvc",
3506
3681
]
3507
3682
3683
[[package]]
3684
name = "windows-threading"
3685
version = "0.2.1"
3686
source = "registry+https://github.com/rust-lang/crates.io-index"
3687
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
3688
dependencies = [
3689
"windows-link",
3690
]
3691
3692
[[package]]
3693
name = "windows-version"
3694
version = "0.1.7"
3695
source = "registry+https://github.com/rust-lang/crates.io-index"
3696
checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631"
3697
dependencies = [
3698
"windows-link",
3699
]
3700
3508
3701
[[package]]
3509
3702
name = "windows_aarch64_gnullvm"
3510
3703
version = "0.52.6"
@@ -629,6 +629,12 @@ version = "1.2.0"629
source = "registry+https://github.com/rust-lang/crates.io-index"629
source = "registry+https://github.com/rust-lang/crates.io-index"630
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"630
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"631
631
632
[[package]]633
name = "deranged"634
version = "0.5.9"635
source = "registry+https://github.com/rust-lang/crates.io-index"636
checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e"637
632
[[package]]638
[[package]]633
name = "dispatch"639
name = "dispatch"634
version = "0.2.0"640
version = "0.2.0"@@ -1242,7 +1248,7 @@ dependencies = [1242
"presser",1248
"presser",1243
"thiserror 1.0.69",1249
"thiserror 1.0.69",1244
"winapi",1250
"winapi",1245
"windows",1251
"windows 0.52.0",1246
]1252
]1247
1253
1248
[[package]]1254
[[package]]@@ -1623,6 +1629,20 @@ version = "0.4.35"1623
source = "registry+https://github.com/rust-lang/crates.io-index"1629
source = "registry+https://github.com/rust-lang/crates.io-index"1624
checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c"1630
checksum = "5d15f86d12da44cd8d4ec3c73984537eb7f4cadcb9776a575a0a8a05ca11005c"1625
1631
1632
[[package]]1633
name = "mac-notification-sys"1634
version = "0.6.15"1635
source = "registry+https://github.com/rust-lang/crates.io-index"1636
checksum = "fd604973958ddcc11b561193c0fb96ba146506ef2f231ef2e7c35fd2cbc9beca"1637
dependencies = [1638
"cc",1639
"log",1640
"objc2 0.6.5",1641
"objc2-foundation 0.3.2",1642
"time",1643
"uuid",1644
]1645
1626
[[package]]1646
[[package]]1627
name = "malloc_buf"1647
name = "malloc_buf"1628
version = "0.0.6"1648
version = "0.0.6"@@ -1767,6 +1787,26 @@ version = "0.2.0"1767
source = "registry+https://github.com/rust-lang/crates.io-index"1787
source = "registry+https://github.com/rust-lang/crates.io-index"1768
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"1788
checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"1769
1789
1790
[[package]]1791
name = "notify-rust"1792
version = "4.18.2"1793
source = "registry+https://github.com/rust-lang/crates.io-index"1794
checksum = "4587364a9a0074333429b3df75a30a205340c56a536ca3eb6ca0e59b87bbf8af"1795
dependencies = [1796
"futures-lite",1797
"log",1798
"mac-notification-sys",1799
"serde",1800
"tauri-winrt-notification",1801
"zbus",1802
]1803
1804
[[package]]1805
name = "num-conv"1806
version = "0.2.2"1807
source = "registry+https://github.com/rust-lang/crates.io-index"1808
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"1809
1770
[[package]]1810
[[package]]1771
name = "num-traits"1811
name = "num-traits"1772
version = "0.2.19"1812
version = "0.2.19"@@ -1972,6 +2012,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"1972
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"2012
checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"1973
dependencies = [2013
dependencies = [1974
"bitflags 2.13.2",2014
"bitflags 2.13.2",2015
"block2 0.6.2",2016
"libc",1975
"objc2 0.6.5",2017
"objc2 0.6.5",1976
"objc2-core-foundation",2018
"objc2-core-foundation",1977
]2019
]@@ -2123,6 +2165,7 @@ dependencies = [2123
"glow 0.14.2",2165
"glow 0.14.2",2124
"gltf",2166
"gltf",2125
"libloading",2167
"libloading",2168
"notify-rust",2126
"png",2169
"png",2127
"rfd",2170
"rfd",2128
"serde",2171
"serde",@@ -2265,6 +2308,12 @@ dependencies = [2265
"zerovec",2308
"zerovec",2266
]2309
]2267
2310
2311
[[package]]2312
name = "powerfmt"2313
version = "0.2.1"2314
source = "registry+https://github.com/rust-lang/crates.io-index"2315
checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958"2316
2268
[[package]]2317
[[package]]2269
name = "ppv-lite86"2318
name = "ppv-lite86"2270
version = "0.2.21"2319
version = "0.2.21"@@ -2771,6 +2820,17 @@ dependencies = [2771
"syn 3.0.9",2820
"syn 3.0.9",2772
]2821
]2773
2822
2823
[[package]]2824
name = "tauri-winrt-notification"2825
version = "0.8.1"2826
source = "registry+https://github.com/rust-lang/crates.io-index"2827
checksum = "f37a6c354fd28fc9e322ed9bd47e3959576dad28c9d58ea1cf888cce1c7ccb36"2828
dependencies = [2829
"thiserror 2.0.21",2830
"windows 0.62.2",2831
"windows-version",2832
]2833
2774
[[package]]2834
[[package]]2775
name = "tempfile"2835
name = "tempfile"2776
version = "3.27.0"2836
version = "3.27.0"@@ -2833,6 +2893,25 @@ dependencies = [2833
"syn 3.0.9",2893
"syn 3.0.9",2834
]2894
]2835
2895
2896
[[package]]2897
name = "time"2898
version = "0.3.55"2899
source = "registry+https://github.com/rust-lang/crates.io-index"2900
checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"2901
dependencies = [2902
"deranged",2903
"num-conv",2904
"powerfmt",2905
"serde_core",2906
"time-core",2907
]2908
2909
[[package]]2910
name = "time-core"2911
version = "0.1.9"2912
source = "registry+https://github.com/rust-lang/crates.io-index"2913
checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"2914
2836
[[package]]2915
[[package]]2837
name = "tinystr"2916
name = "tinystr"2838
version = "0.8.5"2917
version = "0.8.5"@@ -3043,6 +3122,7 @@ version = "1.29.0"3043
source = "registry+https://github.com/rust-lang/crates.io-index"3122
source = "registry+https://github.com/rust-lang/crates.io-index"3044
checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514"3123
checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514"3045
dependencies = [3124
dependencies = [3125
"getrandom 0.4.3",3046
"js-sys",3126
"js-sys",3047
"serde_core",3127
"serde_core",3048
"wasm-bindgen",3128
"wasm-bindgen",@@ -3443,10 +3523,31 @@ version = "0.52.0"3443
source = "registry+https://github.com/rust-lang/crates.io-index"3523
source = "registry+https://github.com/rust-lang/crates.io-index"3444
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"3524
checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"3445
dependencies = [3525
dependencies = [3446
"windows-core",3526
"windows-core 0.52.0",3447
"windows-targets",3527
"windows-targets",3448
]3528
]3449
3529
3530
[[package]]3531
name = "windows"3532
version = "0.62.2"3533
source = "registry+https://github.com/rust-lang/crates.io-index"3534
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"3535
dependencies = [3536
"windows-collections",3537
"windows-core 0.62.2",3538
"windows-future",3539
"windows-numerics",3540
]3541
3542
[[package]]3543
name = "windows-collections"3544
version = "0.3.2"3545
source = "registry+https://github.com/rust-lang/crates.io-index"3546
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"3547
dependencies = [3548
"windows-core 0.62.2",3549
]3550
3450
[[package]]3551
[[package]]3451
name = "windows-core"3552
name = "windows-core"3452
version = "0.52.0"3553
version = "0.52.0"@@ -3456,12 +3557,86 @@ dependencies = [3456
"windows-targets",3557
"windows-targets",3457
]3558
]3458
3559
3560
[[package]]3561
name = "windows-core"3562
version = "0.62.2"3563
source = "registry+https://github.com/rust-lang/crates.io-index"3564
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"3565
dependencies = [3566
"windows-implement",3567
"windows-interface",3568
"windows-link",3569
"windows-result",3570
"windows-strings",3571
]3572
3573
[[package]]3574
name = "windows-future"3575
version = "0.3.2"3576
source = "registry+https://github.com/rust-lang/crates.io-index"3577
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"3578
dependencies = [3579
"windows-core 0.62.2",3580
"windows-link",3581
"windows-threading",3582
]3583
3584
[[package]]3585
name = "windows-implement"3586
version = "0.60.2"3587
source = "registry+https://github.com/rust-lang/crates.io-index"3588
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"3589
dependencies = [3590
"proc-macro2",3591
"quote",3592
"syn 2.0.119",3593
]3594
3595
[[package]]3596
name = "windows-interface"3597
version = "0.59.3"3598
source = "registry+https://github.com/rust-lang/crates.io-index"3599
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"3600
dependencies = [3601
"proc-macro2",3602
"quote",3603
"syn 2.0.119",3604
]3605
3459
[[package]]3606
[[package]]3460
name = "windows-link"3607
name = "windows-link"3461
version = "0.2.1"3608
version = "0.2.1"3462
source = "registry+https://github.com/rust-lang/crates.io-index"3609
source = "registry+https://github.com/rust-lang/crates.io-index"3463
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"3610
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"3464
3611
3612
[[package]]3613
name = "windows-numerics"3614
version = "0.3.1"3615
source = "registry+https://github.com/rust-lang/crates.io-index"3616
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"3617
dependencies = [3618
"windows-core 0.62.2",3619
"windows-link",3620
]3621
3622
[[package]]3623
name = "windows-result"3624
version = "0.4.1"3625
source = "registry+https://github.com/rust-lang/crates.io-index"3626
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"3627
dependencies = [3628
"windows-link",3629
]3630
3631
[[package]]3632
name = "windows-strings"3633
version = "0.5.1"3634
source = "registry+https://github.com/rust-lang/crates.io-index"3635
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"3636
dependencies = [3637
"windows-link",3638
]3639
3465
[[package]]3640
[[package]]3466
name = "windows-sys"3641
name = "windows-sys"3467
version = "0.52.0"3642
version = "0.52.0"@@ -3505,6 +3680,24 @@ dependencies = [3505
"windows_x86_64_msvc",3680
"windows_x86_64_msvc",3506
]3681
]3507
3682
3683
[[package]]3684
name = "windows-threading"3685
version = "0.2.1"3686
source = "registry+https://github.com/rust-lang/crates.io-index"3687
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"3688
dependencies = [3689
"windows-link",3690
]3691
3692
[[package]]3693
name = "windows-version"3694
version = "0.1.7"3695
source = "registry+https://github.com/rust-lang/crates.io-index"3696
checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631"3697
dependencies = [3698
"windows-link",3699
]3700
3508
[[package]]3701
[[package]]3509
name = "windows_aarch64_gnullvm"3702
name = "windows_aarch64_gnullvm"3510
version = "0.52.6"3703
version = "0.52.6"@@ -12,6 +12,7 @@ egui_glow = "0.29.1"
12
12
glow = "0.14.2"
13
13
gltf = { version = "1.4.1", default-features = false, features = ["import", "names", "utils", "KHR_texture_transform", "KHR_materials_specular"] }
14
14
libloading = "0.8"
15
notify-rust = { version = "4.18.2", default-features = false, features = ["z"] }
15
16
png = "0.18"
16
17
rfd = "0.15.4"
17
18
serde = { version = "1", features = ["derive"] }
@@ -12,6 +12,7 @@ egui_glow = "0.29.1"12
glow = "0.14.2"12
glow = "0.14.2"13
gltf = { version = "1.4.1", default-features = false, features = ["import", "names", "utils", "KHR_texture_transform", "KHR_materials_specular"] }13
gltf = { version = "1.4.1", default-features = false, features = ["import", "names", "utils", "KHR_texture_transform", "KHR_materials_specular"] }14
libloading = "0.8"14
libloading = "0.8"15
notify-rust = { version = "4.18.2", default-features = false, features = ["z"] }15
png = "0.18"16
png = "0.18"16
rfd = "0.15.4"17
rfd = "0.15.4"17
serde = { version = "1", features = ["derive"] }18
serde = { version = "1", features = ["derive"] }@@ -107,6 +107,10 @@ All clips from the source file are used. glTF interpolation is kept: LINEAR (lin
107
107
108
108
**Render all** in the Body screen renders the whole project in one queue: first the male and female body (if set), then every equipment preset for each sex it is valid for. Each item gets the full export (all clips × frames × 60 angles, four maps, atlases + `.ppda`) into its own `renders/<sex>-<settype>-atlas/`. Progress shows *item k/n* plus the normal pass count; **Cancel render** stops the queue (the running item stays resumable, the rest is marked *not started*). If an item has a matching interrupted run, it is resumed instead of restarted. Items that cannot run (no body, equipment not configured or without parts, invalid settings) are skipped with a reason and the queue continues. During Render all the live pass preview in the Body screen stays visible and follows the item currently rendering, as with a single render. Afterwards a summary lists what was rendered, skipped, failed or not started.
109
109
110
### Notification when a render ends
111
112
When a single render or **Render all** ends (finished, failed or cancelled) while the app window does not have focus, the app shows one desktop notification with the same status line as the window (one for the whole Render all queue, not one per item). On Linux this is a freedesktop notification (D-Bus) with the app icon and the `paperdoll-renderer` desktop entry; on Windows it is a toast. Without a notification service nothing is shown and the render is not affected.
113
110
114
The body button renders only the body; **Render equipment · all angles** in the equipment editor renders the selected preset, animated on the chosen body but **without body occlusion or body pixels**. The fixed camera of that sex stays the same, also if you zoomed freely in the live preview.
111
115
112
116
Per image **only four target-res PNGs** are stored: `diffuse`, `normal`, `depth`, `specular`. Diffuse is **unlit albedo** (base color factor × texture × vertex color, alpha kept), never baked lighting/shadow/gloss. Depth is linear within a fixed depth range per sex, centered on the orbit point: `near/far = 10 m ∓ total/2`. By default the total is the T-pose arm span plus one arm length of margin on each side (arm = upper arm→hand bone distance × 1.2, span = shoulder width + 2 arms, independent of the bind pose; without recognizable arm/hand bones: span = max(width, height) and arm = 0.4·span). In the body screen, below the render frame, **Depth range** is *automatic* or a custom total in meters (`depth_range_milli` per sex in the `.ppd`), with the resulting near/far. All clips, frames, angles and equipment of that sex share the same range.
@@ -107,6 +107,10 @@ All clips from the source file are used. glTF interpolation is kept: LINEAR (lin107
107
108
**Render all** in the Body screen renders the whole project in one queue: first the male and female body (if set), then every equipment preset for each sex it is valid for. Each item gets the full export (all clips × frames × 60 angles, four maps, atlases + `.ppda`) into its own `renders/<sex>-<settype>-atlas/`. Progress shows *item k/n* plus the normal pass count; **Cancel render** stops the queue (the running item stays resumable, the rest is marked *not started*). If an item has a matching interrupted run, it is resumed instead of restarted. Items that cannot run (no body, equipment not configured or without parts, invalid settings) are skipped with a reason and the queue continues. During Render all the live pass preview in the Body screen stays visible and follows the item currently rendering, as with a single render. Afterwards a summary lists what was rendered, skipped, failed or not started.108
**Render all** in the Body screen renders the whole project in one queue: first the male and female body (if set), then every equipment preset for each sex it is valid for. Each item gets the full export (all clips × frames × 60 angles, four maps, atlases + `.ppda`) into its own `renders/<sex>-<settype>-atlas/`. Progress shows *item k/n* plus the normal pass count; **Cancel render** stops the queue (the running item stays resumable, the rest is marked *not started*). If an item has a matching interrupted run, it is resumed instead of restarted. Items that cannot run (no body, equipment not configured or without parts, invalid settings) are skipped with a reason and the queue continues. During Render all the live pass preview in the Body screen stays visible and follows the item currently rendering, as with a single render. Afterwards a summary lists what was rendered, skipped, failed or not started.109
109
110
### Notification when a render ends111
112
When a single render or **Render all** ends (finished, failed or cancelled) while the app window does not have focus, the app shows one desktop notification with the same status line as the window (one for the whole Render all queue, not one per item). On Linux this is a freedesktop notification (D-Bus) with the app icon and the `paperdoll-renderer` desktop entry; on Windows it is a toast. Without a notification service nothing is shown and the render is not affected.113
110
The body button renders only the body; **Render equipment · all angles** in the equipment editor renders the selected preset, animated on the chosen body but **without body occlusion or body pixels**. The fixed camera of that sex stays the same, also if you zoomed freely in the live preview.114
The body button renders only the body; **Render equipment · all angles** in the equipment editor renders the selected preset, animated on the chosen body but **without body occlusion or body pixels**. The fixed camera of that sex stays the same, also if you zoomed freely in the live preview.111
115
112
Per image **only four target-res PNGs** are stored: `diffuse`, `normal`, `depth`, `specular`. Diffuse is **unlit albedo** (base color factor × texture × vertex color, alpha kept), never baked lighting/shadow/gloss. Depth is linear within a fixed depth range per sex, centered on the orbit point: `near/far = 10 m ∓ total/2`. By default the total is the T-pose arm span plus one arm length of margin on each side (arm = upper arm→hand bone distance × 1.2, span = shoulder width + 2 arms, independent of the bind pose; without recognizable arm/hand bones: span = max(width, height) and arm = 0.4·span). In the body screen, below the render frame, **Depth range** is *automatic* or a custom total in meters (`depth_range_milli` per sex in the `.ppd`), with the resulting near/far. All clips, frames, angles and equipment of that sex share the same range.116
Per image **only four target-res PNGs** are stored: `diffuse`, `normal`, `depth`, `specular`. Diffuse is **unlit albedo** (base color factor × texture × vertex color, alpha kept), never baked lighting/shadow/gloss. Depth is linear within a fixed depth range per sex, centered on the orbit point: `near/far = 10 m ∓ total/2`. By default the total is the T-pose arm span plus one arm length of margin on each side (arm = upper arm→hand bone distance × 1.2, span = shoulder width + 2 arms, independent of the bind pose; without recognizable arm/hand bones: span = max(width, height) and arm = 0.4·span). In the body screen, below the render frame, **Depth range** is *automatic* or a custom total in meters (`depth_range_milli` per sex in the `.ppd`), with the resulting near/far. All clips, frames, angles and equipment of that sex share the same range.@@ -68,6 +68,8 @@ pub struct EditorApp {
68
68
resume_scan_error: Option<String>,
69
69
render_all: Option<RenderAll>,
70
70
render_all_summary: Option<RenderAllSummary>,
71
window_focused: bool,
72
last_toast: Option<crate::notify::Toast>,
71
73
}
72
74
73
75
/// One queued item of **Render alles**: a body (0 = male, 1 = female) with
@@ -160,6 +162,8 @@ impl EditorApp {
160
162
resume_scan_error: None,
161
163
render_all: None,
162
164
render_all_summary: None,
165
window_focused: true,
166
last_toast: None,
163
167
}
164
168
}
165
169
@@ -866,6 +870,20 @@ impl EditorApp {
866
870
self.session.notice = summary.text();
867
871
self.session.notice_ok = summary.failed.is_empty() && !summary.cancelled;
868
872
self.render_all_summary = Some(summary);
873
self.notify_render_end();
874
}
875
/// One desktop notification per finished run when the window is unfocused.
876
fn notify_render_end(&mut self) {
877
let outcome = crate::notify::RenderOutcome::Done {
878
ok: self.session.notice_ok,
879
text: self.session.notice.clone(),
880
};
881
if let Some(toast) = crate::notify::toast_for(&outcome, self.window_focused) {
882
self.last_toast = Some(toast.clone());
883
if !cfg!(test) {
884
crate::notify::show(toast);
885
}
886
}
869
887
}
870
888
fn render_all_ui(&mut self, ui: &mut egui::Ui) {
871
889
if let Some(state) = &self.render_all {
@@ -1043,9 +1061,12 @@ impl EditorApp {
1043
1061
self.render_worker = None;
1044
1062
if self.render_all.is_some() {
1045
1063
self.render_all_item_done();
1046
} else if self.render_ui.saved.is_none() && self.render_ui.error.is_none() {
1047
// Cancelled: offer the run for resumption right away.
1048
self.scan_resumable_runs();
1064
} else {
1065
if self.render_ui.saved.is_none() && self.render_ui.error.is_none() {
1066
// Cancelled: offer the run for resumption right away.
1067
self.scan_resumable_runs();
1068
}
1069
self.notify_render_end();
1049
1070
}
1050
1071
} else if ended {
1051
1072
self.render_ui.apply(RenderEvent::Failed(
@@ -1327,6 +1348,7 @@ impl eframe::App for EditorApp {
1327
1348
{
1328
1349
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);
1329
1350
}
1351
self.window_focused = ctx.input(|i| i.focused);
1330
1352
self.poll_dialogs();
1331
1353
self.drain_render();
1332
1354
if self.render_ui.running
@@ -2847,6 +2869,24 @@ mod tests {
2847
2869
let _ = std::fs::remove_dir_all(root);
2848
2870
}
2849
2871
2872
#[test]
2873
fn render_all_end_toasts_once_only_when_unfocused() {
2874
let root = root();
2875
let opened = crate::session::create_seeded_project(&root).unwrap();
2876
let mut app = EditorApp::default();
2877
app.open_path(opened.manifest_path.clone());
2878
app.window_focused = true;
2879
app.start_render_all();
2880
pump(&mut app);
2881
assert!(app.last_toast.is_none(), "focused: no toast");
2882
app.window_focused = false;
2883
app.start_render_all();
2884
pump(&mut app);
2885
let toast = app.last_toast.clone().expect("unfocused: toast");
2886
assert!(toast.body.contains(" 2 "), "{toast:?}");
2887
let _ = std::fs::remove_dir_all(root);
2888
}
2889
2850
2890
#[test]
2851
2891
fn depth_format_and_range_settings_reach_job_and_persist() {
2852
2892
let root = root();
@@ -68,6 +68,8 @@ pub struct EditorApp {68
resume_scan_error: Option<String>,68
resume_scan_error: Option<String>,69
render_all: Option<RenderAll>,69
render_all: Option<RenderAll>,70
render_all_summary: Option<RenderAllSummary>,70
render_all_summary: Option<RenderAllSummary>,71
window_focused: bool,72
last_toast: Option<crate::notify::Toast>,71
}73
}72
74
73
/// One queued item of **Render alles**: a body (0 = male, 1 = female) with75
/// One queued item of **Render alles**: a body (0 = male, 1 = female) with@@ -160,6 +162,8 @@ impl EditorApp {160
resume_scan_error: None,162
resume_scan_error: None,161
render_all: None,163
render_all: None,162
render_all_summary: None,164
render_all_summary: None,165
window_focused: true,166
last_toast: None,163
}167
}164
}168
}165
169
@@ -866,6 +870,20 @@ impl EditorApp {866
self.session.notice = summary.text();870
self.session.notice = summary.text();867
self.session.notice_ok = summary.failed.is_empty() && !summary.cancelled;871
self.session.notice_ok = summary.failed.is_empty() && !summary.cancelled;868
self.render_all_summary = Some(summary);872
self.render_all_summary = Some(summary);873
self.notify_render_end();874
}875
/// One desktop notification per finished run when the window is unfocused.876
fn notify_render_end(&mut self) {877
let outcome = crate::notify::RenderOutcome::Done {878
ok: self.session.notice_ok,879
text: self.session.notice.clone(),880
};881
if let Some(toast) = crate::notify::toast_for(&outcome, self.window_focused) {882
self.last_toast = Some(toast.clone());883
if !cfg!(test) {884
crate::notify::show(toast);885
}886
}869
}887
}870
fn render_all_ui(&mut self, ui: &mut egui::Ui) {888
fn render_all_ui(&mut self, ui: &mut egui::Ui) {871
if let Some(state) = &self.render_all {889
if let Some(state) = &self.render_all {@@ -1043,9 +1061,12 @@ impl EditorApp {1043
self.render_worker = None;1061
self.render_worker = None;1044
if self.render_all.is_some() {1062
if self.render_all.is_some() {1045
self.render_all_item_done();1063
self.render_all_item_done();1046
} else if self.render_ui.saved.is_none() && self.render_ui.error.is_none() {1064
} else {1047
// Cancelled: offer the run for resumption right away.1065
if self.render_ui.saved.is_none() && self.render_ui.error.is_none() {1048
self.scan_resumable_runs();1066
// Cancelled: offer the run for resumption right away.1067
self.scan_resumable_runs();1068
}1069
self.notify_render_end();1049
}1070
}1050
} else if ended {1071
} else if ended {1051
self.render_ui.apply(RenderEvent::Failed(1072
self.render_ui.apply(RenderEvent::Failed(@@ -1327,6 +1348,7 @@ impl eframe::App for EditorApp {1327
{1348
{1328
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);1349
ctx.send_viewport_cmd(egui::ViewportCommand::CancelClose);1329
}1350
}1351
self.window_focused = ctx.input(|i| i.focused);1330
self.poll_dialogs();1352
self.poll_dialogs();1331
self.drain_render();1353
self.drain_render();1332
if self.render_ui.running1354
if self.render_ui.running@@ -2847,6 +2869,24 @@ mod tests {2847
let _ = std::fs::remove_dir_all(root);2869
let _ = std::fs::remove_dir_all(root);2848
}2870
}2849
2871
2872
#[test]2873
fn render_all_end_toasts_once_only_when_unfocused() {2874
let root = root();2875
let opened = crate::session::create_seeded_project(&root).unwrap();2876
let mut app = EditorApp::default();2877
app.open_path(opened.manifest_path.clone());2878
app.window_focused = true;2879
app.start_render_all();2880
pump(&mut app);2881
assert!(app.last_toast.is_none(), "focused: no toast");2882
app.window_focused = false;2883
app.start_render_all();2884
pump(&mut app);2885
let toast = app.last_toast.clone().expect("unfocused: toast");2886
assert!(toast.body.contains(" 2 "), "{toast:?}");2887
let _ = std::fs::remove_dir_all(root);2888
}2889
2850
#[test]2890
#[test]2851
fn depth_format_and_range_settings_reach_job_and_persist() {2891
fn depth_format_and_range_settings_reach_job_and_persist() {2852
let root = root();2892
let root = root();@@ -160,6 +160,8 @@ pub const TABLE: &[(&str, &str)] = &[
160
160
("{} · {} · {} van {} PNG's vastgelegd", "{} · {} · {} of {} PNGs recorded"),
161
161
("Glow-context ontbreekt", "Glow context missing"),
162
162
("Batch opgeslagen: {path}", "Batch saved: {path}"),
163
("Render klaar", "Render finished"),
164
("Render niet gelukt", "Render did not succeed"),
163
165
("De renderworker stopte zonder eindresultaat.", "The render worker stopped without a final result."),
164
166
("Annuleer render", "Cancel render"),
165
167
("Vaste renderhoogte (m)", "Fixed render height (m)"),
@@ -160,6 +160,8 @@ pub const TABLE: &[(&str, &str)] = &[160
("{} · {} · {} van {} PNG's vastgelegd", "{} · {} · {} of {} PNGs recorded"),160
("{} · {} · {} van {} PNG's vastgelegd", "{} · {} · {} of {} PNGs recorded"),161
("Glow-context ontbreekt", "Glow context missing"),161
("Glow-context ontbreekt", "Glow context missing"),162
("Batch opgeslagen: {path}", "Batch saved: {path}"),162
("Batch opgeslagen: {path}", "Batch saved: {path}"),163
("Render klaar", "Render finished"),164
("Render niet gelukt", "Render did not succeed"),163
("De renderworker stopte zonder eindresultaat.", "The render worker stopped without a final result."),165
("De renderworker stopte zonder eindresultaat.", "The render worker stopped without a final result."),164
("Annuleer render", "Cancel render"),166
("Annuleer render", "Cancel render"),165
("Vaste renderhoogte (m)", "Fixed render height (m)"),167
("Vaste renderhoogte (m)", "Fixed render height (m)"),@@ -26,6 +26,7 @@ pub mod i18n;
26
26
pub mod i18n_table;
27
27
pub mod icon;
28
28
pub mod import;
29
pub mod notify;
29
30
pub mod preview;
30
31
pub mod preview2d;
31
32
pub mod preview_gl;
@@ -26,6 +26,7 @@ pub mod i18n;26
pub mod i18n_table;26
pub mod i18n_table;27
pub mod icon;27
pub mod icon;28
pub mod import;28
pub mod import;29
pub mod notify;29
pub mod preview;30
pub mod preview;30
pub mod preview2d;31
pub mod preview2d;31
pub mod preview_gl;32
pub mod preview_gl;@@ -0,0 +1,85 @@
1
//! Desktop notification when a render ends while the window is unfocused
2
//! (Tim t1025u). Freedesktop notifications on Linux/BSD, a toast on Windows.
3
4
/// How a single render or the Render Alles queue ended.
5
#[derive(Clone, Debug, PartialEq, Eq)]
6
pub enum RenderOutcome {
7
/// One render (or the whole Render Alles queue) finished; `text` is the
8
/// status line also shown in the window.
9
Done { ok: bool, text: String },
10
}
11
12
/// The toast to show, if any.
13
#[derive(Clone, Debug, PartialEq, Eq)]
14
pub struct Toast {
15
pub summary: String,
16
pub body: String,
17
}
18
19
/// Decide whether to notify: only when the window is not focused.
20
pub fn toast_for(outcome: &RenderOutcome, window_focused: bool) -> Option<Toast> {
21
if window_focused {
22
return None;
23
}
24
let RenderOutcome::Done { ok, text } = outcome;
25
let summary = if *ok {
26
crate::i18n::t("Render klaar")
27
} else {
28
crate::i18n::t("Render niet gelukt")
29
};
30
Some(Toast {
31
summary,
32
body: crate::i18n::t(text),
33
})
34
}
35
36
/// Show the toast on a short-lived thread; delivery errors are ignored.
37
pub fn show(toast: Toast) {
38
let _ = std::thread::Builder::new()
39
.name("render-notification".into())
40
.spawn(move || {
41
let mut n = notify_rust::Notification::new();
42
n.summary(&["Paperdoll Renderer", &toast.summary].join(": "))
43
.body(&toast.body)
44
.appname("Paperdoll Renderer");
45
#[cfg(all(unix, not(target_os = "macos")))]
46
{
47
n.icon(crate::icon::APP_ID)
48
.hint(notify_rust::Hint::DesktopEntry(crate::icon::APP_ID.into()));
49
}
50
let _ = n.show();
51
});
52
}
53
54
#[cfg(test)]
55
mod tests {
56
use super::*;
57
58
#[test]
59
fn focused_window_gets_no_toast() {
60
let o = RenderOutcome::Done {
61
ok: true,
62
text: "Batch opgeslagen: x".into(),
63
};
64
assert_eq!(toast_for(&o, true), None);
65
}
66
67
#[test]
68
fn unfocused_window_gets_one_toast_with_status() {
69
let o = RenderOutcome::Done {
70
ok: true,
71
text: "Batch opgeslagen: /p/out".into(),
72
};
73
let t = toast_for(&o, false).unwrap();
74
assert!(t.body.contains("/p/out"));
75
let f = toast_for(
76
&RenderOutcome::Done {
77
ok: false,
78
text: "boom".into(),
79
},
80
false,
81
)
82
.unwrap();
83
assert_ne!(t.summary, f.summary);
84
}
85
}
@@ -0,0 +1,85 @@1
//! Desktop notification when a render ends while the window is unfocused2
//! (Tim t1025u). Freedesktop notifications on Linux/BSD, a toast on Windows.3
4
/// How a single render or the Render Alles queue ended.5
#[derive(Clone, Debug, PartialEq, Eq)]6
pub enum RenderOutcome {7
/// One render (or the whole Render Alles queue) finished; `text` is the8
/// status line also shown in the window.9
Done { ok: bool, text: String },10
}11
12
/// The toast to show, if any.13
#[derive(Clone, Debug, PartialEq, Eq)]14
pub struct Toast {15
pub summary: String,16
pub body: String,17
}18
19
/// Decide whether to notify: only when the window is not focused.20
pub fn toast_for(outcome: &RenderOutcome, window_focused: bool) -> Option<Toast> {21
if window_focused {22
return None;23
}24
let RenderOutcome::Done { ok, text } = outcome;25
let summary = if *ok {26
crate::i18n::t("Render klaar")27
} else {28
crate::i18n::t("Render niet gelukt")29
};30
Some(Toast {31
summary,32
body: crate::i18n::t(text),33
})34
}35
36
/// Show the toast on a short-lived thread; delivery errors are ignored.37
pub fn show(toast: Toast) {38
let _ = std::thread::Builder::new()39
.name("render-notification".into())40
.spawn(move || {41
let mut n = notify_rust::Notification::new();42
n.summary(&["Paperdoll Renderer", &toast.summary].join(": "))43
.body(&toast.body)44
.appname("Paperdoll Renderer");45
#[cfg(all(unix, not(target_os = "macos")))]46
{47
n.icon(crate::icon::APP_ID)48
.hint(notify_rust::Hint::DesktopEntry(crate::icon::APP_ID.into()));49
}50
let _ = n.show();51
});52
}53
54
#[cfg(test)]55
mod tests {56
use super::*;57
58
#[test]59
fn focused_window_gets_no_toast() {60
let o = RenderOutcome::Done {61
ok: true,62
text: "Batch opgeslagen: x".into(),63
};64
assert_eq!(toast_for(&o, true), None);65
}66
67
#[test]68
fn unfocused_window_gets_one_toast_with_status() {69
let o = RenderOutcome::Done {70
ok: true,71
text: "Batch opgeslagen: /p/out".into(),72
};73
let t = toast_for(&o, false).unwrap();74
assert!(t.body.contains("/p/out"));75
let f = toast_for(76
&RenderOutcome::Done {77
ok: false,78
text: "boom".into(),79
},80
false,81
)82
.unwrap();83
assert_ne!(t.summary, f.summary);84
}85
}