feat(wayland): popups, more compatibility, more stability
get_parent grab popups fix head thingy popup list feat: remove set_active feat(wayland): commit_popup feat(wayland): cleanup moar changess actually fix the problem with everything oh my god proper popup state fix: multi thread event loop fix: match popup surface ID make wayland input system go over surfaces instead of toplevels feat: massive refactor of all wayland things
This commit is contained in:
523
Cargo.lock
generated
523
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
@@ -10,7 +10,7 @@ homepage = "https://stardustxr.org"
|
||||
|
||||
[dependencies]
|
||||
color-eyre = { version = "0.6.2", default-features = false }
|
||||
clap = { version = "4.1.6", features = ["derive"] }
|
||||
clap = { version = "4.2.4", features = ["derive"] }
|
||||
dashmap = "5.4.0"
|
||||
glam = {version = "0.23.0", features = ["mint"]}
|
||||
lazy_static = "1.4.0"
|
||||
@@ -18,19 +18,17 @@ mint = "0.5.9"
|
||||
nanoid = "0.4.0"
|
||||
once_cell = "1.17.1"
|
||||
parking_lot = "0.12.1"
|
||||
portable-atomic = {version = "1.0.1", features = ["float", "std"]}
|
||||
portable-atomic = {version = "1.2.0", features = ["float", "std"]}
|
||||
rustc-hash = "1.1.0"
|
||||
tokio = { version = "1.25.0", features = ["rt-multi-thread", "signal"] }
|
||||
tokio = { version = "1.27.0", features = ["rt-multi-thread", "signal"] }
|
||||
send_wrapper = "0.6.0"
|
||||
prisma = "0.1.1"
|
||||
slog = "2.7.0"
|
||||
xkbcommon = { version = "0.5.0", default-features = false, optional = true }
|
||||
stardust-xr = "0.11.0"
|
||||
stardust-xr = "0.11.1"
|
||||
directories = "5.0.0"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde = { version = "1.0.160", features = ["derive"] }
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||
tracing-slog = "0.2.0"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
global_counter = "0.2.2"
|
||||
rand = "0.8.5"
|
||||
|
||||
@@ -40,7 +38,8 @@ features = ["linux-egl", "color_named", "prisma"]
|
||||
version = "0.15.3"
|
||||
|
||||
[dependencies.smithay]
|
||||
git = "https://github.com/technobaboo/smithay.git" # Until we get stereokit to understand OES samplers and external textures
|
||||
# git = "https://github.com/technobaboo/smithay.git" # Until we get stereokit to understand OES samplers and external textures
|
||||
git = "https://github.com/smithay/smithay.git" # Until we get stereokit to understand OES samplers and external textures
|
||||
default-features = false
|
||||
features = ["desktop", "renderer_gl", "wayland_frontend"]
|
||||
version = "*"
|
||||
|
||||
@@ -74,6 +74,7 @@ fn main() -> Result<()> {
|
||||
let log_layer = fmt::Layer::new()
|
||||
.with_thread_names(true)
|
||||
.with_ansi(true)
|
||||
.with_line_number(true)
|
||||
.with_filter(EnvFilter::from_default_env());
|
||||
registry.with(log_layer).init();
|
||||
|
||||
@@ -250,8 +251,8 @@ fn main() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// #[tokio::main]
|
||||
#[tokio::main]
|
||||
// #[tokio::main(flavor = "current_thread")]
|
||||
async fn event_loop(
|
||||
info_sender: oneshot::Sender<EventLoopInfo>,
|
||||
stop_rx: oneshot::Receiver<()>,
|
||||
|
||||
@@ -107,7 +107,7 @@ impl MaterialParameter {
|
||||
let Some(texture_path) = resource.get_file(
|
||||
&client.base_resource_prefixes.lock().clone(),
|
||||
&[OsStr::new("png"), OsStr::new("jpg")],
|
||||
) else { return; };
|
||||
) else {return};
|
||||
if let Some(tex) = Texture::from_file(sk, texture_path, true, 0) {
|
||||
material.set_parameter(sk, parameter_name, &tex);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::{
|
||||
};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use lazy_static::lazy_static;
|
||||
use nanoid::nanoid;
|
||||
use serde::Deserialize;
|
||||
use stardust_xr::{
|
||||
schemas::flex::{deserialize, flexbuffers, serialize},
|
||||
@@ -38,6 +39,7 @@ impl EnvironmentItem {
|
||||
pub fn add_to(node: &Arc<Node>, path: String) {
|
||||
Item::add_to(
|
||||
node,
|
||||
nanoid!(),
|
||||
&ITEM_TYPE_INFO_ENVIRONMENT,
|
||||
ItemType::Environment(EnvironmentItem { path }),
|
||||
);
|
||||
|
||||
@@ -88,12 +88,13 @@ pub struct Item {
|
||||
impl Item {
|
||||
pub fn add_to(
|
||||
node: &Arc<Node>,
|
||||
uid: String,
|
||||
type_info: &'static TypeInfo,
|
||||
specialization: ItemType,
|
||||
) -> Arc<Self> {
|
||||
let item = Item {
|
||||
node: Arc::downgrade(node),
|
||||
uid: node.uid.clone(),
|
||||
uid,
|
||||
type_info,
|
||||
captured_acceptor: Default::default(),
|
||||
specialization,
|
||||
|
||||
@@ -272,3 +272,8 @@ impl Debug for Node {
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl Drop for Node {
|
||||
fn drop(&mut self) {
|
||||
// Debug breakpoint
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use super::{panel_item::PanelItem, state::WaylandState, surface::CoreSurface};
|
||||
use crate::wayland::surface::CoreSurface;
|
||||
|
||||
use super::state::WaylandState;
|
||||
use portable_atomic::{AtomicU32, Ordering};
|
||||
use smithay::{
|
||||
delegate_compositor,
|
||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||
@@ -14,12 +17,24 @@ impl CompositorHandler for WaylandState {
|
||||
|
||||
fn commit(&mut self, surface: &WlSurface) {
|
||||
debug!(?surface, "Surface commit");
|
||||
CoreSurface::add_to(&self.display, self.display_handle.clone(), surface);
|
||||
if let Some(panel_item) = compositor::with_states(surface, |data| {
|
||||
data.data_map.get::<Arc<PanelItem>>().cloned()
|
||||
}) {
|
||||
panel_item.commit_toplevel();
|
||||
};
|
||||
let mut count = 0;
|
||||
let core_surface = compositor::with_states(surface, |data| {
|
||||
let count_new = data
|
||||
.data_map
|
||||
.insert_if_missing_threadsafe(|| AtomicU32::new(0));
|
||||
if !count_new {
|
||||
count = data
|
||||
.data_map
|
||||
.get::<AtomicU32>()
|
||||
.unwrap()
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
data.data_map.get::<Arc<CoreSurface>>().cloned()
|
||||
});
|
||||
if let Some(core_surface) = core_surface {
|
||||
core_surface.commit(count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,9 @@ use global_counter::primitive::exact::CounterU32;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use sk::lifecycle::StereoKitDraw;
|
||||
use slog::Drain;
|
||||
use smithay::{
|
||||
backend::{egl::EGLContext, renderer::gles2::Gles2Renderer},
|
||||
reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket},
|
||||
};
|
||||
use smithay::backend::egl::EGLContext;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::reexports::wayland_server::{backend::GlobalId, Display, ListeningSocket};
|
||||
use std::os::unix::prelude::AsRawFd;
|
||||
use std::{
|
||||
ffi::c_void,
|
||||
@@ -59,36 +57,28 @@ fn get_sk_egl() -> Result<EGLRawHandles> {
|
||||
static GLOBAL_DESTROY_QUEUE: OnceCell<mpsc::Sender<GlobalId>> = OnceCell::new();
|
||||
|
||||
pub struct Wayland {
|
||||
log: slog::Logger,
|
||||
|
||||
display: Arc<Mutex<Display<WaylandState>>>,
|
||||
pub socket_name: String,
|
||||
join_handle: JoinHandle<Result<()>>,
|
||||
renderer: Gles2Renderer,
|
||||
renderer: GlesRenderer,
|
||||
state: Arc<Mutex<WaylandState>>,
|
||||
}
|
||||
impl Wayland {
|
||||
pub fn new() -> Result<Self> {
|
||||
let log = ::slog::Logger::root(::tracing_slog::TracingSlogDrain.fuse(), slog::o!());
|
||||
|
||||
let egl_raw_handles = get_sk_egl()?;
|
||||
let renderer = unsafe {
|
||||
Gles2Renderer::new(
|
||||
EGLContext::from_raw(
|
||||
egl_raw_handles.display,
|
||||
egl_raw_handles.config,
|
||||
egl_raw_handles.context,
|
||||
log.clone(),
|
||||
)?,
|
||||
log.clone(),
|
||||
)?
|
||||
GlesRenderer::new(EGLContext::from_raw(
|
||||
egl_raw_handles.display,
|
||||
egl_raw_handles.config,
|
||||
egl_raw_handles.context,
|
||||
)?)?
|
||||
};
|
||||
|
||||
let display: Display<WaylandState> = Display::new()?;
|
||||
let display_handle = display.handle();
|
||||
|
||||
let display = Arc::new(Mutex::new(display));
|
||||
let state = WaylandState::new(log.clone(), display.clone(), display_handle, &renderer);
|
||||
let state = WaylandState::new(display.clone(), display_handle, &renderer);
|
||||
|
||||
let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);
|
||||
GLOBAL_DESTROY_QUEUE.set(global_destroy_queue_in).unwrap();
|
||||
@@ -101,7 +91,6 @@ impl Wayland {
|
||||
Wayland::start_loop(display.clone(), socket, state.clone(), global_destroy_queue)?;
|
||||
|
||||
Ok(Wayland {
|
||||
log,
|
||||
display,
|
||||
socket_name,
|
||||
join_handle,
|
||||
@@ -157,7 +146,7 @@ impl Wayland {
|
||||
#[instrument(level = "debug", name = "Wayland frame", skip(self, sk))]
|
||||
pub fn update(&mut self, sk: &StereoKitDraw) {
|
||||
for core_surface in CORE_SURFACES.get_valid_contents() {
|
||||
core_surface.process(sk, &mut self.renderer, &self.log);
|
||||
core_surface.process(sk, &mut self.renderer);
|
||||
}
|
||||
|
||||
self.display.lock().flush_clients().unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::{
|
||||
seat::{Cursor, SeatData},
|
||||
surface::CoreSurface,
|
||||
xdg_shell::{XdgSurfaceData, XdgToplevelData},
|
||||
xdg_shell::{PopupData, ToplevelData, XdgSurfaceData},
|
||||
SERIAL_COUNTER,
|
||||
};
|
||||
use crate::{
|
||||
@@ -23,11 +23,18 @@ use lazy_static::lazy_static;
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{
|
||||
de::{Deserializer, Error, SeqAccess, Visitor},
|
||||
ser::Serializer,
|
||||
Deserialize, Serialize,
|
||||
};
|
||||
use smithay::{
|
||||
reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel::{
|
||||
XdgToplevel, EVT_CONFIGURE_BOUNDS_SINCE, EVT_WM_CAPABILITIES_SINCE,
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_popup::XdgPopup,
|
||||
xdg_surface::XdgSurface,
|
||||
xdg_toplevel::{XdgToplevel, EVT_CONFIGURE_BOUNDS_SINCE, EVT_WM_CAPABILITIES_SINCE},
|
||||
},
|
||||
wayland_server::{
|
||||
backend::Credentials, protocol::wl_surface::WlSurface, Resource, Weak as WlWeak,
|
||||
@@ -44,55 +51,92 @@ lazy_static! {
|
||||
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
|
||||
type_name: "panel",
|
||||
aliased_local_signals: vec![
|
||||
"apply_cursor_material",
|
||||
"apply_toplevel_material",
|
||||
"apply_surface_material",
|
||||
"configure_toplevel",
|
||||
"set_toplevel_capabilities",
|
||||
"pointer_set_active",
|
||||
"pointer_scroll",
|
||||
"pointer_button",
|
||||
"pointer_motion",
|
||||
"keyboard_set_active",
|
||||
"keyboard_key",
|
||||
"keyboard_set_keymap_names",
|
||||
"keyboard_set_keymap_string",
|
||||
"close",
|
||||
],
|
||||
aliased_local_methods: vec![],
|
||||
aliased_remote_signals: vec!["commit_toplevel", "recommend_toplevel_state", "set_cursor"],
|
||||
aliased_remote_signals: vec![
|
||||
"commit_toplevel",
|
||||
"recommend_toplevel_state",
|
||||
"set_cursor",
|
||||
"new_popup",
|
||||
"reposition_popup",
|
||||
"drop_popup",
|
||||
],
|
||||
ui: Default::default(),
|
||||
items: Registry::new(),
|
||||
acceptors: Registry::new(),
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ToplevelState {
|
||||
#[serde(skip_serializing)]
|
||||
pub mapped: bool,
|
||||
#[serde(skip_serializing)]
|
||||
pub parent: Option<WlWeak<XdgToplevel>>,
|
||||
pub title: Option<String>,
|
||||
pub app_id: Option<String>,
|
||||
pub size: Vector2<u32>,
|
||||
pub max_size: Option<Vector2<u32>>,
|
||||
pub min_size: Option<Vector2<u32>>,
|
||||
pub states: Vec<u32>,
|
||||
#[serde(skip_serializing)]
|
||||
pub queued_state: Option<Box<ToplevelState>>,
|
||||
/// An ID for a surface inside this panel item
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub enum SurfaceID {
|
||||
Cursor,
|
||||
Toplevel,
|
||||
Popup(String),
|
||||
}
|
||||
impl Default for ToplevelState {
|
||||
impl Default for SurfaceID {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mapped: false,
|
||||
parent: None,
|
||||
title: None,
|
||||
app_id: None,
|
||||
size: Vector2::from([0; 2]),
|
||||
max_size: None,
|
||||
min_size: None,
|
||||
states: Vec::new(),
|
||||
queued_state: None,
|
||||
Self::Toplevel
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::Deserialize<'de> for SurfaceID {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
deserializer.deserialize_seq(SurfaceIDVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
struct SurfaceIDVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for SurfaceIDVisitor {
|
||||
type Value = SurfaceID;
|
||||
|
||||
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
f.write_str("idk")
|
||||
}
|
||||
|
||||
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
|
||||
let Some(discrim) = seq.next_element()? else {
|
||||
return Err(A::Error::missing_field("discrim"));
|
||||
};
|
||||
|
||||
// idk if you wanna check for extraneous elements
|
||||
// I didn't bother
|
||||
|
||||
match discrim {
|
||||
"Cursor" => Ok(SurfaceID::Cursor),
|
||||
"Toplevel" => Ok(SurfaceID::Toplevel),
|
||||
"Popup" => {
|
||||
let Some(text) = seq.next_element()? else {
|
||||
return Err(A::Error::missing_field("popup_text"));
|
||||
};
|
||||
Ok(SurfaceID::Popup(text))
|
||||
}
|
||||
_ => Err(A::Error::unknown_variant(
|
||||
discrim,
|
||||
&["Cursor", "Toplevel", "Popup"],
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for SurfaceID {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
match self {
|
||||
Self::Cursor => ["Cursor"].serialize(serializer),
|
||||
Self::Toplevel => ["Toplevel"].serialize(serializer),
|
||||
Self::Popup(text) => ["Popup", text].serialize(serializer),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,11 +152,15 @@ pub enum RecommendedState {
|
||||
}
|
||||
|
||||
pub struct PanelItem {
|
||||
pub uid: String,
|
||||
node: Weak<Node>,
|
||||
client_credentials: Option<Credentials>,
|
||||
cursor: Mutex<Option<WlWeak<WlSurface>>>,
|
||||
pub seat_data: Arc<SeatData>,
|
||||
toplevel: WlWeak<XdgToplevel>,
|
||||
pub cursor: Mutex<Option<WlWeak<WlSurface>>>,
|
||||
seat_data: Arc<SeatData>,
|
||||
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
|
||||
pointer_grab: Mutex<Option<SurfaceID>>,
|
||||
keyboard_grab: Mutex<Option<SurfaceID>>,
|
||||
}
|
||||
impl PanelItem {
|
||||
pub fn create(
|
||||
@@ -122,51 +170,49 @@ impl PanelItem {
|
||||
seat_data: Arc<SeatData>,
|
||||
) -> (Arc<Node>, Arc<PanelItem>) {
|
||||
debug!(?toplevel, ?client_credentials, "Create panel item");
|
||||
let uid = nanoid!();
|
||||
let node = Arc::new(Node::create(
|
||||
&INTERNAL_CLIENT,
|
||||
"/item/panel/item",
|
||||
&nanoid!(),
|
||||
&uid,
|
||||
true,
|
||||
));
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false).unwrap();
|
||||
let panel_item = Arc::new(PanelItem {
|
||||
uid: uid.clone(),
|
||||
node: Arc::downgrade(&node),
|
||||
client_credentials,
|
||||
toplevel: toplevel.downgrade(),
|
||||
cursor: Mutex::new(None),
|
||||
seat_data,
|
||||
toplevel: toplevel.downgrade(),
|
||||
popups: Mutex::new(FxHashMap::default()),
|
||||
pointer_grab: Mutex::new(None),
|
||||
keyboard_grab: Mutex::new(None),
|
||||
});
|
||||
|
||||
panel_item
|
||||
.seat_data
|
||||
.new_panel_item(&panel_item, &toplevel, &wl_surface);
|
||||
.new_surface(&wl_surface, Arc::downgrade(&panel_item));
|
||||
|
||||
let item = Item::add_to(
|
||||
&node,
|
||||
uid,
|
||||
&ITEM_TYPE_INFO_PANEL,
|
||||
ItemType::Panel(panel_item.clone()),
|
||||
);
|
||||
node.add_local_signal(
|
||||
"apply_toplevel_material",
|
||||
PanelItem::apply_toplevel_material_flex,
|
||||
"apply_surface_material",
|
||||
PanelItem::apply_surface_material_flex,
|
||||
);
|
||||
node.add_local_signal("configure_toplevel", PanelItem::configure_toplevel_flex);
|
||||
if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE {
|
||||
node.add_local_signal(
|
||||
"set_toplevel_capabilities",
|
||||
PanelItem::set_toplevel_capabilities_flex,
|
||||
);
|
||||
}
|
||||
node.add_local_signal(
|
||||
"apply_cursor_material",
|
||||
PanelItem::apply_cursor_material_flex,
|
||||
"set_toplevel_capabilities",
|
||||
PanelItem::set_toplevel_capabilities_flex,
|
||||
);
|
||||
node.add_local_signal("pointer_set_active", PanelItem::pointer_set_active_flex);
|
||||
node.add_local_signal("pointer_scroll", PanelItem::pointer_scroll_flex);
|
||||
node.add_local_signal("pointer_button", PanelItem::pointer_button_flex);
|
||||
node.add_local_signal("pointer_motion", PanelItem::pointer_motion_flex);
|
||||
|
||||
node.add_local_signal("keyboard_set_active", PanelItem::keyboard_set_active_flex);
|
||||
node.add_local_signal(
|
||||
"keyboard_set_keymap_string",
|
||||
PanelItem::keyboard_set_keymap_string_flex,
|
||||
@@ -195,38 +241,26 @@ impl PanelItem {
|
||||
(node, panel_item)
|
||||
}
|
||||
|
||||
pub fn from_node(node: &Node) -> Option<&PanelItem> {
|
||||
node.item.get().and_then(|item| match &item.specialization {
|
||||
ItemType::Panel(panel_item) => Some(&**panel_item),
|
||||
_ => None,
|
||||
})
|
||||
pub fn from_node(node: &Node) -> Option<Arc<PanelItem>> {
|
||||
let ItemType::Panel(panel_item) = &node.item.get()?.specialization else {return None};
|
||||
Some(panel_item.clone())
|
||||
}
|
||||
|
||||
fn toplevel_surface_data(&self) -> Option<XdgSurfaceData> {
|
||||
Some(
|
||||
self.toplevel
|
||||
.upgrade()
|
||||
.ok()?
|
||||
.data::<XdgToplevelData>()?
|
||||
.xdg_surface_data
|
||||
.clone(),
|
||||
)
|
||||
fn toplevel(&self) -> XdgToplevel {
|
||||
self.toplevel.upgrade().unwrap()
|
||||
}
|
||||
fn toplevel_state(&self) -> Option<Arc<Mutex<ToplevelState>>> {
|
||||
Some(
|
||||
self.toplevel
|
||||
.upgrade()
|
||||
.ok()?
|
||||
.data::<XdgToplevelData>()?
|
||||
.state
|
||||
.clone(),
|
||||
)
|
||||
fn toplevel_xdg_surface(&self) -> XdgSurface {
|
||||
let toplevel = self.toplevel();
|
||||
let data = ToplevelData::get(&toplevel).lock();
|
||||
data.xdg_surface()
|
||||
}
|
||||
pub fn toplevel_wl_surface(&self) -> Option<WlSurface> {
|
||||
self.toplevel_surface_data()?.wl_surface.upgrade().ok()
|
||||
fn toplevel_wl_surface(&self) -> WlSurface {
|
||||
XdgSurfaceData::get(&self.toplevel_xdg_surface())
|
||||
.lock()
|
||||
.wl_surface()
|
||||
}
|
||||
fn core_surface(&self) -> Option<Arc<CoreSurface>> {
|
||||
compositor::with_states(&self.toplevel_wl_surface()?, |data| {
|
||||
compositor::with_states(&self.toplevel_wl_surface(), |data| {
|
||||
data.data_map.get::<Arc<CoreSurface>>().cloned()
|
||||
})
|
||||
}
|
||||
@@ -235,55 +269,49 @@ impl PanelItem {
|
||||
core_surface.flush_clients();
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_toplevel_material_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct SurfaceMaterialInfo<'a> {
|
||||
model_path: &'a str,
|
||||
idx: u32,
|
||||
}
|
||||
let info: SurfaceMaterialInfo = deserialize(data)?;
|
||||
let model_node = calling_client
|
||||
.scenegraph
|
||||
.get_node(info.model_path)
|
||||
.ok_or_else(|| eyre!("Model node not found"))?;
|
||||
let Some(Drawable::Model(model)) = model_node.drawable.get() else {bail!("Node is not a model")};
|
||||
debug!(?info, "Apply toplevel material");
|
||||
|
||||
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
|
||||
if let Some(core_surface) = panel_item.core_surface() {
|
||||
core_surface.apply_material(model.clone(), info.idx);
|
||||
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
||||
match id {
|
||||
SurfaceID::Cursor => self.cursor.lock().clone()?.upgrade().ok(),
|
||||
SurfaceID::Toplevel => Some(self.toplevel_wl_surface()),
|
||||
SurfaceID::Popup(popup) => {
|
||||
let popups = self.popups.lock();
|
||||
let popup = popups.get(popup)?.upgrade().ok()?;
|
||||
let surf = PopupData::get(&popup).lock().wl_surface();
|
||||
Some(surf)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn wl_surface_from_id_result(&self, id: &SurfaceID) -> Result<WlSurface> {
|
||||
self.wl_surface_from_id(id)
|
||||
.ok_or(eyre!("Surface with ID not found"))
|
||||
}
|
||||
|
||||
fn apply_cursor_material_flex(
|
||||
fn apply_surface_material_flex(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Some(cursor) = panel_item.cursor.lock().as_ref().and_then(|c| c.upgrade().ok()) else { return Ok(())};
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&cursor) else { return Ok(()) };
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct SurfaceMaterialInfo<'a> {
|
||||
surface: SurfaceID,
|
||||
model_path: &'a str,
|
||||
idx: u32,
|
||||
}
|
||||
|
||||
let info: SurfaceMaterialInfo = deserialize(data)?;
|
||||
debug!(?cursor, ?info, "Apply cursor material");
|
||||
|
||||
let Some(wl_surface) = panel_item.wl_surface_from_id(&info.surface) else { return Ok(()) };
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else { return Ok(()) };
|
||||
|
||||
let model_node = calling_client
|
||||
.scenegraph
|
||||
.get_node(info.model_path)
|
||||
.ok_or_else(|| eyre!("Model node not found"))?;
|
||||
let Some(Drawable::Model(model)) = model_node.drawable.get() else {bail!("Node is not a model")};
|
||||
debug!(?info, "Apply surface material");
|
||||
|
||||
core_surface.apply_material(model.clone(), info.idx);
|
||||
|
||||
Ok(())
|
||||
@@ -291,69 +319,57 @@ impl PanelItem {
|
||||
|
||||
fn pointer_motion_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Ok(toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
debug!(?toplevel, "Pointer deactivate");
|
||||
|
||||
let (surface_id, position): (SurfaceID, Vector2<f64>) = deserialize(data)?;
|
||||
let wl_surface = panel_item.wl_surface_from_id_result(&surface_id)?;
|
||||
debug!(?surface_id, ?position, "Pointer deactivate");
|
||||
|
||||
panel_item
|
||||
.seat_data
|
||||
.pointer_event(&toplevel, PointerEvent::Motion(deserialize(data)?));
|
||||
.pointer_event(&wl_surface, PointerEvent::Motion(position));
|
||||
panel_item.flush_clients();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn pointer_button_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Ok(toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
|
||||
let (button, state): (u32, u32) = deserialize(data)?;
|
||||
debug!(button, state, "Pointer button");
|
||||
let (surface_id, button, state): (SurfaceID, u32, u32) = deserialize(data)?;
|
||||
let wl_surface = panel_item.wl_surface_from_id_result(&surface_id)?;
|
||||
debug!(?surface_id, button, state, "Pointer button");
|
||||
|
||||
panel_item
|
||||
.seat_data
|
||||
.pointer_event(&toplevel, PointerEvent::Button { button, state });
|
||||
.pointer_event(&wl_surface, PointerEvent::Button { button, state });
|
||||
panel_item.flush_clients();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn pointer_scroll_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Ok(toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct PointerScrollArgs {
|
||||
struct PointerScrollInfo {
|
||||
surface_id: SurfaceID,
|
||||
axis_continuous: Option<Vector2<f32>>,
|
||||
axis_discrete: Option<Vector2<f32>>,
|
||||
}
|
||||
let args: PointerScrollArgs = deserialize(data)?;
|
||||
let info: PointerScrollInfo = deserialize(data)?;
|
||||
let wl_surface = panel_item.wl_surface_from_id_result(&info.surface_id)?;
|
||||
|
||||
debug!(?args, "Pointer scroll");
|
||||
debug!(?info, "Pointer scroll");
|
||||
|
||||
panel_item.seat_data.pointer_event(
|
||||
&toplevel,
|
||||
&wl_surface,
|
||||
PointerEvent::Scroll {
|
||||
axis_continuous: args.axis_continuous,
|
||||
axis_discrete: args.axis_discrete,
|
||||
axis_continuous: info.axis_continuous,
|
||||
axis_discrete: info.axis_discrete,
|
||||
},
|
||||
);
|
||||
panel_item.flush_clients();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
fn pointer_set_active_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Ok(toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
let active: bool = deserialize(data)?;
|
||||
debug!(?toplevel, active, "Pointer set active");
|
||||
|
||||
panel_item.seat_data.set_pointer_active(&toplevel, active);
|
||||
panel_item.flush_clients();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn keyboard_set_keymap_string_flex(
|
||||
node: &Node,
|
||||
@@ -397,38 +413,32 @@ impl PanelItem {
|
||||
}
|
||||
fn keyboard_set_keymap_flex(node: &Node, keymap: &Keymap) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Ok(toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
let toplevel = panel_item.toplevel_wl_surface();
|
||||
debug!(?toplevel, "Keyboard set keymap");
|
||||
|
||||
panel_item.seat_data.set_keymap(&toplevel, keymap);
|
||||
let mut surfaces = vec![toplevel];
|
||||
surfaces.extend(panel_item.popups.lock().values().filter_map(|p| {
|
||||
let popup = p.upgrade().ok()?;
|
||||
let popup_data = PopupData::get(&popup).lock();
|
||||
let xdg_surface = popup_data.xdg_surface();
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
|
||||
Some(xdg_surface_data.wl_surface())
|
||||
}));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn keyboard_set_active_flex(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Ok(toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
let active: bool = deserialize(data)?;
|
||||
debug!(?toplevel, active, "Keyboard set active");
|
||||
|
||||
panel_item.seat_data.set_keyboard_active(&toplevel, active);
|
||||
panel_item.seat_data.set_keymap(keymap, surfaces);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn keyboard_key_flex(node: &Node, _calling_client: Arc<Client>, data: &[u8]) -> Result<()> {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Ok(toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
let (key, state): (u32, u32) = deserialize(data)?;
|
||||
let (surface_id, key, state): (SurfaceID, u32, u32) = deserialize(data)?;
|
||||
let wl_surface = panel_item.wl_surface_from_id_result(&surface_id)?;
|
||||
debug!(key, state, "Set keyboard key state");
|
||||
|
||||
panel_item
|
||||
.seat_data
|
||||
.keyboard_event(&toplevel, KeyboardEvent::Key { key, state });
|
||||
.keyboard_event(&wl_surface, KeyboardEvent::Key { key, state });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -441,7 +451,7 @@ impl PanelItem {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
|
||||
let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
let Some(xdg_surface) = panel_item.toplevel_surface_data().and_then(|d| d.xdg_surface.upgrade().ok()) else { return Ok(()) };
|
||||
let xdg_surface = panel_item.toplevel_xdg_surface();
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ConfigureToplevelInfo {
|
||||
@@ -452,9 +462,6 @@ impl PanelItem {
|
||||
|
||||
let info: ConfigureToplevelInfo = deserialize(data)?;
|
||||
debug!(info = ?&info, "Configure toplevel info");
|
||||
if let Some(xdg_state) = panel_item.toplevel_state() {
|
||||
xdg_state.lock().queued_state.as_mut().unwrap().states = info.states.clone();
|
||||
}
|
||||
if let Some(bounds) = info.bounds {
|
||||
if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE {
|
||||
xdg_toplevel.configure_bounds(bounds.x as i32, bounds.y as i32);
|
||||
@@ -483,7 +490,10 @@ impl PanelItem {
|
||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
|
||||
let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
let Some(xdg_surface) = panel_item.toplevel_surface_data().and_then(|d| d.xdg_surface.upgrade().ok()) else { return Ok(()) };
|
||||
if xdg_toplevel.version() < EVT_WM_CAPABILITIES_SINCE {
|
||||
return Ok(());
|
||||
}
|
||||
let xdg_surface = panel_item.toplevel_xdg_surface();
|
||||
|
||||
let capabilities: Vec<u8> = deserialize(data)?;
|
||||
debug!("Set toplevel capabilities");
|
||||
@@ -495,23 +505,22 @@ impl PanelItem {
|
||||
}
|
||||
|
||||
pub fn commit_toplevel(&self) {
|
||||
let mapped_size = self.core_surface().and_then(|c| c.size());
|
||||
let Some(state) = self.toplevel_state() else { return };
|
||||
let mut state = state.lock();
|
||||
let mut queued_state = state.queued_state.take().unwrap();
|
||||
queued_state.mapped = mapped_size.is_some();
|
||||
if let Some(size) = mapped_size {
|
||||
queued_state.size = size;
|
||||
}
|
||||
*state = (*queued_state).clone();
|
||||
state.queued_state = Some(queued_state);
|
||||
// let mapped_size = self.core_surface().and_then(|c| c.size());
|
||||
let toplevel = self.toplevel();
|
||||
let state = ToplevelData::get(&toplevel);
|
||||
let state = state.lock();
|
||||
// let mut queued_state = state.queued_state.take().unwrap();
|
||||
// queued_state.mapped = mapped_size.is_some();
|
||||
// if let Some(size) = mapped_size {
|
||||
// queued_state.size = size;
|
||||
// queued_state.geometry.update_to_surface_size(size);
|
||||
// }
|
||||
// *state = (*queued_state).clone();
|
||||
// state.queued_state = Some(queued_state);
|
||||
|
||||
debug!(state = ?&state.mapped.then_some(&*state), "Commit toplevel");
|
||||
debug!(state = ?&*state, "Commit toplevel");
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
let _ = node.send_remote_signal(
|
||||
"commit_toplevel",
|
||||
&serialize(&state.mapped.then_some(&*state)).unwrap(),
|
||||
);
|
||||
let _ = node.send_remote_signal("commit_toplevel", &serialize(&*state).unwrap());
|
||||
}
|
||||
|
||||
pub fn recommend_toplevel_state(&self, state: RecommendedState) {
|
||||
@@ -522,6 +531,56 @@ impl PanelItem {
|
||||
let _ = node.send_remote_signal("recommend_toplevel_state", &data);
|
||||
}
|
||||
|
||||
pub fn new_popup(&self, popup: &XdgPopup, data: &PopupData) {
|
||||
let uid = data.uid.clone();
|
||||
|
||||
self.popups.lock().insert(uid.clone(), popup.downgrade());
|
||||
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
let _ = node.send_remote_signal("new_popup", &serialize(&(&uid, data)).unwrap());
|
||||
}
|
||||
// pub fn commit_popup(&self, data: &PopupData) {
|
||||
// let xdg_surf = data.xdg_surface.upgrade().unwrap();
|
||||
// let surf = xdg_surf
|
||||
// .data::<XdgSurfaceData>()
|
||||
// .unwrap()
|
||||
// .wl_surface
|
||||
// .upgrade()
|
||||
// .unwrap();
|
||||
|
||||
// let core_surface =
|
||||
// compositor::with_states(&surf, |s| s.data_map.get::<Arc<CoreSurface>>().cloned())
|
||||
// .unwrap();
|
||||
// let mut popup_state = data.state.lock();
|
||||
// popup_state.mapped = core_surface.size().is_some();
|
||||
// }
|
||||
pub fn reposition_popup(&self, popup_state: &PopupData) {
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
|
||||
let _ = node.send_remote_signal(
|
||||
"reposition_popup",
|
||||
&serialize(popup_state.positioner_data().unwrap()).unwrap(),
|
||||
);
|
||||
}
|
||||
pub fn drop_popup(&self, uid: &str) {
|
||||
if let Some(popup) = self
|
||||
.popups
|
||||
.lock()
|
||||
.remove(uid)
|
||||
.and_then(|popup| popup.upgrade().ok()?.data::<Arc<PopupData>>().cloned())
|
||||
{
|
||||
self.seat_data.drop_surface(&popup.wl_surface());
|
||||
}
|
||||
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
let _ = node.send_remote_signal("drop_popup", &serialize(uid).unwrap());
|
||||
}
|
||||
|
||||
pub fn grab_keyboard(&self, sid: Option<SurfaceID>) {
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
|
||||
let _ = node.send_remote_signal("grab_keyboard", &serialize(sid).unwrap());
|
||||
}
|
||||
pub fn set_cursor(&self, surface: Option<&WlSurface>, hotspot_x: i32, hotspot_y: i32) {
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
debug!(?surface, hotspot_x, hotspot_y, "Set cursor size");
|
||||
@@ -540,8 +599,8 @@ impl PanelItem {
|
||||
}
|
||||
|
||||
pub fn on_drop(&self) {
|
||||
let Ok(toplevel) = self.toplevel.upgrade() else { return; };
|
||||
self.seat_data.drop_panel_item(&toplevel);
|
||||
let toplevel = self.toplevel_wl_surface();
|
||||
self.seat_data.drop_surface(&toplevel);
|
||||
|
||||
debug!("Drop panel item");
|
||||
}
|
||||
@@ -559,12 +618,35 @@ impl ItemSpecialization for PanelItem {
|
||||
})
|
||||
.map(|cursor| cursor.hotspot);
|
||||
|
||||
let toplevel_state = self.toplevel_state();
|
||||
let toplevel_state = toplevel_state.as_ref().map(|state| state.lock());
|
||||
let toplevel_state = toplevel_state
|
||||
.as_ref()
|
||||
.and_then(|state| state.mapped.then_some(&**state));
|
||||
let toplevel = self.toplevel();
|
||||
let toplevel_state = ToplevelData::get(&toplevel);
|
||||
let toplevel_state = toplevel_state.lock().clone();
|
||||
|
||||
serialize((id, (toplevel_state, cursor_size.zip(cursor_hotspot)))).unwrap()
|
||||
let popups = self
|
||||
.popups
|
||||
.lock()
|
||||
.values()
|
||||
.filter_map(|v| Some(v.upgrade().ok()?.data::<Mutex<PopupData>>()?.lock().clone()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let pointer_grab = self.pointer_grab.lock().clone();
|
||||
let keyboard_grab = self.keyboard_grab.lock().clone();
|
||||
|
||||
serialize((
|
||||
id,
|
||||
(
|
||||
cursor_size.zip(cursor_hotspot),
|
||||
toplevel_state,
|
||||
popups,
|
||||
pointer_grab,
|
||||
keyboard_grab,
|
||||
),
|
||||
))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl Drop for PanelItem {
|
||||
fn drop(&mut self) {
|
||||
// Dropped panel item, basically just a debug breakpoint place
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::core::task;
|
||||
|
||||
use super::{
|
||||
panel_item::PanelItem, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE,
|
||||
SERIAL_COUNTER,
|
||||
};
|
||||
use crate::core::task;
|
||||
use color_eyre::eyre::Result;
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
@@ -13,20 +12,16 @@ use rand::{seq::IteratorRandom, thread_rng};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use smithay::{
|
||||
input::keyboard::{KeymapFile, ModifiersState},
|
||||
reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel,
|
||||
wayland_server::{
|
||||
backend::{ClientId, GlobalId, ObjectId},
|
||||
protocol::{
|
||||
wl_keyboard::{self, KeyState, WlKeyboard},
|
||||
wl_pointer::{self, Axis, ButtonState, WlPointer},
|
||||
wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE},
|
||||
wl_surface::WlSurface,
|
||||
wl_touch::{self, WlTouch},
|
||||
},
|
||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource,
|
||||
Weak as WlWeak,
|
||||
reexports::wayland_server::{
|
||||
backend::{ClientId, GlobalId, ObjectId},
|
||||
protocol::{
|
||||
wl_keyboard::{self, KeyState, WlKeyboard},
|
||||
wl_pointer::{self, Axis, ButtonState, WlPointer},
|
||||
wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE},
|
||||
wl_surface::WlSurface,
|
||||
wl_touch::{self, WlTouch},
|
||||
},
|
||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak as WlWeak,
|
||||
},
|
||||
wayland::compositor,
|
||||
};
|
||||
@@ -48,7 +43,7 @@ impl KeyboardInfo {
|
||||
pub fn new(keymap: &Keymap) -> Self {
|
||||
KeyboardInfo {
|
||||
state: xkb::State::new(keymap),
|
||||
keymap: KeymapFile::new(keymap, None),
|
||||
keymap: KeymapFile::new(keymap),
|
||||
mods: ModifiersState::default(),
|
||||
keys: FxHashSet::default(),
|
||||
}
|
||||
@@ -109,51 +104,34 @@ pub enum KeyboardEvent {
|
||||
}
|
||||
|
||||
const POINTER_EVENT_TIMEOUT: Duration = Duration::from_secs(1);
|
||||
struct PanelInfo {
|
||||
struct SurfaceInfo {
|
||||
wl_surface: WlWeak<WlSurface>,
|
||||
panel_item: Weak<PanelItem>,
|
||||
toplevel: WlWeak<XdgToplevel>,
|
||||
focus: WlWeak<WlSurface>,
|
||||
pointer_queue: Option<VecDeque<PointerEvent>>,
|
||||
pointer_queue: VecDeque<PointerEvent>,
|
||||
pointer_latest_event: Instant,
|
||||
keyboard_queue: Option<VecDeque<KeyboardEvent>>,
|
||||
keyboard_queue: VecDeque<KeyboardEvent>,
|
||||
keyboard_info: Option<KeyboardInfo>,
|
||||
}
|
||||
impl PanelInfo {
|
||||
fn new(panel_item: &Arc<PanelItem>, toplevel: &XdgToplevel, focus: &WlSurface) -> Self {
|
||||
PanelInfo {
|
||||
toplevel: toplevel.downgrade(),
|
||||
panel_item: Arc::downgrade(panel_item),
|
||||
focus: focus.downgrade(),
|
||||
pointer_queue: None,
|
||||
impl SurfaceInfo {
|
||||
fn new(wl_surface: &WlSurface, panel_item: Weak<PanelItem>) -> Self {
|
||||
SurfaceInfo {
|
||||
wl_surface: wl_surface.downgrade(),
|
||||
panel_item,
|
||||
pointer_queue: VecDeque::new(),
|
||||
pointer_latest_event: Instant::now(),
|
||||
keyboard_queue: None,
|
||||
keyboard_queue: VecDeque::new(),
|
||||
keyboard_info: None,
|
||||
}
|
||||
}
|
||||
pub fn set_pointer_active(&mut self, seat_data: &SeatData, active: bool) {
|
||||
if active && self.pointer_queue.is_none() {
|
||||
self.pointer_queue.replace(Default::default());
|
||||
}
|
||||
|
||||
if !active && self.pointer_queue.is_some() {
|
||||
self.pointer_queue.take();
|
||||
let Ok(focus) = self.focus.upgrade() else {return};
|
||||
let Some((pointer, pointer_focus)) = seat_data.pointer.get() else {return};
|
||||
if &*pointer_focus.lock() == &Some(self.toplevel.id()) {
|
||||
pointer.leave(SERIAL_COUNTER.inc(), &focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn handle_pointer_events(&mut self, pointer: &WlPointer, mut locked: bool) -> bool {
|
||||
let Ok(focus) = self.focus.upgrade() else { return false; };
|
||||
let Some(pointer_queue) = self.pointer_queue.as_mut() else { return false; };
|
||||
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; };
|
||||
let Some(focus_size) = core_surface.size() else { return false; };
|
||||
|
||||
if !pointer_queue.is_empty() {
|
||||
if !self.pointer_queue.is_empty() {
|
||||
self.pointer_latest_event = Instant::now();
|
||||
}
|
||||
while let Some(event) = pointer_queue.pop_front() {
|
||||
while let Some(event) = self.pointer_queue.pop_front() {
|
||||
match (locked, event) {
|
||||
(false, PointerEvent::Motion(pos)) => {
|
||||
pointer.enter(
|
||||
@@ -218,22 +196,8 @@ impl PanelInfo {
|
||||
|
||||
locked
|
||||
}
|
||||
pub fn set_keyboard_active(&mut self, seat_data: &SeatData, active: bool) {
|
||||
if active && self.keyboard_queue.is_none() {
|
||||
self.keyboard_queue.replace(Default::default());
|
||||
}
|
||||
if !active && self.keyboard_queue.is_some() {
|
||||
self.keyboard_queue.take();
|
||||
let Ok(focus) = self.focus.upgrade() else {return};
|
||||
let Some((keyboard, keyboard_focus)) = seat_data.keyboard.get() else {return};
|
||||
if &*keyboard_focus.lock() == &Some(self.toplevel.id()) {
|
||||
keyboard.leave(SERIAL_COUNTER.inc(), &focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, mut locked: bool) -> bool {
|
||||
let Ok(focus) = self.focus.upgrade() else { return false; };
|
||||
let Some(keyboard_queue) = self.keyboard_queue.as_mut() else { return false; };
|
||||
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
||||
let Some(info) = self.keyboard_info.as_mut() else { return true; };
|
||||
|
||||
if !locked {
|
||||
@@ -241,7 +205,7 @@ impl PanelInfo {
|
||||
keyboard.repeat_info(0, 0);
|
||||
locked = info.keymap.send(keyboard).is_ok();
|
||||
}
|
||||
while let Some(event) = keyboard_queue.pop_front() {
|
||||
while let Some(event) = self.keyboard_queue.pop_front() {
|
||||
debug!(locked, ?event, "Process keyboard event");
|
||||
match (locked, event) {
|
||||
(true, KeyboardEvent::Keymap) => {
|
||||
@@ -267,9 +231,9 @@ impl PanelInfo {
|
||||
pub struct SeatData {
|
||||
client: ClientId,
|
||||
global_id: OnceCell<GlobalId>,
|
||||
panels: Mutex<FxHashMap<ObjectId, PanelInfo>>,
|
||||
pointer: OnceCell<(WlPointer, Mutex<Option<ObjectId>>)>,
|
||||
keyboard: OnceCell<(WlKeyboard, Mutex<Option<ObjectId>>)>,
|
||||
surfaces: Mutex<FxHashMap<ObjectId, SurfaceInfo>>,
|
||||
pointer: OnceCell<(WlPointer, Mutex<ObjectId>)>,
|
||||
keyboard: OnceCell<(WlKeyboard, Mutex<ObjectId>)>,
|
||||
touch: OnceCell<WlTouch>,
|
||||
}
|
||||
impl SeatData {
|
||||
@@ -277,7 +241,7 @@ impl SeatData {
|
||||
let seat_data = Arc::new(SeatData {
|
||||
client,
|
||||
global_id: OnceCell::new(),
|
||||
panels: Mutex::new(FxHashMap::default()),
|
||||
surfaces: Mutex::new(FxHashMap::default()),
|
||||
pointer: OnceCell::new(),
|
||||
keyboard: OnceCell::new(),
|
||||
touch: OnceCell::new(),
|
||||
@@ -291,144 +255,111 @@ impl SeatData {
|
||||
seat_data
|
||||
}
|
||||
|
||||
// pub fn set_focus(&self, toplevel: &WlSurface, focus: &WlSurface) {
|
||||
// if let Some(panel_info) = self.panels.lock().get_mut(&toplevel.id()) {
|
||||
// panel_info.focus = focus.downgrade();
|
||||
// match panel_info.pointer_queue.back() {
|
||||
// None => (),
|
||||
// Some(&PointerEvent::Leave) => (),
|
||||
// _ => panel_info.pointer_queue.push_back(PointerEvent::Leave),
|
||||
// };
|
||||
// match panel_info.keyboard_queue.back() {
|
||||
// None => (),
|
||||
// Some(&KeyboardEvent::Leave) => (),
|
||||
// _ => panel_info.keyboard_queue.push_back(KeyboardEvent::Leave),
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
pub fn set_pointer_active(&self, toplevel: &XdgToplevel, active: bool) {
|
||||
let mut panels = self.panels.lock();
|
||||
let Some(panel_info) = panels.get_mut(&toplevel.id()) else {return};
|
||||
panel_info.set_pointer_active(self, active);
|
||||
}
|
||||
pub fn set_keyboard_active(&self, toplevel: &XdgToplevel, active: bool) {
|
||||
let mut panels = self.panels.lock();
|
||||
let Some(panel_info) = panels.get_mut(&toplevel.id()) else {return};
|
||||
panel_info.set_keyboard_active(self, active);
|
||||
}
|
||||
pub fn set_keymap(&self, toplevel: &XdgToplevel, keymap: &Keymap) {
|
||||
let mut panels = self.panels.lock();
|
||||
let Some(panel_info) = panels.get_mut(&toplevel.id()) else {return};
|
||||
panel_info.keyboard_info.replace(KeyboardInfo::new(keymap));
|
||||
|
||||
let Some(keyboard_queue) = panel_info.keyboard_queue.as_mut() else {return};
|
||||
pub fn set_keymap(&self, keymap: &Keymap, surfaces: Vec<WlSurface>) {
|
||||
let mut panels = self.surfaces.lock();
|
||||
let Some((_, focus)) = self.keyboard.get() else {return};
|
||||
let Some(id) = &*focus.lock() else {return};
|
||||
if id == &toplevel.id() {
|
||||
keyboard_queue.push_back(KeyboardEvent::Keymap);
|
||||
for surface in surfaces {
|
||||
let Some(surface_info) = panels.get_mut(&surface.id()) else {continue};
|
||||
surface_info
|
||||
.keyboard_info
|
||||
.replace(KeyboardInfo::new(keymap));
|
||||
|
||||
if *focus.lock() == surface.id() {
|
||||
surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pointer_event(&self, toplevel: &XdgToplevel, event: PointerEvent) {
|
||||
let mut panels = self.panels.lock();
|
||||
let Some(panel_info) = panels.get_mut(&toplevel.id()) else {return};
|
||||
let Some(pointer_queue) = panel_info.pointer_queue.as_mut() else {return};
|
||||
pointer_queue.push_back(event);
|
||||
drop(panels);
|
||||
pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) {
|
||||
let mut surfaces = self.surfaces.lock();
|
||||
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
||||
surface_info.pointer_queue.push_back(event);
|
||||
drop(surfaces);
|
||||
self.handle_pointer_events();
|
||||
}
|
||||
pub fn keyboard_event(&self, toplevel: &XdgToplevel, event: KeyboardEvent) {
|
||||
let mut panels = self.panels.lock();
|
||||
let Some(panel_info) = panels.get_mut(&toplevel.id()) else {return};
|
||||
let Some(keyboard_queue) = panel_info.keyboard_queue.as_mut() else {return};
|
||||
keyboard_queue.push_back(event);
|
||||
drop(panels);
|
||||
pub fn keyboard_event(&self, surface: &WlSurface, event: KeyboardEvent) {
|
||||
let mut surfaces = self.surfaces.lock();
|
||||
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
||||
surface_info.keyboard_queue.push_back(event);
|
||||
drop(surfaces);
|
||||
self.handle_keyboard_events();
|
||||
}
|
||||
|
||||
fn handle_pointer_events(&self) {
|
||||
let mut panels = self.panels.lock();
|
||||
let mut surfaces = self.surfaces.lock();
|
||||
let Some((pointer, pointer_focus)) = self.pointer.get() else {return};
|
||||
let mut pointer_focus = pointer_focus.lock();
|
||||
|
||||
loop {
|
||||
let locked = pointer_focus.is_some();
|
||||
let locked = !pointer_focus.is_null();
|
||||
// Pick a pointer to focus on if there is none
|
||||
if pointer_focus.is_none() {
|
||||
*pointer_focus = panels
|
||||
if pointer_focus.is_null() {
|
||||
*pointer_focus = surfaces
|
||||
.iter()
|
||||
.filter(|(_k, v)| v.pointer_queue.is_some())
|
||||
.filter(|(_k, v)| !v.pointer_queue.as_ref().unwrap().is_empty())
|
||||
.filter(|(_k, v)| !v.pointer_queue.is_empty())
|
||||
.map(|(k, _v)| k)
|
||||
.choose(&mut thread_rng())
|
||||
.cloned();
|
||||
.cloned()
|
||||
.unwrap_or(ObjectId::null());
|
||||
}
|
||||
if pointer_focus.is_none() {
|
||||
if pointer_focus.is_null() {
|
||||
// If there's still none, guess we're done with pointer events for the time being
|
||||
break;
|
||||
}
|
||||
let Some(panel_info) = panels.get_mut(pointer_focus.as_ref().unwrap()) else {break};
|
||||
if panel_info.handle_pointer_events(pointer, locked) {
|
||||
let Some(surface_info) = surfaces.get_mut(&pointer_focus) else {break};
|
||||
if surface_info.handle_pointer_events(pointer, locked) {
|
||||
// We haven't gotten to a point where we can switch the focus
|
||||
break;
|
||||
} else {
|
||||
pointer_focus.take();
|
||||
*pointer_focus = ObjectId::null();
|
||||
}
|
||||
}
|
||||
}
|
||||
fn handle_keyboard_events(&self) {
|
||||
let mut panels = self.panels.lock();
|
||||
let mut surfaces = self.surfaces.lock();
|
||||
let Some((keyboard, keyboard_focus)) = self.keyboard.get() else {return};
|
||||
let mut keyboard_focus = keyboard_focus.lock();
|
||||
loop {
|
||||
let locked = keyboard_focus.is_some();
|
||||
let locked = !keyboard_focus.is_null();
|
||||
// Pick a keyboard to focus on if there is none
|
||||
if keyboard_focus.is_none() {
|
||||
*keyboard_focus = panels
|
||||
if keyboard_focus.is_null() {
|
||||
*keyboard_focus = surfaces
|
||||
.iter()
|
||||
.filter(|(_k, v)| v.keyboard_info.is_some())
|
||||
.filter(|(_k, v)| v.keyboard_queue.is_some())
|
||||
.filter(|(_k, v)| !v.keyboard_queue.as_ref().unwrap().is_empty())
|
||||
.filter(|(_k, v)| !v.keyboard_queue.is_empty())
|
||||
.map(|(k, _v)| k)
|
||||
.choose(&mut thread_rng())
|
||||
.cloned();
|
||||
.cloned()
|
||||
.unwrap_or(ObjectId::null());
|
||||
}
|
||||
if keyboard_focus.is_none() {
|
||||
// If there's still none, guess we're done with keyboard events for the time being
|
||||
break;
|
||||
}
|
||||
let Some(panel_info) = panels.get_mut(keyboard_focus.as_ref().unwrap()) else {break};
|
||||
if panel_info.handle_keyboard_events(keyboard, locked) {
|
||||
// If there's still none, guess we're done with keyboard events for the time being
|
||||
let Some(surface_info) = surfaces.get_mut(&keyboard_focus) else {break};
|
||||
if surface_info.handle_keyboard_events(keyboard, locked) {
|
||||
// We haven't gotten to a point where we can switch the focus
|
||||
break;
|
||||
} else {
|
||||
keyboard_focus.take();
|
||||
*keyboard_focus = ObjectId::null();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_panel_item(
|
||||
&self,
|
||||
panel_item: &Arc<PanelItem>,
|
||||
toplevel: &XdgToplevel,
|
||||
focus: &WlSurface,
|
||||
) {
|
||||
self.panels
|
||||
pub fn new_surface(&self, surface: &WlSurface, panel_item: Weak<PanelItem>) {
|
||||
self.surfaces
|
||||
.lock()
|
||||
.insert(toplevel.id(), PanelInfo::new(panel_item, toplevel, focus));
|
||||
.insert(surface.id(), SurfaceInfo::new(surface, panel_item));
|
||||
}
|
||||
pub fn drop_panel_item(&self, toplevel: &XdgToplevel) {
|
||||
self.panels.lock().remove(&toplevel.id());
|
||||
pub fn drop_surface(&self, surface: &WlSurface) {
|
||||
self.surfaces.lock().remove(&surface.id());
|
||||
if let Some((_, pointer_focus)) = self.pointer.get() {
|
||||
let mut pointer_focus = pointer_focus.lock();
|
||||
if *pointer_focus == Some(toplevel.id()) {
|
||||
pointer_focus.take();
|
||||
if *pointer_focus == surface.id() {
|
||||
*pointer_focus = ObjectId::null();
|
||||
}
|
||||
}
|
||||
if let Some((_, keyboard_focus)) = self.keyboard.get() {
|
||||
let mut keyboard_focus = keyboard_focus.lock();
|
||||
if *keyboard_focus == Some(toplevel.id()) {
|
||||
keyboard_focus.take();
|
||||
if *keyboard_focus == surface.id() {
|
||||
*keyboard_focus = ObjectId::null();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,12 +409,12 @@ impl Dispatch<WlSeat, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
match request {
|
||||
wl_seat::Request::GetPointer { id } => {
|
||||
let pointer = data_init.init(id, data.clone());
|
||||
let _ = data.pointer.set((pointer, Mutex::new(None)));
|
||||
let _ = data.pointer.set((pointer, Mutex::new(ObjectId::null())));
|
||||
}
|
||||
wl_seat::Request::GetKeyboard { id } => {
|
||||
let keyboard = data_init.init(id, data.clone());
|
||||
keyboard.repeat_info(0, 0);
|
||||
let _ = data.keyboard.set((keyboard, Mutex::new(None)));
|
||||
let _ = data.keyboard.set((keyboard, Mutex::new(ObjectId::null())));
|
||||
}
|
||||
wl_seat::Request::GetTouch { id } => {
|
||||
let _ = data.touch.set(data_init.init(id, data.clone()));
|
||||
@@ -515,7 +446,7 @@ impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
hotspot_y,
|
||||
} => {
|
||||
if let Some(surface) = surface.as_ref() {
|
||||
CoreSurface::add_to(&state.display, dh.clone(), surface);
|
||||
CoreSurface::add_to(&state.display, dh.clone(), surface, |_| ());
|
||||
compositor::with_states(surface, |data| {
|
||||
data.data_map.insert_if_missing_threadsafe(|| {
|
||||
Arc::new(Mutex::new(Cursor {
|
||||
@@ -533,10 +464,9 @@ impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
|
||||
|
||||
let Some((_, focus)) = seat_data.pointer.get() else {return};
|
||||
let focus = focus.lock();
|
||||
let Some(id) = &*focus else {return};
|
||||
let panels = seat_data.panels.lock();
|
||||
let Some(panel_info) = panels.get(&id) else {return};
|
||||
let Some(panel_item) = panel_info.panel_item.upgrade() else {return};
|
||||
let surfaces = seat_data.surfaces.lock();
|
||||
let Some(surface_info) = surfaces.get(&focus) else {return};
|
||||
let Some(panel_item) = surface_info.panel_item.upgrade() else {return};
|
||||
panel_item.set_cursor(surface.as_ref(), hotspot_x, hotspot_y);
|
||||
}
|
||||
wl_pointer::Request::Release => (),
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use crate::wayland::seat::SeatData;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use slog::Logger;
|
||||
use smithay::{
|
||||
backend::{
|
||||
allocator::dmabuf::Dmabuf,
|
||||
renderer::{gles2::Gles2Renderer, ImportDma},
|
||||
renderer::{gles::GlesRenderer, ImportDma},
|
||||
},
|
||||
delegate_dmabuf, delegate_output, delegate_shm,
|
||||
output::{Mode, Output, Scale, Subpixel},
|
||||
@@ -49,7 +48,6 @@ impl ClientData for ClientState {
|
||||
|
||||
pub struct WaylandState {
|
||||
pub weak_ref: Weak<Mutex<WaylandState>>,
|
||||
pub log: Logger,
|
||||
pub display: Arc<Mutex<Display<WaylandState>>>,
|
||||
pub display_handle: DisplayHandle,
|
||||
|
||||
@@ -66,24 +64,19 @@ pub struct WaylandState {
|
||||
|
||||
impl WaylandState {
|
||||
pub fn new(
|
||||
log: Logger,
|
||||
display: Arc<Mutex<Display<WaylandState>>>,
|
||||
display_handle: DisplayHandle,
|
||||
renderer: &Gles2Renderer,
|
||||
renderer: &GlesRenderer,
|
||||
) -> Arc<Mutex<Self>> {
|
||||
let compositor_state = CompositorState::new::<Self, _>(&display_handle, log.clone());
|
||||
// let xdg_activation_state = XdgActivationState::new::<Self, _>(&display_handle, log.clone());
|
||||
let kde_decoration_state = KdeDecorationState::new::<Self, _>(
|
||||
&display_handle,
|
||||
DecorationMode::Server,
|
||||
log.clone(),
|
||||
);
|
||||
let shm_state = ShmState::new::<Self, _>(&display_handle, vec![], log.clone());
|
||||
let compositor_state = CompositorState::new::<Self>(&display_handle);
|
||||
// let xdg_activation_state = XdgActivationState::new::<Self, _>(&display_handle);
|
||||
let kde_decoration_state =
|
||||
KdeDecorationState::new::<Self>(&display_handle, DecorationMode::Server);
|
||||
let shm_state = ShmState::new::<Self>(&display_handle, vec![]);
|
||||
let mut dmabuf_state = DmabufState::new();
|
||||
let dmabuf_global = dmabuf_state.create_global::<Self, _>(
|
||||
let dmabuf_global = dmabuf_state.create_global::<Self>(
|
||||
&display_handle,
|
||||
renderer.dmabuf_formats().cloned().collect::<Vec<_>>(),
|
||||
log.clone(),
|
||||
renderer.dmabuf_formats().collect::<Vec<_>>(),
|
||||
);
|
||||
let output = Output::new(
|
||||
"1x".to_owned(),
|
||||
@@ -93,18 +86,19 @@ impl WaylandState {
|
||||
make: "Virtual XR Display".to_owned(),
|
||||
model: "Your Headset Name Here".to_owned(),
|
||||
},
|
||||
log.clone(),
|
||||
);
|
||||
let _output_global = output.create_global::<Self>(&display_handle);
|
||||
let mode = Mode {
|
||||
size: (4096, 4096).into(),
|
||||
refresh: 60000,
|
||||
};
|
||||
output.change_current_state(
|
||||
Some(Mode {
|
||||
size: (4096, 4096).into(),
|
||||
refresh: 60000,
|
||||
}),
|
||||
Some(mode),
|
||||
Some(Transform::Normal),
|
||||
Some(Scale::Integer(2)),
|
||||
None,
|
||||
);
|
||||
output.set_preferred(mode);
|
||||
display_handle.create_global::<Self, WlDataDeviceManager, _>(3, ());
|
||||
display_handle.create_global::<Self, XdgWmBase, _>(5, ());
|
||||
display_handle.create_global::<Self, ZxdgDecorationManagerV1, _>(1, ());
|
||||
@@ -114,7 +108,6 @@ impl WaylandState {
|
||||
Arc::new_cyclic(|weak| {
|
||||
Mutex::new(WaylandState {
|
||||
weak_ref: weak.clone(),
|
||||
log,
|
||||
display,
|
||||
display_handle,
|
||||
|
||||
|
||||
@@ -7,10 +7,9 @@ use mint::Vector2;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use send_wrapper::SendWrapper;
|
||||
use slog::Logger;
|
||||
use smithay::{
|
||||
backend::renderer::{
|
||||
gles2::{Gles2Renderer, Gles2Texture},
|
||||
gles::{GlesRenderer, GlesTexture},
|
||||
utils::{import_surface_tree, on_commit_buffer_handler, RendererSurfaceStateUserData},
|
||||
Renderer, Texture,
|
||||
},
|
||||
@@ -35,22 +34,8 @@ use stereokit::{
|
||||
|
||||
pub static CORE_SURFACES: Registry<CoreSurface> = Registry::new();
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SurfaceGeometry {
|
||||
pub origin: Vector2<u32>,
|
||||
pub size: Vector2<u32>,
|
||||
}
|
||||
impl Default for SurfaceGeometry {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
origin: [0; 2].into(),
|
||||
size: [0; 2].into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CoreSurfaceData {
|
||||
wl_tex: Option<SendWrapper<Gles2Texture>>,
|
||||
wl_tex: Option<SendWrapper<GlesTexture>>,
|
||||
pub size: Vector2<u32>,
|
||||
}
|
||||
impl Drop for CoreSurfaceData {
|
||||
@@ -67,7 +52,7 @@ pub struct CoreSurface {
|
||||
sk_tex: OnceCell<SendWrapper<SKTexture>>,
|
||||
sk_mat: OnceCell<Arc<SendWrapper<Material>>>,
|
||||
material_offset: Mutex<Delta<u32>>,
|
||||
// geometry: Mutex<Delta<Option<SurfaceGeometry>>>,
|
||||
on_commit: Box<dyn Fn(u32) + Send + Sync>,
|
||||
pub pending_material_applications: Mutex<Vec<(Arc<Model>, u32)>>,
|
||||
}
|
||||
|
||||
@@ -76,11 +61,9 @@ impl CoreSurface {
|
||||
display: &Arc<Mutex<Display<WaylandState>>>,
|
||||
dh: DisplayHandle,
|
||||
surface: &WlSurface,
|
||||
on_commit: impl Fn(u32) + Send + Sync + 'static,
|
||||
) {
|
||||
compositor::with_states(surface, |data| {
|
||||
// let mut geometry: Delta<Option<SurfaceGeometry>> =
|
||||
// Delta::new(data.data_map.get::<SurfaceGeometry>().cloned());
|
||||
// geometry.mark_changed();
|
||||
data.data_map.insert_if_missing_threadsafe(|| {
|
||||
CORE_SURFACES.add(CoreSurface {
|
||||
display: Arc::downgrade(display),
|
||||
@@ -90,20 +73,24 @@ impl CoreSurface {
|
||||
sk_tex: OnceCell::new(),
|
||||
sk_mat: OnceCell::new(),
|
||||
material_offset: Mutex::new(Delta::new(0)),
|
||||
// geometry: Mutex::new(geometry),
|
||||
on_commit: Box::new(on_commit) as Box<dyn Fn(u32) + Send + Sync>,
|
||||
pending_material_applications: Mutex::new(Vec::new()),
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn commit(&self, count: u32) {
|
||||
(self.on_commit)(count);
|
||||
}
|
||||
|
||||
pub fn from_wl_surface(surf: &WlSurface) -> Option<Arc<CoreSurface>> {
|
||||
compositor::with_states(surf, |data| {
|
||||
data.data_map.get::<Arc<CoreSurface>>().cloned()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process(&self, sk: &StereoKitDraw, renderer: &mut Gles2Renderer, log: &Logger) {
|
||||
pub fn process(&self, sk: &StereoKitDraw, renderer: &mut GlesRenderer) {
|
||||
let Some(wl_surface) = self.wl_surface() else { return };
|
||||
|
||||
let sk_tex = self.sk_tex.get_or_init(|| {
|
||||
@@ -122,14 +109,14 @@ impl CoreSurface {
|
||||
// Let smithay handle buffer management (has to be done here as RendererSurfaceStates is not thread safe)
|
||||
on_commit_buffer_handler(&wl_surface);
|
||||
// Import all surface buffers into textures
|
||||
if import_surface_tree(renderer, &wl_surface, log).is_err() {
|
||||
if import_surface_tree(renderer, &wl_surface).is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mapped = compositor::with_states(&wl_surface, |data| {
|
||||
data.data_map
|
||||
.get::<RendererSurfaceStateUserData>()
|
||||
.map(|surface_states| surface_states.borrow().wl_buffer().is_some())
|
||||
.map(|surface_states| surface_states.borrow().buffer().is_some())
|
||||
.unwrap_or(false)
|
||||
});
|
||||
|
||||
@@ -147,7 +134,7 @@ impl CoreSurface {
|
||||
.unwrap()
|
||||
.borrow();
|
||||
let smithay_tex = renderer_surface_state
|
||||
.texture::<Gles2Renderer>(renderer.id())
|
||||
.texture::<GlesRenderer>(renderer.id())
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
@@ -156,7 +143,7 @@ impl CoreSurface {
|
||||
unsafe {
|
||||
sk_tex.set_native(
|
||||
smithay_tex.tex_id() as usize,
|
||||
smithay::backend::renderer::gles2::ffi::RGBA8.into(),
|
||||
smithay::backend::renderer::gles::ffi::RGBA8.into(),
|
||||
TextureType::ImageNoMips,
|
||||
smithay_tex.width(),
|
||||
smithay_tex.height(),
|
||||
@@ -195,10 +182,6 @@ impl CoreSurface {
|
||||
*self.material_offset.lock().value_mut() = material_offset;
|
||||
}
|
||||
|
||||
// pub fn set_geometry(&self, geometry: SurfaceGeometry) {
|
||||
// *self.geometry.lock().value_mut() = Some(geometry);
|
||||
// }
|
||||
|
||||
pub fn apply_material(&self, model: Arc<Model>, material_idx: u32) {
|
||||
self.pending_material_applications
|
||||
.lock()
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
use crate::nodes::Node;
|
||||
|
||||
use super::{
|
||||
panel_item::{PanelItem, RecommendedState, ToplevelState},
|
||||
panel_item::{PanelItem, RecommendedState, SurfaceID},
|
||||
state::WaylandState,
|
||||
surface::SurfaceGeometry,
|
||||
surface::CoreSurface,
|
||||
SERIAL_COUNTER,
|
||||
};
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Serialize;
|
||||
use smithay::{
|
||||
reexports::{
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_popup::{self, XdgPopup},
|
||||
xdg_positioner::{self, Anchor, ConstraintAdjustment, Gravity, XdgPositioner},
|
||||
xdg_surface::{self, XdgSurface},
|
||||
xdg_toplevel::{self, XdgToplevel, EVT_WM_CAPABILITIES_SINCE},
|
||||
xdg_wm_base::{self, XdgWmBase},
|
||||
},
|
||||
wayland_server::{
|
||||
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle,
|
||||
GlobalDispatch, New, Resource, WEnum, Weak,
|
||||
},
|
||||
use serde::{ser::SerializeSeq, Serialize, Serializer};
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_popup::{self, XdgPopup},
|
||||
xdg_positioner::{self, Anchor, ConstraintAdjustment, Gravity, XdgPositioner},
|
||||
xdg_surface::{self, XdgSurface},
|
||||
xdg_toplevel::{self, XdgToplevel, EVT_WM_CAPABILITIES_SINCE},
|
||||
xdg_wm_base::{self, XdgWmBase},
|
||||
},
|
||||
wayland_server::{
|
||||
backend::{ClientId, ObjectId},
|
||||
protocol::wl_surface::WlSurface,
|
||||
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, WEnum,
|
||||
Weak as WlWeak,
|
||||
},
|
||||
wayland::compositor,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
|
||||
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
@@ -38,11 +43,6 @@ impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
data_init.init(resource, ());
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct WaylandSurface {
|
||||
wl_surface: Weak<WlSurface>,
|
||||
geometry: Arc<Mutex<Option<SurfaceGeometry>>>,
|
||||
}
|
||||
|
||||
impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn request(
|
||||
@@ -56,18 +56,11 @@ impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
) {
|
||||
match request {
|
||||
xdg_wm_base::Request::CreatePositioner { id } => {
|
||||
let positioner =
|
||||
data_init.init(id, Arc::new(Mutex::new(PositionerData::default())));
|
||||
let positioner = data_init.init(id, Mutex::new(PositionerData::default()));
|
||||
debug!(?positioner, "Create XDG positioner");
|
||||
}
|
||||
xdg_wm_base::Request::GetXdgSurface { id, surface } => {
|
||||
let xdg_surface = data_init.init(
|
||||
id,
|
||||
WaylandSurface {
|
||||
wl_surface: surface.downgrade(),
|
||||
geometry: Arc::new(Mutex::new(None)),
|
||||
},
|
||||
);
|
||||
let xdg_surface = data_init.init(id, Mutex::new(XdgSurfaceData::new(&surface)));
|
||||
debug!(?xdg_surface, "Create XDG surface");
|
||||
}
|
||||
xdg_wm_base::Request::Pong { serial } => {
|
||||
@@ -81,7 +74,7 @@ impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
#[derive(Debug, Serialize, Clone, Copy)]
|
||||
pub struct PositionerData {
|
||||
size: Vector2<u32>,
|
||||
anchor_rect_pos: Vector2<i32>,
|
||||
@@ -107,13 +100,13 @@ impl Default for PositionerData {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgPositioner, Arc<Mutex<PositionerData>>, WaylandState> for WaylandState {
|
||||
impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
positioner: &XdgPositioner,
|
||||
request: xdg_positioner::Request,
|
||||
data: &Arc<Mutex<PositionerData>>,
|
||||
data: &Mutex<PositionerData>,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
@@ -195,39 +188,69 @@ impl Dispatch<XdgPositioner, Arc<Mutex<PositionerData>>, WaylandState> for Wayla
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct XdgSurfaceData {
|
||||
pub wl_surface: Weak<WlSurface>,
|
||||
pub xdg_surface: Weak<XdgSurface>,
|
||||
pub geometry: Arc<Mutex<Option<SurfaceGeometry>>>,
|
||||
#[derive(Debug, Serialize, Clone, Copy)]
|
||||
pub struct Geometry {
|
||||
pub origin: Vector2<i32>,
|
||||
pub size: Vector2<u32>,
|
||||
}
|
||||
impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
impl Default for Geometry {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
origin: Vector2::from([0; 2]),
|
||||
size: Vector2::from([0; 2]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XdgSurfaceData {
|
||||
wl_surface: WlWeak<WlSurface>,
|
||||
surface_id: SurfaceID,
|
||||
panel_item: Weak<PanelItem>,
|
||||
geometry: Option<Geometry>,
|
||||
}
|
||||
impl XdgSurfaceData {
|
||||
pub fn new(wl_surface: &WlSurface) -> Self {
|
||||
XdgSurfaceData {
|
||||
wl_surface: wl_surface.downgrade(),
|
||||
surface_id: SurfaceID::Toplevel,
|
||||
panel_item: Weak::new(),
|
||||
geometry: None,
|
||||
}
|
||||
}
|
||||
pub fn get(xdg_surface: &XdgSurface) -> &Mutex<Self> {
|
||||
xdg_surface.data::<Mutex<Self>>().unwrap()
|
||||
}
|
||||
pub fn wl_surface(&self) -> WlSurface {
|
||||
self.wl_surface.upgrade().unwrap()
|
||||
}
|
||||
pub fn panel_item(&self) -> Option<Arc<PanelItem>> {
|
||||
self.panel_item.upgrade()
|
||||
}
|
||||
}
|
||||
// impl Clone for XdgSurfaceData {
|
||||
// fn clone(&self) -> Self {
|
||||
// Self {
|
||||
// wl_surface: self.wl_surface.clone(),
|
||||
// geometry: self.geometry.clone(),
|
||||
// surface_type: Mutex::new(self.surface_type.lock().clone()),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
state: &mut WaylandState,
|
||||
client: &Client,
|
||||
xdg_surface: &XdgSurface,
|
||||
request: xdg_surface::Request,
|
||||
data: &WaylandSurface,
|
||||
xdg_surface_data: &Mutex<XdgSurfaceData>,
|
||||
_dhandle: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_surface::Request::GetToplevel { id } => {
|
||||
let toplevel_state = Arc::new(Mutex::new(ToplevelState {
|
||||
queued_state: Some(Box::new(ToplevelState::default())),
|
||||
..Default::default()
|
||||
}));
|
||||
let toplevel = data_init.init(
|
||||
id,
|
||||
XdgToplevelData {
|
||||
state: toplevel_state,
|
||||
xdg_surface_data: XdgSurfaceData {
|
||||
wl_surface: data.wl_surface.clone(),
|
||||
xdg_surface: xdg_surface.downgrade(),
|
||||
geometry: data.geometry.clone(),
|
||||
},
|
||||
},
|
||||
);
|
||||
let toplevel_state = Mutex::new(ToplevelData::new(xdg_surface));
|
||||
let toplevel = data_init.init(id, toplevel_state);
|
||||
debug!(?toplevel, ?xdg_surface, "Create XDG toplevel");
|
||||
|
||||
if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE {
|
||||
@@ -236,25 +259,99 @@ impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
toplevel.configure(0, 0, vec![]);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
|
||||
let (node, item) = PanelItem::create(
|
||||
toplevel,
|
||||
data.wl_surface.upgrade().unwrap(),
|
||||
client.get_credentials(&state.display_handle).ok(),
|
||||
state.seats.get(&client.id()).unwrap().clone(),
|
||||
let client_credentials = client.get_credentials(&state.display_handle).ok();
|
||||
let seat_data = state.seats.get(&client.id()).unwrap().clone();
|
||||
let toplevel_weak = toplevel.downgrade();
|
||||
CoreSurface::add_to(
|
||||
&state.display,
|
||||
state.display_handle.clone(),
|
||||
&xdg_surface_data.lock().wl_surface(),
|
||||
move |c| match c {
|
||||
0 => {
|
||||
let toplevel = toplevel_weak.upgrade().unwrap();
|
||||
let toplevel_data = ToplevelData::get(&toplevel);
|
||||
let xdg_surface = toplevel_data.lock().xdg_surface();
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface);
|
||||
let wl_surface = xdg_surface_data.lock().wl_surface();
|
||||
|
||||
xdg_surface_data.lock().surface_id = SurfaceID::Toplevel;
|
||||
let (node, panel_item) = PanelItem::create(
|
||||
toplevel.clone(),
|
||||
wl_surface.clone(),
|
||||
client_credentials,
|
||||
seat_data.clone(),
|
||||
);
|
||||
toplevel_data.lock().panel_item_node.replace(node);
|
||||
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
||||
}
|
||||
_ => {
|
||||
let toplevel = toplevel_weak.upgrade().unwrap();
|
||||
let toplevel_data = ToplevelData::get(&toplevel);
|
||||
let panel_item = toplevel_data.lock().panel_item().unwrap();
|
||||
panel_item.commit_toplevel();
|
||||
}
|
||||
},
|
||||
);
|
||||
compositor::with_states(&data.wl_surface.upgrade().unwrap(), |surface_data| {
|
||||
surface_data.data_map.insert_if_missing_threadsafe(|| node);
|
||||
surface_data.data_map.insert_if_missing_threadsafe(|| item);
|
||||
});
|
||||
}
|
||||
xdg_surface::Request::GetPopup {
|
||||
id,
|
||||
parent: _,
|
||||
positioner: _,
|
||||
parent,
|
||||
positioner,
|
||||
} => {
|
||||
let popup = data_init.init(id, ());
|
||||
debug!(?popup, ?xdg_surface, "Create XDG popup");
|
||||
popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
let parent_clone = parent.clone().unwrap();
|
||||
let parent_data = parent_clone.data::<Mutex<XdgSurfaceData>>().unwrap().lock();
|
||||
// let positioner_data = positioner
|
||||
// .data::<Mutex<PositionerData>>()
|
||||
// .unwrap()
|
||||
// .lock()
|
||||
// .clone();
|
||||
// let parent = match &*parent_data {
|
||||
// XdgSurfaceType::Toplevel(_) => SurfaceID::Toplevel,
|
||||
// XdgSurfaceType::Popup(p) => {
|
||||
// SurfaceID::Popup(p.upgrade().unwrap().uid.clone())
|
||||
// }
|
||||
// XdgSurfaceType::Unknown => return,
|
||||
// };
|
||||
let uid = nanoid!();
|
||||
let popup_data = Mutex::new(PopupData::new(
|
||||
uid.clone(),
|
||||
xdg_surface,
|
||||
parent_data.surface_id.clone(),
|
||||
positioner,
|
||||
));
|
||||
let xdg_popup = data_init.init(id, popup_data);
|
||||
xdg_surface_data.lock().surface_id = SurfaceID::Popup(uid);
|
||||
let panel_item = parent_data.panel_item().unwrap();
|
||||
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
||||
|
||||
panel_item.seat_data.new_surface(
|
||||
&xdg_surface_data.lock().wl_surface(),
|
||||
Arc::downgrade(&panel_item),
|
||||
);
|
||||
debug!(?xdg_popup, ?xdg_surface, "Create XDG popup");
|
||||
|
||||
let xdg_surface = xdg_surface.downgrade();
|
||||
let xdg_popup = xdg_popup.downgrade();
|
||||
CoreSurface::add_to(
|
||||
&state.display,
|
||||
state.display_handle.clone(),
|
||||
&xdg_surface_data.lock().wl_surface.upgrade().unwrap(),
|
||||
move |commit_count| match commit_count {
|
||||
0 => xdg_surface
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.configure(SERIAL_COUNTER.inc()),
|
||||
c => {
|
||||
let xdg_popup = xdg_popup.upgrade().unwrap();
|
||||
let popup_data = PopupData::get(&xdg_popup);
|
||||
let popup_data = popup_data.lock();
|
||||
// panel_item.commit_popup(popup_data);
|
||||
if c == 1 {
|
||||
panel_item.new_popup(&xdg_popup, &*popup_data);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
xdg_surface::Request::SetWindowGeometry {
|
||||
x,
|
||||
@@ -266,18 +363,11 @@ impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
?xdg_surface,
|
||||
x, y, width, height, "Set XDG surface geometry"
|
||||
);
|
||||
let geometry = SurfaceGeometry {
|
||||
origin: [x as u32, y as u32].into(),
|
||||
let geometry = Geometry {
|
||||
origin: [x, y].into(),
|
||||
size: [width as u32, height as u32].into(),
|
||||
};
|
||||
*data.geometry.lock() = Some(geometry);
|
||||
let Ok(wl_surface) = data.wl_surface.upgrade() else { return; };
|
||||
compositor::with_states(&wl_surface, |data| {
|
||||
// if let Some(core_surface) = data.data_map.get::<Arc<CoreSurface>>() {
|
||||
// core_surface.set_geometry(geometry);
|
||||
// }
|
||||
data.data_map.insert_if_missing_threadsafe(|| geometry);
|
||||
});
|
||||
xdg_surface_data.lock().geometry.replace(geometry);
|
||||
}
|
||||
xdg_surface::Request::AckConfigure { serial } => {
|
||||
debug!(?xdg_surface, serial, "Acknowledge XDG surface configure");
|
||||
@@ -290,47 +380,104 @@ impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XdgToplevelData {
|
||||
pub state: Arc<Mutex<ToplevelState>>,
|
||||
pub xdg_surface_data: XdgSurfaceData,
|
||||
fn serde_error<S: Serializer>(msg: &str) -> Result<S::Ok, S::Error> {
|
||||
Err(serde::ser::Error::custom(msg))
|
||||
}
|
||||
impl XdgToplevelData {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ToplevelData {
|
||||
panel_item_node: Option<Arc<Node>>,
|
||||
xdg_surface: WlWeak<XdgSurface>,
|
||||
parent: Option<WlWeak<XdgToplevel>>,
|
||||
title: Option<String>,
|
||||
app_id: Option<String>,
|
||||
max_size: Option<Vector2<u32>>,
|
||||
min_size: Option<Vector2<u32>>,
|
||||
states: Vec<u32>,
|
||||
}
|
||||
impl ToplevelData {
|
||||
fn new(xdg_surface: &XdgSurface) -> Self {
|
||||
ToplevelData {
|
||||
panel_item_node: None,
|
||||
xdg_surface: xdg_surface.downgrade(),
|
||||
parent: None,
|
||||
title: None,
|
||||
app_id: None,
|
||||
max_size: None,
|
||||
min_size: None,
|
||||
states: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(toplevel: &XdgToplevel) -> &Mutex<ToplevelData> {
|
||||
toplevel.data::<Mutex<ToplevelData>>().unwrap()
|
||||
}
|
||||
|
||||
pub fn xdg_surface(&self) -> XdgSurface {
|
||||
self.xdg_surface.upgrade().unwrap()
|
||||
}
|
||||
fn panel_item(&self) -> Option<Arc<PanelItem>> {
|
||||
let wl_surface = self.xdg_surface_data.wl_surface.upgrade().ok()?;
|
||||
compositor::with_states(&wl_surface, |data| {
|
||||
data.data_map.get::<Arc<PanelItem>>().cloned()
|
||||
})
|
||||
let xdg_surface = self.xdg_surface();
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
|
||||
xdg_surface_data.panel_item()
|
||||
}
|
||||
}
|
||||
impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
impl Serialize for ToplevelData {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let xdg_surface = self.xdg_surface();
|
||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
|
||||
let geometry = xdg_surface_data.geometry.clone();
|
||||
let wl_surface = xdg_surface_data.wl_surface();
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {return serde_error::<S>("Core surface not found")};
|
||||
let Some(size) = core_surface.size() else {return serializer.serialize_none()};
|
||||
let geometry = geometry.unwrap_or_else(|| Geometry {
|
||||
origin: [0; 2].into(),
|
||||
size,
|
||||
});
|
||||
|
||||
let mut seq = serializer.serialize_seq(None)?;
|
||||
// Parent UID
|
||||
seq.serialize_element(&self.parent.as_ref().and_then(|p| {
|
||||
Some(
|
||||
ToplevelData::get(&p.upgrade().ok()?)
|
||||
.lock()
|
||||
.panel_item()?
|
||||
.uid
|
||||
.clone(),
|
||||
)
|
||||
}))?;
|
||||
seq.serialize_element(&self.title)?;
|
||||
seq.serialize_element(&self.app_id)?;
|
||||
seq.serialize_element(&size)?;
|
||||
seq.serialize_element(&self.min_size)?;
|
||||
seq.serialize_element(&self.max_size)?;
|
||||
seq.serialize_element(&geometry)?;
|
||||
seq.serialize_element(&self.states)?;
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
xdg_toplevel: &XdgToplevel,
|
||||
request: xdg_toplevel::Request,
|
||||
data: &XdgToplevelData,
|
||||
data: &Mutex<ToplevelData>,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_toplevel::Request::SetParent { parent } => {
|
||||
debug!(?xdg_toplevel, ?parent, "Set XDG Toplevel parent");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.parent = parent.map(|toplevel| toplevel.downgrade());
|
||||
data.lock().parent = parent.map(|toplevel| toplevel.downgrade());
|
||||
}
|
||||
xdg_toplevel::Request::SetTitle { title } => {
|
||||
debug!(?xdg_toplevel, ?title, "Set XDG Toplevel title");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.title = (!title.is_empty()).then_some(title);
|
||||
data.lock().title = (!title.is_empty()).then_some(title);
|
||||
}
|
||||
xdg_toplevel::Request::SetAppId { app_id } => {
|
||||
debug!(?xdg_toplevel, ?app_id, "Set XDG Toplevel app ID");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.app_id = (!app_id.is_empty()).then_some(app_id);
|
||||
data.lock().app_id = (!app_id.is_empty()).then_some(app_id);
|
||||
}
|
||||
xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => {
|
||||
debug!(
|
||||
@@ -344,7 +491,7 @@ impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
}
|
||||
xdg_toplevel::Request::Move { seat, serial } => {
|
||||
debug!(?xdg_toplevel, ?seat, serial, "XDG Toplevel move request");
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Move);
|
||||
}
|
||||
xdg_toplevel::Request::Resize {
|
||||
@@ -360,46 +507,42 @@ impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
?edges,
|
||||
"XDG Toplevel resize request"
|
||||
);
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Resize(edges as u32));
|
||||
}
|
||||
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
||||
debug!(?xdg_toplevel, width, height, "Set XDG Toplevel max size");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.max_size = (width > 1 || height > 1)
|
||||
data.lock().max_size = (width > 1 || height > 1)
|
||||
.then_some(Vector2::from([width as u32, height as u32]));
|
||||
}
|
||||
xdg_toplevel::Request::SetMinSize { width, height } => {
|
||||
debug!(?xdg_toplevel, width, height, "Set XDG Toplevel min size");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.min_size = (width > 1 || height > 1)
|
||||
data.lock().min_size = (width > 1 || height > 1)
|
||||
.then_some(Vector2::from([width as u32, height as u32]));
|
||||
}
|
||||
xdg_toplevel::Request::SetMaximized => {
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(true));
|
||||
}
|
||||
xdg_toplevel::Request::UnsetMaximized => {
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(false));
|
||||
}
|
||||
xdg_toplevel::Request::SetFullscreen { output: _ } => {
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
||||
}
|
||||
xdg_toplevel::Request::UnsetFullscreen => {
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
||||
}
|
||||
xdg_toplevel::Request::SetMinimized => {
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Minimize);
|
||||
}
|
||||
xdg_toplevel::Request::Destroy => {
|
||||
debug!(?xdg_toplevel, "Destroy XDG Toplevel");
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
let Some(panel_item) = data.lock().panel_item() else { return };
|
||||
panel_item.on_drop();
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@@ -407,29 +550,121 @@ impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgPopup, (), WaylandState> for WaylandState {
|
||||
#[derive(Clone)]
|
||||
pub struct PopupData {
|
||||
pub uid: String,
|
||||
grabbed: bool,
|
||||
parent_id: SurfaceID,
|
||||
positioner: XdgPositioner,
|
||||
xdg_surface: WlWeak<XdgSurface>,
|
||||
}
|
||||
impl PopupData {
|
||||
fn new(
|
||||
uid: impl ToString,
|
||||
xdg_surface: &XdgSurface,
|
||||
parent_id: SurfaceID,
|
||||
positioner: XdgPositioner,
|
||||
) -> Self {
|
||||
PopupData {
|
||||
uid: uid.to_string(),
|
||||
grabbed: false,
|
||||
parent_id,
|
||||
positioner,
|
||||
xdg_surface: xdg_surface.downgrade(),
|
||||
}
|
||||
}
|
||||
pub fn get(popup: &XdgPopup) -> &Mutex<Self> {
|
||||
popup.data::<Mutex<Self>>().unwrap()
|
||||
}
|
||||
pub fn xdg_surface(&self) -> XdgSurface {
|
||||
self.xdg_surface.upgrade().unwrap()
|
||||
}
|
||||
|
||||
fn panel_item(&self) -> Option<Arc<PanelItem>> {
|
||||
XdgSurfaceData::get(&self.xdg_surface()).lock().panel_item()
|
||||
}
|
||||
// fn get_parent(&self) -> Option<XdgSurface> {
|
||||
// self.parent.as_ref()?.upgrade().ok()
|
||||
// }
|
||||
pub fn wl_surface(&self) -> WlSurface {
|
||||
XdgSurfaceData::get(&self.xdg_surface()).lock().wl_surface()
|
||||
}
|
||||
|
||||
pub fn positioner_data(&self) -> Option<PositionerData> {
|
||||
Some(
|
||||
self.positioner
|
||||
.data::<Mutex<PositionerData>>()?
|
||||
.lock()
|
||||
.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for PopupData {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let Some(positioner_data) = self.positioner_data() else {return serde_error::<S>("Positioner not found")};
|
||||
let mut seq = serializer.serialize_seq(None)?;
|
||||
seq.serialize_element(&self.uid)?;
|
||||
seq.serialize_element(&self.parent_id)?;
|
||||
seq.serialize_element(&positioner_data)?;
|
||||
seq.end()
|
||||
}
|
||||
}
|
||||
impl Debug for PopupData {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("XdgPopupData")
|
||||
.field("uid", &self.uid)
|
||||
.field("positioner", &self.positioner)
|
||||
.field("xdg_surface", &self.xdg_surface)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl Dispatch<XdgPopup, Mutex<PopupData>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
xdg_popup: &XdgPopup,
|
||||
request: xdg_popup::Request,
|
||||
_data: &(),
|
||||
data: &Mutex<PopupData>,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_popup::Request::Grab { seat, serial } => {
|
||||
let mut data = data.lock();
|
||||
data.grabbed = true;
|
||||
debug!(?xdg_popup, ?seat, serial, "XDG popup grab");
|
||||
xdg_popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
let Some(panel_item) = data.panel_item() else {return};
|
||||
panel_item.grab_keyboard(Some(SurfaceID::Popup(data.uid.clone())));
|
||||
}
|
||||
xdg_popup::Request::Reposition { positioner, token } => {
|
||||
let mut data = data.lock();
|
||||
debug!(?xdg_popup, ?positioner, token, "XDG popup reposition");
|
||||
xdg_popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
data.positioner = positioner;
|
||||
let Some(panel_item) = data.panel_item() else {return};
|
||||
panel_item.reposition_popup(&*data);
|
||||
// xdg_popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
}
|
||||
xdg_popup::Request::Destroy => {
|
||||
let data = data.lock();
|
||||
debug!(?xdg_popup, "Destroy XDG popup");
|
||||
if data.grabbed {
|
||||
let Some(panel_item) = data.panel_item() else {return};
|
||||
panel_item.grab_keyboard(None);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn destroyed(
|
||||
_state: &mut WaylandState,
|
||||
_client: ClientId,
|
||||
_resource: ObjectId,
|
||||
data: &Mutex<PopupData>,
|
||||
) {
|
||||
let data = data.lock();
|
||||
let Some(panel_item) = data.panel_item() else {return};
|
||||
panel_item.drop_popup(&data.uid);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user