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
23 changes: 21 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,31 @@ keyboard-types = { version = "0.6.1", default-features = false }
raw-window-handle = "0.5"

[target.'cfg(target_os="linux")'.dependencies]
x11rb = { version = "0.13.0", features = ["cursor", "resource_manager", "allow-unsafe-code"] }
x11rb = { version = "0.13.0", features = [
"cursor",
"resource_manager",
"allow-unsafe-code",
] }
x11 = { version = "2.21", features = ["xlib", "xlib_xcb"] }
nix = "0.22.0"

[target.'cfg(target_os="windows")'.dependencies]
winapi = { version = "0.3.8", features = ["libloaderapi", "winuser", "windef", "minwindef", "guiddef", "combaseapi", "wingdi", "errhandlingapi", "ole2", "oleidl", "shellapi", "winerror"] }
windows = { version = "0.62.2", features = [
"Win32_Graphics_Gdi",
"Win32_Graphics_OpenGL",
"Win32_System_Com_StructuredStorage",
"Win32_System_Com",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_UI_Controls",
"Win32_UI_HiDpi",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging",
] }
windows-core = { version = "0.62.2" }
uuid = { version = "0.8", features = ["v4"], optional = true }

[target.'cfg(target_os="macos")'.dependencies]
Expand Down
159 changes: 82 additions & 77 deletions src/gl/win.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
use std::ffi::{c_void, CString, OsStr};
use std::os::windows::ffi::OsStrExt;

use raw_window_handle::RawWindowHandle;

