SBgl 0.1.0
A graphics framework in C99
Loading...
Searching...
No Matches
window_wayland.c
Go to the documentation of this file.
1#define _POSIX_C_SOURCE 199309L
2#include "linux_internal.h"
4#include "core/sbl_arena.h"
5#include <string.h>
6#include <time.h>
7#include <poll.h>
8
9
10// --- Window Manager Listeners ---
11static void wm_base_ping(void* data, struct xdg_wm_base* wm_base, uint32_t serial) {
12 (void)data;
13 xdg_wm_base_pong(wm_base, serial);
14}
15static const struct xdg_wm_base_listener wm_base_listener = { .ping = wm_base_ping };
16
17// --- Registry ---
18static void registry_handle_global(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) {
19 (void)version;
20 sbgl_Window* window = (sbgl_Window*)data;
21 if (strcmp(interface, wl_compositor_interface.name) == 0) {
22 window->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
23 } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
24 window->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
25 xdg_wm_base_add_listener(window->wm_base, &wm_base_listener, NULL);
26 } else if (strcmp(interface, wl_seat_interface.name) == 0) {
27 linux_init_input(registry, name, 1, window);
28 } else if (strcmp(interface, zwp_pointer_constraints_v1_interface.name) == 0) {
29 window->pointer_constraints = wl_registry_bind(registry, name, &zwp_pointer_constraints_v1_interface, 1);
30 } else if (strcmp(interface, zwp_relative_pointer_manager_v1_interface.name) == 0) {
31 window->relative_pointer_manager = wl_registry_bind(registry, name, &zwp_relative_pointer_manager_v1_interface, 1);
32 }
33}
34static const struct wl_registry_listener registry_listener = { .global = registry_handle_global };
35
36// --- Window Listeners ---
37static void toplevel_handle_configure(void* data, struct xdg_toplevel* t, int32_t w, int32_t h, struct wl_array* s) {
38 /* (void) cast safely suppresses unused parameter warnings for mandatory signatures */
39 (void)t;
40 (void)s;
41 sbgl_Window* win = (sbgl_Window*)data;
42 if (w > 0 && h > 0 && (w != win->width || h != win->height)) {
43 win->width = w;
44 win->height = h;
45 win->resized = true;
46 }
47}
48static void toplevel_handle_close(void* data, struct xdg_toplevel* t) {
49 /* (void) cast safely suppresses unused parameter warnings for mandatory signatures */
50 (void)t;
51 ((sbgl_Window*)data)->shouldClose = true;
52}
53static const struct xdg_toplevel_listener toplevel_listener = { .configure = toplevel_handle_configure, .close = toplevel_handle_close };
54
55static void xdg_surface_handle_configure(void* data, struct xdg_surface* surf, uint32_t serial) {
56 /* (void) cast safely suppresses unused parameter warnings for mandatory signatures */
57 (void)data;
58 xdg_surface_ack_configure(surf, serial);
59}
61
62// --- Pointer Constraints ---
63static void locked_pointer_locked(void* data, struct zwp_locked_pointer_v1* locked_pointer) { (void)data; (void)locked_pointer; }
64static void locked_pointer_unlocked(void* data, struct zwp_locked_pointer_v1* locked_pointer) { (void)data; (void)locked_pointer; }
65static const struct zwp_locked_pointer_v1_listener locked_pointer_listener = { .locked = locked_pointer_locked, .unlocked = locked_pointer_unlocked };
66
67// --- HAL ---
68sbgl_platform_Result sbgl_os_CreateWindow(struct SblArena* arena, sbgl_InputState* input, int width, int height, const char* title, sbgl_Window** outWindow) {
69 if (!outWindow) {
71 }
72 *outWindow = NULL;
73
74 if (!arena) {
76 }
77
79 if (!window) return SBGL_PLATFORM_ERROR_INIT_FAILED;
80
81 window->width = width; window->height = height;
82 window->shouldClose = false;
83 window->resized = false;
84 window->focused = false;
85 window->cursor_visible = true;
86 window->input = input;
87
88 window->display = wl_display_connect(NULL);
89 if (!window->display) return SBGL_PLATFORM_ERROR_NO_DISPLAY;
90
91 struct wl_registry* reg = wl_display_get_registry(window->display);
92 wl_registry_add_listener(reg, &registry_listener, window);
93 wl_display_roundtrip(window->display);
94
95 window->surface = wl_compositor_create_surface(window->compositor);
96 if (!window->surface) return SBGL_PLATFORM_ERROR_WINDOW_FAILED;
97
98 window->xdg_surface = xdg_wm_base_get_xdg_surface(window->wm_base, window->surface);
99 if (!window->xdg_surface) return SBGL_PLATFORM_ERROR_WINDOW_FAILED;
100
101 xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
102 window->xdg_toplevel = xdg_surface_get_toplevel(window->xdg_surface);
103 if (!window->xdg_toplevel) return SBGL_PLATFORM_ERROR_WINDOW_FAILED;
104
105 xdg_toplevel_add_listener(window->xdg_toplevel, &toplevel_listener, window);
106 xdg_toplevel_set_title(window->xdg_toplevel, title);
107
108 if (window->seat) {
109 struct wl_keyboard* k = wl_seat_get_keyboard(window->seat);
110 if (k) wl_keyboard_add_listener(k, &keyboard_listener, window);
111 struct wl_pointer* p = wl_seat_get_pointer(window->seat);
112 if (p) wl_pointer_add_listener(p, &pointer_listener, window);
113 }
114
115 wl_surface_commit(window->surface);
116 wl_display_roundtrip(window->display);
117
118 *outWindow = window;
120}
121
123 if (!window) return;
124
125 // Clear deltas if relative pointer is active to allow accumulation in listeners
126 if (window->relative_pointer && window->input) {
127 window->input->mouseDeltaX = 0;
128 window->input->mouseDeltaY = 0;
129 }
130
131 /* The system ensures that pending events are dispatched and new events are read
132 from the display in a non-blocking manner to prevent main loop stalls. */
133 while (wl_display_prepare_read(window->display) != 0) {
134 wl_display_dispatch_pending(window->display);
135 }
136 wl_display_flush(window->display);
137
138 struct pollfd pfd = { .fd = wl_display_get_fd(window->display), .events = POLLIN };
139 if (poll(&pfd, 1, 0) > 0) {
140 wl_display_read_events(window->display);
141 } else {
142 wl_display_cancel_read(window->display);
143 }
144
145 wl_display_dispatch_pending(window->display);
147}
148
149bool sbgl_os_WindowShouldClose(sbgl_Window* window) { return window->shouldClose; }
150void sbgl_os_GetWindowSize(sbgl_Window* window, int* w, int* h) { *w = window->width; *h = window->height; }
151
153 bool r = window->resized;
154 window->resized = false;
155 return r;
156}
157
158bool sbgl_os_IsWindowFocused(sbgl_Window* window) { return window->focused; }
159
160void sbgl_os_SetCursorVisible(sbgl_Window* window, bool visible) {
161 if (!window) return;
162 window->cursor_visible = visible;
163
164 if (!visible && window->seat) {
165 struct wl_pointer* pointer = wl_seat_get_pointer(window->seat);
166 if (pointer) {
167 // Setting the cursor surface to NULL hides the cursor for this surface.
168 wl_pointer_set_cursor(pointer, window->pointer_serial, NULL, 0, 0);
169 }
170 }
171}
172
173extern const struct zwp_relative_pointer_v1_listener relative_pointer_listener;
174
175void sbgl_os_SetCursorLocked(sbgl_Window* window, bool locked) {
176 if (!window || !window->seat || !window->pointer_constraints) return;
177 struct wl_pointer* pointer = wl_seat_get_pointer(window->seat);
178 if (!pointer) return;
179
180 if (locked && !window->locked_pointer) {
181 window->locked_pointer = zwp_pointer_constraints_v1_lock_pointer(
182 window->pointer_constraints, window->surface, pointer, NULL,
183 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
184 zwp_locked_pointer_v1_add_listener(window->locked_pointer, &locked_pointer_listener, window);
185
186 if (window->relative_pointer_manager) {
187 window->relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
188 window->relative_pointer_manager, pointer);
189 zwp_relative_pointer_v1_add_listener(window->relative_pointer, &relative_pointer_listener, window);
190 }
191 } else if (!locked && window->locked_pointer) {
192 zwp_locked_pointer_v1_destroy(window->locked_pointer);
193 window->locked_pointer = NULL;
194 if (window->relative_pointer) {
195 zwp_relative_pointer_v1_destroy(window->relative_pointer);
196 window->relative_pointer = NULL;
197 }
198 }
199}
200
201uint64_t sbgl_os_GetPerfCount(sbgl_Window* window) { (void)window; struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (uint64_t)ts.tv_sec * 1000000000ULL + ts.tv_nsec; }
202uint64_t sbgl_os_GetPerfFreq(sbgl_Window* window) { (void)window; return 1000000000ULL; }
203void* sbgl_os_GetNativeWindowHandle(sbgl_Window* window) { return (void*)window->surface; }
204void* sbgl_os_GetNativeDisplayHandle(sbgl_Window* window) { return (void*)window->display; }
206 if (!window) return;
207 if (window->relative_pointer) zwp_relative_pointer_v1_destroy(window->relative_pointer);
208 if (window->locked_pointer) zwp_locked_pointer_v1_destroy(window->locked_pointer);
209 if (window->relative_pointer_manager) zwp_relative_pointer_manager_v1_destroy(window->relative_pointer_manager);
210 if (window->pointer_constraints) zwp_pointer_constraints_v1_destroy(window->pointer_constraints);
211 xdg_toplevel_destroy(window->xdg_toplevel);
212 xdg_surface_destroy(window->xdg_surface);
213 wl_surface_destroy(window->surface);
214 wl_display_disconnect(window->display);
215}
void linux_init_input(struct wl_registry *registry, uint32_t name, uint32_t version, sbgl_Window *window)
void linux_internal_update_input_states(sbgl_Window *window)
const struct wl_pointer_listener pointer_listener
const struct wl_keyboard_listener keyboard_listener
Internal Platform Abstraction Layer (HAL).
sbgl_platform_Result
Result codes for platform layer operations.
Definition sbgl_types.h:233
@ SBGL_PLATFORM_SUCCESS
Definition sbgl_types.h:234
@ SBGL_PLATFORM_ERROR_INIT_FAILED
Definition sbgl_types.h:237
@ SBGL_PLATFORM_ERROR_NO_DISPLAY
Definition sbgl_types.h:236
@ SBGL_PLATFORM_ERROR_WINDOW_FAILED
Definition sbgl_types.h:235
Arena allocator implementation.
#define SBL_ARENA_PUSH_STRUCT_ZERO(arena, type)
Definition sbl_arena.h:20
Arena allocator.
Definition sbl_arena.h:47
Represents the real-time state of physical inputs.
Definition sbgl_input.h:165
Native X11 window state.
sbgl_InputState * input
Display * display
static void xdg_surface_handle_configure(void *data, struct xdg_surface *surf, uint32_t serial)
bool sbgl_os_WasWindowResized(sbgl_Window *window)
Checks if the window has been resized since the last check.
static const struct xdg_wm_base_listener wm_base_listener
uint64_t sbgl_os_GetPerfCount(sbgl_Window *window)
Gets the high-resolution performance counter.
static void locked_pointer_locked(void *data, struct zwp_locked_pointer_v1 *locked_pointer)
static void toplevel_handle_configure(void *data, struct xdg_toplevel *t, int32_t w, int32_t h, struct wl_array *s)
void sbgl_os_PollEvents(sbgl_Window *window)
Dispatches OS events (messages/protocol requests).
const struct zwp_relative_pointer_v1_listener relative_pointer_listener
void sbgl_os_SetCursorLocked(sbgl_Window *window, bool locked)
Locks or unlocks the cursor within the window bounds.
static void toplevel_handle_close(void *data, struct xdg_toplevel *t)
uint64_t sbgl_os_GetPerfFreq(sbgl_Window *window)
Gets the performance counter frequency.
static const struct zwp_locked_pointer_v1_listener locked_pointer_listener
void * sbgl_os_GetNativeWindowHandle(sbgl_Window *window)
Retrieves the raw window handle for Vulkan surface creation.
void sbgl_os_SetCursorVisible(sbgl_Window *window, bool visible)
Sets the visibility of the OS cursor for the given window.
static const struct xdg_surface_listener xdg_surface_listener
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.
static const struct wl_registry_listener registry_listener
static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial)
static const struct xdg_toplevel_listener toplevel_listener
sbgl_platform_Result sbgl_os_CreateWindow(struct SblArena *arena, sbgl_InputState *input, int width, int height, const char *title, sbgl_Window **outWindow)
Creates a native OS window.
bool sbgl_os_IsWindowFocused(sbgl_Window *window)
Checks if the window currently has input focus.
void * sbgl_os_GetNativeDisplayHandle(sbgl_Window *window)
Retrieves the native display handle (Linux specific).
void sbgl_os_DestroyWindow(sbgl_Window *window)
Destroys a native window.
static void registry_handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
static void locked_pointer_unlocked(void *data, struct zwp_locked_pointer_v1 *locked_pointer)