monitor: refactor MonitorHandle to store dyn object

This also alters `VideoMode` to be a regular object and not reference
the `MonitorHandle`, since it's a static data.

Given that `VideoMode` set may change during runtime keeping the
reference as a some sort of validity may not be idea and propagating
errors when changing video mode could be more reliable.
This commit is contained in:
Kirill Chibisov 2024-09-21 20:27:12 +03:00
parent be1baf164c
commit f1c5afd84e
43 changed files with 726 additions and 826 deletions

View file

@ -20,6 +20,7 @@ use crate::event_loop::{
ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
OwnedDisplayHandle as CoreOwnedDisplayHandle,
};
use crate::monitor::MonitorHandle as CoreMonitorHandle;
use crate::platform::pump_events::PumpStatus;
use crate::platform_impl::platform::min_timeout;
use crate::platform_impl::PlatformCustomCursor;
@ -31,6 +32,7 @@ pub mod sink;
use proxy::EventLoopProxy;
use sink::EventSink;
use super::output::MonitorHandle;
use super::state::{WindowCompositorUpdate, WinitState};
use super::window::state::FrameCallbackState;
use super::{logical_to_physical_rounded, WindowId};
@ -621,19 +623,18 @@ impl RootActiveEventLoop for ActiveEventLoop {
Ok(Box::new(window))
}
fn available_monitors(&self) -> Box<dyn Iterator<Item = crate::monitor::MonitorHandle>> {
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
Box::new(
self.state
.borrow()
.output_state
.outputs()
.map(crate::platform_impl::wayland::output::MonitorHandle::new)
.map(crate::platform_impl::MonitorHandle::Wayland)
.map(|inner| crate::monitor::MonitorHandle { inner }),
.map(MonitorHandle::new)
.map(|inner| CoreMonitorHandle(Arc::new(inner))),
)
}
fn primary_monitor(&self) -> Option<crate::monitor::MonitorHandle> {
fn primary_monitor(&self) -> Option<CoreMonitorHandle> {
// There's no primary monitor on Wayland.
None
}

View file

@ -1,10 +1,7 @@
//! Winit's Wayland backend.
pub use event_loop::{ActiveEventLoop, EventLoop};
pub use output::MonitorHandle;
use sctk::reexports::client::protocol::wl_surface::WlSurface;
use sctk::reexports::client::Proxy;
pub use window::Window;
pub(super) use crate::cursor::OnlyCursorImage as CustomCursor;
use crate::dpi::{LogicalSize, PhysicalSize};
@ -17,6 +14,9 @@ mod state;
mod types;
mod window;
pub use event_loop::{ActiveEventLoop, EventLoop};
pub use window::Window;
/// Get the WindowId out of the surface.
#[inline]
fn make_wid(surface: &WlSurface) -> WindowId {

View file

@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::num::NonZeroU32;
use sctk::output::{Mode, OutputData};
@ -5,7 +6,7 @@ use sctk::reexports::client::protocol::wl_output::WlOutput;
use sctk::reexports::client::Proxy;
use crate::dpi::{LogicalPosition, PhysicalPosition};
use crate::monitor::VideoMode;
use crate::monitor::{MonitorHandleProvider as CoreMonitorHandle, VideoMode};
#[derive(Clone, Debug)]
pub struct MonitorHandle {
@ -17,21 +18,24 @@ impl MonitorHandle {
pub(crate) fn new(proxy: WlOutput) -> Self {
Self { proxy }
}
}
#[inline]
pub fn name(&self) -> Option<String> {
let output_data = self.proxy.data::<OutputData>().unwrap();
output_data.with_output_info(|info| info.name.clone())
impl CoreMonitorHandle for MonitorHandle {
fn id(&self) -> u128 {
self.native_id() as _
}
#[inline]
pub fn native_identifier(&self) -> u32 {
fn native_id(&self) -> u64 {
let output_data = self.proxy.data::<OutputData>().unwrap();
output_data.with_output_info(|info| info.id)
output_data.with_output_info(|info| info.id as u64)
}
#[inline]
pub fn position(&self) -> Option<PhysicalPosition<i32>> {
fn name(&self) -> Option<Cow<'_, str>> {
let output_data = self.proxy.data::<OutputData>().unwrap();
output_data.with_output_info(|info| info.name.clone().map(Cow::Owned))
}
fn position(&self) -> Option<PhysicalPosition<i32>> {
let output_data = self.proxy.data::<OutputData>().unwrap();
Some(output_data.with_output_info(|info| {
info.logical_position.map_or_else(
@ -47,56 +51,37 @@ impl MonitorHandle {
}))
}
#[inline]
pub fn scale_factor(&self) -> i32 {
fn scale_factor(&self) -> f64 {
let output_data = self.proxy.data::<OutputData>().unwrap();
output_data.scale_factor()
output_data.scale_factor() as f64
}
#[inline]
pub fn current_video_mode(&self) -> Option<VideoMode> {
fn current_video_mode(&self) -> Option<crate::monitor::VideoMode> {
let output_data = self.proxy.data::<OutputData>().unwrap();
output_data.with_output_info(|info| {
let mode = info.modes.iter().find(|mode| mode.current).cloned();
mode.map(wayland_mode_to_core_mode)
})
}
#[inline]
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>> {
let output_data = self.proxy.data::<OutputData>().unwrap();
let modes = output_data.with_output_info(|info| info.modes.clone());
modes.into_iter().map(wayland_mode_to_core_mode)
Box::new(modes.into_iter().map(wayland_mode_to_core_mode))
}
}
impl PartialEq for MonitorHandle {
fn eq(&self, other: &Self) -> bool {
self.native_identifier() == other.native_identifier()
self.native_id() == other.native_id()
}
}
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);
}
}
/// Convert Wayland's [`Mode`] to winit's [`VideoMode`].
/// Convert the wayland's [`Mode`] to winit's [`VideoMode`].
fn wayland_mode_to_core_mode(mode: Mode) -> VideoMode {
VideoMode {
size: (mode.dimensions.0, mode.dimensions.1).into(),

View file

@ -21,12 +21,12 @@ use crate::dpi::{LogicalSize, PhysicalInsets, PhysicalPosition, PhysicalSize, Po
use crate::error::{NotSupportedError, RequestError};
use crate::event::{Ime, WindowEvent};
use crate::event_loop::AsyncRequestSerial;
use crate::monitor::MonitorHandle as CoreMonitorHandle;
use crate::platform_impl::{Fullscreen, MonitorHandle as PlatformMonitorHandle};
use crate::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle};
use crate::platform_impl::wayland::output;
use crate::utils::AsAny;
use crate::window::{
Cursor, CursorGrabMode, Fullscreen as CoreFullscreen, ImePurpose, ResizeDirection, Theme,
UserAttentionType, Window as CoreWindow, WindowAttributes, WindowButtons, WindowId,
WindowLevel,
Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType,
Window as CoreWindow, WindowAttributes, WindowButtons, WindowId, WindowLevel,
};
pub(crate) mod state;
@ -139,19 +139,20 @@ impl Window {
window_state.set_resizable(attributes.resizable);
// Set startup mode.
match attributes.fullscreen.map(Into::into) {
match attributes.fullscreen {
Some(Fullscreen::Exclusive(..)) => {
warn!("`Fullscreen::Exclusive` is ignored on Wayland");
},
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.and_then(|monitor| match monitor {
PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy),
#[cfg(x11_platform)]
PlatformMonitorHandle::X(_) => None,
let output = monitor.as_ref().and_then(|monitor| {
monitor
.as_any()
.downcast_ref::<output::MonitorHandle>()
.map(|handle| &handle.proxy)
});
window.set_fullscreen(output.as_ref())
window.set_fullscreen(output)
},
_ if attributes.maximized => window.set_maximized(),
_ => (),
@ -437,26 +438,27 @@ impl CoreWindow for Window {
.unwrap_or_default()
}
fn set_fullscreen(&self, fullscreen: Option<CoreFullscreen>) {
fn set_fullscreen(&self, fullscreen: Option<Fullscreen>) {
match fullscreen {
Some(CoreFullscreen::Exclusive(..)) => {
Some(Fullscreen::Exclusive(..)) => {
warn!("`Fullscreen::Exclusive` is ignored on Wayland");
},
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
Some(CoreFullscreen::Borderless(monitor)) => {
let output = monitor.and_then(|monitor| match monitor.inner {
PlatformMonitorHandle::Wayland(monitor) => Some(monitor.proxy),
#[cfg(x11_platform)]
PlatformMonitorHandle::X(_) => None,
Some(Fullscreen::Borderless(monitor)) => {
let output = monitor.as_ref().and_then(|monitor| {
monitor
.as_any()
.downcast_ref::<output::MonitorHandle>()
.map(|handle| &handle.proxy)
});
self.window.set_fullscreen(output.as_ref())
self.window.set_fullscreen(output)
},
None => self.window.unset_fullscreen(),
}
}
fn fullscreen(&self) -> Option<CoreFullscreen> {
fn fullscreen(&self) -> Option<Fullscreen> {
let is_fullscreen = self
.window_state
.lock()
@ -468,7 +470,7 @@ impl CoreWindow for Window {
if is_fullscreen {
let current_monitor = self.current_monitor();
Some(CoreFullscreen::Borderless(current_monitor))
Some(Fullscreen::Borderless(current_monitor))
} else {
None
}
@ -628,8 +630,7 @@ impl CoreWindow for Window {
data.outputs()
.next()
.map(MonitorHandle::new)
.map(crate::platform_impl::MonitorHandle::Wayland)
.map(|inner| CoreMonitorHandle { inner })
.map(|monitor| CoreMonitorHandle(Arc::new(monitor)))
}
fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
@ -639,8 +640,7 @@ impl CoreWindow for Window {
.unwrap()
.clone()
.into_iter()
.map(crate::platform_impl::MonitorHandle::Wayland)
.map(|inner| CoreMonitorHandle { inner }),
.map(|inner| CoreMonitorHandle(Arc::new(inner))),
)
}