Compare commits
188 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cc20e054c | ||
|
|
b12b171b53 | ||
|
|
0e61d51072 | ||
|
|
e61c04960e | ||
|
|
5dc82be1a3 | ||
|
|
6861b92972 | ||
|
|
f68f350cd2 | ||
|
|
2820415373 | ||
|
|
f721a57604 | ||
|
|
fb4149eaa7 | ||
|
|
d3746ef787 | ||
|
|
9d4b4bee4d | ||
|
|
5390b0effb | ||
|
|
13da4c8d60 | ||
|
|
1740d55f9c | ||
|
|
52d5e97de6 | ||
|
|
633df045d4 | ||
|
|
415bf5bb04 | ||
|
|
4e2d4a15c9 | ||
|
|
ef0142183d | ||
|
|
e5dfd9d3df | ||
|
|
6773fe2cf3 | ||
|
|
5a6e7e02ca | ||
|
|
c5d8ec2ef1 | ||
|
|
a31781146e | ||
|
|
cb9368cb8e | ||
|
|
629c05e507 | ||
|
|
9123153bf3 | ||
|
|
f3dc632ffc | ||
|
|
c369100d8a | ||
|
|
e10d40ef5e | ||
|
|
d6ca367187 | ||
|
|
88ac8a8b86 | ||
|
|
70fef89e2d | ||
|
|
4d79a59b20 | ||
|
|
c776c1b712 | ||
|
|
d4de15e0b3 | ||
|
|
9d220ec235 | ||
|
|
09c6c010e2 | ||
|
|
c9e185e9f3 | ||
|
|
4737149c85 | ||
|
|
648451b47e | ||
|
|
a9ef2d6f4b | ||
|
|
d6ffcadd76 | ||
|
|
448b7489e8 | ||
|
|
622cf60a65 | ||
|
|
1ab11f1660 | ||
|
|
9654e6cc59 | ||
|
|
44d177858f | ||
|
|
be41f11b83 | ||
|
|
dd2bffc2b1 | ||
|
|
d2ef508607 | ||
|
|
0cc7c7bc24 | ||
|
|
8d65e304cb | ||
|
|
b0dbccbd18 | ||
|
|
a823fbfb57 | ||
|
|
4a864e6519 | ||
|
|
e23d847449 | ||
|
|
8ba199f053 | ||
|
|
23925b4475 | ||
|
|
7ea0220f33 | ||
|
|
969e4de882 | ||
|
|
e5acb3013f | ||
|
|
3d57bed1c0 | ||
|
|
45839ebf60 | ||
|
|
0bb5b53e02 | ||
|
|
4f966b6d71 | ||
|
|
2687a393b5 | ||
|
|
5c605932ef | ||
|
|
bccdc8221e | ||
|
|
bddf17bbef | ||
|
|
e8511e8759 | ||
|
|
85296f538b | ||
|
|
f8ff80b781 | ||
|
|
932fef87f5 | ||
|
|
742780e34e | ||
|
|
41ede661f7 | ||
|
|
8d85460803 | ||
|
|
ac71581db8 | ||
|
|
2f894c4058 | ||
|
|
2b97c98a6e | ||
|
|
98d9f491ba | ||
|
|
16d710e106 | ||
|
|
9ad202e778 | ||
|
|
b3747d623c | ||
|
|
d5ff9281e6 | ||
|
|
18ebd8c522 | ||
|
|
411f71c217 | ||
|
|
3027ae20a9 | ||
|
|
fbce321426 | ||
|
|
74bc3a306e | ||
|
|
a950ad59f1 | ||
|
|
cf840da444 | ||
|
|
173fba35fa | ||
|
|
97fbbec0fe | ||
|
|
400f3a23bf | ||
|
|
1ad3336b6f | ||
|
|
8e9956abe1 | ||
|
|
6ca93ea24c | ||
|
|
49810e8fd1 | ||
|
|
afd0946558 | ||
|
|
fd31d0cd99 | ||
|
|
2f380da62f | ||
|
|
1c6971cd11 | ||
|
|
da4cf084d2 | ||
|
|
ca95ed5461 | ||
|
|
1b06cb6952 | ||
|
|
df89c826bb | ||
|
|
21f7f66440 | ||
|
|
3f1bad18c8 | ||
|
|
0c190cc833 | ||
|
|
5f0df8e7c1 | ||
|
|
d715f2f9ed | ||
|
|
d7fa4e62b8 | ||
|
|
568ebb0060 | ||
|
|
42efc67625 | ||
|
|
dd4b0097a1 | ||
|
|
a483cdbc7d | ||
|
|
84a7546442 | ||
|
|
dd43f238ff | ||
|
|
4f057358c8 | ||
|
|
e20971aef7 | ||
|
|
eb0d3c5bcf | ||
|
|
a18222e3df | ||
|
|
93ca932da9 | ||
|
|
c512b2fef5 | ||
|
|
f53c684377 | ||
|
|
3552166207 | ||
|
|
0b6eb147c5 | ||
|
|
1833ed50f3 | ||
|
|
6cdbfb3bad | ||
|
|
a5e0cb19c9 | ||
|
|
519ab94312 | ||
|
|
f2a8c0ed13 | ||
|
|
b3998f315d | ||
|
|
40bcd61b98 | ||
|
|
7a4d557c61 | ||
|
|
303b3f3ca2 | ||
|
|
ac5e949614 | ||
|
|
60baabb850 | ||
|
|
248e48fd8e | ||
|
|
b9baee7e5f | ||
|
|
3598ffdbb1 | ||
|
|
c171d9e6db | ||
|
|
d7a607a663 | ||
|
|
03ccf9127d | ||
|
|
6a3024657f | ||
|
|
a0058fcc2e | ||
|
|
410cc13c4f | ||
|
|
bc259dbe01 | ||
|
|
3730e20248 | ||
|
|
1be413065d | ||
|
|
2721c20c8b | ||
|
|
80130f6ffd | ||
|
|
8da778eaba | ||
|
|
3c708d1aaf | ||
|
|
1ae1bef3c1 | ||
|
|
7fd0c1fddb | ||
|
|
fd9957b784 | ||
|
|
57da02dbad | ||
|
|
83a5b36ddc | ||
|
|
8c36d73775 | ||
|
|
8396b98f67 | ||
|
|
46d989ce7f | ||
|
|
75ac570486 | ||
|
|
242def9d06 | ||
|
|
959f32009b | ||
|
|
57796c217d | ||
|
|
cea3390e36 | ||
|
|
a756e80064 | ||
|
|
1f61d32877 | ||
|
|
da7e2c5e6e | ||
|
|
fd0940bfe9 | ||
|
|
2b4a495c07 | ||
|
|
cffb968d2e | ||
|
|
201ab3aee8 | ||
|
|
cfa3584dda | ||
|
|
f19ba93958 | ||
|
|
09a2572c3b | ||
|
|
c6316b4e8b | ||
|
|
9cd900b23f | ||
|
|
a6d30cb366 | ||
|
|
3e94a3f62a | ||
|
|
060f8264ff | ||
|
|
b7b3907647 | ||
|
|
1550555df1 | ||
|
|
c42a29a034 | ||
|
|
621bf6b82a |
46
.github/workflows/build.yml
vendored
46
.github/workflows/build.yml
vendored
@@ -1,46 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
build_and_package:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install runtime dependencies
|
||||
run: sudo apt install -y --no-install-recommends libxkbcommon-dev libstdc++6 libopenxr-dev libx11-dev libxfixes-dev libgl1-mesa-dev libegl1-mesa-dev libgbm-dev libfontconfig-dev libjsoncpp-dev libxcb1-dev libglx-dev libxcb-glx0-dev libdrm-dev libwayland-dev libfreetype-dev libpng-dev
|
||||
|
||||
- name: Install build dependencies
|
||||
run: sudo apt install -y --no-install-recommends cmake ninja-build
|
||||
|
||||
- name: Set up Rust
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Build server
|
||||
run: cargo build --release
|
||||
|
||||
|
||||
- name: Install appimagetool
|
||||
run: |
|
||||
wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$(uname -m).AppImage -O /usr/local/bin/appimagetool; \
|
||||
chmod +x /usr/local/bin/appimagetool; \
|
||||
sed -i 's|AI\x02|\x00\x00\x00|' /usr/local/bin/appimagetool
|
||||
- name: Install cargo-appimage
|
||||
run: cargo install cargo-appimage
|
||||
|
||||
- name: Generate AppImage
|
||||
run: cargo appimage
|
||||
|
||||
- name: Upload AppImage
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: appimage
|
||||
path: '*.AppImage'
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,5 +11,4 @@
|
||||
*result*
|
||||
|
||||
/libs/
|
||||
*.AppImage
|
||||
*.blend1
|
||||
*.AppImage
|
||||
940
Cargo.lock
generated
940
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "stardust-xr-server"
|
||||
version = "0.42.1"
|
||||
version = "0.42.0"
|
||||
authors = ["Nova King <technobaboo@proton.me>"]
|
||||
description = "Stardust XR reference display server"
|
||||
license = "GPLv2"
|
||||
@@ -13,10 +13,8 @@ name = "stardust-xr-server"
|
||||
path = "src/main.rs"
|
||||
|
||||
[features]
|
||||
default = ["wayland", "xwayland"]
|
||||
openxr_runtime = []
|
||||
default = ["wayland"]
|
||||
wayland = ["dep:smithay", "dep:xkbcommon"]
|
||||
xwayland = ["smithay/xwayland"]
|
||||
profile_tokio = ["dep:console-subscriber", "tokio/tracing"]
|
||||
profile_app = ["dep:tracing-chrome"]
|
||||
|
||||
@@ -53,26 +51,25 @@ tokio = { version = "1.27.0", features = ["rt-multi-thread", "signal"] }
|
||||
send_wrapper = "0.6.0"
|
||||
prisma = "0.1.1"
|
||||
xkbcommon = { version = "0.5.0", default-features = false, optional = true }
|
||||
stardust-xr = "0.13.0"
|
||||
stardust-xr = "0.11.4"
|
||||
directories = "5.0.0"
|
||||
serde = { version = "1.0.160", features = ["derive"] }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
global_counter = "0.2.2"
|
||||
rand = "0.8.5"
|
||||
atty = "0.2.14"
|
||||
|
||||
[dependencies.stereokit]
|
||||
default-features = false
|
||||
features = ["linux-egl"]
|
||||
version = "0.16.9"
|
||||
version = "0.16.7"
|
||||
|
||||
[dependencies.smithay]
|
||||
# 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/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
|
||||
# path = "../smithay"
|
||||
default-features = false
|
||||
features = ["desktop", "backend_drm", "renderer_gl", "wayland_frontend"]
|
||||
features = ["desktop", "renderer_gl", "wayland_frontend"]
|
||||
version = "*"
|
||||
optional = true
|
||||
|
||||
|
||||
52
README.md
52
README.md
@@ -15,52 +15,11 @@ This project is a usable Linux display server that reinvents human-computer inte
|
||||
```bash
|
||||
cargo build
|
||||
```
|
||||
The latest stable server is automatically built to an appimage at https://github.com/StardustXR/server/releases for easy testing.
|
||||
|
||||
## Usage
|
||||
|
||||
First, try running `cargo run` in a terminal window. If a headset is plugged in and OpenXR is working no window will show up. However, the headset should show the same things as the window that opens:
|
||||
|
||||

