From e7c8a9780d3ac83bed463b9e28573f8ed884cbf7 Mon Sep 17 00:00:00 2001 From: Mirko Covizzi Date: Mon, 25 May 2020 21:35:03 +0200 Subject: [PATCH 1/3] Add Windows initial code --- .gitignore | 2 + Cargo.toml | 4 ++ examples/windows_demo.rs | 21 ++++++++++ src/lib.rs | 8 +++- src/win/mod.rs | 3 ++ src/win/window.rs | 83 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 examples/windows_demo.rs create mode 100644 src/win/mod.rs create mode 100644 src/win/window.rs diff --git a/.gitignore b/.gitignore index 96ef6c0..15baff9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target Cargo.lock +.idea +*.iml diff --git a/Cargo.toml b/Cargo.toml index 8d79041..82e599f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef"] } + +[[example]] +name = "windows_demo" \ No newline at end of file diff --git a/examples/windows_demo.rs b/examples/windows_demo.rs new file mode 100644 index 0000000..7c57ca5 --- /dev/null +++ b/examples/windows_demo.rs @@ -0,0 +1,21 @@ +use std::ptr::null_mut; + +use baseview::{WindowOpenOptions, create_window, handle_msg}; +use baseview::Parent; + +fn main() { + let window = WindowOpenOptions { + title: "Baseview", + width: 800, + height: 400, + parent: Parent::None + }; + + create_window(window); + + loop { + if !handle_msg(null_mut()) { + break; + } + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index e3fafdb..4a875d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,13 @@ +mod win; + +pub use win::*; + use std::ffi::c_void; pub enum Parent { None, AsIfParented, - WithParent(*mut c_void) + WithParent(*mut c_void), } pub struct WindowOpenOptions<'a> { @@ -12,5 +16,5 @@ pub struct WindowOpenOptions<'a> { pub width: usize, pub height: usize, - pub parent: Parent + pub parent: Parent, } 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..5c460cc --- /dev/null +++ b/src/win/window.rs @@ -0,0 +1,83 @@ +extern crate winapi; + +use self::winapi::_core::mem::MaybeUninit; +use self::winapi::shared::minwindef::{LPARAM, LPVOID, LRESULT, UINT, WPARAM}; +use self::winapi::shared::windef::{HBRUSH, HICON, HMENU, HWND}; +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 { + 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: "BaseviewClass\0".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, + "BaseviewClass\0".as_ptr() as *const i8, + "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, + ); + } +} From 5d429fd5ae88dcf0fdcd60671b0271e21efbced6 Mon Sep 17 00:00:00 2001 From: Mirko Covizzi Date: Mon, 25 May 2020 21:55:49 +0200 Subject: [PATCH 2/3] Fix format and setup platform specific dependencies --- Cargo.toml | 7 +++---- examples/windows_demo.rs | 42 ++++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 82e599f..d1e864b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "baseview" version = "0.1.0" -authors = ["William Light "] +authors = ["William Light ", "Mirko Covizzi "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef"] } -[[example]] -name = "windows_demo" \ No newline at end of file +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef"] } diff --git a/examples/windows_demo.rs b/examples/windows_demo.rs index 7c57ca5..9d32316 100644 --- a/examples/windows_demo.rs +++ b/examples/windows_demo.rs @@ -1,21 +1,21 @@ -use std::ptr::null_mut; - -use baseview::{WindowOpenOptions, create_window, handle_msg}; -use baseview::Parent; - -fn main() { - let window = WindowOpenOptions { - title: "Baseview", - width: 800, - height: 400, - parent: Parent::None - }; - - create_window(window); - - loop { - if !handle_msg(null_mut()) { - break; - } - } -} \ No newline at end of file +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; + } + } +} From f75177e9b64087ccefcf1b087d94bc4545df0afb Mon Sep 17 00:00:00 2001 From: Mirko Covizzi Date: Mon, 25 May 2020 22:15:58 +0200 Subject: [PATCH 3/3] Setup unique class naming for windows on Windows --- Cargo.toml | 2 +- src/win/window.rs | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1e864b..4af40fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,4 +9,4 @@ edition = "2018" [dependencies] [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef"] } +winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi"] } diff --git a/src/win/window.rs b/src/win/window.rs index 5c460cc..4684907 100644 --- a/src/win/window.rs +++ b/src/win/window.rs @@ -1,8 +1,10 @@ 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, @@ -47,13 +49,31 @@ pub unsafe extern "system" fn wnd_proc( 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: "BaseviewClass\0".as_ptr() as *const i8, + lpszClassName: class_name.as_ptr() as *const i8, cbClsExtra: 0, cbWndExtra: 0, hIcon: 0 as HICON, @@ -65,7 +85,8 @@ pub fn create_window(w: WindowOpenOptions) { let _hwnd = CreateWindowExA( 0, - "BaseviewClass\0".as_ptr() as *const i8, + 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,