feat(wayland): configure and commit for toplevel]
This commit is contained in:
@@ -1,69 +1,362 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::nodes::Node;
|
||||
|
||||
use super::{panel_item::PanelItem, state::WaylandState};
|
||||
use super::{
|
||||
panel_item::{PanelItem, ToplevelState},
|
||||
state::WaylandState,
|
||||
};
|
||||
use mint::Vector2;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Serialize;
|
||||
use smithay::{
|
||||
delegate_xdg_shell,
|
||||
reexports::{
|
||||
wayland_protocols::xdg::{
|
||||
decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode,
|
||||
shell::server::xdg_toplevel::State,
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_popup::{self, XdgPopup},
|
||||
xdg_positioner::{self, Anchor, ConstraintAdjustment, Gravity, XdgPositioner},
|
||||
xdg_surface::{self, XdgSurface},
|
||||
xdg_toplevel::{self, XdgToplevel},
|
||||
xdg_wm_base::{self, XdgWmBase},
|
||||
},
|
||||
wayland_server::protocol::{wl_seat::WlSeat, wl_surface::WlSurface},
|
||||
},
|
||||
utils::Serial,
|
||||
wayland::{
|
||||
compositor,
|
||||
shell::xdg::{
|
||||
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler,
|
||||
XdgShellState,
|
||||
wayland_server::{
|
||||
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle,
|
||||
GlobalDispatch, New, Resource, WEnum, Weak,
|
||||
},
|
||||
},
|
||||
wayland::compositor,
|
||||
};
|
||||
|
||||
impl XdgShellHandler for WaylandState {
|
||||
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
|
||||
&mut self.xdg_shell_state
|
||||
}
|
||||
// impl XdgShellHandler for WaylandState {
|
||||
// fn xdg_shell_state(&mut self) -> &mut WaylandState {
|
||||
// &mut self.xdg_shell_state
|
||||
// }
|
||||
|
||||
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||
self.output.enter(surface.wl_surface());
|
||||
surface.with_pending_state(|state| {
|
||||
state.states.set(State::Maximized);
|
||||
state.states.set(State::Activated);
|
||||
state.decoration_mode = Some(Mode::ServerSide);
|
||||
});
|
||||
surface.send_configure();
|
||||
}
|
||||
fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
|
||||
// let size = match configure {
|
||||
// Configure::Toplevel(config) => config.state.size,
|
||||
// Configure::Popup(_) => return,
|
||||
// };
|
||||
// let core_surface = match configure {
|
||||
// Configure::Toplevel(config) => {
|
||||
// .and_then(|panel| panel.core_surface())
|
||||
// }
|
||||
// Configure::Popup(_) => return,
|
||||
// };
|
||||
let Some(panel_item_node) = compositor::with_states(&surface, |data| {
|
||||
data.data_map.get::<Arc<Node>>().cloned()
|
||||
}) else { return };
|
||||
let Some(panel_item) = PanelItem::from_node(&panel_item_node) else { return };
|
||||
panel_item.ack_resize(configure);
|
||||
// fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||
// self.output.enter(surface.wl_surface());
|
||||
// surface.with_pending_state(|state| {
|
||||
// state.states.set(State::Maximized);
|
||||
// state.states.set(State::Activated);
|
||||
// state.decoration_mode = Some(Mode::ServerSide);
|
||||
// });
|
||||
// surface.send_configure();
|
||||
|
||||
// let has_data = core_surface
|
||||
// .with_data(|data| {
|
||||
// data.size.x = size.w as u32;
|
||||
// data.size.y = size.h as u32;
|
||||
// })
|
||||
// .is_some();
|
||||
// if has_data {
|
||||
// }
|
||||
}
|
||||
// let client = surface.wl_surface().client().unwrap();
|
||||
// let (node, item) = PanelItem::create(
|
||||
// &surface,
|
||||
// client.get_credentials(&self.display_handle).ok(),
|
||||
// self.seats.get(&client.id()).unwrap().clone(),
|
||||
// );
|
||||
// compositor::with_states(surface.wl_surface(), |surface_data| {
|
||||
// surface_data.data_map.insert_if_missing_threadsafe(|| node);
|
||||
// surface_data.data_map.insert_if_missing_threadsafe(|| item);
|
||||
// });
|
||||
// }
|
||||
// fn new_popup(&mut self, surface: PopupSurface, _positioner: PositionerState) {
|
||||
// self.output.enter(surface.wl_surface());
|
||||
// let _ = surface.send_configure();
|
||||
// // let panel_item = compositor::with_states(&surface.get_parent_surface().unwrap(), |data| {
|
||||
// // data.data_map.get::<Arc<PanelItem>>().cloned()
|
||||
// // });
|
||||
// }
|
||||
// fn ack_configure(&mut self, surface: WlSurface, configure: Configure) {
|
||||
// compositor::with_states(&surface, |data| {
|
||||
// if let Some(panel_item) = data.data_map.get::<Arc<PanelItem>>() {
|
||||
// panel_item.ack_resize(configure);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
fn new_popup(&mut self, _surface: PopupSurface, _positioner: PositionerState) {}
|
||||
fn grab(&mut self, _surface: PopupSurface, _seat: WlSeat, _serial: Serial) {}
|
||||
// fn grab(&mut self, _surface: PopupSurface, _seat: WlSeat, _serial: Serial) {}
|
||||
// }
|
||||
// delegate_xdg_shell!(WaylandState);
|
||||
|
||||
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn bind(
|
||||
_state: &mut WaylandState,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &Client,
|
||||
resource: New<XdgWmBase>,
|
||||
_global_data: &(),
|
||||
data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
data_init.init(resource, ());
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct WaylandSurface {
|
||||
wl_surface: Weak<WlSurface>,
|
||||
size: Arc<Mutex<Vector2<u32>>>,
|
||||
}
|
||||
|
||||
impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
_resource: &XdgWmBase,
|
||||
request: xdg_wm_base::Request,
|
||||
_data: &(),
|
||||
_dhandle: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_wm_base::Request::CreatePositioner { id } => {
|
||||
data_init.init(id, Arc::new(Mutex::new(PositionerData::default())));
|
||||
}
|
||||
xdg_wm_base::Request::GetXdgSurface { id, surface } => {
|
||||
data_init.init(
|
||||
id,
|
||||
WaylandSurface {
|
||||
wl_surface: surface.downgrade(),
|
||||
size: Arc::new(Mutex::new(Vector2::from([0; 2]))),
|
||||
},
|
||||
);
|
||||
}
|
||||
xdg_wm_base::Request::Pong { serial: _ } => (),
|
||||
xdg_wm_base::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct PositionerData {
|
||||
size: Vector2<u32>,
|
||||
anchor_rect_pos: Vector2<i32>,
|
||||
anchor_rect_size: Vector2<u32>,
|
||||
anchor: u32,
|
||||
gravity: u32,
|
||||
constraint_adjustment: u32,
|
||||
offset: Vector2<i32>,
|
||||
reactive: bool,
|
||||
}
|
||||
impl Default for PositionerData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
size: Vector2::from([0; 2]),
|
||||
anchor_rect_pos: Vector2::from([0; 2]),
|
||||
anchor_rect_size: Vector2::from([0; 2]),
|
||||
anchor: Anchor::None as u32,
|
||||
gravity: Gravity::None as u32,
|
||||
constraint_adjustment: ConstraintAdjustment::None.bits(),
|
||||
offset: Vector2::from([0; 2]),
|
||||
reactive: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgPositioner, Arc<Mutex<PositionerData>>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
resource: &XdgPositioner,
|
||||
request: xdg_positioner::Request,
|
||||
data: &Arc<Mutex<PositionerData>>,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_positioner::Request::SetSize { width, height } => {
|
||||
data.lock().size = Vector2::from([width as u32, height as u32]);
|
||||
}
|
||||
xdg_positioner::Request::SetAnchorRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
} => {
|
||||
if width < 1 || height < 1 {
|
||||
resource.post_error(
|
||||
xdg_positioner::Error::InvalidInput,
|
||||
"Invalid size for positioner's anchor rectangle.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut data = data.lock();
|
||||
data.anchor_rect_pos = [x, y].into();
|
||||
data.anchor_rect_size = [width as u32, height as u32].into();
|
||||
}
|
||||
xdg_positioner::Request::SetAnchor { anchor } => {
|
||||
if let WEnum::Value(anchor) = anchor {
|
||||
data.lock().anchor = anchor as u32;
|
||||
}
|
||||
}
|
||||
xdg_positioner::Request::SetGravity { gravity } => {
|
||||
if let WEnum::Value(gravity) = gravity {
|
||||
data.lock().gravity = gravity as u32;
|
||||
}
|
||||
}
|
||||
xdg_positioner::Request::SetConstraintAdjustment {
|
||||
constraint_adjustment,
|
||||
} => {
|
||||
data.lock().constraint_adjustment = constraint_adjustment;
|
||||
}
|
||||
xdg_positioner::Request::SetOffset { x, y } => {
|
||||
data.lock().offset = [x, y].into();
|
||||
}
|
||||
xdg_positioner::Request::SetReactive => {
|
||||
data.lock().reactive = true;
|
||||
}
|
||||
xdg_positioner::Request::SetParentSize {
|
||||
parent_width: _,
|
||||
parent_height: _,
|
||||
} => (),
|
||||
xdg_positioner::Request::SetParentConfigure { serial: _ } => (),
|
||||
xdg_positioner::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct XdgSurfaceData {
|
||||
pub wl_surface: Weak<WlSurface>,
|
||||
pub xdg_surface: Weak<XdgSurface>,
|
||||
pub size: Arc<Mutex<Vector2<u32>>>,
|
||||
}
|
||||
impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
state: &mut WaylandState,
|
||||
client: &Client,
|
||||
xdg_surface: &XdgSurface,
|
||||
request: xdg_surface::Request,
|
||||
data: &WaylandSurface,
|
||||
_dhandle: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_surface::Request::GetToplevel { id } => {
|
||||
let toplevel_state = Arc::new(Mutex::new(ToplevelState {
|
||||
queued_state: Some(Box::new(ToplevelState::default())),
|
||||
..Default::default()
|
||||
}));
|
||||
let toplevel = data_init.init(
|
||||
id,
|
||||
XdgToplevelData {
|
||||
state: toplevel_state,
|
||||
xdg_surface_data: XdgSurfaceData {
|
||||
wl_surface: data.wl_surface.clone(),
|
||||
xdg_surface: xdg_surface.downgrade(),
|
||||
size: data.size.clone(),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
toplevel.configure(0, 0, vec![]);
|
||||
xdg_surface.configure(0);
|
||||
|
||||
let (node, item) = PanelItem::create(
|
||||
toplevel,
|
||||
client.get_credentials(&state.display_handle).ok(),
|
||||
state.seats.get(&client.id()).unwrap().clone(),
|
||||
);
|
||||
compositor::with_states(&data.wl_surface.upgrade().unwrap(), |surface_data| {
|
||||
surface_data.data_map.insert_if_missing_threadsafe(|| node);
|
||||
surface_data.data_map.insert_if_missing_threadsafe(|| item);
|
||||
});
|
||||
}
|
||||
xdg_surface::Request::GetPopup {
|
||||
id,
|
||||
parent: _,
|
||||
positioner: _,
|
||||
} => {
|
||||
data_init.init(id, ());
|
||||
}
|
||||
xdg_surface::Request::SetWindowGeometry {
|
||||
x: _,
|
||||
y: _,
|
||||
width,
|
||||
height,
|
||||
} => {
|
||||
*data.size.lock() = Vector2::from([width as u32, height as u32]);
|
||||
}
|
||||
xdg_surface::Request::AckConfigure { serial: _ } => (),
|
||||
xdg_surface::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XdgToplevelData {
|
||||
pub state: Arc<Mutex<ToplevelState>>,
|
||||
pub xdg_surface_data: XdgSurfaceData,
|
||||
}
|
||||
impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
_resource: &XdgToplevel,
|
||||
request: xdg_toplevel::Request,
|
||||
data: &XdgToplevelData,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_toplevel::Request::SetParent { parent } => {
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.parent = parent.map(|toplevel| toplevel.downgrade());
|
||||
}
|
||||
xdg_toplevel::Request::SetTitle { title } => {
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.title = title;
|
||||
}
|
||||
xdg_toplevel::Request::SetAppId { app_id } => {
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.app_id = app_id;
|
||||
}
|
||||
xdg_toplevel::Request::ShowWindowMenu {
|
||||
seat: _,
|
||||
serial: _,
|
||||
x: _,
|
||||
y: _,
|
||||
} => (),
|
||||
xdg_toplevel::Request::Move { seat: _, serial: _ } => (),
|
||||
xdg_toplevel::Request::Resize {
|
||||
seat: _,
|
||||
serial: _,
|
||||
edges: _,
|
||||
} => (),
|
||||
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.max_size = Vector2::from([width as u32, height as u32]);
|
||||
}
|
||||
xdg_toplevel::Request::SetMinSize { width, height } => {
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.min_size = Vector2::from([width as u32, height as u32]);
|
||||
}
|
||||
xdg_toplevel::Request::SetMaximized => (),
|
||||
xdg_toplevel::Request::UnsetMaximized => (),
|
||||
xdg_toplevel::Request::SetFullscreen { output: _ } => (),
|
||||
xdg_toplevel::Request::UnsetFullscreen => (),
|
||||
xdg_toplevel::Request::SetMinimized => (),
|
||||
xdg_toplevel::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgPopup, (), WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
_resource: &XdgPopup,
|
||||
request: xdg_popup::Request,
|
||||
_data: &(),
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_popup::Request::Grab { seat: _, serial: _ } => (),
|
||||
xdg_popup::Request::Reposition {
|
||||
positioner: _,
|
||||
token: _,
|
||||
} => (),
|
||||
xdg_popup::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
delegate_xdg_shell!(WaylandState);
|
||||
|
||||
Reference in New Issue
Block a user