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