|
||||
|
||||
Stardust won't do anything interesting without clients! Try some from https://github.com/StardustXR.
|
||||
|
||||
### Default Sky
|
||||
|
||||
You can set a default skytex/skylight by putting your favorite HDRI equirectangular sky in `~/.config/stardust/skytex.hdr`. Certain clients can override this.
|
||||
|
||||
Flatscreen mode when the default skybox is [Zhengyang Gate](https://polyhaven.com/a/zhengyang_gate):
|
||||

|
||||
|
||||
### Windowed Mode
|
||||
|
||||
If the stardust server can't connect to an OpenXR runtime or you force it into flatscreen mode with `-f`, the server will show in a window.
|
||||

|
||||
|
||||
You can navigate around by right click + dragging to look around, Shift+W/A/S/D/Q/E to move. If you have a virtual hand, left click pinches, right click points, both make a fist.
|
||||
|
||||
### Flags
|
||||
#### Flatscreen (-f)
|
||||
|
||||
The server will show up in windowed mode no matter what with your mouse pointer being turned into a 3D pointer. Keyboard input will be sent to whatever your mouse is hovering over like visionOS simulator.
|
||||
Flatscreen mode upon initial startup:
|
||||

|
||||
|
||||
#### Overlay (-o \<PRIORITY>)
|
||||
|
||||
The server will, if in XR mode, be overlaid using the OpenXR overlay extension with the given priority.
|
||||
|
||||
#### Disable controller (--disable-controller)
|
||||
|
||||
Some runtimes such as Monado may emulate a controller using a hand, and this messes with Stardust's input system. Set this flag to ignore the controllers that the OpenXR runtime provides.
|
||||
|
||||
#### Execute (-e </path/to/executable>)
|
||||
|
||||
When wayland and OpenXR and such are initialized, run the given executable (such as a bash script) with all the environment variables needed to connect all clients of any type to the server. If not set, the server will run the executable at `~/.config/stardust/startup` if it exists. This is how stardust desktop environments can be made.
|
||||
|
||||
#### Help (-h, --help)
|
||||
|
||||
help
|
||||
## Install
|
||||
```bash
|
||||
cargo install
|
||||
```
|
||||
|
||||
## Test
|
||||
|
||||
@@ -82,4 +41,5 @@ help
|
||||
|
||||
##### Everything
|
||||
|
||||
`nix flake check` will build every test underneath of the `checks` attribute in the `flake.nix`
|
||||
`nix flake check` will build every test underneath of the `checks` attribute in the `flake.nix`
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 789 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,6 +1,4 @@
|
||||
use super::scenegraph::Scenegraph;
|
||||
#[cfg(feature = "oxr_runtime")]
|
||||
use crate::openxr;
|
||||
use crate::{
|
||||
core::{registry::OwnedRegistry, task},
|
||||
nodes::{
|
||||
@@ -110,8 +108,6 @@ impl Client {
|
||||
items::create_interface(&client)?;
|
||||
input::create_interface(&client)?;
|
||||
startup::create_interface(&client)?;
|
||||
#[cfg(feature = "openxr_runtime")]
|
||||
openxr::create_interface(&client);
|
||||
|
||||
let pid_printable = pid
|
||||
.map(|pid| pid.to_string())
|
||||
|
||||
@@ -7,4 +7,3 @@ pub mod registry;
|
||||
pub mod resource;
|
||||
pub mod scenegraph;
|
||||
pub mod task;
|
||||
pub mod typed_datamap;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::Node;
|
||||
use crate::{core::client::Client, nodes::Message};
|
||||
use color_eyre::eyre::Result;
|
||||
use once_cell::sync::OnceCell;
|
||||
use stardust_xr::scenegraph;
|
||||
use stardust_xr::scenegraph::ScenegraphError;
|
||||
use std::os::fd::OwnedFd;
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{debug, debug_span, instrument};
|
||||
|
||||
@@ -51,25 +50,12 @@ impl Scenegraph {
|
||||
}
|
||||
|
||||
impl scenegraph::Scenegraph for Scenegraph {
|
||||
fn send_signal(
|
||||
&self,
|
||||
path: &str,
|
||||
method: &str,
|
||||
data: &[u8],
|
||||
fds: Vec<OwnedFd>,
|
||||
) -> Result<(), ScenegraphError> {
|
||||
fn send_signal(&self, path: &str, method: &str, data: &[u8]) -> Result<(), ScenegraphError> {
|
||||
let Some(client) = self.get_client() else {return Err(ScenegraphError::SignalNotFound)};
|
||||
debug_span!("Handle signal", path, method).in_scope(|| {
|
||||
self.get_node(path)
|
||||
.ok_or(ScenegraphError::NodeNotFound)?
|
||||
.send_local_signal(
|
||||
client,
|
||||
method,
|
||||
Message {
|
||||
data: data.to_vec(),
|
||||
fds,
|
||||
},
|
||||
)
|
||||
.send_local_signal(client, method, data)
|
||||
})
|
||||
}
|
||||
fn execute_method(
|
||||
@@ -77,22 +63,12 @@ impl scenegraph::Scenegraph for Scenegraph {
|
||||
path: &str,
|
||||
method: &str,
|
||||
data: &[u8],
|
||||
fds: Vec<OwnedFd>,
|
||||
) -> Result<(Vec<u8>, Vec<OwnedFd>), ScenegraphError> {
|
||||
) -> Result<Vec<u8>, ScenegraphError> {
|
||||
let Some(client) = self.get_client() else {return Err(ScenegraphError::MethodNotFound)};
|
||||
debug_span!("Handle method", path, method).in_scope(|| {
|
||||
let message = self
|
||||
.get_node(path)
|
||||
self.get_node(path)
|
||||
.ok_or(ScenegraphError::NodeNotFound)?
|
||||
.execute_local_method(
|
||||
client,
|
||||
method,
|
||||
Message {
|
||||
data: data.to_vec(),
|
||||
fds,
|
||||
},
|
||||
)?;
|
||||
Ok((message.data, message.fds))
|
||||
.execute_local_method(client, method, data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
157
src/main.rs
157
src/main.rs
@@ -1,8 +1,6 @@
|
||||
mod core;
|
||||
mod nodes;
|
||||
mod objects;
|
||||
#[cfg(feature = "openxr_runtime")]
|
||||
mod openxr;
|
||||
#[cfg(feature = "wayland")]
|
||||
mod wayland;
|
||||
|
||||
@@ -12,15 +10,15 @@ use crate::objects::input::eye_pointer::EyePointer;
|
||||
use crate::objects::input::mouse_pointer::MousePointer;
|
||||
use crate::objects::input::sk_controller::SkController;
|
||||
use crate::objects::input::sk_hand::SkHand;
|
||||
use crate::objects::play_space::PlaySpace;
|
||||
|
||||
use self::core::eventloop::EventLoop;
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::Result;
|
||||
use directories::ProjectDirs;
|
||||
use once_cell::sync::OnceCell;
|
||||
use stardust_xr::server;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use stereokit::{
|
||||
@@ -29,12 +27,9 @@ use stereokit::{
|
||||
};
|
||||
use stereokit::{DisplayBlend, Sk};
|
||||
use tokio::{runtime::Handle, sync::oneshot};
|
||||
use tracing::metadata::LevelFilter;
|
||||
use tracing::{debug_span, error, info};
|
||||
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
|
||||
|
||||
pub static SK_INFO: OnceCell<SystemInfo> = OnceCell::new();
|
||||
|
||||
#[derive(Parser)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct CliArgs {
|
||||
@@ -63,7 +58,7 @@ struct EventLoopInfo {
|
||||
socket_path: PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<()> {
|
||||
let registry = tracing_subscriber::registry();
|
||||
#[cfg(feature = "profile_app")]
|
||||
let (chrome_layer, _guard) = tracing_chrome::ChromeLayerBuilder::new()
|
||||
@@ -99,15 +94,7 @@ fn main() {
|
||||
},
|
||||
blend_preference: DisplayBlend::AnyTransparent,
|
||||
depth_mode: DepthMode::D32,
|
||||
log_filter: match EnvFilter::from_default_env().max_level_hint() {
|
||||
Some(LevelFilter::ERROR) => LogLevel::Error,
|
||||
Some(LevelFilter::WARN) => LogLevel::Warning,
|
||||
Some(LevelFilter::INFO) => LogLevel::Inform,
|
||||
Some(LevelFilter::DEBUG) => LogLevel::Diagnostic,
|
||||
Some(LevelFilter::TRACE) => LogLevel::Diagnostic,
|
||||
Some(LevelFilter::OFF) => LogLevel::None,
|
||||
None => LogLevel::Warning,
|
||||
},
|
||||
log_filter: LogLevel::None,
|
||||
overlay_app: cli_args.overlay_priority.is_some(),
|
||||
overlay_priority: cli_args.overlay_priority.unwrap_or(u32::MAX),
|
||||
disable_desktop_input_window: true,
|
||||
@@ -118,11 +105,9 @@ fn main() {
|
||||
let _ = SK_MULTITHREAD.set(sk.multithreaded());
|
||||
info!("Init StereoKit");
|
||||
|
||||
SK_INFO.set(stereokit.system_info()).unwrap();
|
||||
|
||||
sk.material_set_shader(
|
||||
sk.material_find("default/material_pbr").unwrap(),
|
||||
sk.shader_find("default/shader_pbr_clip").unwrap(),
|
||||
sk.material_find("default/material_pbr")?,
|
||||
sk.shader_find("default/shader_pbr_clip")?,
|
||||
);
|
||||
|
||||
// Skytex/light stuff
|
||||
@@ -150,11 +135,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let mut mouse_pointer = cli_args
|
||||
.flatscreen
|
||||
.then(MousePointer::new)
|
||||
.transpose()
|
||||
.unwrap();
|
||||
let mouse_pointer = cli_args.flatscreen.then(MousePointer::new).transpose()?;
|
||||
let mut hands = (!cli_args.flatscreen)
|
||||
.then(|| {
|
||||
let left = SkHand::new(Handed::Left).ok();
|
||||
@@ -164,93 +145,73 @@ fn main() {
|
||||
.flatten();
|
||||
let mut controllers = (!cli_args.flatscreen && !cli_args.disable_controller)
|
||||
.then(|| {
|
||||
let left = SkController::new(&sk, Handed::Left).ok();
|
||||
let right = SkController::new(&sk, Handed::Right).ok();
|
||||
let left = SkController::new(Handed::Left).ok();
|
||||
let right = SkController::new(Handed::Right).ok();
|
||||
left.zip(right)
|
||||
})
|
||||
.flatten();
|
||||
let eye_pointer = (!cli_args.flatscreen && sk.device_has_eye_gaze())
|
||||
.then(EyePointer::new)
|
||||
.transpose()
|
||||
.unwrap();
|
||||
.transpose()?;
|
||||
|
||||
if hands.is_none() {
|
||||
sk.input_hand_visible(Handed::Left, false);
|
||||
sk.input_hand_visible(Handed::Right, false);
|
||||
}
|
||||
|
||||
let play_space = sk
|
||||
.world_has_bounds()
|
||||
.then(|| PlaySpace::new().ok())
|
||||
.flatten();
|
||||
|
||||
let (event_stop_tx, event_stop_rx) = oneshot::channel::<()>();
|
||||
let (info_sender, info_receiver) = oneshot::channel::<EventLoopInfo>();
|
||||
let event_thread = std::thread::Builder::new()
|
||||
.name("event_loop".to_owned())
|
||||
.spawn(move || event_loop(info_sender, event_stop_rx))
|
||||
.unwrap();
|
||||
let event_loop_info = info_receiver.blocking_recv().unwrap();
|
||||
.spawn(move || event_loop(info_sender, event_stop_rx))?;
|
||||
let event_loop_info = info_receiver.blocking_recv()?;
|
||||
let _tokio_handle = event_loop_info.tokio_handle.enter();
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
let mut wayland = Some(wayland::Wayland::new().expect("Could not initialize wayland"));
|
||||
let mut wayland = wayland::Wayland::new()?;
|
||||
info!("Stardust ready!");
|
||||
|
||||
let mut startup_child = if let Some(project_dirs) = project_dirs.as_ref() {
|
||||
if let Some(project_dirs) = project_dirs.as_ref() {
|
||||
let startup_script_path = cli_args
|
||||
.startup_script
|
||||
.clone()
|
||||
.and_then(|p| p.canonicalize().ok())
|
||||
.unwrap_or_else(|| project_dirs.config_dir().join("startup"));
|
||||
let mut startup_command = Command::new(startup_script_path);
|
||||
|
||||
startup_command.stdin(Stdio::null());
|
||||
startup_command.env(
|
||||
"FLAT_WAYLAND_DISPLAY",
|
||||
std::env::var_os("WAYLAND_DISPLAY").unwrap_or_default(),
|
||||
);
|
||||
startup_command.env(
|
||||
"STARDUST_INSTANCE",
|
||||
event_loop_info
|
||||
.socket_path
|
||||
.file_name()
|
||||
.expect("Stardust socket path not found"),
|
||||
);
|
||||
#[cfg(feature = "wayland")]
|
||||
{
|
||||
startup_command.env("WAYLAND_DISPLAY", &wayland.as_ref().unwrap().socket_name);
|
||||
#[cfg(feature = "xwayland")]
|
||||
startup_command.env(
|
||||
"DISPLAY",
|
||||
format!(":{}", wayland.as_ref().unwrap().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");
|
||||
}
|
||||
startup_command.spawn().ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let _startup = Command::new(startup_script_path)
|
||||
.env(
|
||||
"FLAT_WAYLAND_DISPLAY",
|
||||
std::env::var_os("WAYLAND_DISPLAY").unwrap_or_default(),
|
||||
)
|
||||
.env("WAYLAND_DISPLAY", &wayland.socket_name)
|
||||
.env(
|
||||
"STARDUST_INSTANCE",
|
||||
event_loop_info
|
||||
.socket_path
|
||||
.file_name()
|
||||
.expect("Stardust socket path not found"),
|
||||
)
|
||||
.env("GDK_BACKEND", "wayland")
|
||||
.env("QT_QPA_PLATFORM", "wayland")
|
||||
.env("MOZ_ENABLE_WAYLAND", "1")
|
||||
.env("CLUTTER_BACKEND", "wayland")
|
||||
.env("SDL_VIDEODRIVER", "wayland")
|
||||
.spawn();
|
||||
}
|
||||
|
||||
let mut last_frame_delta = Duration::ZERO;
|
||||
let mut sleep_duration = Duration::ZERO;
|
||||
debug_span!("StereoKit").in_scope(|| {
|
||||
sk.run_stateful(
|
||||
&mut wayland,
|
||||
move |wayland, _, sk| {
|
||||
sk.run(
|
||||
|sk| {
|
||||
let _span = debug_span!("StereoKit step");
|
||||
let _span = _span.enter();
|
||||
|
||||
hmd::frame(sk);
|
||||
#[cfg(feature = "wayland")]
|
||||
wayland.as_mut().unwrap().frame_event(sk);
|
||||
wayland.frame_event(sk);
|
||||
destroy_queue::clear();
|
||||
|
||||
if let Some(mouse_pointer) = &mut mouse_pointer {
|
||||
if let Some(mouse_pointer) = &mouse_pointer {
|
||||
mouse_pointer.update(sk);
|
||||
}
|
||||
if let Some((left_hand, right_hand)) = &mut hands {
|
||||
@@ -264,9 +225,6 @@ fn main() {
|
||||
if let Some(eye_pointer) = &eye_pointer {
|
||||
eye_pointer.update(sk);
|
||||
}
|
||||
if let Some(play_space) = &play_space {
|
||||
play_space.update(sk);
|
||||
}
|
||||
input::process_input();
|
||||
nodes::root::Root::send_frame_events(sk.time_elapsed_unscaled());
|
||||
adaptive_sleep(
|
||||
@@ -277,34 +235,27 @@ fn main() {
|
||||
);
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
wayland.as_mut().unwrap().update(sk);
|
||||
wayland.update(sk);
|
||||
drawable::draw(sk);
|
||||
audio::update(sk);
|
||||
#[cfg(feature = "wayland")]
|
||||
wayland.as_mut().unwrap().make_context_current();
|
||||
wayland.make_context_current();
|
||||
},
|
||||
|wayland, _sk| {
|
||||
|_| {
|
||||
info!("Cleanly shut down StereoKit");
|
||||
|
||||
if let Some(mut startup_child) = startup_child.take() {
|
||||
let _ = startup_child.kill();
|
||||
}
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
wayland.take();
|
||||
},
|
||||
)
|
||||
});
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
drop(wayland);
|
||||
|
||||
let _ = event_stop_tx.send(());
|
||||
event_thread
|
||||
.join()
|
||||
.expect("Failed to cleanly shut down event loop")
|
||||
.unwrap();
|
||||
// #[cfg(feature = "wayland")]
|
||||
// let _wayland = ManuallyDrop::new(wayland);
|
||||
|
||||
.expect("Failed to cleanly shut down event loop")?;
|
||||
info!("Cleanly shut down Stardust");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn adaptive_sleep(
|
||||
@@ -350,15 +301,11 @@ async fn event_loop(
|
||||
socket_path,
|
||||
});
|
||||
|
||||
if atty::is(atty::Stream::Stdin) {
|
||||
stop_rx.await?;
|
||||
} else {
|
||||
tokio::select! {
|
||||
biased;
|
||||
_ = tokio::signal::ctrl_c() => (),
|
||||
_ = stop_rx => (),
|
||||
};
|
||||
}
|
||||
let result = tokio::select! {
|
||||
biased;
|
||||
_ = tokio::signal::ctrl_c() => Ok(()),
|
||||
_ = stop_rx => Ok(()),
|
||||
};
|
||||
|
||||
info!("Cleanly shut down event loop");
|
||||
|
||||
@@ -366,5 +313,5 @@ async fn event_loop(
|
||||
stereokit::sys::sk_quit();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
result
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{Message, Node};
|
||||
use super::Node;
|
||||
use crate::core::client::Client;
|
||||
use crate::core::destroy_queue;
|
||||
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();
|
||||
sound.play.lock().replace(());
|
||||
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();
|
||||
sound.stop.lock().replace(());
|
||||
Ok(())
|
||||
@@ -108,7 +108,7 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||
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)]
|
||||
struct CreateSoundInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -116,7 +116,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
|
||||
transform: Transform,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, true);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::alias::AliasInfo;
|
||||
use super::fields::Field;
|
||||
use super::spatial::{parse_transform, Spatial};
|
||||
use super::{Alias, Message, Node};
|
||||
use super::{Alias, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::core::node_collections::LifeLinkedNodeMap;
|
||||
use crate::core::registry::Registry;
|
||||
@@ -24,7 +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() {
|
||||
let lesser_key = mask_map_lesser.get_mask()?.index(key)?;
|
||||
let greater_key = mask_map_greater.get_mask()?.index(key)?;
|
||||
if lesser_key.flexbuffer_type() != greater_key.flexbuffer_type() {
|
||||
if lesser_key.to_string() != greater_key.to_string() {
|
||||
return Err(flexbuffers::ReaderError::InvalidPackedType {}.into());
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,6 @@ pub fn mask_matches(mask_map_lesser: &Mask, mask_map_greater: &Mask) -> bool {
|
||||
|
||||
pub struct Mask(pub Vec<u8>);
|
||||
impl Mask {
|
||||
pub fn from_struct<T: Default + Serialize>() -> Self {
|
||||
let mut serializer = flexbuffers::FlexbufferSerializer::new();
|
||||
T::default().serialize(&mut serializer).unwrap();
|
||||
Mask(serializer.take_buffer())
|
||||
}
|
||||
pub fn get_mask(&self) -> Result<flexbuffers::MapReader<&[u8]>> {
|
||||
flexbuffers::Reader::get_root(self.0.as_slice())
|
||||
.map_err(|_| eyre!("Mask is not a valid flexbuffer"))?
|
||||
@@ -85,9 +80,9 @@ impl PulseSender {
|
||||
if !mask_matches(&self.mask, &receiver.mask) {
|
||||
return;
|
||||
}
|
||||
let Some(tx_node) = self.node.upgrade() else {return};
|
||||
let Some(tx_client) = tx_node.get_client() else {return};
|
||||
let Some(rx_node) = receiver.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(rx_node) = receiver.node.upgrade() else { return };
|
||||
// Receiver itself
|
||||
let rx_alias = Alias::create(
|
||||
&tx_client,
|
||||
@@ -142,7 +137,7 @@ impl PulseSender {
|
||||
};
|
||||
|
||||
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) {
|
||||
@@ -151,11 +146,11 @@ impl PulseSender {
|
||||
self.aliases.remove(&(uid.to_string() + "-field"));
|
||||
let Some(tx_node) = self.node.upgrade() 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<()> {
|
||||
let info: SendDataInfo = deserialize(message.as_ref())?;
|
||||
fn send_data_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
let info: SendDataInfo = deserialize(data)?;
|
||||
let receiver_node = calling_client.get_node("Pulse receiver", info.uid)?;
|
||||
let receiver =
|
||||
receiver_node.get_aspect("Pulse Receiver", "pulse receiver", |n| &n.pulse_receiver)?;
|
||||
@@ -187,7 +182,7 @@ pub struct PulseReceiver {
|
||||
pub mask: Mask,
|
||||
}
|
||||
impl PulseReceiver {
|
||||
pub fn add_to(node: &Arc<Node>, field: Arc<Field>, mask: Mask) -> Result<Arc<PulseReceiver>> {
|
||||
pub fn add_to(node: &Arc<Node>, field: Arc<Field>, mask: Mask) -> Result<()> {
|
||||
ensure!(
|
||||
node.spatial.get().is_some(),
|
||||
"Internal: Node does not have a spatial attached!"
|
||||
@@ -204,13 +199,13 @@ impl PulseReceiver {
|
||||
for sender in PULSE_SENDER_REGISTRY.get_valid_contents() {
|
||||
sender.handle_new_receiver(&receiver);
|
||||
}
|
||||
let _ = node.pulse_receiver.set(receiver.clone());
|
||||
Ok(receiver)
|
||||
let _ = node.pulse_receiver.set(receiver);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_data(&self, uid: &str, data: Vec<u8>) -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
@@ -235,7 +230,7 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||
pub fn create_pulse_sender_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreatePulseSenderInfo<'a> {
|
||||
@@ -244,7 +239,7 @@ pub fn create_pulse_sender_flex(
|
||||
transform: Transform,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
@@ -261,7 +256,7 @@ pub fn create_pulse_sender_flex(
|
||||
pub fn create_pulse_receiver_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreatePulseReceiverInfo<'a> {
|
||||
@@ -271,7 +266,7 @@ pub fn create_pulse_receiver_flex(
|
||||
field_path: &'a str,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::{
|
||||
core::{client::Client, registry::Registry},
|
||||
nodes::{
|
||||
spatial::{find_spatial_parent, parse_transform, Spatial},
|
||||
Message, Node,
|
||||
Node,
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::{bail, ensure, Result};
|
||||
@@ -97,14 +97,10 @@ impl Lines {
|
||||
draw_ctx.line_add_listv(points.make_contiguous());
|
||||
}
|
||||
|
||||
pub fn set_points_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_points_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
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 {
|
||||
p.color[0] = p.color[0].powf(2.2);
|
||||
p.color[1] = p.color[1].powf(2.2);
|
||||
@@ -113,14 +109,10 @@ impl Lines {
|
||||
lines.data.lock().points = points;
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_cyclic_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_cyclic_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -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)]
|
||||
struct CreateTextInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -147,7 +139,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
|
||||
points: Vec<LinePointRaw>,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, true);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
pub mod lines;
|
||||
pub mod model;
|
||||
pub mod shaders;
|
||||
pub mod text;
|
||||
|
||||
use self::{
|
||||
@@ -9,7 +8,7 @@ use self::{
|
||||
text::Text,
|
||||
};
|
||||
|
||||
use super::{Message, Node};
|
||||
use super::Node;
|
||||
use crate::core::client::Client;
|
||||
use color_eyre::eyre::Result;
|
||||
use parking_lot::Mutex;
|
||||
@@ -56,14 +55,14 @@ pub fn draw(sk: &impl StereoKitDraw) {
|
||||
static QUEUED_SKYLIGHT: 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)]
|
||||
struct SkyFileInfo {
|
||||
path: PathBuf,
|
||||
skytex: Option<bool>,
|
||||
skylight: Option<bool>,
|
||||
}
|
||||
let info: SkyFileInfo = deserialize(message.as_ref())?;
|
||||
let info: SkyFileInfo = deserialize(data)?;
|
||||
info.path.metadata()?;
|
||||
if info.skytex.unwrap_or_default() {
|
||||
QUEUED_SKYTEX.lock().replace(info.path.clone());
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::core::registry::Registry;
|
||||
use crate::core::resource::ResourceID;
|
||||
use crate::nodes::drawable::Drawable;
|
||||
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
|
||||
use crate::nodes::Message;
|
||||
use crate::SK_MULTITHREAD;
|
||||
use color_eyre::eyre::{bail, ensure, eyre, Result};
|
||||
use glam::Mat4;
|
||||
@@ -214,11 +213,11 @@ impl ModelPart {
|
||||
fn set_material_parameter_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
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
|
||||
.pending_material_parameters
|
||||
@@ -343,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)]
|
||||
struct CreateModelInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -351,7 +350,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
|
||||
transform: Transform,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, true);
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use smithay::backend::renderer::gles::{
|
||||
ffi::{self, Gles2, FRAGMENT_SHADER, VERTEX_SHADER},
|
||||
GlesError,
|
||||
};
|
||||
use std::mem::transmute;
|
||||
use stereokit::Shader;
|
||||
use tracing::error;
|
||||
|
||||
struct FfiAssetHeader {
|
||||
asset_type: i32,
|
||||
asset_state: i32,
|
||||
id: u64,
|
||||
index: u64,
|
||||
refs: i32,
|
||||
debug: *mut u8,
|
||||
}
|
||||
|
||||
struct FfiSkgShader {
|
||||
meta: *mut u8,
|
||||
vertex: u32,
|
||||
pixel: u32,
|
||||
program: u32,
|
||||
compute: u32,
|
||||
}
|
||||
|
||||
struct FfiShader {
|
||||
header: FfiAssetHeader,
|
||||
shader: FfiSkgShader,
|
||||
}
|
||||
|
||||
unsafe fn compile_shader(
|
||||
gl: &ffi::Gles2,
|
||||
variant: ffi::types::GLuint,
|
||||
src: &str,
|
||||
) -> Result<ffi::types::GLuint, GlesError> {
|
||||
let shader = gl.CreateShader(variant);
|
||||
if shader == 0 {
|
||||
return Err(GlesError::CreateShaderObject);
|
||||
}
|
||||
|
||||
gl.ShaderSource(
|
||||
shader,
|
||||
1,
|
||||
&src.as_ptr() as *const *const u8 as *const *const ffi::types::GLchar,
|
||||
&(src.len() as i32) as *const _,
|
||||
);
|
||||
gl.CompileShader(shader);
|
||||
|
||||
let mut status = ffi::FALSE as i32;
|
||||
gl.GetShaderiv(shader, ffi::COMPILE_STATUS, &mut status as *mut _);
|
||||
if status == ffi::FALSE as i32 {
|
||||
let mut max_len = 0;
|
||||
gl.GetShaderiv(shader, ffi::INFO_LOG_LENGTH, &mut max_len as *mut _);
|
||||
|
||||
let mut error = Vec::with_capacity(max_len as usize);
|
||||
let mut len = 0;
|
||||
gl.GetShaderInfoLog(
|
||||
shader,
|
||||
max_len as _,
|
||||
&mut len as *mut _,
|
||||
error.as_mut_ptr() as *mut _,
|
||||
);
|
||||
error.set_len(len as usize);
|
||||
|
||||
error!(
|
||||
"[GL] {}",
|
||||
std::str::from_utf8(&error).unwrap_or("<Error Message no utf8>")
|
||||
);
|
||||
|
||||
gl.DeleteShader(shader);
|
||||
return Err(GlesError::ShaderCompileError);
|
||||
}
|
||||
|
||||
Ok(shader)
|
||||
}
|
||||
|
||||
unsafe fn link_program(
|
||||
gl: &ffi::Gles2,
|
||||
vert: ffi::types::GLuint,
|
||||
frag: ffi::types::GLuint,
|
||||
) -> Result<ffi::types::GLuint, GlesError> {
|
||||
let program = gl.CreateProgram();
|
||||
gl.AttachShader(program, vert);
|
||||
gl.AttachShader(program, frag);
|
||||
gl.LinkProgram(program);
|
||||
// gl.DetachShader(program, vert);
|
||||
// gl.DetachShader(program, frag);
|
||||
// gl.DeleteShader(vert);
|
||||
// gl.DeleteShader(frag);
|
||||
|
||||
let mut status = ffi::FALSE as i32;
|
||||
gl.GetProgramiv(program, ffi::LINK_STATUS, &mut status as *mut _);
|
||||
if status == ffi::FALSE as i32 {
|
||||
let mut max_len = 0;
|
||||
gl.GetProgramiv(program, ffi::INFO_LOG_LENGTH, &mut max_len as *mut _);
|
||||
|
||||
let mut error = Vec::with_capacity(max_len as usize);
|
||||
let mut len = 0;
|
||||
gl.GetProgramInfoLog(
|
||||
program,
|
||||
max_len as _,
|
||||
&mut len as *mut _,
|
||||
error.as_mut_ptr() as *mut _,
|
||||
);
|
||||
error.set_len(len as usize);
|
||||
|
||||
error!(
|
||||
"[GL] {}",
|
||||
std::str::from_utf8(&error).unwrap_or("<Error Message no utf8>")
|
||||
);
|
||||
|
||||
gl.DeleteProgram(program);
|
||||
return Err(GlesError::ProgramLinkError);
|
||||
}
|
||||
|
||||
Ok(program)
|
||||
}
|
||||
|
||||
pub unsafe fn shader_inject(
|
||||
c: &Gles2,
|
||||
sk_shader: &mut Shader,
|
||||
vert_str: &str,
|
||||
frag_str: &str,
|
||||
) -> Result<(), GlesError> {
|
||||
let gl_vert = compile_shader(c, VERTEX_SHADER, vert_str)?;
|
||||
let gl_frag = compile_shader(c, FRAGMENT_SHADER, frag_str)?;
|
||||
let gl_prog = link_program(c, gl_vert, gl_frag)?;
|
||||
|
||||
let shader: *mut FfiShader = transmute(sk_shader.0.as_mut());
|
||||
if let Some(shader) = shader.as_mut() {
|
||||
shader.shader.vertex = gl_vert;
|
||||
shader.shader.pixel = gl_frag;
|
||||
shader.shader.program = gl_prog;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3,7 +3,7 @@ use crate::{
|
||||
nodes::{
|
||||
drawable::Drawable,
|
||||
spatial::{find_spatial_parent, parse_transform, Spatial},
|
||||
Message, Node,
|
||||
Node,
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::{bail, ensure, eyre, Result};
|
||||
@@ -151,22 +151,18 @@ impl Text {
|
||||
pub fn set_character_height_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
|
||||
pub fn set_text_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_text_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -187,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)]
|
||||
struct CreateTextInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -202,7 +198,7 @@ pub fn create_flex(_node: &Node, calling_client: Arc<Client>, message: Message)
|
||||
bounds_align: TextAlign,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, true);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::{Field, FieldTrait, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
|
||||
use crate::nodes::Message;
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use glam::{vec3, vec3a, Vec3, Vec3A};
|
||||
use mint::Vector3;
|
||||
@@ -17,7 +16,7 @@ pub struct BoxField {
|
||||
}
|
||||
|
||||
impl BoxField {
|
||||
pub fn add_to(node: &Arc<Node>, size: Vector3<f32>) -> Result<Arc<Field>> {
|
||||
pub fn add_to(node: &Arc<Node>, size: Vector3<f32>) -> Result<()> {
|
||||
ensure!(
|
||||
node.spatial.get().is_some(),
|
||||
"Internal: Node does not have a spatial attached!"
|
||||
@@ -32,22 +31,17 @@ impl BoxField {
|
||||
};
|
||||
box_field.add_field_methods(node);
|
||||
node.add_local_signal("set_size", BoxField::set_size_flex);
|
||||
let field = Arc::new(Field::Box(box_field));
|
||||
let _ = node.field.set(field.clone());
|
||||
Ok(field)
|
||||
let _ = node.field.set(Arc::new(Field::Box(box_field)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_size(&self, size: Vector3<f32>) {
|
||||
*self.size.lock() = size.into();
|
||||
}
|
||||
|
||||
pub fn set_size_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_size_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
@@ -69,11 +63,7 @@ impl FieldTrait for BoxField {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_box_field_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn create_box_field_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateFieldInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -81,7 +71,7 @@ pub fn create_box_field_flex(
|
||||
transform: Transform,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::{Field, FieldTrait, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
|
||||
use crate::nodes::Message;
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use glam::{swizzles::*, vec2, Vec3A};
|
||||
use portable_atomic::AtomicF32;
|
||||
@@ -44,13 +43,9 @@ impl CylinderField {
|
||||
self.radius.store(radius.abs(), Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn set_size_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_size_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
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);
|
||||
Ok(())
|
||||
}
|
||||
@@ -72,7 +67,7 @@ impl FieldTrait for CylinderField {
|
||||
pub fn create_cylinder_field_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateFieldInfo<'a> {
|
||||
@@ -82,7 +77,7 @@ pub fn create_cylinder_field_flex(
|
||||
length: 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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pub mod r#box;
|
||||
mod r#box;
|
||||
mod cylinder;
|
||||
mod sphere;
|
||||
mod torus;
|
||||
pub mod torus;
|
||||
|
||||
use self::cylinder::{create_cylinder_field_flex, CylinderField};
|
||||
use self::r#box::{create_box_field_flex, BoxField};
|
||||
@@ -10,7 +10,7 @@ use self::torus::{create_torus_field_flex, TorusField};
|
||||
|
||||
use super::alias::AliasInfo;
|
||||
use super::spatial::Spatial;
|
||||
use super::{Message, Node};
|
||||
use super::Node;
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::spatial::find_reference_space;
|
||||
use color_eyre::eyre::Result;
|
||||
@@ -133,17 +133,13 @@ const MAX_RAY_MARCH: f32 = f32::MAX;
|
||||
// const MIN_RAY_LENGTH: f32 = 0_f32;
|
||||
const MAX_RAY_LENGTH: f32 = 1000_f32;
|
||||
|
||||
fn field_distance_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
fn field_distance_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<Vec<u8>> {
|
||||
#[derive(Deserialize)]
|
||||
struct FieldInfoArgs<'a> {
|
||||
reference_space_path: &'a str,
|
||||
point: Vector3<f32>,
|
||||
}
|
||||
let args: FieldInfoArgs = deserialize(message.as_ref())?;
|
||||
let args: FieldInfoArgs = deserialize(data)?;
|
||||
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
|
||||
|
||||
let distance = node
|
||||
@@ -151,20 +147,16 @@ fn field_distance_flex(
|
||||
.get()
|
||||
.unwrap()
|
||||
.distance(reference_space.as_ref(), args.point.into());
|
||||
Ok(serialize(distance)?.into())
|
||||
Ok(serialize(distance)?)
|
||||
}
|
||||
fn field_normal_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
fn field_normal_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<Vec<u8>> {
|
||||
#[derive(Deserialize)]
|
||||
struct FieldInfoArgs<'a> {
|
||||
reference_space_path: &'a str,
|
||||
point: Vector3<f32>,
|
||||
radius: Option<f32>,
|
||||
}
|
||||
let args: FieldInfoArgs = deserialize(message.as_ref())?;
|
||||
let args: FieldInfoArgs = deserialize(data)?;
|
||||
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
|
||||
|
||||
let normal = node.field.get().as_ref().unwrap().normal(
|
||||
@@ -172,20 +164,20 @@ fn field_normal_flex(
|
||||
args.point.into(),
|
||||
args.radius.unwrap_or(0.001),
|
||||
);
|
||||
Ok(serialize(mint::Vector3::from(normal))?.into())
|
||||
Ok(serialize(mint::Vector3::from(normal))?)
|
||||
}
|
||||
fn field_closest_point_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
#[derive(Deserialize)]
|
||||
struct FieldInfoArgs<'a> {
|
||||
reference_space_path: &'a str,
|
||||
point: Vector3<f32>,
|
||||
radius: Option<f32>,
|
||||
}
|
||||
let args: FieldInfoArgs = deserialize(message.as_ref())?;
|
||||
let args: FieldInfoArgs = deserialize(data)?;
|
||||
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
|
||||
|
||||
let closest_point = node.field.get().as_ref().unwrap().closest_point(
|
||||
@@ -193,20 +185,16 @@ fn field_closest_point_flex(
|
||||
args.point.into(),
|
||||
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(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
fn field_ray_march_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<Vec<u8>> {
|
||||
#[derive(Deserialize)]
|
||||
struct FieldInfoArgs<'a> {
|
||||
reference_space_path: &'a str,
|
||||
ray_origin: Vector3<f32>,
|
||||
ray_direction: Vector3<f32>,
|
||||
}
|
||||
let args: FieldInfoArgs = deserialize(message.as_ref())?;
|
||||
let args: FieldInfoArgs = deserialize(data)?;
|
||||
let reference_space = find_reference_space(&calling_client, args.reference_space_path)?;
|
||||
|
||||
let ray_march_result = node.field.get().unwrap().ray_march(Ray {
|
||||
@@ -214,7 +202,7 @@ fn field_ray_march_flex(
|
||||
direction: args.ray_direction.into(),
|
||||
space: reference_space,
|
||||
});
|
||||
Ok(serialize(ray_march_result)?.into())
|
||||
Ok(serialize(ray_march_result)?)
|
||||
}
|
||||
|
||||
pub enum Field {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::{Field, FieldTrait, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::spatial::{find_spatial_parent, Spatial};
|
||||
use crate::nodes::Message;
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use glam::{Mat4, Vec3A};
|
||||
use mint::Vector3;
|
||||
@@ -40,13 +39,9 @@ impl SphereField {
|
||||
self.radius.store(radius, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn set_radius_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_radius_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
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(())
|
||||
}
|
||||
}
|
||||
@@ -69,7 +64,7 @@ impl FieldTrait for SphereField {
|
||||
pub fn create_sphere_field_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateFieldInfo<'a> {
|
||||
@@ -78,7 +73,7 @@ pub fn create_sphere_field_flex(
|
||||
origin: Option<Vector3<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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = Mat4::from_translation(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::{Field, FieldTrait, Node};
|
||||
use crate::core::client::Client;
|
||||
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
|
||||
use crate::nodes::Message;
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use glam::{swizzles::*, vec2, Vec3A};
|
||||
use portable_atomic::AtomicF32;
|
||||
@@ -44,13 +43,9 @@ impl TorusField {
|
||||
self.radius_b.store(radius_b.abs(), Ordering::Relaxed);
|
||||
}
|
||||
|
||||
pub fn set_size_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_size_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
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);
|
||||
|
||||
Ok(())
|
||||
@@ -72,7 +67,7 @@ impl FieldTrait for TorusField {
|
||||
pub fn create_torus_field_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateFieldInfo<'a> {
|
||||
@@ -82,7 +77,7 @@ pub fn create_torus_field_flex(
|
||||
radius_a: 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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
@@ -10,7 +10,7 @@ use super::{
|
||||
alias::{Alias, AliasInfo},
|
||||
fields::{find_field, Field, FIELD_ALIAS_INFO},
|
||||
spatial::{find_spatial_parent, parse_transform, Spatial},
|
||||
Message, Node,
|
||||
Node,
|
||||
};
|
||||
use crate::core::{client::Client, node_collections::LifeLinkedNodeMap};
|
||||
use crate::core::{node_collections::LifeLinkedNodeList, registry::Registry};
|
||||
@@ -109,21 +109,21 @@ impl InputMethod {
|
||||
.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 handler = InputHandler::find(&calling_client, deserialize(message.as_ref())?)?;
|
||||
let handler = InputHandler::find(&calling_client, deserialize(data)?)?;
|
||||
|
||||
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)?;
|
||||
method.datamap.lock().replace(Datamap::new(message.data)?);
|
||||
method.datamap.lock().replace(Datamap::new(data.to_vec())?);
|
||||
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 handler_paths: Vec<&str> = deserialize(message.as_ref())?;
|
||||
let handler_paths: Vec<&str> = deserialize(data)?;
|
||||
let handlers: Vec<Weak<InputHandler>> = handler_paths
|
||||
.into_iter()
|
||||
.filter_map(|p| InputHandler::find(&calling_client, p).ok())
|
||||
@@ -147,9 +147,9 @@ impl InputMethod {
|
||||
}
|
||||
|
||||
fn handle_new_handler(&self, handler: &InputHandler) {
|
||||
let Some(method_node) = self.node.upgrade() else {return};
|
||||
let Some(method_client) = method_node.get_client() else {return};
|
||||
let Some(handler_node) = handler.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(handler_node) = handler.node.upgrade() else { return };
|
||||
// Receiver itself
|
||||
let Ok(handler_alias) = Alias::create(
|
||||
&method_client,
|
||||
@@ -178,7 +178,7 @@ impl InputMethod {
|
||||
}
|
||||
|
||||
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) {
|
||||
let uid = handler.uid.as_str();
|
||||
@@ -186,7 +186,7 @@ impl InputMethod {
|
||||
self.handler_aliases.remove(&(uid.to_string() + "-field"));
|
||||
let Some(tx_node) = self.node.upgrade() 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 {
|
||||
@@ -284,7 +284,7 @@ impl InputHandler {
|
||||
#[instrument(level = "debug", skip(self, distance_link))]
|
||||
fn send_input(&self, order: u32, distance_link: &DistanceLink, datamap: Datamap) {
|
||||
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 {
|
||||
@@ -312,7 +312,7 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||
pub fn create_input_handler_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateInputHandlerInfo<'a> {
|
||||
@@ -321,7 +321,7 @@ pub fn create_input_handler_flex(
|
||||
transform: Transform,
|
||||
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 transform = parse_transform(info.transform, true, true, true);
|
||||
let field = find_field(&calling_client, info.field_path)?;
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::core::client::Client;
|
||||
use crate::nodes::fields::{Field, Ray, RayMarchResult};
|
||||
use crate::nodes::input::{InputMethod, InputType};
|
||||
use crate::nodes::spatial::{find_spatial_parent, parse_transform, Spatial};
|
||||
use crate::nodes::{Message, Node};
|
||||
use crate::nodes::Node;
|
||||
use glam::{vec3, Mat4};
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flat::{Datamap, InputDataType, Pointer as FlatPointer};
|
||||
@@ -63,7 +63,7 @@ impl InputSpecialization for Pointer {
|
||||
pub fn create_pointer_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreatePointerInfo<'a> {
|
||||
@@ -72,7 +72,7 @@ pub fn create_pointer_flex(
|
||||
transform: Transform,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::core::client::Client;
|
||||
use crate::nodes::fields::Field;
|
||||
use crate::nodes::input::{InputMethod, InputType};
|
||||
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 glam::{vec3a, Mat4};
|
||||
use serde::Deserialize;
|
||||
@@ -17,9 +17,9 @@ pub struct Tip {
|
||||
pub radius: f32,
|
||||
}
|
||||
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() {
|
||||
tip.radius = deserialize(message.as_ref())?;
|
||||
tip.radius = deserialize(data)?;
|
||||
}
|
||||
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)]
|
||||
struct CreateTipInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -54,7 +54,7 @@ pub fn create_tip_flex(_node: &Node, calling_client: Arc<Client>, message: Messa
|
||||
radius: f32,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::{Item, ItemType};
|
||||
use super::{Item, ItemSpecialization, ItemType};
|
||||
use crate::{
|
||||
core::{
|
||||
client::{Client, INTERNAL_CLIENT},
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
nodes::{
|
||||
items::TypeInfo,
|
||||
spatial::{find_spatial_parent, parse_transform, Spatial},
|
||||
Message, Node,
|
||||
Node,
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
@@ -15,7 +15,7 @@ use lazy_static::lazy_static;
|
||||
use nanoid::nanoid;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::{
|
||||
schemas::flex::{deserialize, serialize},
|
||||
schemas::flex::{deserialize, flexbuffers, serialize},
|
||||
values::Transform,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
@@ -46,26 +46,23 @@ impl EnvironmentItem {
|
||||
node.add_local_method("get_path", EnvironmentItem::get_path_flex);
|
||||
}
|
||||
|
||||
fn get_path_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
) -> Result<Message> {
|
||||
fn get_path_flex(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<Vec<u8>> {
|
||||
let ItemType::Environment(environment_item) = &node.item.get().unwrap().specialization else {
|
||||
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> {
|
||||
Ok(serialize((id, self.path.as_str()))?.into())
|
||||
}
|
||||
impl ItemSpecialization for EnvironmentItem {
|
||||
fn serialize_start_data(&self, id: &str) -> Vec<u8> {
|
||||
serialize((id, self.path.as_str())).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn create_environment_item_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateEnvironmentItemInfo<'a> {
|
||||
@@ -74,7 +71,7 @@ pub(super) fn create_environment_item_flex(
|
||||
transform: Transform,
|
||||
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 space = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, false);
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
mod environment;
|
||||
pub mod panel;
|
||||
|
||||
use self::environment::{EnvironmentItem, ITEM_TYPE_INFO_ENVIRONMENT};
|
||||
use self::panel::{PanelItemTrait, ITEM_TYPE_INFO_PANEL};
|
||||
use super::fields::Field;
|
||||
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::node_collections::LifeLinkedNodeMap;
|
||||
use crate::core::registry::Registry;
|
||||
use crate::nodes::alias::AliasInfo;
|
||||
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 lazy_static::lazy_static;
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use portable_atomic::Ordering;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use stardust_xr::schemas::flex::{deserialize, flexbuffers, serialize};
|
||||
use stardust_xr::values::Transform;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
lazy_static! {
|
||||
@@ -153,7 +154,7 @@ impl Item {
|
||||
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)?;
|
||||
release(item, None);
|
||||
|
||||
@@ -170,28 +171,26 @@ impl Drop for Item {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ItemSpecialization {
|
||||
fn serialize_start_data(&self, id: &str) -> Vec<u8>;
|
||||
}
|
||||
|
||||
pub enum ItemType {
|
||||
Environment(EnvironmentItem),
|
||||
Panel(Arc<dyn PanelItemTrait>),
|
||||
#[cfg(feature = "wayland")]
|
||||
Panel(Arc<PanelItem>),
|
||||
}
|
||||
impl ItemType {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||
impl Deref for ItemType {
|
||||
type Target = dyn ItemSpecialization;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
ItemType::Environment(e) => e.serialize_start_data(id),
|
||||
ItemType::Panel(p) => p.serialize_start_data(id),
|
||||
ItemType::Environment(item) => item,
|
||||
#[cfg(feature = "wayland")]
|
||||
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 {
|
||||
node: Weak<Node>,
|
||||
@@ -226,44 +225,49 @@ impl ItemUI {
|
||||
Ok(())
|
||||
}
|
||||
fn send_state(&self, state: &str, name: &str) {
|
||||
let Ok(serialized_data) = serialize(name) else {return};
|
||||
let _ = self
|
||||
.node
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.send_remote_signal(state, serialized_data);
|
||||
.send_remote_signal(state, flexbuffers::singleton(name).as_slice());
|
||||
}
|
||||
|
||||
fn handle_create_item(&self, item: &Item) {
|
||||
let Some(node) = self.node.upgrade() else {return};
|
||||
let Some(client) = node.get_client() else {return};
|
||||
let Some(node) = self.node.upgrade() 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")) {
|
||||
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("create_item", serialized_data);
|
||||
let _ = node.send_remote_signal(
|
||||
"create_item",
|
||||
&item.specialization.serialize_start_data(&item.uid),
|
||||
);
|
||||
}
|
||||
fn handle_destroy_item(&self, item: &Item) {
|
||||
self.item_aliases.remove(&item.uid);
|
||||
self.send_state("destroy_item", item.uid.as_str());
|
||||
}
|
||||
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("capture_item", message);
|
||||
let _ = node.send_remote_signal(
|
||||
"capture_item",
|
||||
&serialize((item.uid.as_str(), acceptor.uid.as_str())).unwrap(),
|
||||
);
|
||||
}
|
||||
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("release_item", message);
|
||||
let _ = node.send_remote_signal(
|
||||
"release_item",
|
||||
&serialize((item.uid.as_str(), acceptor.uid.as_str())).unwrap(),
|
||||
);
|
||||
}
|
||||
fn handle_create_acceptor(&self, acceptor: &ItemAcceptor) {
|
||||
let Some(node) = self.node.upgrade() else {return};
|
||||
let Some(client) = node.get_client() else {return};
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
let Some(client) = node.get_client() else { return };
|
||||
|
||||
let Ok((alias, field_alias)) = acceptor.make_aliases(
|
||||
&client,
|
||||
@@ -272,8 +276,7 @@ impl ItemUI {
|
||||
self.acceptor_aliases.add(acceptor.uid.clone(), &alias);
|
||||
self.acceptor_field_aliases
|
||||
.add(acceptor.uid.clone(), &field_alias);
|
||||
let Ok(message) = serialize(&acceptor.uid) else {return};
|
||||
let _ = node.send_remote_signal("create_acceptor", message);
|
||||
let _ = node.send_remote_signal("create_acceptor", &serialize(&acceptor.uid).unwrap());
|
||||
}
|
||||
fn handle_destroy_acceptor(&self, acceptor: &ItemAcceptor) {
|
||||
self.send_state("destroy_acceptor", acceptor.uid.as_str());
|
||||
@@ -312,13 +315,13 @@ impl ItemAcceptor {
|
||||
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) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
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 = item_node.get_aspect("Item", "item", |n| &n.item)?;
|
||||
capture(item, acceptor);
|
||||
@@ -350,24 +353,24 @@ impl ItemAcceptor {
|
||||
Ok((acceptor_alias, acceptor_field_alias))
|
||||
}
|
||||
fn handle_capture(&self, item: &Arc<Item>) {
|
||||
let Some(node) = self.node.upgrade() else {return};
|
||||
let Some(client) = node.get_client() else {return};
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
let Some(client) = node.get_client() else { return };
|
||||
|
||||
self.accepted_registry.add_raw(item);
|
||||
if let Ok(alias_node) = item.make_alias(&client, &node.path) {
|
||||
self.accepted_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("capture", serialized_data);
|
||||
let _ = node.send_remote_signal(
|
||||
"capture",
|
||||
&item.specialization.serialize_start_data(&item.uid),
|
||||
);
|
||||
}
|
||||
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_aliases.remove(&item.uid);
|
||||
let Ok(message) = serialize(&item.uid) else {return};
|
||||
let _ = node.send_remote_signal("release", message);
|
||||
let _ = node.send_remote_signal("release", &serialize(&item.uid).unwrap());
|
||||
}
|
||||
}
|
||||
impl Drop for ItemAcceptor {
|
||||
@@ -402,16 +405,12 @@ fn type_info(name: &str) -> Result<&'static TypeInfo> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_item_ui_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn register_item_ui_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct RegisterItemUIInfo<'a> {
|
||||
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 ui =
|
||||
Node::create(&calling_client, "/item", type_info.type_name, true).add_to_scenegraph()?;
|
||||
@@ -419,11 +418,7 @@ pub fn register_item_ui_flex(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_item_acceptor_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
fn create_item_acceptor_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateItemAcceptorInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -432,7 +427,7 @@ fn create_item_acceptor_flex(
|
||||
field_path: &'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 transform = parse_transform(info.transform, true, true, false);
|
||||
let field = find_field(&calling_client, info.field_path)?;
|
||||
|
||||
@@ -1,507 +0,0 @@
|
||||
use crate::{
|
||||
core::{
|
||||
client::{get_env, startup_settings, Client, INTERNAL_CLIENT},
|
||||
registry::Registry,
|
||||
},
|
||||
nodes::{
|
||||
drawable::{model::ModelPart, Drawable},
|
||||
items::{self, 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 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",
|
||||
"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 trait Backend: Send + Sync + 'static {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message>;
|
||||
fn serialize_toplevel(&self) -> Result<Message>;
|
||||
fn set_toplevel_capabilities(&self, capabilities: Vec<u8>);
|
||||
fn configure_toplevel(
|
||||
&self,
|
||||
size: Option<Vector2<u32>>,
|
||||
states: Vec<u32>,
|
||||
bounds: Option<Vector2<u32>>,
|
||||
);
|
||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>);
|
||||
|
||||
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_set_keymap(&self, keymap: &str) -> Result<()>;
|
||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool);
|
||||
}
|
||||
|
||||
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 node(&self) -> Option<Arc<Node>>;
|
||||
}
|
||||
|
||||
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<Node>, Arc<PanelItem<B>>) {
|
||||
debug!(?pid, "Create panel item");
|
||||
|
||||
let startup_settings = pid
|
||||
.and_then(|pid| get_env(pid).ok())
|
||||
.and_then(|env| startup_settings(&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(
|
||||
spatial.global_transform().inverse() * startup_settings.transform,
|
||||
);
|
||||
}
|
||||
|
||||
let panel_item = Arc::new(PanelItem {
|
||||
uid: uid.clone(),
|
||||
node: Arc::downgrade(&node),
|
||||
backend,
|
||||
});
|
||||
|
||||
let generic_panel_item: Arc<dyn PanelItemTrait> = panel_item.clone();
|
||||
let item = Item::add_to(
|
||||
&node,
|
||||
uid,
|
||||
&ITEM_TYPE_INFO_PANEL,
|
||||
ItemType::Panel(generic_panel_item),
|
||||
);
|
||||
|
||||
// panel_item
|
||||
// .seat_data
|
||||
// .new_surface(&wl_surface, Arc::downgrade(&panel_item));
|
||||
|
||||
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", Self::apply_surface_material_flex);
|
||||
node.add_local_signal("configure_toplevel", Self::configure_toplevel_flex);
|
||||
node.add_local_signal(
|
||||
"set_toplevel_capabilities",
|
||||
Self::set_toplevel_capabilities_flex,
|
||||
);
|
||||
node.add_local_signal("pointer_scroll", Self::pointer_scroll_flex);
|
||||
node.add_local_signal("pointer_button", Self::pointer_button_flex);
|
||||
node.add_local_signal("pointer_motion", Self::pointer_motion_flex);
|
||||
|
||||
node.add_local_signal(
|
||||
"keyboard_set_keymap_string",
|
||||
Self::keyboard_set_keymap_string_flex,
|
||||
);
|
||||
// node.add_local_signal(
|
||||
// "keyboard_set_keymap_names",
|
||||
// Self::keyboard_set_keymap_names_flex,
|
||||
// );
|
||||
node.add_local_signal("keyboard_key", Self::keyboard_key_flex);
|
||||
|
||||
(node, panel_item)
|
||||
}
|
||||
|
||||
pub fn node(&self) -> Option<Arc<Node>> {
|
||||
self.node.upgrade()
|
||||
}
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
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_set_keymap_string_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
let keymap_string: &str = deserialize(message.as_ref())?;
|
||||
|
||||
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
||||
debug!("Keyboard set keymap");
|
||||
panel_item.keyboard_set_keymap(keymap_string)
|
||||
|
||||
// PanelItem::keyboard_set_keymap_flex(node, &keymap)
|
||||
}
|
||||
// fn keyboard_set_keymap_names_flex(
|
||||
// node: &Node,
|
||||
// _calling_client: Arc<Client>,
|
||||
// message: Message,
|
||||
// ) -> 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(message.as_ref())?;
|
||||
// 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: &str) -> Result<()> {
|
||||
// let Some(panel_item): Option<Arc<PanelItem<dyn WaylandBackend>>> = panel_item_from_node(node) else { return Ok(()) };
|
||||
// debug!("Keyboard set keymap");
|
||||
|
||||
// panel_item.seat_data.set_keymap(
|
||||
// keymap,
|
||||
// match &panel_item {
|
||||
// Backend::Wayland(w) => w.input_surfaces(),
|
||||
// #[cfg(feature = "xwayland")]
|
||||
// Backend::X11(_) => panel_item
|
||||
// .toplevel_wl_surface()
|
||||
// .map(|s| vec![s])
|
||||
// .unwrap_or_default(),
|
||||
// },
|
||||
// );
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
fn keyboard_key_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, key, state): (SurfaceID, u32, u32) = deserialize(message.as_ref())?;
|
||||
debug!(key, state, "Set keyboard key state");
|
||||
|
||||
panel_item.keyboard_key(&surface_id, key, state == 0);
|
||||
|
||||
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 configure_toplevel_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 ConfigureToplevelInfo {
|
||||
size: Option<Vector2<u32>>,
|
||||
states: Vec<u32>,
|
||||
bounds: Option<Vector2<u32>>,
|
||||
}
|
||||
let info: ConfigureToplevelInfo = deserialize(message.as_ref())?;
|
||||
|
||||
panel_item.configure_toplevel(info.size, info.states, info.bounds);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_toplevel_capabilities_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
||||
|
||||
let capabilities: Vec<u8> = deserialize(message.as_ref())?;
|
||||
debug!("Set toplevel capabilities");
|
||||
panel_item.set_toplevel_capabilities(capabilities);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn commit_toplevel(&self) {
|
||||
debug!("Commit toplevel");
|
||||
let Some(node) = self.node.upgrade() else {return};
|
||||
let Ok(data) = self.backend.serialize_toplevel() else {return};
|
||||
let _ = node.send_remote_signal("commit_toplevel", data);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
|
||||
fn uid(&self) -> &str {
|
||||
&self.uid
|
||||
}
|
||||
}
|
||||
impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||
self.backend.serialize_start_data(id)
|
||||
}
|
||||
|
||||
fn serialize_toplevel(&self) -> Result<Message> {
|
||||
self.backend.serialize_toplevel()
|
||||
}
|
||||
|
||||
fn set_toplevel_capabilities(&self, capabilities: Vec<u8>) {
|
||||
self.backend.set_toplevel_capabilities(capabilities)
|
||||
}
|
||||
|
||||
fn configure_toplevel(
|
||||
&self,
|
||||
size: Option<Vector2<u32>>,
|
||||
states: Vec<u32>,
|
||||
bounds: Option<Vector2<u32>>,
|
||||
) {
|
||||
self.backend.configure_toplevel(size, states, bounds)
|
||||
}
|
||||
|
||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||
self.backend.apply_surface_material(surface, model_part)
|
||||
}
|
||||
|
||||
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_set_keymap(&self, keymap: &str) -> Result<()> {
|
||||
self.backend.keyboard_set_keymap(keymap)
|
||||
}
|
||||
|
||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
||||
self.backend.keyboard_key(surface, key, state)
|
||||
}
|
||||
}
|
||||
impl<B: Backend + ?Sized> Drop for PanelItem<B> {
|
||||
fn drop(&mut self) {
|
||||
// Dropped panel item, basically just a debug breakpoint place
|
||||
}
|
||||
}
|
||||
@@ -22,15 +22,12 @@ use stardust_xr::messenger::MessageSenderHandle;
|
||||
use stardust_xr::scenegraph::ScenegraphError;
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
use std::fmt::Debug;
|
||||
use std::os::fd::OwnedFd;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::vec::Vec;
|
||||
use tracing::{debug_span, instrument};
|
||||
|
||||
use crate::core::client::Client;
|
||||
use crate::core::registry::Registry;
|
||||
#[cfg(feature = "openxr_runtime")]
|
||||
use crate::openxr;
|
||||
|
||||
use self::alias::Alias;
|
||||
use self::audio::Sound;
|
||||
@@ -43,26 +40,8 @@ use self::spatial::zone::Zone;
|
||||
use self::spatial::Spatial;
|
||||
use self::startup::StartupSettings;
|
||||
|
||||
pub struct Message {
|
||||
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) -> Result<Message>;
|
||||
pub type Signal = fn(&Node, Arc<Client>, &[u8]) -> Result<()>;
|
||||
pub type Method = fn(&Node, Arc<Client>, &[u8]) -> Result<Vec<u8>>;
|
||||
|
||||
pub struct Node {
|
||||
pub enabled: Arc<AtomicBool>,
|
||||
@@ -103,10 +82,6 @@ pub struct Node {
|
||||
|
||||
// Startup
|
||||
pub startup_settings: OnceCell<Mutex<StartupSettings>>,
|
||||
|
||||
// OpenXR
|
||||
#[cfg(feature = "openxr_runtime")]
|
||||
pub openxr_object: OnceCell<openxr::Object>,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
@@ -150,8 +125,6 @@ impl Node {
|
||||
item_acceptor: OnceCell::new(),
|
||||
item_ui: OnceCell::new(),
|
||||
sound: OnceCell::new(),
|
||||
#[cfg(feature = "openxr_runtime")]
|
||||
openxr_object: OnceCell::new(),
|
||||
startup_settings: OnceCell::new(),
|
||||
};
|
||||
node.add_local_signal("set_enabled", Node::set_enabled_flex);
|
||||
@@ -171,20 +144,11 @@ impl Node {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_enabled_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
node.enabled
|
||||
.store(deserialize(message.as_ref())?, Ordering::Relaxed);
|
||||
pub fn set_enabled_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
node.enabled.store(deserialize(data)?, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
pub fn destroy_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn destroy_flex(node: &Node, _calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
|
||||
if node.destroyable {
|
||||
node.destroy();
|
||||
}
|
||||
@@ -216,7 +180,7 @@ impl Node {
|
||||
&self,
|
||||
calling_client: Arc<Client>,
|
||||
method: &str,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<(), ScenegraphError> {
|
||||
if let Some(alias) = self.alias.get() {
|
||||
if !alias.info.server_signals.iter().any(|e| e == &method) {
|
||||
@@ -226,13 +190,13 @@ impl Node {
|
||||
.original
|
||||
.upgrade()
|
||||
.ok_or(ScenegraphError::BrokenAlias)?
|
||||
.send_local_signal(calling_client, method, message)
|
||||
.send_local_signal(calling_client, method, data)
|
||||
} else {
|
||||
let signal = self
|
||||
.local_signals
|
||||
.get(method)
|
||||
.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(),
|
||||
})
|
||||
}
|
||||
@@ -241,8 +205,8 @@ impl Node {
|
||||
&self,
|
||||
calling_client: Arc<Client>,
|
||||
method: &str,
|
||||
message: Message,
|
||||
) -> Result<Message, ScenegraphError> {
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, ScenegraphError> {
|
||||
if let Some(alias) = self.alias.get() {
|
||||
if !alias.info.server_methods.iter().any(|e| e == &method) {
|
||||
return Err(ScenegraphError::MethodNotFound);
|
||||
@@ -251,14 +215,7 @@ impl Node {
|
||||
.original
|
||||
.upgrade()
|
||||
.ok_or(ScenegraphError::BrokenAlias)?
|
||||
.execute_local_method(
|
||||
calling_client,
|
||||
method,
|
||||
Message {
|
||||
data: message.data.clone(),
|
||||
fds: Vec::new(),
|
||||
},
|
||||
)
|
||||
.execute_local_method(calling_client, method, data)
|
||||
} else {
|
||||
let method = self
|
||||
.local_methods
|
||||
@@ -266,36 +223,27 @@ impl Node {
|
||||
.ok_or(ScenegraphError::MethodNotFound)?;
|
||||
|
||||
debug_span!("Handle method").in_scope(|| {
|
||||
method(self, calling_client, message).map_err(|error| {
|
||||
ScenegraphError::MethodError {
|
||||
error: error.to_string(),
|
||||
}
|
||||
method(self, calling_client, data).map_err(|error| ScenegraphError::MethodError {
|
||||
error: error.to_string(),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn send_remote_signal(&self, method: &str, message: impl Into<Message>) -> Result<()> {
|
||||
let message = message.into();
|
||||
pub fn send_remote_signal(&self, method: &str, data: &[u8]) -> Result<()> {
|
||||
self.aliases
|
||||
.get_valid_contents()
|
||||
.iter()
|
||||
.filter(|alias| alias.info.client_signals.iter().any(|e| e == &method))
|
||||
.filter_map(|alias| alias.node.upgrade())
|
||||
.for_each(|node| {
|
||||
// Beware! file descriptors will not be sent to aliases!!!
|
||||
let _ = node.send_remote_signal(
|
||||
method,
|
||||
Message {
|
||||
data: message.data.clone(),
|
||||
fds: Vec::new(),
|
||||
},
|
||||
);
|
||||
let _ = node.send_remote_signal(method, data);
|
||||
});
|
||||
let path = self.path.clone();
|
||||
let method = method.to_string();
|
||||
let data = data.to_vec();
|
||||
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(())
|
||||
}
|
||||
@@ -304,7 +252,7 @@ impl Node {
|
||||
// &self,
|
||||
// method: &str,
|
||||
// data: Vec<u8>,
|
||||
// ) -> Result<impl Future<Output = Result<Message>>> {
|
||||
// ) -> Result<impl Future<Output = Result<Vec<u8>>>> {
|
||||
// let message_sender_handle = self
|
||||
// .message_sender_handle
|
||||
// .as_ref()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::spatial::Spatial;
|
||||
use super::{Message, Node};
|
||||
use super::Node;
|
||||
use crate::core::client::Client;
|
||||
use crate::core::registry::Registry;
|
||||
use color_eyre::eyre::Result;
|
||||
@@ -39,11 +39,7 @@ impl Root {
|
||||
}))
|
||||
}
|
||||
|
||||
fn subscribe_frame_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
) -> Result<()> {
|
||||
fn subscribe_frame_flex(_node: &Node, calling_client: Arc<Client>, _data: &[u8]) -> Result<()> {
|
||||
calling_client
|
||||
.root
|
||||
.get()
|
||||
@@ -58,7 +54,7 @@ impl Root {
|
||||
if let Ok(data) = serialize((delta, 0.0)) {
|
||||
for root in ROOT_REGISTRY.get_valid_contents() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,9 +63,9 @@ impl Root {
|
||||
fn set_base_prefixes_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
*calling_client.base_resource_prefixes.lock() = deserialize(message.as_ref())?;
|
||||
*calling_client.base_resource_prefixes.lock() = deserialize(data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
pub mod zone;
|
||||
|
||||
use self::zone::{create_zone_flex, Zone};
|
||||
use super::{Message, Node};
|
||||
use super::Node;
|
||||
use crate::core::client::Client;
|
||||
use crate::core::registry::Registry;
|
||||
use color_eyre::eyre::{ensure, eyre, Result};
|
||||
@@ -232,13 +232,13 @@ impl Spatial {
|
||||
pub fn get_bounding_box_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let relative_spatial_path: Option<&str> = deserialize(message.as_ref())?;
|
||||
let relative_spatial_path: Option<&str> = deserialize(data)?;
|
||||
let bounds = if let Some(relative_spatial_path) = relative_spatial_path {
|
||||
let relative_spatial = find_reference_space(&calling_client, relative_spatial_path)?;
|
||||
let center =
|
||||
@@ -260,24 +260,23 @@ impl Spatial {
|
||||
this_spatial.get_bounding_box()
|
||||
};
|
||||
|
||||
Ok(serialize((
|
||||
serialize((
|
||||
mint::Vector3::from(bounds.center),
|
||||
mint::Vector3::from(bounds.dimensions),
|
||||
))?
|
||||
.into())
|
||||
))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn get_transform_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
let this_spatial = node
|
||||
.spatial
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node doesn't have a spatial?"))?;
|
||||
let relative_spatial =
|
||||
find_reference_space(&calling_client, deserialize(message.as_ref())?)?;
|
||||
let relative_spatial = find_reference_space(&calling_client, deserialize(data)?)?;
|
||||
|
||||
let (scale, rotation, position) = Spatial::space_to_space_matrix(
|
||||
Some(this_spatial.as_ref()),
|
||||
@@ -285,24 +284,20 @@ impl Spatial {
|
||||
)
|
||||
.to_scale_rotation_translation();
|
||||
|
||||
Ok(serialize((
|
||||
serialize((
|
||||
mint::Vector3::from(position),
|
||||
mint::Quaternion::from(rotation),
|
||||
mint::Vector3::from(scale),
|
||||
))?
|
||||
.into())
|
||||
))
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
pub fn set_transform_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn set_transform_flex(node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct TransformArgs<'a> {
|
||||
reference_space_path: Option<&'a str>,
|
||||
transform: Transform,
|
||||
}
|
||||
let transform_args: TransformArgs = deserialize(message.as_ref())?;
|
||||
let transform_args: TransformArgs = deserialize(data)?;
|
||||
let reference_space_transform = transform_args
|
||||
.reference_space_path
|
||||
.map(|path| find_reference_space(&calling_client, path))
|
||||
@@ -317,29 +312,25 @@ impl Spatial {
|
||||
pub fn set_spatial_parent_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> 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))
|
||||
}
|
||||
pub fn set_spatial_parent_in_place_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> 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_in_place(Some(parent))?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_zoneable_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
let zoneable: bool = deserialize(message.as_ref())?;
|
||||
pub fn set_zoneable_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
let zoneable: bool = deserialize(data)?;
|
||||
let spatial = node.spatial.get().unwrap();
|
||||
if zoneable {
|
||||
ZONEABLE_REGISTRY.add_raw(spatial);
|
||||
@@ -353,9 +344,9 @@ impl Spatial {
|
||||
pub fn field_distance_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(message.as_ref())?;
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(data)?;
|
||||
let spatial = node.spatial.get().unwrap();
|
||||
|
||||
let output = fields
|
||||
@@ -371,14 +362,14 @@ impl Spatial {
|
||||
.map(|f| f.map(|f| f.distance(spatial, point.into())))
|
||||
.collect::<Vec<Option<f32>>>();
|
||||
|
||||
Ok(serialize(output)?.into())
|
||||
Ok(serialize(output)?)
|
||||
}
|
||||
pub fn field_normal_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(message.as_ref())?;
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(data)?;
|
||||
let spatial = node.spatial.get().unwrap();
|
||||
|
||||
let output = fields
|
||||
@@ -394,14 +385,14 @@ impl Spatial {
|
||||
.map(|f| f.map(|f| Vector3::from(f.normal(spatial, point.into(), 0.001))))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(serialize(output)?.into())
|
||||
Ok(serialize(output)?)
|
||||
}
|
||||
pub fn field_closest_point_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<Message> {
|
||||
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(message.as_ref())?;
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
let (point, fields): (Vector3<f32>, Vec<Option<&str>>) = deserialize(data)?;
|
||||
let spatial = node.spatial.get().unwrap();
|
||||
|
||||
let output = fields
|
||||
@@ -417,7 +408,7 @@ impl Spatial {
|
||||
.map(|f| f.map(|f| Vector3::from(f.closest_point(spatial, point.into(), 0.001))))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(serialize(output)?.into())
|
||||
Ok(serialize(output)?)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
@@ -499,11 +490,7 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||
node.add_to_scenegraph().map(|_| ())
|
||||
}
|
||||
|
||||
pub fn create_spatial_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
) -> Result<()> {
|
||||
pub fn create_spatial_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
struct CreateSpatialInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -511,7 +498,7 @@ pub fn create_spatial_flex(
|
||||
transform: Transform,
|
||||
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 parent = find_spatial_parent(&calling_client, info.parent_path)?;
|
||||
let transform = parse_transform(info.transform, true, true, true);
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
alias::{Alias, AliasInfo},
|
||||
fields::{find_field, Field},
|
||||
spatial::{find_spatial_parent, parse_transform},
|
||||
Message, Node,
|
||||
Node,
|
||||
},
|
||||
};
|
||||
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.zone.lock() = Arc::downgrade(zone);
|
||||
zone.captured.add_raw(spatial);
|
||||
let Some(node) = zone.spatial.node.upgrade() else {return};
|
||||
let Ok(message) = serialize(&spatial.uid) else {return};
|
||||
let _ = node.send_remote_signal("capture", message);
|
||||
let node = zone.spatial.node.upgrade().unwrap();
|
||||
let _ = node.send_remote_signal("capture", &serialize(&spatial.uid).unwrap());
|
||||
}
|
||||
}
|
||||
pub fn release(spatial: &Spatial) {
|
||||
let _ = spatial.set_spatial_parent_in_place(spatial.old_parent.lock().take());
|
||||
let mut spatial_zone = spatial.zone.lock();
|
||||
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);
|
||||
let Ok(message) = serialize(&spatial.uid) else {return};
|
||||
let _ = node.send_remote_signal("release", message);
|
||||
let _ = node.send_remote_signal("release", &serialize(&spatial.uid).unwrap());
|
||||
}
|
||||
*spatial_zone = Weak::new();
|
||||
}
|
||||
@@ -68,20 +66,20 @@ impl Zone {
|
||||
let _ = node.zone.set(zone.clone());
|
||||
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 capture_path: &str = deserialize(message.as_ref())?;
|
||||
let capture_path: &str = deserialize(data)?;
|
||||
let spatial = find_spatial(&calling_client, "Spatial", capture_path)?;
|
||||
capture(&spatial, zone);
|
||||
Ok(())
|
||||
}
|
||||
fn release_flex(_node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> {
|
||||
let capture_path: &str = deserialize(message.as_ref())?;
|
||||
fn release_flex(_node: &Node, calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
let capture_path: &str = deserialize(data)?;
|
||||
let spatial = find_spatial(&calling_client, "Spatial", capture_path)?;
|
||||
release(&spatial);
|
||||
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 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
|
||||
@@ -131,10 +129,10 @@ impl Zone {
|
||||
.collect::<FxHashMap<String, Arc<Node>>>();
|
||||
|
||||
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)) {
|
||||
node.send_remote_signal("leave", serialize(left_uid)?)?;
|
||||
node.send_remote_signal("leave", &serialize(left_uid)?)?;
|
||||
}
|
||||
|
||||
*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)]
|
||||
struct CreateZoneInfo<'a> {
|
||||
name: &'a str,
|
||||
@@ -158,7 +156,7 @@ pub fn create_zone_flex(_node: &Node, calling_client: Arc<Client>, message: Mess
|
||||
transform: Transform,
|
||||
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 transform = parse_transform(info.transform, true, true, false);
|
||||
let field = find_field(&calling_client, info.field_path)?;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#[cfg(feature = "xwayland")]
|
||||
use crate::wayland::xwayland::DISPLAY;
|
||||
use crate::{core::client::Client, wayland::WAYLAND_DISPLAY, STARDUST_INSTANCE};
|
||||
|
||||
use super::{
|
||||
items::{ItemAcceptor, TypeInfo},
|
||||
spatial::find_spatial,
|
||||
Message, Node,
|
||||
Node,
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
@@ -33,12 +31,8 @@ impl StartupSettings {
|
||||
.set(Mutex::new(StartupSettings::default()));
|
||||
}
|
||||
|
||||
fn set_root_flex(node: &Node, calling_client: Arc<Client>, message: Message) -> Result<()> {
|
||||
let spatial = find_spatial(
|
||||
&calling_client,
|
||||
"Root spatial",
|
||||
deserialize(message.as_ref())?,
|
||||
)?;
|
||||
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(())
|
||||
@@ -47,10 +41,9 @@ impl StartupSettings {
|
||||
fn add_automatic_acceptor_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let acceptor_node =
|
||||
calling_client.get_node("Item acceptor", deserialize(message.as_ref())?)?;
|
||||
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();
|
||||
@@ -64,14 +57,14 @@ impl StartupSettings {
|
||||
fn generate_startup_token_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
) -> Result<Message> {
|
||||
_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.into())
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
impl Debug for StartupSettings {
|
||||
@@ -103,12 +96,12 @@ pub fn create_interface(client: &Arc<Client>) -> Result<()> {
|
||||
pub fn create_startup_settings_flex(
|
||||
_node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
message: Message,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let node = Node::create(
|
||||
&calling_client,
|
||||
"/startup/settings",
|
||||
deserialize(message.as_ref())?,
|
||||
deserialize(data)?,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph()?;
|
||||
@@ -135,15 +128,13 @@ macro_rules! var_env_insert {
|
||||
pub fn get_connection_environment_flex(
|
||||
_node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
_message: Message,
|
||||
) -> Result<Message> {
|
||||
_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);
|
||||
#[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());
|
||||
@@ -151,5 +142,5 @@ pub fn get_connection_environment_flex(
|
||||
env.insert("SDL_VIDEODRIVER".to_string(), "wayland".to_string());
|
||||
}
|
||||
|
||||
Ok(serialize(env)?.into())
|
||||
Ok(serialize(env)?)
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap},
|
||||
core::client::INTERNAL_CLIENT,
|
||||
nodes::{
|
||||
data::{mask_matches, Mask, PulseSender, PULSE_RECEIVER_REGISTRY},
|
||||
fields::Ray,
|
||||
@@ -9,25 +9,18 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{vec2, vec3, Mat4, Vec2, Vec3};
|
||||
use glam::{vec3, Mat4, Vec3};
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::schemas::flex::flexbuffers;
|
||||
use serde::Serialize;
|
||||
use stardust_xr::schemas::{flat::Datamap, flex::flexbuffers};
|
||||
use std::{convert::TryFrom, sync::Arc};
|
||||
use stereokit::{ray_from_mouse, ButtonState, Key, StereoKitMultiThread};
|
||||
use tracing::instrument;
|
||||
|
||||
const SK_KEYMAP: &str = include_str!("sk.kmp");
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
struct MouseDatamap {
|
||||
select: f32,
|
||||
grab: f32,
|
||||
scroll: Vec2,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
struct KeyboardEvent {
|
||||
pub struct KeyboardEvent {
|
||||
pub keyboard: String,
|
||||
pub keymap: Option<String>,
|
||||
pub keys_up: Option<Vec<u32>>,
|
||||
@@ -38,7 +31,6 @@ pub struct MousePointer {
|
||||
node: Arc<Node>,
|
||||
spatial: Arc<Spatial>,
|
||||
pointer: Arc<InputMethod>,
|
||||
datamap: TypedDatamap<MouseDatamap>,
|
||||
keyboard_sender: Arc<PulseSender>,
|
||||
}
|
||||
impl MousePointer {
|
||||
@@ -61,12 +53,11 @@ impl MousePointer {
|
||||
node,
|
||||
spatial,
|
||||
pointer,
|
||||
datamap: Default::default(),
|
||||
keyboard_sender,
|
||||
})
|
||||
}
|
||||
#[instrument(level = "debug", name = "Update Flatscreen Pointer Ray", skip_all)]
|
||||
pub fn update(&mut self, sk: &impl StereoKitMultiThread) {
|
||||
pub fn update(&self, sk: &impl StereoKitMultiThread) {
|
||||
let mouse = sk.input_mouse();
|
||||
|
||||
let ray = ray_from_mouse(mouse.pos).unwrap();
|
||||
@@ -80,18 +71,30 @@ impl MousePointer {
|
||||
);
|
||||
{
|
||||
// Set pointer input datamap
|
||||
self.datamap.select = if sk.input_key(Key::MouseLeft).contains(ButtonState::ACTIVE) {
|
||||
1.0f32
|
||||
} else {
|
||||
0.0f32
|
||||
};
|
||||
self.datamap.grab = if sk.input_key(Key::MouseRight).contains(ButtonState::ACTIVE) {
|
||||
1.0f32
|
||||
} else {
|
||||
0.0f32
|
||||
};
|
||||
self.datamap.scroll = vec2(0.0, mouse.scroll_change / 120.0);
|
||||
*self.pointer.datamap.lock() = self.datamap.to_datamap().ok();
|
||||
let mut fbb = flexbuffers::Builder::default();
|
||||
let mut map = fbb.start_map();
|
||||
map.push(
|
||||
"select",
|
||||
if sk.input_key(Key::MouseLeft).contains(ButtonState::ACTIVE) {
|
||||
1.0f32
|
||||
} else {
|
||||
0.0f32
|
||||
},
|
||||
);
|
||||
map.push(
|
||||
"grab",
|
||||
if sk.input_key(Key::MouseRight).contains(ButtonState::ACTIVE) {
|
||||
1.0f32
|
||||
} else {
|
||||
0.0f32
|
||||
},
|
||||
);
|
||||
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);
|
||||
}
|
||||
@@ -104,7 +107,7 @@ impl MousePointer {
|
||||
.map(|rx| {
|
||||
let result = rx.field.ray_march(Ray {
|
||||
origin: vec3(0.0, 0.0, 0.0),
|
||||
direction: vec3(0.0, 0.0, -1.0),
|
||||
direction: vec3(0.0, 0.0, 1.0),
|
||||
space: self.spatial.clone(),
|
||||
});
|
||||
(rx, result)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap},
|
||||
core::client::INTERNAL_CLIENT,
|
||||
nodes::{
|
||||
input::{tip::Tip, InputMethod, InputType},
|
||||
spatial::Spatial,
|
||||
@@ -7,70 +7,51 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::{Mat4, Vec2};
|
||||
use glam::Mat4;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::values::Transform;
|
||||
use std::sync::Arc;
|
||||
use stereokit::{
|
||||
ButtonState, Color128, Handed, Model, RenderLayer, StereoKitDraw, StereoKitMultiThread,
|
||||
use stardust_xr::{
|
||||
schemas::{flat::Datamap, flex::flexbuffers},
|
||||
values::Transform,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use stereokit::{ButtonState, Handed, StereoKitMultiThread};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
struct ControllerDatamap {
|
||||
select: f32,
|
||||
grab: f32,
|
||||
scroll: Vec2,
|
||||
}
|
||||
|
||||
pub struct SkController {
|
||||
_node: Arc<Node>,
|
||||
input: Arc<InputMethod>,
|
||||
model: Model,
|
||||
handed: Handed,
|
||||
datamap: TypedDatamap<ControllerDatamap>,
|
||||
}
|
||||
impl SkController {
|
||||
pub fn new(sk: &impl StereoKitMultiThread, handed: Handed) -> Result<Self> {
|
||||
pub fn new(handed: Handed) -> Result<Self> {
|
||||
let _node = Node::create(&INTERNAL_CLIENT, "", &nanoid!(), false).add_to_scenegraph()?;
|
||||
Spatial::add_to(&_node, None, Mat4::IDENTITY, false)?;
|
||||
let model = sk.model_create_mem("cursor", include_bytes!("cursor.glb"), None)?;
|
||||
let tip = InputType::Tip(Tip::default());
|
||||
let input = InputMethod::add_to(&_node, tip, None)?;
|
||||
Ok(SkController {
|
||||
_node,
|
||||
input,
|
||||
handed,
|
||||
model,
|
||||
datamap: Default::default(),
|
||||
})
|
||||
}
|
||||
#[instrument(level = "debug", name = "Update StereoKit Tip Input Method", skip_all)]
|
||||
pub fn update(&mut self, sk: &impl StereoKitDraw) {
|
||||
pub fn update(&mut self, sk: &impl StereoKitMultiThread) {
|
||||
let controller = sk.input_controller(self.handed);
|
||||
*self.input.enabled.lock() = controller.tracked.contains(ButtonState::ACTIVE);
|
||||
if *self.input.enabled.lock() {
|
||||
sk.model_draw(
|
||||
&self.model,
|
||||
Mat4::from_rotation_translation(
|
||||
controller.aim.orientation,
|
||||
controller.aim.position,
|
||||
),
|
||||
Color128::default(),
|
||||
RenderLayer::all(),
|
||||
);
|
||||
self.input.spatial.set_local_transform_components(
|
||||
None,
|
||||
Transform::from_position_rotation(
|
||||
controller.aim.position,
|
||||
controller.aim.orientation,
|
||||
controller.pose.position,
|
||||
controller.pose.orientation,
|
||||
),
|
||||
);
|
||||
}
|
||||
self.datamap.select = controller.trigger;
|
||||
self.datamap.grab = controller.grip;
|
||||
self.datamap.scroll = controller.stick;
|
||||
*self.input.datamap.lock() = self.datamap.to_datamap().ok();
|
||||
let mut fbb = flexbuffers::Builder::default();
|
||||
let mut map = fbb.start_map();
|
||||
map.push("select", controller.trigger);
|
||||
map.push("grab", controller.grip);
|
||||
map.end_map();
|
||||
*self.input.datamap.lock() = Datamap::new(fbb.take_buffer()).ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
core::{client::INTERNAL_CLIENT, typed_datamap::TypedDatamap},
|
||||
core::client::INTERNAL_CLIENT,
|
||||
nodes::{
|
||||
input::{hand::Hand, InputMethod, InputType},
|
||||
spatial::Spatial,
|
||||
@@ -9,8 +9,10 @@ use crate::{
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stardust_xr::schemas::flat::{Hand as FlatHand, Joint};
|
||||
use stardust_xr::schemas::{
|
||||
flat::{Datamap, Hand as FlatHand, Joint},
|
||||
flex::flexbuffers,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use stereokit::{ButtonState, HandJoint, Handed, StereoKitMultiThread};
|
||||
use tracing::instrument;
|
||||
@@ -23,17 +25,10 @@ fn convert_joint(joint: HandJoint) -> Joint {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Deserialize, Serialize)]
|
||||
struct HandDatamap {
|
||||
pinch_strength: f32,
|
||||
grab_strength: f32,
|
||||
}
|
||||
|
||||
pub struct SkHand {
|
||||
_node: Arc<Node>,
|
||||
input: Arc<InputMethod>,
|
||||
handed: Handed,
|
||||
datamap: TypedDatamap<HandDatamap>,
|
||||
}
|
||||
impl SkHand {
|
||||
pub fn new(handed: Handed) -> Result<Self> {
|
||||
@@ -50,7 +45,6 @@ impl SkHand {
|
||||
_node,
|
||||
input,
|
||||
handed,
|
||||
datamap: Default::default(),
|
||||
})
|
||||
}
|
||||
#[instrument(level = "debug", name = "Update Hand Input Method", skip_all)]
|
||||
@@ -60,7 +54,6 @@ impl SkHand {
|
||||
let controller = sk.input_controller(self.handed);
|
||||
*self.input.enabled.lock() = controller.tracked.contains(ButtonState::INACTIVE)
|
||||
&& sk_hand.tracked_state.contains(ButtonState::ACTIVE);
|
||||
sk.input_hand_visible(self.handed, *self.input.enabled.lock());
|
||||
if *self.input.enabled.lock() {
|
||||
hand.base.thumb.tip = convert_joint(sk_hand.fingers[0][4]);
|
||||
hand.base.thumb.distal = convert_joint(sk_hand.fingers[0][3]);
|
||||
@@ -93,8 +86,11 @@ impl SkHand {
|
||||
hand.base.elbow = None;
|
||||
}
|
||||
}
|
||||
self.datamap.pinch_strength = sk_hand.pinch_activation;
|
||||
self.datamap.grab_strength = sk_hand.grip_activation;
|
||||
*self.input.datamap.lock() = self.datamap.to_datamap().ok();
|
||||
let mut fbb = flexbuffers::Builder::default();
|
||||
let mut map = fbb.start_map();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
pub mod input;
|
||||
pub mod play_space;
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use color_eyre::eyre::Result;
|
||||
use glam::Mat4;
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stereokit::StereoKitMultiThread;
|
||||
|
||||
use crate::{
|
||||
core::client::INTERNAL_CLIENT,
|
||||
nodes::{
|
||||
data::{Mask, PulseReceiver},
|
||||
fields::{r#box::BoxField, Field},
|
||||
spatial::Spatial,
|
||||
Node,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct PlaySpaceMap {
|
||||
play_space: (),
|
||||
size: Vector2<f32>,
|
||||
}
|
||||
impl Default for PlaySpaceMap {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
play_space: (),
|
||||
size: [0.0; 2].into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PlaySpace {
|
||||
_node: Arc<Node>,
|
||||
spatial: Arc<Spatial>,
|
||||
field: Arc<Field>,
|
||||
_pulse_rx: Arc<PulseReceiver>,
|
||||
}
|
||||
impl PlaySpace {
|
||||
pub fn new() -> Result<Self> {
|
||||
let node = Node::create(&INTERNAL_CLIENT, "", &nanoid!(), false).add_to_scenegraph()?;
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false)?;
|
||||
let field = BoxField::add_to(&node, [0.0; 3].into())?;
|
||||
|
||||
let pulse_rx =
|
||||
PulseReceiver::add_to(&node, field.clone(), Mask::from_struct::<PlaySpaceMap>())?;
|
||||
|
||||
Ok(PlaySpace {
|
||||
_node: node,
|
||||
spatial,
|
||||
field,
|
||||
_pulse_rx: pulse_rx,
|
||||
})
|
||||
}
|
||||
pub fn update(&self, sk: &impl StereoKitMultiThread) {
|
||||
let pose = sk.world_get_bounds_pose();
|
||||
self.spatial
|
||||
.set_local_transform(Mat4::from_rotation_translation(
|
||||
pose.orientation,
|
||||
pose.position,
|
||||
));
|
||||
let Field::Box(box_field) = self.field.as_ref() else {return};
|
||||
box_field.set_size(
|
||||
[
|
||||
sk.world_get_bounds_size().x,
|
||||
0.0,
|
||||
sk.world_get_bounds_size().y,
|
||||
]
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
use super::Object;
|
||||
use crate::{core::client::Client, nodes::Node};
|
||||
use color_eyre::eyre::{bail, Result};
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Action {
|
||||
// _info: InstanceInfo,
|
||||
_localized_name: String,
|
||||
suggested_bindings: Mutex<FxHashMap<String, String>>,
|
||||
}
|
||||
impl Action {
|
||||
pub fn create_action_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Object::ActionSet(action_set) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else {
|
||||
bail!("Object not an instance")
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct CreateActionInfo {
|
||||
name: String,
|
||||
localized_name: String,
|
||||
}
|
||||
let info: CreateActionInfo = dbg!(deserialize(data)?);
|
||||
|
||||
let node = Node::create(
|
||||
&node.get_client().unwrap(),
|
||||
node.get_path(),
|
||||
&info.name,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph();
|
||||
node.add_local_signal("suggest_binding", Self::suggest_binding_flex);
|
||||
|
||||
let action = Arc::new(Action {
|
||||
_localized_name: info.localized_name,
|
||||
suggested_bindings: Mutex::new(FxHashMap::default()),
|
||||
});
|
||||
action_set
|
||||
.actions
|
||||
.lock()
|
||||
.insert(info.name, Arc::downgrade(&action));
|
||||
node.openxr_object.set(Object::Action(action)).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn suggest_binding_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Object::Action(action) = node.get_aspect("OpenXR interface", "Action", |n| &n.openxr_object)? else {
|
||||
bail!("Object not an action")
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct SuggestBindingArgs {
|
||||
interaction_profile: String,
|
||||
binding: String,
|
||||
}
|
||||
let args: SuggestBindingArgs = dbg!(deserialize(data)?);
|
||||
action
|
||||
.suggested_bindings
|
||||
.lock()
|
||||
.insert(args.interaction_profile, args.binding);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
use super::{action::Action, Object};
|
||||
use crate::{core::client::Client, nodes::Node};
|
||||
use color_eyre::eyre::{bail, Result};
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ActionSet {
|
||||
// _info: InstanceInfo,
|
||||
_localized_name: String,
|
||||
_priority: u32,
|
||||
pub actions: Mutex<FxHashMap<String, Weak<Action>>>,
|
||||
}
|
||||
impl ActionSet {
|
||||
pub fn create_action_set_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Object::Instance(instance) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else {
|
||||
bail!("Object not an instance")
|
||||
};
|
||||
let Some(instance) = instance.get() else { bail!("Instance not initialized") };
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct CreateActionSetInfo {
|
||||
name: String,
|
||||
localized_name: String,
|
||||
priority: u32,
|
||||
}
|
||||
let info: CreateActionSetInfo = deserialize(data)?;
|
||||
|
||||
let node = Node::create(
|
||||
&node.get_client().unwrap(),
|
||||
"/openxr/action_set",
|
||||
&info.name,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph();
|
||||
node.add_local_signal("create_action", Action::create_action_flex);
|
||||
|
||||
let action_set = Arc::new(ActionSet {
|
||||
_localized_name: info.localized_name,
|
||||
_priority: info.priority,
|
||||
actions: Mutex::new(FxHashMap::default()),
|
||||
});
|
||||
instance
|
||||
.action_sets
|
||||
.lock()
|
||||
.insert(info.name, Arc::downgrade(&action_set));
|
||||
node.openxr_object
|
||||
.set(Object::ActionSet(action_set))
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
use super::{action_set::ActionSet, Object};
|
||||
use crate::{core::client::Client, nodes::Node};
|
||||
use color_eyre::eyre::{bail, eyre, Result};
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct InstanceInfo {
|
||||
_app_info: ApplicationInfo,
|
||||
_extension_names: Vec<String>,
|
||||
}
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ApplicationInfo {
|
||||
_app_name: String,
|
||||
_app_version: u32,
|
||||
_engine_name: String,
|
||||
_engine_version: u32,
|
||||
_api_version: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Instance {
|
||||
_info: InstanceInfo,
|
||||
pub action_sets: Mutex<FxHashMap<String, Weak<ActionSet>>>,
|
||||
}
|
||||
impl Instance {
|
||||
pub fn setup_instance_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Object::Instance(instance) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else {
|
||||
bail!("Object not an instance")
|
||||
};
|
||||
let instance_info = Instance {
|
||||
_info: deserialize(data)?,
|
||||
action_sets: Mutex::new(FxHashMap::default()),
|
||||
};
|
||||
dbg!(&instance_info);
|
||||
instance
|
||||
.set(Arc::new(instance_info))
|
||||
.map_err(|_| eyre!("Instance already set up"))
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
mod action;
|
||||
mod action_set;
|
||||
mod instance;
|
||||
mod session;
|
||||
mod system;
|
||||
|
||||
use self::{
|
||||
action::Action, action_set::ActionSet, instance::Instance, session::Session, system::System,
|
||||
};
|
||||
use crate::{core::client::Client, nodes::Node};
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Object {
|
||||
Instance(OnceCell<Arc<Instance>>),
|
||||
System(System),
|
||||
Session(Session),
|
||||
ActionSet(Arc<ActionSet>),
|
||||
Action(Arc<Action>),
|
||||
}
|
||||
|
||||
pub fn create_interface(client: &Arc<Client>) {
|
||||
let node = Node::create(client, "", "openxr", false);
|
||||
node.add_local_signal("setup_instance", Instance::setup_instance_flex);
|
||||
node.add_local_method("get_system", System::get_system_flex);
|
||||
node.add_local_signal("create_action_set", ActionSet::create_action_set_flex);
|
||||
|
||||
node.openxr_object
|
||||
.set(Object::Instance(OnceCell::new()))
|
||||
.unwrap();
|
||||
|
||||
node.add_to_scenegraph();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use color_eyre::eyre::{bail, Result};
|
||||
use stardust_xr::schemas::flex::deserialize;
|
||||
|
||||
use super::Object;
|
||||
use crate::{core::client::Client, nodes::Node};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Session {
|
||||
// _info: InstanceInfo,
|
||||
}
|
||||
impl Session {
|
||||
pub fn create_session_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Object::System(_system) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else {
|
||||
bail!("Object not a system")
|
||||
};
|
||||
let node = Node::create(
|
||||
&node.get_client().unwrap(),
|
||||
node.get_path(),
|
||||
deserialize(data)?,
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph();
|
||||
let session = Session {};
|
||||
node.openxr_object.set(Object::Session(session)).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
use super::{session::Session, Object};
|
||||
use crate::{core::client::Client, nodes::Node, SK_INFO};
|
||||
use color_eyre::eyre::{bail, eyre, Result};
|
||||
use serde::Serialize;
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum System {
|
||||
Handheld,
|
||||
HeadMounted,
|
||||
}
|
||||
impl System {
|
||||
pub fn from_raw(raw: u32) -> Option<Self> {
|
||||
match raw {
|
||||
1 => Some(System::Handheld),
|
||||
2 => Some(System::HeadMounted),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_system_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
// let Object::Instance(instance) = node.get_aspect("OpenXR interface", "Instance", |n| &n.openxr_object)? else {
|
||||
// bail!("Object not an instance")
|
||||
// };
|
||||
let system_type: u32 = deserialize(data)?;
|
||||
let system = System::from_raw(system_type).ok_or_else(|| eyre!("No system exists!"))?;
|
||||
let node = Node::create(
|
||||
&node.get_client().unwrap(),
|
||||
node.get_path(),
|
||||
&format!("system{}", system_type),
|
||||
true,
|
||||
)
|
||||
.add_to_scenegraph();
|
||||
node.add_local_method("views", System::views_flex);
|
||||
node.add_local_signal("create_session", Session::create_session_flex);
|
||||
node.openxr_object.set(Object::System(system)).unwrap();
|
||||
|
||||
Ok(serialize(system_type)?)
|
||||
}
|
||||
|
||||
fn views_flex(_node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<Vec<u8>> {
|
||||
let view_configuration_type: u64 = deserialize(data)?;
|
||||
let view_count: u32 = match view_configuration_type {
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
1000037000 => 4,
|
||||
1000054000 => 1,
|
||||
_ => bail!("Invalid view config type"),
|
||||
};
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct View {
|
||||
recommended_image_rect_width: u32,
|
||||
max_image_rect_width: u32,
|
||||
recommended_image_rect_height: u32,
|
||||
max_image_rect_height: u32,
|
||||
}
|
||||
let sk_info = SK_INFO.get().unwrap();
|
||||
|
||||
Ok(serialize(
|
||||
(0..view_count)
|
||||
.map(|_| View {
|
||||
recommended_image_rect_width: sk_info.display_width,
|
||||
max_image_rect_width: sk_info.display_width,
|
||||
recommended_image_rect_height: sk_info.display_height,
|
||||
max_image_rect_height: sk_info.display_height,
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)?)
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ use crate::wayland::surface::CoreSurface;
|
||||
|
||||
use super::state::{ClientState, WaylandState};
|
||||
use portable_atomic::{AtomicU32, Ordering};
|
||||
#[cfg(feature = "xwayland")]
|
||||
use smithay::xwayland::XWaylandClientData;
|
||||
use smithay::{
|
||||
delegate_compositor,
|
||||
reexports::wayland_server::{protocol::wl_surface::WlSurface, Client},
|
||||
@@ -40,15 +38,7 @@ impl CompositorHandler for WaylandState {
|
||||
}
|
||||
|
||||
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
|
||||
if let Some(client_state) = client.get_data::<ClientState>() {
|
||||
&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!()
|
||||
}
|
||||
&client.get_data::<ClientState>().unwrap().compositor_state
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,9 +88,9 @@ impl KdeDecorationHandler for WaylandState {
|
||||
&mut self,
|
||||
_surface: &WlSurface,
|
||||
decoration: &OrgKdeKwinServerDecoration,
|
||||
mode: WEnum<KdeMode>,
|
||||
_mode: WEnum<KdeMode>,
|
||||
) {
|
||||
decoration.mode(mode.into_result().unwrap());
|
||||
decoration.mode(KdeMode::Server);
|
||||
}
|
||||
}
|
||||
delegate_kde_decoration!(WaylandState);
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
mod compositor;
|
||||
mod data_device;
|
||||
mod decoration;
|
||||
pub mod panel_item;
|
||||
mod seat;
|
||||
mod shaders;
|
||||
mod state;
|
||||
mod surface;
|
||||
// mod xdg_activation;
|
||||
mod xdg_shell;
|
||||
#[cfg(feature = "xwayland")]
|
||||
pub mod xwayland;
|
||||
|
||||
use self::{state::WaylandState, surface::CORE_SURFACES};
|
||||
use crate::wayland::seat::SeatData;
|
||||
use crate::{core::task, wayland::state::ClientState};
|
||||
use color_eyre::eyre::{ensure, Result};
|
||||
use global_counter::primitive::exact::CounterU32;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use sk::StereoKitDraw;
|
||||
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||
use smithay::backend::egl::EGLContext;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::backend::renderer::ImportDma;
|
||||
use smithay::reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket};
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
use std::{
|
||||
@@ -30,13 +26,13 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
use stereokit as sk;
|
||||
use tokio::sync::mpsc::UnboundedReceiver;
|
||||
use tokio::{
|
||||
io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle,
|
||||
};
|
||||
use tracing::{debug, debug_span, info, instrument};
|
||||
|
||||
pub static WAYLAND_DISPLAY: OnceCell<String> = OnceCell::new();
|
||||
|
||||
pub static SERIAL_COUNTER: CounterU32 = CounterU32::new(0);
|
||||
|
||||
struct EGLRawHandles {
|
||||
@@ -67,10 +63,7 @@ pub struct Wayland {
|
||||
pub socket_name: String,
|
||||
join_handle: JoinHandle<Result<()>>,
|
||||
renderer: GlesRenderer,
|
||||
dmabuf_rx: UnboundedReceiver<Dmabuf>,
|
||||
wayland_state: Arc<Mutex<WaylandState>>,
|
||||
#[cfg(feature = "xwayland")]
|
||||
pub xwayland_state: xwayland::XWaylandState,
|
||||
state: Arc<Mutex<WaylandState>>,
|
||||
}
|
||||
impl Wayland {
|
||||
pub fn new() -> Result<Self> {
|
||||
@@ -86,12 +79,8 @@ impl Wayland {
|
||||
let display: Display<WaylandState> = Display::new()?;
|
||||
let display_handle = display.handle();
|
||||
|
||||
let (dmabuf_tx, dmabuf_rx) = mpsc::unbounded_channel();
|
||||
let display = Arc::new(Mutex::new(display));
|
||||
#[cfg(feature = "xwayland")]
|
||||
let xwayland_state = xwayland::XWaylandState::create(&display_handle).unwrap();
|
||||
let wayland_state =
|
||||
WaylandState::new(display.clone(), display_handle, &renderer, dmabuf_tx);
|
||||
let state = WaylandState::new(display.clone(), display_handle, &renderer);
|
||||
|
||||
let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);
|
||||
GLOBAL_DESTROY_QUEUE.set(global_destroy_queue_in).unwrap();
|
||||
@@ -103,22 +92,15 @@ impl Wayland {
|
||||
.expect("seriously message nova this time they screwed up big time");
|
||||
info!(socket_name, "Wayland active");
|
||||
|
||||
let join_handle = Wayland::start_loop(
|
||||
display.clone(),
|
||||
socket,
|
||||
wayland_state.clone(),
|
||||
global_destroy_queue,
|
||||
)?;
|
||||
let join_handle =
|
||||
Wayland::start_loop(display.clone(), socket, state.clone(), global_destroy_queue)?;
|
||||
|
||||
Ok(Wayland {
|
||||
display,
|
||||
socket_name,
|
||||
join_handle,
|
||||
renderer,
|
||||
dmabuf_rx,
|
||||
wayland_state,
|
||||
#[cfg(feature = "xwayland")]
|
||||
xwayland_state,
|
||||
state,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -147,13 +129,9 @@ impl Wayland {
|
||||
}
|
||||
acc = listen_async.accept() => { // New client connected
|
||||
let (stream, _) = acc?;
|
||||
let client_state = Arc::new(ClientState {
|
||||
compositor_state: Default::default(),
|
||||
display: Arc::downgrade(&display),
|
||||
seat: SeatData::new(&dh1)
|
||||
});
|
||||
let client = dh2.insert_client(stream.into_std()?, client_state.clone())?;
|
||||
client_state.seat.client.set(client.id()).unwrap();
|
||||
let client = dh2.insert_client(stream.into_std()?, Arc::new(ClientState::default()))?;
|
||||
|
||||
state.lock().new_client(client.id(), &dh2);
|
||||
}
|
||||
e = dispatch_poll_listener.readable() => { // Dispatch
|
||||
let mut guard = e?;
|
||||
@@ -172,9 +150,6 @@ impl Wayland {
|
||||
|
||||
#[instrument(level = "debug", name = "Wayland frame", skip(self, sk))]
|
||||
pub fn update(&mut self, sk: &impl StereoKitDraw) {
|
||||
while let Ok(dmabuf) = self.dmabuf_rx.try_recv() {
|
||||
let _ = self.renderer.import_dmabuf(&dmabuf, None);
|
||||
}
|
||||
for core_surface in CORE_SURFACES.get_valid_contents() {
|
||||
core_surface.process(sk, &mut self.renderer);
|
||||
}
|
||||
@@ -183,7 +158,7 @@ impl Wayland {
|
||||
}
|
||||
|
||||
pub fn frame_event(&self, sk: &impl StereoKitDraw) {
|
||||
let state = self.wayland_state.lock();
|
||||
let state = self.state.lock();
|
||||
|
||||
for core_surface in CORE_SURFACES.get_valid_contents() {
|
||||
core_surface.frame(sk, state.output.clone());
|
||||
|
||||
655
src/wayland/panel_item.rs
Normal file
655
src/wayland/panel_item.rs
Normal file
@@ -0,0 +1,655 @@
|
||||
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 size = info.size.unwrap_or(Vector2::from([0; 2]));
|
||||
xdg_toplevel.configure(
|
||||
size.x as i32,
|
||||
size.y as i32,
|
||||
info.states
|
||||
.into_iter()
|
||||
.flat_map(|state| state.to_ne_bytes())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
use super::{
|
||||
state::{ClientState, WaylandState},
|
||||
surface::CoreSurface,
|
||||
GLOBAL_DESTROY_QUEUE, SERIAL_COUNTER,
|
||||
panel_item::PanelItem, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE,
|
||||
SERIAL_COUNTER,
|
||||
};
|
||||
use crate::core::task;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use color_eyre::eyre::Result;
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use once_cell::sync::OnceCell;
|
||||
@@ -28,12 +27,11 @@ use smithay::{
|
||||
};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
sync::Arc,
|
||||
sync::{Arc, Weak},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use tokio::sync::watch;
|
||||
use tracing::{debug, warn};
|
||||
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
|
||||
use xkbcommon::xkb::{self, Keymap};
|
||||
|
||||
pub struct KeyboardInfo {
|
||||
keymap: KeymapFile,
|
||||
@@ -89,7 +87,7 @@ unsafe impl Send for KeyboardInfo {}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum PointerEvent {
|
||||
Motion(Vector2<f32>),
|
||||
Motion(Vector2<f64>),
|
||||
Button {
|
||||
button: u32,
|
||||
state: u32,
|
||||
@@ -108,30 +106,23 @@ pub enum KeyboardEvent {
|
||||
const POINTER_EVENT_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
struct SurfaceInfo {
|
||||
wl_surface: WlWeak<WlSurface>,
|
||||
cursor_sender: watch::Sender<Option<CursorInfo>>,
|
||||
panel_item: Weak<PanelItem>,
|
||||
pointer_queue: VecDeque<PointerEvent>,
|
||||
pointer_latest_event: Instant,
|
||||
keyboard_queue: VecDeque<KeyboardEvent>,
|
||||
keyboard_info: Option<KeyboardInfo>,
|
||||
}
|
||||
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 {
|
||||
wl_surface: wl_surface.downgrade(),
|
||||
cursor_sender,
|
||||
panel_item,
|
||||
pointer_queue: VecDeque::new(),
|
||||
pointer_latest_event: Instant::now(),
|
||||
keyboard_queue: VecDeque::new(),
|
||||
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 {
|
||||
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; };
|
||||
@@ -146,20 +137,18 @@ impl SurfaceInfo {
|
||||
pointer.enter(
|
||||
SERIAL_COUNTER.inc(),
|
||||
&focus,
|
||||
(pos.x as f64).clamp(0.0, focus_size.x as f64),
|
||||
(pos.y as f64).clamp(0.0, focus_size.y as f64),
|
||||
pos.x.clamp(0.0, focus_size.x as f64),
|
||||
pos.y.clamp(0.0, focus_size.y as f64),
|
||||
);
|
||||
locked = true;
|
||||
}
|
||||
(true, PointerEvent::Motion(pos)) => {
|
||||
pointer.motion(
|
||||
0,
|
||||
(pos.x as f64).clamp(0.0, focus_size.x as f64),
|
||||
(pos.y as f64).clamp(0.0, focus_size.y as f64),
|
||||
pos.x.clamp(0.0, focus_size.x 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 }) => {
|
||||
pointer.button(
|
||||
@@ -172,9 +161,7 @@ impl SurfaceInfo {
|
||||
_ => continue,
|
||||
},
|
||||
);
|
||||
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
||||
pointer.frame();
|
||||
}
|
||||
pointer.frame();
|
||||
}
|
||||
(
|
||||
true,
|
||||
@@ -187,22 +174,15 @@ impl SurfaceInfo {
|
||||
pointer.axis(0, Axis::HorizontalScroll, axis_continuous.x 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 {
|
||||
pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32);
|
||||
pointer.axis_discrete(Axis::VerticalScroll, axis_discrete.y as i32);
|
||||
}
|
||||
if let Some(axis_discrete) = axis_discrete {
|
||||
pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32);
|
||||
pointer.axis_discrete(Axis::VerticalScroll, axis_discrete.y as i32);
|
||||
}
|
||||
if pointer.version() >= wl_pointer::EVT_AXIS_STOP_SINCE
|
||||
&& axis_discrete.is_none()
|
||||
&& axis_continuous.is_none()
|
||||
{
|
||||
if axis_discrete.is_none() && axis_continuous.is_none() {
|
||||
pointer.axis_stop(0, Axis::HorizontalScroll);
|
||||
pointer.axis_stop(0, Axis::VerticalScroll);
|
||||
}
|
||||
if pointer.version() >= wl_pointer::EVT_FRAME_SINCE {
|
||||
pointer.frame();
|
||||
}
|
||||
pointer.frame();
|
||||
}
|
||||
(locked, event) => {
|
||||
warn!(locked, ?event, "Invalid pointer event!");
|
||||
@@ -213,7 +193,6 @@ impl SurfaceInfo {
|
||||
pointer.leave(SERIAL_COUNTER.inc(), &focus);
|
||||
locked = false;
|
||||
}
|
||||
self.flush();
|
||||
|
||||
locked
|
||||
}
|
||||
@@ -223,9 +202,7 @@ impl SurfaceInfo {
|
||||
|
||||
if !locked {
|
||||
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();
|
||||
}
|
||||
while let Some(event) = self.keyboard_queue.pop_front() {
|
||||
@@ -247,13 +224,12 @@ impl SurfaceInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
self.flush();
|
||||
locked
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SeatData {
|
||||
pub client: OnceCell<ClientId>,
|
||||
client: ClientId,
|
||||
global_id: OnceCell<GlobalId>,
|
||||
surfaces: Mutex<FxHashMap<ObjectId, SurfaceInfo>>,
|
||||
pointer: OnceCell<(WlPointer, Mutex<ObjectId>)>,
|
||||
@@ -261,9 +237,9 @@ pub struct SeatData {
|
||||
touch: OnceCell<WlTouch>,
|
||||
}
|
||||
impl SeatData {
|
||||
pub fn new(dh: &DisplayHandle) -> Arc<Self> {
|
||||
pub fn new(dh: &DisplayHandle, client: ClientId) -> Arc<Self> {
|
||||
let seat_data = Arc::new(SeatData {
|
||||
client: OnceCell::new(),
|
||||
client,
|
||||
global_id: OnceCell::new(),
|
||||
surfaces: Mutex::new(FxHashMap::default()),
|
||||
pointer: OnceCell::new(),
|
||||
@@ -279,14 +255,6 @@ impl SeatData {
|
||||
seat_data
|
||||
}
|
||||
|
||||
pub fn set_keymap_str(&self, keymap: &str, surfaces: Vec<WlSurface>) -> Result<()> {
|
||||
let context = xkb::Context::new(0);
|
||||
let keymap =
|
||||
Keymap::new_from_string(&context, keymap.to_string(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
|
||||
.ok_or_else(|| eyre!("Keymap is not valid"))?;
|
||||
self.set_keymap(&keymap, surfaces);
|
||||
Ok(())
|
||||
}
|
||||
pub fn set_keymap(&self, keymap: &Keymap, surfaces: Vec<WlSurface>) {
|
||||
let mut panels = self.surfaces.lock();
|
||||
let Some((_, focus)) = self.keyboard.get() else {return};
|
||||
@@ -375,13 +343,10 @@ impl SeatData {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_surface(&self, surface: &WlSurface) -> watch::Receiver<Option<CursorInfo>> {
|
||||
let (tx, rx) = watch::channel(None);
|
||||
pub fn new_surface(&self, surface: &WlSurface, panel_item: Weak<PanelItem>) {
|
||||
self.surfaces
|
||||
.lock()
|
||||
.insert(surface.id(), SurfaceInfo::new(surface, tx));
|
||||
|
||||
rx
|
||||
.insert(surface.id(), SurfaceInfo::new(surface, panel_item));
|
||||
}
|
||||
pub fn drop_surface(&self, surface: &WlSurface) {
|
||||
self.surfaces.lock().remove(&surface.id());
|
||||
@@ -408,18 +373,6 @@ impl Drop for SeatData {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CursorInfo {
|
||||
pub surface: WlWeak<WlSurface>,
|
||||
pub hotspot_x: i32,
|
||||
pub hotspot_y: i32,
|
||||
}
|
||||
impl CursorInfo {
|
||||
pub fn cursor_data(&self) -> Option<(Vector2<u32>, Vector2<i32>)> {
|
||||
let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?;
|
||||
Some((cursor_size, [self.hotspot_x, self.hotspot_y].into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl GlobalDispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
fn bind(
|
||||
_state: &mut WaylandState,
|
||||
@@ -439,8 +392,7 @@ impl GlobalDispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
}
|
||||
|
||||
fn can_view(client: Client, data: &Arc<SeatData>) -> bool {
|
||||
let Some(seat_client) = data.client.get().cloned() else {return false};
|
||||
client.id() == seat_client
|
||||
client.id() == data.client
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,9 +413,7 @@ impl Dispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
}
|
||||
wl_seat::Request::GetKeyboard { id } => {
|
||||
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())));
|
||||
}
|
||||
wl_seat::Request::GetTouch { id } => {
|
||||
@@ -475,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 {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
_resource: &WlPointer,
|
||||
request: wl_pointer::Request,
|
||||
@@ -493,8 +446,16 @@ impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
hotspot_y,
|
||||
} => {
|
||||
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| {
|
||||
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>>() {
|
||||
core_surface.set_material_offset(1);
|
||||
}
|
||||
@@ -505,12 +466,8 @@ impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
let focus = focus.lock();
|
||||
let surfaces = seat_data.surfaces.lock();
|
||||
let Some(surface_info) = surfaces.get(&focus) else {return};
|
||||
let cursor_info = surface.map(|surface| CursorInfo {
|
||||
surface: surface.downgrade(),
|
||||
hotspot_x,
|
||||
hotspot_y,
|
||||
});
|
||||
let _ = surface_info.cursor_sender.send_replace(cursor_info);
|
||||
let Some(panel_item) = surface_info.panel_item.upgrade() else {return};
|
||||
panel_item.set_cursor(surface.as_ref(), hotspot_x, hotspot_y);
|
||||
}
|
||||
wl_pointer::Request::Release => (),
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -5,9 +5,3 @@
|
||||
|
||||
// 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");
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::wayland::seat::SeatData;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::dmabuf::Dmabuf,
|
||||
egl::EGLDevice,
|
||||
renderer::{gles::GlesRenderer, ImportDma},
|
||||
},
|
||||
delegate_dmabuf, delegate_output, delegate_shm,
|
||||
@@ -24,28 +24,17 @@ use smithay::{
|
||||
wayland::{
|
||||
buffer::BufferHandler,
|
||||
compositor::{CompositorClientState, CompositorState},
|
||||
dmabuf::{
|
||||
self, DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState,
|
||||
ImportError,
|
||||
},
|
||||
dmabuf::{self, DmabufGlobal, DmabufHandler, DmabufState},
|
||||
shell::kde::decoration::KdeDecorationState,
|
||||
shm::{ShmHandler, ShmState},
|
||||
},
|
||||
};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use tracing::{info, warn};
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ClientState {
|
||||
pub compositor_state: CompositorClientState,
|
||||
pub display: Weak<Mutex<Display<WaylandState>>>,
|
||||
pub seat: Arc<SeatData>,
|
||||
}
|
||||
impl ClientState {
|
||||
pub fn flush(&self) {
|
||||
let Some(display) = self.display.upgrade() else {return};
|
||||
let _ = display.lock().flush_clients();
|
||||
}
|
||||
}
|
||||
impl ClientData for ClientState {
|
||||
fn initialized(&self, client_id: ClientId) {
|
||||
@@ -69,9 +58,11 @@ pub struct WaylandState {
|
||||
// pub xdg_activation_state: XdgActivationState,
|
||||
pub kde_decoration_state: KdeDecorationState,
|
||||
pub shm_state: ShmState,
|
||||
dmabuf_state: (DmabufState, DmabufGlobal, Option<DmabufFeedback>),
|
||||
dmabuf_tx: UnboundedSender<Dmabuf>,
|
||||
pub dmabuf_state: DmabufState,
|
||||
pub dmabuf_global: DmabufGlobal,
|
||||
pub pending_dmabufs: Vec<Dmabuf>,
|
||||
pub output: Output,
|
||||
pub seats: FxHashMap<ClientId, Arc<SeatData>>,
|
||||
}
|
||||
|
||||
impl WaylandState {
|
||||
@@ -79,51 +70,17 @@ impl WaylandState {
|
||||
display: Arc<Mutex<Display<WaylandState>>>,
|
||||
display_handle: DisplayHandle,
|
||||
renderer: &GlesRenderer,
|
||||
dmabuf_tx: UnboundedSender<Dmabuf>,
|
||||
) -> Arc<Mutex<Self>> {
|
||||
let compositor_state = CompositorState::new::<Self>(&display_handle);
|
||||
// let xdg_activation_state = XdgActivationState::new::<Self, _>(&display_handle);
|
||||
let kde_decoration_state =
|
||||
KdeDecorationState::new::<Self>(&display_handle, DecorationMode::Server);
|
||||
let shm_state = ShmState::new::<Self>(&display_handle, vec![]);
|
||||
let render_node = EGLDevice::device_for_display(renderer.egl_context().display())
|
||||
.and_then(|device| device.try_get_render_node());
|
||||
|
||||
let dmabuf_default_feedback = match render_node {
|
||||
Ok(Some(node)) => {
|
||||
let dmabuf_formats = renderer.dmabuf_formats().collect::<Vec<_>>();
|
||||
let dmabuf_default_feedback =
|
||||
DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats)
|
||||
.build()
|
||||
.unwrap();
|
||||
Some(dmabuf_default_feedback)
|
||||
}
|
||||
Ok(None) => {
|
||||
warn!("failed to query render node, dmabuf will use v3");
|
||||
None
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(?err, "failed to egl device for display, dmabuf will use v3");
|
||||
None
|
||||
}
|
||||
};
|
||||
// if we failed to build dmabuf feedback we fall back to dmabuf v3
|
||||
// Note: egl on Mesa requires either v4 or wl_drm (initialized with bind_wl_display)
|
||||
let dmabuf_state = if let Some(default_feedback) = dmabuf_default_feedback {
|
||||
let mut dmabuf_state = DmabufState::new();
|
||||
let dmabuf_global = dmabuf_state.create_global_with_default_feedback::<WaylandState>(
|
||||
&display_handle,
|
||||
&default_feedback,
|
||||
);
|
||||
(dmabuf_state, dmabuf_global, Some(default_feedback))
|
||||
} else {
|
||||
let dmabuf_formats = renderer.dmabuf_formats().collect::<Vec<_>>();
|
||||
let mut dmabuf_state = DmabufState::new();
|
||||
let dmabuf_global =
|
||||
dmabuf_state.create_global::<WaylandState>(&display_handle, dmabuf_formats);
|
||||
(dmabuf_state, dmabuf_global, None)
|
||||
};
|
||||
|
||||
let mut dmabuf_state = DmabufState::new();
|
||||
let dmabuf_global = dmabuf_state.create_global::<Self>(
|
||||
&display_handle,
|
||||
renderer.dmabuf_formats().collect::<Vec<_>>(),
|
||||
);
|
||||
let output = Output::new(
|
||||
"1x".to_owned(),
|
||||
smithay::output::PhysicalProperties {
|
||||
@@ -135,7 +92,7 @@ impl WaylandState {
|
||||
);
|
||||
let _output_global = output.create_global::<Self>(&display_handle);
|
||||
let mode = Mode {
|
||||
size: (2048, 2048).into(),
|
||||
size: (4096, 4096).into(),
|
||||
refresh: 60000,
|
||||
};
|
||||
output.change_current_state(
|
||||
@@ -162,11 +119,18 @@ impl WaylandState {
|
||||
kde_decoration_state,
|
||||
shm_state,
|
||||
dmabuf_state,
|
||||
dmabuf_tx,
|
||||
dmabuf_global,
|
||||
pending_dmabufs: Vec::new(),
|
||||
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 {
|
||||
fn drop(&mut self) {
|
||||
@@ -183,15 +147,15 @@ impl ShmHandler for WaylandState {
|
||||
}
|
||||
impl DmabufHandler for WaylandState {
|
||||
fn dmabuf_state(&mut self) -> &mut DmabufState {
|
||||
&mut self.dmabuf_state.0
|
||||
&mut self.dmabuf_state
|
||||
}
|
||||
|
||||
fn dmabuf_imported(
|
||||
&mut self,
|
||||
_global: &DmabufGlobal,
|
||||
dmabuf: Dmabuf,
|
||||
_dmabuf: Dmabuf,
|
||||
) -> Result<(), dmabuf::ImportError> {
|
||||
self.dmabuf_tx.send(dmabuf).map_err(|_| ImportError::Failed)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
delegate_dmabuf!(WaylandState);
|
||||
|
||||
@@ -15,10 +15,16 @@ use smithay::{
|
||||
},
|
||||
desktop::utils::send_frames_surface_tree,
|
||||
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},
|
||||
};
|
||||
use std::{ffi::c_void, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
sync::{Arc, Weak},
|
||||
time::Duration,
|
||||
};
|
||||
use stereokit::{
|
||||
Material, StereoKitDraw, Tex, TextureAddress, TextureFormat, TextureSample, TextureType,
|
||||
Transparency,
|
||||
@@ -37,34 +43,34 @@ impl Drop for CoreSurfaceData {
|
||||
}
|
||||
|
||||
pub struct CoreSurface {
|
||||
display: Weak<Mutex<Display<WaylandState>>>,
|
||||
pub dh: DisplayHandle,
|
||||
pub weak_surface: wayland_server::Weak<WlSurface>,
|
||||
mapped_data: Mutex<Option<CoreSurfaceData>>,
|
||||
sk_tex: OnceCell<SendWrapper<Tex>>,
|
||||
sk_mat: OnceCell<Arc<SendWrapper<Material>>>,
|
||||
material_offset: Mutex<Delta<u32>>,
|
||||
on_mapped: Box<dyn Fn() + Send + Sync>,
|
||||
on_commit: Box<dyn Fn(u32) + Send + Sync>,
|
||||
pub pending_material_applications: Registry<ModelPart>,
|
||||
}
|
||||
|
||||
impl CoreSurface {
|
||||
pub fn add_to(
|
||||
display: &Arc<Mutex<Display<WaylandState>>>,
|
||||
dh: DisplayHandle,
|
||||
surface: &WlSurface,
|
||||
on_mapped: impl Fn() + Send + Sync + 'static,
|
||||
on_commit: impl Fn(u32) + Send + Sync + 'static,
|
||||
) {
|
||||
compositor::with_states(surface, |data| {
|
||||
data.data_map.insert_if_missing_threadsafe(|| {
|
||||
CORE_SURFACES.add(CoreSurface {
|
||||
display: Arc::downgrade(display),
|
||||
dh,
|
||||
weak_surface: surface.downgrade(),
|
||||
mapped_data: Mutex::new(None),
|
||||
sk_tex: OnceCell::new(),
|
||||
sk_mat: OnceCell::new(),
|
||||
material_offset: Mutex::new(Delta::new(0)),
|
||||
on_mapped: Box::new(on_mapped) as Box<dyn Fn() + Send + Sync>,
|
||||
on_commit: Box::new(on_commit) as Box<dyn Fn(u32) + Send + Sync>,
|
||||
pending_material_applications: Registry::new(),
|
||||
})
|
||||
@@ -83,17 +89,13 @@ impl CoreSurface {
|
||||
}
|
||||
|
||||
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.sk_tex.get_or_init(|| {
|
||||
SendWrapper::new(sk.tex_create(TextureType::IMAGE_NO_MIPS, TextureFormat::RGBA32))
|
||||
});
|
||||
self.sk_mat.get_or_init(|| {
|
||||
let shader = sk.shader_create_mem(&PANEL_SHADER_BYTES).unwrap();
|
||||
// let _ = renderer.with_context(|c| unsafe {
|
||||
// shader_inject(c, &mut shader, SIMULA_VERT_STR, SIMULA_FRAG_STR)
|
||||
// });
|
||||
|
||||
let mat = sk.material_create(&shader);
|
||||
sk.material_set_texture(&mat, "diffuse", sk_tex.as_ref());
|
||||
sk.material_set_transparency(&mat, Transparency::Blend);
|
||||
@@ -119,8 +121,9 @@ impl CoreSurface {
|
||||
}
|
||||
|
||||
let mut mapped_data = self.mapped_data.lock();
|
||||
let just_mapped = mapped_data.is_none();
|
||||
self.with_states(|data| {
|
||||
// let just_mapped = mapped_data.is_none();
|
||||
// if just_mapped {
|
||||
let renderer_surface_state = data
|
||||
.data_map
|
||||
.get::<RendererSurfaceStateUserData>()
|
||||
@@ -158,15 +161,11 @@ impl CoreSurface {
|
||||
};
|
||||
*mapped_data = Some(new_mapped_data);
|
||||
});
|
||||
drop(mapped_data);
|
||||
if just_mapped {
|
||||
(self.on_mapped)();
|
||||
}
|
||||
self.apply_surface_materials();
|
||||
}
|
||||
|
||||
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(
|
||||
&wl_surface,
|
||||
@@ -181,8 +180,8 @@ impl CoreSurface {
|
||||
*self.material_offset.lock().value_mut() = material_offset;
|
||||
}
|
||||
|
||||
pub fn apply_material(&self, model_part: &Arc<ModelPart>) {
|
||||
self.pending_material_applications.add_raw(model_part)
|
||||
pub fn apply_material(&self, model_node: &Arc<ModelPart>) {
|
||||
self.pending_material_applications.add_raw(model_node)
|
||||
}
|
||||
|
||||
fn apply_surface_materials(&self) {
|
||||
@@ -207,6 +206,15 @@ impl CoreSurface {
|
||||
pub fn size(&self) -> Option<Vector2<u32>> {
|
||||
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 {
|
||||
fn drop(&mut self) {
|
||||
|
||||
@@ -1,26 +1,21 @@
|
||||
use crate::nodes::Node;
|
||||
|
||||
use super::{
|
||||
seat::{CursorInfo, KeyboardEvent, PointerEvent, SeatData},
|
||||
state::{ClientState, WaylandState},
|
||||
panel_item::{PanelItem, RecommendedState, SurfaceID},
|
||||
state::WaylandState,
|
||||
surface::CoreSurface,
|
||||
SERIAL_COUNTER,
|
||||
};
|
||||
use crate::nodes::{
|
||||
drawable::model::ModelPart,
|
||||
items::panel::{Backend, PanelItem, RecommendedState, SurfaceID},
|
||||
Message, Node,
|
||||
};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{ser::SerializeSeq, Serialize, Serializer};
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_popup::{self, XdgPopup},
|
||||
xdg_positioner::{self, Anchor, ConstraintAdjustment, Gravity, XdgPositioner},
|
||||
xdg_surface::{self, XdgSurface},
|
||||
xdg_toplevel::{self, XdgToplevel, EVT_CONFIGURE_BOUNDS_SINCE, EVT_WM_CAPABILITIES_SINCE},
|
||||
xdg_toplevel::{self, XdgToplevel, EVT_WM_CAPABILITIES_SINCE},
|
||||
xdg_wm_base::{self, XdgWmBase},
|
||||
},
|
||||
wayland_server::{
|
||||
@@ -30,14 +25,11 @@ use smithay::reexports::{
|
||||
Weak as WlWeak,
|
||||
},
|
||||
};
|
||||
use stardust_xr::schemas::flex::serialize;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use tokio::sync::watch;
|
||||
use tracing::{debug, warn};
|
||||
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
|
||||
|
||||
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn bind(
|
||||
@@ -213,7 +205,7 @@ impl Default for Geometry {
|
||||
pub struct XdgSurfaceData {
|
||||
wl_surface: WlWeak<WlSurface>,
|
||||
surface_id: SurfaceID,
|
||||
panel_item: Weak<PanelItem<XDGBackend>>,
|
||||
panel_item: Weak<PanelItem>,
|
||||
geometry: Option<Geometry>,
|
||||
}
|
||||
impl XdgSurfaceData {
|
||||
@@ -225,13 +217,13 @@ impl XdgSurfaceData {
|
||||
geometry: None,
|
||||
}
|
||||
}
|
||||
pub fn get(xdg_surface: &XdgSurface) -> Option<&Mutex<Self>> {
|
||||
xdg_surface.data::<Mutex<Self>>()
|
||||
pub fn get(xdg_surface: &XdgSurface) -> &Mutex<Self> {
|
||||
xdg_surface.data::<Mutex<Self>>().unwrap()
|
||||
}
|
||||
pub fn wl_surface(&self) -> Option<WlSurface> {
|
||||
self.wl_surface.upgrade().ok()
|
||||
pub fn wl_surface(&self) -> WlSurface {
|
||||
self.wl_surface.upgrade().unwrap()
|
||||
}
|
||||
pub fn panel_item(&self) -> Option<Arc<PanelItem<XDGBackend>>> {
|
||||
pub fn panel_item(&self) -> Option<Arc<PanelItem>> {
|
||||
self.panel_item.upgrade()
|
||||
}
|
||||
}
|
||||
@@ -261,66 +253,40 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
||||
debug!(?toplevel, ?xdg_surface, "Create XDG toplevel");
|
||||
|
||||
if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE {
|
||||
toplevel.wm_capabilities(vec![2, 3, 4]);
|
||||
toplevel.wm_capabilities(vec![]);
|
||||
}
|
||||
toplevel.configure(
|
||||
0,
|
||||
0,
|
||||
if toplevel.version() >= 2 {
|
||||
vec![5, 6, 7, 8]
|
||||
.into_iter()
|
||||
.flat_map(u32::to_ne_bytes)
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
);
|
||||
toplevel.configure(0, 0, vec![]);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
|
||||
let client_credentials = client.get_credentials(&state.display_handle).ok();
|
||||
let Some(seat_data) = client.get_data::<ClientState>().map(|s| s.seat.clone()) else {return};
|
||||
let Some(wl_surface) = xdg_surface_data.lock().wl_surface() else {return};
|
||||
let seat_data = state.seats.get(&client.id()).unwrap().clone();
|
||||
let toplevel_weak = toplevel.downgrade();
|
||||
CoreSurface::add_to(
|
||||
&state.display,
|
||||
state.display_handle.clone(),
|
||||
&wl_surface,
|
||||
{
|
||||
let toplevel = toplevel.downgrade();
|
||||
move || {
|
||||
let toplevel = toplevel.upgrade().unwrap();
|
||||
&xdg_surface_data.lock().wl_surface(),
|
||||
move |c| match c {
|
||||
0 => {
|
||||
let toplevel = toplevel_weak.upgrade().unwrap();
|
||||
let toplevel_data = ToplevelData::get(&toplevel);
|
||||
let Some(xdg_surface) = toplevel_data.lock().xdg_surface() else {return};
|
||||
let Some(xdg_surface_data) = XdgSurfaceData::get(&xdg_surface) else {return};
|
||||
let xdg_surface = toplevel_data.lock().xdg_surface();
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface);
|
||||
let wl_surface = xdg_surface_data.lock().wl_surface();
|
||||
|
||||
xdg_surface_data.lock().surface_id = SurfaceID::Toplevel;
|
||||
let Some(backend) = XDGBackend::create(toplevel.clone(), seat_data.clone()) else {return};
|
||||
let (node, panel_item) = PanelItem::create(
|
||||
Box::new(backend),
|
||||
client_credentials.map(|c| c.pid),
|
||||
toplevel.clone(),
|
||||
wl_surface.clone(),
|
||||
client_credentials,
|
||||
seat_data.clone(),
|
||||
);
|
||||
toplevel_data.lock().panel_item_node.replace(node);
|
||||
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
||||
}
|
||||
},
|
||||
{
|
||||
let toplevel = toplevel.downgrade();
|
||||
move |_| {
|
||||
let toplevel = toplevel.upgrade().unwrap();
|
||||
_ => {
|
||||
let toplevel = toplevel_weak.upgrade().unwrap();
|
||||
let toplevel_data = ToplevelData::get(&toplevel);
|
||||
let Some(panel_item) = toplevel_data.lock().panel_item() else {
|
||||
let Some(xdg_surface) = toplevel_data.lock().xdg_surface() else {return};
|
||||
// if the wayland toplevel isn't mapped, hammer it again with a configure until it cooperates
|
||||
toplevel.configure(
|
||||
0,
|
||||
0,
|
||||
if toplevel.version() >= 2 {
|
||||
vec![5, 6, 7, 8].into_iter().flat_map(u32::to_ne_bytes).collect()
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
return
|
||||
};
|
||||
let panel_item = toplevel_data.lock().panel_item().unwrap();
|
||||
panel_item.commit_toplevel();
|
||||
}
|
||||
},
|
||||
@@ -356,28 +322,32 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
||||
xdg_surface_data.lock().surface_id = SurfaceID::Popup(uid);
|
||||
let panel_item = parent_data.panel_item().unwrap();
|
||||
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
||||
|
||||
panel_item.seat_data.new_surface(
|
||||
&xdg_surface_data.lock().wl_surface(),
|
||||
Arc::downgrade(&panel_item),
|
||||
);
|
||||
debug!(?xdg_popup, ?xdg_surface, "Create XDG popup");
|
||||
|
||||
let xdg_surface = xdg_surface.downgrade();
|
||||
let xdg_popup = xdg_popup.downgrade();
|
||||
CoreSurface::add_to(
|
||||
&state.display,
|
||||
state.display_handle.clone(),
|
||||
&xdg_surface_data.lock().wl_surface.upgrade().unwrap(),
|
||||
move || {
|
||||
let xdg_popup = xdg_popup.upgrade().unwrap();
|
||||
let Some(popup_data) = PopupData::get(&xdg_popup) else {return};
|
||||
let popup_data = popup_data.lock();
|
||||
// panel_item.commit_popup(popup_data);
|
||||
panel_item
|
||||
.backend
|
||||
.new_popup(&panel_item, &xdg_popup, &*popup_data);
|
||||
},
|
||||
move |commit_count| {
|
||||
if commit_count == 0 {
|
||||
xdg_surface
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.configure(SERIAL_COUNTER.inc())
|
||||
move |commit_count| match commit_count {
|
||||
0 => xdg_surface
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.configure(SERIAL_COUNTER.inc()),
|
||||
c => {
|
||||
let xdg_popup = xdg_popup.upgrade().unwrap();
|
||||
let popup_data = PopupData::get(&xdg_popup);
|
||||
let popup_data = popup_data.lock();
|
||||
// panel_item.commit_popup(popup_data);
|
||||
if c == 1 {
|
||||
panel_item.new_popup(&xdg_popup, &*popup_data);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -442,22 +412,21 @@ impl ToplevelData {
|
||||
toplevel.data::<Mutex<ToplevelData>>().unwrap()
|
||||
}
|
||||
|
||||
pub fn xdg_surface(&self) -> Option<XdgSurface> {
|
||||
self.xdg_surface.upgrade().ok()
|
||||
pub fn xdg_surface(&self) -> XdgSurface {
|
||||
self.xdg_surface.upgrade().unwrap()
|
||||
}
|
||||
fn panel_item(&self) -> Option<Arc<PanelItem<XDGBackend>>> {
|
||||
let xdg_surface = self.xdg_surface()?;
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface)?.lock();
|
||||
fn panel_item(&self) -> Option<Arc<PanelItem>> {
|
||||
let xdg_surface = self.xdg_surface();
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
|
||||
xdg_surface_data.panel_item()
|
||||
}
|
||||
}
|
||||
impl Serialize for ToplevelData {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let Some(xdg_surface) = self.xdg_surface() else {return serializer.serialize_none()};
|
||||
let Some(xdg_surface_data) = XdgSurfaceData::get(&xdg_surface) else {return serializer.serialize_none()};
|
||||
let xdg_surface_data = xdg_surface_data.lock();
|
||||
let xdg_surface = self.xdg_surface();
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
|
||||
let geometry = xdg_surface_data.geometry.clone();
|
||||
let Some(wl_surface) = xdg_surface_data.wl_surface() else {return serde_error::<S>("Wayland surface not found")};
|
||||
let wl_surface = xdg_surface_data.wl_surface();
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {return serde_error::<S>("Core surface not found")};
|
||||
let Some(size) = core_surface.size() else {return serializer.serialize_none()};
|
||||
let geometry = geometry.unwrap_or_else(|| Geometry {
|
||||
@@ -521,7 +490,7 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||
}
|
||||
xdg_toplevel::Request::Move { seat, serial } => {
|
||||
debug!(?xdg_toplevel, ?seat, serial, "XDG Toplevel move request");
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Move);
|
||||
}
|
||||
xdg_toplevel::Request::Resize {
|
||||
@@ -529,7 +498,7 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||
serial,
|
||||
edges,
|
||||
} => {
|
||||
let WEnum::Value(edges) = edges else {return};
|
||||
let WEnum::Value(edges) = edges else { return };
|
||||
debug!(
|
||||
?xdg_toplevel,
|
||||
?seat,
|
||||
@@ -537,7 +506,7 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||
?edges,
|
||||
"XDG Toplevel resize request"
|
||||
);
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Resize(edges as u32));
|
||||
}
|
||||
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
||||
@@ -551,29 +520,29 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||
.then_some(Vector2::from([width as u32, height as u32]));
|
||||
}
|
||||
xdg_toplevel::Request::SetMaximized => {
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(true));
|
||||
}
|
||||
xdg_toplevel::Request::UnsetMaximized => {
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(false));
|
||||
}
|
||||
xdg_toplevel::Request::SetFullscreen { output: _ } => {
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
||||
}
|
||||
xdg_toplevel::Request::UnsetFullscreen => {
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
||||
}
|
||||
xdg_toplevel::Request::SetMinimized => {
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Minimize);
|
||||
}
|
||||
xdg_toplevel::Request::Destroy => {
|
||||
debug!(?xdg_toplevel, "Destroy XDG Toplevel");
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
panel_item.backend.on_drop();
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.on_drop();
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@@ -603,25 +572,21 @@ impl PopupData {
|
||||
xdg_surface: xdg_surface.downgrade(),
|
||||
}
|
||||
}
|
||||
pub fn get(popup: &XdgPopup) -> Option<&Mutex<Self>> {
|
||||
popup.data::<Mutex<Self>>()
|
||||
pub fn get(popup: &XdgPopup) -> &Mutex<Self> {
|
||||
popup.data::<Mutex<Self>>().unwrap()
|
||||
}
|
||||
pub fn xdg_surface(&self) -> Option<XdgSurface> {
|
||||
self.xdg_surface.upgrade().ok()
|
||||
pub fn xdg_surface(&self) -> XdgSurface {
|
||||
self.xdg_surface.upgrade().unwrap()
|
||||
}
|
||||
|
||||
fn panel_item(&self) -> Option<Arc<PanelItem<XDGBackend>>> {
|
||||
XdgSurfaceData::get(&self.xdg_surface()?)?
|
||||
.lock()
|
||||
.panel_item()
|
||||
fn panel_item(&self) -> Option<Arc<PanelItem>> {
|
||||
XdgSurfaceData::get(&self.xdg_surface()).lock().panel_item()
|
||||
}
|
||||
// fn get_parent(&self) -> Option<XdgSurface> {
|
||||
// self.parent.as_ref()?.upgrade().ok()
|
||||
// }
|
||||
pub fn wl_surface(&self) -> Option<WlSurface> {
|
||||
XdgSurfaceData::get(&self.xdg_surface()?)?
|
||||
.lock()
|
||||
.wl_surface()
|
||||
pub fn wl_surface(&self) -> WlSurface {
|
||||
XdgSurfaceData::get(&self.xdg_surface()).lock().wl_surface()
|
||||
}
|
||||
|
||||
pub fn positioner_data(&self) -> Option<PositionerData> {
|
||||
@@ -676,8 +641,8 @@ impl Dispatch<XdgPopup, Mutex<PopupData>, WaylandState> for WaylandState {
|
||||
debug!(?xdg_popup, ?positioner, token, "XDG popup reposition");
|
||||
data.positioner = positioner;
|
||||
let Some(panel_item) = data.panel_item() else {return};
|
||||
|
||||
panel_item.backend.reposition_popup(&panel_item, &*data)
|
||||
panel_item.reposition_popup(&*data);
|
||||
// xdg_popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
}
|
||||
xdg_popup::Request::Destroy => {
|
||||
let data = data.lock();
|
||||
@@ -699,260 +664,6 @@ impl Dispatch<XdgPopup, Mutex<PopupData>, WaylandState> for WaylandState {
|
||||
) {
|
||||
let data = data.lock();
|
||||
let Some(panel_item) = data.panel_item() else {return};
|
||||
panel_item.backend.drop_popup(&panel_item, &data.uid);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XDGBackend {
|
||||
toplevel: WlWeak<XdgToplevel>,
|
||||
toplevel_wl_surface: WlWeak<WlSurface>,
|
||||
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
|
||||
cursor: watch::Receiver<Option<CursorInfo>>,
|
||||
pub seat: Arc<SeatData>,
|
||||
pointer_grab: Mutex<Option<SurfaceID>>,
|
||||
keyboard_grab: Mutex<Option<SurfaceID>>,
|
||||
}
|
||||
impl XDGBackend {
|
||||
pub fn create(toplevel: XdgToplevel, seat: Arc<SeatData>) -> Option<Self> {
|
||||
let toplevel_wl_surface =
|
||||
XdgSurfaceData::get(&ToplevelData::get(&toplevel).lock().xdg_surface()?)?
|
||||
.lock()
|
||||
.wl_surface()?
|
||||
.downgrade();
|
||||
|
||||
let cursor = seat.new_surface(&toplevel_wl_surface.upgrade().ok()?);
|
||||
Some(XDGBackend {
|
||||
toplevel: toplevel.downgrade(),
|
||||
toplevel_wl_surface,
|
||||
popups: Mutex::new(FxHashMap::default()),
|
||||
cursor,
|
||||
seat,
|
||||
pointer_grab: Mutex::new(None),
|
||||
keyboard_grab: Mutex::new(None),
|
||||
})
|
||||
}
|
||||
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
||||
match id {
|
||||
SurfaceID::Cursor => self.cursor.borrow().as_ref()?.surface.upgrade().ok(),
|
||||
SurfaceID::Toplevel => self.toplevel_wl_surface(),
|
||||
SurfaceID::Popup(popup) => {
|
||||
let popups = self.popups.lock();
|
||||
let popup = popups.get(popup)?.upgrade().ok()?;
|
||||
let wl_surface = PopupData::get(&popup)?.lock().wl_surface();
|
||||
wl_surface
|
||||
}
|
||||
}
|
||||
}
|
||||
fn toplevel(&self) -> Option<XdgToplevel> {
|
||||
self.toplevel.upgrade().ok()
|
||||
}
|
||||
fn toplevel_xdg_surface(&self) -> Option<XdgSurface> {
|
||||
let toplevel = self.toplevel()?;
|
||||
let data = ToplevelData::get(&toplevel).lock();
|
||||
data.xdg_surface()
|
||||
}
|
||||
fn toplevel_wl_surface(&self) -> Option<WlSurface> {
|
||||
self.toplevel_wl_surface.upgrade().ok()
|
||||
}
|
||||
fn input_surfaces(&self) -> Vec<WlSurface> {
|
||||
let mut surfaces = self
|
||||
.toplevel_wl_surface()
|
||||
.map(|s| vec![s])
|
||||
.unwrap_or_default();
|
||||
surfaces.extend(self.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();
|
||||
xdg_surface_data.wl_surface()
|
||||
}));
|
||||
surfaces
|
||||
}
|
||||
|
||||
pub fn new_popup(
|
||||
&self,
|
||||
panel_item: &PanelItem<XDGBackend>,
|
||||
popup: &XdgPopup,
|
||||
data: &PopupData,
|
||||
) {
|
||||
let uid = data.uid.clone();
|
||||
|
||||
self.popups.lock().insert(uid.clone(), popup.downgrade());
|
||||
|
||||
let Some(node) = panel_item.node() else {return};
|
||||
let Ok(message) = serialize(&(&uid, data)) else {return};
|
||||
let _ = node.send_remote_signal("new_popup", message);
|
||||
}
|
||||
pub fn reposition_popup(&self, panel_item: &PanelItem<XDGBackend>, popup_state: &PopupData) {
|
||||
let Some(node) = panel_item.node() else {return};
|
||||
|
||||
let _ = node.send_remote_signal(
|
||||
"reposition_popup",
|
||||
serialize(popup_state.positioner_data().unwrap()).unwrap(),
|
||||
);
|
||||
}
|
||||
pub fn drop_popup(&self, panel_item: &PanelItem<XDGBackend>, uid: &str) {
|
||||
'seat_drop: {
|
||||
let Some(popup) = self
|
||||
.popups
|
||||
.lock()
|
||||
.remove(uid) else {break 'seat_drop};
|
||||
let Some(popup) = popup.upgrade().ok() else {break 'seat_drop};
|
||||
let Some(popup) = popup.data::<Arc<PopupData>>().cloned() else {break 'seat_drop};
|
||||
let Some(wl_surface) = popup.wl_surface() else {break 'seat_drop};
|
||||
self.seat.drop_surface(&wl_surface);
|
||||
}
|
||||
|
||||
let Some(node) = panel_item.node() else {return};
|
||||
let Ok(message) = serialize(uid) else {return};
|
||||
let _ = node.send_remote_signal("drop_popup", message);
|
||||
}
|
||||
|
||||
fn popups_data(&self) -> Vec<PopupData> {
|
||||
self.popups
|
||||
.lock()
|
||||
.values()
|
||||
.filter_map(|v| Some(v.upgrade().ok()?.data::<Mutex<PopupData>>()?.lock().clone()))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub fn on_drop(&self) {
|
||||
let Some(toplevel) = self.toplevel_wl_surface() else {return};
|
||||
self.seat.drop_surface(&toplevel);
|
||||
|
||||
debug!("Dropped panel item gracefully");
|
||||
}
|
||||
|
||||
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 XDGBackend {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||
let toplevel_state = self
|
||||
.toplevel()
|
||||
.map(|t| ToplevelData::get(&t).lock().clone());
|
||||
|
||||
let pointer_grab = self.pointer_grab.lock().clone();
|
||||
let keyboard_grab = self.keyboard_grab.lock().clone();
|
||||
|
||||
Ok(serialize((
|
||||
id,
|
||||
(
|
||||
self.cursor.borrow().as_ref().and_then(|c| c.cursor_data()),
|
||||
toplevel_state,
|
||||
self.popups_data(),
|
||||
pointer_grab,
|
||||
keyboard_grab,
|
||||
),
|
||||
))?
|
||||
.into())
|
||||
}
|
||||
fn serialize_toplevel(&self) -> Result<Message> {
|
||||
let toplevel = self
|
||||
.toplevel()
|
||||
.ok_or_else(|| eyre!("Toplevel does not exist"))?;
|
||||
let state = ToplevelData::get(&toplevel);
|
||||
let data = serialize(&state.lock().clone())?;
|
||||
Ok(data.into())
|
||||
}
|
||||
|
||||
fn set_toplevel_capabilities(&self, capabilities: Vec<u8>) {
|
||||
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||
let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
||||
|
||||
if xdg_toplevel.version() < EVT_WM_CAPABILITIES_SINCE {
|
||||
return;
|
||||
}
|
||||
xdg_toplevel.wm_capabilities(capabilities);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
self.flush_client();
|
||||
}
|
||||
|
||||
fn configure_toplevel(
|
||||
&self,
|
||||
size: Option<Vector2<u32>>,
|
||||
states: Vec<u32>,
|
||||
bounds: Option<Vector2<u32>>,
|
||||
) {
|
||||
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||
let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
||||
debug!(?size, ?states, ?bounds, "Configure toplevel info");
|
||||
if let Some(bounds) = bounds {
|
||||
if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE {
|
||||
xdg_toplevel.configure_bounds(bounds.x as i32, bounds.y as i32);
|
||||
}
|
||||
}
|
||||
let size = size.unwrap_or(Vector2::from([0; 2]));
|
||||
xdg_toplevel.configure(
|
||||
size.x as i32,
|
||||
size.y as i32,
|
||||
states
|
||||
.into_iter()
|
||||
.flat_map(|state| state.to_ne_bytes())
|
||||
.collect(),
|
||||
);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
self.flush_client();
|
||||
}
|
||||
|
||||
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_set_keymap(&self, keymap: &str) -> Result<()> {
|
||||
let context = xkb::Context::new(0);
|
||||
let keymap =
|
||||
Keymap::new_from_string(&context, keymap.to_string(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
|
||||
.ok_or_else(|| eyre!("Keymap is not valid"))?;
|
||||
self.seat.set_keymap(&keymap, self.input_surfaces());
|
||||
Ok(())
|
||||
}
|
||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||
self.seat.keyboard_event(
|
||||
&surface,
|
||||
KeyboardEvent::Key {
|
||||
key,
|
||||
state: if state { 1 } else { 0 },
|
||||
},
|
||||
)
|
||||
panel_item.drop_popup(&data.uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,398 +0,0 @@
|
||||
use super::{
|
||||
seat::{KeyboardEvent, PointerEvent, SeatData},
|
||||
state::ClientState,
|
||||
xdg_shell::PopupData,
|
||||
};
|
||||
use crate::{
|
||||
nodes::{
|
||||
drawable::model::ModelPart,
|
||||
items::panel::{Backend, PanelItem, RecommendedState, SurfaceID},
|
||||
Message,
|
||||
},
|
||||
wayland::surface::CoreSurface,
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use mint::Vector2;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use smithay::{
|
||||
reexports::{
|
||||
calloop::{EventLoop, LoopSignal},
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource, WEnum},
|
||||
x11rb::protocol::xproto::Window,
|
||||
},
|
||||
utils::{Logical, Rectangle},
|
||||
wayland::compositor,
|
||||
xwayland::{
|
||||
xwm::{Reorder, ResizeEdge, XwmId},
|
||||
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
|
||||
},
|
||||
};
|
||||
use stardust_xr::schemas::flex::serialize;
|
||||
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();
|
||||
|
||||
tokio::task::spawn_blocking(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 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 (_node, 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.commit_toplevel();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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.recommend_toplevel_state(RecommendedState::Move);
|
||||
}
|
||||
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");
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Resize(
|
||||
WEnum::Value(match resize_edge {
|
||||
ResizeEdge::Top => xdg_toplevel::ResizeEdge::Top,
|
||||
ResizeEdge::Bottom => xdg_toplevel::ResizeEdge::Bottom,
|
||||
ResizeEdge::Left => xdg_toplevel::ResizeEdge::Left,
|
||||
ResizeEdge::TopLeft => xdg_toplevel::ResizeEdge::TopLeft,
|
||||
ResizeEdge::BottomLeft => xdg_toplevel::ResizeEdge::BottomLeft,
|
||||
ResizeEdge::Right => xdg_toplevel::ResizeEdge::Right,
|
||||
ResizeEdge::TopRight => xdg_toplevel::ResizeEdge::TopRight,
|
||||
ResizeEdge::BottomRight => xdg_toplevel::ResizeEdge::BottomRight,
|
||||
})
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
|
||||
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(true));
|
||||
}
|
||||
fn unmaximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(false));
|
||||
}
|
||||
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
||||
}
|
||||
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
||||
}
|
||||
fn minimize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Minimize);
|
||||
}
|
||||
}
|
||||
|
||||
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::Popup(_) => 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 serialize_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 configure_toplevel(
|
||||
&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 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_set_keymap(&self, keymap: &str) -> Result<()> {
|
||||
self.seat.set_keymap_str(
|
||||
&keymap,
|
||||
if let Some(toplevel) = self.toplevel.wl_surface() {
|
||||
vec![toplevel]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
)
|
||||
}
|
||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||
self.seat.keyboard_event(
|
||||
&surface,
|
||||
KeyboardEvent::Key {
|
||||
key,
|
||||
state: if state { 1 } else { 0 },
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user