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

@ -3,6 +3,7 @@ use crate::ifs::ipc::wl_data_source::WlDataSource;
use crate::ifs::ipc::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1;
use crate::ifs::wl_buffer::WlBuffer;
use crate::ifs::wl_display::WlDisplay;
use crate::ifs::wl_output::WlOutput;
use crate::ifs::wl_region::WlRegion;
use crate::ifs::wl_registry::WlRegistry;
use crate::ifs::wl_seat::WlSeat;
@ -16,8 +17,8 @@ use crate::tree::Node;
use crate::utils::clonecell::CloneCell;
use crate::utils::copyhashmap::CopyHashMap;
use crate::wire::{
WlBufferId, WlDataSourceId, WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId,
XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id,
WlBufferId, WlDataSourceId, WlOutputId, WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId,
XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id,
};
use ahash::AHashMap;
use std::cell::{RefCell, RefMut};
@ -29,6 +30,7 @@ pub struct Objects {
pub display: CloneCell<Option<Rc<WlDisplay>>>,
registry: CopyHashMap<ObjectId, Rc<dyn Object>>,
registries: CopyHashMap<WlRegistryId, Rc<WlRegistry>>,
pub outputs: CopyHashMap<WlOutputId, Rc<WlOutput>>,
pub surfaces: CopyHashMap<WlSurfaceId, Rc<WlSurface>>,
pub xdg_surfaces: CopyHashMap<XdgSurfaceId, Rc<XdgSurface>>,
pub xdg_toplevel: CopyHashMap<XdgToplevelId, Rc<XdgToplevel>>,
@ -52,6 +54,7 @@ impl Objects {
display: CloneCell::new(None),
registry: Default::default(),
registries: Default::default(),
outputs: Default::default(),
surfaces: Default::default(),
xdg_surfaces: Default::default(),
xdg_toplevel: Default::default(),
@ -83,6 +86,7 @@ impl Objects {
}
self.display.set(None);
self.registries.clear();
self.outputs.clear();
self.surfaces.clear();
self.xdg_surfaces.clear();
self.wl_data_source.clear();

View file

@ -6,6 +6,7 @@ use crate::ifs::wl_drm::WlDrmGlobal;
use crate::ifs::wl_output::WlOutputGlobal;
use crate::ifs::wl_registry::WlRegistry;
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::ifs::zwlr_layer_shell_v1::ZwlrLayerShellV1Global;
use crate::object::{Interface, ObjectId};
use crate::utils::copyhashmap::CopyHashMap;
use crate::{
@ -18,6 +19,7 @@ use std::error::Error;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
use thiserror::Error;
use crate::ifs::zxdg_output_manager_v1::ZxdgOutputManagerV1Global;
#[derive(Debug, Error)]
pub enum GlobalsError {
@ -103,6 +105,8 @@ impl Globals {
add_singleton!(ZxdgDecorationManagerV1Global);
add_singleton!(OrgKdeKwinServerDecorationManagerGlobal);
add_singleton!(ZwpPrimarySelectionDeviceManagerV1Global);
add_singleton!(ZwlrLayerShellV1Global);
add_singleton!(ZxdgOutputManagerV1Global);
slf
}

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);

View file

@ -44,14 +44,14 @@ macro_rules! object_base {
}
fn interface(&self) -> crate::object::Interface {
crate::object::Interface::$oname
crate::wire::$oname
}
}
impl From<$ename> for crate::client::ObjectError {
fn from(v: $ename) -> Self {
Self {
interface: crate::object::Interface::$oname,
interface: crate::wire::$oname,
error: Box::new(v),
}
}
@ -79,14 +79,14 @@ macro_rules! global_base {
}
fn interface(&self) -> crate::object::Interface {
crate::object::Interface::$ifname
crate::wire::$ifname
}
}
impl From<$ename> for crate::globals::GlobalError {
fn from(e: $ename) -> Self {
Self {
interface: crate::object::Interface::$ifname,
interface: crate::wire::$ifname,
error: Box::new(e),
}
}
@ -281,7 +281,7 @@ macro_rules! dedicated_add_obj {
impl crate::client::WaylandObjectLookup for $idname {
type Object = $oname;
const INTERFACE: crate::object::Interface = crate::object::Interface::$oname;
const INTERFACE: crate::object::Interface = crate::wire::$oname;
fn lookup(client: &crate::client::Client, id: Self) -> Option<Rc<$oname>> {
client.objects.$field.get(&id)

View file

@ -42,91 +42,11 @@ pub trait Object: ObjectBase + 'static {
fn break_loops(&self) {}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Interface {
WlDisplay,
WlCallback,
WlCompositor,
WlOutput,
WlRegistry,
WlShm,
WlShmPool,
WlTouch,
WlPointer,
WlKeyboard,
WlSubcompositor,
WlDataDeviceManager,
WlDataDevice,
WlDataSource,
WlDataOffer,
XdgWmBase,
XdgPositioner,
WlSurface,
WlSubsurface,
XdgSurface,
XdgPopup,
XdgToplevel,
WlRegion,
WlBuffer,
WlSeat,
WlDrm,
ZwpLinuxDmabufV1,
ZwpLinuxDmabufFeedbackV1,
ZwpLinuxBufferParamsV1,
ZxdgDecorationManagerV1,
ZxdgToplevelDecorationV1,
OrgKdeKwinServerDecorationManager,
OrgKdeKwinServerDecoration,
ZwpPrimarySelectionDeviceManagerV1,
ZwpPrimarySelectionDeviceV1,
ZwpPrimarySelectionSourceV1,
ZwpPrimarySelectionOfferV1,
}
#[derive(Copy, Clone, Debug)]
pub struct Interface(pub &'static str);
impl Interface {
pub fn name(self) -> &'static str {
match self {
Interface::WlDisplay => "wl_display",
Interface::WlCallback => "wl_callback",
Interface::WlCompositor => "wl_compositor",
Interface::WlRegistry => "wl_registry",
Interface::WlShm => "wl_shm",
Interface::WlSubcompositor => "wl_subcompositor",
Interface::XdgWmBase => "xdg_wm_base",
Interface::WlSurface => "wl_surface",
Interface::WlSubsurface => "wl_subsurface",
Interface::WlShmPool => "wl_shm_pool",
Interface::WlRegion => "wl_region",
Interface::XdgSurface => "xdg_surface",
Interface::XdgPositioner => "xdg_positioner",
Interface::XdgPopup => "xdg_popup",
Interface::XdgToplevel => "xdg_toplevel",
Interface::WlBuffer => "wl_buffer",
Interface::WlOutput => "wl_output",
Interface::WlSeat => "wl_seat",
Interface::WlTouch => "wl_touch",
Interface::WlPointer => "wl_pointer",
Interface::WlKeyboard => "wl_keyboard",
Interface::WlDataDeviceManager => "wl_data_device_manager",
Interface::WlDataDevice => "wl_data_device",
Interface::WlDataSource => "wl_data_source",
Interface::WlDataOffer => "wl_data_offer",
Interface::ZwpLinuxDmabufV1 => "zwp_linux_dmabuf_v1",
Interface::ZwpLinuxDmabufFeedbackV1 => "zwp_linux_dmabuf_feedback_v1",
Interface::ZwpLinuxBufferParamsV1 => "zwp_linux_buffer_params_v1",
Interface::WlDrm => "wl_drm",
Interface::ZxdgDecorationManagerV1 => "zxdg_decoration_manager_v1",
Interface::ZxdgToplevelDecorationV1 => "zxdg_toplevel_decoration_v1",
Interface::OrgKdeKwinServerDecorationManager => {
"org_kde_kwin_server_decoration_manager"
}
Interface::OrgKdeKwinServerDecoration => "org_kde_kwin_server_decoration",
Interface::ZwpPrimarySelectionDeviceManagerV1 => {
"zwp_primary_selection_device_manager_v1"
}
Interface::ZwpPrimarySelectionDeviceV1 => "zwp_primary_selection_device_v1",
Interface::ZwpPrimarySelectionSourceV1 => "zwp_primary_selection_source_v1",
Interface::ZwpPrimarySelectionOfferV1 => "zwp_primary_selection_offer_v1",
}
self.0
}
}

View file

@ -21,6 +21,7 @@ use crate::State;
use std::ops::Deref;
use std::rc::Rc;
use std::slice;
use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
const NON_COLOR: Color = Color::from_rgbaf(0.2, 0.2, 0.2, 1.0);
const CHILD_COLOR: Color = Color::from_rgbaf(0.8, 0.8, 0.8, 1.0);
@ -42,9 +43,21 @@ pub struct Renderer<'a> {
impl Renderer<'_> {
pub fn render_output(&mut self, output: &OutputNode, x: i32, y: i32) {
macro_rules! render_layer {
($layer:expr) => {
for ls in $layer.iter() {
let pos = ls.position();
self.render_layer_surface(ls.deref(), pos.x1(), pos.y1());
}
}
}
render_layer!(output.layers[0]);
render_layer!(output.layers[1]);
if let Some(ws) = output.workspace.get() {
self.render_workspace(&ws, x, y);
}
render_layer!(output.layers[2]);
render_layer!(output.layers[3]);
}
pub fn render_workspace(&mut self, workspace: &WorkspaceNode, x: i32, y: i32) {
@ -392,4 +405,13 @@ impl Renderer<'_> {
});
}
}
pub fn render_layer_surface(&mut self, surface: &ZwlrLayerSurfaceV1, x: i32, y: i32) {
unsafe {
let body = surface.position();
with_scissor(&body, || {
self.render_surface(&surface.surface, x, y);
});
}
}
}

View file

@ -30,7 +30,9 @@ impl OutputHandler {
workspace: CloneCell::new(None),
seat_state: Default::default(),
global: global.clone(),
layers: Default::default(),
});
global.node.set(Some(on.clone()));
let workspace = Rc::new(WorkspaceNode {
id: self.state.node_ids.next(),
output: CloneCell::new(on.clone()),
@ -60,6 +62,7 @@ impl OutputHandler {
global.update_properties();
ae.triggered().await;
}
global.node.set(None);
self.state.outputs.remove(&self.output.id());
let _ = self.state.remove_global(&*global);
self.state

View file

@ -345,7 +345,13 @@ impl ContainerNode {
}
_ => {
let height = body.height() + add;
(0, pos + title_height + 1, other_content_size, height, height)
(
0,
pos + title_height + 1,
other_content_size,
height,
height,
)
}
};
body = Rect::new_sized(x1, y1, width, height).unwrap();

View file

@ -2,13 +2,11 @@ use crate::backend::{KeyState, OutputId, ScrollAxis};
use crate::client::{Client, ClientId};
use crate::cursor::KnownCursor;
use crate::fixed::Fixed;
use crate::ifs::wl_output::WlOutputGlobal;
use crate::ifs::wl_seat::{Dnd, NodeSeatState, WlSeatGlobal};
use crate::ifs::wl_surface::WlSurface;
use crate::rect::Rect;
use crate::render::Renderer;
use crate::tree::walker::NodeVisitor;
use crate::utils::clonecell::CloneCell;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::linkedlist::LinkedList;
use crate::xkbcommon::ModifierState;
@ -16,16 +14,17 @@ use crate::NumCell;
pub use container::*;
pub use float::*;
use i4config::Direction;
use std::cell::{Cell, RefCell};
use std::fmt::{Debug, Display, Formatter};
use std::fmt::{Debug, Display};
use std::ops::Deref;
use std::rc::Rc;
pub use workspace::*;
pub use output::*;
mod container;
mod float;
pub mod walker;
mod workspace;
mod output;
pub struct NodeIds {
next: NumCell<u32>,
@ -254,6 +253,14 @@ pub trait Node {
false
}
fn is_output(&self) -> bool {
false
}
fn into_output(self: Rc<Self>) -> Option<Rc<OutputNode>> {
None
}
fn accepts_child(&self, node: &dyn Node) -> bool {
let _ = node;
false
@ -422,87 +429,3 @@ impl Node for DisplayNode {
seat.set_known_cursor(KnownCursor::Default);
}
}
tree_id!(OutputNodeId);
pub struct OutputNode {
pub display: Rc<DisplayNode>,
pub id: OutputNodeId,
pub position: Cell<Rect>,
pub global: Rc<WlOutputGlobal>,
pub workspaces: RefCell<Vec<Rc<WorkspaceNode>>>,
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
pub seat_state: NodeSeatState,
}
impl Debug for OutputNode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OutputNode").finish_non_exhaustive()
}
}
impl Node for OutputNode {
fn id(&self) -> NodeId {
self.id.into()
}
fn seat_state(&self) -> &NodeSeatState {
&self.seat_state
}
fn destroy_node(&self, detach: bool) {
if detach {
self.display.clone().remove_child(self);
}
let mut workspaces = self.workspaces.borrow_mut();
for workspace in workspaces.drain(..) {
workspace.destroy_node(false);
}
self.seat_state.destroy_node(self);
}
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
visitor.visit_output(&self);
}
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
let ws = self.workspaces.borrow_mut();
for ws in ws.deref() {
visitor.visit_workspace(ws);
}
}
fn absolute_position(&self) -> Rect {
self.position.get()
}
fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
if let Some(ws) = self.workspace.get() {
tree.push(FoundNode {
node: ws.clone(),
x,
y,
});
ws.find_tree_at(x, y, tree);
}
FindTreeResult::AcceptsInput
}
fn remove_child(self: Rc<Self>, _child: &dyn Node) {
self.workspace.set(None);
}
fn pointer_focus(&self, seat: &Rc<WlSeatGlobal>) {
seat.set_known_cursor(KnownCursor::Default);
}
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
renderer.render_output(self, x, y);
}
fn change_extents(self: Rc<Self>, rect: &Rect) {
self.position.set(*rect);
if let Some(c) = self.workspace.get() {
c.change_extents(rect);
}
}
}

