refactor: panel items
This commit is contained in:
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -1918,9 +1918,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_repr"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e168eaaf71e8f9bd6037feb05190485708e019f4fd87d161b3c0a0d37daf85e5"
|
||||
checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2081,6 +2081,7 @@ dependencies = [
|
||||
"rustc-hash",
|
||||
"send_wrapper",
|
||||
"serde",
|
||||
"serde_repr",
|
||||
"smithay",
|
||||
"stardust-xr",
|
||||
"stereokit",
|
||||
|
||||
@@ -55,6 +55,7 @@ xkbcommon = { version = "0.5.0", default-features = false, optional = true }
|
||||
stardust-xr = "0.14.0"
|
||||
directories = "5.0.0"
|
||||
serde = { version = "1.0.160", features = ["derive"] }
|
||||
serde_repr = "0.1.16"
|
||||
tracing = "0.1.37"
|
||||
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
|
||||
global_counter = "0.2.2"
|
||||
|
||||
@@ -52,7 +52,7 @@ pub fn startup_settings(env: &FxHashMap<String, String>) -> Option<StartupSettin
|
||||
}
|
||||
|
||||
pub struct Client {
|
||||
pid: Option<i32>,
|
||||
pub pid: Option<i32>,
|
||||
// env: Option<FxHashMap<String, String>>,
|
||||
exe: Option<PathBuf>,
|
||||
dispatch_join_handle: OnceCell<JoinHandle<Result<()>>>,
|
||||
|
||||
@@ -20,6 +20,7 @@ use serde::{
|
||||
ser::Serializer,
|
||||
Deserialize, Serialize,
|
||||
};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::debug;
|
||||
@@ -29,20 +30,31 @@ lazy_static! {
|
||||
type_name: "panel",
|
||||
aliased_local_signals: vec![
|
||||
"apply_surface_material",
|
||||
"configure_toplevel",
|
||||
"set_toplevel_capabilities",
|
||||
"close_toplevel",
|
||||
"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_button",
|
||||
"pointer_motion",
|
||||
"keyboard_key",
|
||||
"keyboard_set_keymap_names",
|
||||
"keyboard_set_keymap_string",
|
||||
"close",
|
||||
],
|
||||
aliased_local_methods: vec![],
|
||||
aliased_remote_signals: vec![
|
||||
"commit_toplevel",
|
||||
"toplevel_parent_changed",
|
||||
"toplevel_title_changed",
|
||||
"toplevel_app_id_changed",
|
||||
"toplevel_window_menu",
|
||||
"recommend_toplevel_state",
|
||||
"toplevel_move_request",
|
||||
"toplevel_resize_request",
|
||||
"toplevel_size_changed",
|
||||
"set_cursor",
|
||||
"new_child",
|
||||
"reposition_child",
|
||||
@@ -118,28 +130,101 @@ impl serde::Serialize for SurfaceID {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
#[serde(tag = "type", content = "content")]
|
||||
pub enum RecommendedState {
|
||||
Maximize(bool),
|
||||
Fullscreen(bool),
|
||||
Minimize,
|
||||
Move,
|
||||
Resize(u32),
|
||||
/// The origin and size of the surface's "solid" part.
|
||||
#[derive(Debug, Serialize, Clone, Copy)]
|
||||
pub struct Geometry {
|
||||
pub origin: Vector2<i32>,
|
||||
pub size: Vector2<u32>,
|
||||
}
|
||||
/// The state of the panel item's toplevel.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct ToplevelInfo {
|
||||
/// The UID of the panel item of the parent of this toplevel, if it exists
|
||||
pub parent: Option<String>,
|
||||
/// Equivalent to the window title
|
||||
pub title: Option<String>,
|
||||
/// Application identifier, see <https://standards.freedesktop.org/desktop-entry-spec/>
|
||||
pub app_id: Option<String>,
|
||||
/// Current size in pixels
|
||||
pub size: Vector2<u32>,
|
||||
/// Recommended minimum size in pixels
|
||||
pub min_size: Option<Vector2<u32>>,
|
||||
/// Recommended maximum size in pixels
|
||||
pub max_size: Option<Vector2<u32>>,
|
||||
/// Surface geometry
|
||||
pub logical_rectangle: Geometry,
|
||||
}
|
||||
|
||||
#[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 {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message>;
|
||||
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 start_data(&self) -> Result<PanelItemInitData>;
|
||||
|
||||
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_button(&self, surface: &SurfaceID, button: u32, pressed: bool);
|
||||
fn pointer_scroll(
|
||||
@@ -149,7 +234,6 @@ pub trait Backend: Send + Sync + 'static {
|
||||
scroll_steps: Option<Vector2<f32>>,
|
||||
);
|
||||
|
||||
fn keyboard_set_keymap(&self, keymap: &str) -> Result<()>;
|
||||
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 {
|
||||
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> {
|
||||
@@ -210,20 +294,34 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
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(
|
||||
"keyboard_set_keymap_string",
|
||||
Self::keyboard_set_keymap_string_flex,
|
||||
"set_window_menu_enabled",
|
||||
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(
|
||||
// "keyboard_set_keymap_names",
|
||||
// Self::keyboard_set_keymap_names_flex,
|
||||
@@ -232,11 +330,88 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
|
||||
(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>> {
|
||||
self.node.upgrade()
|
||||
// Remote signals
|
||||
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(
|
||||
node: &Node,
|
||||
calling_client: Arc<Client>,
|
||||
@@ -264,6 +439,30 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
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(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
@@ -312,65 +511,6 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
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(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
@@ -390,89 +530,69 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
let Ok(message) = serialize(sid) else {return};
|
||||
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> {
|
||||
fn uid(&self) -> &str {
|
||||
&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> {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||
self.backend.serialize_start_data(id)
|
||||
}
|
||||
|
||||
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 start_data(&self) -> Result<PanelItemInitData> {
|
||||
self.backend.start_data()
|
||||
}
|
||||
|
||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||
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>) {
|
||||
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)
|
||||
}
|
||||
|
||||
fn keyboard_set_keymap(&self, keymap: &str) -> Result<()> {
|
||||
self.backend.keyboard_set_keymap(keymap)
|
||||
}
|
||||
fn keyboard_key(&self, surface: &SurfaceID, key: u32, state: bool) {
|
||||
self.backend.keyboard_key(surface, key, state)
|
||||
}
|
||||
|
||||
@@ -173,6 +173,19 @@ impl Node {
|
||||
.store(deserialize(message.as_ref())?, Ordering::Relaxed);
|
||||
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(
|
||||
node: &Node,
|
||||
_calling_client: Arc<Client>,
|
||||
|
||||
@@ -3,8 +3,11 @@ use super::{
|
||||
surface::CoreSurface,
|
||||
GLOBAL_DESTROY_QUEUE, SERIAL_COUNTER,
|
||||
};
|
||||
use crate::core::task;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use crate::{
|
||||
core::task,
|
||||
nodes::items::panel::{Backend, Geometry, PanelItem},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
use mint::Vector2;
|
||||
use nanoid::nanoid;
|
||||
use once_cell::sync::OnceCell;
|
||||
@@ -12,7 +15,7 @@ use parking_lot::Mutex;
|
||||
use rand::{seq::IteratorRandom, thread_rng};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use smithay::{
|
||||
input::keyboard::{KeymapFile, ModifiersState},
|
||||
input::keyboard::ModifiersState,
|
||||
reexports::wayland_server::{
|
||||
backend::{ClientId, GlobalId, ObjectId},
|
||||
protocol::{
|
||||
@@ -33,10 +36,23 @@ use std::{
|
||||
};
|
||||
use tokio::sync::watch;
|
||||
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 {
|
||||
keymap: KeymapFile,
|
||||
state: xkb::State,
|
||||
mods: ModifiersState,
|
||||
keys: FxHashSet<u32>,
|
||||
@@ -45,7 +61,6 @@ impl KeyboardInfo {
|
||||
pub fn new(keymap: &Keymap) -> Self {
|
||||
KeyboardInfo {
|
||||
state: xkb::State::new(keymap),
|
||||
keymap: KeymapFile::new(keymap),
|
||||
mods: ModifiersState::default(),
|
||||
keys: FxHashSet::default(),
|
||||
}
|
||||
@@ -101,7 +116,6 @@ pub enum PointerEvent {
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum KeyboardEvent {
|
||||
Keymap,
|
||||
Key { key: u32, state: u32 },
|
||||
}
|
||||
|
||||
@@ -112,7 +126,7 @@ struct SurfaceInfo {
|
||||
pointer_queue: VecDeque<PointerEvent>,
|
||||
pointer_latest_event: Instant,
|
||||
keyboard_queue: VecDeque<KeyboardEvent>,
|
||||
keyboard_info: Option<KeyboardInfo>,
|
||||
keyboard_info: KeyboardInfo,
|
||||
}
|
||||
impl SurfaceInfo {
|
||||
fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender<Option<CursorInfo>>) -> Self {
|
||||
@@ -122,7 +136,9 @@ impl SurfaceInfo {
|
||||
pointer_queue: VecDeque::new(),
|
||||
pointer_latest_event: Instant::now(),
|
||||
keyboard_queue: VecDeque::new(),
|
||||
keyboard_info: None,
|
||||
keyboard_info: KeyboardInfo::new(
|
||||
&Keymap::new_from_names(&Context::new(0), "", "", "", "", None, 0).unwrap(),
|
||||
),
|
||||
}
|
||||
}
|
||||
fn flush(&self) {
|
||||
@@ -217,25 +233,20 @@ impl SurfaceInfo {
|
||||
|
||||
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 Some(info) = self.keyboard_info.as_mut() else { return true; };
|
||||
|
||||
if !locked {
|
||||
keyboard.enter(0, &focus, vec![]);
|
||||
if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE {
|
||||
keyboard.repeat_info(0, 0);
|
||||
}
|
||||
locked = info.keymap.send(keyboard).is_ok();
|
||||
}
|
||||
while let Some(event) = self.keyboard_queue.pop_front() {
|
||||
debug!(locked, ?event, "Process keyboard event");
|
||||
match (locked, event) {
|
||||
(true, KeyboardEvent::Keymap) => {
|
||||
let _ = info.keymap.send(keyboard);
|
||||
}
|
||||
(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 {
|
||||
keyboard.leave(SERIAL_COUNTER.inc(), &focus);
|
||||
return false;
|
||||
@@ -279,29 +290,6 @@ impl SeatData {
|
||||
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) {
|
||||
let mut surfaces = self.surfaces.lock();
|
||||
let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return};
|
||||
@@ -357,7 +345,6 @@ impl SeatData {
|
||||
if keyboard_focus.is_null() {
|
||||
*keyboard_focus = surfaces
|
||||
.iter()
|
||||
.filter(|(_k, v)| v.keyboard_info.is_some())
|
||||
.filter(|(_k, v)| !v.keyboard_queue.is_empty())
|
||||
.map(|(k, _v)| k)
|
||||
.choose(&mut thread_rng())
|
||||
@@ -414,9 +401,12 @@ pub struct CursorInfo {
|
||||
pub hotspot_y: i32,
|
||||
}
|
||||
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()?;
|
||||
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,
|
||||
SERIAL_COUNTER,
|
||||
};
|
||||
use crate::nodes::{
|
||||
drawable::model::ModelPart,
|
||||
items::panel::{Backend, PanelItem, RecommendedState, SurfaceID},
|
||||
Message, Node,
|
||||
use crate::{
|
||||
nodes::{
|
||||
drawable::model::ModelPart,
|
||||
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 nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::{ser::SerializeSeq, Serialize, Serializer};
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_popup::{self, XdgPopup},
|
||||
xdg_positioner::{self, Anchor, ConstraintAdjustment, Gravity, XdgPositioner},
|
||||
xdg_surface::{self, XdgSurface},
|
||||
xdg_toplevel::{self, XdgToplevel, EVT_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},
|
||||
},
|
||||
wayland_server::{
|
||||
@@ -30,14 +37,12 @@ use smithay::reexports::{
|
||||
Weak as WlWeak,
|
||||
},
|
||||
};
|
||||
use stardust_xr::schemas::flex::serialize;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use tokio::sync::watch;
|
||||
use tracing::{debug, warn};
|
||||
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
|
||||
|
||||
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn bind(
|
||||
@@ -195,6 +200,14 @@ impl PositionerData {
|
||||
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 {
|
||||
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 {
|
||||
wl_surface: WlWeak<WlSurface>,
|
||||
surface_id: SurfaceID,
|
||||
@@ -388,6 +387,7 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
||||
);
|
||||
toplevel_data.lock().panel_item_node.replace(node);
|
||||
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());
|
||||
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(),
|
||||
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);
|
||||
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);
|
||||
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 Some(popup_data) = PopupData::get(&xdg_popup) else {return};
|
||||
let popup_data = popup_data.lock();
|
||||
// panel_item.commit_popup(popup_data);
|
||||
panel_item
|
||||
.backend
|
||||
.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)]
|
||||
pub struct ToplevelData {
|
||||
panel_item_node: Option<Arc<Node>>,
|
||||
@@ -511,7 +519,6 @@ pub struct ToplevelData {
|
||||
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 {
|
||||
@@ -523,7 +530,6 @@ impl ToplevelData {
|
||||
app_id: None,
|
||||
max_size: None,
|
||||
min_size: None,
|
||||
states: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -540,41 +546,6 @@ impl ToplevelData {
|
||||
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 {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
@@ -588,30 +559,41 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||
match request {
|
||||
xdg_toplevel::Request::SetParent { 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 } => {
|
||||
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 } => {
|
||||
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 } => {
|
||||
debug!(
|
||||
?xdg_toplevel,
|
||||
?seat,
|
||||
serial,
|
||||
x,
|
||||
y,
|
||||
"Show XDG Toplevel window menu"
|
||||
);
|
||||
xdg_toplevel::Request::ShowWindowMenu {
|
||||
seat: _,
|
||||
serial: _,
|
||||
x,
|
||||
y,
|
||||
} => {
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
panel_item.toplevel_window_menu([x, y].into());
|
||||
}
|
||||
xdg_toplevel::Request::Move { seat, serial } => {
|
||||
debug!(?xdg_toplevel, ?seat, serial, "XDG Toplevel move request");
|
||||
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 {
|
||||
seat,
|
||||
@@ -627,7 +609,18 @@ impl Dispatch<XdgToplevel, Mutex<ToplevelData>, WaylandState> for WaylandState {
|
||||
"XDG Toplevel resize request"
|
||||
);
|
||||
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 } => {
|
||||
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 => {
|
||||
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 => {
|
||||
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: _ } => {
|
||||
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 => {
|
||||
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 => {
|
||||
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 => {
|
||||
debug!(?xdg_toplevel, "Destroy XDG Toplevel");
|
||||
let Some(panel_item) = data.lock().panel_item() else {return};
|
||||
panel_item.backend.on_drop();
|
||||
panel_item.drop_toplevel();
|
||||
}
|
||||
_ => 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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
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 {
|
||||
toplevel: WlWeak<XdgToplevel>,
|
||||
toplevel_wl_surface: WlWeak<WlSurface>,
|
||||
toplevel_state: Mutex<XdgToplevelState>,
|
||||
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
|
||||
cursor: watch::Receiver<Option<CursorInfo>>,
|
||||
pub seat: Arc<SeatData>,
|
||||
seat: Arc<SeatData>,
|
||||
pointer_grab: Mutex<Option<SurfaceID>>,
|
||||
keyboard_grab: Mutex<Option<SurfaceID>>,
|
||||
}
|
||||
@@ -814,6 +811,19 @@ impl XDGBackend {
|
||||
Some(XDGBackend {
|
||||
toplevel: toplevel.downgrade(),
|
||||
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()),
|
||||
cursor,
|
||||
seat,
|
||||
@@ -844,19 +854,50 @@ impl XDGBackend {
|
||||
fn toplevel_wl_surface(&self) -> Option<WlSurface> {
|
||||
self.toplevel_wl_surface.upgrade().ok()
|
||||
}
|
||||
fn input_surfaces(&self) -> Vec<WlSurface> {
|
||||
let mut surfaces = self
|
||||
.toplevel_wl_surface()
|
||||
.map(|s| vec![s])
|
||||
.unwrap_or_default();
|
||||
surfaces.extend(self.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();
|
||||
xdg_surface_data.wl_surface()
|
||||
}));
|
||||
surfaces
|
||||
|
||||
fn configure(&self, size: Option<Vector2<u32>>) {
|
||||
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||
let Some(xdg_surface) = self.toplevel_xdg_surface() else {return};
|
||||
let Some(wl_surface) = self.toplevel_wl_surface() else {return};
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {return};
|
||||
let Some(surface_size) = core_surface.size() else {return};
|
||||
|
||||
xdg_toplevel.configure(
|
||||
size.unwrap_or(surface_size).x as i32,
|
||||
size.unwrap_or(surface_size).y as i32,
|
||||
self.states()
|
||||
.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(
|
||||
@@ -869,53 +910,46 @@ impl XDGBackend {
|
||||
|
||||
self.popups.lock().insert(uid.clone(), popup.downgrade());
|
||||
|
||||
let Some(node) = panel_item.node() else {return};
|
||||
let Ok(message) = serialize(&(&uid, data)) else {return};
|
||||
let _ = node.send_remote_signal("new_child", message);
|
||||
let Some(positioner_data) = data.positioner_data() else {return};
|
||||
panel_item.new_child(ChildInfo {
|
||||
uid,
|
||||
parent: data.parent_id.clone(),
|
||||
geometry: positioner_data.into(),
|
||||
})
|
||||
}
|
||||
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 _ = node.send_remote_signal(
|
||||
"reposition_child",
|
||||
serialize((positioner_data.get_pos(), positioner_data.size)).unwrap(),
|
||||
);
|
||||
panel_item.reposition_child(&popup_state.uid, positioner_data.into())
|
||||
}
|
||||
pub fn drop_popup(&self, panel_item: &PanelItem<XDGBackend>, uid: &str) {
|
||||
'seat_drop: {
|
||||
let Some(popup) = self
|
||||
panel_item.drop_child(uid);
|
||||
let Some(popup) = self
|
||||
.popups
|
||||
.lock()
|
||||
.remove(uid) else {break 'seat_drop};
|
||||
let Some(popup) = popup.upgrade().ok() else {break 'seat_drop};
|
||||
let Some(popup) = popup.data::<Arc<PopupData>>().cloned() else {break 'seat_drop};
|
||||
let Some(wl_surface) = popup.wl_surface() else {break 'seat_drop};
|
||||
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);
|
||||
.remove(uid) else {return};
|
||||
let Some(popup) = popup.upgrade().ok() else {return};
|
||||
let Some(popup) = popup.data::<Arc<PopupData>>().cloned() else {return};
|
||||
let Some(wl_surface) = popup.wl_surface() else {return};
|
||||
self.seat.drop_surface(&wl_surface);
|
||||
}
|
||||
|
||||
fn popups_data(&self) -> Vec<PopupData> {
|
||||
fn child_data(&self) -> Vec<ChildInfo> {
|
||||
self.popups
|
||||
.lock()
|
||||
.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<_>>()
|
||||
}
|
||||
|
||||
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) {
|
||||
let Some(client) = self.toplevel_wl_surface().and_then(|s| s.client()) else {return};
|
||||
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 {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||
let toplevel_state = self
|
||||
fn start_data(&self) -> Result<PanelItemInitData> {
|
||||
let toplevel_data = self
|
||||
.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 keyboard_grab = self.keyboard_grab.lock().clone();
|
||||
|
||||
Ok(serialize((
|
||||
id,
|
||||
(
|
||||
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())
|
||||
}
|
||||
let Some(wl_surface) = self.toplevel_wl_surface() else {bail!("Wayland surface not found")};
|
||||
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")};
|
||||
|
||||
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};
|
||||
let toplevel = ToplevelInfo {
|
||||
parent: toplevel_data
|
||||
.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 {
|
||||
return;
|
||||
}
|
||||
xdg_toplevel.wm_capabilities(capabilities);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
self.flush_client();
|
||||
}
|
||||
|
||||
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();
|
||||
Ok(PanelItemInitData {
|
||||
cursor: self.cursor.borrow().as_ref().and_then(|c| c.cursor_data()),
|
||||
toplevel,
|
||||
children: self.child_data(),
|
||||
pointer_grab,
|
||||
keyboard_grab,
|
||||
})
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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>) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||
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) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||
self.seat.keyboard_event(
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use super::{
|
||||
seat::{KeyboardEvent, PointerEvent, SeatData},
|
||||
state::ClientState,
|
||||
xdg_shell::PopupData,
|
||||
};
|
||||
use crate::{
|
||||
nodes::{
|
||||
drawable::model::ModelPart,
|
||||
items::panel::{Backend, PanelItem, RecommendedState, SurfaceID},
|
||||
Message,
|
||||
items::panel::{
|
||||
Backend, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo, ToplevelState,
|
||||
},
|
||||
},
|
||||
wayland::surface::CoreSurface,
|
||||
};
|
||||
@@ -18,8 +18,7 @@ use parking_lot::Mutex;
|
||||
use smithay::{
|
||||
reexports::{
|
||||
calloop::{EventLoop, LoopSignal},
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel,
|
||||
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource, WEnum},
|
||||
wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource},
|
||||
x11rb::protocol::xproto::Window,
|
||||
},
|
||||
utils::{Logical, Rectangle},
|
||||
@@ -29,7 +28,6 @@ use smithay::{
|
||||
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
|
||||
},
|
||||
};
|
||||
use stardust_xr::schemas::flex::serialize;
|
||||
use std::{ffi::OsStr, iter::empty, sync::Arc, time::Duration};
|
||||
use tokio::sync::oneshot;
|
||||
use tracing::debug;
|
||||
@@ -165,7 +163,13 @@ impl XwmHandler for XWaylandHandler {
|
||||
},
|
||||
move |_| {
|
||||
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) {
|
||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||
debug!(?window, button, "X window requests move");
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Move);
|
||||
panel_item.toplevel_move_request();
|
||||
}
|
||||
fn resize_request(
|
||||
&mut self,
|
||||
@@ -219,40 +223,39 @@ impl XwmHandler for XWaylandHandler {
|
||||
) {
|
||||
let Some(panel_item) = self.panel_item(&window) else {return};
|
||||
debug!(?window, button, ?resize_edge, "X window requests resize");
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Resize(
|
||||
WEnum::Value(match resize_edge {
|
||||
ResizeEdge::Top => xdg_toplevel::ResizeEdge::Top,
|
||||
ResizeEdge::Bottom => xdg_toplevel::ResizeEdge::Bottom,
|
||||
ResizeEdge::Left => xdg_toplevel::ResizeEdge::Left,
|
||||
ResizeEdge::TopLeft => xdg_toplevel::ResizeEdge::TopLeft,
|
||||
ResizeEdge::BottomLeft => xdg_toplevel::ResizeEdge::BottomLeft,
|
||||
ResizeEdge::Right => xdg_toplevel::ResizeEdge::Right,
|
||||
ResizeEdge::TopRight => xdg_toplevel::ResizeEdge::TopRight,
|
||||
ResizeEdge::BottomRight => xdg_toplevel::ResizeEdge::BottomRight,
|
||||
})
|
||||
.into(),
|
||||
));
|
||||
let (up, down, left, right) = match resize_edge {
|
||||
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)
|
||||
}
|
||||
|
||||
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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 {
|
||||
fn serialize_start_data(&self, id: &str) -> Result<Message> {
|
||||
let size = (
|
||||
self.toplevel.geometry().size.w as u32,
|
||||
self.toplevel.geometry().size.h as u32,
|
||||
);
|
||||
let toplevel_state = (
|
||||
None::<String>,
|
||||
self.toplevel.title(),
|
||||
None::<String>,
|
||||
(
|
||||
self.toplevel.geometry().size.w 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.max_size().map(|s| (s.w as u32, s.w as u32)),
|
||||
((0_i32, 0_i32), size),
|
||||
vec![0_u32; 0],
|
||||
);
|
||||
let info = (
|
||||
None::<(Vector2<u32>, Vector2<i32>)>,
|
||||
toplevel_state,
|
||||
Vec::<PopupData>::new(),
|
||||
None::<SurfaceID>,
|
||||
None::<SurfaceID>,
|
||||
);
|
||||
Ok(serialize((id, info))?.into())
|
||||
}
|
||||
fn serialize_toplevel(&self) -> Result<Message> {
|
||||
let toplevel_state = (
|
||||
None::<String>,
|
||||
self.toplevel.title(),
|
||||
None::<String>,
|
||||
(
|
||||
self.toplevel.geometry().size.w,
|
||||
self.toplevel.geometry().size.h,
|
||||
),
|
||||
self.toplevel.min_size().map(|s| (s.w, s.h)),
|
||||
self.toplevel.max_size().map(|s| (s.w, s.w)),
|
||||
);
|
||||
let data = serialize(&toplevel_state)?;
|
||||
Ok(data.into())
|
||||
}
|
||||
// fn start_data(&self, id: &str) -> Result<Message> {
|
||||
// let size = (
|
||||
// self.toplevel.geometry().size.w as u32,
|
||||
// self.toplevel.geometry().size.h as u32,
|
||||
// );
|
||||
// let toplevel_state = (
|
||||
// None::<String>,
|
||||
// self.toplevel.title(),
|
||||
// None::<String>,
|
||||
// (
|
||||
// self.toplevel.geometry().size.w 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.max_size().map(|s| (s.w as u32, s.w as u32)),
|
||||
// ((0_i32, 0_i32), size),
|
||||
// vec![0_u32; 0],
|
||||
// );
|
||||
// let info = (
|
||||
// None::<(Vector2<u32>, Vector2<i32>)>,
|
||||
// toplevel_state,
|
||||
// Vec::<PopupData>::new(),
|
||||
// None::<SurfaceID>,
|
||||
// None::<SurfaceID>,
|
||||
// );
|
||||
// Ok(serialize((id, info))?.into())
|
||||
// }
|
||||
// fn serialize_toplevel(&self) -> Result<Message> {
|
||||
// let toplevel_state = (
|
||||
// None::<String>,
|
||||
// self.toplevel.title(),
|
||||
// None::<String>,
|
||||
// (
|
||||
// self.toplevel.geometry().size.w,
|
||||
// self.toplevel.geometry().size.h,
|
||||
// ),
|
||||
// self.toplevel.min_size().map(|s| (s.w, s.h)),
|
||||
// self.toplevel.max_size().map(|s| (s.w, s.w)),
|
||||
// );
|
||||
// let data = serialize(&toplevel_state)?;
|
||||
// Ok(data.into())
|
||||
// }
|
||||
|
||||
fn set_toplevel_capabilities(&self, _capabilities: Vec<u8>) {}
|
||||
// fn set_toplevel_capabilities(&self, _capabilities: Vec<u8>) {}
|
||||
|
||||
fn configure_toplevel(
|
||||
&self,
|
||||
size: Option<Vector2<u32>>,
|
||||
states: Vec<u32>,
|
||||
_bounds: Option<Vector2<u32>>,
|
||||
) {
|
||||
let _ = self.toplevel.configure(
|
||||
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));
|
||||
// fn set_toplevel_size(
|
||||
// &self,
|
||||
// size: Option<Vector2<u32>>,
|
||||
// states: Vec<u32>,
|
||||
// _bounds: Option<Vector2<u32>>,
|
||||
// ) {
|
||||
// let _ = self.toplevel.configure(
|
||||
// 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));
|
||||
// }
|
||||
|
||||
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>) {
|
||||
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) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {return};
|
||||
self.seat.keyboard_event(
|
||||
|
||||
Reference in New Issue
Block a user