Created Event_Queue and moved to a more correct windows architecture.

This commit is contained in:
2025-11-21 03:40:01 +01:00
parent 0748bd7a7a
commit 0c61dd1de5
2 changed files with 172 additions and 137 deletions

View File

@@ -1,13 +1,19 @@
package window
import "core:container/queue"
import "core:fmt"
Window :: struct {
title: string,
width, height: u16,
backend: Backend_Info,
event_queue: Event_Queue,
}
Event_Queue :: queue.Queue(Event)
Event :: union {
Event_Quit,
Event_Input,
@@ -54,7 +60,6 @@ Event_Input :: union {
}
Event_Resize :: struct {
old_width, old_height: u16,
new_width, new_height: u16,
}
@@ -64,6 +69,7 @@ create :: proc(width, height: u16) -> (^Window, bool) {
w := new(Window)
w.width = width
w.height = height
queue.init(&w.event_queue, 1024)
when ODIN_OS == .Windows {
if !init_window_windows(w) {
@@ -95,7 +101,7 @@ set_title :: proc(window: ^Window, title: string) {
get_pointer_to_surface :: proc(window: ^Window) -> rawptr {
when ODIN_OS == .Windows {
// fmt.printfln("HWND: %v.", window.backend.hwnd)
fmt.printfln("HWND: %v.", window.backend.hwnd)
return window.backend.hwnd
}
else {
@@ -105,29 +111,38 @@ get_pointer_to_surface :: proc(window: ^Window) -> rawptr {
update :: proc(window: ^Window, out_event: ^Event) -> bool {
assert(window != nil)
assert(out_event != nil)
event: Event
when ODIN_OS == .Windows {
event = update_windows(window)
update_windows(window)
}
else {
#assert(false, "Missing implementation for 'set_title'.")
}
out_event^ = event
out_event^ = nil
if out_event^ == nil {
event, ok := queue.pop_front_safe(&window.event_queue)
if !ok {
return false
}
assert(event != nil)
out_event^ = event
return true
}
destroy :: proc(window: ^Window) {
assert(window != nil)
when ODIN_OS == .Windows {
destroy_windows(window)
}
else {
#assert(false, "Missing implementation for 'destroy'.")
}
queue.destroy(&window.event_queue)
free(window)
window^ = {}
}

View File

@@ -1,6 +1,9 @@
package window
import "core:container/queue"
import "core:fmt"
import "core:log"
import "base:runtime"
import win "core:sys/windows"
Backend_Info :: struct {
@@ -8,22 +11,120 @@ Backend_Info :: struct {
hwnd: win.HWND,
}
init_window_windows :: proc(window: ^Window) -> bool {
assert(window != nil)
@(private="file") set_event_queue :: #force_inline proc(hwnd: win.HWND, event_queue: ^Event_Queue) {
win.SetWindowLongPtrW(hwnd, win.GWLP_USERDATA, win.LONG_PTR(uintptr(event_queue)))
}
@(private="file") get_event_queue :: #force_inline proc(hwnd: win.HWND) -> ^Event_Queue {
return (^Event_Queue)(rawptr(uintptr(win.GetWindowLongPtrW(hwnd, win.GWLP_USERDATA))))
}
instance := win.HINSTANCE(win.GetModuleHandleW(nil))
assert(instance != nil, "Failed to fetch current instance")
@(private="file") wm_create :: proc(hwnd: win.HWND, lparam: win.LPARAM) -> win.LRESULT {
pcs := (^win.CREATESTRUCTW)(rawptr(uintptr(lparam)))
assert(pcs != nil)
CLASS_NAME :: "ENSENN_WINDOW"
event_queue := (^Event_Queue)(pcs.lpCreateParams)
assert(event_queue != nil)
cls := win.WNDCLASSW {
lpfnWndProc = proc "stdcall" (hwnd: win.HWND, msg: win.UINT, wparam: win.WPARAM, lparam: win.LPARAM) -> win.LRESULT {
fmt.printfln("Event queue (%v): %v ", &event_queue, event_queue)
set_event_queue(hwnd, event_queue)
fmt.printfln("CREATE")
return 0
}
@(private="file") wnd_proc :: proc "system" (hwnd: win.HWND, msg: win.UINT, wparam: win.WPARAM, lparam: win.LPARAM) -> win.LRESULT {
context = runtime.default_context()
event_queue := get_event_queue(hwnd)
switch(msg) {
case win.WM_CREATE: return wm_create(hwnd, lparam)
case win.WM_KEYDOWN, win.WM_SYSKEYDOWN: {
input_event: Event_Input = Event_Keyboard {
virtual_key = get_virtual_key_windows(i32(wparam)),
state = .Down
}
assert(event_queue != nil)
queue.push_back(event_queue, input_event)
return 0
}
case win.WM_KEYUP, win.WM_SYSKEYUP: {
input_event: Event_Input = Event_Keyboard {
virtual_key = get_virtual_key_windows(i32(wparam)),
state = .Up
}
assert(event_queue != nil)
queue.push_back(event_queue, input_event)
return 0
}
// Mouse.
case win.WM_MOUSEMOVE: {
x := win.GET_X_LPARAM(lparam)
y := win.GET_Y_LPARAM(lparam)
assert(x >= 0)
assert(y >= 0)
mouse_event: Event_Mouse = Event_Mouse_Move {
x = u16(x),
y = u16(y),
}
assert(event_queue != nil)
queue.push_back(event_queue, Event_Input(mouse_event))
return 0
}
case win.WM_LBUTTONDOWN, win.WM_LBUTTONUP: {
mouse_event: Event_Mouse = Event_Mouse_Button {
button = .Left,
state = msg == win.WM_LBUTTONDOWN ? .Down : .Up
}
assert(event_queue != nil)
queue.push_back(event_queue, Event_Input(mouse_event))
return 0
}
case win.WM_MBUTTONDOWN, win.WM_MBUTTONUP: {
mouse_event: Event_Mouse = Event_Mouse_Button {
button = .Middle,
state = msg == win.WM_MBUTTONDOWN ? .Down : .Up
}
assert(event_queue != nil)
queue.push_back(event_queue, Event_Input(mouse_event))
return 0
}
case win.WM_RBUTTONDOWN, win.WM_RBUTTONUP: {
mouse_event: Event_Mouse = Event_Mouse_Button {
button = .Right,
state = msg == win.WM_RBUTTONDOWN ? .Down : .Up
}
assert(event_queue != nil)
queue.push_back(event_queue, Event_Input(mouse_event))
return 0
}
case win.WM_SIZE: {
new_width := u16(win.LOWORD(lparam))
new_height := u16(win.HIWORD(lparam))
assert(event_queue != nil)
queue.push_back(event_queue, Event_Resize { new_width, new_height, })
return 0;
}
case win.WM_CLOSE: {
assert(event_queue != nil)
queue.push_back(event_queue, Event_Quit {})
win.DestroyWindow(hwnd)
}
case win.WM_DESTROY: {
win.PostQuitMessage(0)
return 0
}
case win.WM_ERASEBKGND: {
return 1 // paint should fill out the client area so no need to erase the background
}
case: {
return win.DefWindowProcW(hwnd, msg, wparam, lparam)
@@ -31,8 +132,21 @@ init_window_windows :: proc(window: ^Window) -> bool {
}
return 0
},
lpszClassName = win.utf8_to_wstring(CLASS_NAME),
}
WINDOW_CLASS_NAME :: "ENSENN_WINDOW"
init_window_windows :: proc(window: ^Window) -> bool {
assert(window != nil)
instance := win.HINSTANCE(win.GetModuleHandleW(nil))
assert(instance != nil, "Failed to fetch current instance")
class_name_w := win.utf8_to_wstring(WINDOW_CLASS_NAME)
cls := win.WNDCLASSW {
lpfnWndProc = wnd_proc,
lpszClassName = class_name_w,
hInstance = instance,
hCursor = win.LoadCursorA(nil, win.IDC_ARROW),
}
@@ -52,8 +166,8 @@ init_window_windows :: proc(window: ^Window) -> bool {
actual_window_height := rect.bottom - rect.top
hwnd := win.CreateWindowW(
lpClassName = win.L(CLASS_NAME),
lpWindowName = win.L(CLASS_NAME),
lpClassName = win.L(WINDOW_CLASS_NAME),
lpWindowName = win.L(WINDOW_CLASS_NAME),
dwStyle = window_style,
X = (screen_width - i32(window.width)) / 2,
Y = (screen_height - i32(window.height)) / 2,
@@ -62,7 +176,7 @@ init_window_windows :: proc(window: ^Window) -> bool {
hWndParent = nil,
hMenu = nil,
hInstance = instance,
lpParam = nil
lpParam = &window.event_queue
)
assert(hwnd != nil, "Window creation failed")
@@ -81,124 +195,30 @@ set_title_windows :: proc(window: ^Window) {
win.SetWindowTextW(window.backend.hwnd, win.utf8_to_wstring(window.title))
}
update_windows :: proc(window: ^Window) -> Event {
update_windows :: proc(window: ^Window) {
assert(window != nil)
{ // Message loop.
msg: win.MSG
{ // Resizing.
rect: win.RECT
win.GetClientRect(window.backend.hwnd, &rect)
new_width := u16(rect.right - rect.left)
new_height := u16(rect.bottom - rect.top)
if new_width != window.width || new_height != window.height {
old_width := window.width
old_height := window.height
window.width = new_width
window.height = new_height
if new_width > 0 && new_height > 0 {
return Event_Resize {
old_width, old_height,
window.width, window.height,
}
}
}
}
win.CoInitializeEx(nil)
ok := win.PeekMessageW(
lpMsg = &msg,
hWnd = nil, // NOTE: SS - Don't like that this needs to be nil but apparently it does for this window to receive the WM_CLOSE and WM_QUIT messages.
// If wMsgFilterMin and wMsgFilterMax are both zero,
// PeekMessage returns all available messages (that is, no range filtering is performed).
wMsgFilterMin = 0, wMsgFilterMax = 0,
wRemoveMsg = win.PM_REMOVE // If 'PM_REMOVE', messages are removed from the queue after processing by PeekMessage.
)
if !ok {
// No messages.
return nil
}
for win.PeekMessageW(lpMsg = &msg, hWnd = nil, wMsgFilterMin = 0, wMsgFilterMax = 0, wRemoveMsg = win.PM_REMOVE) == win.TRUE {
win.TranslateMessage(&msg)
win.DispatchMessageW(&msg)
// fmt.printfln("Message type: %x", msg.message)
switch msg.message {
// Keyboard.
case win.WM_KEYDOWN, win.WM_SYSKEYDOWN: {
input_event: Event_Input = Event_Keyboard {
virtual_key = get_virtual_key_windows(i32(msg.wParam)),
state = .Down
}
return input_event
}
case win.WM_KEYUP, win.WM_SYSKEYUP: {
input_event: Event_Input = Event_Keyboard {
virtual_key = get_virtual_key_windows(i32(msg.wParam)),
state = .Up
}
return input_event
}
// Mouse.
case win.WM_MOUSEMOVE: {
x := win.GET_X_LPARAM(msg.lParam)
y := win.GET_Y_LPARAM(msg.lParam)
assert(x >= 0)
assert(y >= 0)
mouse_event: Event_Mouse = Event_Mouse_Move{
x = u16(x),
y = u16(y),
}
return Event_Input(mouse_event)
}
case win.WM_LBUTTONDOWN, win.WM_LBUTTONUP: {
mouse_event: Event_Mouse = Event_Mouse_Button {
button = .Left,
state = msg.message == win.WM_LBUTTONDOWN ? .Down : .Up
}
return Event_Input(mouse_event)
}
case win.WM_MBUTTONDOWN, win.WM_MBUTTONUP: {
mouse_event: Event_Mouse = Event_Mouse_Button {
button = .Middle,
state = msg.message == win.WM_MBUTTONDOWN ? .Down : .Up
}
return Event_Input(mouse_event)
}
case win.WM_RBUTTONDOWN, win.WM_RBUTTONUP: {
mouse_event: Event_Mouse = Event_Mouse_Button {
button = .Right,
state = msg.message == win.WM_RBUTTONDOWN ? .Down : .Up
}
return Event_Input(mouse_event)
}
case win.WM_QUIT: {
return Event_Quit {}
}
}
return nil
}
destroy_windows :: proc(window: ^Window) {
assert(window != nil)
assert(window.backend.hwnd != nil)
win.SetWindowLongPtrW(window.backend.hwnd, win.GWLP_USERDATA, 0)
win.DestroyWindow(window.backend.hwnd)
window.backend.hwnd = nil
class_name_w := win.utf8_to_wstring(WINDOW_CLASS_NAME)
win.UnregisterClassW(class_name_w, window.backend.instance)
}
@(private) get_virtual_key_windows :: proc(vk: i32) -> Virtual_Key {