refactor(items): codegen prototocol
This commit is contained in:
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -15,3 +15,4 @@ split-iter = "0.1.0"
|
||||
|
||||
[dependencies.stardust-xr-schemas]
|
||||
git = "https://github.com/StardustXR/core.git"
|
||||
branch = "dev"
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>()
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user