210 Commits

Author SHA1 Message Date
Nova
bf89b73e8f feat: version bump 2023-07-22 18:31:09 -04:00
Nova
2e252279bb fix: states 2023-07-19 06:04:15 -07:00
Nova
9cf43ec535 fix: surface not mapping 2023-07-19 06:04:08 -07:00
Nova
f15578f7df feat: formatting 2023-07-19 06:03:28 -07:00
Nova
f63ca4a25b feat: play space 2023-07-16 10:42:35 -07:00
technobaboo
89741508e3 feat: make readme more readable 2023-07-11 11:44:38 -07:00
technobaboo
81be807749 fix(ci): add semicolons 2023-07-11 11:16:15 -07:00
technobaboo
fcdb8a7edf fix(ci): appimagetool 2023-07-11 11:11:07 -07:00
technobaboo
90ce185f29 fix(ci): xcb glx 2023-07-11 10:59:26 -07:00
technobaboo
d6353035ae fix(ci): ninja-build instead of ninja 2023-07-11 10:55:08 -07:00
technobaboo
ceb1b23264 feat: ci take 2 2023-07-11 10:53:31 -07:00
Nova
199e6f70b3 refactor: use dmabuf v4 instead of bind_display 2023-06-27 05:53:45 -04:00
Nova
641db4face refactor: disable shader injection 2023-06-26 20:49:21 -04:00
Nova
80d292b511 feat: match stereokit to log level 2023-06-26 20:43:02 -04:00
Nova
7fbcc92d02 fix: unwrap in main fn 2023-06-26 20:33:04 -04:00
Nova
de46726d01 feat: hardware accelerated wayland apps 2023-06-26 20:31:38 -04:00
Nova
6efa3a909e feat: proper dmabuf import 2023-06-26 20:09:20 -04:00
Nova
ea0f174da7 feat: shaders!! working!! 2023-06-26 19:49:10 -04:00
Nova
444146fa21 feat: it borken 2023-06-26 04:37:38 -04:00
Nova
a7930760e8 feat: glsl simula text shaders 2023-06-25 10:05:18 -04:00
Nova
668c32f583 fix: ctrl+c in tty 2023-06-21 01:47:10 -04:00
Nova
927e1c48e2 fix: mouse pointer keyboard ray direction 2023-06-14 23:00:17 -04:00
Nova
8cc20e054c feat: version bump 2023-06-11 01:37:21 -04:00
Nova
b12b171b53 feat: spatial bounds 2023-06-11 00:38:05 -04:00
Nova
0e61d51072 feat(input): custom pointers 2023-05-31 08:50:15 -04:00
Nova
e61c04960e fix(node): better send remote signal 2023-05-31 08:48:59 -04:00
Nova
5dc82be1a3 fix(pointer): proper direction 2023-05-31 08:48:24 -04:00
Nova
6861b92972 fix(main): make eye pointer not work in flatscreen 2023-05-31 08:47:16 -04:00
Nova
f68f350cd2 fix(scenegraph): recurse through aliases 2023-05-31 08:47:02 -04:00
Nova
2820415373 feat: readd dmabufs 2023-05-30 02:20:27 -04:00
Nova
f721a57604 fix: janky dmabuf hack 2023-05-27 09:48:34 -04:00
Nova
fb4149eaa7 feat: eye gaze support 2023-05-23 18:56:46 -04:00
matthewcroughan
d3746ef787 ci: print flatland revision for gnome-graphical-test in Discord message 2023-05-20 11:08:43 +01:00
matthewcroughan
9d4b4bee4d github: remove workflows
Since Hercules CI is in use now, GitHub Actions are not necessarily required
2023-05-20 11:08:43 +01:00
matthewcroughan
5390b0effb flake: add hercules-ci
This commit also adds a HCI Effect for posting to Discord the result of the gnome-graphical-test on every single commit
2023-05-20 11:08:43 +01:00
matthewcroughan
13da4c8d60 nix: add graphical-gnome-test
This VM integration test spawns Gnome, monado-service,
stardust-xr-server, flatland and weston-cliptest and tests that the
functionality works correctly. The result is a screenshot. If any
program in the test produces an exit code above 0 it will fail the test,
graphical rendering bugs should be visible in the resulting screenshot
2023-05-20 11:08:43 +01:00
matthewcroughan
1740d55f9c flake.lock: Update
Flake lock file updates:

• Updated input 'fenix':
    'github:nix-community/fenix/3a0b59a2ea946a533c62ac417596835779087f0e' (2023-04-20)
  → 'github:nix-community/fenix/5816c7bbcc385d2e65877631497df3f7d66b354a' (2023-05-11)
• Updated input 'fenix/rust-analyzer-src':
    'github:rust-lang/rust-analyzer/2400b36a2ed40f68a26473f69ac208ba10d98af9' (2023-04-19)
  → 'github:rust-lang/rust-analyzer/b7cdd93f3e1533e96d4cfa1ac8573e6210a2bedf' (2023-05-09)
• Added input 'flatland':
    'github:StardustXR/flatland/24613a496841bdf38e5f136608d5295860a75fce' (2023-05-11)
• Added input 'flatland/fenix':
    'github:nix-community/fenix/ee59e1c769657b1e27e608f8b981fa8f6b715583' (2023-03-14)
• Added input 'flatland/fenix/nixpkgs':
    follows 'flatland/nixpkgs'
• Added input 'flatland/fenix/rust-analyzer-src':
    'github:rust-lang/rust-analyzer/95497533524537b1cc7a2870ce94b0b14503be8b' (2023-03-13)
• Added input 'flatland/nixpkgs':
    'github:NixOS/nixpkgs/67f26c1cfc5d5783628231e776a81c1ade623e0b' (2023-03-13)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/da45bf6ec7bbcc5d1e14d3795c025199f28e0de0' (2023-04-30)
  → 'github:NixOS/nixpkgs/897876e4c484f1e8f92009fd11b7d988a121a4e7' (2023-05-06)
2023-05-20 11:08:43 +01:00
matthewcroughan
52d5e97de6 flake: filter nix code and README out of src
This means that changing the Nix code doesn't cause the Rust code to need to be recompiled when using nix build
2023-05-20 11:08:43 +01:00
Nova
633df045d4 feat: appimage support!! 2023-05-19 18:12:22 -04:00
Nova
415bf5bb04 feat: clean up main function 2023-05-19 18:11:52 -04:00
Nova
4e2d4a15c9 feat: flat wayland display env var 2023-05-18 06:00:53 -04:00
Nova
ef0142183d fix: better pointer compare distance algorithm 2023-05-10 23:44:36 -04:00
Nova
e5dfd9d3df fix(model): copy on create to make unique 2023-05-10 23:44:23 -04:00
Nova
6773fe2cf3 feat: instant model loading 2023-05-10 20:10:31 -04:00
Nova
5a6e7e02ca fix(wayland): stop crash 2023-05-10 19:14:57 -04:00
Nova
c5d8ec2ef1 fix: remove dbg statement 2023-05-10 19:02:09 -04:00
Nova
a31781146e fix: upgrade smithay 2023-05-10 16:51:39 -04:00
Nova
cb9368cb8e fix: model nodes 2023-05-10 16:49:56 -04:00
Nova
629c05e507 feat: model nodes 2023-05-10 08:38:21 -04:00
Matthew Croughan
9123153bf3 fix: nix flake smithay lock issues
* flake: use allowBuiltInFetchGit to prevent narHash reproducibility issues

using the builtin fetcher allows fetching git dependencies with only the ref and without storing the narHash for the fixed-output-derivation

* gitignore: add nix result symlinks
2023-05-06 17:37:46 +00:00
Nova
f3dc632ffc feat: order inputs 2023-05-02 21:58:53 -04:00
Astavie
c369100d8a fix: nix overlay
* nix flake

* workflow

* remove flake-utils

* update flake

* fix

* remove cargo hash

* fix overlay
2023-05-01 23:29:34 +00:00
Astavie
e10d40ef5e fix: nix flake
* nix flake

* workflow

* remove flake-utils

* update flake

* fix

* remove cargo hash
2023-05-01 21:56:49 +00:00
Nova King
d6ca367187 feat: FUNDING.yml 2023-05-01 17:31:03 +00:00
Nova
88ac8a8b86 better panel item startup settings order 2023-05-01 12:59:49 -04:00
Nova
70fef89e2d fix: launch env vars to launch as much stuff in wayland as possible 2023-05-01 00:05:00 -04:00
Nova
4d79a59b20 fix(objects/hand): hand enabled when controller not 2023-04-30 18:28:40 -04:00
Nova
c776c1b712 feat: new stereokit 2023-04-30 13:25:13 -04:00
Saphira Kai
d4de15e0b3 remove broken Debug derivation for XdgSurfaceData 2023-04-24 13:12:44 -03:00
Nova
9d220ec235 feat(startup): get environment 2023-04-24 09:53:20 -04:00
Nova
09c6c010e2 feat: cargo lock update 2023-04-24 08:31:28 -04:00
Nova
c9e185e9f3 feat: dependency updates 2023-04-24 08:31:07 -04:00
Nova
4737149c85 feat(wayland): popups, more compatibility, more stability
get_parent


grab


popups

fix head thingy


popup list


feat: remove set_active

feat(wayland): commit_popup

feat(wayland): cleanup


moar changess


actually fix the problem with everything oh my god


proper popup state


fix: multi thread event loop


fix: match popup surface ID


make wayland input system go over surfaces instead of toplevels


feat: massive refactor of all wayland things
2023-04-24 06:30:39 -04:00
Nova
648451b47e fix: mouse pointer 2023-04-23 09:34:43 -04:00
Nova
a9ef2d6f4b feat: custom startup script 2023-04-23 09:34:43 -04:00
Astavie
d6ffcadd76 fix: nix flake
* nix flake

* workflow

* remove flake-utils

* update flake
2023-04-20 10:35:50 +00:00
Nova
448b7489e8 feat: desktop file 2023-03-25 03:06:50 -04:00
Nova
622cf60a65 feat: upgrade stereokit-rs 2023-03-23 14:12:48 -04:00
Astavie
1ab11f1660 feat: nix support & github workflow
* nix flake

* workflow

* remove flake-utils
2023-03-14 19:35:40 +00:00
Nova
9654e6cc59 fix: unignore cargo.lock 2023-03-13 13:44:12 -07:00
Nova
44d177858f fix(input/hand): correct serialization transform matrix order 2023-03-08 01:45:03 -05:00
Nova
be41f11b83 feat(input): new system 2023-02-25 16:39:30 -05:00
Nova
dd2bffc2b1 refactor(input): make all inputs have nodes 2023-02-24 11:43:06 -05:00
Nova
d2ef508607 feat: update everything, clean dependencies 2023-02-23 08:41:40 -05:00
Nova
0cc7c7bc24 refactor(model): remove shader use 2023-02-23 07:17:36 -05:00
Nova
8d65e304cb fix(model): make default pbr shader clip 2023-02-20 18:03:02 -05:00
Nova
b0dbccbd18 fix(items): proper drop 2023-02-20 10:24:59 -05:00
Nova
a823fbfb57 fix(mouse pointer): keyboard 2023-02-18 02:06:17 -05:00
Nova
4a864e6519 fix(cargo.toml): upgrade stereokit 2023-02-17 13:10:23 -05:00
Nova
e23d847449 fix(mouse pointer): proper pointer transform 2023-02-17 13:10:08 -05:00
Nova
8ba199f053 fix: order of operations on wayland material properties 2023-02-16 14:03:13 -05:00
Nova
23925b4475 fix(item): send acceptors to new item ui 2023-02-16 14:02:43 -05:00
Nova
7ea0220f33 fix: update stereokit 2023-02-16 14:02:21 -05:00
Nova
969e4de882 feat: disabled/enabled 2023-02-16 00:30:25 -05:00
Nova
e5acb3013f fix: node aspect drawable 2023-02-09 03:58:56 -05:00
Nova
3d57bed1c0 refactor: node aspect drawable 2023-02-08 21:06:24 -05:00
Nova
45839ebf60 fix: cargo fmt 2023-02-07 18:04:20 -05:00
Nova
0bb5b53e02 fix(dev profile): optimization level 0 2023-02-07 16:15:37 -05:00
Nova
4f966b6d71 feat(model): pbr clip shader 2023-02-07 16:15:20 -05:00
awtterpip
2687a393b5 fixed bug where sound wasn't stoppable 2023-02-07 10:34:10 -06:00
awtterpip
5c605932ef gave audio interface proper name 2023-02-07 09:13:55 -06:00
piper
bccdc8221e feat: audio! 2023-02-04 20:39:08 -05:00
Nova
bddf17bbef fix(stereokit): version 2023-02-04 20:38:10 -05:00
Nova
e8511e8759 refactor(cargo.toml): profile optimizations 2023-02-02 16:32:43 -05:00
Nova
85296f538b feat(spatial): fields_distance, normal, closest_point 2023-02-01 19:21:35 -05:00
Nova
f8ff80b781 fix(items): make acceptor fields non-optional 2023-01-28 11:12:51 -05:00
Nova
932fef87f5 refactor: change logic_step to frame event 2023-01-26 09:08:40 -05:00
Nova
742780e34e refactor: remove many unwrap calls 2023-01-25 11:50:53 -05:00
Nova
41ede661f7 feat(material): auto copy on change parameter 2023-01-25 09:23:01 -05:00
Nova
8d85460803 feat: make event loop multithreaded 2023-01-25 09:17:52 -05:00
Nova
ac71581db8 fix(spatial): moving object relative to itself 2023-01-25 05:40:37 -05:00
Nova
2f894c4058 fix(spatial): parse_transform returned result 2023-01-25 05:40:19 -05:00
Nova
2b97c98a6e refactor(wayland): remove SeatData wrapper 2023-01-22 02:38:40 -05:00
Nova
98d9f491ba fix(wayland): update pointer scroll 2023-01-22 02:30:12 -05:00
Nova
16d710e106 fix(panel_item): allow surfaces with size of 0,0 2023-01-22 00:58:25 -05:00
Nova
9ad202e778 refactor(spatial): get/set parent methods 2023-01-22 00:42:04 -05:00
Nova
b3747d623c fix(spatial): reference space can be self 2023-01-22 00:24:38 -05:00
Nova
d5ff9281e6 feat: update/clean dependencies 2023-01-22 00:24:13 -05:00
Nova
18ebd8c522 feat: input multiplexing 2023-01-21 18:07:25 -05:00
Nova
411f71c217 feat: startup script 2023-01-17 18:51:46 -05:00
Nova
3027ae20a9 feat(spatial): keep track of children 2023-01-16 11:17:12 -05:00
Nova
fbce321426 refactor(main): make arrays tuples 2023-01-16 11:03:46 -05:00
Nova
74bc3a306e feat: update stereokit to have fancy tracing 2023-01-15 04:23:26 -05:00
Nova
a950ad59f1 fix(input): grab issues 2023-01-15 04:04:09 -05:00
Nova
cf840da444 feat(stereokit): log filtering 2023-01-15 04:03:21 -05:00
Nova
173fba35fa feat: even more tracing 2023-01-15 01:13:22 -05:00
Nova
97fbbec0fe feat: adaptive sleep delay 2023-01-14 23:48:49 -05:00
Nova
400f3a23bf feat: spatial tracing 2023-01-14 22:59:00 -05:00
Nova
1ad3336b6f feat: span tracing!!! 2023-01-14 22:32:41 -05:00
Nova
8e9956abe1 refactor(input): more compact registry contains 2023-01-14 20:29:33 -05:00
Nova
6ca93ea24c fix(event loop, client): better async 2023-01-14 12:38:05 -05:00
Nova
49810e8fd1 refactor(cargo.toml): remove unneeded deps and features 2023-01-14 11:17:52 -05:00
Nova
afd0946558 fix(input): reduce latency by several frames 2023-01-14 11:03:47 -05:00
Nova
fd31d0cd99 feat(tokio): profiling 2023-01-14 10:38:39 -05:00
Nova
2f380da62f refactor(wayland): remove commented out code\ 2023-01-07 10:15:56 -05:00
Nova
1c6971cd11 feat(model): use resource ID for texture 2023-01-06 09:05:30 -05:00
Nova
da4cf084d2 fix: remove stereokit patch 2023-01-05 21:49:03 -05:00
Nova
ca95ed5461 feat(model): set material parameter 2023-01-05 21:46:25 -05:00
Nova
1b06cb6952 fix(drawable/lines): properly make cyclic point 2023-01-05 08:28:29 -05:00
Nova
df89c826bb fix: remove opt level 3 for dev 2023-01-05 07:59:20 -05:00
Nova
21f7f66440 feat: update stereokit 2023-01-04 23:51:48 -05:00
Nova
3f1bad18c8 feat(wayland/surface): geometry resizing, unused 2023-01-04 21:36:55 -05:00
Nova
0c190cc833 feat(delta): mark_changed 2023-01-04 21:36:25 -05:00
Nova
5f0df8e7c1 fix(wayland): SSD all the things 2023-01-04 08:26:10 -05:00
Nova
d715f2f9ed fix(wayland): toplevel states bytemucked to u8 2023-01-04 08:25:54 -05:00
Nova
d7fa4e62b8 feat(wayland): proper surface geometry 2023-01-04 07:25:33 -05:00
Nova
568ebb0060 feat(wayland): serial counter 2023-01-04 07:25:22 -05:00
Nova
42efc67625 feat(delta): const 2023-01-04 07:23:23 -05:00
Nova
dd4b0097a1 feat(wayland): set toplevel capabilities 2023-01-03 10:08:39 -05:00
Nova
a483cdbc7d feat(wayland): recommended_state 2023-01-02 18:53:58 -05:00
Nova
84a7546442 refactor(wayland): remove xdg output manager 2023-01-02 03:49:29 -05:00
Nova
dd43f238ff refactor(wayland): comment out xdg activation protocol 2023-01-02 03:43:50 -05:00
Nova
4f057358c8 fix(wayland): drop panel item correctly 2023-01-01 14:37:11 -05:00
Nova
e20971aef7 feat(wayland): switch pointer focus dynamically 2023-01-01 14:36:46 -05:00
Nova
eb0d3c5bcf fix(wayland): set seat cursor 2023-01-01 14:34:18 -05:00
Nova
a18222e3df fix(wayland): xdg surface size when not set 2023-01-01 14:33:07 -05:00
Nova
93ca932da9 feat(wayland/xdg_shell): set surface states None 2022-12-26 11:15:37 -05:00
Nova
c512b2fef5 feat(wayland): make state fields optional 2022-12-26 08:22:09 -05:00
Nova
f53c684377 fix(wayland): panel item configure toplevel 2022-12-25 16:19:22 -05:00
Nova
3552166207 feat(wayland): configure and commit for toplevel] 2022-12-25 16:01:23 -05:00
Nova
0b6eb147c5 feat(input): allow scaling input handlers 2022-12-21 05:34:34 -05:00
Nova
1833ed50f3 feat: update stardust-xr 2022-12-17 02:29:32 -05:00
Nova
6cdbfb3bad refactor(data): identical values for mask 2022-12-17 02:28:06 -05:00
Nova
a5e0cb19c9 refactor(startup): auto acceptor on item add to 2022-12-10 10:26:26 -05:00
Nova
519ab94312 refactor(startup): generate startup token 2022-12-10 09:46:47 -05:00
Nova
f2a8c0ed13 refactor(startup): rename to STARTUP_SETTINGS 2022-12-10 09:27:37 -05:00
Nova
b3998f315d feat(startup): automatic acceptors 2022-12-10 09:18:02 -05:00
Nova
40bcd61b98 feat(startup settings): use /proc/{pid}/environ 2022-12-10 09:17:37 -05:00
Nova
7a4d557c61 fix(wayland): dmabuf formats 2022-12-10 00:30:53 -05:00
Nova
303b3f3ca2 refactor(wayland): remove manual dmabuf importing 2022-12-09 07:04:50 -05:00
Nova
ac5e949614 fix: drain all dmabufs 2022-12-08 05:40:54 -05:00
Nova
60baabb850 feat: optimization level 3 for debug 2022-12-07 14:47:25 -05:00
Nova
248e48fd8e feat(wayland): dmabuf 2022-12-07 14:30:48 -05:00
Nova
b9baee7e5f feat(resources): list of extensions to check 2022-12-05 22:44:04 -05:00
Nova
3598ffdbb1 refactor(sk_hand): use snake case for datamap keys 2022-12-03 17:18:27 -05:00
Nova
c171d9e6db feat: tracing 2022-12-02 20:46:28 -05:00
Nova
d7a607a663 switch to color_eyre instead of anyhow 2022-12-02 13:58:54 -05:00
Nova
03ccf9127d fix(input): O(n log n) instead of O(n^2) 2022-12-02 11:09:23 -05:00
Nova
6a3024657f fix(items): give aliases a proper lifetime 2022-11-30 22:34:16 -05:00
Nova
a0058fcc2e fix(alias): make output optional 2022-11-30 07:04:06 -05:00
Nova
410cc13c4f fix(lines): use sRGB colors 2022-11-28 00:32:41 -05:00
Nova
bc259dbe01 fix(lines): convert f32 to u8 colors correctly 2022-11-26 15:22:23 -05:00
Nova
3730e20248 fix(lines): accept f32 colors 2022-11-26 00:43:04 -05:00
Nova
1be413065d fix: text not working 2022-11-26 00:34:37 -05:00
Nova
2721c20c8b fix(wayland): update smithay version 2022-11-25 23:58:22 -05:00
Nova
80130f6ffd feat(fields): torus field 2022-11-24 18:57:11 -05:00
Nova
8da778eaba refactor(fields): use let else for getting field 2022-11-24 18:56:59 -05:00
Nova
3c708d1aaf feat(drawable): lines 2022-11-21 16:39:28 -05:00
Nova
1ae1bef3c1 refactor(items): move capture to item acceptor 2022-11-20 13:34:15 -05:00
Nova
7fd0c1fddb feat(items): acceptor 2022-11-19 11:25:10 -05:00
Nova
fd9957b784 fix(wayland): cursor material queue higher 2022-11-14 11:53:08 -05:00
Nova
57da02dbad refactor(stereokit): upgrade version 2022-11-14 09:05:36 -05:00
Nova
83a5b36ddc refactor(wayland): make code cleaner 2022-11-12 11:53:11 -05:00
Nova
8c36d73775 fix: upgrade rust version 2022-11-11 13:25:57 -05:00
Nova
8396b98f67 fix(wayland): pointer_motion works when inactive 2022-11-11 13:25:48 -05:00
Nova
46d989ce7f fix(wayland): remove unwraps 2022-11-11 12:52:51 -05:00
Nova
75ac570486 refactor(wayland): s/ObjectId/Weak<WlSurface>/ 2022-11-09 13:05:21 -05:00
Nova
242def9d06 feat: wayland feature 2022-11-09 11:13:07 -05:00
Nova
959f32009b fix(wayland): account for surface data map panic 2022-11-09 11:02:48 -05:00
Nova
57796c217d fix(panel item): set cursor full of snake 2022-11-08 21:16:03 -05:00
Nova
cea3390e36 refactor(items): genericize item acceptors/ui 2022-11-08 20:25:43 -05:00
Nova
a756e80064 fix: make aliased signals snake case 2022-11-08 20:17:15 -05:00
Nova
1f61d32877 refactor: use snake case for method names 2022-11-08 06:10:03 -05:00
Nova
da7e2c5e6e fix(wayland): upgrade smithay version 2022-11-06 16:49:30 -05:00
Nova
fd0940bfe9 feat(objects/input): add keyboard to mouse_pointer 2022-11-05 17:56:52 -04:00
Nova
2b4a495c07 refactor(data): simplify 2022-11-05 17:56:34 -04:00
Nova
cffb968d2e refactor: remove item alias remote_methods 2022-11-05 17:56:09 -04:00
Nova
201ab3aee8 feat(field): ray_march 2022-11-05 17:55:27 -04:00
Nova
cfa3584dda feat(field): expose ray marching to clients 2022-11-01 07:59:49 -04:00
Nova
f19ba93958 refactor(client): use new messenger 2022-10-30 00:14:24 -04:00
Nova
09a2572c3b refactor(node): return Result<&T> from get aspect 2022-10-29 07:32:51 -04:00
Nova
c6316b4e8b feat: terrible hack for moses 2022-10-26 05:19:20 -04:00
Nova
9cd900b23f fix(wayland): remove wayland crate pinning 2022-10-25 16:21:22 -04:00
Nova
a6d30cb366 refactor: use master smithay branch 2022-10-25 16:07:36 -04:00
Nova
3e94a3f62a fix(wayland): set default output size 2022-10-25 12:56:59 -04:00
Nova
060f8264ff fix(data): send "data" to receiver 2022-10-25 07:32:25 -04:00
Nova
b7b3907647 feat: pulse sender/receiver 2022-10-21 06:21:56 -04:00
Nova
1550555df1 fix: clippy 2022-10-21 06:21:49 -04:00
Nova
c42a29a034 feat: zones 2022-10-20 11:32:33 -04:00
Nova King
621bf6b82a Merge pull request #2 from philpax/fix-build
fix: remove path dependency for stereokit
2022-10-19 05:55:53 +00:00
67 changed files with 3269 additions and 4448 deletions

3
.gitignore vendored
View File

@@ -11,5 +11,4 @@
*result* *result*
/libs/ /libs/
*.AppImage *.AppImage
*.blend1

1079
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
[package] [package]
edition = "2021" edition = "2021"
name = "stardust-xr-server" name = "stardust-xr-server"
version = "0.43.0" version = "0.42.1"
authors = ["Nova King <technobaboo@proton.me>"] authors = ["Nova King <technobaboo@proton.me>"]
description = "Stardust XR reference display server" description = "Stardust XR reference display server"
license = "GPLv2" license = "GPLv2"
@@ -15,9 +15,8 @@ path = "src/main.rs"
[features] [features]
default = ["wayland"] default = ["wayland"]
wayland = ["dep:smithay", "dep:xkbcommon"] wayland = ["dep:smithay", "dep:xkbcommon"]
xwayland = ["smithay/xwayland"]
profile_tokio = ["dep:console-subscriber", "tokio/tracing"] profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
profile_app = ["dep:tracing-tracy"] profile_app = ["dep:tracing-chrome"]
[package.metadata.appimage] [package.metadata.appimage]
auto_link = true auto_link = true
@@ -39,6 +38,7 @@ lto = true
[dependencies] [dependencies]
color-eyre = { version = "0.6.2", default-features = false } color-eyre = { version = "0.6.2", default-features = false }
clap = { version = "4.2.4", features = ["derive"] } clap = { version = "4.2.4", features = ["derive"] }
dashmap = "5.4.0"
glam = { version = "0.23.0", features = ["mint"] } glam = { version = "0.23.0", features = ["mint"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"
mint = "0.5.9" mint = "0.5.9"
@@ -47,56 +47,46 @@ once_cell = "1.17.1"
parking_lot = "0.12.1" parking_lot = "0.12.1"
portable-atomic = { version = "1.2.0", features = ["float", "std"] } portable-atomic = { version = "1.2.0", features = ["float", "std"] }
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
tokio = { version = "1.27.0", features = ["rt-multi-thread", "signal", "time"] } tokio = { version = "1.27.0", features = ["rt-multi-thread", "signal"] }
send_wrapper = "0.6.0" send_wrapper = "0.6.0"
prisma = "0.1.1" prisma = "0.1.1"
xkbcommon = { version = "0.5.0", default-features = false, optional = true }
stardust-xr = "0.11.4"
directories = "5.0.0" directories = "5.0.0"
serde = { version = "1.0.160", features = ["derive"] } serde = { version = "1.0.160", features = ["derive"] }
serde_repr = "0.1.16"
tracing = "0.1.37" tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
global_counter = "0.2.2" global_counter = "0.2.2"
rand = "0.8.5" rand = "0.8.5"
atty = "0.2.14" atty = "0.2.14"
xkbcommon = { version = "0.6.0", default-features = false, optional = true }
ctrlc = "3.4.1" [dependencies.stereokit]
libc = "0.2.148" default-features = false
input-event-codes = "5.16.8" features = ["linux-egl"]
drm-fourcc = { version = "2.2.0", features = ["serde"] } version = "0.16.7"
[dependencies.smithay] [dependencies.smithay]
# git = "https://github.com/technobaboo/smithay.git" # Until we get stereokit to understand OES samplers and external textures # git = "https://github.com/technobaboo/smithay.git" # Until we get stereokit to understand OES samplers and external textures
git = "https://github.com/smithay/smithay.git" # Until we get stereokit to understand OES samplers and external textures git = "https://github.com/smithay/smithay.git" # Until we get stereokit to understand OES samplers and external textures
# path = "../smithay" # path = "../smithay"
default-features = false default-features = false
features = [ features = ["desktop", "backend_drm", "renderer_gl", "wayland_frontend"]
"desktop",
"backend_drm",
"backend_egl",
"renderer_gl",
"wayland_frontend",
]
version = "*" version = "*"
optional = true optional = true
[dependencies.stereokit]
default-features = false
features = ["linux-egl"]
version = "0.16.9"
[dependencies.console-subscriber] [dependencies.console-subscriber]
version = "0.1.8" version = "0.1.8"
optional = true optional = true
[dependencies.tracing-tracy] [dependencies.tracing-chrome]
version = "0.10.4" version = "0.7.1"
optional = true optional = true
[dependencies.stardust-xr]
git = "https://github.com/StardustXR/core.git"
branch = "camera-item"
# [patch.crates-io.stereokit] # [patch.crates-io.stereokit]
# path = "../stereokit-rs" # path = "../stereokit-rs"
# [patch.crates-io.stereokit-sys] # [patch.crates-io.stereokit-sys]
# path = "../stereokit-sys" # path = "../stereokit-sys"
# [patch.crates-io.stardust-xr]
# path = "../core/core"
# [patch.crates-io.stardust-xr-schemas]
# path = "../core/schemas"

260
flake.lock generated
View File

@@ -3,11 +3,32 @@
"fenix": { "fenix": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"flatland",
"nixpkgs" "nixpkgs"
], ],
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": {
"lastModified": 1683786056,
"narHash": "sha256-Wrz/X9D0t8akhvEGj5a93xgpxI3vAcdPGcwn6tKHooc=",
"owner": "nix-community",
"repo": "fenix",
"rev": "5816c7bbcc385d2e65877631497df3f7d66b354a",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "fenix",
"type": "github"
}
},
"fenix_2": {
"inputs": {
"nixpkgs": [
"flatland",
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src_2"
},
"locked": { "locked": {
"lastModified": 1678775037, "lastModified": 1678775037,
"narHash": "sha256-chx0tWnXKpcayPkPY3Qh+2hNwptvX8XE3o+fYZ+GNzg=", "narHash": "sha256-chx0tWnXKpcayPkPY3Qh+2hNwptvX8XE3o+fYZ+GNzg=",
@@ -22,34 +43,32 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": { "flake-parts": {
"inputs": { "inputs": {
"nixpkgs-lib": "nixpkgs-lib" "nixpkgs-lib": "nixpkgs-lib"
}, },
"locked": { "locked": {
"lastModified": 1690933134, "lastModified": 1678379998,
"narHash": "sha256-ab989mN63fQZBFrkk4Q8bYxQCktuHmBIBqUG1jl6/FQ=", "narHash": "sha256-TZdfNqftHhDuIFwBcN9MUThx5sQXCTeZk9je5byPKRw=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "59cf3f1447cfc75087e7273b04b31e689a8599fb", "rev": "c13d60b89adea3dc20704c045ec4d50dd964d447",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_2": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_2"
},
"locked": {
"lastModified": 1688466019,
"narHash": "sha256-VeM2akYrBYMsb4W/MmBo1zmaMfgbL4cH3Pu8PGyIwJ0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8e8d955c22df93dbe24f19ea04f47a74adbdc5ec",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -57,7 +76,7 @@
"type": "indirect" "type": "indirect"
} }
}, },
"flake-parts_3": { "flake-parts_2": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"hercules-ci-effects", "hercules-ci-effects",
@@ -66,11 +85,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1688466019, "lastModified": 1678379998,
"narHash": "sha256-VeM2akYrBYMsb4W/MmBo1zmaMfgbL4cH3Pu8PGyIwJ0=", "narHash": "sha256-TZdfNqftHhDuIFwBcN9MUThx5sQXCTeZk9je5byPKRw=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "8e8d955c22df93dbe24f19ea04f47a74adbdc5ec", "rev": "c13d60b89adea3dc20704c045ec4d50dd964d447",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -79,17 +98,32 @@
"type": "github" "type": "github"
} }
}, },
"flake-utils": {
"locked": {
"lastModified": 1667395993,
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flatland": { "flatland": {
"inputs": { "inputs": {
"fenix": "fenix", "fenix": "fenix_2",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1694190588, "lastModified": 1683766358,
"narHash": "sha256-tcvp09A54AbXkkXS/P6Ed5TUWzMEuQ9h/fnfLz7gnJc=", "narHash": "sha256-wX1Lpj95kkHUZAloB1fGs+ixaRycaOJq4F77+HvaJCQ=",
"owner": "StardustXR", "owner": "StardustXR",
"repo": "flatland", "repo": "flatland",
"rev": "3867067452761959a95497d6589f9336b347270c", "rev": "24613a496841bdf38e5f136608d5295860a75fce",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -98,34 +132,59 @@
"type": "github" "type": "github"
} }
}, },
"haskell-flake": { "gitignore": {
"inputs": {
"nixpkgs": [
"hercules-ci-effects",
"hercules-ci-agent",
"pre-commit-hooks-nix",
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1684780604, "lastModified": 1660459072,
"narHash": "sha256-2uMZsewmRn7rRtAnnQNw1lj0uZBMh4m6Cs/7dV5YF08=", "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
"owner": "srid", "owner": "hercules-ci",
"repo": "haskell-flake", "repo": "gitignore.nix",
"rev": "74210fa80a49f1b6f67223debdbf1494596ff9f2", "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "srid", "owner": "hercules-ci",
"ref": "0.3.0", "repo": "gitignore.nix",
"type": "github"
}
},
"haskell-flake": {
"locked": {
"lastModified": 1678138103,
"narHash": "sha256-D0lao82bV3t2gEFjHiU6RN233t+1MnkQV+bq8MEu2ic=",
"owner": "hercules-ci",
"repo": "haskell-flake",
"rev": "1e1660e6dd00838ba73bc7952e6e73be67da18d1",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"ref": "0.1-extraLibraries",
"repo": "haskell-flake", "repo": "haskell-flake",
"type": "github" "type": "github"
} }
}, },
"hercules-ci-agent": { "hercules-ci-agent": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_3", "flake-parts": "flake-parts_2",
"haskell-flake": "haskell-flake", "haskell-flake": "haskell-flake",
"nixpkgs": "nixpkgs_2" "nix-darwin": "nix-darwin",
"nixpkgs": "nixpkgs_2",
"pre-commit-hooks-nix": "pre-commit-hooks-nix"
}, },
"locked": { "locked": {
"lastModified": 1688568579, "lastModified": 1678446614,
"narHash": "sha256-ON0M56wtY/TIIGPkXDlJboAmuYwc73Hi8X9iJGtxOhM=", "narHash": "sha256-Z6Gsba5ahn/N0QlF0vJfIEfnZgCs4qr1IZtXAqjbE7s=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "hercules-ci-agent", "repo": "hercules-ci-agent",
"rev": "367dd8cd649b57009a6502e878005a1e54ad78c5", "rev": "0b90d1a87c117a5861785cb85833dd1c9df0b6ef",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -135,16 +194,16 @@
}, },
"hercules-ci-effects": { "hercules-ci-effects": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_2", "flake-parts": "flake-parts",
"hercules-ci-agent": "hercules-ci-agent", "hercules-ci-agent": "hercules-ci-agent",
"nixpkgs": "nixpkgs_3" "nixpkgs": "nixpkgs_3"
}, },
"locked": { "locked": {
"lastModified": 1689397210, "lastModified": 1681898675,
"narHash": "sha256-fVxZnqxMbsDkB4GzGAs/B41K0wt/e+B/fLxmTFF/S20=", "narHash": "sha256-nIJ7CAdiHv4i1no/VgDoeTJLzbLYwu5+/Ycoyzn0S78=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "hercules-ci-effects", "repo": "hercules-ci-effects",
"rev": "0a63bfa3f00a3775ea3a6722b247880f1ffe91ce", "rev": "15ff4f63e5f28070391a5b09a82f6d5c6cc5c9d0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -153,6 +212,28 @@
"type": "github" "type": "github"
} }
}, },
"nix-darwin": {
"inputs": {
"nixpkgs": [
"hercules-ci-effects",
"hercules-ci-agent",
"nixpkgs"
]
},
"locked": {
"lastModified": 1673295039,
"narHash": "sha256-AsdYgE8/GPwcelGgrntlijMg4t3hLFJFCRF3tL5WVjA=",
"owner": "LnL7",
"repo": "nix-darwin",
"rev": "87b9d090ad39b25b2400029c64825fc2a8868943",
"type": "github"
},
"original": {
"owner": "LnL7",
"repo": "nix-darwin",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1678703398, "lastModified": 1678703398,
@@ -172,11 +253,11 @@
"nixpkgs-lib": { "nixpkgs-lib": {
"locked": { "locked": {
"dir": "lib", "dir": "lib",
"lastModified": 1690881714, "lastModified": 1678375444,
"narHash": "sha256-h/nXluEqdiQHs1oSgkOOWF+j8gcJMWhwnZ9PFabN6q0=", "narHash": "sha256-XIgHfGvjFvZQ8hrkfocanCDxMefc/77rXeHvYdzBMc8=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9e1960bc196baf6881340d53dccb203a951745a2", "rev": "130fa0baaa2b93ec45523fdcde942f6844ee9f6e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -187,31 +268,29 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-lib_2": { "nixpkgs-stable": {
"locked": { "locked": {
"dir": "lib", "lastModified": 1673800717,
"lastModified": 1688049487, "narHash": "sha256-SFHraUqLSu5cC6IxTprex/nTsI81ZQAtDvlBvGDWfnA=",
"narHash": "sha256-100g4iaKC9MalDjUW9iN6Jl/OocTDtXdeAj7pEGIRh4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "4bc72cae107788bf3f24f30db2e2f685c9298dc9", "rev": "2f9fd351ec37f5d479556cd48be4ca340da59b8f",
"type": "github" "type": "github"
}, },
"original": { "original": {
"dir": "lib",
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-unstable", "ref": "nixos-22.11",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1688322751, "lastModified": 1678293141,
"narHash": "sha256-eW62dC5f33oKZL7VWlomttbUnOTHrAbte9yNUNW8rbk=", "narHash": "sha256-lLlQHaR0y+q6nd6kfpydPTGHhl1rS9nU9OQmztzKOYs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "0fbe93c5a7cac99f90b60bdf5f149383daaa615f", "rev": "c90c4025bb6e0c4eaf438128a3b2640314b1c58d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -223,11 +302,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1689393711, "lastModified": 1678891326,
"narHash": "sha256-l3gyTPy/qWLDk1CY1EgYwlsxcGxN2aVd7MlCzQa69rk=", "narHash": "sha256-cjgrjKx7y+hO9I8O2b6QvBaTt9w7Xhk/5hsnJYTUb2I=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "27fcd46fa18df36d270174246e7bd8f1787129ff", "rev": "1544ef240132d4357d9a39a40c8e6afd1678b052",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -238,29 +317,72 @@
}, },
"nixpkgs_4": { "nixpkgs_4": {
"locked": { "locked": {
"lastModified": 1692734709, "lastModified": 1683408522,
"narHash": "sha256-SCFnyHCyYjwEmgUsHDDuU0TsbVMKeU1vwkR+r7uS2Rg=", "narHash": "sha256-9kcPh6Uxo17a3kK3XCHhcWiV1Yu1kYj22RHiymUhMkU=",
"owner": "nixos", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "b85ed9dcbf187b909ef7964774f8847d554fab3b", "rev": "897876e4c484f1e8f92009fd11b7d988a121a4e7",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "NixOS",
"ref": "nixos-unstable", "ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"pre-commit-hooks-nix": {
"inputs": {
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"gitignore": "gitignore",
"nixpkgs": [
"hercules-ci-effects",
"hercules-ci-agent",
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
"lastModified": 1678376203,
"narHash": "sha256-3tyYGyC8h7fBwncLZy5nCUjTJPrHbmNwp47LlNLOHSM=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "1a20b9708962096ec2481eeb2ddca29ed747770a",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"flake-parts": "flake-parts", "fenix": "fenix",
"flatland": "flatland", "flatland": "flatland",
"hercules-ci-effects": "hercules-ci-effects", "hercules-ci-effects": "hercules-ci-effects",
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_4"
} }
}, },
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1683653808,
"narHash": "sha256-GiKwJySG/YCPIKwz9wSm9fJa5e4CU3GvTYAKZzjBhFo=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "b7cdd93f3e1533e96d4cfa1ac8573e6210a2bedf",
"type": "github"
},
"original": {
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
"rust-analyzer-src_2": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1678695923, "lastModified": 1678695923,

183
flake.nix
View File

@@ -3,77 +3,130 @@
extra-substituters = [ "https://stardustxr.cachix.org" ]; extra-substituters = [ "https://stardustxr.cachix.org" ];
extra-trusted-public-keys = [ "stardustxr.cachix.org-1:mWSn8Ap2RLsIWT/8gsj+VfbJB6xoOkPaZpbjO+r9HBo=" ]; extra-trusted-public-keys = [ "stardustxr.cachix.org-1:mWSn8Ap2RLsIWT/8gsj+VfbJB6xoOkPaZpbjO+r9HBo=" ];
}; };
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects";
# Since we do not have a monorepo, we have to fetch Flatland in order to use # 22.11 does not include PR #218472, hence we use the unstable version
# it to create VM Tests inputs.nixpkgs.url = github:NixOS/nixpkgs/nixos-unstable;
flatland.url = "github:StardustXR/flatland";
}; # Since we do not have a monorepo, we have to fetch Flatland in order to use
outputs = inputs@{ self, flake-parts, nixpkgs, hercules-ci-effects, flatland, ... }: # it to create VM Tests
inputs.flatland.url = "github:StardustXR/flatland";
inputs.fenix.url = github:nix-community/fenix;
inputs.fenix.inputs.nixpkgs.follows = "nixpkgs";
inputs.hercules-ci-effects.url = "github:hercules-ci/hercules-ci-effects";
outputs = { self, nixpkgs, fenix, hercules-ci-effects, flatland, ... }:
let let
name = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.name; name = "server";
src = builtins.path { pkgs = system: import nixpkgs {
name = "${name}-source"; inherit system;
path = toString ./.;
filter = path: type:
nixpkgs.lib.all
(n: builtins.baseNameOf path != n)
[
"flake.nix"
"flake.lock"
"nix"
"README.md"
];
}; };
in shell = pkgs: pkgs.mkShell {
flake-parts.lib.mkFlake { inherit inputs; } { inputsFrom = [ self.packages.${pkgs.system}.default ];
imports = [
flake-parts.flakeModules.easyOverlay # ---- START package specific dev settings ----
]; LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
systems = [ "aarch64-linux" "x86_64-linux" "riscv64-linux" ]; # ---- END package specific dev settings ----
perSystem = { config, self', inputs', pkgs, system, ... }: {
_module.args.pkgs = import inputs.nixpkgs { inherit system; overlays = [ inputs.self.overlays.default ]; };
overlayAttrs = config.packages;
packages = {
default = self'.packages.${name};
gnome-graphical-test = self'.checks.gnome-graphical-test;
"${name}" = pkgs.callPackage ./nix/stardust-xr-server.nix { inherit name src; };
};
checks.gnome-graphical-test = pkgs.nixosTest (import ./nix/gnome-graphical-test.nix { inherit pkgs self; });
devShells.default = pkgs.mkShell {
inputsFrom = [ self'.packages.default ];
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
};
}; };
flake = { package = pkgs:
herculesCI.ciSystems = [ "x86_64-linux" ]; let
effects = let toolchain = fenix.packages.${pkgs.system}.minimal.toolchain;
pkgs = nixpkgs.legacyPackages.x86_64-linux; in
hci-effects = hercules-ci-effects.lib.withPkgs pkgs; (pkgs.makeRustPlatform {
in { branch, rev, ... }: { cargo = toolchain;
gnome-graphical-test = hci-effects.mkEffect { rustc = toolchain;
secretsMap."stardustxrDiscord" = "stardustxrDiscord"; }).buildRustPackage rec {
secretsMap."stardustxrIpfs" = "stardustxrIpfs"; pname = "stardust-xr-${name}";
effectScript = '' src = builtins.path {
readSecretString stardustxrDiscord .webhook > .webhook name = "stardust-xr-source";
readSecretString stardustxrIpfs .basicauth > .basicauth path = toString ./.;
set -x filter = path: type:
export RESPONSE=$(curl -H @.basicauth -F file=@${self.packages."x86_64-linux".gnome-graphical-test}/screen.png https://ipfs-api.stardustxr.org/api/v0/add) nixpkgs.lib.all
export CID=$(echo "$RESPONSE" | ${pkgs.jq}/bin/jq -r .Hash) (n: builtins.baseNameOf path != n)
set +x [
export ADDRESS="https://ipfs.stardustxr.org/ipfs/$CID" "flake.nix"
${pkgs.discord-sh}/bin/discord.sh \ "flake.lock"
--description "\`stardustxr/server\` has been modified, here's how it renders \`weston-cliptest\` on \`flatland\` via \`monado-service\` inside of the \`gnome-graphical-test\`" \ "nix"
--field "Branch;${branch}" \ "README.md"
--field "Commit ID;${rev}" \ ];
--field "Flatland Revision;${flatland.rev}" \ };
--field "Reproducer;\`nix build github:stardustxr/server/${rev}#gnome-graphical-test\`" \
--image "$ADDRESS" # ---- START package specific settings ----
version = "0.10.2";
cargoLock = {
lockFile = ./Cargo.lock;
allowBuiltinFetchGit = true;
};
postPatch = ''
sk=$(echo $cargoDepsCopy/stereokit-sys-*/StereoKit)
mkdir -p $sk/build/cpm
cp ${pkgs.fetchurl {
url = "https://github.com/cpm-cmake/CPM.cmake/releases/download/v0.32.2/CPM.cmake";
hash = "sha256-yDHlpqmpAE8CWiwJRoWyaqbuBAg0090G8WJIC2KLHp8=";
}} $sk/build/cpm/CPM_0.32.2.cmake
''; '';
CPM_SOURCE_CACHE = "./build";
nativeBuildInputs = with pkgs; [
cmake pkg-config llvmPackages.libcxxClang
];
buildInputs = with pkgs; [
openxr-loader libGL mesa xorg.libX11 fontconfig libxkbcommon
];
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
# ---- END package specific settings ----
}; };
in
{
overlays.default = final: prev: {
stardust-xr = (prev.stardust-xr or {}) // {
${name} = package final;
};
};
packages."x86_64-linux".default = package (pkgs "x86_64-linux");
packages."aarch64-linux".default = package (pkgs "aarch64-linux");
packages."x86_64-linux".gnome-graphical-test = self.checks.x86_64-linux.gnome-graphical-test;
packages."aarch64-linux".gnome-graphical-test = self.checks.aarch64-linux.gnome-graphical-test;
checks."x86_64-linux".gnome-graphical-test = (pkgs "x86_64-linux").nixosTest (import ./nix/gnome-graphical-test.nix { pkgs = (pkgs "x86_64-linux"); inherit self; });
checks."aarch64-linux".gnome-graphical-test = (pkgs "aarch64-linux").nixosTest (import ./nix/gnome-graphical-test.nix { pkgs = (pkgs "aarch64-linux"); inherit self; });
devShells."x86_64-linux".default = shell (pkgs "x86_64-linux");
devShells."aarch64-linux".default = shell (pkgs "aarch64-linux");
herculesCI.ciSystems = [ "x86_64-linux" ];
effects = let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
hci-effects = hercules-ci-effects.lib.withPkgs pkgs;
in { branch, rev, ... }: {
gnome-graphical-test = hci-effects.mkEffect {
secretsMap."stardustxrDiscord" = "stardustxrDiscord";
secretsMap."stardustxrIpfs" = "stardustxrIpfs";
effectScript = ''
readSecretString stardustxrDiscord .webhook > .webhook
readSecretString stardustxrIpfs .basicauth > .basicauth
set -x
export RESPONSE=$(curl -H @.basicauth -F file=@${self.packages."x86_64-linux".gnome-graphical-test}/screen.png https://ipfs-api.stardustxr.org/api/v0/add)
export CID=$(echo "$RESPONSE" | ${pkgs.jq}/bin/jq -r .Hash)
set +x
export ADDRESS="https://ipfs.stardustxr.org/ipfs/$CID"
${pkgs.discord-sh}/bin/discord.sh \
--description "\`stardustxr/server\` has been modified, here's how it renders \`weston-cliptest\` on \`flatland\` via \`monado-service\` inside of the \`gnome-graphical-test\`" \
--field "Branch;${branch}" \
--field "Commit ID;${rev}" \
--field "Flatland Revision;${flatland.rev}" \
--field "Reproducer;\`nix build github:stardustxr/server/${rev}#gnome-graphical-test\`" \
--image "$ADDRESS"
'';
}; };
}; };
}; };

View File

@@ -1,40 +0,0 @@
{ rustPlatform
, src
, name
, openxr-loader
, libGL
, mesa
, xorg
, fontconfig
, libxkbcommon
, libclang
, cmake
, cpm-cmake
, pkg-config
, llvmPackages
}:
rustPlatform.buildRustPackage rec {
inherit src name;
cargoLock = {
lockFile = (src + "/Cargo.lock");
allowBuiltinFetchGit = true;
};
CPM_SOURCE_CACHE = "./build";
postPatch = ''
sk=$(echo $cargoDepsCopy/stereokit-sys-*/StereoKit)
mkdir -p $sk/build/cpm
# This is not ideal, the original approach was to fetch the exact cmake
# file version that was wanted from GitHub directly, but at least this way it comes from Nixpkgs.. so meh
cp ${cpm-cmake}/share/cpm/CPM.cmake $sk/build/cpm/CPM_0.32.2.cmake
'';
nativeBuildInputs = [
cmake pkg-config llvmPackages.libcxxClang
];
buildInputs = [
openxr-loader libGL mesa xorg.libX11 fontconfig libxkbcommon
];
LIBCLANG_PATH = "${libclang.lib}/lib";
}

View File

@@ -1,50 +0,0 @@
use std::ffi::c_void;
use color_eyre::eyre::{ensure, Result};
use smithay::backend::{egl::EGLContext, renderer::gles::GlesRenderer};
use stereokit as sk;
struct EGLRawHandles {
display: *const c_void,
config: *const c_void,
context: *const c_void,
}
fn get_sk_egl() -> Result<EGLRawHandles> {
ensure!(
unsafe { sk::sys::backend_graphics_get() }
== sk::sys::backend_graphics__backend_graphics_opengles_egl,
"StereoKit is not running using EGL!"
);
Ok(unsafe {
EGLRawHandles {
display: sk::sys::backend_opengl_egl_get_display() as *const c_void,
config: sk::sys::backend_opengl_egl_get_config() as *const c_void,
context: sk::sys::backend_opengl_egl_get_context() as *const c_void,
}
})
}
pub struct BufferManager {
pub renderer: GlesRenderer,
}
impl BufferManager {
pub fn new() -> Result<Self> {
let egl_raw_handles = get_sk_egl()?;
let renderer = unsafe {
GlesRenderer::new(EGLContext::from_raw(
egl_raw_handles.display,
egl_raw_handles.config,
egl_raw_handles.context,
)?)?
};
Ok(BufferManager { renderer })
}
pub fn make_context_current(&self) {
unsafe {
let _ = self.renderer.egl_context().make_current();
}
}
}

View File

@@ -1,20 +1,20 @@
use super::{ use super::scenegraph::Scenegraph;
client_state::{ClientState, CLIENT_STATES},
scenegraph::Scenegraph,
};
use crate::{ use crate::{
core::{registry::OwnedRegistry, task}, core::{registry::OwnedRegistry, task},
nodes::{audio, data, drawable, fields, hmd, input, items, root::Root, spatial, Node}, nodes::{
audio, data, drawable, fields, hmd, input, items,
root::Root,
spatial,
startup::{self, StartupSettings, STARTUP_SETTINGS},
Node,
},
}; };
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use stardust_xr::{ use stardust_xr::messenger::{self, MessageSenderHandle};
messenger::{self, MessageSenderHandle},
schemas::flex::serialize,
};
use std::{fs, iter::FromIterator, path::PathBuf, sync::Arc}; use std::{fs, iter::FromIterator, path::PathBuf, sync::Arc};
use tokio::{net::UnixStream, task::JoinHandle}; use tokio::{net::UnixStream, task::JoinHandle};
use tracing::info; use tracing::info;
@@ -34,7 +34,7 @@ lazy_static! {
scenegraph: Default::default(), scenegraph: Default::default(),
root: OnceCell::new(), root: OnceCell::new(),
base_resource_prefixes: Default::default(), base_resource_prefixes: Default::default(),
state: Arc::new(ClientState::default()), startup_settings: None,
}); });
} }
@@ -46,13 +46,13 @@ pub fn get_env(pid: i32) -> Result<FxHashMap<String, String>, std::io::Error> {
.map(|(k, v)| (k.to_string(), v.to_string())), .map(|(k, v)| (k.to_string(), v.to_string())),
)) ))
} }
pub fn state(env: &FxHashMap<String, String>) -> Option<Arc<ClientState>> { pub fn startup_settings(env: &FxHashMap<String, String>) -> Option<StartupSettings> {
let token = env.get("STARDUST_STARTUP_TOKEN")?; let token = env.get("STARDUST_STARTUP_TOKEN")?;
CLIENT_STATES.lock().get(token).cloned() STARTUP_SETTINGS.lock().get(token).cloned()
} }
pub struct Client { pub struct Client {
pub pid: Option<i32>, pid: Option<i32>,
// env: Option<FxHashMap<String, String>>, // env: Option<FxHashMap<String, String>>,
exe: Option<PathBuf>, exe: Option<PathBuf>,
dispatch_join_handle: OnceCell<JoinHandle<Result<()>>>, dispatch_join_handle: OnceCell<JoinHandle<Result<()>>>,
@@ -63,7 +63,7 @@ pub struct Client {
pub scenegraph: Arc<Scenegraph>, pub scenegraph: Arc<Scenegraph>,
pub root: OnceCell<Arc<Root>>, pub root: OnceCell<Arc<Root>>,
pub base_resource_prefixes: Mutex<Vec<PathBuf>>, pub base_resource_prefixes: Mutex<Vec<PathBuf>>,
pub state: Arc<ClientState>, pub startup_settings: Option<StartupSettings>,
} }
impl Client { impl Client {
pub fn from_connection(connection: UnixStream) -> Result<Arc<Self>> { pub fn from_connection(connection: UnixStream) -> Result<Arc<Self>> {
@@ -80,10 +80,7 @@ impl Client {
let (mut messenger_tx, mut messenger_rx) = messenger::create(connection); let (mut messenger_tx, mut messenger_rx) = messenger::create(connection);
let scenegraph = Arc::new(Scenegraph::default()); let scenegraph = Arc::new(Scenegraph::default());
let state = env let startup_settings = env.as_ref().and_then(startup_settings);
.as_ref()
.and_then(state)
.unwrap_or_else(|| Arc::new(ClientState::default()));
let client = CLIENTS.add(Client { let client = CLIENTS.add(Client {
pid, pid,
@@ -98,7 +95,7 @@ impl Client {
scenegraph: scenegraph.clone(), scenegraph: scenegraph.clone(),
root: OnceCell::new(), root: OnceCell::new(),
base_resource_prefixes: Default::default(), base_resource_prefixes: Default::default(),
state, startup_settings,
}); });
let _ = client.scenegraph.client.set(Arc::downgrade(&client)); let _ = client.scenegraph.client.set(Arc::downgrade(&client));
let _ = client.root.set(Root::create(&client)?); let _ = client.root.set(Root::create(&client)?);
@@ -110,13 +107,7 @@ impl Client {
data::create_interface(&client)?; data::create_interface(&client)?;
items::create_interface(&client)?; items::create_interface(&client)?;
input::create_interface(&client)?; input::create_interface(&client)?;
startup::create_interface(&client)?;
client
.root
.get()
.unwrap()
.node
.send_remote_signal("restore_state", serialize(client.state.apply_to(&client))?)?;
let pid_printable = pid let pid_printable = pid
.map(|pid| pid.to_string()) .map(|pid| pid.to_string())
@@ -173,27 +164,6 @@ impl Client {
Ok(client) Ok(client)
} }
pub fn get_cmdline(&self) -> Option<Vec<String>> {
let pid = self.pid?;
let exe_proc_path = format!("/proc/{pid}/exe");
let cmdline_proc_path = format!("/proc/{pid}/cmdline");
let exe = std::fs::read_link(exe_proc_path).ok()?;
let cmdline = std::fs::read_to_string(cmdline_proc_path).ok()?;
let mut cmdline_split: Vec<_> = cmdline.split('\0').map(ToString::to_string).collect();
cmdline_split.pop();
*cmdline_split.get_mut(0).unwrap() = exe.to_str()?.to_string();
Some(cmdline_split)
}
pub fn get_cwd(&self) -> Option<PathBuf> {
let pid = self.pid?;
let cwd_proc_path = format!("/proc/{pid}/cwd");
std::fs::read_link(cwd_proc_path).ok()
}
pub async fn save_state(&self) -> Option<ClientState> {
let internal = self.root.get()?.save_state().await.ok()?;
Some(ClientState::from_deserialized(self, internal))
}
#[inline] #[inline]
pub fn get_node(&self, name: &'static str, path: &str) -> Result<Arc<Node>> { pub fn get_node(&self, name: &'static str, path: &str) -> Result<Arc<Node>> {
self.scenegraph self.scenegraph

View File

@@ -1,108 +0,0 @@
use super::client::{get_env, Client};
use crate::nodes::{spatial::Spatial, Node};
use glam::Mat4;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use std::{io::Write, path::PathBuf, sync::Arc};
lazy_static::lazy_static! {
pub static ref CLIENT_STATES: Mutex<FxHashMap<String, Arc<ClientState>>> = Default::default();
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LaunchInfo {
pub cmdline: Vec<String>,
pub cwd: PathBuf,
pub env: FxHashMap<String, String>,
}
impl LaunchInfo {
fn from_client(client: &Client) -> Option<Self> {
Some(LaunchInfo {
cmdline: client.get_cmdline()?,
cwd: client.get_cwd()?,
env: get_env(client.pid?).ok()?,
})
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ClientState {
pub launch_info: Option<LaunchInfo>,
pub data: Option<Vec<u8>>,
pub root: Mat4,
pub spatial_anchors: FxHashMap<String, Mat4>,
}
impl ClientState {
pub fn from_deserialized(client: &Client, state: ClientStateInternal) -> Self {
ClientState {
launch_info: LaunchInfo::from_client(client),
data: state.data,
root: Self::spatial_transform(client, &state.root.unwrap_or_default())
.unwrap_or_default(),
spatial_anchors: state
.spatial_anchors
.into_iter()
.filter_map(|(k, v)| Some((k, Self::spatial_transform(client, &v)?)))
.collect(),
}
}
fn spatial_transform(client: &Client, path: &str) -> Option<Mat4> {
let node = client.scenegraph.get_node(path)?;
let spatial = node.spatial.get()?;
Some(spatial.global_transform())
}
pub fn token(self) -> String {
let token = nanoid::nanoid!();
CLIENT_STATES.lock().insert(token.clone(), Arc::new(self));
token
}
pub fn to_file(self) {
let project_dirs = directories::ProjectDirs::from("", "", "stardust").unwrap();
let state_dir = project_dirs.state_dir().unwrap();
std::fs::create_dir_all(state_dir).unwrap();
let mut file = std::fs::File::create(state_dir.join(nanoid::nanoid!())).unwrap();
file.write_all(&stardust_xr::schemas::flex::flexbuffers::to_vec(self).unwrap())
.unwrap();
}
pub fn apply_to(&self, client: &Arc<Client>) -> ClientStateInternal {
if let Some(root) = client.root.get() {
root.set_transform(self.root)
}
ClientStateInternal {
data: self.data.clone(),
root: Some("/".to_string()),
spatial_anchors: self
.spatial_anchors
.iter()
.map(|(k, v)| {
(k.clone(), {
let node = Node::create(client, "/spatial/anchor", k, true)
.add_to_scenegraph()
.unwrap();
Spatial::add_to(&node, None, *v, false).unwrap();
k.clone()
})
})
.collect(),
}
}
}
impl Default for ClientState {
fn default() -> Self {
Self {
launch_info: None,
data: None,
root: Mat4::IDENTITY,
spatial_anchors: Default::default(),
}
}
}
#[derive(Default, Serialize, Deserialize)]
pub struct ClientStateInternal {
data: Option<Vec<u8>>,
root: Option<String>,
spatial_anchors: FxHashMap<String, String>,
}

View File

@@ -1,5 +1,4 @@
pub mod client; pub mod client;
pub mod client_state;
pub mod delta; pub mod delta;
pub mod destroy_queue; pub mod destroy_queue;
pub mod eventloop; pub mod eventloop;
@@ -8,5 +7,3 @@ pub mod registry;
pub mod resource; pub mod resource;
pub mod scenegraph; pub mod scenegraph;
pub mod task; pub mod task;
pub mod typed_datamap;
pub mod buffers;

View File

@@ -7,32 +7,33 @@ use std::{
sync::{Arc, Weak}, sync::{Arc, Weak},
}; };
// #[derive(Default)] #[derive(Default)]
// pub struct LifeLinkedNodeList { pub struct LifeLinkedNodeList {
// nodes: Mutex<Vec<Weak<Node>>>, nodes: Mutex<Vec<Weak<Node>>>,
// } }
// impl LifeLinkedNodeList { impl LifeLinkedNodeList {
// pub fn add(&self, node: Weak<Node>) { pub fn add(&self, node: Weak<Node>) {
// self.nodes.lock().push(node); self.nodes.lock().push(node);
// } }
// pub fn clear(&self) {
// self.nodes
// .lock()
// .iter()
// .filter_map(|node| node.upgrade())
// .for_each(|node| {
// node.destroy();
// });
// self.nodes.lock().clear();
// }
// }
// impl Drop for LifeLinkedNodeList {
// fn drop(&mut self) {
// self.clear();
// }
// }
#[derive(Default, Debug)] pub fn clear(&self) {
self.nodes
.lock()
.iter()
.filter_map(|node| node.upgrade())
.for_each(|node| {
node.destroy();
});
self.nodes.lock().clear();
}
}
impl Drop for LifeLinkedNodeList {
fn drop(&mut self) {
self.clear();
}
}
#[derive(Default)]
pub struct LifeLinkedNodeMap<K: Hash + Eq> { pub struct LifeLinkedNodeMap<K: Hash + Eq> {
nodes: Mutex<FxHashMap<K, Weak<Node>>>, nodes: Mutex<FxHashMap<K, Weak<Node>>>,
} }

View File

@@ -54,14 +54,6 @@ impl<T: Send + Sync + ?Sized> Registry<T> {
pub fn clear(&self) { pub fn clear(&self) {
self.lock().clear(); self.lock().clear();
} }
pub fn is_empty(&self) -> bool {
let registry = self.0.lock();
let Some(registry) = &*registry else {return true};
if registry.is_empty() {
return true;
}
registry.values().all(|v| v.strong_count() == 0)
}
} }
impl<T: Send + Sync + ?Sized> Clone for Registry<T> { impl<T: Send + Sync + ?Sized> Clone for Registry<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {

View File

@@ -1,21 +1,20 @@
use crate::core::client::Client;
use crate::nodes::Node; use crate::nodes::Node;
use crate::{core::client::Client, nodes::Message};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use portable_atomic::Ordering;
use rustc_hash::FxHashMap;
use stardust_xr::scenegraph; use stardust_xr::scenegraph;
use stardust_xr::scenegraph::ScenegraphError; use stardust_xr::scenegraph::ScenegraphError;
use std::os::fd::OwnedFd;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use tokio::sync::oneshot; use tracing::{debug, debug_span, instrument};
use tracing::{debug, debug_span};
use core::hash::BuildHasherDefault;
use dashmap::DashMap;
use rustc_hash::FxHasher;
#[derive(Default)] #[derive(Default)]
pub struct Scenegraph { pub struct Scenegraph {
pub(super) client: OnceCell<Weak<Client>>, pub(super) client: OnceCell<Weak<Client>>,
nodes: Mutex<FxHashMap<String, Arc<Node>>>, nodes: DashMap<String, Arc<Node>, BuildHasherDefault<FxHasher>>,
} }
impl Scenegraph { impl Scenegraph {
@@ -31,60 +30,32 @@ impl Scenegraph {
pub fn add_node_raw(&self, node: Arc<Node>) { pub fn add_node_raw(&self, node: Arc<Node>) {
debug!(node = ?&*node, "Add node"); debug!(node = ?&*node, "Add node");
let path = node.get_path().to_string(); let path = node.get_path().to_string();
self.nodes.lock().insert(path, node); self.nodes.insert(path, node);
} }
#[instrument(level = "debug", skip(self))]
pub fn get_node(&self, path: &str) -> Option<Arc<Node>> { pub fn get_node(&self, path: &str) -> Option<Arc<Node>> {
let mut node = self.nodes.lock().get(path)?.clone(); let mut node = self.nodes.get(path)?.clone();
while let Some(alias) = node.alias.get() { while let Some(alias) = node.alias.get() {
if alias.enabled.load(Ordering::Relaxed) { node = alias.original.upgrade()?;
node = alias.original.upgrade()?;
} else {
return None;
}
} }
Some(node) Some(node)
} }
pub fn remove_node(&self, path: &str) -> Option<Arc<Node>> { pub fn remove_node(&self, path: &str) -> Option<Arc<Node>> {
debug!(path, "Remove node"); debug!(path, "Remove node");
self.nodes.lock().remove(path) let (_, node) = self.nodes.remove(path)?;
Some(node)
} }
} }
pub struct MethodResponseSender(oneshot::Sender<Result<(Vec<u8>, Vec<OwnedFd>), ScenegraphError>>);
impl MethodResponseSender {
pub fn send(self, t: Result<Message, ScenegraphError>) {
let _ = self.0.send(t.map(|m| (m.data, m.fds)));
}
pub fn wrap_sync<F: FnOnce() -> color_eyre::eyre::Result<Message>>(self, f: F) {
self.send(f().map_err(|e| ScenegraphError::MethodError {
error: e.to_string(),
}))
}
}
impl scenegraph::Scenegraph for Scenegraph { impl scenegraph::Scenegraph for Scenegraph {
fn send_signal( fn send_signal(&self, path: &str, method: &str, data: &[u8]) -> Result<(), ScenegraphError> {
&self, let Some(client) = self.get_client() else {return Err(ScenegraphError::SignalNotFound)};
path: &str,
method: &str,
data: &[u8],
fds: Vec<OwnedFd>,
) -> Result<(), ScenegraphError> {
let Some(client) = self.get_client() else {
return Err(ScenegraphError::SignalNotFound);
};
debug_span!("Handle signal", path, method).in_scope(|| { debug_span!("Handle signal", path, method).in_scope(|| {
self.get_node(path) self.get_node(path)
.ok_or(ScenegraphError::NodeNotFound)? .ok_or(ScenegraphError::NodeNotFound)?
.send_local_signal( .send_local_signal(client, method, data)
client,
method,
Message {
data: data.to_vec(),
fds,
},
)
}) })
} }
fn execute_method( fn execute_method(
@@ -92,26 +63,12 @@ impl scenegraph::Scenegraph for Scenegraph {
path: &str, path: &str,
method: &str, method: &str,
data: &[u8], data: &[u8],
fds: Vec<OwnedFd>, ) -> Result<Vec<u8>, ScenegraphError> {
response: oneshot::Sender<Result<(Vec<u8>, Vec<OwnedFd>), ScenegraphError>>, let Some(client) = self.get_client() else {return Err(ScenegraphError::MethodNotFound)};
) { debug_span!("Handle method", path, method).in_scope(|| {
let Some(client) = self.get_client() else { self.get_node(path)
let _ = response.send(Err(ScenegraphError::MethodNotFound)); .ok_or(ScenegraphError::NodeNotFound)?
return; .execute_local_method(client, method, data)
}; })
debug!(path, method, "Handle method");
let Some(node) = self.get_node(path) else {
let _ = response.send(Err(ScenegraphError::NodeNotFound));
return;
};
node.execute_local_method(
client,
method,
Message {
data: data.to_vec(),
fds,
},
MethodResponseSender(response),
);
} }
} }

View File

@@ -1,8 +1,10 @@
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use std::future::Future; use std::future::Future;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use tracing::instrument;
#[allow(unused_variables)] #[allow(unused_variables)]
#[instrument(level = "debug", skip_all)]
pub fn new< pub fn new<
F: FnOnce() -> S, F: FnOnce() -> S,
S: AsRef<str>, S: AsRef<str>,

View File

@@ -1,56 +0,0 @@
#![allow(unused)]
use std::ops::{Deref, DerefMut};
use color_eyre::eyre::Result;
use once_cell::sync::Lazy;
use serde::{de::DeserializeOwned, Serialize};
use stardust_xr::schemas::{
flat::Datamap,
flex::flexbuffers::{FlexbufferSerializer, Reader, ReaderError},
};
use crate::nodes::Message;
pub struct TypedDatamap<T: DeserializeOwned + Serialize>(T);
impl<T: DeserializeOwned + Serialize> TypedDatamap<T> {
pub fn new(data: T) -> Self {
TypedDatamap(data)
}
pub fn from_flex(message: Message) -> Result<Self> {
let root = Reader::get_root(message.as_ref())?;
T::deserialize(root).map(Self::new).map_err(|e| e.into())
}
pub fn to_datamap(&mut self) -> Result<Datamap> {
let mut serializer = FlexbufferSerializer::default();
self.0.serialize(&mut serializer)?;
Datamap::new(serializer.take_buffer()).map_err(|e| e.into())
}
pub fn serialize(&mut self) -> Option<Vec<u8>> {
let mut serializer = FlexbufferSerializer::default();
self.0.serialize(&mut serializer).ok()?;
// check if this is actually a map
Reader::get_root(serializer.view()).ok()?.get_map().ok()?;
Some(serializer.take_buffer())
}
}
impl<T: DeserializeOwned + Serialize> Default for TypedDatamap<T>
where
T: Default,
{
fn default() -> Self {
Self(T::default())
}
}
impl<T: DeserializeOwned + Serialize> Deref for TypedDatamap<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: DeserializeOwned + Serialize> DerefMut for TypedDatamap<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

View File

@@ -4,10 +4,7 @@ mod objects;
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
mod wayland; mod wayland;
use crate::core::client::CLIENTS; use crate::core::destroy_queue;
use crate::core::client_state::ClientState;
use crate::core::{destroy_queue, buffers};
use crate::nodes::items::camera;
use crate::nodes::{audio, drawable, hmd, input}; use crate::nodes::{audio, drawable, hmd, input};
use crate::objects::input::eye_pointer::EyePointer; use crate::objects::input::eye_pointer::EyePointer;
use crate::objects::input::mouse_pointer::MousePointer; use crate::objects::input::mouse_pointer::MousePointer;
@@ -19,9 +16,8 @@ use self::core::eventloop::EventLoop;
use clap::Parser; use clap::Parser;
use directories::ProjectDirs; use directories::ProjectDirs;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use smithay::reexports::nix;
use stardust_xr::server; use stardust_xr::server;
use std::os::unix::process::CommandExt; use std::mem::ManuallyDrop;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::sync::Arc; use std::sync::Arc;
@@ -31,8 +27,6 @@ use stereokit::{
TextureFormat, TextureType, TextureFormat, TextureType,
}; };
use stereokit::{DisplayBlend, Sk}; use stereokit::{DisplayBlend, Sk};
use tokio::sync::Notify;
use tokio::task::LocalSet;
use tokio::{runtime::Handle, sync::oneshot}; use tokio::{runtime::Handle, sync::oneshot};
use tracing::metadata::LevelFilter; use tracing::metadata::LevelFilter;
use tracing::{debug_span, error, info}; use tracing::{debug_span, error, info};
@@ -60,7 +54,6 @@ struct CliArgs {
static STARDUST_INSTANCE: OnceCell<String> = OnceCell::new(); static STARDUST_INSTANCE: OnceCell<String> = OnceCell::new();
static SK_MULTITHREAD: OnceCell<Sk> = OnceCell::new(); static SK_MULTITHREAD: OnceCell<Sk> = OnceCell::new();
static STOP_NOTIFIER: Notify = Notify::const_new();
struct EventLoopInfo { struct EventLoopInfo {
tokio_handle: Handle, tokio_handle: Handle,
@@ -68,17 +61,13 @@ struct EventLoopInfo {
} }
fn main() { fn main() {
ctrlc::set_handler(|| {
if atty::isnt(atty::Stream::Stdout) {
STOP_NOTIFIER.notify_waiters()
}
})
.unwrap();
let registry = tracing_subscriber::registry(); let registry = tracing_subscriber::registry();
#[cfg(feature = "profile_app")] #[cfg(feature = "profile_app")]
let registry = registry.with(tracing_tracy::TracyLayer::new().with_filter(LevelFilter::DEBUG)); let (chrome_layer, _guard) = tracing_chrome::ChromeLayerBuilder::new()
.include_args(true)
.build();
#[cfg(feature = "profile_app")]
let registry = registry.with(chrome_layer);
#[cfg(feature = "profile_tokio")] #[cfg(feature = "profile_tokio")]
let (console_layer, _) = console_subscriber::ConsoleLayer::builder().build(); let (console_layer, _) = console_subscriber::ConsoleLayer::builder().build();
@@ -156,7 +145,7 @@ fn main() {
} }
} }
let mut mouse_pointer = cli_args let mouse_pointer = cli_args
.flatscreen .flatscreen
.then(MousePointer::new) .then(MousePointer::new)
.transpose() .transpose()
@@ -170,16 +159,15 @@ fn main() {
.flatten(); .flatten();
let mut controllers = (!cli_args.flatscreen && !cli_args.disable_controller) let mut controllers = (!cli_args.flatscreen && !cli_args.disable_controller)
.then(|| { .then(|| {
let left = SkController::new(&sk, Handed::Left).ok(); let left = SkController::new(Handed::Left).ok();
let right = SkController::new(&sk, Handed::Right).ok(); let right = SkController::new(Handed::Right).ok();
left.zip(right) left.zip(right)
}) })
.flatten(); .flatten();
let eye_pointer = (sk.active_display_mode() == DisplayMode::MixedReality let eye_pointer = (!cli_args.flatscreen && sk.device_has_eye_gaze())
&& sk.device_has_eye_gaze()) .then(EyePointer::new)
.then(EyePointer::new) .transpose()
.transpose() .unwrap();
.unwrap();
if hands.is_none() { if hands.is_none() {
sk.input_hand_visible(Handed::Left, false); sk.input_hand_visible(Handed::Left, false);
@@ -191,68 +179,46 @@ fn main() {
.then(|| PlaySpace::new().ok()) .then(|| PlaySpace::new().ok())
.flatten(); .flatten();
let (event_stop_tx, event_stop_rx) = oneshot::channel::<()>();
let (info_sender, info_receiver) = oneshot::channel::<EventLoopInfo>(); let (info_sender, info_receiver) = oneshot::channel::<EventLoopInfo>();
let event_thread = std::thread::Builder::new() let event_thread = std::thread::Builder::new()
.name("event_loop".to_owned()) .name("event_loop".to_owned())
.spawn(move || event_loop(info_sender)) .spawn(move || event_loop(info_sender, event_stop_rx))
.unwrap(); .unwrap();
let event_loop_info = info_receiver.blocking_recv().unwrap(); let event_loop_info = info_receiver.blocking_recv().unwrap();
let _tokio_handle = event_loop_info.tokio_handle.enter(); let _tokio_handle = event_loop_info.tokio_handle.enter();
let mut buffer_manager = buffers::BufferManager::new().expect("Could not initialize buffer manager");
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
let mut wayland = wayland::Wayland::new(&buffer_manager).expect("Could not initialize wayland"); let mut wayland = wayland::Wayland::new().unwrap();
info!("Stardust ready!"); info!("Stardust ready!");
let mut startup_child = (|| { if let Some(project_dirs) = project_dirs.as_ref() {
let project_dirs = project_dirs.as_ref()?;
let startup_script_path = cli_args let startup_script_path = cli_args
.startup_script .startup_script
.clone() .clone()
.and_then(|p| p.canonicalize().ok()) .and_then(|p| p.canonicalize().ok())
.unwrap_or_else(|| project_dirs.config_dir().join("startup")); .unwrap_or_else(|| project_dirs.config_dir().join("startup"));
let mut startup_command = Command::new("bash"); let _startup = Command::new(startup_script_path)
startup_command.arg(startup_script_path); .stdin(Stdio::null())
startup_command.arg("&"); .env(
"FLAT_WAYLAND_DISPLAY",
startup_command.stdin(Stdio::null()); std::env::var_os("WAYLAND_DISPLAY").unwrap_or_default(),
startup_command.stdout(Stdio::null()); )
startup_command.stderr(Stdio::null()); .env("WAYLAND_DISPLAY", &wayland.socket_name)
startup_command.env( .env(
"FLAT_WAYLAND_DISPLAY", "STARDUST_INSTANCE",
std::env::var_os("WAYLAND_DISPLAY").unwrap_or_default(), event_loop_info
); .socket_path
startup_command.env( .file_name()
"STARDUST_INSTANCE", .expect("Stardust socket path not found"),
event_loop_info )
.socket_path .env("GDK_BACKEND", "wayland")
.file_name() .env("QT_QPA_PLATFORM", "wayland")
.expect("Stardust socket path not found"), .env("MOZ_ENABLE_WAYLAND", "1")
); .env("CLUTTER_BACKEND", "wayland")
#[cfg(feature = "wayland")] .env("SDL_VIDEODRIVER", "wayland")
{ .spawn();
if let Some(wayland_socket) = wayland.socket_name.as_ref() { }
startup_command.env("WAYLAND_DISPLAY", &wayland_socket);
}
#[cfg(feature = "xwayland")]
startup_command.env("DISPLAY", format!(":{}", wayland.xwayland_state.display));
startup_command.env("GDK_BACKEND", "wayland");
startup_command.env("QT_QPA_PLATFORM", "wayland");
startup_command.env("MOZ_ENABLE_WAYLAND", "1");
startup_command.env("CLUTTER_BACKEND", "wayland");
startup_command.env("SDL_VIDEODRIVER", "wayland");
}
unsafe {
startup_command.pre_exec(|| {
nix::unistd::setsid()
.map(|_| ())
.map_err(|_| std::io::ErrorKind::Other.into())
})
};
let child = startup_command.spawn().ok()?;
Some(child)
})();
let mut last_frame_delta = Duration::ZERO; let mut last_frame_delta = Duration::ZERO;
let mut sleep_duration = Duration::ZERO; let mut sleep_duration = Duration::ZERO;
@@ -262,18 +228,17 @@ fn main() {
let _span = debug_span!("StereoKit step"); let _span = debug_span!("StereoKit step");
let _span = _span.enter(); let _span = _span.enter();
camera::send_rendered();
hmd::frame(sk); hmd::frame(sk);
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
wayland.frame_event(sk); wayland.frame_event(sk);
destroy_queue::clear(); destroy_queue::clear();
if let Some(mouse_pointer) = &mut mouse_pointer { if let Some(mouse_pointer) = &mouse_pointer {
mouse_pointer.update(sk); mouse_pointer.update(sk);
} }
if let Some((left_hand, right_hand)) = &mut hands { if let Some((left_hand, right_hand)) = &mut hands {
left_hand.update(!cli_args.disable_controller, sk); left_hand.update(sk);
right_hand.update(!cli_args.disable_controller, sk); right_hand.update(sk);
} }
if let Some((left_controller, right_controller)) = &mut controllers { if let Some((left_controller, right_controller)) = &mut controllers {
left_controller.update(sk); left_controller.update(sk);
@@ -295,33 +260,26 @@ fn main() {
); );
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
wayland.update(sk, &mut buffer_manager); wayland.update(sk);
drawable::draw(sk); drawable::draw(sk);
audio::update(sk); audio::update(sk);
#[cfg(feature = "wayland")]
buffer_manager.make_context_current(); wayland.make_context_current();
camera::update(sk, &mut buffer_manager);
}, },
|_sk| { |_| {
info!("Cleanly shut down StereoKit"); info!("Cleanly shut down StereoKit");
if let Some(mut startup_child) = startup_child.take() {
let _ = startup_child.kill();
}
}, },
) )
}); });
#[cfg(feature = "wayland")] #[cfg(feature = "wayland")]
drop(wayland); let _wayland = ManuallyDrop::new(wayland);
STOP_NOTIFIER.notify_waiters(); let _ = event_stop_tx.send(());
event_thread event_thread
.join() .join()
.expect("Failed to cleanly shut down event loop") .expect("Failed to cleanly shut down event loop")
.unwrap(); .unwrap();
info!("Cleanly shut down Stardust"); info!("Cleanly shut down Stardust");
} }
@@ -350,7 +308,10 @@ fn adaptive_sleep(
#[tokio::main] #[tokio::main]
// #[tokio::main(flavor = "current_thread")] // #[tokio::main(flavor = "current_thread")]
async fn event_loop(info_sender: oneshot::Sender<EventLoopInfo>) -> color_eyre::eyre::Result<()> { async fn event_loop(
info_sender: oneshot::Sender<EventLoopInfo>,
stop_rx: oneshot::Receiver<()>,
) -> color_eyre::eyre::Result<()> {
let socket_path = let socket_path =
server::get_free_socket_path().expect("Unable to find a free stardust socket path"); server::get_free_socket_path().expect("Unable to find a free stardust socket path");
STARDUST_INSTANCE.set(socket_path.file_name().unwrap().to_string_lossy().into_owned()).expect("Someone hasn't done their job, yell at Nova because how is this set multiple times what the hell"); STARDUST_INSTANCE.set(socket_path.file_name().unwrap().to_string_lossy().into_owned()).expect("Someone hasn't done their job, yell at Nova because how is this set multiple times what the hell");
@@ -365,9 +326,15 @@ async fn event_loop(info_sender: oneshot::Sender<EventLoopInfo>) -> color_eyre::
socket_path, socket_path,
}); });
STOP_NOTIFIER.notified().await; if atty::is(atty::Stream::Stdin) {
println!("Stopping..."); stop_rx.await?;
save_clients().await; } else {
tokio::select! {
biased;
_ = tokio::signal::ctrl_c() => (),
_ = stop_rx => (),
};
}
info!("Cleanly shut down event loop"); info!("Cleanly shut down event loop");
@@ -377,17 +344,3 @@ async fn event_loop(info_sender: oneshot::Sender<EventLoopInfo>) -> color_eyre::
Ok(()) Ok(())
} }
async fn save_clients() {
let local_set = LocalSet::new();
for client in CLIENTS.get_vec() {
local_set.spawn_local(async move {
tokio::select! {
biased;
s = client.save_state() => {s.map(ClientState::to_file);},
_ = tokio::time::sleep(Duration::from_millis(100)) => (),
}
});
}
local_set.await;
}

View File

@@ -1,7 +1,6 @@
use super::Node; use super::Node;
use crate::core::client::Client; use crate::core::client::Client;
use color_eyre::eyre::{ensure, Result}; use color_eyre::eyre::{ensure, Result};
use portable_atomic::AtomicBool;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
#[derive(Debug, Default, Clone)] #[derive(Debug, Default, Clone)]
@@ -13,7 +12,6 @@ pub struct AliasInfo {
#[allow(dead_code)] #[allow(dead_code)]
pub struct Alias { pub struct Alias {
pub enabled: Arc<AtomicBool>,
pub(super) node: Weak<Node>, pub(super) node: Weak<Node>,
pub original: Weak<Node>, pub original: Weak<Node>,
@@ -37,7 +35,6 @@ impl Alias {
let node = Node::create(client, parent, name, true).add_to_scenegraph()?; let node = Node::create(client, parent, name, true).add_to_scenegraph()?;
let alias = Alias { let alias = Alias {
enabled: Arc::new(AtomicBool::new(true)),
node: Arc::downgrade(&node), node: Arc::downgrade(&node),
original: Arc::downgrade(original), original: Arc::downgrade(original),
info, info,

View File

@@ -1,4 +1,4 @@
use super::{Message, Node}; use super::Node;
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::destroy_queue; use crate::core::destroy_queue;
use crate::core::registry::Registry; use crate::core::registry::Registry;
@@ -83,13 +83,13 @@ impl Sound {
} }
} }
fn play_flex(node: &Node, _calling_client: Arc<Client>, _message: Message) -> Result<()> { fn play_flex(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
let sound = node.sound.get().unwrap(); let sound = node.sound.get().unwrap();
sound.play.lock().replace(()); sound.play.lock().replace(());
Ok(()) Ok(())
} }
pub fn stop_flex(node: &Node, _calling_client: Arc<Client>, _message: Message) -> Result<()> { pub fn stop_flex(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
let sound = node.sound.get().unwrap(); let sound = node.sound.get().unwrap();
sound.stop.lock().replace(()); sound.stop.lock().replace(());
Ok(()) Ok(())
@@ -108,7 +108,7 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
node.add_to_scenegraph().map(|_| ()) node.add_to_scenegraph().map(|_| ())
} }
pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateSoundInfo<'a> { struct CreateSoundInfo<'a> {
name: &'a str, name: &'a str,
@@ -116,7 +116,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
transform: Transform, transform: Transform,
resource: ResourceID, resource: ResourceID,
} }
let info: CreateSoundInfo = deserialize(message.as_ref())?; let info: CreateSoundInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/audio/sound", info.name, true); let node = Node::create(&calling_client, "/audio/sound", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, true); let transform = parse_transform(info.transform, true, true, true);

View File

@@ -1,30 +1,21 @@
use super::alias::AliasInfo; use super::alias::AliasInfo;
use super::fields::Field; use super::fields::Field;
use super::spatial::{parse_transform, Spatial}; use super::spatial::{parse_transform, Spatial};
use super::{Alias, Message, Node}; use super::{Alias, Node};
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::node_collections::LifeLinkedNodeMap; use crate::core::node_collections::LifeLinkedNodeMap;
use crate::core::registry::Registry; use crate::core::registry::Registry;
use crate::core::scenegraph::MethodResponseSender;
use crate::nodes::fields::{find_field, FIELD_ALIAS_INFO}; use crate::nodes::fields::{find_field, FIELD_ALIAS_INFO};
use crate::nodes::spatial::find_spatial_parent; use crate::nodes::spatial::find_spatial_parent;
use color_eyre::eyre::{bail, ensure, eyre, Result}; use color_eyre::eyre::{ensure, eyre, Result};
use glam::vec3a; use glam::vec3a;
use lazy_static::lazy_static;
use mint::{Quaternion, Vector3}; use mint::{Quaternion, Vector3};
use nanoid::nanoid; use nanoid::nanoid;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use stardust_xr::schemas::flex::{deserialize, flexbuffers, serialize}; use stardust_xr::schemas::flex::{deserialize, flexbuffers, serialize};
use stardust_xr::values::Transform; use stardust_xr::values::Transform;
use std::fmt::Display;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
lazy_static! {
pub static ref KEYMAPS: Mutex<FxHashMap<String, String>> = Mutex::new(FxHashMap::default());
}
static PULSE_SENDER_REGISTRY: Registry<PulseSender> = Registry::new(); static PULSE_SENDER_REGISTRY: Registry<PulseSender> = Registry::new();
pub static PULSE_RECEIVER_REGISTRY: Registry<PulseReceiver> = Registry::new(); pub static PULSE_RECEIVER_REGISTRY: Registry<PulseReceiver> = Registry::new();
@@ -33,16 +24,7 @@ pub fn mask_matches(mask_map_lesser: &Mask, mask_map_greater: &Mask) -> bool {
for key in mask_map_lesser.get_mask()?.iter_keys() { for key in mask_map_lesser.get_mask()?.iter_keys() {
let lesser_key = mask_map_lesser.get_mask()?.index(key)?; let lesser_key = mask_map_lesser.get_mask()?.index(key)?;
let greater_key = mask_map_greater.get_mask()?.index(key)?; let greater_key = mask_map_greater.get_mask()?.index(key)?;
// otherwise zero-length vectors don't count the same as a single type vector if lesser_key.to_string() != greater_key.to_string() {
if lesser_key.flexbuffer_type().is_heterogenous_vector()
&& lesser_key.as_vector().len() == 0
&& greater_key.flexbuffer_type().is_vector()
{
continue;
}
if !lesser_key.flexbuffer_type().is_null()
&& lesser_key.flexbuffer_type() != greater_key.flexbuffer_type()
{
return Err(flexbuffers::ReaderError::InvalidPackedType {}.into()); return Err(flexbuffers::ReaderError::InvalidPackedType {}.into());
} }
} }
@@ -65,14 +47,6 @@ impl Mask {
.map_err(|_| eyre!("Mask is not a valid map")) .map_err(|_| eyre!("Mask is not a valid map"))
} }
} }
impl Display for Mask {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
flexbuffers::Reader::get_root(self.0.as_slice())
.unwrap()
.to_string()
.fmt(f)
}
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct SendDataInfo<'a> { struct SendDataInfo<'a> {
@@ -111,9 +85,9 @@ impl PulseSender {
if !mask_matches(&self.mask, &receiver.mask) { if !mask_matches(&self.mask, &receiver.mask) {
return; return;
} }
let Some(tx_node) = self.node.upgrade() else {return}; let Some(tx_node) = self.node.upgrade() else { return };
let Some(tx_client) = tx_node.get_client() else {return}; let Some(tx_client) = tx_node.get_client() else { return };
let Some(rx_node) = receiver.node.upgrade() else {return}; let Some(rx_node) = receiver.node.upgrade() else { return };
// Receiver itself // Receiver itself
let rx_alias = Alias::create( let rx_alias = Alias::create(
&tx_client, &tx_client,
@@ -168,7 +142,7 @@ impl PulseSender {
}; };
let Ok(data) = serialize(info) else {return}; let Ok(data) = serialize(info) else {return};
let _ = tx_node.send_remote_signal("new_receiver", data); let _ = tx_node.send_remote_signal("new_receiver", &data);
} }
fn handle_drop_receiver(&self, receiver: &PulseReceiver) { fn handle_drop_receiver(&self, receiver: &PulseReceiver) {
@@ -177,11 +151,11 @@ impl PulseSender {
self.aliases.remove(&(uid.to_string() + "-field")); self.aliases.remove(&(uid.to_string() + "-field"));
let Some(tx_node) = self.node.upgrade() else {return}; let Some(tx_node) = self.node.upgrade() else {return};
let Ok(data) = serialize(&uid) else {return}; let Ok(data) = serialize(&uid) else {return};
let _ = tx_node.send_remote_signal("drop_receiver", data); let _ = tx_node.send_remote_signal("drop_receiver", &data);
} }
fn send_data_flex(node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { fn send_data_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let info: SendDataInfo = deserialize(message.as_ref())?; let info: SendDataInfo = deserialize(data)?;
let receiver_node = calling_client.get_node("Pulse receiver", info.uid)?; let receiver_node = calling_client.get_node("Pulse receiver", info.uid)?;
let receiver = let receiver =
receiver_node.get_aspect("Pulse Receiver", "pulse receiver", |n| &n.pulse_receiver)?; receiver_node.get_aspect("Pulse Receiver", "pulse receiver", |n| &n.pulse_receiver)?;
@@ -195,9 +169,7 @@ impl PulseSender {
data_mask.get_mask()?; data_mask.get_mask()?;
ensure!( ensure!(
mask_matches(receiver_mask, &data_mask), mask_matches(receiver_mask, &data_mask),
"Message ({}) does not contain the same keys as the receiver's mask ({})", "Message does not contain the same keys as the receiver's mask"
data_mask,
receiver_mask
); );
receiver.send_data(&node.pulse_sender.get().unwrap().uid, data_mask.0) receiver.send_data(&node.pulse_sender.get().unwrap().uid, data_mask.0)
} }
@@ -238,7 +210,7 @@ impl PulseReceiver {
pub fn send_data(&self, uid: &str, data: Vec<u8>) -> Result<()> { pub fn send_data(&self, uid: &str, data: Vec<u8>) -> Result<()> {
if let Some(node) = self.node.upgrade() { if let Some(node) = self.node.upgrade() {
node.send_remote_signal("data", serialize(SendDataInfo { uid, data })?)?; node.send_remote_signal("data", &serialize(SendDataInfo { uid, data })?)?;
} }
Ok(()) Ok(())
} }
@@ -257,15 +229,13 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
let node = Node::create(client, "", "data", false); let node = Node::create(client, "", "data", false);
node.add_local_signal("create_pulse_sender", create_pulse_sender_flex); node.add_local_signal("create_pulse_sender", create_pulse_sender_flex);
node.add_local_signal("create_pulse_receiver", create_pulse_receiver_flex); node.add_local_signal("create_pulse_receiver", create_pulse_receiver_flex);
node.add_local_method("register_keymap", register_keymap_flex);
node.add_local_method("get_keymap", get_keymap_flex);
node.add_to_scenegraph().map(|_| ()) node.add_to_scenegraph().map(|_| ())
} }
pub fn create_pulse_sender_flex( pub fn create_pulse_sender_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreatePulseSenderInfo<'a> { struct CreatePulseSenderInfo<'a> {
@@ -274,7 +244,7 @@ pub fn create_pulse_sender_flex(
transform: Transform, transform: Transform,
mask: Vec<u8>, mask: Vec<u8>,
} }
let info: CreatePulseSenderInfo = deserialize(message.as_ref())?; let info: CreatePulseSenderInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/data/sender", info.name, true); let node = Node::create(&calling_client, "/data/sender", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);
@@ -291,7 +261,7 @@ pub fn create_pulse_sender_flex(
pub fn create_pulse_receiver_flex( pub fn create_pulse_receiver_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreatePulseReceiverInfo<'a> { struct CreatePulseReceiverInfo<'a> {
@@ -301,7 +271,7 @@ pub fn create_pulse_receiver_flex(
field_path: &'a str, field_path: &'a str,
mask: Vec<u8>, mask: Vec<u8>,
} }
let info: CreatePulseReceiverInfo = deserialize(message.as_ref())?; let info: CreatePulseReceiverInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/data/receiver", info.name, true); let node = Node::create(&calling_client, "/data/receiver", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);
@@ -314,42 +284,3 @@ pub fn create_pulse_receiver_flex(
PulseReceiver::add_to(&node, field, mask)?; PulseReceiver::add_to(&node, field, mask)?;
Ok(()) Ok(())
} }
pub fn register_keymap_flex(
_node: &Node,
_calling_client: Arc<Client>,
message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(move || {
let keymap: String = deserialize(message.as_ref())?;
let mut keymaps = KEYMAPS.lock();
if let Some(found_keymap_id) = keymaps
.iter()
.filter(|(_k, v)| *v == &keymap)
.map(|(k, _v)| k)
.last()
{
return Ok(serialize(found_keymap_id)?.into());
}
let generated_id = nanoid!();
keymaps.insert(generated_id.clone(), keymap);
Ok(serialize(generated_id)?.into())
});
}
pub fn get_keymap_flex(
_node: &Node,
_calling_client: Arc<Client>,
message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(move || {
let keymap_id: &str = deserialize(message.as_ref())?;
let keymaps = KEYMAPS.lock();
let Some(keymap) = keymaps.get(keymap_id) else {bail!("Could not find keymap. Try registering it")};
Ok(serialize(keymap)?.into())
});
}

View File

@@ -2,7 +2,7 @@ use crate::{
core::{client::Client, registry::Registry}, core::{client::Client, registry::Registry},
nodes::{ nodes::{
spatial::{find_spatial_parent, parse_transform, Spatial}, spatial::{find_spatial_parent, parse_transform, Spatial},
Message, Node, Node,
}, },
}; };
use color_eyre::eyre::{bail, ensure, Result}; use color_eyre::eyre::{bail, ensure, Result};
@@ -97,14 +97,10 @@ impl Lines {
draw_ctx.line_add_listv(points.make_contiguous()); draw_ctx.line_add_listv(points.make_contiguous());
} }
pub fn set_points_flex( pub fn set_points_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(Drawable::Lines(lines)) = node.drawable.get() else {bail!("Not a drawable??")}; let Some(Drawable::Lines(lines)) = node.drawable.get() else {bail!("Not a drawable??")};
let mut points: Vec<LinePointRaw> = deserialize(message.as_ref())?; let mut points: Vec<LinePointRaw> = deserialize(data)?;
for p in &mut points { for p in &mut points {
p.color[0] = p.color[0].powf(2.2); p.color[0] = p.color[0].powf(2.2);
p.color[1] = p.color[1].powf(2.2); p.color[1] = p.color[1].powf(2.2);
@@ -113,14 +109,10 @@ impl Lines {
lines.data.lock().points = points; lines.data.lock().points = points;
Ok(()) Ok(())
} }
pub fn set_cyclic_flex( pub fn set_cyclic_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(Drawable::Lines(lines)) = node.drawable.get() else {bail!("Not a drawable??")}; let Some(Drawable::Lines(lines)) = node.drawable.get() else {bail!("Not a drawable??")};
lines.data.lock().cyclic = deserialize(message.as_ref())?; lines.data.lock().cyclic = deserialize(data)?;
Ok(()) Ok(())
} }
} }
@@ -138,7 +130,7 @@ pub fn draw_all(draw_ctx: &impl StereoKitDraw) {
} }
} }
pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateTextInfo<'a> { struct CreateTextInfo<'a> {
name: &'a str, name: &'a str,
@@ -147,7 +139,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
points: Vec<LinePointRaw>, points: Vec<LinePointRaw>,
cyclic: bool, cyclic: bool,
} }
let mut info: CreateTextInfo = deserialize(message.as_ref())?; let mut info: CreateTextInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/drawable/lines", info.name, true); let node = Node::create(&calling_client, "/drawable/lines", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, true); let transform = parse_transform(info.transform, true, true, true);

View File

@@ -9,7 +9,7 @@ use self::{
text::Text, text::Text,
}; };
use super::{Message, Node}; use super::Node;
use crate::core::client::Client; use crate::core::client::Client;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use parking_lot::Mutex; use parking_lot::Mutex;
@@ -56,14 +56,14 @@ pub fn draw(sk: &impl StereoKitDraw) {
static QUEUED_SKYLIGHT: Mutex<Option<PathBuf>> = Mutex::new(None); static QUEUED_SKYLIGHT: Mutex<Option<PathBuf>> = Mutex::new(None);
static QUEUED_SKYTEX: Mutex<Option<PathBuf>> = Mutex::new(None); static QUEUED_SKYTEX: Mutex<Option<PathBuf>> = Mutex::new(None);
fn set_sky_file_flex(_node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<()> { fn set_sky_file_flex(_node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct SkyFileInfo { struct SkyFileInfo {
path: PathBuf, path: PathBuf,
skytex: Option<bool>, skytex: Option<bool>,
skylight: Option<bool>, skylight: Option<bool>,
} }
let info: SkyFileInfo = deserialize(message.as_ref())?; let info: SkyFileInfo = deserialize(data)?;
info.path.metadata()?; info.path.metadata()?;
if info.skytex.unwrap_or_default() { if info.skytex.unwrap_or_default() {
QUEUED_SKYTEX.lock().replace(info.path.clone()); QUEUED_SKYTEX.lock().replace(info.path.clone());

View File

@@ -5,7 +5,6 @@ use crate::core::registry::Registry;
use crate::core::resource::ResourceID; use crate::core::resource::ResourceID;
use crate::nodes::drawable::Drawable; use crate::nodes::drawable::Drawable;
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
use crate::nodes::Message;
use crate::SK_MULTITHREAD; use crate::SK_MULTITHREAD;
use color_eyre::eyre::{bail, ensure, eyre, Result}; use color_eyre::eyre::{bail, ensure, eyre, Result};
use glam::Mat4; use glam::Mat4;
@@ -14,6 +13,7 @@ use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use portable_atomic::{AtomicBool, Ordering}; use portable_atomic::{AtomicBool, Ordering};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use send_wrapper::SendWrapper;
use serde::Deserialize; use serde::Deserialize;
use stardust_xr::schemas::flex::deserialize; use stardust_xr::schemas::flex::deserialize;
use stardust_xr::values::Transform; use stardust_xr::values::Transform;
@@ -121,7 +121,7 @@ pub struct ModelPart {
space: Arc<Spatial>, space: Arc<Spatial>,
model: Weak<Model>, model: Weak<Model>,
pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>, pending_material_parameters: Mutex<FxHashMap<String, MaterialParameter>>,
pending_material_replacement: Mutex<Option<Arc<Material>>>, pending_material_replacement: Mutex<Option<Arc<SendWrapper<Material>>>>,
} }
impl ModelPart { impl ModelPart {
fn create_for_model(sk: &impl StereoKitMultiThread, model: &Arc<Model>, sk_model: &SKModel) { fn create_for_model(sk: &impl StereoKitMultiThread, model: &Arc<Model>, sk_model: &SKModel) {
@@ -213,11 +213,11 @@ impl ModelPart {
fn set_material_parameter_flex( fn set_material_parameter_flex(
node: &Node, node: &Node,
_calling_client: Arc<Client>, _calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
let Some(Drawable::ModelPart(model_part)) = node.drawable.get() else {bail!("Not a drawable??")}; let Some(Drawable::ModelPart(model_part)) = node.drawable.get() else {bail!("Not a drawable??")};
let (name, value): (String, MaterialParameter) = deserialize(message.as_ref())?; let (name, value): (String, MaterialParameter) = deserialize(data)?;
model_part model_part
.pending_material_parameters .pending_material_parameters
@@ -227,7 +227,7 @@ impl ModelPart {
Ok(()) Ok(())
} }
pub fn replace_material(&self, replacement: Arc<Material>) { pub fn replace_material(&self, replacement: Arc<SendWrapper<Material>>) {
self.pending_material_replacement self.pending_material_replacement
.lock() .lock()
.replace(replacement); .replace(replacement);
@@ -342,7 +342,7 @@ pub fn draw_all(sk: &impl StereoKitDraw) {
} }
} }
pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateModelInfo<'a> { struct CreateModelInfo<'a> {
name: &'a str, name: &'a str,
@@ -350,7 +350,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
transform: Transform, transform: Transform,
resource: ResourceID, resource: ResourceID,
} }
let info: CreateModelInfo = deserialize(message.as_ref())?; let info: CreateModelInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/drawable/model", info.name, true); let node = Node::create(&calling_client, "/drawable/model", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, true); let transform = parse_transform(info.transform, true, true, true);

View File

@@ -1,4 +1,5 @@
#![allow(dead_code)] #![allow(dead_code)]
use smithay::backend::renderer::gles::{ use smithay::backend::renderer::gles::{
ffi::{self, Gles2, FRAGMENT_SHADER, VERTEX_SHADER}, ffi::{self, Gles2, FRAGMENT_SHADER, VERTEX_SHADER},
GlesError, GlesError,
@@ -7,12 +8,6 @@ use std::mem::transmute;
use stereokit::Shader; use stereokit::Shader;
use tracing::error; use tracing::error;
// Simula shader with fancy lanzcos sampling
pub const UNLIT_SHADER_BYTES: &[u8] = include_bytes!("shader_unlit_gamma.sks");
// Simula shader with fancy lanzcos sampling
pub const PANEL_SHADER_BYTES: &[u8] = include_bytes!("shader_unlit_simula.sks");
struct FfiAssetHeader { struct FfiAssetHeader {
asset_type: i32, asset_type: i32,
asset_state: i32, asset_state: i32,

View File

@@ -3,7 +3,7 @@ use crate::{
nodes::{ nodes::{
drawable::Drawable, drawable::Drawable,
spatial::{find_spatial_parent, parse_transform, Spatial}, spatial::{find_spatial_parent, parse_transform, Spatial},
Message, Node, Node,
}, },
}; };
use color_eyre::eyre::{bail, ensure, eyre, Result}; use color_eyre::eyre::{bail, ensure, eyre, Result};
@@ -13,6 +13,7 @@ use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use portable_atomic::{AtomicBool, Ordering}; use portable_atomic::{AtomicBool, Ordering};
use prisma::{Flatten, Rgba}; use prisma::{Flatten, Rgba};
use send_wrapper::SendWrapper;
use serde::Deserialize; use serde::Deserialize;
use stardust_xr::{schemas::flex::deserialize, values::Transform}; use stardust_xr::{schemas::flex::deserialize, values::Transform};
use std::{ffi::OsStr, path::PathBuf, sync::Arc}; use std::{ffi::OsStr, path::PathBuf, sync::Arc};
@@ -34,7 +35,7 @@ pub struct Text {
enabled: Arc<AtomicBool>, enabled: Arc<AtomicBool>,
space: Arc<Spatial>, space: Arc<Spatial>,
font_path: Option<PathBuf>, font_path: Option<PathBuf>,
style: OnceCell<TextStyle>, style: OnceCell<SendWrapper<TextStyle>>,
data: Mutex<TextData>, data: Mutex<TextData>,
} }
@@ -90,16 +91,18 @@ impl Text {
} }
fn draw(&self, sk: &impl StereoKitDraw) { fn draw(&self, sk: &impl StereoKitDraw) {
let style = self let style = self.style.get_or_try_init(
.style || -> Result<SendWrapper<TextStyle>, color_eyre::eyre::Error> {
.get_or_try_init(|| -> Result<TextStyle, color_eyre::eyre::Error> {
let font = self let font = self
.font_path .font_path
.as_deref() .as_deref()
.and_then(|path| sk.font_create(path).ok()) .and_then(|path| sk.font_create(path).ok())
.unwrap_or_else(|| sk.font_find("default/font").unwrap()); .unwrap_or_else(|| sk.font_find("default/font").unwrap());
Ok(unsafe { sk.text_make_style(font, 1.0, WHITE) }) Ok(SendWrapper::new(unsafe {
}); sk.text_make_style(font, 1.0, WHITE)
}))
},
);
if let Ok(style) = style { if let Ok(style) = style {
let data = self.data.lock(); let data = self.data.lock();
@@ -115,7 +118,7 @@ impl Text {
transform, transform,
bounds / data.character_height, bounds / data.character_height,
data.fit, data.fit,
*style, **style,
data.bounds_align, data.bounds_align,
data.text_align, data.text_align,
vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0),
@@ -130,7 +133,7 @@ impl Text {
sk.text_add_at( sk.text_add_at(
&data.text, &data.text,
transform, transform,
*style, **style,
data.bounds_align, data.bounds_align,
data.text_align, data.text_align,
vec3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 0.0),
@@ -148,22 +151,18 @@ impl Text {
pub fn set_character_height_flex( pub fn set_character_height_flex(
node: &Node, node: &Node,
_calling_client: Arc<Client>, _calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
let Some(Drawable::Text(text)) = node.drawable.get() else {bail!("Not a drawable??")}; let Some(Drawable::Text(text)) = node.drawable.get() else {bail!("Not a drawable??")};
text.data.lock().character_height = deserialize(message.as_ref())?; text.data.lock().character_height = deserialize(data)?;
Ok(()) Ok(())
} }
pub fn set_text_flex( pub fn set_text_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(Drawable::Text(text)) = node.drawable.get() else {bail!("Not a drawable??")}; let Some(Drawable::Text(text)) = node.drawable.get() else {bail!("Not a drawable??")};
text.data.lock().text = deserialize(message.as_ref())?; text.data.lock().text = deserialize(data)?;
Ok(()) Ok(())
} }
} }
@@ -184,7 +183,7 @@ pub fn draw_all(sk: &impl StereoKitDraw) {
} }
} }
pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { pub fn create_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateTextInfo<'a> { struct CreateTextInfo<'a> {
name: &'a str, name: &'a str,
@@ -199,7 +198,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
bounds_align: TextAlign, bounds_align: TextAlign,
color: [f32; 4], color: [f32; 4],
} }
let info: CreateTextInfo = deserialize(message.as_ref())?; let info: CreateTextInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/drawable/text", info.name, true); let node = Node::create(&calling_client, "/drawable/text", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, true); let transform = parse_transform(info.transform, true, true, true);

View File

@@ -1,7 +1,6 @@
use super::{Field, FieldTrait, Node}; use super::{Field, FieldTrait, Node};
use crate::core::client::Client; use crate::core::client::Client;
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
use crate::nodes::Message;
use color_eyre::eyre::{ensure, Result}; use color_eyre::eyre::{ensure, Result};
use glam::{vec3, vec3a, Vec3, Vec3A}; use glam::{vec3, vec3a, Vec3, Vec3A};
use mint::Vector3; use mint::Vector3;
@@ -41,13 +40,9 @@ impl BoxField {
*self.size.lock() = size.into(); *self.size.lock() = size.into();
} }
pub fn set_size_flex( pub fn set_size_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Field::Box(box_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; let Field::Box(box_field) = node.field.get().unwrap().as_ref() else { return Ok(()) };
box_field.set_size(deserialize(message.as_ref())?); box_field.set_size(deserialize(data)?);
Ok(()) Ok(())
} }
@@ -69,11 +64,7 @@ impl FieldTrait for BoxField {
} }
} }
pub fn create_box_field_flex( pub fn create_box_field_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
_node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateFieldInfo<'a> { struct CreateFieldInfo<'a> {
name: &'a str, name: &'a str,
@@ -81,7 +72,7 @@ pub fn create_box_field_flex(
transform: Transform, transform: Transform,
size: Vector3<f32>, size: Vector3<f32>,
} }
let info: CreateFieldInfo = deserialize(message.as_ref())?; let info: CreateFieldInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/field", info.name, true); let node = Node::create(&calling_client, "/field", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);

View File

@@ -1,7 +1,6 @@
use super::{Field, FieldTrait, Node}; use super::{Field, FieldTrait, Node};
use crate::core::client::Client; use crate::core::client::Client;
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
use crate::nodes::Message;
use color_eyre::eyre::{ensure, Result}; use color_eyre::eyre::{ensure, Result};
use glam::{swizzles::*, vec2, Vec3A}; use glam::{swizzles::*, vec2, Vec3A};
use portable_atomic::AtomicF32; use portable_atomic::AtomicF32;
@@ -44,13 +43,9 @@ impl CylinderField {
self.radius.store(radius.abs(), Ordering::Relaxed); self.radius.store(radius.abs(), Ordering::Relaxed);
} }
pub fn set_size_flex( pub fn set_size_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Field::Cylinder(cylinder_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; let Field::Cylinder(cylinder_field) = node.field.get().unwrap().as_ref() else { return Ok(()) };
let (length, radius) = deserialize(message.as_ref())?; let (length, radius) = deserialize(data)?;
cylinder_field.set_size(length, radius); cylinder_field.set_size(length, radius);
Ok(()) Ok(())
} }
@@ -72,7 +67,7 @@ impl FieldTrait for CylinderField {
pub fn create_cylinder_field_flex( pub fn create_cylinder_field_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateFieldInfo<'a> { struct CreateFieldInfo<'a> {
@@ -82,7 +77,7 @@ pub fn create_cylinder_field_flex(
length: f32, length: f32,
radius: f32, radius: f32,
} }
let info: CreateFieldInfo = deserialize(message.as_ref())?; let info: CreateFieldInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/field", info.name, true); let node = Node::create(&calling_client, "/field", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);

View File

@@ -10,9 +10,8 @@ use self::torus::{create_torus_field_flex, TorusField};
use super::alias::AliasInfo; use super::alias::AliasInfo;
use super::spatial::Spatial; use super::spatial::Spatial;
use super::{Message, Node}; use super::Node;
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::scenegraph::MethodResponseSender;
use crate::nodes::spatial::find_reference_space; use crate::nodes::spatial::find_reference_space;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use glam::{vec2, vec3a, Vec3, Vec3A}; use glam::{vec2, vec3a, Vec3, Vec3A};
@@ -134,98 +133,76 @@ const MAX_RAY_MARCH: f32 = f32::MAX;
// const MIN_RAY_LENGTH: f32 = 0_f32; // const MIN_RAY_LENGTH: f32 = 0_f32;
const MAX_RAY_LENGTH: f32 = 1000_f32; const MAX_RAY_LENGTH: f32 = 1000_f32;
fn field_distance_flex( fn field_distance_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<Vec<u8>> {
node: &Node, #[derive(Deserialize)]
calling_client: Arc<Client>, struct FieldInfoArgs<'a> {
message: Message, reference_space_path: &'a str,
response: MethodResponseSender, point: Vector3<f32>,
) { }
response.wrap_sync(move || { let args: FieldInfoArgs = deserialize(data)?;
#[derive(Deserialize)] let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
struct FieldInfoArgs<'a> {
reference_space_path: &'a str,
point: Vector3<f32>,
}
let args: FieldInfoArgs = deserialize(message.as_ref())?;
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
let distance = node let distance = node
.field .field
.get() .get()
.unwrap() .unwrap()
.distance(reference_space.as_ref(), args.point.into()); .distance(reference_space.as_ref(), args.point.into());
Ok(serialize(distance)?.into()) Ok(serialize(distance)?)
});
} }
fn field_normal_flex( fn field_normal_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<Vec<u8>> {
node: &Node, #[derive(Deserialize)]
calling_client: Arc<Client>, struct FieldInfoArgs<'a> {
message: Message, reference_space_path: &'a str,
response: MethodResponseSender, point: Vector3<f32>,
) { radius: Option<f32>,
response.wrap_sync(move || { }
#[derive(Deserialize)] let args: FieldInfoArgs = deserialize(data)?;
struct FieldInfoArgs<'a> { let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
reference_space_path: &'a str,
point: Vector3<f32>,
}
let args: FieldInfoArgs = deserialize(message.as_ref())?;
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
let normal = node.field.get().as_ref().unwrap().normal( let normal = node.field.get().as_ref().unwrap().normal(
reference_space.as_ref(), reference_space.as_ref(),
args.point.into(), args.point.into(),
0.001, args.radius.unwrap_or(0.001),
); );
Ok(serialize(mint::Vector3::from(normal))?.into()) Ok(serialize(mint::Vector3::from(normal))?)
});
} }
fn field_closest_point_flex( fn field_closest_point_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
response: MethodResponseSender, ) -> Result<Vec<u8>> {
) { #[derive(Deserialize)]
response.wrap_sync(move || { struct FieldInfoArgs<'a> {
#[derive(Deserialize)] reference_space_path: &'a str,
struct FieldInfoArgs<'a> { point: Vector3<f32>,
reference_space_path: &'a str, radius: Option<f32>,
point: Vector3<f32>, }
} let args: FieldInfoArgs = deserialize(data)?;
let args: FieldInfoArgs = deserialize(message.as_ref())?; let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
let closest_point = node.field.get().as_ref().unwrap().closest_point( let closest_point = node.field.get().as_ref().unwrap().closest_point(
reference_space.as_ref(), reference_space.as_ref(),
args.point.into(), args.point.into(),
0.001, args.radius.unwrap_or(0.001),
); );
Ok(serialize(mint::Vector3::from(closest_point))?.into()) Ok(serialize(mint::Vector3::from(closest_point))?)
});
} }
fn field_ray_march_flex( fn field_ray_march_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<Vec<u8>> {
node: &Node, #[derive(Deserialize)]
calling_client: Arc<Client>, struct FieldInfoArgs<'a> {
message: Message, reference_space_path: &'a str,
response: MethodResponseSender, ray_origin: Vector3<f32>,
) { ray_direction: Vector3<f32>,
response.wrap_sync(move || { }
#[derive(Deserialize)] let args: FieldInfoArgs = deserialize(data)?;
struct FieldInfoArgs<'a> { let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
reference_space_path: &'a str,
ray_origin: Vector3<f32>,
ray_direction: Vector3<f32>,
}
let args: FieldInfoArgs = deserialize(message.as_ref())?;
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
let ray_march_result = node.field.get().unwrap().ray_march(Ray { let ray_march_result = node.field.get().unwrap().ray_march(Ray {
origin: args.ray_origin.into(), origin: args.ray_origin.into(),
direction: args.ray_direction.into(), direction: args.ray_direction.into(),
space: reference_space, space: reference_space,
});
Ok(serialize(ray_march_result)?.into())
}); });
Ok(serialize(ray_march_result)?)
} }
pub enum Field { pub enum Field {

View File

@@ -1,7 +1,6 @@
use super::{Field, FieldTrait, Node}; use super::{Field, FieldTrait, Node};
use crate::core::client::Client; use crate::core::client::Client;
use crate::nodes::spatial::{find_spatial_parent, Spatial}; use crate::nodes::spatial::{find_spatial_parent, Spatial};
use crate::nodes::Message;
use color_eyre::eyre::{ensure, Result}; use color_eyre::eyre::{ensure, Result};
use glam::{Mat4, Vec3A}; use glam::{Mat4, Vec3A};
use mint::Vector3; use mint::Vector3;
@@ -40,13 +39,9 @@ impl SphereField {
self.radius.store(radius, Ordering::Relaxed); self.radius.store(radius, Ordering::Relaxed);
} }
pub fn set_radius_flex( pub fn set_radius_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Field::Sphere(sphere_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; let Field::Sphere(sphere_field) = node.field.get().unwrap().as_ref() else { return Ok(()) };
sphere_field.set_radius(deserialize(message.as_ref())?); sphere_field.set_radius(deserialize(data)?);
Ok(()) Ok(())
} }
} }
@@ -69,7 +64,7 @@ impl FieldTrait for SphereField {
pub fn create_sphere_field_flex( pub fn create_sphere_field_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateFieldInfo<'a> { struct CreateFieldInfo<'a> {
@@ -78,7 +73,7 @@ pub fn create_sphere_field_flex(
origin: Option<Vector3<f32>>, origin: Option<Vector3<f32>>,
radius: f32, radius: f32,
} }
let info: CreateFieldInfo = deserialize(message.as_ref())?; let info: CreateFieldInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/field", info.name, true); let node = Node::create(&calling_client, "/field", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = Mat4::from_translation( let transform = Mat4::from_translation(

View File

@@ -1,7 +1,6 @@
use super::{Field, FieldTrait, Node}; use super::{Field, FieldTrait, Node};
use crate::core::client::Client; use crate::core::client::Client;
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
use crate::nodes::Message;
use color_eyre::eyre::{ensure, Result}; use color_eyre::eyre::{ensure, Result};
use glam::{swizzles::*, vec2, Vec3A}; use glam::{swizzles::*, vec2, Vec3A};
use portable_atomic::AtomicF32; use portable_atomic::AtomicF32;
@@ -44,13 +43,9 @@ impl TorusField {
self.radius_b.store(radius_b.abs(), Ordering::Relaxed); self.radius_b.store(radius_b.abs(), Ordering::Relaxed);
} }
pub fn set_size_flex( pub fn set_size_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Field::Torus(torus_field) = node.field.get().unwrap().as_ref() else { return Ok(()) }; let Field::Torus(torus_field) = node.field.get().unwrap().as_ref() else { return Ok(()) };
let (radius_a, radius_b) = deserialize(message.as_ref())?; let (radius_a, radius_b) = deserialize(data)?;
torus_field.set_size(radius_a, radius_b); torus_field.set_size(radius_a, radius_b);
Ok(()) Ok(())
@@ -72,7 +67,7 @@ impl FieldTrait for TorusField {
pub fn create_torus_field_flex( pub fn create_torus_field_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateFieldInfo<'a> { struct CreateFieldInfo<'a> {
@@ -82,7 +77,7 @@ pub fn create_torus_field_flex(
radius_a: f32, radius_a: f32,
radius_b: f32, radius_b: f32,
} }
let info: CreateFieldInfo = deserialize(message.as_ref())?; let info: CreateFieldInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/field", info.name, true); let node = Node::create(&calling_client, "/field", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);

View File

@@ -7,6 +7,7 @@ use color_eyre::eyre::Result;
use glam::{vec3, Mat4}; use glam::{vec3, Mat4};
use std::sync::Arc; use std::sync::Arc;
use stereokit::StereoKitMultiThread; use stereokit::StereoKitMultiThread;
use tracing::instrument;
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref HMD: Arc<Node> = create(); static ref HMD: Arc<Node> = create();
@@ -19,6 +20,7 @@ fn create() -> Arc<Node> {
node node
} }
#[instrument(level = "debug", name = "Update HMD Pose", skip(sk))]
pub fn frame(sk: &impl StereoKitMultiThread) { pub fn frame(sk: &impl StereoKitMultiThread) {
let spatial = HMD let spatial = HMD
.spatial .spatial

View File

@@ -31,7 +31,7 @@ impl InputSpecialization for Hand {
} }
fn serialize( fn serialize(
&self, &self,
distance_link: &DistanceLink, _distance_link: &DistanceLink,
local_to_handler_matrix: Mat4, local_to_handler_matrix: Mat4,
) -> InputDataType { ) -> InputDataType {
let mut hand = self.base; let mut hand = self.base;
@@ -68,10 +68,6 @@ impl InputSpecialization for Hand {
let (_, rotation, position) = joint_matrix.to_scale_rotation_translation(); let (_, rotation, position) = joint_matrix.to_scale_rotation_translation();
joint.position = position.into(); joint.position = position.into();
joint.rotation = rotation.into(); joint.rotation = rotation.into();
joint.distance = distance_link
.handler
.field
.distance(&distance_link.handler.spatial, position.into());
} }
InputDataType::Hand(Box::new(hand)) InputDataType::Hand(Box::new(hand))

View File

@@ -10,10 +10,10 @@ use super::{
alias::{Alias, AliasInfo}, alias::{Alias, AliasInfo},
fields::{find_field, Field, FIELD_ALIAS_INFO}, fields::{find_field, Field, FIELD_ALIAS_INFO},
spatial::{find_spatial_parent, parse_transform, Spatial}, spatial::{find_spatial_parent, parse_transform, Spatial},
Message, Node, Node,
}; };
use crate::core::registry::Registry;
use crate::core::{client::Client, node_collections::LifeLinkedNodeMap}; use crate::core::{client::Client, node_collections::LifeLinkedNodeMap};
use crate::core::{node_collections::LifeLinkedNodeList, registry::Registry};
use color_eyre::eyre::{ensure, Result}; use color_eyre::eyre::{ensure, Result};
use glam::Mat4; use glam::Mat4;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@@ -99,7 +99,6 @@ impl InputMethod {
}; };
for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() { for handler in INPUT_HANDLER_REGISTRY.get_valid_contents() {
method.handle_new_handler(&handler); method.handle_new_handler(&handler);
method.make_alias(&handler);
} }
let method = INPUT_METHOD_REGISTRY.add(method); let method = INPUT_METHOD_REGISTRY.add(method);
let _ = node.input_method.set(method.clone()); let _ = node.input_method.set(method.clone());
@@ -110,21 +109,21 @@ impl InputMethod {
.cloned() .cloned()
} }
fn capture_flex(node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { fn capture_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let method = InputMethod::get(node)?; let method = InputMethod::get(node)?;
let handler = InputHandler::find(&calling_client, deserialize(message.as_ref())?)?; let handler = InputHandler::find(&calling_client, deserialize(data)?)?;
method.captures.add_raw(&handler); method.captures.add_raw(&handler);
node.send_remote_signal("capture", message) node.send_remote_signal("capture", data)
} }
fn set_datamap_flex(node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<()> { fn set_datamap_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let method = InputMethod::get(node)?; let method = InputMethod::get(node)?;
method.datamap.lock().replace(Datamap::new(message.data)?); method.datamap.lock().replace(Datamap::new(data.to_vec())?);
Ok(()) Ok(())
} }
fn set_handlers_flex(node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { fn set_handlers_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let method = InputMethod::get(node)?; let method = InputMethod::get(node)?;
let handler_paths: Vec<&str> = deserialize(message.as_ref())?; let handler_paths: Vec<&str> = deserialize(data)?;
let handlers: Vec<Weak<InputHandler>> = handler_paths let handlers: Vec<Weak<InputHandler>> = handler_paths
.into_iter() .into_iter()
.filter_map(|p| InputHandler::find(&calling_client, p).ok()) .filter_map(|p| InputHandler::find(&calling_client, p).ok())
@@ -138,26 +137,6 @@ impl InputMethod {
Ok(()) Ok(())
} }
fn make_alias(&self, handler: &InputHandler) {
let Some(method_node) = self.node.upgrade() else {return};
let Some(handler_node) = handler.node.upgrade() else {return};
let Some(client) = handler_node.get_client() else {return};
let Ok(method_alias) = Alias::create(
&client,
handler_node.get_path(),
&self.uid,
&method_node,
AliasInfo {
server_signals: vec!["capture"],
..Default::default()
},
) else {return};
method_alias.enabled.store(false, Ordering::Relaxed);
handler
.method_aliases
.add(self as *const InputMethod as usize, &method_alias);
}
fn compare_distance(&self, to: &Field) -> f32 { fn compare_distance(&self, to: &Field) -> f32 {
self.specialization self.specialization
.lock() .lock()
@@ -168,9 +147,9 @@ impl InputMethod {
} }
fn handle_new_handler(&self, handler: &InputHandler) { fn handle_new_handler(&self, handler: &InputHandler) {
let Some(method_node) = self.node.upgrade() else {return}; let Some(method_node) = self.node.upgrade() else { return };
let Some(method_client) = method_node.get_client() else {return}; let Some(method_client) = method_node.get_client() else { return };
let Some(handler_node) = handler.node.upgrade() else {return}; let Some(handler_node) = handler.node.upgrade() else { return };
// Receiver itself // Receiver itself
let Ok(handler_alias) = Alias::create( let Ok(handler_alias) = Alias::create(
&method_client, &method_client,
@@ -199,7 +178,7 @@ impl InputMethod {
} }
let Ok(data) = serialize(&handler.uid) else {return}; let Ok(data) = serialize(&handler.uid) else {return};
let _ = method_node.send_remote_signal("handler_created", data); let _ = method_node.send_remote_signal("handler_created", &data);
} }
fn handle_drop_handler(&self, handler: &InputHandler) { fn handle_drop_handler(&self, handler: &InputHandler) {
let uid = handler.uid.as_str(); let uid = handler.uid.as_str();
@@ -207,7 +186,7 @@ impl InputMethod {
self.handler_aliases.remove(&(uid.to_string() + "-field")); self.handler_aliases.remove(&(uid.to_string() + "-field"));
let Some(tx_node) = self.node.upgrade() else {return}; let Some(tx_node) = self.node.upgrade() else {return};
let Ok(data) = serialize(&uid) else {return}; let Ok(data) = serialize(&uid) else {return};
let _ = tx_node.send_remote_signal("handler_destroyed", data); let _ = tx_node.send_remote_signal("handler_destroyed", &data);
} }
} }
impl Drop for InputMethod { impl Drop for InputMethod {
@@ -222,12 +201,25 @@ pub struct DistanceLink {
handler: Arc<InputHandler>, handler: Arc<InputHandler>,
} }
impl DistanceLink { impl DistanceLink {
fn from(method: Arc<InputMethod>, handler: Arc<InputHandler>) -> Self { fn from(method: Arc<InputMethod>, handler: Arc<InputHandler>) -> Option<Self> {
DistanceLink { let handler_node = handler.node.upgrade()?;
let method_alias = Alias::create(
&handler_node.get_client()?,
handler_node.get_path(),
&method.uid,
&method.node.upgrade()?,
AliasInfo {
server_signals: vec!["capture"],
..Default::default()
},
)
.ok()?;
handler.method_aliases.add(Arc::downgrade(&method_alias));
Some(DistanceLink {
distance: method.compare_distance(&handler.field), distance: method.compare_distance(&handler.field),
method, method,
handler, handler,
} })
} }
fn send_input(&self, order: u32, datamap: Datamap) { fn send_input(&self, order: u32, datamap: Datamap) {
@@ -257,7 +249,7 @@ pub struct InputHandler {
node: Weak<Node>, node: Weak<Node>,
spatial: Arc<Spatial>, spatial: Arc<Spatial>,
field: Arc<Field>, field: Arc<Field>,
method_aliases: LifeLinkedNodeMap<usize>, method_aliases: LifeLinkedNodeList,
} }
impl InputHandler { impl InputHandler {
pub fn add_to(node: &Arc<Node>, field: &Arc<Field>) -> Result<()> { pub fn add_to(node: &Arc<Node>, field: &Arc<Field>) -> Result<()> {
@@ -272,10 +264,9 @@ impl InputHandler {
node: Arc::downgrade(node), node: Arc::downgrade(node),
spatial: node.spatial.get().unwrap().clone(), spatial: node.spatial.get().unwrap().clone(),
field: field.clone(), field: field.clone(),
method_aliases: LifeLinkedNodeMap::default(), method_aliases: LifeLinkedNodeList::default(),
}; };
for method in INPUT_METHOD_REGISTRY.get_valid_contents() { for method in INPUT_METHOD_REGISTRY.get_valid_contents() {
method.make_alias(&handler);
method.handle_new_handler(&handler); method.handle_new_handler(&handler);
} }
let handler = INPUT_HANDLER_REGISTRY.add(handler); let handler = INPUT_HANDLER_REGISTRY.add(handler);
@@ -293,7 +284,7 @@ impl InputHandler {
#[instrument(level = "debug", skip(self, distance_link))] #[instrument(level = "debug", skip(self, distance_link))]
fn send_input(&self, order: u32, distance_link: &DistanceLink, datamap: Datamap) { fn send_input(&self, order: u32, distance_link: &DistanceLink, datamap: Datamap) {
let Some(node) = self.node.upgrade() else {return}; let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("input", distance_link.serialize(order, datamap)); let _ = node.send_remote_signal("input", &distance_link.serialize(order, datamap));
} }
} }
impl PartialEq for InputHandler { impl PartialEq for InputHandler {
@@ -321,7 +312,7 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
pub fn create_input_handler_flex( pub fn create_input_handler_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateInputHandlerInfo<'a> { struct CreateInputHandlerInfo<'a> {
@@ -330,7 +321,7 @@ pub fn create_input_handler_flex(
transform: Transform, transform: Transform,
field_path: &'a str, field_path: &'a str,
} }
let info: CreateInputHandlerInfo = deserialize(message.as_ref())?; let info: CreateInputHandlerInfo = deserialize(data)?;
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, true); let transform = parse_transform(info.transform, true, true, true);
let field = find_field(&calling_client, info.field_path)?; let field = find_field(&calling_client, info.field_path)?;
@@ -352,12 +343,10 @@ pub fn process_input() {
.filter(|method| method.datamap.lock().is_some()) .filter(|method| method.datamap.lock().is_some())
}); });
let handlers = INPUT_HANDLER_REGISTRY.get_valid_contents(); let handlers = INPUT_HANDLER_REGISTRY.get_valid_contents();
const LIMIT: usize = 50; for handler in &handlers {
handler.method_aliases.clear();
}
for method in methods { for method in methods {
for alias in method.node.upgrade().unwrap().aliases.get_valid_contents() {
alias.enabled.store(false, Ordering::Relaxed);
}
debug_span!("Process input method").in_scope(|| { debug_span!("Process input method").in_scope(|| {
// Get all valid input handlers and convert them to DistanceLink objects // Get all valid input handlers and convert them to DistanceLink objects
let distance_links: Vec<DistanceLink> = debug_span!("Generate distance links") let distance_links: Vec<DistanceLink> = debug_span!("Generate distance links")
@@ -368,16 +357,14 @@ pub fn process_input() {
.iter() .iter()
.filter_map(|h| h.upgrade()) .filter_map(|h| h.upgrade())
.filter(|handler| handler.enabled.load(Ordering::Relaxed)) .filter(|handler| handler.enabled.load(Ordering::Relaxed))
.map(|handler| DistanceLink::from(method.clone(), handler)) .filter_map(|handler| DistanceLink::from(method.clone(), handler))
.collect() .collect()
} else { } else {
let mut distance_links: Vec<_> = handlers let mut distance_links: Vec<_> = handlers
.iter() .iter()
.filter(|handler| handler.enabled.load(Ordering::Relaxed)) .filter(|handler| handler.enabled.load(Ordering::Relaxed))
.map(|handler| { .filter_map(|handler| {
debug_span!("Create distance link").in_scope(|| { DistanceLink::from(method.clone(), handler.clone())
DistanceLink::from(method.clone(), handler.clone())
})
}) })
.collect(); .collect();
@@ -388,7 +375,6 @@ pub fn process_input() {
}); });
}); });
distance_links.truncate(LIMIT);
distance_links distance_links
} }
}); });
@@ -396,18 +382,6 @@ pub fn process_input() {
let captures = method.captures.take_valid_contents(); let captures = method.captures.take_valid_contents();
// Iterate over the distance links and send input to them // Iterate over the distance links and send input to them
for (i, distance_link) in distance_links.into_iter().enumerate() { for (i, distance_link) in distance_links.into_iter().enumerate() {
if i > LIMIT {
break;
}
if let Some(method_alias) = distance_link
.handler
.method_aliases
.get(&(Arc::as_ptr(&distance_link.method) as usize))
.and_then(|a| a.alias.get().cloned())
{
method_alias.enabled.store(true, Ordering::Relaxed);
}
distance_link.send_input(i as u32, method.datamap.lock().clone().unwrap()); distance_link.send_input(i as u32, method.datamap.lock().clone().unwrap());
// If the current distance link is in the list of captured input handlers, // If the current distance link is in the list of captured input handlers,

View File

@@ -3,7 +3,7 @@ use crate::core::client::Client;
use crate::nodes::fields::{Field, Ray, RayMarchResult}; use crate::nodes::fields::{Field, Ray, RayMarchResult};
use crate::nodes::input::{InputMethod, InputType}; use crate::nodes::input::{InputMethod, InputType};
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
use crate::nodes::{Message, Node}; use crate::nodes::Node;
use glam::{vec3, Mat4}; use glam::{vec3, Mat4};
use serde::Deserialize; use serde::Deserialize;
use stardust_xr::schemas::flat::{Datamap, InputDataType, Pointer as FlatPointer}; use stardust_xr::schemas::flat::{Datamap, InputDataType, Pointer as FlatPointer};
@@ -34,13 +34,9 @@ impl Pointer {
impl InputSpecialization for Pointer { impl InputSpecialization for Pointer {
fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 { fn compare_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
let ray_info = self.ray_march(space, field); let ray_info = self.ray_march(space, field);
if ray_info.min_distance > 0.0 { ray_info
ray_info.deepest_point_distance + 1000.0 .deepest_point_distance
} else { .hypot(ray_info.min_distance.recip())
ray_info
.deepest_point_distance
.hypot(0.001 / ray_info.min_distance)
}
} }
fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 { fn true_distance(&self, space: &Arc<Spatial>, field: &Field) -> f32 {
let ray_info = self.ray_march(space, field); let ray_info = self.ray_march(space, field);
@@ -67,7 +63,7 @@ impl InputSpecialization for Pointer {
pub fn create_pointer_flex( pub fn create_pointer_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> color_eyre::eyre::Result<()> { ) -> color_eyre::eyre::Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreatePointerInfo<'a> { struct CreatePointerInfo<'a> {
@@ -76,7 +72,7 @@ pub fn create_pointer_flex(
transform: Transform, transform: Transform,
datamap: Option<Vec<u8>>, datamap: Option<Vec<u8>>,
} }
let info: CreatePointerInfo = deserialize(message.as_ref())?; let info: CreatePointerInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/input/method/pointer", info.name, true); let node = Node::create(&calling_client, "/input/method/pointer", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);

View File

@@ -3,7 +3,7 @@ use crate::core::client::Client;
use crate::nodes::fields::Field; use crate::nodes::fields::Field;
use crate::nodes::input::{InputMethod, InputType}; use crate::nodes::input::{InputMethod, InputType};
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial}; use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
use crate::nodes::{Message, Node}; use crate::nodes::Node;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use glam::{vec3a, Mat4}; use glam::{vec3a, Mat4};
use serde::Deserialize; use serde::Deserialize;
@@ -17,9 +17,9 @@ pub struct Tip {
pub radius: f32, pub radius: f32,
} }
impl Tip { impl Tip {
fn set_radius(node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<()> { fn set_radius(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
if let InputType::Tip(tip) = &mut *node.input_method.get().unwrap().specialization.lock() { if let InputType::Tip(tip) = &mut *node.input_method.get().unwrap().specialization.lock() {
tip.radius = deserialize(message.as_ref())?; tip.radius = deserialize(data)?;
} }
Ok(()) Ok(())
} }
@@ -45,7 +45,7 @@ impl InputSpecialization for Tip {
} }
} }
pub fn create_tip_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { pub fn create_tip_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateTipInfo<'a> { struct CreateTipInfo<'a> {
name: &'a str, name: &'a str,
@@ -54,7 +54,7 @@ pub fn create_tip_flex(_node: &Node, calling_client: Arc<Client>, message: Messa
radius: f32, radius: f32,
datamap: Option<Vec<u8>>, datamap: Option<Vec<u8>>,
} }
let info: CreateTipInfo = deserialize(message.as_ref())?; let info: CreateTipInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/input/method/tip", info.name, true); let node = Node::create(&calling_client, "/input/method/tip", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);

View File

@@ -1,357 +0,0 @@
use super::{Item, ItemType};
use crate::{
core::{
buffers::BufferManager,
client::{Client, INTERNAL_CLIENT},
registry::Registry,
scenegraph::MethodResponseSender,
},
nodes::{
drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES, Drawable},
items::TypeInfo,
spatial::{find_spatial_parent, parse_transform, Spatial},
Message, Node,
},
};
use color_eyre::eyre::{bail, Result};
use glam::Mat4;
use lazy_static::lazy_static;
use mint::{RowMatrix4, Vector2};
use nanoid::nanoid;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use serde::Deserialize;
use smithay::backend::{
allocator::{
dmabuf::{Dmabuf, DmabufFlags},
Buffer,
},
renderer::ImportDma,
};
use stardust_xr::{
scenegraph::ScenegraphError,
schemas::flex::{deserialize, serialize},
values::{BufferInfo, Transform},
};
use std::{ffi::c_void, sync::Arc};
use stereokit::{
Color128, Material, Rect, RenderLayer, StereoKitDraw, Tex, TextureFormat, TextureType,
Transparency,
};
use tokio::sync::mpsc::{self, error::SendError};
lazy_static! {
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
type_name: "camera",
aliased_local_signals: vec!["apply_preview_material", "set_proj_matrix"],
aliased_local_methods: vec!["render"],
aliased_remote_signals: vec![],
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
};
}
struct FrameInfo {
proj_matrix: Mat4,
preview_size: Vector2<u32>,
}
pub struct CameraItem {
space: Arc<Spatial>,
frame_info: Mutex<FrameInfo>,
sk_tex: OnceCell<Tex>,
sk_mat: OnceCell<Arc<Material>>,
render_requests_tx: mpsc::UnboundedSender<(Dmabuf, MethodResponseSender)>,
render_requests_rx: Mutex<mpsc::UnboundedReceiver<(Dmabuf, MethodResponseSender)>>,
rendered_notifiers: Mutex<Vec<MethodResponseSender>>,
applied_preview_to: Registry<ModelPart>,
apply_preview_to: Registry<ModelPart>,
}
impl CameraItem {
pub fn add_to(node: &Arc<Node>, proj_matrix: Mat4, preview_size: Vector2<u32>) {
let (render_requests_tx, render_requests_rx) = mpsc::unbounded_channel();
let camera_specialization = CameraItem {
space: node.spatial.get().unwrap().clone(),
frame_info: Mutex::new(FrameInfo {
proj_matrix,
preview_size,
}),
sk_tex: OnceCell::new(),
sk_mat: OnceCell::new(),
render_requests_tx,
render_requests_rx: Mutex::new(render_requests_rx),
rendered_notifiers: Mutex::new(Vec::new()),
applied_preview_to: Registry::new(),
apply_preview_to: Registry::new(),
};
Item::add_to(
node,
nanoid!(),
&ITEM_TYPE_INFO_CAMERA,
ItemType::Camera(camera_specialization),
);
node.add_local_method("render", CameraItem::render_flex);
node.add_local_signal(
"apply_preview_material",
CameraItem::apply_preview_material_flex,
);
node.add_local_signal("set_proj_matrix", CameraItem::set_proj_matrix_flex);
}
fn render_flex(
node: &Node,
_calling_client: Arc<Client>,
message: Message,
response: MethodResponseSender,
) {
let Some(item) = node.item.get() else {
let _ = response.send(Err(ScenegraphError::MethodError {
error: "Item not found".to_string(),
}));
return;
};
let ItemType::Camera(camera) = &item.specialization else {
let _ = response.send(Err(ScenegraphError::MethodError {
error: "Wrong item type?".to_string(),
}));
return;
};
let buffer_info: BufferInfo = match deserialize(&message.data) {
Ok(i) => i,
Err(e) => {
let _ = response.send(Err(ScenegraphError::MethodError {
error: e.to_string(),
}));
return;
}
};
let mut builder = Dmabuf::builder(
(buffer_info.width as i32, buffer_info.height as i32),
buffer_info.fourcc.try_into().unwrap(),
DmabufFlags::from_bits_truncate(buffer_info.flags),
);
for (fd, plane) in message.fds.into_iter().zip(buffer_info.planes) {
builder.add_plane(
fd,
plane.idx,
plane.offset,
plane.stride,
plane.modifier.try_into().unwrap(),
);
}
let buffer_to_render = builder.build().unwrap();
if let Err(SendError((_dmabuf, sender))) =
camera.render_requests_tx.send((buffer_to_render, response))
{
sender.send(Err(ScenegraphError::MethodError {
error: "Internal: sender broke????".to_string(),
}));
}
}
fn apply_preview_material_flex(
node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(item) = node.item.get() else {
bail!("Item not found?")
};
let ItemType::Camera(camera) = &item.specialization else {
bail!("Wrong item type?")
};
let model_part_path = deserialize(&message.data)?;
let model_part_node = calling_client.get_node("Model part", model_part_path)?;
let Drawable::ModelPart(model_part) =
model_part_node.get_aspect("Model part", "model part", |n| &n.drawable)?
else {
bail!("Drawable is not a model node")
};
camera.applied_preview_to.add_raw(model_part);
camera.apply_preview_to.add_raw(model_part);
Ok(())
}
fn set_proj_matrix_flex(
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(item) = node.item.get() else {
bail!("Item not found?")
};
let ItemType::Camera(camera) = &item.specialization else {
bail!("Wrong item type?")
};
let proj_matrix: RowMatrix4<f32> = deserialize(&message.data)?;
let mut frame_info = camera.frame_info.lock();
frame_info.proj_matrix = proj_matrix.into();
Ok(())
}
pub fn serialize_start_data(&self, id: &str) -> Result<Message> {
Ok(serialize(id)?.into())
}
pub fn update(&self, sk: &impl StereoKitDraw, buffer_manager: &mut BufferManager) {
let frame_info = self.frame_info.lock();
self.render_preview(sk, &*frame_info);
self.render_dmabuf(sk, buffer_manager, &*frame_info);
}
fn render_preview(&self, sk: &impl StereoKitDraw, frame_info: &FrameInfo) {
if !self.apply_preview_to.is_empty() {
let sk_tex = self.sk_tex.get_or_init(|| {
sk.tex_gen_color(
Color128::default(),
frame_info.preview_size.x as i32,
frame_info.preview_size.y as i32,
TextureType::RENDER_TARGET,
TextureFormat::RGBA32Linear,
)
});
let sk_mat = self.sk_mat.get_or_init(|| {
let shader = sk.shader_create_mem(&UNLIT_SHADER_BYTES).unwrap();
let mat = sk.material_create(&shader);
sk.material_set_texture(&mat, "diffuse", sk_tex.as_ref());
sk.material_set_transparency(&mat, Transparency::Blend);
Arc::new(mat)
});
for model_part in self.apply_preview_to.take_valid_contents() {
model_part.replace_material(sk_mat.clone())
}
}
if !self.applied_preview_to.is_empty() {
sk.render_to(
self.sk_tex.get().unwrap(),
self.space.global_transform(),
frame_info.proj_matrix,
RenderLayer::all(),
stereokit::RenderClear::All,
Rect {
x: 0.0,
y: 0.0,
w: 0.0,
h: 0.0,
},
);
}
}
fn render_dmabuf(
&self,
sk: &impl StereoKitDraw,
buffer_manager: &mut BufferManager,
frame_info: &FrameInfo,
) {
let mut render_notifiers = self.rendered_notifiers.lock();
let mut render_requests_rx = self.render_requests_rx.lock();
while let Ok((buffer_to_render, render_response_sender)) = render_requests_rx.try_recv() {
let imported_dmabuf = buffer_manager
.renderer
.import_dmabuf(&buffer_to_render, None);
let smithay_tex = match imported_dmabuf {
Ok(t) => t,
Err(e) => {
let _ = render_response_sender.send(Err(ScenegraphError::MethodError {
error: e.to_string(),
}));
continue;
}
};
let sk_tex = sk.tex_create(TextureType::IMAGE_NO_MIPS, TextureFormat::RGBA32);
unsafe {
sk.tex_set_surface(
&sk_tex,
smithay_tex.tex_id() as usize as *mut c_void,
TextureType::RENDER_TARGET,
smithay::backend::renderer::gles::ffi::SRGB8_ALPHA8.into(),
buffer_to_render.size().w,
buffer_to_render.size().h,
1,
false,
);
}
sk.render_to(
sk_tex,
self.space.global_transform(),
frame_info.proj_matrix,
RenderLayer::all(),
stereokit::RenderClear::All,
Rect {
x: 0.0,
y: 0.0,
w: 0.0,
h: 0.0,
},
);
render_notifiers.push(render_response_sender);
}
}
pub fn send_rendered(&self) {
for notifier in self.rendered_notifiers.lock().drain(..) {
let _ = notifier.send(Ok(Vec::new().into()));
}
}
}
pub fn update(sk: &impl StereoKitDraw, buffer_manager: &mut BufferManager) {
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
let ItemType::Camera(camera) = &camera.specialization else {
continue;
};
camera.update(sk, buffer_manager);
}
}
pub fn send_rendered() {
for camera in ITEM_TYPE_INFO_CAMERA.items.get_valid_contents() {
let ItemType::Camera(camera) = &camera.specialization else {
continue;
};
camera.send_rendered();
}
}
pub(super) fn create_camera_item_flex(
_node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)]
struct CreateCameraItemInfo<'a> {
name: &'a str,
parent_path: &'a str,
transform: Transform,
proj_matrix: RowMatrix4<f32>,
preview_size: Vector2<u32>,
}
let info: CreateCameraItemInfo = deserialize(message.as_ref())?;
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_CAMERA.type_name);
let space = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false);
let node =
Node::create(&INTERNAL_CLIENT, &parent_name, info.name, false).add_to_scenegraph()?;
Spatial::add_to(&node, None, transform * space.global_transform(), false)?;
CameraItem::add_to(&node, info.proj_matrix.into(), info.preview_size);
// TODO: this means ANY client can render anywhere with no limits, this needs to be changed!!
node.item
.get()
.unwrap()
.make_alias_named(&calling_client, &parent_name, info.name)?;
Ok(())
}

View File

@@ -1,14 +1,13 @@
use super::{Item, ItemType}; use super::{Item, ItemSpecialization, ItemType};
use crate::{ use crate::{
core::{ core::{
client::{Client, INTERNAL_CLIENT}, client::{Client, INTERNAL_CLIENT},
registry::Registry, registry::Registry,
scenegraph::MethodResponseSender,
}, },
nodes::{ nodes::{
items::TypeInfo, items::TypeInfo,
spatial::{find_spatial_parent, parse_transform, Spatial}, spatial::{find_spatial_parent, parse_transform, Spatial},
Message, Node, Node,
}, },
}; };
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
@@ -16,7 +15,7 @@ use lazy_static::lazy_static;
use nanoid::nanoid; use nanoid::nanoid;
use serde::Deserialize; use serde::Deserialize;
use stardust_xr::{ use stardust_xr::{
schemas::flex::{deserialize, serialize}, schemas::flex::{deserialize, flexbuffers, serialize},
values::Transform, values::Transform,
}; };
use std::sync::Arc; use std::sync::Arc;
@@ -47,29 +46,23 @@ impl EnvironmentItem {
node.add_local_method("get_path", EnvironmentItem::get_path_flex); node.add_local_method("get_path", EnvironmentItem::get_path_flex);
} }
fn get_path_flex( fn get_path_flex(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<Vec<u8>> {
node: &Node, let ItemType::Environment(environment_item) = &node.item.get().unwrap().specialization else {
_calling_client: Arc<Client>,
_message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(move || {
let ItemType::Environment(environment_item) = &node.item.get().unwrap().specialization else {
return Err(eyre!("Wrong item type?")) return Err(eyre!("Wrong item type?"))
}; };
Ok(serialize(environment_item.path.as_str())?.into()) Ok(flexbuffers::singleton(environment_item.path.as_str()))
});
} }
}
pub fn serialize_start_data(&self, id: &str) -> Result<Message> { impl ItemSpecialization for EnvironmentItem {
Ok(serialize((id, self.path.as_str()))?.into()) fn serialize_start_data(&self, id: &str) -> Vec<u8> {
serialize((id, self.path.as_str())).unwrap()
} }
} }
pub(super) fn create_environment_item_flex( pub(super) fn create_environment_item_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateEnvironmentItemInfo<'a> { struct CreateEnvironmentItemInfo<'a> {
@@ -78,7 +71,7 @@ pub(super) fn create_environment_item_flex(
transform: Transform, transform: Transform,
item_data: String, item_data: String,
} }
let info: CreateEnvironmentItemInfo = deserialize(message.as_ref())?; let info: CreateEnvironmentItemInfo = deserialize(data)?;
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_ENVIRONMENT.type_name); let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_ENVIRONMENT.type_name);
let space = find_spatial_parent(&calling_client, info.parent_path)?; let space = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);

View File

@@ -1,27 +1,26 @@
pub mod camera;
mod environment; mod environment;
pub mod panel;
use self::camera::CameraItem;
use self::environment::{EnvironmentItem, ITEM_TYPE_INFO_ENVIRONMENT}; use self::environment::{EnvironmentItem, ITEM_TYPE_INFO_ENVIRONMENT};
use self::panel::{PanelItemTrait, ITEM_TYPE_INFO_PANEL};
use super::fields::Field; use super::fields::Field;
use super::spatial::{find_spatial_parent, parse_transform, Spatial}; use super::spatial::{find_spatial_parent, parse_transform, Spatial};
use super::{Alias, Message, Node}; use super::{Alias, Node};
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::node_collections::LifeLinkedNodeMap; use crate::core::node_collections::LifeLinkedNodeMap;
use crate::core::registry::Registry; use crate::core::registry::Registry;
use crate::nodes::alias::AliasInfo; use crate::nodes::alias::AliasInfo;
use crate::nodes::fields::find_field; use crate::nodes::fields::find_field;
#[cfg(feature = "wayland")]
use crate::wayland::panel_item::{PanelItem, ITEM_TYPE_INFO_PANEL};
use color_eyre::eyre::{ensure, eyre, Result}; use color_eyre::eyre::{ensure, eyre, Result};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use nanoid::nanoid; use nanoid::nanoid;
use parking_lot::Mutex; use parking_lot::Mutex;
use portable_atomic::Ordering; use portable_atomic::Ordering;
use serde::Deserialize; use serde::Deserialize;
use stardust_xr::schemas::flex::{deserialize, serialize}; use stardust_xr::schemas::flex::{deserialize, flexbuffers, serialize};
use stardust_xr::values::Transform; use stardust_xr::values::Transform;
use std::hash::Hash; use std::hash::Hash;
use std::ops::Deref;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
lazy_static! { lazy_static! {
@@ -39,8 +38,8 @@ lazy_static! {
} }
pub fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) { pub fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) {
if item.captured_acceptor.lock().strong_count() > 0 { if let Some(acceptor) = item.captured_acceptor.lock().upgrade() {
release(item); release(item, Some(&acceptor));
} }
*item.captured_acceptor.lock() = Arc::downgrade(acceptor); *item.captured_acceptor.lock() = Arc::downgrade(acceptor);
acceptor.handle_capture(item); acceptor.handle_capture(item);
@@ -48,9 +47,9 @@ pub fn capture(item: &Arc<Item>, acceptor: &Arc<ItemAcceptor>) {
ui.handle_capture_item(item, acceptor); ui.handle_capture_item(item, acceptor);
} }
} }
fn release(item: &Item) { fn release(item: &Item, acceptor: Option<&ItemAcceptor>) {
let mut captured_acceptor = item.captured_acceptor.lock(); let mut captured_acceptor = item.captured_acceptor.lock();
if let Some(acceptor) = captured_acceptor.upgrade().as_ref() { if let Some(acceptor) = captured_acceptor.upgrade().as_deref().or(acceptor) {
*captured_acceptor = Weak::default(); *captured_acceptor = Weak::default();
acceptor.handle_release(item); acceptor.handle_release(item);
if let Some(ui) = item.type_info.ui.lock().upgrade() { if let Some(ui) = item.type_info.ui.lock().upgrade() {
@@ -109,15 +108,15 @@ impl Item {
} }
let _ = node.item.set(item.clone()); let _ = node.item.set(item.clone());
// if let Some(auto_acceptor) = node.get_client().and_then(|client| { if let Some(auto_acceptor) = node.get_client().and_then(|client| {
// client client
// .state .startup_settings
// .as_ref() .as_ref()
// .and_then(|settings| settings.acceptors.get(type_info)) .and_then(|settings| settings.acceptors.get(type_info))
// .and_then(|acceptor| acceptor.upgrade()) .and_then(|acceptor| acceptor.upgrade())
// }) { }) {
// capture(&item, &auto_acceptor); capture(&item, &auto_acceptor);
// } }
item item
} }
@@ -155,9 +154,9 @@ impl Item {
self.make_alias_named(client, parent, &self.uid) self.make_alias_named(client, parent, &self.uid)
} }
fn release_flex(node: &Node, _calling_client: Arc<Client>, _message: Message) -> Result<()> { fn release_flex(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
let item = node.get_aspect("Item", "item", |n| &n.item)?; let item = node.get_aspect("Item", "item", |n| &n.item)?;
release(item); release(item, None);
Ok(()) Ok(())
} }
@@ -165,37 +164,33 @@ impl Item {
impl Drop for Item { impl Drop for Item {
fn drop(&mut self) { fn drop(&mut self) {
self.type_info.items.remove(self); self.type_info.items.remove(self);
release(self); release(self, None);
if let Some(ui) = self.type_info.ui.lock().upgrade() { if let Some(ui) = self.type_info.ui.lock().upgrade() {
ui.handle_destroy_item(self); ui.handle_destroy_item(self);
} }
} }
} }
pub enum ItemType { pub trait ItemSpecialization {
Camera(CameraItem), fn serialize_start_data(&self, id: &str) -> Vec<u8>;
Environment(EnvironmentItem),
Panel(Arc<dyn PanelItemTrait>),
} }
impl ItemType {
fn serialize_start_data(&self, id: &str) -> Result<Message> { pub enum ItemType {
Environment(EnvironmentItem),
#[cfg(feature = "wayland")]
Panel(Arc<PanelItem>),
}
impl Deref for ItemType {
type Target = dyn ItemSpecialization;
fn deref(&self) -> &Self::Target {
match self { match self {
ItemType::Camera(c) => c.serialize_start_data(id), ItemType::Environment(item) => item,
ItemType::Environment(e) => e.serialize_start_data(id), #[cfg(feature = "wayland")]
ItemType::Panel(p) => p.serialize_start_data(id), ItemType::Panel(item) => item.as_ref(),
} }
} }
} }
// impl Deref for ItemType {
// type Target = dyn ItemSpecialization;
// fn deref(&self) -> &Self::Target {
// match self {
// ItemType::Environment(item) => item,
// ItemType::Panel(item) => item.as_ref(),
// }
// }
// }
pub struct ItemUI { pub struct ItemUI {
node: Weak<Node>, node: Weak<Node>,
@@ -230,44 +225,49 @@ impl ItemUI {
Ok(()) Ok(())
} }
fn send_state(&self, state: &str, name: &str) { fn send_state(&self, state: &str, name: &str) {
let Ok(serialized_data) = serialize(name) else {return};
let _ = self let _ = self
.node .node
.upgrade() .upgrade()
.unwrap() .unwrap()
.send_remote_signal(state, serialized_data); .send_remote_signal(state, flexbuffers::singleton(name).as_slice());
} }
fn handle_create_item(&self, item: &Item) { fn handle_create_item(&self, item: &Item) {
let Some(node) = self.node.upgrade() else {return}; let Some(node) = self.node.upgrade() else { return };
let Some(client) = node.get_client() else {return}; let Some(client) = node.get_client() else { return };
if let Ok(alias_node) = item.make_alias(&client, &(node.get_path().to_string() + "/item")) { if let Ok(alias_node) = item.make_alias(&client, &(node.get_path().to_string() + "/item")) {
self.item_aliases.add(item.uid.clone(), &alias_node); self.item_aliases.add(item.uid.clone(), &alias_node);
} }
let Ok(serialized_data) = item.specialization.serialize_start_data(&item.uid) else {return}; let _ = node.send_remote_signal(
let _ = node.send_remote_signal("create_item", serialized_data); "create_item",
&item.specialization.serialize_start_data(&item.uid),
);
} }
fn handle_destroy_item(&self, item: &Item) { fn handle_destroy_item(&self, item: &Item) {
self.item_aliases.remove(&item.uid); self.item_aliases.remove(&item.uid);
self.send_state("destroy_item", item.uid.as_str()); self.send_state("destroy_item", item.uid.as_str());
} }
fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) { fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) {
let Some(node) = self.node.upgrade() else {return}; let Some(node) = self.node.upgrade() else { return };
let Ok(message) = serialize((item.uid.as_str(), acceptor.uid.as_str())) else {return}; let _ = node.send_remote_signal(
let _ = node.send_remote_signal("capture_item", message); "capture_item",
&serialize((item.uid.as_str(), acceptor.uid.as_str())).unwrap(),
);
} }
fn handle_release_item(&self, item: &Item, acceptor: &ItemAcceptor) { fn handle_release_item(&self, item: &Item, acceptor: &ItemAcceptor) {
let Some(node) = self.node.upgrade() else {return}; let Some(node) = self.node.upgrade() else { return };
let Ok(message) = serialize((item.uid.as_str(), acceptor.uid.as_str())) else {return}; let _ = node.send_remote_signal(
let _ = node.send_remote_signal("release_item", message); "release_item",
&serialize((item.uid.as_str(), acceptor.uid.as_str())).unwrap(),
);
} }
fn handle_create_acceptor(&self, acceptor: &ItemAcceptor) { fn handle_create_acceptor(&self, acceptor: &ItemAcceptor) {
let Some(node) = self.node.upgrade() else {return}; let Some(node) = self.node.upgrade() else { return };
let Some(client) = node.get_client() else {return}; let Some(client) = node.get_client() else { return };
let Ok((alias, field_alias)) = acceptor.make_aliases( let Ok((alias, field_alias)) = acceptor.make_aliases(
&client, &client,
@@ -276,8 +276,7 @@ impl ItemUI {
self.acceptor_aliases.add(acceptor.uid.clone(), &alias); self.acceptor_aliases.add(acceptor.uid.clone(), &alias);
self.acceptor_field_aliases self.acceptor_field_aliases
.add(acceptor.uid.clone(), &field_alias); .add(acceptor.uid.clone(), &field_alias);
let Ok(message) = serialize(&acceptor.uid) else {return}; let _ = node.send_remote_signal("create_acceptor", &serialize(&acceptor.uid).unwrap());
let _ = node.send_remote_signal("create_acceptor", message);
} }
fn handle_destroy_acceptor(&self, acceptor: &ItemAcceptor) { fn handle_destroy_acceptor(&self, acceptor: &ItemAcceptor) {
self.send_state("destroy_acceptor", acceptor.uid.as_str()); self.send_state("destroy_acceptor", acceptor.uid.as_str());
@@ -316,13 +315,13 @@ impl ItemAcceptor {
let _ = node.item_acceptor.set(acceptor); let _ = node.item_acceptor.set(acceptor);
} }
fn capture_flex(node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { fn capture_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
if !node.enabled.load(Ordering::Relaxed) { if !node.enabled.load(Ordering::Relaxed) {
return Ok(()); return Ok(());
} }
let acceptor = node.item_acceptor.get().unwrap(); let acceptor = node.item_acceptor.get().unwrap();
let item_path: &str = deserialize(message.as_ref())?; let item_path: &str = deserialize(data)?;
let item_node = calling_client.get_node("Item", item_path)?; let item_node = calling_client.get_node("Item", item_path)?;
let item = item_node.get_aspect("Item", "item", |n| &n.item)?; let item = item_node.get_aspect("Item", "item", |n| &n.item)?;
capture(item, acceptor); capture(item, acceptor);
@@ -354,31 +353,31 @@ impl ItemAcceptor {
Ok((acceptor_alias, acceptor_field_alias)) Ok((acceptor_alias, acceptor_field_alias))
} }
fn handle_capture(&self, item: &Arc<Item>) { fn handle_capture(&self, item: &Arc<Item>) {
let Some(node) = self.node.upgrade() else {return}; let Some(node) = self.node.upgrade() else { return };
let Some(client) = node.get_client() else {return}; let Some(client) = node.get_client() else { return };
self.accepted_registry.add_raw(item); self.accepted_registry.add_raw(item);
if let Ok(alias_node) = item.make_alias(&client, &node.path) { if let Ok(alias_node) = item.make_alias(&client, &node.path) {
self.accepted_aliases.add(item.uid.clone(), &alias_node); self.accepted_aliases.add(item.uid.clone(), &alias_node);
} }
let _ = node.send_remote_signal(
let Ok(serialized_data) = item.specialization.serialize_start_data(&item.uid) else {return}; "capture",
let _ = node.send_remote_signal("capture", serialized_data); &item.specialization.serialize_start_data(&item.uid),
);
} }
fn handle_release(&self, item: &Item) { fn handle_release(&self, item: &Item) {
let Some(node) = self.node.upgrade() else {return}; let Some(node) = self.node.upgrade() else { return };
self.accepted_registry.remove(item); self.accepted_registry.remove(item);
self.accepted_aliases.remove(&item.uid); self.accepted_aliases.remove(&item.uid);
let Ok(message) = serialize(&item.uid) else {return}; let _ = node.send_remote_signal("release", &serialize(&item.uid).unwrap());
let _ = node.send_remote_signal("release", message);
} }
} }
impl Drop for ItemAcceptor { impl Drop for ItemAcceptor {
fn drop(&mut self) { fn drop(&mut self) {
self.type_info.acceptors.remove(self); self.type_info.acceptors.remove(self);
for item in self.accepted_registry.get_valid_contents() { for item in self.accepted_registry.get_valid_contents() {
release(&item); release(&item, Some(self));
} }
if let Some(ui) = self.type_info.ui.lock().upgrade() { if let Some(ui) = self.type_info.ui.lock().upgrade() {
ui.handle_destroy_acceptor(self); ui.handle_destroy_acceptor(self);
@@ -388,7 +387,6 @@ impl Drop for ItemAcceptor {
pub fn create_interface(client: &Arc<Client>) -> Result<()> { pub fn create_interface(client: &Arc<Client>) -> Result<()> {
let node = Node::create(client, "", "item", false); let node = Node::create(client, "", "item", false);
node.add_local_signal("create_camera_item", camera::create_camera_item_flex);
node.add_local_signal( node.add_local_signal(
"create_environment_item", "create_environment_item",
environment::create_environment_item_flex, environment::create_environment_item_flex,
@@ -407,16 +405,12 @@ fn type_info(name: &str) -> Result<&'static TypeInfo> {
} }
} }
pub fn register_item_ui_flex( pub fn register_item_ui_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
_node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct RegisterItemUIInfo<'a> { struct RegisterItemUIInfo<'a> {
item_type: &'a str, item_type: &'a str,
} }
let info: RegisterItemUIInfo = deserialize(message.as_ref())?; let info: RegisterItemUIInfo = deserialize(data)?;
let type_info = type_info(info.item_type)?; let type_info = type_info(info.item_type)?;
let ui = let ui =
Node::create(&calling_client, "/item", type_info.type_name, true).add_to_scenegraph()?; Node::create(&calling_client, "/item", type_info.type_name, true).add_to_scenegraph()?;
@@ -424,11 +418,7 @@ pub fn register_item_ui_flex(
Ok(()) Ok(())
} }
fn create_item_acceptor_flex( fn create_item_acceptor_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
_node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateItemAcceptorInfo<'a> { struct CreateItemAcceptorInfo<'a> {
name: &'a str, name: &'a str,
@@ -437,7 +427,7 @@ fn create_item_acceptor_flex(
field_path: &'a str, field_path: &'a str,
item_type: &'a str, item_type: &'a str,
} }
let info: CreateItemAcceptorInfo = deserialize(message.as_ref())?; let info: CreateItemAcceptorInfo = deserialize(data)?;
let space = find_spatial_parent(&calling_client, info.parent_path)?; let space = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);
let field = find_field(&calling_client, info.field_path)?; let field = find_field(&calling_client, info.field_path)?;

View File

@@ -1,542 +0,0 @@
use crate::{
core::{
client::{get_env, state, Client, INTERNAL_CLIENT},
registry::Registry,
},
nodes::{
drawable::{model::ModelPart, Drawable},
items::{Item, ItemType, TypeInfo},
spatial::Spatial,
Message, Node,
},
};
use color_eyre::eyre::{bail, eyre, Result};
use glam::Mat4;
use lazy_static::lazy_static;
use mint::Vector2;
use nanoid::nanoid;
use rustc_hash::FxHashMap;
use serde::{
de::{Deserializer, Error, SeqAccess, Visitor},
ser::Serializer,
Deserialize, Serialize,
};
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::sync::{Arc, Weak};
use tracing::debug;
lazy_static! {
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
type_name: "panel",
aliased_local_signals: vec![
"apply_surface_material",
"close_toplevel",
"auto_size_toplevel",
"set_toplevel_size",
"set_toplevel_focused_visuals",
"pointer_motion",
"pointer_button",
"pointer_scroll",
"keyboard_keymap",
"keyboard_key",
"touch_down",
"touch_move",
"touch_up",
"reset_touches",
],
aliased_local_methods: vec![],
aliased_remote_signals: vec![
"toplevel_parent_changed",
"toplevel_title_changed",
"toplevel_app_id_changed",
"toplevel_fullscreen_active",
"toplevel_move_request",
"toplevel_resize_request",
"toplevel_size_changed",
"set_cursor",
"new_child",
"reposition_child",
"drop_child",
],
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
};
}
/// An ID for a surface inside this panel item
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum SurfaceID {
Cursor,
Toplevel,
Child(String),
}
impl Default for SurfaceID {
fn default() -> Self {
Self::Toplevel
}
}
impl<'de> serde::Deserialize<'de> for SurfaceID {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_seq(SurfaceIDVisitor)
}
}
struct SurfaceIDVisitor;
impl<'de> Visitor<'de> for SurfaceIDVisitor {
type Value = SurfaceID;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("idk")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let Some(discrim) = seq.next_element()? else {
return Err(A::Error::missing_field("discrim"));
};
// idk if you wanna check for extraneous elements
// I didn't bother
match discrim {
"Cursor" => Ok(SurfaceID::Cursor),
"Toplevel" => Ok(SurfaceID::Toplevel),
"Child" => {
let Some(text) = seq.next_element()? else {
return Err(A::Error::missing_field("child_text"));
};
Ok(SurfaceID::Child(text))
}
_ => Err(A::Error::unknown_variant(
discrim,
&["Cursor", "Toplevel", "Child"],
)),
}
}
}
impl serde::Serialize for SurfaceID {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Cursor => ["Cursor"].serialize(serializer),
Self::Toplevel => ["Toplevel"].serialize(serializer),
Self::Child(text) => ["Child", text].serialize(serializer),
}
}
}
/// The origin and size of the surface's "solid" part.
#[derive(Debug, Serialize, Clone, Copy)]
pub struct Geometry {
pub origin: Vector2<i32>,
pub size: Vector2<u32>,
}
/// The state of the panel item's toplevel.
#[derive(Debug, Clone, Serialize)]
pub struct ToplevelInfo {
/// The UID of the panel item of the parent of this toplevel, if it exists
pub parent: Option<String>,
/// Equivalent to the window title
pub title: Option<String>,
/// Application identifier, see <https://standards.freedesktop.org/desktop-entry-spec/>
pub app_id: Option<String>,
/// Current size in pixels
pub size: Vector2<u32>,
/// Recommended minimum size in pixels
pub min_size: Option<Vector2<u32>>,
/// Recommended maximum size in pixels
pub max_size: Option<Vector2<u32>>,
/// Surface geometry
pub logical_rectangle: Geometry,
}
/// Data on positioning a child
#[derive(Debug, Clone, Serialize)]
pub struct ChildInfo {
pub parent: SurfaceID,
pub geometry: Geometry,
}
/// The init data for the panel item.
#[derive(Debug, Clone, Serialize)]
pub struct PanelItemInitData {
/// The cursor, if applicable.
pub cursor: Option<Geometry>,
/// Size of the toplevel surface in pixels.
pub toplevel: ToplevelInfo,
/// Vector of childs that already exist
pub children: FxHashMap<String, ChildInfo>,
/// The surface, if any, that has exclusive input to the pointer.
pub pointer_grab: Option<SurfaceID>,
/// The surface, if any, that has exclusive input to the keyboard.
pub keyboard_grab: Option<SurfaceID>,
}
pub trait Backend: Send + Sync + 'static {
fn start_data(&self) -> Result<PanelItemInitData>;
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>);
fn close_toplevel(&self);
fn auto_size_toplevel(&self);
fn set_toplevel_size(&self, size: Vector2<u32>);
fn set_toplevel_focused_visuals(&self, focused: bool);
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>);
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool);
fn pointer_scroll(
&self,
surface: &SurfaceID,
scroll_distance: Option<Vector2<f32>>,
scroll_steps: Option<Vector2<f32>>,
);
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>);
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>);
fn touch_move(&self, id: u32, position: Vector2<f32>);
fn touch_up(&self, id: u32);
fn reset_touches(&self);
}
pub fn panel_item_from_node(node: &Node) -> Option<Arc<dyn PanelItemTrait>> {
let ItemType::Panel(panel_item) = &node.item.get()?.specialization else {return None};
Some(panel_item.clone())
}
pub trait PanelItemTrait: Backend + Send + Sync + 'static {
fn uid(&self) -> &str;
fn serialize_start_data(&self, id: &str) -> Result<Message>;
}
pub struct PanelItem<B: Backend + ?Sized> {
pub uid: String,
node: Weak<Node>,
pub backend: Box<B>,
}
impl<B: Backend + ?Sized> PanelItem<B> {
pub fn create(backend: Box<B>, pid: Option<i32>) -> Arc<PanelItem<B>> {
debug!(?pid, "Create panel item");
let startup_settings = pid
.and_then(|pid| get_env(pid).ok())
.and_then(|env| state(&env));
let uid = nanoid!();
let node = Node::create(&INTERNAL_CLIENT, "/item/panel/item", &uid, true)
.add_to_scenegraph()
.unwrap();
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false).unwrap();
if let Some(startup_settings) = &startup_settings {
spatial.set_local_transform(startup_settings.root);
}
let panel_item = Arc::new(PanelItem {
uid: uid.clone(),
node: Arc::downgrade(&node),
backend,
});
let generic_panel_item: Arc<dyn PanelItemTrait> = panel_item.clone();
Item::add_to(
&node,
uid,
&ITEM_TYPE_INFO_PANEL,
ItemType::Panel(generic_panel_item),
);
node.add_local_signal("apply_surface_material", Self::apply_surface_material_flex);
node.add_local_signal("close_toplevel", Self::close_toplevel_flex);
node.add_local_signal("auto_size_toplevel", Self::auto_size_toplevel_flex);
node.add_local_signal(
"set_toplevel_size_changed",
Self::set_toplevel_size_changed_flex,
);
node.add_local_signal("pointer_motion", Self::pointer_motion_flex);
node.add_local_signal("pointer_button", Self::pointer_button_flex);
node.add_local_signal("pointer_scroll", Self::pointer_scroll_flex);
node.add_local_signal("keyboard_key", Self::keyboard_keys_flex);
node.add_local_signal("touch_down", Self::touch_down_flex);
node.add_local_signal("touch_move", Self::touch_move_flex);
node.add_local_signal("touch_up", Self::touch_up_flex);
node.add_local_signal("reset_touches", Self::reset_touches_flex);
panel_item
}
pub fn drop_toplevel(&self) {
let Some(node) = self.node.upgrade() else {return};
node.destroy();
}
}
// Remote signals
impl<B: Backend + ?Sized> PanelItem<B> {
pub fn toplevel_parent_changed(&self, parent: &str) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("toplevel_parent_changed", serialize(parent).unwrap());
}
pub fn toplevel_title_changed(&self, title: &str) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("toplevel_title_changed", serialize(title).unwrap());
}
pub fn toplevel_app_id_changed(&self, app_id: &str) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("toplevel_app_id_changed", serialize(app_id).unwrap());
}
pub fn toplevel_fullscreen_active(&self, active: bool) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("toplevel_fullscreen_active", serialize(active).unwrap());
}
pub fn toplevel_move_request(&self) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("toplevel_move_request", Vec::<u8>::new());
}
pub fn toplevel_resize_request(&self, up: bool, down: bool, left: bool, right: bool) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal(
"toplevel_resize_request",
serialize((up, down, left, right)).unwrap(),
);
}
pub fn toplevel_size_changed(&self, size: Vector2<u32>) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("toplevel_size_changed", serialize(size).unwrap());
}
pub fn set_cursor(&self, geometry: Option<Geometry>) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("set_cursor", serialize(geometry).unwrap());
}
pub fn new_child(&self, uid: &str, info: ChildInfo) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("new_child", serialize((uid, info)).unwrap());
}
pub fn reposition_child(&self, uid: &str, geometry: Geometry) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("reposition_child", serialize((uid, geometry)).unwrap());
}
pub fn drop_child(&self, uid: &str) {
let Some(node) = self.node.upgrade() else {return};
let _ = node.send_remote_signal("drop_child", serialize(uid).unwrap());
}
}
// Local signals
macro_rules! flex_no_args {
($fn_name: ident, $trait_fn: ident) => {
fn $fn_name(node: &Node, _calling_client: Arc<Client>, _message: Message) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
panel_item.$trait_fn();
Ok(())
}
};
}
macro_rules! flex_deserialize {
($fn_name: ident, $trait_fn: ident) => {
fn $fn_name(node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
panel_item.$trait_fn(deserialize(message.as_ref())?);
Ok(())
}
};
}
impl<B: Backend + ?Sized> PanelItem<B> {
fn apply_surface_material_flex(
node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
#[derive(Debug, Deserialize)]
struct SurfaceMaterialInfo<'a> {
surface: SurfaceID,
model_node_path: &'a str,
}
let info: SurfaceMaterialInfo = deserialize(message.as_ref())?;
let model_node = calling_client
.scenegraph
.get_node(info.model_node_path)
.ok_or_else(|| eyre!("Model node not found"))?;
let Some(Drawable::ModelPart(model_part)) = model_node.drawable.get() else {bail!("Node is not a model")};
debug!(?info, "Apply surface material");
panel_item.apply_surface_material(info.surface, model_part);
Ok(())
}
flex_no_args!(close_toplevel_flex, close_toplevel);
flex_no_args!(auto_size_toplevel_flex, auto_size_toplevel);
flex_deserialize!(set_toplevel_size_changed_flex, set_toplevel_size);
fn pointer_motion_flex(
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
let (surface_id, position): (SurfaceID, Vector2<f32>) = deserialize(message.as_ref())?;
debug!(?surface_id, ?position, "Pointer deactivate");
panel_item.pointer_motion(&surface_id, position);
Ok(())
}
fn pointer_button_flex(
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
let (surface_id, button, state): (SurfaceID, u32, u32) = deserialize(message.as_ref())?;
debug!(?surface_id, button, state, "Pointer button");
panel_item.pointer_button(&surface_id, button, state != 0);
Ok(())
}
fn pointer_scroll_flex(
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
#[derive(Debug, Deserialize)]
struct PointerScrollInfo {
surface_id: SurfaceID,
axis_continuous: Option<Vector2<f32>>,
axis_discrete: Option<Vector2<f32>>,
}
let info: PointerScrollInfo = deserialize(message.as_ref())?;
debug!(?info, "Pointer scroll");
panel_item.pointer_scroll(&info.surface_id, info.axis_continuous, info.axis_discrete);
Ok(())
}
fn keyboard_keys_flex(
node: &Node,
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
let (surface_id, keymap_id, keys): (SurfaceID, &str, Vec<i32>) =
deserialize(message.as_ref())?;
debug!(?keys, "Set keyboard key state");
panel_item.keyboard_keys(&surface_id, keymap_id, keys);
Ok(())
}
pub fn grab_keyboard(&self, sid: Option<SurfaceID>) {
let Some(node) = self.node.upgrade() else {return};
let Ok(message) = serialize(sid) else {return};
let _ = node.send_remote_signal("grab_keyboard", message);
}
fn touch_down_flex(node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
let (surface_id, id, position): (SurfaceID, u32, Vector2<f32>) =
deserialize(message.as_ref())?;
debug!(?surface_id, id, ?position, "Touch down");
panel_item.touch_down(&surface_id, id, position);
Ok(())
}
fn touch_move_flex(node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<()> {
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
let (id, position): (u32, Vector2<f32>) = deserialize(message.as_ref())?;
debug!(?position, "Touch move");
panel_item.touch_move(id, position);
Ok(())
}
flex_deserialize!(touch_up_flex, touch_up);
flex_no_args!(reset_touches_flex, reset_touches);
}
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
fn uid(&self) -> &str {
&self.uid
}
fn serialize_start_data(&self, id: &str) -> Result<Message> {
Ok(serialize((id, self.start_data()?))?.into())
}
}
impl<B: Backend + ?Sized> Backend for PanelItem<B> {
fn start_data(&self) -> Result<PanelItemInitData> {
self.backend.start_data()
}
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
self.backend.apply_surface_material(surface, model_part)
}
fn close_toplevel(&self) {
self.backend.close_toplevel()
}
fn auto_size_toplevel(&self) {
self.backend.auto_size_toplevel()
}
fn set_toplevel_size(&self, size: Vector2<u32>) {
self.backend.set_toplevel_size(size)
}
fn set_toplevel_focused_visuals(&self, focused: bool) {
self.backend.set_toplevel_focused_visuals(focused)
}
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
self.backend.pointer_motion(surface, position)
}
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool) {
self.backend.pointer_button(surface, button, pressed)
}
fn pointer_scroll(
&self,
surface: &SurfaceID,
scroll_distance: Option<Vector2<f32>>,
scroll_steps: Option<Vector2<f32>>,
) {
self.backend
.pointer_scroll(surface, scroll_distance, scroll_steps)
}
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
self.backend.keyboard_keys(surface, keymap_id, keys)
}
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>) {
self.backend.touch_down(surface, id, position)
}
fn touch_move(&self, id: u32, position: Vector2<f32>) {
self.backend.touch_move(id, position)
}
fn touch_up(&self, id: u32) {
self.backend.touch_up(id)
}
fn reset_touches(&self) {
self.backend.reset_touches()
}
}
impl<B: Backend + ?Sized> Drop for PanelItem<B> {
fn drop(&mut self) {
// Dropped panel item, basically just a debug breakpoint place
}
}

View File

@@ -8,25 +8,26 @@ pub mod input;
pub mod items; pub mod items;
pub mod root; pub mod root;
pub mod spatial; pub mod spatial;
pub mod startup;
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
use core::hash::BuildHasherDefault;
use dashmap::DashMap;
use nanoid::nanoid; use nanoid::nanoid;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use portable_atomic::{AtomicBool, Ordering}; use portable_atomic::{AtomicBool, Ordering};
use rustc_hash::FxHashMap; use rustc_hash::FxHasher;
use stardust_xr::messenger::MessageSenderHandle; use stardust_xr::messenger::MessageSenderHandle;
use stardust_xr::scenegraph::ScenegraphError; use stardust_xr::scenegraph::ScenegraphError;
use stardust_xr::schemas::flex::deserialize; use stardust_xr::schemas::flex::deserialize;
use std::fmt::Debug; use std::fmt::Debug;
use std::future::Future;
use std::os::fd::OwnedFd;
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use std::vec::Vec; use std::vec::Vec;
use tracing::{debug_span, instrument};
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::registry::Registry; use crate::core::registry::Registry;
use crate::core::scenegraph::MethodResponseSender;
use self::alias::Alias; use self::alias::Alias;
use self::audio::Sound; use self::audio::Sound;
@@ -37,28 +38,10 @@ use self::input::{InputHandler, InputMethod};
use self::items::{Item, ItemAcceptor, ItemUI}; use self::items::{Item, ItemAcceptor, ItemUI};
use self::spatial::zone::Zone; use self::spatial::zone::Zone;
use self::spatial::Spatial; use self::spatial::Spatial;
use self::startup::StartupSettings;
#[derive(Default)] pub type Signal = fn(&Node, Arc<Client>, &[u8]) -> Result<()>;
pub struct Message { pub type Method = fn(&Node, Arc<Client>, &[u8]) -> Result<Vec<u8>>;
pub data: Vec<u8>,
pub fds: Vec<OwnedFd>,
}
impl From<Vec<u8>> for Message {
fn from(data: Vec<u8>) -> Self {
Message {
data,
fds: Vec::new(),
}
}
}
impl AsRef<[u8]> for Message {
fn as_ref(&self) -> &[u8] {
&self.data
}
}
pub type Signal = fn(&Node, Arc<Client>, Message) -> Result<()>;
pub type Method = fn(&Node, Arc<Client>, Message, MethodResponseSender);
pub struct Node { pub struct Node {
pub enabled: Arc<AtomicBool>, pub enabled: Arc<AtomicBool>,
@@ -67,8 +50,8 @@ pub struct Node {
client: Weak<Client>, client: Weak<Client>,
message_sender_handle: Option<MessageSenderHandle>, message_sender_handle: Option<MessageSenderHandle>,
// trailing_slash_pos: usize, // trailing_slash_pos: usize,
local_signals: Mutex<FxHashMap<String, Signal>>, local_signals: DashMap<String, Signal, BuildHasherDefault<FxHasher>>,
local_methods: Mutex<FxHashMap<String, Method>>, local_methods: DashMap<String, Method, BuildHasherDefault<FxHasher>>,
destroyable: bool, destroyable: bool,
pub alias: OnceCell<Arc<Alias>>, pub alias: OnceCell<Arc<Alias>>,
@@ -96,6 +79,9 @@ pub struct Node {
// Sound // Sound
pub sound: OnceCell<Arc<Sound>>, pub sound: OnceCell<Arc<Sound>>,
// Startup
pub startup_settings: OnceCell<Mutex<StartupSettings>>,
} }
impl Node { impl Node {
@@ -139,6 +125,7 @@ impl Node {
item_acceptor: OnceCell::new(), item_acceptor: OnceCell::new(),
item_ui: OnceCell::new(), item_ui: OnceCell::new(),
sound: OnceCell::new(), sound: OnceCell::new(),
startup_settings: OnceCell::new(),
}; };
node.add_local_signal("set_enabled", Node::set_enabled_flex); node.add_local_signal("set_enabled", Node::set_enabled_flex);
node.add_local_signal("destroy", Node::destroy_flex); node.add_local_signal("destroy", Node::destroy_flex);
@@ -157,33 +144,11 @@ impl Node {
} }
} }
pub fn set_enabled_flex( pub fn set_enabled_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node, node.enabled.store(deserialize(data)?, Ordering::Relaxed);
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
node.enabled
.store(deserialize(message.as_ref())?, Ordering::Relaxed);
Ok(()) Ok(())
} }
// very much up for debate if we should allow this, as you can match objects using this pub fn destroy_flex(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
// pub fn get_client_pid_flex(
// node: &Node,
// _calling_client: Arc<Client>,
// _message: Message,
// ) -> Result<Message> {
// let client = node
// .client
// .upgrade()
// .ok_or_else(|| eyre!("Could not get client for node?"))?;
// let pid = client.pid.ok_or_else(|| eyre!("Client PID is unknown"))?;
// Ok(serialize(pid)?.into())
// }
pub fn destroy_flex(
node: &Node,
_calling_client: Arc<Client>,
_message: Message,
) -> Result<()> {
if node.destroyable { if node.destroyable {
node.destroy(); node.destroy();
} }
@@ -191,10 +156,10 @@ impl Node {
} }
pub fn add_local_signal(&self, name: &str, signal: Signal) { pub fn add_local_signal(&self, name: &str, signal: Signal) {
self.local_signals.lock().insert(name.to_string(), signal); self.local_signals.insert(name.to_string(), signal);
} }
pub fn add_local_method(&self, name: &str, method: Method) { pub fn add_local_method(&self, name: &str, method: Method) {
self.local_methods.lock().insert(name.to_string(), method); self.local_methods.insert(name.to_string(), method);
} }
pub fn get_aspect<F, T>( pub fn get_aspect<F, T>(
@@ -215,7 +180,7 @@ impl Node {
&self, &self,
calling_client: Arc<Client>, calling_client: Arc<Client>,
method: &str, method: &str,
message: Message, data: &[u8],
) -> Result<(), ScenegraphError> { ) -> Result<(), ScenegraphError> {
if let Some(alias) = self.alias.get() { if let Some(alias) = self.alias.get() {
if !alias.info.server_signals.iter().any(|e| e == &method) { if !alias.info.server_signals.iter().any(|e| e == &method) {
@@ -225,15 +190,13 @@ impl Node {
.original .original
.upgrade() .upgrade()
.ok_or(ScenegraphError::BrokenAlias)? .ok_or(ScenegraphError::BrokenAlias)?
.send_local_signal(calling_client, method, message) .send_local_signal(calling_client, method, data)
} else { } else {
let signal = self let signal = self
.local_signals .local_signals
.lock()
.get(method) .get(method)
.cloned()
.ok_or(ScenegraphError::SignalNotFound)?; .ok_or(ScenegraphError::SignalNotFound)?;
signal(self, calling_client, message).map_err(|error| ScenegraphError::SignalError { signal(self, calling_client, data).map_err(|error| ScenegraphError::SignalError {
error: error.to_string(), error: error.to_string(),
}) })
} }
@@ -242,83 +205,63 @@ impl Node {
&self, &self,
calling_client: Arc<Client>, calling_client: Arc<Client>,
method: &str, method: &str,
message: Message, data: &[u8],
response: MethodResponseSender, ) -> Result<Vec<u8>, ScenegraphError> {
) {
if let Some(alias) = self.alias.get() { if let Some(alias) = self.alias.get() {
if !alias.info.server_methods.iter().any(|e| e == &method) { if !alias.info.server_methods.iter().any(|e| e == &method) {
response.send(Err(ScenegraphError::MethodNotFound)); return Err(ScenegraphError::MethodNotFound);
return;
} }
let Some(alias) = alias.original.upgrade() else { alias
response.send(Err(ScenegraphError::BrokenAlias)); .original
return; .upgrade()
}; .ok_or(ScenegraphError::BrokenAlias)?
alias.execute_local_method( .execute_local_method(calling_client, method, data)
calling_client,
method,
Message {
data: message.data.clone(),
fds: Vec::new(),
},
response,
)
} else { } else {
let Some(method) = self.local_methods.lock().get(method).cloned() else { let method = self
response.send(Err(ScenegraphError::MethodNotFound)); .local_methods
return; .get(method)
}; .ok_or(ScenegraphError::MethodNotFound)?;
method(self, calling_client, message, response);
debug_span!("Handle method").in_scope(|| {
method(self, calling_client, data).map_err(|error| ScenegraphError::MethodError {
error: error.to_string(),
})
})
} }
} }
pub fn send_remote_signal(&self, method: &str, message: impl Into<Message>) -> Result<()> { #[instrument(level = "debug", skip_all)]
let message = message.into(); pub fn send_remote_signal(&self, method: &str, data: &[u8]) -> Result<()> {
self.aliases self.aliases
.get_valid_contents() .get_valid_contents()
.iter() .iter()
.filter(|alias| alias.info.client_signals.iter().any(|e| e == &method)) .filter(|alias| alias.info.client_signals.iter().any(|e| e == &method))
.filter_map(|alias| alias.node.upgrade()) .filter_map(|alias| alias.node.upgrade())
.for_each(|node| { .for_each(|node| {
// Beware! file descriptors will not be sent to aliases!!! let _ = node.send_remote_signal(method, data);
let _ = node.send_remote_signal(
method,
Message {
data: message.data.clone(),
fds: Vec::new(),
},
);
}); });
let path = self.path.clone(); let path = self.path.clone();
let method = method.to_string(); let method = method.to_string();
let data = data.to_vec();
if let Some(handle) = self.message_sender_handle.as_ref() { if let Some(handle) = self.message_sender_handle.as_ref() {
handle.signal(path.as_str(), method.as_str(), &message.data, message.fds)?; handle.signal(path.as_str(), method.as_str(), data.as_slice())?;
} }
Ok(()) Ok(())
} }
pub fn execute_remote_method( // #[instrument(level = "debug", skip_all)]
&self, // pub fn execute_remote_method(
method: &str, // &self,
message: impl Into<Message>, // method: &str,
) -> Result<impl Future<Output = Result<Message>>> { // data: Vec<u8>,
let message = message.into(); // ) -> Result<impl Future<Output = Result<Vec<u8>>>> {
let message_sender_handle = self // let message_sender_handle = self
.message_sender_handle // .message_sender_handle
.as_ref() // .as_ref()
.ok_or(eyre!("Messenger does not exist for this node"))?; // .ok_or(eyre!("Messenger does not exist for this node"))?;
let future = // let future = message_sender_handle.method(self.path.as_str(), method, &data)?;
message_sender_handle.method(self.path.as_str(), method, &message.data, message.fds)?;
Ok(async { // Ok(async { future.await.map_err(|e| eyre!(e)) })
match future.await { // }
Ok(m) => {
let (data, fds) = m.into_components();
Ok(Message { data, fds })
}
Err(e) => Err(eyre!(e)),
}
})
}
} }
impl Debug for Node { impl Debug for Node {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

View File

@@ -1,25 +1,19 @@
use super::spatial::Spatial; use super::spatial::Spatial;
use super::{Message, Node}; use super::Node;
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::client_state::{ClientState, ClientStateInternal};
use crate::core::registry::Registry; use crate::core::registry::Registry;
use crate::core::scenegraph::MethodResponseSender;
use crate::wayland::WAYLAND_DISPLAY;
use crate::STARDUST_INSTANCE;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use glam::Mat4; use glam::Mat4;
use rustc_hash::FxHashMap;
use stardust_xr::schemas::flex::{deserialize, serialize}; use stardust_xr::schemas::flex::{deserialize, serialize};
use tracing::instrument; use tracing::instrument;
use std::future::Future;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
static ROOT_REGISTRY: Registry<Root> = Registry::new(); static ROOT_REGISTRY: Registry<Root> = Registry::new();
pub struct Root { pub struct Root {
pub node: Arc<Node>, node: Arc<Node>,
send_frame_event: AtomicBool, send_frame_event: AtomicBool,
} }
impl Root { impl Root {
@@ -27,13 +21,17 @@ impl Root {
let node = Node::create(client, "", "", false); let node = Node::create(client, "", "", false);
node.add_local_signal("subscribe_frame", Root::subscribe_frame_flex); node.add_local_signal("subscribe_frame", Root::subscribe_frame_flex);
node.add_local_signal("set_base_prefixes", Root::set_base_prefixes_flex); node.add_local_signal("set_base_prefixes", Root::set_base_prefixes_flex);
node.add_local_method("state_token", Root::state_token_flex);
node.add_local_method(
"get_connection_environment",
get_connection_environment_flex,
);
let node = node.add_to_scenegraph()?; let node = node.add_to_scenegraph()?;
let _ = Spatial::add_to(&node, None, client.state.root, false); let _ = Spatial::add_to(
&node,
None,
client
.startup_settings
.as_ref()
.map(|settings| settings.transform)
.unwrap_or(Mat4::IDENTITY),
false,
);
Ok(ROOT_REGISTRY.add(Root { Ok(ROOT_REGISTRY.add(Root {
node, node,
@@ -41,11 +39,7 @@ impl Root {
})) }))
} }
fn subscribe_frame_flex( fn subscribe_frame_flex(_node: &Node, calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
_node: &Node,
calling_client: Arc<Client>,
_message: Message,
) -> Result<()> {
calling_client calling_client
.root .root
.get() .get()
@@ -60,7 +54,7 @@ impl Root {
if let Ok(data) = serialize((delta, 0.0)) { if let Ok(data) = serialize((delta, 0.0)) {
for root in ROOT_REGISTRY.get_valid_contents() { for root in ROOT_REGISTRY.get_valid_contents() {
if root.send_frame_event.load(Ordering::Relaxed) { if root.send_frame_event.load(Ordering::Relaxed) {
let _ = root.node.send_remote_signal("frame", data.clone()); let _ = root.node.send_remote_signal("frame", &data);
} }
} }
} }
@@ -69,36 +63,11 @@ impl Root {
fn set_base_prefixes_flex( fn set_base_prefixes_flex(
_node: &Node, _node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
*calling_client.base_resource_prefixes.lock() = deserialize(message.as_ref())?; *calling_client.base_resource_prefixes.lock() = deserialize(data)?;
Ok(()) Ok(())
} }
fn state_token_flex(
_node: &Node,
calling_client: Arc<Client>,
message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(|| {
let state: ClientStateInternal = deserialize(message.as_ref())?;
let token = ClientState::from_deserialized(&calling_client, state).token();
Ok(serialize(token)?.into())
})
}
pub fn set_transform(&self, transform: Mat4) {
let spatial = self.node.spatial.get().unwrap();
spatial.set_spatial_parent(None).unwrap();
spatial.set_local_transform(transform);
}
pub fn save_state(&self) -> impl Future<Output = Result<ClientStateInternal>> {
let future = self
.node
.execute_remote_method("save_state", Message::default());
async move { Ok(deserialize(&future?.await?.data)?) }
}
} }
impl Drop for Root { impl Drop for Root {
@@ -106,33 +75,3 @@ impl Drop for Root {
ROOT_REGISTRY.remove(self); ROOT_REGISTRY.remove(self);
} }
} }
macro_rules! var_env_insert {
($env:ident, $name:ident) => {
$env.insert(stringify!($name).to_string(), $name.get().unwrap().clone());
};
}
pub fn get_connection_environment_flex(
_node: &Node,
_calling_client: Arc<Client>,
_message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(move || {
let mut env: FxHashMap<String, String> = FxHashMap::default();
var_env_insert!(env, STARDUST_INSTANCE);
#[cfg(feature = "wayland")]
{
var_env_insert!(env, WAYLAND_DISPLAY);
#[cfg(feature = "xwayland")]
var_env_insert!(env, DISPLAY);
env.insert("GDK_BACKEND".to_string(), "wayland".to_string());
env.insert("QT_QPA_PLATFORM".to_string(), "wayland".to_string());
env.insert("MOZ_ENABLE_WAYLAND".to_string(), "1".to_string());
env.insert("CLUTTER_BACKEND".to_string(), "wayland".to_string());
env.insert("SDL_VIDEODRIVER".to_string(), "wayland".to_string());
}
Ok(serialize(env)?.into())
});
}

View File

@@ -1,10 +1,9 @@
pub mod zone; pub mod zone;
use self::zone::{create_zone_flex, Zone}; use self::zone::{create_zone_flex, Zone};
use super::{Message, Node}; use super::Node;
use crate::core::client::Client; use crate::core::client::Client;
use crate::core::registry::Registry; use crate::core::registry::Registry;
use crate::core::scenegraph::MethodResponseSender;
use color_eyre::eyre::{ensure, eyre, Result}; use color_eyre::eyre::{ensure, eyre, Result};
use glam::{vec3a, Mat4, Quat}; use glam::{vec3a, Mat4, Quat};
use mint::Vector3; use mint::Vector3;
@@ -17,6 +16,7 @@ use std::fmt::Debug;
use std::ptr; use std::ptr;
use std::sync::{Arc, OnceLock, Weak}; use std::sync::{Arc, OnceLock, Weak};
use stereokit::{bounds_grow_to_fit_box, Bounds}; use stereokit::{bounds_grow_to_fit_box, Bounds};
use tracing::instrument;
static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new(); static ZONEABLE_REGISTRY: Registry<Spatial> = Registry::new();
@@ -80,6 +80,7 @@ impl Spatial {
self.node.upgrade() self.node.upgrade()
} }
#[instrument(level = "debug", skip_all)]
pub fn space_to_space_matrix(from: Option<&Spatial>, to: Option<&Spatial>) -> Mat4 { pub fn space_to_space_matrix(from: Option<&Spatial>, to: Option<&Spatial>) -> Mat4 {
let space_to_world_matrix = from.map_or(Mat4::IDENTITY, |from| from.global_transform()); let space_to_world_matrix = from.map_or(Mat4::IDENTITY, |from| from.global_transform());
let world_to_space_matrix = to.map_or(Mat4::IDENTITY, |to| to.global_transform().inverse()); let world_to_space_matrix = to.map_or(Mat4::IDENTITY, |to| to.global_transform().inverse());
@@ -87,6 +88,7 @@ impl Spatial {
} }
// the output bounds are probably way bigger than they need to be // the output bounds are probably way bigger than they need to be
#[instrument(level = "debug")]
pub fn get_bounding_box(&self) -> Bounds { pub fn get_bounding_box(&self) -> Bounds {
let Some(node) = self.node() else {return Bounds::default()}; let Some(node) = self.node() else {return Bounds::default()};
let mut bounds = self let mut bounds = self
@@ -104,6 +106,7 @@ impl Spatial {
bounds bounds
} }
#[instrument(level = "debug", skip_all)]
pub fn local_transform(&self) -> Mat4 { pub fn local_transform(&self) -> Mat4 {
*self.transform.lock() *self.transform.lock()
} }
@@ -113,9 +116,11 @@ impl Spatial {
None => *self.transform.lock(), None => *self.transform.lock(),
} }
} }
#[instrument]
pub fn set_local_transform(&self, transform: Mat4) { pub fn set_local_transform(&self, transform: Mat4) {
*self.transform.lock() = transform; *self.transform.lock() = transform;
} }
#[instrument(level = "debug", skip(self, reference_space))]
pub fn set_local_transform_components( pub fn set_local_transform_components(
&self, &self,
reference_space: Option<&Spatial>, reference_space: Option<&Spatial>,
@@ -159,6 +164,7 @@ impl Spatial {
); );
} }
#[instrument(level = "debug", skip_all)]
pub fn is_ancestor_of(&self, spatial: Arc<Spatial>) -> bool { pub fn is_ancestor_of(&self, spatial: Arc<Spatial>) -> bool {
let mut current_ancestor = spatial; let mut current_ancestor = spatial;
loop { loop {
@@ -190,6 +196,7 @@ impl Spatial {
*self.parent.lock() = new_parent; *self.parent.lock() = new_parent;
} }
#[instrument(level = "debug", skip_all)]
pub fn set_spatial_parent(&self, parent: Option<Arc<Spatial>>) -> Result<()> { pub fn set_spatial_parent(&self, parent: Option<Arc<Spatial>>) -> Result<()> {
let is_ancestor = parent let is_ancestor = parent
.as_ref() .as_ref()
@@ -203,6 +210,7 @@ impl Spatial {
Ok(()) Ok(())
} }
#[instrument(level = "debug", skip_all)]
pub fn set_spatial_parent_in_place(&self, parent: Option<Arc<Spatial>>) -> Result<()> { pub fn set_spatial_parent_in_place(&self, parent: Option<Arc<Spatial>>) -> Result<()> {
let is_ancestor = parent let is_ancestor = parent
.as_ref() .as_ref()
@@ -224,84 +232,72 @@ impl Spatial {
pub fn get_bounding_box_flex( pub fn get_bounding_box_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
response: MethodResponseSender, ) -> Result<Vec<u8>> {
) { let this_spatial = node
response.wrap_sync(move || { .spatial
let this_spatial = node .get()
.spatial .ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
.get() let relative_spatial_path: Option<&str> = deserialize(data)?;
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?; let bounds = if let Some(relative_spatial_path) = relative_spatial_path {
let relative_spatial_path: Option<&str> = deserialize(message.as_ref())?; let relative_spatial = find_reference_space(&calling_client, relative_spatial_path)?;
let bounds = if let Some(relative_spatial_path) = relative_spatial_path { let center =
let relative_spatial = Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial))
find_reference_space(&calling_client, relative_spatial_path)?; .transform_point3([0.0; 3].into());
let center = let bounds: Bounds = Bounds {
Spatial::space_to_space_matrix(Some(&this_spatial), Some(&relative_spatial)) center,
.transform_point3([0.0; 3].into()); dimensions: [0.0; 3].into(),
let bounds: Bounds = Bounds {
center,
dimensions: [0.0; 3].into(),
};
bounds_grow_to_fit_box(
bounds,
this_spatial.get_bounding_box(),
Some(Spatial::space_to_space_matrix(
Some(&this_spatial),
Some(&relative_spatial),
)),
)
} else {
this_spatial.get_bounding_box()
}; };
bounds_grow_to_fit_box(
bounds,
this_spatial.get_bounding_box(),
Some(Spatial::space_to_space_matrix(
Some(&this_spatial),
Some(&relative_spatial),
)),
)
} else {
this_spatial.get_bounding_box()
};
Ok(serialize(( serialize((
mint::Vector3::from(bounds.center), mint::Vector3::from(bounds.center),
mint::Vector3::from(bounds.dimensions), mint::Vector3::from(bounds.dimensions),
))? ))
.into()) .map_err(|e| e.into())
});
} }
pub fn get_transform_flex( pub fn get_transform_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
response: MethodResponseSender, ) -> Result<Vec<u8>> {
) { let this_spatial = node
response.wrap_sync(move || { .spatial
let this_spatial = node .get()
.spatial .ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
.get() let relative_spatial = find_reference_space(&calling_client, deserialize(data)?)?;
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
let relative_spatial =
find_reference_space(&calling_client, deserialize(message.as_ref())?)?;
let (scale, rotation, position) = Spatial::space_to_space_matrix( let (scale, rotation, position) = Spatial::space_to_space_matrix(
Some(this_spatial.as_ref()), Some(this_spatial.as_ref()),
Some(relative_spatial.as_ref()), Some(relative_spatial.as_ref()),
) )
.to_scale_rotation_translation(); .to_scale_rotation_translation();
Ok(serialize(( serialize((
mint::Vector3::from(position), mint::Vector3::from(position),
mint::Quaternion::from(rotation), mint::Quaternion::from(rotation),
mint::Vector3::from(scale), mint::Vector3::from(scale),
))? ))
.into()) .map_err(|e| e.into())
});
} }
pub fn set_transform_flex( pub fn set_transform_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct TransformArgs<'a> { struct TransformArgs<'a> {
reference_space_path: Option<&'a str>, reference_space_path: Option<&'a str>,
transform: Transform, transform: Transform,
} }
let transform_args: TransformArgs = deserialize(message.as_ref())?; let transform_args: TransformArgs = deserialize(data)?;
let reference_space_transform = transform_args let reference_space_transform = transform_args
.reference_space_path .reference_space_path
.map(|path| find_reference_space(&calling_client, path)) .map(|path| find_reference_space(&calling_client, path))
@@ -316,29 +312,25 @@ impl Spatial {
pub fn set_spatial_parent_flex( pub fn set_spatial_parent_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
let parent = find_spatial_parent(&calling_client, deserialize(message.as_ref())?)?; let parent = find_spatial_parent(&calling_client, deserialize(data)?)?;
node.spatial.get().unwrap().set_spatial_parent(Some(parent)) node.spatial.get().unwrap().set_spatial_parent(Some(parent))
} }
pub fn set_spatial_parent_in_place_flex( pub fn set_spatial_parent_in_place_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
) -> Result<()> { ) -> Result<()> {
let parent = find_spatial_parent(&calling_client, deserialize(message.as_ref())?)?; let parent = find_spatial_parent(&calling_client, deserialize(data)?)?;
node.spatial node.spatial
.get() .get()
.unwrap() .unwrap()
.set_spatial_parent_in_place(Some(parent))?; .set_spatial_parent_in_place(Some(parent))?;
Ok(()) Ok(())
} }
pub fn set_zoneable_flex( pub fn set_zoneable_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
node: &Node, let zoneable: bool = deserialize(data)?;
_calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
let zoneable: bool = deserialize(message.as_ref())?;
let spatial = node.spatial.get().unwrap(); let spatial = node.spatial.get().unwrap();
if zoneable { if zoneable {
ZONEABLE_REGISTRY.add_raw(spatial); ZONEABLE_REGISTRY.add_raw(spatial);
@@ -352,82 +344,74 @@ impl Spatial {
pub fn field_distance_flex( pub fn field_distance_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
response: MethodResponseSender, ) -> Result<Vec<u8>> {
) { let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(data)?;
response.wrap_sync(move || { let spatial = node.spatial.get().unwrap();
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(message.as_ref())?;
let spatial = node.spatial.get().unwrap();
let output = fields let output = fields
.into_iter() .into_iter()
.map(|f| { .map(|f| {
calling_client calling_client
.get_node("Field", f?) .get_node("Field", f?)
.ok()? .ok()?
.get_aspect("Field", "field", |n| &n.field) .get_aspect("Field", "field", |n| &n.field)
.ok() .ok()
.cloned() .cloned()
}) })
.map(|f| f.map(|f| f.distance(spatial, point.into()))) .map(|f| f.map(|f| f.distance(spatial, point.into())))
.collect::<Vec<Option<f32>>>(); .collect::<Vec<Option<f32>>>();
Ok(serialize(output)?.into()) Ok(serialize(output)?)
});
} }
pub fn field_normal_flex( pub fn field_normal_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
response: MethodResponseSender, ) -> Result<Vec<u8>> {
) { let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(data)?;
response.wrap_sync(move || { let spatial = node.spatial.get().unwrap();
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(message.as_ref())?;
let spatial = node.spatial.get().unwrap();
let output = fields let output = fields
.into_iter() .into_iter()
.map(|f| { .map(|f| {
calling_client calling_client
.get_node("Field", f?) .get_node("Field", f?)
.ok()? .ok()?
.get_aspect("Field", "field", |n| &n.field) .get_aspect("Field", "field", |n| &n.field)
.ok() .ok()
.cloned() .cloned()
}) })
.map(|f| f.map(|f| Vector3::from(f.normal(spatial, point.into(), 0.001)))) .map(|f| f.map(|f| Vector3::from(f.normal(spatial, point.into(), 0.001))))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Ok(serialize(output)?.into()) Ok(serialize(output)?)
});
} }
pub fn field_closest_point_flex( pub fn field_closest_point_flex(
node: &Node, node: &Node,
calling_client: Arc<Client>, calling_client: Arc<Client>,
message: Message, data: &[u8],
response: MethodResponseSender, ) -> Result<Vec<u8>> {
) { let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(data)?;
response.wrap_sync(move || { let spatial = node.spatial.get().unwrap();
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(message.as_ref())?;
let spatial = node.spatial.get().unwrap();
let output = fields let output = fields
.into_iter() .into_iter()
.map(|f| { .map(|f| {
calling_client calling_client
.get_node("Field", f?) .get_node("Field", f?)
.ok()? .ok()?
.get_aspect("Field", "field", |n| &n.field) .get_aspect("Field", "field", |n| &n.field)
.ok() .ok()
.cloned() .cloned()
}) })
.map(|f| f.map(|f| Vector3::from(f.closest_point(spatial, point.into(), 0.001)))) .map(|f| f.map(|f| Vector3::from(f.closest_point(spatial, point.into(), 0.001))))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Ok(serialize(output)?.into()) Ok(serialize(output)?)
});
} }
#[instrument]
pub(self) fn zone_distance(&self) -> f32 { pub(self) fn zone_distance(&self) -> f32 {
self.zone self.zone
.lock() .lock()
@@ -506,11 +490,7 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
node.add_to_scenegraph().map(|_| ()) node.add_to_scenegraph().map(|_| ())
} }
pub fn create_spatial_flex( pub fn create_spatial_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
_node: &Node,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateSpatialInfo<'a> { struct CreateSpatialInfo<'a> {
name: &'a str, name: &'a str,
@@ -518,7 +498,7 @@ pub fn create_spatial_flex(
transform: Transform, transform: Transform,
zoneable: bool, zoneable: bool,
} }
let info: CreateSpatialInfo = deserialize(message.as_ref())?; let info: CreateSpatialInfo = deserialize(data)?;
let node = Node::create(&calling_client, "/spatial/spatial", info.name, true); let node = Node::create(&calling_client, "/spatial/spatial", info.name, true);
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, true); let transform = parse_transform(info.transform, true, true, true);

View File

@@ -5,7 +5,7 @@ use crate::{
alias::{Alias, AliasInfo}, alias::{Alias, AliasInfo},
fields::{find_field, Field}, fields::{find_field, Field},
spatial::{find_spatial_parent, parse_transform}, spatial::{find_spatial_parent, parse_transform},
Message, Node, Node,
}, },
}; };
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
@@ -31,19 +31,17 @@ pub fn capture(spatial: &Arc<Spatial>, zone: &Arc<Zone>) {
*spatial.old_parent.lock() = spatial.get_parent(); *spatial.old_parent.lock() = spatial.get_parent();
*spatial.zone.lock() = Arc::downgrade(zone); *spatial.zone.lock() = Arc::downgrade(zone);
zone.captured.add_raw(spatial); zone.captured.add_raw(spatial);
let Some(node) = zone.spatial.node.upgrade() else {return}; let node = zone.spatial.node.upgrade().unwrap();
let Ok(message) = serialize(&spatial.uid) else {return}; let _ = node.send_remote_signal("capture", &serialize(&spatial.uid).unwrap());
let _ = node.send_remote_signal("capture", message);
} }
} }
pub fn release(spatial: &Spatial) { pub fn release(spatial: &Spatial) {
let _ = spatial.set_spatial_parent_in_place(spatial.old_parent.lock().take()); let _ = spatial.set_spatial_parent_in_place(spatial.old_parent.lock().take());
let mut spatial_zone = spatial.zone.lock(); let mut spatial_zone = spatial.zone.lock();
if let Some(spatial_zone) = spatial_zone.upgrade() { if let Some(spatial_zone) = spatial_zone.upgrade() {
let Some(node) = spatial_zone.spatial.node.upgrade() else {return}; let node = spatial_zone.spatial.node.upgrade().unwrap();
spatial_zone.captured.remove(spatial); spatial_zone.captured.remove(spatial);
let Ok(message) = serialize(&spatial.uid) else {return}; let _ = node.send_remote_signal("release", &serialize(&spatial.uid).unwrap());
let _ = node.send_remote_signal("release", message);
} }
*spatial_zone = Weak::new(); *spatial_zone = Weak::new();
} }
@@ -68,20 +66,20 @@ impl Zone {
let _ = node.zone.set(zone.clone()); let _ = node.zone.set(zone.clone());
zone zone
} }
fn capture_flex(node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { fn capture_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let zone = node.zone.get().unwrap(); let zone = node.zone.get().unwrap();
let capture_path: &str = deserialize(message.as_ref())?; let capture_path: &str = deserialize(data)?;
let spatial = find_spatial(&calling_client, "Spatial", capture_path)?; let spatial = find_spatial(&calling_client, "Spatial", capture_path)?;
capture(&spatial, zone); capture(&spatial, zone);
Ok(()) Ok(())
} }
fn release_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { fn release_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let capture_path: &str = deserialize(message.as_ref())?; let capture_path: &str = deserialize(data)?;
let spatial = find_spatial(&calling_client, "Spatial", capture_path)?; let spatial = find_spatial(&calling_client, "Spatial", capture_path)?;
release(&spatial); release(&spatial);
Ok(()) Ok(())
} }
fn update(node: &Node, _calling_client: Arc<Client>, _message: Message) -> Result<()> { fn update(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
let zone = node.zone.get().unwrap(); let zone = node.zone.get().unwrap();
let Some(field) = zone.field.upgrade() else { return Err(color_eyre::eyre::eyre!("Zone's field has been destroyed")) }; let Some(field) = zone.field.upgrade() else { return Err(color_eyre::eyre::eyre!("Zone's field has been destroyed")) };
let Some((zone_client, zone_node)) = zone let Some((zone_client, zone_node)) = zone
@@ -131,10 +129,10 @@ impl Zone {
.collect::<FxHashMap<String, Arc<Node>>>(); .collect::<FxHashMap<String, Arc<Node>>>();
for entered_uid in zoneables.keys().filter(|k| !old_zoneables.contains_key(*k)) { for entered_uid in zoneables.keys().filter(|k| !old_zoneables.contains_key(*k)) {
node.send_remote_signal("enter", serialize(entered_uid)?)?; node.send_remote_signal("enter", &serialize(entered_uid)?)?;
} }
for left_uid in old_zoneables.keys().filter(|k| !zoneables.contains_key(*k)) { for left_uid in old_zoneables.keys().filter(|k| !zoneables.contains_key(*k)) {
node.send_remote_signal("leave", serialize(left_uid)?)?; node.send_remote_signal("leave", &serialize(left_uid)?)?;
} }
*old_zoneables = zoneables; *old_zoneables = zoneables;
@@ -150,7 +148,7 @@ impl Drop for Zone {
} }
} }
pub fn create_zone_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> { pub fn create_zone_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
#[derive(Deserialize)] #[derive(Deserialize)]
struct CreateZoneInfo<'a> { struct CreateZoneInfo<'a> {
name: &'a str, name: &'a str,
@@ -158,7 +156,7 @@ pub fn create_zone_flex(_node: &Node, calling_client: Arc<Client>, message: Mess
transform: Transform, transform: Transform,
field_path: &'a str, field_path: &'a str,
} }
let info: CreateZoneInfo = deserialize(message.as_ref())?; let info: CreateZoneInfo = deserialize(data)?;
let parent = find_spatial_parent(&calling_client, info.parent_path)?; let parent = find_spatial_parent(&calling_client, info.parent_path)?;
let transform = parse_transform(info.transform, true, true, false); let transform = parse_transform(info.transform, true, true, false);
let field = find_field(&calling_client, info.field_path)?; let field = find_field(&calling_client, info.field_path)?;

146
src/nodes/startup.rs Normal file
View File

@@ -0,0 +1,146 @@
use crate::{core::client::Client, wayland::WAYLAND_DISPLAY, STARDUST_INSTANCE};
use super::{
items::{ItemAcceptor, TypeInfo},
spatial::find_spatial,
Node,
};
use color_eyre::eyre::Result;
use glam::Mat4;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::{
fmt::Debug,
sync::{Arc, Weak},
};
lazy_static::lazy_static! {
pub static ref STARTUP_SETTINGS: Mutex<FxHashMap<String, StartupSettings>> = Default::default();
}
#[derive(Default, Clone)]
pub struct StartupSettings {
pub transform: Mat4,
pub acceptors: FxHashMap<&'static TypeInfo, Weak<ItemAcceptor>>,
}
impl StartupSettings {
pub fn add_to(node: &Arc<Node>) {
let _ = node
.startup_settings
.set(Mutex::new(StartupSettings::default()));
}
fn set_root_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let spatial = find_spatial(&calling_client, "Root spatial", deserialize(data)?)?;
node.startup_settings.get().unwrap().lock().transform = spatial.global_transform();
Ok(())
}
fn add_automatic_acceptor_flex(
node: &Node,
calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let acceptor_node = calling_client.get_node("Item acceptor", deserialize(data)?)?;
let acceptor =
acceptor_node.get_aspect("Item acceptor", "item acceptor", |n| &n.item_acceptor)?;
let mut startup_settings = node.startup_settings.get().unwrap().lock();
startup_settings
.acceptors
.insert(acceptor.type_info, Arc::downgrade(acceptor));
Ok(())
}
fn generate_startup_token_flex(
node: &Node,
_calling_client: Arc<Client>,
_data: &[u8],
) -> Result<Vec<u8>> {
let id = nanoid::nanoid!();
let data = serialize(&id)?;
STARTUP_SETTINGS
.lock()
.insert(id, node.startup_settings.get().unwrap().lock().clone());
Ok(data)
}
}
impl Debug for StartupSettings {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StartupSettings")
.field("transform", &self.transform)
.field(
"acceptors",
&self
.acceptors
.iter()
.map(|(k, _)| k.type_name)
.collect::<Vec<_>>(),
)
.finish()
}
}
pub fn create_interface(client: &Arc<Client>) -> Result<()> {
let node = Node::create(client, "", "startup", false);
node.add_local_signal("create_startup_settings", create_startup_settings_flex);
node.add_local_method(
"get_connection_environment",
get_connection_environment_flex,
);
node.add_to_scenegraph().map(|_| ())
}
pub fn create_startup_settings_flex(
_node: &Node,
calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let node = Node::create(
&calling_client,
"/startup/settings",
deserialize(data)?,
true,
)
.add_to_scenegraph()?;
StartupSettings::add_to(&node);
node.add_local_signal("set_root", StartupSettings::set_root_flex);
node.add_local_signal(
"add_automatic_acceptor",
StartupSettings::add_automatic_acceptor_flex,
);
node.add_local_method(
"generate_startup_token",
StartupSettings::generate_startup_token_flex,
);
Ok(())
}
macro_rules! var_env_insert {
($env:ident, $name:ident) => {
$env.insert(stringify!($name).to_string(), $name.get().unwrap().clone());
};
}
pub fn get_connection_environment_flex(
_node: &Node,
_calling_client: Arc<Client>,
_data: &[u8],
) -> Result<Vec<u8>> {
let mut env: FxHashMap<String, String> = FxHashMap::default();
var_env_insert!(env, STARDUST_INSTANCE);
#[cfg(feature = "wayland")]
{
var_env_insert!(env, WAYLAND_DISPLAY);
env.insert("GDK_BACKEND".to_string(), "wayland".to_string());
env.insert("QT_QPA_PLATFORM".to_string(), "wayland".to_string());
env.insert("MOZ_ENABLE_WAYLAND".to_string(), "1".to_string());
env.insert("CLUTTER_BACKEND".to_string(), "wayland".to_string());
env.insert("SDL_VIDEODRIVER".to_string(), "wayland".to_string());
}
Ok(serialize(env)?)
}

Binary file not shown.

Binary file not shown.

View File

@@ -13,6 +13,7 @@ use serde::Serialize;
use stardust_xr::schemas::{flat::Datamap, flex::flexbuffers}; use stardust_xr::schemas::{flat::Datamap, flex::flexbuffers};
use std::sync::Arc; use std::sync::Arc;
use stereokit::StereoKitMultiThread; use stereokit::StereoKitMultiThread;
use tracing::instrument;
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct KeyboardEvent { pub struct KeyboardEvent {
@@ -35,6 +36,7 @@ impl EyePointer {
Ok(EyePointer { spatial, pointer }) Ok(EyePointer { spatial, pointer })
} }
#[instrument(level = "debug", name = "Update Flatscreen Pointer Ray", skip_all)]
pub fn update(&self, sk: &impl StereoKitMultiThread) { pub fn update(&self, sk: &impl StereoKitMultiThread) {
let ray = sk.input_eyes(); let ray = sk.input_eyes();
self.spatial self.spatial

View File

@@ -1,7 +1,7 @@
use crate::{ use crate::{
core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap}, core::client::INTERNAL_CLIENT,
nodes::{ nodes::{
data::{mask_matches, Mask, PulseSender, KEYMAPS, PULSE_RECEIVER_REGISTRY}, data::{mask_matches, Mask, PulseSender, PULSE_RECEIVER_REGISTRY},
fields::Ray, fields::Ray,
input::{pointer::Pointer, InputMethod, InputType}, input::{pointer::Pointer, InputMethod, InputType},
spatial::Spatial, spatial::Spatial,
@@ -9,45 +9,28 @@ use crate::{
}, },
}; };
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use glam::{vec2, vec3, Mat4, Vec2, Vec3}; use glam::{vec3, Mat4, Vec3};
use nanoid::nanoid; use nanoid::nanoid;
use serde::{Deserialize, Serialize}; use serde::Serialize;
use stardust_xr::schemas::{flat::Datamap, flex::flexbuffers};
use std::{convert::TryFrom, sync::Arc}; use std::{convert::TryFrom, sync::Arc};
use stereokit::{ray_from_mouse, ButtonState, Key, StereoKitMultiThread}; use stereokit::{ray_from_mouse, ButtonState, Key, StereoKitMultiThread};
use xkbcommon::xkb::{Context, Keymap, FORMAT_TEXT_V1}; use tracing::instrument;
#[derive(Default, Deserialize, Serialize)] const SK_KEYMAP: &str = include_str!("sk.kmp");
struct MouseEvent {
select: f32,
grab: f32,
scroll_continuous: Vec2,
scroll_discrete: Vec2,
}
#[derive(Debug, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct KeyboardEvent { pub struct KeyboardEvent {
pub keyboard: (), pub keyboard: String,
pub xkbv1: (), pub keymap: Option<String>,
pub keymap_id: String, pub keys_up: Option<Vec<u32>>,
pub keys: Vec<i32>, pub keys_down: Option<Vec<u32>>,
}
impl Default for KeyboardEvent {
fn default() -> Self {
Self {
keyboard: (),
xkbv1: (),
keymap_id: "flatscreen".to_string(),
keys: Default::default(),
}
}
} }
pub struct MousePointer { pub struct MousePointer {
node: Arc<Node>, node: Arc<Node>,
spatial: Arc<Spatial>, spatial: Arc<Spatial>,
pointer: Arc<InputMethod>, pointer: Arc<InputMethod>,
mouse_datamap: TypedDatamap<MouseEvent>,
keyboard_datamap: TypedDatamap<KeyboardEvent>,
keyboard_sender: Arc<PulseSender>, keyboard_sender: Arc<PulseSender>,
} }
impl MousePointer { impl MousePointer {
@@ -57,26 +40,24 @@ impl MousePointer {
let pointer = let pointer =
InputMethod::add_to(&node, InputType::Pointer(Pointer::default()), None).unwrap(); InputMethod::add_to(&node, InputType::Pointer(Pointer::default()), None).unwrap();
KEYMAPS.lock().insert( let keyboard_mask = {
"flatscreen".to_string(), let mut fbb = flexbuffers::Builder::default();
Keymap::new_from_names(&Context::new(0), "evdev", "", "", "", None, 0) let mut map = fbb.start_map();
.unwrap() map.push("keyboard", "xkbv1");
.get_as_string(FORMAT_TEXT_V1), map.end_map();
); Mask(fbb.take_buffer())
};
let keyboard_sender = let keyboard_sender = PulseSender::add_to(&node, keyboard_mask).unwrap();
PulseSender::add_to(&node, Mask::from_struct::<KeyboardEvent>()).unwrap();
Ok(MousePointer { Ok(MousePointer {
node, node,
spatial, spatial,
pointer, pointer,
mouse_datamap: Default::default(),
keyboard_datamap: Default::default(),
keyboard_sender, keyboard_sender,
}) })
} }
pub fn update(&mut self, sk: &impl StereoKitMultiThread) { #[instrument(level = "debug", name = "Update Flatscreen Pointer Ray", skip_all)]
pub fn update(&self, sk: &impl StereoKitMultiThread) {
let mouse = sk.input_mouse(); let mouse = sk.input_mouse();
let ray = ray_from_mouse(mouse.pos).unwrap(); let ray = ray_from_mouse(mouse.pos).unwrap();
@@ -90,26 +71,35 @@ impl MousePointer {
); );
{ {
// Set pointer input datamap // Set pointer input datamap
self.mouse_datamap.select = let mut fbb = flexbuffers::Builder::default();
let mut map = fbb.start_map();
map.push(
"select",
if sk.input_key(Key::MouseLeft).contains(ButtonState::ACTIVE) { if sk.input_key(Key::MouseLeft).contains(ButtonState::ACTIVE) {
1.0f32 1.0f32
} else { } else {
0.0f32 0.0f32
}; },
self.mouse_datamap.grab = if sk.input_key(Key::MouseRight).contains(ButtonState::ACTIVE) );
{ map.push(
1.0f32 "grab",
} else { if sk.input_key(Key::MouseRight).contains(ButtonState::ACTIVE) {
0.0f32 1.0f32
}; } else {
self.mouse_datamap.scroll_continuous = vec2(0.0, mouse.scroll_change / 120.0); 0.0f32
self.mouse_datamap.scroll_discrete = vec2(0.0, mouse.scroll_change / 120.0); },
*self.pointer.datamap.lock() = self.mouse_datamap.to_datamap().ok(); );
let mut scroll_vec = map.start_vector("scroll");
scroll_vec.push(0_f32);
scroll_vec.push(mouse.scroll_change / 120.0);
scroll_vec.end_vector();
map.end_map();
*self.pointer.datamap.lock() = Datamap::new(fbb.take_buffer()).ok();
} }
self.send_keyboard_input(sk); self.send_keyboard_input(sk);
} }
fn send_keyboard_input(&mut self, sk: &impl StereoKitMultiThread) { fn send_keyboard_input(&self, sk: &impl StereoKitMultiThread) {
let rx = PULSE_RECEIVER_REGISTRY let rx = PULSE_RECEIVER_REGISTRY
.get_valid_contents() .get_valid_contents()
.into_iter() .into_iter()
@@ -135,127 +125,29 @@ impl MousePointer {
.map(|(rx, _)| rx); .map(|(rx, _)| rx);
if let Some(rx) = rx { if let Some(rx) = rx {
let mut keys_up = vec![];
let mut keys_down = vec![];
let keys = (8_u32..254) let keys = (8_u32..254)
.filter_map(|i| Key::try_from(i).ok()) .filter_map(|i| Some((i, Key::try_from(i).ok()?)))
.filter_map(|k| Some((map_key(k)?, sk.input_key(k)))) .map(|(i, k)| (i - 8, sk.input_key(k)));
.filter_map(|(i, k)| { for (key, state) in keys {
if k.contains(ButtonState::JUST_ACTIVE) { if state.contains(ButtonState::JUST_ACTIVE) {
Some(i as i32) keys_down.push(key);
} else if k.contains(ButtonState::JUST_INACTIVE) { } else if state.contains(ButtonState::JUST_INACTIVE) {
Some(-(i as i32)) keys_up.push(key);
} else { }
None
}
})
.collect();
self.keyboard_datamap.keys = keys;
if !self.keyboard_datamap.keys.is_empty() {
rx.send_data(&self.node.uid, self.keyboard_datamap.serialize().unwrap())
.unwrap();
} }
let key_event = KeyboardEvent {
keyboard: "xkbv1".to_string(),
keymap: Some(SK_KEYMAP.to_string()),
keys_up: Some(keys_up),
keys_down: Some(keys_down),
};
let mut serializer = flexbuffers::FlexbufferSerializer::new();
let _ = key_event.serialize(&mut serializer);
rx.send_data(&self.node.uid, serializer.take_buffer())
.unwrap();
} }
} }
} }
fn map_key(key: Key) -> Option<u32> {
match key {
Key::Backspace => Some(input_event_codes::KEY_BACKSPACE!()),
Key::Tab => Some(input_event_codes::KEY_TAB!()),
Key::Return => Some(input_event_codes::KEY_ENTER!()),
Key::Shift => Some(input_event_codes::KEY_LEFTSHIFT!()),
Key::Ctrl => Some(input_event_codes::KEY_LEFTCTRL!()),
Key::Alt => Some(input_event_codes::KEY_LEFTALT!()),
Key::CapsLock => Some(input_event_codes::KEY_CAPSLOCK!()),
Key::Esc => Some(input_event_codes::KEY_ESC!()),
Key::Space => Some(input_event_codes::KEY_SPACE!()),
Key::End => Some(input_event_codes::KEY_END!()),
Key::Home => Some(input_event_codes::KEY_HOME!()),
Key::Left => Some(input_event_codes::KEY_LEFT!()),
Key::Right => Some(input_event_codes::KEY_RIGHT!()),
Key::Up => Some(input_event_codes::KEY_UP!()),
Key::Down => Some(input_event_codes::KEY_DOWN!()),
Key::PageUp => Some(input_event_codes::KEY_PAGEUP!()),
Key::PageDown => Some(input_event_codes::KEY_PAGEDOWN!()),
Key::PrintScreen => Some(input_event_codes::KEY_PRINT!()),
Key::KeyInsert => Some(input_event_codes::KEY_INSERT!()),
Key::Del => Some(input_event_codes::KEY_DELETE!()),
Key::Key0 => Some(input_event_codes::KEY_0!()),
Key::Key1 => Some(input_event_codes::KEY_1!()),
Key::Key2 => Some(input_event_codes::KEY_2!()),
Key::Key3 => Some(input_event_codes::KEY_3!()),
Key::Key4 => Some(input_event_codes::KEY_4!()),
Key::Key5 => Some(input_event_codes::KEY_5!()),
Key::Key6 => Some(input_event_codes::KEY_6!()),
Key::Key7 => Some(input_event_codes::KEY_7!()),
Key::Key8 => Some(input_event_codes::KEY_8!()),
Key::Key9 => Some(input_event_codes::KEY_9!()),
Key::A => Some(input_event_codes::KEY_A!()),
Key::B => Some(input_event_codes::KEY_B!()),
Key::C => Some(input_event_codes::KEY_C!()),
Key::D => Some(input_event_codes::KEY_D!()),
Key::E => Some(input_event_codes::KEY_E!()),
Key::F => Some(input_event_codes::KEY_F!()),
Key::G => Some(input_event_codes::KEY_G!()),
Key::H => Some(input_event_codes::KEY_H!()),
Key::I => Some(input_event_codes::KEY_I!()),
Key::J => Some(input_event_codes::KEY_J!()),
Key::K => Some(input_event_codes::KEY_K!()),
Key::L => Some(input_event_codes::KEY_L!()),
Key::M => Some(input_event_codes::KEY_M!()),
Key::N => Some(input_event_codes::KEY_N!()),
Key::O => Some(input_event_codes::KEY_O!()),
Key::P => Some(input_event_codes::KEY_P!()),
Key::Q => Some(input_event_codes::KEY_Q!()),
Key::R => Some(input_event_codes::KEY_R!()),
Key::S => Some(input_event_codes::KEY_S!()),
Key::T => Some(input_event_codes::KEY_T!()),
Key::U => Some(input_event_codes::KEY_U!()),
Key::V => Some(input_event_codes::KEY_V!()),
Key::W => Some(input_event_codes::KEY_W!()),
Key::X => Some(input_event_codes::KEY_X!()),
Key::Y => Some(input_event_codes::KEY_Y!()),
Key::Z => Some(input_event_codes::KEY_Z!()),
Key::Numpad0 => Some(input_event_codes::KEY_NUMERIC_0!()),
Key::Numpad1 => Some(input_event_codes::KEY_NUMERIC_1!()),
Key::Numpad2 => Some(input_event_codes::KEY_NUMERIC_2!()),
Key::Numpad3 => Some(input_event_codes::KEY_NUMERIC_3!()),
Key::Numpad4 => Some(input_event_codes::KEY_NUMERIC_4!()),
Key::Numpad5 => Some(input_event_codes::KEY_NUMERIC_5!()),
Key::Numpad6 => Some(input_event_codes::KEY_NUMERIC_6!()),
Key::Numpad7 => Some(input_event_codes::KEY_NUMERIC_7!()),
Key::Numpad8 => Some(input_event_codes::KEY_NUMERIC_8!()),
Key::Numpad9 => Some(input_event_codes::KEY_NUMERIC_9!()),
Key::F1 => Some(input_event_codes::KEY_F1!()),
Key::F2 => Some(input_event_codes::KEY_F2!()),
Key::F3 => Some(input_event_codes::KEY_F3!()),
Key::F4 => Some(input_event_codes::KEY_F4!()),
Key::F5 => Some(input_event_codes::KEY_F5!()),
Key::F6 => Some(input_event_codes::KEY_F6!()),
Key::F7 => Some(input_event_codes::KEY_F7!()),
Key::F8 => Some(input_event_codes::KEY_F8!()),
Key::F9 => Some(input_event_codes::KEY_F9!()),
Key::F10 => Some(input_event_codes::KEY_F10!()),
Key::F11 => Some(input_event_codes::KEY_F11!()),
Key::F12 => Some(input_event_codes::KEY_F12!()),
Key::Comma => Some(input_event_codes::KEY_COMMA!()),
Key::Period => Some(input_event_codes::KEY_DOT!()),
Key::SlashFwd => Some(input_event_codes::KEY_SLASH!()),
Key::SlashBack => Some(input_event_codes::KEY_BACKSLASH!()),
Key::Semicolon => Some(input_event_codes::KEY_SEMICOLON!()),
Key::Apostrophe => Some(input_event_codes::KEY_APOSTROPHE!()),
Key::BracketOpen => Some(input_event_codes::KEY_LEFTBRACE!()),
Key::BracketClose => Some(input_event_codes::KEY_RIGHTBRACE!()),
Key::Minus => Some(input_event_codes::KEY_MINUS!()),
Key::Equals => Some(input_event_codes::KEY_EQUAL!()),
Key::Backtick => None,
Key::LCmd => Some(input_event_codes::KEY_LEFTMETA!()),
Key::RCmd => Some(input_event_codes::KEY_RIGHTMETA!()),
Key::Multiply => Some(input_event_codes::KEY_NUMERIC_STAR!()),
Key::Add => Some(input_event_codes::KEY_KPPLUS!()),
Key::Subtract => Some(input_event_codes::KEY_MINUS!()),
Key::Decimal => Some(input_event_codes::KEY_DOT!()),
Key::Divide => Some(input_event_codes::KEY_SLASH!()),
_ => None,
}
}

275
src/objects/input/sk.kmp Normal file
View File

@@ -0,0 +1,275 @@
xkb_keymap {
default xkb_keycodes "basic" {
minimum = 8;
maximum = 255;
<backspace> = 8;
<tab> = 9;
<return> = 13;
<shift> = 16;
<ctrl> = 17;
<alt> = 18;
<caps_lock> = 20;
<esc> = 27;
<space> = 32;
<end> = 35;
<home> = 36;
<left> = 37;
<right> = 39;
<up> = 38;
<down> = 40;
<page_up> = 33;
<page_down> = 34;
<printscreen> = 42;
<key_insert> = 45;
<del> = 46;
<0> = 48;
<1> = 49;
<2> = 50;
<3> = 51;
<4> = 52;
<5> = 53;
<6> = 54;
<7> = 55;
<8> = 56;
<9> = 57;
<a> = 65;
<b> = 66;
<c> = 67;
<d> = 68;
<e> = 69;
<f> = 70;
<g> = 71;
<h> = 72;
<i> = 73;
<j> = 74;
<k> = 75;
<l> = 76;
<m> = 77;
<n> = 78;
<o> = 79;
<p> = 80;
<q> = 81;
<r> = 82;
<s> = 83;
<t> = 84;
<u> = 85;
<v> = 86;
<w> = 87;
<x> = 88;
<y> = 89;
<z> = 90;
<num0> = 96;
<num1> = 97;
<num2> = 98;
<num3> = 99;
<num4> = 100;
<num5> = 101;
<num6> = 102;
<num7> = 103;
<num8> = 104;
<num9> = 105;
<f1> = 112;
<f2> = 113;
<f3> = 114;
<f4> = 115;
<f5> = 116;
<f6> = 117;
<f7> = 118;
<f8> = 119;
<f9> = 120;
<f10> = 121;
<f11> = 122;
<f12> = 123;
<comma> = 188;
<period> = 190;
<slash_fwd> = 191;
<slash_back> = 220;
<semicolon> = 186;
<apostrophe> = 222;
<bracket_open> = 219;
<bracket_close> = 221;
<minus> = 189;
<equals> = 187;
<backtick> = 192;
<lcmd> = 91;
<rcmd> = 92;
<multiply> = 106;
<add> = 107;
<subtract> = 109;
<decimal> = 110;
<divide> = 111;
};
partial default xkb_types "basic" {
virtual_modifiers Alt;
type "ONE_LEVEL" {
modifiers= none;
level_name[1]= "Any";
};
type "TWO_LEVEL" {
modifiers= Shift;
map[Shift]= 2;
level_name[1]= "Base";
level_name[2]= "Shift";
};
type "ALPHABETIC" {
modifiers= Shift+Lock;
map[Shift]= 2;
map[Lock]= 2;
level_name[1]= "Base";
level_name[2]= "Caps";
};
type "SHIFT+ALT" {
modifiers= Shift+Alt;
map[Shift+Alt]= 2;
level_name[1]= "Base";
level_name[2]= "Shift+Alt";
};
type "PC_CONTROL_LEVEL2" {
modifiers= Control;
map[Control]= 2;
level_name[1]= "Base";
level_name[2]= "Control";
};
};
partial default xkb_compatibility "basic" {
interpret.useModMapMods= AnyLevel;
interpret.repeat= False;
interpret ISO_Level2_Latch+Exactly(Shift) {
useModMapMods=level1;
action= LatchMods(modifiers=Shift,clearLocks,latchToLock);
};
interpret Caps_Lock+AnyOfOrNone(all) {
action= LockMods(modifiers=Lock);
};
indicator "Caps Lock" {
whichModState= locked;
modifiers= Lock;
};
};
default xkb_symbols "basic" {
name[Group1]="English (US)";
key <backspace> { [ BackSpace, BackSpace ] };
key <tab> { [ Tab, ISO_Left_Tab ] };
key <return> { [ Return ] };
key <shift> { [ Shift_L ] };
key <shift> { [ Shift_R ] };
key <ctrl> { [ Control_L ] };
key <ctrl> { [ Control_R ] };
key <alt> { [ Alt_L ] };
key <alt> { [ Alt_R ] };
key <caps_lock> { [ Caps_Lock ] };
key <esc> { [ Escape ] };
key <space> { [ space ] };
key <end> { [ End ] };
key <home> { [ Home ] };
key <left> { [ Left ] };
key <right> { [ Right ] };
key <up> { [ Up ] };
key <down> { [ Down ] };
key <page_up> { [ Page_Up ] };
key <page_down> { [ Page_Down ] };
key <printscreen> { [ Print ] };
key <key_insert> { [ Insert ] };
key <del> { [ Delete ] };
key <1> { [ 1, exclam ] };
key <2> { [ 2, at ] };
key <3> { [ 3, numbersign ] };
key <4> { [ 4, dollar ] };
key <5> { [ 5, percent ] };
key <6> { [ 6, asciicircum ] };
key <7> { [ 7, ampersand ] };
key <8> { [ 8, asterisk ] };
key <9> { [ 9, parenleft ] };
key <0> { [ 0, parenright ] };
key <a> { [ a, A ] };
key <b> { [ b, B ] };
key <c> { [ c, C ] };
key <d> { [ d, D ] };
key <e> { [ e, E ] };
key <f> { [ f, F ] };
key <g> { [ g, G ] };
key <h> { [ h, H ] };
key <i> { [ i, I ] };
key <j> { [ j, J ] };
key <k> { [ k, K ] };
key <l> { [ l, L ] };
key <m> { [ m, M ] };
key <n> { [ n, N ] };
key <o> { [ o, O ] };
key <p> { [ p, P ] };
key <q> { [ q, Q ] };
key <r> { [ r, R ] };
key <s> { [ s, S ] };
key <t> { [ t, T ] };
key <u> { [ u, U ] };
key <v> { [ v, V ] };
key <w> { [ w, W ] };
key <x> { [ x, X ] };
key <y> { [ y, Y ] };
key <z> { [ z, Z ] };
key <num0> { [ KP_0 ] };
key <num1> { [ KP_1 ] };
key <num2> { [ KP_2 ] };
key <num3> { [ KP_3 ] };
key <num4> { [ KP_4 ] };
key <num5> { [ KP_5 ] };
key <num6> { [ KP_6 ] };
key <num7> { [ KP_7 ] };
key <num8> { [ KP_8 ] };
key <num9> { [ KP_9 ] };
key <f1> { [ F1 ] };
key <f2> { [ F2 ] };
key <f3> { [ F3 ] };
key <f4> { [ F4 ] };
key <f5> { [ F5 ] };
key <f6> { [ F6 ] };
key <f7> { [ F7 ] };
key <f8> { [ F8 ] };
key <f9> { [ F9 ] };
key <f10> { [ F10 ] };
key <f11> { [ F11 ] };
key <f12> { [ F12 ] };
key <comma> { [ comma, less ] };
key <period> { [ period, greater ] };
key <slash_fwd> { [ slash, question ] };
key <slash_back> { [ backslash, bar ] };
key <semicolon> { [ semicolon, colon ] };
key <apostrophe> { [ apostrophe ] };
key <bracket_open> { [ bracketleft, braceleft ] };
key <bracket_close> { [ bracketright, braceright ] };
key <minus> { [ minus, underscore ] };
key <equals> { [ equal, plus ] };
key <backtick> { [ grave, asciitilde ] };
key <lcmd> { [ Super_L ] };
key <rcmd> { [ Super_R ] };
key <multiply> { [ KP_Multiply ] };
key <add> { [ KP_Add ] };
key <subtract> { [ KP_Subtract ] };
key <decimal> { [ KP_Decimal ] };
key <divide> { [ KP_Divide ] };
modifier_map Shift { <shift> };
modifier_map Lock { <caps_lock> };
modifier_map Control { <caps_lock> };
modifier_map Mod1 { <alt> };
modifier_map Mod4 { <lcmd>, <rcmd> };
};
};

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap}, core::client::INTERNAL_CLIENT,
nodes::{ nodes::{
input::{tip::Tip, InputMethod, InputType}, input::{tip::Tip, InputMethod, InputType},
spatial::Spatial, spatial::Spatial,
@@ -7,72 +7,51 @@ use crate::{
}, },
}; };
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use glam::{Mat4, Vec2, Vec3}; use glam::Mat4;
use serde::{Deserialize, Serialize}; use nanoid::nanoid;
use std::sync::Arc; use stardust_xr::{
use stereokit::{ schemas::{flat::Datamap, flex::flexbuffers},
named_colors::WHITE, ButtonState, Handed, Model, RenderLayer, StereoKitDraw, values::Transform,
StereoKitMultiThread,
}; };
use std::sync::Arc;
#[derive(Default, Deserialize, Serialize)] use stereokit::{ButtonState, Handed, StereoKitMultiThread};
struct ControllerDatamap { use tracing::instrument;
select: f32,
grab: f32,
scroll: Vec2,
}
pub struct SkController { pub struct SkController {
_node: Arc<Node>, _node: Arc<Node>,
input: Arc<InputMethod>, input: Arc<InputMethod>,
model: Model,
handed: Handed, handed: Handed,
datamap: TypedDatamap<ControllerDatamap>,
} }
impl SkController { impl SkController {
pub fn new(sk: &impl StereoKitMultiThread, handed: Handed) -> Result<Self> { pub fn new(handed: Handed) -> Result<Self> {
let _node = Node::create( let _node = Node::create(&INTERNAL_CLIENT, "", &nanoid!(), false).add_to_scenegraph()?;
&INTERNAL_CLIENT,
"",
if handed == Handed::Left {
"controller_left"
} else {
"controller_right"
},
false,
)
.add_to_scenegraph()?;
Spatial::add_to(&_node, None, Mat4::IDENTITY, false)?; Spatial::add_to(&_node, None, Mat4::IDENTITY, false)?;
let model = sk.model_create_mem("cursor.glb", include_bytes!("cursor.glb"), None)?;
let tip = InputType::Tip(Tip::default()); let tip = InputType::Tip(Tip::default());
let input = InputMethod::add_to(&_node, tip, None)?; let input = InputMethod::add_to(&_node, tip, None)?;
Ok(SkController { Ok(SkController {
_node, _node,
input, input,
handed, handed,
model,
datamap: Default::default(),
}) })
} }
pub fn update(&mut self, sk: &impl StereoKitDraw) { #[instrument(level = "debug", name = "Update StereoKit Tip Input Method", skip_all)]
pub fn update(&mut self, sk: &impl StereoKitMultiThread) {
let controller = sk.input_controller(self.handed); let controller = sk.input_controller(self.handed);
*self.input.enabled.lock() = controller.tracked.contains(ButtonState::ACTIVE); *self.input.enabled.lock() = controller.tracked.contains(ButtonState::ACTIVE);
if *self.input.enabled.lock() { if *self.input.enabled.lock() {
let world_transform = Mat4::from_rotation_translation( self.input.spatial.set_local_transform_components(
controller.aim.orientation, None,
controller.aim.position, Transform::from_position_rotation(
controller.pose.position,
controller.pose.orientation,
),
); );
sk.model_draw(
&self.model,
world_transform * Mat4::from_scale(Vec3::ONE * 0.02),
WHITE,
RenderLayer::LAYER0,
);
self.input.spatial.set_local_transform(world_transform);
} }
self.datamap.select = controller.trigger; let mut fbb = flexbuffers::Builder::default();
self.datamap.grab = controller.grip; let mut map = fbb.start_map();
self.datamap.scroll = controller.stick; map.push("select", controller.trigger);
*self.input.datamap.lock() = self.datamap.to_datamap().ok(); map.push("grab", controller.grip);
map.end_map();
*self.input.datamap.lock() = Datamap::new(fbb.take_buffer()).ok();
} }
} }

View File

@@ -1,5 +1,5 @@
use crate::{ use crate::{
core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap}, core::client::INTERNAL_CLIENT,
nodes::{ nodes::{
input::{hand::Hand, InputMethod, InputType}, input::{hand::Hand, InputMethod, InputType},
spatial::Spatial, spatial::Spatial,
@@ -9,31 +9,26 @@ use crate::{
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use glam::Mat4; use glam::Mat4;
use nanoid::nanoid; use nanoid::nanoid;
use serde::{Deserialize, Serialize}; use stardust_xr::schemas::{
use stardust_xr::schemas::flat::{Hand as FlatHand, Joint}; flat::{Datamap, Hand as FlatHand, Joint},
flex::flexbuffers,
};
use std::sync::Arc; use std::sync::Arc;
use stereokit::{ButtonState, HandJoint, Handed, StereoKitMultiThread}; use stereokit::{ButtonState, HandJoint, Handed, StereoKitMultiThread};
use tracing::instrument;
fn convert_joint(joint: HandJoint) -> Joint { fn convert_joint(joint: HandJoint) -> Joint {
Joint { Joint {
position: joint.position.into(), position: joint.position.into(),
rotation: joint.orientation.into(), rotation: joint.orientation.into(),
radius: joint.radius, radius: joint.radius,
distance: 0.0,
} }
} }
#[derive(Default, Deserialize, Serialize)]
struct HandDatamap {
pinch_strength: f32,
grab_strength: f32,
}
pub struct SkHand { pub struct SkHand {
_node: Arc<Node>, _node: Arc<Node>,
input: Arc<InputMethod>, input: Arc<InputMethod>,
handed: Handed, handed: Handed,
datamap: TypedDatamap<HandDatamap>,
} }
impl SkHand { impl SkHand {
pub fn new(handed: Handed) -> Result<Self> { pub fn new(handed: Handed) -> Result<Self> {
@@ -50,20 +45,15 @@ impl SkHand {
_node, _node,
input, input,
handed, handed,
datamap: Default::default(),
}) })
} }
pub fn update(&mut self, controller_enabled: bool, sk: &impl StereoKitMultiThread) { #[instrument(level = "debug", name = "Update Hand Input Method", skip_all)]
pub fn update(&mut self, sk: &impl StereoKitMultiThread) {
let sk_hand = sk.input_hand(self.handed); let sk_hand = sk.input_hand(self.handed);
if let InputType::Hand(hand) = &mut *self.input.specialization.lock() { if let InputType::Hand(hand) = &mut *self.input.specialization.lock() {
let controller_active = controller_enabled let controller = sk.input_controller(self.handed);
&& sk *self.input.enabled.lock() = controller.tracked.contains(ButtonState::INACTIVE)
.input_controller(self.handed) && sk_hand.tracked_state.contains(ButtonState::ACTIVE);
.tracked
.contains(ButtonState::ACTIVE);
*self.input.enabled.lock() =
!controller_active && sk_hand.tracked_state.contains(ButtonState::ACTIVE);
sk.input_hand_visible(self.handed, *self.input.enabled.lock());
if *self.input.enabled.lock() { if *self.input.enabled.lock() {
hand.base.thumb.tip = convert_joint(sk_hand.fingers[0][4]); hand.base.thumb.tip = convert_joint(sk_hand.fingers[0][4]);
hand.base.thumb.distal = convert_joint(sk_hand.fingers[0][3]); hand.base.thumb.distal = convert_joint(sk_hand.fingers[0][3]);
@@ -96,8 +86,11 @@ impl SkHand {
hand.base.elbow = None; hand.base.elbow = None;
} }
} }
self.datamap.pinch_strength = sk_hand.pinch_activation; let mut fbb = flexbuffers::Builder::default();
self.datamap.grab_strength = sk_hand.grip_activation; let mut map = fbb.start_map();
*self.input.datamap.lock() = self.datamap.to_datamap().ok(); map.push("grab_strength", sk_hand.grip_activation);
map.push("pinch_strength", sk_hand.pinch_activation);
map.end_map();
*self.input.datamap.lock() = Datamap::new(fbb.take_buffer()).ok();
} }
} }

View File

@@ -2,8 +2,6 @@ use crate::wayland::surface::CoreSurface;
use super::state::{ClientState, WaylandState}; use super::state::{ClientState, WaylandState};
use portable_atomic::{AtomicU32, Ordering}; use portable_atomic::{AtomicU32, Ordering};
#[cfg(feature = "xwayland")]
use smithay::xwayland::XWaylandClientData;
use smithay::{ use smithay::{
delegate_compositor, delegate_compositor,
reexports::wayland_server::{protocol::wl_surface::WlSurface, Client}, reexports::wayland_server::{protocol::wl_surface::WlSurface, Client},
@@ -25,9 +23,11 @@ impl CompositorHandler for WaylandState {
.data_map .data_map
.insert_if_missing_threadsafe(|| AtomicU32::new(0)); .insert_if_missing_threadsafe(|| AtomicU32::new(0));
if !count_new { if !count_new {
if let Some(stored_count) = data.data_map.get::<AtomicU32>() { count = data
count = stored_count.fetch_add(1, Ordering::Relaxed); .data_map
} .get::<AtomicU32>()
.unwrap()
.fetch_add(1, Ordering::Relaxed);
} }
data.data_map.get::<Arc<CoreSurface>>().cloned() data.data_map.get::<Arc<CoreSurface>>().cloned()
@@ -38,15 +38,7 @@ impl CompositorHandler for WaylandState {
} }
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState { fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
if let Some(client_state) = client.get_data::<ClientState>() { &client.get_data::<ClientState>().unwrap().compositor_state
&client_state.compositor_state
} else {
#[cfg(feature = "xwayland")]
if let Some(xwayland_client_data) = client.get_data::<XWaylandClientData>() {
return &xwayland_client_data.compositor_state;
}
unimplemented!()
}
} }
} }

View File

@@ -88,10 +88,9 @@ impl KdeDecorationHandler for WaylandState {
&mut self, &mut self,
_surface: &WlSurface, _surface: &WlSurface,
decoration: &OrgKdeKwinServerDecoration, decoration: &OrgKdeKwinServerDecoration,
mode: WEnum<KdeMode>, _mode: WEnum<KdeMode>,
) { ) {
let Ok(mode) = mode.into_result() else {return}; decoration.mode(KdeMode::Server);
decoration.mode(mode);
} }
} }
delegate_kde_decoration!(WaylandState); delegate_kde_decoration!(WaylandState);

View File

@@ -1,32 +1,29 @@
mod compositor; mod compositor;
mod data_device; mod data_device;
mod decoration; mod decoration;
pub mod panel_item;
mod seat; mod seat;
mod shaders;
mod state; mod state;
mod surface; mod surface;
// mod xdg_activation; // mod xdg_activation;
mod xdg_shell; mod xdg_shell;
#[cfg(feature = "xwayland")]
pub mod xwayland;
use self::{state::WaylandState, surface::CORE_SURFACES}; use self::{state::WaylandState, surface::CORE_SURFACES};
use crate::core::buffers::BufferManager;
use crate::wayland::seat::SeatData;
use crate::{core::task, wayland::state::ClientState}; use crate::{core::task, wayland::state::ClientState};
use color_eyre::eyre::Result; use color_eyre::eyre::{ensure, Result};
use global_counter::primitive::exact::CounterU32; use global_counter::primitive::exact::CounterU32;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use sk::StereoKitDraw; use sk::StereoKitDraw;
use smithay::backend::allocator::dmabuf::Dmabuf; use smithay::backend::allocator::dmabuf::Dmabuf;
use smithay::backend::egl::EGLContext;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::backend::renderer::ImportDma; use smithay::backend::renderer::ImportDma;
use smithay::reexports::wayland_server::backend::ClientId; use smithay::reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket};
use smithay::reexports::wayland_server::DisplayHandle;
use smithay::reexports::wayland_server::{Display, ListeningSocket};
use std::ffi::OsStr;
use std::os::fd::OwnedFd;
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
use std::{ use std::{
ffi::c_void,
os::unix::{net::UnixListener, prelude::FromRawFd}, os::unix::{net::UnixListener, prelude::FromRawFd},
sync::Arc, sync::Arc,
}; };
@@ -35,106 +32,119 @@ use tokio::sync::mpsc::UnboundedReceiver;
use tokio::{ use tokio::{
io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle, io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle,
}; };
use tracing::{debug_span, info, instrument}; use tracing::{debug, debug_span, info, instrument};
pub static WAYLAND_DISPLAY: OnceCell<String> = OnceCell::new(); pub static WAYLAND_DISPLAY: OnceCell<String> = OnceCell::new();
pub static SERIAL_COUNTER: CounterU32 = CounterU32::new(0); pub static SERIAL_COUNTER: CounterU32 = CounterU32::new(0);
pub struct DisplayWrapper(Mutex<Display<WaylandState>>, DisplayHandle); struct EGLRawHandles {
impl DisplayWrapper { display: *const c_void,
pub fn handle(&self) -> DisplayHandle { config: *const c_void,
self.1.clone() context: *const c_void,
} }
pub fn dispatch_clients(&self, state: &mut WaylandState) -> Result<usize, std::io::Error> { fn get_sk_egl() -> Result<EGLRawHandles> {
self.0.lock().dispatch_clients(state) ensure!(
} unsafe { sk::sys::backend_graphics_get() }
pub fn flush_clients(&self, client: Option<ClientId>) { == sk::sys::backend_graphics__backend_graphics_opengles_egl,
if let Some(mut lock) = self.0.try_lock() { "StereoKit is not running using EGL!"
let _ = lock.backend().flush(client); );
Ok(unsafe {
EGLRawHandles {
display: sk::sys::backend_opengl_egl_get_display() as *const c_void,
config: sk::sys::backend_opengl_egl_get_config() as *const c_void,
context: sk::sys::backend_opengl_egl_get_context() as *const c_void,
} }
} })
pub fn poll_fd(&self) -> Result<OwnedFd, std::io::Error> {
self.0.lock().backend().poll_fd().try_clone_to_owned()
}
} }
static GLOBAL_DESTROY_QUEUE: OnceCell<mpsc::Sender<GlobalId>> = OnceCell::new();
pub struct Wayland { pub struct Wayland {
display: Arc<DisplayWrapper>, display: Arc<Mutex<Display<WaylandState>>>,
pub socket_name: Option<String>, pub socket_name: String,
join_handle: JoinHandle<Result<()>>, join_handle: JoinHandle<Result<()>>,
renderer: GlesRenderer,
dmabuf_rx: UnboundedReceiver<Dmabuf>, dmabuf_rx: UnboundedReceiver<Dmabuf>,
wayland_state: Arc<Mutex<WaylandState>>, state: Arc<Mutex<WaylandState>>,
#[cfg(feature = "xwayland")]
pub xwayland_state: xwayland::XWaylandState,
} }
impl Wayland { impl Wayland {
pub fn new(buffer_manager: &BufferManager) -> Result<Self> { pub fn new() -> Result<Self> {
let egl_raw_handles = get_sk_egl()?;
let renderer = unsafe {
GlesRenderer::new(EGLContext::from_raw(
egl_raw_handles.display,
egl_raw_handles.config,
egl_raw_handles.context,
)?)?
};
let display: Display<WaylandState> = Display::new()?; let display: Display<WaylandState> = Display::new()?;
let display_handle = display.handle(); let display_handle = display.handle();
let (dmabuf_tx, dmabuf_rx) = mpsc::unbounded_channel(); let (dmabuf_tx, dmabuf_rx) = mpsc::unbounded_channel();
let display = Arc::new(DisplayWrapper(Mutex::new(display), display_handle.clone())); let display = Arc::new(Mutex::new(display));
#[cfg(feature = "xwayland")] let state = WaylandState::new(display.clone(), display_handle, &renderer, dmabuf_tx);
let xwayland_state = xwayland::XWaylandState::create(&display_handle)?;
let wayland_state = WaylandState::new(display_handle, &buffer_manager.renderer, dmabuf_tx); let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);
GLOBAL_DESTROY_QUEUE.set(global_destroy_queue_in).unwrap();
let socket = ListeningSocket::bind_auto("wayland", 0..33)?; let socket = ListeningSocket::bind_auto("wayland", 0..33)?;
let socket_name = socket let socket_name = socket.socket_name().unwrap().to_str().unwrap().to_string();
.socket_name() WAYLAND_DISPLAY
.and_then(OsStr::to_str) .set(socket_name.clone())
.map(ToString::to_string); .expect("seriously message nova this time they screwed up big time");
if let Some(socket_name) = &socket_name {
let _ = WAYLAND_DISPLAY.set(socket_name.clone());
}
info!(socket_name, "Wayland active"); info!(socket_name, "Wayland active");
let join_handle = Wayland::start_loop(display.clone(), socket, wayland_state.clone())?; let join_handle =
Wayland::start_loop(display.clone(), socket, state.clone(), global_destroy_queue)?;
Ok(Wayland { Ok(Wayland {
display, display,
socket_name, socket_name,
join_handle, join_handle,
renderer,
dmabuf_rx, dmabuf_rx,
wayland_state, state,
#[cfg(feature = "xwayland")]
xwayland_state,
}) })
} }
fn start_loop( fn start_loop(
display: Arc<DisplayWrapper>, display: Arc<Mutex<Display<WaylandState>>>,
socket: ListeningSocket, socket: ListeningSocket,
state: Arc<Mutex<WaylandState>>, state: Arc<Mutex<WaylandState>>,
mut global_destroy_queue: mpsc::Receiver<GlobalId>,
) -> Result<JoinHandle<Result<()>>> { ) -> Result<JoinHandle<Result<()>>> {
let listen_async = let listen_async =
AsyncUnixListener::from_std(unsafe { UnixListener::from_raw_fd(socket.as_raw_fd()) })?; AsyncUnixListener::from_std(unsafe { UnixListener::from_raw_fd(socket.as_raw_fd()) })?;
let dispatch_poll_fd = display.poll_fd()?; let dispatch_poll_fd = display.lock().backend().poll_fd().try_clone_to_owned()?;
let dispatch_poll_listener = AsyncFd::new(dispatch_poll_fd)?; let dispatch_poll_listener = AsyncFd::new(dispatch_poll_fd)?;
let dh1 = display.handle(); let dh1 = display.lock().handle();
let mut dh2 = dh1.clone(); let mut dh2 = dh1.clone();
Ok(task::new(|| "wayland loop", async move { Ok(task::new(|| "wayland loop", async move {
let _socket = socket; // Keep the socket alive let _socket = socket; // Keep the socket alive
loop { loop {
tokio::select! { tokio::select! {
e = global_destroy_queue.recv() => { // New global to destroy
debug!(?e, "destroy global");
dh1.remove_global::<WaylandState>(e.unwrap());
}
acc = listen_async.accept() => { // New client connected acc = listen_async.accept() => { // New client connected
let (stream, _) = acc?; let (stream, _) = acc?;
let client_state = Arc::new(ClientState { let client = dh2.insert_client(stream.into_std()?, Arc::new(ClientState::default()))?;
id: OnceCell::new(),
compositor_state: Default::default(), state.lock().new_client(client.id(), &dh2);
display: Arc::downgrade(&display),
seat: SeatData::new(&dh1)
});
let client = dh2.insert_client(stream.into_std()?, client_state.clone())?;
let _ = client_state.seat.client.set(client.id());
} }
e = dispatch_poll_listener.readable() => { // Dispatch e = dispatch_poll_listener.readable() => { // Dispatch
let mut guard = e?; let mut guard = e?;
debug_span!("Dispatch wayland event").in_scope(|| -> Result<(), color_eyre::Report> { debug_span!("Dispatch wayland event").in_scope(|| -> Result<(), color_eyre::Report> {
let mut display = display.lock();
display.dispatch_clients(&mut *state.lock())?; display.dispatch_clients(&mut *state.lock())?;
display.flush_clients(None); display.flush_clients()?;
Ok(()) Ok(())
})?; })?;
guard.clear_ready(); guard.clear_ready();
@@ -144,27 +154,29 @@ impl Wayland {
})?) })?)
} }
#[instrument( #[instrument(level = "debug", name = "Wayland frame", skip(self, sk))]
level = "debug", pub fn update(&mut self, sk: &impl StereoKitDraw) {
name = "Wayland frame",
skip(self, sk, buffer_manager)
)]
pub fn update(&mut self, sk: &impl StereoKitDraw, buffer_manager: &mut BufferManager) {
while let Ok(dmabuf) = self.dmabuf_rx.try_recv() { while let Ok(dmabuf) = self.dmabuf_rx.try_recv() {
let _ = buffer_manager.renderer.import_dmabuf(&dmabuf, None); let _ = self.renderer.import_dmabuf(&dmabuf, None);
} }
for core_surface in CORE_SURFACES.get_valid_contents() { for core_surface in CORE_SURFACES.get_valid_contents() {
core_surface.process(sk, &mut buffer_manager.renderer); core_surface.process(sk, &mut self.renderer);
} }
self.display.flush_clients(None); self.display.lock().flush_clients().unwrap();
} }
pub fn frame_event(&self, sk: &impl StereoKitDraw) { pub fn frame_event(&self, sk: &impl StereoKitDraw) {
let output = self.wayland_state.lock().output.clone(); let state = self.state.lock();
for core_surface in CORE_SURFACES.get_valid_contents() { for core_surface in CORE_SURFACES.get_valid_contents() {
core_surface.frame(sk, output.clone()); core_surface.frame(sk, state.output.clone());
}
}
pub fn make_context_current(&self) {
unsafe {
self.renderer.egl_context().make_current().unwrap();
} }
} }
} }

663
src/wayland/panel_item.rs Normal file
View File

@@ -0,0 +1,663 @@
use super::{
seat::{Cursor, SeatData},
surface::CoreSurface,
xdg_shell::{PopupData, ToplevelData, XdgSurfaceData},
SERIAL_COUNTER,
};
use crate::{
core::{
client::{get_env, startup_settings, Client, INTERNAL_CLIENT},
registry::Registry,
},
nodes::{
drawable::Drawable,
items::{self, Item, ItemSpecialization, ItemType, TypeInfo},
spatial::Spatial,
Node,
},
wayland::seat::{KeyboardEvent, PointerEvent},
};
use color_eyre::eyre::{bail, eyre, Result};
use glam::Mat4;
use lazy_static::lazy_static;
use mint::Vector2;
use nanoid::nanoid;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use serde::{
de::{Deserializer, Error, SeqAccess, Visitor},
ser::Serializer,
Deserialize, Serialize,
};
use smithay::{
reexports::{
wayland_protocols::xdg::shell::server::{
xdg_popup::XdgPopup,
xdg_surface::XdgSurface,
xdg_toplevel::{XdgToplevel, EVT_CONFIGURE_BOUNDS_SINCE, EVT_WM_CAPABILITIES_SINCE},
},
wayland_server::{
backend::Credentials, protocol::wl_surface::WlSurface, Resource, Weak as WlWeak,
},
},
wayland::compositor,
};
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::sync::{Arc, Weak};
use tracing::debug;
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
lazy_static! {
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
type_name: "panel",
aliased_local_signals: vec![
"apply_surface_material",
"configure_toplevel",
"set_toplevel_capabilities",
"pointer_scroll",
"pointer_button",
"pointer_motion",
"keyboard_key",
"keyboard_set_keymap_names",
"keyboard_set_keymap_string",
"close",
],
aliased_local_methods: vec![],
aliased_remote_signals: vec![
"commit_toplevel",
"recommend_toplevel_state",
"set_cursor",
"new_popup",
"reposition_popup",
"drop_popup",
],
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
};
}
/// An ID for a surface inside this panel item
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum SurfaceID {
Cursor,
Toplevel,
Popup(String),
}
impl Default for SurfaceID {
fn default() -> Self {
Self::Toplevel
}
}
impl<'de> serde::Deserialize<'de> for SurfaceID {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_seq(SurfaceIDVisitor)
}
}
struct SurfaceIDVisitor;
impl<'de> Visitor<'de> for SurfaceIDVisitor {
type Value = SurfaceID;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("idk")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let Some(discrim) = seq.next_element()? else {
return Err(A::Error::missing_field("discrim"));
};
// idk if you wanna check for extraneous elements
// I didn't bother
match discrim {
"Cursor" => Ok(SurfaceID::Cursor),
"Toplevel" => Ok(SurfaceID::Toplevel),
"Popup" => {
let Some(text) = seq.next_element()? else {
return Err(A::Error::missing_field("popup_text"));
};
Ok(SurfaceID::Popup(text))
}
_ => Err(A::Error::unknown_variant(
discrim,
&["Cursor", "Toplevel", "Popup"],
)),
}
}
}
impl serde::Serialize for SurfaceID {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Cursor => ["Cursor"].serialize(serializer),
Self::Toplevel => ["Toplevel"].serialize(serializer),
Self::Popup(text) => ["Popup", text].serialize(serializer),
}
}
}
#[derive(Debug, Clone, Copy, Serialize)]
#[serde(tag = "type", content = "content")]
pub enum RecommendedState {
Maximize(bool),
Fullscreen(bool),
Minimize,
Move,
Resize(u32),
}
pub struct PanelItem {
pub uid: String,
node: Weak<Node>,
cursor: Mutex<Option<WlWeak<WlSurface>>>,
pub seat_data: Arc<SeatData>,
toplevel: WlWeak<XdgToplevel>,
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
pointer_grab: Mutex<Option<SurfaceID>>,
keyboard_grab: Mutex<Option<SurfaceID>>,
}
impl PanelItem {
pub fn create(
toplevel: XdgToplevel,
wl_surface: WlSurface,
client_credentials: Option<Credentials>,
seat_data: Arc<SeatData>,
) -> (Arc<Node>, Arc<PanelItem>) {
debug!(?toplevel, ?client_credentials, "Create panel item");
let startup_settings = client_credentials
.and_then(|cred| get_env(cred.pid).ok())
.and_then(|env| startup_settings(&env));
let uid = nanoid!();
let node = Arc::new(Node::create(
&INTERNAL_CLIENT,
"/item/panel/item",
&uid,
true,
));
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false).unwrap();
let panel_item = Arc::new(PanelItem {
uid: uid.clone(),
node: Arc::downgrade(&node),
cursor: Mutex::new(None),
seat_data,
toplevel: toplevel.downgrade(),
popups: Mutex::new(FxHashMap::default()),
pointer_grab: Mutex::new(None),
keyboard_grab: Mutex::new(None),
});
if let Some(startup_settings) = &startup_settings {
spatial.set_local_transform(
spatial.global_transform().inverse() * startup_settings.transform,
);
}
panel_item
.seat_data
.new_surface(&wl_surface, Arc::downgrade(&panel_item));
let item = Item::add_to(
&node,
uid,
&ITEM_TYPE_INFO_PANEL,
ItemType::Panel(panel_item.clone()),
);
if let Some(startup_settings) = &startup_settings {
if let Some(acceptor) = startup_settings
.acceptors
.get(&*ITEM_TYPE_INFO_PANEL)
.and_then(|acc| acc.upgrade())
{
items::capture(&item, &acceptor);
}
}
node.add_local_signal(
"apply_surface_material",
PanelItem::apply_surface_material_flex,
);
node.add_local_signal("configure_toplevel", PanelItem::configure_toplevel_flex);
node.add_local_signal(
"set_toplevel_capabilities",
PanelItem::set_toplevel_capabilities_flex,
);
node.add_local_signal("pointer_scroll", PanelItem::pointer_scroll_flex);
node.add_local_signal("pointer_button", PanelItem::pointer_button_flex);
node.add_local_signal("pointer_motion", PanelItem::pointer_motion_flex);
node.add_local_signal(
"keyboard_set_keymap_string",
PanelItem::keyboard_set_keymap_string_flex,
);
node.add_local_signal(
"keyboard_set_keymap_names",
PanelItem::keyboard_set_keymap_names_flex,
);
node.add_local_signal("keyboard_key", PanelItem::keyboard_key_flex);
(node, panel_item)
}
pub fn from_node(node: &Node) -> Option<Arc<PanelItem>> {
let ItemType::Panel(panel_item) = &node.item.get()?.specialization else {return None};
Some(panel_item.clone())
}
fn toplevel(&self) -> XdgToplevel {
self.toplevel.upgrade().unwrap()
}
fn toplevel_xdg_surface(&self) -> XdgSurface {
let toplevel = self.toplevel();
let data = ToplevelData::get(&toplevel).lock();
data.xdg_surface()
}
fn toplevel_wl_surface(&self) -> WlSurface {
XdgSurfaceData::get(&self.toplevel_xdg_surface())
.lock()
.wl_surface()
}
fn core_surface(&self) -> Option<Arc<CoreSurface>> {
compositor::with_states(&self.toplevel_wl_surface(), |data| {
data.data_map.get::<Arc<CoreSurface>>().cloned()
})
}
fn flush_clients(&self) {
if let Some(core_surface) = self.core_surface() {
core_surface.flush_clients();
}
}
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
match id {
SurfaceID::Cursor => self.cursor.lock().clone()?.upgrade().ok(),
SurfaceID::Toplevel => Some(self.toplevel_wl_surface()),
SurfaceID::Popup(popup) => {
let popups = self.popups.lock();
let popup = popups.get(popup)?.upgrade().ok()?;
let surf = PopupData::get(&popup).lock().wl_surface();
Some(surf)
}
}
}
fn wl_surface_from_id_result(&self, id: &SurfaceID) -> Result<WlSurface> {
self.wl_surface_from_id(id)
.ok_or(eyre!("Surface with ID not found"))
}
fn apply_surface_material_flex(
node: &Node,
calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
#[derive(Debug, Deserialize)]
struct SurfaceMaterialInfo<'a> {
surface: SurfaceID,
model_node_path: &'a str,
}
let info: SurfaceMaterialInfo = deserialize(data)?;
let Some(wl_surface) = panel_item.wl_surface_from_id(&info.surface) else { return Ok(()) };
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else { return Ok(()) };
let model_node = calling_client
.scenegraph
.get_node(info.model_node_path)
.ok_or_else(|| eyre!("Model node not found"))?;
let Some(Drawable::ModelPart(model_node)) = model_node.drawable.get() else {bail!("Node is not a model")};
debug!(?info, "Apply surface material");
core_surface.apply_material(model_node);
Ok(())
}
fn pointer_motion_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
let (surface_id, position): (SurfaceID, Vector2<f64>) = deserialize(data)?;
let wl_surface = panel_item.wl_surface_from_id_result(&surface_id)?;
debug!(?surface_id, ?position, "Pointer deactivate");
panel_item
.seat_data
.pointer_event(&wl_surface, PointerEvent::Motion(position));
panel_item.flush_clients();
Ok(())
}
fn pointer_button_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
let (surface_id, button, state): (SurfaceID, u32, u32) = deserialize(data)?;
let wl_surface = panel_item.wl_surface_from_id_result(&surface_id)?;
debug!(?surface_id, button, state, "Pointer button");
panel_item
.seat_data
.pointer_event(&wl_surface, PointerEvent::Button { button, state });
panel_item.flush_clients();
Ok(())
}
fn pointer_scroll_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
#[derive(Debug, Deserialize)]
struct PointerScrollInfo {
surface_id: SurfaceID,
axis_continuous: Option<Vector2<f32>>,
axis_discrete: Option<Vector2<f32>>,
}
let info: PointerScrollInfo = deserialize(data)?;
let wl_surface = panel_item.wl_surface_from_id_result(&info.surface_id)?;
debug!(?info, "Pointer scroll");
panel_item.seat_data.pointer_event(
&wl_surface,
PointerEvent::Scroll {
axis_continuous: info.axis_continuous,
axis_discrete: info.axis_discrete,
},
);
panel_item.flush_clients();
Ok(())
}
fn keyboard_set_keymap_string_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let context = xkb::Context::new(0);
let keymap =
Keymap::new_from_string(&context, deserialize(data)?, XKB_KEYMAP_FORMAT_TEXT_V1, 0)
.ok_or_else(|| eyre!("Keymap is not valid"))?;
PanelItem::keyboard_set_keymap_flex(node, &keymap)
}
fn keyboard_set_keymap_names_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
#[derive(Debug, Deserialize)]
struct Names<'a> {
rules: &'a str,
model: &'a str,
layout: &'a str,
variant: &'a str,
options: Option<String>,
}
let names: Names = deserialize(data)?;
let context = xkb::Context::new(0);
let keymap = Keymap::new_from_names(
&context,
names.rules,
names.model,
names.layout,
names.variant,
names.options,
XKB_KEYMAP_FORMAT_TEXT_V1,
)
.ok_or_else(|| eyre!("Keymap is not valid"))?;
PanelItem::keyboard_set_keymap_flex(node, &keymap)
}
fn keyboard_set_keymap_flex(node: &Node, keymap: &Keymap) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
let toplevel = panel_item.toplevel_wl_surface();
debug!(?toplevel, "Keyboard set keymap");
let mut surfaces = vec![toplevel];
surfaces.extend(panel_item.popups.lock().values().filter_map(|p| {
let popup = p.upgrade().ok()?;
let popup_data = PopupData::get(&popup).lock();
let xdg_surface = popup_data.xdg_surface();
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
Some(xdg_surface_data.wl_surface())
}));
panel_item.seat_data.set_keymap(keymap, surfaces);
Ok(())
}
fn keyboard_key_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
let (surface_id, key, state): (SurfaceID, u32, u32) = deserialize(data)?;
let wl_surface = panel_item.wl_surface_from_id_result(&surface_id)?;
debug!(key, state, "Set keyboard key state");
panel_item
.seat_data
.keyboard_event(&wl_surface, KeyboardEvent::Key { key, state });
Ok(())
}
fn configure_toplevel_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
let xdg_surface = panel_item.toplevel_xdg_surface();
#[derive(Debug, Deserialize)]
struct ConfigureToplevelInfo {
size: Option<Vector2<u32>>,
states: Vec<u32>,
bounds: Option<Vector2<u32>>,
}
let info: ConfigureToplevelInfo = deserialize(data)?;
debug!(info = ?&info, "Configure toplevel info");
if let Some(bounds) = info.bounds {
if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE {
xdg_toplevel.configure_bounds(bounds.x as i32, bounds.y as i32);
}
}
let zero_size = Vector2::from([0; 2]);
let size = info.size.unwrap_or(zero_size);
// if size == zero_size && (info.states.contains(1) || info.states.contains(2)) {
// xdg_toplevel.configure(
// size.x as i32,
// size.y as i32,
// info.states
// .into_iter()
// .flat_map(|state| state.to_ne_bytes())
// .collect(),
// );
// }
xdg_toplevel.configure(
size.x as i32,
size.y as i32,
info.states.into_iter().flat_map(u32::to_ne_bytes).collect(),
);
xdg_surface.configure(SERIAL_COUNTER.inc());
core_surface.flush_clients();
Ok(())
}
fn set_toplevel_capabilities_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
if xdg_toplevel.version() < EVT_WM_CAPABILITIES_SINCE {
return Ok(());
}
let xdg_surface = panel_item.toplevel_xdg_surface();
let capabilities: Vec<u8> = deserialize(data)?;
debug!("Set toplevel capabilities");
xdg_toplevel.wm_capabilities(capabilities);
xdg_surface.configure(SERIAL_COUNTER.inc());
core_surface.flush_clients();
Ok(())
}
pub fn commit_toplevel(&self) {
// let mapped_size = self.core_surface().and_then(|c| c.size());
let toplevel = self.toplevel();
let state = ToplevelData::get(&toplevel);
let state = state.lock();
// let mut queued_state = state.queued_state.take().unwrap();
// queued_state.mapped = mapped_size.is_some();
// if let Some(size) = mapped_size {
// queued_state.size = size;
// queued_state.geometry.update_to_surface_size(size);
// }
// *state = (*queued_state).clone();
// state.queued_state = Some(queued_state);
debug!(state = ?&*state, "Commit toplevel");
let Some(node) = self.node.upgrade() else { return };
let _ = node.send_remote_signal("commit_toplevel", &serialize(&*state).unwrap());
}
pub fn recommend_toplevel_state(&self, state: RecommendedState) {
let Some(node) = self.node.upgrade() else { return };
let data = serialize(state).unwrap();
debug!(?state, "Recommend toplevel state");
let _ = node.send_remote_signal("recommend_toplevel_state", &data);
}
pub fn new_popup(&self, popup: &XdgPopup, data: &PopupData) {
let uid = data.uid.clone();
self.popups.lock().insert(uid.clone(), popup.downgrade());
let Some(node) = self.node.upgrade() else { return };
let _ = node.send_remote_signal("new_popup", &serialize(&(&uid, data)).unwrap());
}
// pub fn commit_popup(&self, data: &PopupData) {
// let xdg_surf = data.xdg_surface.upgrade().unwrap();
// let surf = xdg_surf
// .data::<XdgSurfaceData>()
// .unwrap()
// .wl_surface
// .upgrade()
// .unwrap();
// let core_surface =
// compositor::with_states(&surf, |s| s.data_map.get::<Arc<CoreSurface>>().cloned())
// .unwrap();
// let mut popup_state = data.state.lock();
// popup_state.mapped = core_surface.size().is_some();
// }
pub fn reposition_popup(&self, popup_state: &PopupData) {
let Some(node) = self.node.upgrade() else { return };
let _ = node.send_remote_signal(
"reposition_popup",
&serialize(popup_state.positioner_data().unwrap()).unwrap(),
);
}
pub fn drop_popup(&self, uid: &str) {
if let Some(popup) = self
.popups
.lock()
.remove(uid)
.and_then(|popup| popup.upgrade().ok()?.data::<Arc<PopupData>>().cloned())
{
self.seat_data.drop_surface(&popup.wl_surface());
}
let Some(node) = self.node.upgrade() else { return };
let _ = node.send_remote_signal("drop_popup", &serialize(uid).unwrap());
}
pub fn grab_keyboard(&self, sid: Option<SurfaceID>) {
let Some(node) = self.node.upgrade() else { return };
let _ = node.send_remote_signal("grab_keyboard", &serialize(sid).unwrap());
}
pub fn set_cursor(&self, surface: Option<&WlSurface>, hotspot_x: i32, hotspot_y: i32) {
let Some(node) = self.node.upgrade() else { return };
debug!(?surface, hotspot_x, hotspot_y, "Set cursor size");
let mut data = serialize(()).unwrap();
let cursor_size = surface
.and_then(|c| CoreSurface::from_wl_surface(c))
.and_then(|c| c.size());
if let Some(size) = cursor_size {
data = serialize((size, (hotspot_x, hotspot_y))).unwrap();
}
let _ = node.send_remote_signal("set_cursor", &data);
*self.cursor.lock() = surface.map(|surf| surf.downgrade());
}
pub fn on_drop(&self) {
let toplevel = self.toplevel_wl_surface();
self.seat_data.drop_surface(&toplevel);
debug!("Drop panel item");
}
}
impl ItemSpecialization for PanelItem {
fn serialize_start_data(&self, id: &str) -> Vec<u8> {
let cursor = self.cursor.lock().as_ref().and_then(|c| c.upgrade().ok());
let cursor_size = cursor
.as_ref()
.and_then(|c| CoreSurface::from_wl_surface(&c))
.and_then(|c| c.size());
let cursor_hotspot = cursor
.and_then(|c| {
compositor::with_states(&c, |data| data.data_map.get::<Arc<Cursor>>().cloned())
})
.map(|cursor| cursor.hotspot);
let toplevel = self.toplevel();
let toplevel_state = ToplevelData::get(&toplevel);
let toplevel_state = toplevel_state.lock().clone();
let popups = self
.popups
.lock()
.values()
.filter_map(|v| Some(v.upgrade().ok()?.data::<Mutex<PopupData>>()?.lock().clone()))
.collect::<Vec<_>>();
let pointer_grab = self.pointer_grab.lock().clone();
let keyboard_grab = self.keyboard_grab.lock().clone();
serialize((
id,
(
cursor_size.zip(cursor_hotspot),
toplevel_state,
popups,
pointer_grab,
keyboard_grab,
),
))
.unwrap()
}
}
impl Drop for PanelItem {
fn drop(&mut self) {
// Dropped panel item, basically just a debug breakpoint place
}
}

View File

@@ -1,13 +1,9 @@
use super::{ use super::{
state::{ClientState, WaylandState}, panel_item::PanelItem, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE,
surface::CoreSurface,
SERIAL_COUNTER, SERIAL_COUNTER,
}; };
use crate::{ use crate::core::task;
core::task, use color_eyre::eyre::Result;
nodes::items::panel::{Backend, Geometry, PanelItem},
};
use color_eyre::eyre::{bail, eyre, Result};
use mint::Vector2; use mint::Vector2;
use nanoid::nanoid; use nanoid::nanoid;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@@ -31,51 +27,39 @@ use smithay::{
}; };
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
sync::Arc, sync::{Arc, Weak},
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use tokio::sync::watch;
use tracing::{debug, warn}; use tracing::{debug, warn};
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keycode, Keymap}; use xkbcommon::xkb::{self, Keymap};
pub fn handle_cursor<B: Backend>(
panel_item: &Arc<PanelItem<B>>,
mut cursor: watch::Receiver<Option<CursorInfo>>,
) {
let panel_item_weak = Arc::downgrade(panel_item);
let _ = task::new(|| "cursor handler", async move {
while cursor.changed().await.is_ok() {
let Some(panel_item) = panel_item_weak.upgrade() else {continue};
let cursor_info = cursor.borrow();
panel_item.set_cursor(cursor_info.as_ref().and_then(CursorInfo::cursor_data));
}
});
}
pub struct KeyboardInfo { pub struct KeyboardInfo {
keymap_string: String,
keymap: KeymapFile, keymap: KeymapFile,
state: xkb::State, state: xkb::State,
mods: ModifiersState, mods: ModifiersState,
keys: FxHashSet<u32>, keys: FxHashSet<u32>,
} }
impl KeyboardInfo { impl KeyboardInfo {
pub fn new(keymap_string: String, keymap: &Keymap) -> Self { pub fn new(keymap: &Keymap) -> Self {
KeyboardInfo { KeyboardInfo {
keymap_string,
state: xkb::State::new(keymap), state: xkb::State::new(keymap),
keymap: KeymapFile::new(keymap), keymap: KeymapFile::new(keymap),
mods: ModifiersState::default(), mods: ModifiersState::default(),
keys: FxHashSet::default(), keys: FxHashSet::default(),
} }
} }
pub fn process(&mut self, key: u32, pressed: bool, keyboard: &WlKeyboard) -> Result<usize> { pub fn process(&mut self, key: u32, state: u32, keyboard: &WlKeyboard) -> Result<usize> {
let xkb_key_state = if pressed { let wl_key_state = match state {
xkb::KeyDirection::Down 0 => KeyState::Released,
} else { 1 => KeyState::Pressed,
xkb::KeyDirection::Up _ => color_eyre::eyre::bail!("Invalid key state!"),
}; };
let state_components = self.state.update_key(Keycode::new(key + 8), xkb_key_state); let xkb_key_state = match state {
0 => xkb::KeyDirection::Up,
1 => xkb::KeyDirection::Down,
_ => color_eyre::eyre::bail!("Invalid key state!"),
};
let state_components = self.state.update_key(key + 8, xkb_key_state);
if state_components != 0 { if state_components != 0 {
self.mods.update_with(&self.state); self.mods.update_with(&self.state);
keyboard.modifiers( keyboard.modifiers(
@@ -86,17 +70,6 @@ impl KeyboardInfo {
0, 0,
); );
} }
// if pressed {
// println!("Key {key} is being pressed with {state_components} modifiers");
// } else {
// println!("Key {key} is being released with {state_components} modifiers");
// }
let wl_key_state = if pressed {
KeyState::Pressed
} else {
KeyState::Released
};
keyboard.key(SERIAL_COUNTER.inc(), 0, key, wl_key_state); keyboard.key(SERIAL_COUNTER.inc(), 0, key, wl_key_state);
match wl_key_state { match wl_key_state {
KeyState::Pressed => { KeyState::Pressed => {
@@ -114,7 +87,7 @@ unsafe impl Send for KeyboardInfo {}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum PointerEvent { pub enum PointerEvent {
Motion(Vector2<f32>), Motion(Vector2<f64>),
Button { Button {
button: u32, button: u32,
state: u32, state: u32,
@@ -127,36 +100,29 @@ pub enum PointerEvent {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum KeyboardEvent { pub enum KeyboardEvent {
Keymap, Keymap,
Key { key: u32, state: bool }, Key { key: u32, state: u32 },
} }
const POINTER_EVENT_TIMEOUT: Duration = Duration::from_millis(50); const POINTER_EVENT_TIMEOUT: Duration = Duration::from_secs(1);
struct SurfaceInfo { struct SurfaceInfo {
wl_surface: WlWeak<WlSurface>, wl_surface: WlWeak<WlSurface>,
cursor_sender: watch::Sender<Option<CursorInfo>>, panel_item: Weak<PanelItem>,
pointer_queue: VecDeque<PointerEvent>, pointer_queue: VecDeque<PointerEvent>,
pointer_latest_event: Instant, pointer_latest_event: Instant,
keyboard_queue: VecDeque<KeyboardEvent>, keyboard_queue: VecDeque<KeyboardEvent>,
keyboard_info: Option<KeyboardInfo>, keyboard_info: Option<KeyboardInfo>,
} }
impl SurfaceInfo { impl SurfaceInfo {
fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender<Option<CursorInfo>>) -> Self { fn new(wl_surface: &WlSurface, panel_item: Weak<PanelItem>) -> Self {
SurfaceInfo { SurfaceInfo {
wl_surface: wl_surface.downgrade(), wl_surface: wl_surface.downgrade(),
cursor_sender, panel_item,
pointer_queue: VecDeque::new(), pointer_queue: VecDeque::new(),
pointer_latest_event: Instant::now(), pointer_latest_event: Instant::now(),
keyboard_queue: VecDeque::new(), keyboard_queue: VecDeque::new(),
keyboard_info: None, keyboard_info: None,
} }
} }
fn flush(&self) {
if let Some(client) = self.wl_surface.upgrade().ok().and_then(|s| s.client()) {
if let Some(client_data) = client.get_data::<ClientState>() {
client_data.flush();
}
}
}
fn handle_pointer_events(&mut self, pointer: &WlPointer, mut locked: bool) -> bool { fn handle_pointer_events(&mut self, pointer: &WlPointer, mut locked: bool) -> bool {
let Ok(focus) = self.wl_surface.upgrade() else { return false; }; let Ok(focus) = self.wl_surface.upgrade() else { return false; };
let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; }; let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; };
@@ -171,20 +137,18 @@ impl SurfaceInfo {
pointer.enter( pointer.enter(
SERIAL_COUNTER.inc(), SERIAL_COUNTER.inc(),
&focus, &focus,
(pos.x as f64).clamp(0.0, focus_size.x as f64), pos.x.clamp(0.0, focus_size.x as f64),
(pos.y as f64).clamp(0.0, focus_size.y as f64), pos.y.clamp(0.0, focus_size.y as f64),
); );
locked = true; locked = true;
} }
(true, PointerEvent::Motion(pos)) => { (true, PointerEvent::Motion(pos)) => {
pointer.motion( pointer.motion(
0, 0,
(pos.x as f64).clamp(0.0, focus_size.x as f64), pos.x.clamp(0.0, focus_size.x as f64),
(pos.y as f64).clamp(0.0, focus_size.y as f64), pos.y.clamp(0.0, focus_size.y as f64),
); );
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { pointer.frame();
pointer.frame();
}
} }
(true, PointerEvent::Button { button, state }) => { (true, PointerEvent::Button { button, state }) => {
pointer.button( pointer.button(
@@ -197,9 +161,7 @@ impl SurfaceInfo {
_ => continue, _ => continue,
}, },
); );
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { pointer.frame();
pointer.frame();
}
} }
( (
true, true,
@@ -210,24 +172,17 @@ impl SurfaceInfo {
) => { ) => {
if let Some(axis_continuous) = axis_continuous { if let Some(axis_continuous) = axis_continuous {
pointer.axis(0, Axis::HorizontalScroll, axis_continuous.x as f64); pointer.axis(0, Axis::HorizontalScroll, axis_continuous.x as f64);
pointer.axis(0, Axis::VerticalScroll, -axis_continuous.y as f64); pointer.axis(0, Axis::VerticalScroll, axis_continuous.y as f64);
} }
if pointer.version() >= wl_pointer::EVT_AXIS_DISCRETE_SINCE { if let Some(axis_discrete) = axis_discrete {
if let Some(axis_discrete) = axis_discrete { pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32);
pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32); pointer.axis_discrete(Axis::VerticalScroll, axis_discrete.y as i32);
pointer.axis_discrete(Axis::VerticalScroll, -axis_discrete.y as i32);
}
} }
if pointer.version() >= wl_pointer::EVT_AXIS_STOP_SINCE if axis_discrete.is_none() && axis_continuous.is_none() {
&& axis_discrete.is_none()
&& axis_continuous.is_none()
{
pointer.axis_stop(0, Axis::HorizontalScroll); pointer.axis_stop(0, Axis::HorizontalScroll);
pointer.axis_stop(0, Axis::VerticalScroll); pointer.axis_stop(0, Axis::VerticalScroll);
} }
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { pointer.frame();
pointer.frame();
}
} }
(locked, event) => { (locked, event) => {
warn!(locked, ?event, "Invalid pointer event!"); warn!(locked, ?event, "Invalid pointer event!");
@@ -238,7 +193,6 @@ impl SurfaceInfo {
pointer.leave(SERIAL_COUNTER.inc(), &focus); pointer.leave(SERIAL_COUNTER.inc(), &focus);
locked = false; locked = false;
} }
self.flush();
locked locked
} }
@@ -248,9 +202,7 @@ impl SurfaceInfo {
if !locked { if !locked {
keyboard.enter(0, &focus, vec![]); keyboard.enter(0, &focus, vec![]);
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE { keyboard.repeat_info(0, 0);
keyboard.repeat_info(0, 0);
}
locked = info.keymap.send(keyboard).is_ok(); locked = info.keymap.send(keyboard).is_ok();
} }
while let Some(event) = self.keyboard_queue.pop_front() { while let Some(event) = self.keyboard_queue.pop_front() {
@@ -272,62 +224,50 @@ impl SurfaceInfo {
} }
} }
} }
self.flush();
locked locked
} }
} }
pub struct SeatData { pub struct SeatData {
pub client: OnceCell<ClientId>, client: ClientId,
global_id: OnceCell<GlobalId>, global_id: OnceCell<GlobalId>,
surfaces: Mutex<FxHashMap<ObjectId, SurfaceInfo>>, surfaces: Mutex<FxHashMap<ObjectId, SurfaceInfo>>,
pointer: OnceCell<(WlPointer, Mutex<ObjectId>)>, pointer: OnceCell<(WlPointer, Mutex<ObjectId>)>,
keyboard: OnceCell<(WlKeyboard, Mutex<ObjectId>)>, keyboard: OnceCell<(WlKeyboard, Mutex<ObjectId>)>,
touch: OnceCell<WlTouch>, touch: OnceCell<WlTouch>,
touches: Mutex<FxHashMap<ObjectId, u32>>,
} }
impl SeatData { impl SeatData {
pub fn new(dh: &DisplayHandle) -> Arc<Self> { pub fn new(dh: &DisplayHandle, client: ClientId) -> Arc<Self> {
let seat_data = Arc::new(SeatData { let seat_data = Arc::new(SeatData {
client: OnceCell::new(), client,
global_id: OnceCell::new(), global_id: OnceCell::new(),
surfaces: Mutex::new(FxHashMap::default()), surfaces: Mutex::new(FxHashMap::default()),
pointer: OnceCell::new(), pointer: OnceCell::new(),
keyboard: OnceCell::new(), keyboard: OnceCell::new(),
touch: OnceCell::new(), touch: OnceCell::new(),
touches: Mutex::new(FxHashMap::default()),
}); });
let _ = seat_data seat_data
.global_id .global_id
.set(dh.create_global::<WaylandState, _, _>(7, seat_data.clone())); .set(dh.create_global::<WaylandState, _, _>(7, seat_data.clone()))
.unwrap();
seat_data seat_data
} }
pub fn set_keymap(&self, keymap_str: String, surfaces: Vec<WlSurface>) -> Result<()> { pub fn set_keymap(&self, keymap: &Keymap, surfaces: Vec<WlSurface>) {
let context = xkb::Context::new(0);
let keymap =
Keymap::new_from_string(&context, keymap_str.clone(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
.ok_or_else(|| eyre!("Keymap is not valid"))?;
let mut panels = self.surfaces.lock(); let mut panels = self.surfaces.lock();
let Some((_, focus)) = self.keyboard.get() else {bail!("Could not get keyboard")}; let Some((_, focus)) = self.keyboard.get() else {return};
for surface in surfaces { for surface in surfaces {
let Some(surface_info) = panels.get_mut(&surface.id()) else {continue}; let Some(surface_info) = panels.get_mut(&surface.id()) else {continue};
if let Some(keyboard_info) = &mut surface_info.keyboard_info {
if &keyboard_info.keymap_string == &keymap_str {
continue;
}
}
surface_info surface_info
.keyboard_info .keyboard_info
.replace(KeyboardInfo::new(keymap_str.clone(), &keymap)); .replace(KeyboardInfo::new(keymap));
if *focus.lock() == surface.id() { if *focus.lock() == surface.id() {
surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap); surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap);
} }
} }
Ok(())
} }
pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) { pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) {
@@ -403,13 +343,10 @@ impl SeatData {
} }
} }
pub fn new_surface(&self, surface: &WlSurface) -> watch::Receiver<Option<CursorInfo>> { pub fn new_surface(&self, surface: &WlSurface, panel_item: Weak<PanelItem>) {
let (tx, rx) = watch::channel(None);
self.surfaces self.surfaces
.lock() .lock()
.insert(surface.id(), SurfaceInfo::new(surface, tx)); .insert(surface.id(), SurfaceInfo::new(surface, panel_item));
rx
} }
pub fn drop_surface(&self, surface: &WlSurface) { pub fn drop_surface(&self, surface: &WlSurface) {
self.surfaces.lock().remove(&surface.id()); self.surfaces.lock().remove(&surface.id());
@@ -425,51 +362,14 @@ impl SeatData {
*keyboard_focus = ObjectId::null(); *keyboard_focus = ObjectId::null();
} }
} }
self.touches.lock().remove(&surface.id());
}
pub fn touch_down(&self, surface: &WlSurface, id: u32, position: Vector2<f32>) {
let Some(touch) = self.touch.get() else {return};
touch.down(
SERIAL_COUNTER.inc(),
0,
surface,
id as i32,
position.x as f64,
position.y as f64,
);
self.touches.lock().insert(surface.id(), id);
}
pub fn touch_move(&self, id: u32, position: Vector2<f32>) {
let Some(touch) = self.touch.get() else {return};
touch.motion(0, id as i32, position.x as f64, position.y as f64);
}
pub fn touch_up(&self, id: u32) {
let Some(touch) = self.touch.get() else {return};
touch.up(SERIAL_COUNTER.inc(), 0, id as i32);
let mut touches = self.touches.lock();
touches.retain(|_, tid| *tid != id);
}
pub fn reset_touches(&self) {
let Some(touch) = self.touch.get() else {return};
for (_, touch_id) in self.touches.lock().drain() {
touch.up(SERIAL_COUNTER.inc(), 0, touch_id as i32);
}
} }
} }
impl Drop for SeatData {
pub struct CursorInfo { fn drop(&mut self) {
pub surface: WlWeak<WlSurface>, let id = self.global_id.take().unwrap();
pub hotspot_x: i32, let _ = task::new(|| "global destroy queue garbage collection", async move {
pub hotspot_y: i32, GLOBAL_DESTROY_QUEUE.get().unwrap().send(id).await
} });
impl CursorInfo {
pub fn cursor_data(&self) -> Option<Geometry> {
let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?;
Some(Geometry {
origin: [self.hotspot_x, self.hotspot_y].into(),
size: cursor_size,
})
} }
} }
@@ -488,12 +388,11 @@ impl GlobalDispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
resource.name(nanoid!()); resource.name(nanoid!());
} }
resource.capabilities(Capability::Pointer | Capability::Keyboard | Capability::Touch); resource.capabilities(Capability::Pointer | Capability::Keyboard);
} }
fn can_view(client: Client, data: &Arc<SeatData>) -> bool { fn can_view(client: Client, data: &Arc<SeatData>) -> bool {
let Some(seat_client) = data.client.get().cloned() else {return false}; client.id() == data.client
client.id() == seat_client
} }
} }
@@ -514,9 +413,7 @@ impl Dispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
} }
wl_seat::Request::GetKeyboard { id } => { wl_seat::Request::GetKeyboard { id } => {
let keyboard = data_init.init(id, data.clone()); let keyboard = data_init.init(id, data.clone());
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE { keyboard.repeat_info(0, 0);
keyboard.repeat_info(0, 0);
}
let _ = data.keyboard.set((keyboard, Mutex::new(ObjectId::null()))); let _ = data.keyboard.set((keyboard, Mutex::new(ObjectId::null())));
} }
wl_seat::Request::GetTouch { id } => { wl_seat::Request::GetTouch { id } => {
@@ -528,9 +425,12 @@ impl Dispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
} }
} }
pub struct Cursor {
pub hotspot: Vector2<i32>,
}
impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState { impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
fn request( fn request(
_state: &mut WaylandState, state: &mut WaylandState,
_client: &Client, _client: &Client,
_resource: &WlPointer, _resource: &WlPointer,
request: wl_pointer::Request, request: wl_pointer::Request,
@@ -546,8 +446,16 @@ impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
hotspot_y, hotspot_y,
} => { } => {
if let Some(surface) = surface.as_ref() { if let Some(surface) = surface.as_ref() {
CoreSurface::add_to(dh.clone(), surface, || (), |_| ()); CoreSurface::add_to(&state.display, dh.clone(), surface, || (), |_| ());
compositor::with_states(surface, |data| { compositor::with_states(surface, |data| {
data.data_map.insert_if_missing_threadsafe(|| {
Arc::new(Mutex::new(Cursor {
hotspot: Vector2::from([hotspot_x, hotspot_y]),
}))
});
let mut cursor = data.data_map.get::<Arc<Mutex<Cursor>>>().unwrap().lock();
cursor.hotspot = Vector2::from([hotspot_x, hotspot_y]);
if let Some(core_surface) = data.data_map.get::<Arc<CoreSurface>>() { if let Some(core_surface) = data.data_map.get::<Arc<CoreSurface>>() {
core_surface.set_material_offset(1); core_surface.set_material_offset(1);
} }
@@ -558,12 +466,8 @@ impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
let focus = focus.lock(); let focus = focus.lock();
let surfaces = seat_data.surfaces.lock(); let surfaces = seat_data.surfaces.lock();
let Some(surface_info) = surfaces.get(&focus) else {return}; let Some(surface_info) = surfaces.get(&focus) else {return};
let cursor_info = surface.map(|surface| CursorInfo { let Some(panel_item) = surface_info.panel_item.upgrade() else {return};
surface: surface.downgrade(), panel_item.set_cursor(surface.as_ref(), hotspot_x, hotspot_y);
hotspot_x,
hotspot_y,
});
let _ = surface_info.cursor_sender.send_replace(cursor_info);
} }
wl_pointer::Request::Release => (), wl_pointer::Request::Release => (),
_ => unreachable!(), _ => unreachable!(),

View File

@@ -0,0 +1,16 @@
#version 320 es
precision mediump float;
precision highp int;
layout(binding = 0) uniform highp sampler2D diffuse;
layout(location = 0) in highp vec2 fs_uv;
layout(location = 0) out highp vec4 _entryPointOutput;
void main()
{
highp vec4 _101 = texture(diffuse, fs_uv);
highp vec3 _104 = pow(_101.xyz, vec3(2.2000000476837158203125));
_entryPointOutput = vec4(_104.x, _104.y, _104.z, _101.w);
}

View File

@@ -0,0 +1,13 @@
#![allow(dead_code)]
// Basic gamma correction shader
// pub const PANEL_SHADER_BYTES: &[u8] = include_bytes!("shader_unlit_gamma.sks");
// Simula shader with fancy lanzcos sampling
pub const PANEL_SHADER_BYTES: &[u8] = include_bytes!("shader_unlit_simula.sks");
// Simula text shader (fragment)
// pub const SIMULA_FRAG_STR: &str = include_str!("simula.frag");
// Simula text shader (vertex)
// pub const SIMULA_VERT_STR: &str = include_str!("simula.vert");

View File

@@ -0,0 +1,75 @@
#version 320 es
#extension GL_OES_EGL_image_external : require
precision mediump float;
precision highp int;
layout(binding = 0, std140) uniform _Global
{
highp vec4 diffuse_i;
highp vec2 uv_scale;
highp vec2 uv_offset;
highp float fcFactor;
highp float ripple;
highp float alpha_min;
highp float alpha_max;
} uniforms;
layout(binding = 0) uniform highp samplerExternalOES diffuse;
layout(location = 0) in highp vec2 fs_uv;
layout(location = 0) out highp vec4 fragColor;
void main()
{
highp vec2 dx_uv = dFdx(fs_uv);
highp vec2 dy_uv = dFdy(fs_uv);
highp vec2 width = fs_uv * uniforms.diffuse_i.xy;
ivec2 _475 = ivec2(width);
highp vec2 _477 = clamp(floor(abs(vec2(dx_uv.x, dy_uv.y)) * uniforms.diffuse_i.xy), vec2(1.0), vec2(2.0));
ivec2 _480 = ivec2(_477);
ivec2 _481 = _475 - _480;
ivec2 _485 = _475 + _480;
int _487 = _481.y;
highp vec4 _671;
highp float _672;
_672 = 0.0;
_671 = vec4(0.0);
highp vec4 _679;
highp float _681;
for (int _670 = _487; _670 <= _485.y; _672 = _681, _671 = _679, _670++)
{
int _496 = _481.x;
_681 = _672;
_679 = _671;
highp vec4 _553;
highp float _556;
for (int _673 = _496; _673 <= _485.x; _681 = _556, _679 = _553, _673++)
{
highp float _509 = float(_673);
highp float _514 = (uniforms.fcFactor * (width.x - _509)) / _477.x;
highp float _520 = float(_670);
highp float _525 = (uniforms.fcFactor * (width.y - _520)) / _477.y;
highp float _533 = sqrt((_514 * _514) + (_525 * _525));
highp float _675;
do
{
if (_533 > 1.0)
{
_675 = 0.0;
break;
}
highp float _592 = pow(uniforms.ripple * sqrt(1.0 - (_533 * _533)), 2.0);
_675 = 1.0 + (_592 * (0.25 + (_592 * (0.015625 + (_592 * (0.00043402801384218037128448486328125 + (_592 * (6.7816799855791032314300537109375e-06 + (_592 * (6.7816799287356843706220388412476e-08 + (_592 * (4.709500012189948847662890329957e-10 + (_592 * (2.4028099388645474121517509047408e-12 + (_592 * (9.3859703944590075486154034933861e-15 + (_592 * (2.8968999943407451927966655969016e-17 + (7.242260299760125752555485045131e-20 * _592)))))))))))))))))));
break;
} while(false);
_553 = _679 + (texture2D(diffuse, (vec2(_509, _520) + vec2(0.5)) / uniforms.diffuse_i.xy) * _675);
_556 = _681 + _675;
}
}
highp vec4 _568 = _671 / vec4(_672);
highp vec3 _417 = pow(_568.xyz, vec3(2.2000000476837158203125));
highp vec4 _669 = vec4(_417.x, _417.y, _417.z, _568.w);
_669.w = uniforms.alpha_min + (_568.w * (uniforms.alpha_max - uniforms.alpha_min));
fragColor = _669;
}

View File

@@ -0,0 +1,61 @@
#version 320 es
// #ifdef GL_AMD_vertex_shader_layer
// #extension GL_AMD_vertex_shader_layer : enable
// #elif defined(GL_NV_viewport_array2)
// #extension GL_NV_viewport_array2 : enable
// #else
// #define gl_Layer int _dummy_gl_layer_var
// #endif
struct Inst
{
mat4 world;
vec4 color;
};
layout(binding = 1, std140) uniform StereoKitBuffer
{
layout(row_major) mat4 sk_view[2];
layout(row_major) mat4 sk_proj[2];
layout(row_major) mat4 sk_proj_inv[2];
layout(row_major) mat4 sk_viewproj[2];
vec4 sk_lighting_sh[9];
vec4 sk_camera_pos[2];
vec4 sk_camera_dir[2];
vec4 sk_fingertip[2];
vec4 sk_cubemap_i;
float sk_time;
uint sk_view_count;
} _38;
layout(binding = 2, std140) uniform TransformBuffer
{
layout(row_major) Inst sk_inst[819];
} _56;
layout(binding = 0, std140) uniform _Global
{
vec4 diffuse_i;
vec2 uv_scale;
vec2 uv_offset;
float fcFactor;
float ripple;
float alpha_min;
float alpha_max;
} _91;
layout(location = 0) in vec4 input_pos;
layout(location = 1) in vec3 input_norm;
layout(location = 2) in vec2 input_uv;
layout(location = 0) out vec2 fs_uv;
mat4 spvWorkaroundRowMajor(mat4 wrap) { return wrap; }
void main()
{
uint _155 = uint(gl_InstanceID) % _38.sk_view_count;
gl_Position = spvWorkaroundRowMajor(_38.sk_viewproj[_155]) * vec4((spvWorkaroundRowMajor(_56.sk_inst[uint(gl_InstanceID) / _38.sk_view_count].world) * vec4(input_pos.xyz, 1.0)).xyz, 1.0);
fs_uv = (input_uv + _91.uv_offset) * _91.uv_scale;
// gl_Layer = int(_155);
}

View File

@@ -1,8 +1,12 @@
use crate::wayland::seat::SeatData; use crate::wayland::seat::SeatData;
use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use smithay::{ use smithay::{
backend::{allocator::dmabuf::Dmabuf, egl::EGLDevice, renderer::gles::GlesRenderer}, backend::{
allocator::dmabuf::Dmabuf,
egl::EGLDevice,
renderer::{gles::GlesRenderer, ImportDma},
},
delegate_dmabuf, delegate_output, delegate_shm, delegate_dmabuf, delegate_output, delegate_shm,
output::{Mode, Output, Scale, Subpixel}, output::{Mode, Output, Scale, Subpixel},
reexports::{ reexports::{
@@ -14,7 +18,7 @@ use smithay::{
wayland_server::{ wayland_server::{
backend::{ClientData, ClientId, DisconnectReason}, backend::{ClientData, ClientId, DisconnectReason},
protocol::{wl_buffer::WlBuffer, wl_data_device_manager::WlDataDeviceManager}, protocol::{wl_buffer::WlBuffer, wl_data_device_manager::WlDataDeviceManager},
DisplayHandle, Display, DisplayHandle,
}, },
}, },
utils::{Size, Transform}, utils::{Size, Transform},
@@ -33,24 +37,13 @@ use std::sync::{Arc, Weak};
use tokio::sync::mpsc::UnboundedSender; use tokio::sync::mpsc::UnboundedSender;
use tracing::{info, warn}; use tracing::{info, warn};
use super::DisplayWrapper; #[derive(Default)]
pub struct ClientState { pub struct ClientState {
pub id: OnceCell<ClientId>,
pub compositor_state: CompositorClientState, pub compositor_state: CompositorClientState,
pub display: Weak<DisplayWrapper>,
pub seat: Arc<SeatData>,
}
impl ClientState {
pub fn flush(&self) {
let Some(display) = self.display.upgrade() else {return};
let _ = display.flush_clients(self.id.get().cloned());
}
} }
impl ClientData for ClientState { impl ClientData for ClientState {
fn initialized(&self, client_id: ClientId) { fn initialized(&self, client_id: ClientId) {
info!("Wayland client {:?} connected", client_id); info!("Wayland client {:?} connected", client_id);
let _ = self.id.set(client_id);
} }
fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) { fn disconnected(&self, client_id: ClientId, reason: DisconnectReason) {
@@ -63,6 +56,7 @@ impl ClientData for ClientState {
pub struct WaylandState { pub struct WaylandState {
pub weak_ref: Weak<Mutex<WaylandState>>, pub weak_ref: Weak<Mutex<WaylandState>>,
pub display: Arc<Mutex<Display<WaylandState>>>,
pub display_handle: DisplayHandle, pub display_handle: DisplayHandle,
pub compositor_state: CompositorState, pub compositor_state: CompositorState,
@@ -72,10 +66,12 @@ pub struct WaylandState {
dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>), dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
dmabuf_tx: UnboundedSender<Dmabuf>, dmabuf_tx: UnboundedSender<Dmabuf>,
pub output: Output, pub output: Output,
pub seats: FxHashMap<ClientId, Arc<SeatData>>,
} }
impl WaylandState { impl WaylandState {
pub fn new( pub fn new(
display: Arc<Mutex<Display<WaylandState>>>,
display_handle: DisplayHandle, display_handle: DisplayHandle,
renderer: &GlesRenderer, renderer: &GlesRenderer,
dmabuf_tx: UnboundedSender<Dmabuf>, dmabuf_tx: UnboundedSender<Dmabuf>,
@@ -88,16 +84,15 @@ impl WaylandState {
let render_node = EGLDevice::device_for_display(renderer.egl_context().display()) let render_node = EGLDevice::device_for_display(renderer.egl_context().display())
.and_then(|device| device.try_get_render_node()); .and_then(|device| device.try_get_render_node());
let dmabuf_formats = renderer
.egl_context()
.dmabuf_render_formats()
.iter()
.cloned()
.collect::<Vec<_>>();
let dmabuf_default_feedback = match render_node { let dmabuf_default_feedback = match render_node {
Ok(Some(node)) => DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats.clone()) Ok(Some(node)) => {
.build() let dmabuf_formats = renderer.dmabuf_formats().collect::<Vec<_>>();
.ok(), let dmabuf_default_feedback =
DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats)
.build()
.unwrap();
Some(dmabuf_default_feedback)
}
Ok(None) => { Ok(None) => {
warn!("failed to query render node, dmabuf will use v3"); warn!("failed to query render node, dmabuf will use v3");
None None
@@ -117,9 +112,10 @@ impl WaylandState {
); );
(dmabuf_state, dmabuf_global, Some(default_feedback)) (dmabuf_state, dmabuf_global, Some(default_feedback))
} else { } else {
let dmabuf_formats = renderer.dmabuf_formats().collect::<Vec<_>>();
let mut dmabuf_state = DmabufState::new(); let mut dmabuf_state = DmabufState::new();
let dmabuf_global = let dmabuf_global =
dmabuf_state.create_global::<WaylandState>(&display_handle, dmabuf_formats.clone()); dmabuf_state.create_global::<WaylandState>(&display_handle, dmabuf_formats);
(dmabuf_state, dmabuf_global, None) (dmabuf_state, dmabuf_global, None)
}; };
@@ -134,7 +130,7 @@ impl WaylandState {
); );
let _output_global = output.create_global::<Self>(&display_handle); let _output_global = output.create_global::<Self>(&display_handle);
let mode = Mode { let mode = Mode {
size: (2048, 2048).into(), size: (4096, 4096).into(),
refresh: 60000, refresh: 60000,
}; };
output.change_current_state( output.change_current_state(
@@ -153,6 +149,7 @@ impl WaylandState {
Arc::new_cyclic(|weak| { Arc::new_cyclic(|weak| {
Mutex::new(WaylandState { Mutex::new(WaylandState {
weak_ref: weak.clone(), weak_ref: weak.clone(),
display,
display_handle, display_handle,
compositor_state, compositor_state,
@@ -162,9 +159,15 @@ impl WaylandState {
dmabuf_state, dmabuf_state,
dmabuf_tx, dmabuf_tx,
output, output,
seats: FxHashMap::default(),
}) })
}) })
} }
pub fn new_client(&mut self, client: ClientId, dh: &DisplayHandle) {
let seat_data = SeatData::new(dh, client.clone());
self.seats.insert(client, seat_data);
}
} }
impl Drop for WaylandState { impl Drop for WaylandState {
fn drop(&mut self) { fn drop(&mut self) {

View File

@@ -1,7 +1,7 @@
use super::state::WaylandState; use super::{shaders::PANEL_SHADER_BYTES, state::WaylandState};
use crate::{ use crate::{
core::{delta::Delta, destroy_queue, registry::Registry}, core::{delta::Delta, destroy_queue, registry::Registry},
nodes::drawable::{model::ModelPart, shaders::PANEL_SHADER_BYTES}, nodes::drawable::model::ModelPart,
}; };
use mint::Vector2; use mint::Vector2;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
@@ -15,13 +15,19 @@ use smithay::{
}, },
desktop::utils::send_frames_surface_tree, desktop::utils::send_frames_surface_tree,
output::Output, output::Output,
reexports::wayland_server::{self, protocol::wl_surface::WlSurface, DisplayHandle, Resource}, reexports::wayland_server::{
self, protocol::wl_surface::WlSurface, Display, DisplayHandle, Resource,
},
wayland::compositor::{self, SurfaceData}, wayland::compositor::{self, SurfaceData},
}; };
use std::{cell::RefCell, ffi::c_void, sync::Arc, time::Duration}; use std::{
ffi::c_void,
sync::{Arc, Weak},
time::Duration,
};
use stereokit::{ use stereokit::{
Material, Shader, StereoKitDraw, Tex, TextureAddress, TextureFormat, TextureSample, Material, StereoKitDraw, Tex, TextureAddress, TextureFormat, TextureSample, TextureType,
TextureType, Transparency, Transparency,
}; };
pub static CORE_SURFACES: Registry<CoreSurface> = Registry::new(); pub static CORE_SURFACES: Registry<CoreSurface> = Registry::new();
@@ -37,11 +43,12 @@ impl Drop for CoreSurfaceData {
} }
pub struct CoreSurface { pub struct CoreSurface {
display: Weak<Mutex<Display<WaylandState>>>,
pub dh: DisplayHandle, pub dh: DisplayHandle,
pub weak_surface: wayland_server::Weak<WlSurface>, pub weak_surface: wayland_server::Weak<WlSurface>,
mapped_data: Mutex<Option<CoreSurfaceData>>, mapped_data: Mutex<Option<CoreSurfaceData>>,
sk_tex: OnceCell<Tex>, sk_tex: OnceCell<SendWrapper<Tex>>,
sk_mat: OnceCell<Arc<Material>>, sk_mat: OnceCell<Arc<SendWrapper<Material>>>,
material_offset: Mutex<Delta<u32>>, material_offset: Mutex<Delta<u32>>,
on_mapped: Box<dyn Fn() + Send + Sync>, on_mapped: Box<dyn Fn() + Send + Sync>,
on_commit: Box<dyn Fn(u32) + Send + Sync>, on_commit: Box<dyn Fn(u32) + Send + Sync>,
@@ -50,6 +57,7 @@ pub struct CoreSurface {
impl CoreSurface { impl CoreSurface {
pub fn add_to( pub fn add_to(
display: &Arc<Mutex<Display<WaylandState>>>,
dh: DisplayHandle, dh: DisplayHandle,
surface: &WlSurface, surface: &WlSurface,
on_mapped: impl Fn() + Send + Sync + 'static, on_mapped: impl Fn() + Send + Sync + 'static,
@@ -58,6 +66,7 @@ impl CoreSurface {
compositor::with_states(surface, |data| { compositor::with_states(surface, |data| {
data.data_map.insert_if_missing_threadsafe(|| { data.data_map.insert_if_missing_threadsafe(|| {
CORE_SURFACES.add(CoreSurface { CORE_SURFACES.add(CoreSurface {
display: Arc::downgrade(display),
dh, dh,
weak_surface: surface.downgrade(), weak_surface: surface.downgrade(),
mapped_data: Mutex::new(None), mapped_data: Mutex::new(None),
@@ -83,21 +92,21 @@ impl CoreSurface {
} }
pub fn process(&self, sk: &impl StereoKitDraw, renderer: &mut GlesRenderer) { pub fn process(&self, sk: &impl StereoKitDraw, renderer: &mut GlesRenderer) {
let Some(wl_surface) = self.wl_surface() else {return}; let Some(wl_surface) = self.wl_surface() else { return };
let sk_tex = self let sk_tex = self.sk_tex.get_or_init(|| {
.sk_tex SendWrapper::new(sk.tex_create(TextureType::IMAGE_NO_MIPS, TextureFormat::RGBA32))
.get_or_init(|| sk.tex_create(TextureType::IMAGE_NO_MIPS, TextureFormat::RGBA32)); });
self.sk_mat.get_or_init(|| { self.sk_mat.get_or_init(|| {
let shader = sk.shader_create_mem(&PANEL_SHADER_BYTES); let shader = sk.shader_create_mem(&PANEL_SHADER_BYTES).unwrap();
// let _ = renderer.with_context(|c| unsafe { // let _ = renderer.with_context(|c| unsafe {
// shader_inject(c, &mut shader, SIMULA_VERT_STR, SIMULA_FRAG_STR) // shader_inject(c, &mut shader, SIMULA_VERT_STR, SIMULA_FRAG_STR)
// }); // });
let mat = sk.material_create(shader.as_ref().unwrap_or(Shader::UI.as_ref())); let mat = sk.material_create(&shader);
sk.material_set_texture(&mat, "diffuse", sk_tex.as_ref()); sk.material_set_texture(&mat, "diffuse", sk_tex.as_ref());
sk.material_set_transparency(&mat, Transparency::Blend); sk.material_set_transparency(&mat, Transparency::Blend);
Arc::new(mat) Arc::new(SendWrapper::new(mat))
}); });
// Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe) // Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe)
@@ -121,16 +130,18 @@ impl CoreSurface {
let mut mapped_data = self.mapped_data.lock(); let mut mapped_data = self.mapped_data.lock();
let just_mapped = mapped_data.is_none(); let just_mapped = mapped_data.is_none();
self.with_states(|data| { self.with_states(|data| {
let Some(renderer_surface_state) = data let renderer_surface_state = data
.data_map .data_map
.get::<RendererSurfaceStateUserData>() .get::<RendererSurfaceStateUserData>()
.map(RefCell::borrow) else {return}; .unwrap()
let Some(smithay_tex) = renderer_surface_state .borrow();
let smithay_tex = renderer_surface_state
.texture::<GlesRenderer>(renderer.id()) .texture::<GlesRenderer>(renderer.id())
.cloned() else {return}; .unwrap()
.clone();
let Some(sk_tex) = self.sk_tex.get() else {return}; let sk_tex = self.sk_tex.get().unwrap();
let Some(sk_mat) = self.sk_mat.get() else {return}; let sk_mat = self.sk_mat.get().unwrap();
unsafe { unsafe {
sk.tex_set_surface( sk.tex_set_surface(
sk_tex.as_ref(), sk_tex.as_ref(),
@@ -149,7 +160,7 @@ impl CoreSurface {
sk.material_set_queue_offset(sk_mat.as_ref().as_ref(), *material_offset as i32); sk.material_set_queue_offset(sk_mat.as_ref().as_ref(), *material_offset as i32);
} }
let Some(surface_size) = renderer_surface_state.surface_size() else {return}; let surface_size = renderer_surface_state.surface_size().unwrap();
let new_mapped_data = CoreSurfaceData { let new_mapped_data = CoreSurfaceData {
size: Vector2::from([surface_size.w as u32, surface_size.h as u32]), size: Vector2::from([surface_size.w as u32, surface_size.h as u32]),
wl_tex: Some(SendWrapper::new(smithay_tex)), wl_tex: Some(SendWrapper::new(smithay_tex)),
@@ -164,7 +175,7 @@ impl CoreSurface {
} }
pub fn frame(&self, sk: &impl StereoKitDraw, output: Output) { pub fn frame(&self, sk: &impl StereoKitDraw, output: Output) {
let Some(wl_surface) = self.wl_surface() else {return}; let Some(wl_surface) = self.wl_surface() else { return };
send_frames_surface_tree( send_frames_surface_tree(
&wl_surface, &wl_surface,
@@ -179,17 +190,15 @@ impl CoreSurface {
*self.material_offset.lock().value_mut() = material_offset; *self.material_offset.lock().value_mut() = material_offset;
} }
pub fn apply_material(&self, model_part: &Arc<ModelPart>) { pub fn apply_material(&self, model_node: &Arc<ModelPart>) {
self.pending_material_applications.add_raw(model_part) self.pending_material_applications.add_raw(model_node)
} }
fn apply_surface_materials(&self) { fn apply_surface_materials(&self) {
if let Some(sk_mat) = self.sk_mat.get() { for model_node in self.pending_material_applications.get_valid_contents() {
for model_node in self.pending_material_applications.get_valid_contents() { model_node.replace_material(self.sk_mat.clone().get().unwrap().clone());
model_node.replace_material(sk_mat.clone());
}
self.pending_material_applications.clear();
} }
self.pending_material_applications.clear();
} }
pub fn wl_surface(&self) -> Option<WlSurface> { pub fn wl_surface(&self) -> Option<WlSurface> {
@@ -207,6 +216,15 @@ impl CoreSurface {
pub fn size(&self) -> Option<Vector2<u32>> { pub fn size(&self) -> Option<Vector2<u32>> {
self.mapped_data.lock().as_ref().map(|d| d.size) self.mapped_data.lock().as_ref().map(|d| d.size)
} }
pub fn flush_clients(&self) {
self.display
.upgrade()
.unwrap()
.lock()
.flush_clients()
.unwrap();
}
} }
impl Drop for CoreSurface { impl Drop for CoreSurface {
fn drop(&mut self) { fn drop(&mut self) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,437 +0,0 @@
use super::{
seat::{KeyboardEvent, PointerEvent, SeatData},
state::ClientState,
};
use crate::{
nodes::{
data::KEYMAPS,
drawable::model::ModelPart,
items::panel::{Backend, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo},
},
wayland::surface::CoreSurface,
};
use color_eyre::eyre::Result;
use mint::Vector2;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use rustc_hash::FxHashMap;
use smithay::{
reexports::{
calloop::{EventLoop, LoopSignal},
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
x11rb::protocol::xproto::Window,
},
utils::{Logical, Rectangle},
wayland::compositor,
xwayland::{
xwm::{Reorder, ResizeEdge, XwmId},
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
},
};
use std::{ffi::OsStr, iter::empty, sync::Arc, time::Duration};
use tokio::sync::oneshot;
use tracing::debug;
pub static DISPLAY: OnceCell<String> = OnceCell::new();
pub struct XWaylandState {
pub display: u32,
event_loop_signal: LoopSignal,
}
impl XWaylandState {
pub fn create(dh: &DisplayHandle) -> Result<Self> {
let dh = dh.clone();
let (tx, rx) = oneshot::channel();
std::thread::spawn(move || {
let mut event_loop: EventLoop<XWaylandHandler> = EventLoop::try_new()?;
let (xwayland, connection) = XWayland::new(&dh);
let handle = event_loop.handle();
event_loop
.handle()
.insert_source(connection, {
let dh = dh.clone();
move |event, _, handler| match event {
XWaylandEvent::Ready {
connection,
client,
client_fd: _,
display: _,
} => {
handler.seat = client.get_data::<ClientState>().map(|s| s.seat.clone());
handler.wm =
X11Wm::start_wm(handle.clone(), dh.clone(), connection, client)
.ok();
}
XWaylandEvent::Exited => (),
}
})
.map_err(|e| e.error)?;
let display = xwayland.start(
event_loop.handle(),
None,
empty::<(&OsStr, &OsStr)>(),
true,
|_| (),
)?;
let _ = tx.send(XWaylandState {
display,
event_loop_signal: event_loop.get_signal(),
});
let mut handler = XWaylandHandler {
wayland_display_handle: dh,
wm: None,
seat: None,
};
event_loop.run(Duration::from_millis(100), &mut handler, |_| ())
});
let state = rx.blocking_recv()?;
let _ = DISPLAY.set(format!(":{}", state.display));
Ok(state)
}
}
impl Drop for XWaylandState {
fn drop(&mut self) {
self.event_loop_signal.stop();
}
}
struct XWaylandHandler {
wayland_display_handle: DisplayHandle,
wm: Option<X11Wm>,
seat: Option<Arc<SeatData>>,
}
impl XWaylandHandler {
fn panel_item(&self, window: &X11Surface) -> Option<Arc<PanelItem<X11Backend>>> {
compositor::with_states(&window.wl_surface()?, |s| {
s.data_map.get::<Arc<PanelItem<X11Backend>>>().cloned()
})
}
}
impl XwmHandler for XWaylandHandler {
fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm {
self.wm.as_mut().unwrap()
}
fn new_window(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "New X window");
}
fn new_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "New X override redirect window");
}
fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "X map window request");
window.set_mapped(true).unwrap();
}
fn map_window_notify(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "X map window notify");
let _ = window.set_maximized(true);
let dh = self.wayland_display_handle.clone();
let seat = self.seat.clone().unwrap();
CoreSurface::add_to(
self.wayland_display_handle.clone(),
&window.wl_surface().unwrap(),
{
let window = window.clone();
move || {
let Some(wl_surface) = window.wl_surface() else {return};
let seat = seat.clone();
window.user_data().insert_if_missing_threadsafe(|| {
let panel_item = PanelItem::create(
Box::new(X11Backend {
toplevel_parent: None,
toplevel: window.clone(),
seat,
_pointer_grab: Mutex::new(None),
_keyboard_grab: Mutex::new(None),
}),
wl_surface
.client()
.and_then(|c| c.get_credentials(&dh).ok())
.map(|c| c.pid),
);
panel_item
});
}
},
move |_| {
let Some(panel_item) = window.user_data().get::<Arc<PanelItem<X11Backend>>>() else {return};
panel_item.toplevel_size_changed(
[
window.geometry().size.w as u32,
window.geometry().size.h as u32,
]
.into(),
);
},
);
}
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "X map override redirect window");
}
fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "Unmap X window");
}
fn destroyed_window(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "Destroy X window");
}
fn configure_request(
&mut self,
_xwm: XwmId,
window: X11Surface,
x: Option<i32>,
y: Option<i32>,
w: Option<u32>,
h: Option<u32>,
reorder: Option<Reorder>,
) {
debug!(?window, x, y, w, h, ?reorder, "Configure X window");
}
fn configure_notify(
&mut self,
_xwm: XwmId,
window: X11Surface,
geometry: Rectangle<i32, Logical>,
above: Option<Window>,
) {
debug!(?window, ?geometry, above, "Configure X window");
}
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, button: u32) {
let Some(panel_item) = self.panel_item(&window) else {return};
debug!(?window, button, "X window requests move");
panel_item.toplevel_move_request();
}
fn resize_request(
&mut self,
_xwm: XwmId,
window: X11Surface,
button: u32,
resize_edge: ResizeEdge,
) {
let Some(panel_item) = self.panel_item(&window) else {return};
debug!(?window, button, ?resize_edge, "X window requests resize");
let (up, down, left, right) = match resize_edge {
ResizeEdge::Top => (true, false, false, false),
ResizeEdge::Bottom => (false, true, false, false),
ResizeEdge::Left => (false, false, true, false),
ResizeEdge::TopLeft => (true, false, true, false),
ResizeEdge::BottomLeft => (false, true, true, false),
ResizeEdge::Right => (false, false, false, true),
ResizeEdge::TopRight => (true, false, false, true),
ResizeEdge::BottomRight => (false, true, false, true),
// _ => (false, false, false, false),
};
panel_item.toplevel_resize_request(up, down, left, right)
}
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
let _ = window.set_fullscreen(true);
let Some(panel_item) = self.panel_item(&window) else {return};
panel_item.toplevel_fullscreen_active(true);
}
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
let _ = window.set_fullscreen(false);
let Some(panel_item) = self.panel_item(&window) else {return};
panel_item.toplevel_fullscreen_active(true);
}
}
pub struct X11Backend {
pub toplevel_parent: Option<X11Surface>,
pub toplevel: X11Surface,
pub seat: Arc<SeatData>,
_pointer_grab: Mutex<Option<SurfaceID>>,
_keyboard_grab: Mutex<Option<SurfaceID>>,
}
impl X11Backend {
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
match id {
SurfaceID::Cursor => None,
SurfaceID::Toplevel => self.toplevel.wl_surface(),
SurfaceID::Child(_) => None,
}
}
// fn flush_client(&self) {
// let Some(client) = self.toplevel.wl_surface().and_then(|s| s.client()) else {return};
// if let Some(client_state) = client.get_data::<ClientState>() {
// client_state.flush();
// }
// }
}
impl Backend for X11Backend {
// fn start_data(&self, id: &str) -> Result<Message> {
// let size = (
// self.toplevel.geometry().size.w as u32,
// self.toplevel.geometry().size.h as u32,
// );
// let toplevel_state = (
// None::<String>,
// self.toplevel.title(),
// None::<String>,
// (
// self.toplevel.geometry().size.w as u32,
// self.toplevel.geometry().size.h as u32,
// ),
// self.toplevel.min_size().map(|s| (s.w as u32, s.h as u32)),
// self.toplevel.max_size().map(|s| (s.w as u32, s.w as u32)),
// ((0_i32, 0_i32), size),
// vec![0_u32; 0],
// );
// let info = (
// None::<(Vector2<u32>, Vector2<i32>)>,
// toplevel_state,
// Vec::<PopupData>::new(),
// None::<SurfaceID>,
// None::<SurfaceID>,
// );
// Ok(serialize((id, info))?.into())
// }
// fn serialize_toplevel(&self) -> Result<Message> {
// let toplevel_state = (
// None::<String>,
// self.toplevel.title(),
// None::<String>,
// (
// self.toplevel.geometry().size.w,
// self.toplevel.geometry().size.h,
// ),
// self.toplevel.min_size().map(|s| (s.w, s.h)),
// self.toplevel.max_size().map(|s| (s.w, s.w)),
// );
// let data = serialize(&toplevel_state)?;
// Ok(data.into())
// }
// fn set_toplevel_capabilities(&self, _capabilities: Vec<u8>) {}
// fn set_toplevel_size(
// &self,
// size: Option<Vector2<u32>>,
// states: Vec<u32>,
// _bounds: Option<Vector2<u32>>,
// ) {
// let _ = self.toplevel.configure(
// size.map(|s| Rectangle::from_loc_and_size((0, 0), (s.x as i32, s.y as i32))),
// );
// let _ = self.toplevel.set_maximized(states.contains(&1));
// }
fn start_data(&self) -> Result<PanelItemInitData> {
Ok(PanelItemInitData {
cursor: None,
toplevel: ToplevelInfo {
parent: None,
title: Some(self.toplevel.title()),
app_id: Some(self.toplevel.instance()),
size: [
self.toplevel.geometry().size.w as u32,
self.toplevel.geometry().size.h as u32,
]
.into(),
min_size: self
.toplevel
.min_size()
.map(|s| [s.w as u32, s.h as u32].into()),
max_size: self
.toplevel
.max_size()
.map(|s| [s.w as u32, s.h as u32].into()),
logical_rectangle: Geometry {
origin: [0, 0].into(),
size: [
self.toplevel.geometry().size.w as u32,
self.toplevel.geometry().size.h as u32,
]
.into(),
},
},
children: FxHashMap::default(),
pointer_grab: self._pointer_grab.lock().clone(),
keyboard_grab: self._keyboard_grab.lock().clone(),
})
}
fn close_toplevel(&self) {}
fn auto_size_toplevel(&self) {
let _ = self.toplevel.configure(None);
}
fn set_toplevel_size(&self, size: Vector2<u32>) {
let _ = self.toplevel.configure(Some(Rectangle {
loc: self.toplevel.geometry().loc,
size: (size.x as i32, size.y as i32).into(),
}));
}
fn set_toplevel_focused_visuals(&self, focused: bool) {
let _ = self.toplevel.set_activated(focused);
}
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
let Some(wl_surface) = self.wl_surface_from_id(&surface) else {return};
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {return};
core_surface.apply_material(model_part);
}
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
let Some(surface) = self.wl_surface_from_id(surface) else {return};
self.seat
.pointer_event(&surface, PointerEvent::Motion(position));
}
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool) {
let Some(surface) = self.wl_surface_from_id(surface) else {return};
self.seat.pointer_event(
&surface,
PointerEvent::Button {
button,
state: if pressed { 1 } else { 0 },
},
)
}
fn pointer_scroll(
&self,
surface: &SurfaceID,
scroll_distance: Option<Vector2<f32>>,
scroll_steps: Option<Vector2<f32>>,
) {
let Some(surface) = self.wl_surface_from_id(surface) else {return};
self.seat.pointer_event(
&surface,
PointerEvent::Scroll {
axis_continuous: scroll_distance,
axis_discrete: scroll_steps,
},
)
}
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
let Some(surface) = self.wl_surface_from_id(surface) else {return};
let keymaps = KEYMAPS.lock();
let Some(keymap) = keymaps.get(keymap_id).cloned() else {return};
if self.seat.set_keymap(keymap, vec![surface.clone()]).is_err() {
return;
}
for key in keys {
self.seat.keyboard_event(
&surface,
KeyboardEvent::Key {
key: key.abs() as u32,
state: if key < 0 { 1 } else { 0 },
},
);
}
}
}