/* * GLEQ - A basic event queue for GLFW 3 * Copyright © Camilla Löwy * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would * be appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. */ #ifndef GLEQ_HEADER_FILE #define GLEQ_HEADER_FILE // #include #ifdef GLEQ_STATIC #define GLEQDEF static #else #define GLEQDEF extern #endif #ifdef __cplusplus extern "C" { #endif typedef enum { GLEQ_NONE = 0, GLEQ_WINDOW_MOVED = 1<<1, GLEQ_WINDOW_RESIZED = 1<<2, GLEQ_WINDOW_CLOSED = 1<<3, GLEQ_WINDOW_REFRESH = 1<<4, GLEQ_WINDOW_FOCUSED = 1<<5, GLEQ_WINDOW_DEFOCUSED = 1<<6, GLEQ_WINDOW_ICONIFIED = 1<<7, GLEQ_WINDOW_UNICONIFIED = 1<<8, GLEQ_FRAMEBUFFER_RESIZED = 1<<9, GLEQ_BUTTON_PRESSED = 1<<10, GLEQ_BUTTON_RELEASED = 1<<11, GLEQ_CURSOR_MOVED = 1<<12, GLEQ_CURSOR_ENTERED = 1<<13, GLEQ_CURSOR_LEFT = 1<<14, GLEQ_SCROLLED = 1<<15, GLEQ_KEY_PRESSED = 1<<16, GLEQ_KEY_REPEATED = 1<<17, GLEQ_KEY_RELEASED = 1<<18, GLEQ_CODEPOINT_INPUT = 1<<19, GLEQ_MONITOR_CONNECTED = 1<<20, GLEQ_MONITOR_DISCONNECTED = 1<<21, #if GLFW_VERSION_MINOR >= 1 GLEQ_FILE_DROPPED = 1<<22, #endif #if GLFW_VERSION_MINOR >= 2 GLEQ_JOYSTICK_CONNECTED = 1<<23, GLEQ_JOYSTICK_DISCONNECTED = 1<<24, #endif #if GLFW_VERSION_MINOR >= 3 GLEQ_WINDOW_MAXIMIZED = 1<<25, GLEQ_WINDOW_UNMAXIMIZED = 1<<26, GLEQ_WINDOW_SCALE_CHANGED = 1<<27, #endif } GLEQtype; typedef struct GLEQevent { unsigned/*GLEQtype*/ type; union { GLFWwindow* window; GLFWmonitor* monitor; int joystick; }; union { struct { int x; int y; } pos; struct { int width; int height; } size; struct { double x; double y; } scroll; struct { int key; int scancode; int mods; } keyboard; struct { int button; int mods; } mouse; unsigned int codepoint; #if GLFW_VERSION_MINOR >= 1 struct { char** paths; int count; } file; #endif #if GLFW_VERSION_MINOR >= 3 struct { float x; float y; } scale; #endif }; } GLEQevent; GLEQDEF void gleqInit(void); GLEQDEF void gleqTrackWindow(GLFWwindow* window); GLEQDEF int gleqNextEvent(GLEQevent* event); GLEQDEF void gleqFreeEvent(GLEQevent* event); #ifdef __cplusplus } #endif #ifdef GLEQ_IMPLEMENTATION #include #include #include #ifndef GLEQ_CAPACITY #define GLEQ_CAPACITY 1024 #endif static struct { GLEQevent events[GLEQ_CAPACITY]; size_t head; size_t tail; } gleq_queue = { {0}, 0, 0 }; static char* gleq_strdup(const char* string) { const size_t size = strlen(string) + 1; char* result = (char*) malloc(size); memcpy(result, string, size); return result; } static GLEQevent* gleq_new_event(void) { GLEQevent* event = gleq_queue.events + gleq_queue.head; gleq_queue.head = (gleq_queue.head + 1) % GLEQ_CAPACITY; assert(gleq_queue.head != gleq_queue.tail); memset(event, 0, sizeof(GLEQevent)); return event; } static void gleq_window_pos_callback(GLFWwindow* window, int x, int y) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_WINDOW_MOVED; event->window = window; event->pos.x = x; event->pos.y = y; } static void gleq_window_size_callback(GLFWwindow* window, int width, int height) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_WINDOW_RESIZED; event->window = window; event->size.width = width; event->size.height = height; } static void gleq_window_close_callback(GLFWwindow* window) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_WINDOW_CLOSED; event->window = window; } static void gleq_window_refresh_callback(GLFWwindow* window) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_WINDOW_REFRESH; event->window = window; } static void gleq_window_focus_callback(GLFWwindow* window, int focused) { GLEQevent* event = gleq_new_event(); event->window = window; if (focused) event->type = GLEQ_WINDOW_FOCUSED; else event->type = GLEQ_WINDOW_DEFOCUSED; } static void gleq_window_iconify_callback(GLFWwindow* window, int iconified) { GLEQevent* event = gleq_new_event(); event->window = window; if (iconified) event->type = GLEQ_WINDOW_ICONIFIED; else event->type = GLEQ_WINDOW_UNICONIFIED; } static void gleq_framebuffer_size_callback(GLFWwindow* window, int width, int height) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_FRAMEBUFFER_RESIZED; event->window = window; event->size.width = width; event->size.height = height; } static void gleq_mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { GLEQevent* event = gleq_new_event(); event->window = window; event->mouse.button = button; event->mouse.mods = mods; if (action == GLFW_PRESS) event->type = GLEQ_BUTTON_PRESSED; else if (action == GLFW_RELEASE) event->type = GLEQ_BUTTON_RELEASED; } static void gleq_cursor_pos_callback(GLFWwindow* window, double x, double y) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_CURSOR_MOVED; event->window = window; event->pos.x = (int) x; event->pos.y = (int) y; } static void gleq_cursor_enter_callback(GLFWwindow* window, int entered) { GLEQevent* event = gleq_new_event(); event->window = window; if (entered) event->type = GLEQ_CURSOR_ENTERED; else event->type = GLEQ_CURSOR_LEFT; } static void gleq_scroll_callback(GLFWwindow* window, double x, double y) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_SCROLLED; event->window = window; event->scroll.x = x; event->scroll.y = y; } static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { GLEQevent* event = gleq_new_event(); event->window = window; event->keyboard.key = key; event->keyboard.scancode = scancode; event->keyboard.mods = mods; if (action == GLFW_PRESS) event->type = GLEQ_KEY_PRESSED; else if (action == GLFW_RELEASE) event->type = GLEQ_KEY_RELEASED; else if (action == GLFW_REPEAT) event->type = GLEQ_KEY_REPEATED; } static void (*gleq_char_callback_prev)(GLFWwindow* window, unsigned int codepoint) = 0; static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint) { if( gleq_char_callback_prev ) gleq_char_callback_prev(window, codepoint); GLEQevent* event = gleq_new_event(); event->type = GLEQ_CODEPOINT_INPUT; event->window = window; event->codepoint = codepoint; } static void gleq_monitor_callback(GLFWmonitor* monitor, int action) { GLEQevent* event = gleq_new_event(); event->monitor = monitor; if (action == GLFW_CONNECTED) event->type = GLEQ_MONITOR_CONNECTED; else if (action == GLFW_DISCONNECTED) event->type = GLEQ_MONITOR_DISCONNECTED; } #if GLFW_VERSION_MINOR >= 1 static void gleq_file_drop_callback(GLFWwindow* window, int count, const char** paths) { GLEQevent* event = gleq_new_event(); event->type = GLEQ_FILE_DROPPED; event->window = window; event->file.paths = (char**) malloc(count * sizeof(char*)); event->file.count = count; while (count--) event->file.paths[count] = gleq_strdup(paths[count]); } #endif #if GLFW_VERSION_MINOR >= 2 static void gleq_joystick_callback(int jid, int action) { GLEQevent* event = gleq_new_event(); event->joystick = jid; if (action == GLFW_CONNECTED) event->type = GLEQ_JOYSTICK_CONNECTED; else if (action == GLFW_DISCONNECTED) event->type = GLEQ_JOYSTICK_DISCONNECTED; } #endif #if GLFW_VERSION_MINOR >= 3 static void gleq_window_maximize_callback(GLFWwindow* window, int maximized) { GLEQevent* event = gleq_new_event(); event->window = window; if (maximized) event->type = GLEQ_WINDOW_MAXIMIZED; else event->type = GLEQ_WINDOW_UNMAXIMIZED; } static void gleq_window_content_scale_callback(GLFWwindow* window, float xscale, float yscale) { GLEQevent* event = gleq_new_event(); event->window = window; event->type = GLEQ_WINDOW_SCALE_CHANGED; event->scale.x = xscale; event->scale.y = yscale; } #endif GLEQDEF void gleqInit(void) { glfwSetMonitorCallback(gleq_monitor_callback); #if GLFW_VERSION_MINOR >= 2 glfwSetJoystickCallback(gleq_joystick_callback); #endif } GLEQDEF void gleqTrackWindow(GLFWwindow* window) { glfwSetWindowPosCallback(window, gleq_window_pos_callback); glfwSetWindowSizeCallback(window, gleq_window_size_callback); glfwSetWindowCloseCallback(window, gleq_window_close_callback); glfwSetWindowRefreshCallback(window, gleq_window_refresh_callback); glfwSetWindowFocusCallback(window, gleq_window_focus_callback); glfwSetWindowIconifyCallback(window, gleq_window_iconify_callback); glfwSetFramebufferSizeCallback(window, gleq_framebuffer_size_callback); glfwSetMouseButtonCallback(window, gleq_mouse_button_callback); glfwSetCursorPosCallback(window, gleq_cursor_pos_callback); glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback); glfwSetScrollCallback(window, gleq_scroll_callback); glfwSetKeyCallback(window, gleq_key_callback); gleq_char_callback_prev = //< @r-lyeh glfwSetCharCallback(window, gleq_char_callback); #if GLFW_VERSION_MINOR >= 1 glfwSetDropCallback(window, gleq_file_drop_callback); #endif #if GLFW_VERSION_MINOR >= 3 glfwSetWindowMaximizeCallback(window, gleq_window_maximize_callback); glfwSetWindowContentScaleCallback(window, gleq_window_content_scale_callback); #endif } GLEQDEF int gleqNextEvent(GLEQevent* event) { memset(event, 0, sizeof(GLEQevent)); if (gleq_queue.head != gleq_queue.tail) { *event = gleq_queue.events[gleq_queue.tail]; gleq_queue.tail = (gleq_queue.tail + 1) % GLEQ_CAPACITY; } return event->type != GLEQ_NONE; } GLEQDEF void gleqFreeEvent(GLEQevent* event) { #if GLFW_VERSION_MINOR >= 1 if (event->type == GLEQ_FILE_DROPPED) { while (event->file.count--) free(event->file.paths[event->file.count]); free(event->file.paths); } #endif memset(event, 0, sizeof(GLEQevent)); } #endif /* GLEQ_IMPLEMENTATION */ #endif /* GLEQ_HEADER_FILE */