26 window->
state = state;
30 state->
connection = xcb_connect(NULL, &screenp);
31 if (xcb_connection_has_error(state->
connection)) {
32 KB_ERROR(
"failed to establish connection to X server");
37 const xcb_query_extension_reply_t *ext_reply = xcb_get_extension_data(state->
connection, &xcb_xkb_id);
39 KB_ERROR(
"xkb extension not available on X server");
44 xcb_xkb_use_extension_cookie_t use_ext_cookie =
45 xcb_xkb_use_extension(state->
connection, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
46 xcb_generic_error_t *error =
KB_NULL;
47 xcb_xkb_use_extension_reply_t *use_ext_reply =
KB_NULL;
48 use_ext_reply = xcb_xkb_use_extension_reply(state->
connection, use_ext_cookie, &error);
50 KB_ERROR(
"failed to load xkb extension of X server");
53 if (!use_ext_reply->supported || error !=
KB_NULL) {
54 KB_ERROR(
"xkb extension is not supported on this X server");
61 xcb_xkb_per_client_flags_cookie_t pcf_cookie;
62 xcb_xkb_per_client_flags_reply_t *pcf_reply;
63 pcf_cookie = xcb_xkb_per_client_flags(state->
connection,
64 XCB_XKB_ID_USE_CORE_KBD,
65 XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
66 XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
70 pcf_reply = xcb_xkb_per_client_flags_reply(state->
connection, pcf_cookie, &error);
73 KB_ERROR(
"failed to set xkb per-client flag, error code: {u8}", error->major_code);
81 const xcb_setup_t *setup = xcb_get_setup(state->
connection);
82 state->
screen = xcb_setup_roots_iterator(setup).data;
86 u32 event_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
87 u32 event_values = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_KEY_PRESS
88 | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_POINTER_MOTION
89 | XCB_EVENT_MASK_STRUCTURE_NOTIFY;
90 u32 value_list[] = {state->
screen->black_pixel, event_values};
102 XCB_WINDOW_CLASS_INPUT_OUTPUT,
103 state->
screen->root_visual,
109 XCB_PROP_MODE_REPLACE,
118 const char *wm_delete_cmd_name =
"WM_DELETE_WINDOW";
119 const char *wm_protocols_cmd_name =
"WM_PROTOCOLS";
120 xcb_intern_atom_cookie_t wm_delete_cookie =
121 xcb_intern_atom(state->
connection, 0, (u16) strlen(wm_delete_cmd_name), wm_delete_cmd_name);
122 xcb_intern_atom_cookie_t wm_protocols_cookie =
123 xcb_intern_atom(state->
connection, 0, (u16) strlen(wm_protocols_cmd_name), wm_protocols_cmd_name);
124 xcb_intern_atom_reply_t *wm_delete_reply = xcb_intern_atom_reply(state->
connection, wm_delete_cookie, NULL);
125 xcb_intern_atom_reply_t *wm_protocols_reply = xcb_intern_atom_reply(state->
connection, wm_protocols_cookie, NULL);
129 XCB_PROP_MODE_REPLACE,
135 &wm_delete_reply->atom);
141 i32 stream_result = xcb_flush(state->
connection);
142 if (stream_result <= 0) {
143 KB_ERROR(
"failed to flush the stream, result: {i32}", stream_result);
148 KB_ERROR(
"failed to allocate memory for window's surface");
151 if (!gpu_surface_create(surface, state)) {
152 KB_ERROR(
"failed to create window surface");
155 window->
title = title;
161 window->
alloc = alloc;
167 gpu_surface_destroy(window->
surface);
173 xcb_key_symbols_free(state->
syms);
199 xcb_generic_event_t *event;
201 while ((event = xcb_poll_for_event(state->
connection))) {
203 i32 type =
event->response_type & ~0x80;
206 case XCB_KEY_RELEASE: {
207 xcb_key_press_event_t *key_event = (xcb_key_press_event_t *) event;
208 xcb_keysym_t key_sym = xcb_key_symbols_get_keysym(state->
syms, key_event->detail, 0);
210 b8 pressed = type == XCB_KEY_PRESS;
212 context.data.u32[0] = code;
213 event_fire(pressed ? EVENT_CODE_KEY_PRESSED : EVENT_CODE_KEY_RELEASED, state, context);
215 case XCB_BUTTON_PRESS:
216 case XCB_BUTTON_RELEASE: {
217 xcb_button_press_event_t *button_event = (xcb_button_press_event_t *) event;
218 if (button_event->detail > 3) {
219 i8 wheel_dir = button_event->detail == 4 ? -1 : 1;
221 context.data.i8[0] = wheel_dir;
222 event_fire(EVENT_CODE_MOUSE_WHEEL, state, context);
225 b8 pressed = type == XCB_BUTTON_PRESS;
227 context.data.u32[0] = code;
228 event_fire(pressed ? EVENT_CODE_KEY_PRESSED : EVENT_CODE_KEY_RELEASED, state, context);
231 case XCB_MOTION_NOTIFY: {
232 xcb_motion_notify_event_t *motion_event = (xcb_motion_notify_event_t *) event;
234 context.data.u32[0] = (u32) motion_event->event_x;
235 context.data.u32[1] = (u32) motion_event->event_y;
237 event_fire(EVENT_CODE_MOUSE_MOVED, state, context);
240 case XCB_CONFIGURE_NOTIFY: {
241 xcb_configure_notify_event_t *configure_event = (xcb_configure_notify_event_t *) event;
242 window->
x = (u32) configure_event->x;
243 window->
y = (u32) configure_event->y;
244 window->
w = configure_event->width;
245 window->
h = configure_event->height;
247 context.data.u32[0] = window->
w;
248 context.data.u32[1] = window->
h;
249 event_fire(EVENT_CODE_WINDOW_RESIZE, state, context);
251 case XCB_MAP_NOTIFY: {
252 context.data.c[0] =
'R';
253 event_fire(EVENT_CODE_WINDOW_RAISED, state, context);
255 case XCB_UNMAP_NOTIFY: {
256 context.data.c[0] =
'M';
257 event_fire(EVENT_CODE_WINDOW_MINIMIZED, state, context);
259 case XCB_CLIENT_MESSAGE: {
260 xcb_client_message_event_t *message_event = (xcb_client_message_event_t *) event;
261 quit = message_event->data.data32[0] == state->
wm_delete_win;
272 if ((x_key_code >> 8) == 0 && x_key_code >= 0x0061 && x_key_code <= 0x007a) {
273 x_key_code -= (0x0061 - 0x0041);
275 switch (x_key_code) {
277 return KEY_BACKSPACE;
287 return KEY_CONTROL_L;
289 return KEY_CONTROL_R;
312 return KEY_PAGE_DOWN;
380 return KEY_SEMICOLON;
398 return KEY_BRACKET_L;
400 return KEY_BRACKET_R;
402 return KEY_BACK_SLASH;
444 return KEY_NUMPAD_ENTER;
482 KB_WARN(
"unmapped key code received {u32}", x_key_code);
489 return KEY_MOUSE_LEFT;
491 return KEY_MOUSE_MIDDLE;
493 return KEY_MOUSE_RIGHT;
495 KB_WARN(
"unmapped button code received {u32}", button);
void * allocator_allocate_aligned(allocator *alloc, usize size, usize alignment)
Allocate aligned memory.
void allocator_free(allocator *alloc, void *mem)
Give back memory to the allocator.
#define ALIGN_OF(x)
Get alignment of type.
#define KB_NULL
Value of an invalid ptr (nullptr).
b8 event_fire(u16 event_code, void *sender, event_context context)
Fire an event.
#define KB_ASSERT(expr,...)
Perform runtime assertion and log failures.
#define KB_WARN(...)
Log entry with warn log level.
#define KB_ERROR(...)
Log entry with error log level.
Central allocator structure.
Context used to store data of an event.
xcb_window_t window
X window.
xcb_atom_t wm_protocols
Window manager protocol atom.
xcb_key_symbols_t * syms
Pointer to xcb keysyms.
xcb_connection_t * connection
Connection to X server.
xcb_screen_t * screen
X screen.
xcb_atom_t wm_delete_win
Window manager delete atom.
key_code translate_keysym(xcb_keysym_t key_code)
Translates xcb keysym to kiba key code.
void window_destroy(platform_window *window)
Destroy platform window and clean up internal state.
b8 window_poll_events(platform_window *window)
Poll for events emited by the window.
key_code translate_button(xcb_button_t button)
Translates xcb button to kiba key code.
b8 window_create(platform_window *window, const char *title, u32 x, u32 y, u32 w, u32 h, allocator *alloc)
Create a platform window.
Interface to access platform specific windowing functionality.