SBgl 0.1.0
A graphics framework in C99
Loading...
Searching...
No Matches
window.c File Reference
#include "core/sbgl_platform.h"
#include "core/sbl_arena.h"
#include "win32_internal.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Include dependency graph for window.c:

Go to the source code of this file.

Functions

static void win32_report_error (const wchar_t *message)
 Reports errors to both debugger output and stderr.
 
static LRESULT CALLBACK WindowProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 
sbgl_Windowsbgl_os_CreateWindow (struct SblArena *arena, sbgl_InputState *input, int width, int height, const char *title)
 
void sbgl_os_DestroyWindow (sbgl_Window *window)
 Destroys a native window.
 
bool sbgl_os_WindowShouldClose (sbgl_Window *window)
 Checks the window's close flag.
 
void sbgl_os_GetWindowSize (sbgl_Window *window, int *w, int *h)
 Retrieves the current client area size.
 
bool sbgl_os_WasWindowResized (sbgl_Window *window)
 Checks if the window has been resized since the last check.
 
void sbgl_os_SetCursorVisible (sbgl_Window *window, bool visible)
 Sets the visibility of the OS cursor for the given window.
 
void sbgl_os_SetCursorLocked (sbgl_Window *window, bool locked)
 Locks or unlocks the cursor within the window bounds.
 
bool sbgl_os_IsWindowFocused (sbgl_Window *window)
 Checks if the window currently has input focus.
 
void sbgl_os_PollEvents (sbgl_Window *window)
 Dispatches OS events (messages/protocol requests).
 
uint64_t sbgl_os_GetPerfCount (sbgl_Window *window)
 Gets the high-resolution performance counter.
 
uint64_t sbgl_os_GetPerfFreq (sbgl_Window *window)
 Gets the performance counter frequency.
 
void * sbgl_os_GetNativeWindowHandle (sbgl_Window *window)
 Retrieves the raw window handle for Vulkan surface creation.
 
void * sbgl_os_GetNativeInstanceHandle (sbgl_Window *window)
 Retrieves the native instance handle (Win32 specific).
 
void * sbgl_os_GetNativeDisplayHandle (sbgl_Window *window)
 Retrieves the native display handle (Linux specific).
 

Function Documentation

◆ sbgl_os_CreateWindow()

sbgl_Window * sbgl_os_CreateWindow ( struct SblArena * arena,
sbgl_InputState * input,
int width,
int height,
const char * title )

Definition at line 101 of file window.c.

107 {
108 // Set DPI awareness for Windows 10+ (Per-Monitor V2)
109 SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
110
111 HINSTANCE hinstance = GetModuleHandle(NULL);
112
113 WNDCLASSW wc = { 0 };
114 wc.lpfnWndProc = WindowProc;
115 wc.hInstance = hinstance;
116 wc.lpszClassName = L"SBglWindowClass";
117 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
118
119 RegisterClassW(&wc);
120
121 // Convert title to WideChar
122 int title_len = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
123 wchar_t* wtitle = malloc(title_len * sizeof(wchar_t));
124 MultiByteToWideChar(CP_UTF8, 0, title, -1, wtitle, title_len);
125
126 // Calculate proper window size for requested client area
127 RECT rect = { 0, 0, width, height };
128 AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, FALSE, 0);
129
130 HWND hwnd = CreateWindowExW(
131 0,
132 wc.lpszClassName,
133 wtitle,
134 WS_OVERLAPPEDWINDOW,
135 CW_USEDEFAULT,
136 CW_USEDEFAULT,
137 rect.right - rect.left, // Adjusted width including borders
138 rect.bottom - rect.top, // Adjusted height including title bar
139 NULL,
140 NULL,
141 hinstance,
142 NULL
143 );
144
145 free(wtitle);
146
147 if (!hwnd) {
148 win32_report_error(L"Failed to create window: CreateWindowExW returned NULL");
149 return NULL;
150 }
151
153 if (!window) {
154 DestroyWindow(hwnd);
155 return NULL;
156 }
157 window->hinstance = hinstance;
158 window->hwnd = hwnd;
159 window->shouldClose = false;
160 window->resized = false;
161 window->width = width;
162 window->height = height;
163 window->focused = true;
164 window->cursorVisible = true;
165 window->cursorLocked = false;
166 window->input = input;
167 window->accumulatedDeltaX = 0;
168 window->accumulatedDeltaY = 0;
169
170 /* Store class name for unregistration on destroy */
171 wcsncpy(window->className, wc.lpszClassName, 255);
172 window->className[255] = L'\0';
173
174 SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window);
175
176 ShowWindow(hwnd, SW_SHOW);
177 return window;
178}
#define SBL_ARENA_PUSH_STRUCT_ZERO(arena, type)
Definition sbl_arena.h:20
Native X11 window state.
sbgl_InputState * input
wchar_t className[256]
HINSTANCE hinstance
static void win32_report_error(const wchar_t *message)
Reports errors to both debugger output and stderr.
Definition window.c:14
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
Definition window.c:31

