Skip to content

Commit

Permalink
Windows & X11: Window::set_resizable (#558)
Browse files Browse the repository at this point in the history
* Windows: Window::set_resizable

* X11: Window::set_resizable

* Code style regarding resizable

* X11: set_resizable remember max/min window size

* Stub out set_resizable on Android, iOS, and emscripten

* remove comment block from docs

* Windows: set_resizable in fullscreen

* Special case Xfwm

* Added fun provisos to docs
  • Loading branch information
dannyfritz authored and francesca64 committed Jun 11, 2018
1 parent 2b4b64f commit be5a2b0
Show file tree
Hide file tree
Showing 11 changed files with 155 additions and 26 deletions.
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

0 comments on commit be5a2b0

Please sign in to comment.