feat(wayland): cursors!

This commit is contained in:
Nova
2022-09-10 08:54:15 -04:00
parent 5323479670
commit 43b2b67254
6 changed files with 522 additions and 278 deletions

View File

@@ -1,11 +1,9 @@
use super::state::WaylandState; use super::{state::WaylandState, surface::CoreSurface};
use crate::nodes::{core::Node, item::ItemType};
use smithay::{ use smithay::{
delegate_compositor, delegate_compositor,
reexports::wayland_server::protocol::wl_surface::WlSurface, reexports::wayland_server::protocol::wl_surface::WlSurface,
wayland::compositor::{self, CompositorHandler, CompositorState}, wayland::compositor::{self, CompositorHandler, CompositorState},
}; };
use std::sync::Arc;
impl CompositorHandler for WaylandState { impl CompositorHandler for WaylandState {
fn compositor_state(&mut self) -> &mut CompositorState { fn compositor_state(&mut self) -> &mut CompositorState {
@@ -13,13 +11,10 @@ impl CompositorHandler for WaylandState {
} }
fn commit(&mut self, surface: &WlSurface) { fn commit(&mut self, surface: &WlSurface) {
compositor::with_states(surface, |data| { compositor::with_states(&surface, |data| {
if let Some(panel_node) = data.data_map.get::<Arc<Node>>() { data.data_map.insert_if_missing_threadsafe(|| {
let item = panel_node.item.get().unwrap(); CoreSurface::new(&self.display, self.display_handle.clone(), &surface)
if let ItemType::Panel(panel_item) = &item.specialization { })
panel_item.resize(&data.data_map);
}
}
}); });
} }
} }

View File

@@ -7,23 +7,15 @@ pub mod surface;
pub mod xdg_decoration; pub mod xdg_decoration;
pub mod xdg_shell; pub mod xdg_shell;
use self::{panel_item::PanelItem, state::WaylandState}; use self::{panel_item::PanelItem, state::WaylandState, surface::CORE_SURFACES};
use crate::{nodes::core::Node, wayland::state::ClientState}; use crate::wayland::state::ClientState;
use anyhow::{ensure, Result}; use anyhow::{ensure, Result};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use slog::Logger; use slog::Logger;
use smithay::{ use smithay::{
backend::{ backend::{egl::EGLContext, renderer::gles2::Gles2Renderer},
egl::EGLContext,
renderer::{
gles2::Gles2Renderer,
utils::{import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData},
},
},
desktop::utils::send_frames_surface_tree,
reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket}, reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket},
wayland::{compositor::with_states, shell::xdg::XdgToplevelSurfaceData},
}; };
use std::os::unix::prelude::AsRawFd; use std::os::unix::prelude::AsRawFd;
use std::{ use std::{
@@ -36,7 +28,6 @@ use std::{
}; };
use stereokit as sk; use stereokit as sk;
use stereokit::StereoKit; use stereokit::StereoKit;
use surface::CoreSurface;
use tokio::{ use tokio::{
io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle, io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle,
}; };
@@ -70,7 +61,7 @@ pub struct Wayland {
display: Arc<Mutex<Display<WaylandState>>>, display: Arc<Mutex<Display<WaylandState>>>,
join_handle: JoinHandle<Result<()>>, join_handle: JoinHandle<Result<()>>,
renderer: Gles2Renderer, renderer: Gles2Renderer,
state: Arc<Mutex<WaylandState>>, // state: Arc<Mutex<WaylandState>>,
} }
impl Wayland { impl Wayland {
pub fn new(log: Logger) -> Result<Self> { pub fn new(log: Logger) -> Result<Self> {
@@ -93,7 +84,8 @@ impl Wayland {
let display = Arc::new(Mutex::new(display)); let display = Arc::new(Mutex::new(display));
let state = Arc::new(Mutex::new(WaylandState::new( let state = Arc::new(Mutex::new(WaylandState::new(
log.clone(), log.clone(),
display_handle.clone(), display.clone(),
display_handle,
))); )));
let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8); let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);
@@ -107,7 +99,7 @@ impl Wayland {
display, display,
join_handle, join_handle,
renderer, renderer,
state, // state,
}) })
} }
@@ -154,47 +146,23 @@ impl Wayland {
} }
pub fn frame(&mut self, sk: &StereoKit) { pub fn frame(&mut self, sk: &StereoKit) {
let log = self.log.clone();
let time_ms = (sk.time_getf() * 1000.) as u32; let time_ms = (sk.time_getf() * 1000.) as u32;
let toplevel_surfaces = self
.state
.lock()
.xdg_shell_state
.toplevel_surfaces(|surfs| surfs.to_vec());
for surf in toplevel_surfaces {
// Let Smithay handle all the buffer maintenance
on_commit_buffer_handler(surf.wl_surface());
// Import all surface buffers into textures
import_surface_tree(&mut self.renderer, surf.wl_surface(), &log).unwrap();
with_states(surf.wl_surface(), |data| { for core_surface in CORE_SURFACES.get_valid_contents() {
let mapped = data core_surface.process(
.data_map sk,
.get::<RendererSurfaceStateUserData>() &mut self.renderer,
.map(|surface_states| surface_states.borrow().wl_buffer().is_some()) time_ms,
.unwrap_or(false); &self.log,
|data| {
if mapped && data.data_map.get::<XdgToplevelSurfaceData>().is_some() { PanelItem::on_mapped(&core_surface, data);
data.data_map.insert_if_missing_threadsafe(CoreSurface::new); },
data.data_map.insert_if_missing_threadsafe(|| { |data| {
PanelItem::create( PanelItem::if_mapped(&core_surface, data);
&self.display, },
self.display.lock().handle(), );
&data.data_map,
surf.wl_surface().clone(),
)
});
if let Some(core_surface) = data.data_map.get::<CoreSurface>() {
core_surface.update_tex(sk, data, &self.renderer);
if let Some(panel_item) = data.data_map.get::<Arc<Node>>() {
PanelItem::apply_surface_materials(panel_item, core_surface);
}
}
}
});
send_frames_surface_tree(surf.wl_surface(), time_ms);
} }
self.display.lock().flush_clients().unwrap(); self.display.lock().flush_clients().unwrap();
} }

