api: make VideoModeHandle into VideoMode
The video mode is generally a static data and not a reference to some video mode. This changes the exclusive fullscreen API to match that an accept a monitor now.
This commit is contained in:
parent
5462f27dda
commit
ee245c569d
28 changed files with 247 additions and 475 deletions
|
|
@ -1,6 +1,5 @@
|
|||
use std::cell::Cell;
|
||||
use std::hash::Hash;
|
||||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant};
|
||||
|
|
@ -21,7 +20,7 @@ use crate::event_loop::{
|
|||
EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
|
||||
OwnedDisplayHandle as CoreOwnedDisplayHandle,
|
||||
};
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::monitor::{MonitorHandle as RootMonitorHandle, VideoMode};
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::window::{
|
||||
self, CursorGrabMode, CustomCursor, CustomCursorSource, Fullscreen, ImePurpose,
|
||||
|
|
@ -1021,32 +1020,11 @@ impl MonitorHandle {
|
|||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> std::iter::Empty<VideoModeHandle> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct VideoModeHandle;
|
||||
|
||||
impl VideoModeHandle {
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
pub fn video_modes(&self) -> std::iter::Empty<VideoMode> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub(crate) use self::event::{physicalkey_to_scancode, scancode_to_physicalkey, K
|
|||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, PlatformSpecificEventLoopAttributes,
|
||||
};
|
||||
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
|
||||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::Window;
|
||||
pub(crate) use self::window_delegate::PlatformSpecificWindowAttributes;
|
||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||
|
|
|
|||
|
|
@ -17,22 +17,18 @@ use objc2_foundation::{ns_string, run_on_main, MainThreadMarker, NSNumber, NSPoi
|
|||
|
||||
use super::ffi;
|
||||
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
|
||||
use crate::monitor::VideoMode;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VideoModeHandle {
|
||||
size: PhysicalSize<u32>,
|
||||
bit_depth: Option<NonZeroU16>,
|
||||
refresh_rate_millihertz: Option<NonZeroU32>,
|
||||
pub(crate) mode: VideoMode,
|
||||
pub(crate) monitor: MonitorHandle,
|
||||
pub(crate) native_mode: NativeDisplayMode,
|
||||
}
|
||||
|
||||
impl PartialEq for VideoModeHandle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.size == other.size
|
||||
&& self.bit_depth == other.bit_depth
|
||||
&& self.refresh_rate_millihertz == other.refresh_rate_millihertz
|
||||
&& self.monitor == other.monitor
|
||||
self.monitor == other.monitor && self.mode == other.mode
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,19 +36,14 @@ impl Eq for VideoModeHandle {}
|
|||
|
||||
impl std::hash::Hash for VideoModeHandle {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.size.hash(state);
|
||||
self.bit_depth.hash(state);
|
||||
self.refresh_rate_millihertz.hash(state);
|
||||
self.monitor.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for VideoModeHandle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("VideoModeHandle")
|
||||
.field("size", &self.size)
|
||||
.field("bit_depth", &self.bit_depth)
|
||||
.field("refresh_rate_millihertz", &self.refresh_rate_millihertz)
|
||||
f.debug_struct("VideoMode")
|
||||
.field("mode", &self.mode)
|
||||
.field("monitor", &self.monitor)
|
||||
.finish()
|
||||
}
|
||||
|
|
@ -83,13 +74,14 @@ impl Clone for NativeDisplayMode {
|
|||
impl VideoModeHandle {
|
||||
fn new(
|
||||
monitor: MonitorHandle,
|
||||
mode: NativeDisplayMode,
|
||||
native_mode: NativeDisplayMode,
|
||||
refresh_rate_millihertz: Option<NonZeroU32>,
|
||||
) -> Self {
|
||||
unsafe {
|
||||
let pixel_encoding =
|
||||
CFString::wrap_under_create_rule(ffi::CGDisplayModeCopyPixelEncoding(mode.0))
|
||||
.to_string();
|
||||
let pixel_encoding = CFString::wrap_under_create_rule(
|
||||
ffi::CGDisplayModeCopyPixelEncoding(native_mode.0),
|
||||
)
|
||||
.to_string();
|
||||
let bit_depth = if pixel_encoding.eq_ignore_ascii_case(ffi::IO32BitDirectPixels) {
|
||||
32
|
||||
} else if pixel_encoding.eq_ignore_ascii_case(ffi::IO16BitDirectPixels) {
|
||||
|
|
@ -100,34 +92,18 @@ impl VideoModeHandle {
|
|||
unimplemented!()
|
||||
};
|
||||
|
||||
VideoModeHandle {
|
||||
let mode = VideoMode {
|
||||
size: PhysicalSize::new(
|
||||
ffi::CGDisplayModeGetPixelWidth(mode.0) as u32,
|
||||
ffi::CGDisplayModeGetPixelHeight(mode.0) as u32,
|
||||
ffi::CGDisplayModeGetPixelWidth(native_mode.0) as u32,
|
||||
ffi::CGDisplayModeGetPixelHeight(native_mode.0) as u32,
|
||||
),
|
||||
refresh_rate_millihertz,
|
||||
bit_depth: NonZeroU16::new(bit_depth),
|
||||
monitor: monitor.clone(),
|
||||
native_mode: mode,
|
||||
}
|
||||
};
|
||||
|
||||
VideoModeHandle { mode, monitor: monitor.clone(), native_mode }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
self.refresh_rate_millihertz
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.monitor.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -240,13 +216,17 @@ impl MonitorHandle {
|
|||
refresh_rate_millihertz(self.0, ¤t_display_mode)
|
||||
}
|
||||
|
||||
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
let mode = NativeDisplayMode(unsafe { CGDisplayCopyDisplayMode(self.0) } as _);
|
||||
let refresh_rate_millihertz = refresh_rate_millihertz(self.0, &mode);
|
||||
Some(VideoModeHandle::new(self.clone(), mode, refresh_rate_millihertz))
|
||||
Some(VideoModeHandle::new(self.clone(), mode, refresh_rate_millihertz).mode)
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
self.video_modes_handles().map(|handle| handle.mode)
|
||||
}
|
||||
|
||||
pub(crate) fn video_modes_handles(&self) -> impl Iterator<Item = VideoModeHandle> {
|
||||
let refresh_rate_millihertz = self.refresh_rate_millihertz();
|
||||
let monitor = self.clone();
|
||||
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ impl Window {
|
|||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
// Restore the video mode.
|
||||
if matches!(self.fullscreen(), Some(Fullscreen::Exclusive(_))) {
|
||||
if matches!(self.fullscreen(), Some(Fullscreen::Exclusive(_, _))) {
|
||||
self.set_fullscreen(None);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use std::rc::Rc;
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use core_graphics::display::CGDisplay;
|
||||
use monitor::VideoModeHandle;
|
||||
use objc2::rc::{autoreleasepool, Retained};
|
||||
use objc2::runtime::{AnyObject, ProtocolObject};
|
||||
use objc2::{declare_class, msg_send_id, mutability, sel, ClassType, DeclaredClass};
|
||||
|
|
@ -247,7 +246,7 @@ declare_class!(
|
|||
// Exclusive mode sets the state in `set_fullscreen` as the user
|
||||
// can't enter exclusive mode by other means (like the
|
||||
// fullscreen button on the window decorations)
|
||||
Some(Fullscreen::Exclusive(_)) => (),
|
||||
Some(Fullscreen::Exclusive(_, _)) => (),
|
||||
// `window_will_enter_fullscreen` was triggered and we're already
|
||||
// in fullscreen, so we must've reached here by `set_fullscreen`
|
||||
// as it updates the state
|
||||
|
|
@ -287,7 +286,7 @@ declare_class!(
|
|||
// user-provided options are ignored in exclusive fullscreen.
|
||||
let mut options = proposed_options;
|
||||
let fullscreen = self.ivars().fullscreen.borrow();
|
||||
if let Some(Fullscreen::Exclusive(_)) = &*fullscreen {
|
||||
if let Some(Fullscreen::Exclusive(_, _)) = &*fullscreen {
|
||||
options = NSApplicationPresentationOptions::NSApplicationPresentationFullScreen
|
||||
| NSApplicationPresentationOptions::NSApplicationPresentationHideDock
|
||||
| NSApplicationPresentationOptions::NSApplicationPresentationHideMenuBar;
|
||||
|
|
@ -507,7 +506,7 @@ fn new_window(
|
|||
autoreleasepool(|_| {
|
||||
let screen = match attrs.fullscreen.clone().map(Into::into) {
|
||||
Some(Fullscreen::Borderless(Some(monitor)))
|
||||
| Some(Fullscreen::Exclusive(VideoModeHandle { monitor, .. })) => {
|
||||
| Some(Fullscreen::Exclusive(monitor, _)) => {
|
||||
monitor.ns_screen(mtm).or_else(|| NSScreen::mainScreen(mtm))
|
||||
},
|
||||
Some(Fullscreen::Borderless(None)) => NSScreen::mainScreen(mtm),
|
||||
|
|
@ -1426,7 +1425,7 @@ impl WindowDelegate {
|
|||
return;
|
||||
}
|
||||
},
|
||||
Fullscreen::Exclusive(video_mode) => video_mode.monitor(),
|
||||
Fullscreen::Exclusive(monitor, _) => monitor.clone(),
|
||||
}
|
||||
.ns_screen(mtm)
|
||||
.unwrap();
|
||||
|
|
@ -1437,7 +1436,7 @@ impl WindowDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(Fullscreen::Exclusive(ref video_mode)) = fullscreen {
|
||||
if let Some(Fullscreen::Exclusive(ref monitor, ref video_mode)) = fullscreen {
|
||||
// Note: `enterFullScreenMode:withOptions:` seems to do the exact
|
||||
// same thing as we're doing here (captures the display, sets the
|
||||
// video mode, and hides the menu bar and dock), with the exception
|
||||
|
|
@ -1450,7 +1449,7 @@ impl WindowDelegate {
|
|||
// parameter, which is not consistent with the docs saying that it
|
||||
// takes a `NSDictionary`..
|
||||
|
||||
let display_id = video_mode.monitor().native_identifier();
|
||||
let display_id = monitor.native_identifier();
|
||||
|
||||
let mut fade_token = ffi::kCGDisplayFadeReservationInvalidToken;
|
||||
|
||||
|
|
@ -1479,6 +1478,12 @@ impl WindowDelegate {
|
|||
assert_eq!(ffi::CGDisplayCapture(display_id), ffi::kCGErrorSuccess);
|
||||
}
|
||||
|
||||
let video_mode =
|
||||
match monitor.video_modes_handles().find(|mode| &mode.mode == video_mode) {
|
||||
Some(video_mode) => video_mode,
|
||||
None => return,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let result = ffi::CGDisplaySetDisplayMode(
|
||||
display_id,
|
||||
|
|
@ -1543,11 +1548,11 @@ impl WindowDelegate {
|
|||
// State is restored by `window_did_exit_fullscreen`
|
||||
toggle_fullscreen(self.window());
|
||||
},
|
||||
(Some(Fullscreen::Exclusive(ref video_mode)), None) => {
|
||||
restore_and_release_display(&video_mode.monitor());
|
||||
(Some(Fullscreen::Exclusive(ref monitor, _)), None) => {
|
||||
restore_and_release_display(monitor);
|
||||
toggle_fullscreen(self.window());
|
||||
},
|
||||
(Some(Fullscreen::Borderless(_)), Some(Fullscreen::Exclusive(_))) => {
|
||||
(Some(Fullscreen::Borderless(_)), Some(Fullscreen::Exclusive(..))) => {
|
||||
// If we're already in fullscreen mode, calling
|
||||
// `CGDisplayCapture` will place the shielding window on top of
|
||||
// our window, which results in a black display and is not what
|
||||
|
|
@ -1567,7 +1572,7 @@ impl WindowDelegate {
|
|||
let window_level = unsafe { ffi::CGShieldingWindowLevel() } as NSWindowLevel + 1;
|
||||
self.window().setLevel(window_level);
|
||||
},
|
||||
(Some(Fullscreen::Exclusive(ref video_mode)), Some(Fullscreen::Borderless(_))) => {
|
||||
(Some(Fullscreen::Exclusive(ref monitor, _)), Some(Fullscreen::Borderless(_))) => {
|
||||
let presentation_options = self.ivars().save_presentation_opts.get().unwrap_or(
|
||||
NSApplicationPresentationOptions::NSApplicationPresentationFullScreen
|
||||
| NSApplicationPresentationOptions::NSApplicationPresentationAutoHideDock
|
||||
|
|
@ -1575,7 +1580,7 @@ impl WindowDelegate {
|
|||
);
|
||||
app.setPresentationOptions(presentation_options);
|
||||
|
||||
restore_and_release_display(&video_mode.monitor());
|
||||
restore_and_release_display(monitor);
|
||||
|
||||
// Restore the normal window level following the Borderless fullscreen
|
||||
// `CGShieldingWindowLevel() + 1` hack.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use std::fmt;
|
|||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, EventLoopProxy, PlatformSpecificEventLoopAttributes,
|
||||
};
|
||||
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
|
||||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::{PlatformSpecificWindowAttributes, Window};
|
||||
pub(crate) use crate::cursor::{
|
||||
NoCustomCursor as PlatformCustomCursor, NoCustomCursor as PlatformCustomCursorSource,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#![allow(clippy::unnecessary_cast)]
|
||||
|
||||
use std::collections::{BTreeSet, VecDeque};
|
||||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::collections::VecDeque;
|
||||
use std::num::NonZeroU32;
|
||||
use std::{fmt, hash, ptr};
|
||||
|
||||
use objc2::mutability::IsRetainable;
|
||||
|
|
@ -11,8 +11,8 @@ use objc2_foundation::{run_on_main, MainThreadBound, MainThreadMarker, NSInteger
|
|||
use objc2_ui_kit::{UIScreen, UIScreenMode};
|
||||
|
||||
use super::app_state;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::monitor::VideoModeHandle as RootVideoModeHandle;
|
||||
use crate::dpi::PhysicalPosition;
|
||||
use crate::monitor::VideoMode;
|
||||
|
||||
// Workaround for `MainThreadBound` implementing almost no traits
|
||||
#[derive(Debug)]
|
||||
|
|
@ -44,10 +44,8 @@ impl<T: IsRetainable + Message> Eq for MainThreadBoundDelegateImpls<T> {}
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
pub struct VideoModeHandle {
|
||||
pub(crate) size: (u32, u32),
|
||||
pub(crate) refresh_rate_millihertz: Option<NonZeroU32>,
|
||||
pub(crate) mode: VideoMode,
|
||||
screen_mode: MainThreadBoundDelegateImpls<UIScreenMode>,
|
||||
pub(crate) monitor: MonitorHandle,
|
||||
}
|
||||
|
||||
impl VideoModeHandle {
|
||||
|
|
@ -58,30 +56,18 @@ impl VideoModeHandle {
|
|||
) -> VideoModeHandle {
|
||||
let refresh_rate_millihertz = refresh_rate_millihertz(&uiscreen);
|
||||
let size = screen_mode.size();
|
||||
VideoModeHandle {
|
||||
size: (size.width as u32, size.height as u32),
|
||||
let mode = VideoMode {
|
||||
size: (size.width as u32, size.height as u32).into(),
|
||||
bit_depth: None,
|
||||
refresh_rate_millihertz,
|
||||
};
|
||||
|
||||
VideoModeHandle {
|
||||
mode,
|
||||
screen_mode: MainThreadBoundDelegateImpls(MainThreadBound::new(screen_mode, mtm)),
|
||||
monitor: MonitorHandle::new(uiscreen),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size.into()
|
||||
}
|
||||
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
self.refresh_rate_millihertz
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.monitor.clone()
|
||||
}
|
||||
|
||||
pub(super) fn screen_mode(&self, mtm: MainThreadMarker) -> &Retained<UIScreenMode> {
|
||||
self.screen_mode.0.get(mtm)
|
||||
}
|
||||
|
|
@ -179,44 +165,46 @@ impl MonitorHandle {
|
|||
self.ui_screen.get_on_main(|ui_screen| ui_screen.nativeScale()) as f64
|
||||
}
|
||||
|
||||
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
Some(run_on_main(|mtm| {
|
||||
VideoModeHandle::new(
|
||||
self.ui_screen(mtm).clone(),
|
||||
self.ui_screen(mtm).currentMode().unwrap(),
|
||||
mtm,
|
||||
)
|
||||
.mode
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
|
||||
pub fn video_modes_handles(&self) -> impl Iterator<Item = VideoModeHandle> {
|
||||
run_on_main(|mtm| {
|
||||
let ui_screen = self.ui_screen(mtm);
|
||||
// Use Ord impl of RootVideoModeHandle
|
||||
|
||||
let modes: BTreeSet<_> = ui_screen
|
||||
ui_screen
|
||||
.availableModes()
|
||||
.into_iter()
|
||||
.map(|mode| RootVideoModeHandle {
|
||||
video_mode: VideoModeHandle::new(ui_screen.clone(), mode, mtm),
|
||||
})
|
||||
.collect();
|
||||
|
||||
modes.into_iter().map(|mode| mode.video_mode)
|
||||
.map(|mode| VideoModeHandle::new(ui_screen.clone(), mode, mtm))
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
self.video_modes_handles().map(|handle| handle.mode)
|
||||
}
|
||||
|
||||
pub(crate) fn ui_screen(&self, mtm: MainThreadMarker) -> &Retained<UIScreen> {
|
||||
self.ui_screen.get(mtm)
|
||||
}
|
||||
|
||||
pub fn preferred_video_mode(&self) -> VideoModeHandle {
|
||||
pub fn preferred_video_mode(&self) -> VideoMode {
|
||||
run_on_main(|mtm| {
|
||||
VideoModeHandle::new(
|
||||
self.ui_screen(mtm).clone(),
|
||||
self.ui_screen(mtm).preferredMode().unwrap(),
|
||||
mtm,
|
||||
)
|
||||
.mode
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,10 +91,13 @@ impl WinitUIWindow {
|
|||
this.setRootViewController(Some(view_controller));
|
||||
|
||||
match window_attributes.fullscreen.clone().map(Into::into) {
|
||||
Some(Fullscreen::Exclusive(ref video_mode)) => {
|
||||
let monitor = video_mode.monitor();
|
||||
Some(Fullscreen::Exclusive(ref monitor, ref video_mode)) => {
|
||||
let screen = monitor.ui_screen(mtm);
|
||||
screen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
|
||||
if let Some(video_mode) =
|
||||
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
|
||||
{
|
||||
screen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
|
||||
}
|
||||
this.setScreen(screen);
|
||||
},
|
||||
Some(Fullscreen::Borderless(Some(ref monitor))) => {
|
||||
|
|
@ -312,9 +315,13 @@ impl Inner {
|
|||
pub(crate) fn set_fullscreen(&self, monitor: Option<Fullscreen>) {
|
||||
let mtm = MainThreadMarker::new().unwrap();
|
||||
let uiscreen = match &monitor {
|
||||
Some(Fullscreen::Exclusive(video_mode)) => {
|
||||
let uiscreen = video_mode.monitor.ui_screen(mtm);
|
||||
uiscreen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
|
||||
Some(Fullscreen::Exclusive(monitor, video_mode)) => {
|
||||
let uiscreen = monitor.ui_screen(mtm);
|
||||
if let Some(video_mode) =
|
||||
monitor.video_modes_handles().find(|mode| &mode.mode == video_mode)
|
||||
{
|
||||
uiscreen.setCurrentMode(Some(video_mode.screen_mode(mtm)));
|
||||
}
|
||||
uiscreen.clone()
|
||||
},
|
||||
Some(Fullscreen::Borderless(Some(monitor))) => monitor.ui_screen(mtm).clone(),
|
||||
|
|
@ -489,7 +496,7 @@ impl Window {
|
|||
let main_screen = UIScreen::mainScreen(mtm);
|
||||
let fullscreen = window_attributes.fullscreen.clone().map(Into::into);
|
||||
let screen = match fullscreen {
|
||||
Some(Fullscreen::Exclusive(ref video_mode)) => video_mode.monitor.ui_screen(mtm),
|
||||
Some(Fullscreen::Exclusive(ref monitor, _)) => monitor.ui_screen(mtm),
|
||||
Some(Fullscreen::Borderless(Some(ref monitor))) => monitor.ui_screen(mtm),
|
||||
Some(Fullscreen::Borderless(None)) | None => &main_screen,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
|
||||
|
||||
use std::env;
|
||||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||
use std::time::Duration;
|
||||
#[cfg(x11_platform)]
|
||||
|
|
@ -17,13 +16,14 @@ pub(crate) use self::common::xkb::{physicalkey_to_scancode, scancode_to_physical
|
|||
use self::x11::{XConnection, XError, XNotSupported};
|
||||
use crate::application::ApplicationHandler;
|
||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||
use crate::dpi::PhysicalPosition;
|
||||
#[cfg(x11_platform)]
|
||||
use crate::dpi::Size;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::error::{EventLoopError, NotSupportedError};
|
||||
use crate::event_loop::ActiveEventLoop;
|
||||
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
||||
use crate::keyboard::Key;
|
||||
use crate::monitor::VideoMode;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
#[cfg(x11_platform)]
|
||||
use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook};
|
||||
|
|
@ -165,46 +165,16 @@ impl MonitorHandle {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
x11_or_wayland!(match self; MonitorHandle(m) => m.current_video_mode())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> Box<dyn Iterator<Item = VideoModeHandle>> {
|
||||
pub fn video_modes(&self) -> Box<dyn Iterator<Item = VideoMode>> {
|
||||
x11_or_wayland!(match self; MonitorHandle(m) => Box::new(m.video_modes()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum VideoModeHandle {
|
||||
#[cfg(x11_platform)]
|
||||
X(x11::VideoModeHandle),
|
||||
#[cfg(wayland_platform)]
|
||||
Wayland(wayland::VideoModeHandle),
|
||||
}
|
||||
|
||||
impl VideoModeHandle {
|
||||
#[inline]
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
x11_or_wayland!(match self; VideoModeHandle(m) => m.size())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
x11_or_wayland!(match self; VideoModeHandle(m) => m.bit_depth())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
x11_or_wayland!(match self; VideoModeHandle(m) => m.refresh_rate_millihertz())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
x11_or_wayland!(match self; VideoModeHandle(m) => m.monitor(); as MonitorHandle)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct KeyEventExtra {
|
||||
pub text_with_all_modifiers: Option<SmolStr>,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Winit's Wayland backend.
|
||||
|
||||
pub use event_loop::{ActiveEventLoop, EventLoop};
|
||||
pub use output::{MonitorHandle, VideoModeHandle};
|
||||
pub use output::MonitorHandle;
|
||||
use sctk::reexports::client::protocol::wl_surface::WlSurface;
|
||||
use sctk::reexports::client::Proxy;
|
||||
pub use window::Window;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use sctk::output::{Mode, OutputData};
|
||||
use sctk::reexports::client::protocol::wl_output::WlOutput;
|
||||
use sctk::reexports::client::Proxy;
|
||||
|
||||
use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize};
|
||||
use crate::platform_impl::platform::VideoModeHandle as PlatformVideoModeHandle;
|
||||
use crate::dpi::{LogicalPosition, PhysicalPosition};
|
||||
use crate::monitor::VideoMode;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MonitorHandle {
|
||||
|
|
@ -54,27 +54,19 @@ impl MonitorHandle {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current_video_mode(&self) -> Option<PlatformVideoModeHandle> {
|
||||
pub fn current_video_mode(&self) -> Option<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(|mode| {
|
||||
PlatformVideoModeHandle::Wayland(VideoModeHandle::new(self.clone(), mode))
|
||||
})
|
||||
mode.map(wayland_mode_to_core_mode)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = PlatformVideoModeHandle> {
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
let output_data = self.proxy.data::<OutputData>().unwrap();
|
||||
let modes = output_data.with_output_info(|info| info.modes.clone());
|
||||
|
||||
let monitor = self.clone();
|
||||
|
||||
modes.into_iter().map(move |mode| {
|
||||
PlatformVideoModeHandle::Wayland(VideoModeHandle::new(monitor.clone(), mode))
|
||||
})
|
||||
modes.into_iter().map(wayland_mode_to_core_mode)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -104,38 +96,11 @@ impl std::hash::Hash for MonitorHandle {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VideoModeHandle {
|
||||
pub(crate) size: PhysicalSize<u32>,
|
||||
pub(crate) refresh_rate_millihertz: Option<NonZeroU32>,
|
||||
pub(crate) monitor: MonitorHandle,
|
||||
}
|
||||
|
||||
impl VideoModeHandle {
|
||||
fn new(monitor: MonitorHandle, mode: Mode) -> Self {
|
||||
VideoModeHandle {
|
||||
size: (mode.dimensions.0 as u32, mode.dimensions.1 as u32).into(),
|
||||
refresh_rate_millihertz: NonZeroU32::new(mode.refresh_rate as u32),
|
||||
monitor: monitor.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
self.refresh_rate_millihertz
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.monitor.clone()
|
||||
/// Convert 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(),
|
||||
bit_depth: None,
|
||||
refresh_rate_millihertz: NonZeroU32::new(mode.refresh_rate as u32),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ impl Window {
|
|||
|
||||
// Set startup mode.
|
||||
match attributes.fullscreen.map(Into::into) {
|
||||
Some(Fullscreen::Exclusive(_)) => {
|
||||
Some(Fullscreen::Exclusive(..)) => {
|
||||
warn!("`Fullscreen::Exclusive` is ignored on Wayland");
|
||||
},
|
||||
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
|
||||
|
|
@ -438,7 +438,7 @@ impl CoreWindow for Window {
|
|||
|
||||
fn set_fullscreen(&self, fullscreen: Option<CoreFullscreen>) {
|
||||
match fullscreen {
|
||||
Some(CoreFullscreen::Exclusive(_)) => {
|
||||
Some(CoreFullscreen::Exclusive(..)) => {
|
||||
warn!("`Fullscreen::Exclusive` is ignored on Wayland");
|
||||
},
|
||||
#[cfg_attr(not(x11_platform), allow(clippy::bind_instead_of_map))]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use x11rb::connection::RequestConnection;
|
||||
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
||||
use x11rb::protocol::xproto;
|
||||
|
||||
use super::{util, X11Error, XConnection};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::platform_impl::VideoModeHandle as PlatformVideoModeHandle;
|
||||
use crate::dpi::PhysicalPosition;
|
||||
use crate::monitor::VideoMode;
|
||||
|
||||
// Used for testing. This should always be committed as false.
|
||||
const DISABLE_MONITOR_LIST_CACHING: bool = false;
|
||||
|
|
@ -21,32 +21,14 @@ impl XConnection {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VideoModeHandle {
|
||||
pub(crate) current: bool,
|
||||
pub(crate) size: (u32, u32),
|
||||
pub(crate) bit_depth: Option<NonZeroU16>,
|
||||
pub(crate) refresh_rate_millihertz: Option<NonZeroU32>,
|
||||
pub(crate) mode: VideoMode,
|
||||
pub(crate) native_mode: randr::Mode,
|
||||
pub(crate) monitor: Option<MonitorHandle>,
|
||||
}
|
||||
|
||||
impl VideoModeHandle {
|
||||
#[inline]
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size.into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
self.refresh_rate_millihertz
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.monitor.clone().unwrap()
|
||||
impl From<VideoModeHandle> for VideoMode {
|
||||
fn from(handle: VideoModeHandle) -> Self {
|
||||
handle.mode
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +47,7 @@ pub struct MonitorHandle {
|
|||
/// Used to determine which windows are on this monitor
|
||||
pub(crate) rect: util::AaRect,
|
||||
/// Supported video modes on this monitor
|
||||
video_modes: Vec<VideoModeHandle>,
|
||||
pub(crate) video_modes: Vec<VideoModeHandle>,
|
||||
}
|
||||
|
||||
impl PartialEq for MonitorHandle {
|
||||
|
|
@ -159,17 +141,13 @@ impl MonitorHandle {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current_video_mode(&self) -> Option<PlatformVideoModeHandle> {
|
||||
self.video_modes.iter().find(|mode| mode.current).cloned().map(PlatformVideoModeHandle::X)
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
self.video_modes.iter().find(|mode| mode.current).cloned().map(Into::into)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = PlatformVideoModeHandle> {
|
||||
let monitor = self.clone();
|
||||
self.video_modes.clone().into_iter().map(move |mut x| {
|
||||
x.monitor = Some(monitor.clone());
|
||||
PlatformVideoModeHandle::X(x)
|
||||
})
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
self.video_modes.clone().into_iter().map(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use x11rb::protocol::randr::{self, ConnectionExt as _};
|
|||
|
||||
use super::*;
|
||||
use crate::dpi::validate_scale_factor;
|
||||
use crate::monitor::VideoMode;
|
||||
use crate::platform_impl::platform::x11::{monitor, VideoModeHandle};
|
||||
|
||||
/// Represents values of `WINIT_HIDPI_FACTOR`.
|
||||
|
|
@ -85,9 +86,11 @@ impl XConnection {
|
|||
.map(|mode| {
|
||||
VideoModeHandle {
|
||||
current: mode.id == current_mode,
|
||||
size: (mode.width.into(), mode.height.into()),
|
||||
refresh_rate_millihertz: monitor::mode_refresh_rate_millihertz(mode),
|
||||
bit_depth: NonZeroU16::new(bit_depth as u16),
|
||||
mode: VideoMode {
|
||||
size: (mode.width as u32, mode.height as u32).into(),
|
||||
refresh_rate_millihertz: monitor::mode_refresh_rate_millihertz(mode),
|
||||
bit_depth: NonZeroU16::new(bit_depth as u16),
|
||||
},
|
||||
native_mode: mode.id,
|
||||
// This is populated in `MonitorHandle::video_modes` as the
|
||||
// video mode is returned to the user
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ use crate::platform_impl::x11::{
|
|||
};
|
||||
use crate::platform_impl::{
|
||||
common, Fullscreen, MonitorHandle as PlatformMonitorHandle, PlatformCustomCursor, PlatformIcon,
|
||||
VideoModeHandle as PlatformVideoModeHandle,
|
||||
};
|
||||
use crate::window::{
|
||||
CursorGrabMode, ImePurpose, ResizeDirection, Theme, UserAttentionType, Window as CoreWindow,
|
||||
|
|
@ -327,7 +326,7 @@ impl Drop for Window {
|
|||
let xconn = &window.xconn;
|
||||
|
||||
// Restore the video mode on drop.
|
||||
if let Some(Fullscreen::Exclusive(_)) = window.fullscreen() {
|
||||
if let Some(Fullscreen::Exclusive(..)) = window.fullscreen() {
|
||||
window.set_fullscreen(None);
|
||||
}
|
||||
|
||||
|
|
@ -1035,20 +1034,17 @@ impl UnownedWindow {
|
|||
// fullscreen, so we can restore it upon exit, as XRandR does not
|
||||
// provide a mechanism to set this per app-session or restore this
|
||||
// to the desktop video mode as macOS and Windows do
|
||||
(&None, &Some(Fullscreen::Exclusive(PlatformVideoModeHandle::X(ref video_mode))))
|
||||
| (
|
||||
&Some(Fullscreen::Borderless(_)),
|
||||
&Some(Fullscreen::Exclusive(PlatformVideoModeHandle::X(ref video_mode))),
|
||||
) => {
|
||||
let monitor = video_mode.monitor.as_ref().unwrap();
|
||||
(&None, &Some(Fullscreen::Exclusive(ref monitor, _)))
|
||||
| (&Some(Fullscreen::Borderless(_)), &Some(Fullscreen::Exclusive(ref monitor, _))) => {
|
||||
let id = monitor.native_identifier();
|
||||
shared_state_lock.desktop_video_mode = Some((
|
||||
monitor.id,
|
||||
self.xconn.get_crtc_mode(monitor.id).expect("Failed to get desktop video mode"),
|
||||
id,
|
||||
self.xconn.get_crtc_mode(id).expect("Failed to get desktop video mode"),
|
||||
));
|
||||
},
|
||||
// Restore desktop video mode upon exiting exclusive fullscreen
|
||||
(&Some(Fullscreen::Exclusive(_)), &None)
|
||||
| (&Some(Fullscreen::Exclusive(_)), &Some(Fullscreen::Borderless(_))) => {
|
||||
(&Some(Fullscreen::Exclusive(..)), &None)
|
||||
| (&Some(Fullscreen::Exclusive(..)), &Some(Fullscreen::Borderless(_))) => {
|
||||
let (monitor_id, mode_id) = shared_state_lock.desktop_video_mode.take().unwrap();
|
||||
self.xconn
|
||||
.set_crtc_config(monitor_id, mode_id)
|
||||
|
|
@ -1072,8 +1068,8 @@ impl UnownedWindow {
|
|||
},
|
||||
Some(fullscreen) => {
|
||||
let (video_mode, monitor) = match fullscreen {
|
||||
Fullscreen::Exclusive(PlatformVideoModeHandle::X(ref video_mode)) => {
|
||||
(Some(video_mode), video_mode.monitor.clone().unwrap())
|
||||
Fullscreen::Exclusive(PlatformMonitorHandle::X(monitor), video_mode) => {
|
||||
(Some(video_mode), monitor.clone())
|
||||
},
|
||||
Fullscreen::Borderless(Some(PlatformMonitorHandle::X(monitor))) => {
|
||||
(None, monitor)
|
||||
|
|
@ -1090,7 +1086,15 @@ impl UnownedWindow {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
if let Some(video_mode) = video_mode {
|
||||
if let Some(native_mode) = video_mode.and_then(|requested| {
|
||||
monitor.video_modes.iter().find_map(|mode| {
|
||||
if mode.mode == requested {
|
||||
Some(mode.native_mode)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}) {
|
||||
// FIXME: this is actually not correct if we're setting the
|
||||
// video mode to a resolution higher than the current
|
||||
// desktop resolution, because XRandR does not automatically
|
||||
|
|
@ -1117,7 +1121,7 @@ impl UnownedWindow {
|
|||
// this will make someone unhappy, but it's very unusual for
|
||||
// games to want to do this anyway).
|
||||
self.xconn
|
||||
.set_crtc_config(monitor.id, video_mode.native_mode)
|
||||
.set_crtc_config(monitor.id, native_mode)
|
||||
.expect("failed to set video mode");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::monitor::{MonitorHandle as RootMonitorHandle, VideoModeHandle as RootVideoModeHandle};
|
||||
use crate::monitor::{MonitorHandle as RootMonitorHandle, VideoMode};
|
||||
use crate::window::Fullscreen as RootFullscreen;
|
||||
|
||||
#[cfg(android_platform)]
|
||||
|
|
@ -30,17 +30,19 @@ use self::web as platform;
|
|||
use self::windows as platform;
|
||||
|
||||
/// Helper for converting between platform-specific and generic
|
||||
/// [`VideoModeHandle`]/[`MonitorHandle`]
|
||||
/// [`VideoMode`]/[`MonitorHandle`]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) enum Fullscreen {
|
||||
Exclusive(VideoModeHandle),
|
||||
Exclusive(MonitorHandle, VideoMode),
|
||||
Borderless(Option<MonitorHandle>),
|
||||
}
|
||||
|
||||
impl From<RootFullscreen> for Fullscreen {
|
||||
fn from(f: RootFullscreen) -> Self {
|
||||
match f {
|
||||
RootFullscreen::Exclusive(mode) => Self::Exclusive(mode.video_mode),
|
||||
RootFullscreen::Exclusive(handle, video_mode) => {
|
||||
Self::Exclusive(handle.inner, video_mode)
|
||||
},
|
||||
RootFullscreen::Borderless(Some(handle)) => Self::Borderless(Some(handle.inner)),
|
||||
RootFullscreen::Borderless(None) => Self::Borderless(None),
|
||||
}
|
||||
|
|
@ -50,8 +52,8 @@ impl From<RootFullscreen> for Fullscreen {
|
|||
impl From<Fullscreen> for RootFullscreen {
|
||||
fn from(f: Fullscreen) -> Self {
|
||||
match f {
|
||||
Fullscreen::Exclusive(video_mode) => {
|
||||
Self::Exclusive(RootVideoModeHandle { video_mode })
|
||||
Fullscreen::Exclusive(inner, video_mode) => {
|
||||
Self::Exclusive(RootMonitorHandle { inner }, video_mode)
|
||||
},
|
||||
Fullscreen::Borderless(Some(inner)) => {
|
||||
Self::Borderless(Some(RootMonitorHandle { inner }))
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
#![cfg(target_os = "redox")]
|
||||
|
||||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::{fmt, str};
|
||||
|
||||
use smol_str::SmolStr;
|
||||
|
||||
pub(crate) use self::event_loop::{ActiveEventLoop, EventLoop};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::keyboard::Key;
|
||||
mod event_loop;
|
||||
|
||||
pub use self::window::Window;
|
||||
use crate::dpi::PhysicalPosition;
|
||||
use crate::keyboard::Key;
|
||||
use crate::monitor::VideoMode;
|
||||
|
||||
mod event_loop;
|
||||
mod window;
|
||||
|
||||
pub(crate) use crate::cursor::{
|
||||
|
|
@ -151,38 +151,13 @@ impl MonitorHandle {
|
|||
1.0 // TODO
|
||||
}
|
||||
|
||||
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
// (it is guaranteed to support 32 bit color though)
|
||||
Some(VideoModeHandle { monitor: self.clone() })
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
|
||||
self.current_video_mode().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct VideoModeHandle {
|
||||
monitor: MonitorHandle,
|
||||
}
|
||||
|
||||
impl VideoModeHandle {
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
// TODO
|
||||
PhysicalSize::default()
|
||||
}
|
||||
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
// TODO
|
||||
None
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.monitor.clone()
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
std::iter::empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ pub(crate) use self::event_loop::{
|
|||
pub(crate) use self::keyboard::KeyEventExtra;
|
||||
pub(crate) use self::monitor::{
|
||||
HasMonitorPermissionFuture, MonitorHandle, MonitorPermissionFuture, OrientationLockFuture,
|
||||
VideoModeHandle,
|
||||
};
|
||||
use self::web_sys as backend;
|
||||
pub use self::window::{PlatformSpecificWindowAttributes, Window};
|
||||
|
|
|
|||
|
|
@ -3,9 +3,8 @@ use std::cmp::Ordering;
|
|||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::future::Future;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::{self, Once};
|
||||
use std::mem;
|
||||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::num::NonZeroU16;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::pin::Pin;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
|
@ -29,7 +28,7 @@ use super::main_thread::MainThreadMarker;
|
|||
use super::r#async::{Dispatcher, Notified, Notifier};
|
||||
use super::web_sys::{Engine, EventListenerHandle};
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::monitor::{MonitorHandle as RootMonitorHandle, VideoMode};
|
||||
use crate::platform::web::{
|
||||
MonitorPermissionError, Orientation, OrientationData, OrientationLock, OrientationLockError,
|
||||
};
|
||||
|
|
@ -59,12 +58,16 @@ impl MonitorHandle {
|
|||
self.inner.queue(|inner| inner.name())
|
||||
}
|
||||
|
||||
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
||||
Some(VideoModeHandle(self.clone()))
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
Some(VideoMode {
|
||||
size: self.inner.queue(|inner| inner.size()),
|
||||
bit_depth: self.inner.queue(|inner| inner.bit_depth()),
|
||||
refresh_rate_millihertz: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> Once<VideoModeHandle> {
|
||||
iter::once(VideoModeHandle(self.clone()))
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
self.current_video_mode().into_iter()
|
||||
}
|
||||
|
||||
pub fn orientation(&self) -> OrientationData {
|
||||
|
|
@ -252,35 +255,6 @@ impl OrientationLockError {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, Hash, PartialEq)]
|
||||
pub struct VideoModeHandle(MonitorHandle);
|
||||
|
||||
impl VideoModeHandle {
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.0.inner.queue(|inner| inner.size())
|
||||
}
|
||||
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
self.0.inner.queue(|inner| inner.bit_depth())
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for VideoModeHandle {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
let (size, bit_depth) = self.0.inner.queue(|this| (this.size(), this.bit_depth()));
|
||||
|
||||
f.debug_struct("MonitorHandle").field("size", &size).field("bit_depth", &bit_depth).finish()
|
||||
}
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
window: WindowExt,
|
||||
engine: Option<Engine>,
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ pub(crate) fn request_fullscreen(
|
|||
let canvas: &RequestFullscreen = canvas.unchecked_ref();
|
||||
|
||||
match fullscreen {
|
||||
Fullscreen::Exclusive(_) => error!("Exclusive full screen mode is not supported"),
|
||||
Fullscreen::Exclusive(..) => error!("Exclusive full screen mode is not supported"),
|
||||
Fullscreen::Borderless(Some(monitor)) => {
|
||||
if !monitor::has_screen_details_support(window) {
|
||||
error!(
|
||||
|
|
|
|||
|
|
@ -1311,8 +1311,8 @@ unsafe fn public_window_callback_inner(
|
|||
*fullscreen_monitor = Some(MonitorHandle::new(new_monitor));
|
||||
}
|
||||
},
|
||||
Fullscreen::Exclusive(ref video_mode) => {
|
||||
let old_monitor = video_mode.monitor.hmonitor();
|
||||
Fullscreen::Exclusive(ref monitor, _) => {
|
||||
let old_monitor = monitor.hmonitor();
|
||||
if let Ok(old_monitor_info) = monitor::get_monitor_info(old_monitor) {
|
||||
let old_monitor_rect = old_monitor_info.monitorInfo.rcMonitor;
|
||||
window_pos.x = old_monitor_rect.left;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ pub(crate) use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes
|
|||
pub use self::icon::WinIcon as PlatformIcon;
|
||||
pub(crate) use self::icon::{SelectedCursor, WinCursor as PlatformCustomCursor, WinIcon};
|
||||
pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
pub(crate) use self::monitor::{MonitorHandle, VideoModeHandle};
|
||||
pub(crate) use self::monitor::MonitorHandle;
|
||||
pub(crate) use self::window::Window;
|
||||
pub(crate) use crate::cursor::OnlyCursorImageSource as PlatformCustomCursorSource;
|
||||
use crate::event::DeviceId;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::collections::{BTreeSet, VecDeque};
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
use std::hash::Hash;
|
||||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
use std::{io, mem, ptr};
|
||||
|
|
@ -13,26 +13,20 @@ use windows_sys::Win32::Graphics::Gdi::{
|
|||
|
||||
use super::util::decode_wide;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::monitor::VideoModeHandle as RootVideoModeHandle;
|
||||
use crate::monitor::VideoMode;
|
||||
use crate::platform_impl::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi};
|
||||
use crate::platform_impl::platform::util::has_flag;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VideoModeHandle {
|
||||
pub(crate) size: (u32, u32),
|
||||
pub(crate) bit_depth: Option<NonZeroU16>,
|
||||
pub(crate) refresh_rate_millihertz: Option<NonZeroU32>,
|
||||
pub(crate) monitor: MonitorHandle,
|
||||
pub(crate) mode: VideoMode,
|
||||
// DEVMODEW is huge so we box it to avoid blowing up the size of winit::window::Fullscreen
|
||||
pub(crate) native_video_mode: Box<DEVMODEW>,
|
||||
}
|
||||
|
||||
impl PartialEq for VideoModeHandle {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.size == other.size
|
||||
&& self.bit_depth == other.bit_depth
|
||||
&& self.refresh_rate_millihertz == other.refresh_rate_millihertz
|
||||
&& self.monitor == other.monitor
|
||||
self.mode == other.mode
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,53 +34,29 @@ impl Eq for VideoModeHandle {}
|
|||
|
||||
impl std::hash::Hash for VideoModeHandle {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.size.hash(state);
|
||||
self.bit_depth.hash(state);
|
||||
self.refresh_rate_millihertz.hash(state);
|
||||
self.monitor.hash(state);
|
||||
self.mode.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for VideoModeHandle {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("VideoModeHandle")
|
||||
.field("size", &self.size)
|
||||
.field("bit_depth", &self.bit_depth)
|
||||
.field("refresh_rate_millihertz", &self.refresh_rate_millihertz)
|
||||
.field("monitor", &self.monitor)
|
||||
.finish()
|
||||
f.debug_struct("VideoMode").field("mode", &self.mode).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoModeHandle {
|
||||
fn new(monitor: MonitorHandle, mode: DEVMODEW) -> Self {
|
||||
fn new(native_video_mode: DEVMODEW) -> Self {
|
||||
const REQUIRED_FIELDS: u32 =
|
||||
DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
|
||||
assert!(has_flag(mode.dmFields, REQUIRED_FIELDS));
|
||||
assert!(has_flag(native_video_mode.dmFields, REQUIRED_FIELDS));
|
||||
|
||||
VideoModeHandle {
|
||||
size: (mode.dmPelsWidth, mode.dmPelsHeight),
|
||||
bit_depth: NonZeroU16::new(mode.dmBitsPerPel as u16),
|
||||
refresh_rate_millihertz: NonZeroU32::new(mode.dmDisplayFrequency * 1000),
|
||||
monitor,
|
||||
native_video_mode: Box::new(mode),
|
||||
}
|
||||
}
|
||||
let mode = VideoMode {
|
||||
size: (native_video_mode.dmPelsWidth, native_video_mode.dmPelsHeight).into(),
|
||||
bit_depth: NonZeroU16::new(native_video_mode.dmBitsPerPel as u16),
|
||||
refresh_rate_millihertz: NonZeroU32::new(native_video_mode.dmDisplayFrequency * 1000),
|
||||
};
|
||||
|
||||
pub fn size(&self) -> PhysicalSize<u32> {
|
||||
self.size.into()
|
||||
}
|
||||
|
||||
pub fn bit_depth(&self) -> Option<NonZeroU16> {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
pub fn refresh_rate_millihertz(&self) -> Option<NonZeroU32> {
|
||||
self.refresh_rate_millihertz
|
||||
}
|
||||
|
||||
pub fn monitor(&self) -> MonitorHandle {
|
||||
self.monitor.clone()
|
||||
VideoModeHandle { mode, native_video_mode: Box::new(native_video_mode) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +163,7 @@ impl MonitorHandle {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current_video_mode(&self) -> Option<VideoModeHandle> {
|
||||
pub fn current_video_mode(&self) -> Option<VideoMode> {
|
||||
let monitor_info = get_monitor_info(self.0).ok()?;
|
||||
let device_name = monitor_info.szDevice.as_ptr();
|
||||
unsafe {
|
||||
|
|
@ -204,29 +174,26 @@ impl MonitorHandle {
|
|||
{
|
||||
None
|
||||
} else {
|
||||
Some(VideoModeHandle::new(self.clone(), mode))
|
||||
Some(VideoModeHandle::new(mode).mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoModeHandle> {
|
||||
pub(crate) fn video_mode_handles(&self) -> impl Iterator<Item = VideoModeHandle> {
|
||||
// EnumDisplaySettingsExW can return duplicate values (or some of the
|
||||
// fields are probably changing, but we aren't looking at those fields
|
||||
// anyway), so we're using a BTreeSet deduplicate
|
||||
let mut modes = BTreeSet::<RootVideoModeHandle>::new();
|
||||
let mod_map = |mode: RootVideoModeHandle| mode.video_mode;
|
||||
let mut modes = HashSet::<VideoModeHandle>::new();
|
||||
|
||||
let monitor_info = match get_monitor_info(self.0) {
|
||||
Ok(monitor_info) => monitor_info,
|
||||
Err(error) => {
|
||||
tracing::warn!("Error from get_monitor_info: {error}");
|
||||
return modes.into_iter().map(mod_map);
|
||||
return modes.into_iter();
|
||||
},
|
||||
};
|
||||
|
||||
let device_name = monitor_info.szDevice.as_ptr();
|
||||
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let mut mode: DEVMODEW = unsafe { mem::zeroed() };
|
||||
|
|
@ -236,13 +203,15 @@ impl MonitorHandle {
|
|||
}
|
||||
|
||||
// Use Ord impl of RootVideoModeHandle
|
||||
modes.insert(RootVideoModeHandle {
|
||||
video_mode: VideoModeHandle::new(self.clone(), mode),
|
||||
});
|
||||
modes.insert(VideoModeHandle::new(mode));
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
modes.into_iter().map(mod_map)
|
||||
modes.into_iter()
|
||||
}
|
||||
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
self.video_mode_handles().map(|mode| mode.mode)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ impl Window {
|
|||
impl Drop for Window {
|
||||
fn drop(&mut self) {
|
||||
// Restore fullscreen video mode on exit.
|
||||
if matches!(self.fullscreen(), Some(CoreFullscreen::Exclusive(_))) {
|
||||
if matches!(self.fullscreen(), Some(CoreFullscreen::Exclusive(_, _))) {
|
||||
self.set_fullscreen(None);
|
||||
}
|
||||
|
||||
|
|
@ -771,9 +771,13 @@ impl CoreWindow for Window {
|
|||
// Change video mode if we're transitioning to or from exclusive
|
||||
// fullscreen
|
||||
match (&old_fullscreen, &fullscreen) {
|
||||
(_, Some(Fullscreen::Exclusive(video_mode))) => {
|
||||
let monitor = video_mode.monitor();
|
||||
(_, Some(Fullscreen::Exclusive(monitor, video_mode))) => {
|
||||
let monitor_info = monitor::get_monitor_info(monitor.hmonitor()).unwrap();
|
||||
let video_mode =
|
||||
match monitor.video_mode_handles().find(|mode| &mode.mode == video_mode) {
|
||||
Some(monitor) => monitor,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let res = unsafe {
|
||||
ChangeDisplaySettingsExW(
|
||||
|
|
@ -791,7 +795,7 @@ impl CoreWindow for Window {
|
|||
debug_assert!(res != DISP_CHANGE_FAILED);
|
||||
assert_eq!(res, DISP_CHANGE_SUCCESSFUL);
|
||||
},
|
||||
(Some(Fullscreen::Exclusive(_)), _) => {
|
||||
(Some(Fullscreen::Exclusive(..)), _) => {
|
||||
let res = unsafe {
|
||||
ChangeDisplaySettingsExW(
|
||||
ptr::null(),
|
||||
|
|
@ -828,7 +832,7 @@ impl CoreWindow for Window {
|
|||
WindowState::set_window_flags(window_state.lock().unwrap(), window, |f| {
|
||||
f.set(
|
||||
WindowFlags::MARKER_EXCLUSIVE_FULLSCREEN,
|
||||
matches!(fullscreen, Some(Fullscreen::Exclusive(_))),
|
||||
matches!(fullscreen, Some(Fullscreen::Exclusive(_, _))),
|
||||
);
|
||||
f.set(
|
||||
WindowFlags::MARKER_BORDERLESS_FULLSCREEN,
|
||||
|
|
@ -858,7 +862,7 @@ impl CoreWindow for Window {
|
|||
window_state.lock().unwrap().saved_window = Some(SavedWindow { placement });
|
||||
|
||||
let monitor = match &fullscreen {
|
||||
Fullscreen::Exclusive(video_mode) => video_mode.monitor(),
|
||||
Fullscreen::Exclusive(monitor, _) => monitor.clone(),
|
||||
Fullscreen::Borderless(Some(monitor)) => monitor.clone(),
|
||||
Fullscreen::Borderless(None) => monitor::current_monitor(window),
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue