Add window maximization API

Implement a simple API to set a window to maximized. Implement it
only for the X11 backend.
This commit is contained in:
Pedro Côrte-Real 2017-08-28 00:19:26 +01:00
parent 17de3f1d15
commit a4052b8693
4 changed files with 90 additions and 42 deletions

View file

@ -402,6 +402,11 @@ pub struct WindowAttributes {
/// The default is `"winit window"`. /// The default is `"winit window"`.
pub title: String, 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. /// Whether the window should be immediately visible upon creation.
/// ///
/// The default is `true`. /// The default is `true`.
@ -432,6 +437,7 @@ impl Default for WindowAttributes {
max_dimensions: None, max_dimensions: None,
monitor: None, monitor: None,
title: "winit window".to_owned(), title: "winit window".to_owned(),
maximized: false,
visible: true, visible: true,
transparent: false, transparent: false,
decorations: true, decorations: true,

View file

@ -309,6 +309,14 @@ impl Window2 {
&Window2::Wayland(ref w) => w.get_surface().ptr() as *mut _ &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) unsafe extern "C" fn x_error_callback(dpy: *mut x11::ffi::Display, event: *mut x11::ffi::XErrorEvent)

View file

@ -35,6 +35,7 @@ unsafe impl Send for WindowProxyData {}
pub struct XWindow { pub struct XWindow {
display: Arc<XConnection>, display: Arc<XConnection>,
window: ffi::Window, window: ffi::Window,
root: ffi::Window,
is_fullscreen: bool, is_fullscreen: bool,
screen_id: libc::c_int, screen_id: libc::c_int,
xf86_desk_mode: Option<ffi::XF86VidModeModeInfo>, xf86_desk_mode: Option<ffi::XF86VidModeModeInfo>,
@ -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 // set visibility
if window_attrs.visible { if window_attrs.visible {
unsafe { unsafe {
@ -257,48 +264,7 @@ impl Window {
let is_fullscreen = window_attrs.monitor.is_some(); let is_fullscreen = window_attrs.monitor.is_some();
if is_fullscreen { if is_fullscreen {
let state_atom = unsafe { Window::set_netwm(display, window, root, "_NET_WM_STATE_FULLSCREEN", true);
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");
}
if let Some(mut mode_to_switch_to) = mode_to_switch_to { if let Some(mut mode_to_switch_to) = mode_to_switch_to {
unsafe { unsafe {
@ -375,6 +341,7 @@ impl Window {
x: Arc::new(XWindow { x: Arc::new(XWindow {
display: display.clone(), display: display.clone(),
window: window, window: window,
root: root,
screen_id: screen_id, screen_id: screen_id,
is_fullscreen: is_fullscreen, is_fullscreen: is_fullscreen,
xf86_desk_mode: xf86_desk_mode, xf86_desk_mode: xf86_desk_mode,
@ -418,6 +385,60 @@ impl Window {
Ok(window) Ok(window)
} }
fn set_netwm(display: &Arc<XConnection>, 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) { pub fn set_title(&self, title: &str) {
let wm_name = unsafe { let wm_name = unsafe {
(self.x.display.xlib.XInternAtom)(self.x.display.display, b"_NET_WM_NAME\0".as_ptr() as *const _, 0) (self.x.display.xlib.XInternAtom)(self.x.display.display, b"_NET_WM_NAME\0".as_ptr() as *const _, 0)

View file

@ -66,6 +66,13 @@ impl WindowBuilder {
self 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. /// Sets whether the window will be initially hidden or visible.
#[inline] #[inline]
pub fn with_visibility(mut self, visible: bool) -> WindowBuilder { pub fn with_visibility(mut self, visible: bool) -> WindowBuilder {
@ -292,6 +299,12 @@ impl Window {
self.window.set_cursor_state(state) 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] #[inline]
pub fn id(&self) -> WindowId { pub fn id(&self) -> WindowId {
WindowId(self.window.id()) WindowId(self.window.id())