◆ sbgl_os_DestroyWindow()

void sbgl_os_DestroyWindow ( sbgl_Window * window)

Destroys a native window.

Parameters
windowThe window to destroy.

Definition at line 180 of file window.c.

180 {
181 if (!window)
182 return;
183
184 /* Unregister raw input if cursor is still locked */
185 if (window->cursorLocked) {
186 RAWINPUTDEVICE rid = {
187 .usUsagePage = 0x01,
188 .usUsage = 0x02,
189 .dwFlags = RIDEV_REMOVE,
190 .hwndTarget = NULL
191 };
192 RegisterRawInputDevices(&rid, 1, sizeof(rid));
193 ClipCursor(NULL);
194 }
195
196 DestroyWindow(window->hwnd);
197
198 /* Unregister window class to prevent resource leaks */
199 if (window->className[0] != L'\0') {
200 UnregisterClassW(window->className, window->hinstance);
201 }
202}

◆ sbgl_os_GetNativeDisplayHandle()

void * sbgl_os_GetNativeDisplayHandle ( sbgl_Window * window)

Retrieves the native display handle (Linux specific).

Parameters
windowThe window handle.
Returns
Display* or wl_display*.

Definition at line 334 of file window.c.

334 {
335 (void)window;
336 return NULL; // Not used on Win32
337}

◆ sbgl_os_GetNativeInstanceHandle()

void * sbgl_os_GetNativeInstanceHandle ( sbgl_Window * window)

Retrieves the native instance handle (Win32 specific).

Parameters
windowThe window handle.
Returns
HINSTANCE on Windows, NULL otherwise.

Definition at line 330 of file window.c.

330 {
331 return window ? (void*)window->hinstance : NULL;
332}

◆ sbgl_os_GetNativeWindowHandle()

void * sbgl_os_GetNativeWindowHandle ( sbgl_Window * window)

Retrieves the raw window handle for Vulkan surface creation.

Parameters
windowThe window handle.
Returns
Native handle (e.g., HWND or wl_surface*).

Definition at line 326 of file window.c.

326 {
327 return window ? (void*)window->hwnd : NULL;
328}

◆ sbgl_os_GetPerfCount()

uint64_t sbgl_os_GetPerfCount ( sbgl_Window * window)

Gets the high-resolution performance counter.

Parameters
windowThe window handle.
Returns
Absolute ticks.

Definition at line 312 of file window.c.

312 {
313 (void)window; // Not used, but kept for API consistency
314 LARGE_INTEGER count;
315 QueryPerformanceCounter(&count);
316 return (uint64_t)count.QuadPart;
317}

◆ sbgl_os_GetPerfFreq()

uint64_t sbgl_os_GetPerfFreq ( sbgl_Window * window)

Gets the performance counter frequency.

Parameters
windowThe window handle.
Returns
Ticks per second.

Definition at line 319 of file window.c.

319 {
320 (void)window;
321 LARGE_INTEGER freq;
322 QueryPerformanceFrequency(&freq);
323 return (uint64_t)freq.QuadPart;
324}

◆ sbgl_os_GetWindowSize()

void sbgl_os_GetWindowSize ( sbgl_Window * window,
int * w,
int * h )

Retrieves the current client area size.

Parameters
windowThe window handle.
wPointer to store width.
hPointer to store height.

Definition at line 206 of file window.c.

