// TODO(MA): Do stuff for general unix platforms some day static Window linux_window = { .w = 1920, .h = 1080, }; // Init b32 _LoadLib(const char *name, Library *out_lib) { if (!name) { return false; } out_lib->lib = dlopen(name, RTLD_NOW); if (!out_lib->lib) { return false; } return true; } b32 _LoadFn(const char *name, Library *lib, Function *out_fn) { if (!name) { return false; } out_fn->fn = dlsym(lib->lib, name); if (!out_fn->fn) { Printf("unable to find function\n"); return false; } return true; } b32 _InitPlatform() { return true; } // Init End // General Utils b32 CheckSyscallErr(void *ptr) { return (isize)ptr == SYS_ERR ? true : false; } // General Utils End i32 Write(int fd, void const *str, isize count) { i32 result = (i32)write(fd, str, count); return result; } i32 _EPrint(void const *str) { return Write(_STDERR, str, (isize)StrLen(str)); } i32 _EPrintf(const char *fmt, va_list arg) { char buffer[1024]; int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg); if (sprf_res < 0) return sprf_res; i32 pr_res = EPrint(&buffer); return pr_res; } i32 _Printf(const char *fmt, va_list arg) { char buffer[1024]; int sprf_res = stbsp_vsnprintf(&buffer[0], 1024, fmt, arg); i32 pr_res; if (sprf_res < 0) pr_res = sprf_res; else pr_res = Write(_STDOUT, &buffer, sprf_res); return pr_res; } i32 _Printfln(const char *fmt, va_list arg) { char buffer[1024]; int sprf_res = stbsp_vsnprintf(&buffer[0], 1023, fmt, arg); i32 pr_res; if (sprf_res < 0) { pr_res = sprf_res; } else { buffer[sprf_res] = '\n'; buffer[sprf_res+1] = '\0'; pr_res = Write(_STDOUT, &buffer, sprf_res+1); } return pr_res; } rawptr _MemAlloc(isize size) { void *addr = mmap( NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ); if (CheckSyscallErr(addr)) addr = NULL; return addr; } rawptr _MemAllocZeroed(isize size) { rawptr ptr = MemAlloc(size); MemZero(ptr, size); return ptr; } isize _GetPageSize() { return (isize)sysconf(_SC_PAGESIZE); } b32 _CreateWindow() { Window *window = &linux_window; int screen_index; window->connection = xcb_connect(NULL, &screen_index); if (!window->connection) { return false; } xcb_void_cookie_t cookie; xcb_generic_error_t *error; const xcb_setup_t *setup = xcb_get_setup(window->connection); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); xcb_screen_t *screen = iter.data; const int event_mask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_STRUCTURE_NOTIFY; const int val_win[] = {screen->black_pixel, event_mask}; const int val_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; window->window = xcb_generate_id(window->connection); cookie = xcb_create_window( window->connection, XCB_COPY_FROM_PARENT, window->window, screen->root, 0, // x pos 0, // y pos window->w, // width window->h, // height 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, val_mask, val_win ); XCB_CHECK_ERROR(window, cookie, error, "Failed to create window."); cookie = xcb_map_window_checked(window->connection, window->window); XCB_CHECK_ERROR(window, cookie, error, "Failed to map window."); cookie = xcb_change_property_checked( window->connection, XCB_PROP_MODE_REPLACE, window->window, XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8, StrLen(WINDOW_NAME), WINDOW_NAME ); XCB_CHECK_ERROR(window, cookie, error, "Failed to rename window."); xcb_intern_atom_cookie_t c_proto = xcb_intern_atom(window->connection, 1, 12, "WM_PROTOCOLS"); xcb_intern_atom_reply_t *r_proto = xcb_intern_atom_reply(window->connection, c_proto, &error); XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get WM_PROTOCOLS."); xcb_intern_atom_cookie_t c_close = xcb_intern_atom(window->connection, 0, 16, "WM_DELETE_WINDOW"); xcb_intern_atom_reply_t *r_close = xcb_intern_atom_reply(window->connection, c_close, &error); XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get WM_DELETE_WINDOW."); xcb_intern_atom_cookie_t c_minimize = xcb_intern_atom(window->connection, 0, 20, "_NET_WM_STATE_HIDDEN"); xcb_intern_atom_reply_t *r_minimize = xcb_intern_atom_reply(window->connection, c_minimize, &error); XCB_CHECK_CURRENT_ERROR(window, error, "Failed to get _NET_WM_STATE_HIDDEN"); cookie = xcb_change_property_checked( window->connection, XCB_PROP_MODE_REPLACE, window->window, r_proto->atom, XCB_ATOM_ATOM, 32, 1, &r_close->atom ); XCB_CHECK_ERROR(window, cookie, error, "Failed to set window close event."); window->close_event = r_close->atom; window->minimize_event = r_minimize->atom; free(r_proto); free(r_close); free(r_minimize); xcb_map_window(window->connection, window->window); i32 stream_result = xcb_flush(window->connection); if (stream_result <= 0) { Printfln("Error flushing the stream: %d", stream_result); return false; } return true; } Window *_GetWindow() { return &linux_window; } WindowSize _GetWindowSize() { return (WindowSize) { .w = linux_window.w, .h = linux_window.h, }; } b32 _GetWindowEvent(WindowEvent *event) { return HandleWindowEvent(event, false); } void _WaitForWindowEvent(WindowEvent *event) { HandleWindowEvent(event, true); } b32 HandleWindowEvent(WindowEvent *event, b32 wait_for_event) { Assert(event != NULL, "GetWindowEvent received a null pointer"); b32 valid_event = false; b32 no_event = false; do { xcb_generic_event_t *e; if (wait_for_event) e = xcb_wait_for_event(linux_window.connection); else e = xcb_poll_for_event(linux_window.connection); // XCB_UNMAP_NOTIFY if (e != NULL) { switch (e->response_type & ~0x80) { case XCB_CLIENT_MESSAGE: xcb_client_message_event_t *msg = (xcb_client_message_event_t *)e; if (msg->data.data32[0] == linux_window.close_event) { event->type = EVENT_QUIT; valid_event = true; } if (msg->data.data32[0] == linux_window.minimize_event) { event->type = EVENT_MINIMIZE; valid_event = true; linux_window.w = 0; linux_window.h = 0; } break; case XCB_UNMAP_NOTIFY: break; case XCB_EXPOSE: event->type = EVENT_SHOW; xcb_expose_event_t *expose_e = (xcb_expose_event_t *)e; linux_window.w = expose_e->width; linux_window.h = expose_e->height; break; case XCB_CONFIGURE_NOTIFY: xcb_configure_notify_event_t *configure_event = (xcb_configure_notify_event_t *)e; if (linux_window.w != configure_event->width || linux_window.h != configure_event->height) { event->type = EVENT_RESIZE; valid_event = true; event->resize.w = configure_event->width; event->resize.h = configure_event->height; linux_window.w = configure_event->width; linux_window.h = configure_event->height; } break; default: break; } free(e); } else { break; } } while(!valid_event && !wait_for_event); return valid_event; } b32 ChangeWorkingDir(const char *) { b32 success = false; return success; } u8 *OpenFile(const char *) { u8 *bytes = NULL; return bytes; }