refactor(items): codegen prototocol

This commit is contained in:
Nova
2024-05-30 00:34:29 -04:00
parent eda50b7d51
commit 5f9d9d4714
12 changed files with 432 additions and 591 deletions

8
Cargo.lock generated
View File

@@ -880,9 +880,9 @@ checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "flatbuffers"
version = "23.5.26"
version = "24.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dac53e22462d78c16d64a1cd22371b54cc3fe94aa15e7886a2fa6e5d1ab8640"
checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f"
dependencies = [
"bitflags 1.3.2",
"rustc_version",
@@ -2483,7 +2483,7 @@ checksum = "2f2b15926089e5526bb2dd738a2eb0e59034356e06eb71e1cd912358c0e62c4d"
[[package]]
name = "stardust-xr"
version = "0.45.0"
source = "git+https://github.com/StardustXR/core.git#6ee323df1a1e76666609c1ebfd79f3390ce43c29"
source = "git+https://github.com/StardustXR/core.git?branch=dev#47208187ffdb00627fabbb3af2bd0a12a6208194"
dependencies = [
"cluFlock",
"color-rs",
@@ -2503,7 +2503,7 @@ dependencies = [
[[package]]
name = "stardust-xr-schemas"
version = "1.5.3"
source = "git+https://github.com/StardustXR/core.git#6ee323df1a1e76666609c1ebfd79f3390ce43c29"
source = "git+https://github.com/StardustXR/core.git?branch=dev#47208187ffdb00627fabbb3af2bd0a12a6208194"
dependencies = [
"flatbuffers",
"flexbuffers",

View File

@@ -99,11 +99,7 @@ optional = true
[dependencies.stardust-xr]
git = "https://github.com/StardustXR/core.git"
branch = "dev"
[dependencies.stardust-xr-server-codegen]
path = "codegen"
# [patch.crates-io.stereokit]
# path = "../stereokit-rs"
# [patch.crates-io.stereokit-sys]
# path = "../stereokit-sys"

View File

@@ -15,3 +15,4 @@ split-iter = "0.1.0"
[dependencies.stardust-xr-schemas]
git = "https://github.com/StardustXR/core.git"
branch = "dev"

View File

@@ -40,6 +40,18 @@ pub fn codegen_drawable_protocol(_input: proc_macro::TokenStream) -> proc_macro:
pub fn codegen_input_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
codegen_protocol(INPUT_PROTOCOL)
}
#[proc_macro]
pub fn codegen_item_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
codegen_protocol(ITEM_PROTOCOL)
}
#[proc_macro]
pub fn codegen_item_camera_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
codegen_protocol(ITEM_CAMERA_PROTOCOL)
}
#[proc_macro]
pub fn codegen_item_panel_protocol(_input: proc_macro::TokenStream) -> proc_macro::TokenStream {
codegen_protocol(ITEM_PANEL_PROTOCOL)
}
fn codegen_protocol(protocol: &'static str) -> proc_macro::TokenStream {
let protocol = Protocol::parse(protocol).unwrap();
@@ -457,13 +469,15 @@ fn generate_argument_decl(argument: &Argument, owned_values: bool) -> TokenStrea
}
fn argument_type_option_name(argument_type: &ArgumentType) -> String {
match argument_type {
ArgumentType::Empty => "Empty".to_string(),
ArgumentType::Bool => "Bool".to_string(),
ArgumentType::Int => "Int".to_string(),
ArgumentType::UInt => "UInt".to_string(),
ArgumentType::Float => "Float".to_string(),
ArgumentType::Vec2 => "Vec2".to_string(),
ArgumentType::Vec3 => "Vec3".to_string(),
ArgumentType::Vec2(_) => "Vec2".to_string(),
ArgumentType::Vec3(_) => "Vec3".to_string(),
ArgumentType::Quat => "Quat".to_string(),
ArgumentType::Mat4 => "Mat4".to_string(),
ArgumentType::Color => "Color".to_string(),
ArgumentType::String => "String".to_string(),
ArgumentType::Bytes => "Bytes".to_string(),
@@ -483,13 +497,21 @@ fn generate_argument_type(
owned: bool,
) -> TokenStream {
let _type = match argument_type {
ArgumentType::Empty => quote!(()),
ArgumentType::Bool => quote!(bool),
ArgumentType::Int => quote!(i32),
ArgumentType::UInt => quote!(u32),
ArgumentType::Float => quote!(f32),
ArgumentType::Vec2 => quote!(mint::Vector2<f32>),
ArgumentType::Vec3 => quote!(mint::Vector3<f32>),
ArgumentType::Quat => quote!(mint::Quaternion<f32>),
ArgumentType::Vec2(t) => {
let t = generate_argument_type(&t, false, true);
quote!(stardust_xr::values::Vector2<#t>)
}
ArgumentType::Vec3(t) => {
let t = generate_argument_type(&t, false, true);
quote!(stardust_xr::values::Vector3<#t>)
}
ArgumentType::Quat => quote!(stardust_xr::values::Quaternion),
ArgumentType::Mat4 => quote!(stardust_xr::values::Mat4),
ArgumentType::Color => quote!(stardust_xr::values::Color),
ArgumentType::Bytes => {
if !owned {
@@ -517,9 +539,9 @@ fn generate_argument_type(
let t = generate_argument_type(&t, false, true);
if !owned {
quote!(&rustc_hash::FxHashMap<String, #t>)
quote!(&stardust_xr::values::Map<String, #t>)
} else {
quote!(rustc_hash::FxHashMap<String, #t>)
quote!(stardust_xr::values::Map<String, #t>)
}
}
ArgumentType::Datamap => {

View File

@@ -109,8 +109,9 @@ impl Client {
drawable::create_interface(&client)?;
audio::create_interface(&client)?;
data::create_interface(&client)?;
items::create_interface(&client)?;
input::create_interface(&client)?;
items::camera::create_interface(&client)?;
items::panel::create_interface(&client)?;
client
.root

View File

@@ -297,7 +297,3 @@ impl FieldInterfaceAspect for FieldInterface {
Ok(())
}
}
pub fn find_field(client: &Client, path: &str) -> Result<Arc<Field>> {
client.get_node("Field", path)?.get_aspect::<Field>()
}

View File

@@ -1,26 +1,26 @@
use super::{Item, ItemType};
use super::{create_item_acceptor_flex, register_item_ui_flex, Item, ItemInterface, ItemType};
use crate::{
core::{
client::{Client, INTERNAL_CLIENT},
registry::Registry,
scenegraph::MethodResponseSender,
},
create_interface,
nodes::{
drawable::{model::ModelPart, shaders::UNLIT_SHADER_BYTES},
items::TypeInfo,
spatial::{parse_transform, Spatial, Transform},
spatial::{Spatial, Transform},
Message, Node,
},
};
use color_eyre::eyre::{bail, eyre, Result};
use glam::Mat4;
use lazy_static::lazy_static;
use mint::{RowMatrix4, Vector2};
use mint::{ColumnMatrix4, Vector2};
use nanoid::nanoid;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use send_wrapper::SendWrapper;
use serde::Deserialize;
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::sync::Arc;
use stereokit_rust::{
@@ -33,6 +33,7 @@ use stereokit_rust::{
};
use tracing::error;
stardust_xr_server_codegen::codegen_item_camera_protocol!();
lazy_static! {
pub(super) static ref ITEM_TYPE_INFO_CAMERA: TypeInfo = TypeInfo {
type_name: "camera",
@@ -42,6 +43,9 @@ lazy_static! {
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
new_acceptor_fn: |node, uid, acceptor, acceptor_field| {
let _ = camera_item_ui_client::create_acceptor(node, uid, acceptor, acceptor_field);
}
};
}
@@ -114,8 +118,11 @@ impl CameraItem {
Ok(())
}
pub fn serialize_start_data(&self, id: &str) -> Result<Message> {
Ok(serialize(id)?.into())
pub fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
let _ = camera_item_ui_client::create_item(node, uid, item);
}
pub fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
let _ = camera_item_acceptor_client::capture_item(node, uid, item);
}
pub fn update(&self, token: &MainThreadToken) {
@@ -169,34 +176,55 @@ pub fn update(token: &MainThreadToken) {
}
}
pub(super) fn create_camera_item_flex(
_node: Arc<Node>,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)]
struct CreateCameraItemInfo<'a> {
name: &'a str,
parent_path: &'a str,
create_interface!(ItemInterface, ItemCameraInterfaceAspect, "/item/camera");
impl ItemCameraInterfaceAspect for ItemInterface {
#[doc = "Create a camera item at a specific location"]
fn create_camera_item(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
parent: Arc<Node>,
transform: Transform,
proj_matrix: RowMatrix4<f32>,
proj_matrix: ColumnMatrix4<f32>,
px_size: Vector2<u32>,
}
let info: CreateCameraItemInfo = deserialize(message.as_ref())?;
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_CAMERA.type_name);
let space = calling_client
.get_node("Spatial parent", info.parent_path)?
.get_aspect::<Spatial>()?;
let transform = parse_transform(info.transform, true, true, false);
) -> Result<()> {
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_CAMERA.type_name);
let space = parent.get_aspect::<Spatial>()?;
let transform = transform.to_mat4(true, true, false);
let node = Node::create_parent_name(&INTERNAL_CLIENT, &parent_name, info.name, false)
.add_to_scenegraph()?;
Spatial::add_to(&node, None, transform * space.global_transform(), false);
CameraItem::add_to(&node, info.proj_matrix.into(), info.px_size);
node.get_aspect::<Item>().unwrap().make_alias_named(
&calling_client,
&parent_name,
info.name,
)?;
Ok(())
let node = Node::create_parent_name(&INTERNAL_CLIENT, &parent_name, &name, false)
.add_to_scenegraph()?;
Spatial::add_to(&node, None, transform * space.global_transform(), false);
CameraItem::add_to(&node, proj_matrix.into(), px_size);
node.get_aspect::<Item>().unwrap().make_alias_named(
&calling_client,
&parent_name,
&name,
)?;
Ok(())
}
#[doc = "Register this client to manage camera items and create default 3D UI for them."]
fn register_camera_item_ui(_node: Arc<Node>, calling_client: Arc<Client>) -> Result<()> {
register_item_ui_flex(calling_client, &ITEM_TYPE_INFO_CAMERA)
}
#[doc = "Create an item acceptor to allow temporary ownership of a given type of item. Creates a node at `/item/camera/acceptor/<name>`."]
fn create_camera_item_acceptor(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
parent: Arc<Node>,
transform: Transform,
field: Arc<Node>,
) -> Result<()> {
create_item_acceptor_flex(
calling_client,
name,
parent,
transform,
&ITEM_TYPE_INFO_CAMERA,
field,
)
}
}

View File

@@ -1,97 +0,0 @@
use super::{Item, ItemType};
use crate::{
core::{
client::{Client, INTERNAL_CLIENT},
registry::Registry,
scenegraph::MethodResponseSender,
},
nodes::{
items::TypeInfo,
spatial::{parse_transform, Spatial, Transform},
Message, Node,
},
};
use color_eyre::eyre::{eyre, Result};
use lazy_static::lazy_static;
use nanoid::nanoid;
use serde::Deserialize;
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::sync::Arc;
lazy_static! {
pub(super) static ref ITEM_TYPE_INFO_ENVIRONMENT: TypeInfo = TypeInfo {
type_name: "environment",
aliased_local_signals: vec!["apply_sky_tex", "apply_sky_light"],
aliased_local_methods: vec![],
aliased_remote_signals: vec![],
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
};
}
pub struct EnvironmentItem {
path: String,
}
impl EnvironmentItem {
pub fn add_to(node: &Arc<Node>, path: String) {
Item::add_to(
node,
nanoid!(),
&ITEM_TYPE_INFO_ENVIRONMENT,
ItemType::Environment(EnvironmentItem { path }),
);
node.add_local_method("get_path", EnvironmentItem::get_path_flex);
}
fn get_path_flex(
node: Arc<Node>,
_calling_client: Arc<Client>,
_message: Message,
response: MethodResponseSender,
) {
response.wrap_sync(move || {
let ItemType::Environment(environment_item) =
&node.get_aspect::<Item>().unwrap().specialization
else {
return Err(eyre!("Wrong item type?"));
};
Ok(serialize(environment_item.path.as_str())?.into())
});
}
pub fn serialize_start_data(&self, id: &str) -> Result<Message> {
Ok(serialize((id, self.path.as_str()))?.into())
}
}
pub(super) fn create_environment_item_flex(
_node: Arc<Node>,
calling_client: Arc<Client>,
message: Message,
) -> Result<()> {
#[derive(Deserialize)]
struct CreateEnvironmentItemInfo<'a> {
name: &'a str,
parent_path: &'a str,
transform: Transform,
item_data: String,
}
let info: CreateEnvironmentItemInfo = deserialize(message.as_ref())?;
let parent_name = format!("/item/{}/item", ITEM_TYPE_INFO_ENVIRONMENT.type_name);
let space = calling_client
.get_node("Spatial parent", info.parent_path)?
.get_aspect::<Spatial>()?;
let transform = parse_transform(info.transform, true, true, false);
let node = Node::create_parent_name(&INTERNAL_CLIENT, &parent_name, info.name, false)
.add_to_scenegraph()?;
Spatial::add_to(&node, None, transform * space.global_transform(), false);
EnvironmentItem::add_to(&node, info.item_data);
node.get_aspect::<Item>().unwrap().make_alias_named(
&calling_client,
&parent_name,
info.name,
)?;
Ok(())
}

View File

@@ -1,30 +1,28 @@
pub mod camera;
mod environment;
pub mod panel;
use self::camera::CameraItem;
use self::environment::{EnvironmentItem, ITEM_TYPE_INFO_ENVIRONMENT};
use self::panel::{PanelItemTrait, ITEM_TYPE_INFO_PANEL};
use self::panel::PanelItemTrait;
use super::fields::Field;
use super::spatial::{parse_transform, Spatial};
use super::spatial::Spatial;
use super::{Alias, Aspect, Message, 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;
use crate::nodes::spatial::Transform;
use color_eyre::eyre::{ensure, eyre, Result};
use color_eyre::eyre::{ensure, 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;
use std::hash::Hash;
use std::sync::{Arc, Weak};
stardust_xr_server_codegen::codegen_item_protocol!();
lazy_static! {
static ref ITEM_ALIAS_LOCAL_SIGNALS: Vec<&'static str> = vec![
"get_bounds",
@@ -68,6 +66,8 @@ pub struct TypeInfo {
pub ui: Mutex<Weak<ItemUI>>,
pub items: Registry<Item>,
pub acceptors: Registry<ItemAcceptor>,
pub new_acceptor_fn:
fn(node: &Node, uid: &str, acceptor: &Arc<Node>, acceptor_field: &Arc<Node>),
}
impl Hash for TypeInfo {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
@@ -182,15 +182,19 @@ impl Drop for Item {
pub enum ItemType {
Camera(CameraItem),
Environment(EnvironmentItem),
Panel(Arc<dyn PanelItemTrait>),
}
impl ItemType {
fn serialize_start_data(&self, id: &str) -> Result<Message> {
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
match self {
ItemType::Camera(c) => c.serialize_start_data(id),
ItemType::Environment(e) => e.serialize_start_data(id),
ItemType::Panel(p) => p.serialize_start_data(id),
ItemType::Camera(c) => c.send_ui_item_created(node, uid, item),
ItemType::Panel(p) => p.send_ui_item_created(node, uid, item),
}
}
fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
match self {
ItemType::Camera(c) => c.send_acceptor_item_created(node, uid, item),
ItemType::Panel(p) => p.send_acceptor_item_created(node, uid, item),
}
}
}
@@ -237,16 +241,6 @@ 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);
}
fn handle_create_item(&self, item: &Item) {
let Some(node) = self.node.upgrade() else {
@@ -256,38 +250,26 @@ impl ItemUI {
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 {
let Ok(item_alias) = item.make_alias(&client, &(node.get_path().to_string() + "/item"))
else {
return;
};
let _ = node.send_remote_signal("create_item", serialized_data);
}
fn handle_destroy_item(&self, item: &Item) {
self.item_aliases.remove(&item.uid);
self.send_state("destroy_item", item.uid.as_str());
self.item_aliases.add(item.uid.clone(), &item_alias);
item.specialization
.send_ui_item_created(&node, &item.uid, &item_alias);
}
fn handle_capture_item(&self, item: &Item, acceptor: &ItemAcceptor) {
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 _ =
item_ui_client::capture_item(&self.node.upgrade().unwrap(), &item.uid, &acceptor.uid);
}
fn handle_release_item(&self, item: &Item, acceptor: &ItemAcceptor) {
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 _ =
item_ui_client::release_item(&self.node.upgrade().unwrap(), &item.uid, &acceptor.uid);
}
fn handle_destroy_item(&self, item: &Item) {
let _ = item_ui_client::destroy_item(&self.node.upgrade().unwrap(), &item.uid);
self.item_aliases.remove(&item.uid);
}
fn handle_create_acceptor(&self, acceptor: &ItemAcceptor) {
let Some(node) = self.node.upgrade() else {
@@ -297,22 +279,26 @@ impl ItemUI {
return;
};
let Ok((alias, field_alias)) = acceptor.make_aliases(
let Ok((acceptor_alias, acceptor_field_alias)) = acceptor.make_aliases(
&client,
&format!("/item/{}/acceptor", self.type_info.type_name),
) else {
return;
};
self.acceptor_aliases.add(acceptor.uid.clone(), &alias);
self.acceptor_aliases
.add(acceptor.uid.clone(), &acceptor_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);
.add(acceptor.uid.clone(), &acceptor_field_alias);
(acceptor.type_info.new_acceptor_fn)(
&node,
&acceptor.uid,
&acceptor_alias,
&acceptor_field_alias,
);
}
fn handle_destroy_acceptor(&self, acceptor: &ItemAcceptor) {
self.send_state("destroy_acceptor", acceptor.uid.as_str());
let _ = item_ui_client::destroy_acceptor(&self.node.upgrade().unwrap(), &acceptor.uid);
self.acceptor_aliases.remove(&acceptor.uid);
self.acceptor_field_aliases.remove(&acceptor.uid);
}
@@ -397,31 +383,27 @@ impl ItemAcceptor {
};
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 {
let Ok(alias_node) = item.make_alias(&client, &node.path) else {
return;
};
let _ = node.send_remote_signal("capture", serialized_data);
self.accepted_aliases.add(item.uid.clone(), &alias_node);
item.specialization
.send_acceptor_item_created(&node, &item.uid, &alias_node);
}
fn handle_release(&self, item: &Item) {
let Some(node) = self.node.upgrade() else {
return;
};
if let Some(node) = self.node.upgrade() {
let _ = item_acceptor_client::release_item(&node, &item.uid);
}
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);
}
}
impl Aspect for ItemAcceptor {
const NAME: &'static str = "ItemAcceptor";
}
impl ItemAcceptorAspect for ItemAcceptor {}
impl Drop for ItemAcceptor {
fn drop(&mut self) {
self.type_info.acceptors.remove(self);
@@ -434,69 +416,31 @@ impl Drop for ItemAcceptor {
}
}
pub fn create_interface(client: &Arc<Client>) -> Result<()> {
let node = Node::create_parent_name(client, "", "item", false);
node.add_local_signal("create_camera_item", camera::create_camera_item_flex);
node.add_local_signal(
"create_environment_item",
environment::create_environment_item_flex,
);
node.add_local_signal("register_item_ui", register_item_ui_flex);
node.add_local_signal("create_item_acceptor", create_item_acceptor_flex);
node.add_to_scenegraph().map(|_| ())
}
fn type_info(name: &str) -> Result<&'static TypeInfo> {
match name {
"environment" => Ok(&ITEM_TYPE_INFO_ENVIRONMENT),
#[cfg(feature = "wayland")]
"panel" => Ok(&ITEM_TYPE_INFO_PANEL),
_ => Err(eyre!("Invalid item type")),
}
}
pub fn register_item_ui_flex(
_node: Arc<Node>,
calling_client: Arc<Client>,
message: Message,
type_info: &'static TypeInfo,
) -> Result<()> {
#[derive(Deserialize)]
struct RegisterItemUIInfo<'a> {
item_type: &'a str,
}
let info: RegisterItemUIInfo = deserialize(message.as_ref())?;
let type_info = type_info(info.item_type)?;
let ui = Node::create_parent_name(&calling_client, "/item", type_info.type_name, true)
.add_to_scenegraph()?;
ItemUI::add_to(&ui, type_info)?;
Ok(())
}
fn create_item_acceptor_flex(
_node: Arc<Node>,
calling_client: Arc<Client>,
message: Message,
name: String,
parent: Arc<Node>,
transform: Transform,
type_info: &'static TypeInfo,
field: Arc<Node>,
) -> Result<()> {
#[derive(Deserialize)]
struct CreateItemAcceptorInfo<'a> {
name: &'a str,
parent_path: &'a str,
transform: Transform,
field_path: &'a str,
item_type: &'a str,
}
let info: CreateItemAcceptorInfo = deserialize(message.as_ref())?;
let space = calling_client
.get_node("Reference space", info.parent_path)?
.get_aspect::<Spatial>()?;
let transform = parse_transform(info.transform, true, true, false);
let field = find_field(&calling_client, info.field_path)?;
let type_info = type_info(info.item_type)?;
let space = parent.get_aspect::<Spatial>()?;
let field = field.get_aspect::<Field>()?;
let transform = transform.to_mat4(true, true, false);
let node = Node::create_parent_name(
&calling_client,
&format!("/item/{}/acceptor", type_info.type_name),
info.name,
&name,
true,
)
.add_to_scenegraph()?;
@@ -504,3 +448,6 @@ fn create_item_acceptor_flex(
ItemAcceptor::add_to(&node, type_info, field);
Ok(())
}
struct ItemInterface;
// create_interface!(ItemInterface, ItemInterfaceAspect, "/item");

View File

@@ -3,28 +3,25 @@ use crate::{
client::{get_env, state, Client, INTERNAL_CLIENT},
registry::Registry,
},
create_interface,
nodes::{
drawable::model::ModelPart,
items::{Item, ItemType, TypeInfo},
spatial::Spatial,
Message, Node,
spatial::{Spatial, Transform},
Node,
},
};
use color_eyre::eyre::{eyre, Result};
use color_eyre::eyre::Result;
use glam::Mat4;
use lazy_static::lazy_static;
use mint::Vector2;
use nanoid::nanoid;
use rustc_hash::FxHashMap;
use serde::{
de::{Deserializer, Error, SeqAccess, Visitor},
ser::Serializer,
Deserialize, Serialize,
};
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::sync::{Arc, Weak};
use tracing::{debug, info};
use super::{create_item_acceptor_flex, register_item_ui_flex, ItemInterface};
stardust_xr_server_codegen::codegen_item_panel_protocol!();
lazy_static! {
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
type_name: "panel",
@@ -61,146 +58,39 @@ lazy_static! {
ui: Default::default(),
items: Registry::new(),
acceptors: Registry::new(),
new_acceptor_fn: |node, uid, acceptor, acceptor_field| {
let _ = panel_item_ui_client::create_acceptor(node, uid, acceptor, acceptor_field);
}
};
}
/// An ID for a surface inside this panel item
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum SurfaceID {
Cursor,
Toplevel,
Child(String),
}
impl Default for SurfaceID {
fn default() -> Self {
Self::Toplevel
}
}
impl<'de> serde::Deserialize<'de> for SurfaceID {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_seq(SurfaceIDVisitor)
}
}
struct SurfaceIDVisitor;
impl<'de> Visitor<'de> for SurfaceIDVisitor {
type Value = SurfaceID;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.write_str("idk")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let Some(discrim) = seq.next_element()? else {
return Err(A::Error::missing_field("discrim"));
};
// idk if you wanna check for extraneous elements
// I didn't bother
match discrim {
"Cursor" => Ok(SurfaceID::Cursor),
"Toplevel" => Ok(SurfaceID::Toplevel),
"Child" => {
let Some(text) = seq.next_element()? else {
return Err(A::Error::missing_field("child_text"));
};
Ok(SurfaceID::Child(text))
}
_ => Err(A::Error::unknown_variant(
discrim,
&["Cursor", "Toplevel", "Child"],
)),
}
}
}
impl serde::Serialize for SurfaceID {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Self::Cursor => ["Cursor"].serialize(serializer),
Self::Toplevel => ["Toplevel"].serialize(serializer),
Self::Child(text) => ["Child", text].serialize(serializer),
}
}
}
/// The origin and size of the surface's "solid" part.
#[derive(Debug, Serialize, Clone, Copy)]
pub struct Geometry {
pub origin: Vector2<i32>,
pub size: Vector2<u32>,
}
/// The state of the panel item's toplevel.
#[derive(Debug, Clone, Serialize)]
pub struct ToplevelInfo {
/// The UID of the panel item of the parent of this toplevel, if it exists
pub parent: Option<String>,
/// Equivalent to the window title
pub title: Option<String>,
/// Application identifier, see <https://standards.freedesktop.org/desktop-entry-spec/>
pub app_id: Option<String>,
/// Current size in pixels
pub size: Vector2<u32>,
/// Recommended minimum size in pixels
pub min_size: Option<Vector2<u32>>,
/// Recommended maximum size in pixels
pub max_size: Option<Vector2<u32>>,
/// Surface geometry
pub logical_rectangle: Geometry,
}
/// Data on positioning a child
#[derive(Debug, Clone, Serialize)]
pub struct ChildInfo {
pub parent: SurfaceID,
pub geometry: Geometry,
}
/// The init data for the panel item.
#[derive(Debug, Clone, Serialize)]
pub struct PanelItemInitData {
/// The cursor, if applicable.
pub cursor: Option<Geometry>,
/// Size of the toplevel surface in pixels.
pub toplevel: ToplevelInfo,
/// Vector of childs that already exist
pub children: FxHashMap<String, ChildInfo>,
/// The surface, if any, that has exclusive input to the pointer.
pub pointer_grab: Option<SurfaceID>,
/// The surface, if any, that has exclusive input to the keyboard.
pub keyboard_grab: Option<SurfaceID>,
}
pub trait Backend: Send + Sync + 'static {
fn start_data(&self) -> Result<PanelItemInitData>;
fn surface_alive(&self, surface: &SurfaceID) -> bool;
fn surface_alive(&self, surface: &SurfaceId) -> bool;
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>);
fn apply_cursor_material(&self, model_part: &Arc<ModelPart>);
fn apply_surface_material(&self, surface: SurfaceId, model_part: &Arc<ModelPart>);
fn close_toplevel(&self);
fn auto_size_toplevel(&self);
fn set_toplevel_size(&self, size: Vector2<u32>);
fn set_toplevel_focused_visuals(&self, focused: bool);
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>);
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool);
fn pointer_motion(&self, surface: &SurfaceId, position: Vector2<f32>);
fn pointer_button(&self, surface: &SurfaceId, button: u32, pressed: bool);
fn pointer_scroll(
&self,
surface: &SurfaceID,
surface: &SurfaceId,
scroll_distance: Option<Vector2<f32>>,
scroll_steps: Option<Vector2<f32>>,
);
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>);
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>);
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>);
fn touch_down(&self, surface: &SurfaceId, id: u32, position: Vector2<f32>);
fn touch_move(&self, id: u32, position: Vector2<f32>);
fn touch_up(&self, id: u32);
fn reset_touches(&self);
fn reset_input(&self);
}
pub fn panel_item_from_node(node: &Node) -> Option<Arc<dyn PanelItemTrait>> {
@@ -211,7 +101,8 @@ pub fn panel_item_from_node(node: &Node) -> Option<Arc<dyn PanelItemTrait>> {
}
pub trait PanelItemTrait: Backend + Send + Sync + 'static {
fn serialize_start_data(&self, id: &str) -> Result<Message>;
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>);
fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>);
}
pub struct PanelItem<B: Backend + ?Sized> {
@@ -252,22 +143,7 @@ impl<B: Backend + ?Sized> PanelItem<B> {
&ITEM_TYPE_INFO_PANEL,
ItemType::Panel(generic_panel_item),
);
node.add_local_signal("apply_surface_material", Self::apply_surface_material_flex);
node.add_local_signal("close_toplevel", Self::close_toplevel_flex);
node.add_local_signal("auto_size_toplevel", Self::auto_size_toplevel_flex);
node.add_local_signal("set_toplevel_size", Self::set_toplevel_size_flex);
node.add_local_signal("pointer_motion", Self::pointer_motion_flex);
node.add_local_signal("pointer_button", Self::pointer_button_flex);
node.add_local_signal("pointer_scroll", Self::pointer_scroll_flex);
node.add_local_signal("keyboard_key", Self::keyboard_keys_flex);
node.add_local_signal("touch_down", Self::touch_down_flex);
node.add_local_signal("touch_move", Self::touch_move_flex);
node.add_local_signal("touch_up", Self::touch_up_flex);
node.add_local_signal("reset_touches", Self::reset_touches_flex);
<Self as PanelItemAspect>::add_node_members(&node);
(node, panel_item)
}
@@ -286,265 +162,300 @@ impl<B: Backend + ?Sized> PanelItem<B> {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("toplevel_parent_changed", serialize(parent).unwrap());
panel_item_client::toplevel_parent_changed(&node, parent);
}
pub fn toplevel_title_changed(&self, title: &str) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("toplevel_title_changed", serialize(title).unwrap());
panel_item_client::toplevel_title_changed(&node, title);
}
pub fn toplevel_app_id_changed(&self, app_id: &str) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("toplevel_app_id_changed", serialize(app_id).unwrap());
panel_item_client::toplevel_app_id_changed(&node, app_id);
}
pub fn toplevel_fullscreen_active(&self, active: bool) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("toplevel_fullscreen_active", serialize(active).unwrap());
panel_item_client::toplevel_fullscreen_active(&node, active);
}
pub fn toplevel_move_request(&self) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("toplevel_move_request", Vec::<u8>::new());
panel_item_client::toplevel_move_request(&node);
}
pub fn toplevel_resize_request(&self, up: bool, down: bool, left: bool, right: bool) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal(
"toplevel_resize_request",
serialize((up, down, left, right)).unwrap(),
);
panel_item_client::toplevel_resize_request(&node, up, down, left, right);
}
pub fn toplevel_size_changed(&self, size: Vector2<u32>) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("toplevel_size_changed", serialize(size).unwrap());
panel_item_client::toplevel_size_changed(&node, size);
}
pub fn set_cursor(&self, geometry: Option<Geometry>) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("set_cursor", serialize(geometry).unwrap());
if let Some(geometry) = geometry {
panel_item_client::set_cursor(&node, &geometry);
} else {
panel_item_client::hide_cursor(&node);
}
}
pub fn new_child(&self, uid: &str, info: ChildInfo) {
pub fn create_child(&self, uid: &str, info: ChildInfo) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("new_child", serialize((uid, info)).unwrap());
panel_item_client::create_child(&node, uid, &info);
}
pub fn reposition_child(&self, uid: &str, geometry: Geometry) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("reposition_child", serialize((uid, geometry)).unwrap());
panel_item_client::reposition_child(&node, uid, &geometry);
}
pub fn drop_child(&self, uid: &str) {
pub fn destroy_child(&self, uid: &str) {
let Some(node) = self.node.upgrade() else {
return;
};
let _ = node.send_remote_signal("drop_child", serialize(uid).unwrap());
panel_item_client::destroy_child(&node, uid);
}
}
// Local signals
macro_rules! flex_no_args {
($fn_name: ident, $trait_fn: ident) => {
fn $fn_name(
node: Arc<Node>,
_calling_client: Arc<Client>,
_message: Message,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.$trait_fn();
Ok(())
}
};
}
macro_rules! flex_deserialize {
($fn_name: ident, $trait_fn: ident) => {
fn $fn_name(node: Arc<Node>, _calling_client: Arc<Client>, message: Message) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.$trait_fn(deserialize(message.as_ref())?);
Ok(())
}
};
}
// make these stupid vectors u32 in the protocol somehow!!!!!!!1
#[allow(unused)]
impl<B: Backend + ?Sized> PanelItem<B> {
fn apply_surface_material_flex(
impl<B: Backend + ?Sized> PanelItemAspect for PanelItem<B> {
#[doc = "Apply the cursor as a material to a model."]
fn apply_cursor_material(
node: Arc<Node>,
_calling_client: Arc<Client>,
model_part: Arc<Node>,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
let model_part = model_part.get_aspect::<ModelPart>()?;
panel_item.apply_cursor_material(&model_part);
Ok(())
}
#[doc = "Apply a surface's visuals as a material to a model."]
fn apply_surface_material(
node: Arc<Node>,
calling_client: Arc<Client>,
message: Message,
surface: SurfaceId,
model_part: Arc<Node>,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
let model_part = model_part.get_aspect::<ModelPart>()?;
#[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 model_part = model_node.get_aspect::<ModelPart>()?;
debug!(?info, "Apply surface material");
panel_item.apply_surface_material(info.surface, &model_part);
panel_item.apply_surface_material(surface, &model_part);
Ok(())
}
flex_no_args!(close_toplevel_flex, close_toplevel);
flex_no_args!(auto_size_toplevel_flex, auto_size_toplevel);
flex_deserialize!(set_toplevel_size_flex, set_toplevel_size);
#[doc = "Try to close the toplevel.\n \n The panel item UI handler or panel item acceptor will drop the panel item if this succeeds."]
fn close_toplevel(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.close_toplevel();
Ok(())
}
fn pointer_motion_flex(
#[doc = "Request a resize of the surface to whatever size the 2D app wants."]
fn auto_size_toplevel(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.auto_size_toplevel();
Ok(())
}
#[doc = "Request a resize of the surface (in pixels)."]
fn set_toplevel_size(
node: Arc<Node>,
_calling_client: Arc<Client>,
message: Message,
size: mint::Vector2<u32>,
) -> 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);
panel_item.set_toplevel_size(size);
Ok(())
}
fn pointer_button_flex(
#[doc = "Tell the toplevel to appear focused visually if true, or unfocused if false."]
fn set_toplevel_focused_visuals(
node: Arc<Node>,
_calling_client: Arc<Client>,
message: Message,
focused: bool,
) -> 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);
panel_item.set_toplevel_focused_visuals(focused);
Ok(())
}
fn pointer_scroll_flex(
#[doc = "Send an event to set the pointer's position (in pixels, relative to top-left of surface). This will activate the pointer."]
fn pointer_motion(
node: Arc<Node>,
_calling_client: Arc<Client>,
message: Message,
surface: SurfaceId,
position: mint::Vector2<f32>,
) -> 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);
panel_item.pointer_motion(&surface, position);
Ok(())
}
fn keyboard_keys_flex(
#[doc = "Send an event to set a pointer button's state if the pointer's active. The `button` is from the `input_event_codes` crate (e.g. BTN_LEFT for left click)."]
fn pointer_button(
node: Arc<Node>,
_calling_client: Arc<Client>,
message: Message,
surface: SurfaceId,
button: u32,
pressed: bool,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
let (surface_id, keymap_id, keys): (SurfaceID, &str, Vec<i32>) =
deserialize(message.as_ref())?;
debug!(?keys, "Set keyboard key state");
panel_item.keyboard_keys(&surface_id, keymap_id, keys);
panel_item.pointer_button(&surface, button, pressed);
Ok(())
}
pub fn grab_keyboard(&self, sid: Option<SurfaceID>) {
let Some(node) = self.node.upgrade() else {
return;
};
let Ok(message) = serialize(sid) else { return };
let _ = node.send_remote_signal("grab_keyboard", message);
}
fn touch_down_flex(
#[doc = "Send an event to scroll the pointer if it's active.\nScroll distance is a value in pixels corresponding to the `distance` the surface should be scrolled.\nScroll steps is a value in columns/rows corresponding to the wheel clicks of a mouse or such. This also supports fractions of a wheel click."]
fn pointer_scroll(
node: Arc<Node>,
_calling_client: Arc<Client>,
message: Message,
surface: SurfaceId,
scroll_distance: mint::Vector2<f32>,
scroll_steps: mint::Vector2<f32>,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
let (surface_id, id, position): (SurfaceID, u32, Vector2<f32>) =
deserialize(message.as_ref())?;
debug!(?surface_id, id, ?position, "Touch down");
panel_item.touch_down(&surface_id, id, position);
panel_item.pointer_scroll(&surface, Some(scroll_distance), Some(scroll_steps));
Ok(())
}
fn touch_move_flex(
#[doc = "Send an event to stop scrolling the pointer."]
fn pointer_stop_scroll(
node: Arc<Node>,
_calling_client: Arc<Client>,
message: Message,
surface: SurfaceId,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
let (id, position): (u32, Vector2<f32>) = deserialize(message.as_ref())?;
debug!(?position, "Touch move");
panel_item.touch_move(id, position);
panel_item.pointer_scroll(&surface, None, None);
Ok(())
}
#[doc = "Send a series of key presses and releases (positive keycode for pressed, negative for released)."]
fn keyboard_keys(
node: Arc<Node>,
_calling_client: Arc<Client>,
surface: SurfaceId,
keymap_id: String,
keys: Vec<i32>,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.keyboard_keys(&surface, &keymap_id, keys);
Ok(())
}
#[doc = "Put a touch down on this surface with the unique ID `uid` at `position` (in pixels) from top left corner of the surface."]
fn touch_down(
node: Arc<Node>,
_calling_client: Arc<Client>,
surface: SurfaceId,
uid: u32,
position: mint::Vector2<f32>,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.touch_down(&surface, uid, position);
Ok(())
}
#[doc = "Move an existing touch point."]
fn touch_move(
node: Arc<Node>,
_calling_client: Arc<Client>,
uid: u32,
position: mint::Vector2<f32>,
) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.touch_move(uid, position);
Ok(())
}
#[doc = "Release a touch from its surface."]
fn touch_up(node: Arc<Node>, _calling_client: Arc<Client>, uid: u32) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.touch_up(uid);
Ok(())
}
#[doc = "Reset all input, such as pressed keys and pointer clicks and touches. Useful for when it's newly captured into an item acceptor to make sure no input gets stuck."]
fn reset_input(node: Arc<Node>, _calling_client: Arc<Client>) -> Result<()> {
let Some(panel_item) = panel_item_from_node(&node) else {
return Ok(());
};
panel_item.reset_input();
Ok(())
}
flex_deserialize!(touch_up_flex, touch_up);
flex_no_args!(reset_touches_flex, reset_touches);
}
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
fn serialize_start_data(&self, id: &str) -> Result<Message> {
Ok(serialize((id, self.start_data()?))?.into())
fn send_ui_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
let Ok(init_data) = self.backend.start_data() else {
return;
};
let _ = panel_item_ui_client::create_item(node, uid, item, init_data);
}
fn send_acceptor_item_created(&self, node: &Node, uid: &str, item: &Arc<Node>) {
let Ok(init_data) = self.backend.start_data() else {
return;
};
let _ = panel_item_acceptor_client::capture_item(node, uid, item, init_data);
}
}
impl<B: Backend + ?Sized> Backend for PanelItem<B> {
fn start_data(&self) -> Result<PanelItemInitData> {
self.backend.start_data()
}
fn surface_alive(&self, surface: &SurfaceID) -> bool {
fn surface_alive(&self, surface: &SurfaceId) -> bool {
self.backend.surface_alive(surface)
}
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
fn apply_cursor_material(&self, model_part: &Arc<ModelPart>) {
self.backend.apply_cursor_material(model_part)
}
fn apply_surface_material(&self, surface: SurfaceId, model_part: &Arc<ModelPart>) {
self.backend.apply_surface_material(surface, model_part)
}
@@ -561,15 +472,15 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
self.backend.set_toplevel_focused_visuals(focused)
}
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
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) {
fn pointer_button(&self, surface: &SurfaceId, button: u32, pressed: bool) {
self.backend.pointer_button(surface, button, pressed)
}
fn pointer_scroll(
&self,
surface: &SurfaceID,
surface: &SurfaceId,
scroll_distance: Option<Vector2<f32>>,
scroll_steps: Option<Vector2<f32>>,
) {
@@ -577,11 +488,11 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
.pointer_scroll(surface, scroll_distance, scroll_steps)
}
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>) {
self.backend.keyboard_keys(surface, keymap_id, keys)
}
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>) {
fn touch_down(&self, surface: &SurfaceId, id: u32, position: Vector2<f32>) {
self.backend.touch_down(surface, id, position)
}
fn touch_move(&self, id: u32, position: Vector2<f32>) {
@@ -590,8 +501,8 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
fn touch_up(&self, id: u32) {
self.backend.touch_up(id)
}
fn reset_touches(&self) {
self.backend.reset_touches()
fn reset_input(&self) {
self.backend.reset_input()
}
}
impl<B: Backend + ?Sized> Drop for PanelItem<B> {
@@ -600,3 +511,30 @@ impl<B: Backend + ?Sized> Drop for PanelItem<B> {
info!("Dropped panel item {}", self.uid);
}
}
create_interface!(ItemInterface, ItemPanelInterfaceAspect, "/item/panel");
impl ItemPanelInterfaceAspect for ItemInterface {
#[doc = "Register this client to manage the items of a certain type and create default 3D UI for them."]
fn register_panel_item_ui(_node: Arc<Node>, calling_client: Arc<Client>) -> Result<()> {
register_item_ui_flex(calling_client, &ITEM_TYPE_INFO_PANEL)
}
#[doc = "Create an item acceptor to allow temporary ownership of a given type of item. Creates a node at `/item/<item_type>/acceptor/<name>`."]
fn create_panel_item_acceptor(
_node: Arc<Node>,
calling_client: Arc<Client>,
name: String,
parent: Arc<Node>,
transform: Transform,
field: Arc<Node>,
) -> Result<()> {
create_item_acceptor_flex(
calling_client,
name,
parent,
transform,
&ITEM_TYPE_INFO_PANEL,
field,
)
}
}

View File

@@ -307,7 +307,7 @@ impl SeatWrapper {
},
);
}
pub fn reset_touches(&self) {
pub fn reset_input(&self) {
for id in self.touches.lock().keys() {
self.touch_up(*id)
}

View File

@@ -7,7 +7,7 @@ use super::{
use crate::nodes::{
drawable::model::ModelPart,
items::panel::{
Backend, ChildInfo, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo,
Backend, ChildInfo, Geometry, PanelItem, PanelItemInitData, SurfaceId, ToplevelInfo,
},
};
use color_eyre::eyre::Result;
@@ -85,7 +85,7 @@ impl XdgShellHandler for WaylandState {
s.states.unset(State::Fullscreen);
});
toplevel.send_configure();
utils::insert_data(toplevel.wl_surface(), SurfaceID::Toplevel);
utils::insert_data(toplevel.wl_surface(), SurfaceId::Toplevel);
CoreSurface::add_to(
self.display_handle.clone(),
toplevel.wl_surface(),
@@ -194,7 +194,7 @@ impl XdgShellHandler for WaylandState {
if popup.send_configure().is_err() {
return;
}
utils::insert_data(popup.wl_surface(), SurfaceID::Child(uid.clone()));
utils::insert_data(popup.wl_surface(), SurfaceId::Child(uid.clone()));
utils::insert_data(popup.wl_surface(), uid.clone());
utils::insert_data(popup.wl_surface(), Arc::downgrade(&panel_item));
CoreSurface::add_to(
@@ -341,18 +341,10 @@ impl XdgBackend {
seat,
}
}
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
fn wl_surface_from_id(&self, id: &SurfaceId) -> Option<WlSurface> {
match id {
SurfaceID::Cursor => self
.seat
.cursor_info_rx
.borrow()
.surface
.clone()?
.upgrade()
.ok(),
SurfaceID::Toplevel => Some(self.toplevel.lock().clone()?.wl_surface().clone()),
SurfaceID::Child(popup) => {
SurfaceId::Toplevel(_) => Some(self.toplevel.lock().clone()?.wl_surface().clone()),
SurfaceId::Child(popup) => {
let popups = self.popups.lock();
Some(popups.get(popup)?.0.wl_surface().clone())
}
@@ -371,12 +363,12 @@ impl XdgBackend {
.lock()
.insert(uid.to_string(), (popup, positioner));
panel_item.new_child(uid, self.child_data(uid).unwrap());
panel_item.create_child(uid, self.child_data(uid).unwrap());
}
pub fn reposition_popup(&self, uid: &str, _popup: PopupSurface, positioner: PositionerState) {
let mut popups = self.popups.lock();
let Some((_, old_positioner)) = popups.get_mut(uid) else {
return
return;
};
let Some(panel_item) = self.panel_item() else {
return;
@@ -390,13 +382,13 @@ impl XdgBackend {
let Some(panel_item) = self.panel_item() else {
return;
};
panel_item.drop_child(uid);
panel_item.destroy_child(uid);
}
fn child_data(&self, uid: &str) -> Option<ChildInfo> {
let (popup, positioner) = self.popups.lock().get(uid)?.clone();
Some(ChildInfo {
parent: (*utils::get_data::<SurfaceID>(&popup.get_parent_surface()?)?).clone(),
parent: (*utils::get_data::<SurfaceId>(&popup.get_parent_surface()?)?).clone(),
geometry: positioner.get_geometry().into(),
})
}
@@ -448,9 +440,9 @@ impl Backend for XdgBackend {
.current_state()
.size
.clone()
.map(|s| [s.w as u32, s.h as u32].into())
.map(|s| Vector2::from([s.w as u32, s.h as u32]))
.or_else(|| toplevel_core_surface.size())
.unwrap_or([0; 2].into());
.unwrap_or(Vector2::from([0; 2]));
let toplevel = ToplevelInfo {
parent: toplevel
.parent()
@@ -465,8 +457,8 @@ impl Backend for XdgBackend {
{
Some(
[
toplevel_cached_state.min_size.w as u32,
toplevel_cached_state.min_size.h as u32,
toplevel_cached_state.min_size.w as f32,
toplevel_cached_state.min_size.h as f32,
]
.into(),
)
@@ -478,8 +470,8 @@ impl Backend for XdgBackend {
{
Some(
[
toplevel_cached_state.max_size.w as u32,
toplevel_cached_state.max_size.h as u32,
toplevel_cached_state.max_size.w as f32,
toplevel_cached_state.max_size.h as f32,
]
.into(),
)
@@ -489,7 +481,7 @@ impl Backend for XdgBackend {
logical_rectangle: toplevel_cached_state
.geometry
.map(Into::into)
.unwrap_or(Geometry {
.unwrap_or_else(|| Geometry {
origin: [0; 2].into(),
size,
}),
@@ -511,14 +503,31 @@ impl Backend for XdgBackend {
})
}
fn surface_alive(&self, surface: &SurfaceID) -> bool {
fn surface_alive(&self, surface: &SurfaceId) -> bool {
let Some(surface) = self.wl_surface_from_id(surface) else {
return false;
};
surface.is_alive()
}
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
fn apply_cursor_material(&self, model_part: &Arc<ModelPart>) {
let Some(surface) = self
.seat
.cursor_info_rx
.borrow()
.surface
.clone()
.and_then(|s| s.upgrade().ok())
else {
return;
};
let Some(core_surface) = CoreSurface::from_wl_surface(&surface) else {
return;
};
core_surface.apply_material(model_part);
}
fn apply_surface_material(&self, surface: SurfaceId, model_part: &Arc<ModelPart>) {
let Some(surface) = self.wl_surface_from_id(&surface) else {
return;
};
@@ -561,32 +570,32 @@ impl Backend for XdgBackend {
})
}
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
fn pointer_motion(&self, surface: &SurfaceId, position: Vector2<f32>) {
let Some(surface) = self.wl_surface_from_id(&surface) else {
return;
};
self.seat.pointer_motion(surface, position)
}
fn pointer_button(&self, _surface: &SurfaceID, button: u32, pressed: bool) {
fn pointer_button(&self, _surface: &SurfaceId, button: u32, pressed: bool) {
self.seat.pointer_button(button, pressed)
}
fn pointer_scroll(
&self,
_surface: &SurfaceID,
_surface: &SurfaceId,
scroll_distance: Option<Vector2<f32>>,
scroll_steps: Option<Vector2<f32>>,
) {
self.seat.pointer_scroll(scroll_distance, scroll_steps)
}
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
fn keyboard_keys(&self, surface: &SurfaceId, keymap_id: &str, keys: Vec<i32>) {
let Some(surface) = self.wl_surface_from_id(&surface) else {
return;
};
self.seat.keyboard_keys(surface, keymap_id, keys)
}
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>) {
fn touch_down(&self, surface: &SurfaceId, id: u32, position: Vector2<f32>) {
let Some(surface) = self.wl_surface_from_id(&surface) else {
return;
};
@@ -598,7 +607,7 @@ impl Backend for XdgBackend {
fn touch_up(&self, id: u32) {
self.seat.touch_up(id)
}
fn reset_touches(&self) {
self.seat.reset_touches()
fn reset_input(&self) {
self.seat.reset_input()
}
}