206 {
207 if (!window) {
208 if (w) *w = 0;
209 if (h) *h = 0;
210 return;
211 }
212 if (w) *w = window->width;
213 if (h) *h = window->height;
214}

◆ sbgl_os_IsWindowFocused()

bool sbgl_os_IsWindowFocused ( sbgl_Window * window)

Checks if the window currently has input focus.

Parameters
windowThe native window handle.
Returns
True if focused.

Definition at line 295 of file window.c.

295 {
296 /* Returns the current focus state as tracked by window messages. */
297 return window ? window->focused : false;
298}

◆ sbgl_os_PollEvents()

void sbgl_os_PollEvents ( sbgl_Window * window)

Dispatches OS events (messages/protocol requests).

Parameters
windowThe window to process events for.

Definition at line 300 of file window.c.

300 {
301 MSG msg;
302 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
303 TranslateMessage(&msg);
304 DispatchMessage(&msg);
305 }
306
307 // Update input states after processing all messages
308 if (window)
310}
void win32_internal_update_input_states(sbgl_InputState *input, sbgl_Window *window)
Definition input.c:142

◆ sbgl_os_SetCursorLocked()

void sbgl_os_SetCursorLocked ( sbgl_Window * window,
bool locked )

Locks or unlocks the cursor within the window bounds.

When locked, the cursor is typically constrained to the window center to support relative motion for 3D navigation.

Parameters
windowThe native window handle.
lockedTrue to capture the cursor, false to release it.

Definition at line 238 of file window.c.

238 {
239 if (!window || window->cursorLocked == locked)
240 return;
241
242 window->cursorLocked = locked;
243
244 if (locked) {
245 /* Register for raw mouse input to get high-precision deltas */
246 RAWINPUTDEVICE rid = {
247 .usUsagePage = 0x01, // Generic Desktop
248 .usUsage = 0x02, // Mouse
249 .dwFlags = RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE,
250 .hwndTarget = window->hwnd
251 };
252 if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
253 win32_report_error(L"Failed to register raw input device");
254 }
255
256 /* The cursor is confined to the window client area by clipping it
257 to the screen-space coordinates of the client rectangle. */
258 RECT rect;
259 GetClientRect(window->hwnd, &rect);
260 ClientToScreen(window->hwnd, (POINT*)&rect.left);
261 ClientToScreen(window->hwnd, (POINT*)&rect.right);
262 ClipCursor(&rect);
263
264 /* Hide the cursor */
265 ShowCursor(FALSE);
266 window->cursorVisible = false;
267
268 /* The cursor is initially centered within the window to ensure
269 consistent relative motion tracking. */
270 int centerX = window->width / 2;
271 int centerY = window->height / 2;
272 POINT p = { centerX, centerY };
273 ClientToScreen(window->hwnd, &p);
274 SetCursorPos(p.x, p.y);
275 } else {
276 /* Unregister raw input device */
277 RAWINPUTDEVICE rid = {
278 .usUsagePage = 0x01,
279 .usUsage = 0x02,
280 .dwFlags = RIDEV_REMOVE,
281 .hwndTarget = NULL
282 };
283 RegisterRawInputDevices(&rid, 1, sizeof(rid));
284
285 /* Any existing cursor clipping is removed, allowing the pointer
286 to move freely across the entire desktop. */
287 ClipCursor(NULL);
288
289 /* Show the cursor */
290 ShowCursor(TRUE);
291 window->cursorVisible = true;
292 }
293}

◆ sbgl_os_SetCursorVisible()

void sbgl_os_SetCursorVisible ( sbgl_Window * window,
bool visible )

Sets the visibility of the OS cursor for the given window.

Provides a platform-agnostic way to show or hide the mouse pointer.

Parameters
windowThe native window handle.
visibleTrue to show the cursor, false to hide it.

Definition at line 224 of file window.c.

224 {
225 if (!window || window->cursorVisible == visible)
226 return;
227
228 /* The cursor visibility state is updated and the system cursor counter
229 is incremented or decremented accordingly. */
230 window->cursorVisible = visible;
231 if (visible) {
232 ShowCursor(TRUE);
233 } else {
234 ShowCursor(FALSE);
235 }
236}

