window management. still missing first paint but progressing

This commit is contained in:
Patedam committed 2026-10-24 22:52:26 -04:00
1 parent bf13f269fe
commit f6b48a1c11
9 files changed
+4703 -18

No files matched your search

+19 -2
View File
@@ -74,16 +74,22 @@
// For loop helpers // For loop helpers
#define EachIndex(it, count) (uint64 it = 0; it < (count); ++it) #define EachIndex(it, count) (uint64 it = 0; it < (count); ++it)
#define EachNode(it, Type, first) (Type* it = first; it != 0; it = it->next)
// ============================================================================= // =============================================================================
// Memory Helpers // Memory Helpers
#define MemoryCopy(dst, src, size) memmove((dst), (src), (size)) #define MemoryCopy(dst, src, size) memmove((dst), (src), (size))
#define MemorySet(dst, src, size) memset((dst), (src), (size)) #define MemorySet(dst, src, size) memset((dst), (src), (size))
#define MemoryCompare(a, b, size) memcmp((a), (b), (size))
#define MemoryZero(ptr, size) memset((ptr), 0, (size)) #define MemoryZero(ptr, size) memset((ptr), 0, (size))
#define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s))) #define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s)))
#define MemoryMatch(a, b, size) (MemoryCompare((a), (b), (size)) == 0)
#define MemoryMatchStruct(a, b) MemoryMatch((a), (b), sizeof(*(a)))
#define MemoryMatchArray(a, b) MemoryMatch((a), (b), sizeof(a))
// ============================================================================= // =============================================================================
// Asserts // Asserts
@@ -135,18 +141,29 @@
(CheckNil(nil, (node)->next) ? (0) : ((node)->next->previous = (node)->previous))) (CheckNil(nil, (node)->next) ? (0) : ((node)->next->previous = (node)->previous)))
// clang-format on // clang-format on
// Single link double head lists (= queues)
#define SLL_queue_push_next_zero(nil, first, last, node, next) \
(CheckNil(nil, first) ? ((first) = (last) = (node), SetNil(nil, (node)->next)) \
: ((last)->next = (node), (last) = (node), SetNil(nil, (node)->next)))
// Single (link & head) lists (= stacks) // Single (link & head) lists (= stacks)
#define SLL_stack_push_next(first, node, next) ((node)->next = (first), (first) = (node)) #define SLL_stack_push_next(first, node, next) ((node)->next = (first), (first) = (node))
#define SLL_stack_pop_next(first, next) ((first) = (first)->next); #define SLL_stack_pop_next(first, next) ((first) = (first)->next);
#define SLL_stack_push(first, node) SLL_stack_push_next(first, node, next)
#define SLL_stack_pop(first) SLL_stack_pop_next(first, next)
// Double linked list helpers // Double linked list helpers
#define DLL_push_back_next_prev(first, last, node, next, previous) \ #define DLL_push_back_next_prev(first, last, node, next, previous) \
DLL_push_back_next_prev_zero(0, first, last, node, next, previous) DLL_push_back_next_prev_zero(0, first, last, node, next, previous)
#define DLL_remove_next_prev(first, last, node, next, prev) DLL_remove_next_prev_zero(0, first, last, node, next, prev)
#define DLL_push_back(first, last, node) DLL_push_back_next_prev_zero(0, first, last, node, next, previous) #define DLL_push_back(first, last, node) DLL_push_back_next_prev_zero(0, first, last, node, next, previous)
#define DLL_remove(first, last, node) DLL_remove_next_prev_zero(0, first, last, node, next, previous) #define DLL_remove(first, last, node) DLL_remove_next_prev_zero(0, first, last, node, next, previous)
// Queue helpers
#define SLL_queue_push(first, last, node) SLL_queue_push_next_zero(0, first, last, node, next)
// Stack helpers
#define SLL_stack_push(first, node) SLL_stack_push_next(first, node, next)
#define SLL_stack_pop(first) SLL_stack_pop_next(first, next)
// ============================================================================= // =============================================================================
// Helpers // Helpers
+98 -2
View File
@@ -1,6 +1,57 @@
#ifndef MEM_STATIC
# define MEM_STATIC
# define MEM_API static inline
# include "external/memfun/memfun.h"
#endif
// =============================================================================
// String conversions
internal bool32 char_is_upper(uint8 c)
{
return ('A' <= c && c <= 'Z');
}
internal bool32 char_is_lower(uint8 c)
{
return ('a' <= c && c <= 'z');
}
internal bool32 char_is_slash(uint8 c)
{
return (c == '/' || c == '\\');
}
internal uint8 lower_from_char(uint8 c)
{
if (char_is_upper(c))
{
c += ('a' - 'A');
}
return c;
}
internal uint8 upper_from_char(uint8 c)
{
if (char_is_lower(c))
{
c += ('A' - 'a');
}
return c;
}
internal uint8 correct_slash_from_char(uint8 c)
{
if (char_is_slash(c))
{
c = '/';
}
return c;
}
// ========================================================================== // // ========================================================================== //
// String Length // String Length
#include "core/core_arena.h"
internal uint64 cstring8_length(uint8* cstring) internal uint64 cstring8_length(uint8* cstring)
{ {
uint64 length = 0; uint64 length = 0;
@@ -85,7 +136,52 @@ internal String32 str32_cstring(uint32* cstring)
return result; return result;
} }
// ========================================================================== // // =============================================================================
// String Matching
internal bool32 str8_match(String8 a, String8 b, StringMatchFlags flags)
{
bool32 result = 0;
if (a.size == b.size && flags == 0)
{
result = MemIsEqual(a.str, b.str, b.size);
}
else if (a.size == b.size && flags == StringMatchFlag_CaseInsensitive)
{
result = MemCompareI(a.str, b.str, a.size) == 0;
}
else if (a.size == b.size || (flags * StringMatchFlag_RightSideSloppy))
{
bool32 case_insensitive = (flags & StringMatchFlag_CaseInsensitive);
bool32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive);
uint64 size = Min(a.size, b.size);
result = 1;
for
EachIndex(i, size)
{
uint8 at = a.str[i];
uint8 bt = b.str[i];
if (case_insensitive)
{
at = upper_from_char(at);
bt = upper_from_char(bt);
}
if (slash_insensitive)
{
at = correct_slash_from_char(at);
bt = correct_slash_from_char(bt);
}
if (at != bt)
{
result = 0;
break;
}
}
}
return result;
}
// =============================================================================
// String Formatting & Copying // String Formatting & Copying
internal String8 str8_copy(Arena* arena, String8 in) internal String8 str8_copy(Arena* arena, String8 in)
+35 -7
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
// ========================================================================== // // =============================================================================
// String Types // String Types
typedef struct String8 String8; typedef struct String8 String8;
@@ -24,7 +24,18 @@ struct String32
uint64 size; uint64 size;
}; };
// ========================================================================== // // =============================================================================
// String Matching Types
typedef uint32 StringMatchFlags;
enum
{
StringMatchFlag_CaseInsensitive = (1 << 0),
StringMatchFlag_RightSideSloppy = (1 << 1),
StringMatchFlag_SlashInsensitive = (1 << 2),
};
// =============================================================================
// Unicode decoding Types // Unicode decoding Types
typedef struct UnicodeDecode UnicodeDecode; typedef struct UnicodeDecode UnicodeDecode;
@@ -34,13 +45,24 @@ struct UnicodeDecode
uint32 codepoint; uint32 codepoint;
}; };
// ========================================================================== // // =============================================================================
// String conversions
internal bool32 char_is_upper(uint8 c);
internal bool32 char_is_lower(uint8 c);
internal bool32 char_is_slash(uint8 c);
internal uint8 lower_from_char(uint8 c);
internal uint8 upper_from_char(uint8 c);
internal uint8 correct_slash_from_char(uint8 c);
// =============================================================================
// String Length // String Length
internal uint64 cstring8_length(uint8* cstring); internal uint64 cstring8_length(uint8* cstring);
internal uint64 cstring16_length(uint16* cstring); internal uint64 cstring16_length(uint16* cstring);
internal uint64 cstring32_length(uint32* cstring); internal uint64 cstring32_length(uint32* cstring);
// ========================================================================== // // =============================================================================
// String Constructor // String Constructor
#define str8_literal(S) str8((uint8*)(S), sizeof(S) - 1) #define str8_literal(S) str8((uint8*)(S), sizeof(S) - 1)
@@ -55,13 +77,19 @@ internal String8 str8_cstring(const char* cstring);
internal String16 str16_cstring(uint16* cstring); internal String16 str16_cstring(uint16* cstring);
internal String32 str32_cstring(uint32* cstring); internal String32 str32_cstring(uint32* cstring);
// ========================================================================== // // =============================================================================
// String Matching
internal bool32 str8_match(String8 a, String8 b, StringMatchFlags flags);
#define str8_matchi(a, b) str8_match(a, b, StringMatchFlag_CaseInsensitive)
// =============================================================================
// String Formatting & Copying // String Formatting & Copying
internal String8 str8_copy(Arena* arena, String8 in); internal String8 str8_copy(Arena* arena, String8 in);
internal String8 str8fv(Arena* arena, char* fmt, va_list args); internal String8 str8fv(Arena* arena, char* fmt, va_list args);
// ========================================================================== // // =============================================================================
// Unicode String Encode/Decode // Unicode String Encode/Decode
internal UnicodeDecode utf8_decode(uint8* str, uint64 max); internal UnicodeDecode utf8_decode(uint8* str, uint64 max);
@@ -69,7 +97,7 @@ internal UnicodeDecode utf16_decode(uint16* str, uint64 max);
internal uint32 utf8_encode(uint8* str, uint32 codepoint); internal uint32 utf8_encode(uint8* str, uint32 codepoint);
internal uint32 utf16_encode(uint16* str, uint32 codepoint); internal uint32 utf16_encode(uint16* str, uint32 codepoint);
// ========================================================================== // // =============================================================================
// Unicode String Conversions // Unicode String Conversions
internal String8 str8_from_16(Arena* arena, String16 in); internal String8 str8_from_16(Arena* arena, String16 in);
+4285
View File
File diff suppressed because it is too large. Load diff
+62 -2
View File
@@ -56,13 +56,36 @@ internal void ja_frame()
} }
} }
// Window Garbage collect
{
for
EachIndex(slot_idx, ja_state->window_state_slots_count)
{
for (JA_WindowState *ws = ja_state->window_state_slots[slot_idx].first, *next; ws != 0; ws = next)
{
next = ws->hash_next;
// TODO : need to be able to gc a closed window. Right now we only know number of window using
// the gen id, but we must do better. No need to save opened window in config so leaner version is ok
if (ja_state->quit)
{
wm_window_close(ws->plat_handle);
arena_release(ws->arena);
DLL_remove_next_prev_zero(&ja_nil_window_state, ja_state->first_window_state,
ja_state->last_window_state, ws, order_next, order_previous);
DLL_remove_next_prev(ja_state->window_state_slots[slot_idx].first,
ja_state->window_state_slots[slot_idx].last, ws, hash_next, hash_previous);
SLL_stack_push_next(ja_state->free_window_state, ws, order_next);
}
}
}
}
scratch_end(scratch); scratch_end(scratch);
} }
internal void ja_shutdown() internal void ja_shutdown()
{ {
// wm_window_close(aaa); arena_release(ja_state->arena);
arena_clear(ja_state->arena);
} }
// ============================================================================= // =============================================================================
@@ -117,5 +140,42 @@ internal JA_WindowState* ja_window_state_from_id(JA_ID id)
DLL_push_back_next_prev(slot->first, slot->last, ws, hash_next, hash_previous); DLL_push_back_next_prev(slot->first, slot->last, ws, hash_next, hash_previous);
} }
if (ws != &ja_nil_window_state && wm_window_match(ws->plat_handle, wm_window_zero()))
{
TempArena scratch = scratch_begin(0, 0);
// TODO: save fav monitor in config
WM_Monitor prim_m = wm_primary_monitor();
String8 prim_name = wm_name_from_monitor(scratch.arena, prim_m);
WM_Monitor fav_monitor = { 0 };
{
WM_MonitorArray monitors = wm_push_monitors_array(scratch.arena);
for
EachIndex(idx, monitors.count)
{
String8 monitor_name = wm_name_from_monitor(scratch.arena, monitors.ptr[idx]);
if (str8_match(monitor_name, prim_name, StringMatchFlag_CaseInsensitive))
{
fav_monitor = monitors.ptr[idx];
break;
}
}
}
// TODO : put those in config, hardcoded for now
String8 title = str8_literal("Juliet");
ws->plat_handle = wm_window_open(rect2fp(50.f, 240.f, 1280.f, 720.f), WM_WindowFlag_UseDefaultPosition, title);
WM_Monitor zero_monitor = { 0 };
if (!wm_monitor_match(zero_monitor, fav_monitor))
{
wm_window_set_monitor(ws->plat_handle, fav_monitor);
}
scratch_end(scratch);
}
ja_state->window_state_last_accessed_id = ws->id;
ja_state->window_state_last_accessed = ws;
return ws; return ws;
} }
+140 -5
View File
@@ -79,6 +79,14 @@ internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd)
return result; return result;
} }
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window)
{
WM_Event* result = 0;
result->window = w32_wm_handle_from_window(window);
result->modifiers = wm_get_modifiers();
return result;
}
internal void w32_wm_window_release(W32_WM_Window* window) internal void w32_wm_window_release(W32_WM_Window* window)
{ {
if (window->paint_arena != 0) if (window->paint_arena != 0)
@@ -91,14 +99,23 @@ internal void w32_wm_window_release(W32_WM_Window* window)
SLL_stack_push(w32_wm_state->free_window, window); SLL_stack_push(w32_wm_state->free_window, window);
} }
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window) // =============================================================================
// Monitors
internal BOOL w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr)
{ {
WM_Event* result = 0; W32_WM_MonitorGatherBundle* bundle = (W32_WM_MonitorGatherBundle*)bundle_ptr;
result->window = w32_wm_handle_from_window(window); WM_Monitor m = { (uint64)monitor };
result->modifiers = wm_get_modifiers(); W32_WM_MonitorGatherNode* node = push_array(bundle->arena, W32_WM_MonitorGatherNode, 1);
return result; node->handle = m;
SLL_queue_push(bundle->first_monitor, bundle->last_monitor, node);
bundle->monitor_count += 1;
return 1;
} }
// =============================================================================
// w32 windows proc
internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
LRESULT result = 0; LRESULT result = 0;
@@ -508,6 +525,37 @@ internal void wm_window_first_paint(WM_Window window_handle)
} }
} }
internal void wm_window_set_monitor(WM_Window window_handle, WM_Monitor monitor)
{
W32_WM_Window* window = w32_wm_window_from_handle(window_handle);
if (window != 0)
{
HMONITOR hmonitor = (HMONITOR)monitor.handle[0];
MONITORINFOEXW info;
info.cbSize = sizeof(MONITORINFOEXW);
if (GetMonitorInfoW(hmonitor, (MONITORINFO*)&info))
{
Rect2f existing_rect = wm_rect_from_window(window_handle);
Vector2f window_size = dimension_2f(existing_rect);
SetWindowPos(window->hwnd, HWND_TOP, (info.rcWork.left + info.rcWork.right) / 2 - window_size.x / 2,
(info.rcWork.top + info.rcWork.bottom) / 2 - window_size.y / 2, window_size.x, window_size.y, 0);
}
}
}
internal Rect2f wm_rect_from_window(WM_Window window_handle)
{
Rect2f r = { 0 };
W32_WM_Window* window = w32_wm_window_from_handle(window_handle);
if (window != 0)
{
RECT rect = { 0 };
GetWindowRect(w32_wm_hwnd_from_window(window), &rect);
r = w32_wm_rect2f_from_rect(rect);
}
return r;
}
internal Rect2f wm_client_rect_from_window(WM_Window handle) internal Rect2f wm_client_rect_from_window(WM_Window handle)
{ {
Rect2f result = { 0 }; Rect2f result = { 0 };
@@ -521,6 +569,93 @@ internal Rect2f wm_client_rect_from_window(WM_Window handle)
return result; return result;
} }
// =============================================================================
// Monitors
internal WM_MonitorArray wm_push_monitors_array(Arena* arena)
{
TempArena scratch = scratch_begin(&arena, 1);
W32_WM_MonitorGatherBundle bundle = { arena };
EnumDisplayMonitors(0, 0, w32_wm_monitor_gather_enum_proc, (LPARAM)&bundle);
WM_MonitorArray array = { 0 };
array.count = bundle.monitor_count;
array.ptr = push_array(arena, WM_Monitor, array.count);
{
uint64 idx = 0;
for
EachNode(node, W32_WM_MonitorGatherNode, bundle.first_monitor)
{
array.ptr[idx] = node->handle;
idx += 1;
}
}
scratch_end(scratch);
return array;
}
internal WM_Monitor wm_primary_monitor()
{
POINT zero_pt = { 0, 0 };
HMONITOR monitor = MonitorFromPoint(zero_pt, MONITOR_DEFAULTTOPRIMARY);
WM_Monitor result = { (uint64)monitor };
return result;
}
internal WM_Monitor wm_monitor_from_window(WM_Window window)
{
W32_WM_Window* w = w32_wm_window_from_handle(window);
WM_Monitor result = { 0 };
if (w != 0)
{
HMONITOR handle = MonitorFromWindow(w->hwnd, MONITOR_DEFAULTTOPRIMARY);
result.handle[0] = (uint64)handle;
}
return result;
}
internal String8 wm_name_from_monitor(Arena* arena, WM_Monitor monitor)
{
String8 result = { 0 };
HMONITOR monitor_handle = (HMONITOR)monitor.handle[0];
MONITORINFOEXW info;
info.cbSize = sizeof(MONITORINFOEXW);
if (GetMonitorInfoW(monitor_handle, (MONITORINFO*)&info))
{
String16 result16 = str16_cstring((uint16*)info.szDevice);
result = str8_from_16(arena, result16);
}
return result;
}
internal Vector2f wm_dim_from_monitor(WM_Monitor monitor)
{
Vector2f result = { 0 };
HMONITOR monitor_handle = (HMONITOR)monitor.handle[0];
MONITORINFO info;
info.cbSize = sizeof(MONITORINFO);
if (GetMonitorInfoW(monitor_handle, &info))
{
result.x = info.rcWork.right - info.rcWork.left;
result.y = info.rcWork.bottom - info.rcWork.top;
}
return result;
}
internal float32 wm_dpi_from_monitor(WM_Monitor monitor)
{
float32 result = 96.f;
HMONITOR monitor_handle = (HMONITOR)monitor.handle[0];
if (w32_GetDpiForMonitor_func != 0)
{
UINT dpi_x = 0;
UINT dpi_y = 0;
HRESULT hr = w32_GetDpiForMonitor_func(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y);
result = (float32)dpi_x;
}
return result;
}
// ============================================================================= // =============================================================================
// Events // Events
@@ -27,6 +27,25 @@ struct W32_WM_Window
Arena* paint_arena; Arena* paint_arena;
}; };
// =============================================================================
// Monitor gathering bundle
typedef struct W32_WM_MonitorGatherNode W32_WM_MonitorGatherNode;
struct W32_WM_MonitorGatherNode
{
W32_WM_MonitorGatherNode* next;
WM_Monitor handle;
};
typedef struct W32_WM_MonitorGatherBundle W32_WM_MonitorGatherBundle;
struct W32_WM_MonitorGatherBundle
{
Arena* arena;
W32_WM_MonitorGatherNode* first_monitor;
W32_WM_MonitorGatherNode* last_monitor;
uint64 monitor_count;
};
// ============================================================================= // =============================================================================
// Windows Global State // Windows Global State
@@ -68,3 +87,8 @@ internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window);
internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd); internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd);
internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window); internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window);
internal void w32_wm_window_release(W32_WM_Window* window); internal void w32_wm_window_release(W32_WM_Window* window);
// =============================================================================
// Monitors
internal BOOL w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr);
+21
View File
@@ -1,3 +1,24 @@
// =============================================================================
// Handle type helpers
internal WM_Window wm_window_zero()
{
WM_Window result = { 0 };
return result;
}
internal bool32 wm_window_match(WM_Window a, WM_Window b)
{
bool32 result = MemoryMatchStruct(&a, &b);
return result;
}
internal bool32 wm_monitor_match(WM_Monitor a, WM_Monitor b)
{
bool32 result = MemoryMatchStruct(&a, &b);
return result;
}
// ============================================================================= // =============================================================================
// Event Functions // Event Functions
+19
View File
@@ -99,6 +99,13 @@ struct WM_EventList
internal bool32 frame(); internal bool32 frame();
// =============================================================================
// Handle type helpers
internal WM_Window wm_window_zero();
internal bool32 wm_window_match(WM_Window a, WM_Window b);
internal bool32 wm_monitor_match(WM_Monitor a, WM_Monitor b);
// ============================================================================= // =============================================================================
// Event Functions // Event Functions
@@ -119,8 +126,20 @@ internal void wm_init();
internal WM_Window wm_widow_open(Rect2f rect, WM_WindowFlags flags, String8 title); internal WM_Window wm_widow_open(Rect2f rect, WM_WindowFlags flags, String8 title);
internal void wm_window_close(WM_Window handle); internal void wm_window_close(WM_Window handle);
internal void wm_window_first_paint(WM_Window window_handle); internal void wm_window_first_paint(WM_Window window_handle);
internal void wm_window_set_monitor(WM_Window window, WM_Monitor monitor);
internal Rect2f wm_rect_from_window(WM_Window window_handle);
internal Rect2f wm_client_rect_from_window(WM_Window window); internal Rect2f wm_client_rect_from_window(WM_Window window);
// =============================================================================
// Monitors
internal WM_MonitorArray wm_push_monitors_array(Arena* arena);
internal WM_Monitor wm_primary_monitor();
internal WM_Monitor wm_monitor_from_window(WM_Window window);
internal String8 wm_name_from_monitor(Arena* arena, WM_Monitor monitor);
internal Vector2f wm_dim_from_monitor(WM_Monitor monitor);
internal float32 wm_dpi_from_monitor(WM_Monitor monitor);
// ============================================================================= // =============================================================================
// Events // Events