Add ability to change the min/max size of windows at runtime (#405)
* Add min/max size setting for win32 and wayland backends * Implement dynamic min/max size on macos * Add min/max size setting for x11 * Add empty functions for remaining platforms * Improved min/max size setting for x11 * Added CHANGELOG entry for new min/max methods * Added documentation for new min/max methods * On win32, bound window size to min/max dimensions on window creation * On win32, force re-check of window size when changing min/max dimensions * Fix freeze when setting min and max size
This commit is contained in:
parent
d667a395b6
commit
bbcd3019e8
12 changed files with 270 additions and 24 deletions
|
|
@ -194,6 +194,22 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
|
||||
match self {
|
||||
&Window::X(ref w) => w.set_min_dimensions(dimensions),
|
||||
&Window::Wayland(ref w) => w.set_min_dimensions(dimensions)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
|
||||
match self {
|
||||
&Window::X(ref w) => w.set_max_dimensions(dimensions),
|
||||
&Window::Wayland(ref w) => w.set_max_dimensions(dimensions)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor(&self, cursor: MouseCursor) {
|
||||
match self {
|
||||
|
|
|
|||
|
|
@ -136,6 +136,16 @@ impl Window {
|
|||
*(self.size.lock().unwrap()) = (x, y);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
|
||||
self.frame.lock().unwrap().set_min_size(dimensions.map(|(w, h)| (w as i32, h as i32)));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
|
||||
self.frame.lock().unwrap().set_max_size(dimensions.map(|(w, h)| (w as i32, h as i32)));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor(&self, _cursor: MouseCursor) {
|
||||
// TODO
|
||||
|
|
@ -190,11 +200,11 @@ impl Window {
|
|||
// TODO: not yet possible on wayland
|
||||
Err(())
|
||||
}
|
||||
|
||||
|
||||
pub fn get_display(&self) -> &wl_display::WlDisplay {
|
||||
&*self.display
|
||||
}
|
||||
|
||||
|
||||
pub fn get_surface(&self) -> &wl_surface::WlSurface {
|
||||
&self.surface
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,54 @@
|
|||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::raw::{c_char, c_double, c_int, c_long, c_short, c_uchar, c_uint, c_ulong};
|
||||
|
||||
use super::{ffi, XConnection, XError};
|
||||
use events::ModifiersState;
|
||||
|
||||
pub struct XSmartPointer<'a, T> {
|
||||
xconn: &'a Arc<XConnection>,
|
||||
pub ptr: *mut T,
|
||||
}
|
||||
|
||||
impl<'a, T> XSmartPointer<'a, T> {
|
||||
// You're responsible for only passing things to this that should be XFree'd.
|
||||
// Returns None if ptr is null.
|
||||
pub fn new(xconn: &'a Arc<XConnection>, ptr: *mut T) -> Option<Self> {
|
||||
if !ptr.is_null() {
|
||||
Some(XSmartPointer {
|
||||
xconn,
|
||||
ptr,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Deref for XSmartPointer<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> DerefMut for XSmartPointer<'a, T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.ptr }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for XSmartPointer<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
(self.xconn.xlib.XFree)(self.ptr as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get_atom(xconn: &Arc<XConnection>, name: &[u8]) -> Result<ffi::Atom, XError> {
|
||||
let atom_name: *const c_char = name.as_ptr() as _;
|
||||
let atom = (xconn.xlib.XInternAtom)(xconn.display, atom_name, ffi::False);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use window::MonitorId as RootMonitorId;
|
|||
|
||||
use platform::x11::monitor::get_available_monitors;
|
||||
|
||||
use super::{ffi, util, XConnection, WindowId, EventsLoop};
|
||||
use super::{ffi, util, XConnection, XError, WindowId, EventsLoop};
|
||||
|
||||
// TODO: remove me
|
||||
fn with_c_str<F, T>(s: &str, f: F) -> T where F: FnOnce(*const libc::c_char) -> T {
|
||||
|
|
@ -230,23 +230,33 @@ impl Window2 {
|
|||
}
|
||||
|
||||
// set size hints
|
||||
let mut size_hints: ffi::XSizeHints = unsafe { mem::zeroed() };
|
||||
size_hints.flags = ffi::PSize;
|
||||
size_hints.width = dimensions.0 as i32;
|
||||
size_hints.height = dimensions.1 as i32;
|
||||
if let Some(dimensions) = window_attrs.min_dimensions {
|
||||
size_hints.flags |= ffi::PMinSize;
|
||||
size_hints.min_width = dimensions.0 as i32;
|
||||
size_hints.min_height = dimensions.1 as i32;
|
||||
}
|
||||
if let Some(dimensions) = window_attrs.max_dimensions {
|
||||
size_hints.flags |= ffi::PMaxSize;
|
||||
size_hints.max_width = dimensions.0 as i32;
|
||||
size_hints.max_height = dimensions.1 as i32;
|
||||
}
|
||||
unsafe {
|
||||
(display.xlib.XSetNormalHints)(display.display, x_window.window, &mut size_hints);
|
||||
display.check_errors().expect("Failed to call XSetNormalHints");
|
||||
{
|
||||
let mut size_hints = {
|
||||
let size_hints = unsafe { (display.xlib.XAllocSizeHints)() };
|
||||
util::XSmartPointer::new(&display, size_hints)
|
||||
.expect("XAllocSizeHints returned null; out of memory")
|
||||
};
|
||||
(*size_hints).flags = ffi::PSize;
|
||||
(*size_hints).width = dimensions.0 as c_int;
|
||||
(*size_hints).height = dimensions.1 as c_int;
|
||||
if let Some(dimensions) = window_attrs.min_dimensions {
|
||||
(*size_hints).flags |= ffi::PMinSize;
|
||||
(*size_hints).min_width = dimensions.0 as c_int;
|
||||
(*size_hints).min_height = dimensions.1 as c_int;
|
||||
}
|
||||
if let Some(dimensions) = window_attrs.max_dimensions {
|
||||
(*size_hints).flags |= ffi::PMaxSize;
|
||||
(*size_hints).max_width = dimensions.0 as c_int;
|
||||
(*size_hints).max_height = dimensions.1 as c_int;
|
||||
}
|
||||
unsafe {
|
||||
(display.xlib.XSetWMNormalHints)(
|
||||
display.display,
|
||||
x_window.window,
|
||||
size_hints.ptr,
|
||||
);
|
||||
}
|
||||
display.check_errors().expect("Failed to call XSetWMNormalHints");
|
||||
}
|
||||
|
||||
// Opt into handling window close
|
||||
|
|
@ -603,6 +613,67 @@ impl Window2 {
|
|||
self.x.display.check_errors().expect("Failed to call XResizeWindow");
|
||||
}
|
||||
|
||||
unsafe fn update_normal_hints<F>(&self, callback: F) -> Result<(), XError>
|
||||
where F: FnOnce(*mut ffi::XSizeHints) -> ()
|
||||
{
|
||||
let xconn = &self.x.display;
|
||||
|
||||
let size_hints = {
|
||||
let size_hints = (xconn.xlib.XAllocSizeHints)();
|
||||
util::XSmartPointer::new(&xconn, size_hints)
|
||||
.expect("XAllocSizeHints returned null; out of memory")
|
||||
};
|
||||
|
||||
let mut flags: c_long = mem::uninitialized();
|
||||
|
||||
(xconn.xlib.XGetWMNormalHints)(
|
||||
xconn.display,
|
||||
self.x.window,
|
||||
size_hints.ptr,
|
||||
&mut flags,
|
||||
);
|
||||
xconn.check_errors()?;
|
||||
|
||||
callback(size_hints.ptr);
|
||||
|
||||
(xconn.xlib.XSetWMNormalHints)(
|
||||
xconn.display,
|
||||
self.x.window,
|
||||
size_hints.ptr,
|
||||
);
|
||||
xconn.check_errors()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_min_dimensions(&self, dimensions: Option<(u32, u32)>) {
|
||||
unsafe {
|
||||
self.update_normal_hints(|size_hints| {
|
||||
if let Some((width, height)) = dimensions {
|
||||
(*size_hints).flags |= ffi::PMinSize;
|
||||
(*size_hints).min_width = width as c_int;
|
||||
(*size_hints).min_height = height as c_int;
|
||||
} else {
|
||||
(*size_hints).flags &= !ffi::PMinSize;
|
||||
}
|
||||
})
|
||||
}.expect("Failed to call XSetWMNormalHints");
|
||||
}
|
||||
|
||||
pub fn set_max_dimensions(&self, dimensions: Option<(u32, u32)>) {
|
||||
unsafe {
|
||||
self.update_normal_hints(|size_hints| {
|
||||
if let Some((width, height)) = dimensions {
|
||||
(*size_hints).flags |= ffi::PMaxSize;
|
||||
(*size_hints).max_width = width as c_int;
|
||||
(*size_hints).max_height = height as c_int;
|
||||
} else {
|
||||
(*size_hints).flags &= !ffi::PMaxSize;
|
||||
}
|
||||
})
|
||||
}.expect("Failed to call XSetWMNormalHints");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_xlib_display(&self) -> *mut c_void {
|
||||
self.x.display.display as _
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue