1
0
Fork 0

Windows: Refactor: move register window class into its own function

This commit is contained in:
Mirko Covizzi 2020-06-12 22:41:30 +02:00
parent c54a2b3fb3
commit f35f97c73e

View file

@ -4,8 +4,8 @@ use std::ffi::CString;
use std::ptr::null_mut;
use self::winapi::shared::guiddef::GUID;
use self::winapi::shared::minwindef::{LPARAM, LRESULT, UINT, WPARAM};
use self::winapi::shared::windef::{HDC, HGLRC, HWND};
use self::winapi::shared::minwindef::{ATOM, FALSE, LPARAM, LRESULT, UINT, WPARAM};
use self::winapi::shared::windef::{HDC, HGLRC, HWND, RECT};
use self::winapi::um::combaseapi::CoCreateGuid;
use self::winapi::um::libloaderapi::{GetProcAddress, LoadLibraryA};
use self::winapi::um::wingdi::{
@ -14,11 +14,11 @@ use self::winapi::um::wingdi::{
PFD_TYPE_RGBA, PIXELFORMATDESCRIPTOR,
};
use self::winapi::um::winuser::{
CreateWindowExA, DefWindowProcA, DestroyWindow, DispatchMessageA, GetDC, MessageBoxA,
PeekMessageA, PostQuitMessage, RegisterClassA, ReleaseDC, TranslateMessage, UnregisterClassA,
CS_HREDRAW, CS_OWNDC, CS_VREDRAW, MB_ICONERROR, MB_OK, MB_TOPMOST, MSG, PM_REMOVE, WM_CLOSE,
WM_QUIT, WNDCLASSA, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX,
WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
AdjustWindowRectEx, CreateWindowExA, DefWindowProcA, DestroyWindow, DispatchMessageA, GetDC,
MessageBoxA, PeekMessageA, PostQuitMessage, RegisterClassA, ReleaseDC, TranslateMessage,
UnregisterClassA, CS_OWNDC, MB_ICONERROR, MB_OK, MB_TOPMOST, MSG,
PM_REMOVE, WM_CLOSE, WM_QUIT, WNDCLASSA, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX,
WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
};
use crate::Parent::WithParent;
@ -49,151 +49,6 @@ unsafe fn generate_guid() -> String {
)
}
pub struct Window {
hwnd: HWND,
hdc: HDC,
gl_context: HGLRC,
class_name: *const i8,
}
impl Window {
// todo: we should decide this interface
pub fn open(options: WindowOpenOptions) -> Self {
unsafe {
let mut hwnd = null_mut();
let mut hdc = null_mut();
let mut gl_context = null_mut();
// We generate a unique name for the new window class to prevent name collisions
let class_name = format!("Baseview-{}", generate_guid()).as_ptr() as *const i8;
let window = Window {
hwnd,
hdc,
gl_context,
class_name,
};
let wnd_class = WNDCLASSA {
style: CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wnd_proc),
hInstance: null_mut(),
lpszClassName: class_name,
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: null_mut(),
lpszMenuName: std::ptr::null::<i8>(),
};
RegisterClassA(&wnd_class);
let mut flags = WS_POPUPWINDOW
| WS_CAPTION
| WS_VISIBLE
| WS_SIZEBOX
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPSIBLINGS;
let mut parent = null_mut();
if let WithParent(p) = options.parent {
parent = p;
flags = WS_CHILD | WS_VISIBLE;
}
hwnd = CreateWindowExA(
0,
class_name,
(options.title.to_owned() + "\0").as_ptr() as *const i8,
flags,
0,
0,
// todo: check if usize fits into i32
options.width as i32,
options.height as i32,
parent as *mut _,
null_mut(),
null_mut(),
null_mut(),
);
hdc = GetDC(hwnd);
let mut pfd: PIXELFORMATDESCRIPTOR = std::mem::zeroed();
pfd.nSize = std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u16;
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
// todo: ask wrl why 24 instead of 32?
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
let pf_id: i32 = ChoosePixelFormat(hdc, &pfd);
if pf_id == 0 {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
if SetPixelFormat(hdc, pf_id, &pfd) == 0 {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
gl_context = wglCreateContext(hdc);
if gl_context == 0 as HGLRC {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
if wglMakeCurrent(hdc, gl_context) == 0 {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
let h = LoadLibraryA("opengl32.dll\0".as_ptr() as *const i8);
gl::load_with(|symbol| {
let symbol = CString::new(symbol.as_bytes()).unwrap();
let symbol = symbol.as_ptr();
GetProcAddress(h, symbol) as *const _
});
// todo: decide what to do with the message pump
if parent.is_null() {
loop {
if !handle_msg(null_mut()) {
break;
}
// todo: pass callback rendering function instead
gl::ClearColor(0.3, 0.8, 0.3, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
SwapBuffers(hdc);
}
}
window
}
}
pub fn close(&self) {
// todo: see https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L402
unsafe {
wglMakeCurrent(null_mut(), null_mut());
wglDeleteContext(self.gl_context);
ReleaseDC(self.hwnd, self.hdc);
DestroyWindow(self.hwnd);
UnregisterClassA(self.class_name, null_mut());
}
}
}
fn handle_msg(_window: HWND) -> bool {
unsafe {
let mut msg: MSG = std::mem::zeroed();
@ -224,3 +79,170 @@ unsafe extern "system" fn wnd_proc(
}
0
}
unsafe fn register_wnd_class() -> ATOM {
// We generate a unique name for the new window class to prevent name collisions
let class_name = format!("Baseview-{}", generate_guid()).as_ptr() as *const i8;
let wnd_class = WNDCLASSA {
style: CS_OWNDC,
lpfnWndProc: Some(wnd_proc),
hInstance: null_mut(),
lpszClassName: class_name,
cbClsExtra: 0,
cbWndExtra: 0,
hIcon: null_mut(),
hCursor: null_mut(),
hbrBackground: null_mut(),
lpszMenuName: null_mut(),
};
RegisterClassA(&wnd_class)
}
unsafe fn unregister_wnd_class(wnd_class: ATOM) {
UnregisterClassA(wnd_class as _, null_mut());
}
unsafe fn init_gl_context() {}
pub struct Window {
hwnd: HWND,
hdc: HDC,
gl_context: HGLRC,
window_class: ATOM,
}
impl Window {
pub fn open(options: WindowOpenOptions) -> Self {
unsafe {
let mut window = Window {
hwnd: null_mut(),
hdc: null_mut(),
gl_context: null_mut(),
window_class: 0,
};
let title = (options.title.to_owned() + "\0").as_ptr() as *const i8;
window.window_class = register_wnd_class();
// todo: manage error ^
let mut flags = WS_POPUPWINDOW
| WS_CAPTION
| WS_VISIBLE
| WS_SIZEBOX
| WS_MINIMIZEBOX
| WS_MAXIMIZEBOX
| WS_CLIPSIBLINGS;
let mut rect = RECT {
left: 0,
top: 0,
// todo: check if usize fits into i32
right: options.width as i32,
bottom: options.height as i32,
};
// todo: add check flags https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L351
let mut parent = null_mut();
if let WithParent(p) = options.parent {
parent = p;
flags = WS_CHILD | WS_VISIBLE;
} else {
AdjustWindowRectEx(&mut rect, flags, FALSE, 0);
}
window.hwnd = CreateWindowExA(
0,
window.window_class as _,
title,
flags,
0,
0,
rect.right - rect.left,
rect.bottom - rect.top,
parent as *mut _,
null_mut(),
null_mut(),
null_mut(),
);
// todo: manage error ^
window.hdc = GetDC(window.hwnd);
//init_gl_context(&window, title);
let mut pfd: PIXELFORMATDESCRIPTOR = std::mem::zeroed();
pfd.nSize = std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u16;
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
// todo: ask wrl why 24 instead of 32?
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
let pf_id: i32 = ChoosePixelFormat(window.hdc, &pfd);
if pf_id == 0 {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
if SetPixelFormat(window.hdc, pf_id, &pfd) == 0 {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
window.gl_context = wglCreateContext(window.hdc);
if window.gl_context == 0 as HGLRC {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
if wglMakeCurrent(window.hdc, window.gl_context) == 0 {
// todo: use a more useful return like an Option
// todo: also launch error message boxes
return window;
}
let h = LoadLibraryA("opengl32.dll\0".as_ptr() as *const i8);
gl::load_with(|symbol| {
let symbol = CString::new(symbol.as_bytes()).unwrap();
let symbol = symbol.as_ptr();
GetProcAddress(h, symbol) as *const _
});
// todo: decide what to do with the message pump
if parent.is_null() {
loop {
if !handle_msg(null_mut()) {
break;
}
// todo: pass callback rendering function instead
gl::ClearColor(0.3, 0.8, 0.3, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
SwapBuffers(window.hdc);
}
}
window
}
}
pub fn close(&self) {
// todo: see https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L402
unsafe {
wglMakeCurrent(null_mut(), null_mut());
wglDeleteContext(self.gl_context);
ReleaseDC(self.hwnd, self.hdc);
DestroyWindow(self.hwnd);
unregister_wnd_class(self.window_class);
}
}
}