1
0
Fork 0
forked from wry/wry

autocommit 2022-02-21 23:21:13 CET

This commit is contained in:
Julian Orth 2022-02-21 23:21:13 +01:00
parent 1cbc7a6445
commit 145d1c15b7
31 changed files with 1455 additions and 252 deletions

View file

@ -16,7 +16,10 @@ pub mod wl_subcompositor;
pub mod wl_surface;
pub mod xdg_positioner;
pub mod xdg_wm_base;
pub mod zwlr_layer_shell_v1;
pub mod zwp_linux_buffer_params_v1;
pub mod zwp_linux_dmabuf_v1;
pub mod zxdg_decoration_manager_v1;
pub mod zxdg_toplevel_decoration_v1;
pub mod zxdg_output_manager_v1;
pub mod zxdg_output_v1;

View file

@ -6,12 +6,17 @@ use crate::object::Object;
use crate::utils::buffd::MsgParser;
use crate::utils::buffd::MsgParserError;
use crate::wire::wl_output::*;
use crate::wire::WlOutputId;
use crate::wire::{WlOutputId, ZxdgOutputV1Id};
use ahash::AHashMap;
use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry;
use std::rc::Rc;
use thiserror::Error;
use crate::CloneCell;
use crate::ifs::zxdg_output_v1::ZxdgOutputV1;
use crate::rect::Rect;
use crate::tree::OutputNode;
use crate::utils::copyhashmap::CopyHashMap;
const SP_UNKNOWN: i32 = 0;
#[allow(dead_code)]
@ -48,10 +53,8 @@ const MODE_PREFERRED: u32 = 2;
pub struct WlOutputGlobal {
name: GlobalName,
output: Rc<dyn Output>,
pub x: Cell<i32>,
pub y: Cell<i32>,
width: Cell<i32>,
height: Cell<i32>,
pos: Cell<Rect>,
pub node: CloneCell<Option<Rc<OutputNode>>>,
pub bindings: RefCell<AHashMap<ClientId, AHashMap<WlOutputId, Rc<WlOutput>>>>,
}
@ -60,23 +63,27 @@ impl WlOutputGlobal {
Self {
name,
output: output.clone(),
x: Cell::new(0),
y: Cell::new(0),
width: Cell::new(output.width()),
height: Cell::new(output.height()),
pos: Cell::new(Rect::new_sized(0, 0, output.width(), output.height()).unwrap()),
node: Default::default(),
bindings: Default::default(),
}
}
pub fn position(&self) -> Rect {
self.pos.get()
}
pub fn update_properties(&self) {
let width = self.output.width();
let height = self.output.height();
let mut changed = false;
changed |= self.width.replace(width) != width;
changed |= self.height.replace(height) != height;
let pos = self.pos.get();
let old_width = pos.width();
let old_height = pos.height();
let changed = old_width != width || old_height != height;
if changed {
self.pos.set(Rect::new_sized(pos.x1(), pos.y1(), width, height).unwrap());
let bindings = self.bindings.borrow_mut();
for binding in bindings.values() {
for binding in binding.values() {
@ -85,6 +92,10 @@ impl WlOutputGlobal {
binding.send_scale();
binding.send_done();
binding.client.flush();
let xdg = binding.xdg_outputs.lock();
for xdg in xdg.values() {
xdg.send_updates();
}
}
}
}
@ -99,6 +110,7 @@ impl WlOutputGlobal {
let obj = Rc::new(WlOutput {
global: self.clone(),
id,
xdg_outputs: Default::default(),
client: client.clone(),
version,
tracker: Default::default(),
@ -141,10 +153,11 @@ impl Global for WlOutputGlobal {
dedicated_add_global!(WlOutputGlobal, outputs);
pub struct WlOutput {
global: Rc<WlOutputGlobal>,
pub global: Rc<WlOutputGlobal>,
pub id: WlOutputId,
pub xdg_outputs: CopyHashMap<ZxdgOutputV1Id, Rc<ZxdgOutputV1>>,
client: Rc<Client>,
version: u32,
pub version: u32,
tracker: Tracker<Self>,
}
@ -153,12 +166,13 @@ pub const SEND_SCALE_SINCE: u32 = 2;
impl WlOutput {
fn send_geometry(&self) {
let pos = self.global.pos.get();
let event = Geometry {
self_id: self.id,
x: 0,
y: 0,
physical_width: self.global.width.get() as _,
physical_height: self.global.height.get() as _,
x: pos.x1(),
y: pos.y1(),
physical_width: pos.width(),
physical_height: pos.height(),
subpixel: SP_UNKNOWN,
make: "i4",
model: "i4",
@ -168,11 +182,12 @@ impl WlOutput {
}
fn send_mode(&self) {
let pos = self.global.pos.get();
let event = Mode {
self_id: self.id,
flags: MODE_CURRENT,
width: self.global.width.get() as _,
height: self.global.height.get() as _,
width: pos.width(),
height: pos.height(),
refresh: 60_000_000,
};
self.client.event(event);
@ -186,7 +201,7 @@ impl WlOutput {
self.client.event(event);
}
fn send_done(&self) {
pub fn send_done(&self) {
let event = Done { self_id: self.id };
self.client.event(event);
}
@ -202,6 +217,7 @@ impl WlOutput {
fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> {
let _req: Release = self.client.parse(self, parser)?;
self.xdg_outputs.clear();
self.remove_binding();
self.client.remove_obj(self)?;
Ok(())
@ -224,11 +240,12 @@ impl Object for WlOutput {
}
fn break_loops(&self) {
self.xdg_outputs.clear();
self.remove_binding();
}
}
simple_add_obj!(WlOutput);
dedicated_add_obj!(WlOutput, WlOutputId, outputs);
#[derive(Debug, Error)]
pub enum WlOutputError {

View file

@ -3,6 +3,7 @@ mod pointer_owner;
pub mod wl_keyboard;
pub mod wl_pointer;
pub mod wl_touch;
mod kb_owner;
use crate::async_engine::SpawnedFuture;
use crate::client::{Client, ClientError, ClientId};
@ -43,10 +44,12 @@ use i4config::Direction;
use std::cell::{Cell, RefCell};
use std::collections::hash_map::Entry;
use std::mem;
use std::ops::DerefMut;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use thiserror::Error;
use uapi::{c, Errno, OwnedFd};
use crate::ifs::wl_output::{WlOutputGlobal};
use crate::ifs::wl_seat::kb_owner::KbOwnerHolder;
const POINTER: u32 = 1;
const KEYBOARD: u32 = 2;
@ -112,6 +115,7 @@ pub struct WlSeatGlobal {
selection: CloneCell<Option<Rc<WlDataSource>>>,
primary_selection: CloneCell<Option<Rc<ZwpPrimarySelectionSourceV1>>>,
pointer_owner: PointerOwnerHolder,
kb_owner: KbOwnerHolder,
dropped_dnd: RefCell<Option<DroppedDnd>>,
shortcuts: CopyHashMap<(u32, u32), Modifiers>,
queue_link: Cell<Option<LinkedNode<Rc<Self>>>>,
@ -146,6 +150,7 @@ impl WlSeatGlobal {
selection: Default::default(),
primary_selection: Default::default(),
pointer_owner: Default::default(),
kb_owner: Default::default(),
dropped_dnd: RefCell::new(None),
shortcuts: Default::default(),
queue_link: Cell::new(None),
@ -162,6 +167,17 @@ impl WlSeatGlobal {
slf
}
pub fn get_output(&self) -> Option<Rc<WlOutputGlobal>> {
let ps = self.pointer_stack.borrow_mut();
for node in ps.deref() {
if node.is_output() {
let on = node.clone().into_output().unwrap();
return Some(on.global.clone());
}
}
None
}
pub fn mark_last_active(self: &Rc<Self>) {
self.queue_link
.set(Some(self.state.seat_queue.add_last(self.clone())));

View file

@ -75,6 +75,22 @@ impl NodeSeatState {
self.kb_foci.len() > 0
}
pub fn release_kb_grab(&self) {
for (_, seat) in &self.kb_foci {
seat.ungrab_kb();
}
}
pub fn release_kb_focus(&self) {
while let Some((_, seat)) = self.kb_foci.pop() {
seat.ungrab_kb();
seat.keyboard_node.set(seat.state.root.clone());
if let Some(tl) = seat.toplevel_focus_history.last() {
seat.focus_xdg_surface(&tl.xdg);
}
}
}
pub fn destroy_node(&self, node: &dyn Node) {
while let Some((_, seat)) = self.grabs.pop() {
seat.pointer_owner.revert_to_default(&seat);
@ -94,12 +110,7 @@ impl NodeSeatState {
}
seat.state.tree_changed();
}
while let Some((_, seat)) = self.kb_foci.pop() {
seat.keyboard_node.set(seat.state.root.clone());
if let Some(tl) = seat.toplevel_focus_history.last() {
seat.focus_xdg_surface(&tl.xdg);
}
}
self.release_kb_focus();
}
}
@ -124,8 +135,9 @@ impl WlSeatGlobal {
Some(o) => o,
_ => return,
};
x += Fixed::from_int(output.x.get());
y += Fixed::from_int(output.y.get());
let pos = output.position();
x += Fixed::from_int(pos.x1());
y += Fixed::from_int(pos.y1());
self.set_new_position(x, y);
}
@ -216,21 +228,16 @@ impl WlSeatGlobal {
self.focus_node(xdg.focus_surface(self));
}
pub fn focus_node(self: &Rc<Self>, node: Rc<dyn Node>) {
let old = self.keyboard_node.get();
if old.id() == node.id() {
return;
}
old.unfocus(self);
if old.seat_state().unfocus(self) {
old.active_changed(false);
}
fn ungrab_kb(self: &Rc<Self>) {
self.kb_owner.ungrab(self);
}
if node.seat_state().focus(self) {
node.active_changed(true);
}
node.clone().focus(self);
self.keyboard_node.set(node.clone());
pub fn grab(self: &Rc<Self>, node: Rc<dyn Node>) {
self.kb_owner.grab(self, node);
}
pub fn focus_node(self: &Rc<Self>, node: Rc<dyn Node>) {
self.kb_owner.set_kb_node(self, node);
}
fn offer_selection<T: ipc::Vtable>(
@ -380,7 +387,7 @@ impl WlSeatGlobal {
let serial = self.serial.fetch_add(1);
self.surface_pointer_event(0, surface, |p| p.send_button(serial, 0, button, state));
self.surface_pointer_frame(surface);
if pressed && surface.belongs_to_toplevel() {
if pressed && surface.accepts_kb_focus() {
self.focus_node(surface.clone());
}
}

View file

@ -0,0 +1,85 @@
use std::rc::Rc;
use crate::CloneCell;
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::tree::Node;
pub struct KbOwnerHolder {
default: Rc<DefaultKbOwner>,
owner: CloneCell<Rc<dyn KbOwner>>,
}
impl Default for KbOwnerHolder {
fn default() -> Self {
Self {
default: Rc::new(DefaultKbOwner),
owner: CloneCell::new(Rc::new(DefaultKbOwner)),
}
}
}
impl KbOwnerHolder {
pub fn grab(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) -> bool {
self.owner.get().grab(seat, node)
}
pub fn ungrab(&self, seat: &Rc<WlSeatGlobal>) {
self.owner.get().ungrab(seat)
}
pub fn set_kb_node(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) {
self.owner.get().set_kb_node(seat, node);
}
}
struct DefaultKbOwner;
struct GrabKbOwner;
trait KbOwner {
fn grab(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) -> bool;
fn ungrab(&self, seat: &Rc<WlSeatGlobal>);
fn set_kb_node(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>);
}
impl KbOwner for DefaultKbOwner {
fn grab(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) -> bool {
self.set_kb_node(seat, node);
seat.kb_owner.owner.set(Rc::new(GrabKbOwner));
true
}
fn ungrab(&self, _seat: &Rc<WlSeatGlobal>) {
// nothing
}
fn set_kb_node(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) {
let old = seat.keyboard_node.get();
if old.id() == node.id() {
return;
}
old.unfocus(seat);
if old.seat_state().unfocus(seat) {
old.active_changed(false);
}
if node.seat_state().focus(seat) {
node.active_changed(true);
}
node.clone().focus(seat);
seat.keyboard_node.set(node.clone());
}
}
impl KbOwner for GrabKbOwner {
fn grab(&self, _seat: &Rc<WlSeatGlobal>, _node: Rc<dyn Node>) -> bool {
false
}
fn ungrab(&self, seat: &Rc<WlSeatGlobal>) {
seat.kb_owner.owner.set(seat.kb_owner.default.clone());
}
fn set_kb_node(&self, _seat: &Rc<WlSeatGlobal>, _node: Rc<dyn Node>) {
// nothing
}
}

View file

@ -147,9 +147,11 @@ impl PointerOwner for DefaultPointerOwner {
}
if (stack.len(), found_tree.len()) == (divergence, divergence) {
if let Some(node) = found_tree.last() {
node.node
.clone()
.pointer_motion(seat, x.apply_fract(node.x), y.apply_fract(node.y));
node.node.clone().pointer_motion(
seat,
x.apply_fract(node.x),
y.apply_fract(node.y),
);
}
} else {
if let Some(last) = stack.last() {
@ -161,16 +163,20 @@ impl PointerOwner for DefaultPointerOwner {
}
if found_tree.len() == divergence {
if let Some(node) = found_tree.last() {
node.node
.clone()
.pointer_motion(seat, x.apply_fract(node.x), y.apply_fract(node.y));
node.node.clone().pointer_motion(
seat,
x.apply_fract(node.x),
y.apply_fract(node.y),
);
}
} else {
for new in found_tree.drain(divergence..) {
new.node.seat_state().enter(seat);
new.node
.clone()
.pointer_enter(seat, x.apply_fract(new.x), y.apply_fract(new.y));
new.node.clone().pointer_enter(
seat,
x.apply_fract(new.x),
y.apply_fract(new.y),
);
stack.push(new.node);
}
}

View file

@ -1,6 +1,7 @@
pub mod cursor;
pub mod wl_subsurface;
pub mod xdg_surface;
pub mod zwlr_layer_surface_v1;
use crate::backend::{KeyState, ScrollAxis};
use crate::client::{Client, ClientError, RequestParser};
@ -34,6 +35,7 @@ use std::mem;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use thiserror::Error;
use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error;
#[allow(dead_code)]
const INVALID_SCALE: u32 = 0;
@ -49,6 +51,7 @@ pub enum SurfaceRole {
XdgSurface,
Cursor,
DndIcon,
ZwlrLayerSurface,
}
impl SurfaceRole {
@ -59,6 +62,7 @@ impl SurfaceRole {
SurfaceRole::XdgSurface => "xdg_surface",
SurfaceRole::Cursor => "cursor",
SurfaceRole::DndIcon => "dnd_icon",
SurfaceRole::ZwlrLayerSurface => "zwlr_layer_surface",
}
}
}
@ -111,7 +115,7 @@ trait SurfaceExt {
Ok(CommitAction::ContinueCommit)
}
fn post_commit(&self) {
fn post_commit(self: Rc<Self>) {
// nothing
}
@ -134,6 +138,10 @@ trait SurfaceExt {
fn into_subsurface(self: Rc<Self>) -> Option<Rc<WlSubsurface>> {
None
}
fn accepts_kb_focus(&self) -> bool {
true
}
}
pub struct NoneSurfaceExt;
@ -222,11 +230,11 @@ impl WlSurface {
Ok(cursor)
}
pub fn belongs_to_toplevel(&self) -> bool {
pub fn accepts_kb_focus(&self) -> bool {
if let Some(xdg) = self.xdg.get() {
return xdg.role() == XdgSurfaceRole::XdgToplevel;
}
false
self.ext.get().accepts_kb_focus()
}
fn send_enter(&self, output: WlOutputId) {
@ -747,6 +755,8 @@ pub enum WlSurfaceError {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error(transparent)]
ZwlrLayerSurfaceV1Error(Box<ZwlrLayerSurfaceV1Error>),
#[error(transparent)]
XdgSurfaceError(Box<XdgSurfaceError>),
#[error("Could not process `destroy` request")]
DestroyError(#[source] Box<DestroyError>),
@ -784,13 +794,10 @@ efrom!(WlSurfaceError, FrameError);
efrom!(WlSurfaceError, SetOpaqueRegionError);
efrom!(WlSurfaceError, SetInputRegionError);
efrom!(WlSurfaceError, CommitError);
efrom!(
WlSurfaceError,
SetBufferTransformError,
SetBufferTransformError
);
efrom!(WlSurfaceError, SetBufferTransformError);
efrom!(WlSurfaceError, SetBufferScaleError);
efrom!(WlSurfaceError, DamageBufferError);
efrom!(WlSurfaceError, ZwlrLayerSurfaceV1Error);
#[derive(Debug, Error)]
pub enum DestroyError {

View file

@ -263,9 +263,8 @@ impl SurfaceExt for WlSubsurface {
Ok(CommitAction::ContinueCommit)
}
fn post_commit(&self) {
fn post_commit(self: Rc<Self>) {
if let Some(v) = self.pending.node.take() {
log::info!("post commit");
v.pending.set(false);
self.node.borrow_mut().replace(v);
}

View file

@ -443,7 +443,7 @@ impl SurfaceExt for XdgSurface {
Ok(CommitAction::ContinueCommit)
}
fn post_commit(&self) {
fn post_commit(self: Rc<Self>) {
if let Some(ext) = self.ext.get() {
ext.post_commit();
}

View file

@ -27,6 +27,7 @@ use std::fmt::{Debug, Formatter};
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use backtrace::Backtrace;
use thiserror::Error;
#[derive(Copy, Clone, Debug, FromPrimitive)]

View file

@ -0,0 +1,533 @@
use std::cell::Cell;
use std::ops::Deref;
use crate::client::{Client, ClientError, ClientId};
use crate::ifs::wl_output::{WlOutput, WlOutputGlobal};
use crate::ifs::wl_surface::{CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError};
use crate::ifs::zwlr_layer_shell_v1::{OVERLAY, ZwlrLayerShellV1};
use crate::leaks::Tracker;
use crate::object::Object;
use crate::utils::buffd::MsgParser;
use crate::utils::buffd::MsgParserError;
use crate::wire::zwlr_layer_surface_v1::*;
use crate::wire::{WlSurfaceId, ZwlrLayerSurfaceV1Id};
use std::rc::Rc;
use thiserror::Error;
use i4config::Direction;
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
use crate::{CloneCell, NumCell};
use crate::backend::{KeyState, ScrollAxis};
use crate::fixed::Fixed;
use crate::ifs::wl_seat::{Dnd, NodeSeatState, WlSeatGlobal};
use crate::rect::Rect;
use crate::render::Renderer;
use crate::tree::{ContainerNode, ContainerSplit, FindTreeResult, FloatNode, FoundNode, Node, NodeId, OutputNode, WorkspaceNode};
use crate::tree::walker::NodeVisitor;
use crate::utils::bitflags::BitflagsExt;
use crate::utils::linkedlist::LinkedNode;
const KI_NONE: u32 = 0;
#[allow(dead_code)]
const KI_EXCLUSIVE: u32 = 1;
const KI_ON_DEMAND: u32 = 2;
const TOP: u32 = 1;
const BOTTOM: u32 = 2;
const LEFT: u32 = 4;
const RIGHT: u32 = 8;
tree_id!(ZwlrLayerSurfaceV1NodeId);
pub struct ZwlrLayerSurfaceV1 {
pub id: ZwlrLayerSurfaceV1Id,
node_id: ZwlrLayerSurfaceV1NodeId,
pub shell: Rc<ZwlrLayerShellV1>,
pub client: Rc<Client>,
pub surface: Rc<WlSurface>,
pub output: Rc<OutputNode>,
pub namespace: String,
pub tracker: Tracker<Self>,
pos: Cell<Rect>,
mapped: Cell<bool>,
layer: Cell<u32>,
pending: Pending,
requested_serial: NumCell<u32>,
acked_serial: Cell<Option<u32>>,
size: Cell<(i32, i32)>,
anchor: Cell<u32>,
exclusive_zone: Cell<i32>,
margin: Cell<(i32, i32, i32, i32)>,
keyboard_interactivity: Cell<u32>,
link: Cell<Option<LinkedNode<Rc<Self>>>>,
seat_state: NodeSeatState,
}
#[derive(Default)]
struct Pending {
size: Cell<Option<(i32, i32)>>,
anchor: Cell<Option<u32>>,
exclusive_zone: Cell<Option<i32>>,
margin: Cell<Option<(i32, i32, i32, i32)>>,
keyboard_interactivity: Cell<Option<u32>>,
layer: Cell<Option<u32>>,
}
impl ZwlrLayerSurfaceV1 {
pub fn new(
id: ZwlrLayerSurfaceV1Id,
shell: &Rc<ZwlrLayerShellV1>,
surface: &Rc<WlSurface>,
output: &Rc<OutputNode>,
layer: u32,
namespace: &str,
) -> Self {
Self {
id,
node_id: shell.client.state.node_ids.next(),
shell: shell.clone(),
client: shell.client.clone(),
surface: surface.clone(),
output: output.clone(),
namespace: namespace.to_string(),
tracker: Default::default(),
pos: Cell::new(Default::default()),
mapped: Cell::new(false),
layer: Cell::new(layer),
pending: Default::default(),
requested_serial: Default::default(),
acked_serial: Cell::new(None),
size: Cell::new((0, 0)),
anchor: Cell::new(0),
exclusive_zone: Cell::new(0),
margin: Cell::new((0, 0, 0, 0)),
keyboard_interactivity: Cell::new(0),
link: Cell::new(None),
seat_state: Default::default()
}
}
pub fn install(self: &Rc<Self>) -> Result<(), ZwlrLayerSurfaceV1Error> {
self.surface.set_role(SurfaceRole::ZwlrLayerSurface)?;
if self.surface.ext.get().is_some() {
return Err(ZwlrLayerSurfaceV1Error::AlreadyAttached(self.surface.id));
}
self.surface.ext.set(self.clone());
Ok(())
}
fn send_configure(&self, serial: u32, width: u32, height: u32) {
self.client.event(Configure {
self_id: self.id,
serial,
width,
height,
});
}
#[allow(dead_code)]
fn send_closed(&self) {
self.client.event(Closed { self_id: self.id });
}
fn set_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSizeError> {
let req: SetSize = self.client.parse(self, parser)?;
if req.width > u16::MAX as u32 || req.height > u16::MAX as u32 {
return Err(SetSizeError::ExcessiveSize);
}
self.pending.size.set(Some((req.width as _, req.height as _)));
Ok(())
}
fn set_anchor(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAnchorError> {
let req: SetAnchor = self.client.parse(self, parser)?;
if req.anchor & !(LEFT | RIGHT | TOP | BOTTOM) != 0 {
return Err(SetAnchorError::UnknownAnchor(req.anchor));
}
self.pending.anchor.set(Some(req.anchor));
Ok(())
}
fn set_exclusive_zone(&self, parser: MsgParser<'_, '_>) -> Result<(), SetExclusiveZoneError> {
let req: SetExclusiveZone = self.client.parse(self, parser)?;
self.pending.exclusive_zone.set(Some(req.zone));
Ok(())
}
fn set_margin(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMarginError> {
let req: SetMargin = self.client.parse(self, parser)?;
self.pending.margin.set(Some((req.top, req.right, req.bottom, req.left)));
Ok(())
}
fn set_keyboard_interactivity(&self, parser: MsgParser<'_, '_>) -> Result<(), SetKeyboardInteractivityError> {
let req: SetKeyboardInteractivity = self.client.parse(self, parser)?;
if req.keyboard_interactivity > KI_ON_DEMAND {
return Err(SetKeyboardInteractivityError::UnknownKi(req.keyboard_interactivity));
}
self.pending.keyboard_interactivity.set(Some(req.keyboard_interactivity));
Ok(())
}
fn get_popup(&self, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> {
let _req: GetPopup = self.client.parse(self, parser)?;
Ok(())
}
fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> {
let req: AckConfigure = self.client.parse(self, parser)?;
self.acked_serial.set(Some(req.serial));
Ok(())
}
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
let _req: Destroy = self.client.parse(self, parser)?;
self.destroy_node(true);
self.client.remove_obj(self)?;
self.surface.unset_ext();
Ok(())
}
fn set_layer(&self, parser: MsgParser<'_, '_>) -> Result<(), SetLayerError> {
let req: SetLayer = self.client.parse(self, parser)?;
if req.layer > OVERLAY {
return Err(SetLayerError::UnknownLayer(req.layer));
}
self.pending.layer.set(Some(req.layer));
Ok(())
}
fn pre_commit(&self) -> Result<(), ZwlrLayerSurfaceV1Error> {
let mut send_configure = false;
if let Some(size) = self.pending.size.take() {
self.size.set(size);
}
if let Some(anchor) = self.pending.anchor.take() {
self.anchor.set(anchor);
}
if let Some(ez) = self.pending.exclusive_zone.take() {
self.exclusive_zone.set(ez);
}
if let Some(margin) = self.pending.margin.take() {
self.margin.set(margin);
}
if let Some(ki) = self.pending.keyboard_interactivity.take() {
self.keyboard_interactivity.set(ki);
}
if let Some(layer) = self.pending.layer.take() {
self.layer.set(layer);
}
{
let (mut width, mut height) = self.size.get();
let anchor = self.anchor.get();
if width == 0 {
if !anchor.contains(LEFT | RIGHT) {
return Err(ZwlrLayerSurfaceV1Error::WidthZero);
}
send_configure = true;
width = self.output.global.position().width();
}
if height == 0 {
if !anchor.contains(TOP | BOTTOM) {
return Err(ZwlrLayerSurfaceV1Error::HeightZero);
}
send_configure = true;
height = self.output.global.position().height();
}
self.size.set((width, height));
}
if self.acked_serial.get().is_none() {
send_configure = true;
}
if send_configure {
let (width, height) = self.size.get();
let serial = self.requested_serial.fetch_add(1) + 1;
self.send_configure(serial, width as _, height as _);
}
Ok(())
}
pub fn position(&self) -> Rect {
self.pos.get()
}
fn compute_position(&self) {
let (width, height) = self.size.get();
let mut anchor = self.anchor.get();
if anchor == 0 {
anchor = LEFT | RIGHT | TOP | BOTTOM;
}
let opos = self.output.position.get();
let mut x1 = opos.x1();
let mut y1 = opos.y1();
if anchor.contains(LEFT) {
if anchor.contains(RIGHT) {
x1 += (opos.width() - width) / 2;
}
} else if anchor.contains(RIGHT) {
x1 += opos.width() - width;
}
if anchor.contains(TOP) {
if anchor.contains(BOTTOM) {
y1 += (opos.height() - height) / 2;
}
} else if anchor.contains(BOTTOM) {
y1 += opos.height() - height;
}
self.pos.set(Rect::new_sized(x1, y1, width, height).unwrap());
self.client.state.tree_changed();
}
}
impl SurfaceExt for ZwlrLayerSurfaceV1 {
fn pre_commit(self: Rc<Self>, _ctx: CommitContext) -> Result<CommitAction, WlSurfaceError> {
self.deref().pre_commit()?;
Ok(CommitAction::ContinueCommit)
}
fn post_commit(self: Rc<Self>) {
let buffer = self.surface.buffer.get();
if self.mapped.get() {
if buffer.is_none() {
self.destroy_node(true);
} else {
let pos = self.pos.get();
let (width, height) = self.size.get();
if width != pos.width() || height != pos.height() {
self.compute_position();
}
}
} else if buffer.is_some() {
let layer = &self.output.layers[self.layer.get() as usize];
self.link.set(Some(layer.add_last(self.clone())));
self.mapped.set(true);
self.compute_position();
}
if self.mapped.get() {
match self.keyboard_interactivity.get() {
KI_NONE => {
let was_active = self.surface.seat_state.is_active();
self.surface.seat_state.release_kb_focus();
if was_active {
self.surface.active_changed(false);
}
},
KI_ON_DEMAND => self.surface.seat_state.release_kb_grab(),
KI_EXCLUSIVE => {
let seats = self.client.state.globals.seats.lock();
for seat in seats.values() {
seat.grab(self.surface.clone());
}
}
_ => unreachable!(),
}
}
}
fn accepts_kb_focus(&self) -> bool {
self.keyboard_interactivity.get() != KI_NONE
}
}
impl Node for ZwlrLayerSurfaceV1 {
fn id(&self) -> NodeId {
self.node_id.into()
}
fn seat_state(&self) -> &NodeSeatState {
&self.seat_state
}
fn destroy_node(&self, _detach: bool) {
self.link.set(None);
self.mapped.set(false);
self.surface.destroy_node(false);
self.seat_state.destroy_node(self);
}
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
visitor.visit_layer_surface(&self);
}
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
self.surface.clone().visit(visitor);
}
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
renderer.render_layer_surface(self, x, y);
}
fn absolute_position(&self) -> Rect {
self.pos.get()
}
fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
tree.push(FoundNode {
node: self.surface.clone(),
x,
y
});
self.surface.find_tree_at(x, y, tree)
}
fn change_extents(self: Rc<Self>, _rect: &Rect) {
self.compute_position();
}
}
object_base! {
ZwlrLayerSurfaceV1, ZwlrLayerSurfaceV1Error;
SET_SIZE => set_size,
SET_ANCHOR => set_anchor,
SET_EXCLUSIVE_ZONE => set_exclusive_zone,
SET_MARGIN => set_margin,
SET_KEYBOARD_INTERACTIVITY => set_keyboard_interactivity,
GET_POPUP => get_popup,
ACK_CONFIGURE => ack_configure,
DESTROY => destroy,
SET_LAYER => set_layer,
}
impl Object for ZwlrLayerSurfaceV1 {
fn num_requests(&self) -> u32 {
let last_req = match self.shell.version {
0..=1 => DESTROY,
_ => SET_LAYER,
};
last_req + 1
}
fn break_loops(&self) {
self.destroy_node(true);
self.link.set(None);
}
}
simple_add_obj!(ZwlrLayerSurfaceV1);
#[derive(Debug, Error)]
pub enum ZwlrLayerSurfaceV1Error {
#[error("Could not process `set_size` request")]
SetSizeError(#[from] SetSizeError),
#[error("Could not process `set_anchor` request")]
SetAnchorError(#[from] SetAnchorError),
#[error("Could not process `set_exclusive_zone` request")]
SetExclusiveZoneError(#[from] SetExclusiveZoneError),
#[error("Could not process `set_margin` request")]
SetMarginError(#[from] SetMarginError),
#[error("Could not process `set_keyboard_interactivity` request")]
SetKeyboardInteractivityError(#[from] SetKeyboardInteractivityError),
#[error("Could not process `get_popup` request")]
GetPopupError(#[from] GetPopupError),
#[error("Could not process `ack_configure` request")]
AckConfigureError(#[from] AckConfigureError),
#[error("Could not process `destroy` request")]
DestroyError(#[from] DestroyError),
#[error("Could not process `set_layer` request")]
SetLayerError(#[from] SetLayerError),
#[error("Surface {0} cannot be turned into a zwlr_layer_surface because it already has an attached zwlr_layer_surface")]
AlreadyAttached(WlSurfaceId),
#[error("Width was set to 0 but anchor did not contain LEFT and RIGHT")]
WidthZero,
#[error("Height was set to 0 but anchor did not contain TOP and BOTTOM")]
HeightZero,
#[error(transparent)]
WlSurfaceError(Box<WlSurfaceError>),
}
efrom!(ZwlrLayerSurfaceV1Error, WlSurfaceError);
#[derive(Debug, Error)]
pub enum SetSizeError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Surface size must not be larger than 65535x65535")]
ExcessiveSize,
}
efrom!(SetSizeError, MsgParserError);
efrom!(SetSizeError, ClientError);
#[derive(Debug, Error)]
pub enum SetAnchorError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Unknown anchor {0}")]
UnknownAnchor(u32),
}
efrom!(SetAnchorError, MsgParserError);
efrom!(SetAnchorError, ClientError);
#[derive(Debug, Error)]
pub enum SetExclusiveZoneError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(SetExclusiveZoneError, MsgParserError);
efrom!(SetExclusiveZoneError, ClientError);
#[derive(Debug, Error)]
pub enum SetMarginError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(SetMarginError, MsgParserError);
efrom!(SetMarginError, ClientError);
#[derive(Debug, Error)]
pub enum SetKeyboardInteractivityError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Unknown keyboard interactivity {0}")]
UnknownKi(u32),
}
efrom!(SetKeyboardInteractivityError, MsgParserError);
efrom!(SetKeyboardInteractivityError, ClientError);
#[derive(Debug, Error)]
pub enum GetPopupError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(GetPopupError, MsgParserError);
efrom!(GetPopupError, ClientError);
#[derive(Debug, Error)]
pub enum AckConfigureError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(AckConfigureError, MsgParserError);
efrom!(AckConfigureError, ClientError);
#[derive(Debug, Error)]
pub enum DestroyError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(DestroyError, MsgParserError);
efrom!(DestroyError, ClientError);
#[derive(Debug, Error)]
pub enum SetLayerError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Unknown layer {0}")]
UnknownLayer(u32),
}
efrom!(SetLayerError, MsgParserError);
efrom!(SetLayerError, ClientError);

View file

@ -0,0 +1,176 @@
use crate::client::{Client, ClientError};
use crate::globals::{Global, GlobalName};
use crate::ifs::wl_surface::zwlr_layer_surface_v1::{ZwlrLayerSurfaceV1, ZwlrLayerSurfaceV1Error};
use crate::leaks::Tracker;
use crate::object::Object;
use crate::utils::buffd::MsgParser;
use crate::utils::buffd::MsgParserError;
use crate::wire::zwlr_layer_shell_v1::*;
use crate::wire::ZwlrLayerShellV1Id;
use std::rc::Rc;
use thiserror::Error;
#[allow(dead_code)]
pub const BACKGROUND: u32 = 0;
#[allow(dead_code)]
pub const BOTTOM: u32 = 1;
#[allow(dead_code)]
pub const TOP: u32 = 2;
pub const OVERLAY: u32 = 3;
pub struct ZwlrLayerShellV1Global {
name: GlobalName,
}
pub struct ZwlrLayerShellV1 {
pub id: ZwlrLayerShellV1Id,
pub client: Rc<Client>,
pub version: u32,
pub tracker: Tracker<Self>,
}
impl ZwlrLayerShellV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: ZwlrLayerShellV1Id,
client: &Rc<Client>,
version: u32,
) -> Result<(), ZwlrLayerShellV1Error> {
let obj = Rc::new(ZwlrLayerShellV1 {
id,
client: client.clone(),
version,
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}
impl ZwlrLayerShellV1 {
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
let _req: Destroy = self.client.parse(self, parser)?;
self.client.remove_obj(self)?;
Ok(())
}
fn get_layer_surface(
self: &Rc<Self>,
parser: MsgParser<'_, '_>,
) -> Result<(), GetLayerSurfaceError> {
let req: GetLayerSurface = self.client.parse(&**self, parser)?;
let surface = self.client.lookup(req.surface)?;
let output = 'get_output: {
if req.output.is_some() {
self.client.lookup(req.output)?.global.node.get().unwrap()
} else {
for seat in self.client.state.seat_queue.rev_iter() {
if let Some(output) = seat.get_output() {
break 'get_output output.node.get().unwrap();
}
}
let outputs = self.client.state.outputs.lock();
match outputs.values().next() {
Some(ou) => ou.node.get().unwrap(),
_ => return Err(GetLayerSurfaceError::NoOutputs),
}
}
};
if req.layer > OVERLAY {
return Err(GetLayerSurfaceError::UnknownLayer(req.layer));
}
let surface = Rc::new(ZwlrLayerSurfaceV1::new(
req.id,
self,
&surface,
&output,
req.layer,
req.namespace,
));
track!(self.client, surface);
self.client.add_client_obj(&surface)?;
surface.install()?;
Ok(())
}
}
global_base!(
ZwlrLayerShellV1Global,
ZwlrLayerShellV1,
ZwlrLayerShellV1Error
);
impl Global for ZwlrLayerShellV1Global {
fn singleton(&self) -> bool {
true
}
fn version(&self) -> u32 {
4
}
}
simple_add_global!(ZwlrLayerShellV1Global);
object_base! {
ZwlrLayerShellV1, ZwlrLayerShellV1Error;
GET_LAYER_SURFACE => get_layer_surface,
DESTROY => destroy,
}
simple_add_obj!(ZwlrLayerShellV1);
impl Object for ZwlrLayerShellV1 {
fn num_requests(&self) -> u32 {
let last_request = if self.version >= 3 {
DESTROY
} else {
GET_LAYER_SURFACE
};
last_request + 1
}
}
#[derive(Debug, Error)]
pub enum ZwlrLayerShellV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Could not process a `destroy` request")]
DestroyError(#[from] DestroyError),
#[error("Could not process a `get_layer_surface` request")]
GetLayerSurfaceError(#[from] GetLayerSurfaceError),
}
efrom!(ZwlrLayerShellV1Error, ClientError);
#[derive(Debug, Error)]
pub enum DestroyError {
#[error("Parsing failed")]
ParseError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(DestroyError, ParseError, MsgParserError);
efrom!(DestroyError, ClientError);
#[derive(Debug, Error)]
pub enum GetLayerSurfaceError {
#[error("Parsing failed")]
ParseError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Unknown layer {0}")]
UnknownLayer(u32),
#[error("There are no outputs")]
NoOutputs,
#[error(transparent)]
ZwlrLayerSurfaceV1Error(Box<ZwlrLayerSurfaceV1Error>),
}
efrom!(GetLayerSurfaceError, ParseError, MsgParserError);
efrom!(GetLayerSurfaceError, ClientError);
efrom!(GetLayerSurfaceError, ZwlrLayerSurfaceV1Error);

View file

@ -0,0 +1,137 @@
use crate::client::{Client, ClientError};
use crate::globals::{Global, GlobalName};
use crate::leaks::Tracker;
use crate::object::Object;
use crate::utils::buffd::MsgParser;
use crate::utils::buffd::MsgParserError;
use crate::wire::zxdg_output_manager_v1::*;
use crate::wire::{ZxdgOutputManagerV1Id};
use std::rc::Rc;
use thiserror::Error;
use crate::ifs::zxdg_output_v1::ZxdgOutputV1;
pub struct ZxdgOutputManagerV1Global {
name: GlobalName,
}
pub struct ZxdgOutputManagerV1 {
pub id: ZxdgOutputManagerV1Id,
pub client: Rc<Client>,
pub version: u32,
pub tracker: Tracker<Self>,
}
impl ZxdgOutputManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: ZxdgOutputManagerV1Id,
client: &Rc<Client>,
version: u32,
) -> Result<(), ZxdgOutputManagerV1Error> {
let obj = Rc::new(ZxdgOutputManagerV1 {
id,
client: client.clone(),
version,
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}
impl ZxdgOutputManagerV1 {
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
let _req: Destroy = self.client.parse(self, parser)?;
self.client.remove_obj(self)?;
Ok(())
}
fn get_xdg_output(
self: &Rc<Self>,
parser: MsgParser<'_, '_>,
) -> Result<(), GetXdgOutputError> {
let req: GetXdgOutput = self.client.parse(&**self, parser)?;
let output = self.client.lookup(req.output)?;
let xdg_output = Rc::new(ZxdgOutputV1 {
id: req.id,
version: self.version,
client: self.client.clone(),
output: output.clone(),
tracker: Default::default()
});
track!(self.client, xdg_output);
self.client.add_client_obj(&xdg_output)?;
xdg_output.send_updates();
output.xdg_outputs.set(req.id, xdg_output);
Ok(())
}
}
global_base!(
ZxdgOutputManagerV1Global,
ZxdgOutputManagerV1,
ZxdgOutputManagerV1Error
);
impl Global for ZxdgOutputManagerV1Global {
fn singleton(&self) -> bool {
true
}
fn version(&self) -> u32 {
3
}
}
simple_add_global!(ZxdgOutputManagerV1Global);
object_base! {
ZxdgOutputManagerV1, ZxdgOutputManagerV1Error;
DESTROY => destroy,
GET_XDG_OUTPUT => get_xdg_output,
}
simple_add_obj!(ZxdgOutputManagerV1);
impl Object for ZxdgOutputManagerV1 {
fn num_requests(&self) -> u32 {
GET_XDG_OUTPUT + 1
}
}
#[derive(Debug, Error)]
pub enum ZxdgOutputManagerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Could not process a `destroy` request")]
DestroyError(#[from] DestroyError),
#[error("Could not process a `get_xdg_output` request")]
GetXdgOutputError(#[from] GetXdgOutputError),
}
efrom!(ZxdgOutputManagerV1Error, ClientError);
#[derive(Debug, Error)]
pub enum DestroyError {
#[error("Parsing failed")]
ParseError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(DestroyError, ParseError, MsgParserError);
efrom!(DestroyError, ClientError);
#[derive(Debug, Error)]
pub enum GetXdgOutputError {
#[error("Parsing failed")]
ParseError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(GetXdgOutputError, ParseError, MsgParserError);
efrom!(GetXdgOutputError, ClientError);

107
src/ifs/zxdg_output_v1.rs Normal file
View file

@ -0,0 +1,107 @@
use std::rc::Rc;
use thiserror::Error;
use crate::client::{Client, ClientError};
use crate::ifs::wl_output::{SEND_DONE_SINCE, WlOutput};
use crate::leaks::Tracker;
use crate::object::Object;
use crate::utils::buffd::{MsgParser, MsgParserError};
use crate::wire::ZxdgOutputV1Id;
use crate::wire::zxdg_output_v1::*;
pub const NAME_SINCE: u32 = 2;
pub const DESCRIPTION_SINCE: u32 = 2;
pub const NO_DONE_SINCE: u32 = 3;
pub struct ZxdgOutputV1 {
pub id: ZxdgOutputV1Id,
pub version: u32,
pub client: Rc<Client>,
pub output: Rc<WlOutput>,
pub tracker: Tracker<Self>,
}
impl ZxdgOutputV1 {
pub fn send_logical_position(&self, x: i32, y: i32) {
self.client.event(LogicalPosition {
self_id: self.id,
x,
y,
});
}
pub fn send_logical_size(&self, width: i32, height: i32) {
self.client.event(LogicalSize {
self_id: self.id,
width,
height,
});
}
pub fn send_done(&self) {
self.client.event(Done {
self_id: self.id,
});
}
pub fn send_name(&self, name: &str) {
self.client.event(Name {
self_id: self.id,
name,
});
}
pub fn send_description(&self, description: &str) {
self.client.event(Description {
self_id: self.id,
description,
});
}
pub fn send_updates(&self) {
let pos = self.output.global.position();
self.send_logical_position(pos.x1(), pos.y1());
self.send_logical_size(pos.width(), pos.height());
if self.version >= NO_DONE_SINCE || self.output.version < SEND_DONE_SINCE {
self.output.send_done();
} else {
self.send_done();
}
}
pub fn destroy(&self, msg: MsgParser) -> Result<(), DestroyError> {
let _req: Destroy = self.client.parse(self, msg)?;
self.output.xdg_outputs.remove(&self.id);
self.client.remove_obj(self)?;
Ok(())
}
}
object_base! {
ZxdgOutputV1, ZxdgOutputV1Error;
DESTROY => destroy,
}
impl Object for ZxdgOutputV1 {
fn num_requests(&self) -> u32 {
DESTROY + 1
}
}
simple_add_obj!(ZxdgOutputV1);
#[derive(Debug, Error)]
pub enum ZxdgOutputV1Error {
#[error("Could not process a `destroy` request")]
DestroyError(#[from] DestroyError),
}
#[derive(Debug, Error)]
pub enum DestroyError {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(DestroyError, MsgParserError);
efrom!(DestroyError, ClientError);