1
0
Fork 0
forked from wry/wry
wry/src/ifs/wl_output/mod.rs
2022-01-25 16:45:44 +01:00

249 lines
5.8 KiB
Rust

mod types;
use crate::backend::Output;
use crate::client::{Client, ClientId, DynEventFormatter, WlEvent};
use crate::globals::{Global, GlobalName};
use crate::object::{Interface, Object, ObjectId};
use crate::utils::buffd::MsgParser;
use crate::utils::copyhashmap::CopyHashMap;
use std::cell::Cell;
use std::iter;
use std::rc::Rc;
pub use types::*;
id!(WlOutputId);
const RELEASE: u32 = 0;
const GEOMETRY: u32 = 0;
const MODE: u32 = 1;
const DONE: u32 = 2;
const SCALE: u32 = 3;
const SP_UNKNOWN: i32 = 0;
#[allow(dead_code)]
const SP_NONE: i32 = 1;
#[allow(dead_code)]
const SP_HORIZONTAL_RGB: i32 = 2;
#[allow(dead_code)]
const SP_HORIZONTAL_BGR: i32 = 3;
#[allow(dead_code)]
const SP_VERTICAL_RGB: i32 = 4;
#[allow(dead_code)]
const SP_VERTICAL_BGR: i32 = 5;
const TF_NORMAL: i32 = 0;
#[allow(dead_code)]
const TF_90: i32 = 1;
#[allow(dead_code)]
const TF_180: i32 = 2;
#[allow(dead_code)]
const TF_270: i32 = 3;
#[allow(dead_code)]
const TF_FLIPPED: i32 = 4;
#[allow(dead_code)]
const TF_FLIPPED_90: i32 = 5;
#[allow(dead_code)]
const TF_FLIPPED_180: i32 = 6;
#[allow(dead_code)]
const TF_FLIPPED_270: i32 = 7;
const MODE_CURRENT: u32 = 1;
#[allow(dead_code)]
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>,
bindings: CopyHashMap<(ClientId, WlOutputId), Rc<WlOutputObj>>,
}
impl WlOutputGlobal {
pub fn new(name: GlobalName, output: &Rc<dyn Output>) -> Self {
Self {
name,
output: output.clone(),
x: Cell::new(0),
y: Cell::new(0),
width: Cell::new(output.width()),
height: Cell::new(output.height()),
bindings: Default::default(),
}
}
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;
if changed {
let bindings = self.bindings.lock();
for binding in bindings.values() {
let events = [
binding.geometry(),
binding.mode(),
binding.scale(),
binding.done(),
];
let events = events
.into_iter()
.map(|e| WlEvent::Event(e))
.chain(iter::once(WlEvent::Flush));
for event in events {
binding.client.event2(event);
}
}
}
}
fn bind_(
self: Rc<Self>,
id: WlOutputId,
client: &Rc<Client>,
version: u32,
) -> Result<(), WlOutputError> {
let obj = Rc::new(WlOutputObj {
global: self.clone(),
id,
client: client.clone(),
version,
});
client.add_client_obj(&obj)?;
self.bindings.set((client.id, id), obj.clone());
client.event(obj.geometry());
client.event(obj.mode());
if obj.send_scale() {
client.event(obj.scale());
}
if obj.send_done() {
client.event(obj.done());
}
Ok(())
}
}
bind!(WlOutputGlobal);
impl Global for WlOutputGlobal {
fn name(&self) -> GlobalName {
self.name
}
fn singleton(&self) -> bool {
false
}
fn interface(&self) -> Interface {
Interface::WlOutput
}
fn version(&self) -> u32 {
3
}
fn break_loops(&self) {
self.bindings.clear();
}
}
pub struct WlOutputObj {
global: Rc<WlOutputGlobal>,
id: WlOutputId,
client: Rc<Client>,
version: u32,
}
impl WlOutputObj {
fn send_done(&self) -> bool {
self.version >= 2
}
fn send_scale(&self) -> bool {
self.version >= 2
}
fn geometry(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Geometry {
obj: self.clone(),
x: 0,
y: 0,
physical_width: self.global.width.get() as _,
physical_height: self.global.height.get() as _,
subpixel: SP_UNKNOWN,
make: String::new(),
model: String::new(),
transform: TF_NORMAL,
})
}
fn mode(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Mode {
obj: self.clone(),
flags: MODE_CURRENT,
width: self.global.width.get() as _,
height: self.global.height.get() as _,
refresh: 60_000_000,
})
}
fn scale(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Scale {
obj: self.clone(),
factor: 1,
})
}
fn done(self: &Rc<Self>) -> DynEventFormatter {
Box::new(Done { obj: self.clone() })
}
fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> {
let _req: Release = self.client.parse(self, parser)?;
self.global.bindings.remove(&(self.client.id, self.id));
self.client.remove_obj(self)?;
Ok(())
}
fn handle_request_(
&self,
request: u32,
parser: MsgParser<'_, '_>,
) -> Result<(), WlOutputError> {
match request {
RELEASE => self.release(parser)?,
_ => unreachable!(),
}
Ok(())
}
}
handle_request!(WlOutputObj);
impl Object for WlOutputObj {
fn id(&self) -> ObjectId {
self.id.into()
}
fn interface(&self) -> Interface {
Interface::WlOutput
}
fn num_requests(&self) -> u32 {
if self.version < 3 {
0
} else {
RELEASE + 1
}
}
fn break_loops(&self) {
self.global.bindings.remove(&(self.client.id, self.id));
}
}