use std::ops;
use std::vec::Vec;
use crate::logging;
use crate::main;
use crate::util::DivCeil;
use crate::logging::Warn;
pub mod c {
use super::*;
use std::os::raw::{ c_char, c_void };
use std::ptr;
use crate::util::c::{COpaquePtr, Wrapped};
#[repr(transparent)]
#[derive(Clone, PartialEq, Copy, Debug, Eq, Hash)]
pub struct WlOutput(*const c_void);
impl WlOutput {
const fn null() -> Self {
Self(ptr::null())
}
#[cfg(test)]
pub const fn dummy() -> Self {
Self::null()
}
}
#[repr(C)]
struct WlOutputListener<T: COpaquePtr> {
geometry: extern fn(
T, WlOutput,
i32, i32, i32, i32, i32, *const c_char, *const c_char, i32, ),
mode: extern fn(
T, WlOutput,
u32, i32, i32, i32, ),
done: extern fn(
T, WlOutput,
),
scale: extern fn(
T, WlOutput,
i32, ),
}
bitflags!{
pub struct Mode: u32 {
const NONE = 0x0;
const CURRENT = 0x1;
const PREFERRED = 0x2;
}
}
#[derive(Clone, Copy, Debug)]
pub enum Transform {
Normal = 0,
Rotated90 = 1,
Rotated180 = 2,
Rotated270 = 3,
Flipped = 4,
FlippedRotated90 = 5,
FlippedRotated180 = 6,
FlippedRotated270 = 7,
}
impl Transform {
fn from_u32(v: u32) -> Option<Transform> {
use self::Transform::*;
match v {
0 => Some(Normal),
1 => Some(Rotated90),
2 => Some(Rotated180),
3 => Some(Rotated270),
4 => Some(Flipped),
5 => Some(FlippedRotated90),
6 => Some(FlippedRotated180),
7 => Some(FlippedRotated270),
_ => None,
}
}
}
extern "C" {
#[allow(improper_ctypes)]
fn squeek_output_add_listener(
wl_output: WlOutput,
listener: *const WlOutputListener<COutputs>,
data: COutputs,
) -> i32;
}
type COutputs = Wrapped<Outputs>;
extern fn outputs_handle_geometry(
outputs: COutputs,
wl_output: WlOutput,
_x: i32, _y: i32,
phys_width: i32, phys_height: i32,
_subpixel: i32,
_make: *const c_char, _model: *const c_char,
transform: i32,
) {
let transform = Transform::from_u32(transform as u32)
.or_print(
logging::Problem::Warning,
"Received invalid wl_output.transform value",
).unwrap_or(Transform::Normal);
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output_state: Option<&mut OutputState>
= collection
.find_output_mut(wl_output)
.map(|o| &mut o.pending);
match output_state {
Some(state) => {
fn maybe_mm(value: i32) -> Option<Millimeter> {
if value == 0 { None }
else { Some(Millimeter(value)) }
}
state.geometry = Some(Geometry {
phys_size: Size {
width: maybe_mm(phys_width),
height: maybe_mm(phys_height),
},
transform,
});
},
None => log_print!(
logging::Level::Warning,
"Got geometry on unknown output",
),
};
}
extern fn outputs_handle_mode(
outputs: COutputs,
wl_output: WlOutput,
flags: u32,
width: i32,
height: i32,
_refresh: i32,
) {
let flags = Mode::from_bits(flags)
.or_print(
logging::Problem::Warning,
"Received invalid wl_output.mode flags",
).unwrap_or(Mode::NONE);
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output_state: Option<&mut OutputState>
= collection
.find_output_mut(wl_output)
.map(|o| &mut o.pending);
match output_state {
Some(state) => {
if flags.contains(Mode::CURRENT) {
state.current_mode = Some(super::Mode { width, height});
}
},
None => log_print!(
logging::Level::Warning,
"Got mode on unknown output",
),
};
}
extern fn outputs_handle_done(
outputs: COutputs,
wl_output: WlOutput,
) {
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output = collection
.find_output_mut(wl_output);
let event = match output {
Some(output) => {
output.current = output.pending.clone();
Some(Event {
output: OutputId(wl_output),
change: ChangeType::Altered(output.current),
})
},
None => {
log_print!(
logging::Level::Warning,
"Got done on unknown output",
);
None
}
};
if let Some(event) = event {
collection.send_event(event);
}
}
extern fn outputs_handle_scale(
outputs: COutputs,
wl_output: WlOutput,
factor: i32,
) {
let outputs = outputs.clone_ref();
let mut collection = outputs.borrow_mut();
let output_state: Option<&mut OutputState>
= collection
.find_output_mut(wl_output)
.map(|o| &mut o.pending);
match output_state {
Some(state) => { state.scale = factor; }
None => log_print!(
logging::Level::Warning,
"Got scale on unknown output",
),
};
}
#[no_mangle]
pub extern "C"
fn squeek_outputs_free(outputs: COutputs) {
unsafe { outputs.unwrap() }; }
#[no_mangle]
pub extern "C"
fn squeek_outputs_register(raw_collection: COutputs, output: WlOutput, id: u32) {
let collection = raw_collection.clone_ref();
let mut collection = collection.borrow_mut();
collection.outputs.push((
Output {
output: output.clone(),
pending: OutputState::uninitialized(),
current: OutputState::uninitialized(),
},
id,
));
unsafe { squeek_output_add_listener(
output,
&WlOutputListener {
geometry: outputs_handle_geometry,
mode: outputs_handle_mode,
done: outputs_handle_done,
scale: outputs_handle_scale,
} as *const WlOutputListener<COutputs>,
raw_collection,
)};
}
#[no_mangle]
pub extern "C"
fn squeek_outputs_try_unregister(raw_collection: COutputs, id: u32) -> WlOutput {
let collection = raw_collection.clone_ref();
let mut collection = collection.borrow_mut();
collection.remove_output_by_global(id)
.map_err(|e| log_print!(
logging::Level::Debug,
"Tried to remove global {:x} but it is not registered as an output: {:?}",
id, e,
))
.unwrap_or(WlOutput::null())
}
}
#[derive(Clone, Copy, Debug)]
pub struct Size<Unit> {
pub width: Unit,
pub height: Unit,
}
pub type PixelSize = Size<u32>;
#[derive(Clone, Copy, Debug)]
pub struct Mode {
pub width: i32,
pub height: i32,
}
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Millimeter(pub i32);
impl DivCeil<i32> for Millimeter {
type Output = Millimeter;
fn div_ceil(self, other: i32) -> Self {
Self(self.0.div_ceil(other))
}
}
impl ops::Mul<i32> for Millimeter {
type Output = Self;
fn mul(self, m: i32) -> Self {
Self(self.0 * m as i32)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Geometry {
pub transform: c::Transform,
pub phys_size: Size<Option<Millimeter>>,
}
#[derive(Clone, Copy, Debug)]
pub struct OutputState {
pub current_mode: Option<Mode>,
pub geometry: Option<Geometry>,
pub scale: i32,
}
impl OutputState {
fn uninitialized() -> OutputState {
OutputState {
current_mode: None,
geometry: None,
scale: 1,
}
}
fn transform_size<T>(
width: T,
height: T,
transform: self::c::Transform,
) -> Size<T> {
use self::c::Transform;
match transform {
Transform::Normal
| Transform::Rotated180
| Transform::Flipped
| Transform::FlippedRotated180 => Size {
width,
height,
},
_ => Size {
width: height,
height: width,
},
}
}
pub fn get_pixel_size(&self) -> Option<PixelSize> {
match self {
OutputState {
current_mode: Some(Mode { width, height } ),
geometry: Some(Geometry { transform, .. } ),
scale: _,
} => Some(Self::transform_size(*width as u32, *height as u32, *transform)),
OutputState {
current_mode: Some(Mode { width, height } ),
..
} => Some(PixelSize { width: *width as u32, height: *height as u32 } ),
_ => None,
}
}
pub fn get_physical_size(&self) -> Option<Size<Option<Millimeter>>> {
match self {
OutputState {
geometry: Some(Geometry { transform, phys_size } ),
..
} => Some(Self::transform_size(phys_size.width, phys_size.height, *transform)),
_ => None,
}
}
}
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash)]
pub struct OutputId(pub c::WlOutput);
unsafe impl Send for OutputId {}
struct Output {
output: c::WlOutput,
pending: OutputState,
current: OutputState,
}
#[derive(Debug)]
struct NotFound;
type GlobalId = u32;
pub struct Outputs {
outputs: Vec<(Output, GlobalId)>,
sender: main::EventLoop,
}
impl Outputs {
pub fn new(sender: main::EventLoop) -> Outputs {
Outputs {
outputs: Vec::new(),
sender,
}
}
fn send_event(&self, event: Event) {
self.sender.send(event.into()).unwrap()
}
fn remove_output_by_global(&mut self, id: GlobalId)
-> Result<c::WlOutput, NotFound>
{
let index = self.outputs.iter()
.position(|(_o, global_id)| *global_id == id);
if let Some(index) = index {
let (output, _id) = self.outputs.remove(index);
self.send_event(Event {
change: ChangeType::Removed,
output: OutputId(output.output),
});
Ok(output.output)
} else {
Err(NotFound)
}
}
fn find_output_mut(&mut self, wl_output: c::WlOutput)
-> Option<&mut Output>
{
self.outputs
.iter_mut()
.find_map(|(o, _global)|
if o.output == wl_output { Some(o) } else { None }
)
}
}
#[derive(Clone, Copy, Debug)]
pub enum ChangeType {
Altered(OutputState),
Removed,
}
#[derive(Clone, Copy, Debug)]
pub struct Event {
pub output: OutputId,
pub change: ChangeType,
}