Get latest tely changes, w/ new OS primitives from internal project
This commit is contained in:
@@ -1057,6 +1057,36 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_OS_W32Init(DN_OSW32Core *w32)
|
||||
{
|
||||
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
|
||||
QueryPerformanceFrequency(&w32->qpc_frequency);
|
||||
|
||||
// NOTE: DPI
|
||||
HMODULE user32 = LoadLibraryA("user32.dll");
|
||||
if (user32) {
|
||||
w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow");
|
||||
w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor");
|
||||
w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi");
|
||||
FreeLibrary(user32);
|
||||
}
|
||||
|
||||
// NOTE: SetThreadDesc
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
if (kernel32) {
|
||||
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription");
|
||||
FreeLibrary(kernel32);
|
||||
}
|
||||
|
||||
// NOTE: win32 bcrypt
|
||||
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
|
||||
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
|
||||
if (w32->bcrypt_rng_handle && init_status == 0)
|
||||
w32->bcrypt_init_success = true;
|
||||
else
|
||||
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
|
||||
}
|
||||
|
||||
DN_API DN_OSW32Core *DN_OS_W32GetCore()
|
||||
{
|
||||
DN_Core *dn = DN_Get();
|
||||
@@ -1456,6 +1486,160 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
|
||||
DN_TcScratchEnd(&scratch);
|
||||
}
|
||||
|
||||
DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena)
|
||||
{
|
||||
DN_OSW32Window *result = nullptr;
|
||||
for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) {
|
||||
if (check->hwnd == hwnd)
|
||||
result = check;
|
||||
}
|
||||
|
||||
if (!result && arena) {
|
||||
result = DN_ArenaNewZ(arena, DN_OSW32Window);
|
||||
if (result) {
|
||||
result->hwnd = hwnd;
|
||||
if (w32->windows)
|
||||
w32->windows->next = result;
|
||||
result->next = w32->windows;
|
||||
w32->windows = result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
|
||||
{
|
||||
DN_OSW32Core *w32 = DN_OS_W32GetCore();
|
||||
DN_AssertF(w32, "Using this window proc requires that DN's OS layer has been initialised");
|
||||
|
||||
LRESULT result = 0;
|
||||
bool handled = true;
|
||||
switch (msg) {
|
||||
// NOTE: Sent when the size and position of a window's client area must be calculated. By
|
||||
// processing this message, an application can control the content of the window's client area
|
||||
// when the size or position of the window changes.
|
||||
case WM_NCCALCSIZE: {
|
||||
DN_OSW32Window *w32_window = DN_OS_W32WindowFromHwndMaybeAlloc(w32, hwnd, nullptr);
|
||||
if (w32_window && w32_window->custom_title_bar) {
|
||||
// NOTE: Code adapted from raddebugger
|
||||
// https://github.com/EpicGames/raddebugger/blob/7a5a649b89f6a06abdbaee61540468fca9db58f9/src/win32/window_manager/win32_window_manager.c#L668
|
||||
//
|
||||
// The goal here is to subtract away the title bar from the window and restore the pixel
|
||||
// border that native Windows renders windows with. Note that on Windows 11 a non-maximised
|
||||
// window has rounded corners which eats into the available client space that is normally
|
||||
// otherwise eaten into from the native titlebar.
|
||||
DWORD window_style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||
bool is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
|
||||
if (is_fullscreen) {
|
||||
handled = false;
|
||||
} else {
|
||||
DN_UInt dpi = w32->get_dpi_for_window ? w32->get_dpi_for_window(hwnd) : 96;
|
||||
int frame_x = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CXFRAME, dpi) : GetSystemMetrics(SM_CXFRAME);
|
||||
int frame_y = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CYFRAME, dpi) : GetSystemMetrics(SM_CYFRAME);
|
||||
int padding = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CXPADDEDBORDER, dpi) : GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||
|
||||
RECT *rect = w_param == 0 ? DN_Cast(RECT *)l_param : (DN_Cast(NCCALCSIZE_PARAMS *)l_param)->rgrc;
|
||||
rect->right -= frame_x + padding;
|
||||
rect->left += frame_x + padding;
|
||||
rect->bottom -= frame_y + padding;
|
||||
bool is_maximised = IsZoomed(hwnd) != 0;
|
||||
if (is_maximised) {
|
||||
rect->top += frame_y + padding;
|
||||
// If we do not do this hidden taskbar can not be unhidden on mouse hover
|
||||
// Unfortunately it can create an ugly bottom border when maximized...
|
||||
rect->bottom -= 1;
|
||||
} else {
|
||||
int edge_height = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CYEDGE, dpi) : GetSystemMetrics(SM_CYEDGE);
|
||||
rect->top += edge_height;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
// NOTE: Sent to a window in order to determine what part of the window corresponds to a
|
||||
// particular screen coordinate. This can happen, for example, when the cursor moves, when a
|
||||
// mouse button is pressed or released, or in response to a call to a function such as
|
||||
// WindowFromPoint. If the mouse is not captured, the message is sent to the window beneath
|
||||
// the cursor. Otherwise, the message is sent to the window that has captured the mouse.
|
||||
case WM_NCHITTEST: {
|
||||
DN_OSW32Window *w32_window = DN_OS_W32WindowFromHwndMaybeAlloc(w32, hwnd, nullptr);
|
||||
if (w32_window && w32_window->custom_title_bar) {
|
||||
// NOTE: Code adapted from raddebugger
|
||||
// https://github.com/EpicGames/raddebugger/blob/7a5a649b89f6a06abdbaee61540468fca9db58f9/src/win32/window_manager/win32_window_manager.c#L668
|
||||
//
|
||||
// Since we removed the titlebar from the window, the resize handlers/grabbers at the top of
|
||||
// the window are no longer functional. We have to reimplement it ourselves.
|
||||
DWORD window_style = GetWindowLongW(hwnd, GWL_STYLE);
|
||||
bool is_fullscreen = !(window_style & WS_OVERLAPPEDWINDOW);
|
||||
handled = false;
|
||||
if (!is_fullscreen) {
|
||||
// Let the default procedure handle resizing areas
|
||||
if (w32->fallback_wnd_proc)
|
||||
result = CallWindowProcW(w32->fallback_wnd_proc, hwnd, msg, w_param, l_param);
|
||||
else
|
||||
result = DefWindowProcW(hwnd, msg, w_param, l_param);
|
||||
|
||||
switch (result) {
|
||||
case HTNOWHERE:
|
||||
case HTRIGHT:
|
||||
case HTLEFT:
|
||||
case HTTOPLEFT:
|
||||
case HTTOPRIGHT:
|
||||
case HTBOTTOMRIGHT:
|
||||
case HTBOTTOM:
|
||||
case HTBOTTOMLEFT: {
|
||||
handled = true;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
POINT pos_monitor = {};
|
||||
pos_monitor.x = GET_X_LPARAM(l_param);
|
||||
pos_monitor.y = GET_Y_LPARAM(l_param);
|
||||
handled = true;
|
||||
|
||||
POINT pos_client = pos_monitor;
|
||||
ScreenToClient(hwnd, &pos_client);
|
||||
|
||||
DN_V2F32 title_bar_min = w32_window->custom_title_bar_rect_that_is_draggable.pos;
|
||||
DN_V2F32 title_bar_max = title_bar_min + w32_window->custom_title_bar_rect_that_is_draggable.size;
|
||||
DN_UInt dpi = w32->get_dpi_for_window ? w32->get_dpi_for_window(hwnd) : 96;
|
||||
int frame_y = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CYFRAME, dpi) : GetSystemMetrics(SM_CYFRAME);
|
||||
int padding = w32->get_system_metrics_for_dpi ? w32->get_system_metrics_for_dpi(SM_CXPADDEDBORDER, dpi) : GetSystemMetrics(SM_CXPADDEDBORDER);
|
||||
bool is_over_top_resize = pos_client.y >= 0 && pos_client.y < (frame_y + padding);
|
||||
bool is_over_title_bar = pos_client.x >= title_bar_min.x && pos_client.x < title_bar_max.x &&
|
||||
pos_client.y >= title_bar_min.y && pos_client.y < title_bar_max.y;
|
||||
bool is_maximised = IsZoomed(hwnd) != 0;
|
||||
if (!is_maximised && is_over_top_resize)
|
||||
result = HTTOP;
|
||||
else if (is_over_title_bar)
|
||||
result = HTCAPTION;
|
||||
else
|
||||
result = HTCLIENT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
handled = false;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: {
|
||||
handled = false;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
if (w32->fallback_wnd_proc) {
|
||||
result = CallWindowProcW(w32->fallback_wnd_proc, hwnd, msg, w_param, l_param);
|
||||
} else {
|
||||
result = DefWindowProcW(hwnd, msg, w_param, l_param);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code)
|
||||
{
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
|
||||
Reference in New Issue
Block a user