This commit also drops 'Theme' trait with its support types in favor of 'FallbackFrame' meaning that winit will use some predefined frame for the time being, since porting 'ConceptFrame' will require adding font rendering librarires right into winit, which is not desired. Fixes #1889.
240 lines
6.4 KiB
Rust
240 lines
6.4 KiB
Rust
use std::collections::VecDeque;
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
use sctk::reexports::client::protocol::wl_output::WlOutput;
|
|
use sctk::reexports::client::Display;
|
|
|
|
use sctk::environment::Environment;
|
|
use sctk::output::OutputStatusListener;
|
|
|
|
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
|
use crate::monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode};
|
|
use crate::platform_impl::platform::{
|
|
MonitorHandle as PlatformMonitorHandle, VideoMode as PlatformVideoMode,
|
|
};
|
|
|
|
use super::env::WinitEnv;
|
|
use super::event_loop::EventLoopWindowTarget;
|
|
|
|
/// Output manager.
|
|
pub struct OutputManager {
|
|
/// A handle that actually performs all operations on outputs.
|
|
handle: OutputManagerHandle,
|
|
|
|
_output_listener: OutputStatusListener,
|
|
}
|
|
|
|
impl OutputManager {
|
|
pub fn new(env: &Environment<WinitEnv>) -> Self {
|
|
let handle = OutputManagerHandle::new();
|
|
|
|
// Handle existing outputs.
|
|
for output in env.get_all_outputs() {
|
|
match sctk::output::with_output_info(&output, |info| info.obsolete) {
|
|
Some(false) => (),
|
|
// The output is obsolete or we've failed to access its data, skipping.
|
|
_ => continue,
|
|
}
|
|
|
|
// The output is present and unusable, add it to the output manager manager.
|
|
handle.add_output(output);
|
|
}
|
|
|
|
let handle_for_listener = handle.clone();
|
|
|
|
let output_listener = env.listen_for_outputs(move |output, info, _| {
|
|
if info.obsolete {
|
|
handle_for_listener.remove_output(output)
|
|
} else {
|
|
handle_for_listener.add_output(output)
|
|
}
|
|
});
|
|
|
|
Self {
|
|
handle,
|
|
_output_listener: output_listener,
|
|
}
|
|
}
|
|
|
|
pub fn handle(&self) -> OutputManagerHandle {
|
|
self.handle.clone()
|
|
}
|
|
}
|
|
|
|
/// A handle to output manager.
|
|
#[derive(Debug, Clone)]
|
|
pub struct OutputManagerHandle {
|
|
outputs: Arc<Mutex<VecDeque<MonitorHandle>>>,
|
|
}
|
|
|
|
impl OutputManagerHandle {
|
|
fn new() -> Self {
|
|
let outputs = Arc::new(Mutex::new(VecDeque::new()));
|
|
Self { outputs }
|
|
}
|
|
|
|
/// Handle addition of the output.
|
|
fn add_output(&self, output: WlOutput) {
|
|
let mut outputs = self.outputs.lock().unwrap();
|
|
let position = outputs.iter().position(|handle| handle.proxy == output);
|
|
if position.is_none() {
|
|
outputs.push_back(MonitorHandle::new(output));
|
|
}
|
|
}
|
|
|
|
/// Handle removal of the output.
|
|
fn remove_output(&self, output: WlOutput) {
|
|
let mut outputs = self.outputs.lock().unwrap();
|
|
let position = outputs.iter().position(|handle| handle.proxy == output);
|
|
if let Some(position) = position {
|
|
outputs.remove(position);
|
|
}
|
|
}
|
|
|
|
/// Get all observed outputs.
|
|
pub fn available_outputs(&self) -> VecDeque<MonitorHandle> {
|
|
self.outputs.lock().unwrap().clone()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct MonitorHandle {
|
|
pub(crate) proxy: WlOutput,
|
|
}
|
|
|
|
impl PartialEq for MonitorHandle {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
self.native_identifier() == other.native_identifier()
|
|
}
|
|
}
|
|
|
|
impl Eq for MonitorHandle {}
|
|
|
|
impl PartialOrd for MonitorHandle {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(self.cmp(other))
|
|
}
|
|
}
|
|
|
|
impl Ord for MonitorHandle {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
self.native_identifier().cmp(&other.native_identifier())
|
|
}
|
|
}
|
|
|
|
impl std::hash::Hash for MonitorHandle {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
self.native_identifier().hash(state);
|
|
}
|
|
}
|
|
|
|
impl MonitorHandle {
|
|
#[inline]
|
|
pub(crate) fn new(proxy: WlOutput) -> Self {
|
|
Self { proxy }
|
|
}
|
|
|
|
#[inline]
|
|
pub fn name(&self) -> Option<String> {
|
|
sctk::output::with_output_info(&self.proxy, |info| {
|
|
format!("{} ({})", info.model, info.make)
|
|
})
|
|
}
|
|
|
|
#[inline]
|
|
pub fn native_identifier(&self) -> u32 {
|
|
sctk::output::with_output_info(&self.proxy, |info| info.id).unwrap_or(0)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn size(&self) -> PhysicalSize<u32> {
|
|
match sctk::output::with_output_info(&self.proxy, |info| {
|
|
info.modes
|
|
.iter()
|
|
.find(|mode| mode.is_current)
|
|
.map(|mode| mode.dimensions)
|
|
}) {
|
|
Some(Some((w, h))) => (w as u32, h as u32),
|
|
_ => (0, 0),
|
|
}
|
|
.into()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn position(&self) -> PhysicalPosition<i32> {
|
|
sctk::output::with_output_info(&self.proxy, |info| info.location)
|
|
.unwrap_or((0, 0))
|
|
.into()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn scale_factor(&self) -> i32 {
|
|
sctk::output::with_output_info(&self.proxy, |info| info.scale_factor).unwrap_or(1)
|
|
}
|
|
|
|
#[inline]
|
|
pub fn video_modes(&self) -> impl Iterator<Item = RootVideoMode> {
|
|
let modes = sctk::output::with_output_info(&self.proxy, |info| info.modes.clone())
|
|
.unwrap_or_else(Vec::new);
|
|
|
|
let monitor = self.clone();
|
|
|
|
modes.into_iter().map(move |mode| RootVideoMode {
|
|
video_mode: PlatformVideoMode::Wayland(VideoMode {
|
|
size: (mode.dimensions.0 as u32, mode.dimensions.1 as u32).into(),
|
|
refresh_rate: (mode.refresh_rate as f32 / 1000.0).round() as u16,
|
|
bit_depth: 32,
|
|
monitor: monitor.clone(),
|
|
}),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub struct VideoMode {
|
|
pub(crate) size: PhysicalSize<u32>,
|
|
pub(crate) bit_depth: u16,
|
|
pub(crate) refresh_rate: u16,
|
|
pub(crate) monitor: MonitorHandle,
|
|
}
|
|
|
|
impl VideoMode {
|
|
#[inline]
|
|
pub fn size(&self) -> PhysicalSize<u32> {
|
|
self.size
|
|
}
|
|
|
|
#[inline]
|
|
pub fn bit_depth(&self) -> u16 {
|
|
self.bit_depth
|
|
}
|
|
|
|
#[inline]
|
|
pub fn refresh_rate(&self) -> u16 {
|
|
self.refresh_rate
|
|
}
|
|
|
|
pub fn monitor(&self) -> RootMonitorHandle {
|
|
RootMonitorHandle {
|
|
inner: PlatformMonitorHandle::Wayland(self.monitor.clone()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> EventLoopWindowTarget<T> {
|
|
#[inline]
|
|
pub fn display(&self) -> &Display {
|
|
&self.display
|
|
}
|
|
|
|
#[inline]
|
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
|
self.output_manager.handle.available_outputs()
|
|
}
|
|
|
|
#[inline]
|
|
pub fn primary_monitor(&self) -> Option<RootMonitorHandle> {
|
|
// There's no primary monitor on Wayland.
|
|
None
|
|
}
|
|
}
|