◆ sbgl_os_WasWindowResized()

bool sbgl_os_WasWindowResized ( sbgl_Window * window)

Checks if the window has been resized since the last check.

Resets the internal resize flag to false upon returning.

Parameters
windowThe window handle.
Returns
True if a resize event occurred.

Definition at line 216 of file window.c.

216 {
217 if (!window)
218 return false;
219 bool r = window->resized;
220 window->resized = false;
221 return r;
222}

◆ sbgl_os_WindowShouldClose()

bool sbgl_os_WindowShouldClose ( sbgl_Window * window)

Checks the window's close flag.

Parameters
windowThe window to check.
Returns
True if closing.

Definition at line 204 of file window.c.

204{ return window ? window->shouldClose : true; }

◆ win32_report_error()

static void win32_report_error ( const wchar_t * message)
static

Reports errors to both debugger output and stderr.

Uses OutputDebugStringW for Visual Studio debugger visibility and fprintf(stderr, ...) for console output.

Definition at line 14 of file window.c.

14 {
15 // Output to debugger (visible in Visual Studio Output window)
16 OutputDebugStringW(message);
17 OutputDebugStringW(L"\n");
18
19 // Output to stderr (visible in console)
20 int len = WideCharToMultiByte(CP_UTF8, 0, message, -1, NULL, 0, NULL, NULL);
21 if (len > 0) {
22 char* utf8 = (char*)malloc(len);
23 if (utf8) {
24 WideCharToMultiByte(CP_UTF8, 0, message, -1, utf8, len, NULL, NULL);
25 fprintf(stderr, "[Win32] %s\n", utf8);
26 free(utf8);
27 }
28 }
29}

◆ WindowProc()

static LRESULT CALLBACK WindowProc ( HWND hwnd,
UINT msg,
WPARAM wparam,
LPARAM lparam )
static

Definition at line 31 of file window.c.

31 {
32 sbgl_Window* window = (sbgl_Window*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
33
34 switch (msg) {
35 case WM_CLOSE:
36 if (window)
37 window->shouldClose = true;
38 return 0;
39 case WM_DESTROY:
40 PostQuitMessage(0);
41 return 0;
42 case WM_SIZE:
43 if (window) {
44 int w = LOWORD(lparam);
45 int h = HIWORD(lparam);
46 if (w > 0 && h > 0 && (w != window->width || h != window->height)) {
47 window->width = w;
48 window->height = h;
49 window->resized = true;
50 }
51 }
52 break;
53 case WM_SETFOCUS:
54 if (window)
55 window->focused = true;
56 break;
57 case WM_KILLFOCUS:
58 if (window)
59 window->focused = false;
60 break;
61 case WM_INPUT: {
62 // Handle raw input for high-precision mouse deltas when cursor is locked
63 if (window && window->cursorLocked) {
64 RAWINPUT raw;
65 UINT size = sizeof(raw);
66
67 if (GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &raw,
68 &size, sizeof(RAWINPUTHEADER)) != (UINT)-1) {
69 if (raw.header.dwType == RIM_TYPEMOUSE) {
70 // Accumulate raw deltas
71 window->accumulatedDeltaX += raw.mouse.lLastX;
72 window->accumulatedDeltaY += raw.mouse.lLastY;
73 }
74 }
75 }
76 break;
77 }
78 case WM_DPICHANGED: {
79 // Handle DPI changes for high-DPI display support
80 if (window) {
81 RECT* const prcNewWindow = (RECT*)lparam;
82 SetWindowPos(window->hwnd, NULL,
83 prcNewWindow->left,
84 prcNewWindow->top,
85 prcNewWindow->right - prcNewWindow->left,
86 prcNewWindow->bottom - prcNewWindow->top,
87 SWP_NOZORDER | SWP_NOACTIVATE);
88 window->resized = true;
89 }
90 break;
91 }
92 }
93
94 // Pass input messages to the input system
95 if (window)
96 win32_internal_process_message(window->input, msg, wparam, lparam);
97
98 return DefWindowProc(hwnd, msg, wparam, lparam);
99}
void win32_internal_process_message(sbgl_InputState *input, UINT msg, WPARAM wparam, LPARAM lparam)
Definition input.c:98