diff --git a/.gitignore b/.gitignore index 26629f5..15baff9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ /target Cargo.lock - -# CLion stuff -.idea/ +.idea +*.iml diff --git a/Cargo.toml b/Cargo.toml index a61ec75..d27fcb2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,14 +3,17 @@ name = "baseview" version = "0.1.0" authors = [ "William Light ", - "Charles Saracco " + "Charles Saracco ", + "Mirko Covizzi " ] edition = "2018" [dependencies] + [target.'cfg(target_os="linux")'.dependencies] xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] } -# [target.'cfg(target_os="windows")'.dependencies] +[target.'cfg(target_os="windows")'.dependencies] +winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi"] } -# [target.'cfg(target_os="macos")'.dependencies] \ No newline at end of file +# [target.'cfg(target_os="macos")'.dependencies] diff --git a/examples/windows.rs b/examples/windows.rs new file mode 100644 index 0000000..9d32316 --- /dev/null +++ b/examples/windows.rs @@ -0,0 +1,21 @@ +use std::ptr::null_mut; + +use baseview::Parent; +use baseview::{create_window, handle_msg, WindowOpenOptions}; + +fn main() { + let window = WindowOpenOptions { + title: "Baseview", + width: 800, + height: 400, + parent: Parent::None, + }; + + create_window(window); + + loop { + if !handle_msg(null_mut()) { + break; + } + } +} diff --git a/src/lib.rs b/src/lib.rs index aaf7105..1f469d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +mod win; + +pub use win::*; + use std::ffi::c_void; mod x11; diff --git a/src/win/mod.rs b/src/win/mod.rs new file mode 100644 index 0000000..b0fcdd9 --- /dev/null +++ b/src/win/mod.rs @@ -0,0 +1,3 @@ +mod window; + +pub use window::*; diff --git a/src/win/window.rs b/src/win/window.rs new file mode 100644 index 0000000..4684907 --- /dev/null +++ b/src/win/window.rs @@ -0,0 +1,104 @@ +extern crate winapi; + +use self::winapi::_core::mem::MaybeUninit; +use self::winapi::shared::guiddef::GUID; +use self::winapi::shared::minwindef::{LPARAM, LPVOID, LRESULT, UINT, WPARAM}; +use self::winapi::shared::windef::{HBRUSH, HICON, HMENU, HWND}; +use self::winapi::um::combaseapi::CoCreateGuid; +use self::winapi::um::libloaderapi::GetModuleHandleA; +use self::winapi::um::winuser::{ + CreateWindowExA, DefWindowProcA, DispatchMessageA, PeekMessageA, PostQuitMessage, + RegisterClassA, TranslateMessage, CS_HREDRAW, CS_OWNDC, CS_VREDRAW, CW_USEDEFAULT, MSG, + PM_REMOVE, WM_DESTROY, WM_QUIT, WNDCLASSA, WS_OVERLAPPEDWINDOW, WS_VISIBLE, +}; + +use crate::WindowOpenOptions; + +pub fn handle_msg(_window: HWND) -> bool { + unsafe { + let mut msg: MSG = MaybeUninit::uninit().assume_init(); + loop { + if PeekMessageA(&mut msg, 0 as HWND, 0, 0, PM_REMOVE) == 0 { + return true; + } + if msg.message == WM_QUIT { + return false; + } + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } +} + +pub unsafe extern "system" fn wnd_proc( + hwnd: HWND, + msg: UINT, + w_param: WPARAM, + l_param: LPARAM, +) -> LRESULT { + match msg { + WM_DESTROY => { + PostQuitMessage(0); + } + _ => { + return DefWindowProcA(hwnd, msg, w_param, l_param); + } + } + return 0; +} + +pub fn create_window(w: WindowOpenOptions) { + unsafe { + // We generate a unique name for the new window class to prevent name collisions + let mut guid: GUID = MaybeUninit::uninit().assume_init(); + CoCreateGuid(&mut guid); + let class_name = format!( + "Baseview-{}-{}-{}-{}{}{}{}{}{}{}{}\0", + guid.Data1, + guid.Data2, + guid.Data3, + guid.Data4[0], + guid.Data4[1], + guid.Data4[2], + guid.Data4[3], + guid.Data4[4], + guid.Data4[5], + guid.Data4[6], + guid.Data4[7] + ); + + let hinstance = GetModuleHandleA(0 as *const i8); + let wnd_class = WNDCLASSA { + // todo: for OpenGL, will use it later + style: CS_OWNDC | CS_HREDRAW | CS_VREDRAW, + lpfnWndProc: Some(wnd_proc), + hInstance: hinstance, + lpszClassName: class_name.as_ptr() as *const i8, + cbClsExtra: 0, + cbWndExtra: 0, + hIcon: 0 as HICON, + hCursor: 0 as HICON, + hbrBackground: 0 as HBRUSH, + lpszMenuName: 0 as *const i8, + }; + RegisterClassA(&wnd_class); + + let _hwnd = CreateWindowExA( + 0, + class_name.as_ptr() as *const i8, + // todo: change title based on options struct + "Baseview\0".as_ptr() as *const i8, + // todo: fine for now, will have to change with a parent + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + // todo: check if usize fits into i32 + w.width as i32, + w.height as i32, + 0 as HWND, + 0 as HMENU, + hinstance, + 0 as LPVOID, + ); + } +}