diff options
Diffstat (limited to 'src/konwinlib.h')
| -rw-r--r-- | src/konwinlib.h | 1357 |
1 files changed, 0 insertions, 1357 deletions
diff --git a/src/konwinlib.h b/src/konwinlib.h deleted file mode 100644 index c50f828..0000000 --- a/src/konwinlib.h +++ /dev/null @@ -1,1357 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* - * konwinlib.h - * - * Copyright (c) 2026 KonAki - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef KONWINLIB_H -#define KONWINLIB_H - -#include <stdint.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> - -/*** definitions ***/ - -typedef struct kon_context kon_context_t; - -bool kon_init(void); -void kon_deinit(void); - -typedef struct kon_window kon_window_t; - -typedef enum kon_windowFlags { - KON_WINDOW_NONE = 0, - KON_WINDOW_TRANSPARENT = 1 << 0, - KON_WINDOW_NO_DECOR = 1 << 1, - KON_WINDOW_ALWAYS_ONTOP = 1 << 2, - KON_WINDOW_CENTER = 1 << 3, - KON_WINDOW_RESIZABLE = 1 << 4 -} kon_windowFlags_t; - -typedef enum kon_eventType { - KON_EVENT_NONE = 0, - KON_EVENT_CLOSE, - KON_EVENT_RESIZE, - KON_EVENT_KEY_DOWN, - KON_EVENT_KEY_UP, - KON_EVENT_MOUSE_DOWN, - KON_EVENT_MOUSE_UP, - KON_EVENT_MOUSE_MOVE -} kon_eventType_t; - -typedef enum kon_mouseButton { - KON_MOUSE_LEFT = 0, - KON_MOUSE_MIDDLE, - KON_MOUSE_RIGHT -} kon_mouseButton_t; - -typedef enum kon_key { - KON_KEY_UNKNOWN = 0, - - KON_KEY_A, KON_KEY_B, KON_KEY_C, KON_KEY_D, KON_KEY_E, KON_KEY_F, KON_KEY_G, - KON_KEY_H, KON_KEY_I, KON_KEY_J, KON_KEY_K, KON_KEY_L, KON_KEY_M, KON_KEY_N, KON_KEY_O, KON_KEY_P, - KON_KEY_Q, KON_KEY_R, KON_KEY_S, KON_KEY_T, KON_KEY_U, KON_KEY_V, - KON_KEY_W, KON_KEY_X, KON_KEY_Y, KON_KEY_Z, - - KON_KEY_0, KON_KEY_1, KON_KEY_2, KON_KEY_3, KON_KEY_4, KON_KEY_5, KON_KEY_6, KON_KEY_7, KON_KEY_8, KON_KEY_9, - - KON_KEY_F1, KON_KEY_F2, KON_KEY_F3, KON_KEY_F4, KON_KEY_F5, KON_KEY_F6, - KON_KEY_F7, KON_KEY_F8, KON_KEY_F9, KON_KEY_F10, KON_KEY_F11, KON_KEY_F12, - - KON_KEY_LEFT, KON_KEY_RIGHT, KON_KEY_UP, KON_KEY_DOWN, - - KON_KEY_SPACE, KON_KEY_ENTER, KON_KEY_TAB, KON_KEY_BACKSPACE, - KON_KEY_ESCAPE, KON_KEY_DELETE, - - KON_KEY_LEFT_SHIFT, KON_KEY_RIGHT_SHIFT, - KON_KEY_LEFT_CTRL, KON_KEY_RIGHT_CTRL, - KON_KEY_LEFT_ALT, KON_KEY_RIGHT_ALT, - - KON_KEY_MINUS, KON_KEY_EQUAL, - KON_KEY_LEFT_BRACKET, KON_KEY_RIGHT_BRACKET, - KON_KEY_SEMICOLON, KON_KEY_APOSTROPHE, - KON_KEY_COMMA, KON_KEY_PERIOD, KON_KEY_SLASH, KON_KEY_BACKSLASH, - KON_KEY_GRAVE, - - KON_KEY_COUNT -} kon_key_t; - -typedef struct kon_event { - kon_eventType_t type; - int width, height; /* will be used to store data for resize events */ - int key; - int mouseX, mouseY; - kon_mouseButton_t mouseButton; -} kon_event_t; - -kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags); -void kon_destroyWindow(kon_window_t *window); - -bool kon_windowShouldClose(kon_window_t *window); - -void kon_setExitKey(kon_window_t *window, int key); - -void kon_setWindowPos(kon_window_t *window, int x, int y); -void kon_setWindowSize(kon_window_t *window, int width, int height); - -void kon_getWindowPos(kon_window_t *window, int *x, int *y); -void kon_getWindowSize(kon_window_t *window, int *width, int *height); - -int kon_pollEvent(kon_window_t *window, kon_event_t *event); -void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height); - -// added these for web dev -typedef void (*kon_mainLoopFn)(void *userData); -void kon_runMainLoop(kon_window_t *window, kon_mainLoopFn callback, void *userData); - -/*** implementation ***/ - -#ifdef KONWINLIB_IMPLEMENTATION - -static kon_context_t *kon_ctx; - -#define KON_EVENT_QUEUE_SIZE 256 - -typedef struct kon_eventQueue { - kon_event_t events[KON_EVENT_QUEUE_SIZE]; - int head, count; -} kon_eventQueue_t; - -static void kon_pushEvent_(kon_eventQueue_t *q, const kon_event_t *event) { - /* only the newest mouse move or resize matters, so overwrite instead of piling up */ - if (q->count > 0 && (event->type == KON_EVENT_MOUSE_MOVE || event->type == KON_EVENT_RESIZE)) { - kon_event_t *last = &q->events[(q->head + q->count - 1) % KON_EVENT_QUEUE_SIZE]; - if (last->type == event->type) { - *last = *event; - return; - } - } - - if (q->count == KON_EVENT_QUEUE_SIZE) return; - q->events[(q->head + q->count) % KON_EVENT_QUEUE_SIZE] = *event; - q->count++; -} - -static bool kon_popEvent_(kon_eventQueue_t *q, kon_event_t *event) { - if (q->count == 0) return false; - *event = q->events[q->head]; - q->head = (q->head + 1) % KON_EVENT_QUEUE_SIZE; - q->count--; - return true; -} - -#ifdef __EMSCRIPTEN__ - -#include <emscripten/emscripten.h> -#include <emscripten/html5.h> -#include <string.h> - -struct kon_context { - int initialized; -}; - -struct kon_window { - char canvasID[64]; - bool shouldClose; - int exitKey; - - bool hasKeyEvent; - kon_eventType_t keyEventType; - int keyEventKey; - - bool hasResizeEvent; - int resizeWidth, resizeHeight; - - bool hasMouseEvent; - kon_eventType_t mouseEventType; - int mouseEventX, mouseEventY; - kon_mouseButton_t mouseEventButton; -}; - -static kon_key_t kon_translateEmKey_(int keyCode) { - switch (keyCode) { - case 65: return KON_KEY_A; - case 66: return KON_KEY_B; - case 67: return KON_KEY_C; - case 68: return KON_KEY_D; - case 69: return KON_KEY_E; - case 70: return KON_KEY_F; - case 71: return KON_KEY_G; - case 72: return KON_KEY_H; - case 73: return KON_KEY_I; - case 74: return KON_KEY_J; - case 75: return KON_KEY_K; - case 76: return KON_KEY_L; - case 77: return KON_KEY_M; - case 78: return KON_KEY_N; - case 79: return KON_KEY_O; - case 80: return KON_KEY_P; - case 81: return KON_KEY_Q; - case 82: return KON_KEY_R; - case 83: return KON_KEY_S; - case 84: return KON_KEY_T; - case 85: return KON_KEY_U; - case 86: return KON_KEY_V; - case 87: return KON_KEY_W; - case 88: return KON_KEY_X; - case 89: return KON_KEY_Y; - case 90: return KON_KEY_Z; - - case 48: return KON_KEY_0; - case 49: return KON_KEY_1; - case 50: return KON_KEY_2; - case 51: return KON_KEY_3; - case 52: return KON_KEY_4; - case 53: return KON_KEY_5; - case 54: return KON_KEY_6; - case 55: return KON_KEY_7; - case 56: return KON_KEY_8; - case 57: return KON_KEY_9; - - case 112: return KON_KEY_F1; - case 113: return KON_KEY_F2; - case 114: return KON_KEY_F3; - case 115: return KON_KEY_F4; - case 116: return KON_KEY_F5; - case 117: return KON_KEY_F6; - case 118: return KON_KEY_F7; - case 119: return KON_KEY_F8; - case 120: return KON_KEY_F9; - case 121: return KON_KEY_F10; - case 122: return KON_KEY_F11; - case 123: return KON_KEY_F12; - - case 37: return KON_KEY_LEFT; - case 39: return KON_KEY_RIGHT; - case 38: return KON_KEY_UP; - case 40: return KON_KEY_DOWN; - - case 32: return KON_KEY_SPACE; - case 13: return KON_KEY_ENTER; - case 9: return KON_KEY_TAB; - case 8: return KON_KEY_BACKSPACE; - case 27: return KON_KEY_ESCAPE; - case 46: return KON_KEY_DELETE; - - case 16: return KON_KEY_LEFT_SHIFT; - case 17: return KON_KEY_LEFT_CTRL; - case 18: return KON_KEY_LEFT_ALT; - - case 189: return KON_KEY_MINUS; - case 187: return KON_KEY_EQUAL; - case 219: return KON_KEY_LEFT_BRACKET; - case 221: return KON_KEY_RIGHT_BRACKET; - case 186: return KON_KEY_SEMICOLON; - case 222: return KON_KEY_APOSTROPHE; - case 188: return KON_KEY_COMMA; - case 190: return KON_KEY_PERIOD; - case 191: return KON_KEY_SLASH; - case 220: return KON_KEY_BACKSLASH; - case 192: return KON_KEY_GRAVE; - - default: return KON_KEY_UNKNOWN; - } -} -bool kon_init(void) { - kon_context_t *ctx = malloc(sizeof(kon_context_t)); - if (!ctx) return false; - - ctx->initialized = 1; - kon_ctx = ctx; - return true; -} - -void kon_deinit(void) { - if (!kon_ctx) return; - - free(kon_ctx); - kon_ctx = NULL; -} - -static EM_BOOL kon_keyDownCallback_(int eventType, const EmscriptenKeyboardEvent *e, void *userData) { - (void)eventType; - kon_window_t *window = (kon_window_t *)userData; - - window->hasKeyEvent = true; - window->keyEventType = KON_EVENT_KEY_DOWN; - window->keyEventKey = kon_translateEmKey_(e->keyCode); - - if (window->exitKey != 0 && window->keyEventKey == window->exitKey) { - window->shouldClose = true; - } - - return EM_TRUE; -} - -static EM_BOOL kon_keyUpCallback_(int eventType, const EmscriptenKeyboardEvent *e, void *userData) { - (void)eventType; - kon_window_t *window = (kon_window_t *)userData; - - window->hasKeyEvent = true; - window->keyEventType = KON_EVENT_KEY_UP; - window->keyEventKey = kon_translateEmKey_(e->keyCode); - - return EM_TRUE; -} - -static EM_BOOL kon_mouseDownCallback_(int eventType, const EmscriptenMouseEvent *e, void *userData) { - (void)eventType; - kon_window_t *window = (kon_window_t *)userData; - - if (e->button > KON_MOUSE_RIGHT) return EM_FALSE; - - window->hasMouseEvent = true; - window->mouseEventType = KON_EVENT_MOUSE_DOWN; - window->mouseEventButton = (kon_windowButton_t)e->button; - window->mouseEventX = e->targetX; - window->mouseEventY = e->targetY; - - return EM_TRUE; -} - -static EM_BOOL kon_mouseUpCallback_(int eventType, const EmscriptenMouseEvent *e, void *userData) { - (void)eventType; - kon_window_t *window = (kon_window_t *)userData; - - if (e->button > KON_MOUSE_RIGHT) return EM_FALSE: - - window->hasMouseEvent = true; - window->mouseEventType = KON_EVENT_MOUSE_UP; - window->mouseEventButton = (kon_windowButton_t)e->button; - window->mouseEventX = e->targetX; - window->mouseEventY = e->targetY; - - return EM_TRUE; -} - -static EM_BOOL kon_mouseMoveCallback_(int eventType, const EmscriptenMouseEvent *e, void *userData) { - (void)eventType; - kon_window_t *window = (kon_window_t *)userData; - - window->hasMouseEvent = true; - window->mouseEventType = KON_EVENT_MOUSE_MOVE; - window->mouseEventX = e->targetX; - window->mouseEventY = e->targetY; - - return EM_TRUE; -} - -kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags) { - (void)x; (void)y; (void)flags; - - if (!kon_ctx) { - fprintf(stderr, "kon_createWindow: error creating window, no ctx\n"); - return NULL; - } - - kon_window_t *window = malloc(sizeof(kon_window_t)); - if (!window) return NULL; - - strncpy(window->canvasID, "#canvas", sizeof(window->canvasID) - 1); - window->canvasID[sizeof(window->canvasID) - 1] = '\0'; - - window->shouldClose = false; - window->exitKey = 0; - window->hasKeyEvent = false; - window->hasResizeEvent = false; - window->hasMouseEvent = false; - - emscripten_set_canvas_element_size(window->canvasID, width, height); - - EM_ASM({ - try { document.title = UTF8ToString($0); } catch (e) {} - }, title); - - emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, window, EM_FALSE, kon_keyDownCallback_); - emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, window, EM_FALSE, kon_keyUpCallback_); - emscripten_set_mousedown_callback(window->canvasID, window, EM_FALSE, kon_mouseDownCallback_); - emscripten_set_mouseup_callback(window->canvasID, window, EM_FALSE, kon_mouseUpCallback_); - emscripten_set_mousemove_callback(window->canvasID, window, EM_FALSE, kon_mouseMoveCallback_); - - return window; -} - -void kon_destroyWindow(kon_window_t *window) { - if (!window) return; - - emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, NULL); - emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, NULL); - emscripten_set_mousedown_callback(window->canvasID, NULL, EM_FALSE, NULL); - emscripten_set_mouseup_callback(window->canvasID, NULL, EM_FALSE, NULL); - emscripten_set_mousemove_callback(window->canvasID, NULL, EM_FALSE, NULL); - - free(window); -} - -bool kon_windowShouldClose(kon_window_t *window) { - if (!window) return true; - return window->shouldClose; -} - -void kon_setExitKey(kon_window_t *window, int key) { - if (!window) return; - window->exitKey = key; -} - -void kon_setWindowPos(kon_window_t *window, int x, int y) { - (void)window; (void)x; (void)y; -} - -void kon_setWindowSize(kon_window_t *window, int width, int height) { - if (!window) return; - emscripten_set_canvas_element_size(window->canvasID, width, height); -} - -void kon_getWindowPos(kon_window_t *window, int *x, int *y) { - (void)window; - if (x) *x = 0; - if (y) *y = 0; -} - -void kon_getWindowSize(kon_window_t *window, int *width, int *height) { - if (!window || !width || !height) return; - - double w, h; - emscripten_get_element_css_size(window->canvasID, &w, &h); - *width = (int)w; - *height = (int)h; -} - -int kon_pollEvent(kon_window_t *window, kon_event_t *event) { - if (!window || !event) return 0; - - event->type = KON_EVENT_NONE; - - if (window->hasResizeEvent) { - event->type = KON_EVENT_RESIZE; - event->width = window->resizeWidth; - event->height = window->resizeHeight; - window->hasResizeEvent = false; - return 1; - } - - if (window->hasKeyEvent) { - event->type = window->keyEventType; - event->key = window->keyEventKey; - window->hasKeyEvent = false; - return 1; - } - - if (window->hasMouseEvent) { - event->type = window->mouseEventType; - event->mouseX = window->mouseEventX; - event->mouseY = window-<mouseEventY; - event->mouseButton = window->mouseEventButton; - window->hasMouseEvent = false; - return 1; - } - - return 0; -} - -EM_JS(void, kon_jsBlit_, (const char *canvasID, uint32_t *pixels, int width, int height), { - var sel = UTF8ToString(canvasID); - var canvas = document.querySelector(sel); - if (!canvas) return; - - if (!canvas.__konCtx) canvas.__konCtx = canvas.getContext('2d'); - var ctx = canvas.__konCtx; - - if (!canvas.__konImgData || canvas.__konImgData.width !== width || canvas.__konImgData.height !== height) { - canvas.__konImgData = ctx.createImageData(width, height); - } - var imgData = canvas.__konImgData; - - var dst = new Uint32Array(imgData.data.buffer); - var srcIdx = pixels >> 2; - var count = width * height; - - for (var i = 0; i < count; i++) { - var px = HEAPU32[srcIdx + i]; - dst[i] = (px & 0xFF00FF00) | ((px & 0x00FF0000) >>> 16) | ((px & 0x000000FF) << 16); - } - - ctx.putImageData(imgData, 0, 0); -}); - -void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height) { - if (!window || !pixels) return; - kon_jsBlit_(window->canvasID, (uint32_t *)pixels, width, height); -} - -#elif defined(__linux__) || defined(__unix__) - -#include <X11/Xlib.h> -#include <X11/Xutil.h> -#include <X11/Xatom.h> -#include <X11/extensions/Xrandr.h> -#include <X11/keysym.h> -#include <string.h> - -static kon_key_t kon_translateX11Key_(KeySym sym) { - switch (sym) { - case XK_a: return KON_KEY_A; - case XK_b: return KON_KEY_B; - case XK_c: return KON_KEY_C; - case XK_d: return KON_KEY_D; - case XK_e: return KON_KEY_E; - case XK_f: return KON_KEY_F; - case XK_g: return KON_KEY_G; - case XK_h: return KON_KEY_H; - case XK_i: return KON_KEY_I; - case XK_j: return KON_KEY_J; - case XK_k: return KON_KEY_K; - case XK_l: return KON_KEY_L; - case XK_m: return KON_KEY_M; - case XK_n: return KON_KEY_N; - case XK_o: return KON_KEY_O; - case XK_p: return KON_KEY_P; - case XK_q: return KON_KEY_Q; - case XK_r: return KON_KEY_R; - case XK_s: return KON_KEY_S; - case XK_t: return KON_KEY_T; - case XK_u: return KON_KEY_U; - case XK_v: return KON_KEY_V; - case XK_w: return KON_KEY_W; - case XK_x: return KON_KEY_X; - case XK_y: return KON_KEY_Y; - case XK_z: return KON_KEY_Z; - - case XK_0: return KON_KEY_0; - case XK_1: return KON_KEY_1; - case XK_2: return KON_KEY_2; - case XK_3: return KON_KEY_3; - case XK_4: return KON_KEY_4; - case XK_5: return KON_KEY_5; - case XK_6: return KON_KEY_6; - case XK_7: return KON_KEY_7; - case XK_8: return KON_KEY_8; - case XK_9: return KON_KEY_9; - - case XK_F1: return KON_KEY_F1; - case XK_F2: return KON_KEY_F2; - case XK_F3: return KON_KEY_F3; - case XK_F4: return KON_KEY_F4; - case XK_F5: return KON_KEY_F5; - case XK_F6: return KON_KEY_F6; - case XK_F7: return KON_KEY_F7; - case XK_F8: return KON_KEY_F8; - case XK_F9: return KON_KEY_F9; - case XK_F10: return KON_KEY_F10; - case XK_F11: return KON_KEY_F11; - case XK_F12: return KON_KEY_F12; - - case XK_Left: return KON_KEY_LEFT; - case XK_Right: return KON_KEY_RIGHT; - case XK_Up: return KON_KEY_UP; - case XK_Down: return KON_KEY_DOWN; - - case XK_space: return KON_KEY_SPACE; - case XK_Return: return KON_KEY_ENTER; - case XK_Tab: return KON_KEY_TAB; - case XK_BackSpace: return KON_KEY_BACKSPACE; - case XK_Escape: return KON_KEY_ESCAPE; - case XK_Delete: return KON_KEY_DELETE; - - case XK_Shift_L: return KON_KEY_LEFT_SHIFT; - case XK_Shift_R: return KON_KEY_RIGHT_SHIFT; - case XK_Control_L: return KON_KEY_LEFT_CTRL; - case XK_Control_R: return KON_KEY_RIGHT_CTRL; - case XK_Alt_L: return KON_KEY_LEFT_ALT; - case XK_Alt_R: return KON_KEY_RIGHT_ALT; - - case XK_minus: return KON_KEY_MINUS; - case XK_equal: return KON_KEY_EQUAL; - case XK_bracketleft: return KON_KEY_LEFT_BRACKET; - case XK_bracketright: return KON_KEY_RIGHT_BRACKET; - case XK_semicolon: return KON_KEY_SEMICOLON; - case XK_apostrophe: return KON_KEY_APOSTROPHE; - case XK_comma: return KON_KEY_COMMA; - case XK_period: return KON_KEY_PERIOD; - case XK_slash: return KON_KEY_SLASH; - case XK_backslash: return KON_KEY_BACKSLASH; - case XK_grave: return KON_KEY_GRAVE; - - default: return KON_KEY_UNKNOWN; - } -} - -struct kon_context { - Display *display; -}; - -bool kon_init(void) { - kon_context_t *ctx = malloc(sizeof(kon_context_t)); - if (!ctx) return false; - ctx->display = XOpenDisplay(NULL); - if (!ctx->display) return false; - kon_ctx = ctx; - return true; -} - -void kon_deinit(void) { - if (!kon_ctx) return; - - XCloseDisplay(kon_ctx->display); - free(kon_ctx); - kon_ctx=NULL; -} - -struct kon_window { - Window window; - GC gc; - Visual *visual; - int depth; - Colormap colormap; - bool owns_colormap; - Atom wm_delete; - bool shouldClose; - int exitKey; -}; - -kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags) { - if (!kon_ctx) { - fprintf(stderr, "kon_createWindow: There appears to be no kon_ctx. \nPlease, do kon_init(); before doing anything with konwinlib, thank you.\n"); - return NULL; - } - - kon_window_t *window = malloc(sizeof(kon_window_t)); - if (!window) return NULL; - - int screen = DefaultScreen(kon_ctx->display); - - if (flags & KON_WINDOW_CENTER) { - Window root = RootWindow(kon_ctx->display, screen); - - int mon_x = 0, mon_y = 0; - int mon_width = DisplayWidth(kon_ctx->display, screen); - int mon_height = DisplayHeight(kon_ctx->display, screen); - - Window root_ret, child_ret; - int root_x, root_y, win_x, win_y; - unsigned int mask; - XQueryPointer(kon_ctx->display, root, &root_ret, &child_ret, &root_x, &root_y, &win_x, &win_y, &mask); - - XRRScreenResources *res = XRRGetScreenResourcesCurrent(kon_ctx->display, root); - if (res) { - for (int i = 0; i < res->noutput; i++) { - XRROutputInfo *out_info = XRRGetOutputInfo(kon_ctx->display, res, res->outputs[i]); - - if (out_info && out_info->crtc) { - XRRCrtcInfo *crtc = XRRGetCrtcInfo(kon_ctx->display, res, out_info->crtc); - if (crtc) { - - if (root_x >= crtc->x && root_x < crtc->x + (int)crtc->width && - root_y >= crtc->y && root_y < crtc->y + (int)crtc->height) { - mon_x = crtc->x; - mon_y = crtc->y; - mon_width = crtc->width; - mon_height = crtc->height; - XRRFreeCrtcInfo(crtc); - if (out_info) XRRFreeOutputInfo(out_info); - break; - } - XRRFreeCrtcInfo(crtc); - } - } - if (out_info) XRRFreeOutputInfo(out_info); - } - XRRFreeScreenResources(res); - } - - x = mon_x + (mon_width - width ) / 2; - y = mon_y + (mon_height - height) / 2; - } - - if (flags & KON_WINDOW_TRANSPARENT) { - XVisualInfo vinfo; - if (!XMatchVisualInfo(kon_ctx->display, screen, 32, TrueColor, &vinfo)) { - free(window); - return NULL; - } - - window->visual = vinfo.visual; - window->depth = vinfo.depth; - window->colormap = XCreateColormap(kon_ctx->display, RootWindow(kon_ctx->display, screen), window->visual, AllocNone); - - XSetWindowAttributes attrs; - attrs.colormap = window->colormap; - attrs.background_pixel = 0; - attrs.border_pixel = 0; - - window->window = XCreateWindow( - kon_ctx->display, RootWindow(kon_ctx->display, screen), - x, y, width, height, 0, window->depth, InputOutput, - window->visual, CWColormap | CWBackPixel | CWBorderPixel, &attrs); - - window->owns_colormap = true; - } else { - window->visual = DefaultVisual(kon_ctx->display, screen); - window->depth = DefaultDepth(kon_ctx->display, screen); - window->colormap = DefaultColormap(kon_ctx->display, screen); - - window->window = XCreateSimpleWindow( - kon_ctx->display, RootWindow(kon_ctx->display, screen), - x, y, width, height, 0, 0, 0); - - window->owns_colormap = false; - } - - if (!window->window) { - if (window->owns_colormap) { - XFreeColormap(kon_ctx->display, window->colormap); - } - free(window); - return NULL; - } - - XStoreName(kon_ctx->display, window->window, title); - XSelectInput(kon_ctx->display, window->window, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask); - - if (flags & KON_WINDOW_NO_DECOR) { - Atom motif_hints = XInternAtom(kon_ctx->display, "_MOTIF_WM_HINTS", False); - struct { unsigned long flags, functions, decorations; long input_mode; unsigned long status; } hints; - memset(&hints, 0, sizeof(hints)); - hints.flags = 2; - hints.decorations = 0; - XChangeProperty(kon_ctx->display, window->window, motif_hints, - motif_hints, 32, PropModeReplace, (unsigned char *)&hints, 5); - } - - if (flags & KON_WINDOW_ALWAYS_ONTOP) { - Atom wm_state = XInternAtom(kon_ctx->display, "_NET_WM_STATE", False); - Atom wm_above = XInternAtom(kon_ctx->display, "_NET_WM_STATE_ABOVE", False); - XChangeProperty(kon_ctx->display, window->window, wm_state, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&wm_above, 1); - } - - if (!(flags & KON_WINDOW_RESIZABLE)) { - XSizeHints hints; - hints.flags = PMinSize | PMaxSize; - hints.min_width = hints.max_width = width; - hints.min_height = hints.max_height = height; - XSetWMNormalHints(kon_ctx->display, window->window, &hints); - } - - window->wm_delete = XInternAtom(kon_ctx->display, "WM_DELETE_WINDOW", False); - XSetWMProtocols(kon_ctx->display, window->window, &window->wm_delete, 1); - - window->gc = XCreateGC(kon_ctx->display, window->window, 0, NULL); - - XMapWindow(kon_ctx->display, window->window); - XFlush(kon_ctx->display); - - window->exitKey = 0; - - window->shouldClose = false; - - return window; -} - -void kon_destroyWindow(kon_window_t *window) { - if (!window) return; - if (!kon_ctx) { free(window); return; } - - if (window->gc) XFreeGC(kon_ctx->display, window->gc); - if (window->window) XDestroyWindow(kon_ctx->display, window->window); - if (window->owns_colormap && window->colormap) XFreeColormap(kon_ctx->display, window->colormap); - - XFlush(kon_ctx->display); - - free(window); -} - -void kon_setExitKey(kon_window_t *window, int key) { - if (!window) return; - window->exitKey = key; -} - -void kon_setWindowPos(kon_window_t *window, int x, int y) { - if (!window || !kon_ctx) return; - - XMoveWindow(kon_ctx->display, window->window, x, y); - XFlush(kon_ctx->display); -} - -void kon_setWindowSize(kon_window_t *window, int width, int height) { - if (!window || !kon_ctx) return; - - XResizeWindow(kon_ctx->display, window->window, width, height); - XFlush(kon_ctx->display); -} - -void kon_getWindowPos(kon_window_t *window, int *x, int *y) { - if (!window || !kon_ctx || !x || !y) return; - - Window child; - XTranslateCoordinates(kon_ctx->display, window->window, RootWindow(kon_ctx->display, DefaultScreen(kon_ctx->display)), - 0, 0, x, y, &child); -} - -void kon_getWindowSize(kon_window_t *window, int *width, int *height) { - if (!window || !kon_ctx || !width || !height) return; - - XWindowAttributes attrs; - XGetWindowAttributes(kon_ctx->display, window->window, &attrs); - *width = attrs.width; - *height = attrs.height; -} - -int kon_pollEvent(kon_window_t *window, kon_event_t *event) { - if (!window || !kon_ctx || !event) return 0; - - event->type = KON_EVENT_NONE; - - if (!XPending(kon_ctx->display)) return 0; - - XEvent xev; - XNextEvent(kon_ctx->display, &xev); - - if (xev.type == ClientMessage) { - if ((Atom)xev.xclient.data.l[0] == window->wm_delete) { - event->type = KON_EVENT_CLOSE; - window->shouldClose = true; - } - } - - if (xev.type == ConfigureNotify) { - event->type = KON_EVENT_RESIZE; - event->width = xev.xconfigure.width; - event->height = xev.xconfigure.height; - return 1; - } - - if (xev.type == KeyPress) { - event->type = KON_EVENT_KEY_DOWN; - event->key = (int)kon_translateX11Key_(XLookupKeysym(&xev.xkey, 0)); - if (window->exitKey != 0 && event->key == window->exitKey) { - window->shouldClose = true; - } - return 1; - } - - if (xev.type == KeyRelease) { - event->type = KON_EVENT_KEY_UP; - event->key = (int)kon_translateX11Key_(XLookupKeysym(&xev.xkey, 0)); - return 1; - } - - if (xev.type == ButtonPress || xev.type == ButtonRelease) { - int konButton = -1; - switch (xev.xbutton.button) { - case Button1: - konButton = KON_MOUSE_LEFT; - break; - case Button2: - konButton = KON_MOUSE_MIDDLE; - break; - case Button3: - konButton = KON_MOUSE_RIGHT; - break; - default: - break; - } - - if (konButton != -1) { - event->type = (xev.type == ButtonPress) ? KON_EVENT_MOUSE_DOWN : KON_EVENT_MOUSE_UP; - event->mouseButton = (kon_mouseButton_t)konButton; - event->mouseX = xev.xbutton.x; - event->mouseY = xev.xbutton.y; - } - return 1; - } - - if (xev.type == MotionNotify) { - event->type = KON_EVENT_MOUSE_MOVE; - event->mouseX = xev.xmotion.x; - event->mouseY = xev.xmotion.y; - return 1; - } - - return 1; -} - -bool kon_windowShouldClose(kon_window_t *window) { - if (!window || !kon_ctx) return true; - return window->shouldClose; -} - -/* TODO: implement the rest of these */ - -void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height) { - if (!window || !kon_ctx || !pixels) return; - - XImage *ximg = XCreateImage(kon_ctx->display, window->visual, window->depth, ZPixmap, 0, (char *)pixels, width, height, 32, 0); - if (!ximg) return; - - XPutImage(kon_ctx->display, window->window, window->gc, ximg, 0, 0, 0, 0, width, height); - - ximg->data = NULL; - XDestroyImage(ximg); - - XFlush(kon_ctx->display); -} - -/*** windows implementation ***/ - -#elif defined(_WIN32) - -#include <windows.h> -#include <string.h> - -struct kon_context { - HINSTANCE hInstance; -}; - -struct kon_window { - HWND hwnd; - bool shouldClose; - bool isTransparent; - int exitKey; - kon_eventQueue_t queue; -}; - -static kon_key_t kon_translateWin32Key_(WPARAM vk, LPARAM lParam) { - if (vk == VK_SHIFT) { - UINT scancode = (lParam >> 16) & 0xFF; - UINT lshift = MapVirtualKey(VK_LSHIFT, MAPVK_VK_TO_VSC); - return (scancode == lshift) ? KON_KEY_LEFT_SHIFT : KON_KEY_RIGHT_SHIFT; - } - if (vk == VK_CONTROL) { - return (lParam & 0x01000000) ? KON_KEY_RIGHT_CTRL : KON_KEY_LEFT_CTRL; - } - if (vk == VK_MENU) { - return (lParam & 0x01000000) ? KON_KEY_RIGHT_ALT : KON_KEY_LEFT_ALT; - } - - switch (vk) { - case 'A': return KON_KEY_A; - case 'B': return KON_KEY_B; - case 'C': return KON_KEY_C; - case 'D': return KON_KEY_D; - case 'E': return KON_KEY_E; - case 'F': return KON_KEY_F; - case 'G': return KON_KEY_G; - case 'H': return KON_KEY_H; - case 'I': return KON_KEY_I; - case 'J': return KON_KEY_J; - case 'K': return KON_KEY_K; - case 'L': return KON_KEY_L; - case 'M': return KON_KEY_M; - case 'N': return KON_KEY_N; - case 'O': return KON_KEY_O; - case 'P': return KON_KEY_P; - case 'Q': return KON_KEY_Q; - case 'R': return KON_KEY_R; - case 'S': return KON_KEY_S; - case 'T': return KON_KEY_T; - case 'U': return KON_KEY_U; - case 'V': return KON_KEY_V; - case 'W': return KON_KEY_W; - case 'X': return KON_KEY_X; - case 'Y': return KON_KEY_Y; - case 'Z': return KON_KEY_Z; - - case '0': return KON_KEY_0; - case '1': return KON_KEY_1; - case '2': return KON_KEY_2; - case '3': return KON_KEY_3; - case '4': return KON_KEY_4; - case '5': return KON_KEY_5; - case '6': return KON_KEY_6; - case '7': return KON_KEY_7; - case '8': return KON_KEY_8; - case '9': return KON_KEY_9; - - case VK_F1: return KON_KEY_F1; - case VK_F2: return KON_KEY_F2; - case VK_F3: return KON_KEY_F3; - case VK_F4: return KON_KEY_F4; - case VK_F5: return KON_KEY_F5; - case VK_F6: return KON_KEY_F6; - case VK_F7: return KON_KEY_F7; - case VK_F8: return KON_KEY_F8; - case VK_F9: return KON_KEY_F9; - case VK_F10: return KON_KEY_F10; - case VK_F11: return KON_KEY_F11; - case VK_F12: return KON_KEY_F12; - - case VK_LEFT: return KON_KEY_LEFT; - case VK_RIGHT: return KON_KEY_RIGHT; - case VK_UP: return KON_KEY_UP; - case VK_DOWN: return KON_KEY_DOWN; - - case VK_SPACE: return KON_KEY_SPACE; - case VK_RETURN: return KON_KEY_ENTER; - case VK_TAB: return KON_KEY_TAB; - case VK_BACK: return KON_KEY_BACKSPACE; - case VK_ESCAPE: return KON_KEY_ESCAPE; - case VK_DELETE: return KON_KEY_DELETE; - - case VK_OEM_MINUS: return KON_KEY_MINUS; - case VK_OEM_PLUS: return KON_KEY_EQUAL; - case VK_OEM_4: return KON_KEY_LEFT_BRACKET; - case VK_OEM_6: return KON_KEY_RIGHT_BRACKET; - case VK_OEM_1: return KON_KEY_SEMICOLON; - case VK_OEM_7: return KON_KEY_APOSTROPHE; - case VK_OEM_COMMA: return KON_KEY_COMMA; - case VK_OEM_PERIOD: return KON_KEY_PERIOD; - case VK_OEM_2: return KON_KEY_SLASH; - case VK_OEM_5: return KON_KEY_BACKSLASH; - case VK_OEM_3: return KON_KEY_GRAVE; - - default: return KON_KEY_UNKNOWN; - } -} - -LRESULT CALLBACK kon_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - kon_window_t *window = (kon_window_t *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - - switch (msg) { - case WM_NCCREATE: { - CREATESTRUCT *cs = (CREATESTRUCT *)lParam; - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams); - break; - } - case WM_KEYDOWN: - if (window) { - kon_event_t ev = {0}; - ev.type = KON_EVENT_KEY_DOWN; - ev.key = (int)kon_translateWin32Key_(wParam, lParam); - kon_pushEvent_(&window->queue, &ev); - if (window->exitKey != 0 && ev.key == window->exitKey) { - window->shouldClose = true; - ev.type = KON_EVENT_CLOSE; - kon_pushEvent_(&window->queue, &ev); - } - } - break; - case WM_KEYUP: - if (window) { - kon_event_t ev = {0}; - ev.type = KON_EVENT_KEY_UP; - ev.key = (int)kon_translateWin32Key_(wParam, lParam); - kon_pushEvent_(&window->queue, &ev); - } - break; - case WM_LBUTTONDOWN: case WM_LBUTTONUP: - case WM_RBUTTONDOWN: case WM_RBUTTONUP: - case WM_MBUTTONDOWN: case WM_MBUTTONUP: - if (window) { - kon_event_t ev = {0}; - ev.type = (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN) - ? KON_EVENT_MOUSE_DOWN : KON_EVENT_MOUSE_UP; - ev.mouseButton = (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP) ? KON_MOUSE_LEFT - : (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP) ? KON_MOUSE_RIGHT - : KON_MOUSE_MIDDLE; - ev.mouseX = (int)(short)LOWORD(lParam); - ev.mouseY = (int)(short)HIWORD(lParam); - kon_pushEvent_(&window->queue, &ev); - } - break; - case WM_MOUSEMOVE: - if (window) { - kon_event_t ev = {0}; - ev.type = KON_EVENT_MOUSE_MOVE; - ev.mouseX = (int)(short)LOWORD(lParam); - ev.mouseY = (int)(short)HIWORD(lParam); - kon_pushEvent_(&window->queue, &ev); - } - break; - case WM_CLOSE: - if (window) { - kon_event_t ev = {0}; - ev.type = KON_EVENT_CLOSE; - window->shouldClose = true; - kon_pushEvent_(&window->queue, &ev); - } - break; - case WM_SIZE: - /* minimizing reports 0x0, which would wreck the framebuffer */ - if (window && wParam != SIZE_MINIMIZED && LOWORD(lParam) > 0 && HIWORD(lParam) > 0) { - kon_event_t ev = {0}; - ev.type = KON_EVENT_RESIZE; - ev.width = LOWORD(lParam); - ev.height = HIWORD(lParam); - kon_pushEvent_(&window->queue, &ev); - } - break; - case WM_DESTROY: - PostQuitMessage(0); - return 0; - break; - case WM_ERASEBKGND: - return 1; - } - return DefWindowProc(hwnd, msg, wParam, lParam); -} - -bool kon_init(void) { - kon_context_t *ctx = malloc(sizeof(kon_context_t)); - if (!ctx) return false; - - ctx->hInstance = GetModuleHandle(NULL); - - WNDCLASSEX wc = {0}; - wc.cbSize = sizeof(WNDCLASSEX); - wc.lpfnWndProc = kon_wndProc; - wc.hInstance = ctx->hInstance; - wc.lpszClassName = "KonWinLibClass"; - wc.hCursor = LoadCursor(NULL, IDC_ARROW); - - if (!RegisterClassEx(&wc)) { - free(ctx); - return false; - } - - kon_ctx = ctx; - return true; -} - -void kon_deinit(void) { - if (!kon_ctx) return; - - free(kon_ctx); - kon_ctx = NULL; -} - - -kon_window_t *kon_createWindow(const char *title, int x, int y, int width, int height, kon_windowFlags_t flags) { - if (!kon_ctx) return NULL; - - kon_window_t *window = calloc(1, sizeof(kon_window_t)); - if (!window) return NULL; - - window->isTransparent = (flags & KON_WINDOW_TRANSPARENT); - window->exitKey = 0; - - DWORD style; - if (flags & KON_WINDOW_NO_DECOR) { - style = WS_POPUP; - } else { - style = WS_OVERLAPPEDWINDOW; - if (!(flags & KON_WINDOW_RESIZABLE)) { - style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX); - } - } - - DWORD exStyle = 0; - if (flags & KON_WINDOW_ALWAYS_ONTOP) exStyle |= WS_EX_TOPMOST; - if (flags & KON_WINDOW_TRANSPARENT) exStyle |= WS_EX_LAYERED; - - RECT adj = { 0, 0, width, height }; - AdjustWindowRectEx(&adj, style, FALSE, exStyle); - int winW = adj.right - adj.left; - int winH = adj.bottom - adj.top; - - if (flags & KON_WINDOW_CENTER) { - POINT cursor; - GetCursorPos(&cursor); - - HMONITOR hmon = MonitorFromPoint(cursor, MONITOR_DEFAULTTONEAREST); - - MONITORINFO mi; - mi.cbSize = sizeof(MONITORINFO); - GetMonitorInfo(hmon, &mi); - - int mon_x = mi.rcMonitor.left; - int mon_y = mi.rcMonitor.top; - int mon_width = mi.rcMonitor.right - mi.rcMonitor.left; - int mon_height = mi.rcMonitor.bottom - mi.rcMonitor.top; - - x = mon_x + (mon_width - winW) / 2; - y = mon_y + (mon_height - winH) / 2; - } - - window->hwnd = CreateWindowEx(exStyle, "KonWinLibClass", title, style, x, y, winW, winH, NULL, NULL, kon_ctx->hInstance, window); - - if (!window->hwnd) { - free(window); - return NULL; - } - - ShowWindow(window->hwnd, SW_SHOW); - - return window; -} - -void kon_destroyWindow(kon_window_t *window) { - if (!window) return; - if (window->hwnd) DestroyWindow(window->hwnd); - free(window); -} - -bool kon_windowShouldClose(kon_window_t *window) { - if (!window) return true; - return window->shouldClose; -} - - -void kon_setExitKey(kon_window_t *window, int key) { - if (!window) return; - window->exitKey = key; -} - -void kon_setWindowPos(kon_window_t *window, int x, int y) { - if (!window || !kon_ctx) return; - - SetWindowPos(window->hwnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER); -} - -void kon_setWindowSize(kon_window_t *window, int width, int height) { - if (!window || !kon_ctx) return; - - RECT r = { 0, 0, width, height }; - AdjustWindowRectEx(&r, (DWORD)GetWindowLongPtr(window->hwnd, GWL_STYLE), FALSE, (DWORD)GetWindowLongPtr(window->hwnd, GWL_EXSTYLE)); - SetWindowPos(window->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER); -} - - -void kon_getWindowPos(kon_window_t *window, int *x, int *y) { - if (!window || !x || !y) return; - - RECT rect; - GetWindowRect(window->hwnd, &rect); - *x = rect.left; - *y = rect.top; -} - -void kon_getWindowSize(kon_window_t *window, int *width, int *height) { - if (!window || !width || !height) return; - - RECT rect; - GetClientRect(window->hwnd, &rect); - *width = rect.right - rect.left; - *height = rect.bottom - rect.top; -} - -int kon_pollEvent(kon_window_t *window, kon_event_t *event) { - if (!window || !event) return 0; - - MSG msg; - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - if (!kon_popEvent_(&window->queue, event)) { - event->type = KON_EVENT_NONE; - return 0; - } - return 1; -} - -void kon_blitPixels(kon_window_t *window, const uint32_t *pixels, int width, int height) { - if (!window || !pixels) return; - - BITMAPINFO bmi = {0}; - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = -height; /* top-down */ - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; - bmi.bmiHeader.biCompression = BI_RGB; - - if (window->isTransparent) { - HDC screenDC = GetDC(NULL); - HDC memDC = CreateCompatibleDC(screenDC); - - void *dibPixels; - HBITMAP hbm = CreateDIBSection(screenDC, &bmi, DIB_RGB_COLORS, &dibPixels, NULL, 0); - if (hbm) { - memcpy(dibPixels, pixels, (size_t)width * height * 4); - HBITMAP oldBmp = (HBITMAP)SelectObject(memDC, hbm); - - RECT winRect; - GetWindowRect(window->hwnd, &winRect); - POINT dstPos = { winRect.left, winRect.top }; - POINT srcPos = { 0, 0 }; - SIZE size = { width, height }; - BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; - - UpdateLayeredWindow(window->hwnd, screenDC, &dstPos, &size, memDC, &srcPos, 0, &blend, ULW_ALPHA); - - SelectObject(memDC, oldBmp); - DeleteObject(hbm); - } - - DeleteDC(memDC); - ReleaseDC(NULL, screenDC); - } else { - HDC winDC = GetDC(window->hwnd); - SetDIBitsToDevice(winDC, 0, 0, width, height, 0, 0, 0, height, pixels, &bmi, DIB_RGB_COLORS); - ReleaseDC(window->hwnd, winDC); - } -} - -#else - #error "konwinlib.h: unsupported platform" -#endif /* end of platform switch */ - -/*** main loop ***/ - -#ifdef __EMSCRIPTEN__ - -typedef struct { - kon_window_t *window; - kon_mainLoopFn callback; - void *userData; -} kon_mainLoopCtx_; - -static void kon_mainLoopTrampoline_(void *arg) { - kon_mainLoopCtx_ *ctx = (kon_mainLoopCtx_ *)arg; - - if (kon_windowShouldClose(ctx->window)) { - emscripten_cancel_main_loop(); - free(ctx); - return; - } - - ctx->callback(ctx->userData); -} - -void kon_runMainLoop(kon_window_t *window, kon_mainLoopFn callback, void *userData) { - kon_mainLoopCtx_ *ctx = malloc(sizeof(kon_mainLoopCtx_)); - if (!ctx) return; - - ctx->window = window; - ctx->callback = callback; - ctx->userData = userData; - - emscripten_set_main_loop_arg(kon_mainLoopTrampoline_, ctx, 0, 1); -} - -#else - -void kon_runMainLoop(kon_window_t *window, kon_mainLoopFn callback, void *userData) { - while (!kon_windowShouldClose(window)) { - callback(userData); - } -} - -#endif /* __EMSCRIPTEN__ */ - -#endif /* end of KONWINLIB_IMPLEMENTATION */ - -#endif |