117
src/tree/output.rs Normal file
View file

@ -0,0 +1,117 @@
use std::cell::{Cell, RefCell};
use std::fmt::{Debug, Formatter};
use std::ops::Deref;
use std::rc::Rc;
use crate::{CloneCell, DisplayNode};
use crate::cursor::KnownCursor;
use crate::ifs::wl_output::WlOutputGlobal;
use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal};
use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
use crate::rect::Rect;
use crate::render::Renderer;
use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode};
use crate::tree::walker::NodeVisitor;
use crate::utils::linkedlist::LinkedList;
tree_id!(OutputNodeId);
pub struct OutputNode {
pub display: Rc<DisplayNode>,
pub id: OutputNodeId,
pub position: Cell<Rect>,
pub global: Rc<WlOutputGlobal>,
pub workspaces: RefCell<Vec<Rc<WorkspaceNode>>>,
pub workspace: CloneCell<Option<Rc<WorkspaceNode>>>,
pub seat_state: NodeSeatState,
pub layers: [LinkedList<Rc<ZwlrLayerSurfaceV1>>; 4],
}
impl Debug for OutputNode {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OutputNode").finish_non_exhaustive()
}
}
impl Node for OutputNode {
fn id(&self) -> NodeId {
self.id.into()
}
fn seat_state(&self) -> &NodeSeatState {
&self.seat_state
}
fn destroy_node(&self, detach: bool) {
if detach {
self.display.clone().remove_child(self);
}
let mut workspaces = self.workspaces.borrow_mut();
for workspace in workspaces.drain(..) {
workspace.destroy_node(false);
}
self.seat_state.destroy_node(self);
}
fn visit(self: Rc<Self>, visitor: &mut dyn NodeVisitor) {
visitor.visit_output(&self);
}
fn visit_children(&self, visitor: &mut dyn NodeVisitor) {
let ws = self.workspaces.borrow_mut();
for ws in ws.deref() {
visitor.visit_workspace(ws);
}
for layers in &self.layers {
for surface in layers.iter() {
visitor.visit_layer_surface(surface.deref());
}
}
}
fn absolute_position(&self) -> Rect {
self.position.get()
}
fn find_tree_at(&self, x: i32, y: i32, tree: &mut Vec<FoundNode>) -> FindTreeResult {
if let Some(ws) = self.workspace.get() {
tree.push(FoundNode {
node: ws.clone(),
x,
y,
});
ws.find_tree_at(x, y, tree);
}
FindTreeResult::AcceptsInput
}
fn remove_child(self: Rc<Self>, _child: &dyn Node) {
self.workspace.set(None);
}
fn pointer_focus(&self, seat: &Rc<WlSeatGlobal>) {
seat.set_known_cursor(KnownCursor::Default);
}
fn render(&self, renderer: &mut Renderer, x: i32, y: i32) {
renderer.render_output(self, x, y);
}
fn is_output(&self) -> bool {
true
}
fn into_output(self: Rc<Self>) -> Option<Rc<OutputNode>> {
Some(self)
}
fn change_extents(self: Rc<Self>, rect: &Rect) {
self.position.set(*rect);
if let Some(c) = self.workspace.get() {
c.change_extents(rect);
}
for layer in &self.layers {
for surface in layer.iter() {
surface.deref().clone().change_extents(rect);
}
}
}
}

