autocommit 2022-01-25 16:45:44 CET
This commit is contained in:
parent
0336bf3bde
commit
c340df0d08
59 changed files with 3085 additions and 1710 deletions
|
|
@ -2,26 +2,27 @@ mod types;
|
|||
pub mod wl_subsurface;
|
||||
pub mod xdg_surface;
|
||||
|
||||
use crate::client::{AddObj, Client, RequestParser};
|
||||
use crate::client::{Client, RequestParser};
|
||||
use crate::ifs::wl_buffer::WlBuffer;
|
||||
use crate::ifs::wl_callback::WlCallback;
|
||||
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::pixman::Region;
|
||||
use crate::tree::{NodeBase, NodeCommon, ToplevelNode};
|
||||
use crate::rect::Rect;
|
||||
use crate::tree::{Node, NodeId};
|
||||
use crate::utils::buffd::{MsgParser, MsgParserError};
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::utils::linkedlist::{LinkedList, Node as LinkNode};
|
||||
use crate::utils::linkedlist::LinkedList;
|
||||
use crate::NumCell;
|
||||
use ahash::AHashMap;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
use crate::backend::{KeyState, ScrollAxis};
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
|
||||
const DESTROY: u32 = 0;
|
||||
const ATTACH: u32 = 1;
|
||||
|
|
@ -53,6 +54,8 @@ pub enum SurfaceRole {
|
|||
None,
|
||||
Subsurface,
|
||||
XdgSurface,
|
||||
XdgPopup,
|
||||
XdgToplevel,
|
||||
}
|
||||
|
||||
impl SurfaceRole {
|
||||
|
|
@ -61,213 +64,189 @@ impl SurfaceRole {
|
|||
SurfaceRole::None => "none",
|
||||
SurfaceRole::Subsurface => "subsurface",
|
||||
SurfaceRole::XdgSurface => "xdg_surface",
|
||||
SurfaceRole::XdgPopup => "xdg_popup",
|
||||
SurfaceRole::XdgToplevel => "xdg_toplevel",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WlSurface {
|
||||
pub id: WlSurfaceId,
|
||||
pub node_id: SurfaceNodeId,
|
||||
pub client: Rc<Client>,
|
||||
role: Cell<SurfaceRole>,
|
||||
pending: PendingState,
|
||||
input_region: Cell<Option<Region>>,
|
||||
opaque_region: Cell<Option<Region>>,
|
||||
pub extents: Cell<SurfaceExtents>,
|
||||
pub effective_extents: Cell<SurfaceExtents>,
|
||||
pub extents: Cell<Rect>,
|
||||
pub need_extents_update: Cell<bool>,
|
||||
pub effective_extents: Cell<Rect>,
|
||||
pub buffer: CloneCell<Option<Rc<WlBuffer>>>,
|
||||
pub buf_x: NumCell<i32>,
|
||||
pub buf_y: NumCell<i32>,
|
||||
pub children: RefCell<Option<Box<ParentData>>>,
|
||||
role_data: RefCell<RoleData>,
|
||||
ext: CloneCell<Rc<dyn SurfaceExt>>,
|
||||
pub frame_requests: RefCell<Vec<Rc<WlCallback>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub struct SurfaceExtents {
|
||||
pub x1: i32,
|
||||
pub y1: i32,
|
||||
pub x2: i32,
|
||||
pub y2: i32,
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
enum CommitContext {
|
||||
RootCommit,
|
||||
ChildCommit,
|
||||
}
|
||||
|
||||
enum RoleData {
|
||||
None,
|
||||
Subsurface(Box<SubsurfaceData>),
|
||||
XdgSurface(Box<XdgSurfaceData>),
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
enum CommitAction {
|
||||
ContinueCommit,
|
||||
AbortCommit,
|
||||
}
|
||||
|
||||
impl RoleData {
|
||||
trait SurfaceExt {
|
||||
fn pre_commit(self: Rc<Self>, ctx: CommitContext) -> CommitAction {
|
||||
let _ = ctx;
|
||||
CommitAction::ContinueCommit
|
||||
}
|
||||
|
||||
fn post_commit(&self) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn is_some(&self) -> bool {
|
||||
!matches!(self, RoleData::None)
|
||||
true
|
||||
}
|
||||
|
||||
fn update_subsurface_parent_extents(&self) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn subsurface_parent(&self) -> Option<Rc<WlSurface>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn into_subsurface(self: Rc<Self>) -> Option<Rc<WlSubsurface>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NoneSurfaceExt;
|
||||
|
||||
impl SurfaceExt for NoneSurfaceExt {
|
||||
fn is_some(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PendingState {
|
||||
buffer: Cell<Option<Option<(i32, i32, Rc<WlBuffer>)>>>,
|
||||
opaque_region: Cell<Option<Region>>,
|
||||
input_region: Cell<Option<Region>>,
|
||||
frame_request: RefCell<Vec<Rc<WlCallback>>>,
|
||||
}
|
||||
|
||||
struct XdgSurfaceData {
|
||||
xdg_surface: Rc<XdgSurface>,
|
||||
requested_serial: u32,
|
||||
acked_serial: Option<u32>,
|
||||
role: XdgSurfaceRole,
|
||||
extents: Option<SurfaceExtents>,
|
||||
role_data: XdgSurfaceRoleData,
|
||||
popups: CopyHashMap<WlSurfaceId, Rc<XdgPopup>>,
|
||||
pending: PendingXdgSurfaceData,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PendingXdgSurfaceData {
|
||||
extents: Cell<Option<SurfaceExtents>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum XdgSurfaceRole {
|
||||
None,
|
||||
Popup,
|
||||
Toplevel,
|
||||
}
|
||||
|
||||
impl XdgSurfaceRole {
|
||||
fn is_compatible(self, role: XdgSurfaceRole) -> bool {
|
||||
self == XdgSurfaceRole::None || self == role
|
||||
}
|
||||
}
|
||||
|
||||
enum XdgSurfaceRoleData {
|
||||
None,
|
||||
Popup(XdgPopupData),
|
||||
Toplevel(XdgToplevelData),
|
||||
}
|
||||
|
||||
impl XdgSurfaceRoleData {
|
||||
fn is_some(&self) -> bool {
|
||||
!matches!(self, XdgSurfaceRoleData::None)
|
||||
}
|
||||
}
|
||||
|
||||
struct XdgPopupData {
|
||||
_popup: Rc<XdgPopup>,
|
||||
parent: Option<Rc<XdgSurface>>,
|
||||
}
|
||||
|
||||
struct XdgToplevelData {
|
||||
toplevel: Rc<XdgToplevel>,
|
||||
node: Option<ToplevelNodeHolder>,
|
||||
}
|
||||
|
||||
struct ToplevelNodeHolder {
|
||||
node: Rc<ToplevelNode>,
|
||||
}
|
||||
|
||||
impl Drop for ToplevelNodeHolder {
|
||||
fn drop(&mut self) {
|
||||
mem::take(&mut *self.node.common.floating_outputs.borrow_mut());
|
||||
}
|
||||
}
|
||||
|
||||
struct SubsurfaceData {
|
||||
subsurface: Rc<WlSubsurface>,
|
||||
x: i32,
|
||||
y: i32,
|
||||
sync_requested: bool,
|
||||
sync_ancestor: bool,
|
||||
node: LinkNode<StackElement>,
|
||||
depth: u32,
|
||||
pending: PendingSubsurfaceData,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PendingSubsurfaceData {
|
||||
node: Option<LinkNode<StackElement>>,
|
||||
position: Option<(i32, i32)>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ParentData {
|
||||
subsurfaces: AHashMap<WlSurfaceId, Rc<WlSurface>>,
|
||||
subsurfaces: AHashMap<WlSurfaceId, Rc<WlSubsurface>>,
|
||||
pub below: LinkedList<StackElement>,
|
||||
pub above: LinkedList<StackElement>,
|
||||
}
|
||||
|
||||
pub struct StackElement {
|
||||
pending: Cell<bool>,
|
||||
pub surface: Rc<WlSurface>,
|
||||
pub pending: Cell<bool>,
|
||||
pub sub_surface: Rc<WlSubsurface>,
|
||||
}
|
||||
|
||||
impl WlSurface {
|
||||
pub fn new(id: WlSurfaceId, client: &Rc<Client>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
node_id: client.state.node_ids.next(),
|
||||
client: client.clone(),
|
||||
role: Cell::new(SurfaceRole::None),
|
||||
pending: Default::default(),
|
||||
input_region: Cell::new(None),
|
||||
opaque_region: Cell::new(None),
|
||||
extents: Default::default(),
|
||||
need_extents_update: Cell::new(false),
|
||||
effective_extents: Default::default(),
|
||||
buffer: CloneCell::new(None),
|
||||
buf_x: Default::default(),
|
||||
buf_y: Default::default(),
|
||||
children: Default::default(),
|
||||
role_data: RefCell::new(RoleData::None),
|
||||
ext: CloneCell::new(client.state.none_surface_ext.clone()),
|
||||
frame_requests: RefCell::new(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subsurface_position(&self) -> Option<(i32, i32)> {
|
||||
let rd = self.role_data.borrow();
|
||||
match rd.deref() {
|
||||
RoleData::Subsurface(ss) => Some((ss.x, ss.y)),
|
||||
_ => None,
|
||||
fn set_role(&self, role: SurfaceRole) -> Result<(), WlSurfaceError> {
|
||||
use SurfaceRole::*;
|
||||
match (self.role.get(), role) {
|
||||
(None, _) => {}
|
||||
(old, new) if old == new => {}
|
||||
(XdgSurface, XdgPopup) => {}
|
||||
(XdgSurface, XdgToplevel) => {}
|
||||
(old, new) => {
|
||||
return Err(WlSurfaceError::IncompatibleRole {
|
||||
id: self.id,
|
||||
old,
|
||||
new,
|
||||
})
|
||||
}
|
||||
}
|
||||
self.role.set(role);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unset_ext(&self) {
|
||||
self.ext.set(self.client.state.none_surface_ext.clone());
|
||||
}
|
||||
|
||||
fn calculate_extents(&self) {
|
||||
{
|
||||
let mut extents = SurfaceExtents::default();
|
||||
if let Some(b) = self.buffer.get() {
|
||||
extents.x2 = b.width as i32;
|
||||
extents.y2 = b.height as i32;
|
||||
}
|
||||
let children = self.children.borrow();
|
||||
if let Some(children) = &*children {
|
||||
for surface in children.subsurfaces.values() {
|
||||
let rd = surface.role_data.borrow();
|
||||
if let RoleData::Subsurface(ss) = &*rd {
|
||||
let ss_extents = surface.extents.get();
|
||||
extents.x1 = extents.x1.min(ss_extents.x1 + ss.x);
|
||||
extents.y1 = extents.y1.min(ss_extents.y1 + ss.y);
|
||||
extents.x2 = extents.x2.max(ss_extents.x2 + ss.x);
|
||||
extents.y2 = extents.y2.max(ss_extents.y2 + ss.y);
|
||||
}
|
||||
let old_extents = self.extents.get();
|
||||
let mut extents = Rect::new_empty(0, 0);
|
||||
if let Some(b) = self.buffer.get() {
|
||||
extents = b.rect;
|
||||
}
|
||||
let children = self.children.borrow();
|
||||
if let Some(children) = &*children {
|
||||
for ss in children.subsurfaces.values() {
|
||||
let ce = ss.surface.extents.get();
|
||||
if !ce.is_empty() {
|
||||
let cp = ss.position.get();
|
||||
let ce = ce.move_(cp.x1(), cp.y1());
|
||||
extents = if extents.is_empty() {
|
||||
ce
|
||||
} else {
|
||||
extents.union(ce)
|
||||
};
|
||||
}
|
||||
}
|
||||
self.extents.set(extents);
|
||||
}
|
||||
let parent = {
|
||||
let rd = self.role_data.borrow();
|
||||
match &*rd {
|
||||
RoleData::Subsurface(ss) => ss.subsurface.parent.clone(),
|
||||
_ => return,
|
||||
}
|
||||
};
|
||||
parent.calculate_extents();
|
||||
self.extents.set(extents);
|
||||
self.need_extents_update.set(false);
|
||||
if old_extents != extents {
|
||||
self.ext.get().extents_changed()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_root(self: &Rc<Self>) -> Rc<WlSurface> {
|
||||
let mut root = self.clone();
|
||||
loop {
|
||||
let tmp = root;
|
||||
let data = tmp.role_data.borrow();
|
||||
match &*data {
|
||||
RoleData::Subsurface(d) => root = d.subsurface.parent.clone(),
|
||||
_ => {
|
||||
drop(data);
|
||||
return tmp;
|
||||
}
|
||||
if let Some(parent) = root.ext.get().subsurface_parent() {
|
||||
root = parent;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
root
|
||||
}
|
||||
|
||||
fn parse<'a, T: RequestParser<'a>>(
|
||||
|
|
@ -277,16 +256,16 @@ impl WlSurface {
|
|||
self.client.parse(self, parser)
|
||||
}
|
||||
|
||||
async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
let _req: Destroy = self.parse(parser)?;
|
||||
if self.role_data.borrow().is_some() {
|
||||
if self.ext.get().is_some() {
|
||||
return Err(DestroyError::ReloObjectStillExists);
|
||||
}
|
||||
{
|
||||
let mut children = self.children.borrow_mut();
|
||||
if let Some(children) = &mut *children {
|
||||
for surface in children.subsurfaces.values() {
|
||||
*surface.role_data.borrow_mut() = RoleData::None;
|
||||
for ss in children.subsurfaces.values() {
|
||||
ss.surface.unset_ext();
|
||||
}
|
||||
}
|
||||
*children = None;
|
||||
|
|
@ -297,62 +276,27 @@ impl WlSurface {
|
|||
buffer.surfaces.remove(&self.id);
|
||||
}
|
||||
}
|
||||
self.client.remove_obj(self).await?;
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn attach(&self, parser: MsgParser<'_, '_>) -> Result<(), AttachError> {
|
||||
fn attach(&self, parser: MsgParser<'_, '_>) -> Result<(), AttachError> {
|
||||
let req: Attach = self.parse(parser)?;
|
||||
{
|
||||
if let Some(buffer) = self.buffer.take() {
|
||||
self.client.event(buffer.release()).await?;
|
||||
buffer.surfaces.remove(&self.id);
|
||||
}
|
||||
let mut rd = self.role_data.borrow_mut();
|
||||
if req.buffer.is_some() {
|
||||
self.buffer.set(Some(self.client.get_buffer(req.buffer)?));
|
||||
if let RoleData::XdgSurface(xdg) = &mut *rd {
|
||||
if let XdgSurfaceRoleData::Toplevel(td) = &mut xdg.role_data {
|
||||
if td.node.is_none() {
|
||||
let outputs = self.client.state.root.outputs.lock();
|
||||
if let Some(output) = outputs.values().next() {
|
||||
let node = Rc::new(ToplevelNode {
|
||||
common: NodeCommon {
|
||||
extents: Cell::new(Default::default()),
|
||||
id: self.client.state.node_ids.next(),
|
||||
parent: Some(output.clone()),
|
||||
floating_outputs: RefCell::new(Default::default()),
|
||||
},
|
||||
surface: td.toplevel.clone(),
|
||||
});
|
||||
td.node = Some(ToplevelNodeHolder { node: node.clone() });
|
||||
let link = output.floating.add_last(node.clone());
|
||||
node.common
|
||||
.floating_outputs
|
||||
.borrow_mut()
|
||||
.insert(output.id(), link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.buffer.set(None);
|
||||
if let RoleData::XdgSurface(xdg) = &mut *rd {
|
||||
if let XdgSurfaceRoleData::Toplevel(td) = &mut xdg.role_data {
|
||||
td.node = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let buf = if req.buffer.is_some() {
|
||||
Some((req.x, req.y, self.client.get_buffer(req.buffer)?))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.pending.buffer.set(Some(buf));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn damage(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageError> {
|
||||
fn damage(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageError> {
|
||||
let _req: Damage = self.parse(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn frame(&self, parser: MsgParser<'_, '_>) -> Result<(), FrameError> {
|
||||
fn frame(&self, parser: MsgParser<'_, '_>) -> Result<(), FrameError> {
|
||||
let req: Frame = self.parse(parser)?;
|
||||
let cb = Rc::new(WlCallback::new(req.callback));
|
||||
self.client.add_client_obj(&cb)?;
|
||||
|
|
@ -360,49 +304,57 @@ impl WlSurface {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_opaque_region(
|
||||
&self,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), SetOpaqueRegionError> {
|
||||
fn set_opaque_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetOpaqueRegionError> {
|
||||
let region: SetOpaqueRegion = self.parse(parser)?;
|
||||
let region = self.client.get_region(region.region)?;
|
||||
self.pending.opaque_region.set(Some(region.region()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_input_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetInputRegionError> {
|
||||
fn set_input_region(&self, parser: MsgParser<'_, '_>) -> Result<(), SetInputRegionError> {
|
||||
let req: SetInputRegion = self.parse(parser)?;
|
||||
let region = self.client.get_region(req.region)?;
|
||||
self.pending.input_region.set(Some(region.region()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn do_commit(&self) {
|
||||
let mut xdg_extents = None;
|
||||
let mut td_node = None;
|
||||
fn do_commit(&self, ctx: CommitContext) {
|
||||
let ext = self.ext.get();
|
||||
if ext.clone().pre_commit(ctx) == CommitAction::AbortCommit {
|
||||
return;
|
||||
}
|
||||
{
|
||||
let mut rd = self.role_data.borrow_mut();
|
||||
match &mut *rd {
|
||||
RoleData::None => {}
|
||||
RoleData::Subsurface(ss) => {
|
||||
if let Some(v) = ss.pending.node.take() {
|
||||
v.pending.set(false);
|
||||
ss.node = v;
|
||||
}
|
||||
if let Some((x, y)) = ss.pending.position.take() {
|
||||
ss.x = x;
|
||||
ss.y = y;
|
||||
}
|
||||
let children = self.children.borrow();
|
||||
if let Some(children) = children.deref() {
|
||||
for child in children.subsurfaces.values() {
|
||||
child.surface.do_commit(CommitContext::ChildCommit);
|
||||
}
|
||||
RoleData::XdgSurface(xdg) => {
|
||||
if let Some(extents) = xdg.pending.extents.take() {
|
||||
xdg.extents = Some(extents);
|
||||
}
|
||||
xdg_extents = xdg.extents;
|
||||
if let XdgSurfaceRoleData::Toplevel(tl) = &xdg.role_data {
|
||||
td_node = tl.node.as_ref().map(|n| n.node.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(buffer_change) = self.pending.buffer.take() {
|
||||
let mut old_size = None;
|
||||
let mut new_size = None;
|
||||
log::info!("changing buffer");
|
||||
if let Some(buffer) = self.buffer.take() {
|
||||
log::info!("releasing buffer {}", buffer.id());
|
||||
old_size = Some(buffer.rect);
|
||||
self.client.event(buffer.release());
|
||||
buffer.surfaces.remove(&self.id);
|
||||
}
|
||||
if let Some((dx, dy, buffer)) = buffer_change {
|
||||
new_size = Some(buffer.rect);
|
||||
self.buffer.set(Some(buffer));
|
||||
self.buf_x.fetch_add(dx);
|
||||
self.buf_y.fetch_add(dy);
|
||||
if (dx, dy) != (0, 0) {
|
||||
self.need_extents_update.set(true);
|
||||
}
|
||||
} else {
|
||||
self.buf_x.set(0);
|
||||
self.buf_y.set(0);
|
||||
}
|
||||
if old_size != new_size {
|
||||
self.need_extents_update.set(true);
|
||||
}
|
||||
}
|
||||
{
|
||||
|
|
@ -417,71 +369,19 @@ impl WlSurface {
|
|||
self.opaque_region.set(Some(region));
|
||||
}
|
||||
}
|
||||
let mut committed_any_children = false;
|
||||
{
|
||||
let children = self.children.borrow();
|
||||
if let Some(children) = children.deref() {
|
||||
for child in children.subsurfaces.values() {
|
||||
child.do_commit();
|
||||
committed_any_children = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !committed_any_children {
|
||||
if self.need_extents_update.get() {
|
||||
self.calculate_extents();
|
||||
}
|
||||
let mut effective_extents = self.extents.get();
|
||||
if let Some(extents) = xdg_extents {
|
||||
effective_extents.x1 = effective_extents.x1.max(extents.x1);
|
||||
effective_extents.y1 = effective_extents.y1.max(extents.y1);
|
||||
effective_extents.x2 = effective_extents.x2.min(extents.x2);
|
||||
effective_extents.y2 = effective_extents.y2.min(extents.y2);
|
||||
if effective_extents.x1 > effective_extents.x2 {
|
||||
effective_extents.x1 = 0;
|
||||
effective_extents.x2 = 0;
|
||||
}
|
||||
if effective_extents.y1 > effective_extents.y2 {
|
||||
effective_extents.y1 = 0;
|
||||
effective_extents.y2 = 0;
|
||||
}
|
||||
}
|
||||
if let Some(node) = td_node {
|
||||
let mut td_extents = node.common.extents.get();
|
||||
td_extents.width = (effective_extents.x2 - effective_extents.x1) as u32;
|
||||
td_extents.height = (effective_extents.y2 - effective_extents.y1) as u32;
|
||||
node.common.extents.set(td_extents);
|
||||
}
|
||||
self.effective_extents.set(effective_extents);
|
||||
ext.post_commit();
|
||||
}
|
||||
|
||||
async fn commit(&self, parser: MsgParser<'_, '_>) -> Result<(), CommitError> {
|
||||
fn commit(&self, parser: MsgParser<'_, '_>) -> Result<(), CommitError> {
|
||||
let _req: Commit = self.parse(parser)?;
|
||||
{
|
||||
let rd = self.role_data.borrow();
|
||||
match rd.deref() {
|
||||
RoleData::Subsurface(ss) => {
|
||||
if ss.sync_ancestor || ss.sync_requested {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
RoleData::XdgSurface(xdg) => {
|
||||
if xdg.acked_serial != Some(xdg.requested_serial) {
|
||||
if xdg.acked_serial.is_none() {
|
||||
self.client
|
||||
.event(xdg.xdg_surface.configure(xdg.requested_serial))
|
||||
.await?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
self.do_commit();
|
||||
self.do_commit(CommitContext::RootCommit);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_buffer_transform(
|
||||
fn set_buffer_transform(
|
||||
&self,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), SetBufferTransformError> {
|
||||
|
|
@ -489,36 +389,79 @@ impl WlSurface {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_buffer_scale(&self, parser: MsgParser<'_, '_>) -> Result<(), SetBufferScaleError> {
|
||||
fn set_buffer_scale(&self, parser: MsgParser<'_, '_>) -> Result<(), SetBufferScaleError> {
|
||||
let _req: SetBufferScale = self.parse(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn damage_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageBufferError> {
|
||||
fn damage_buffer(&self, parser: MsgParser<'_, '_>) -> Result<(), DamageBufferError> {
|
||||
let _req: DamageBuffer = self.parse(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_request_(
|
||||
fn handle_request_(
|
||||
&self,
|
||||
request: u32,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), WlSurfaceError> {
|
||||
match request {
|
||||
DESTROY => self.destroy(parser).await?,
|
||||
ATTACH => self.attach(parser).await?,
|
||||
DAMAGE => self.damage(parser).await?,
|
||||
FRAME => self.frame(parser).await?,
|
||||
SET_OPAQUE_REGION => self.set_opaque_region(parser).await?,
|
||||
SET_INPUT_REGION => self.set_input_region(parser).await?,
|
||||
COMMIT => self.commit(parser).await?,
|
||||
SET_BUFFER_TRANSFORM => self.set_buffer_transform(parser).await?,
|
||||
SET_BUFFER_SCALE => self.set_buffer_scale(parser).await?,
|
||||
DAMAGE_BUFFER => self.damage_buffer(parser).await?,
|
||||
DESTROY => self.destroy(parser)?,
|
||||
ATTACH => self.attach(parser)?,
|
||||
DAMAGE => self.damage(parser)?,
|
||||
FRAME => self.frame(parser)?,
|
||||
SET_OPAQUE_REGION => self.set_opaque_region(parser)?,
|
||||
SET_INPUT_REGION => self.set_input_region(parser)?,
|
||||
COMMIT => self.commit(parser)?,
|
||||
SET_BUFFER_TRANSFORM => self.set_buffer_transform(parser)?,
|
||||
SET_BUFFER_SCALE => self.set_buffer_scale(parser)?,
|
||||
DAMAGE_BUFFER => self.damage_buffer(parser)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_surface_at(self: &Rc<Self>, x: i32, y: i32) -> Option<(Rc<Self>, i32, i32)> {
|
||||
let buffer = match self.buffer.get() {
|
||||
Some(b) => b,
|
||||
_ => return None,
|
||||
};
|
||||
let children = self.children.borrow();
|
||||
let children = match children.deref() {
|
||||
Some(c) => c,
|
||||
_ => {
|
||||
return if buffer.rect.contains(x, y) {
|
||||
Some((self.clone(), x, y))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
}
|
||||
};
|
||||
let ss = |c: &LinkedList<StackElement>| {
|
||||
for child in c.rev_iter() {
|
||||
if child.pending.get() {
|
||||
continue;
|
||||
}
|
||||
let pos = child.sub_surface.position.get();
|
||||
if pos.contains(x, y) {
|
||||
let (x, y) = pos.translate(x, y);
|
||||
if let Some(res) = child.sub_surface.surface.find_surface_at(x, y) {
|
||||
return Some(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
};
|
||||
if let Some(res) = ss(&children.above) {
|
||||
return Some(res);
|
||||
}
|
||||
if buffer.rect.contains(x, y) {
|
||||
return Some((self.clone(), x, y));
|
||||
}
|
||||
if let Some(res) = ss(&children.below) {
|
||||
return Some(res);
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
handle_request!(WlSurface);
|
||||
|
|
@ -538,8 +481,43 @@ impl Object for WlSurface {
|
|||
|
||||
fn break_loops(&self) {
|
||||
*self.children.borrow_mut() = None;
|
||||
*self.role_data.borrow_mut() = RoleData::None;
|
||||
self.unset_ext();
|
||||
mem::take(self.frame_requests.borrow_mut().deref_mut());
|
||||
self.buffer.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
tree_id!(SurfaceNodeId);
|
||||
impl Node for WlSurface {
|
||||
fn id(&self) -> NodeId {
|
||||
self.node_id.into()
|
||||
}
|
||||
|
||||
fn enter(self: Rc<Self>, seat: &WlSeatGlobal, x: Fixed, y: Fixed) {
|
||||
seat.enter_surface(&self, x, y)
|
||||
}
|
||||
|
||||
fn leave(&self, seat: &WlSeatGlobal) {
|
||||
seat.leave_surface(self);
|
||||
}
|
||||
|
||||
fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) {
|
||||
seat.motion_surface(self, x, y)
|
||||
}
|
||||
|
||||
fn scroll(&self, seat: &WlSeatGlobal, delta: i32, axis: ScrollAxis) {
|
||||
seat.scroll_surface(self, delta, axis);
|
||||
}
|
||||
|
||||
fn button(self: Rc<Self>, seat: &WlSeatGlobal, button: u32, state: KeyState) {
|
||||
seat.button_surface(&self, button, state);
|
||||
}
|
||||
|
||||
fn focus(self: Rc<Self>, seat: &WlSeatGlobal) {
|
||||
seat.focus_surface(&self);
|
||||
}
|
||||
|
||||
fn unfocus(self: Rc<Self>, seat: &WlSeatGlobal) {
|
||||
seat.unfocus_surface(&self);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
use crate::client::{ClientError, RequestParser};
|
||||
use crate::ifs::wl_callback::WlCallbackId;
|
||||
use crate::ifs::wl_region::WlRegionId;
|
||||
use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId};
|
||||
use crate::utils::buffd::{MsgParser, MsgParserError};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum WlSurfaceError {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error("Could not process `destroy` request")]
|
||||
DestroyError(#[source] Box<DestroyError>),
|
||||
#[error("Could not process `attach` request")]
|
||||
|
|
@ -27,7 +30,14 @@ pub enum WlSurfaceError {
|
|||
SetBufferScaleError(#[source] Box<SetBufferScaleError>),
|
||||
#[error("Could not process `damage_buffer` request")]
|
||||
DamageBufferError(#[source] Box<DamageBufferError>),
|
||||
#[error("Surface {} cannot be assigned the role {} because it already has the role {}", .id, .new.name(), .old.name())]
|
||||
IncompatibleRole {
|
||||
id: WlSurfaceId,
|
||||
old: SurfaceRole,
|
||||
new: SurfaceRole,
|
||||
},
|
||||
}
|
||||
efrom!(WlSurfaceError, ClientError, ClientError);
|
||||
efrom!(WlSurfaceError, DestroyError, DestroyError);
|
||||
efrom!(WlSurfaceError, AttachError, AttachError);
|
||||
efrom!(WlSurfaceError, DamageError, DamageError);
|
||||
|
|
@ -104,11 +114,14 @@ efrom!(SetInputRegionError, ClientError, ClientError);
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CommitError {
|
||||
#[error(transparent)]
|
||||
WlSurfaceError(Box<WlSurfaceError>),
|
||||
#[error("Parsing failed")]
|
||||
ParseFailed(#[source] Box<MsgParserError>),
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
}
|
||||
efrom!(CommitError, WlSurfaceError, WlSurfaceError);
|
||||
efrom!(CommitError, ParseFailed, MsgParserError);
|
||||
efrom!(CommitError, ClientError, ClientError);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,21 @@
|
|||
mod types;
|
||||
|
||||
use crate::client::AddObj;
|
||||
use crate::ifs::wl_surface::{
|
||||
RoleData, StackElement, SubsurfaceData, SurfaceRole, WlSurface, WlSurfaceId,
|
||||
CommitAction, CommitContext, StackElement, SurfaceExt, SurfaceRole, WlSurface, WlSurfaceId,
|
||||
};
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::rect::Rect;
|
||||
use crate::tree::{Node, NodeId};
|
||||
use crate::utils::buffd::MsgParser;
|
||||
use std::cell::Cell;
|
||||
use crate::utils::linkedlist::LinkedNode;
|
||||
use crate::NumCell;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
use crate::backend::{KeyState, ScrollAxis};
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
|
||||
const DESTROY: u32 = 0;
|
||||
const SET_POSITION: u32 = 1;
|
||||
|
|
@ -22,49 +29,57 @@ const BAD_SURFACE: u32 = 0;
|
|||
|
||||
const MAX_SUBSURFACE_DEPTH: u32 = 100;
|
||||
|
||||
tree_id!(SubsurfaceNodeId);
|
||||
id!(WlSubsurfaceId);
|
||||
|
||||
pub struct WlSubsurface {
|
||||
id: WlSubsurfaceId,
|
||||
surface: Rc<WlSurface>,
|
||||
node_id: SubsurfaceNodeId,
|
||||
pub surface: Rc<WlSurface>,
|
||||
pub(super) parent: Rc<WlSurface>,
|
||||
pub position: Cell<Rect>,
|
||||
sync_requested: Cell<bool>,
|
||||
sync_ancestor: Cell<bool>,
|
||||
node: RefCell<Option<LinkedNode<StackElement>>>,
|
||||
depth: NumCell<u32>,
|
||||
pending: PendingSubsurfaceData,
|
||||
}
|
||||
|
||||
fn update_children_sync(surface: &Rc<WlSurface>, sync: bool) {
|
||||
let children = surface.children.borrow();
|
||||
#[derive(Default)]
|
||||
struct PendingSubsurfaceData {
|
||||
node: RefCell<Option<LinkedNode<StackElement>>>,
|
||||
position: Cell<Option<(i32, i32)>>,
|
||||
}
|
||||
|
||||
fn update_children_sync(surface: &WlSubsurface, sync: bool) {
|
||||
let children = surface.surface.children.borrow();
|
||||
if let Some(children) = &*children {
|
||||
for child in children.subsurfaces.values() {
|
||||
let mut data = child.role_data.borrow_mut();
|
||||
if let RoleData::Subsurface(data) = &mut *data {
|
||||
let was_sync = data.sync_ancestor || data.sync_requested;
|
||||
data.sync_ancestor = sync;
|
||||
let is_sync = data.sync_ancestor || data.sync_requested;
|
||||
if was_sync != is_sync {
|
||||
update_children_sync(child, sync);
|
||||
}
|
||||
let was_sync = child.sync();
|
||||
child.sync_ancestor.set(sync);
|
||||
let is_sync = child.sync();
|
||||
if was_sync != is_sync {
|
||||
update_children_sync(child, sync);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_children_attach(
|
||||
surface: &Rc<WlSurface>,
|
||||
sync: bool,
|
||||
surface: &WlSubsurface,
|
||||
mut sync: bool,
|
||||
depth: u32,
|
||||
) -> Result<(), WlSubsurfaceError> {
|
||||
let children = surface.children.borrow();
|
||||
let children = surface.surface.children.borrow();
|
||||
if let Some(children) = &*children {
|
||||
for child in children.subsurfaces.values() {
|
||||
let mut data = child.role_data.borrow_mut();
|
||||
if let RoleData::Subsurface(data) = &mut *data {
|
||||
data.depth = depth + 1;
|
||||
if data.depth > MAX_SUBSURFACE_DEPTH {
|
||||
return Err(WlSubsurfaceError::MaxDepthExceeded);
|
||||
}
|
||||
data.sync_ancestor = sync;
|
||||
let sync = data.sync_ancestor || data.sync_requested;
|
||||
update_children_attach(child, sync, depth + 1)?;
|
||||
child.depth.set(depth + 1);
|
||||
if depth + 1 > MAX_SUBSURFACE_DEPTH {
|
||||
return Err(WlSubsurfaceError::MaxDepthExceeded);
|
||||
}
|
||||
child.sync_ancestor.set(sync);
|
||||
sync |= child.sync_requested.get();
|
||||
update_children_attach(child, sync, depth + 1)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -74,8 +89,15 @@ impl WlSubsurface {
|
|||
pub fn new(id: WlSubsurfaceId, surface: &Rc<WlSurface>, parent: &Rc<WlSurface>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
node_id: surface.client.state.node_ids.next(),
|
||||
surface: surface.clone(),
|
||||
parent: parent.clone(),
|
||||
position: Cell::new(Default::default()),
|
||||
sync_requested: Cell::new(false),
|
||||
sync_ancestor: Cell::new(false),
|
||||
node: RefCell::new(None),
|
||||
depth: NumCell::new(0),
|
||||
pending: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -83,13 +105,8 @@ impl WlSubsurface {
|
|||
if self.surface.id == self.parent.id {
|
||||
return Err(WlSubsurfaceError::OwnParent(self.surface.id));
|
||||
}
|
||||
let old_ty = self.surface.role.get();
|
||||
if !matches!(old_ty, SurfaceRole::None | SurfaceRole::Subsurface) {
|
||||
return Err(WlSubsurfaceError::IncompatibleType(self.surface.id, old_ty));
|
||||
}
|
||||
self.surface.role.set(SurfaceRole::Subsurface);
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
if matches!(*data, RoleData::Subsurface(_)) {
|
||||
self.surface.set_role(SurfaceRole::Subsurface)?;
|
||||
if self.surface.ext.get().is_some() {
|
||||
return Err(WlSubsurfaceError::AlreadyAttached(self.surface.id));
|
||||
}
|
||||
if self.surface.id == self.parent.get_root().id {
|
||||
|
|
@ -98,10 +115,9 @@ impl WlSubsurface {
|
|||
let mut sync_ancestor = false;
|
||||
let mut depth = 1;
|
||||
{
|
||||
let data = self.parent.role_data.borrow();
|
||||
if let RoleData::Subsurface(data) = &*data {
|
||||
sync_ancestor = data.sync_requested || data.sync_ancestor;
|
||||
depth = data.depth + 1;
|
||||
if let Some(ss) = self.parent.ext.get().into_subsurface() {
|
||||
sync_ancestor = ss.sync();
|
||||
depth = ss.depth.get() + 1;
|
||||
if depth >= MAX_SUBSURFACE_DEPTH {
|
||||
return Err(WlSubsurfaceError::MaxDepthExceeded);
|
||||
}
|
||||
|
|
@ -110,138 +126,136 @@ impl WlSubsurface {
|
|||
let node = {
|
||||
let mut data = self.parent.children.borrow_mut();
|
||||
let data = data.get_or_insert_with(Default::default);
|
||||
data.subsurfaces
|
||||
.insert(self.surface.id, self.surface.clone());
|
||||
data.subsurfaces.insert(self.surface.id, self.clone());
|
||||
data.above.add_first(StackElement {
|
||||
pending: Cell::new(true),
|
||||
surface: self.surface.clone(),
|
||||
sub_surface: self.clone(),
|
||||
})
|
||||
};
|
||||
*data = RoleData::Subsurface(Box::new(SubsurfaceData {
|
||||
subsurface: self.clone(),
|
||||
x: 0,
|
||||
y: 0,
|
||||
sync_requested: false,
|
||||
sync_ancestor,
|
||||
depth,
|
||||
node,
|
||||
pending: Default::default(),
|
||||
}));
|
||||
update_children_attach(&self.surface, sync_ancestor, depth)?;
|
||||
|
||||
*self.pending.node.borrow_mut() = Some(node);
|
||||
self.sync_ancestor.set(sync_ancestor);
|
||||
self.depth.set(depth);
|
||||
self.surface.ext.set(self.clone());
|
||||
update_children_attach(&self, sync_ancestor, depth)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
let _req: Destroy = self.surface.client.parse(self, parser)?;
|
||||
*self.surface.role_data.borrow_mut() = RoleData::None;
|
||||
self.surface.unset_ext();
|
||||
*self.node.borrow_mut() = None;
|
||||
{
|
||||
let mut children = self.parent.children.borrow_mut();
|
||||
if let Some(children) = &mut *children {
|
||||
children.subsurfaces.remove(&self.surface.id);
|
||||
}
|
||||
}
|
||||
self.surface.client.remove_obj(self).await?;
|
||||
self.parent.calculate_extents();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_position(&self, parser: MsgParser<'_, '_>) -> Result<(), SetPositionError> {
|
||||
let req: SetPosition = self.surface.client.parse(self, parser)?;
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
if let RoleData::Subsurface(data) = &mut *data {
|
||||
data.pending.position = Some((req.x, req.y));
|
||||
if !self.surface.extents.get().is_empty() {
|
||||
let mut parent_opt = Some(self.parent.clone());
|
||||
while let Some(parent) = parent_opt.take() {
|
||||
if !parent.need_extents_update.get() {
|
||||
break;
|
||||
}
|
||||
parent.calculate_extents();
|
||||
parent_opt = parent.ext.get().subsurface_parent();
|
||||
}
|
||||
}
|
||||
self.surface.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn place(&self, sibling: WlSurfaceId, above: bool) -> Result<(), PlacementError> {
|
||||
fn set_position(&self, parser: MsgParser<'_, '_>) -> Result<(), SetPositionError> {
|
||||
let req: SetPosition = self.surface.client.parse(self, parser)?;
|
||||
self.pending.position.set(Some((req.x, req.y)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn place(self: &Rc<Self>, sibling: WlSurfaceId, above: bool) -> Result<(), PlacementError> {
|
||||
if sibling == self.surface.id {
|
||||
return Err(PlacementError::AboveSelf(sibling));
|
||||
}
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
let pdata = self.parent.children.borrow();
|
||||
if let (RoleData::Subsurface(data), Some(pdata)) = (&mut *data, &*pdata) {
|
||||
if let Some(pdata) = &*pdata {
|
||||
let element = StackElement {
|
||||
pending: Cell::new(true),
|
||||
surface: self.surface.clone(),
|
||||
sub_surface: self.clone(),
|
||||
};
|
||||
if sibling == self.parent.id {
|
||||
let node = match above {
|
||||
let node = if sibling == self.parent.id {
|
||||
match above {
|
||||
true => pdata.above.add_first(element),
|
||||
_ => pdata.below.add_last(element),
|
||||
};
|
||||
data.pending.node = Some(node);
|
||||
}
|
||||
} else {
|
||||
let sibling = match pdata.subsurfaces.get(&sibling) {
|
||||
Some(s) => s,
|
||||
_ => return Err(PlacementError::NotASibling(sibling, self.surface.id)),
|
||||
};
|
||||
let sdata = sibling.role_data.borrow();
|
||||
if let RoleData::Subsurface(p) = &*sdata {
|
||||
let node = match &p.pending.node {
|
||||
Some(n) => n,
|
||||
_ => &p.node,
|
||||
};
|
||||
let node = match above {
|
||||
true => node.append(element),
|
||||
_ => node.prepend(element),
|
||||
};
|
||||
data.pending.node = Some(node);
|
||||
let node = match sibling.pending.node.borrow().deref() {
|
||||
Some(n) => n.to_ref(),
|
||||
_ => match sibling.node.borrow().deref() {
|
||||
Some(n) => n.to_ref(),
|
||||
_ => return Ok(()),
|
||||
},
|
||||
};
|
||||
match above {
|
||||
true => node.append(element),
|
||||
_ => node.prepend(element),
|
||||
}
|
||||
}
|
||||
};
|
||||
self.pending.node.borrow_mut().replace(node);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn place_above(&self, parser: MsgParser<'_, '_>) -> Result<(), PlaceAboveError> {
|
||||
let req: PlaceAbove = self.surface.client.parse(self, parser)?;
|
||||
fn place_above(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), PlaceAboveError> {
|
||||
let req: PlaceAbove = self.surface.client.parse(self.deref(), parser)?;
|
||||
self.place(req.sibling, true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn place_below(&self, parser: MsgParser<'_, '_>) -> Result<(), PlaceBelowError> {
|
||||
let req: PlaceBelow = self.surface.client.parse(self, parser)?;
|
||||
fn place_below(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), PlaceBelowError> {
|
||||
let req: PlaceBelow = self.surface.client.parse(self.deref(), parser)?;
|
||||
self.place(req.sibling, false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn sync(&self) -> bool {
|
||||
self.sync_requested.get() || self.sync_ancestor.get()
|
||||
}
|
||||
|
||||
fn update_sync(&self, sync: bool) {
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
if let RoleData::Subsurface(data) = &mut *data {
|
||||
let was_sync = data.sync_requested || data.sync_ancestor;
|
||||
data.sync_requested = sync;
|
||||
let is_sync = data.sync_requested || data.sync_ancestor;
|
||||
if was_sync != is_sync {
|
||||
update_children_sync(&self.surface, is_sync);
|
||||
}
|
||||
let was_sync = self.sync();
|
||||
self.sync_requested.set(sync);
|
||||
let is_sync = self.sync();
|
||||
if was_sync != is_sync {
|
||||
update_children_sync(self, is_sync);
|
||||
}
|
||||
}
|
||||
|
||||
async fn set_sync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSyncError> {
|
||||
fn set_sync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSyncError> {
|
||||
let _req: SetSync = self.surface.client.parse(self, parser)?;
|
||||
self.update_sync(true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_desync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetDesyncError> {
|
||||
fn set_desync(&self, parser: MsgParser<'_, '_>) -> Result<(), SetDesyncError> {
|
||||
let _req: SetDesync = self.surface.client.parse(self, parser)?;
|
||||
self.update_sync(false);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_request_(
|
||||
&self,
|
||||
fn handle_request_(
|
||||
self: &Rc<Self>,
|
||||
request: u32,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), WlSubsurfaceError> {
|
||||
match request {
|
||||
DESTROY => self.destroy(parser).await?,
|
||||
SET_POSITION => self.set_position(parser).await?,
|
||||
PLACE_ABOVE => self.place_above(parser).await?,
|
||||
PLACE_BELOW => self.place_below(parser).await?,
|
||||
SET_SYNC => self.set_sync(parser).await?,
|
||||
SET_DESYNC => self.set_desync(parser).await?,
|
||||
DESTROY => self.destroy(parser)?,
|
||||
SET_POSITION => self.set_position(parser)?,
|
||||
PLACE_ABOVE => self.place_above(parser)?,
|
||||
PLACE_BELOW => self.place_below(parser)?,
|
||||
SET_SYNC => self.set_sync(parser)?,
|
||||
SET_DESYNC => self.set_desync(parser)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -263,3 +277,79 @@ impl Object for WlSubsurface {
|
|||
SET_DESYNC + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl SurfaceExt for WlSubsurface {
|
||||
fn pre_commit(self: Rc<Self>, ctx: CommitContext) -> CommitAction {
|
||||
if ctx == CommitContext::RootCommit && self.sync() {
|
||||
log::info!("Aborting commit due to sync");
|
||||
return CommitAction::AbortCommit;
|
||||
}
|
||||
CommitAction::ContinueCommit
|
||||
}
|
||||
|
||||
fn post_commit(&self) {
|
||||
if let Some(v) = self.pending.node.take() {
|
||||
log::info!("post commit");
|
||||
v.pending.set(false);
|
||||
self.node.borrow_mut().replace(v);
|
||||
}
|
||||
if let Some((x, y)) = self.pending.position.take() {
|
||||
if let Some(buffer) = self.surface.buffer.get() {
|
||||
self.position.set(buffer.rect.move_(x, y));
|
||||
self.parent.need_extents_update.set(true);
|
||||
} else {
|
||||
self.position.set(Rect::new_empty(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn subsurface_parent(&self) -> Option<Rc<WlSurface>> {
|
||||
Some(self.parent.clone())
|
||||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
self.parent.need_extents_update.set(true);
|
||||
}
|
||||
|
||||
fn into_subsurface(self: Rc<Self>) -> Option<Rc<WlSubsurface>> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for WlSubsurface {
|
||||
fn id(&self) -> NodeId {
|
||||
self.node_id.into()
|
||||
}
|
||||
|
||||
fn enter(self: Rc<Self>, seat: &WlSeatGlobal, x: Fixed, y: Fixed) {
|
||||
seat.enter_surface(&self.surface, x, y)
|
||||
}
|
||||
|
||||
fn leave(&self, seat: &WlSeatGlobal) {
|
||||
seat.leave_surface(&self.surface);
|
||||
}
|
||||
|
||||
fn motion(&self, seat: &WlSeatGlobal, x: Fixed, y: Fixed) {
|
||||
seat.motion_surface(&self.surface, x, y)
|
||||
}
|
||||
|
||||
fn button(self: Rc<Self>, seat: &WlSeatGlobal, button: u32, state: KeyState) {
|
||||
seat.button_surface(&self.surface, button, state);
|
||||
}
|
||||
|
||||
fn scroll(&self, seat: &WlSeatGlobal, delta: i32, axis: ScrollAxis) {
|
||||
seat.scroll_surface(&self.surface, delta, axis);
|
||||
}
|
||||
|
||||
fn focus(self: Rc<Self>, seat: &WlSeatGlobal) {
|
||||
seat.focus_surface(&self.surface);
|
||||
}
|
||||
|
||||
fn unfocus(self: Rc<Self>, seat: &WlSeatGlobal) {
|
||||
seat.unfocus_surface(&self.surface)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::client::{ClientError, RequestParser};
|
||||
use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId};
|
||||
use crate::ifs::wl_surface::{WlSurfaceError, WlSurfaceId};
|
||||
use crate::utils::buffd::{MsgParser, MsgParserError};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use thiserror::Error;
|
||||
|
|
@ -18,8 +18,6 @@ pub enum WlSubsurfaceError {
|
|||
SetSync(#[from] SetSyncError),
|
||||
#[error("Could not process `set_desync` request")]
|
||||
SetDesync(#[from] SetDesyncError),
|
||||
#[error("Surface {0} cannot be assigned the role `Subsurface` because it already has the role `{1:?}`")]
|
||||
IncompatibleType(WlSurfaceId, SurfaceRole),
|
||||
#[error("Surface {0} already has an attached `wl_subsurface`")]
|
||||
AlreadyAttached(WlSurfaceId),
|
||||
#[error("Surface {0} cannot be made its own parent")]
|
||||
|
|
@ -28,7 +26,10 @@ pub enum WlSubsurfaceError {
|
|||
Ancestor(WlSurfaceId, WlSurfaceId),
|
||||
#[error("Subsurfaces cannot be nested deeper than 100 levels")]
|
||||
MaxDepthExceeded,
|
||||
#[error(transparent)]
|
||||
WlSurfaceError(Box<WlSurfaceError>),
|
||||
}
|
||||
efrom!(WlSubsurfaceError, WlSurfaceError, WlSurfaceError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DestroyError {
|
||||
|
|
|
|||
|
|
@ -2,17 +2,19 @@ mod types;
|
|||
pub mod xdg_popup;
|
||||
pub mod xdg_toplevel;
|
||||
|
||||
use crate::client::{AddObj, DynEventFormatter};
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup;
|
||||
use crate::client::DynEventFormatter;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::{XdgPopup, XdgPopupId};
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
|
||||
use crate::ifs::wl_surface::{
|
||||
RoleData, SurfaceExtents, SurfaceRole, WlSurface, XdgPopupData, XdgSurfaceData, XdgSurfaceRole,
|
||||
XdgSurfaceRoleData, XdgToplevelData,
|
||||
};
|
||||
use crate::ifs::wl_surface::{CommitAction, CommitContext, SurfaceExt, SurfaceRole, WlSurface};
|
||||
use crate::ifs::xdg_wm_base::XdgWmBaseObj;
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::rect::Rect;
|
||||
use crate::tree::Node;
|
||||
use crate::utils::buffd::MsgParser;
|
||||
use std::ops::DerefMut;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::NumCell;
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
|
||||
|
|
@ -36,6 +38,32 @@ pub struct XdgSurface {
|
|||
id: XdgSurfaceId,
|
||||
base: Rc<XdgWmBaseObj>,
|
||||
pub surface: Rc<WlSurface>,
|
||||
requested_serial: NumCell<u32>,
|
||||
acked_serial: Cell<Option<u32>>,
|
||||
geometry: Cell<Option<Rect>>,
|
||||
extents: Cell<Rect>,
|
||||
ext: CloneCell<Option<Rc<dyn XdgSurfaceExt>>>,
|
||||
popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
|
||||
pending: PendingXdgSurfaceData,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PendingXdgSurfaceData {
|
||||
geometry: Cell<Option<Rect>>,
|
||||
}
|
||||
|
||||
trait XdgSurfaceExt {
|
||||
fn post_commit(self: Rc<Self>) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl XdgSurface {
|
||||
|
|
@ -44,9 +72,25 @@ impl XdgSurface {
|
|||
id,
|
||||
base: wm_base.clone(),
|
||||
surface: surface.clone(),
|
||||
requested_serial: NumCell::new(0),
|
||||
acked_serial: Cell::new(None),
|
||||
geometry: Cell::new(None),
|
||||
extents: Cell::new(Default::default()),
|
||||
ext: Default::default(),
|
||||
popups: Default::default(),
|
||||
pending: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn geometry(&self) -> Option<Rect> {
|
||||
self.geometry.get()
|
||||
}
|
||||
|
||||
pub fn send_configure(self: &Rc<Self>) {
|
||||
let serial = self.requested_serial.fetch_add(1) + 1;
|
||||
self.surface.client.event(self.configure(serial));
|
||||
}
|
||||
|
||||
pub fn configure(self: &Rc<Self>, serial: u32) -> DynEventFormatter {
|
||||
Box::new(Configure {
|
||||
obj: self.clone(),
|
||||
|
|
@ -55,171 +99,125 @@ impl XdgSurface {
|
|||
}
|
||||
|
||||
pub fn install(self: &Rc<Self>) -> Result<(), XdgSurfaceError> {
|
||||
let old_role = self.surface.role.get();
|
||||
if !matches!(old_role, SurfaceRole::None | SurfaceRole::XdgSurface) {
|
||||
return Err(XdgSurfaceError::IncompatibleRole(self.surface.id, old_role));
|
||||
}
|
||||
self.surface.role.set(SurfaceRole::XdgSurface);
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
if data.is_some() {
|
||||
self.surface.set_role(SurfaceRole::XdgSurface)?;
|
||||
if self.surface.ext.get().is_some() {
|
||||
return Err(XdgSurfaceError::AlreadyAttached(self.surface.id));
|
||||
}
|
||||
*data = RoleData::XdgSurface(Box::new(XdgSurfaceData {
|
||||
xdg_surface: self.clone(),
|
||||
requested_serial: 0,
|
||||
acked_serial: None,
|
||||
role: XdgSurfaceRole::None,
|
||||
extents: None,
|
||||
role_data: XdgSurfaceRoleData::None,
|
||||
popups: Default::default(),
|
||||
pending: Default::default(),
|
||||
}));
|
||||
self.surface.ext.set(self.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
let _req: Destroy = self.surface.client.parse(self, parser)?;
|
||||
if self.ext.get().is_some() {
|
||||
return Err(DestroyError::RoleNotYetDestroyed(self.id));
|
||||
}
|
||||
{
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(rd) = &*data {
|
||||
if rd.role_data.is_some() {
|
||||
return Err(DestroyError::RoleNotYetDestroyed(self.id));
|
||||
}
|
||||
let children = rd.popups.lock();
|
||||
for child in children.values() {
|
||||
let mut data = child.surface.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(xdg) = &mut *data {
|
||||
if let XdgSurfaceRoleData::Popup(p) = &mut xdg.role_data {
|
||||
p.parent = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
let children = self.popups.lock();
|
||||
for child in children.values() {
|
||||
child.parent.set(None);
|
||||
}
|
||||
*data = RoleData::None;
|
||||
}
|
||||
self.surface.unset_ext();
|
||||
self.base.surfaces.remove(&self.id);
|
||||
self.surface.client.remove_obj(self).await?;
|
||||
self.surface.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_toplevel(
|
||||
self: &Rc<Self>,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), GetToplevelError> {
|
||||
fn get_toplevel(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), GetToplevelError> {
|
||||
let req: GetToplevel = self.surface.client.parse(&**self, parser)?;
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(data) = &mut *data {
|
||||
if !data.role.is_compatible(XdgSurfaceRole::Toplevel) {
|
||||
return Err(GetToplevelError::IncompatibleRole);
|
||||
}
|
||||
if data.role_data.is_some() {
|
||||
self.surface.client.protocol_error(
|
||||
&**self,
|
||||
ALREADY_CONSTRUCTED,
|
||||
format!(
|
||||
"wl_surface {} already has an assigned xdg_toplevel",
|
||||
self.surface.id
|
||||
),
|
||||
);
|
||||
return Err(GetToplevelError::AlreadyConstructed);
|
||||
}
|
||||
data.role = XdgSurfaceRole::Toplevel;
|
||||
let toplevel = Rc::new(XdgToplevel::new(req.id, self));
|
||||
self.surface.client.add_client_obj(&toplevel)?;
|
||||
data.role_data = XdgSurfaceRoleData::Toplevel(XdgToplevelData {
|
||||
toplevel,
|
||||
node: None,
|
||||
});
|
||||
self.surface.set_role(SurfaceRole::XdgToplevel)?;
|
||||
if self.ext.get().is_some() {
|
||||
self.surface.client.protocol_error(
|
||||
&**self,
|
||||
ALREADY_CONSTRUCTED,
|
||||
format!(
|
||||
"wl_surface {} already has an assigned xdg_toplevel",
|
||||
self.surface.id
|
||||
),
|
||||
);
|
||||
return Err(GetToplevelError::AlreadyConstructed);
|
||||
}
|
||||
let toplevel = Rc::new(XdgToplevel::new(req.id, self));
|
||||
self.surface.client.add_client_obj(&toplevel)?;
|
||||
self.ext.set(Some(toplevel));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_popup(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> {
|
||||
fn get_popup(self: &Rc<Self>, parser: MsgParser<'_, '_>) -> Result<(), GetPopupError> {
|
||||
let req: GetPopup = self.surface.client.parse(&**self, parser)?;
|
||||
let mut data = self.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(data) = &mut *data {
|
||||
let mut parent = None;
|
||||
if req.parent.is_some() {
|
||||
parent = Some(self.surface.client.get_xdg_surface(req.parent)?);
|
||||
}
|
||||
if !data.role.is_compatible(XdgSurfaceRole::Popup) {
|
||||
return Err(GetPopupError::IncompatibleRole);
|
||||
}
|
||||
if data.role_data.is_some() {
|
||||
self.surface.client.protocol_error(
|
||||
&**self,
|
||||
ALREADY_CONSTRUCTED,
|
||||
format!(
|
||||
"wl_surface {} already has an assigned xdg_popup",
|
||||
self.surface.id
|
||||
),
|
||||
);
|
||||
return Err(GetPopupError::AlreadyConstructed);
|
||||
}
|
||||
data.role = XdgSurfaceRole::Popup;
|
||||
let popup = Rc::new(XdgPopup::new(req.id, self));
|
||||
self.surface.client.add_client_obj(&popup)?;
|
||||
if let Some(parent) = &parent {
|
||||
let mut data = parent.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(xdg) = &mut *data {
|
||||
xdg.popups.set(self.surface.id, popup.clone());
|
||||
}
|
||||
}
|
||||
data.role_data = XdgSurfaceRoleData::Popup(XdgPopupData {
|
||||
_popup: popup,
|
||||
parent,
|
||||
});
|
||||
self.surface.set_role(SurfaceRole::XdgPopup)?;
|
||||
let mut parent = None;
|
||||
if req.parent.is_some() {
|
||||
parent = Some(self.surface.client.get_xdg_surface(req.parent)?);
|
||||
}
|
||||
if self.ext.get().is_some() {
|
||||
self.surface.client.protocol_error(
|
||||
&**self,
|
||||
ALREADY_CONSTRUCTED,
|
||||
format!(
|
||||
"wl_surface {} already has an assigned xdg_popup",
|
||||
self.surface.id
|
||||
),
|
||||
);
|
||||
return Err(GetPopupError::AlreadyConstructed);
|
||||
}
|
||||
let popup = Rc::new(XdgPopup::new(req.id, self, parent.as_ref()));
|
||||
self.surface.client.add_client_obj(&popup)?;
|
||||
if let Some(parent) = &parent {
|
||||
parent.popups.set(req.id, popup.clone());
|
||||
}
|
||||
self.ext.set(Some(popup));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_window_geometry(
|
||||
&self,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), SetWindowGeometryError> {
|
||||
fn set_window_geometry(&self, parser: MsgParser<'_, '_>) -> Result<(), SetWindowGeometryError> {
|
||||
let req: SetWindowGeometry = self.surface.client.parse(self, parser)?;
|
||||
if req.height <= 0 || req.width <= 0 {
|
||||
return Err(SetWindowGeometryError::NonPositiveWidthHeight);
|
||||
}
|
||||
let mut rd = self.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(xdg) = rd.deref_mut() {
|
||||
let extents = SurfaceExtents {
|
||||
x1: req.x,
|
||||
y1: req.y,
|
||||
x2: req.x + req.width,
|
||||
y2: req.y + req.height,
|
||||
};
|
||||
xdg.pending.extents.set(Some(extents));
|
||||
}
|
||||
let extents = Rect::new_sized(req.x, req.y, req.width, req.height).unwrap();
|
||||
self.pending.geometry.set(Some(extents));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> {
|
||||
fn ack_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), AckConfigureError> {
|
||||
let req: AckConfigure = self.surface.client.parse(self, parser)?;
|
||||
let mut rd = self.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(xdg) = rd.deref_mut() {
|
||||
if xdg.requested_serial == req.serial {
|
||||
xdg.acked_serial = Some(xdg.requested_serial);
|
||||
}
|
||||
if self.requested_serial.get() == req.serial {
|
||||
self.acked_serial.set(Some(req.serial));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_request_(
|
||||
fn handle_request_(
|
||||
self: &Rc<Self>,
|
||||
request: u32,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), XdgSurfaceError> {
|
||||
match request {
|
||||
DESTROY => self.destroy(parser).await?,
|
||||
GET_TOPLEVEL => self.get_toplevel(parser).await?,
|
||||
GET_POPUP => self.get_popup(parser).await?,
|
||||
SET_WINDOW_GEOMETRY => self.set_window_geometry(parser).await?,
|
||||
ACK_CONFIGURE => self.ack_configure(parser).await?,
|
||||
DESTROY => self.destroy(parser)?,
|
||||
GET_TOPLEVEL => self.get_toplevel(parser)?,
|
||||
GET_POPUP => self.get_popup(parser)?,
|
||||
SET_WINDOW_GEOMETRY => self.set_window_geometry(parser)?,
|
||||
ACK_CONFIGURE => self.ack_configure(parser)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_extents(&self) {
|
||||
let old_extents = self.extents.get();
|
||||
let mut new_extents = self.surface.extents.get();
|
||||
if let Some(geometry) = self.geometry.get() {
|
||||
new_extents = new_extents.intersect(geometry);
|
||||
}
|
||||
self.extents.set(new_extents);
|
||||
if old_extents != new_extents {
|
||||
if let Some(ext) = self.ext.get() {
|
||||
ext.extents_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle_request!(XdgSurface);
|
||||
|
|
@ -237,3 +235,40 @@ impl Object for XdgSurface {
|
|||
ACK_CONFIGURE + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl SurfaceExt for XdgSurface {
|
||||
fn pre_commit(self: Rc<Self>, _ctx: CommitContext) -> CommitAction {
|
||||
{
|
||||
let ase = self.acked_serial.get();
|
||||
let rse = self.requested_serial.get();
|
||||
if ase != Some(rse) {
|
||||
if ase.is_none() {
|
||||
self.surface.client.event(self.configure(rse));
|
||||
}
|
||||
// return CommitAction::AbortCommit;
|
||||
}
|
||||
}
|
||||
if let Some(geometry) = self.pending.geometry.take() {
|
||||
self.geometry.set(Some(geometry));
|
||||
self.update_extents();
|
||||
}
|
||||
CommitAction::ContinueCommit
|
||||
}
|
||||
|
||||
fn post_commit(&self) {
|
||||
if let Some(ext) = self.ext.get() {
|
||||
ext.post_commit();
|
||||
}
|
||||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
self.update_extents();
|
||||
}
|
||||
|
||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
||||
match self.ext.get() {
|
||||
Some(e) => e.into_node(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::client::{ClientError, EventFormatter, RequestParser};
|
|||
use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopupId;
|
||||
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevelId;
|
||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceId, CONFIGURE};
|
||||
use crate::ifs::wl_surface::{SurfaceRole, WlSurfaceId};
|
||||
use crate::ifs::wl_surface::{WlSurfaceError, WlSurfaceId};
|
||||
use crate::ifs::xdg_positioner::XdgPositionerId;
|
||||
use crate::object::Object;
|
||||
use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError};
|
||||
|
|
@ -22,11 +22,12 @@ pub enum XdgSurfaceError {
|
|||
SetWindowGeometryError(#[from] SetWindowGeometryError),
|
||||
#[error("Could not process `ack_configure` request")]
|
||||
AckConfigureError(#[from] AckConfigureError),
|
||||
#[error("Surface {0} cannot be turned into a xdg_surface because it already has the role {}", .1.name())]
|
||||
IncompatibleRole(WlSurfaceId, SurfaceRole),
|
||||
#[error("Surface {0} cannot be turned into a xdg_surface because it already has an attached xdg_surface")]
|
||||
AlreadyAttached(WlSurfaceId),
|
||||
#[error(transparent)]
|
||||
WlSurfaceError(Box<WlSurfaceError>),
|
||||
}
|
||||
efrom!(XdgSurfaceError, WlSurfaceError, WlSurfaceError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DestroyError {
|
||||
|
|
@ -46,13 +47,14 @@ pub enum GetToplevelError {
|
|||
ParseFailed(#[source] Box<MsgParserError>),
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error("The surface already has a different role")]
|
||||
IncompatibleRole,
|
||||
#[error("The surface already has an assigned xdg_toplevel")]
|
||||
AlreadyConstructed,
|
||||
#[error(transparent)]
|
||||
WlSurfaceError(Box<WlSurfaceError>),
|
||||
}
|
||||
efrom!(GetToplevelError, ParseFailed, MsgParserError);
|
||||
efrom!(GetToplevelError, ClientError, ClientError);
|
||||
efrom!(GetToplevelError, WlSurfaceError, WlSurfaceError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GetPopupError {
|
||||
|
|
@ -60,13 +62,14 @@ pub enum GetPopupError {
|
|||
ParseFailed(#[source] Box<MsgParserError>),
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error("The surface already has a different role")]
|
||||
IncompatibleRole,
|
||||
#[error("The surface already has an assigned xdg_popup")]
|
||||
AlreadyConstructed,
|
||||
#[error(transparent)]
|
||||
WlSurfaceError(Box<WlSurfaceError>),
|
||||
}
|
||||
efrom!(GetPopupError, ParseFailed, MsgParserError);
|
||||
efrom!(GetPopupError, ClientError, ClientError);
|
||||
efrom!(GetPopupError, WlSurfaceError, WlSurfaceError);
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SetWindowGeometryError {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
mod types;
|
||||
|
||||
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
|
||||
use crate::ifs::wl_surface::{RoleData, XdgSurfaceRoleData};
|
||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceExt};
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::tree::{Node, NodeId};
|
||||
use crate::utils::buffd::MsgParser;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
|
||||
|
|
@ -18,59 +19,55 @@ const REPOSITIONED: u32 = 2;
|
|||
#[allow(dead_code)]
|
||||
const INVALID_GRAB: u32 = 1;
|
||||
|
||||
tree_id!(PopupId);
|
||||
id!(XdgPopupId);
|
||||
|
||||
pub struct XdgPopup {
|
||||
id: XdgPopupId,
|
||||
node_id: PopupId,
|
||||
pub(in super::super) surface: Rc<XdgSurface>,
|
||||
pub(super) parent: CloneCell<Option<Rc<XdgSurface>>>,
|
||||
}
|
||||
|
||||
impl XdgPopup {
|
||||
pub fn new(id: XdgPopupId, surface: &Rc<XdgSurface>) -> Self {
|
||||
pub fn new(id: XdgPopupId, surface: &Rc<XdgSurface>, parent: Option<&Rc<XdgSurface>>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
node_id: surface.surface.client.state.node_ids.next(),
|
||||
surface: surface.clone(),
|
||||
parent: CloneCell::new(parent.cloned()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
let _req: Destroy = self.surface.surface.client.parse(self, parser)?;
|
||||
{
|
||||
let mut rd = self.surface.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(xdg) = &mut *rd {
|
||||
if let XdgSurfaceRoleData::Popup(p) = &xdg.role_data {
|
||||
if let Some(p) = &p.parent {
|
||||
let mut rd = p.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(xdg) = &mut *rd {
|
||||
xdg.popups.remove(&self.surface.surface.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
xdg.role_data = XdgSurfaceRoleData::None;
|
||||
if let Some(parent) = self.parent.take() {
|
||||
parent.popups.remove(&self.id);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn grab(&self, parser: MsgParser<'_, '_>) -> Result<(), GrabError> {
|
||||
fn grab(&self, parser: MsgParser<'_, '_>) -> Result<(), GrabError> {
|
||||
let _req: Grab = self.surface.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn reposition(&self, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> {
|
||||
fn reposition(&self, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> {
|
||||
let _req: Reposition = self.surface.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_request_(
|
||||
fn handle_request_(
|
||||
&self,
|
||||
request: u32,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), XdgPopupError> {
|
||||
match request {
|
||||
DESTROY => self.destroy(parser).await?,
|
||||
GRAB => self.grab(parser).await?,
|
||||
REPOSITION => self.reposition(parser).await?,
|
||||
DESTROY => self.destroy(parser)?,
|
||||
GRAB => self.grab(parser)?,
|
||||
REPOSITION => self.reposition(parser)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -92,3 +89,11 @@ impl Object for XdgPopup {
|
|||
REPOSITION + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for XdgPopup {
|
||||
fn id(&self) -> NodeId {
|
||||
self.node_id.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl XdgSurfaceExt for XdgPopup {}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,21 @@
|
|||
mod types;
|
||||
|
||||
use crate::ifs::wl_surface::xdg_surface::XdgSurface;
|
||||
use crate::ifs::wl_surface::{RoleData, XdgSurfaceRoleData};
|
||||
use crate::client::DynEventFormatter;
|
||||
use crate::fixed::Fixed;
|
||||
use crate::ifs::wl_seat::WlSeatGlobal;
|
||||
use crate::ifs::wl_surface::wl_subsurface::WlSubsurface;
|
||||
use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceExt};
|
||||
use crate::object::{Interface, Object, ObjectId};
|
||||
use crate::rect::Rect;
|
||||
use crate::render::Renderer;
|
||||
use crate::tree::ContainerNode;
|
||||
use crate::tree::{FloatNode, FoundNode, Node, NodeId, ToplevelNodeId, WorkspaceNode};
|
||||
use crate::utils::buffd::MsgParser;
|
||||
use crate::utils::clonecell::CloneCell;
|
||||
use ahash::{AHashMap, AHashSet};
|
||||
use num_derive::FromPrimitive;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
pub use types::*;
|
||||
|
|
@ -60,130 +71,245 @@ const STATE_TILED_BOTTOM: u32 = 8;
|
|||
id!(XdgToplevelId);
|
||||
|
||||
pub struct XdgToplevel {
|
||||
id: XdgToplevelId,
|
||||
pub surface: Rc<XdgSurface>,
|
||||
pub id: XdgToplevelId,
|
||||
pub xdg: Rc<XdgSurface>,
|
||||
pub node_id: ToplevelNodeId,
|
||||
pub parent_node: CloneCell<Option<Rc<dyn Node>>>,
|
||||
pub parent: CloneCell<Option<Rc<XdgToplevel>>>,
|
||||
pub children: RefCell<AHashMap<XdgToplevelId, Rc<XdgToplevel>>>,
|
||||
pub focus_subsurface: CloneCell<Option<Rc<WlSubsurface>>>,
|
||||
states: RefCell<AHashSet<u32>>,
|
||||
}
|
||||
|
||||
impl XdgToplevel {
|
||||
pub fn new(id: XdgToplevelId, surface: &Rc<XdgSurface>) -> Self {
|
||||
let mut states = AHashSet::new();
|
||||
states.insert(STATE_TILED_LEFT);
|
||||
states.insert(STATE_TILED_RIGHT);
|
||||
states.insert(STATE_TILED_TOP);
|
||||
states.insert(STATE_TILED_BOTTOM);
|
||||
Self {
|
||||
id,
|
||||
surface: surface.clone(),
|
||||
xdg: surface.clone(),
|
||||
node_id: surface.surface.client.state.node_ids.next(),
|
||||
parent_node: Default::default(),
|
||||
parent: Default::default(),
|
||||
children: RefCell::new(Default::default()),
|
||||
focus_subsurface: Default::default(),
|
||||
states: RefCell::new(states),
|
||||
}
|
||||
}
|
||||
|
||||
async fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
let _req: Destroy = self.surface.surface.client.parse(self, parser)?;
|
||||
pub fn parent_is_float(&self) -> bool {
|
||||
if let Some(parent) = self.parent_node.get() {
|
||||
return parent.is_float();
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn configure(self: &Rc<Self>, width: i32, height: i32) -> DynEventFormatter {
|
||||
Box::new(Configure {
|
||||
obj: self.clone(),
|
||||
width,
|
||||
height,
|
||||
states: self.states.borrow().iter().copied().collect(),
|
||||
})
|
||||
}
|
||||
|
||||
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> {
|
||||
let _req: Destroy = self.xdg.surface.client.parse(self, parser)?;
|
||||
self.xdg.ext.set(None);
|
||||
if let Some(parent) = self.parent_node.take() {
|
||||
parent.remove_child(self);
|
||||
}
|
||||
{
|
||||
let mut rd = self.surface.surface.role_data.borrow_mut();
|
||||
if let RoleData::XdgSurface(rd) = &mut *rd {
|
||||
rd.role_data = XdgSurfaceRoleData::None;
|
||||
let mut children = self.children.borrow_mut();
|
||||
for (_, child) in children.drain() {
|
||||
child.parent.set(self.parent.get());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_parent(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentError> {
|
||||
let _req: SetParent = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_parent(&self, parser: MsgParser<'_, '_>) -> Result<(), SetParentError> {
|
||||
let _req: SetParent = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_title(&self, parser: MsgParser<'_, '_>) -> Result<(), SetTitleError> {
|
||||
let _req: SetTitle = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_title(&self, parser: MsgParser<'_, '_>) -> Result<(), SetTitleError> {
|
||||
let _req: SetTitle = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_app_id(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAppIdError> {
|
||||
let _req: SetAppId = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_app_id(&self, parser: MsgParser<'_, '_>) -> Result<(), SetAppIdError> {
|
||||
let _req: SetAppId = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn show_window_menu(&self, parser: MsgParser<'_, '_>) -> Result<(), ShowWindowMenuError> {
|
||||
let _req: ShowWindowMenu = self.surface.surface.client.parse(self, parser)?;
|
||||
fn show_window_menu(&self, parser: MsgParser<'_, '_>) -> Result<(), ShowWindowMenuError> {
|
||||
let _req: ShowWindowMenu = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn move_(&self, parser: MsgParser<'_, '_>) -> Result<(), MoveError> {
|
||||
let req: Move = self.surface.surface.client.parse(self, parser)?;
|
||||
let rd = self.surface.surface.role_data.borrow();
|
||||
if let RoleData::XdgSurface(xdg) = rd.deref() {
|
||||
if let XdgSurfaceRoleData::Toplevel(tl) = &xdg.role_data {
|
||||
if let Some(node) = tl.node.as_ref() {
|
||||
let seat = self.surface.surface.client.get_wl_seat(req.seat)?;
|
||||
seat.move_(&node.node);
|
||||
}
|
||||
fn move_(&self, parser: MsgParser<'_, '_>) -> Result<(), MoveError> {
|
||||
let req: Move = self.xdg.surface.client.parse(self, parser)?;
|
||||
let seat = self.xdg.surface.client.get_wl_seat(req.seat)?;
|
||||
if let Some(parent) = self.parent_node.get() {
|
||||
if let Some(float) = parent.into_float() {
|
||||
seat.move_(&float);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> {
|
||||
let _req: Resize = self.surface.surface.client.parse(self, parser)?;
|
||||
fn resize(&self, parser: MsgParser<'_, '_>) -> Result<(), ResizeError> {
|
||||
let _req: Resize = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_max_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaxSizeError> {
|
||||
let _req: SetMaxSize = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_max_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaxSizeError> {
|
||||
let _req: SetMaxSize = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_min_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinSizeError> {
|
||||
let _req: SetMinSize = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_min_size(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinSizeError> {
|
||||
let _req: SetMinSize = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaximizedError> {
|
||||
let _req: SetMaximized = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMaximizedError> {
|
||||
let _req: SetMaximized = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn unset_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), UnsetMaximizedError> {
|
||||
let _req: UnsetMaximized = self.surface.surface.client.parse(self, parser)?;
|
||||
fn unset_maximized(&self, parser: MsgParser<'_, '_>) -> Result<(), UnsetMaximizedError> {
|
||||
let _req: UnsetMaximized = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_fullscreen(&self, parser: MsgParser<'_, '_>) -> Result<(), SetFullscreenError> {
|
||||
let _req: SetFullscreen = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_fullscreen(&self, parser: MsgParser<'_, '_>) -> Result<(), SetFullscreenError> {
|
||||
let _req: SetFullscreen = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn unset_fullscreen(
|
||||
&self,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), UnsetFullscreenError> {
|
||||
let _req: UnsetFullscreen = self.surface.surface.client.parse(self, parser)?;
|
||||
fn unset_fullscreen(&self, parser: MsgParser<'_, '_>) -> Result<(), UnsetFullscreenError> {
|
||||
let _req: UnsetFullscreen = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_minimized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinimizedError> {
|
||||
let _req: SetMinimized = self.surface.surface.client.parse(self, parser)?;
|
||||
fn set_minimized(&self, parser: MsgParser<'_, '_>) -> Result<(), SetMinimizedError> {
|
||||
let _req: SetMinimized = self.xdg.surface.client.parse(self, parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_request_(
|
||||
fn handle_request_(
|
||||
&self,
|
||||
request: u32,
|
||||
parser: MsgParser<'_, '_>,
|
||||
) -> Result<(), XdgToplevelError> {
|
||||
match request {
|
||||
DESTROY => self.destroy(parser).await?,
|
||||
SET_PARENT => self.set_parent(parser).await?,
|
||||
SET_TITLE => self.set_title(parser).await?,
|
||||
SET_APP_ID => self.set_app_id(parser).await?,
|
||||
SHOW_WINDOW_MENU => self.show_window_menu(parser).await?,
|
||||
MOVE => self.move_(parser).await?,
|
||||
RESIZE => self.resize(parser).await?,
|
||||
SET_MAX_SIZE => self.set_max_size(parser).await?,
|
||||
SET_MIN_SIZE => self.set_min_size(parser).await?,
|
||||
SET_MAXIMIZED => self.set_maximized(parser).await?,
|
||||
UNSET_MAXIMIZED => self.unset_maximized(parser).await?,
|
||||
SET_FULLSCREEN => self.set_fullscreen(parser).await?,
|
||||
UNSET_FULLSCREEN => self.unset_fullscreen(parser).await?,
|
||||
SET_MINIMIZED => self.set_minimized(parser).await?,
|
||||
DESTROY => self.destroy(parser)?,
|
||||
SET_PARENT => self.set_parent(parser)?,
|
||||
SET_TITLE => self.set_title(parser)?,
|
||||
SET_APP_ID => self.set_app_id(parser)?,
|
||||
SHOW_WINDOW_MENU => self.show_window_menu(parser)?,
|
||||
MOVE => self.move_(parser)?,
|
||||
RESIZE => self.resize(parser)?,
|
||||
SET_MAX_SIZE => self.set_max_size(parser)?,
|
||||
SET_MIN_SIZE => self.set_min_size(parser)?,
|
||||
SET_MAXIMIZED => self.set_maximized(parser)?,
|
||||
UNSET_MAXIMIZED => self.unset_maximized(parser)?,
|
||||
SET_FULLSCREEN => self.set_fullscreen(parser)?,
|
||||
UNSET_FULLSCREEN => self.unset_fullscreen(parser)?,
|
||||
SET_MINIMIZED => self.set_minimized(parser)?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map_child(self: &Rc<Self>, parent: &XdgToplevel) {
|
||||
let workspace = match parent.get_workspace() {
|
||||
Some(w) => w,
|
||||
_ => return self.map_tiled(),
|
||||
};
|
||||
let output = workspace.output.get();
|
||||
let output_rect = output.position.get();
|
||||
let position = {
|
||||
let extents = self.xdg.extents.get().to_origin();
|
||||
let width = extents.width();
|
||||
let height = extents.height();
|
||||
let mut x1 = output_rect.x1();
|
||||
let mut y1 = output_rect.y1();
|
||||
if width < output_rect.width() {
|
||||
x1 += (output_rect.width() - width) as i32 / 2;
|
||||
}
|
||||
if height < output_rect.height() {
|
||||
y1 += (output_rect.height() - height) as i32 / 2;
|
||||
}
|
||||
Rect::new_sized(x1, y1, width, height).unwrap()
|
||||
};
|
||||
let state = &self.xdg.surface.client.state;
|
||||
let floater = Rc::new(FloatNode {
|
||||
id: state.node_ids.next(),
|
||||
visible: Cell::new(true),
|
||||
position: Cell::new(position),
|
||||
display: output.display.clone(),
|
||||
display_link: Cell::new(None),
|
||||
workspace_link: Cell::new(None),
|
||||
workspace: CloneCell::new(workspace.clone()),
|
||||
child: CloneCell::new(Some(self.clone())),
|
||||
});
|
||||
self.parent_node.set(Some(floater.clone()));
|
||||
floater
|
||||
.display_link
|
||||
.set(Some(state.root.floaters.add_last(floater.clone())));
|
||||
floater
|
||||
.workspace_link
|
||||
.set(Some(workspace.floaters.add_last(floater.clone())));
|
||||
}
|
||||
|
||||
fn map_tiled(self: &Rc<Self>) {
|
||||
log::info!("mapping tiled");
|
||||
let state = &self.xdg.surface.client.state;
|
||||
let seat = state.seat_queue.last();
|
||||
if let Some(seat) = seat {
|
||||
if let Some(prev) = seat.last_tiled_keyboard_toplevel() {
|
||||
if let Some(container) = prev.parent_node.get() {
|
||||
if let Some(container) = container.into_container() {
|
||||
container.add_child_after(&*prev, self.clone());
|
||||
self.parent_node.set(Some(container));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let output = {
|
||||
let outputs = state.root.outputs.lock();
|
||||
outputs.values().next().cloned()
|
||||
};
|
||||
if let Some(output) = output {
|
||||
if let Some(workspace) = output.workspace.get() {
|
||||
if let Some(container) = workspace.container.get() {
|
||||
container.append_child(self.clone());
|
||||
self.parent_node.set(Some(container));
|
||||
} else {
|
||||
let container =
|
||||
Rc::new(ContainerNode::new(state, workspace.clone(), self.clone()));
|
||||
workspace.set_container(&container);
|
||||
self.parent_node.set(Some(container));
|
||||
};
|
||||
return;
|
||||
}
|
||||
}
|
||||
todo!("map_tiled");
|
||||
}
|
||||
|
||||
fn get_workspace(&self) -> Option<Rc<WorkspaceNode>> {
|
||||
match self.parent_node.get() {
|
||||
Some(node) => node.get_workspace(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle_request!(XdgToplevel);
|
||||
|
|
@ -200,4 +326,101 @@ impl Object for XdgToplevel {
|
|||
fn num_requests(&self) -> u32 {
|
||||
SET_MINIMIZED + 1
|
||||
}
|
||||
|
||||
fn break_loops(&self) {
|
||||
if let Some(parent) = self.parent_node.take() {
|
||||
parent.remove_child(self);
|
||||
}
|
||||
self.parent.set(None);
|
||||
let _children = mem::take(&mut *self.children.borrow_mut());
|
||||
self.focus_subsurface.set(None);
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for XdgToplevel {
|
||||
fn id(&self) -> NodeId {
|
||||
self.node_id.into()
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
self.parent_node.set(None);
|
||||
}
|
||||
|
||||
fn find_child_at(&self, mut x: i32, mut y: i32) -> Option<FoundNode> {
|
||||
if let Some(geo) = self.xdg.geometry.get() {
|
||||
let (xt, yt) = geo.translate_inv(x, y);
|
||||
x = xt;
|
||||
y = yt;
|
||||
}
|
||||
match self.xdg.surface.find_surface_at(x, y) {
|
||||
Some((node, x, y)) => Some(FoundNode {
|
||||
node: if std::ptr::eq(node.deref(), self.xdg.surface.deref()) {
|
||||
node
|
||||
} else {
|
||||
node.ext.get().into_node().unwrap()
|
||||
},
|
||||
x,
|
||||
y,
|
||||
contained: true,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&self, renderer: &mut dyn Renderer, x: i32, y: i32) {
|
||||
renderer.render_toplevel(self, x, y)
|
||||
}
|
||||
|
||||
fn get_workspace(self: Rc<Self>) -> Option<Rc<WorkspaceNode>> {
|
||||
self.deref().get_workspace()
|
||||
}
|
||||
|
||||
fn enter(self: Rc<Self>, seat: &WlSeatGlobal, _x: Fixed, _y: Fixed) {
|
||||
seat.enter_toplevel(&self);
|
||||
}
|
||||
|
||||
fn change_size(self: Rc<Self>, width: i32, height: i32) {
|
||||
self.xdg.surface.client.event(self.configure(width, height));
|
||||
self.xdg.send_configure();
|
||||
self.xdg.surface.client.flush();
|
||||
}
|
||||
}
|
||||
|
||||
impl XdgSurfaceExt for XdgToplevel {
|
||||
fn post_commit(self: Rc<Self>) {
|
||||
let surface = &self.xdg.surface;
|
||||
if let Some(parent) = self.parent_node.get() {
|
||||
if surface.buffer.get().is_none() {
|
||||
parent.remove_child(&*self);
|
||||
{
|
||||
let new_parent = self.parent.get();
|
||||
let mut children = self.children.borrow_mut();
|
||||
for (_, child) in children.drain() {
|
||||
child.parent.set(new_parent.clone());
|
||||
}
|
||||
}
|
||||
surface.client.state.tree_changed();
|
||||
}
|
||||
} else if surface.buffer.get().is_some() {
|
||||
if let Some(parent) = self.parent.get() {
|
||||
self.map_child(&parent);
|
||||
} else {
|
||||
self.map_tiled();
|
||||
}
|
||||
self.extents_changed();
|
||||
surface.client.state.tree_changed();
|
||||
}
|
||||
}
|
||||
|
||||
fn extents_changed(&self) {
|
||||
if let Some(parent) = self.parent_node.get() {
|
||||
let extents = self.xdg.extents.get();
|
||||
parent.child_size_changed(self, extents.width(), extents.height());
|
||||
self.xdg.surface.client.state.tree_changed();
|
||||
}
|
||||
}
|
||||
|
||||
fn into_node(self: Rc<Self>) -> Option<Rc<dyn Node>> {
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue