refactor: panel items
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -1918,9 +1918,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_repr"
|
name = "serde_repr"
|
||||||
version = "0.1.15"
|
version = "0.1.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e168eaaf71e8f9bd6037feb05190485708e019f4fd87d161b3c0a0d37daf85e5"
|
checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2081,6 +2081,7 @@ dependencies = [
|
|||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"send_wrapper",
|
"send_wrapper",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_repr",
|
||||||
"smithay",
|
"smithay",
|
||||||
"stardust-xr",
|
"stardust-xr",
|
||||||
"stereokit",
|
"stereokit",
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ xkbcommon = { version = "0.5.0", default-features = false, optional = true }
|
|||||||
stardust-xr = "0.14.0"
|
stardust-xr = "0.14.0"
|
||||||
directories = "5.0.0"
|
directories = "5.0.0"
|
||||||
serde = { version = "1.0.160", features = ["derive"] }
|
serde = { version = "1.0.160", features = ["derive"] }
|
||||||
|
serde_repr = "0.1.16"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||||
global_counter = "0.2.2"
|
global_counter = "0.2.2"
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ pub fn startup_settings(env: &FxHashMap<String, String>) -> Option<StartupSettin
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
pid: Option<i32>,
|
pub pid: Option<i32>,
|
||||||
// env: Option<FxHashMap<String, String>>,
|
// env: Option<FxHashMap<String, String>>,
|
||||||
exe: Option<PathBuf>,
|
exe: Option<PathBuf>,
|
||||||
dispatch_join_handle: OnceCell<JoinHandle<Result<()>>>,
|
dispatch_join_handle: OnceCell<JoinHandle<Result<()>>>,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ use serde::{
|
|||||||
ser::Serializer,
|
ser::Serializer,
|
||||||
Deserialize, Serialize,
|
Deserialize, Serialize,
|
||||||
};
|
};
|
||||||
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
@@ -29,20 +30,31 @@ lazy_static! {
|
|||||||
type_name: "panel",
|
type_name: "panel",
|
||||||
aliased_local_signals: vec![
|
aliased_local_signals: vec![
|
||||||
"apply_surface_material",
|
"apply_surface_material",
|
||||||
"configure_toplevel",
|
"close_toplevel",
|
||||||
"set_toplevel_capabilities",
|
"auto_size_toplevel",
|
||||||
|
"set_toplevel_size_changed",
|
||||||
|
"set_toplevel_state",
|
||||||
|
"set_toplevel_tiling",
|
||||||
|
"set_toplevel_bounds",
|
||||||
|
"set_maximize_enabled",
|
||||||
|
"set_minimize_enabled",
|
||||||
|
"set_fullscreen_enabled",
|
||||||
|
"set_window_menu_enabled",
|
||||||
"pointer_scroll",
|
"pointer_scroll",
|
||||||
"pointer_button",
|
"pointer_button",
|
||||||
"pointer_motion",
|
"pointer_motion",
|
||||||
"keyboard_key",
|
"keyboard_key",
|
||||||
"keyboard_set_keymap_names",
|
|
||||||
"keyboard_set_keymap_string",
|
|
||||||
"close",
|
|
||||||
],
|
],
|
||||||
aliased_local_methods: vec![],
|
aliased_local_methods: vec![],
|
||||||
aliased_remote_signals: vec![
|
aliased_remote_signals: vec![
|
||||||
"commit_toplevel",
|
"toplevel_parent_changed",
|
||||||
|
"toplevel_title_changed",
|
||||||
|
"toplevel_app_id_changed",
|
||||||
|
"toplevel_window_menu",
|
||||||
"recommend_toplevel_state",
|
"recommend_toplevel_state",
|
||||||
|
"toplevel_move_request",
|
||||||
|
"toplevel_resize_request",
|
||||||
|
"toplevel_size_changed",
|
||||||
"set_cursor",
|
"set_cursor",
|
||||||
"new_child",
|
"new_child",
|
||||||
"reposition_child",
|
"reposition_child",
|
||||||
@@ -118,28 +130,101 @@ impl serde::Serialize for SurfaceID {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize)]
|
/// The origin and size of the surface's "solid" part.
|
||||||
#[serde(tag = "type", content = "content")]
|
#[derive(Debug, Serialize, Clone, Copy)]
|
||||||
pub enum RecommendedState {
|
pub struct Geometry {
|
||||||
Maximize(bool),
|
pub origin: Vector2<i32>,
|
||||||
Fullscreen(bool),
|
pub size: Vector2<u32>,
|
||||||
Minimize,
|
}
|
||||||
Move,
|
/// The state of the panel item's toplevel.
|
||||||
Resize(u32),
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct ToplevelInfo {
|
||||||
|
/// The UID of the panel item of the parent of this toplevel, if it exists
|
||||||
|
pub parent: Option<String>,
|
||||||
|
/// Equivalent to the window title
|
||||||
|
pub title: Option<String>,
|
||||||
|
/// Application identifier, see <https://standards.freedesktop.org/desktop-entry-spec/>
|
||||||
|
pub app_id: Option<String>,
|
||||||
|
/// Current size in pixels
|
||||||
|
pub size: Vector2<u32>,
|
||||||
|
/// Recommended minimum size in pixels
|
||||||
|
pub min_size: Option<Vector2<u32>>,
|
||||||
|
/// Recommended maximum size in pixels
|
||||||
|
pub max_size: Option<Vector2<u32>>,
|
||||||
|
/// Surface geometry
|
||||||
|
pub logical_rectangle: Geometry,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr)]
|
||||||
|
pub enum ToplevelState {
|
||||||
|
Floating,
|
||||||
|
Minimized,
|
||||||
|
UnMinimized,
|
||||||
|
Maximized,
|
||||||
|
UnMaximized,
|
||||||
|
Fullscreen,
|
||||||
|
UnFullscreen,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Data on positioning a child
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct ChildInfo {
|
||||||
|
pub uid: String,
|
||||||
|
pub parent: SurfaceID,
|
||||||
|
pub geometry: Geometry,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Deserialize_repr)]
|
||||||
|
#[repr(u32)]
|
||||||
|
pub enum Edge {
|
||||||
|
None = 0,
|
||||||
|
Top = 1,
|
||||||
|
Bottom = 2,
|
||||||
|
Left = 4,
|
||||||
|
TopLeft = 5,
|
||||||
|
BottomLeft = 6,
|
||||||
|
Right = 8,
|
||||||
|
TopRight = 9,
|
||||||
|
BottomRight = 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The init data for the panel item.
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct PanelItemInitData {
|
||||||
|
/// The cursor, if applicable.
|
||||||
|
pub cursor: Option<Geometry>,
|
||||||
|
/// Size of the toplevel surface in pixels.
|
||||||
|
pub toplevel: ToplevelInfo,
|
||||||
|
/// Vector of childs that already exist
|
||||||
|
pub children: Vec<ChildInfo>,
|
||||||
|
/// The surface, if any, that has exclusive input to the pointer.
|
||||||
|
pub pointer_grab: Option<SurfaceID>,
|
||||||
|
/// The surface, if any, that has exclusive input to the keyboard.
|
||||||
|
pub keyboard_grab: Option<SurfaceID>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Backend: Send + Sync + 'static {
|
pub trait Backend: Send + Sync + 'static {
|
||||||
fn serialize_start_data(&self, id: &str) -> Result<Message>;
|
fn start_data(&self) -> Result<PanelItemInitData>;
|
||||||
fn serialize_toplevel(&self) -> Result<Message>;
|
|
||||||
fn set_toplevel_capabilities(&self, capabilities: Vec<u8>);
|
|
||||||
fn configure_toplevel(
|
|
||||||
&self,
|
|
||||||
size: Option<Vector2<u32>>,
|
|
||||||
states: Vec<u32>,
|
|
||||||
bounds: Option<Vector2<u32>>,
|
|
||||||
);
|
|
||||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>);
|
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>);
|
||||||
|
|
||||||
|
fn close_toplevel(&self);
|
||||||
|
fn auto_size_toplevel(&self);
|
||||||
|
fn set_toplevel_size(&self, size: Vector2<u32>);
|
||||||
|
fn toplevel_maximize(&self);
|
||||||
|
fn toplevel_unmaximize(&self);
|
||||||
|
fn toplevel_fullscreen(&self);
|
||||||
|
fn toplevel_unfullscreen(&self);
|
||||||
|
fn set_toplevel_tiling(&self, up: bool, down: bool, left: bool, right: bool);
|
||||||
|
fn set_toplevel_bounds(&self, bounds: Option<Vector2<u32>>);
|
||||||
|
fn set_toplevel_focused_visuals(&self, focused: bool);
|
||||||
|
|
||||||
|
fn set_maximize_enabled(&self, enabled: bool);
|
||||||
|
fn set_minimize_enabled(&self, enabled: bool);
|
||||||
|
fn set_fullscreen_enabled(&self, enabled: bool);
|
||||||
|
fn set_window_menu_enabled(&self, enabled: bool);
|
||||||
|
|
||||||
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>);
|
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>);
|
||||||
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool);
|
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool);
|
||||||
fn pointer_scroll(
|
fn pointer_scroll(
|
||||||
@@ -149,7 +234,6 @@ pub trait Backend: Send + Sync + 'static {
|
|||||||
scroll_steps: Option<Vector2<f32>>,
|
scroll_steps: Option<Vector2<f32>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn keyboard_set_keymap(&self, keymap: &str) -> Result<()>;
|
|
||||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool);
|
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +244,7 @@ pub fn panel_item_from_node(node: &Node) -> Option<Arc<dyn PanelItemTrait>> {
|
|||||||
|
|
||||||
pub trait PanelItemTrait: Backend + Send + Sync + 'static {
|
pub trait PanelItemTrait: Backend + Send + Sync + 'static {
|
||||||
fn uid(&self) -> &str;
|
fn uid(&self) -> &str;
|
||||||
// fn node(&self) -> Option<Arc<Node>>;
|
fn serialize_start_data(&self, id: &str) -> Result<Message>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PanelItem<B: Backend + ?Sized> {
|
pub struct PanelItem<B: Backend + ?Sized> {
|
||||||
@@ -210,20 +294,34 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
|||||||
items::capture(&item, &acceptor);
|
items::capture(&item, &acceptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.add_local_signal("apply_surface_material", Self::apply_surface_material_flex);
|
|
||||||
node.add_local_signal("configure_toplevel", Self::configure_toplevel_flex);
|
|
||||||
node.add_local_signal(
|
|
||||||
"set_toplevel_capabilities",
|
|
||||||
Self::set_toplevel_capabilities_flex,
|
|
||||||
);
|
|
||||||
node.add_local_signal("pointer_scroll", Self::pointer_scroll_flex);
|
|
||||||
node.add_local_signal("pointer_button", Self::pointer_button_flex);
|
|
||||||
node.add_local_signal("pointer_motion", Self::pointer_motion_flex);
|
|
||||||
|
|
||||||
|
node.add_local_signal("apply_surface_material", Self::apply_surface_material_flex);
|
||||||
|
node.add_local_signal("close_toplevel", Self::close_toplevel_flex);
|
||||||
|
node.add_local_signal("auto_size_toplevel", Self::auto_size_toplevel_flex);
|
||||||
|
node.add_local_signal("set_toplevel_size_changed", Self::set_toplevel_size_changed);
|
||||||
|
node.add_local_signal("toplevel_maximize", Self::toplevel_maximize_flex);
|
||||||
|
node.add_local_signal("toplevel_unmaximize", Self::toplevel_unmaximize_flex);
|
||||||
|
node.add_local_signal("toplevel_fullscreen", Self::toplevel_fullscreen_flex);
|
||||||
|
node.add_local_signal("toplevel_unfullscreen", Self::toplevel_unfullscreen_flex);
|
||||||
|
node.add_local_signal("set_toplevel_tiling", Self::set_toplevel_tiling_flex);
|
||||||
|
node.add_local_signal("set_toplevel_bounds", Self::set_toplevel_bounds_flex);
|
||||||
|
|
||||||
|
node.add_local_signal("set_maximize_enabled", Self::set_maximize_enabled_flex);
|
||||||
|
node.add_local_signal("set_minimize_enabled", Self::set_minimize_enabled_flex);
|
||||||
|
node.add_local_signal("set_fullscreen_enabled", Self::set_fullscreen_enabled_flex);
|
||||||
node.add_local_signal(
|
node.add_local_signal(
|
||||||
"keyboard_set_keymap_string",
|
"set_window_menu_enabled",
|
||||||
Self::keyboard_set_keymap_string_flex,
|
Self::set_window_menu_enabled_flex,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
node.add_local_signal("pointer_motion", Self::pointer_motion_flex);
|
||||||
|
node.add_local_signal("pointer_button", Self::pointer_button_flex);
|
||||||
|
node.add_local_signal("pointer_scroll", Self::pointer_scroll_flex);
|
||||||
|
|
||||||
|
// node.add_local_signal(
|
||||||
|
// "keyboard_set_keymap_string",
|
||||||
|
// Self::keyboard_set_keymap_string_flex,
|
||||||
|
// );
|
||||||
// node.add_local_signal(
|
// node.add_local_signal(
|
||||||
// "keyboard_set_keymap_names",
|
// "keyboard_set_keymap_names",
|
||||||
// Self::keyboard_set_keymap_names_flex,
|
// Self::keyboard_set_keymap_names_flex,
|
||||||
@@ -232,11 +330,88 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
|||||||
|
|
||||||
(node, panel_item)
|
(node, panel_item)
|
||||||
}
|
}
|
||||||
|
pub fn drop_toplevel(&self) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
node.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn node(&self) -> Option<Arc<Node>> {
|
// Remote signals
|
||||||
self.node.upgrade()
|
impl<B: Backend + ?Sized> PanelItem<B> {
|
||||||
|
pub fn toplevel_parent_changed(&self, parent: &str) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("toplevel_parent_changed", serialize(parent).unwrap());
|
||||||
|
}
|
||||||
|
pub fn toplevel_title_changed(&self, title: &str) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("toplevel_title_changed", serialize(title).unwrap());
|
||||||
|
}
|
||||||
|
pub fn toplevel_app_id_changed(&self, app_id: &str) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("toplevel_app_id_changed", serialize(app_id).unwrap());
|
||||||
|
}
|
||||||
|
pub fn toplevel_window_menu(&self, offset: Vector2<i32>) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("toplevel_window_menu", serialize(offset).unwrap());
|
||||||
|
}
|
||||||
|
pub fn recommend_toplevel_state(&self, state: ToplevelState) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("recommend_toplevel_state", serialize(state).unwrap());
|
||||||
|
}
|
||||||
|
pub fn toplevel_move_request(&self) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("toplevel_move_request", Vec::<u8>::new());
|
||||||
|
}
|
||||||
|
pub fn toplevel_resize_request(&self, up: bool, down: bool, left: bool, right: bool) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal(
|
||||||
|
"toplevel_resize_request",
|
||||||
|
serialize((up, down, left, right)).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn toplevel_size_changed(&self, size: Vector2<u32>) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("toplevel_size_changed", serialize(size).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_cursor(&self, geometry: Option<Geometry>) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("set_cursor", serialize(geometry).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_child(&self, info: ChildInfo) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("new_child", serialize(info).unwrap());
|
||||||
|
}
|
||||||
|
pub fn reposition_child(&self, uid: &str, geometry: Geometry) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("reposition_child", serialize((uid, geometry)).unwrap());
|
||||||
|
}
|
||||||
|
pub fn drop_child(&self, uid: &str) {
|
||||||
|
let Some(node) = self.node.upgrade() else {return};
|
||||||
|
let _ = node.send_remote_signal("drop_child", serialize(uid).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Local signals
|
||||||
|
macro_rules! flex_no_args {
|
||||||
|
($fn_name: ident, $trait_fn: ident) => {
|
||||||
|
fn $fn_name(node: &Node, _calling_client: Arc<Client>, _message: Message) -> Result<()> {
|
||||||
|
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
||||||
|
panel_item.$trait_fn();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
macro_rules! flex_deserialize {
|
||||||
|
($fn_name: ident, $trait_fn: ident) => {
|
||||||
|
fn $fn_name(node: &Node, _calling_client: Arc<Client>, message: Message) -> Result<()> {
|
||||||
|
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
||||||
|
panel_item.$trait_fn(deserialize(message.as_ref())?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
impl<B: Backend + ?Sized> PanelItem<B> {
|
||||||
fn apply_surface_material_flex(
|
fn apply_surface_material_flex(
|
||||||
node: &Node,
|
node: &Node,
|
||||||
calling_client: Arc<Client>,
|
calling_client: Arc<Client>,
|
||||||
@@ -264,6 +439,30 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flex_no_args!(close_toplevel_flex, close_toplevel);
|
||||||
|
flex_no_args!(auto_size_toplevel_flex, auto_size_toplevel);
|
||||||
|
flex_deserialize!(set_toplevel_size_changed, set_toplevel_size);
|
||||||
|
flex_no_args!(toplevel_maximize_flex, toplevel_maximize);
|
||||||
|
flex_no_args!(toplevel_unmaximize_flex, toplevel_unmaximize);
|
||||||
|
flex_no_args!(toplevel_fullscreen_flex, toplevel_fullscreen);
|
||||||
|
flex_no_args!(toplevel_unfullscreen_flex, toplevel_unfullscreen);
|
||||||
|
flex_deserialize!(set_toplevel_bounds_flex, set_toplevel_bounds);
|
||||||
|
fn set_toplevel_tiling_flex(
|
||||||
|
node: &Node,
|
||||||
|
_calling_client: Arc<Client>,
|
||||||
|
message: Message,
|
||||||
|
) -> Result<()> {
|
||||||
|
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
||||||
|
let (up, down, left, right) = deserialize(message.as_ref())?;
|
||||||
|
panel_item.set_toplevel_tiling(up, down, left, right);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
flex_deserialize!(set_maximize_enabled_flex, set_maximize_enabled);
|
||||||
|
flex_deserialize!(set_minimize_enabled_flex, set_minimize_enabled);
|
||||||
|
flex_deserialize!(set_fullscreen_enabled_flex, set_fullscreen_enabled);
|
||||||
|
flex_deserialize!(set_window_menu_enabled_flex, set_window_menu_enabled);
|
||||||
|
|
||||||
fn pointer_motion_flex(
|
fn pointer_motion_flex(
|
||||||
node: &Node,
|
node: &Node,
|
||||||
_calling_client: Arc<Client>,
|
_calling_client: Arc<Client>,
|
||||||
@@ -312,65 +511,6 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_set_keymap_string_flex(
|
|
||||||
node: &Node,
|
|
||||||
_calling_client: Arc<Client>,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<()> {
|
|
||||||
let keymap_string: &str = deserialize(message.as_ref())?;
|
|
||||||
|
|
||||||
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
|
||||||
debug!("Keyboard set keymap");
|
|
||||||
panel_item.keyboard_set_keymap(keymap_string)
|
|
||||||
|
|
||||||
// PanelItem::keyboard_set_keymap_flex(node, &keymap)
|
|
||||||
}
|
|
||||||
// fn keyboard_set_keymap_names_flex(
|
|
||||||
// node: &Node,
|
|
||||||
// _calling_client: Arc<Client>,
|
|
||||||
// message: Message,
|
|
||||||
// ) -> Result<()> {
|
|
||||||
// #[derive(Debug, Deserialize)]
|
|
||||||
// struct Names<'a> {
|
|
||||||
// rules: &'a str,
|
|
||||||
// model: &'a str,
|
|
||||||
// layout: &'a str,
|
|
||||||
// variant: &'a str,
|
|
||||||
// options: Option<String>,
|
|
||||||
// }
|
|
||||||
// let names: Names = deserialize(message.as_ref())?;
|
|
||||||
// let context = xkb::Context::new(0);
|
|
||||||
// let keymap = Keymap::new_from_names(
|
|
||||||
// &context,
|
|
||||||
// names.rules,
|
|
||||||
// names.model,
|
|
||||||
// names.layout,
|
|
||||||
// names.variant,
|
|
||||||
// names.options,
|
|
||||||
// XKB_KEYMAP_FORMAT_TEXT_V1,
|
|
||||||
// )
|
|
||||||
// .ok_or_else(|| eyre!("Keymap is not valid"))?;
|
|
||||||
|
|
||||||
// PanelItem::keyboard_set_keymap_flex(node, &keymap)
|
|
||||||
// }
|
|
||||||
// fn keyboard_set_keymap_flex(node: &Node, keymap: &str) -> Result<()> {
|
|
||||||
// let Some(panel_item): Option<Arc<PanelItem<dyn WaylandBackend>>> = panel_item_from_node(node) else { return Ok(()) };
|
|
||||||
// debug!("Keyboard set keymap");
|
|
||||||
|
|
||||||
// panel_item.seat_data.set_keymap(
|
|
||||||
// keymap,
|
|
||||||
// match &panel_item {
|
|
||||||
// Backend::Wayland(w) => w.input_surfaces(),
|
|
||||||
// #[cfg(feature = "xwayland")]
|
|
||||||
// Backend::X11(_) => panel_item
|
|
||||||
// .toplevel_wl_surface()
|
|
||||||
// .map(|s| vec![s])
|
|
||||||
// .unwrap_or_default(),
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
fn keyboard_key_flex(
|
fn keyboard_key_flex(
|
||||||
node: &Node,
|
node: &Node,
|
||||||
_calling_client: Arc<Client>,
|
_calling_client: Arc<Client>,
|
||||||
@@ -390,89 +530,69 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
|||||||
let Ok(message) = serialize(sid) else {return};
|
let Ok(message) = serialize(sid) else {return};
|
||||||
let _ = node.send_remote_signal("grab_keyboard", message);
|
let _ = node.send_remote_signal("grab_keyboard", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_toplevel_flex(
|
|
||||||
node: &Node,
|
|
||||||
_calling_client: Arc<Client>,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<()> {
|
|
||||||
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
|
||||||
struct ConfigureToplevelInfo {
|
|
||||||
size: Option<Vector2<u32>>,
|
|
||||||
states: Vec<u32>,
|
|
||||||
bounds: Option<Vector2<u32>>,
|
|
||||||
}
|
|
||||||
let info: ConfigureToplevelInfo = deserialize(message.as_ref())?;
|
|
||||||
|
|
||||||
panel_item.configure_toplevel(info.size, info.states, info.bounds);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn set_toplevel_capabilities_flex(
|
|
||||||
node: &Node,
|
|
||||||
_calling_client: Arc<Client>,
|
|
||||||
message: Message,
|
|
||||||
) -> Result<()> {
|
|
||||||
let Some(panel_item) = panel_item_from_node(node) else { return Ok(()) };
|
|
||||||
|
|
||||||
let capabilities: Vec<u8> = deserialize(message.as_ref())?;
|
|
||||||
debug!("Set toplevel capabilities");
|
|
||||||
panel_item.set_toplevel_capabilities(capabilities);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit_toplevel(&self) {
|
|
||||||
debug!("Commit toplevel");
|
|
||||||
let Some(node) = self.node.upgrade() else {return};
|
|
||||||
let Ok(data) = self.backend.serialize_toplevel() else {return};
|
|
||||||
let _ = node.send_remote_signal("commit_toplevel", data);
|
|
||||||
}
|
|
||||||
pub fn recommend_toplevel_state(&self, state: RecommendedState) {
|
|
||||||
let Some(node) = self.node.upgrade() else {return};
|
|
||||||
let data = serialize(state).unwrap();
|
|
||||||
debug!(?state, "Recommend toplevel state");
|
|
||||||
|
|
||||||
let _ = node.send_remote_signal("recommend_toplevel_state", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn drop_toplevel(&self) {
|
|
||||||
let Some(node) = self.node.upgrade() else {return};
|
|
||||||
node.destroy();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
|
impl<B: Backend + ?Sized> PanelItemTrait for PanelItem<B> {
|
||||||
fn uid(&self) -> &str {
|
fn uid(&self) -> &str {
|
||||||
&self.uid
|
&self.uid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||||
|
Ok(serialize((id, self.start_data()?))?.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
||||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
fn start_data(&self) -> Result<PanelItemInitData> {
|
||||||
self.backend.serialize_start_data(id)
|
self.backend.start_data()
|
||||||
}
|
|
||||||
|
|
||||||
fn serialize_toplevel(&self) -> Result<Message> {
|
|
||||||
self.backend.serialize_toplevel()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_toplevel_capabilities(&self, capabilities: Vec<u8>) {
|
|
||||||
self.backend.set_toplevel_capabilities(capabilities)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_toplevel(
|
|
||||||
&self,
|
|
||||||
size: Option<Vector2<u32>>,
|
|
||||||
states: Vec<u32>,
|
|
||||||
bounds: Option<Vector2<u32>>,
|
|
||||||
) {
|
|
||||||
self.backend.configure_toplevel(size, states, bounds)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||||
self.backend.apply_surface_material(surface, model_part)
|
self.backend.apply_surface_material(surface, model_part)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn close_toplevel(&self) {
|
||||||
|
self.backend.close_toplevel()
|
||||||
|
}
|
||||||
|
fn auto_size_toplevel(&self) {
|
||||||
|
self.backend.auto_size_toplevel()
|
||||||
|
}
|
||||||
|
fn set_toplevel_size(&self, size: Vector2<u32>) {
|
||||||
|
self.backend.set_toplevel_size(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_toplevel_tiling(&self, up: bool, down: bool, left: bool, right: bool) {
|
||||||
|
self.backend.set_toplevel_tiling(up, down, left, right)
|
||||||
|
}
|
||||||
|
fn set_toplevel_bounds(&self, bounds: Option<Vector2<u32>>) {
|
||||||
|
self.backend.set_toplevel_bounds(bounds)
|
||||||
|
}
|
||||||
|
fn set_toplevel_focused_visuals(&self, focused: bool) {
|
||||||
|
self.backend.set_toplevel_focused_visuals(focused)
|
||||||
|
}
|
||||||
|
fn toplevel_maximize(&self) {
|
||||||
|
self.backend.toplevel_maximize()
|
||||||
|
}
|
||||||
|
fn toplevel_unmaximize(&self) {
|
||||||
|
self.backend.toplevel_unmaximize()
|
||||||
|
}
|
||||||
|
fn toplevel_fullscreen(&self) {
|
||||||
|
self.backend.toplevel_fullscreen()
|
||||||
|
}
|
||||||
|
fn toplevel_unfullscreen(&self) {
|
||||||
|
self.backend.toplevel_unfullscreen()
|
||||||
|
}
|
||||||
|
fn set_maximize_enabled(&self, enabled: bool) {
|
||||||
|
self.backend.set_maximize_enabled(enabled)
|
||||||
|
}
|
||||||
|
fn set_minimize_enabled(&self, enabled: bool) {
|
||||||
|
self.backend.set_minimize_enabled(enabled)
|
||||||
|
}
|
||||||
|
fn set_fullscreen_enabled(&self, enabled: bool) {
|
||||||
|
self.backend.set_fullscreen_enabled(enabled)
|
||||||
|
}
|
||||||
|
fn set_window_menu_enabled(&self, enabled: bool) {
|
||||||
|
self.backend.set_window_menu_enabled(enabled)
|
||||||
|
}
|
||||||
|
|
||||||
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
|
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
|
||||||
self.backend.pointer_motion(surface, position)
|
self.backend.pointer_motion(surface, position)
|
||||||
}
|
}
|
||||||
@@ -489,9 +609,6 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
|||||||
.pointer_scroll(surface, scroll_distance, scroll_steps)
|
.pointer_scroll(surface, scroll_distance, scroll_steps)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_set_keymap(&self, keymap: &str) -> Result<()> {
|
|
||||||
self.backend.keyboard_set_keymap(keymap)
|
|
||||||
}
|
|
||||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
||||||
self.backend.keyboard_key(surface, key, state)
|
self.backend.keyboard_key(surface, key, state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,6 +173,19 @@ impl Node {
|
|||||||
.store(deserialize(message.as_ref())?, Ordering::Relaxed);
|
.store(deserialize(message.as_ref())?, Ordering::Relaxed);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
// very much up for debate if we should allow this, as you can match objects using this
|
||||||
|
// pub fn get_client_pid_flex(
|
||||||
|
// node: &Node,
|
||||||
|
// _calling_client: Arc<Client>,
|
||||||
|
// _message: Message,
|
||||||
|
// ) -> Result<Message> {
|
||||||
|
// let client = node
|
||||||
|
// .client
|
||||||
|
// .upgrade()
|
||||||
|
// .ok_or_else(|| eyre!("Could not get client for node?"))?;
|
||||||
|
// let pid = client.pid.ok_or_else(|| eyre!("Client PID is unknown"))?;
|
||||||
|
// Ok(serialize(pid)?.into())
|
||||||
|
// }
|
||||||
pub fn destroy_flex(
|
pub fn destroy_flex(
|
||||||
node: &Node,
|
node: &Node,
|
||||||
_calling_client: Arc<Client>,
|
_calling_client: Arc<Client>,
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ use super::{
|
|||||||
surface::CoreSurface,
|
surface::CoreSurface,
|
||||||
GLOBAL_DESTROY_QUEUE, SERIAL_COUNTER,
|
GLOBAL_DESTROY_QUEUE, SERIAL_COUNTER,
|
||||||
};
|
};
|
||||||
use crate::core::task;
|
use crate::{
|
||||||
use color_eyre::eyre::{eyre, Result};
|
core::task,
|
||||||
|
nodes::items::panel::{Backend, Geometry, PanelItem},
|
||||||
|
};
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
use mint::Vector2;
|
use mint::Vector2;
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
@@ -12,7 +15,7 @@ use parking_lot::Mutex;
|
|||||||
use rand::{seq::IteratorRandom, thread_rng};
|
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::ModifiersState,
|
||||||
reexports::wayland_server::{
|
reexports::wayland_server::{
|
||||||
backend::{ClientId, GlobalId, ObjectId},
|
backend::{ClientId, GlobalId, ObjectId},
|
||||||
protocol::{
|
protocol::{
|
||||||
@@ -33,10 +36,23 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
|
use xkbcommon::xkb::{self, Context, Keymap};
|
||||||
|
|
||||||
|
pub fn handle_cursor<B: Backend>(
|
||||||
|
panel_item: &Arc<PanelItem<B>>,
|
||||||
|
mut cursor: watch::Receiver<Option<CursorInfo>>,
|
||||||
|
) {
|
||||||
|
let panel_item_weak = Arc::downgrade(panel_item);
|
||||||
|
let _ = task::new(|| "cursor handler", async move {
|
||||||
|
while cursor.changed().await.is_ok() {
|
||||||
|
let Some(panel_item) = panel_item_weak.upgrade() else {continue};
|
||||||
|
let cursor_info = cursor.borrow();
|
||||||
|
panel_item.set_cursor(cursor_info.as_ref().and_then(CursorInfo::cursor_data));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub struct KeyboardInfo {
|
pub struct KeyboardInfo {
|
||||||
keymap: KeymapFile,
|
|
||||||
state: xkb::State,
|
state: xkb::State,
|
||||||
mods: ModifiersState,
|
mods: ModifiersState,
|
||||||
keys: FxHashSet<u32>,
|
keys: FxHashSet<u32>,
|
||||||
@@ -45,7 +61,6 @@ 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),
|
|
||||||
mods: ModifiersState::default(),
|
mods: ModifiersState::default(),
|
||||||
keys: FxHashSet::default(),
|
keys: FxHashSet::default(),
|
||||||
}
|
}
|
||||||
@@ -101,7 +116,6 @@ pub enum PointerEvent {
|
|||||||
}
|
}
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum KeyboardEvent {
|
pub enum KeyboardEvent {
|
||||||
Keymap,
|
|
||||||
Key { key: u32, state: u32 },
|
Key { key: u32, state: u32 },
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +126,7 @@ struct SurfaceInfo {
|
|||||||
pointer_queue: VecDeque<PointerEvent>,
|
pointer_queue: VecDeque<PointerEvent>,
|
||||||
pointer_latest_event: Instant,
|
pointer_latest_event: Instant,
|
||||||
keyboard_queue: VecDeque<KeyboardEvent>,
|
keyboard_queue: VecDeque<KeyboardEvent>,
|
||||||
keyboard_info: Option<KeyboardInfo>,
|
keyboard_info: KeyboardInfo,
|
||||||
}
|
}
|
||||||
impl SurfaceInfo {
|
impl SurfaceInfo {
|
||||||
fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender<Option<CursorInfo>>) -> Self {
|
fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender<Option<CursorInfo>>) -> Self {
|
||||||
@@ -122,7 +136,9 @@ impl SurfaceInfo {
|
|||||||
pointer_queue: VecDeque::new(),
|
pointer_queue: VecDeque::new(),
|
||||||
pointer_latest_event: Instant::now(),
|
pointer_latest_event: Instant::now(),
|
||||||
keyboard_queue: VecDeque::new(),
|
keyboard_queue: VecDeque::new(),
|
||||||
keyboard_info: None,
|
keyboard_info: KeyboardInfo::new(
|
||||||
|
&Keymap::new_from_names(&Context::new(0), "", "", "", "", None, 0).unwrap(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn flush(&self) {
|
fn flush(&self) {
|
||||||
@@ -217,25 +233,20 @@ impl SurfaceInfo {
|
|||||||
|
|
||||||
locked
|
locked
|
||||||
}
|
}
|
||||||
fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, mut locked: bool) -> bool {
|
fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, locked: bool) -> bool {
|
||||||
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
let Ok(focus) = self.wl_surface.upgrade() else { return false; };
|
||||||
let Some(info) = self.keyboard_info.as_mut() else { return true; };
|
|
||||||
|
|
||||||
if !locked {
|
if !locked {
|
||||||
keyboard.enter(0, &focus, vec![]);
|
keyboard.enter(0, &focus, vec![]);
|
||||||
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
|
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
|
||||||
keyboard.repeat_info(0, 0);
|
keyboard.repeat_info(0, 0);
|
||||||
}
|
}
|
||||||
locked = info.keymap.send(keyboard).is_ok();
|
|
||||||
}
|
}
|
||||||
while let Some(event) = self.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) => {
|
|
||||||
let _ = info.keymap.send(keyboard);
|
|
||||||
}
|
|
||||||
(true, KeyboardEvent::Key { key, state }) => {
|
(true, KeyboardEvent::Key { key, state }) => {
|
||||||
if let Ok(key_count) = info.process(key, state, keyboard) {
|
if let Ok(key_count) = self.keyboard_info.process(key, state, keyboard) {
|
||||||
if key_count == 0 {
|
if key_count == 0 {
|
||||||
keyboard.leave(SERIAL_COUNTER.inc(), &focus);
|
keyboard.leave(SERIAL_COUNTER.inc(), &focus);
|
||||||
return false;
|
return false;
|
||||||
@@ -279,29 +290,6 @@ impl SeatData {
|
|||||||
seat_data
|
seat_data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_keymap_str(&self, keymap: &str, surfaces: Vec<WlSurface>) -> Result<()> {
|
|
||||||
let context = xkb::Context::new(0);
|
|
||||||
let keymap =
|
|
||||||
Keymap::new_from_string(&context, keymap.to_string(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
|
|
||||||
.ok_or_else(|| eyre!("Keymap is not valid"))?;
|
|
||||||
self.set_keymap(&keymap, surfaces);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
pub fn set_keymap(&self, keymap: &Keymap, surfaces: Vec<WlSurface>) {
|
|
||||||
let mut panels = self.surfaces.lock();
|
|
||||||
let Some((_, focus)) = self.keyboard.get() else {return};
|
|
||||||
for surface in surfaces {
|
|
||||||
let Some(surface_info) = panels.get_mut(&surface.id()) else {continue};
|
|
||||||
surface_info
|
|
||||||
.keyboard_info
|
|
||||||
.replace(KeyboardInfo::new(keymap));
|
|
||||||
|
|
||||||
if *focus.lock() == surface.id() {
|
|
||||||
surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) {
|
pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) {
|
||||||
let mut surfaces = self.surfaces.lock();
|
let mut surfaces = self.surfaces.lock();
|
||||||
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
||||||
@@ -357,7 +345,6 @@ impl SeatData {
|
|||||||
if keyboard_focus.is_null() {
|
if keyboard_focus.is_null() {
|
||||||
*keyboard_focus = surfaces
|
*keyboard_focus = surfaces
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_k, v)| v.keyboard_info.is_some())
|
|
||||||
.filter(|(_k, v)| !v.keyboard_queue.is_empty())
|
.filter(|(_k, v)| !v.keyboard_queue.is_empty())
|
||||||
.map(|(k, _v)| k)
|
.map(|(k, _v)| k)
|
||||||
.choose(&mut thread_rng())
|
.choose(&mut thread_rng())
|
||||||
@@ -414,9 +401,12 @@ pub struct CursorInfo {
|
|||||||
pub hotspot_y: i32,
|
pub hotspot_y: i32,
|
||||||
}
|
}
|
||||||
impl CursorInfo {
|
impl CursorInfo {
|
||||||
pub fn cursor_data(&self) -> Option<(Vector2<u32>, Vector2<i32>)> {
|
pub fn cursor_data(&self) -> Option<Geometry> {
|
||||||
let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?;
|
let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?;
|
||||||
Some((cursor_size, [self.hotspot_x, self.hotspot_y].into()))
|
Some(Geometry {
|
||||||
|
origin: [self.hotspot_x, self.hotspot_y].into(),
|
||||||
|
size: cursor_size,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,23 +4,30 @@ use super::{
|
|||||||
surface::CoreSurface,
|
surface::CoreSurface,
|
||||||
SERIAL_COUNTER,
|
SERIAL_COUNTER,
|
||||||
};
|
};
|
||||||
use crate::nodes::{
|
use crate::{
|
||||||
drawable::model::ModelPart,
|
nodes::{
|
||||||
items::panel::{Backend, PanelItem, RecommendedState, SurfaceID},
|
drawable::model::ModelPart,
|
||||||
Message, Node,
|
items::panel::{
|
||||||
|
Backend, ChildInfo, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo,
|
||||||
|
ToplevelState,
|
||||||
|
},
|
||||||
|
Node,
|
||||||
|
},
|
||||||
|
wayland::seat::handle_cursor,
|
||||||
};
|
};
|
||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{bail, eyre, Result};
|
||||||
use mint::Vector2;
|
use mint::Vector2;
|
||||||
use nanoid::nanoid;
|
use nanoid::nanoid;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::{ser::SerializeSeq, Serialize, Serializer};
|
|
||||||
use smithay::reexports::{
|
use smithay::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_CONFIGURE_BOUNDS_SINCE, EVT_WM_CAPABILITIES_SINCE},
|
xdg_toplevel::{
|
||||||
|
self, ResizeEdge, XdgToplevel, EVT_CONFIGURE_BOUNDS_SINCE, EVT_WM_CAPABILITIES_SINCE,
|
||||||
|
},
|
||||||
xdg_wm_base::{self, XdgWmBase},
|
xdg_wm_base::{self, XdgWmBase},
|
||||||
},
|
},
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
@@ -30,14 +37,12 @@ use smithay::reexports::{
|
|||||||
Weak as WlWeak,
|
Weak as WlWeak,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use stardust_xr::schemas::flex::serialize;
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
};
|
};
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
|
|
||||||
|
|
||||||
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||||
fn bind(
|
fn bind(
|
||||||
@@ -195,6 +200,14 @@ impl PositionerData {
|
|||||||
pos
|
pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl From<PositionerData> for Geometry {
|
||||||
|
fn from(value: PositionerData) -> Self {
|
||||||
|
Geometry {
|
||||||
|
origin: value.get_pos(),
|
||||||
|
size: value.size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandState {
|
impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandState {
|
||||||
fn request(
|
fn request(
|
||||||
@@ -285,20 +298,6 @@ impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandSta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Clone, Copy)]
|
|
||||||
pub struct Geometry {
|
|
||||||
pub origin: Vector2<i32>,
|
|
||||||
pub size: Vector2<u32>,
|
|
||||||
}
|
|
||||||
impl Default for Geometry {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
origin: Vector2::from([0; 2]),
|
|
||||||
size: Vector2::from([0; 2]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct XdgSurfaceData {
|
pub struct XdgSurfaceData {
|
||||||
wl_surface: WlWeak<WlSurface>,
|
wl_surface: WlWeak<WlSurface>,
|
||||||
surface_id: SurfaceID,
|
surface_id: SurfaceID,
|
||||||
@@ -388,6 +387,7 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
|||||||
);
|
);
|
||||||
toplevel_data.lock().panel_item_node.replace(node);
|
toplevel_data.lock().panel_item_node.replace(node);
|
||||||
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
||||||
|
handle_cursor(&panel_item, panel_item.backend.cursor.clone());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -410,7 +410,12 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
|||||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
panel_item.commit_toplevel();
|
let Some(xdg_surface) = toplevel_data.lock().xdg_surface() else {return};
|
||||||
|
let Some(xdg_surface_data) = XdgSurfaceData::get(&xdg_surface) else {return};
|
||||||
|
let Some(wl_surface) = xdg_surface_data.lock().wl_surface() else {return};
|
||||||
|
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {return};
|
||||||
|
let Some(size) = core_surface.size() else {return};
|
||||||
|
panel_item.toplevel_size_changed(size);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -441,9 +446,17 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
|||||||
parent_data.surface_id.clone(),
|
parent_data.surface_id.clone(),
|
||||||
positioner,
|
positioner,
|
||||||
));
|
));
|
||||||
|
let panel_item = parent_data.panel_item().unwrap();
|
||||||
|
handle_cursor(
|
||||||
|
&panel_item,
|
||||||
|
panel_item
|
||||||
|
.backend
|
||||||
|
.seat
|
||||||
|
.new_surface(&popup_data.lock().wl_surface().unwrap()),
|
||||||
|
);
|
||||||
let xdg_popup = data_init.init(id, popup_data);
|
let xdg_popup = data_init.init(id, popup_data);
|
||||||
xdg_surface_data.lock().surface_id = SurfaceID::Child(uid);
|
xdg_surface_data.lock().surface_id = SurfaceID::Child(uid);
|
||||||
let panel_item = parent_data.panel_item().unwrap();
|
|
||||||
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
|
||||||
debug!(?xdg_popup, ?xdg_surface, "Create XDG popup");
|
debug!(?xdg_popup, ?xdg_surface, "Create XDG popup");
|
||||||
|
|
||||||
@@ -456,7 +469,6 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
|||||||
let xdg_popup = xdg_popup.upgrade().unwrap();
|
let xdg_popup = xdg_popup.upgrade().unwrap();
|
||||||
let Some(popup_data) = PopupData::get(&xdg_popup) else {return};
|
let Some(popup_data) = PopupData::get(&xdg_popup) else {return};
|
||||||
let popup_data = popup_data.lock();
|
let popup_data = popup_data.lock();
|
||||||
// panel_item.commit_popup(popup_data);
|
|
||||||
panel_item
|
panel_item
|
||||||
.backend
|
.backend
|
||||||
.new_popup(&panel_item, &xdg_popup, &*popup_data);
|
.new_popup(&panel_item, &xdg_popup, &*popup_data);
|
||||||
@@ -498,10 +510,6 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serde_error<S: Serializer>(msg: &str) -> Result<S::Ok, S::Error> {
|
|
||||||
Err(serde::ser::Error::custom(msg))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ToplevelData {
|
pub struct ToplevelData {
|
||||||
panel_item_node: Option<Arc<Node>>,
|
panel_item_node: Option<Arc<Node>>,
|
||||||
@@ -511,7 +519,6 @@ pub struct ToplevelData {
|
|||||||
app_id: Option<String>,
|
app_id: Option<String>,
|
||||||
max_size: Option<Vector2<u32>>,
|
max_size: Option<Vector2<u32>>,
|
||||||
min_size: Option<Vector2<u32>>,
|
min_size: Option<Vector2<u32>>,
|
||||||
states: Vec<u32>,
|
|
||||||
}
|
}
|
||||||
impl ToplevelData {
|
impl ToplevelData {
|
||||||
fn new(xdg_surface: &XdgSurface) -> Self {
|
fn new(xdg_surface: &XdgSurface) -> Self {
|
||||||
@@ -523,7 +530,6 @@ impl ToplevelData {
|
|||||||
app_id: None,
|
app_id: None,
|
||||||
max_size: None,
|
max_size: None,
|
||||||
min_size: None,
|
min_size: None,
|
||||||
states: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,41 +546,6 @@ impl ToplevelData {
|
|||||||
xdg_surface_data.panel_item()
|
xdg_surface_data.panel_item()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Serialize for ToplevelData {
|
|
||||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
||||||
let Some(xdg_surface) = self.xdg_surface() else {return serializer.serialize_none()};
|
|
||||||
let Some(xdg_surface_data) = XdgSurfaceData::get(&xdg_surface) else {return serializer.serialize_none()};
|
|
||||||
let xdg_surface_data = xdg_surface_data.lock();
|
|
||||||
let geometry = xdg_surface_data.geometry.clone();
|
|
||||||
let Some(wl_surface) = xdg_surface_data.wl_surface() else {return serde_error::<S>("Wayland surface not found")};
|
|
||||||
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 {
|
impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||||
fn request(
|
fn request(
|
||||||
_state: &mut WaylandState,
|
_state: &mut WaylandState,
|
||||||
@@ -588,30 +559,41 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for 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");
|
||||||
data.lock().parent = parent.map(|toplevel| toplevel.downgrade());
|
data.lock().parent = parent.clone().map(|toplevel| toplevel.downgrade());
|
||||||
|
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||||
|
if let Some(parent) = parent {
|
||||||
|
panel_item.toplevel_parent_changed(
|
||||||
|
&ToplevelData::get(&parent).lock().panel_item().unwrap().uid,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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");
|
||||||
data.lock().title = (!title.is_empty()).then_some(title);
|
data.lock().title = (!title.is_empty()).then_some(title.clone());
|
||||||
|
|
||||||
|
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||||
|
panel_item.toplevel_title_changed(&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");
|
||||||
data.lock().app_id = (!app_id.is_empty()).then_some(app_id);
|
data.lock().app_id = (!app_id.is_empty()).then_some(app_id.clone());
|
||||||
|
|
||||||
|
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||||
|
panel_item.toplevel_app_id_changed(&app_id);
|
||||||
}
|
}
|
||||||
xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => {
|
xdg_toplevel::Request::ShowWindowMenu {
|
||||||
debug!(
|
seat: _,
|
||||||
?xdg_toplevel,
|
serial: _,
|
||||||
?seat,
|
x,
|
||||||
serial,
|
y,
|
||||||
x,
|
} => {
|
||||||
y,
|
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||||
"Show XDG Toplevel window menu"
|
panel_item.toplevel_window_menu([x, y].into());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
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.lock().panel_item() else {return};
|
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Move);
|
panel_item.toplevel_move_request();
|
||||||
}
|
}
|
||||||
xdg_toplevel::Request::Resize {
|
xdg_toplevel::Request::Resize {
|
||||||
seat,
|
seat,
|
||||||
@@ -627,7 +609,18 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
|||||||
"XDG Toplevel resize request"
|
"XDG Toplevel resize request"
|
||||||
);
|
);
|
||||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Resize(edges as u32));
|
let (up, down, left, right) = match edges {
|
||||||
|
ResizeEdge::Top => (true, false, false, false),
|
||||||
|
ResizeEdge::Bottom => (false, true, false, false),
|
||||||
|
ResizeEdge::Left => (false, false, true, false),
|
||||||
|
ResizeEdge::TopLeft => (true, false, true, false),
|
||||||
|
ResizeEdge::BottomLeft => (false, true, true, false),
|
||||||
|
ResizeEdge::Right => (false, false, false, true),
|
||||||
|
ResizeEdge::TopRight => (true, false, false, true),
|
||||||
|
ResizeEdge::BottomRight => (false, true, false, true),
|
||||||
|
_ => (false, false, false, false),
|
||||||
|
};
|
||||||
|
panel_item.toplevel_resize_request(up, down, left, right)
|
||||||
}
|
}
|
||||||
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");
|
||||||
@@ -641,28 +634,28 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
|||||||
}
|
}
|
||||||
xdg_toplevel::Request::SetMaximized => {
|
xdg_toplevel::Request::SetMaximized => {
|
||||||
let Some(panel_item) = data.lock().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(ToplevelState::Maximized);
|
||||||
}
|
}
|
||||||
xdg_toplevel::Request::UnsetMaximized => {
|
xdg_toplevel::Request::UnsetMaximized => {
|
||||||
let Some(panel_item) = data.lock().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(ToplevelState::UnMaximized);
|
||||||
}
|
}
|
||||||
xdg_toplevel::Request::SetFullscreen { output: _ } => {
|
xdg_toplevel::Request::SetFullscreen { output: _ } => {
|
||||||
let Some(panel_item) = data.lock().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(ToplevelState::Fullscreen);
|
||||||
}
|
}
|
||||||
xdg_toplevel::Request::UnsetFullscreen => {
|
xdg_toplevel::Request::UnsetFullscreen => {
|
||||||
let Some(panel_item) = data.lock().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(ToplevelState::UnFullscreen);
|
||||||
}
|
}
|
||||||
xdg_toplevel::Request::SetMinimized => {
|
xdg_toplevel::Request::SetMinimized => {
|
||||||
let Some(panel_item) = data.lock().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(ToplevelState::Minimized);
|
||||||
}
|
}
|
||||||
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.lock().panel_item() else {return};
|
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||||
panel_item.backend.on_drop();
|
panel_item.drop_toplevel();
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -723,17 +716,6 @@ impl PopupData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.get_pos())?;
|
|
||||||
seq.serialize_element(&positioner_data.size)?;
|
|
||||||
seq.end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Debug for PopupData {
|
impl Debug for PopupData {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("XdgPopupData")
|
f.debug_struct("XdgPopupData")
|
||||||
@@ -793,12 +775,27 @@ impl Dispatch<XdgPopup, Mutex<PopupData>, WaylandState> for WaylandState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct XdgToplevelState {
|
||||||
|
fullscreen: bool,
|
||||||
|
maximized: bool,
|
||||||
|
activated: bool,
|
||||||
|
tiled_up: bool,
|
||||||
|
tiled_down: bool,
|
||||||
|
tiled_left: bool,
|
||||||
|
tiled_right: bool,
|
||||||
|
capability_window_menu: bool,
|
||||||
|
capability_maximize: bool,
|
||||||
|
capability_fullscreen: bool,
|
||||||
|
capability_minimize: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct XDGBackend {
|
pub struct XDGBackend {
|
||||||
toplevel: WlWeak<XdgToplevel>,
|
toplevel: WlWeak<XdgToplevel>,
|
||||||
toplevel_wl_surface: WlWeak<WlSurface>,
|
toplevel_wl_surface: WlWeak<WlSurface>,
|
||||||
|
toplevel_state: Mutex<XdgToplevelState>,
|
||||||
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
|
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
|
||||||
cursor: watch::Receiver<Option<CursorInfo>>,
|
cursor: watch::Receiver<Option<CursorInfo>>,
|
||||||
pub seat: Arc<SeatData>,
|
seat: Arc<SeatData>,
|
||||||
pointer_grab: Mutex<Option<SurfaceID>>,
|
pointer_grab: Mutex<Option<SurfaceID>>,
|
||||||
keyboard_grab: Mutex<Option<SurfaceID>>,
|
keyboard_grab: Mutex<Option<SurfaceID>>,
|
||||||
}
|
}
|
||||||
@@ -814,6 +811,19 @@ impl XDGBackend {
|
|||||||
Some(XDGBackend {
|
Some(XDGBackend {
|
||||||
toplevel: toplevel.downgrade(),
|
toplevel: toplevel.downgrade(),
|
||||||
toplevel_wl_surface,
|
toplevel_wl_surface,
|
||||||
|
toplevel_state: Mutex::new(XdgToplevelState {
|
||||||
|
fullscreen: false,
|
||||||
|
maximized: false,
|
||||||
|
activated: false,
|
||||||
|
tiled_up: false,
|
||||||
|
tiled_down: false,
|
||||||
|
tiled_left: false,
|
||||||
|
tiled_right: false,
|
||||||
|
capability_window_menu: false,
|
||||||
|
capability_maximize: false,
|
||||||
|
capability_fullscreen: false,
|
||||||
|
capability_minimize: false,
|
||||||
|
}),
|
||||||
popups: Mutex::new(FxHashMap::default()),
|
popups: Mutex::new(FxHashMap::default()),
|
||||||
cursor,
|
cursor,
|
||||||
seat,
|
seat,
|
||||||
@@ -844,19 +854,50 @@ impl XDGBackend {
|
|||||||
fn toplevel_wl_surface(&self) -> Option<WlSurface> {
|
fn toplevel_wl_surface(&self) -> Option<WlSurface> {
|
||||||
self.toplevel_wl_surface.upgrade().ok()
|
self.toplevel_wl_surface.upgrade().ok()
|
||||||
}
|
}
|
||||||
fn input_surfaces(&self) -> Vec<WlSurface> {
|
|
||||||
let mut surfaces = self
|
fn configure(&self, size: Option<Vector2<u32>>) {
|
||||||
.toplevel_wl_surface()
|
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||||
.map(|s| vec![s])
|
let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
||||||
.unwrap_or_default();
|
let Some(wl_surface) = self.toplevel_wl_surface() else {return};
|
||||||
surfaces.extend(self.popups.lock().values().filter_map(|p| {
|
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {return};
|
||||||
let popup = p.upgrade().ok()?;
|
let Some(surface_size) = core_surface.size() else {return};
|
||||||
let popup_data = PopupData::get(&popup)?.lock();
|
|
||||||
let xdg_surface = popup_data.xdg_surface()?;
|
xdg_toplevel.configure(
|
||||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface)?.lock();
|
size.unwrap_or(surface_size).x as i32,
|
||||||
xdg_surface_data.wl_surface()
|
size.unwrap_or(surface_size).y as i32,
|
||||||
}));
|
self.states()
|
||||||
surfaces
|
.into_iter()
|
||||||
|
.flat_map(|state| state.to_ne_bytes())
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||||
|
self.flush_client();
|
||||||
|
}
|
||||||
|
fn states(&self) -> Vec<u32> {
|
||||||
|
let mut states = Vec::new();
|
||||||
|
let toplevel_state = self.toplevel_state.lock();
|
||||||
|
if toplevel_state.maximized {
|
||||||
|
states.push(1);
|
||||||
|
}
|
||||||
|
if toplevel_state.fullscreen {
|
||||||
|
states.push(2);
|
||||||
|
}
|
||||||
|
if toplevel_state.activated {
|
||||||
|
states.push(4);
|
||||||
|
}
|
||||||
|
if toplevel_state.tiled_left {
|
||||||
|
states.push(5);
|
||||||
|
}
|
||||||
|
if toplevel_state.tiled_right {
|
||||||
|
states.push(6);
|
||||||
|
}
|
||||||
|
if toplevel_state.tiled_up {
|
||||||
|
states.push(7);
|
||||||
|
}
|
||||||
|
if toplevel_state.tiled_down {
|
||||||
|
states.push(8);
|
||||||
|
}
|
||||||
|
states
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_popup(
|
pub fn new_popup(
|
||||||
@@ -869,53 +910,46 @@ impl XDGBackend {
|
|||||||
|
|
||||||
self.popups.lock().insert(uid.clone(), popup.downgrade());
|
self.popups.lock().insert(uid.clone(), popup.downgrade());
|
||||||
|
|
||||||
let Some(node) = panel_item.node() else {return};
|
let Some(positioner_data) = data.positioner_data() else {return};
|
||||||
let Ok(message) = serialize(&(&uid, data)) else {return};
|
panel_item.new_child(ChildInfo {
|
||||||
let _ = node.send_remote_signal("new_child", message);
|
uid,
|
||||||
|
parent: data.parent_id.clone(),
|
||||||
|
geometry: positioner_data.into(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
pub fn reposition_popup(&self, panel_item: &PanelItem<XDGBackend>, popup_state: &PopupData) {
|
pub fn reposition_popup(&self, panel_item: &PanelItem<XDGBackend>, popup_state: &PopupData) {
|
||||||
let Some(node) = panel_item.node() else {return};
|
|
||||||
let Some(positioner_data) = popup_state.positioner_data() else {return};
|
let Some(positioner_data) = popup_state.positioner_data() else {return};
|
||||||
|
panel_item.reposition_child(&popup_state.uid, positioner_data.into())
|
||||||
let _ = node.send_remote_signal(
|
|
||||||
"reposition_child",
|
|
||||||
serialize((positioner_data.get_pos(), positioner_data.size)).unwrap(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
pub fn drop_popup(&self, panel_item: &PanelItem<XDGBackend>, uid: &str) {
|
pub fn drop_popup(&self, panel_item: &PanelItem<XDGBackend>, uid: &str) {
|
||||||
'seat_drop: {
|
panel_item.drop_child(uid);
|
||||||
let Some(popup) = self
|
let Some(popup) = self
|
||||||
.popups
|
.popups
|
||||||
.lock()
|
.lock()
|
||||||
.remove(uid) else {break 'seat_drop};
|
.remove(uid) else {return};
|
||||||
let Some(popup) = popup.upgrade().ok() else {break 'seat_drop};
|
let Some(popup) = popup.upgrade().ok() else {return};
|
||||||
let Some(popup) = popup.data::<Arc<PopupData>>().cloned() else {break 'seat_drop};
|
let Some(popup) = popup.data::<Arc<PopupData>>().cloned() else {return};
|
||||||
let Some(wl_surface) = popup.wl_surface() else {break 'seat_drop};
|
let Some(wl_surface) = popup.wl_surface() else {return};
|
||||||
self.seat.drop_surface(&wl_surface);
|
self.seat.drop_surface(&wl_surface);
|
||||||
}
|
|
||||||
|
|
||||||
let Some(node) = panel_item.node() else {return};
|
|
||||||
let Ok(message) = serialize(uid) else {return};
|
|
||||||
let _ = node.send_remote_signal("drop_child", message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn popups_data(&self) -> Vec<PopupData> {
|
fn child_data(&self) -> Vec<ChildInfo> {
|
||||||
self.popups
|
self.popups
|
||||||
.lock()
|
.lock()
|
||||||
.values()
|
.values()
|
||||||
.filter_map(|v| Some(v.upgrade().ok()?.data::<Mutex<PopupData>>()?.lock().clone()))
|
.filter_map(|v| {
|
||||||
|
let popup = v.upgrade().ok()?;
|
||||||
|
let data = PopupData::get(&popup)?;
|
||||||
|
let data_lock = data.lock();
|
||||||
|
Some(ChildInfo {
|
||||||
|
uid: data_lock.uid.clone(),
|
||||||
|
parent: data_lock.parent_id.clone(),
|
||||||
|
geometry: data_lock.positioner_data()?.into(),
|
||||||
|
})
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_drop(&self) {
|
|
||||||
let Some(toplevel_popup) = self.toplevel_xdg_surface().and_then(|s| XdgSurfaceData::get(&s).and_then(|s| s.lock().panel_item.upgrade())) else {return};
|
|
||||||
toplevel_popup.drop_toplevel();
|
|
||||||
let Some(toplevel) = self.toplevel_wl_surface() else {return};
|
|
||||||
self.seat.drop_surface(&toplevel);
|
|
||||||
|
|
||||||
debug!("Dropped panel item gracefully");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush_client(&self) {
|
fn flush_client(&self) {
|
||||||
let Some(client) = self.toplevel_wl_surface().and_then(|s| s.client()) else {return};
|
let Some(client) = self.toplevel_wl_surface().and_then(|s| s.client()) else {return};
|
||||||
if let Some(client_state) = client.get_data::<ClientState>() {
|
if let Some(client_state) = client.get_data::<ClientState>() {
|
||||||
@@ -923,73 +957,54 @@ impl XDGBackend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Drop for XDGBackend {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let Some(toplevel) = self.toplevel_wl_surface() else {return};
|
||||||
|
self.seat.drop_surface(&toplevel);
|
||||||
|
debug!("Dropped panel item gracefully");
|
||||||
|
}
|
||||||
|
}
|
||||||
impl Backend for XDGBackend {
|
impl Backend for XDGBackend {
|
||||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
fn start_data(&self) -> Result<PanelItemInitData> {
|
||||||
let toplevel_state = self
|
let toplevel_data = self
|
||||||
.toplevel()
|
.toplevel()
|
||||||
.map(|t| ToplevelData::get(&t).lock().clone());
|
.map(|t| ToplevelData::get(&t).lock().clone())
|
||||||
|
.ok_or_else(|| eyre!("Could not get toplevel"))?;
|
||||||
|
|
||||||
let pointer_grab = self.pointer_grab.lock().clone();
|
let pointer_grab = self.pointer_grab.lock().clone();
|
||||||
let keyboard_grab = self.keyboard_grab.lock().clone();
|
let keyboard_grab = self.keyboard_grab.lock().clone();
|
||||||
|
|
||||||
Ok(serialize((
|
let Some(wl_surface) = self.toplevel_wl_surface() else {bail!("Wayland surface not found")};
|
||||||
id,
|
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {bail!("Core surface not found")};
|
||||||
(
|
let Some(size) = core_surface.size() else {bail!("Surface size not found")};
|
||||||
self.cursor.borrow().as_ref().and_then(|c| c.cursor_data()),
|
|
||||||
toplevel_state,
|
|
||||||
self.popups_data(),
|
|
||||||
pointer_grab,
|
|
||||||
keyboard_grab,
|
|
||||||
),
|
|
||||||
))?
|
|
||||||
.into())
|
|
||||||
}
|
|
||||||
fn serialize_toplevel(&self) -> Result<Message> {
|
|
||||||
let toplevel = self
|
|
||||||
.toplevel()
|
|
||||||
.ok_or_else(|| eyre!("Toplevel does not exist"))?;
|
|
||||||
let state = ToplevelData::get(&toplevel);
|
|
||||||
let data = serialize(&state.lock().clone())?;
|
|
||||||
Ok(data.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_toplevel_capabilities(&self, capabilities: Vec<u8>) {
|
let toplevel = ToplevelInfo {
|
||||||
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
parent: toplevel_data
|
||||||
let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
.parent
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|p| p.upgrade().ok())
|
||||||
|
.and_then(|p| ToplevelData::get(&p).lock().panel_item())
|
||||||
|
.map(|p| p.uid.clone()),
|
||||||
|
title: toplevel_data.title.clone(),
|
||||||
|
app_id: toplevel_data.app_id.clone(),
|
||||||
|
size,
|
||||||
|
min_size: toplevel_data.min_size.clone(),
|
||||||
|
max_size: toplevel_data.max_size.clone(),
|
||||||
|
logical_rectangle: XdgSurfaceData::get(&self.toplevel_xdg_surface().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.geometry
|
||||||
|
.clone()
|
||||||
|
.unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
if xdg_toplevel.version() < EVT_WM_CAPABILITIES_SINCE {
|
Ok(PanelItemInitData {
|
||||||
return;
|
cursor: self.cursor.borrow().as_ref().and_then(|c| c.cursor_data()),
|
||||||
}
|
toplevel,
|
||||||
xdg_toplevel.wm_capabilities(capabilities);
|
children: self.child_data(),
|
||||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
pointer_grab,
|
||||||
self.flush_client();
|
keyboard_grab,
|
||||||
}
|
})
|
||||||
|
|
||||||
fn configure_toplevel(
|
|
||||||
&self,
|
|
||||||
size: Option<Vector2<u32>>,
|
|
||||||
states: Vec<u32>,
|
|
||||||
bounds: Option<Vector2<u32>>,
|
|
||||||
) {
|
|
||||||
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
|
||||||
let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
|
||||||
debug!(?size, ?states, ?bounds, "Configure toplevel info");
|
|
||||||
if let Some(bounds) = bounds {
|
|
||||||
if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE {
|
|
||||||
xdg_toplevel.configure_bounds(bounds.x as i32, bounds.y as i32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let size = size.unwrap_or(Vector2::from([0; 2]));
|
|
||||||
xdg_toplevel.configure(
|
|
||||||
size.x as i32,
|
|
||||||
size.y as i32,
|
|
||||||
states
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|state| state.to_ne_bytes())
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
|
||||||
self.flush_client();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||||
@@ -999,6 +1014,86 @@ impl Backend for XDGBackend {
|
|||||||
core_surface.apply_material(model_part);
|
core_surface.apply_material(model_part);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn set_toplevel_capabilities(&self, capabilities: Vec<u8>) {
|
||||||
|
// let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||||
|
// let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
||||||
|
|
||||||
|
// if xdg_toplevel.version() < EVT_WM_CAPABILITIES_SINCE {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// xdg_toplevel.wm_capabilities(capabilities);
|
||||||
|
// xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||||
|
// self.flush_client();
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn close_toplevel(&self) {
|
||||||
|
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||||
|
xdg_toplevel.close();
|
||||||
|
}
|
||||||
|
fn auto_size_toplevel(&self) {
|
||||||
|
self.configure(Some([0, 0].into()));
|
||||||
|
}
|
||||||
|
fn set_toplevel_size(&self, size: Vector2<u32>) {
|
||||||
|
self.configure(Some(size));
|
||||||
|
}
|
||||||
|
fn toplevel_maximize(&self) {
|
||||||
|
self.toplevel_state.lock().maximized = true;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn toplevel_unmaximize(&self) {
|
||||||
|
self.toplevel_state.lock().maximized = false;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn toplevel_fullscreen(&self) {
|
||||||
|
self.toplevel_state.lock().fullscreen = true;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn toplevel_unfullscreen(&self) {
|
||||||
|
self.toplevel_state.lock().fullscreen = false;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn set_toplevel_focused_visuals(&self, focused: bool) {
|
||||||
|
self.toplevel_state.lock().activated = focused;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn set_toplevel_tiling(&self, up: bool, down: bool, left: bool, right: bool) {
|
||||||
|
self.toplevel_state.lock().tiled_up = up;
|
||||||
|
self.toplevel_state.lock().tiled_down = down;
|
||||||
|
self.toplevel_state.lock().tiled_left = left;
|
||||||
|
self.toplevel_state.lock().tiled_right = right;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn set_toplevel_bounds(&self, bounds: Option<Vector2<u32>>) {
|
||||||
|
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||||
|
let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
||||||
|
if xdg_toplevel.version() <= EVT_CONFIGURE_BOUNDS_SINCE {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xdg_toplevel.configure_bounds(
|
||||||
|
bounds.map(|b| b.x as i32).unwrap_or_default(),
|
||||||
|
bounds.map(|b| b.y as i32).unwrap_or_default(),
|
||||||
|
);
|
||||||
|
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||||
|
self.flush_client();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_maximize_enabled(&self, enabled: bool) {
|
||||||
|
self.toplevel_state.lock().capability_maximize = enabled;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn set_minimize_enabled(&self, enabled: bool) {
|
||||||
|
self.toplevel_state.lock().capability_minimize = enabled;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn set_fullscreen_enabled(&self, enabled: bool) {
|
||||||
|
self.toplevel_state.lock().capability_fullscreen = enabled;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
fn set_window_menu_enabled(&self, enabled: bool) {
|
||||||
|
self.toplevel_state.lock().capability_window_menu = enabled;
|
||||||
|
self.configure(None);
|
||||||
|
}
|
||||||
|
|
||||||
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
|
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
|
||||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||||
self.seat
|
self.seat
|
||||||
@@ -1030,14 +1125,6 @@ impl Backend for XDGBackend {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_set_keymap(&self, keymap: &str) -> Result<()> {
|
|
||||||
let context = xkb::Context::new(0);
|
|
||||||
let keymap =
|
|
||||||
Keymap::new_from_string(&context, keymap.to_string(), XKB_KEYMAP_FORMAT_TEXT_V1, 0)
|
|
||||||
.ok_or_else(|| eyre!("Keymap is not valid"))?;
|
|
||||||
self.seat.set_keymap(&keymap, self.input_surfaces());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
||||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||||
self.seat.keyboard_event(
|
self.seat.keyboard_event(
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use super::{
|
use super::{
|
||||||
seat::{KeyboardEvent, PointerEvent, SeatData},
|
seat::{KeyboardEvent, PointerEvent, SeatData},
|
||||||
state::ClientState,
|
state::ClientState,
|
||||||
xdg_shell::PopupData,
|
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
nodes::{
|
nodes::{
|
||||||
drawable::model::ModelPart,
|
drawable::model::ModelPart,
|
||||||
items::panel::{Backend, PanelItem, RecommendedState, SurfaceID},
|
items::panel::{
|
||||||
Message,
|
Backend, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo, ToplevelState,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
wayland::surface::CoreSurface,
|
wayland::surface::CoreSurface,
|
||||||
};
|
};
|
||||||
@@ -18,8 +18,7 @@ use parking_lot::Mutex;
|
|||||||
use smithay::{
|
use smithay::{
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{EventLoop, LoopSignal},
|
calloop::{EventLoop, LoopSignal},
|
||||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
|
||||||
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource, WEnum},
|
|
||||||
x11rb::protocol::xproto::Window,
|
x11rb::protocol::xproto::Window,
|
||||||
},
|
},
|
||||||
utils::{Logical, Rectangle},
|
utils::{Logical, Rectangle},
|
||||||
@@ -29,7 +28,6 @@ use smithay::{
|
|||||||
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
|
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use stardust_xr::schemas::flex::serialize;
|
|
||||||
use std::{ffi::OsStr, iter::empty, sync::Arc, time::Duration};
|
use std::{ffi::OsStr, iter::empty, sync::Arc, time::Duration};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
@@ -165,7 +163,13 @@ impl XwmHandler for XWaylandHandler {
|
|||||||
},
|
},
|
||||||
move |_| {
|
move |_| {
|
||||||
let Some(panel_item) = window.user_data().get::<Arc<PanelItem<X11Backend>>>() else {return};
|
let Some(panel_item) = window.user_data().get::<Arc<PanelItem<X11Backend>>>() else {return};
|
||||||
panel_item.commit_toplevel();
|
panel_item.toplevel_size_changed(
|
||||||
|
[
|
||||||
|
window.geometry().size.w as u32,
|
||||||
|
window.geometry().size.h as u32,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -208,7 +212,7 @@ impl XwmHandler for XWaylandHandler {
|
|||||||
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, button: u32) {
|
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, button: u32) {
|
||||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||||
debug!(?window, button, "X window requests move");
|
debug!(?window, button, "X window requests move");
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Move);
|
panel_item.toplevel_move_request();
|
||||||
}
|
}
|
||||||
fn resize_request(
|
fn resize_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -219,40 +223,39 @@ impl XwmHandler for XWaylandHandler {
|
|||||||
) {
|
) {
|
||||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||||
debug!(?window, button, ?resize_edge, "X window requests resize");
|
debug!(?window, button, ?resize_edge, "X window requests resize");
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Resize(
|
let (up, down, left, right) = match resize_edge {
|
||||||
WEnum::Value(match resize_edge {
|
ResizeEdge::Top => (true, false, false, false),
|
||||||
ResizeEdge::Top => xdg_toplevel::ResizeEdge::Top,
|
ResizeEdge::Bottom => (false, true, false, false),
|
||||||
ResizeEdge::Bottom => xdg_toplevel::ResizeEdge::Bottom,
|
ResizeEdge::Left => (false, false, true, false),
|
||||||
ResizeEdge::Left => xdg_toplevel::ResizeEdge::Left,
|
ResizeEdge::TopLeft => (true, false, true, false),
|
||||||
ResizeEdge::TopLeft => xdg_toplevel::ResizeEdge::TopLeft,
|
ResizeEdge::BottomLeft => (false, true, true, false),
|
||||||
ResizeEdge::BottomLeft => xdg_toplevel::ResizeEdge::BottomLeft,
|
ResizeEdge::Right => (false, false, false, true),
|
||||||
ResizeEdge::Right => xdg_toplevel::ResizeEdge::Right,
|
ResizeEdge::TopRight => (true, false, false, true),
|
||||||
ResizeEdge::TopRight => xdg_toplevel::ResizeEdge::TopRight,
|
ResizeEdge::BottomRight => (false, true, false, true),
|
||||||
ResizeEdge::BottomRight => xdg_toplevel::ResizeEdge::BottomRight,
|
// _ => (false, false, false, false),
|
||||||
})
|
};
|
||||||
.into(),
|
panel_item.toplevel_resize_request(up, down, left, right)
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(true));
|
panel_item.recommend_toplevel_state(ToplevelState::Maximized);
|
||||||
}
|
}
|
||||||
fn unmaximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn unmaximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Maximize(false));
|
panel_item.recommend_toplevel_state(ToplevelState::UnMaximized);
|
||||||
}
|
}
|
||||||
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
panel_item.recommend_toplevel_state(ToplevelState::Fullscreen);
|
||||||
}
|
}
|
||||||
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
|
panel_item.recommend_toplevel_state(ToplevelState::UnFullscreen);
|
||||||
}
|
}
|
||||||
fn minimize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn minimize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||||
panel_item.recommend_toplevel_state(RecommendedState::Minimize);
|
panel_item.recommend_toplevel_state(ToplevelState::Minimized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,62 +283,129 @@ impl X11Backend {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
impl Backend for X11Backend {
|
impl Backend for X11Backend {
|
||||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
// fn start_data(&self, id: &str) -> Result<Message> {
|
||||||
let size = (
|
// let size = (
|
||||||
self.toplevel.geometry().size.w as u32,
|
// self.toplevel.geometry().size.w as u32,
|
||||||
self.toplevel.geometry().size.h as u32,
|
// self.toplevel.geometry().size.h as u32,
|
||||||
);
|
// );
|
||||||
let toplevel_state = (
|
// let toplevel_state = (
|
||||||
None::<String>,
|
// None::<String>,
|
||||||
self.toplevel.title(),
|
// self.toplevel.title(),
|
||||||
None::<String>,
|
// None::<String>,
|
||||||
(
|
// (
|
||||||
self.toplevel.geometry().size.w as u32,
|
// self.toplevel.geometry().size.w as u32,
|
||||||
self.toplevel.geometry().size.h as u32,
|
// self.toplevel.geometry().size.h as u32,
|
||||||
),
|
// ),
|
||||||
self.toplevel.min_size().map(|s| (s.w as u32, s.h as u32)),
|
// self.toplevel.min_size().map(|s| (s.w as u32, s.h as u32)),
|
||||||
self.toplevel.max_size().map(|s| (s.w as u32, s.w as u32)),
|
// self.toplevel.max_size().map(|s| (s.w as u32, s.w as u32)),
|
||||||
((0_i32, 0_i32), size),
|
// ((0_i32, 0_i32), size),
|
||||||
vec![0_u32; 0],
|
// vec![0_u32; 0],
|
||||||
);
|
// );
|
||||||
let info = (
|
// let info = (
|
||||||
None::<(Vector2<u32>, Vector2<i32>)>,
|
// None::<(Vector2<u32>, Vector2<i32>)>,
|
||||||
toplevel_state,
|
// toplevel_state,
|
||||||
Vec::<PopupData>::new(),
|
// Vec::<PopupData>::new(),
|
||||||
None::<SurfaceID>,
|
// None::<SurfaceID>,
|
||||||
None::<SurfaceID>,
|
// None::<SurfaceID>,
|
||||||
);
|
// );
|
||||||
Ok(serialize((id, info))?.into())
|
// Ok(serialize((id, info))?.into())
|
||||||
}
|
// }
|
||||||
fn serialize_toplevel(&self) -> Result<Message> {
|
// fn serialize_toplevel(&self) -> Result<Message> {
|
||||||
let toplevel_state = (
|
// let toplevel_state = (
|
||||||
None::<String>,
|
// None::<String>,
|
||||||
self.toplevel.title(),
|
// self.toplevel.title(),
|
||||||
None::<String>,
|
// None::<String>,
|
||||||
(
|
// (
|
||||||
self.toplevel.geometry().size.w,
|
// self.toplevel.geometry().size.w,
|
||||||
self.toplevel.geometry().size.h,
|
// self.toplevel.geometry().size.h,
|
||||||
),
|
// ),
|
||||||
self.toplevel.min_size().map(|s| (s.w, s.h)),
|
// self.toplevel.min_size().map(|s| (s.w, s.h)),
|
||||||
self.toplevel.max_size().map(|s| (s.w, s.w)),
|
// self.toplevel.max_size().map(|s| (s.w, s.w)),
|
||||||
);
|
// );
|
||||||
let data = serialize(&toplevel_state)?;
|
// let data = serialize(&toplevel_state)?;
|
||||||
Ok(data.into())
|
// Ok(data.into())
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn set_toplevel_capabilities(&self, _capabilities: Vec<u8>) {}
|
// fn set_toplevel_capabilities(&self, _capabilities: Vec<u8>) {}
|
||||||
|
|
||||||
fn configure_toplevel(
|
// fn set_toplevel_size(
|
||||||
&self,
|
// &self,
|
||||||
size: Option<Vector2<u32>>,
|
// size: Option<Vector2<u32>>,
|
||||||
states: Vec<u32>,
|
// states: Vec<u32>,
|
||||||
_bounds: Option<Vector2<u32>>,
|
// _bounds: Option<Vector2<u32>>,
|
||||||
) {
|
// ) {
|
||||||
let _ = self.toplevel.configure(
|
// let _ = self.toplevel.configure(
|
||||||
size.map(|s| Rectangle::from_loc_and_size((0, 0), (s.x as i32, s.y as i32))),
|
// size.map(|s| Rectangle::from_loc_and_size((0, 0), (s.x as i32, s.y as i32))),
|
||||||
);
|
// );
|
||||||
let _ = self.toplevel.set_maximized(states.contains(&1));
|
// let _ = self.toplevel.set_maximized(states.contains(&1));
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn start_data(&self) -> Result<PanelItemInitData> {
|
||||||
|
Ok(PanelItemInitData {
|
||||||
|
cursor: None,
|
||||||
|
toplevel: ToplevelInfo {
|
||||||
|
parent: None,
|
||||||
|
title: Some(self.toplevel.title()),
|
||||||
|
app_id: Some(self.toplevel.instance()),
|
||||||
|
size: [
|
||||||
|
self.toplevel.geometry().size.w as u32,
|
||||||
|
self.toplevel.geometry().size.h as u32,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
min_size: self
|
||||||
|
.toplevel
|
||||||
|
.min_size()
|
||||||
|
.map(|s| [s.w as u32, s.h as u32].into()),
|
||||||
|
max_size: self
|
||||||
|
.toplevel
|
||||||
|
.max_size()
|
||||||
|
.map(|s| [s.w as u32, s.h as u32].into()),
|
||||||
|
logical_rectangle: Geometry {
|
||||||
|
origin: [0, 0].into(),
|
||||||
|
size: [
|
||||||
|
self.toplevel.geometry().size.w as u32,
|
||||||
|
self.toplevel.geometry().size.h as u32,
|
||||||
|
]
|
||||||
|
.into(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
children: vec![],
|
||||||
|
pointer_grab: self._pointer_grab.lock().clone(),
|
||||||
|
keyboard_grab: self._keyboard_grab.lock().clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
fn close_toplevel(&self) {}
|
||||||
|
|
||||||
|
fn auto_size_toplevel(&self) {
|
||||||
|
let _ = self.toplevel.configure(None);
|
||||||
|
}
|
||||||
|
fn set_toplevel_size(&self, size: Vector2<u32>) {
|
||||||
|
let _ = self.toplevel.configure(Some(Rectangle {
|
||||||
|
loc: self.toplevel.geometry().loc,
|
||||||
|
size: (size.x as i32, size.y as i32).into(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
fn toplevel_maximize(&self) {
|
||||||
|
let _ = self.toplevel.set_maximized(true);
|
||||||
|
}
|
||||||
|
fn toplevel_unmaximize(&self) {
|
||||||
|
let _ = self.toplevel.set_maximized(false);
|
||||||
|
}
|
||||||
|
fn toplevel_fullscreen(&self) {
|
||||||
|
let _ = self.toplevel.set_fullscreen(true);
|
||||||
|
}
|
||||||
|
fn toplevel_unfullscreen(&self) {
|
||||||
|
let _ = self.toplevel.set_fullscreen(false);
|
||||||
|
}
|
||||||
|
fn set_toplevel_tiling(&self, _up: bool, _down: bool, _left: bool, _right: bool) {}
|
||||||
|
fn set_toplevel_bounds(&self, _bounds: Option<Vector2<u32>>) {}
|
||||||
|
fn set_toplevel_focused_visuals(&self, focused: bool) {
|
||||||
|
let _ = self.toplevel.set_activated(focused);
|
||||||
|
}
|
||||||
|
fn set_maximize_enabled(&self, _enabled: bool) {}
|
||||||
|
fn set_minimize_enabled(&self, _enabled: bool) {}
|
||||||
|
fn set_fullscreen_enabled(&self, _enabled: bool) {}
|
||||||
|
fn set_window_menu_enabled(&self, _enabled: bool) {}
|
||||||
|
|
||||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||||
let Some(wl_surface) = self.wl_surface_from_id(&surface) else {return};
|
let Some(wl_surface) = self.wl_surface_from_id(&surface) else {return};
|
||||||
@@ -375,16 +445,6 @@ impl Backend for X11Backend {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn keyboard_set_keymap(&self, keymap: &str) -> Result<()> {
|
|
||||||
self.seat.set_keymap_str(
|
|
||||||
&keymap,
|
|
||||||
if let Some(toplevel) = self.toplevel.wl_surface() {
|
|
||||||
vec![toplevel]
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
||||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||||
self.seat.keyboard_event(
|
self.seat.keyboard_event(
|
||||||
|
|||||||
Reference in New Issue
Block a user