Implement XdgOutput protocol
This commit is contained in:
parent
2536a5a9cb
commit
7e4e78151a
|
@ -51,7 +51,7 @@ impl Output {
|
||||||
|
|
||||||
let output_scale = scale.round() as i32;
|
let output_scale = scale.round() as i32;
|
||||||
|
|
||||||
output.change_current_state(Some(mode), None, Some(output_scale));
|
output.change_current_state(Some(mode), None, Some(output_scale), Some(location));
|
||||||
output.set_preferred(mode);
|
output.set_preferred(mode);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -159,6 +159,11 @@ impl OutputMap {
|
||||||
|
|
||||||
output.location.x = output_x;
|
output.location.x = output_x;
|
||||||
output.location.y = 0;
|
output.location.y = 0;
|
||||||
|
|
||||||
|
output
|
||||||
|
.output
|
||||||
|
.change_current_state(None, None, None, Some(output.location));
|
||||||
|
|
||||||
output_x += output.size().w;
|
output_x += output.size().w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +319,7 @@ impl OutputMap {
|
||||||
output.output.delete_mode(output.current_mode);
|
output.output.delete_mode(output.current_mode);
|
||||||
output
|
output
|
||||||
.output
|
.output
|
||||||
.change_current_state(Some(mode), None, Some(output.output_scale));
|
.change_current_state(Some(mode), None, Some(output.output_scale), None);
|
||||||
output.output.set_preferred(mode);
|
output.output.set_preferred(mode);
|
||||||
output.current_mode = mode;
|
output.current_mode = mode;
|
||||||
}
|
}
|
||||||
|
@ -356,9 +361,12 @@ impl OutputMap {
|
||||||
|
|
||||||
if output.output_scale != output_scale {
|
if output.output_scale != output_scale {
|
||||||
output.output_scale = output_scale;
|
output.output_scale = output_scale;
|
||||||
output
|
output.output.change_current_state(
|
||||||
.output
|
Some(output.current_mode),
|
||||||
.change_current_state(Some(output.current_mode), None, Some(output_scale));
|
None,
|
||||||
|
Some(output_scale),
|
||||||
|
None,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ use smithay::{
|
||||||
utils::{Logical, Point},
|
utils::{Logical, Point},
|
||||||
wayland::{
|
wayland::{
|
||||||
data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent},
|
data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent},
|
||||||
|
output::xdg::init_xdg_output_manager,
|
||||||
seat::{CursorImageStatus, KeyboardHandle, PointerHandle, Seat, XkbConfig},
|
seat::{CursorImageStatus, KeyboardHandle, PointerHandle, Seat, XkbConfig},
|
||||||
shm::init_shm_global,
|
shm::init_shm_global,
|
||||||
tablet_manager::{init_tablet_manager_global, TabletSeatTrait},
|
tablet_manager::{init_tablet_manager_global, TabletSeatTrait},
|
||||||
|
@ -82,6 +83,8 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
|
||||||
|
|
||||||
let shell_handles = init_shell::<BackendData>(display.clone(), log.clone());
|
let shell_handles = init_shell::<BackendData>(display.clone(), log.clone());
|
||||||
|
|
||||||
|
init_xdg_output_manager(&mut display.borrow_mut(), log.clone());
|
||||||
|
|
||||||
let socket_name = display
|
let socket_name = display
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.add_socket_auto()
|
.add_socket_auto()
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
//! Some(Mode { size: (1920, 1080).into(), refresh: 60000 }), // the resolution mode,
|
//! Some(Mode { size: (1920, 1080).into(), refresh: 60000 }), // the resolution mode,
|
||||||
//! Some(wl_output::Transform::Normal), // global screen transformation
|
//! Some(wl_output::Transform::Normal), // global screen transformation
|
||||||
//! Some(1), // global screen scaling factor
|
//! Some(1), // global screen scaling factor
|
||||||
|
//! Some((0,0).into()) // output position
|
||||||
//! );
|
//! );
|
||||||
//! // set the preferred mode
|
//! // set the preferred mode
|
||||||
//! output.set_preferred(Mode { size: (1920, 1080).into(), refresh: 60000 });
|
//! output.set_preferred(Mode { size: (1920, 1080).into(), refresh: 60000 });
|
||||||
|
@ -47,6 +48,8 @@
|
||||||
//! output.add_mode(Mode { size: (1024, 768).into(), refresh: 60000 });
|
//! output.add_mode(Mode { size: (1024, 768).into(), refresh: 60000 });
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
|
pub mod xdg;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ops::Deref as _,
|
ops::Deref as _,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
|
@ -65,6 +68,8 @@ use slog::{info, o, trace, warn};
|
||||||
|
|
||||||
use crate::utils::{Logical, Physical, Point, Raw, Size};
|
use crate::utils::{Logical, Physical, Point, Raw, Size};
|
||||||
|
|
||||||
|
use self::xdg::XdgOutput;
|
||||||
|
|
||||||
/// 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.
|
||||||
|
@ -106,6 +111,8 @@ struct Inner {
|
||||||
modes: Vec<Mode>,
|
modes: Vec<Mode>,
|
||||||
current_mode: Option<Mode>,
|
current_mode: Option<Mode>,
|
||||||
preferred_mode: Option<Mode>,
|
preferred_mode: Option<Mode>,
|
||||||
|
|
||||||
|
xdg_output: Option<XdgOutput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Inner {
|
impl Inner {
|
||||||
|
@ -194,6 +201,7 @@ impl Output {
|
||||||
modes: Vec::new(),
|
modes: Vec::new(),
|
||||||
current_mode: None,
|
current_mode: None,
|
||||||
preferred_mode: None,
|
preferred_mode: None,
|
||||||
|
xdg_output: None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let output = Output { inner: inner.clone() };
|
let output = Output { inner: inner.clone() };
|
||||||
|
@ -220,6 +228,16 @@ impl Output {
|
||||||
(output, global)
|
(output, global)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempt to retrieve a [`Output`] from an existing resource
|
||||||
|
pub fn from_resource(output: &WlOutput) -> Option<Output> {
|
||||||
|
output
|
||||||
|
.as_ref()
|
||||||
|
.user_data()
|
||||||
|
.get::<Arc<Mutex<Inner>>>()
|
||||||
|
.cloned()
|
||||||
|
.map(|inner| Output { inner })
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -257,7 +275,7 @@ impl Output {
|
||||||
|
|
||||||
/// Change the current state of this output
|
/// Change the current state of this output
|
||||||
///
|
///
|
||||||
/// You can changed the current mode, transform status or scale of this output. Providing
|
/// You can changed the current mode, transform status, location or scale of this output. Providing
|
||||||
/// `None` to any of these field means that the value does not change.
|
/// `None` to any of these field means that the value does not change.
|
||||||
///
|
///
|
||||||
/// 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
|
||||||
|
@ -269,6 +287,7 @@ impl Output {
|
||||||
new_mode: Option<Mode>,
|
new_mode: Option<Mode>,
|
||||||
new_transform: Option<Transform>,
|
new_transform: Option<Transform>,
|
||||||
new_scale: Option<i32>,
|
new_scale: Option<i32>,
|
||||||
|
new_location: Option<Point<i32, Logical>>,
|
||||||
) {
|
) {
|
||||||
let mut inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
if let Some(mode) = new_mode {
|
if let Some(mode) = new_mode {
|
||||||
|
@ -287,11 +306,21 @@ impl Output {
|
||||||
if inner.preferred_mode == new_mode {
|
if inner.preferred_mode == new_mode {
|
||||||
flags |= WMode::Preferred;
|
flags |= WMode::Preferred;
|
||||||
}
|
}
|
||||||
|
if let Some(new_location) = new_location {
|
||||||
|
inner.location = new_location;
|
||||||
|
}
|
||||||
|
|
||||||
|
// XdgOutput has to be updated before WlOutput
|
||||||
|
// Because WlOutput::done() has to allways be called last
|
||||||
|
if let Some(xdg_output) = inner.xdg_output.as_ref() {
|
||||||
|
xdg_output.change_current_state(new_mode, new_scale, new_location);
|
||||||
|
}
|
||||||
|
|
||||||
for output in &inner.instances {
|
for output in &inner.instances {
|
||||||
if let Some(mode) = new_mode {
|
if let Some(mode) = new_mode {
|
||||||
output.mode(flags, mode.size.w, mode.size.h, mode.refresh);
|
output.mode(flags, mode.size.w, mode.size.h, mode.refresh);
|
||||||
}
|
}
|
||||||
if new_transform.is_some() {
|
if new_transform.is_some() || new_location.is_some() {
|
||||||
inner.send_geometry(output);
|
inner.send_geometry(output);
|
||||||
}
|
}
|
||||||
if let Some(scale) = new_scale {
|
if let Some(scale) = new_scale {
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
//! XDG Output advertising capabilities
|
||||||
|
//!
|
||||||
|
//! This protocol is ment for describing outputs in a way
|
||||||
|
//! which is more in line with the concept of an output on desktop oriented systems.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
ops::Deref as _,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
use slog::{o, trace};
|
||||||
|
use wayland_protocols::unstable::xdg_output::v1::server::{
|
||||||
|
zxdg_output_manager_v1::{self, ZxdgOutputManagerV1},
|
||||||
|
zxdg_output_v1::ZxdgOutputV1,
|
||||||
|
};
|
||||||
|
use wayland_server::{protocol::wl_output::WlOutput, Display, Filter, Global, Main};
|
||||||
|
|
||||||
|
use crate::utils::{Logical, Physical, Point, Size};
|
||||||
|
|
||||||
|
use super::{Mode, Output};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Inner {
|
||||||
|
name: String,
|
||||||
|
description: String,
|
||||||
|
logical_position: Point<i32, Logical>,
|
||||||
|
|
||||||
|
physical_size: Option<Size<i32, Physical>>,
|
||||||
|
scale: i32,
|
||||||
|
|
||||||
|
instances: Vec<ZxdgOutputV1>,
|
||||||
|
log: ::slog::Logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(super) struct XdgOutput {
|
||||||
|
inner: Arc<Mutex<Inner>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XdgOutput {
|
||||||
|
fn new(output: &super::Inner, log: ::slog::Logger) -> Self {
|
||||||
|
trace!(log, "Creating new xdg_output"; "name" => &output.name);
|
||||||
|
|
||||||
|
let description = format!(
|
||||||
|
"{} - {} - {}",
|
||||||
|
output.physical.make, output.physical.model, output.name
|
||||||
|
);
|
||||||
|
|
||||||
|
let physical_size = output.current_mode.map(|mode| mode.size);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
inner: Arc::new(Mutex::new(Inner {
|
||||||
|
name: output.name.clone(),
|
||||||
|
description,
|
||||||
|
logical_position: output.location,
|
||||||
|
|
||||||
|
physical_size,
|
||||||
|
scale: output.scale,
|
||||||
|
|
||||||
|
instances: Vec::new(),
|
||||||
|
log,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_instance(&self, xdg_output: Main<ZxdgOutputV1>, wl_output: &WlOutput) {
|
||||||
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
|
||||||
|
xdg_output.logical_position(inner.logical_position.x, inner.logical_position.y);
|
||||||
|
|
||||||
|
if let Some(size) = inner.physical_size {
|
||||||
|
let logical_size = size.to_logical(inner.scale);
|
||||||
|
xdg_output.logical_size(logical_size.w, logical_size.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if xdg_output.as_ref().version() >= 2 {
|
||||||
|
xdg_output.name(inner.name.clone());
|
||||||
|
xdg_output.description(inner.description.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// xdg_output.done() is deprecated since version 3
|
||||||
|
if xdg_output.as_ref().version() < 3 {
|
||||||
|
xdg_output.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_output.done();
|
||||||
|
|
||||||
|
xdg_output.quick_assign(|_, _, _| {});
|
||||||
|
xdg_output.assign_destructor(Filter::new(|xdg_output: ZxdgOutputV1, _, _| {
|
||||||
|
let inner = &xdg_output.as_ref().user_data().get::<XdgOutput>().unwrap().inner;
|
||||||
|
inner
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.instances
|
||||||
|
.retain(|o| !o.as_ref().equals(&xdg_output.as_ref()));
|
||||||
|
}));
|
||||||
|
xdg_output.as_ref().user_data().set_threadsafe({
|
||||||
|
let xdg_output = self.clone();
|
||||||
|
move || xdg_output
|
||||||
|
});
|
||||||
|
|
||||||
|
inner.instances.push(xdg_output.deref().clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn change_current_state(
|
||||||
|
&self,
|
||||||
|
new_mode: Option<Mode>,
|
||||||
|
new_scale: Option<i32>,
|
||||||
|
new_location: Option<Point<i32, Logical>>,
|
||||||
|
) {
|
||||||
|
let mut output = self.inner.lock().unwrap();
|
||||||
|
|
||||||
|
if let Some(new_mode) = new_mode {
|
||||||
|
output.physical_size = Some(new_mode.size);
|
||||||
|
}
|
||||||
|
if let Some(new_scale) = new_scale {
|
||||||
|
output.scale = new_scale;
|
||||||
|
}
|
||||||
|
if let Some(new_location) = new_location {
|
||||||
|
output.logical_position = new_location;
|
||||||
|
}
|
||||||
|
|
||||||
|
for instance in output.instances.iter() {
|
||||||
|
if new_mode.is_some() | new_scale.is_some() {
|
||||||
|
if let Some(size) = output.physical_size {
|
||||||
|
let logical_size = size.to_logical(output.scale);
|
||||||
|
instance.logical_size(logical_size.w, logical_size.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_location.is_some() {
|
||||||
|
instance.logical_position(output.logical_position.x, output.logical_position.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// xdg_output.done() is deprecated since version 3
|
||||||
|
if instance.as_ref().version() < 3 {
|
||||||
|
instance.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need for wl_output.done() here, it will be called by caller (super::Output::change_current_state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize a xdg output manager global.
|
||||||
|
pub fn init_xdg_output_manager<L>(display: &mut Display, logger: L) -> Global<ZxdgOutputManagerV1>
|
||||||
|
where
|
||||||
|
L: Into<Option<::slog::Logger>>,
|
||||||
|
{
|
||||||
|
let log = crate::slog_or_fallback(logger).new(o!("smithay_module" => "xdg_output_handler"));
|
||||||
|
|
||||||
|
display.create_global(
|
||||||
|
3,
|
||||||
|
Filter::new(move |(manager, _version): (Main<ZxdgOutputManagerV1>, _), _, _| {
|
||||||
|
let log = log.clone();
|
||||||
|
manager.quick_assign(move |_, req, _| match req {
|
||||||
|
zxdg_output_manager_v1::Request::GetXdgOutput {
|
||||||
|
id,
|
||||||
|
output: wl_output,
|
||||||
|
} => {
|
||||||
|
let output = Output::from_resource(&wl_output).unwrap();
|
||||||
|
let mut inner = output.inner.lock().unwrap();
|
||||||
|
|
||||||
|
if inner.xdg_output.is_none() {
|
||||||
|
inner.xdg_output = Some(XdgOutput::new(&inner, log.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
inner.xdg_output.as_ref().unwrap().add_instance(id, &wl_output);
|
||||||
|
}
|
||||||
|
zxdg_output_manager_v1::Request::Destroy => {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue