Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows & X11: Window::set_resizable #558

Merged
merged 9 commits into from
Jun 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- On X11, the `Moved` event is no longer sent when the window is resized without changing position.
- `MouseCursor` and `CursorState` now implement `Default`.
- `WindowBuilder::with_resizable` implemented for Windows, X11, and macOS.
- `Window::set_resizable` implemented for Windows, X11, and macOS.
- On X11, if the monitor's width or height in millimeters is reported as 0, the DPI is now 1.0 instead of +inf.
- On X11, the environment variable `WINIT_HIDPI_FACTOR` has been added for overriding DPI factor.
- On X11, enabling transparency no longer causes the window contents to flicker when resizing.
Expand Down
22 changes: 0 additions & 22 deletions examples/no_resize.rs

This file was deleted.

38 changes: 38 additions & 0 deletions examples/resizable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
extern crate winit;

fn main() {
let mut events_loop = winit::EventsLoop::new();

let mut resizable = false;

let window = winit::WindowBuilder::new()
.with_title("Hit space to toggle resizability.")
.with_dimensions(400, 200)
.with_resizable(resizable)
.build(&events_loop)
.unwrap();

events_loop.run_forever(|event| {
match event {
winit::Event::WindowEvent { event, .. } => match event {
winit::WindowEvent::CloseRequested => return winit::ControlFlow::Break,
winit::WindowEvent::KeyboardInput {
input:
winit::KeyboardInput {
virtual_keycode: Some(winit::VirtualKeyCode::Space),
state: winit::ElementState::Released,
..
},
..
} => {
resizable = !resizable;
println!("Resizable: {}", resizable);
window.set_resizable(resizable);
}
_ => (),
},
_ => (),
};
winit::ControlFlow::Continue
});
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ pub struct WindowAttributes {
/// The default is `None`.
pub max_dimensions: Option<(u32, u32)>,

/// [Windows & X11 only] Whether the window is resizable or not
/// Whether the window is resizable or not.
///
/// The default is `true`.
pub resizable: bool,
Expand Down
5 changes: 5 additions & 0 deletions src/platform/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,11 @@ impl Window {
#[inline]
pub fn set_max_dimensions(&self, _dimensions: Option<(u32, u32)>) { }

#[inline]
pub fn set_resizable(&self, _resizable: bool) {
// N/A
}

#[inline]
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
if self.native_window.is_null() {
Expand Down
5 changes: 5 additions & 0 deletions src/platform/emscripten/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,11 @@ impl Window {

#[inline]
pub fn set_max_dimensions(&self, _dimensions: Option<(u32, u32)>) { }

#[inline]
pub fn set_resizable(&self, _resizable: bool) {
// N/A
}

#[inline]
pub fn show(&self) {}
Expand Down
5 changes: 5 additions & 0 deletions src/platform/ios/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,11 @@ impl Window {
#[inline]
pub fn set_max_dimensions(&self, _dimensions: Option<(u32, u32)>) { }

#[inline]
pub fn set_resizable(&self, _resizable: bool) {
// N/A
}

#[inline]
pub fn platform_display(&self) -> *mut libc::c_void {
unimplemented!();
Expand Down
8 changes: 8 additions & 0 deletions src/platform/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,14 @@ impl Window {
&Window::Wayland(ref w) => w.set_max_dimensions(dimensions)
}
}

#[inline]
pub fn set_resizable(&self, resizable: bool) {
match self {
&Window::X(ref w) => w.set_resizable(resizable),
&Window::Wayland(ref _w) => unimplemented!(),
}
}

#[inline]
pub fn set_cursor(&self, cursor: MouseCursor) {
Expand Down
35 changes: 34 additions & 1 deletion src/platform/linux/x11/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ pub struct SharedState {
pub last_monitor: Option<X11MonitorId>,
pub dpi_adjusted: Option<(f64, f64)>,
pub frame_extents: Option<util::FrameExtentsHeuristic>,
pub min_dimensions: Option<(u32, u32)>,
pub max_dimensions: Option<(u32, u32)>,
}

unsafe impl Send for UnownedWindow {}
Expand Down Expand Up @@ -216,9 +218,11 @@ impl UnownedWindow {

// set size hints
{
(*window.shared_state.lock()).min_dimensions = window_attrs.min_dimensions;
(*window.shared_state.lock()).max_dimensions = window_attrs.max_dimensions;
let mut min_dimensions = window_attrs.min_dimensions;
let mut max_dimensions = window_attrs.max_dimensions;
if !window_attrs.resizable {
if !window_attrs.resizable && !util::wm_name_is_one_of(&["Xfwm4"]) {
max_dimensions = Some(dimensions);
min_dimensions = Some(dimensions);
}
Expand Down Expand Up @@ -699,6 +703,7 @@ impl UnownedWindow {
}

pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
(*self.shared_state.lock()).min_dimensions = dimensions;
unsafe {
self.update_normal_hints(|size_hints| {
if let Some((width, height)) = dimensions {
Expand All @@ -713,6 +718,7 @@ impl UnownedWindow {
}

pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
(*self.shared_state.lock()).max_dimensions = dimensions;
unsafe {
self.update_normal_hints(|size_hints| {
if let Some((width, height)) = dimensions {
Expand All @@ -726,6 +732,33 @@ impl UnownedWindow {
}.expect("Failed to call XSetWMNormalHints");
}

pub fn set_resizable(&self, resizable: bool) {
if util::wm_name_is_one_of(&["Xfwm4"]) {
// Making the window unresizable on Xfwm prevents further changes to `WM_NORMAL_HINTS` from being detected.
// This makes it impossible for resizing to be re-enabled, and also breaks DPI scaling. As such, we choose
// the lesser of two evils and do nothing.
return;
}
if resizable {
let min_dimensions = (*self.shared_state.lock()).min_dimensions;
let max_dimensions = (*self.shared_state.lock()).max_dimensions;
self.set_min_dimensions(min_dimensions);
self.set_max_dimensions(max_dimensions);
} else {
unsafe {
self.update_normal_hints(|size_hints| {
(*size_hints).flags |= ffi::PMinSize | ffi::PMaxSize;
if let Some((width, height)) = self.get_inner_size() {
(*size_hints).min_width = width as c_int;
(*size_hints).min_height = height as c_int;
(*size_hints).max_width = width as c_int;
(*size_hints).max_height = height as c_int;
}
})
}.expect("Failed to call XSetWMNormalHints");
}
}

#[inline]
pub fn get_xlib_display(&self) -> *mut c_void {
self.xconn.display as _
Expand Down
38 changes: 37 additions & 1 deletion src/platform/windows/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,36 @@ impl Window {
}
}
}

#[inline]
pub fn set_resizable(&self, resizable: bool) {
if let Ok(mut window_state) = self.window_state.lock() {
if window_state.attributes.resizable == resizable {
return;
}
if window_state.attributes.fullscreen.is_some() {
window_state.attributes.resizable = resizable;
return;
}
let window = self.window.clone();
let mut style = unsafe {
winuser::GetWindowLongW(self.window.0, winuser::GWL_STYLE)
};
if resizable {
style |= winuser::WS_SIZEBOX as LONG;
} else {
style &= !winuser::WS_SIZEBOX as LONG;
}
unsafe {
winuser::SetWindowLongW(
window.0,
winuser::GWL_STYLE,
style as _,
);
};
window_state.attributes.resizable = resizable;
}
}

// TODO: remove
pub fn platform_display(&self) -> *mut ::libc::c_void {
Expand Down Expand Up @@ -478,14 +508,20 @@ impl Window {

let rect = saved_window_info.rect.clone();
let window = self.window.clone();
let (style, ex_style) = (saved_window_info.style, saved_window_info.ex_style);
let (mut style, ex_style) = (saved_window_info.style, saved_window_info.ex_style);

let maximized = window_state.attributes.maximized;
let resizable = window_state.attributes.resizable;

// On restore, resize to the previous saved rect size.
// And because SetWindowPos will resize the window
// We call it in the main thread
self.events_loop_proxy.execute_in_thread(move |_| {
if resizable {
style |= winuser::WS_SIZEBOX as LONG;
} else {
style &= !winuser::WS_SIZEBOX as LONG;
}
winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style);
winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style);

Expand Down
22 changes: 21 additions & 1 deletion src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,14 @@ impl WindowBuilder {

/// Sets whether the window is resizable or not
///
/// Note that making the window unresizable doesn't exempt you from handling `Resized`, as that event can still be
/// triggered by DPI scaling, entering fullscreen mode, etc.
///
/// ## Platform-specific
///
/// This only has an effect on Windows, X11, and macOS.
/// This only has an effect on desktop platforms.
///
/// Due to a bug in XFCE, this has no effect on Xfwm.
#[inline]
pub fn with_resizable(mut self, resizable: bool) -> WindowBuilder {
self.window.resizable = resizable;
Expand Down Expand Up @@ -317,6 +322,21 @@ impl Window {
self.window.set_max_dimensions(dimensions)
}

/// Sets whether the window is resizable or not.
///
/// Note that making the window unresizable doesn't exempt you from handling `Resized`, as that event can still be
/// triggered by DPI scaling, entering fullscreen mode, etc.
///
/// ## Platform-specific
///
/// This only has an effect on desktop platforms.
///
/// Due to a bug in XFCE, this has no effect on Xfwm.
#[inline]
pub fn set_resizable(&self, resizable: bool) {
self.window.set_resizable(resizable)
}

/// DEPRECATED. Gets the native platform specific display for this window.
/// This is typically only required when integrating with
/// other libraries that need this information.
Expand Down