use winapi::shared::minwindef::{HINSTANCE, HMODULE};
use winapi::shared::ntdef::WCHAR;
use winapi::shared::windef::{HDC, HGLRC, HWND};
use winapi::um::libloaderapi::{FreeLibrary, GetProcAddress, LoadLibraryA};
use winapi::um::wingdi::{
wglCreateContext, wglDeleteContext, wglGetProcAddress, wglMakeCurrent, ChoosePixelFormat,
DescribePixelFormat, SetPixelFormat, SwapBuffers, PFD_DOUBLEBUFFER, PFD_DRAW_TO_WINDOW,
PFD_MAIN_PLANE, PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, PIXELFORMATDESCRIPTOR,
};
use winapi::um::winnt::IMAGE_DOS_HEADER;
use winapi::um::winuser::{
CreateWindowExW, DefWindowProcW, DestroyWindow, GetDC, RegisterClassW, ReleaseDC,
UnregisterClassW, CS_OWNDC, CW_USEDEFAULT, WNDCLASSW,
use windows::{
core::{s, PCSTR, PCWSTR},
Win32::{
Foundation::{FreeLibrary, HINSTANCE, HMODULE, HWND, LPARAM, LRESULT, WPARAM},
Graphics::{
Gdi::{GetDC, ReleaseDC, HDC},
OpenGL::{
wglCreateContext, wglDeleteContext, wglGetProcAddress, wglMakeCurrent,
ChoosePixelFormat, DescribePixelFormat, SetPixelFormat, SwapBuffers, HGLRC,
PFD_DOUBLEBUFFER, PFD_DRAW_TO_WINDOW, PFD_MAIN_PLANE, PFD_SUPPORT_OPENGL,
PFD_TYPE_RGBA, PIXELFORMATDESCRIPTOR,
},
},
System::{
LibraryLoader::{GetProcAddress, LoadLibraryA},
SystemServices::IMAGE_DOS_HEADER,
},
UI::WindowsAndMessaging::{
CreateWindowExW, DefWindowProcW, DestroyWindow, RegisterClassW, UnregisterClassW,
CS_OWNDC, CW_USEDEFAULT, WINDOW_EX_STYLE, WINDOW_STYLE, WNDCLASSW,
},
},
};

use raw_window_handle::RawWindowHandle;

use super::{GlConfig, GlError, Profile};

// See https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_create_context.txt
Expand Down Expand Up @@ -77,6 +86,7 @@ extern "C" {
}

impl GlContext {
#[allow(unused)]
pub unsafe fn create(parent: &RawWindowHandle, config: GlConfig) -> Result<GlContext, GlError> {
let handle = if let RawWindowHandle::Win32(handle) = parent {
handle
Expand All @@ -91,16 +101,24 @@ impl GlContext {
// Create temporary window and context to load function pointers

let class_name_str = format!("raw-gl-context-window-{}", uuid::Uuid::new_v4().to_simple());
let mut class_name: Vec<WCHAR> = OsStr::new(&class_name_str).encode_wide().collect();
let mut class_name: Vec<u16> = OsStr::new(&class_name_str).encode_wide().collect();
class_name.push(0);

let hinstance = &__ImageBase as *const IMAGE_DOS_HEADER as HINSTANCE;
let pcw_class_name = PCWSTR(class_name.as_ptr());

let hinstance = HINSTANCE(&__ImageBase as *const IMAGE_DOS_HEADER as *mut c_void);

extern "system" fn wndproc(
hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM,
) -> LRESULT {
unsafe { DefWindowProcW(hwnd, msg, wparam, lparam) }
}

let wnd_class = WNDCLASSW {
style: CS_OWNDC,
lpfnWndProc: Some(DefWindowProcW),
lpfnWndProc: Some(wndproc),
hInstance: hinstance,
lpszClassName: class_name.as_ptr(),
lpszClassName: pcw_class_name,
..std::mem::zeroed()
};

Expand All @@ -110,23 +128,24 @@ impl GlContext {
}

let hwnd_tmp = CreateWindowExW(
0,
class as *const WCHAR,
[0].as_ptr(),
0,
WINDOW_EX_STYLE(0),
pcw_class_name,
None,
WINDOW_STYLE(0),
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
std::ptr::null_mut(),
std::ptr::null_mut(),
hinstance,
std::ptr::null_mut(),
None,
None,
Some(hinstance),
None,
);

if hwnd_tmp.is_null() {
if hwnd_tmp.is_err() {
return Err(GlError::CreationFailed(()));
}
let hwnd_tmp = hwnd_tmp.ok();

let hdc_tmp = GetDC(hwnd_tmp);

Expand All @@ -139,69 +158,49 @@ impl GlContext {
cAlphaBits: 8,
cDepthBits: 24,
cStencilBits: 8,
iLayerType: PFD_MAIN_PLANE,
iLayerType: PFD_MAIN_PLANE.0 as u8,
..std::mem::zeroed()
};

SetPixelFormat(hdc_tmp, ChoosePixelFormat(hdc_tmp, &pfd_tmp), &pfd_tmp);

let hglrc_tmp = wglCreateContext(hdc_tmp);
if hglrc_tmp.is_null() {
if hglrc_tmp.is_err() {
ReleaseDC(hwnd_tmp, hdc_tmp);
UnregisterClassW(class as *const WCHAR, hinstance);
DestroyWindow(hwnd_tmp);
UnregisterClassW(pcw_class_name, Some(hinstance));
DestroyWindow(hwnd_tmp.unwrap());
return Err(GlError::CreationFailed(()));
}
let hglrc_tmp = hglrc_tmp.unwrap();

wglMakeCurrent(hdc_tmp, hglrc_tmp);

#[allow(non_snake_case)]
let wglCreateContextAttribsARB: Option<WglCreateContextAttribsARB> = {
let symbol = CString::new("wglCreateContextAttribsARB").unwrap();
let addr = wglGetProcAddress(symbol.as_ptr());
if !addr.is_null() {
#[allow(clippy::missing_transmute_annotations)]
Some(std::mem::transmute(addr))
} else {
None
}
wglGetProcAddress(s!("wglCreateContextAttribsARB"))
.map(|addr| std::mem::transmute(addr))
};

#[allow(non_snake_case)]
let wglChoosePixelFormatARB: Option<WglChoosePixelFormatARB> = {
let symbol = CString::new("wglChoosePixelFormatARB").unwrap();
let addr = wglGetProcAddress(symbol.as_ptr());
if !addr.is_null() {
#[allow(clippy::missing_transmute_annotations)]
Some(std::mem::transmute(addr))
} else {
None
}
wglGetProcAddress(s!("wglChoosePixelFormatARB")).map(|addr| std::mem::transmute(addr))
};

#[allow(non_snake_case)]
let wglSwapIntervalEXT: Option<WglSwapIntervalEXT> = {
let symbol = CString::new("wglSwapIntervalEXT").unwrap();
let addr = wglGetProcAddress(symbol.as_ptr());
if !addr.is_null() {
#[allow(clippy::missing_transmute_annotations)]
Some(std::mem::transmute(addr))
} else {
None
}
};
let wglSwapIntervalEXT: Option<WglSwapIntervalEXT> =
{ wglGetProcAddress(s!("wglSwapIntervalEXT")).map(|addr| std::mem::transmute(addr)) };

wglMakeCurrent(hdc_tmp, std::ptr::null_mut());
wglMakeCurrent(hdc_tmp, HGLRC::default());
wglDeleteContext(hglrc_tmp);
ReleaseDC(hwnd_tmp, hdc_tmp);
UnregisterClassW(class as *const WCHAR, hinstance);
DestroyWindow(hwnd_tmp);
UnregisterClassW(wnd_class.lpszClassName, Some(hinstance));
DestroyWindow(hwnd_tmp.unwrap());

// Create actual context

let hwnd = handle.hwnd as HWND;
let hwnd = HWND(handle.hwnd);

let hdc = GetDC(hwnd);
let hdc = GetDC(Some(hwnd));

#[rustfmt::skip]
let pixel_format_attribs = [
Expand Down Expand Up @@ -238,7 +237,7 @@ impl GlContext {
hdc,
pixel_format,
std::mem::size_of::<PIXELFORMATDESCRIPTOR>() as u32,
&mut pfd,
Some(&mut pfd),
);
SetPixelFormat(hdc, pixel_format, &pfd);

Expand All @@ -256,40 +255,45 @@ impl GlContext {
];

let hglrc =
wglCreateContextAttribsARB.unwrap()(hdc, std::ptr::null_mut(), ctx_attribs.as_ptr());
if hglrc.is_null() {
wglCreateContextAttribsARB.unwrap()(hdc, HGLRC::default(), ctx_attribs.as_ptr());
if hglrc.is_invalid() {
return Err(GlError::CreationFailed(()));
}

let gl_library_name = CString::new("opengl32.dll").unwrap();
let gl_library = LoadLibraryA(gl_library_name.as_ptr());
let gl_library = LoadLibraryA(s!("opengl32.dll")).unwrap_or_default();

wglMakeCurrent(hdc, hglrc);
wglSwapIntervalEXT.unwrap()(config.vsync as i32);
wglMakeCurrent(hdc, std::ptr::null_mut());
wglMakeCurrent(hdc, HGLRC::default());

Ok(GlContext { hwnd, hdc, hglrc, gl_library })
}

#[allow(unused)]
pub unsafe fn make_current(&self) {
wglMakeCurrent(self.hdc, self.hglrc);
}

#[allow(unused)]
pub unsafe fn make_not_current(&self) {
wglMakeCurrent(self.hdc, std::ptr::null_mut());
wglMakeCurrent(self.hdc, HGLRC::default());
}

pub fn get_proc_address(&self, symbol: &str) -> *const c_void {
let symbol = CString::new(symbol).unwrap();
let addr = unsafe { wglGetProcAddress(symbol.as_ptr()) as *const c_void };
if !addr.is_null() {
addr
} else {
unsafe { GetProcAddress(self.gl_library, symbol.as_ptr()) as *const c_void }
unsafe {
wglGetProcAddress(PCSTR(symbol.as_ptr() as *const u8))
.map(|p| p as *const c_void)
.or_else(|| {
GetProcAddress(self.gl_library, PCSTR(symbol.as_ptr() as *const u8))
.map(|p| p as *const c_void)
})
.unwrap_or_default()
}
}

pub fn swap_buffers(&self) {
#[allow(unused)]
unsafe {
SwapBuffers(self.hdc);
}
Expand All @@ -298,10 +302,11 @@ impl GlContext {

impl Drop for GlContext {
fn drop(&mut self) {
#[allow(unused)]
unsafe {
wglMakeCurrent(std::ptr::null_mut(), std::ptr::null_mut());
wglMakeCurrent(HDC::default(), HGLRC::default());
wglDeleteContext(self.hglrc);
ReleaseDC(self.hwnd, self.hdc);
ReleaseDC(Some(self.hwnd), self.hdc);
FreeLibrary(self.gl_library);
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/win/cursor.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use crate::MouseCursor;
use winapi::{
shared::ntdef::LPCWSTR,
um::winuser::{
use windows::{
core::PCWSTR,
Win32::UI::WindowsAndMessaging::{
IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM, IDC_NO, IDC_SIZEALL,
IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE, IDC_WAIT,
},
};

pub fn cursor_to_lpcwstr(cursor: MouseCursor) -> LPCWSTR {
pub fn cursor_to_lpcwstr(cursor: MouseCursor) -> PCWSTR {
match cursor {
MouseCursor::Default => IDC_ARROW,
MouseCursor::Hand => IDC_HAND,
MouseCursor::HandGrabbing => IDC_SIZEALL,
MouseCursor::Help => IDC_HELP,
// an empty LPCWSTR results in the cursor being hidden
MouseCursor::Hidden => std::ptr::null(),
MouseCursor::Hidden => PCWSTR::null(),

MouseCursor::Text => IDC_IBEAM,
MouseCursor::VerticalText => IDC_IBEAM,
Expand Down
Loading
Loading