diff --git a/.travis.yml b/.travis.yml index 5ea7a677..673896b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,11 +6,6 @@ rust: cache: cargo -addons: - apt: - packages: - - libxxf86vm-dev - install: - rustup self update - | diff --git a/examples/fullscreen.rs b/examples/fullscreen.rs index e39003f9..bbabe34b 100644 --- a/examples/fullscreen.rs +++ b/examples/fullscreen.rs @@ -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(); diff --git a/src/lib.rs b/src/lib.rs index d76bfde5..b8b4e3f2 100644 --- a/src/lib.rs +++ b/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, /// 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, diff --git a/src/platform/android/mod.rs b/src/platform/android/mod.rs index 4050652a..45b29a21 100644 --- a/src/platform/android/mod.rs +++ b/src/platform/android/mod.rs @@ -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, @@ -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) { + // 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 { diff --git a/src/platform/ios/mod.rs b/src/platform/ios/mod.rs index df1275dd..cb881118 100644 --- a/src/platform/ios/mod.rs +++ b/src/platform/ios/mod.rs @@ -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) { + // iOS has single screen maximized apps so nothing to do + } + + #[inline] + pub fn get_current_monitor(&self) -> RootMonitorId { + RootMonitorId{inner: MonitorId} } #[inline] diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 84a70405..d5628040 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -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) { 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) diff --git a/src/platform/linux/wayland/context.rs b/src/platform/linux/wayland/context.rs index c4ac627c..1c5ae5d6 100644 --- a/src/platform/linux/wayland/context.rs +++ b/src/platform/linux/wayland/context.rs @@ -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::(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 diff --git a/src/platform/linux/wayland/window.rs b/src/platform/linux/wayland/window.rs index dcfe34a9..0061711e 100644 --- a/src/platform/linux/wayland/window.rs +++ b/src/platform/linux/wayland/window.rs @@ -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 { diff --git a/src/platform/linux/x11/ffi.rs b/src/platform/linux/x11/ffi.rs index e04e4ad2..964b0ced 100644 --- a/src/platform/linux/x11/ffi.rs +++ b/src/platform/linux/x11/ffi.rs @@ -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::*; diff --git a/src/platform/linux/x11/monitor.rs b/src/platform/linux/x11/monitor.rs index 4623b792..463dde6c 100644 --- a/src/platform/linux/x11/monitor.rs +++ b/src/platform/linux/x11/monitor.rs @@ -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, 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) -> VecDeque { - let nb_monitors = unsafe { (x.xlib.XScreenCount)(x.display) }; - x.check_errors().expect("Failed to call XScreenCount"); +pub fn get_available_monitors(x: &Arc) -> Vec { + 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) -> 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 { - 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 } } diff --git a/src/platform/linux/x11/window.rs b/src/platform/linux/x11/window.rs index baecb417..1b1ae60f 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform/linux/x11/window.rs @@ -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(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, window: ffi::Window, root: ffi::Window, - // screen we're using, original screen mode if we've switched - fullscreen: Arc)>>, + 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, cursor_state: Mutex, @@ -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) { + 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. } diff --git a/src/platform/linux/x11/xdisplay.rs b/src/platform/linux/x11/xdisplay.rs index 05a29f40..62d93295 100644 --- a/src/platform/linux/x11/xdisplay.rs +++ b/src/platform/linux/x11/xdisplay.rs @@ -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, diff --git a/src/platform/macos/monitor.rs b/src/platform/macos/monitor.rs index 1d70d66f..76b5dfe8 100644 --- a/src/platform/macos/monitor.rs +++ b/src/platform/macos/monitor.rs @@ -48,4 +48,9 @@ impl MonitorId { }; dimension } + + #[inline] + pub fn get_position(&self) -> (u32, u32) { + unimplemented!() + } } diff --git a/src/platform/macos/window.rs b/src/platform/macos/window.rs index ae18c1d2..0c292c73 100644 --- a/src/platform/macos/window.rs +++ b/src/platform/macos/window.rs @@ -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 { 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) { + unimplemented!() + } + + #[inline] + pub fn get_current_monitor(&self) -> RootMonitorId { + unimplemented!() } } diff --git a/src/platform/windows/monitor.rs b/src/platform/windows/monitor.rs index f51aea9b..14eea3ee 100644 --- a/src/platform/windows/monitor.rs +++ b/src/platform/windows/monitor.rs @@ -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) { diff --git a/src/platform/windows/window.rs b/src/platform/windows/window.rs index da179a78..c4a3be85 100644 --- a/src/platform/windows/window.rs +++ b/src/platform/windows/window.rs @@ -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) { + 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 { diff --git a/src/window.rs b/src/window.rs index b0249ef8..cdc07172 100644 --- a/src/window.rs +++ b/src/window.rs @@ -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) -> WindowBuilder { + self.window.fullscreen = monitor; self } @@ -107,7 +105,7 @@ impl WindowBuilder { pub fn build(mut self, events_loop: &EventsLoop) -> Result { // 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) { + 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() + } }