Skip to content

Commit

Permalink
Merge pull request #185 from mahkoh/jorth/output-removal
Browse files Browse the repository at this point in the history
wayland: allow binding to removed outputs
  • Loading branch information
mahkoh authored Apr 25, 2024
2 parents 0605438 + c27bf4d commit 5b851ef
Show file tree
Hide file tree
Showing 16 changed files with 212 additions and 70 deletions.
21 changes: 19 additions & 2 deletions src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ pub trait Global: GlobalBase {
pub struct Globals {
next_name: NumCell<u32>,
registry: CopyHashMap<GlobalName, Rc<dyn Global>>,
removed: CopyHashMap<GlobalName, Rc<dyn Global>>,
pub outputs: CopyHashMap<GlobalName, Rc<WlOutputGlobal>>,
pub seats: CopyHashMap<GlobalName, Rc<WlSeatGlobal>>,
}
Expand All @@ -136,6 +137,7 @@ impl Globals {
let slf = Self {
next_name: NumCell::new(1),
registry: CopyHashMap::new(),
removed: CopyHashMap::new(),
outputs: Default::default(),
seats: Default::default(),
};
Expand Down Expand Up @@ -241,9 +243,17 @@ impl Globals {
Ok(global)
}

pub fn remove<T: WaylandGlobal>(&self, state: &State, global: &T) -> Result<(), GlobalsError> {
pub fn remove<T: RemovableWaylandGlobal>(
&self,
state: &State,
global: &T,
) -> Result<(), GlobalsError> {
let _global = self.take(global.name(), true)?;
global.remove(self);
let replacement = global.create_replacement();
assert_eq!(global.name(), replacement.name());
assert_eq!(global.interface().0, replacement.interface().0);
self.removed.set(global.name(), replacement);
self.broadcast(state, global.required_caps(), global.xwayland_only(), |r| {
r.send_global_remove(global.name())
});
Expand Down Expand Up @@ -295,7 +305,10 @@ impl Globals {
let res = if remove {
self.registry.remove(&name)
} else {
self.registry.get(&name)
match self.registry.get(&name) {
Some(res) => Some(res),
_ => self.removed.get(&name),
}
};
match res {
Some(g) => Ok(g),
Expand Down Expand Up @@ -330,3 +343,7 @@ pub trait WaylandGlobal: Global + 'static {
let _ = globals;
}
}

pub trait RemovableWaylandGlobal: WaylandGlobal {
fn create_replacement(&self) -> Rc<dyn Global>;
}
8 changes: 4 additions & 4 deletions src/ifs/ext_session_lock_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,20 @@ impl ExtSessionLockV1RequestHandler for ExtSessionLockV1 {
surface,
tracker: Default::default(),
serial: Default::default(),
output: output.global.node.get(),
output: output.global.clone(),
seat_state: Default::default(),
version: self.version,
});
track!(new.client, new);
new.install()?;
self.client.add_client_obj(&new)?;
if !output.global.destroyed.get() && !self.finished.get() {
if let Some(node) = output.global.node.get() {
if !self.finished.get() {
if let Some(node) = output.global.node() {
if node.lock_surface.is_some() {
return Err(ExtSessionLockV1Error::OutputAlreadyLocked);
}
node.set_lock_surface(Some(new.clone()));
let pos = output.global.pos.get();
let pos = node.global.pos.get();
new.change_extents(pos);
self.client.state.tree_changed();
}
Expand Down
6 changes: 3 additions & 3 deletions src/ifs/jay_compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use {
leaks::Tracker,
object::{Object, Version},
screenshoter::take_screenshot,
utils::{clonecell::CloneCell, errorfmt::ErrorFmt},
utils::errorfmt::ErrorFmt,
wire::{jay_compositor::*, JayCompositorId, JayScreenshotId},
},
bstr::ByteSlice,
Expand Down Expand Up @@ -264,12 +264,12 @@ impl JayCompositorRequestHandler for JayCompositor {
let jo = Rc::new(JayOutput {
id: req.id,
client: self.client.clone(),
output: CloneCell::new(output.global.node.get()),
output: output.global.clone(),
tracker: Default::default(),
});
track!(self.client, jo);
self.client.add_client_obj(&jo)?;
if let Some(node) = jo.output.get() {
if let Some(node) = jo.output.node() {
node.jay_outputs.set((self.client.id, req.id), jo.clone());
jo.send_linear_id();
} else {
Expand Down
9 changes: 4 additions & 5 deletions src/ifs/jay_output.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use {
crate::{
client::{Client, ClientError},
ifs::wl_output::OutputGlobalOpt,
leaks::Tracker,
object::{Object, Version},
tree::OutputNode,
utils::clonecell::CloneCell,
wire::{jay_output::*, JayOutputId},
},
std::rc::Rc,
Expand All @@ -14,7 +13,7 @@ use {
pub struct JayOutput {
pub id: JayOutputId,
pub client: Rc<Client>,
pub output: CloneCell<Option<Rc<OutputNode>>>,
pub output: Rc<OutputGlobalOpt>,
pub tracker: Tracker<Self>,
}

Expand All @@ -24,7 +23,7 @@ impl JayOutput {
}

pub fn send_linear_id(&self) {
if let Some(output) = self.output.get() {
if let Some(output) = self.output.node() {
self.client.event(LinearId {
self_id: self.id,
linear_id: output.id.raw(),
Expand All @@ -33,7 +32,7 @@ impl JayOutput {
}

fn remove_from_node(&self) {
if let Some(output) = self.output.get() {
if let Some(output) = self.output.node() {
output.jay_outputs.remove(&(self.client.id, self.id));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ifs/jay_screencast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ impl JayScreencastRequestHandler for JayScreencast {
if let Some(new) = target {
match new {
PendingTarget::Output(o) => {
let Some(o) = o.output.get() else {
let Some(o) = o.output.node() else {
self.do_destroy();
return Ok(());
};
Expand Down
74 changes: 57 additions & 17 deletions src/ifs/wl_output.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod removed_output;

use {
crate::{
backend,
Expand Down Expand Up @@ -55,13 +57,34 @@ pub struct WlOutputGlobal {
pub output_id: Rc<OutputId>,
pub mode: Cell<backend::Mode>,
pub modes: Vec<backend::Mode>,
pub node: CloneCell<Option<Rc<OutputNode>>>,
pub width_mm: i32,
pub height_mm: i32,
pub bindings: RefCell<AHashMap<ClientId, AHashMap<WlOutputId, Rc<WlOutput>>>>,
pub destroyed: Cell<bool>,
pub legacy_scale: Cell<u32>,
pub persistent: Rc<PersistentOutputState>,
pub opt: Rc<OutputGlobalOpt>,
}

#[derive(Default)]
pub struct OutputGlobalOpt {
pub global: CloneCell<Option<Rc<WlOutputGlobal>>>,
pub node: CloneCell<Option<Rc<OutputNode>>>,
}

impl OutputGlobalOpt {
pub fn get(&self) -> Option<Rc<WlOutputGlobal>> {
self.global.get()
}

pub fn node(&self) -> Option<Rc<OutputNode>> {
self.node.get()
}

pub fn clear(&self) {
self.node.take();
self.global.take();
}
}

pub struct PersistentOutputState {
Expand All @@ -80,7 +103,7 @@ pub struct OutputId {

impl WlOutputGlobal {
pub fn clear(&self) {
self.node.take();
self.opt.clear();
self.bindings.borrow_mut().clear();
}

Expand Down Expand Up @@ -110,13 +133,13 @@ impl WlOutputGlobal {
output_id: output_id.clone(),
mode: Cell::new(*mode),
modes,
node: Default::default(),
width_mm,
height_mm,
bindings: Default::default(),
destroyed: Cell::new(false),
legacy_scale: Cell::new(scale.round_up()),
persistent: persistent_state.clone(),
opt: Default::default(),
}
}

Expand Down Expand Up @@ -169,7 +192,7 @@ impl WlOutputGlobal {
version: Version,
) -> Result<(), WlOutputError> {
let obj = Rc::new(WlOutput {
global: self.clone(),
global: self.opt.clone(),
id,
xdg_outputs: Default::default(),
client: client.clone(),
Expand Down Expand Up @@ -208,13 +231,15 @@ impl WlOutputGlobal {

global_base!(WlOutputGlobal, WlOutput, WlOutputError);

const OUTPUT_VERSION: u32 = 4;

impl Global for WlOutputGlobal {
fn singleton(&self) -> bool {
false
}

fn version(&self) -> u32 {
4
OUTPUT_VERSION
}

fn break_loops(&self) {
Expand All @@ -225,7 +250,7 @@ impl Global for WlOutputGlobal {
dedicated_add_global!(WlOutputGlobal, outputs);

pub struct WlOutput {
pub global: Rc<WlOutputGlobal>,
pub global: Rc<OutputGlobalOpt>,
pub id: WlOutputId,
pub xdg_outputs: CopyHashMap<ZxdgOutputV1Id, Rc<ZxdgOutputV1>>,
client: Rc<Client>,
Expand All @@ -239,23 +264,29 @@ pub const SEND_NAME_SINCE: Version = Version(4);

impl WlOutput {
fn send_geometry(&self) {
let pos = self.global.pos.get();
let Some(global) = self.global.get() else {
return;
};
let pos = global.pos.get();
let event = Geometry {
self_id: self.id,
x: pos.x1(),
y: pos.y1(),
physical_width: self.global.width_mm,
physical_height: self.global.height_mm,
physical_width: global.width_mm,
physical_height: global.height_mm,
subpixel: SP_UNKNOWN,
make: &self.global.output_id.manufacturer,
model: &self.global.output_id.model,
transform: self.global.persistent.transform.get().to_wl(),
make: &global.output_id.manufacturer,
model: &global.output_id.model,
transform: global.persistent.transform.get().to_wl(),
};
self.client.event(event);
}

fn send_mode(&self) {
let mode = self.global.mode.get();
let Some(global) = self.global.get() else {
return;
};
let mode = global.mode.get();
let event = Mode {
self_id: self.id,
flags: MODE_CURRENT,
Expand All @@ -267,17 +298,23 @@ impl WlOutput {
}

fn send_scale(self: &Rc<Self>) {
let Some(global) = self.global.get() else {
return;
};
let event = Scale {
self_id: self.id,
factor: self.global.legacy_scale.get() as _,
factor: global.legacy_scale.get() as _,
};
self.client.event(event);
}

fn send_name(&self) {
let Some(global) = self.global.get() else {
return;
};
self.client.event(Name {
self_id: self.id,
name: &self.global.connector.name,
name: &global.connector.name,
});
}

Expand All @@ -287,12 +324,15 @@ impl WlOutput {
}

fn remove_binding(&self) {
if let Entry::Occupied(mut e) = self.global.bindings.borrow_mut().entry(self.client.id) {
let Some(global) = self.global.get() else {
return;
};
if let Entry::Occupied(mut e) = global.bindings.borrow_mut().entry(self.client.id) {
e.get_mut().remove(&self.id);
if e.get().is_empty() {
e.remove();
}
}
};
}
}

Expand Down
63 changes: 63 additions & 0 deletions src/ifs/wl_output/removed_output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName, RemovableWaylandGlobal},
ifs::wl_output::{WlOutput, WlOutputGlobal, OUTPUT_VERSION},
object::Version,
wire::WlOutputId,
},
std::rc::Rc,
thiserror::Error,
};

struct RemovedOutputGlobal {
name: GlobalName,
}

impl RemovedOutputGlobal {
fn bind_(
self: Rc<Self>,
id: WlOutputId,
client: &Rc<Client>,
version: Version,
) -> Result<(), RemovedOutputError> {
let obj = Rc::new(WlOutput {
global: Default::default(),
id,
xdg_outputs: Default::default(),
client: client.clone(),
version,
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}

global_base!(RemovedOutputGlobal, WlOutput, RemovedOutputError);

impl Global for RemovedOutputGlobal {
fn singleton(&self) -> bool {
false
}

fn version(&self) -> u32 {
OUTPUT_VERSION
}
}

simple_add_global!(RemovedOutputGlobal);

impl RemovableWaylandGlobal for WlOutputGlobal {
fn create_replacement(&self) -> Rc<dyn Global> {
Rc::new(RemovedOutputGlobal { name: self.name })
}
}

#[derive(Debug, Error)]
enum RemovedOutputError {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(RemovedOutputError, ClientError);
Loading

0 comments on commit 5b851ef

Please sign in to comment.