View file

@ -4,6 +4,7 @@ use crate::ifs::wl_surface::WlSurface;
use crate::tree::{ContainerNode, FloatNode, Node, OutputNode, WorkspaceNode};
use crate::DisplayNode;
use std::rc::Rc;
use crate::ifs::wl_surface::zwlr_layer_surface_v1::ZwlrLayerSurfaceV1;
pub trait NodeVisitorBase: Sized {
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
@ -37,6 +38,10 @@ pub trait NodeVisitorBase: Sized {
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
node.visit_children(self);
}
fn visit_layer_surface(&mut self, node: &Rc<ZwlrLayerSurfaceV1>) {
node.visit_children(self);
}
}
pub trait NodeVisitor {
@ -48,6 +53,7 @@ pub trait NodeVisitor {
fn visit_output(&mut self, node: &Rc<OutputNode>);
fn visit_float(&mut self, node: &Rc<FloatNode>);
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>);
fn visit_layer_surface(&mut self, node: &Rc<ZwlrLayerSurfaceV1>);
}
impl<T: NodeVisitorBase> NodeVisitor for T {
@ -82,6 +88,10 @@ impl<T: NodeVisitorBase> NodeVisitor for T {
fn visit_workspace(&mut self, node: &Rc<WorkspaceNode>) {
<T as NodeVisitorBase>::visit_workspace(self, node)
}
fn visit_layer_surface(&mut self, node: &Rc<ZwlrLayerSurfaceV1>) {
<T as NodeVisitorBase>::visit_layer_surface(self, node)
}
}
// pub fn visit_containers<F: FnMut(&Rc<ContainerNode>)>(f: F) -> impl NodeVisitor {

View file

@ -1 +1,3 @@
#![allow(non_upper_case_globals)]
include!(concat!(env!("OUT_DIR"), "/wire.rs"));