wayland.output: migrate to wayland_rs-0.20
This commit is contained in:
parent
b9cac1a373
commit
1140b484cd
|
@ -19,7 +19,7 @@
|
||||||
//! quickly encounter a panic.
|
//! quickly encounter a panic.
|
||||||
|
|
||||||
//pub mod compositor;
|
//pub mod compositor;
|
||||||
//pub mod output;
|
pub mod output;
|
||||||
//pub mod seat;
|
//pub mod seat;
|
||||||
pub mod shm;
|
pub mod shm;
|
||||||
//pub mod shell;
|
//pub mod shell;
|
||||||
|
|
|
@ -22,10 +22,11 @@
|
||||||
//! use wayland_server::protocol::wl_output;
|
//! use wayland_server::protocol::wl_output;
|
||||||
//!
|
//!
|
||||||
//! # fn main() {
|
//! # fn main() {
|
||||||
//! # let (display, mut event_loop) = wayland_server::create_display();
|
//! # let (mut display, event_loop) = wayland_server::Display::new();
|
||||||
//! // Insert the Output with given name and physical properties
|
//! // Insert the Output with given name and physical properties
|
||||||
//! let (output_state_token, _output_global) = Output::new(
|
//! let (output, _output_global) = Output::new(
|
||||||
//! &mut event_loop, // the event loop
|
//! &mut display, // the display
|
||||||
|
//! event_loop.token(), // the LoopToken
|
||||||
//! "output-0".into(), // the name of this output,
|
//! "output-0".into(), // the name of this output,
|
||||||
//! PhysicalProperties {
|
//! PhysicalProperties {
|
||||||
//! width: 200, // width in mm
|
//! width: 200, // width in mm
|
||||||
|
@ -37,33 +38,33 @@
|
||||||
//! None // insert a logger here
|
//! None // insert a logger here
|
||||||
//! );
|
//! );
|
||||||
//! // Now you can configure it
|
//! // Now you can configure it
|
||||||
//! {
|
//! output.change_current_state(
|
||||||
//! let output = event_loop.state().get_mut(&output_state_token);
|
//! Some(Mode { width: 1902, height: 1080, refresh: 60000 }), // the resolution mode,
|
||||||
//! // set the current state
|
//! Some(wl_output::Transform::Normal), // global screen transformation
|
||||||
//! output.change_current_state(
|
//! Some(1), // global screen scaling factor
|
||||||
//! Some(Mode { width: 1902, height: 1080, refresh: 60000 }), // the resolution mode,
|
//! );
|
||||||
//! Some(wl_output::Transform::Normal), // global screen transformation
|
//! // set the prefered mode
|
||||||
//! Some(1), // global screen scaling factor
|
//! output.set_preferred(Mode { width: 1920, height: 1080, refresh: 60000 });
|
||||||
//! );
|
//! // add other supported modes
|
||||||
//! // set the prefered mode
|
//! output.add_mode(Mode { width: 800, height: 600, refresh: 60000 });
|
||||||
//! output.set_preferred(Mode { width: 1920, height: 1080, refresh: 60000 });
|
//! output.add_mode(Mode { width: 1024, height: 768, refresh: 60000 });
|
||||||
//! // add other supported modes
|
|
||||||
//! output.add_mode(Mode { width: 800, height: 600, refresh: 60000 });
|
|
||||||
//! output.add_mode(Mode { width: 1024, height: 768, refresh: 60000 });
|
|
||||||
//! }
|
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use wayland_server::{Client, EventLoopHandle, Global, Liveness, Resource, StateToken};
|
use std::sync::{Arc, Mutex};
|
||||||
use wayland_server::protocol::wl_output;
|
|
||||||
|
use wayland_server::{Display, Global, LoopToken, NewResource, Resource};
|
||||||
|
use wayland_server::commons::{downcast_impl, Implementation};
|
||||||
|
use wayland_server::protocol::wl_output::{Event, Mode as WMode, Request, WlOutput};
|
||||||
|
pub use wayland_server::protocol::wl_output::{Subpixel, Transform};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
|
||||||
/// An output mode
|
/// An output mode
|
||||||
///
|
///
|
||||||
/// A possible combination of dimensions and refresh rate for an output.
|
/// A possible combination of dimensions and refresh rate for an output.
|
||||||
///
|
///
|
||||||
/// This should only describe the characteristics of the video driver,
|
/// This should only describe the characteristics of the video driver,
|
||||||
/// not taking into account any global scaling.
|
/// not taking into account any global scaling.
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct Mode {
|
pub struct Mode {
|
||||||
/// The width in pixels
|
/// The width in pixels
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
|
@ -82,68 +83,28 @@ pub struct PhysicalProperties {
|
||||||
/// The height in milimeters
|
/// The height in milimeters
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
/// The subpixel geometry
|
/// The subpixel geometry
|
||||||
pub subpixel: wl_output::Subpixel,
|
pub subpixel: Subpixel,
|
||||||
/// Textual representation of the manufacturer
|
/// Textual representation of the manufacturer
|
||||||
pub maker: String,
|
pub maker: String,
|
||||||
/// Textual representation of the model
|
/// Textual representation of the model
|
||||||
pub model: String,
|
pub model: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An output as seen by the clients
|
struct Inner {
|
||||||
///
|
|
||||||
/// This handle is stored in the events loop, and allows you to notify clients
|
|
||||||
/// about any change in the properties of this output.
|
|
||||||
pub struct Output {
|
|
||||||
name: String,
|
name: String,
|
||||||
log: ::slog::Logger,
|
log: ::slog::Logger,
|
||||||
instances: Vec<wl_output::WlOutput>,
|
instances: Vec<Resource<WlOutput>>,
|
||||||
physical: PhysicalProperties,
|
physical: PhysicalProperties,
|
||||||
location: (i32, i32),
|
location: (i32, i32),
|
||||||
transform: wl_output::Transform,
|
transform: Transform,
|
||||||
scale: i32,
|
scale: i32,
|
||||||
modes: Vec<Mode>,
|
modes: Vec<Mode>,
|
||||||
current_mode: Option<Mode>,
|
current_mode: Option<Mode>,
|
||||||
preferred_mode: Option<Mode>,
|
preferred_mode: Option<Mode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Inner {
|
||||||
/// Create a new output global with given name and physical properties
|
fn new_global(&mut self, output: Resource<WlOutput>) {
|
||||||
///
|
|
||||||
/// The global is directly registered into the eventloop, and this function
|
|
||||||
/// returns the state token allowing you to access it, as well as the global handle,
|
|
||||||
/// in case you whish to remove this global in the future.
|
|
||||||
pub fn new<L>(
|
|
||||||
evlh: &mut EventLoopHandle, name: String, physical: PhysicalProperties, logger: L
|
|
||||||
) -> (
|
|
||||||
StateToken<Output>,
|
|
||||||
Global<wl_output::WlOutput, StateToken<Output>>,
|
|
||||||
)
|
|
||||||
where
|
|
||||||
L: Into<Option<::slog::Logger>>,
|
|
||||||
{
|
|
||||||
let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "output_handler"));
|
|
||||||
|
|
||||||
info!(log, "Creating new wl_output"; "name" => &name);
|
|
||||||
|
|
||||||
let token = evlh.state().insert(Output {
|
|
||||||
name: name,
|
|
||||||
log: log,
|
|
||||||
instances: Vec::new(),
|
|
||||||
physical: physical,
|
|
||||||
location: (0, 0),
|
|
||||||
transform: wl_output::Transform::Normal,
|
|
||||||
scale: 1,
|
|
||||||
modes: Vec::new(),
|
|
||||||
current_mode: None,
|
|
||||||
preferred_mode: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
let global = evlh.register_global(3, output_bind, token.clone());
|
|
||||||
|
|
||||||
(token, global)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_global(&mut self, output: wl_output::WlOutput) {
|
|
||||||
trace!(self.log, "New global instanciated.");
|
trace!(self.log, "New global instanciated.");
|
||||||
|
|
||||||
if self.modes.is_empty() {
|
if self.modes.is_empty() {
|
||||||
|
@ -158,51 +119,140 @@ impl Output {
|
||||||
|
|
||||||
self.send_geometry(&output);
|
self.send_geometry(&output);
|
||||||
for &mode in &self.modes {
|
for &mode in &self.modes {
|
||||||
let mut flags = wl_output::Mode::empty();
|
let mut flags = WMode::empty();
|
||||||
if Some(mode) == self.current_mode {
|
if Some(mode) == self.current_mode {
|
||||||
flags |= wl_output::Mode::Current;
|
flags |= WMode::Current;
|
||||||
}
|
}
|
||||||
if Some(mode) == self.preferred_mode {
|
if Some(mode) == self.preferred_mode {
|
||||||
flags |= wl_output::Mode::Preferred;
|
flags |= WMode::Preferred;
|
||||||
}
|
}
|
||||||
output.mode(flags, mode.width, mode.height, mode.refresh);
|
output.send(Event::Mode {
|
||||||
|
flags: flags,
|
||||||
|
width: mode.width,
|
||||||
|
height: mode.height,
|
||||||
|
refresh: mode.refresh,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if output.version() >= 2 {
|
if output.version() >= 2 {
|
||||||
output.scale(self.scale);
|
output.send(Event::Scale { factor: self.scale });
|
||||||
output.done();
|
output.send(Event::Done);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.instances.push(output);
|
self.instances.push(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_geometry(&self, output: &wl_output::WlOutput) {
|
fn send_geometry(&self, output: &Resource<WlOutput>) {
|
||||||
output.geometry(
|
output.send(Event::Geometry {
|
||||||
self.location.0,
|
x: self.location.0,
|
||||||
self.location.1,
|
y: self.location.1,
|
||||||
self.physical.width,
|
physical_width: self.physical.width,
|
||||||
self.physical.height,
|
physical_height: self.physical.height,
|
||||||
self.physical.subpixel,
|
subpixel: self.physical.subpixel,
|
||||||
self.physical.maker.clone(),
|
make: self.physical.maker.clone(),
|
||||||
self.physical.model.clone(),
|
model: self.physical.model.clone(),
|
||||||
self.transform,
|
transform: self.transform,
|
||||||
);
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InnerWrapper {
|
||||||
|
inner: Arc<Mutex<Inner>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This implementation does nothing, we just use it as a stable type to downcast the
|
||||||
|
// implementation in the destructor of wl_output, in order to retrieve the Arc to the
|
||||||
|
// inner and remove this output from the list
|
||||||
|
impl Implementation<Resource<WlOutput>, Request> for InnerWrapper {
|
||||||
|
fn receive(&mut self, req: Request, _res: Resource<WlOutput>) {
|
||||||
|
// this will break if new variants are added :)
|
||||||
|
let Request::Release = req;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An output as seen by the clients
|
||||||
|
///
|
||||||
|
/// This handle is stored in the events loop, and allows you to notify clients
|
||||||
|
/// about any change in the properties of this output.
|
||||||
|
pub struct Output {
|
||||||
|
inner: Arc<Mutex<Inner>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Output {
|
||||||
|
/// Create a new output global with given name and physical properties
|
||||||
|
///
|
||||||
|
/// The global is directly registered into the eventloop, and this function
|
||||||
|
/// returns the state token allowing you to access it, as well as the global handle,
|
||||||
|
/// in case you whish to remove this global in the future.
|
||||||
|
pub fn new<L>(
|
||||||
|
display: &mut Display,
|
||||||
|
token: LoopToken,
|
||||||
|
name: String,
|
||||||
|
physical: PhysicalProperties,
|
||||||
|
logger: L,
|
||||||
|
) -> (Output, Global<WlOutput>)
|
||||||
|
where
|
||||||
|
L: Into<Option<::slog::Logger>>,
|
||||||
|
{
|
||||||
|
let log = ::slog_or_stdlog(logger).new(o!("smithay_module" => "output_handler"));
|
||||||
|
|
||||||
|
info!(log, "Creating new wl_output"; "name" => &name);
|
||||||
|
|
||||||
|
let inner = Arc::new(Mutex::new(Inner {
|
||||||
|
name: name,
|
||||||
|
log: log,
|
||||||
|
instances: Vec::new(),
|
||||||
|
physical: physical,
|
||||||
|
location: (0, 0),
|
||||||
|
transform: Transform::Normal,
|
||||||
|
scale: 1,
|
||||||
|
modes: Vec::new(),
|
||||||
|
current_mode: None,
|
||||||
|
preferred_mode: None,
|
||||||
|
}));
|
||||||
|
|
||||||
|
let output = Output {
|
||||||
|
inner: inner.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let global = display.create_global(&token, 3, move |_version, new_output: NewResource<_>| {
|
||||||
|
let output = new_output.implement(
|
||||||
|
InnerWrapper {
|
||||||
|
inner: inner.clone(),
|
||||||
|
},
|
||||||
|
Some(|output, boxed_impl| {
|
||||||
|
let wrapper: Box<InnerWrapper> =
|
||||||
|
downcast_impl(boxed_impl).unwrap_or_else(|_| unreachable!());
|
||||||
|
wrapper
|
||||||
|
.inner
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.instances
|
||||||
|
.retain(|o| !o.equals(&output));
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
inner.lock().unwrap().new_global(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
(output, global)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the preferred mode of this output
|
/// Sets the preferred mode of this output
|
||||||
///
|
///
|
||||||
/// If the provided mode was not previously known to this output, it is added to its
|
/// If the provided mode was not previously known to this output, it is added to its
|
||||||
/// internal list.
|
/// internal list.
|
||||||
pub fn set_preferred(&mut self, mode: Mode) {
|
pub fn set_preferred(&self, mode: Mode) {
|
||||||
self.preferred_mode = Some(mode);
|
let mut inner = self.inner.lock().unwrap();
|
||||||
if self.modes.iter().find(|&m| *m == mode).is_none() {
|
inner.preferred_mode = Some(mode);
|
||||||
self.modes.push(mode);
|
if inner.modes.iter().find(|&m| *m == mode).is_none() {
|
||||||
|
inner.modes.push(mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a mode to the list of known modes to this output
|
/// Adds a mode to the list of known modes to this output
|
||||||
pub fn add_mode(&mut self, mode: Mode) {
|
pub fn add_mode(&self, mode: Mode) {
|
||||||
if self.modes.iter().find(|&m| *m == mode).is_none() {
|
let mut inner = self.inner.lock().unwrap();
|
||||||
self.modes.push(mode);
|
if inner.modes.iter().find(|&m| *m == mode).is_none() {
|
||||||
|
inner.modes.push(mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,13 +260,14 @@ impl Output {
|
||||||
///
|
///
|
||||||
/// It will not de-advertize it from existing clients (the protocol does not
|
/// It will not de-advertize it from existing clients (the protocol does not
|
||||||
/// allow it), but it won't be advertized to now clients from now on.
|
/// allow it), but it won't be advertized to now clients from now on.
|
||||||
pub fn delete_mode(&mut self, mode: Mode) {
|
pub fn delete_mode(&self, mode: Mode) {
|
||||||
self.modes.retain(|&m| m != mode);
|
let mut inner = self.inner.lock().unwrap();
|
||||||
if self.current_mode == Some(mode) {
|
inner.modes.retain(|&m| m != mode);
|
||||||
self.current_mode = None;
|
if inner.current_mode == Some(mode) {
|
||||||
|
inner.current_mode = None;
|
||||||
}
|
}
|
||||||
if self.preferred_mode == Some(mode) {
|
if inner.preferred_mode == Some(mode) {
|
||||||
self.preferred_mode = None;
|
inner.preferred_mode = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,75 +281,58 @@ impl Output {
|
||||||
///
|
///
|
||||||
/// By default, transform status is `Normal`, and scale is `1`.
|
/// By default, transform status is `Normal`, and scale is `1`.
|
||||||
pub fn change_current_state(
|
pub fn change_current_state(
|
||||||
&mut self, new_mode: Option<Mode>, new_transform: Option<wl_output::Transform>,
|
&self,
|
||||||
|
new_mode: Option<Mode>,
|
||||||
|
new_transform: Option<Transform>,
|
||||||
new_scale: Option<i32>,
|
new_scale: Option<i32>,
|
||||||
) {
|
) {
|
||||||
|
let mut inner = self.inner.lock().unwrap();
|
||||||
if let Some(mode) = new_mode {
|
if let Some(mode) = new_mode {
|
||||||
if self.modes.iter().find(|&m| *m == mode).is_none() {
|
if inner.modes.iter().find(|&m| *m == mode).is_none() {
|
||||||
self.modes.push(mode);
|
inner.modes.push(mode);
|
||||||
}
|
}
|
||||||
self.current_mode = new_mode;
|
inner.current_mode = new_mode;
|
||||||
}
|
}
|
||||||
if let Some(transform) = new_transform {
|
if let Some(transform) = new_transform {
|
||||||
self.transform = transform;
|
inner.transform = transform;
|
||||||
}
|
}
|
||||||
if let Some(scale) = new_scale {
|
if let Some(scale) = new_scale {
|
||||||
self.scale = scale;
|
inner.scale = scale;
|
||||||
}
|
}
|
||||||
let mut flags = wl_output::Mode::Current;
|
let mut flags = WMode::Current;
|
||||||
if self.preferred_mode == new_mode {
|
if inner.preferred_mode == new_mode {
|
||||||
flags |= wl_output::Mode::Preferred;
|
flags |= WMode::Preferred;
|
||||||
}
|
}
|
||||||
for output in &self.instances {
|
for output in &inner.instances {
|
||||||
if let Some(mode) = new_mode {
|
if let Some(mode) = new_mode {
|
||||||
output.mode(flags, mode.width, mode.height, mode.refresh);
|
output.send(Event::Mode {
|
||||||
|
flags: flags,
|
||||||
|
width: mode.width,
|
||||||
|
height: mode.height,
|
||||||
|
refresh: mode.refresh,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if new_transform.is_some() {
|
if new_transform.is_some() {
|
||||||
self.send_geometry(output);
|
inner.send_geometry(output);
|
||||||
}
|
}
|
||||||
if let Some(scale) = new_scale {
|
if let Some(scale) = new_scale {
|
||||||
if output.version() >= 2 {
|
if output.version() >= 2 {
|
||||||
output.scale(scale);
|
output.send(Event::Scale { factor: scale });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if output.version() >= 2 {
|
if output.version() >= 2 {
|
||||||
output.done();
|
output.send(Event::Done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chech is given wl_output instance is managed by this `Output`.
|
/// Chech is given wl_output instance is managed by this `Output`.
|
||||||
pub fn owns(&self, output: &wl_output::WlOutput) -> bool {
|
pub fn owns(&self, output: &Resource<WlOutput>) -> bool {
|
||||||
self.instances.iter().any(|o| o.equals(output))
|
self.inner
|
||||||
}
|
.lock()
|
||||||
|
.unwrap()
|
||||||
/// Cleanup internal `wl_output` instances list
|
.instances
|
||||||
///
|
.iter()
|
||||||
/// Clients do not necessarily notify the server on the destruction
|
.any(|o| o.equals(output))
|
||||||
/// of their `wl_output` instances. This can lead to accumulation of
|
|
||||||
/// stale values in the internal instances list. This methods delete
|
|
||||||
/// them.
|
|
||||||
///
|
|
||||||
/// It can be good to call this regularly (but not necessarily very often).
|
|
||||||
pub fn cleanup(&mut self) {
|
|
||||||
self.instances.retain(|o| o.status() == Liveness::Alive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_bind(
|
|
||||||
evlh: &mut EventLoopHandle, token: &mut StateToken<Output>, _: &Client, global: wl_output::WlOutput
|
|
||||||
) {
|
|
||||||
evlh.register(&global, output_implementation(), token.clone(), None);
|
|
||||||
evlh.state().get_mut(token).new_global(global);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_implementation() -> wl_output::Implementation<StateToken<Output>> {
|
|
||||||
wl_output::Implementation {
|
|
||||||
release: |evlh, token, _, output| {
|
|
||||||
evlh.state()
|
|
||||||
.get_mut(token)
|
|
||||||
.instances
|
|
||||||
.retain(|o| !o.equals(output));
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue