Skip to content
Open
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
17 changes: 17 additions & 0 deletions src/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,19 @@ pub struct Conf {
/// Defaults to `600`.
pub window_height: i32,

/// Optional top-left window position in screen coordinates.
///
/// `None` (default) lets the platform / window manager place the window.
/// Applied at window creation on Windows, Linux X11, and macOS.
/// Ignored on Wayland (compositor-owned placement), WASM, Android, and iOS.
///
/// Using create-time position avoids a visible jump that happens when moving
/// the window with [`crate::window::set_window_position`] after it is mapped.
pub window_x: Option<u32>,

/// See [`Conf::window_x`].
pub window_y: Option<u32>,

/// If `true`, the rendering canvas is scaled for HighDPI displays.
/// Defaults to `false`.
pub high_dpi: bool,
Expand Down Expand Up @@ -279,6 +292,8 @@ impl Default for Conf {
window_title: "".to_owned(),
window_width: 800,
window_height: 600,
window_x: None,
window_y: None,
high_dpi: false,
fullscreen: false,
sample_count: 1,
Expand All @@ -296,6 +311,8 @@ impl Default for Conf {
window_title: "".to_owned(),
window_width: 800,
window_height: 600,
window_x: None,
window_y: None,
high_dpi: true,
fullscreen: true, //
sample_count: 1,
Expand Down
6 changes: 6 additions & 0 deletions src/native/linux_wayland.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,12 @@ where
display.decorations = decorations::Decorations::new(&mut display, conf);
assert!(!display.xdg_toplevel.is_null());

if conf.window_x.is_some() || conf.window_y.is_some() {
// Wayland compositors own toplevel placement; there is no portable
// absolute position API for regular windows.
eprintln!("miniquad: Conf.window_x/window_y ignored on Wayland");
}

display.decorations.set_title(
&mut display.client,
display.xdg_toplevel,
Expand Down
2 changes: 2 additions & 0 deletions src/native/linux_x11/libx11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,8 @@ pub mod Xutil_h {
pub colormap_size: libc::c_int,
pub bits_per_rgb: libc::c_int,
}
pub const USPosition: libc::c_long = (1 as libc::c_long) << 0 as libc::c_int;
pub const PPosition: libc::c_long = (1 as libc::c_long) << 2 as libc::c_int;
pub const PMinSize: libc::c_long = (1 as libc::c_long) << 4 as libc::c_int;
pub const PMaxSize: libc::c_long = (1 as libc::c_long) << 5 as libc::c_int;
pub const PWinGravity: libc::c_long = (1 as libc::c_long) << 9 as libc::c_int;
Expand Down
13 changes: 11 additions & 2 deletions src/native/linux_x11/libx11_ex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,14 @@ impl LibX11 {
| PropertyChangeMask;
self.grab_error_handler();

let pos_x = conf.window_x.map(|x| x as libc::c_int).unwrap_or(0);
let pos_y = conf.window_y.map(|y| y as libc::c_int).unwrap_or(0);

let window = (self.XCreateWindow)(
display,
root,
0 as libc::c_int,
0 as libc::c_int,
pos_x,
pos_y,
conf.window_width as _,
conf.window_height as _,
0 as libc::c_int as libc::c_uint,
Expand All @@ -223,6 +226,12 @@ impl LibX11 {
(self.XSetWMProtocols)(display, window, protocols.as_mut_ptr(), 1 as libc::c_int);
let hints = (self.XAllocSizeHints)();
(*hints).flags |= PWinGravity;
if conf.window_x.is_some() || conf.window_y.is_some() {
// Ask the WM to honor create-time coordinates instead of its own placement.
(*hints).flags |= USPosition | PPosition;
(*hints).x = pos_x;
(*hints).y = pos_y;
}
if !conf.window_resizable {
(*hints).flags |= PMinSize | PMaxSize;
(*hints).min_width = conf.window_width;
Expand Down
4 changes: 3 additions & 1 deletion src/native/linux_x11/x.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub use Xresource_h::{
XrmDatabase, XrmDestroyDatabase, XrmGetResource, XrmGetStringDatabase, XrmValue,
};
pub use Xutil_h::{
IconicState, NormalState, PMinSize, PMaxSize, PWinGravity, WithdrawnState, XAllocSizeHints, XClassHint,
IconicState, NormalState, USPosition, PPosition, PMinSize, PMaxSize, PWinGravity, WithdrawnState, XAllocSizeHints, XClassHint,
XComposeStatus, XLookupString, XSetWMNormalHints, XSizeHints, XVisualInfo, XWMHints,
Xutf8SetWMProperties,
};
Expand Down Expand Up @@ -896,6 +896,8 @@ pub mod Xutil_h {
pub colormap_size: libc::c_int,
pub bits_per_rgb: libc::c_int,
}
pub const USPosition: libc::c_long = (1 as libc::c_long) << 0 as libc::c_int;
pub const PPosition: libc::c_long = (1 as libc::c_long) << 2 as libc::c_int;
pub const PMinSize: libc::c_long = (1 as libc::c_long) << 4 as libc::c_int;
pub const PMaxSize: libc::c_long = (1 as libc::c_long) << 5 as libc::c_int;
pub const PWinGravity: libc::c_long = (1 as libc::c_long) << 9 as libc::c_int;
Expand Down
13 changes: 12 additions & 1 deletion src/native/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,18 @@ where

assert!(!view.is_null());

let () = msg_send![window, center];
if let (Some(x), Some(y)) = (conf.window_x, conf.window_y) {
// Conf uses top-left screen coords; Cocoa screen origin is bottom-left.
let main_screen: ObjcId = msg_send![class!(NSScreen), mainScreen];
let screen_frame: NSRect = msg_send![main_screen, frame];
let top_left = NSPoint {
x: x as f64,
y: screen_frame.size.height - (y as f64),
};
let () = msg_send![window, setFrameTopLeftPoint: top_left];
} else {
let () = msg_send![window, center];
}
let () = msg_send![window, setAcceptsMouseMovedEvents: YES];

if conf.fullscreen {
Expand Down
14 changes: 12 additions & 2 deletions src/native/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@
if unsafe { GetClientRect(self.wnd, &mut rect as *mut _ as _) } != 0 {
let mut new_rect = rect;
new_rect.right = new_rect.right - new_rect.left + new_x as i32;
new_rect.bottom = new_rect.bottom - new_rect.top + new_y as i32;

Check warning on line 253 in src/native/windows.rs

View workflow job for this annotation

GitHub Actions / Build (ubuntu-latest, x86_64-pc-windows-gnu)

value assigned to `new_rect` is never read

Check warning on line 253 in src/native/windows.rs

View workflow job for this annotation

GitHub Actions / Build (windows-latest, x86_64-pc-windows-msvc)

value assigned to `new_rect` is never read
unsafe {
SetWindowPos(
self.wnd,
Expand Down Expand Up @@ -897,6 +897,8 @@
resizable: bool,
width: i32,
height: i32,
window_x: Option<u32>,
window_y: Option<u32>,
) -> (HWND, HDC) {
let mut wndclassw: WNDCLASSW = std::mem::zeroed();

Expand Down Expand Up @@ -948,13 +950,19 @@
let class_name = "MINIQUADAPP\0".encode_utf16().collect::<Vec<u16>>();
let mut window_name = window_title.encode_utf16().collect::<Vec<u16>>();
window_name.push(0);
let (pos_x, pos_y) = match (window_x, window_y) {
(Some(x), Some(y)) => (x as i32, y as i32),
(Some(x), None) => (x as i32, CW_USEDEFAULT),
(None, Some(y)) => (CW_USEDEFAULT, y as i32),
(None, None) => (CW_USEDEFAULT, CW_USEDEFAULT),
};
let hwnd = CreateWindowExW(
win_ex_style, // dwExStyle
class_name.as_ptr(), // lpClassName
window_name.as_ptr(), // lpWindowName
win_style, // dwStyle
CW_USEDEFAULT, // X
CW_USEDEFAULT, // Y
pos_x, // X
pos_y, // Y
win_width, // nWidth
win_height, // nHeight
NULL as _, // hWndParent
Expand Down Expand Up @@ -1164,6 +1172,8 @@
conf.window_resizable,
conf.window_width as _,
conf.window_height as _,
conf.window_x,
conf.window_y,
);
if let Some(icon) = &conf.icon {
set_icon(wnd, icon);
Expand Down
Loading