From a4052b8693a648142e12de623f46215da96da708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20C=C3=B4rte-Real?= Date: Mon, 28 Aug 2017 00:19:26 +0100 Subject: [PATCH] Add window maximization API Implement a simple API to set a window to maximized. Implement it only for the X11 backend. --- src/lib.rs | 6 ++ src/platform/linux/mod.rs | 8 +++ src/platform/linux/x11/window.rs | 105 ++++++++++++++++++------------- src/window.rs | 13 ++++ 4 files changed, 90 insertions(+), 42 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 89e37f1f..0121365e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -402,6 +402,11 @@ pub struct WindowAttributes { /// The default is `"winit window"`. pub title: String, + /// Whether the window should be maximized upon creation. + /// + /// The default is `false`. + pub maximized: bool, + /// Whether the window should be immediately visible upon creation. /// /// The default is `true`. @@ -432,6 +437,7 @@ impl Default for WindowAttributes { max_dimensions: None, monitor: None, title: "winit window".to_owned(), + maximized: false, visible: true, transparent: false, decorations: true, diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index af431a10..03e5ae4c 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -309,6 +309,14 @@ impl Window2 { &Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _ } } + + #[inline] + pub fn set_maximized(&self, maximized: bool) { + match self { + &Window2::X(ref w) => w.set_maximized(maximized), + &Window2::Wayland(ref _w) => {}, + } + } } unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent) diff --git a/src/platform/linux/x11/window.rs b/src/platform/linux/x11/window.rs index 7e2ddfe1..f7b1e8d1 100644 --- a/src/platform/linux/x11/window.rs +++ b/src/platform/linux/x11/window.rs @@ -35,6 +35,7 @@ unsafe impl Send for WindowProxyData {} pub struct XWindow { display: Arc, window: ffi::Window, + root: ffi::Window, is_fullscreen: bool, screen_id: libc::c_int, xf86_desk_mode: Option, @@ -227,6 +228,12 @@ impl Window { }); } + // set maximization + if window_attrs.maximized { + Window::set_netwm(display, window, root, "_NET_WM_STATE_MAXIMIZED_HORZ", true); + Window::set_netwm(display, window, root, "_NET_WM_STATE_MAXIMIZED_VERT", true); + } + // set visibility if window_attrs.visible { unsafe { @@ -257,48 +264,7 @@ impl Window { let is_fullscreen = window_attrs.monitor.is_some(); if is_fullscreen { - let state_atom = unsafe { - with_c_str("_NET_WM_STATE", |state| - (display.xlib.XInternAtom)(display.display, state, 0) - ) - }; - display.check_errors().expect("Failed to call XInternAtom"); - let fullscreen_atom = unsafe { - with_c_str("_NET_WM_STATE_FULLSCREEN", |state_fullscreen| - (display.xlib.XInternAtom)(display.display, state_fullscreen, 0) - ) - }; - display.check_errors().expect("Failed to call XInternAtom"); - - let client_message_event = ffi::XClientMessageEvent { - type_: ffi::ClientMessage, - serial: 0, - send_event: 1, // true because we are sending this through `XSendEvent` - display: display.display, - window: window, - message_type: state_atom, // the _NET_WM_STATE atom is sent to change the state of a window - format: 32, // view `data` as `c_long`s - data: { - let mut data = ffi::ClientMessageData::new(); - // This first `long` is the action; `1` means add/set following property. - data.set_long(0, 1); - // This second `long` is the property to set (fullscreen) - data.set_long(1, fullscreen_atom as c_long); - data - } - }; - let mut x_event = ffi::XEvent::from(client_message_event); - - unsafe { - (display.xlib.XSendEvent)( - display.display, - root, - 0, - ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask, - &mut x_event as *mut _ - ); - display.check_errors().expect("Failed to call XSendEvent"); - } + Window::set_netwm(display, window, root, "_NET_WM_STATE_FULLSCREEN", true); if let Some(mut mode_to_switch_to) = mode_to_switch_to { unsafe { @@ -375,6 +341,7 @@ impl Window { x: Arc::new(XWindow { display: display.clone(), window: window, + root: root, screen_id: screen_id, is_fullscreen: is_fullscreen, xf86_desk_mode: xf86_desk_mode, @@ -418,6 +385,60 @@ impl Window { Ok(window) } + fn set_netwm(display: &Arc, window: u64, root: u64, property: &str, val: bool) { + let state_atom = unsafe { + with_c_str("_NET_WM_STATE", |state| + (display.xlib.XInternAtom)(display.display, state, 0) + ) + }; + display.check_errors().expect("Failed to call XInternAtom"); + let atom = unsafe { + with_c_str(property, |state| + (display.xlib.XInternAtom)(display.display, state, 0) + ) + }; + display.check_errors().expect("Failed to call XInternAtom"); + + let client_message_event = ffi::XClientMessageEvent { + type_: ffi::ClientMessage, + serial: 0, + send_event: 1, // true because we are sending this through `XSendEvent` + display: display.display, + window: window, + message_type: state_atom, // the _NET_WM_STATE atom is sent to change the state of a window + format: 32, // view `data` as `c_long`s + data: { + let mut data = ffi::ClientMessageData::new(); + // This first `long` is the action; `1` means add/set following property. + data.set_long(0, val as i64); + // This second `long` is the property to set (fullscreen) + data.set_long(1, atom as c_long); + data + } + }; + let mut x_event = ffi::XEvent::from(client_message_event); + + unsafe { + (display.xlib.XSendEvent)( + display.display, + root, + 0, + ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask, + &mut x_event as *mut _ + ); + display.check_errors().expect("Failed to call XSendEvent"); + } + } + + pub fn set_fullscreen_windowed(&self, fullscreen: bool) { + Window::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_FULLSCREEN", fullscreen); + } + + pub fn set_maximized(&self, maximized: bool) { + Window::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_MAXIMIZED_HORZ", maximized); + Window::set_netwm(&self.x.display, self.x.window, self.x.root, "_NET_WM_STATE_MAXIMIZED_VERT", maximized); + } + 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) diff --git a/src/window.rs b/src/window.rs index c499eaf6..c81f58ce 100644 --- a/src/window.rs +++ b/src/window.rs @@ -66,6 +66,13 @@ impl WindowBuilder { self } + /// Requests maximized mode. + #[inline] + pub fn with_maximized(mut self, maximized: bool) -> WindowBuilder { + self.window.maximized = maximized; + self + } + /// Sets whether the window will be initially hidden or visible. #[inline] pub fn with_visibility(mut self, visible: bool) -> WindowBuilder { @@ -292,6 +299,12 @@ impl Window { self.window.set_cursor_state(state) } + /// Sets the window to maximized or back + #[inline] + pub fn set_maximized(&self, maximized: bool) { + self.window.set_maximized(maximized) + } + #[inline] pub fn id(&self) -> WindowId { WindowId(self.window.id())