diff --git a/src/conf.rs b/src/conf.rs index 6a6d0378..9a2203f1 100644 --- a/src/conf.rs +++ b/src/conf.rs @@ -162,6 +162,10 @@ pub struct Conf { /// /// Default: false pub fullscreen: bool, + /// Whether the window should be created without borders, ignored on wasm/android. + /// + /// Default: false + pub borderless: bool, /// MSAA sample count /// /// Default: 1 @@ -221,6 +225,7 @@ impl Default for Conf { window_height: 600, high_dpi: false, fullscreen: false, + borderless: false, sample_count: 1, window_resizable: true, icon: Some(Icon::miniquad_logo()), @@ -238,6 +243,7 @@ impl Default for Conf { window_height: 600, high_dpi: true, fullscreen: true, + borderless: false, sample_count: 1, window_resizable: false, icon: Some(Icon::miniquad_logo()), diff --git a/src/lib.rs b/src/lib.rs index 939758b5..f544eb34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -266,6 +266,13 @@ pub mod window { .unwrap(); } + pub fn set_borderless(borderless: bool) { + let d = native_display().lock().unwrap(); + d.native_requests + .send(native::Request::SetBorderless(borderless)) + .unwrap(); + } + /// Get current OS clipboard value pub fn clipboard_get() -> Option { let mut d = native_display().lock().unwrap(); diff --git a/src/native.rs b/src/native.rs index 88640a55..45c976a2 100644 --- a/src/native.rs +++ b/src/native.rs @@ -70,6 +70,7 @@ pub(crate) enum Request { SetWindowSize { new_width: u32, new_height: u32 }, SetWindowPosition { new_x: u32, new_y: u32 }, SetFullscreen(bool), + SetBorderless(bool), ShowKeyboard(bool), } diff --git a/src/native/linux_x11.rs b/src/native/linux_x11.rs index 12aeea03..68a5ddd0 100644 --- a/src/native/linux_x11.rs +++ b/src/native/linux_x11.rs @@ -16,7 +16,7 @@ use crate::{ use libx11::*; -use std::collections::HashMap; +use std::{collections::HashMap, mem}; #[derive(Debug, PartialEq, Eq, Clone)] pub enum X11Error { @@ -261,6 +261,31 @@ impl X11Display { } } + unsafe fn set_borderless(&mut self, window: Window, borderless: bool) { + let hints_atom = (self.libx11.XInternAtom)( + self.display, + b"_MOTIF_WM_HINTS\x00" as *const u8 as *const _, + false as _, + ); + + let mut hints: MWMHints = mem::zeroed(); + + hints.flags = 2; // MWM_HINTS_DECORATIONS + hints.decorations = if borderless { 0 } else { 1 }; + + (self.libx11.XChangeProperty)( + self.display, + window, + hints_atom as _, + hints_atom as _, + 32, + PropModeReplace, + &mut hints as *mut _ as *mut _, + 5, + ); + (self.libx11.XFlush)(self.display); + } + unsafe fn set_window_size(&mut self, window: Window, new_width: i32, new_height: i32) { (self.libx11.XResizeWindow)(self.display, window, new_width, new_height); (self.libx11.XFlush)(self.display); @@ -359,6 +384,7 @@ impl X11Display { self.set_window_position(self.window, new_x as _, new_y as _) } SetFullscreen(fullscreen) => self.set_fullscreen(self.window, fullscreen), + SetBorderless(borderless) => self.set_borderless(self.window, borderless), ShowKeyboard(..) => { eprintln!("Not implemented for X11") } @@ -419,6 +445,9 @@ where if conf.fullscreen { display.set_fullscreen(display.window, true); } + if conf.borderless { + display.set_borderless(display.window, true); + } let mut event_handler = (f.take().unwrap())(); diff --git a/src/native/linux_x11/libx11.rs b/src/native/linux_x11/libx11.rs index 8000b342..6c38402b 100644 --- a/src/native/linux_x11/libx11.rs +++ b/src/native/linux_x11/libx11.rs @@ -722,6 +722,15 @@ pub mod Xutil_h { } #[derive(Copy, Clone)] #[repr(C)] + pub struct MWMHints { + pub flags: libc::c_ulong, + pub functions: libc::c_ulong, + pub decorations: libc::c_ulong, + pub input_mode: libc::c_long, + pub status: libc::c_ulong, + } + #[derive(Copy, Clone)] + #[repr(C)] pub struct XWMHints { pub flags: libc::c_long, pub input: libc::c_int, diff --git a/src/native/windows.rs b/src/native/windows.rs index a420e820..72c94484 100644 --- a/src/native/windows.rs +++ b/src/native/windows.rs @@ -30,6 +30,7 @@ use libopengl32::LibOpengl32; pub(crate) struct WindowsDisplay { fullscreen: bool, + borderless: bool, dpi_aware: bool, window_resizable: bool, cursor_grabbed: bool, @@ -104,7 +105,7 @@ impl WindowsDisplay { rect.right = (rect.left + new_width as i32) as _; rect.top = (rect.bottom - new_height as i32) as _; - let win_style = get_win_style(self.fullscreen, self.window_resizable); + let win_style = get_win_style(self.fullscreen, self.borderless, self.window_resizable); let win_style_ex: DWORD = unsafe { GetWindowLongA(self.wnd, GWL_EXSTYLE) as _ }; if unsafe { AdjustWindowRectEx( @@ -155,7 +156,8 @@ impl WindowsDisplay { fn set_fullscreen(&mut self, fullscreen: bool) { self.fullscreen = fullscreen as _; - let win_style: DWORD = get_win_style(self.fullscreen, self.window_resizable); + let win_style: DWORD = + get_win_style(self.fullscreen, self.borderless, self.window_resizable); unsafe { #[cfg(target_arch = "x86_64")] @@ -194,14 +196,35 @@ impl WindowsDisplay { ShowWindow(self.wnd, SW_SHOW); }; } + + fn set_borderless(&mut self, borderless: bool) { + self.borderless = borderless as _; + + let win_style: DWORD = + get_win_style(self.fullscreen, self.borderless, self.window_resizable); + + unsafe { + #[cfg(target_arch = "x86_64")] + SetWindowLongPtrA(self.wnd, GWL_STYLE, win_style as _); + #[cfg(target_arch = "i686")] + SetWindowLong(self.wnd, GWL_STYLE, win_style as _); + + ShowWindow(self.wnd, SW_SHOW); + }; + } } -fn get_win_style(is_fullscreen: bool, is_resizable: bool) -> DWORD { +fn get_win_style(is_fullscreen: bool, is_borderless: bool, is_resizable: bool) -> DWORD { if is_fullscreen { WS_POPUP | WS_SYSMENU | WS_VISIBLE } else { - let mut win_style: DWORD = - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; + let mut win_style: DWORD = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX; + + if !is_borderless { + win_style |= WS_CAPTION; + } else { + win_style |= WS_POPUP; + } if is_resizable { win_style |= WS_MAXIMIZEBOX | WS_SIZEBOX; @@ -606,6 +629,7 @@ unsafe fn set_icon(wnd: HWND, icon: &Icon) { unsafe fn create_window( window_title: &str, fullscreen: bool, + borderless: bool, resizable: bool, width: i32, height: i32, @@ -623,7 +647,7 @@ unsafe fn create_window( wndclassw.cbWndExtra = std::mem::size_of::<*mut std::ffi::c_void>() as i32; RegisterClassW(&wndclassw); - let win_style: DWORD; + let win_style: DWORD = get_win_style(fullscreen, borderless, resizable); let win_ex_style: DWORD = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; let mut rect = RECT { left: 0, @@ -633,22 +657,9 @@ unsafe fn create_window( }; if fullscreen { - win_style = WS_POPUP | WS_SYSMENU | WS_VISIBLE; rect.right = GetSystemMetrics(SM_CXSCREEN); rect.bottom = GetSystemMetrics(SM_CYSCREEN); } else { - win_style = if resizable { - WS_CLIPSIBLINGS - | WS_CLIPCHILDREN - | WS_CAPTION - | WS_SYSMENU - | WS_MINIMIZEBOX - | WS_MAXIMIZEBOX - | WS_SIZEBOX - } else { - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX - }; - rect.right = width; rect.bottom = height; } @@ -838,6 +849,7 @@ impl WindowsDisplay { } => self.set_window_size(new_width as _, new_height as _), SetWindowPosition { new_x, new_y } => self.set_window_position(new_x, new_y), SetFullscreen(fullscreen) => self.set_fullscreen(fullscreen), + SetBorderless(borderless) => self.set_borderless(borderless), ShowKeyboard(show) => { eprintln!("Not implemented for windows") } @@ -857,6 +869,7 @@ where let (wnd, dc) = create_window( &conf.window_title, conf.fullscreen, + conf.borderless, conf.window_resizable, conf.window_width as _, conf.window_height as _, @@ -870,6 +883,7 @@ where let (msg_wnd, msg_dc) = create_msg_window(); let mut display = WindowsDisplay { fullscreen: false, + borderless: false, dpi_aware: false, window_resizable: conf.window_resizable, cursor_grabbed: false,