View File

@@ -1,4 +1,4 @@
use super::{seat::SeatData, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE}; use super::{seat::SeatData, surface::CoreSurface};
use crate::{ use crate::{
core::{ core::{
client::{Client, INTERNAL_CLIENT}, client::{Client, INTERNAL_CLIENT},
@@ -7,28 +7,26 @@ use crate::{
nodes::{ nodes::{
core::Node, core::Node,
item::{register_item_ui_flex, Item, ItemSpecialization, ItemType, TypeInfo}, item::{register_item_ui_flex, Item, ItemSpecialization, ItemType, TypeInfo},
model::Model,
spatial::Spatial, spatial::Spatial,
}, },
}; };
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use glam::Mat4; use glam::Mat4;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use libstardustxr::{flex::flexbuffer_from_vector_arguments, flex_to_vec2}; use libstardustxr::{
flex::{flexbuffer_from_arguments, flexbuffer_from_vector_arguments},
flex_to_vec2,
};
use nanoid::nanoid; use nanoid::nanoid;
use parking_lot::Mutex;
use smithay::{ use smithay::{
backend::renderer::utils::RendererSurfaceStateUserData,
reexports::wayland_server::{ reexports::wayland_server::{
backend::ObjectId,
protocol::{ protocol::{
wl_keyboard::KeyState, wl_keyboard::KeyState,
wl_pointer::{Axis, ButtonState}, wl_pointer::{Axis, ButtonState},
wl_surface::WlSurface,
}, },
Display, DisplayHandle, Resource, Resource,
}, },
utils::{user_data::UserDataMap, Logical, Size}, wayland::{compositor::SurfaceData, shell::xdg::XdgToplevelSurfaceData},
}; };
use std::{ use std::{
convert::TryInto, convert::TryInto,
@@ -40,6 +38,7 @@ lazy_static! {
type_name: "panel", type_name: "panel",
aliased_local_signals: vec![ aliased_local_signals: vec![
"applySurfaceMaterial", "applySurfaceMaterial",
"applyCursorMaterial",
"pointerDeactivate", "pointerDeactivate",
"pointerScroll", "pointerScroll",
"pointerButton", "pointerButton",
@@ -51,7 +50,7 @@ lazy_static! {
"close", "close",
], ],
aliased_local_methods: vec![], aliased_local_methods: vec![],
aliased_remote_signals: vec![], aliased_remote_signals: vec!["resize", "setCursor",],
aliased_remote_methods: vec![], aliased_remote_methods: vec![],
ui: Default::default(), ui: Default::default(),
items: Registry::new(), items: Registry::new(),
@@ -61,20 +60,11 @@ lazy_static! {
pub struct PanelItem { pub struct PanelItem {
node: Weak<Node>, node: Weak<Node>,
pending_material_applications: Mutex<Vec<(Arc<Model>, u32)>>, core_surface: Weak<CoreSurface>,
display: Weak<Mutex<Display<WaylandState>>>,
dh: DisplayHandle,
pub toplevel_surface_id: ObjectId,
seat_data: SeatData, seat_data: SeatData,
size: Mutex<Size<i32, Logical>>,
} }
impl PanelItem { impl PanelItem {
pub fn create( pub fn create(core_surface: &Arc<CoreSurface>) -> Arc<Node> {
display: &Arc<Mutex<Display<WaylandState>>>,
dh: DisplayHandle,
data: &UserDataMap,
toplevel_surface: WlSurface,
) -> Arc<Node> {
let node = Arc::new(Node::create( let node = Arc::new(Node::create(
&INTERNAL_CLIENT, &INTERNAL_CLIENT,
"/item/panel/item", "/item/panel/item",
@@ -83,30 +73,26 @@ impl PanelItem {
)); ));
Spatial::add_to(&node, None, Mat4::IDENTITY).unwrap(); Spatial::add_to(&node, None, Mat4::IDENTITY).unwrap();
let seat_data = SeatData::new(&dh, toplevel_surface.client_id().unwrap()); let seat_data = SeatData::new(
&core_surface.dh,
let size = data core_surface.wl_surface().client_id().unwrap(),
.get::<RendererSurfaceStateUserData>() );
.unwrap()
.borrow()
.surface_size()
.map(Mutex::new)
.unwrap();
let specialization = ItemType::Panel(PanelItem { let specialization = ItemType::Panel(PanelItem {
node: Arc::downgrade(&node), node: Arc::downgrade(&node),
pending_material_applications: Mutex::new(Vec::new()), core_surface: Arc::downgrade(core_surface),
display: Arc::downgrade(display),
dh,
toplevel_surface_id: toplevel_surface.id(),
seat_data, seat_data,
size,
}); });
Item::add_to(&node, &ITEM_TYPE_INFO_PANEL, specialization); let item = Item::add_to(&node, &ITEM_TYPE_INFO_PANEL, specialization);
if let ItemType::Panel(panel) = &item.specialization {
let _ = panel.seat_data.panel_item.set(Arc::downgrade(&item));
}
node.add_local_signal( node.add_local_signal(
"applySurfaceMaterial", "applySurfaceMaterial",
PanelItem::apply_surface_material_flex, PanelItem::apply_surface_material_flex,
); );
node.add_local_signal("applyCursorMaterial", PanelItem::apply_cursor_material_flex);
node.add_local_signal("pointerDeactivate", PanelItem::pointer_deactivate_flex); node.add_local_signal("pointerDeactivate", PanelItem::pointer_deactivate_flex);
node.add_local_signal("pointerScroll", PanelItem::pointer_scroll_flex); node.add_local_signal("pointerScroll", PanelItem::pointer_scroll_flex);
node.add_local_signal("pointerButton", PanelItem::pointer_button_flex); node.add_local_signal("pointerButton", PanelItem::pointer_button_flex);
@@ -123,30 +109,10 @@ impl PanelItem {
node node
} }
fn toplevel_surface(&self) -> WlSurface { fn from_node(node: &Node) -> &PanelItem {
WlSurface::from_id(&self.dh, self.toplevel_surface_id.clone()).unwrap() match &node.item.get().unwrap().specialization {
} ItemType::Panel(panel_item) => panel_item,
fn flush_clients(&self) { _ => unreachable!(),
self.display
.upgrade()
.unwrap()
.lock()
.flush_clients()
.unwrap();
}
pub fn resize(&self, data: &UserDataMap) {
if let Some(surface_states) = data.get::<RendererSurfaceStateUserData>() {
if let Some(size) = surface_states.borrow().buffer_size() {
*self.size.lock() = size;
let _ = self.node.upgrade().unwrap().send_remote_signal(
"resize",
&flexbuffer_from_vector_arguments(|vec| {
vec.push(size.w);
vec.push(size.h);
}),
);
}
} }
} }
@@ -164,30 +130,125 @@ impl PanelItem {
.model .model
.get() .get()
.ok_or_else(|| anyhow!("Node is not a model"))?; .ok_or_else(|| anyhow!("Node is not a model"))?;
let material_idx = flex_vec.idx(1).get_u64()?; let material_idx = flex_vec.idx(1).get_u64()? as u32;
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
panel_item if let Some(core_surface) = panel_item.core_surface.upgrade() {
.pending_material_applications core_surface.apply_material(model.clone(), material_idx);
.lock() }
.push((model.clone(), material_idx as u32));
} }
Ok(()) Ok(())
} }
pub fn apply_surface_materials(node: &Node, core_surface: &CoreSurface) { fn apply_cursor_material_flex(
node: &Node,
calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
let model_node = calling_client
.scenegraph
.get_node(flex_vec.idx(0).as_str())
.ok_or_else(|| anyhow!("Model node not found"))?;
let model = model_node
.model
.get()
.ok_or_else(|| anyhow!("Node is not a model"))?;
let material_idx = flex_vec.idx(1).get_u64()? as u32;
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
let mut pending_material_applications = panel_item.pending_material_applications.lock(); if let Some(cursor) = &*panel_item.seat_data.cursor.lock() {
for (model, material_idx) in &*pending_material_applications { if let Some(core_surface) = cursor.lock().core_surface.upgrade() {
let sk_mat = core_surface.sk_mat.get().unwrap().clone(); core_surface.apply_material(model.clone(), material_idx);
model }
.pending_material_replacements
.lock()
.insert(*material_idx, sk_mat);
} }
pending_material_applications.clear();
} }
Ok(())
}
pub fn on_mapped(core_surface: &Arc<CoreSurface>, surface_data: &SurfaceData) {
if surface_data
.data_map
.get::<XdgToplevelSurfaceData>()
.is_some()
{
surface_data
.data_map
.insert_if_missing_threadsafe(|| PanelItem::create(core_surface));
}
}
pub fn if_mapped(core_surface: &Arc<CoreSurface>, surface_data: &SurfaceData) {
if let Some(panel_node) = surface_data.data_map.get::<Arc<Node>>() {
let panel_item = PanelItem::from_node(panel_node);
core_surface.with_data(|core_surface_data| {
if core_surface_data.resized {
panel_item.resize(core_surface);
core_surface_data.resized = false;
}
});
panel_item.set_cursor();
}
}
pub fn resize(&self, core_surface: &CoreSurface) {
core_surface.with_data(|data| {
if data.resized {
let _ = self.node.upgrade().unwrap().send_remote_signal(
"resize",
&flexbuffer_from_vector_arguments(|vec| {
vec.push(data.size.x);
vec.push(data.size.y);
}),
);
data.resized = false;
}
});
}
pub fn set_cursor(&self) {
let mut cursor_changed = self.seat_data.cursor_changed.lock();
if !*cursor_changed {
return;
}
let mut data = flexbuffer_from_arguments(|flex| {
flex.build_singleton(());
});
if let Some(cursor) = &*self.seat_data.cursor.lock() {
let cursor = cursor.lock();
if let Some(core_surface) = cursor.core_surface.upgrade() {
if let Some(mapped_data) = &*core_surface.mapped_data.lock() {
data = flexbuffer_from_vector_arguments(|vec| {
let mut size_vec = vec.start_vector();
let size = mapped_data.size;
size_vec.push(size.x);
size_vec.push(size.y);
size_vec.end_vector();
let mut hotspot_vec = vec.start_vector();
hotspot_vec.push(cursor.hotspot.x);
hotspot_vec.push(cursor.hotspot.y);
hotspot_vec.end_vector();
});
} else {
return;
};
} else {
return;
}
}
let _ = self
.node
.upgrade()
.unwrap()
.send_remote_signal("setCursor", &data);
*cursor_changed = false;
} }
fn pointer_deactivate_flex( fn pointer_deactivate_flex(
@@ -195,13 +256,14 @@ impl PanelItem {
_calling_client: Arc<Client>, _calling_client: Arc<Client>,
_data: &[u8], _data: &[u8],
) -> Result<()> { ) -> Result<()> {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { let panel_item = PanelItem::from_node(node);
if *panel_item.seat_data.pointer_active.lock() { if *panel_item.seat_data.pointer_active.lock() {
if let Some(core_surface) = panel_item.core_surface.upgrade() {
if let Some(pointer) = panel_item.seat_data.pointer() { if let Some(pointer) = panel_item.seat_data.pointer() {
pointer.leave(0, &panel_item.toplevel_surface()); pointer.leave(0, &core_surface.wl_surface());
*panel_item.seat_data.pointer_active.lock() = false; *panel_item.seat_data.pointer_active.lock() = false;
pointer.frame(); pointer.frame();
panel_item.flush_clients(); core_surface.flush_clients();
} }
} }
} }
@@ -212,18 +274,20 @@ impl PanelItem {
fn pointer_motion_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> { fn pointer_motion_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(pointer) = panel_item.seat_data.pointer() { if let Some(pointer) = panel_item.seat_data.pointer() {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?; if let Some(core_surface) = panel_item.core_surface.upgrade() {
let x = flex_vec.index(0)?.get_f64()?; let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
let y = flex_vec.index(1)?.get_f64()?; let x = flex_vec.index(0)?.get_f64()?;
let mut pointer_active = panel_item.seat_data.pointer_active.lock(); let y = flex_vec.index(1)?.get_f64()?;
if *pointer_active { let mut pointer_active = panel_item.seat_data.pointer_active.lock();
pointer.motion(0, x, y); if *pointer_active {
} else { pointer.motion(0, x, y);
pointer.enter(0, &panel_item.toplevel_surface(), x, y); } else {
*pointer_active = true; pointer.enter(0, &core_surface.wl_surface(), x, y);
*pointer_active = true;
}
pointer.frame();
core_surface.flush_clients();
} }
pointer.frame();
panel_item.flush_clients();
} }
} }
@@ -234,23 +298,25 @@ impl PanelItem {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(pointer) = panel_item.seat_data.pointer() { if let Some(pointer) = panel_item.seat_data.pointer() {
if *panel_item.seat_data.pointer_active.lock() { if *panel_item.seat_data.pointer_active.lock() {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?; if let Some(core_surface) = panel_item.core_surface.upgrade() {
let button = flex_vec.index(0)?.get_u64()? as u32; let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
let state = flex_vec.index(1)?.get_u64()? as u32; let button = flex_vec.index(0)?.get_u64()? as u32;
pointer.button( let state = flex_vec.index(1)?.get_u64()? as u32;
0, pointer.button(
0, 0,
button, 0,
match state { button,
0 => ButtonState::Released, match state {
1 => ButtonState::Pressed, 0 => ButtonState::Released,
_ => { 1 => ButtonState::Pressed,
bail!("Button state is out of bounds") _ => {
} bail!("Button state is out of bounds")
}, }
); },
pointer.frame(); );
panel_item.flush_clients(); pointer.frame();
core_surface.flush_clients();
}
} }
} }
} }
@@ -262,24 +328,31 @@ impl PanelItem {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(pointer) = panel_item.seat_data.pointer() { if let Some(pointer) = panel_item.seat_data.pointer() {
if *panel_item.seat_data.pointer_active.lock() { if *panel_item.seat_data.pointer_active.lock() {
let flex = flexbuffers::Reader::get_root(data)?; if let Some(core_surface) = panel_item.core_surface.upgrade() {
if flex.flexbuffer_type().is_null() { let flex = flexbuffers::Reader::get_root(data)?;
pointer.axis_stop(0, Axis::HorizontalScroll); if flex.flexbuffer_type().is_null() {
pointer.axis_stop(0, Axis::VerticalScroll); pointer.axis_stop(0, Axis::HorizontalScroll);
} else { pointer.axis_stop(0, Axis::VerticalScroll);
let flex_vec = flex.get_vector()?; } else {
let axis_continuous_vec = flex_to_vec2!(flex_vec.idx(0)) let flex_vec = flex.get_vector()?;
.ok_or_else(|| anyhow!("No continuous axis vector!"))?; let axis_continuous_vec = flex_to_vec2!(flex_vec.idx(0))
pointer.axis(0, Axis::HorizontalScroll, axis_continuous_vec.x as f64); .ok_or_else(|| anyhow!("No continuous axis vector!"))?;
pointer.axis(0, Axis::VerticalScroll, axis_continuous_vec.y as f64); pointer.axis(0, Axis::HorizontalScroll, axis_continuous_vec.x as f64);
if let Some(axis_discrete_vec) = flex_to_vec2!(flex_vec.idx(0)) { pointer.axis(0, Axis::VerticalScroll, axis_continuous_vec.y as f64);
pointer if let Some(axis_discrete_vec) = flex_to_vec2!(flex_vec.idx(0)) {
.axis_discrete(Axis::HorizontalScroll, axis_discrete_vec.x as i32); pointer.axis_discrete(
pointer.axis_discrete(Axis::VerticalScroll, axis_discrete_vec.y as i32); Axis::HorizontalScroll,
axis_discrete_vec.x as i32,
);
pointer.axis_discrete(
Axis::VerticalScroll,
axis_discrete_vec.y as i32,
);
}
} }
pointer.frame();
core_surface.flush_clients();
} }
pointer.frame();
panel_item.flush_clients();
} }
} }
} }
@@ -294,15 +367,17 @@ impl PanelItem {
) -> Result<()> { ) -> Result<()> {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization { if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(keyboard) = panel_item.seat_data.keyboard() { if let Some(keyboard) = panel_item.seat_data.keyboard() {
let mut keyboard_active = panel_item.seat_data.keyboard_active.lock(); if let Some(core_surface) = panel_item.core_surface.upgrade() {
let active = flexbuffers::Reader::get_root(data)?.get_bool()?; let mut keyboard_active = panel_item.seat_data.keyboard_active.lock();
if *keyboard_active != active { let active = flexbuffers::Reader::get_root(data)?.get_bool()?;
if active { if *keyboard_active != active {
keyboard.enter(0, &panel_item.toplevel_surface(), vec![]); if active {
} else { keyboard.enter(0, &core_surface.wl_surface(), vec![]);
keyboard.leave(0, &panel_item.toplevel_surface()); } else {
keyboard.leave(0, &core_surface.wl_surface());
}
*keyboard_active = active;
} }
*keyboard_active = active;
} }
} }
} }
@@ -358,16 +433,40 @@ impl PanelItem {
} }
impl ItemSpecialization for PanelItem { impl ItemSpecialization for PanelItem {
fn serialize_start_data(&self, vec: &mut flexbuffers::VectorBuilder) { fn serialize_start_data(&self, vec: &mut flexbuffers::VectorBuilder) {
let mut size_vec = vec.start_vector(); // Panel size
let size = *self.size.lock(); {
size_vec.push(size.w as u32); let mut size_vec = vec.start_vector();
size_vec.push(size.h as u32); self.core_surface.upgrade().unwrap().with_data(|data| {
} size_vec.push(data.size.x);
} size_vec.push(data.size.y);
impl Drop for PanelItem { });
fn drop(&mut self) { }
let id = self.seat_data.global_id.get().cloned().unwrap();
tokio::spawn(async move { GLOBAL_DESTROY_QUEUE.get().unwrap().send(id).await }); // Cursor size and hotspot
if let Some(cursor) = &*self.seat_data.cursor.lock() {
let cursor = cursor.lock();
if let Some(cursor_core_surface) = cursor.core_surface.upgrade() {
if let Some(mapped_data) = &*cursor_core_surface.mapped_data.lock() {
let mut cursor_vec = vec.start_vector();
{
let mut cursor_size_vec = cursor_vec.start_vector();
cursor_size_vec.push(mapped_data.size.x);
cursor_size_vec.push(mapped_data.size.y);
}
{
let mut cursor_hotspot_vec = cursor_vec.start_vector();
cursor_hotspot_vec.push(cursor.hotspot.x);
cursor_hotspot_vec.push(cursor.hotspot.y);
}
} else {
vec.push(());
}
} else {
vec.push(());
}
} else {
vec.push(());
}
} }
} }

View File

@@ -1,21 +1,30 @@
use super::{state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE};
use crate::nodes::item::Item;
use mint::Vector2;
use nanoid::nanoid; use nanoid::nanoid;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use smithay::reexports::wayland_server::{ use smithay::{
backend::{ClientId, GlobalId}, reexports::wayland_server::{
delegate_dispatch, delegate_global_dispatch, backend::{ClientId, GlobalId},
protocol::{ delegate_dispatch, delegate_global_dispatch,
wl_keyboard::{self, WlKeyboard}, protocol::{
wl_pointer::{self, WlPointer}, wl_keyboard::{self, WlKeyboard},
wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE}, wl_pointer::{self, WlPointer},
wl_touch::{self, WlTouch}, wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE},
wl_touch::{self, WlTouch},
},
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
}, },
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, wayland::compositor,
}; };
use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
use std::{ops::Deref, sync::Weak};
use super::state::WaylandState; pub struct Cursor {
pub core_surface: Weak<CoreSurface>,
pub hotspot: Vector2<i32>,
}
pub struct SeatDelegate; pub struct SeatDelegate;
@@ -26,6 +35,9 @@ impl SeatData {
let seat_data = SeatData(Arc::new(SeatDataInner { let seat_data = SeatData(Arc::new(SeatDataInner {
client, client,
global_id: OnceCell::new(), global_id: OnceCell::new(),
panel_item: OnceCell::new(),
cursor: Mutex::new(None),
cursor_changed: Mutex::new(false),
pointer: OnceCell::new(), pointer: OnceCell::new(),
pointer_active: Mutex::new(false), pointer_active: Mutex::new(false),
keyboard: OnceCell::new(), keyboard: OnceCell::new(),
@@ -52,6 +64,9 @@ impl Deref for SeatData {
pub struct SeatDataInner { pub struct SeatDataInner {
client: ClientId, client: ClientId,
pub global_id: OnceCell<GlobalId>, pub global_id: OnceCell<GlobalId>,
pub panel_item: OnceCell<Weak<Item>>,
pub cursor: Mutex<Option<Arc<Mutex<Cursor>>>>,
pub cursor_changed: Mutex<bool>,
pointer: OnceCell<WlPointer>, pointer: OnceCell<WlPointer>,
pub pointer_active: Mutex<bool>, pub pointer_active: Mutex<bool>,
keyboard: OnceCell<WlKeyboard>, keyboard: OnceCell<WlKeyboard>,
@@ -69,6 +84,12 @@ impl SeatDataInner {
self.touch.get() self.touch.get()
} }
} }
impl Drop for SeatDataInner {
fn drop(&mut self) {
let id = self.global_id.take().unwrap();
tokio::spawn(async move { GLOBAL_DESTROY_QUEUE.get().unwrap().send(id).await });
}
}
impl GlobalDispatch<WlSeat, SeatData, WaylandState> for SeatDelegate { impl GlobalDispatch<WlSeat, SeatData, WaylandState> for SeatDelegate {
fn bind( fn bind(
@@ -123,21 +144,50 @@ delegate_dispatch!(WaylandState: [WlSeat: SeatData] => SeatDelegate);
impl Dispatch<WlPointer, SeatData, WaylandState> for SeatDelegate { impl Dispatch<WlPointer, SeatData, WaylandState> for SeatDelegate {
fn request( fn request(
_state: &mut WaylandState, state: &mut WaylandState,
_client: &Client, _client: &Client,
_resource: &WlPointer, _resource: &WlPointer,
request: <WlPointer as Resource>::Request, request: <WlPointer as Resource>::Request,
_data: &SeatData, seat_data: &SeatData,
_dh: &DisplayHandle, dh: &DisplayHandle,
_data_init: &mut DataInit<'_, WaylandState>, _data_init: &mut DataInit<'_, WaylandState>,
) { ) {
match request { match request {
wl_pointer::Request::SetCursor { wl_pointer::Request::SetCursor {
serial: _, serial: _,
surface: _, surface,
hotspot_x: _, hotspot_x,
hotspot_y: _, hotspot_y,
} => (), } => {
if !*seat_data.pointer_active.lock() {
return;
}
*seat_data.0.cursor_changed.lock() = true;
if let Some(surface) = surface.as_ref() {
compositor::with_states(surface, |data| {
data.data_map.insert_if_missing_threadsafe(|| {
CoreSurface::new(&state.display, dh.clone(), surface)
});
if !data.data_map.insert_if_missing_threadsafe(|| {
Arc::new(Mutex::new(Cursor {
core_surface: Arc::downgrade(
data.data_map.get::<Arc<CoreSurface>>().unwrap(),
),
hotspot: Vector2::from([hotspot_x, hotspot_y]),
}))
}) {
let mut cursor =
data.data_map.get::<Arc<Mutex<Cursor>>>().unwrap().lock();
cursor.hotspot = Vector2::from([hotspot_x, hotspot_y]);
}
})
}
*seat_data.cursor.lock() = surface.and_then(|surf| {
compositor::with_states(&surf, |data| {
data.data_map.get::<Arc<Mutex<Cursor>>>().cloned()
})
});
}
wl_pointer::Request::Release => (), wl_pointer::Request::Release => (),
_ => unreachable!(), _ => unreachable!(),
} }

View File

@@ -1,10 +1,13 @@
use std::sync::Arc;
use parking_lot::Mutex;
use slog::Logger; use slog::Logger;
use smithay::{ use smithay::{
delegate_output, delegate_shm, delegate_output, delegate_shm,
reexports::wayland_server::{ reexports::wayland_server::{
backend::{ClientData, ClientId, DisconnectReason}, backend::{ClientData, ClientId, DisconnectReason},
protocol::wl_output::Subpixel, protocol::wl_output::Subpixel,
DisplayHandle, Display, DisplayHandle,
}, },
utils::Size, utils::Size,
wayland::{ wayland::{
@@ -33,6 +36,7 @@ impl ClientData for ClientState {
} }
pub struct WaylandState { pub struct WaylandState {
pub display: Arc<Mutex<Display<WaylandState>>>,
pub display_handle: DisplayHandle, pub display_handle: DisplayHandle,
pub compositor_state: CompositorState, pub compositor_state: CompositorState,
@@ -46,7 +50,11 @@ pub struct WaylandState {
} }
impl WaylandState { impl WaylandState {
pub fn new(log: Logger, display_handle: DisplayHandle) -> Self { pub fn new(
log: Logger,
display: Arc<Mutex<Display<WaylandState>>>,
display_handle: DisplayHandle,
) -> Self {
let compositor_state = CompositorState::new::<Self, _>(&display_handle, log.clone()); let compositor_state = CompositorState::new::<Self, _>(&display_handle, log.clone());
let xdg_shell_state = XdgShellState::new::<Self, _>(&display_handle, log.clone()); let xdg_shell_state = XdgShellState::new::<Self, _>(&display_handle, log.clone());
let xdg_decoration_state = XdgDecorationState::new::<Self, _>(&display_handle, log.clone()); let xdg_decoration_state = XdgDecorationState::new::<Self, _>(&display_handle, log.clone());
@@ -69,6 +77,7 @@ impl WaylandState {
println!("Init Wayland compositor"); println!("Init Wayland compositor");
WaylandState { WaylandState {
display,
display_handle, display_handle,
compositor_state, compositor_state,

View File

@@ -1,17 +1,26 @@
use std::{fmt::Error, mem, sync::Arc}; use super::{shaders::PANEL_SHADER_BYTES, state::WaylandState};
use crate::{
core::{destroy_queue, registry::Registry},
nodes::model::Model,
};
use glam::vec2; use glam::vec2;
use once_cell::sync::OnceCell; use mint::Vector2;
use parking_lot::Mutex; use parking_lot::Mutex;
use send_wrapper::SendWrapper; use send_wrapper::SendWrapper;
use slog::Logger;
use smithay::{ use smithay::{
backend::renderer::{ backend::renderer::{
gles2::{Gles2Renderer, Gles2Texture}, gles2::{Gles2Renderer, Gles2Texture},
utils::RendererSurfaceStateUserData, utils::{import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData},
Texture, Texture,
}, },
wayland::compositor::SurfaceData, desktop::utils::send_frames_surface_tree,
reexports::wayland_server::{
backend::ObjectId, protocol::wl_surface::WlSurface, Display, DisplayHandle, Resource,
},
wayland::compositor::{self, SurfaceData},
}; };
use std::sync::{Arc, Weak};
use stereokit::{ use stereokit::{
material::{Material, Transparency}, material::{Material, Transparency},
shader::Shader, shader::Shader,
@@ -19,57 +28,47 @@ use stereokit::{
StereoKit, StereoKit,
}; };
use crate::core::destroy_queue; pub static CORE_SURFACES: Registry<CoreSurface> = Registry::new();
use super::shaders::PANEL_SHADER_BYTES; pub struct CoreSurfaceData {
wl_tex: Option<SendWrapper<Gles2Texture>>,
pub struct CoreSurface { sk_tex: Option<SendWrapper<SKTexture>>,
pub wl_tex: Mutex<Option<SendWrapper<Gles2Texture>>>, sk_mat: Option<Arc<SendWrapper<Material>>>,
sk_tex: OnceCell<SendWrapper<SKTexture>>, pub size: Vector2<u32>,
pub sk_mat: OnceCell<Arc<SendWrapper<Material>>>, pub resized: bool,
} }
impl CoreSurfaceData {
impl CoreSurface { fn new(sk: &StereoKit) -> Self {
pub fn new() -> Self { let sk_tex = SendWrapper::new(
CoreSurface { SKTexture::create(sk, TextureType::ImageNoMips, TextureFormat::RGBA32).unwrap(),
wl_tex: Mutex::new(None), );
sk_tex: OnceCell::new(), let sk_mat = {
sk_mat: OnceCell::new(), let shader = Shader::from_mem(sk, PANEL_SHADER_BYTES).unwrap();
let mat = Material::create(sk, &shader).unwrap();
mat.set_parameter("diffuse", &*sk_tex);
mat.set_transparency(Transparency::Blend);
Arc::new(SendWrapper::new(mat))
};
CoreSurfaceData {
wl_tex: None,
sk_tex: Some(sk_tex),
sk_mat: Some(sk_mat),
size: Vector2::from([0, 0]),
resized: false,
} }
} }
fn update_tex(&mut self, data: &RendererSurfaceStateUserData, renderer: &Gles2Renderer) {
pub fn update_tex(&self, sk: &StereoKit, data: &SurfaceData, renderer: &Gles2Renderer) { if let Some(surface_size) = data.borrow().surface_size() {
let sk_tex = self self.size = Vector2::from([surface_size.w as u32, surface_size.h as u32]);
.sk_tex
.get_or_try_init(|| {
SKTexture::create(sk, TextureType::ImageNoMips, TextureFormat::RGBA32)
.ok_or(Error)
.map(SendWrapper::new)
})
.unwrap();
let sk_mat = self
.sk_mat
.get_or_try_init(|| {
let shader = Shader::from_mem(sk, PANEL_SHADER_BYTES).unwrap();
Material::create(sk, &shader)
.ok_or(Error)
.map(|mat| {
mat.set_parameter("diffuse", &**self.sk_tex.get().unwrap());
mat.set_transparency(Transparency::Blend);
mat
})
.map(|mat| Arc::new(SendWrapper::new(mat)))
})
.unwrap();
if let Some(surface_states) = data.data_map.get::<RendererSurfaceStateUserData>() {
*self.wl_tex.lock() = surface_states
.borrow()
.texture(renderer)
.cloned()
.map(SendWrapper::new);
} }
if let Some(smithay_tex) = self.wl_tex.lock().as_ref() { self.wl_tex = data
.borrow()
.texture(renderer)
.cloned()
.map(SendWrapper::new);
if let Some(smithay_tex) = self.wl_tex.as_ref() {
let sk_tex = self.sk_tex.as_ref().unwrap();
let sk_mat = self.sk_mat.as_ref().unwrap();
unsafe { unsafe {
sk_tex.set_native( sk_tex.set_native(
smithay_tex.tex_id() as usize, smithay_tex.tex_id() as usize,
@@ -88,10 +87,134 @@ impl CoreSurface {
} }
} }
} }
impl Drop for CoreSurface { impl Drop for CoreSurfaceData {
fn drop(&mut self) { fn drop(&mut self) {
destroy_queue::add(mem::replace(self.wl_tex.get_mut(), None)); destroy_queue::add(self.wl_tex.take());
self.sk_tex.take().map(destroy_queue::add); destroy_queue::add(self.sk_tex.take());
self.sk_mat.take().map(destroy_queue::add); destroy_queue::add(self.sk_mat.take());
}
}
pub struct CoreSurface {
display: Weak<Mutex<Display<WaylandState>>>,
pub dh: DisplayHandle,
pub surface_id: ObjectId,
pub mapped_data: Mutex<Option<CoreSurfaceData>>,
pub pending_material_applications: Mutex<Vec<(Arc<Model>, u32)>>,
}
impl CoreSurface {
pub fn new(
display: &Arc<Mutex<Display<WaylandState>>>,
dh: DisplayHandle,
surface: &WlSurface,
) -> Arc<Self> {
CORE_SURFACES.add(CoreSurface {
display: Arc::downgrade(display),
dh,
surface_id: surface.id(),
mapped_data: Mutex::new(None),
pending_material_applications: Mutex::new(Vec::new()),
})
}
pub fn process<F: FnOnce(&SurfaceData), M: FnOnce(&SurfaceData)>(
&self,
sk: &StereoKit,
renderer: &mut Gles2Renderer,
time_ms: u32,
log: &Logger,
on_mapped: F,
if_mapped: M,
) {
// Let Smithay handle all the buffer maintenance
on_commit_buffer_handler(&self.wl_surface());
// Import all surface buffers into textures
import_surface_tree(renderer, &self.wl_surface(), log).unwrap();
let mapped = compositor::with_states(&self.wl_surface(), |data| {
data.data_map
.get::<RendererSurfaceStateUserData>()
.map(|surface_states| surface_states.borrow().wl_buffer().is_some())
.unwrap_or(false)
});
if !mapped {
return;
}
let mut mapped_data = self.mapped_data.lock();
let just_mapped = mapped_data.is_none();
if just_mapped {
*mapped_data = Some(CoreSurfaceData::new(sk));
}
drop(mapped_data);
self.with_states(|data| {
self.with_data(|mapped_data| {
mapped_data.update_tex(
data.data_map.get::<RendererSurfaceStateUserData>().unwrap(),
renderer,
);
});
self.apply_surface_materials();
if just_mapped {
on_mapped(data);
}
if_mapped(data);
});
send_frames_surface_tree(&self.wl_surface(), time_ms);
}
pub fn apply_material(&self, model: Arc<Model>, material_idx: u32) {
self.pending_material_applications
.lock()
.push((model, material_idx));
}
fn apply_surface_materials(&self) {
self.with_data(|mapped_data| {
let mut pending_material_applications = self.pending_material_applications.lock();
for (model, material_idx) in &*pending_material_applications {
model
.pending_material_replacements
.lock()
.insert(*material_idx, mapped_data.sk_mat.clone().unwrap());
}
pending_material_applications.clear();
});
}
pub fn wl_surface(&self) -> WlSurface {
WlSurface::from_id(&self.dh, self.surface_id.clone()).unwrap()
}
pub fn with_states<F, T>(&self, f: F) -> T
where
F: FnOnce(&SurfaceData) -> T,
{
compositor::with_states(&self.wl_surface(), f)
}
pub fn with_data<F, T>(&self, f: F) -> Option<T>
where
F: FnOnce(&mut CoreSurfaceData) -> T,
{
self.mapped_data.lock().as_mut().map(f)
}
pub fn flush_clients(&self) {
self.display
.upgrade()
.unwrap()
.lock()
.flush_clients()
.unwrap();
}
}
impl Drop for CoreSurface {
fn drop(&mut self) {
CORE_SURFACES.remove(self);
} }
} }