mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 05:21:31 +11:00
Move fullscreen modes to not touch physical resolutions (#270)
* Fix X11 screen resolution change using XrandR The previous XF86 resolution switching was broken and everything seems to have moved on to xrandr. Use that instead while cleaning up the code a bit as well. * Use XRandR for actual multiscreen support in X11 * Use actual monitor names in X11 * Get rid of ptr::read usage in X11 * Use a bog standard Vec instead of VecDeque * Get rid of the XRandR mode switching stuff Wayland has made the decision that apps shouldn't change screen resolutions and just take the screens as they've been setup. In the modern world where GPU scaling is cheap and LCD panels are scaling anyway it makes no sense to make "physical" resolution changes when software should be taking care of it. This massively simplifies the code and makes it easier to extend to more niche setups like MST and videowalls. * Rename fullscreen options to match new semantics * Implement XRandR 1.5 support * Get rid of the FullScreen enum Moving to just having two states None and Some(MonitorId) and then being able to set full screen in the current monitor with something like: window.set_fullscreen(Some(window.current_monitor())); * Implement Window::get_current_monitor() Do it by iterating over the available monitors and finding which has the biggest overlap with the window. For this MonitorId needs a new get_position() that needs to be implemented for all platforms. * Add unimplemented get_position() to all MonitorId * Make get_current_monitor() platform specific * Add unimplemented get_current_monitor() to all * Implement proper primary monitor selection in X11 * Shut up some warnings * Remove libxxf86vm package from travis Since we're no longer using XF86 there's no need to keep the package around for CI. * Don't use new struct syntax * Fix indentation * Adjust Android/iOS fullscreen/maximized On Android and iOS we can assume single screen apps that are already fullscreen and maximized so there are a few methods that are implemented by just returning a fixed value or not doing anything. * Mark OSX/Win fullscreen/maximized unimplemented()! These would be safe as no-ops but we should make it explicit so there is more of an incentive to actually implement them.
This commit is contained in:
parent
342d5d8587
commit
59c33d2c6a
|
@ -6,11 +6,6 @@ rust:
|
|||
|
||||
cache: cargo
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libxxf86vm-dev
|
||||
|
||||
install:
|
||||
- rustup self update
|
||||
- |
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
extern crate winit;
|
||||
|
||||
use std::io::{self, Write};
|
||||
use winit::{ControlFlow, Event, WindowEvent, FullScreenState};
|
||||
use winit::{ControlFlow, Event, WindowEvent};
|
||||
|
||||
fn main() {
|
||||
let mut events_loop = winit::EventsLoop::new();
|
||||
|
@ -27,7 +27,7 @@ fn main() {
|
|||
|
||||
let _window = winit::WindowBuilder::new()
|
||||
.with_title("Hello world!")
|
||||
.with_fullscreen(FullScreenState::Exclusive(monitor))
|
||||
.with_fullscreen(Some(monitor))
|
||||
.build(&events_loop)
|
||||
.unwrap();
|
||||
|
||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -379,14 +379,6 @@ pub enum MouseCursor {
|
|||
RowResize,
|
||||
}
|
||||
|
||||
/// Describes if the Window is in one of the fullscreen modes
|
||||
#[derive(Clone)]
|
||||
pub enum FullScreenState {
|
||||
None,
|
||||
Windowed,
|
||||
Exclusive(MonitorId),
|
||||
}
|
||||
|
||||
/// Describes how winit handles the cursor.
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum CursorState {
|
||||
|
@ -426,7 +418,7 @@ pub struct WindowAttributes {
|
|||
/// Whether the window should be set as fullscreen upon creation.
|
||||
///
|
||||
/// The default is `None`.
|
||||
pub fullscreen: FullScreenState,
|
||||
pub fullscreen: Option<MonitorId>,
|
||||
|
||||
/// The title of the window in the title bar.
|
||||
///
|
||||
|
@ -468,7 +460,7 @@ impl Default for WindowAttributes {
|
|||
max_dimensions: None,
|
||||
title: "winit window".to_owned(),
|
||||
maximized: false,
|
||||
fullscreen: FullScreenState::None,
|
||||
fullscreen: None,
|
||||
visible: true,
|
||||
transparent: false,
|
||||
decorations: true,
|
||||
|
|
|
@ -9,12 +9,12 @@ use {CreationError, Event, WindowEvent, MouseCursor};
|
|||
use CreationError::OsError;
|
||||
use WindowId as RootWindowId;
|
||||
use events::{Touch, TouchPhase};
|
||||
use window::MonitorId as RootMonitorId;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use CursorState;
|
||||
use WindowAttributes;
|
||||
use FullScreenState;
|
||||
|
||||
pub struct EventsLoop {
|
||||
event_rx: Receiver<android_glue::Event>,
|
||||
|
@ -152,6 +152,12 @@ impl MonitorId {
|
|||
pub fn get_dimensions(&self) -> (u32, u32) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
// Android assumes single screen
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
|
@ -258,10 +264,17 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, _maximized: bool) {
|
||||
// Android has single screen maximized apps so nothing to do
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_fullscreen(&self, _state: FullScreenState) {
|
||||
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
||||
// Android has single screen maximized apps so nothing to do
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||
RootMonitorId{inner: MonitorId}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> WindowId {
|
||||
|
|
|
@ -70,11 +70,12 @@ use libc::c_int;
|
|||
use objc::runtime::{Class, Object, Sel, BOOL, YES };
|
||||
use objc::declare::{ ClassDecl };
|
||||
|
||||
use { CreationError, CursorState, MouseCursor, WindowAttributes, FullScreenState };
|
||||
use { CreationError, CursorState, MouseCursor, WindowAttributes };
|
||||
use WindowId as RootEventId;
|
||||
use WindowEvent;
|
||||
use Event;
|
||||
use events::{ Touch, TouchPhase };
|
||||
use window::MonitorId as RootMonitorId;
|
||||
|
||||
mod ffi;
|
||||
use self::ffi::{
|
||||
|
@ -138,6 +139,12 @@ impl MonitorId {
|
|||
pub fn get_dimensions(&self) -> (u32, u32) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
// iOS assumes single screen
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventsLoop {
|
||||
|
@ -341,11 +348,18 @@ impl Window {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
pub fn set_maximized(&self, _maximized: bool) {
|
||||
// iOS has single screen maximized apps so nothing to do
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_fullscreen(&self, state: FullScreenState) {
|
||||
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
||||
// iOS has single screen maximized apps so nothing to do
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||
RootMonitorId{inner: MonitorId}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::collections::VecDeque;
|
|||
use std::sync::Arc;
|
||||
use std::env;
|
||||
|
||||
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow, FullScreenState};
|
||||
use {CreationError, CursorState, EventsLoopClosed, MouseCursor, ControlFlow};
|
||||
use libc;
|
||||
|
||||
use self::x11::XConnection;
|
||||
|
@ -12,6 +12,7 @@ use self::x11::XError;
|
|||
use self::x11::ffi::XVisualInfo;
|
||||
|
||||
pub use self::x11::XNotSupported;
|
||||
use window::MonitorId as RootMonitorId;
|
||||
|
||||
mod dlopen;
|
||||
pub mod wayland;
|
||||
|
@ -85,6 +86,14 @@ impl MonitorId {
|
|||
&MonitorId::Wayland(ref m) => m.get_dimensions(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
match self {
|
||||
&MonitorId::X(ref m) => m.get_position(),
|
||||
&MonitorId::Wayland(ref m) => m.get_position(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
@ -236,12 +245,20 @@ impl Window {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_fullscreen(&self, state: FullScreenState) {
|
||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
||||
match self {
|
||||
&Window::X(ref w) => w.set_fullscreen(state),
|
||||
&Window::X(ref w) => w.set_fullscreen(monitor),
|
||||
&Window::Wayland(ref _w) => {},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||
match self {
|
||||
&Window::X(ref w) => RootMonitorId{inner: MonitorId::X(w.get_current_monitor())},
|
||||
&Window::Wayland(ref w) => RootMonitorId{inner: MonitorId::Wayland(w.get_current_monitor())},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)
|
||||
|
|
|
@ -37,6 +37,7 @@ struct OutputInfo {
|
|||
id: u32,
|
||||
scale: f32,
|
||||
pix_size: (u32, u32),
|
||||
pix_pos: (u32, u32),
|
||||
name: String
|
||||
}
|
||||
|
||||
|
@ -47,6 +48,7 @@ impl OutputInfo {
|
|||
id: id,
|
||||
scale: 1.0,
|
||||
pix_size: (0, 0),
|
||||
pix_pos: (0, 0),
|
||||
name: "".into()
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +155,7 @@ impl wl_output::Handler for WaylandEnv {
|
|||
fn geometry(&mut self,
|
||||
_: &mut EventQueueHandle,
|
||||
proxy: &wl_output::WlOutput,
|
||||
_x: i32, _y: i32,
|
||||
x: i32, y: i32,
|
||||
_physical_width: i32, _physical_height: i32,
|
||||
_subpixel: wl_output::Subpixel,
|
||||
make: String, model: String,
|
||||
|
@ -161,6 +163,7 @@ impl wl_output::Handler for WaylandEnv {
|
|||
{
|
||||
for m in self.monitors.iter_mut().filter(|m| m.output.equals(proxy)) {
|
||||
m.name = format!("{} ({})", model, make);
|
||||
m.pix_pos = (x as u32, y as u32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -386,6 +389,17 @@ impl MonitorId {
|
|||
// if we reach here, this monitor does not exist any more
|
||||
(0,0)
|
||||
}
|
||||
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
let mut guard = self.ctxt.evq.lock().unwrap();
|
||||
let state = guard.state();
|
||||
let env = state.get_handler::<WaylandEnv>(self.ctxt.env_id);
|
||||
for m in env.monitors.iter().filter(|m| m.id == self.id) {
|
||||
return m.pix_pos
|
||||
}
|
||||
// if we reach here, this monitor does not exist any more
|
||||
(0,0)
|
||||
}
|
||||
}
|
||||
|
||||
// a handler to release the ressources acquired to draw the initial white screen as soon as
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::cmp;
|
||||
|
||||
use wayland_client::{EventQueue, EventQueueHandle, Proxy};
|
||||
use wayland_client::protocol::{wl_display,wl_surface};
|
||||
|
||||
use {CreationError, MouseCursor, CursorState, WindowAttributes, FullScreenState};
|
||||
use {CreationError, MouseCursor, CursorState, WindowAttributes};
|
||||
use platform::MonitorId as PlatformMonitorId;
|
||||
use window::MonitorId as RootMonitorId;
|
||||
use platform::wayland::MonitorId as WaylandMonitorId;
|
||||
use platform::wayland::context::get_available_monitors;
|
||||
|
||||
use super::{WaylandContext, EventsLoop};
|
||||
use super::wayland_window;
|
||||
|
@ -56,7 +59,7 @@ impl Window {
|
|||
*(decorated.handler()) = Some(DecoratedHandler::new());
|
||||
|
||||
// set fullscreen if necessary
|
||||
if let FullScreenState::Exclusive(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = attributes.fullscreen {
|
||||
if let Some(RootMonitorId { inner: PlatformMonitorId::Wayland(ref monitor_id) }) = attributes.fullscreen {
|
||||
ctxt.with_output(monitor_id.clone(), |output| {
|
||||
decorated.set_fullscreen(Some(output))
|
||||
});
|
||||
|
@ -175,6 +178,41 @@ impl Window {
|
|||
pub fn get_surface(&self) -> &wl_surface::WlSurface {
|
||||
&self.surface
|
||||
}
|
||||
|
||||
pub fn get_current_monitor(&self) -> WaylandMonitorId {
|
||||
let monitors = get_available_monitors(&self.ctxt);
|
||||
let default = monitors[0].clone();
|
||||
|
||||
let (wx,wy) = match self.get_position() {
|
||||
Some(val) => (cmp::max(0,val.0) as u32, cmp::max(0,val.1) as u32),
|
||||
None=> return default,
|
||||
};
|
||||
let (ww,wh) = match self.get_outer_size() {
|
||||
Some(val) => val,
|
||||
None=> return default,
|
||||
};
|
||||
// Opposite corner coordinates
|
||||
let (wxo, wyo) = (wx+ww-1, wy+wh-1);
|
||||
|
||||
// Find the monitor with the biggest overlap with the window
|
||||
let mut overlap = 0;
|
||||
let mut find = default;
|
||||
for monitor in monitors {
|
||||
let (mx, my) = monitor.get_position();
|
||||
let (mw, mh) = monitor.get_dimensions();
|
||||
let (mxo, myo) = (mx+mw-1, my+mh-1);
|
||||
let (ox, oy) = (cmp::max(wx, mx), cmp::max(wy, my));
|
||||
let (oxo, oyo) = (cmp::min(wxo, mxo), cmp::min(wyo, myo));
|
||||
let osize = if ox <= oxo || oy <= oyo { 0 } else { (oxo-ox)*(oyo-oy) };
|
||||
|
||||
if osize > overlap {
|
||||
overlap = osize;
|
||||
find = monitor;
|
||||
}
|
||||
}
|
||||
|
||||
find
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Window {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
pub use x11_dl::keysym::*;
|
||||
pub use x11_dl::xcursor::*;
|
||||
pub use x11_dl::xf86vmode::*;
|
||||
pub use x11_dl::xlib::*;
|
||||
pub use x11_dl::xinput::*;
|
||||
pub use x11_dl::xinput2::*;
|
||||
pub use x11_dl::xlib_xcb::*;
|
||||
pub use x11_dl::error::OpenError;
|
||||
pub use x11_dl::xrandr::*;
|
||||
|
|
|
@ -1,43 +1,104 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use std::slice;
|
||||
|
||||
use super::XConnection;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MonitorId(pub Arc<XConnection>, pub u32);
|
||||
pub struct MonitorId {
|
||||
/// The actual id
|
||||
id: u32,
|
||||
/// The name of the monitor
|
||||
name: String,
|
||||
/// The size of the monitor
|
||||
dimensions: (u32, u32),
|
||||
/// The position of the monitor in the X screen
|
||||
position: (u32, u32),
|
||||
/// If the monitor is the primary one
|
||||
primary: bool,
|
||||
}
|
||||
|
||||
pub fn get_available_monitors(x: &Arc<XConnection>) -> VecDeque<MonitorId> {
|
||||
let nb_monitors = unsafe { (x.xlib.XScreenCount)(x.display) };
|
||||
x.check_errors().expect("Failed to call XScreenCount");
|
||||
pub fn get_available_monitors(x: &Arc<XConnection>) -> Vec<MonitorId> {
|
||||
let mut available = Vec::new();
|
||||
unsafe {
|
||||
let root = (x.xlib.XDefaultRootWindow)(x.display);
|
||||
let resources = (x.xrandr.XRRGetScreenResources)(x.display, root);
|
||||
|
||||
let mut monitors = VecDeque::new();
|
||||
monitors.extend((0 .. nb_monitors).map(|i| MonitorId(x.clone(), i as u32)));
|
||||
monitors
|
||||
let mut major = 0;
|
||||
let mut minor = 0;
|
||||
(x.xrandr.XRRQueryVersion)(x.display, &mut major, &mut minor);
|
||||
if ((major as u64)<<32)+(minor as u64) >= (1<<32)+5 {
|
||||
// We're in XRandR >= 1.5, enumerate Monitors to handle things like MST and videowalls
|
||||
let mut nmonitors = 0;
|
||||
let monitors = (x.xrandr.XRRGetMonitors)(x.display, root, 1, &mut nmonitors);
|
||||
for i in 0..nmonitors {
|
||||
let monitor = *(monitors.offset(i as isize));
|
||||
let output = (x.xrandr.XRRGetOutputInfo)(x.display, resources, *(monitor.outputs.offset(0)));
|
||||
let nameslice = slice::from_raw_parts((*output).name as *mut u8, (*output).nameLen as usize);
|
||||
let name = String::from_utf8_lossy(nameslice).into_owned();
|
||||
(x.xrandr.XRRFreeOutputInfo)(output);
|
||||
available.push(MonitorId{
|
||||
id: i as u32,
|
||||
name,
|
||||
dimensions: (monitor.width as u32, monitor.height as u32),
|
||||
position: (monitor.x as u32, monitor.y as u32),
|
||||
primary: (monitor.primary != 0),
|
||||
});
|
||||
}
|
||||
(x.xrandr.XRRFreeMonitors)(monitors);
|
||||
} else {
|
||||
// We're in XRandR < 1.5, enumerate CRTCs. Everything will work but MST and
|
||||
// videowall setups will show more monitors than the logical groups the user
|
||||
// cares about
|
||||
for i in 0..(*resources).ncrtc {
|
||||
let crtcid = *((*resources).crtcs.offset(i as isize));
|
||||
let crtc = (x.xrandr.XRRGetCrtcInfo)(x.display, resources, crtcid);
|
||||
if (*crtc).width > 0 && (*crtc).height > 0 && (*crtc).noutput > 0 {
|
||||
let output = (x.xrandr.XRRGetOutputInfo)(x.display, resources, *((*crtc).outputs.offset(0)));
|
||||
let nameslice = slice::from_raw_parts((*output).name as *mut u8, (*output).nameLen as usize);
|
||||
let name = String::from_utf8_lossy(nameslice).into_owned();
|
||||
(x.xrandr.XRRFreeOutputInfo)(output);
|
||||
available.push(MonitorId{
|
||||
id: crtcid as u32,
|
||||
name,
|
||||
dimensions: ((*crtc).width as u32, (*crtc).height as u32),
|
||||
position: ((*crtc).x as u32, (*crtc).y as u32),
|
||||
primary: true,
|
||||
});
|
||||
}
|
||||
(x.xrandr.XRRFreeCrtcInfo)(crtc);
|
||||
}
|
||||
}
|
||||
(x.xrandr.XRRFreeScreenResources)(resources);
|
||||
}
|
||||
available
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_primary_monitor(x: &Arc<XConnection>) -> MonitorId {
|
||||
let primary_monitor = unsafe { (x.xlib.XDefaultScreen)(x.display) };
|
||||
x.check_errors().expect("Failed to call XDefaultScreen");
|
||||
MonitorId(x.clone(), primary_monitor as u32)
|
||||
for monitor in get_available_monitors(x) {
|
||||
if monitor.primary {
|
||||
return monitor.clone()
|
||||
}
|
||||
}
|
||||
|
||||
panic!("[winit] Failed to find the primary monitor")
|
||||
}
|
||||
|
||||
impl MonitorId {
|
||||
pub fn get_name(&self) -> Option<String> {
|
||||
let MonitorId(_, screen_num) = *self;
|
||||
Some(format!("Monitor #{}", screen_num))
|
||||
Some(self.name.clone())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_native_identifier(&self) -> u32 {
|
||||
self.1
|
||||
self.id as u32
|
||||
}
|
||||
|
||||
pub fn get_dimensions(&self) -> (u32, u32) {
|
||||
let screen = unsafe { (self.0.xlib.XScreenOfDisplay)(self.0.display, self.1 as i32) };
|
||||
let width = unsafe { (self.0.xlib.XWidthOfScreen)(screen) };
|
||||
let height = unsafe { (self.0.xlib.XHeightOfScreen)(screen) };
|
||||
self.0.check_errors().expect("Failed to get monitor dimensions");
|
||||
(width as u32, height as u32)
|
||||
self.dimensions
|
||||
}
|
||||
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
self.position
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use CreationError;
|
|||
use CreationError::OsError;
|
||||
use libc;
|
||||
use std::borrow::Borrow;
|
||||
use std::{mem, ptr, cmp};
|
||||
use std::{mem, cmp};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::os::raw::{c_int, c_long, c_uchar};
|
||||
use std::thread;
|
||||
|
@ -11,17 +11,17 @@ use std::time::Duration;
|
|||
|
||||
use CursorState;
|
||||
use WindowAttributes;
|
||||
use FullScreenState;
|
||||
use platform::PlatformSpecificWindowBuilderAttributes;
|
||||
|
||||
use platform::MonitorId as PlatformMonitorId;
|
||||
use platform::x11::MonitorId as X11MonitorId;
|
||||
use window::MonitorId as RootMonitorId;
|
||||
|
||||
use platform::x11::monitor::get_available_monitors;
|
||||
|
||||
use super::{ffi};
|
||||
use super::{XConnection, WindowId, EventsLoop};
|
||||
|
||||
use super::MonitorId as X11MonitorId;
|
||||
|
||||
// TODO: remove me
|
||||
fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) -> T {
|
||||
use std::ffi::CString;
|
||||
|
@ -33,8 +33,7 @@ pub struct XWindow {
|
|||
display: Arc<XConnection>,
|
||||
window: ffi::Window,
|
||||
root: ffi::Window,
|
||||
// screen we're using, original screen mode if we've switched
|
||||
fullscreen: Arc<Mutex<(i32, Option<ffi::XF86VidModeModeInfo>)>>,
|
||||
screen_id: i32,
|
||||
}
|
||||
|
||||
unsafe impl Send for XWindow {}
|
||||
|
@ -43,104 +42,6 @@ unsafe impl Sync for XWindow {}
|
|||
unsafe impl Send for Window2 {}
|
||||
unsafe impl Sync for Window2 {}
|
||||
|
||||
impl XWindow {
|
||||
fn switch_to_fullscreen_mode(&self, monitor: i32, width: u16, height: u16) {
|
||||
let original_monitor = {
|
||||
let fullscreen = self.fullscreen.lock().unwrap();
|
||||
fullscreen.0
|
||||
};
|
||||
if monitor != original_monitor {
|
||||
// We're setting fullscreen on a new screen so first revert the original screen
|
||||
self.switch_from_fullscreen_mode();
|
||||
}
|
||||
|
||||
let current_mode = unsafe {
|
||||
let mut mode_num: libc::c_int = mem::uninitialized();
|
||||
let mut modes: *mut *mut ffi::XF86VidModeModeInfo = mem::uninitialized();
|
||||
if (self.display.xf86vmode.XF86VidModeGetAllModeLines)(self.display.display, monitor, &mut mode_num, &mut modes) == 0 {
|
||||
eprintln!("[winit] Couldn't get current resolution mode");
|
||||
return
|
||||
}
|
||||
ptr::read(*modes.offset(0))
|
||||
};
|
||||
|
||||
let new_mode = unsafe {
|
||||
let mut mode_num: libc::c_int = mem::uninitialized();
|
||||
let mut modes: *mut *mut ffi::XF86VidModeModeInfo = mem::uninitialized();
|
||||
if (self.display.xf86vmode.XF86VidModeGetAllModeLines)(self.display.display, monitor, &mut mode_num, &mut modes) == 0 {
|
||||
// There are no modes, mighty weird
|
||||
eprintln!("[winit] X has no valid modes");
|
||||
return
|
||||
} else {
|
||||
let matching_mode = (0 .. mode_num).map(|i| {
|
||||
let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
|
||||
}).find(|m| m.hdisplay == width && m.vdisplay == height);
|
||||
|
||||
if let Some(matching_mode) = matching_mode {
|
||||
matching_mode
|
||||
} else {
|
||||
let m = (0 .. mode_num).map(|i| {
|
||||
let m: ffi::XF86VidModeModeInfo = ptr::read(*modes.offset(i as isize) as *const _); m
|
||||
}).find(|m| m.hdisplay >= width && m.vdisplay >= height);
|
||||
|
||||
match m {
|
||||
Some(m) => m,
|
||||
None => {
|
||||
eprintln!("[winit] Could not find a suitable graphics mode");
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if new_mode != current_mode {
|
||||
// We actually need to change modes
|
||||
self.set_mode(monitor, new_mode);
|
||||
let mut fullscreen = self.fullscreen.lock().unwrap();
|
||||
if fullscreen.1.is_none() {
|
||||
// It's our first mode switch, save the original mode
|
||||
fullscreen.1 = Some(current_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn switch_from_fullscreen_mode(&self) {
|
||||
let (monitor, mode) = {
|
||||
let fullscreen = self.fullscreen.lock().unwrap();
|
||||
(fullscreen.0, fullscreen.1)
|
||||
};
|
||||
|
||||
if let Some(mode) = mode {
|
||||
self.set_mode(monitor, mode);
|
||||
let mut fullscreen = self.fullscreen.lock().unwrap();
|
||||
fullscreen.1 = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_mode(&self, monitor: i32, mode: ffi::XF86VidModeModeInfo) {
|
||||
unsafe {
|
||||
let mut mode_to_switch_to = mode;
|
||||
(self.display.xf86vmode.XF86VidModeSwitchToMode)(
|
||||
self.display.display,
|
||||
monitor,
|
||||
&mut mode_to_switch_to
|
||||
);
|
||||
self.display.check_errors().expect("Failed to call XF86VidModeSwitchToMode");
|
||||
|
||||
(self.display.xf86vmode.XF86VidModeSetViewPort)(self.display.display, monitor, 0, 0);
|
||||
self.display.check_errors().expect("Failed to call XF86VidModeSetViewPort");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for XWindow {
|
||||
fn drop(&mut self) {
|
||||
// Make sure we return the display to the original resolution if we've changed it
|
||||
self.switch_from_fullscreen_mode();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Window2 {
|
||||
pub x: Arc<XWindow>,
|
||||
cursor_state: Mutex<CursorState>,
|
||||
|
@ -172,10 +73,7 @@ impl Window2 {
|
|||
|
||||
let screen_id = match pl_attribs.screen_id {
|
||||
Some(id) => id,
|
||||
None => match window_attrs.fullscreen {
|
||||
FullScreenState::Exclusive(RootMonitorId { inner: PlatformMonitorId::X(X11MonitorId(_, monitor)) }) => monitor as i32,
|
||||
_ => unsafe { (display.xlib.XDefaultScreen)(display.display) },
|
||||
}
|
||||
None => unsafe { (display.xlib.XDefaultScreen)(display.display) },
|
||||
};
|
||||
|
||||
// getting the root window
|
||||
|
@ -309,9 +207,9 @@ impl Window2 {
|
|||
let window = Window2 {
|
||||
x: Arc::new(XWindow {
|
||||
display: display.clone(),
|
||||
window: window,
|
||||
root: root,
|
||||
fullscreen: Arc::new(Mutex::new((screen_id, None))),
|
||||
window,
|
||||
root,
|
||||
screen_id,
|
||||
}),
|
||||
cursor_state: Mutex::new(CursorState::Normal),
|
||||
};
|
||||
|
@ -398,33 +296,66 @@ impl Window2 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_fullscreen(&self, state: FullScreenState) {
|
||||
match state {
|
||||
FullScreenState::None => {
|
||||
self.x.switch_from_fullscreen_mode();
|
||||
Window2::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_FULLSCREEN", false);
|
||||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorId>) {
|
||||
match monitor {
|
||||
None => {
|
||||
self.set_fullscreen_hint(false);
|
||||
},
|
||||
FullScreenState::Windowed => {
|
||||
self.x.switch_from_fullscreen_mode();
|
||||
Window2::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_FULLSCREEN", true);
|
||||
},
|
||||
FullScreenState::Exclusive(RootMonitorId { inner: PlatformMonitorId::X(X11MonitorId(_, monitor)) }) => {
|
||||
if let Some(dimensions) = self.get_inner_size() {
|
||||
self.x.switch_to_fullscreen_mode(monitor as i32, dimensions.0 as u16, dimensions.1 as u16);
|
||||
Window2::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_FULLSCREEN", true);
|
||||
} else {
|
||||
eprintln!("[winit] Couldn't get window dimensions to go fullscreen");
|
||||
}
|
||||
Some(RootMonitorId { inner: PlatformMonitorId::X(monitor) }) => {
|
||||
let screenpos = monitor.get_position();
|
||||
self.set_position(screenpos.0 as i32, screenpos.1 as i32);
|
||||
self.set_fullscreen_hint(true);
|
||||
}
|
||||
_ => {
|
||||
eprintln!("[winit] Something's broken, got an unknown fullscreen state in X11");
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_current_monitor(&self) -> X11MonitorId {
|
||||
let monitors = get_available_monitors(&self.x.display);
|
||||
let default = monitors[0].clone();
|
||||
|
||||
let (wx,wy) = match self.get_position() {
|
||||
Some(val) => (cmp::max(0,val.0) as u32, cmp::max(0,val.1) as u32),
|
||||
None=> return default,
|
||||
};
|
||||
let (ww,wh) = match self.get_outer_size() {
|
||||
Some(val) => val,
|
||||
None=> return default,
|
||||
};
|
||||
// Opposite corner coordinates
|
||||
let (wxo, wyo) = (wx+ww-1, wy+wh-1);
|
||||
|
||||
// Find the monitor with the biggest overlap with the window
|
||||
let mut overlap = 0;
|
||||
let mut find = default;
|
||||
for monitor in monitors {
|
||||
let (mx, my) = monitor.get_position();
|
||||
let (mw, mh) = monitor.get_dimensions();
|
||||
let (mxo, myo) = (mx+mw-1, my+mh-1);
|
||||
let (ox, oy) = (cmp::max(wx, mx), cmp::max(wy, my));
|
||||
let (oxo, oyo) = (cmp::min(wxo, mxo), cmp::min(wyo, myo));
|
||||
let osize = if ox <= oxo || oy <= oyo { 0 } else { (oxo-ox)*(oyo-oy) };
|
||||
|
||||
if osize > overlap {
|
||||
overlap = osize;
|
||||
find = monitor;
|
||||
}
|
||||
}
|
||||
|
||||
find
|
||||
}
|
||||
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
Window2::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_MAXIMIZED_HORZ", maximized);
|
||||
Window2::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_MAXIMIZED_VERT", maximized);
|
||||
}
|
||||
|
||||
fn set_fullscreen_hint(&self, fullscreen: bool) {
|
||||
Window2::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_FULLSCREEN", fullscreen);
|
||||
}
|
||||
|
||||
pub fn set_title(&self, title: &str) {
|
||||
let wm_name = unsafe {
|
||||
(self.x.display.xlib.XInternAtom)(self.x.display.display, b"_NET_WM_NAME\0".as_ptr() as *const _, 0)
|
||||
|
@ -563,12 +494,7 @@ impl Window2 {
|
|||
|
||||
#[inline]
|
||||
pub fn get_xlib_screen_id(&self) -> *mut libc::c_void {
|
||||
let screen_id = {
|
||||
let fullscreen = self.x.fullscreen.lock().unwrap();
|
||||
fullscreen.0
|
||||
};
|
||||
|
||||
screen_id as *mut libc::c_void
|
||||
self.x.screen_id as *mut libc::c_void
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -775,16 +701,11 @@ impl Window2 {
|
|||
}
|
||||
|
||||
pub fn hidpi_factor(&self) -> f32 {
|
||||
let screen_id = {
|
||||
let fullscreen = self.x.fullscreen.lock().unwrap();
|
||||
fullscreen.0
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let x_px = (self.x.display.xlib.XDisplayWidth)(self.x.display.display, screen_id);
|
||||
let y_px = (self.x.display.xlib.XDisplayHeight)(self.x.display.display, screen_id);
|
||||
let x_mm = (self.x.display.xlib.XDisplayWidthMM)(self.x.display.display, screen_id);
|
||||
let y_mm = (self.x.display.xlib.XDisplayHeightMM)(self.x.display.display, screen_id);
|
||||
let x_px = (self.x.display.xlib.XDisplayWidth)(self.x.display.display, self.x.screen_id);
|
||||
let y_px = (self.x.display.xlib.XDisplayHeight)(self.x.display.display, self.x.screen_id);
|
||||
let x_mm = (self.x.display.xlib.XDisplayWidthMM)(self.x.display.display, self.x.screen_id);
|
||||
let y_mm = (self.x.display.xlib.XDisplayHeightMM)(self.x.display.display, self.x.screen_id);
|
||||
let ppmm = ((x_px as f32 * y_px as f32) / (x_mm as f32 * y_mm as f32)).sqrt();
|
||||
((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0) // quantize with 1/12 step size.
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use super::ffi;
|
|||
/// A connection to an X server.
|
||||
pub struct XConnection {
|
||||
pub xlib: ffi::Xlib,
|
||||
pub xf86vmode: ffi::Xf86vmode,
|
||||
pub xrandr: ffi::Xrandr,
|
||||
pub xcursor: ffi::Xcursor,
|
||||
pub xinput2: ffi::XInput2,
|
||||
pub xlib_xcb: ffi::Xlib_xcb,
|
||||
|
@ -28,7 +28,7 @@ impl XConnection {
|
|||
// opening the libraries
|
||||
let xlib = try!(ffi::Xlib::open());
|
||||
let xcursor = try!(ffi::Xcursor::open());
|
||||
let xf86vmode = try!(ffi::Xf86vmode::open());
|
||||
let xrandr = try!(ffi::Xrandr::open());
|
||||
let xinput2 = try!(ffi::XInput2::open());
|
||||
let xlib_xcb = try!(ffi::Xlib_xcb::open());
|
||||
|
||||
|
@ -46,7 +46,7 @@ impl XConnection {
|
|||
|
||||
Ok(XConnection {
|
||||
xlib: xlib,
|
||||
xf86vmode: xf86vmode,
|
||||
xrandr: xrandr,
|
||||
xcursor: xcursor,
|
||||
xinput2: xinput2,
|
||||
xlib_xcb: xlib_xcb,
|
||||
|
|
|
@ -48,4 +48,9 @@ impl MonitorId {
|
|||
};
|
||||
dimension
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ use CreationError::OsError;
|
|||
use libc;
|
||||
|
||||
use WindowAttributes;
|
||||
use FullScreenState;
|
||||
use os::macos::ActivationPolicy;
|
||||
use os::macos::WindowExt;
|
||||
|
||||
|
@ -25,6 +24,7 @@ use std::sync::Weak;
|
|||
|
||||
use super::events_loop::Shared;
|
||||
|
||||
use window::MonitorId as RootMonitorId;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Id(pub usize);
|
||||
|
@ -384,7 +384,7 @@ impl Window2 {
|
|||
fn create_window(attrs: &WindowAttributes) -> Option<IdRef> {
|
||||
unsafe {
|
||||
let screen = match attrs.fullscreen {
|
||||
FullScreenState::Exclusive(ref monitor_id) => {
|
||||
Some(ref monitor_id) => {
|
||||
let native_id = monitor_id.inner.get_native_identifier();
|
||||
let matching_screen = {
|
||||
let screens = appkit::NSScreen::screens(nil);
|
||||
|
@ -636,11 +636,18 @@ impl Window2 {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
pub fn set_maximized(&self, _maximized: bool) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_fullscreen(&self, state: FullScreenState) {
|
||||
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -176,8 +176,6 @@ impl MonitorId {
|
|||
&self.adapter_name
|
||||
}
|
||||
|
||||
/// This is a Win32-only function for `MonitorId` that returns the position of the
|
||||
/// monitor on the desktop.
|
||||
/// A window that is positionned at these coordinates will overlap the monitor.
|
||||
#[inline]
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
|
|
|
@ -20,7 +20,6 @@ use CreationError;
|
|||
use CursorState;
|
||||
use MouseCursor;
|
||||
use WindowAttributes;
|
||||
use FullScreenState;
|
||||
use MonitorId as RootMonitorId;
|
||||
|
||||
use dwmapi;
|
||||
|
@ -280,11 +279,18 @@ impl Window {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_maximized(&self, maximized: bool) {
|
||||
pub fn set_maximized(&self, _maximized: bool) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_fullscreen(&self, state: FullScreenState) {
|
||||
pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_current_monitor(&self) -> RootMonitorId {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,7 +335,7 @@ unsafe fn init(window: WindowAttributes, pl_attribs: PlatformSpecificWindowBuild
|
|||
// switching to fullscreen if necessary
|
||||
// this means adjusting the window's position so that it overlaps the right monitor,
|
||||
// and change the monitor's resolution if necessary
|
||||
let fullscreen = if let FullScreenState::Exclusive(RootMonitorId { ref inner }) = window.fullscreen {
|
||||
let fullscreen = if let Some(RootMonitorId { ref inner }) = window.fullscreen {
|
||||
try!(switch_to_fullscreen(&mut rect, inner));
|
||||
true
|
||||
} else {
|
||||
|
|
|
@ -7,7 +7,6 @@ use MouseCursor;
|
|||
use Window;
|
||||
use WindowBuilder;
|
||||
use WindowId;
|
||||
use FullScreenState;
|
||||
|
||||
use libc;
|
||||
use platform;
|
||||
|
@ -56,12 +55,11 @@ impl WindowBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
/// Sets the fullscreen mode.
|
||||
///
|
||||
/// If you don't specify dimensions for the window, it will match the monitor's.
|
||||
/// Sets the window fullscreen state. None means a normal window, Some(MonitorId)
|
||||
/// means a fullscreen window on that specific monitor
|
||||
#[inline]
|
||||
pub fn with_fullscreen(mut self, state: FullScreenState) -> WindowBuilder {
|
||||
self.window.fullscreen = state;
|
||||
pub fn with_fullscreen(mut self, monitor: Option<MonitorId>) -> WindowBuilder {
|
||||
self.window.fullscreen = monitor;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -107,7 +105,7 @@ impl WindowBuilder {
|
|||
pub fn build(mut self, events_loop: &EventsLoop) -> Result<Window, CreationError> {
|
||||
// resizing the window to the dimensions of the monitor when fullscreen
|
||||
if self.window.dimensions.is_none() {
|
||||
if let FullScreenState::Exclusive(ref monitor) = self.window.fullscreen {
|
||||
if let Some(ref monitor) = self.window.fullscreen {
|
||||
self.window.dimensions = Some(monitor.get_dimensions());
|
||||
}
|
||||
}
|
||||
|
@ -308,8 +306,14 @@ impl Window {
|
|||
|
||||
/// Sets the window to fullscreen or back
|
||||
#[inline]
|
||||
pub fn set_fullscreen(&self, state: FullScreenState) {
|
||||
self.window.set_fullscreen(state)
|
||||
pub fn set_fullscreen(&self, monitor: Option<MonitorId>) {
|
||||
self.window.set_fullscreen(monitor)
|
||||
}
|
||||
|
||||
/// Returns the current monitor the window is on or the primary monitor is nothing
|
||||
/// matches
|
||||
pub fn get_current_monitor(&self) -> MonitorId {
|
||||
self.window.get_current_monitor()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -359,4 +363,11 @@ impl MonitorId {
|
|||
pub fn get_dimensions(&self) -> (u32, u32) {
|
||||
self.inner.get_dimensions()
|
||||
}
|
||||
|
||||
/// Returns the top-left corner position of the monitor relative to the larger full
|
||||
/// screen area.
|
||||
#[inline]
|
||||
pub fn get_position(&self) -> (u32, u32) {
|
||||
self.inner.get_position()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue