RGFW.h (293229B)
1 /* 2 * Copyright (C) 2023-24 ColleagueRiley 3 * 4 * libpng license 5 * 6 * This software is provided 'as-is', without any express or implied 7 * warranty. In no event will the authors be held liable for any damages 8 * arising from the use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not 15 * claim that you wrote the original software. If you use this software 16 * in a product, an acknowledgment in the product documentation would be 17 * appreciated but is not required. 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 3. This notice may not be removed or altered from any source distribution. 21 * 22 * 23 */ 24 25 /* 26 (MAKE SURE RGFW_IMPLEMENTATION is in exactly one header or you use -D RGFW_IMPLEMENTATION) 27 #define RGFW_IMPLEMENTATION - makes it so source code is included with header 28 */ 29 30 /* 31 #define RGFW_IMPLEMENTATION - (required) makes it so the source code is included 32 #define RGFW_PRINT_ERRORS - (optional) makes it so RGFW prints errors when they're found 33 #define RGFW_OSMESA - (optional) use OSmesa as backend (instead of system's opengl api + regular opengl) 34 #define RGFW_BUFFER - (optional) just draw directly to (RGFW) window pixel buffer that is drawn to screen (the buffer is in the RGBA format) 35 #define RGFW_EGL - (optional) use EGL for loading an OpenGL context (instead of the system's opengl api) 36 #define RGFW_OPENGL_ES1 - (optional) use EGL to load and use Opengl ES (version 1) for backend rendering (instead of the system's opengl api) 37 This version doesn't work for desktops (I'm pretty sure) 38 #define RGFW_OPENGL_ES2 - (optional) use OpenGL ES (version 2) 39 #define RGFW_OPENGL_ES3 - (optional) use OpenGL ES (version 3) 40 #define RGFW_DIRECTX - (optional) use directX for the rendering backend (rather than opengl) (windows only, defaults to opengl for unix) 41 #define RGFW_WEBGPU - (optional) use webGPU for rendering (Web ONLY) 42 #define RGFW_NO_API - (optional) don't use any rendering API (no opengl, no vulkan, no directX) 43 44 #define RGFW_LINK_EGL (optional) (windows only) if EGL is being used, if EGL functions should be defined dymanically (using GetProcAddress) 45 #define RGFW_LINK_OSMESA (optional) (windows only) if EGL is being used, if OS Mesa functions should be defined dymanically (using GetProcAddress) 46 47 #define RGFW_X11 (optional) (unix only) if X11 should be used. This option is turned on by default by unix systems except for MacOS 48 #define RGFW_WGL_LOAD (optional) (windows only) if WGL should be loaded dynamically during runtime 49 #define RGFW_NO_X11_CURSOR (optional) (unix only) don't use XCursor 50 #define RGFW_NO_X11_CURSOR_PRELOAD (optional) (unix only) Use XCursor, but don't link it in code, (you'll have to link it with -lXcursor) 51 52 #define RGFW_NO_DPI - Do not include calculate DPI (no XRM nor libShcore included) 53 54 #define RGFW_ALLOC_DROPFILES (optional) if room should be allocating for drop files (by default it's global data) 55 #define RGFW_MALLOC x - choose what function to use to allocate, by default the standard malloc is used 56 #define RGFW_CALLOC x - choose what function to use to allocate (calloc), by default the standard calloc is used 57 #define RGFW_FREE x - choose what function to use to allocated memory, by default the standard free is used 58 59 #define RGFW_EXPORT - Use when building RGFW 60 #define RGFW_IMPORT - Use when linking with RGFW (not as a single-header) 61 62 #define RGFW_STD_INT - force the use stdint.h (for systems that might not have stdint.h (msvc)) 63 */ 64 65 /* 66 Credits : 67 EimaMei/Sacode : Much of the code for creating windows using winapi, Wrote the Silicon library, helped with MacOS Support, siliapp.h -> referencing 68 69 stb - This project is heavily inspired by the stb single header files 70 71 GLFW: 72 certain parts of winapi and X11 are very poorly documented, 73 GLFW's source code was referenced and used throughout the project (used code is marked in some way), 74 this mainly includes, code for drag and drops, code for setting the icon to a bitmap and the code for managing the clipboard for X11 (as these parts are not documented very well) 75 76 GLFW Copyright, https::/github.com/GLFW/GLFW 77 78 Copyright (c) 2002-2006 Marcus Geelnard 79 Copyright (c) 2006-2019 Camilla Löwy 80 81 contributors : (feel free to put yourself here if you contribute) 82 krisvers -> code review 83 EimaMei (SaCode) -> code review 84 Code-Nycticebus -> bug fixes 85 Rob Rohan -> X11 bugs and missing features, MacOS/Cocoa fixing memory issues/bugs 86 AICDG (@THISISAGOODNAME) -> vulkan support (example) 87 @Easymode -> support, testing/debugging, bug fixes and reviews 88 Joshua Rowe (omnisci3nce) - bug fix, review (macOS) 89 @lesleyrs -> bug fix, review (OpenGL) 90 Nick Porcino (meshula) - testing, organization, review (MacOS, examples) 91 */ 92 93 #if _MSC_VER 94 #pragma comment(lib, "gdi32") 95 #pragma comment(lib, "shell32") 96 #pragma comment(lib, "opengl32") 97 #pragma comment(lib, "winmm") 98 #pragma comment(lib, "user32") 99 #endif 100 101 #ifndef RGFW_MALLOC 102 #include <stdlib.h> 103 104 #ifndef __USE_POSIX199309 105 #define __USE_POSIX199309 106 #endif 107 108 #include <time.h> 109 #define RGFW_MALLOC malloc 110 #define RGFW_CALLOC calloc 111 #define RGFW_FREE free 112 #endif 113 114 #if !_MSC_VER 115 #ifndef inline 116 #ifndef __APPLE__ 117 #define inline __inline 118 #endif 119 #endif 120 #endif 121 122 #ifdef RGFW_WIN95 /* for windows 95 testing (not that it really works) */ 123 #define RGFW_NO_MONITOR 124 #define RGFW_NO_PASSTHROUGH 125 #endif 126 127 #if defined(RGFW_EXPORT) || defined(RGFW_IMPORT) 128 #if defined(_WIN32) 129 #if defined(__TINYC__) && (defined(RGFW_EXPORT) || defined(RGFW_IMPORT)) 130 #define __declspec(x) __attribute__((x)) 131 #endif 132 133 #if defined(RGFW_EXPORT) 134 #define RGFWDEF __declspec(dllexport) 135 #else 136 #define RGFWDEF __declspec(dllimport) 137 #endif 138 #else 139 #if defined(RGFW_EXPORT) 140 #define RGFWDEF __attribute__((visibility("default"))) 141 #endif 142 #endif 143 #endif 144 145 #ifndef RGFWDEF 146 #ifdef __clang__ 147 #define RGFWDEF static inline 148 #else 149 #define RGFWDEF inline 150 #endif 151 #endif 152 153 #ifndef RGFW_ENUM 154 #define RGFW_ENUM(type, name) type name; enum 155 #endif 156 157 #ifndef RGFW_UNUSED 158 #define RGFW_UNUSED(x) (void)(x); 159 #endif 160 161 #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) 162 extern "C" { 163 #endif 164 165 /* makes sure the header file part is only defined once by default */ 166 #ifndef RGFW_HEADER 167 168 #define RGFW_HEADER 169 170 #if !defined(u8) 171 #if ((defined(_MSC_VER) || defined(__SYMBIAN32__)) && !defined(RGFW_STD_INT)) /* MSVC might not have stdint.h */ 172 typedef unsigned char u8; 173 typedef signed char i8; 174 typedef unsigned short u16; 175 typedef signed short i16; 176 typedef unsigned int u32; 177 typedef signed int i32; 178 typedef unsigned long u64; 179 typedef signed long i64; 180 #else /* use stdint standard types instead of c ""standard"" types */ 181 #include <stdint.h> 182 183 typedef uint8_t u8; 184 typedef int8_t i8; 185 typedef uint16_t u16; 186 typedef int16_t i16; 187 typedef uint32_t u32; 188 typedef int32_t i32; 189 typedef uint64_t u64; 190 typedef int64_t i64; 191 #endif 192 #endif 193 194 #if !defined(b8) /* RGFW bool type */ 195 typedef u8 b8; 196 typedef u32 b32; 197 #endif 198 199 #define RGFW_TRUE (!(0)) 200 #define RGFW_FALSE 0 201 202 /* thse OS macros looks better & are standardized */ 203 /* plus it helps with cross-compiling */ 204 205 #ifdef __EMSCRIPTEN__ 206 #define RGFW_WEBASM 207 208 #if !defined(RGFW_NO_API) && !defined(RGFW_WEBGPU) 209 #define RGFW_OPENGL 210 #endif 211 212 #ifdef RGFW_EGL 213 #undef RGFW_EGL 214 #endif 215 216 #include <emscripten/html5.h> 217 #include <emscripten/key_codes.h> 218 219 #ifdef RGFW_WEBGPU 220 #include <emscripten/html5_webgpu.h> 221 #endif 222 #endif 223 224 #if defined(RGFW_X11) && defined(__APPLE__) 225 #define RGFW_MACOS_X11 226 #undef __APPLE__ 227 #endif 228 229 #if defined(_WIN32) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) /* (if you're using X11 on windows some how) */ 230 #define RGFW_WINDOWS 231 232 /* make sure the correct architecture is defined */ 233 #if defined(_WIN64) 234 #define _AMD64_ 235 #undef _X86_ 236 #else 237 #undef _AMD64_ 238 #ifndef _X86_ 239 #define _X86_ 240 #endif 241 #endif 242 243 #ifndef RGFW_NO_XINPUT 244 #ifdef __MINGW32__ /* try to find the right header */ 245 #include <xinput.h> 246 #else 247 #include <XInput.h> 248 #endif 249 #endif 250 251 #if defined(RGFW_DIRECTX) 252 #include <d3d11.h> 253 #include <dxgi.h> 254 #include <dxgi.h> 255 #include <d3dcompiler.h> 256 257 #ifndef __cplusplus 258 #define __uuidof(T) IID_##T 259 #endif 260 #endif 261 262 #elif defined(RGFW_WAYLAND) 263 #if !defined(RGFW_NO_API) && (!defined(RGFW_BUFFER) || defined(RGFW_OPENGL)) 264 #define RGFW_EGL 265 #define RGFW_OPENGL 266 #include <wayland-egl.h> 267 #endif 268 269 #include <wayland-client.h> 270 #elif (defined(__unix__) || defined(RGFW_MACOS_X11) || defined(RGFW_X11)) && !defined(RGFW_WEBASM) 271 #define RGFW_MACOS_X11 272 #define RGFW_X11 273 #include <X11/Xlib.h> 274 #elif defined(__APPLE__) && !defined(RGFW_MACOS_X11) && !defined(RGFW_X11) && !defined(RGFW_WEBASM) 275 #define RGFW_MACOS 276 #endif 277 278 #if (defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3)) && !defined(RGFW_EGL) 279 #define RGFW_EGL 280 #endif 281 282 #if !defined(RGFW_OSMESA) && !defined(RGFW_EGL) && !defined(RGFW_OPENGL) && !defined(RGFW_DIRECTX) && !defined(RGFW_BUFFER) && !defined(RGFW_NO_API) 283 #define RGFW_OPENGL 284 #endif 285 286 #ifdef RGFW_EGL 287 #include <EGL/egl.h> 288 #elif defined(RGFW_OSMESA) 289 #ifndef __APPLE__ 290 #include <GL/osmesa.h> 291 #else 292 #include <OpenGL/osmesa.h> 293 #endif 294 #endif 295 296 #if defined(RGFW_OPENGL) && defined(RGFW_X11) 297 #ifndef GLX_MESA_swap_control 298 #define GLX_MESA_swap_control 299 #endif 300 #include <GL/glx.h> /* GLX defs, xlib.h, gl.h */ 301 #endif 302 303 #ifndef RGFW_ALPHA 304 #define RGFW_ALPHA 128 /* alpha value for RGFW_TRANSPARENT_WINDOW (WINAPI ONLY, macOS + linux don't need this) */ 305 #endif 306 307 /*! Optional arguments for making a windows */ 308 #define RGFW_TRANSPARENT_WINDOW (1L<<9) /*!< the window is transparent (only properly works on X11 and MacOS, although it's although for windows) */ 309 #define RGFW_NO_BORDER (1L<<3) /*!< the window doesn't have border */ 310 #define RGFW_NO_RESIZE (1L<<4) /*!< the window cannot be resized by the user */ 311 #define RGFW_ALLOW_DND (1L<<5) /*!< the window supports drag and drop*/ 312 #define RGFW_HIDE_MOUSE (1L<<6) /*! the window should hide the mouse or not (can be toggled later on) using `RGFW_window_mouseShow*/ 313 #define RGFW_FULLSCREEN (1L<<8) /* the window is fullscreen by default or not */ 314 #define RGFW_CENTER (1L<<10) /*! center the window on the screen */ 315 #define RGFW_OPENGL_SOFTWARE (1L<<11) /*! use OpenGL software rendering */ 316 #define RGFW_COCOA_MOVE_TO_RESOURCE_DIR (1L << 12) /* (cocoa only), move to resource folder */ 317 #define RGFW_SCALE_TO_MONITOR (1L << 13) /* scale the window to the screen */ 318 #define RGFW_NO_INIT_API (1L << 2) /* DO not init an API (mostly for bindings, you should use `#define RGFW_NO_API` in C */ 319 320 #define RGFW_NO_GPU_RENDER (1L<<14) /* don't render (using the GPU based API)*/ 321 #define RGFW_NO_CPU_RENDER (1L<<15) /* don't render (using the CPU based buffer rendering)*/ 322 #define RGFW_WINDOW_HIDE (1L << 16)/* the window is hidden */ 323 324 typedef RGFW_ENUM(u8, RGFW_event_types) { 325 /*! event codes */ 326 RGFW_keyPressed = 1, /* a key has been pressed */ 327 RGFW_keyReleased, /*!< a key has been released*/ 328 /*! key event note 329 the code of the key pressed is stored in 330 RGFW_Event.keyCode 331 !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! 332 333 while a string version is stored in 334 RGFW_Event.KeyString 335 336 RGFW_Event.lockState holds the current lockState 337 this means if CapsLock, NumLock are active or not 338 */ 339 RGFW_mouseButtonPressed, /*!< a mouse button has been pressed (left,middle,right)*/ 340 RGFW_mouseButtonReleased, /*!< a mouse button has been released (left,middle,right)*/ 341 RGFW_mousePosChanged, /*!< the position of the mouse has been changed*/ 342 /*! mouse event note 343 the x and y of the mouse can be found in the vector, RGFW_Event.point 344 345 RGFW_Event.button holds which mouse button was pressed 346 */ 347 RGFW_jsButtonPressed, /*!< a joystick button was pressed */ 348 RGFW_jsButtonReleased, /*!< a joystick button was released */ 349 RGFW_jsAxisMove, /*!< an axis of a joystick was moved*/ 350 /*! joystick event note 351 RGFW_Event.joystick holds which joystick was altered, if any 352 RGFW_Event.button holds which joystick button was pressed 353 354 RGFW_Event.axis holds the data of all the axis 355 RGFW_Event.axisCount says how many axis there are 356 */ 357 RGFW_windowMoved, /*!< the window was moved (by the user) */ 358 RGFW_windowResized, /*!< the window was resized (by the user), [on webASM this means the browser was resized] */ 359 RGFW_focusIn, /*!< window is in focus now */ 360 RGFW_focusOut, /*!< window is out of focus now */ 361 RGFW_mouseEnter, /* mouse entered the window */ 362 RGFW_mouseLeave, /* mouse left the window */ 363 RGFW_windowRefresh, /* The window content needs to be refreshed */ 364 365 /* attribs change event note 366 The event data is sent straight to the window structure 367 with win->r.x, win->r.y, win->r.w and win->r.h 368 */ 369 RGFW_quit, /*!< the user clicked the quit button*/ 370 RGFW_dnd, /*!< a file has been dropped into the window*/ 371 RGFW_dnd_init /*!< the start of a dnd event, when the place where the file drop is known */ 372 /* dnd data note 373 The x and y coords of the drop are stored in the vector RGFW_Event.point 374 375 RGFW_Event.droppedFilesCount holds how many files were dropped 376 377 This is also the size of the array which stores all the dropped file string, 378 RGFW_Event.droppedFiles 379 */ 380 }; 381 382 /*! mouse button codes (RGFW_Event.button) */ 383 #define RGFW_mouseLeft 1 /*!< left mouse button is pressed*/ 384 #define RGFW_mouseMiddle 2 /*!< mouse-wheel-button is pressed*/ 385 #define RGFW_mouseRight 3 /*!< right mouse button is pressed*/ 386 #define RGFW_mouseScrollUp 4 /*!< mouse wheel is scrolling up*/ 387 #define RGFW_mouseScrollDown 5 /*!< mouse wheel is scrolling down*/ 388 389 #ifndef RGFW_MAX_PATH 390 #define RGFW_MAX_PATH 260 /* max length of a path (for dnd) */ 391 #endif 392 #ifndef RGFW_MAX_DROPS 393 #define RGFW_MAX_DROPS 260 /* max items you can drop at once */ 394 #endif 395 396 397 /* for RGFW_Event.lockstate */ 398 #define RGFW_CAPSLOCK (1L << 1) 399 #define RGFW_NUMLOCK (1L << 2) 400 401 /*! joystick button codes (based on xbox/playstation), you may need to change these values per controller */ 402 #ifndef RGFW_joystick_codes 403 typedef RGFW_ENUM(u8, RGFW_joystick_codes) { 404 RGFW_JS_A = 0, /*!< or PS X button */ 405 RGFW_JS_B = 1, /*!< or PS circle button */ 406 RGFW_JS_Y = 2, /*!< or PS triangle button */ 407 RGFW_JS_X = 3, /*!< or PS square button */ 408 RGFW_JS_START = 9, /*!< start button */ 409 RGFW_JS_SELECT = 8, /*!< select button */ 410 RGFW_JS_HOME = 10, /*!< home button */ 411 RGFW_JS_UP = 13, /*!< dpad up */ 412 RGFW_JS_DOWN = 14, /*!< dpad down*/ 413 RGFW_JS_LEFT = 15, /*!< dpad left */ 414 RGFW_JS_RIGHT = 16, /*!< dpad right */ 415 RGFW_JS_L1 = 4, /*!< left bump */ 416 RGFW_JS_L2 = 5, /*!< left trigger*/ 417 RGFW_JS_R1 = 6, /*!< right bumper */ 418 RGFW_JS_R2 = 7, /*!< right trigger */ 419 }; 420 #endif 421 422 /*! basic vector type, if there's not already a point/vector type of choice */ 423 #ifndef RGFW_point 424 typedef struct { i32 x, y; } RGFW_point; 425 #endif 426 427 /*! basic rect type, if there's not already a rect type of choice */ 428 #ifndef RGFW_rect 429 typedef struct { i32 x, y, w, h; } RGFW_rect; 430 #endif 431 432 /*! basic area type, if there's not already a area type of choice */ 433 #ifndef RGFW_area 434 typedef struct { u32 w, h; } RGFW_area; 435 #endif 436 437 #ifndef __cplusplus 438 #define RGFW_POINT(x, y) (RGFW_point){(i32)(x), (i32)(y)} 439 #define RGFW_RECT(x, y, w, h) (RGFW_rect){(i32)(x), (i32)(y), (i32)(w), (i32)(h)} 440 #define RGFW_AREA(w, h) (RGFW_area){(u32)(w), (u32)(h)} 441 #else 442 #define RGFW_POINT(x, y) {(i32)(x), (i32)(y)} 443 #define RGFW_RECT(x, y, w, h) {(i32)(x), (i32)(y), (i32)(w), (i32)(h)} 444 #define RGFW_AREA(w, h) {(u32)(w), (u32)(h)} 445 #endif 446 447 #ifndef RGFW_NO_MONITOR 448 /*! structure for monitor data */ 449 typedef struct RGFW_monitor { 450 char name[128]; /*!< monitor name */ 451 RGFW_rect rect; /*!< monitor Workarea */ 452 float scaleX, scaleY; /*!< monitor content scale*/ 453 float physW, physH; /*!< monitor physical size */ 454 } RGFW_monitor; 455 456 /* 457 NOTE : Monitor functions should be ran only as many times as needed (not in a loop) 458 */ 459 460 /*! get an array of all the monitors (max 6) */ 461 RGFWDEF RGFW_monitor* RGFW_getMonitors(void); 462 /*! get the primary monitor */ 463 RGFWDEF RGFW_monitor RGFW_getPrimaryMonitor(void); 464 #endif 465 466 /* NOTE: some parts of the data can represent different things based on the event (read comments in RGFW_Event struct) */ 467 /*! Event structure for checking/getting events */ 468 typedef struct RGFW_Event { 469 char keyName[16]; /*!< key name of event*/ 470 471 /*! drag and drop data */ 472 /* 260 max paths with a max length of 260 */ 473 #ifdef RGFW_ALLOC_DROPFILES 474 char** droppedFiles; 475 #else 476 char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH]; /*!< dropped files*/ 477 #endif 478 u32 droppedFilesCount; /*!< house many files were dropped */ 479 480 u32 type; /*!< which event has been sent?*/ 481 RGFW_point point; /*!< mouse x, y of event (or drop point) */ 482 483 u8 keyCode; /*!< keycode of event !!Keycodes defined at the bottom of the RGFW_HEADER part of this file!! */ 484 485 b8 repeat; /*!< key press event repeated (the key is being held) */ 486 b8 inFocus; /*!< if the window is in focus or not (this is always true for MacOS windows due to the api being weird) */ 487 488 u8 lockState; 489 490 u8 button; /* !< which mouse button was pressed */ 491 double scroll; /*!< the raw mouse scroll value */ 492 493 u16 joystick; /*! which joystick this event applies to (if applicable to any) */ 494 u8 axisesCount; /*!< number of axises */ 495 RGFW_point axis[2]; /*!< x, y of axises (-100 to 100) */ 496 497 u64 frameTime, frameTime2; /*!< this is used for counting the fps */ 498 } RGFW_Event; 499 500 /*! source data for the window (used by the APIs) */ 501 typedef struct RGFW_window_src { 502 #ifdef RGFW_WINDOWS 503 HWND window; /*!< source window */ 504 HDC hdc; /*!< source HDC */ 505 u32 hOffset; /*!< height offset for window */ 506 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) 507 HGLRC ctx; /*!< source graphics context */ 508 #elif defined(RGFW_OSMESA) 509 OSMesaContext ctx; 510 #elif defined(RGFW_DIRECTX) 511 IDXGISwapChain* swapchain; 512 ID3D11RenderTargetView* renderTargetView; 513 ID3D11DepthStencilView* pDepthStencilView; 514 #elif defined(RGFW_EGL) 515 EGLSurface EGL_surface; 516 EGLDisplay EGL_display; 517 EGLContext EGL_context; 518 #endif 519 520 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 521 HDC hdcMem; 522 HBITMAP bitmap; 523 #endif 524 RGFW_area maxSize, minSize; /*!< for setting max/min resize (RGFW_WINDOWS) */ 525 #elif defined(RGFW_X11) 526 Display* display; /*!< source display */ 527 Window window; /*!< source window */ 528 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) 529 GLXContext ctx; /*!< source graphics context */ 530 #elif defined(RGFW_OSMESA) 531 OSMesaContext ctx; 532 #elif defined(RGFW_EGL) 533 EGLSurface EGL_surface; 534 EGLDisplay EGL_display; 535 EGLContext EGL_context; 536 #endif 537 538 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 539 XImage* bitmap; 540 GC gc; 541 #endif 542 #elif defined(RGFW_WAYLAND) 543 struct wl_display* display; 544 struct wl_surface* surface; 545 struct wl_buffer* wl_buffer; 546 struct wl_keyboard* keyboard; 547 548 struct xdg_surface* xdg_surface; 549 struct xdg_toplevel* xdg_toplevel; 550 struct zxdg_toplevel_decoration_v1* decoration; 551 RGFW_Event events[20]; 552 i32 eventLen; 553 size_t eventIndex; 554 #if defined(RGFW_EGL) 555 struct wl_egl_window* window; 556 EGLSurface EGL_surface; 557 EGLDisplay EGL_display; 558 EGLContext EGL_context; 559 #elif defined(RGFW_OSMESA) 560 OSMesaContext ctx; 561 #endif 562 #elif defined(RGFW_MACOS) 563 u32 display; 564 void* displayLink; 565 void* window; 566 b8 dndPassed; 567 #if (defined(RGFW_OPENGL)) && !defined(RGFW_OSMESA) && !defined(RGFW_EGL) 568 void* ctx; /*!< source graphics context */ 569 #elif defined(RGFW_OSMESA) 570 OSMesaContext ctx; 571 #elif defined(RGFW_EGL) 572 EGLSurface EGL_surface; 573 EGLDisplay EGL_display; 574 EGLContext EGL_context; 575 #endif 576 577 void* view; /*apple viewpoint thingy*/ 578 579 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 580 void* bitmap; /*!< API's bitmap for storing or managing */ 581 void* image; 582 #endif 583 #elif defined(RGFW_WEBASM) 584 #ifdef RGFW_WEBGPU 585 WGPUInstance ctx; 586 WGPUDevice device; 587 WGPUQueue queue; 588 #else 589 EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx; 590 #endif 591 #endif 592 } RGFW_window_src; 593 594 595 596 typedef struct RGFW_window { 597 RGFW_window_src src; /*!< src window data */ 598 599 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 600 u8* buffer; /*!< buffer for non-GPU systems (OSMesa, basic software rendering) */ 601 /* when rendering using RGFW_BUFFER, the buffer is in the RGBA format */ 602 #endif 603 void* userPtr; /* ptr for usr data */ 604 605 RGFW_Event event; /*!< current event */ 606 607 RGFW_rect r; /*!< the x, y, w and h of the struct */ 608 609 RGFW_point _lastMousePoint; /*!< last cusor point (for raw mouse data) */ 610 611 u32 _winArgs; /*!< windows args (for RGFW to check) */ 612 } RGFW_window; /*!< Window structure for managing the window */ 613 614 #if defined(RGFW_X11) || defined(RGFW_MACOS) 615 typedef u64 RGFW_thread; /*!< thread type unix */ 616 #else 617 typedef void* RGFW_thread; /*!< thread type for window */ 618 #endif 619 620 /** * @defgroup Window_management 621 * @{ */ 622 623 624 /*! 625 * the class name for X11 and WinAPI. apps with the same class will be grouped by the WM 626 * by default the class name will == the root window's name 627 */ 628 RGFWDEF void RGFW_setClassName(char* name); 629 630 /*! this has to be set before createWindow is called, else the fulscreen size is used */ 631 RGFWDEF void RGFW_setBufferSize(RGFW_area size); /*!< the buffer cannot be resized (by RGFW) */ 632 633 RGFWDEF RGFW_window* RGFW_createWindow( 634 const char* name, /* name of the window */ 635 RGFW_rect rect, /* rect of window */ 636 u16 args /* extra arguments (NULL / (u16)0 means no args used)*/ 637 ); /*!< function to create a window struct */ 638 639 /*! get the size of the screen to an area struct */ 640 RGFWDEF RGFW_area RGFW_getScreenSize(void); 641 642 /*! 643 this function checks an *individual* event (and updates window structure attributes) 644 this means, using this function without a while loop may cause event lag 645 646 ex. 647 648 while (RGFW_window_checkEvent(win) != NULL) [this keeps checking events until it reaches the last one] 649 650 this function is optional if you choose to use event callbacks, 651 although you still need some way to tell RGFW to process events eg. `RGFW_window_checkEvents` 652 */ 653 654 RGFWDEF RGFW_Event* RGFW_window_checkEvent(RGFW_window* win); /*!< check current event (returns a pointer to win->event or NULL if there is no event)*/ 655 656 /*! 657 for RGFW_window_eventWait and RGFW_window_checkEvents 658 waitMS -> Allows th e function to keep checking for events even after `RGFW_window_checkEvent == NULL` 659 if waitMS == 0, the loop will not wait for events 660 if waitMS == a positive integer, the loop will wait that many miliseconds after there are no more events until it returns 661 if waitMS == a negative integer, the loop will not return until it gets another event 662 */ 663 typedef RGFW_ENUM(i32, RGFW_eventWait) { 664 RGFW_NEXT = -1, 665 RGFW_NO_WAIT = 0 666 }; 667 668 /*! sleep until RGFW gets an event or the timer ends (defined by OS) */ 669 RGFWDEF void RGFW_window_eventWait(RGFW_window* win, i32 waitMS); 670 671 /*! 672 check all the events until there are none left, 673 this should only be used if you're using callbacks only 674 */ 675 RGFWDEF void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS); 676 677 /*! 678 Tell RGFW_window_eventWait to stop waiting, to be ran from another thread 679 */ 680 RGFWDEF void RGFW_stopCheckEvents(void); 681 682 /*! window managment functions*/ 683 RGFWDEF void RGFW_window_close(RGFW_window* win); /*!< close the window and free leftover data */ 684 685 /*! moves window to a given point */ 686 RGFWDEF void RGFW_window_move(RGFW_window* win, 687 RGFW_point v/*!< new pos*/ 688 ); 689 690 #ifndef RGFW_NO_MONITOR 691 /*! move to a specific monitor */ 692 RGFWDEF void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m /* monitor */); 693 #endif 694 695 /*! resize window to a current size/area */ 696 RGFWDEF void RGFW_window_resize(RGFW_window* win, /*!< source window */ 697 RGFW_area a/*!< new size*/ 698 ); 699 700 /*! set the minimum size a user can shrink a window to a given size/area */ 701 RGFWDEF void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a); 702 /*! set the minimum size a user can extend a window to a given size/area */ 703 RGFWDEF void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a); 704 705 RGFWDEF void RGFW_window_maximize(RGFW_window* win); /*!< maximize the window size */ 706 RGFWDEF void RGFW_window_minimize(RGFW_window* win); /*!< minimize the window (in taskbar (per OS))*/ 707 RGFWDEF void RGFW_window_restore(RGFW_window* win); /*!< restore the window from minimized (per OS)*/ 708 709 /*! if the window should have a border or not (borderless) based on bool value of `border` */ 710 RGFWDEF void RGFW_window_setBorder(RGFW_window* win, b8 border); 711 712 /*! turn on / off dnd (RGFW_ALLOW_DND stil must be passed to the window)*/ 713 RGFWDEF void RGFW_window_setDND(RGFW_window* win, b8 allow); 714 715 #ifndef RGFW_NO_PASSTHROUGH 716 /*!! turn on / off mouse passthrough */ 717 RGFWDEF void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough); 718 #endif 719 720 /*! rename window to a given string */ 721 RGFWDEF void RGFW_window_setName(RGFW_window* win, 722 char* name 723 ); 724 725 RGFWDEF void RGFW_window_setIcon(RGFW_window* win, /*!< source window */ 726 u8* icon /*!< icon bitmap */, 727 RGFW_area a /*!< width and height of the bitmap*/, 728 i32 channels /*!< how many channels the bitmap has (rgb : 3, rgba : 4) */ 729 ); /*!< image resized by default */ 730 731 /*!< sets mouse to bitmap (very simular to RGFW_window_setIcon), image NOT resized by default*/ 732 RGFWDEF void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels); 733 734 /*!< sets the mouse to a standard API cursor (based on RGFW_MOUSE, as seen at the end of the RGFW_HEADER part of this file) */ 735 RGFWDEF void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse); 736 737 RGFWDEF void RGFW_window_setMouseDefault(RGFW_window* win); /*!< sets the mouse to the default mouse icon */ 738 /* 739 Locks cursor at the center of the window 740 win->event.point become raw mouse movement data 741 742 this is useful for a 3D camera 743 */ 744 RGFWDEF void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area); 745 /*! stop holding the mouse and let it move freely */ 746 RGFWDEF void RGFW_window_mouseUnhold(RGFW_window* win); 747 748 /*! hide the window */ 749 RGFWDEF void RGFW_window_hide(RGFW_window* win); 750 /*! show the window */ 751 RGFWDEF void RGFW_window_show(RGFW_window* win); 752 753 /* 754 makes it so `RGFW_window_shouldClose` returns true 755 by setting the window event.type to RGFW_quit 756 */ 757 RGFWDEF void RGFW_window_setShouldClose(RGFW_window* win); 758 759 /*! where the mouse is on the screen */ 760 RGFWDEF RGFW_point RGFW_getGlobalMousePoint(void); 761 762 /*! where the mouse is on the window */ 763 RGFWDEF RGFW_point RGFW_window_getMousePoint(RGFW_window* win); 764 765 /*! show the mouse or hide the mouse*/ 766 RGFWDEF void RGFW_window_showMouse(RGFW_window* win, i8 show); 767 /*! move the mouse to a set x, y pos*/ 768 RGFWDEF void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v); 769 770 /*! if the window should close (RGFW_close was sent or escape was pressed) */ 771 RGFWDEF b8 RGFW_window_shouldClose(RGFW_window* win); 772 /*! if window is fullscreen'd */ 773 RGFWDEF b8 RGFW_window_isFullscreen(RGFW_window* win); 774 /*! if window is hidden */ 775 RGFWDEF b8 RGFW_window_isHidden(RGFW_window* win); 776 /*! if window is minimized */ 777 RGFWDEF b8 RGFW_window_isMinimized(RGFW_window* win); 778 /*! if window is maximized */ 779 RGFWDEF b8 RGFW_window_isMaximized(RGFW_window* win); 780 781 /** @} */ 782 783 /** * @defgroup Monitor 784 * @{ */ 785 786 #ifndef RGFW_NO_MONITOR 787 /* 788 scale the window to the monitor, 789 this is run by default if the user uses the arg `RGFW_SCALE_TO_MONITOR` during window creation 790 */ 791 RGFWDEF void RGFW_window_scaleToMonitor(RGFW_window* win); 792 /*! get the struct of the window's monitor */ 793 RGFWDEF RGFW_monitor RGFW_window_getMonitor(RGFW_window* win); 794 #endif 795 796 /** @} */ 797 798 /** * @defgroup Input 799 * @{ */ 800 801 /*error handling*/ 802 RGFWDEF b8 RGFW_Error(void); /*!< returns true if an error has occurred (doesn't print errors itself) */ 803 804 /*! returns true if the key should be shifted */ 805 RGFWDEF b8 RGFW_shouldShift(u32 keycode, u8 lockState); 806 807 /*! get char from RGFW keycode (using a LUT), uses shift'd version if shift = true */ 808 RGFWDEF char RGFW_keyCodeToChar(u32 keycode, b8 shift); 809 /*! get char from RGFW keycode (using a LUT), uses lockState for shouldShift) */ 810 RGFWDEF char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState); 811 812 /*! if window == NULL, it checks if the key is pressed globally. Otherwise, it checks only if the key is pressed while the window in focus.*/ 813 RGFWDEF b8 RGFW_isPressed(RGFW_window* win, u8 key); /*!< if key is pressed (key code)*/ 814 815 RGFWDEF b8 RGFW_wasPressed(RGFW_window* win, u8 key); /*!< if key was pressed (checks previous state only) (key code)*/ 816 817 RGFWDEF b8 RGFW_isHeld(RGFW_window* win, u8 key); /*!< if key is held (key code)*/ 818 RGFWDEF b8 RGFW_isReleased(RGFW_window* win, u8 key); /*!< if key is released (key code)*/ 819 820 /* if a key is pressed and then released, pretty much the same as RGFW_isReleased */ 821 RGFWDEF b8 RGFW_isClicked(RGFW_window* win, u8 key /*!< key code*/); 822 823 /*! if a mouse button is pressed */ 824 RGFWDEF b8 RGFW_isMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ ); 825 /*! if a mouse button is held */ 826 RGFWDEF b8 RGFW_isMouseHeld(RGFW_window* win, u8 button /*!< mouse button code */ ); 827 /*! if a mouse button was released */ 828 RGFWDEF b8 RGFW_isMouseReleased(RGFW_window* win, u8 button /*!< mouse button code */ ); 829 /*! if a mouse button was pressed (checks previous state only) */ 830 RGFWDEF b8 RGFW_wasMousePressed(RGFW_window* win, u8 button /*!< mouse button code */ ); 831 /** @} */ 832 833 /** * @defgroup Clipboard 834 * @{ */ 835 RGFWDEF char* RGFW_readClipboard(size_t* size); /*!< read clipboard data */ 836 RGFWDEF void RGFW_clipboardFree(char* str); /*!< the string returned from RGFW_readClipboard must be freed */ 837 838 RGFWDEF void RGFW_writeClipboard(const char* text, u32 textLen); /*!< write text to the clipboard */ 839 /** @} */ 840 841 /** 842 843 844 Event callbacks, 845 these are completely optional, you can use the normal 846 RGFW_checkEvent() method if you prefer that 847 848 * @defgroup Callbacks 849 * @{ 850 */ 851 852 /*! RGFW_windowMoved, the window and its new rect value */ 853 typedef void (* RGFW_windowmovefunc)(RGFW_window* win, RGFW_rect r); 854 /*! RGFW_windowResized, the window and its new rect value */ 855 typedef void (* RGFW_windowresizefunc)(RGFW_window* win, RGFW_rect r); 856 /*! RGFW_quit, the window that was closed */ 857 typedef void (* RGFW_windowquitfunc)(RGFW_window* win); 858 /*! RGFW_focusIn / RGFW_focusOut, the window who's focus has changed and if its inFocus */ 859 typedef void (* RGFW_focusfunc)(RGFW_window* win, b8 inFocus); 860 /*! RGFW_mouseEnter / RGFW_mouseLeave, the window that changed, the point of the mouse (enter only) and if the mouse has entered */ 861 typedef void (* RGFW_mouseNotifyfunc)(RGFW_window* win, RGFW_point point, b8 status); 862 /*! RGFW_mousePosChanged, the window that the move happened on and the new point of the mouse */ 863 typedef void (* RGFW_mouseposfunc)(RGFW_window* win, RGFW_point point); 864 /*! RGFW_dnd_init, the window, the point of the drop on the windows */ 865 typedef void (* RGFW_dndInitfunc)(RGFW_window* win, RGFW_point point); 866 /*! RGFW_windowRefresh, the window that needs to be refreshed */ 867 typedef void (* RGFW_windowrefreshfunc)(RGFW_window* win); 868 /*! RGFW_keyPressed / RGFW_keyReleased, the window that got the event, the keycode, the string version, the state of mod keys, if it was a press (else it's a release) */ 869 typedef void (* RGFW_keyfunc)(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed); 870 /*! RGFW_mouseButtonPressed / RGFW_mouseButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ 871 typedef void (* RGFW_mousebuttonfunc)(RGFW_window* win, u8 button, double scroll, b8 pressed); 872 /*! RGFW_jsButtonPressed / RGFW_jsButtonReleased, the window that got the event, the button that was pressed, the scroll value, if it was a press (else it's a release) */ 873 typedef void (* RGFW_jsButtonfunc)(RGFW_window* win, u16 joystick, u8 button, b8 pressed); 874 /*! RGFW_jsAxisMove, the window that got the event, the joystick in question, the axis values and the amount of axises */ 875 typedef void (* RGFW_jsAxisfunc)(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount); 876 877 878 /*! RGFW_dnd, the window that had the drop, the drop data and the amount files dropped returns previous callback function (if it was set) */ 879 #ifdef RGFW_ALLOC_DROPFILES 880 typedef void (* RGFW_dndfunc)(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount); 881 #else 882 typedef void (* RGFW_dndfunc)(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount); 883 #endif 884 /*! set callback for a window move event returns previous callback function (if it was set) */ 885 RGFWDEF RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func); 886 /*! set callback for a window resize event returns previous callback function (if it was set) */ 887 RGFWDEF RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func); 888 /*! set callback for a window quit event returns previous callback function (if it was set) */ 889 RGFWDEF RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func); 890 /*! set callback for a mouse move event returns previous callback function (if it was set) */ 891 RGFWDEF RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func); 892 /*! set callback for a window refresh event returns previous callback function (if it was set) */ 893 RGFWDEF RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func); 894 /*! set callback for a window focus change event returns previous callback function (if it was set) */ 895 RGFWDEF RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func); 896 /*! set callback for a mouse notify event returns previous callback function (if it was set) */ 897 RGFWDEF RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func); 898 /*! set callback for a drop event event returns previous callback function (if it was set) */ 899 RGFWDEF RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func); 900 /*! set callback for a start of a drop event returns previous callback function (if it was set) */ 901 RGFWDEF RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func); 902 /*! set callback for a key (press / release ) event returns previous callback function (if it was set) */ 903 RGFWDEF RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func); 904 /*! set callback for a mouse button (press / release ) event returns previous callback function (if it was set) */ 905 RGFWDEF RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func); 906 /*! set callback for a controller button (press / release ) event returns previous callback function (if it was set) */ 907 RGFWDEF RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func); 908 /*! set callback for a joystick axis mov event returns previous callback function (if it was set) */ 909 RGFWDEF RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func); 910 911 /** @} */ 912 913 /** * @defgroup Threads 914 * @{ */ 915 916 #ifndef RGFW_NO_THREADS 917 /*! threading functions*/ 918 919 /*! NOTE! (for X11/linux) : if you define a window in a thread, it must be run after the original thread's window is created or else there will be a memory error */ 920 /* 921 I'd suggest you use sili's threading functions instead 922 if you're going to use sili 923 which is a good idea generally 924 */ 925 926 #if defined(__unix__) || defined(__APPLE__) || defined(RGFW_WEBASM) 927 typedef void* (* RGFW_threadFunc_ptr)(void*); 928 #else 929 typedef DWORD (__stdcall *RGFW_threadFunc_ptr) (LPVOID lpThreadParameter); 930 #endif 931 932 RGFWDEF RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args); /*!< create a thread*/ 933 RGFWDEF void RGFW_cancelThread(RGFW_thread thread); /*!< cancels a thread*/ 934 RGFWDEF void RGFW_joinThread(RGFW_thread thread); /*!< join thread to current thread */ 935 RGFWDEF void RGFW_setThreadPriority(RGFW_thread thread, u8 priority); /*!< sets the priority priority */ 936 #endif 937 938 /** @} */ 939 940 /** * @defgroup joystick 941 * @{ */ 942 943 /*! joystick count starts at 0*/ 944 /*!< register joystick to window based on a number (the number is based on when it was connected eg. /dev/js0)*/ 945 RGFWDEF u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber); 946 RGFWDEF u16 RGFW_registerJoystickF(RGFW_window* win, char* file); 947 948 RGFWDEF u32 RGFW_isPressedJS(RGFW_window* win, u16 controller, u8 button); 949 950 /** @} */ 951 952 /** * @defgroup graphics_API 953 * @{ */ 954 955 /*!< make the window the current opengl drawing context 956 957 NOTE: 958 if you want to switch the graphics context's thread, 959 you have to run RGFW_window_makeCurrent(NULL); on the old thread 960 then RGFW_window_makeCurrent(valid_window) on the new thread 961 */ 962 RGFWDEF void RGFW_window_makeCurrent(RGFW_window* win); 963 964 /*< updates fps / sets fps to cap (must by ran manually by the user at the end of a frame), returns current fps */ 965 RGFWDEF u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap); 966 967 /* supports openGL, directX, OSMesa, EGL and software rendering */ 968 RGFWDEF void RGFW_window_swapBuffers(RGFW_window* win); /*!< swap the rendering buffer */ 969 RGFWDEF void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval); 970 971 RGFWDEF void RGFW_window_setGPURender(RGFW_window* win, i8 set); 972 RGFWDEF void RGFW_window_setCPURender(RGFW_window* win, i8 set); 973 974 /*! native API functions */ 975 #if defined(RGFW_OPENGL) || defined(RGFW_EGL) 976 /*! OpenGL init hints */ 977 RGFWDEF void RGFW_setGLStencil(i32 stencil); /*!< set stencil buffer bit size (8 by default) */ 978 RGFWDEF void RGFW_setGLSamples(i32 samples); /*!< set number of sampiling buffers (4 by default) */ 979 RGFWDEF void RGFW_setGLStereo(i32 stereo); /*!< use GL_STEREO (GL_FALSE by default) */ 980 RGFWDEF void RGFW_setGLAuxBuffers(i32 auxBuffers); /*!< number of aux buffers (0 by default) */ 981 982 /*! which profile to use for the opengl verion */ 983 typedef RGFW_ENUM(u8, RGFW_GL_profile) { RGFW_GL_CORE = 0, RGFW_GL_COMPATIBILITY }; 984 /*! Set OpenGL version hint (core or compatibility profile)*/ 985 RGFWDEF void RGFW_setGLVersion(RGFW_GL_profile profile, i32 major, i32 minor); 986 RGFWDEF void RGFW_setDoubleBuffer(b8 useDoubleBuffer); 987 RGFWDEF void* RGFW_getProcAddress(const char* procname); /*!< get native opengl proc address */ 988 RGFWDEF void RGFW_window_makeCurrent_OpenGL(RGFW_window* win); /*!< to be called by RGFW_window_makeCurrent */ 989 #elif defined(RGFW_DIRECTX) 990 typedef struct { 991 IDXGIFactory* pFactory; 992 IDXGIAdapter* pAdapter; 993 ID3D11Device* pDevice; 994 ID3D11DeviceContext* pDeviceContext; 995 } RGFW_directXinfo; 996 997 /* 998 RGFW stores a global instance of RGFW_directXinfo, 999 you can use this function to get a pointer the instance 1000 */ 1001 RGFWDEF RGFW_directXinfo* RGFW_getDirectXInfo(void); 1002 #endif 1003 1004 /** @} */ 1005 1006 /** * @defgroup Supporting 1007 * @{ */ 1008 RGFWDEF u64 RGFW_getTime(void); /*!< get time in seconds */ 1009 RGFWDEF u64 RGFW_getTimeNS(void); /*!< get time in nanoseconds */ 1010 RGFWDEF void RGFW_sleep(u64 milisecond); /*!< sleep for a set time */ 1011 1012 /*! 1013 key codes and mouse icon enums 1014 */ 1015 1016 typedef RGFW_ENUM(u8, RGFW_Key) { 1017 RGFW_KEY_NULL = 0, 1018 RGFW_Escape, 1019 RGFW_F1, 1020 RGFW_F2, 1021 RGFW_F3, 1022 RGFW_F4, 1023 RGFW_F5, 1024 RGFW_F6, 1025 RGFW_F7, 1026 RGFW_F8, 1027 RGFW_F9, 1028 RGFW_F10, 1029 RGFW_F11, 1030 RGFW_F12, 1031 1032 RGFW_Backtick, 1033 1034 RGFW_0, 1035 RGFW_1, 1036 RGFW_2, 1037 RGFW_3, 1038 RGFW_4, 1039 RGFW_5, 1040 RGFW_6, 1041 RGFW_7, 1042 RGFW_8, 1043 RGFW_9, 1044 1045 RGFW_Minus, 1046 RGFW_Equals, 1047 RGFW_BackSpace, 1048 RGFW_Tab, 1049 RGFW_CapsLock, 1050 RGFW_ShiftL, 1051 RGFW_ControlL, 1052 RGFW_AltL, 1053 RGFW_SuperL, 1054 RGFW_ShiftR, 1055 RGFW_ControlR, 1056 RGFW_AltR, 1057 RGFW_SuperR, 1058 RGFW_Space, 1059 1060 RGFW_a, 1061 RGFW_b, 1062 RGFW_c, 1063 RGFW_d, 1064 RGFW_e, 1065 RGFW_f, 1066 RGFW_g, 1067 RGFW_h, 1068 RGFW_i, 1069 RGFW_j, 1070 RGFW_k, 1071 RGFW_l, 1072 RGFW_m, 1073 RGFW_n, 1074 RGFW_o, 1075 RGFW_p, 1076 RGFW_q, 1077 RGFW_r, 1078 RGFW_s, 1079 RGFW_t, 1080 RGFW_u, 1081 RGFW_v, 1082 RGFW_w, 1083 RGFW_x, 1084 RGFW_y, 1085 RGFW_z, 1086 1087 RGFW_Period, 1088 RGFW_Comma, 1089 RGFW_Slash, 1090 RGFW_Bracket, 1091 RGFW_CloseBracket, 1092 RGFW_Semicolon, 1093 RGFW_Return, 1094 RGFW_Quote, 1095 RGFW_BackSlash, 1096 1097 RGFW_Up, 1098 RGFW_Down, 1099 RGFW_Left, 1100 RGFW_Right, 1101 1102 RGFW_Delete, 1103 RGFW_Insert, 1104 RGFW_End, 1105 RGFW_Home, 1106 RGFW_PageUp, 1107 RGFW_PageDown, 1108 1109 RGFW_Numlock, 1110 RGFW_KP_Slash, 1111 RGFW_Multiply, 1112 RGFW_KP_Minus, 1113 RGFW_KP_1, 1114 RGFW_KP_2, 1115 RGFW_KP_3, 1116 RGFW_KP_4, 1117 RGFW_KP_5, 1118 RGFW_KP_6, 1119 RGFW_KP_7, 1120 RGFW_KP_8, 1121 RGFW_KP_9, 1122 RGFW_KP_0, 1123 RGFW_KP_Period, 1124 RGFW_KP_Return, 1125 1126 final_key, 1127 }; 1128 1129 1130 typedef RGFW_ENUM(u8, RGFW_mouseIcons) { 1131 RGFW_MOUSE_NORMAL = 0, 1132 RGFW_MOUSE_ARROW, 1133 RGFW_MOUSE_IBEAM, 1134 RGFW_MOUSE_CROSSHAIR, 1135 RGFW_MOUSE_POINTING_HAND, 1136 RGFW_MOUSE_RESIZE_EW, 1137 RGFW_MOUSE_RESIZE_NS, 1138 RGFW_MOUSE_RESIZE_NWSE, 1139 RGFW_MOUSE_RESIZE_NESW, 1140 RGFW_MOUSE_RESIZE_ALL, 1141 RGFW_MOUSE_NOT_ALLOWED, 1142 }; 1143 1144 /** @} */ 1145 1146 #endif /* RGFW_HEADER */ 1147 1148 /* 1149 Example to get you started : 1150 1151 linux : gcc main.c -lX11 -lXcursor -lGL 1152 windows : gcc main.c -lopengl32 -lshell32 -lgdi32 1153 macos : gcc main.c -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo 1154 1155 #define RGFW_IMPLEMENTATION 1156 #include "RGFW.h" 1157 1158 u8 icon[4 * 3 * 3] = {0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF}; 1159 1160 int main() { 1161 RGFW_window* win = RGFW_createWindow("name", RGFW_RECT(500, 500, 500, 500), (u64)0); 1162 1163 RGFW_window_setIcon(win, icon, RGFW_AREA(3, 3), 4); 1164 1165 for (;;) { 1166 RGFW_window_checkEvent(win); // NOTE: checking events outside of a while loop may cause input lag 1167 if (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape)) 1168 break; 1169 1170 RGFW_window_swapBuffers(win); 1171 1172 glClearColor(0xFF, 0XFF, 0xFF, 0xFF); 1173 glClear(GL_COLOR_BUFFER_BIT); 1174 } 1175 1176 RGFW_window_close(win); 1177 } 1178 1179 compiling : 1180 1181 if you wish to compile the library all you have to do is create a new file with this in it 1182 1183 rgfw.c 1184 #define RGFW_IMPLEMENTATION 1185 #include "RGFW.h" 1186 1187 then you can use gcc (or whatever compile you wish to use) to compile the library into object file 1188 1189 ex. gcc -c RGFW.c -fPIC 1190 1191 after you compile the library into an object file, you can also turn the object file into an static or shared library 1192 1193 (commands ar and gcc can be replaced with whatever equivalent your system uses) 1194 static : ar rcs RGFW.a RGFW.o 1195 shared : 1196 windows: 1197 gcc -shared RGFW.o -lwinmm -lopengl32 -lshell32 -lgdi32 -o RGFW.dll 1198 linux: 1199 gcc -shared RGFW.o -lX11 -lXcursor -lGL -lXrandr -o RGFW.so 1200 macos: 1201 gcc -shared RGFW.o -framework Foundation -framework AppKit -framework OpenGL -framework CoreVideo 1202 */ 1203 1204 #ifdef RGFW_X11 1205 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) l 1206 #elif defined(RGFW_WINDOWS) 1207 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) w 1208 #elif defined(RGFW_MACOS) 1209 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) m 1210 #elif defined(RGFW_WEBASM) 1211 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) h 1212 #elif defined(RGFW_WAYLAND) 1213 #define RGFW_OS_BASED_VALUE(l, w, m, h, ww) ww 1214 #endif 1215 1216 1217 #ifdef RGFW_IMPLEMENTATION 1218 1219 #include <stdio.h> 1220 #include <string.h> 1221 #include <math.h> 1222 #include <assert.h> 1223 1224 /* 1225 RGFW_IMPLEMENTATION starts with generic RGFW defines 1226 1227 This is the start of keycode data 1228 1229 Why not use macros instead of the numbers itself? 1230 Windows -> Not all virtual keys are macros (VK_0 - VK_1, VK_a - VK_z) 1231 Linux -> Only symcodes are values, (XK_0 - XK_1, XK_a - XK_z) are larger than 0xFF00, I can't find any way to work with them without making the array an unreasonable size 1232 MacOS -> windows and linux already don't have keycodes as macros, so there's no point 1233 */ 1234 1235 1236 1237 /* 1238 the c++ compiler doesn't support setting up an array like, 1239 we'll have to do it during runtime using a function & this messy setup 1240 */ 1241 #ifndef __cplusplus 1242 #define RGFW_NEXT , 1243 #define RGFW_MAP 1244 #else 1245 #define RGFW_NEXT ; 1246 #define RGFW_MAP RGFW_keycodes 1247 #endif 1248 1249 #ifdef RGFW_WAYLAND 1250 #include <linux/input-event-codes.h> 1251 #endif 1252 1253 u8 RGFW_keycodes [RGFW_OS_BASED_VALUE(136, 337, 128, DOM_VK_WIN_OEM_CLEAR + 1, 130)] = { 1254 #ifdef __cplusplus 1255 0 1256 }; 1257 void RGFW_init_keys(void) { 1258 #endif 1259 RGFW_MAP [RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE)] = RGFW_Backtick RGFW_NEXT 1260 1261 RGFW_MAP [RGFW_OS_BASED_VALUE(19, 0x30, 29, DOM_VK_0, KEY_0)] = RGFW_0 RGFW_NEXT 1262 RGFW_MAP [RGFW_OS_BASED_VALUE(10, 0x31, 18, DOM_VK_1, KEY_1)] = RGFW_1 RGFW_NEXT 1263 RGFW_MAP [RGFW_OS_BASED_VALUE(11, 0x32, 19, DOM_VK_2, KEY_2)] = RGFW_2 RGFW_NEXT 1264 RGFW_MAP [RGFW_OS_BASED_VALUE(12, 0x33, 20, DOM_VK_3, KEY_3)] = RGFW_3 RGFW_NEXT 1265 RGFW_MAP [RGFW_OS_BASED_VALUE(13, 0x34, 21, DOM_VK_4, KEY_4)] = RGFW_4 RGFW_NEXT 1266 RGFW_MAP [RGFW_OS_BASED_VALUE(14, 0x35, 23, DOM_VK_5, KEY_5)] = RGFW_5 RGFW_NEXT 1267 RGFW_MAP [RGFW_OS_BASED_VALUE(15, 0x36, 22, DOM_VK_6, KEY_6)] = RGFW_6 RGFW_NEXT 1268 RGFW_MAP [RGFW_OS_BASED_VALUE(16, 0x37, 26, DOM_VK_7, KEY_7)] = RGFW_7 RGFW_NEXT 1269 RGFW_MAP [RGFW_OS_BASED_VALUE(17, 0x38, 28, DOM_VK_8, KEY_8)] = RGFW_8 RGFW_NEXT 1270 RGFW_MAP [RGFW_OS_BASED_VALUE(18, 0x39, 25, DOM_VK_9, KEY_9)] = RGFW_9, 1271 1272 RGFW_MAP [RGFW_OS_BASED_VALUE(65, 0x20, 49, DOM_VK_SPACE, KEY_SPACE)] = RGFW_Space, 1273 1274 RGFW_MAP [RGFW_OS_BASED_VALUE(38, 0x41, 0, DOM_VK_A, KEY_A)] = RGFW_a RGFW_NEXT 1275 RGFW_MAP [RGFW_OS_BASED_VALUE(56, 0x42, 11, DOM_VK_B, KEY_B)] = RGFW_b RGFW_NEXT 1276 RGFW_MAP [RGFW_OS_BASED_VALUE(54, 0x43, 8, DOM_VK_C, KEY_C)] = RGFW_c RGFW_NEXT 1277 RGFW_MAP [RGFW_OS_BASED_VALUE(40, 0x44, 2, DOM_VK_D, KEY_D)] = RGFW_d RGFW_NEXT 1278 RGFW_MAP [RGFW_OS_BASED_VALUE(26, 0x45, 14, DOM_VK_E, KEY_E)] = RGFW_e RGFW_NEXT 1279 RGFW_MAP [RGFW_OS_BASED_VALUE(41, 0x46, 3, DOM_VK_F, KEY_F)] = RGFW_f RGFW_NEXT 1280 RGFW_MAP [RGFW_OS_BASED_VALUE(42, 0x47, 5, DOM_VK_G, KEY_G)] = RGFW_g RGFW_NEXT 1281 RGFW_MAP [RGFW_OS_BASED_VALUE(43, 0x48, 4, DOM_VK_H, KEY_H)] = RGFW_h RGFW_NEXT 1282 RGFW_MAP [RGFW_OS_BASED_VALUE(31, 0x49, 34, DOM_VK_I, KEY_I)] = RGFW_i RGFW_NEXT 1283 RGFW_MAP [RGFW_OS_BASED_VALUE(44, 0x4A, 38, DOM_VK_J, KEY_J)] = RGFW_j RGFW_NEXT 1284 RGFW_MAP [RGFW_OS_BASED_VALUE(45, 0x4B, 40, DOM_VK_K, KEY_K)] = RGFW_k RGFW_NEXT 1285 RGFW_MAP [RGFW_OS_BASED_VALUE(46, 0x4C, 37, DOM_VK_L, KEY_L)] = RGFW_l RGFW_NEXT 1286 RGFW_MAP [RGFW_OS_BASED_VALUE(58, 0x4D, 46, DOM_VK_M, KEY_M)] = RGFW_m RGFW_NEXT 1287 RGFW_MAP [RGFW_OS_BASED_VALUE(57, 0x4E, 45, DOM_VK_N, KEY_N)] = RGFW_n RGFW_NEXT 1288 RGFW_MAP [RGFW_OS_BASED_VALUE(32, 0x4F, 31, DOM_VK_O, KEY_O)] = RGFW_o RGFW_NEXT 1289 RGFW_MAP [RGFW_OS_BASED_VALUE(33, 0x50, 35, DOM_VK_P, KEY_P)] = RGFW_p RGFW_NEXT 1290 RGFW_MAP [RGFW_OS_BASED_VALUE(24, 0x51, 12, DOM_VK_Q, KEY_Q)] = RGFW_q RGFW_NEXT 1291 RGFW_MAP [RGFW_OS_BASED_VALUE(27, 0x52, 15, DOM_VK_R, KEY_R)] = RGFW_r RGFW_NEXT 1292 RGFW_MAP [RGFW_OS_BASED_VALUE(39, 0x53, 1, DOM_VK_S, KEY_S)] = RGFW_s RGFW_NEXT 1293 RGFW_MAP [RGFW_OS_BASED_VALUE(28, 0x54, 17, DOM_VK_T, KEY_T)] = RGFW_t RGFW_NEXT 1294 RGFW_MAP [RGFW_OS_BASED_VALUE(30, 0x55, 32, DOM_VK_U, KEY_U)] = RGFW_u RGFW_NEXT 1295 RGFW_MAP [RGFW_OS_BASED_VALUE(55, 0x56, 9, DOM_VK_V, KEY_V)] = RGFW_v RGFW_NEXT 1296 RGFW_MAP [RGFW_OS_BASED_VALUE(25, 0x57, 13, DOM_VK_W, KEY_W)] = RGFW_w RGFW_NEXT 1297 RGFW_MAP [RGFW_OS_BASED_VALUE(53, 0x58, 7, DOM_VK_X, KEY_X)] = RGFW_x RGFW_NEXT 1298 RGFW_MAP [RGFW_OS_BASED_VALUE(29, 0x59, 16, DOM_VK_Y, KEY_Y)] = RGFW_y RGFW_NEXT 1299 RGFW_MAP [RGFW_OS_BASED_VALUE(52, 0x5A, 6, DOM_VK_Z, KEY_Z)] = RGFW_z, 1300 1301 RGFW_MAP [RGFW_OS_BASED_VALUE(60, 190, 47, DOM_VK_PERIOD, KEY_DOT)] = RGFW_Period RGFW_NEXT 1302 RGFW_MAP [RGFW_OS_BASED_VALUE(59, 188, 43, DOM_VK_COMMA, KEY_COMMA)] = RGFW_Comma RGFW_NEXT 1303 RGFW_MAP [RGFW_OS_BASED_VALUE(61, 191, 44, DOM_VK_SLASH, KEY_SLASH)] = RGFW_Slash RGFW_NEXT 1304 RGFW_MAP [RGFW_OS_BASED_VALUE(34, 219, 33, DOM_VK_OPEN_BRACKET, KEY_LEFTBRACE)] = RGFW_Bracket RGFW_NEXT 1305 RGFW_MAP [RGFW_OS_BASED_VALUE(35, 221, 30, DOM_VK_CLOSE_BRACKET, KEY_RIGHTBRACE)] = RGFW_CloseBracket RGFW_NEXT 1306 RGFW_MAP [RGFW_OS_BASED_VALUE(47, 186, 41, DOM_VK_SEMICOLON, KEY_SEMICOLON)] = RGFW_Semicolon RGFW_NEXT 1307 RGFW_MAP [RGFW_OS_BASED_VALUE(48, 222, 39, DOM_VK_QUOTE, KEY_APOSTROPHE)] = RGFW_Quote RGFW_NEXT 1308 RGFW_MAP [RGFW_OS_BASED_VALUE(51, 322, 42, DOM_VK_BACK_SLASH, KEY_BACKSLASH)] = RGFW_BackSlash, 1309 1310 RGFW_MAP [RGFW_OS_BASED_VALUE(36, 0x0D, 36, DOM_VK_RETURN, KEY_ENTER)] = RGFW_Return RGFW_NEXT 1311 RGFW_MAP [RGFW_OS_BASED_VALUE(119, 0x2E, 118, DOM_VK_DELETE, KEY_DELETE)] = RGFW_Delete RGFW_NEXT 1312 RGFW_MAP [RGFW_OS_BASED_VALUE(77, 0x90, 72, DOM_VK_NUM_LOCK, KEY_NUMLOCK)] = RGFW_Numlock RGFW_NEXT 1313 RGFW_MAP [RGFW_OS_BASED_VALUE(106, 0x6F, 82, DOM_VK_DIVIDE, KEY_KPSLASH)] = RGFW_KP_Slash RGFW_NEXT 1314 RGFW_MAP [RGFW_OS_BASED_VALUE(63, 0x6A, 76, DOM_VK_MULTIPLY, KEY_KPASTERISK)] = RGFW_Multiply RGFW_NEXT 1315 RGFW_MAP [RGFW_OS_BASED_VALUE(82, 0x6D, 67, DOM_VK_SUBTRACT, KEY_KPMINUS)] = RGFW_KP_Minus RGFW_NEXT 1316 RGFW_MAP [RGFW_OS_BASED_VALUE(87, 0x61, 84, DOM_VK_NUMPAD1, KEY_KP1)] = RGFW_KP_1 RGFW_NEXT 1317 RGFW_MAP [RGFW_OS_BASED_VALUE(88, 0x62, 85, DOM_VK_NUMPAD2, KEY_KP2)] = RGFW_KP_2 RGFW_NEXT 1318 RGFW_MAP [RGFW_OS_BASED_VALUE(89, 0x63, 86, DOM_VK_NUMPAD3, KEY_KP3)] = RGFW_KP_3 RGFW_NEXT 1319 RGFW_MAP [RGFW_OS_BASED_VALUE(83, 0x64, 87, DOM_VK_NUMPAD4, KEY_KP4)] = RGFW_KP_4 RGFW_NEXT 1320 RGFW_MAP [RGFW_OS_BASED_VALUE(84, 0x65, 88, DOM_VK_NUMPAD5, KEY_KP5)] = RGFW_KP_5 RGFW_NEXT 1321 RGFW_MAP [RGFW_OS_BASED_VALUE(85, 0x66, 89, DOM_VK_NUMPAD6, KEY_KP6)] = RGFW_KP_6 RGFW_NEXT 1322 RGFW_MAP [RGFW_OS_BASED_VALUE(79, 0x67, 90, DOM_VK_NUMPAD7, KEY_KP7)] = RGFW_KP_7 RGFW_NEXT 1323 RGFW_MAP [RGFW_OS_BASED_VALUE(80, 0x68, 92, DOM_VK_NUMPAD8, KEY_KP8)] = RGFW_KP_8 RGFW_NEXT 1324 RGFW_MAP [RGFW_OS_BASED_VALUE(81, 0x69, 93, DOM_VK_NUMPAD9, KEY_KP9)] = RGFW_KP_9 RGFW_NEXT 1325 RGFW_MAP [RGFW_OS_BASED_VALUE(90, 0x60, 83, DOM_VK_NUMPAD0, KEY_KP0)] = RGFW_KP_0 RGFW_NEXT 1326 RGFW_MAP [RGFW_OS_BASED_VALUE(91, 0x6E, 65, DOM_VK_DECIMAL, KEY_KPDOT)] = RGFW_KP_Period RGFW_NEXT 1327 RGFW_MAP [RGFW_OS_BASED_VALUE(104, 0x92, 77, 0, KEY_KPENTER)] = RGFW_KP_Return, 1328 1329 RGFW_MAP [RGFW_OS_BASED_VALUE(20, 189, 27, DOM_VK_HYPHEN_MINUS, KEY_MINUS)] = RGFW_Minus RGFW_NEXT 1330 RGFW_MAP [RGFW_OS_BASED_VALUE(21, 187, 24, DOM_VK_EQUALS, KEY_EQUAL)] = RGFW_Equals RGFW_NEXT 1331 RGFW_MAP [RGFW_OS_BASED_VALUE(22, 8, 51, DOM_VK_BACK_SPACE, KEY_BACKSPACE)] = RGFW_BackSpace RGFW_NEXT 1332 RGFW_MAP [RGFW_OS_BASED_VALUE(23, 0x09, 48, DOM_VK_TAB, KEY_TAB)] = RGFW_Tab RGFW_NEXT 1333 RGFW_MAP [RGFW_OS_BASED_VALUE(66, 20, 57, DOM_VK_CAPS_LOCK, KEY_CAPSLOCK)] = RGFW_CapsLock RGFW_NEXT 1334 RGFW_MAP [RGFW_OS_BASED_VALUE(50, 0x10, 56, DOM_VK_SHIFT, KEY_LEFTSHIFT)] = RGFW_ShiftL RGFW_NEXT 1335 RGFW_MAP [RGFW_OS_BASED_VALUE(37, 0x11, 59, DOM_VK_CONTROL, KEY_LEFTCTRL)] = RGFW_ControlL RGFW_NEXT 1336 RGFW_MAP [RGFW_OS_BASED_VALUE(64,0x12, 58, DOM_VK_ALT, KEY_LEFTALT)] = RGFW_AltL RGFW_NEXT 1337 RGFW_MAP [RGFW_OS_BASED_VALUE(133, 0x5B, 55, DOM_VK_WIN, KEY_LEFTMETA)] = RGFW_SuperL, 1338 1339 #if !defined(RGFW_WINDOWS) && !defined(RGFW_MACOS) && !defined(RGFW_WEBASM) 1340 RGFW_MAP [RGFW_OS_BASED_VALUE(105, 0x11, 59, 0, KEY_RIGHTCTRL)] = RGFW_ControlR RGFW_NEXT 1341 RGFW_MAP [RGFW_OS_BASED_VALUE(135, 0xA4, 55, 0, KEY_RIGHTMETA)] = RGFW_SuperR, 1342 RGFW_MAP [RGFW_OS_BASED_VALUE(62, 0x5C, 56, 0, KEY_RIGHTSHIFT)] = RGFW_ShiftR RGFW_NEXT 1343 RGFW_MAP [RGFW_OS_BASED_VALUE(108, 165, 58, 0, KEY_RIGHTALT)] = RGFW_AltR, 1344 #endif 1345 1346 RGFW_MAP [RGFW_OS_BASED_VALUE(67, 0x70, 127, DOM_VK_F1, KEY_F1)] = RGFW_F1 RGFW_NEXT 1347 RGFW_MAP [RGFW_OS_BASED_VALUE(68, 0x71, 121, DOM_VK_F2, KEY_F2)] = RGFW_F2 RGFW_NEXT 1348 RGFW_MAP [RGFW_OS_BASED_VALUE(69, 0x72, 100, DOM_VK_F3, KEY_F3)] = RGFW_F3 RGFW_NEXT 1349 RGFW_MAP [RGFW_OS_BASED_VALUE(70, 0x73, 119, DOM_VK_F4, KEY_F4)] = RGFW_F4 RGFW_NEXT 1350 RGFW_MAP [RGFW_OS_BASED_VALUE(71, 0x74, 97, DOM_VK_F5, KEY_F5)] = RGFW_F5 RGFW_NEXT 1351 RGFW_MAP [RGFW_OS_BASED_VALUE(72, 0x75, 98, DOM_VK_F6, KEY_F6)] = RGFW_F6 RGFW_NEXT 1352 RGFW_MAP [RGFW_OS_BASED_VALUE(73, 0x76, 99, DOM_VK_F7, KEY_F7)] = RGFW_F7 RGFW_NEXT 1353 RGFW_MAP [RGFW_OS_BASED_VALUE(74, 0x77, 101, DOM_VK_F8, KEY_F8)] = RGFW_F8 RGFW_NEXT 1354 RGFW_MAP [RGFW_OS_BASED_VALUE(75, 0x78, 102, DOM_VK_F9, KEY_F9)] = RGFW_F9 RGFW_NEXT 1355 RGFW_MAP [RGFW_OS_BASED_VALUE(76, 0x79, 110, DOM_VK_F10, KEY_F10)] = RGFW_F10 RGFW_NEXT 1356 RGFW_MAP [RGFW_OS_BASED_VALUE(95, 0x7A, 104, DOM_VK_F11, KEY_F11)] = RGFW_F11 RGFW_NEXT 1357 RGFW_MAP [RGFW_OS_BASED_VALUE(96, 0x7B, 112, DOM_VK_F12, KEY_F12)] = RGFW_F12 RGFW_NEXT 1358 RGFW_MAP [RGFW_OS_BASED_VALUE(111, 0x26, 126, DOM_VK_UP, KEY_UP)] = RGFW_Up RGFW_NEXT 1359 RGFW_MAP [RGFW_OS_BASED_VALUE(116, 0x28, 125, DOM_VK_DOWN, KEY_DOWN)] = RGFW_Down RGFW_NEXT 1360 RGFW_MAP [RGFW_OS_BASED_VALUE(113, 0x25, 123, DOM_VK_LEFT, KEY_LEFT)] = RGFW_Left RGFW_NEXT 1361 RGFW_MAP [RGFW_OS_BASED_VALUE(114, 0x27, 124, DOM_VK_RIGHT, KEY_RIGHT)] = RGFW_Right RGFW_NEXT 1362 RGFW_MAP [RGFW_OS_BASED_VALUE(118, 0x2D, 115, DOM_VK_INSERT, KEY_INSERT)] = RGFW_Insert RGFW_NEXT 1363 RGFW_MAP [RGFW_OS_BASED_VALUE(115, 0x23, 120, DOM_VK_END, KEY_END)] = RGFW_End RGFW_NEXT 1364 RGFW_MAP [RGFW_OS_BASED_VALUE(112, 336, 117, DOM_VK_PAGE_UP, KEY_PAGEUP)] = RGFW_PageUp RGFW_NEXT 1365 RGFW_MAP [RGFW_OS_BASED_VALUE(117, 325, 122, DOM_VK_PAGE_DOWN, KEY_PAGEDOWN)] = RGFW_PageDown RGFW_NEXT 1366 RGFW_MAP [RGFW_OS_BASED_VALUE(9, 0x1B, 53, DOM_VK_ESCAPE, KEY_ESC)] = RGFW_Escape RGFW_NEXT 1367 RGFW_MAP [RGFW_OS_BASED_VALUE(110, 0x24, 116, DOM_VK_HOME, KEY_HOME)] = RGFW_Home RGFW_NEXT 1368 #ifndef __cplusplus 1369 }; 1370 #else 1371 } 1372 #endif 1373 1374 #undef RGFW_NEXT 1375 #undef RGFW_MAP 1376 1377 typedef struct { 1378 b8 current : 1; 1379 b8 prev : 1; 1380 } RGFW_keyState; 1381 1382 RGFW_keyState RGFW_keyboard[final_key] = { {0, 0} }; 1383 1384 RGFWDEF u32 RGFW_apiKeyCodeToRGFW(u32 keycode); 1385 1386 u32 RGFW_apiKeyCodeToRGFW(u32 keycode) { 1387 #ifdef __cplusplus 1388 if (RGFW_OS_BASED_VALUE(49, 192, 50, DOM_VK_BACK_QUOTE, KEY_GRAVE) != RGFW_Backtick) { 1389 RGFW_init_keys(); 1390 } 1391 #endif 1392 1393 /* make sure the key isn't out of bounds */ 1394 if (keycode > sizeof(RGFW_keycodes) / sizeof(u8)) 1395 return 0; 1396 1397 return RGFW_keycodes[keycode]; 1398 } 1399 1400 RGFWDEF void RGFW_resetKey(void); 1401 void RGFW_resetKey(void) { 1402 size_t len = final_key; /*!< last_key == length */ 1403 1404 size_t i; /*!< reset each previous state */ 1405 for (i = 0; i < len; i++) 1406 RGFW_keyboard[i].prev = 0; 1407 } 1408 1409 b8 RGFW_shouldShift(u32 keycode, u8 lockState) { 1410 #define RGFW_xor(x, y) (( (x) && (!(y)) ) || ((y) && (!(x)) )) 1411 b8 caps4caps = (lockState & RGFW_CAPSLOCK) && ((keycode >= RGFW_a) && (keycode <= RGFW_z)); 1412 b8 shouldShift = RGFW_xor((RGFW_isPressed(NULL, RGFW_ShiftL) || RGFW_isPressed(NULL, RGFW_ShiftR)), caps4caps); 1413 #undef RGFW_xor 1414 1415 return shouldShift; 1416 } 1417 1418 char RGFW_keyCodeToChar(u32 keycode, b8 shift) { 1419 static const char map[] = { 1420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '`', '0', '1', '2', '3', '4', '5', '6', '7', '8', 1421 '9', '-', '=', 0, '\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 1422 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '.', ',', '/', '[', ']', ';', '\n', '\'', '\\', 1423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '/', '*', '-', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '\n' 1424 }; 1425 1426 static const char mapCaps[] = { 1427 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '~', ')', '!', '@', '#', '$', '%', '^', '&', '*', 1428 '(', '_', '+', 0, '0', 0, 0, 0, 0, 0, 0, 0, 0, 0, ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 1429 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 1430 'X', 'Y', 'Z', '>', '<', '?', '{', '}', ':', '\n', '"', '|', 1431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '?', '*', '-', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1432 }; 1433 1434 if (shift == RGFW_FALSE) 1435 return map[keycode]; 1436 return mapCaps[keycode]; 1437 } 1438 1439 char RGFW_keyCodeToCharAuto(u32 keycode, u8 lockState) { return RGFW_keyCodeToChar(keycode, RGFW_shouldShift(keycode, lockState)); } 1440 1441 /* 1442 this is the end of keycode data 1443 */ 1444 1445 /* joystick data */ 1446 u8 RGFW_jsPressed[4][16]; /*!< if a key is currently pressed or not (per joystick) */ 1447 1448 i32 RGFW_joysticks[4]; /*!< limit of 4 joysticks at a time */ 1449 u16 RGFW_joystickCount; /*!< the actual amount of joysticks */ 1450 1451 /* 1452 event callback defines start here 1453 */ 1454 1455 1456 /* 1457 These exist to avoid the 1458 if (func == NULL) check 1459 for (allegedly) better performance 1460 */ 1461 void RGFW_windowmovefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } 1462 void RGFW_windowresizefuncEMPTY(RGFW_window* win, RGFW_rect r) { RGFW_UNUSED(win); RGFW_UNUSED(r); } 1463 void RGFW_windowquitfuncEMPTY(RGFW_window* win) { RGFW_UNUSED(win); } 1464 void RGFW_focusfuncEMPTY(RGFW_window* win, b8 inFocus) {RGFW_UNUSED(win); RGFW_UNUSED(inFocus);} 1465 void RGFW_mouseNotifyfuncEMPTY(RGFW_window* win, RGFW_point point, b8 status) {RGFW_UNUSED(win); RGFW_UNUSED(point); RGFW_UNUSED(status);} 1466 void RGFW_mouseposfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} 1467 void RGFW_dndInitfuncEMPTY(RGFW_window* win, RGFW_point point) {RGFW_UNUSED(win); RGFW_UNUSED(point);} 1468 void RGFW_windowrefreshfuncEMPTY(RGFW_window* win) {RGFW_UNUSED(win); } 1469 void RGFW_keyfuncEMPTY(RGFW_window* win, u32 keycode, char keyName[16], u8 lockState, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(keycode); RGFW_UNUSED(keyName); RGFW_UNUSED(lockState); RGFW_UNUSED(pressed);} 1470 void RGFW_mousebuttonfuncEMPTY(RGFW_window* win, u8 button, double scroll, b8 pressed) {RGFW_UNUSED(win); RGFW_UNUSED(button); RGFW_UNUSED(scroll); RGFW_UNUSED(pressed);} 1471 void RGFW_jsButtonfuncEMPTY(RGFW_window* win, u16 joystick, u8 button, b8 pressed){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(button); RGFW_UNUSED(pressed); } 1472 void RGFW_jsAxisfuncEMPTY(RGFW_window* win, u16 joystick, RGFW_point axis[2], u8 axisesCount){RGFW_UNUSED(win); RGFW_UNUSED(joystick); RGFW_UNUSED(axis); RGFW_UNUSED(axisesCount); } 1473 1474 #ifdef RGFW_ALLOC_DROPFILES 1475 void RGFW_dndfuncEMPTY(RGFW_window* win, char** droppedFiles, u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} 1476 #else 1477 void RGFW_dndfuncEMPTY(RGFW_window* win, char droppedFiles[RGFW_MAX_DROPS][RGFW_MAX_PATH], u32 droppedFilesCount) {RGFW_UNUSED(win); RGFW_UNUSED(droppedFiles); RGFW_UNUSED(droppedFilesCount);} 1478 #endif 1479 1480 RGFW_windowmovefunc RGFW_windowMoveCallback = RGFW_windowmovefuncEMPTY; 1481 RGFW_windowresizefunc RGFW_windowResizeCallback = RGFW_windowresizefuncEMPTY; 1482 RGFW_windowquitfunc RGFW_windowQuitCallback = RGFW_windowquitfuncEMPTY; 1483 RGFW_mouseposfunc RGFW_mousePosCallback = RGFW_mouseposfuncEMPTY; 1484 RGFW_windowrefreshfunc RGFW_windowRefreshCallback = RGFW_windowrefreshfuncEMPTY; 1485 RGFW_focusfunc RGFW_focusCallback = RGFW_focusfuncEMPTY; 1486 RGFW_mouseNotifyfunc RGFW_mouseNotifyCallBack = RGFW_mouseNotifyfuncEMPTY; 1487 RGFW_dndfunc RGFW_dndCallback = RGFW_dndfuncEMPTY; 1488 RGFW_dndInitfunc RGFW_dndInitCallback = RGFW_dndInitfuncEMPTY; 1489 RGFW_keyfunc RGFW_keyCallback = RGFW_keyfuncEMPTY; 1490 RGFW_mousebuttonfunc RGFW_mouseButtonCallback = RGFW_mousebuttonfuncEMPTY; 1491 RGFW_jsButtonfunc RGFW_jsButtonCallback = RGFW_jsButtonfuncEMPTY; 1492 RGFW_jsAxisfunc RGFW_jsAxisCallback = RGFW_jsAxisfuncEMPTY; 1493 1494 void RGFW_window_checkEvents(RGFW_window* win, i32 waitMS) { 1495 RGFW_window_eventWait(win, waitMS); 1496 1497 while (RGFW_window_checkEvent(win) != NULL && RGFW_window_shouldClose(win) == 0) { 1498 if (win->event.type == RGFW_quit) return; 1499 } 1500 1501 #ifdef RGFW_WEBASM /* webasm needs to run the sleep function for asyncify */ 1502 RGFW_sleep(0); 1503 #endif 1504 } 1505 1506 RGFW_windowmovefunc RGFW_setWindowMoveCallback(RGFW_windowmovefunc func) { 1507 RGFW_windowmovefunc prev = (RGFW_windowMoveCallback == RGFW_windowmovefuncEMPTY) ? NULL : RGFW_windowMoveCallback; 1508 RGFW_windowMoveCallback = func; 1509 return prev; 1510 } 1511 RGFW_windowresizefunc RGFW_setWindowResizeCallback(RGFW_windowresizefunc func) { 1512 RGFW_windowresizefunc prev = (RGFW_windowResizeCallback == RGFW_windowresizefuncEMPTY) ? NULL : RGFW_windowResizeCallback; 1513 RGFW_windowResizeCallback = func; 1514 return prev; 1515 } 1516 RGFW_windowquitfunc RGFW_setWindowQuitCallback(RGFW_windowquitfunc func) { 1517 RGFW_windowquitfunc prev = (RGFW_windowQuitCallback == RGFW_windowquitfuncEMPTY) ? NULL : RGFW_windowQuitCallback; 1518 RGFW_windowQuitCallback = func; 1519 return prev; 1520 } 1521 1522 RGFW_mouseposfunc RGFW_setMousePosCallback(RGFW_mouseposfunc func) { 1523 RGFW_mouseposfunc prev = (RGFW_mousePosCallback == RGFW_mouseposfuncEMPTY) ? NULL : RGFW_mousePosCallback; 1524 RGFW_mousePosCallback = func; 1525 return prev; 1526 } 1527 RGFW_windowrefreshfunc RGFW_setWindowRefreshCallback(RGFW_windowrefreshfunc func) { 1528 RGFW_windowrefreshfunc prev = (RGFW_windowRefreshCallback == RGFW_windowrefreshfuncEMPTY) ? NULL : RGFW_windowRefreshCallback; 1529 RGFW_windowRefreshCallback = func; 1530 return prev; 1531 } 1532 RGFW_focusfunc RGFW_setFocusCallback(RGFW_focusfunc func) { 1533 RGFW_focusfunc prev = (RGFW_focusCallback == RGFW_focusfuncEMPTY) ? NULL : RGFW_focusCallback; 1534 RGFW_focusCallback = func; 1535 return prev; 1536 } 1537 1538 RGFW_mouseNotifyfunc RGFW_setMouseNotifyCallBack(RGFW_mouseNotifyfunc func) { 1539 RGFW_mouseNotifyfunc prev = (RGFW_mouseNotifyCallBack == RGFW_mouseNotifyfuncEMPTY) ? NULL : RGFW_mouseNotifyCallBack; 1540 RGFW_mouseNotifyCallBack = func; 1541 return prev; 1542 } 1543 RGFW_dndfunc RGFW_setDndCallback(RGFW_dndfunc func) { 1544 RGFW_dndfunc prev = (RGFW_dndCallback == RGFW_dndfuncEMPTY) ? NULL : RGFW_dndCallback; 1545 RGFW_dndCallback = func; 1546 return prev; 1547 } 1548 RGFW_dndInitfunc RGFW_setDndInitCallback(RGFW_dndInitfunc func) { 1549 RGFW_dndInitfunc prev = (RGFW_dndInitCallback == RGFW_dndInitfuncEMPTY) ? NULL : RGFW_dndInitCallback; 1550 RGFW_dndInitCallback = func; 1551 return prev; 1552 } 1553 RGFW_keyfunc RGFW_setKeyCallback(RGFW_keyfunc func) { 1554 RGFW_keyfunc prev = (RGFW_keyCallback == RGFW_keyfuncEMPTY) ? NULL : RGFW_keyCallback; 1555 RGFW_keyCallback = func; 1556 return prev; 1557 } 1558 RGFW_mousebuttonfunc RGFW_setMouseButtonCallback(RGFW_mousebuttonfunc func) { 1559 RGFW_mousebuttonfunc prev = (RGFW_mouseButtonCallback == RGFW_mousebuttonfuncEMPTY) ? NULL : RGFW_mouseButtonCallback; 1560 RGFW_mouseButtonCallback = func; 1561 return prev; 1562 } 1563 RGFW_jsButtonfunc RGFW_setjsButtonCallback(RGFW_jsButtonfunc func) { 1564 RGFW_jsButtonfunc prev = (RGFW_jsButtonCallback == RGFW_jsButtonfuncEMPTY) ? NULL : RGFW_jsButtonCallback; 1565 RGFW_jsButtonCallback = func; 1566 return prev; 1567 } 1568 RGFW_jsAxisfunc RGFW_setjsAxisCallback(RGFW_jsAxisfunc func) { 1569 RGFW_jsAxisfunc prev = (RGFW_jsAxisCallback == RGFW_jsAxisfuncEMPTY) ? NULL : RGFW_jsAxisCallback; 1570 RGFW_jsAxisCallback = func; 1571 return prev; 1572 } 1573 /* 1574 no more event call back defines 1575 */ 1576 1577 #define RGFW_ASSERT(check, str) {\ 1578 if (!(check)) { \ 1579 printf(str); \ 1580 assert(check); \ 1581 } \ 1582 } 1583 1584 b8 RGFW_error = 0; 1585 b8 RGFW_Error(void) { return RGFW_error; } 1586 1587 #define SET_ATTRIB(a, v) { \ 1588 assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \ 1589 attribs[index++] = a; \ 1590 attribs[index++] = v; \ 1591 } 1592 1593 RGFW_area RGFW_bufferSize = {0, 0}; 1594 void RGFW_setBufferSize(RGFW_area size) { 1595 RGFW_bufferSize = size; 1596 } 1597 1598 1599 RGFWDEF RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args); 1600 1601 /* do a basic initialization for RGFW_window, this is to standard it for each OS */ 1602 RGFW_window* RGFW_window_basic_init(RGFW_rect rect, u16 args) { 1603 RGFW_window* win = (RGFW_window*) RGFW_MALLOC(sizeof(RGFW_window)); /*!< make a new RGFW struct */ 1604 1605 /* clear out dnd info */ 1606 #ifdef RGFW_ALLOC_DROPFILES 1607 win->event.droppedFiles = (char**) RGFW_MALLOC(sizeof(char*) * RGFW_MAX_DROPS); 1608 u32 i; 1609 for (i = 0; i < RGFW_MAX_DROPS; i++) 1610 win->event.droppedFiles[i] = (char*) RGFW_CALLOC(RGFW_MAX_PATH, sizeof(char)); 1611 #endif 1612 1613 /* X11 requires us to have a display to get the screen size */ 1614 #ifndef RGFW_X11 1615 RGFW_area screenR = RGFW_getScreenSize(); 1616 #else 1617 win->src.display = XOpenDisplay(NULL); 1618 assert(win->src.display != NULL); 1619 1620 Screen* scrn = DefaultScreenOfDisplay((Display*)win->src.display); 1621 RGFW_area screenR = RGFW_AREA((u32)scrn->width, (u32)scrn->height); 1622 #endif 1623 1624 /* rect based the requested args */ 1625 if (args & RGFW_FULLSCREEN) 1626 rect = RGFW_RECT(0, 0, screenR.w, screenR.h); 1627 1628 /* set and init the new window's data */ 1629 win->r = rect; 1630 win->event.inFocus = 1; 1631 win->event.droppedFilesCount = 0; 1632 RGFW_joystickCount = 0; 1633 win->_winArgs = 0; 1634 win->event.lockState = 0; 1635 1636 return win; 1637 } 1638 1639 #ifndef RGFW_NO_MONITOR 1640 void RGFW_window_scaleToMonitor(RGFW_window* win) { 1641 RGFW_monitor monitor = RGFW_window_getMonitor(win); 1642 1643 RGFW_window_resize(win, RGFW_AREA((u32)(monitor.scaleX * (float)win->r.w), (u32)(monitor.scaleX * (float)win->r.h))); 1644 } 1645 #endif 1646 1647 RGFW_window* RGFW_root = NULL; 1648 1649 1650 #define RGFW_HOLD_MOUSE (1L<<2) /*!< hold the moues still */ 1651 #define RGFW_MOUSE_LEFT (1L<<3) /* if mouse left the window */ 1652 1653 #ifdef RGFW_MACOS 1654 RGFWDEF void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer); 1655 RGFWDEF void* RGFW_cocoaGetLayer(void); 1656 #endif 1657 1658 char* RGFW_className = NULL; 1659 void RGFW_setClassName(char* name) { 1660 RGFW_className = name; 1661 } 1662 1663 void RGFW_clipboardFree(char* str) { RGFW_FREE(str); } 1664 1665 RGFW_keyState RGFW_mouseButtons[5] = { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }; 1666 1667 b8 RGFW_isMousePressed(RGFW_window* win, u8 button) { 1668 assert(win != NULL); 1669 return RGFW_mouseButtons[button].current && (win != NULL) && win->event.inFocus; 1670 } 1671 b8 RGFW_wasMousePressed(RGFW_window* win, u8 button) { 1672 assert(win != NULL); 1673 return RGFW_mouseButtons[button].prev && (win != NULL) && win->event.inFocus; 1674 } 1675 b8 RGFW_isMouseHeld(RGFW_window* win, u8 button) { 1676 return (RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); 1677 } 1678 b8 RGFW_isMouseReleased(RGFW_window* win, u8 button) { 1679 return (!RGFW_isMousePressed(win, button) && RGFW_wasMousePressed(win, button)); 1680 } 1681 1682 b8 RGFW_isPressed(RGFW_window* win, u8 key) { 1683 return RGFW_keyboard[key].current && (win == NULL || win->event.inFocus); 1684 } 1685 1686 b8 RGFW_wasPressed(RGFW_window* win, u8 key) { 1687 return RGFW_keyboard[key].prev && (win == NULL || win->event.inFocus); 1688 } 1689 1690 b8 RGFW_isHeld(RGFW_window* win, u8 key) { 1691 return (RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); 1692 } 1693 1694 b8 RGFW_isClicked(RGFW_window* win, u8 key) { 1695 return (RGFW_wasPressed(win, key) && !RGFW_isPressed(win, key)); 1696 } 1697 1698 b8 RGFW_isReleased(RGFW_window* win, u8 key) { 1699 return (!RGFW_isPressed(win, key) && RGFW_wasPressed(win, key)); 1700 } 1701 1702 #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) /* defines for directX context*/ 1703 RGFW_directXinfo RGFW_dxInfo; 1704 RGFW_directXinfo* RGFW_getDirectXInfo(void) { return &RGFW_dxInfo; } 1705 #endif 1706 1707 void RGFW_window_makeCurrent(RGFW_window* win) { 1708 #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) 1709 if (win == NULL) 1710 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, NULL, NULL); 1711 else 1712 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, NULL); 1713 #elif defined(RGFW_OPENGL) 1714 RGFW_window_makeCurrent_OpenGL(win); 1715 #else 1716 RGFW_UNUSED(win) 1717 #endif 1718 } 1719 1720 void RGFW_window_setGPURender(RGFW_window* win, i8 set) { 1721 if (!set && !(win->_winArgs & RGFW_NO_GPU_RENDER)) 1722 win->_winArgs |= RGFW_NO_GPU_RENDER; 1723 1724 else if (set && win->_winArgs & RGFW_NO_GPU_RENDER) 1725 win->_winArgs ^= RGFW_NO_GPU_RENDER; 1726 } 1727 1728 void RGFW_window_setCPURender(RGFW_window* win, i8 set) { 1729 if (!set && !(win->_winArgs & RGFW_NO_CPU_RENDER)) 1730 win->_winArgs |= RGFW_NO_CPU_RENDER; 1731 1732 else if (set && win->_winArgs & RGFW_NO_CPU_RENDER) 1733 win->_winArgs ^= RGFW_NO_CPU_RENDER; 1734 } 1735 1736 void RGFW_window_maximize(RGFW_window* win) { 1737 assert(win != NULL); 1738 1739 RGFW_area screen = RGFW_getScreenSize(); 1740 1741 RGFW_window_move(win, RGFW_POINT(0, 0)); 1742 RGFW_window_resize(win, screen); 1743 } 1744 1745 b8 RGFW_window_shouldClose(RGFW_window* win) { 1746 assert(win != NULL); 1747 return (win->event.type == RGFW_quit || RGFW_isPressed(win, RGFW_Escape)); 1748 } 1749 1750 void RGFW_window_setShouldClose(RGFW_window* win) { win->event.type = RGFW_quit; RGFW_windowQuitCallback(win); } 1751 1752 #ifndef RGFW_NO_MONITOR 1753 void RGFW_window_moveToMonitor(RGFW_window* win, RGFW_monitor m) { 1754 RGFW_window_move(win, RGFW_POINT(m.rect.x + win->r.x, m.rect.y + win->r.y)); 1755 } 1756 #endif 1757 1758 RGFWDEF void RGFW_captureCursor(RGFW_window* win, RGFW_rect); 1759 RGFWDEF void RGFW_releaseCursor(RGFW_window* win); 1760 1761 void RGFW_window_mouseHold(RGFW_window* win, RGFW_area area) { 1762 if ((win->_winArgs & RGFW_HOLD_MOUSE)) 1763 return; 1764 1765 1766 if (!area.w && !area.h) 1767 area = RGFW_AREA(win->r.w / 2, win->r.h / 2); 1768 1769 win->_winArgs |= RGFW_HOLD_MOUSE; 1770 RGFW_captureCursor(win, win->r); 1771 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); 1772 } 1773 1774 void RGFW_window_mouseUnhold(RGFW_window* win) { 1775 if ((win->_winArgs & RGFW_HOLD_MOUSE)) { 1776 win->_winArgs ^= RGFW_HOLD_MOUSE; 1777 1778 RGFW_releaseCursor(win); 1779 } 1780 } 1781 1782 u32 RGFW_window_checkFPS(RGFW_window* win, u32 fpsCap) { 1783 u64 deltaTime = RGFW_getTimeNS() - win->event.frameTime; 1784 1785 u32 output_fps = 0; 1786 u64 fps = round(1e+9 / deltaTime); 1787 output_fps= fps; 1788 1789 if (fpsCap && fps > fpsCap) { 1790 u64 frameTimeNS = 1e+9 / fpsCap; 1791 u64 sleepTimeMS = (frameTimeNS - deltaTime) / 1e6; 1792 1793 if (sleepTimeMS > 0) { 1794 RGFW_sleep(sleepTimeMS); 1795 win->event.frameTime = 0; 1796 } 1797 } 1798 1799 win->event.frameTime = RGFW_getTimeNS(); 1800 1801 if (fpsCap == 0) 1802 return (u32) output_fps; 1803 1804 deltaTime = RGFW_getTimeNS() - win->event.frameTime2; 1805 output_fps = round(1e+9 / deltaTime); 1806 win->event.frameTime2 = RGFW_getTimeNS(); 1807 1808 return output_fps; 1809 } 1810 1811 u32 RGFW_isPressedJS(RGFW_window* win, u16 c, u8 button) { 1812 RGFW_UNUSED(win); 1813 return RGFW_jsPressed[c][button]; 1814 } 1815 1816 #if defined(RGFW_X11) || defined(RGFW_WINDOWS) 1817 void RGFW_window_showMouse(RGFW_window* win, i8 show) { 1818 static u8 RGFW_blk[] = { 0, 0, 0, 0 }; 1819 if (show == 0) 1820 RGFW_window_setMouse(win, RGFW_blk, RGFW_AREA(1, 1), 4); 1821 else 1822 RGFW_window_setMouseDefault(win); 1823 } 1824 #endif 1825 1826 RGFWDEF void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock); 1827 void RGFW_updateLockState(RGFW_window* win, b8 capital, b8 numlock) { 1828 if (capital && !(win->event.lockState & RGFW_CAPSLOCK)) 1829 win->event.lockState |= RGFW_CAPSLOCK; 1830 else if (!capital && (win->event.lockState & RGFW_CAPSLOCK)) 1831 win->event.lockState ^= RGFW_CAPSLOCK; 1832 1833 if (numlock && !(win->event.lockState & RGFW_NUMLOCK)) 1834 win->event.lockState |= RGFW_NUMLOCK; 1835 else if (!numlock && (win->event.lockState & RGFW_NUMLOCK)) 1836 win->event.lockState ^= RGFW_NUMLOCK; 1837 } 1838 1839 #if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND) 1840 struct timespec; 1841 1842 int nanosleep(const struct timespec* duration, struct timespec* rem); 1843 int clock_gettime(clockid_t clk_id, struct timespec* tp); 1844 int setenv(const char *name, const char *value, int overwrite); 1845 1846 void RGFW_window_setDND(RGFW_window* win, b8 allow) { 1847 if (allow && !(win->_winArgs & RGFW_ALLOW_DND)) 1848 win->_winArgs |= RGFW_ALLOW_DND; 1849 1850 else if (!allow && (win->_winArgs & RGFW_ALLOW_DND)) 1851 win->_winArgs ^= RGFW_ALLOW_DND; 1852 } 1853 #endif 1854 1855 /* 1856 graphics API specific code (end of generic code) 1857 starts here 1858 */ 1859 1860 1861 /* 1862 OpenGL defines start here (Normal, EGL, OSMesa) 1863 */ 1864 1865 #if defined(RGFW_OPENGL) || defined(RGFW_EGL) || defined(RGFW_OSMESA) 1866 #ifdef RGFW_WINDOWS 1867 #define WIN32_LEAN_AND_MEAN 1868 #define OEMRESOURCE 1869 #include <windows.h> 1870 #endif 1871 1872 #if !defined(__APPLE__) && !defined(RGFW_NO_GL_HEADER) 1873 #include <GL/gl.h> 1874 #elif defined(__APPLE__) 1875 #ifndef GL_SILENCE_DEPRECATION 1876 #define GL_SILENCE_DEPRECATION 1877 #endif 1878 #include <OpenGL/gl.h> 1879 #include <OpenGL/OpenGL.h> 1880 #endif 1881 1882 /* EGL, normal OpenGL only */ 1883 #if !defined(RGFW_OSMESA) 1884 i32 RGFW_majorVersion = 0, RGFW_minorVersion = 0; 1885 b8 RGFW_profile = RGFW_GL_CORE; 1886 1887 #ifndef RGFW_EGL 1888 i32 RGFW_STENCIL = 8, RGFW_SAMPLES = 4, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1; 1889 #else 1890 i32 RGFW_STENCIL = 0, RGFW_SAMPLES = 0, RGFW_STEREO = 0, RGFW_AUX_BUFFERS = 0, RGFW_DOUBLE_BUFFER = 1; 1891 #endif 1892 1893 1894 void RGFW_setGLStencil(i32 stencil) { RGFW_STENCIL = stencil; } 1895 void RGFW_setGLSamples(i32 samples) { RGFW_SAMPLES = samples; } 1896 void RGFW_setGLStereo(i32 stereo) { RGFW_STEREO = stereo; } 1897 void RGFW_setGLAuxBuffers(i32 auxBuffers) { RGFW_AUX_BUFFERS = auxBuffers; } 1898 void RGFW_setDoubleBuffer(b8 useDoubleBuffer) { RGFW_DOUBLE_BUFFER = useDoubleBuffer; } 1899 1900 void RGFW_setGLVersion(b8 profile, i32 major, i32 minor) { 1901 RGFW_profile = profile; 1902 RGFW_majorVersion = major; 1903 RGFW_minorVersion = minor; 1904 } 1905 1906 /* OPENGL normal only (no EGL / OSMesa) */ 1907 #ifndef RGFW_EGL 1908 1909 #define RGFW_GL_RENDER_TYPE RGFW_OS_BASED_VALUE(GLX_X_VISUAL_TYPE, 0x2003, 73, 0, 0) 1910 #define RGFW_GL_ALPHA_SIZE RGFW_OS_BASED_VALUE(GLX_ALPHA_SIZE, 0x201b, 11, 0, 0) 1911 #define RGFW_GL_DEPTH_SIZE RGFW_OS_BASED_VALUE(GLX_DEPTH_SIZE, 0x2022, 12, 0, 0) 1912 #define RGFW_GL_DOUBLEBUFFER RGFW_OS_BASED_VALUE(GLX_DOUBLEBUFFER, 0x2011, 5, 0, 0) 1913 #define RGFW_GL_STENCIL_SIZE RGFW_OS_BASED_VALUE(GLX_STENCIL_SIZE, 0x2023, 13, 0, 0) 1914 #define RGFW_GL_SAMPLES RGFW_OS_BASED_VALUE(GLX_SAMPLES, 0x2042, 55, 0, 0) 1915 #define RGFW_GL_STEREO RGFW_OS_BASED_VALUE(GLX_STEREO, 0x2012, 6, 0, 0) 1916 #define RGFW_GL_AUX_BUFFERS RGFW_OS_BASED_VALUE(GLX_AUX_BUFFERS, 0x2024, 7, 0, 0) 1917 1918 #if defined(RGFW_X11) || defined(RGFW_WINDOWS) 1919 #define RGFW_GL_DRAW RGFW_OS_BASED_VALUE(GLX_X_RENDERABLE, 0x2001, 0, 0, 0) 1920 #define RGFW_GL_DRAW_TYPE RGFW_OS_BASED_VALUE(GLX_RENDER_TYPE, 0x2013, 0, 0, 0) 1921 #define RGFW_GL_FULL_FORMAT RGFW_OS_BASED_VALUE(GLX_TRUE_COLOR, 0x2027, 0, 0, 0) 1922 #define RGFW_GL_RED_SIZE RGFW_OS_BASED_VALUE(GLX_RED_SIZE, 0x2015, 0, 0, 0) 1923 #define RGFW_GL_GREEN_SIZE RGFW_OS_BASED_VALUE(GLX_GREEN_SIZE, 0x2017, 0, 0, 0) 1924 #define RGFW_GL_BLUE_SIZE RGFW_OS_BASED_VALUE(GLX_BLUE_SIZE, 0x2019, 0, 0, 0) 1925 #define RGFW_GL_USE_RGBA RGFW_OS_BASED_VALUE(GLX_RGBA_BIT, 0x202B, 0, 0, 0) 1926 #endif 1927 1928 #ifdef RGFW_WINDOWS 1929 #define WGL_SUPPORT_OPENGL_ARB 0x2010 1930 #define WGL_COLOR_BITS_ARB 0x2014 1931 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 1932 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 1933 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 1934 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 1935 #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 1936 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 1937 #define WGL_SAMPLE_BUFFERS_ARB 0x2041 1938 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 1939 #define WGL_PIXEL_TYPE_ARB 0x2013 1940 #define WGL_TYPE_RGBA_ARB 0x202B 1941 1942 #define WGL_TRANSPARENT_ARB 0x200A 1943 #endif 1944 1945 /* The window'ing api needs to know how to render the data we (or opengl) give it 1946 MacOS and Windows do this using a structure called a "pixel format" 1947 X11 calls it a "Visual" 1948 This function returns the attributes for the format we want */ 1949 static u32* RGFW_initFormatAttribs(u32 useSoftware) { 1950 RGFW_UNUSED(useSoftware); 1951 static u32 attribs[] = { 1952 #if defined(RGFW_X11) || defined(RGFW_WINDOWS) 1953 RGFW_GL_RENDER_TYPE, 1954 RGFW_GL_FULL_FORMAT, 1955 #endif 1956 RGFW_GL_ALPHA_SIZE , 8, 1957 RGFW_GL_DEPTH_SIZE , 24, 1958 #if defined(RGFW_X11) || defined(RGFW_WINDOWS) 1959 RGFW_GL_DRAW, 1, 1960 RGFW_GL_RED_SIZE , 8, 1961 RGFW_GL_GREEN_SIZE , 8, 1962 RGFW_GL_BLUE_SIZE , 8, 1963 RGFW_GL_DRAW_TYPE , RGFW_GL_USE_RGBA, 1964 #endif 1965 1966 #ifdef RGFW_X11 1967 GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, 1968 #endif 1969 1970 #ifdef RGFW_MACOS 1971 72, 1972 8, 24, 1973 #endif 1974 1975 #ifdef RGFW_WINDOWS 1976 WGL_SUPPORT_OPENGL_ARB, 1, 1977 WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB, 1978 WGL_COLOR_BITS_ARB, 32, 1979 #endif 1980 1981 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1982 }; 1983 1984 size_t index = (sizeof(attribs) / sizeof(attribs[0])) - 13; 1985 1986 #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ 1987 if (attVal) { \ 1988 attribs[index] = attrib;\ 1989 attribs[index + 1] = attVal;\ 1990 index += 2;\ 1991 } 1992 1993 RGFW_GL_ADD_ATTRIB(RGFW_GL_DOUBLEBUFFER, 1); 1994 1995 RGFW_GL_ADD_ATTRIB(RGFW_GL_STENCIL_SIZE, RGFW_STENCIL); 1996 RGFW_GL_ADD_ATTRIB(RGFW_GL_STEREO, RGFW_STEREO); 1997 RGFW_GL_ADD_ATTRIB(RGFW_GL_AUX_BUFFERS, RGFW_AUX_BUFFERS); 1998 1999 #ifndef RGFW_X11 2000 RGFW_GL_ADD_ATTRIB(RGFW_GL_SAMPLES, RGFW_SAMPLES); 2001 #endif 2002 2003 #ifdef RGFW_MACOS 2004 if (useSoftware) { 2005 RGFW_GL_ADD_ATTRIB(70, kCGLRendererGenericFloatID); 2006 } else { 2007 attribs[index] = RGFW_GL_RENDER_TYPE; 2008 index += 1; 2009 } 2010 #endif 2011 2012 #ifdef RGFW_MACOS 2013 /* macOS has the surface attribs and the opengl attribs connected for some reason 2014 maybe this is to give macOS more control to limit openGL/the opengl version? */ 2015 2016 attribs[index] = 99; 2017 attribs[index + 1] = 0x1000; 2018 2019 if (RGFW_majorVersion >= 4 || RGFW_majorVersion >= 3) { 2020 attribs[index + 1] = (u32) ((RGFW_majorVersion >= 4) ? 0x4100 : 0x3200); 2021 } 2022 #endif 2023 2024 RGFW_GL_ADD_ATTRIB(0, 0); 2025 2026 return attribs; 2027 } 2028 2029 /* EGL only (no OSMesa nor normal OPENGL) */ 2030 #elif defined(RGFW_EGL) 2031 2032 #include <EGL/egl.h> 2033 2034 #if defined(RGFW_LINK_EGL) 2035 typedef EGLBoolean(EGLAPIENTRY* PFN_eglInitialize)(EGLDisplay, EGLint*, EGLint*); 2036 2037 PFNEGLINITIALIZEPROC eglInitializeSource; 2038 PFNEGLGETCONFIGSPROC eglGetConfigsSource; 2039 PFNEGLCHOOSECONFIGPROC eglChooseConfigSource; 2040 PFNEGLCREATEWINDOWSURFACEPROC eglCreateWindowSurfaceSource; 2041 PFNEGLCREATECONTEXTPROC eglCreateContextSource; 2042 PFNEGLMAKECURRENTPROC eglMakeCurrentSource; 2043 PFNEGLGETDISPLAYPROC eglGetDisplaySource; 2044 PFNEGLSWAPBUFFERSPROC eglSwapBuffersSource; 2045 PFNEGLSWAPINTERVALPROC eglSwapIntervalSource; 2046 PFNEGLBINDAPIPROC eglBindAPISource; 2047 PFNEGLDESTROYCONTEXTPROC eglDestroyContextSource; 2048 PFNEGLTERMINATEPROC eglTerminateSource; 2049 PFNEGLDESTROYSURFACEPROC eglDestroySurfaceSource; 2050 2051 #define eglInitialize eglInitializeSource 2052 #define eglGetConfigs eglGetConfigsSource 2053 #define eglChooseConfig eglChooseConfigSource 2054 #define eglCreateWindowSurface eglCreateWindowSurfaceSource 2055 #define eglCreateContext eglCreateContextSource 2056 #define eglMakeCurrent eglMakeCurrentSource 2057 #define eglGetDisplay eglGetDisplaySource 2058 #define eglSwapBuffers eglSwapBuffersSource 2059 #define eglSwapInterval eglSwapIntervalSource 2060 #define eglBindAPI eglBindAPISource 2061 #define eglDestroyContext eglDestroyContextSource 2062 #define eglTerminate eglTerminateSource 2063 #define eglDestroySurface eglDestroySurfaceSource; 2064 #endif 2065 2066 2067 #define EGL_SURFACE_MAJOR_VERSION_KHR 0x3098 2068 #define EGL_SURFACE_MINOR_VERSION_KHR 0x30fb 2069 2070 #ifndef RGFW_GL_ADD_ATTRIB 2071 #define RGFW_GL_ADD_ATTRIB(attrib, attVal) \ 2072 if (attVal) { \ 2073 attribs[index] = attrib;\ 2074 attribs[index + 1] = attVal;\ 2075 index += 2;\ 2076 } 2077 #endif 2078 2079 2080 void RGFW_createOpenGLContext(RGFW_window* win) { 2081 #if defined(RGFW_LINK_EGL) 2082 eglInitializeSource = (PFNEGLINITIALIZEPROC) eglGetProcAddress("eglInitialize"); 2083 eglGetConfigsSource = (PFNEGLGETCONFIGSPROC) eglGetProcAddress("eglGetConfigs"); 2084 eglChooseConfigSource = (PFNEGLCHOOSECONFIGPROC) eglGetProcAddress("eglChooseConfig"); 2085 eglCreateWindowSurfaceSource = (PFNEGLCREATEWINDOWSURFACEPROC) eglGetProcAddress("eglCreateWindowSurface"); 2086 eglCreateContextSource = (PFNEGLCREATECONTEXTPROC) eglGetProcAddress("eglCreateContext"); 2087 eglMakeCurrentSource = (PFNEGLMAKECURRENTPROC) eglGetProcAddress("eglMakeCurrent"); 2088 eglGetDisplaySource = (PFNEGLGETDISPLAYPROC) eglGetProcAddress("eglGetDisplay"); 2089 eglSwapBuffersSource = (PFNEGLSWAPBUFFERSPROC) eglGetProcAddress("eglSwapBuffers"); 2090 eglSwapIntervalSource = (PFNEGLSWAPINTERVALPROC) eglGetProcAddress("eglSwapInterval"); 2091 eglBindAPISource = (PFNEGLBINDAPIPROC) eglGetProcAddress("eglBindAPI"); 2092 eglDestroyContextSource = (PFNEGLDESTROYCONTEXTPROC) eglGetProcAddress("eglDestroyContext"); 2093 eglTerminateSource = (PFNEGLTERMINATEPROC) eglGetProcAddress("eglTerminate"); 2094 eglDestroySurfaceSource = (PFNEGLDESTROYSURFACEPROC) eglGetProcAddress("eglDestroySurface"); 2095 #endif /* RGFW_LINK_EGL */ 2096 2097 #ifdef RGFW_WINDOWS 2098 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.hdc); 2099 #elif defined(RGFW_MACOS) 2100 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType)0); 2101 #else 2102 win->src.EGL_display = eglGetDisplay((EGLNativeDisplayType) win->src.display); 2103 #endif 2104 2105 EGLint major, minor; 2106 2107 eglInitialize(win->src.EGL_display, &major, &minor); 2108 2109 #ifndef EGL_OPENGL_ES1_BIT 2110 #define EGL_OPENGL_ES1_BIT 0x1 2111 #endif 2112 2113 EGLint egl_config[] = { 2114 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 2115 EGL_RENDERABLE_TYPE, 2116 #ifdef RGFW_OPENGL_ES1 2117 EGL_OPENGL_ES1_BIT, 2118 #elif defined(RGFW_OPENGL_ES3) 2119 EGL_OPENGL_ES3_BIT, 2120 #elif defined(RGFW_OPENGL_ES2) 2121 EGL_OPENGL_ES2_BIT, 2122 #else 2123 EGL_OPENGL_BIT, 2124 #endif 2125 EGL_NONE, EGL_NONE 2126 }; 2127 2128 EGLConfig config; 2129 EGLint numConfigs; 2130 eglChooseConfig(win->src.EGL_display, egl_config, &config, 1, &numConfigs); 2131 2132 #if defined(RGFW_MACOS) 2133 void* layer = RGFW_cocoaGetLayer(); 2134 2135 RGFW_window_cocoaSetLayer(win, layer); 2136 2137 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) layer, NULL); 2138 #else 2139 win->src.EGL_surface = eglCreateWindowSurface(win->src.EGL_display, config, (EGLNativeWindowType) win->src.window, NULL); 2140 #endif 2141 2142 EGLint attribs[] = { 2143 EGL_CONTEXT_CLIENT_VERSION, 2144 #ifdef RGFW_OPENGL_ES1 2145 1, 2146 #else 2147 2, 2148 #endif 2149 EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE, EGL_NONE 2150 }; 2151 2152 size_t index = 4; 2153 RGFW_GL_ADD_ATTRIB(EGL_STENCIL_SIZE, RGFW_STENCIL); 2154 RGFW_GL_ADD_ATTRIB(EGL_SAMPLES, RGFW_SAMPLES); 2155 2156 if (RGFW_DOUBLE_BUFFER) 2157 RGFW_GL_ADD_ATTRIB(EGL_RENDER_BUFFER, EGL_BACK_BUFFER); 2158 2159 if (RGFW_majorVersion) { 2160 attribs[1] = RGFW_majorVersion; 2161 2162 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MAJOR_VERSION, RGFW_majorVersion); 2163 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_MINOR_VERSION, RGFW_minorVersion); 2164 2165 if (RGFW_profile == RGFW_GL_CORE) { 2166 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT); 2167 } 2168 else { 2169 RGFW_GL_ADD_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); 2170 } 2171 2172 } 2173 2174 #if defined(RGFW_OPENGL_ES1) || defined(RGFW_OPENGL_ES2) || defined(RGFW_OPENGL_ES3) 2175 eglBindAPI(EGL_OPENGL_ES_API); 2176 #else 2177 eglBindAPI(EGL_OPENGL_API); 2178 #endif 2179 2180 win->src.EGL_context = eglCreateContext(win->src.EGL_display, config, EGL_NO_CONTEXT, attribs); 2181 2182 if (win->src.EGL_context == NULL) 2183 fprintf(stderr, "failed to create an EGL opengl context\n"); 2184 2185 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); 2186 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); 2187 } 2188 2189 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { 2190 eglMakeCurrent(win->src.EGL_display, win->src.EGL_surface, win->src.EGL_surface, win->src.EGL_context); 2191 } 2192 2193 #ifdef RGFW_APPLE 2194 void* RGFWnsglFramework = NULL; 2195 #elif defined(RGFW_WINDOWS) 2196 static HMODULE wglinstance = NULL; 2197 #endif 2198 2199 void* RGFW_getProcAddress(const char* procname) { 2200 #if defined(RGFW_WINDOWS) 2201 void* proc = (void*) GetProcAddress(wglinstance, procname); 2202 2203 if (proc) 2204 return proc; 2205 #endif 2206 2207 return (void*) eglGetProcAddress(procname); 2208 } 2209 2210 void RGFW_closeEGL(RGFW_window* win) { 2211 eglDestroySurface(win->src.EGL_display, win->src.EGL_surface); 2212 eglDestroyContext(win->src.EGL_display, win->src.EGL_context); 2213 2214 eglTerminate(win->src.EGL_display); 2215 } 2216 2217 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { 2218 assert(win != NULL); 2219 2220 eglSwapInterval(win->src.EGL_display, swapInterval); 2221 2222 } 2223 #endif /* RGFW_EGL */ 2224 2225 /* 2226 end of RGFW_EGL defines 2227 */ 2228 2229 /* OPENGL Normal / EGL defines only (no OS MESA) Ends here */ 2230 2231 #elif defined(RGFW_OSMESA) /* OSmesa only */ 2232 RGFWDEF void RGFW_OSMesa_reorganize(void); 2233 2234 /* reorganize buffer for osmesa */ 2235 void RGFW_OSMesa_reorganize(void) { 2236 u8* row = (u8*) RGFW_MALLOC(win->r.w * 3); 2237 2238 i32 half_height = win->r.h / 2; 2239 i32 stride = win->r.w * 3; 2240 2241 i32 y; 2242 for (y = 0; y < half_height; ++y) { 2243 i32 top_offset = y * stride; 2244 i32 bottom_offset = (win->r.h - y - 1) * stride; 2245 memcpy(row, win->buffer + top_offset, stride); 2246 memcpy(win->buffer + top_offset, win->buffer + bottom_offset, stride); 2247 memcpy(win->buffer + bottom_offset, row, stride); 2248 } 2249 2250 RGFW_FREE(row); 2251 } 2252 #endif /* RGFW_OSMesa */ 2253 2254 #endif /* RGFW_GL (OpenGL, EGL, OSMesa )*/ 2255 2256 /* 2257 This is where OS specific stuff starts 2258 */ 2259 2260 2261 #if defined(RGFW_WAYLAND) || defined(RGFW_X11) 2262 int RGFW_eventWait_forceStop[] = {0, 0, 0}; /* for wait events */ 2263 2264 #ifdef __linux__ 2265 #include <linux/joystick.h> 2266 #include <fcntl.h> 2267 #include <unistd.h> 2268 2269 RGFW_Event* RGFW_linux_updateJoystick(RGFW_window* win) { 2270 static int xAxis = 0, yAxis = 0; 2271 u8 i; 2272 for (i = 0; i < RGFW_joystickCount; i++) { 2273 struct js_event e; 2274 2275 2276 if (RGFW_joysticks[i] == 0) 2277 continue; 2278 2279 i32 flags = fcntl(RGFW_joysticks[i], F_GETFL, 0); 2280 fcntl(RGFW_joysticks[i], F_SETFL, flags | O_NONBLOCK); 2281 2282 ssize_t bytes; 2283 while ((bytes = read(RGFW_joysticks[i], &e, sizeof(e))) > 0) { 2284 switch (e.type) { 2285 case JS_EVENT_BUTTON: 2286 win->event.type = e.value ? RGFW_jsButtonPressed : RGFW_jsButtonReleased; 2287 win->event.button = e.number; 2288 RGFW_jsPressed[i][e.number] = e.value; 2289 RGFW_jsButtonCallback(win, i, e.number, e.value); 2290 return &win->event; 2291 case JS_EVENT_AXIS: 2292 ioctl(RGFW_joysticks[i], JSIOCGAXES, &win->event.axisesCount); 2293 2294 if ((e.number == 0 || e.number % 2) && e.number != 1) 2295 xAxis = e.value; 2296 else 2297 yAxis = e.value; 2298 2299 win->event.axis[e.number / 2].x = xAxis; 2300 win->event.axis[e.number / 2].y = yAxis; 2301 win->event.type = RGFW_jsAxisMove; 2302 win->event.joystick = i; 2303 RGFW_jsAxisCallback(win, i, win->event.axis, win->event.axisesCount); 2304 return &win->event; 2305 2306 default: break; 2307 } 2308 } 2309 } 2310 2311 return NULL; 2312 } 2313 2314 #endif 2315 #endif 2316 2317 /* 2318 2319 2320 Start of Linux / Unix defines 2321 2322 2323 */ 2324 2325 #ifdef RGFW_X11 2326 #ifndef RGFW_NO_X11_CURSOR 2327 #include <X11/Xcursor/Xcursor.h> 2328 #endif 2329 #include <dlfcn.h> 2330 2331 #ifndef RGFW_NO_DPI 2332 #include <X11/extensions/Xrandr.h> 2333 #include <X11/Xresource.h> 2334 #endif 2335 2336 #include <X11/Xutil.h> 2337 #include <X11/Xatom.h> 2338 #include <X11/keysymdef.h> 2339 #include <unistd.h> 2340 2341 #include <X11/XKBlib.h> /* for converting keycode to string */ 2342 #include <X11/cursorfont.h> /* for hiding */ 2343 #include <X11/extensions/shapeconst.h> 2344 #include <X11/extensions/shape.h> 2345 #include <X11/extensions/XInput2.h> 2346 2347 #include <limits.h> /* for data limits (mainly used in drag and drop functions) */ 2348 #include <poll.h> 2349 2350 2351 #ifdef __linux__ 2352 #include <linux/joystick.h> 2353 #endif 2354 2355 u8 RGFW_mouseIconSrc[] = { XC_arrow, XC_left_ptr, XC_xterm, XC_crosshair, XC_hand2, XC_sb_h_double_arrow, XC_sb_v_double_arrow, XC_bottom_left_corner, XC_bottom_right_corner, XC_fleur, XC_X_cursor}; 2356 /*atoms needed for drag and drop*/ 2357 Atom XdndAware, XdndTypeList, XdndSelection, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, XdndActionCopy, XtextPlain, XtextUriList; 2358 2359 Atom wm_delete_window = 0; 2360 2361 #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) 2362 typedef XcursorImage* (*PFN_XcursorImageCreate)(int, int); 2363 typedef void (*PFN_XcursorImageDestroy)(XcursorImage*); 2364 typedef Cursor(*PFN_XcursorImageLoadCursor)(Display*, const XcursorImage*); 2365 #endif 2366 #ifdef RGFW_OPENGL 2367 typedef GLXContext(*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); 2368 #endif 2369 2370 #if !defined(RGFW_NO_X11_XI_PRELOAD) 2371 typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); 2372 PFN_XISelectEvents XISelectEventsSrc = NULL; 2373 #define XISelectEvents XISelectEventsSrc 2374 2375 void* X11Xihandle = NULL; 2376 #endif 2377 2378 #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) 2379 PFN_XcursorImageLoadCursor XcursorImageLoadCursorSrc = NULL; 2380 PFN_XcursorImageCreate XcursorImageCreateSrc = NULL; 2381 PFN_XcursorImageDestroy XcursorImageDestroySrc = NULL; 2382 2383 #define XcursorImageLoadCursor XcursorImageLoadCursorSrc 2384 #define XcursorImageCreate XcursorImageCreateSrc 2385 #define XcursorImageDestroy XcursorImageDestroySrc 2386 2387 void* X11Cursorhandle = NULL; 2388 #endif 2389 2390 u32 RGFW_windowsOpen = 0; 2391 2392 #ifdef RGFW_OPENGL 2393 void* RGFW_getProcAddress(const char* procname) { return (void*) glXGetProcAddress((GLubyte*) procname); } 2394 #endif 2395 2396 RGFWDEF void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi); 2397 void RGFW_init_buffer(RGFW_window* win, XVisualInfo* vi) { 2398 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 2399 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) 2400 RGFW_bufferSize = RGFW_getScreenSize(); 2401 2402 win->buffer = (u8*)RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); 2403 2404 #ifdef RGFW_OSMESA 2405 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); 2406 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); 2407 #endif 2408 2409 win->src.bitmap = XCreateImage( 2410 win->src.display, XDefaultVisual(win->src.display, vi->screen), 2411 vi->depth, 2412 ZPixmap, 0, NULL, RGFW_bufferSize.w, RGFW_bufferSize.h, 2413 32, 0 2414 ); 2415 2416 win->src.gc = XCreateGC(win->src.display, win->src.window, 0, NULL); 2417 2418 #else 2419 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ 2420 RGFW_UNUSED(vi) 2421 #endif 2422 } 2423 2424 2425 2426 void RGFW_window_setBorder(RGFW_window* win, u8 border) { 2427 static Atom _MOTIF_WM_HINTS = 0; 2428 if (_MOTIF_WM_HINTS == 0 ) 2429 _MOTIF_WM_HINTS = XInternAtom(win->src.display, "_MOTIF_WM_HINTS", False); 2430 2431 struct __x11WindowHints { 2432 unsigned long flags, functions, decorations, status; 2433 long input_mode; 2434 } hints; 2435 hints.flags = (1L << 1); 2436 hints.decorations = border; 2437 2438 XChangeProperty( 2439 win->src.display, win->src.window, 2440 _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 2441 32, PropModeReplace, (u8*)&hints, 5 2442 ); 2443 } 2444 2445 void RGFW_releaseCursor(RGFW_window* win) { 2446 XUngrabPointer(win->src.display, CurrentTime); 2447 2448 /* disable raw input */ 2449 unsigned char mask[] = { 0 }; 2450 XIEventMask em; 2451 em.deviceid = XIAllMasterDevices; 2452 em.mask_len = sizeof(mask); 2453 em.mask = mask; 2454 2455 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); 2456 } 2457 2458 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { 2459 /* enable raw input */ 2460 unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; 2461 XISetMask(mask, XI_RawMotion); 2462 2463 XIEventMask em; 2464 em.deviceid = XIAllMasterDevices; 2465 em.mask_len = sizeof(mask); 2466 em.mask = mask; 2467 2468 XISelectEvents(win->src.display, XDefaultRootWindow(win->src.display), &em, 1); 2469 2470 XGrabPointer(win->src.display, win->src.window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); 2471 2472 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (i32)(r.w / 2), win->r.y + (i32)(r.h / 2))); 2473 } 2474 2475 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { 2476 #if !defined(RGFW_NO_X11_CURSOR) && !defined(RGFW_NO_X11_CURSOR_PRELOAD) 2477 if (X11Cursorhandle == NULL) { 2478 #if defined(__CYGWIN__) 2479 X11Cursorhandle = dlopen("libXcursor-1.so", RTLD_LAZY | RTLD_LOCAL); 2480 #elif defined(__OpenBSD__) || defined(__NetBSD__) 2481 X11Cursorhandle = dlopen("libXcursor.so", RTLD_LAZY | RTLD_LOCAL); 2482 #else 2483 X11Cursorhandle = dlopen("libXcursor.so.1", RTLD_LAZY | RTLD_LOCAL); 2484 #endif 2485 2486 XcursorImageCreateSrc = (PFN_XcursorImageCreate) dlsym(X11Cursorhandle, "XcursorImageCreate"); 2487 XcursorImageDestroySrc = (PFN_XcursorImageDestroy) dlsym(X11Cursorhandle, "XcursorImageDestroy"); 2488 XcursorImageLoadCursorSrc = (PFN_XcursorImageLoadCursor) dlsym(X11Cursorhandle, "XcursorImageLoadCursor"); 2489 } 2490 #endif 2491 2492 #if !defined(RGFW_NO_X11_XI_PRELOAD) 2493 if (X11Xihandle == NULL) { 2494 #if defined(__CYGWIN__) 2495 X11Xihandle = dlopen("libXi-6.so", RTLD_LAZY | RTLD_LOCAL); 2496 #elif defined(__OpenBSD__) || defined(__NetBSD__) 2497 X11Xihandle = dlopen("libXi.so", RTLD_LAZY | RTLD_LOCAL); 2498 #else 2499 X11Xihandle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_LOCAL); 2500 #endif 2501 2502 XISelectEventsSrc = (PFN_XISelectEvents) dlsym(X11Xihandle, "XISelectEvents"); 2503 } 2504 #endif 2505 2506 XInitThreads(); /*!< init X11 threading*/ 2507 2508 if (args & RGFW_OPENGL_SOFTWARE) 2509 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); 2510 2511 RGFW_window* win = RGFW_window_basic_init(rect, args); 2512 2513 u64 event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask | FocusChangeMask | LeaveWindowMask | EnterWindowMask | ExposureMask; /*!< X11 events accepted*/ 2514 2515 #ifdef RGFW_OPENGL 2516 u32* visual_attribs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE); 2517 i32 fbcount; 2518 GLXFBConfig* fbc = glXChooseFBConfig((Display*) win->src.display, DefaultScreen(win->src.display), (i32*) visual_attribs, &fbcount); 2519 2520 i32 best_fbc = -1; 2521 2522 if (fbcount == 0) { 2523 printf("Failed to find any valid GLX visual configs\n"); 2524 return NULL; 2525 } 2526 2527 u32 i; 2528 for (i = 0; i < (u32)fbcount; i++) { 2529 XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, fbc[i]); 2530 if (vi == NULL) 2531 continue; 2532 2533 XFree(vi); 2534 2535 i32 samp_buf, samples; 2536 glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); 2537 glXGetFBConfigAttrib((Display*) win->src.display, fbc[i], GLX_SAMPLES, &samples); 2538 2539 if ((!(args & RGFW_TRANSPARENT_WINDOW) || vi->depth == 32) && 2540 (best_fbc < 0 || samp_buf) && (samples == RGFW_SAMPLES || best_fbc == -1)) { 2541 best_fbc = i; 2542 } 2543 } 2544 2545 if (best_fbc == -1) { 2546 printf("Failed to get a valid GLX visual\n"); 2547 return NULL; 2548 } 2549 2550 GLXFBConfig bestFbc = fbc[best_fbc]; 2551 2552 /* Get a visual */ 2553 XVisualInfo* vi = glXGetVisualFromFBConfig((Display*) win->src.display, bestFbc); 2554 2555 XFree(fbc); 2556 #else 2557 XVisualInfo viNorm; 2558 2559 viNorm.visual = DefaultVisual((Display*) win->src.display, DefaultScreen((Display*) win->src.display)); 2560 2561 viNorm.depth = 0; 2562 XVisualInfo* vi = &viNorm; 2563 2564 XMatchVisualInfo((Display*) win->src.display, DefaultScreen((Display*) win->src.display), 32, TrueColor, vi); /*!< for RGBA backgrounds*/ 2565 #endif 2566 /* make X window attrubutes*/ 2567 XSetWindowAttributes swa; 2568 Colormap cmap; 2569 2570 swa.colormap = cmap = XCreateColormap((Display*) win->src.display, 2571 DefaultRootWindow(win->src.display), 2572 vi->visual, AllocNone); 2573 2574 swa.background_pixmap = None; 2575 swa.border_pixel = 0; 2576 swa.event_mask = event_mask; 2577 2578 swa.background_pixel = 0; 2579 2580 /* create the window*/ 2581 win->src.window = XCreateWindow((Display*) win->src.display, DefaultRootWindow((Display*) win->src.display), win->r.x, win->r.y, win->r.w, win->r.h, 2582 0, vi->depth, InputOutput, vi->visual, 2583 CWColormap | CWBorderPixel | CWBackPixel | CWEventMask, &swa); 2584 2585 XFreeColors((Display*) win->src.display, cmap, NULL, 0, 0); 2586 2587 #ifdef RGFW_OPENGL 2588 XFree(vi); 2589 #endif 2590 2591 // In your .desktop app, if you set the property 2592 // StartupWMClass=RGFW that will assoicate the launcher icon 2593 // with your application - robrohan 2594 2595 if (RGFW_className == NULL) 2596 RGFW_className = (char*)name; 2597 2598 XClassHint *hint = XAllocClassHint(); 2599 assert(hint != NULL); 2600 hint->res_class = (char*)RGFW_className; 2601 hint->res_name = (char*)name; // just use the window name as the app name 2602 XSetClassHint((Display*) win->src.display, win->src.window, hint); 2603 XFree(hint); 2604 2605 if ((args & RGFW_NO_INIT_API) == 0) { 2606 #ifdef RGFW_OPENGL /* This is the second part of setting up opengl. This is where we ask OpenGL for a specific version. */ 2607 i32 context_attribs[7] = { 0, 0, 0, 0, 0, 0, 0 }; 2608 context_attribs[0] = GLX_CONTEXT_PROFILE_MASK_ARB; 2609 if (RGFW_profile == RGFW_GL_CORE) 2610 context_attribs[1] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; 2611 else 2612 context_attribs[1] = GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB; 2613 2614 if (RGFW_majorVersion || RGFW_minorVersion) { 2615 context_attribs[2] = GLX_CONTEXT_MAJOR_VERSION_ARB; 2616 context_attribs[3] = RGFW_majorVersion; 2617 context_attribs[4] = GLX_CONTEXT_MINOR_VERSION_ARB; 2618 context_attribs[5] = RGFW_minorVersion; 2619 } 2620 2621 glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; 2622 glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) 2623 glXGetProcAddressARB((GLubyte*) "glXCreateContextAttribsARB"); 2624 2625 GLXContext ctx = NULL; 2626 2627 if (RGFW_root != NULL) 2628 ctx = RGFW_root->src.ctx; 2629 2630 win->src.ctx = glXCreateContextAttribsARB((Display*) win->src.display, bestFbc, ctx, True, context_attribs); 2631 #endif 2632 if (RGFW_root == NULL) 2633 RGFW_root = win; 2634 2635 RGFW_init_buffer(win, vi); 2636 } 2637 2638 2639 #ifndef RGFW_NO_MONITOR 2640 if (args & RGFW_SCALE_TO_MONITOR) 2641 RGFW_window_scaleToMonitor(win); 2642 #endif 2643 2644 if (args & RGFW_CENTER) { 2645 RGFW_area screenR = RGFW_getScreenSize(); 2646 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); 2647 } 2648 2649 if (args & RGFW_NO_RESIZE) { /* make it so the user can't resize the window*/ 2650 XSizeHints* sh = XAllocSizeHints(); 2651 sh->flags = (1L << 4) | (1L << 5); 2652 sh->min_width = sh->max_width = win->r.w; 2653 sh->min_height = sh->max_height = win->r.h; 2654 2655 XSetWMSizeHints((Display*) win->src.display, (Drawable) win->src.window, sh, XA_WM_NORMAL_HINTS); 2656 XFree(sh); 2657 } 2658 2659 if (args & RGFW_NO_BORDER) { 2660 RGFW_window_setBorder(win, 0); 2661 } 2662 2663 XSelectInput((Display*) win->src.display, (Drawable) win->src.window, event_mask); /*!< tell X11 what events we want*/ 2664 2665 /* make it so the user can't close the window until the program does*/ 2666 if (wm_delete_window == 0) 2667 wm_delete_window = XInternAtom((Display*) win->src.display, "WM_DELETE_WINDOW", False); 2668 2669 XSetWMProtocols((Display*) win->src.display, (Drawable) win->src.window, &wm_delete_window, 1); 2670 2671 /* connect the context to the window*/ 2672 #ifdef RGFW_OPENGL 2673 if ((args & RGFW_NO_INIT_API) == 0) 2674 glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); 2675 #endif 2676 2677 /* set the background*/ 2678 XStoreName((Display*) win->src.display, (Drawable) win->src.window, name); /*!< set the name*/ 2679 2680 XMapWindow((Display*) win->src.display, (Drawable) win->src.window); /* draw the window*/ 2681 XMoveWindow((Display*) win->src.display, (Drawable) win->src.window, win->r.x, win->r.y); /*!< move the window to it's proper cords*/ 2682 2683 if (args & RGFW_ALLOW_DND) { /* init drag and drop atoms and turn on drag and drop for this window */ 2684 win->_winArgs |= RGFW_ALLOW_DND; 2685 2686 XdndTypeList = XInternAtom((Display*) win->src.display, "XdndTypeList", False); 2687 XdndSelection = XInternAtom((Display*) win->src.display, "XdndSelection", False); 2688 2689 /* client messages */ 2690 XdndEnter = XInternAtom((Display*) win->src.display, "XdndEnter", False); 2691 XdndPosition = XInternAtom((Display*) win->src.display, "XdndPosition", False); 2692 XdndStatus = XInternAtom((Display*) win->src.display, "XdndStatus", False); 2693 XdndLeave = XInternAtom((Display*) win->src.display, "XdndLeave", False); 2694 XdndDrop = XInternAtom((Display*) win->src.display, "XdndDrop", False); 2695 XdndFinished = XInternAtom((Display*) win->src.display, "XdndFinished", False); 2696 2697 /* actions */ 2698 XdndActionCopy = XInternAtom((Display*) win->src.display, "XdndActionCopy", False); 2699 2700 XtextUriList = XInternAtom((Display*) win->src.display, "text/uri-list", False); 2701 XtextPlain = XInternAtom((Display*) win->src.display, "text/plain", False); 2702 2703 XdndAware = XInternAtom((Display*) win->src.display, "XdndAware", False); 2704 const u8 version = 5; 2705 2706 XChangeProperty((Display*) win->src.display, (Window) win->src.window, 2707 XdndAware, 4, 32, 2708 PropModeReplace, &version, 1); /*!< turns on drag and drop */ 2709 } 2710 2711 #ifdef RGFW_EGL 2712 if ((args & RGFW_NO_INIT_API) == 0) 2713 RGFW_createOpenGLContext(win); 2714 #endif 2715 2716 RGFW_window_setMouseDefault(win); 2717 2718 RGFW_windowsOpen++; 2719 2720 return win; /*return newly created window*/ 2721 } 2722 2723 RGFW_area RGFW_getScreenSize(void) { 2724 assert(RGFW_root != NULL); 2725 2726 Screen* scrn = DefaultScreenOfDisplay((Display*) RGFW_root->src.display); 2727 return RGFW_AREA(scrn->width, scrn->height); 2728 } 2729 2730 RGFW_point RGFW_getGlobalMousePoint(void) { 2731 assert(RGFW_root != NULL); 2732 2733 RGFW_point RGFWMouse; 2734 2735 i32 x, y; 2736 u32 z; 2737 Window window1, window2; 2738 XQueryPointer((Display*) RGFW_root->src.display, XDefaultRootWindow((Display*) RGFW_root->src.display), &window1, &window2, &RGFWMouse.x, &RGFWMouse.y, &x, &y, &z); 2739 2740 return RGFWMouse; 2741 } 2742 2743 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { 2744 assert(win != NULL); 2745 2746 RGFW_point RGFWMouse; 2747 2748 i32 x, y; 2749 u32 z; 2750 Window window1, window2; 2751 XQueryPointer((Display*) win->src.display, win->src.window, &window1, &window2, &x, &y, &RGFWMouse.x, &RGFWMouse.y, &z); 2752 2753 return RGFWMouse; 2754 } 2755 2756 int xAxis = 0, yAxis = 0; 2757 2758 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { 2759 assert(win != NULL); 2760 2761 static struct { 2762 long source, version; 2763 i32 format; 2764 } xdnd; 2765 2766 if (win->event.type == 0) 2767 RGFW_resetKey(); 2768 2769 if (win->event.type == RGFW_quit) { 2770 return NULL; 2771 } 2772 2773 win->event.type = 0; 2774 2775 #ifdef __linux__ 2776 RGFW_Event* event = RGFW_linux_updateJoystick(win); 2777 if (event != NULL) 2778 return event; 2779 #endif 2780 2781 XPending(win->src.display); 2782 2783 XEvent E; /*!< raw X11 event */ 2784 2785 /* if there is no unread qued events, get a new one */ 2786 if ((QLength(win->src.display) || XEventsQueued((Display*) win->src.display, QueuedAlready) + XEventsQueued((Display*) win->src.display, QueuedAfterReading)) 2787 && win->event.type != RGFW_quit 2788 ) 2789 XNextEvent((Display*) win->src.display, &E); 2790 else { 2791 return NULL; 2792 } 2793 2794 u32 i; 2795 win->event.type = 0; 2796 2797 2798 switch (E.type) { 2799 case KeyPress: 2800 case KeyRelease: { 2801 win->event.repeat = RGFW_FALSE; 2802 /* check if it's a real key release */ 2803 if (E.type == KeyRelease && XEventsQueued((Display*) win->src.display, QueuedAfterReading)) { /* get next event if there is one*/ 2804 XEvent NE; 2805 XPeekEvent((Display*) win->src.display, &NE); 2806 2807 if (E.xkey.time == NE.xkey.time && E.xkey.keycode == NE.xkey.keycode) /* check if the current and next are both the same*/ 2808 win->event.repeat = RGFW_TRUE; 2809 } 2810 2811 /* set event key data */ 2812 KeySym sym = (KeySym)XkbKeycodeToKeysym((Display*) win->src.display, E.xkey.keycode, 0, E.xkey.state & ShiftMask ? 1 : 0); 2813 win->event.keyCode = RGFW_apiKeyCodeToRGFW(E.xkey.keycode); 2814 2815 char* str = (char*)XKeysymToString(sym); 2816 if (str != NULL) 2817 strncpy(win->event.keyName, str, 16); 2818 2819 win->event.keyName[15] = '\0'; 2820 2821 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); 2822 2823 /* get keystate data */ 2824 win->event.type = (E.type == KeyPress) ? RGFW_keyPressed : RGFW_keyReleased; 2825 2826 XKeyboardState keystate; 2827 XGetKeyboardControl((Display*) win->src.display, &keystate); 2828 2829 RGFW_updateLockState(win, (keystate.led_mask & 1), (keystate.led_mask & 2)); 2830 RGFW_keyboard[win->event.keyCode].current = (E.type == KeyPress); 2831 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, (E.type == KeyPress)); 2832 break; 2833 } 2834 case ButtonPress: 2835 case ButtonRelease: 2836 win->event.type = RGFW_mouseButtonPressed + (E.type == ButtonRelease); // the events match 2837 2838 switch(win->event.button) { 2839 case RGFW_mouseScrollUp: 2840 win->event.scroll = 1; 2841 break; 2842 case RGFW_mouseScrollDown: 2843 win->event.scroll = -1; 2844 break; 2845 default: break; 2846 } 2847 2848 win->event.button = E.xbutton.button; 2849 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 2850 2851 if (win->event.repeat == RGFW_FALSE) 2852 win->event.repeat = RGFW_isPressed(win, win->event.keyCode); 2853 2854 RGFW_mouseButtons[win->event.button].current = (E.type == ButtonPress); 2855 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, (E.type == ButtonPress)); 2856 break; 2857 2858 case MotionNotify: 2859 win->event.point.x = E.xmotion.x; 2860 win->event.point.y = E.xmotion.y; 2861 2862 if ((win->_winArgs & RGFW_HOLD_MOUSE)) { 2863 win->event.point.y = E.xmotion.y; 2864 2865 win->event.point.x = win->_lastMousePoint.x - abs(win->event.point.x); 2866 win->event.point.y = win->_lastMousePoint.y - abs(win->event.point.y); 2867 } 2868 2869 win->_lastMousePoint = RGFW_POINT(E.xmotion.x, E.xmotion.y); 2870 2871 win->event.type = RGFW_mousePosChanged; 2872 RGFW_mousePosCallback(win, win->event.point); 2873 break; 2874 2875 case GenericEvent: { 2876 /* MotionNotify is used for mouse events if the mouse isn't held */ 2877 if (!(win->_winArgs & RGFW_HOLD_MOUSE)) { 2878 XFreeEventData(win->src.display, &E.xcookie); 2879 break; 2880 } 2881 2882 XGetEventData(win->src.display, &E.xcookie); 2883 if (E.xcookie.evtype == XI_RawMotion) { 2884 XIRawEvent *raw = (XIRawEvent *)E.xcookie.data; 2885 if (raw->valuators.mask_len == 0) { 2886 XFreeEventData(win->src.display, &E.xcookie); 2887 break; 2888 } 2889 2890 double deltaX = 0.0f; 2891 double deltaY = 0.0f; 2892 2893 /* check if relative motion data exists where we think it does */ 2894 if (XIMaskIsSet(raw->valuators.mask, 0) != 0) 2895 deltaX += raw->raw_values[0]; 2896 if (XIMaskIsSet(raw->valuators.mask, 1) != 0) 2897 deltaY += raw->raw_values[1]; 2898 2899 win->event.point = RGFW_POINT((i32)deltaX, (i32)deltaY); 2900 2901 RGFW_window_moveMouse(win, RGFW_POINT(win->r.x + (win->r.w / 2), win->r.y + (win->r.h / 2))); 2902 2903 win->event.type = RGFW_mousePosChanged; 2904 RGFW_mousePosCallback(win, win->event.point); 2905 } 2906 2907 XFreeEventData(win->src.display, &E.xcookie); 2908 break; 2909 } 2910 2911 case Expose: 2912 win->event.type = RGFW_windowRefresh; 2913 RGFW_windowRefreshCallback(win); 2914 break; 2915 2916 case ClientMessage: 2917 /* if the client closed the window*/ 2918 if (E.xclient.data.l[0] == (i64) wm_delete_window) { 2919 win->event.type = RGFW_quit; 2920 RGFW_windowQuitCallback(win); 2921 break; 2922 } 2923 2924 /* reset DND values */ 2925 if (win->event.droppedFilesCount) { 2926 for (i = 0; i < win->event.droppedFilesCount; i++) 2927 win->event.droppedFiles[i][0] = '\0'; 2928 } 2929 2930 win->event.droppedFilesCount = 0; 2931 2932 if ((win->_winArgs & RGFW_ALLOW_DND) == 0) 2933 break; 2934 2935 XEvent reply = { ClientMessage }; 2936 reply.xclient.window = xdnd.source; 2937 reply.xclient.format = 32; 2938 reply.xclient.data.l[0] = (long) win->src.window; 2939 reply.xclient.data.l[1] = 0; 2940 reply.xclient.data.l[2] = None; 2941 2942 if (E.xclient.message_type == XdndEnter) { 2943 unsigned long count; 2944 Atom* formats; 2945 Atom real_formats[6]; 2946 2947 Bool list = E.xclient.data.l[1] & 1; 2948 2949 xdnd.source = E.xclient.data.l[0]; 2950 xdnd.version = E.xclient.data.l[1] >> 24; 2951 xdnd.format = None; 2952 2953 if (xdnd.version > 5) 2954 break; 2955 2956 if (list) { 2957 Atom actualType; 2958 i32 actualFormat; 2959 unsigned long bytesAfter; 2960 2961 XGetWindowProperty((Display*) win->src.display, 2962 xdnd.source, 2963 XdndTypeList, 2964 0, 2965 LONG_MAX, 2966 False, 2967 4, 2968 &actualType, 2969 &actualFormat, 2970 &count, 2971 &bytesAfter, 2972 (u8**) &formats); 2973 } else { 2974 count = 0; 2975 2976 if (E.xclient.data.l[2] != None) 2977 real_formats[count++] = E.xclient.data.l[2]; 2978 if (E.xclient.data.l[3] != None) 2979 real_formats[count++] = E.xclient.data.l[3]; 2980 if (E.xclient.data.l[4] != None) 2981 real_formats[count++] = E.xclient.data.l[4]; 2982 2983 formats = real_formats; 2984 } 2985 2986 unsigned long i; 2987 for (i = 0; i < count; i++) { 2988 if (formats[i] == XtextUriList || formats[i] == XtextPlain) { 2989 xdnd.format = formats[i]; 2990 break; 2991 } 2992 } 2993 2994 if (list) { 2995 XFree(formats); 2996 } 2997 2998 break; 2999 } 3000 if (E.xclient.message_type == XdndPosition) { 3001 const i32 xabs = (E.xclient.data.l[2] >> 16) & 0xffff; 3002 const i32 yabs = (E.xclient.data.l[2]) & 0xffff; 3003 Window dummy; 3004 i32 xpos, ypos; 3005 3006 if (xdnd.version > 5) 3007 break; 3008 3009 XTranslateCoordinates((Display*) win->src.display, 3010 XDefaultRootWindow((Display*) win->src.display), 3011 (Window) win->src.window, 3012 xabs, yabs, 3013 &xpos, &ypos, 3014 &dummy); 3015 3016 win->event.point.x = xpos; 3017 win->event.point.y = ypos; 3018 3019 reply.xclient.window = xdnd.source; 3020 reply.xclient.message_type = XdndStatus; 3021 3022 if (xdnd.format) { 3023 reply.xclient.data.l[1] = 1; 3024 if (xdnd.version >= 2) 3025 reply.xclient.data.l[4] = XdndActionCopy; 3026 } 3027 3028 XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply); 3029 XFlush((Display*) win->src.display); 3030 break; 3031 } 3032 3033 if (E.xclient.message_type != XdndDrop) 3034 break; 3035 3036 if (xdnd.version > 5) 3037 break; 3038 3039 win->event.type = RGFW_dnd_init; 3040 3041 if (xdnd.format) { 3042 Time time = CurrentTime; 3043 3044 if (xdnd.version >= 1) 3045 time = E.xclient.data.l[2]; 3046 3047 XConvertSelection((Display*) win->src.display, 3048 XdndSelection, 3049 xdnd.format, 3050 XdndSelection, 3051 (Window) win->src.window, 3052 time); 3053 } else if (xdnd.version >= 2) { 3054 XEvent reply = { ClientMessage }; 3055 3056 XSendEvent((Display*) win->src.display, xdnd.source, 3057 False, NoEventMask, &reply); 3058 XFlush((Display*) win->src.display); 3059 } 3060 3061 RGFW_dndInitCallback(win, win->event.point); 3062 break; 3063 case SelectionNotify: { 3064 /* this is only for checking for xdnd drops */ 3065 if (E.xselection.property != XdndSelection || !(win->_winArgs | RGFW_ALLOW_DND)) 3066 break; 3067 3068 char* data; 3069 unsigned long result; 3070 3071 Atom actualType; 3072 i32 actualFormat; 3073 unsigned long bytesAfter; 3074 3075 XGetWindowProperty((Display*) win->src.display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (u8**) &data); 3076 3077 if (result == 0) 3078 break; 3079 3080 /* 3081 SOURCED FROM GLFW _glfwParseUriList 3082 Copyright (c) 2002-2006 Marcus Geelnard 3083 Copyright (c) 2006-2019 Camilla Löwy 3084 */ 3085 3086 const char* prefix = (const char*)"file://"; 3087 3088 char* line; 3089 3090 win->event.droppedFilesCount = 0; 3091 3092 win->event.type = RGFW_dnd; 3093 3094 while ((line = strtok(data, "\r\n"))) { 3095 char path[RGFW_MAX_PATH]; 3096 3097 data = NULL; 3098 3099 if (line[0] == '#') 3100 continue; 3101 3102 char* l; 3103 for (l = line; 1; l++) { 3104 if ((l - line) > 7) 3105 break; 3106 else if (*l != prefix[(l - line)]) 3107 break; 3108 else if (*l == '\0' && prefix[(l - line)] == '\0') { 3109 line += 7; 3110 while (*line != '/') 3111 line++; 3112 break; 3113 } else if (*l == '\0') 3114 break; 3115 } 3116 3117 win->event.droppedFilesCount++; 3118 3119 size_t index = 0; 3120 while (*line) { 3121 if (line[0] == '%' && line[1] && line[2]) { 3122 const char digits[3] = { line[1], line[2], '\0' }; 3123 path[index] = (char) strtol(digits, NULL, 16); 3124 line += 2; 3125 } else 3126 path[index] = *line; 3127 3128 index++; 3129 line++; 3130 } 3131 path[index] = '\0'; 3132 strncpy(win->event.droppedFiles[win->event.droppedFilesCount - 1], path, index + 1); 3133 } 3134 3135 if (data) 3136 XFree(data); 3137 3138 if (xdnd.version >= 2) { 3139 reply.xclient.message_type = XdndFinished; 3140 reply.xclient.data.l[1] = result; 3141 reply.xclient.data.l[2] = XdndActionCopy; 3142 3143 XSendEvent((Display*) win->src.display, xdnd.source, False, NoEventMask, &reply); 3144 XFlush((Display*) win->src.display); 3145 } 3146 3147 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); 3148 break; 3149 } 3150 case FocusIn: 3151 win->event.inFocus = 1; 3152 win->event.type = RGFW_focusIn; 3153 RGFW_focusCallback(win, 1); 3154 break; 3155 3156 break; 3157 case FocusOut: 3158 win->event.inFocus = 0; 3159 win->event.type = RGFW_focusOut; 3160 RGFW_focusCallback(win, 0); 3161 break; 3162 3163 case EnterNotify: { 3164 win->event.type = RGFW_mouseEnter; 3165 win->event.point.x = E.xcrossing.x; 3166 win->event.point.y = E.xcrossing.y; 3167 RGFW_mouseNotifyCallBack(win, win->event.point, 1); 3168 break; 3169 } 3170 3171 case LeaveNotify: { 3172 win->event.type = RGFW_mouseLeave; 3173 RGFW_mouseNotifyCallBack(win, win->event.point, 0); 3174 break; 3175 } 3176 3177 case ConfigureNotify: { 3178 /* detect resize */ 3179 if (E.xconfigure.width != win->r.w || E.xconfigure.height != win->r.h) { 3180 win->event.type = RGFW_windowResized; 3181 win->r = RGFW_RECT(win->r.x, win->r.y, E.xconfigure.width, E.xconfigure.height); 3182 RGFW_windowResizeCallback(win, win->r); 3183 break; 3184 } 3185 3186 /* detect move */ 3187 if (E.xconfigure.x != win->r.x || E.xconfigure.y != win->r.y) { 3188 win->event.type = RGFW_windowMoved; 3189 win->r = RGFW_RECT(E.xconfigure.x, E.xconfigure.y, win->r.w, win->r.h); 3190 RGFW_windowMoveCallback(win, win->r); 3191 break; 3192 } 3193 3194 break; 3195 } 3196 default: { 3197 break; 3198 } 3199 } 3200 3201 XFlush((Display*) win->src.display); 3202 3203 if (win->event.type) 3204 return &win->event; 3205 else 3206 return NULL; 3207 } 3208 3209 void RGFW_window_move(RGFW_window* win, RGFW_point v) { 3210 assert(win != NULL); 3211 win->r.x = v.x; 3212 win->r.y = v.y; 3213 3214 XMoveWindow((Display*) win->src.display, (Window) win->src.window, v.x, v.y); 3215 } 3216 3217 3218 void RGFW_window_resize(RGFW_window* win, RGFW_area a) { 3219 assert(win != NULL); 3220 win->r.w = a.w; 3221 win->r.h = a.h; 3222 3223 XResizeWindow((Display*) win->src.display, (Window) win->src.window, a.w, a.h); 3224 } 3225 3226 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { 3227 assert(win != NULL); 3228 3229 if (a.w == 0 && a.h == 0) 3230 return; 3231 3232 XSizeHints hints; 3233 long flags; 3234 3235 XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags); 3236 3237 hints.flags |= PMinSize; 3238 3239 hints.min_width = a.w; 3240 hints.min_height = a.h; 3241 3242 XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints); 3243 } 3244 3245 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { 3246 assert(win != NULL); 3247 3248 if (a.w == 0 && a.h == 0) 3249 return; 3250 3251 XSizeHints hints; 3252 long flags; 3253 3254 XGetWMNormalHints(win->src.display, (Window) win->src.window, &hints, &flags); 3255 3256 hints.flags |= PMaxSize; 3257 3258 hints.max_width = a.w; 3259 hints.max_height = a.h; 3260 3261 XSetWMNormalHints(win->src.display, (Window) win->src.window, &hints); 3262 } 3263 3264 3265 void RGFW_window_minimize(RGFW_window* win) { 3266 assert(win != NULL); 3267 3268 XIconifyWindow(win->src.display, (Window) win->src.window, DefaultScreen(win->src.display)); 3269 XFlush(win->src.display); 3270 } 3271 3272 void RGFW_window_restore(RGFW_window* win) { 3273 assert(win != NULL); 3274 3275 XMapWindow(win->src.display, (Window) win->src.window); 3276 XFlush(win->src.display); 3277 } 3278 3279 void RGFW_window_setName(RGFW_window* win, char* name) { 3280 assert(win != NULL); 3281 3282 XStoreName((Display*) win->src.display, (Window) win->src.window, name); 3283 } 3284 3285 void* RGFW_libxshape = NULL; 3286 3287 #ifndef RGFW_NO_PASSTHROUGH 3288 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { 3289 assert(win != NULL); 3290 3291 #if defined(__CYGWIN__) 3292 RGFW_libxshape = dlopen("libXext-6.so", RTLD_LAZY | RTLD_LOCAL); 3293 #elif defined(__OpenBSD__) || defined(__NetBSD__) 3294 RGFW_libxshape = dlopen("libXext.so", RTLD_LAZY | RTLD_LOCAL); 3295 #else 3296 RGFW_libxshape = dlopen("libXext.so.6", RTLD_LAZY | RTLD_LOCAL); 3297 #endif 3298 3299 typedef void (* PFN_XShapeCombineMask)(Display*,Window,int,int,int,Pixmap,int); 3300 static PFN_XShapeCombineMask XShapeCombineMask; 3301 3302 typedef void (* PFN_XShapeCombineRegion)(Display*,Window,int,int,int,Region,int); 3303 static PFN_XShapeCombineRegion XShapeCombineRegion; 3304 3305 if (XShapeCombineMask != NULL) 3306 XShapeCombineMask = (PFN_XShapeCombineMask) dlsym(RGFW_libxshape, "XShapeCombineMask"); 3307 3308 if (XShapeCombineRegion != NULL) 3309 XShapeCombineRegion = (PFN_XShapeCombineRegion) dlsym(RGFW_libxshape, "XShapeCombineMask"); 3310 3311 if (passthrough) { 3312 Region region = XCreateRegion(); 3313 XShapeCombineRegion(win->src.display, win->src.window, ShapeInput, 0, 0, region, ShapeSet); 3314 XDestroyRegion(region); 3315 3316 return; 3317 } 3318 3319 XShapeCombineMask(win->src.display, win->src.window, ShapeInput, 0, 0, None, ShapeSet); 3320 } 3321 #endif 3322 3323 /* 3324 the majority function is sourced from GLFW 3325 */ 3326 3327 void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { 3328 assert(win != NULL); 3329 3330 i32 longCount = 2 + a.w * a.h; 3331 3332 u64* X11Icon = (u64*) RGFW_MALLOC(longCount * sizeof(u64)); 3333 u64* target = X11Icon; 3334 3335 *target++ = a.w; 3336 *target++ = a.h; 3337 3338 u32 i; 3339 3340 for (i = 0; i < a.w * a.h; i++) { 3341 if (channels == 3) 3342 *target++ = ((icon[i * 3 + 0]) << 16) | 3343 ((icon[i * 3 + 1]) << 8) | 3344 ((icon[i * 3 + 2]) << 0) | 3345 (0xFF << 24); 3346 3347 else if (channels == 4) 3348 *target++ = ((icon[i * 4 + 0]) << 16) | 3349 ((icon[i * 4 + 1]) << 8) | 3350 ((icon[i * 4 + 2]) << 0) | 3351 ((icon[i * 4 + 3]) << 24); 3352 } 3353 3354 static Atom NET_WM_ICON = 0; 3355 if (NET_WM_ICON == 0) 3356 NET_WM_ICON = XInternAtom((Display*) win->src.display, "_NET_WM_ICON", False); 3357 3358 XChangeProperty((Display*) win->src.display, (Window) win->src.window, 3359 NET_WM_ICON, 3360 6, 32, 3361 PropModeReplace, 3362 (u8*) X11Icon, 3363 longCount); 3364 3365 RGFW_FREE(X11Icon); 3366 3367 XFlush((Display*) win->src.display); 3368 } 3369 3370 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { 3371 assert(win != NULL); 3372 3373 #ifndef RGFW_NO_X11_CURSOR 3374 XcursorImage* native = XcursorImageCreate(a.w, a.h); 3375 native->xhot = 0; 3376 native->yhot = 0; 3377 3378 u8* source = (u8*) image; 3379 XcursorPixel* target = native->pixels; 3380 3381 u32 i; 3382 for (i = 0; i < a.w * a.h; i++, target++, source += 4) { 3383 u8 alpha = 0xFF; 3384 if (channels == 4) 3385 alpha = source[3]; 3386 3387 *target = (alpha << 24) | (((source[0] * alpha) / 255) << 16) | (((source[1] * alpha) / 255) << 8) | (((source[2] * alpha) / 255) << 0); 3388 } 3389 3390 Cursor cursor = XcursorImageLoadCursor((Display*) win->src.display, native); 3391 XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor); 3392 3393 XFreeCursor((Display*) win->src.display, (Cursor) cursor); 3394 XcursorImageDestroy(native); 3395 #else 3396 RGFW_UNUSED(image) RGFW_UNUSED(a.w) RGFW_UNUSED(channels) 3397 #endif 3398 } 3399 3400 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { 3401 assert(win != NULL); 3402 3403 XEvent event; 3404 XQueryPointer(win->src.display, DefaultRootWindow(win->src.display), 3405 &event.xbutton.root, &event.xbutton.window, 3406 &event.xbutton.x_root, &event.xbutton.y_root, 3407 &event.xbutton.x, &event.xbutton.y, 3408 &event.xbutton.state); 3409 3410 if (event.xbutton.x == v.x && event.xbutton.y == v.y) 3411 return; 3412 3413 XWarpPointer(win->src.display, None, win->src.window, 0, 0, 0, 0, (int) v.x - win->r.x, (int) v.y - win->r.y); 3414 } 3415 3416 RGFWDEF void RGFW_window_disableMouse(RGFW_window* win) { 3417 RGFW_UNUSED(win); 3418 } 3419 3420 void RGFW_window_setMouseDefault(RGFW_window* win) { 3421 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW); 3422 } 3423 3424 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { 3425 assert(win != NULL); 3426 3427 if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u8))) 3428 return; 3429 3430 mouse = RGFW_mouseIconSrc[mouse]; 3431 3432 Cursor cursor = XCreateFontCursor((Display*) win->src.display, mouse); 3433 XDefineCursor((Display*) win->src.display, (Window) win->src.window, (Cursor) cursor); 3434 3435 XFreeCursor((Display*) win->src.display, (Cursor) cursor); 3436 } 3437 3438 void RGFW_window_hide(RGFW_window* win) { 3439 XMapWindow(win->src.display, win->src.window); 3440 } 3441 3442 void RGFW_window_show(RGFW_window* win) { 3443 XUnmapWindow(win->src.display, win->src.window); 3444 } 3445 3446 /* 3447 the majority function is sourced from GLFW 3448 */ 3449 char* RGFW_readClipboard(size_t* size) { 3450 static Atom UTF8 = 0; 3451 if (UTF8 == 0) 3452 UTF8 = XInternAtom(RGFW_root->src.display, "UTF8_STRING", True); 3453 3454 XEvent event; 3455 int format; 3456 unsigned long N, sizeN; 3457 char* data, * s = NULL; 3458 Atom target; 3459 Atom CLIPBOARD = 0, XSEL_DATA = 0; 3460 3461 if (CLIPBOARD == 0) { 3462 CLIPBOARD = XInternAtom(RGFW_root->src.display, "CLIPBOARD", 0); 3463 XSEL_DATA = XInternAtom(RGFW_root->src.display, "XSEL_DATA", 0); 3464 } 3465 3466 XConvertSelection(RGFW_root->src.display, CLIPBOARD, UTF8, XSEL_DATA, RGFW_root->src.window, CurrentTime); 3467 XSync(RGFW_root->src.display, 0); 3468 XNextEvent(RGFW_root->src.display, &event); 3469 3470 if (event.type != SelectionNotify || event.xselection.selection != CLIPBOARD || event.xselection.property == 0) 3471 return NULL; 3472 3473 XGetWindowProperty(event.xselection.display, event.xselection.requestor, 3474 event.xselection.property, 0L, (~0L), 0, AnyPropertyType, &target, 3475 &format, &sizeN, &N, (unsigned char**) &data); 3476 3477 if (target == UTF8 || target == XA_STRING) { 3478 s = (char*)RGFW_MALLOC(sizeof(char) * sizeN); 3479 strncpy(s, data, sizeN); 3480 s[sizeN] = '\0'; 3481 XFree(data); 3482 } 3483 3484 XDeleteProperty(event.xselection.display, event.xselection.requestor, event.xselection.property); 3485 3486 if (s != NULL && size != NULL) 3487 *size = sizeN; 3488 3489 return s; 3490 } 3491 3492 /* 3493 almost all of this function is sourced from GLFW 3494 */ 3495 void RGFW_writeClipboard(const char* text, u32 textLen) { 3496 static Atom CLIPBOARD = 0, 3497 UTF8_STRING = 0, 3498 SAVE_TARGETS = 0, 3499 TARGETS = 0, 3500 MULTIPLE = 0, 3501 ATOM_PAIR = 0, 3502 CLIPBOARD_MANAGER = 0; 3503 3504 if (CLIPBOARD == 0) { 3505 CLIPBOARD = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD", False); 3506 UTF8_STRING = XInternAtom((Display*) RGFW_root->src.display, "UTF8_STRING", False); 3507 SAVE_TARGETS = XInternAtom((Display*) RGFW_root->src.display, "SAVE_TARGETS", False); 3508 TARGETS = XInternAtom((Display*) RGFW_root->src.display, "TARGETS", False); 3509 MULTIPLE = XInternAtom((Display*) RGFW_root->src.display, "MULTIPLE", False); 3510 ATOM_PAIR = XInternAtom((Display*) RGFW_root->src.display, "ATOM_PAIR", False); 3511 CLIPBOARD_MANAGER = XInternAtom((Display*) RGFW_root->src.display, "CLIPBOARD_MANAGER", False); 3512 } 3513 3514 XSetSelectionOwner((Display*) RGFW_root->src.display, CLIPBOARD, (Window) RGFW_root->src.window, CurrentTime); 3515 3516 XConvertSelection((Display*) RGFW_root->src.display, CLIPBOARD_MANAGER, SAVE_TARGETS, None, (Window) RGFW_root->src.window, CurrentTime); 3517 for (;;) { 3518 XEvent event; 3519 3520 XNextEvent((Display*) RGFW_root->src.display, &event); 3521 if (event.type != SelectionRequest) { 3522 break; 3523 } 3524 3525 const XSelectionRequestEvent* request = &event.xselectionrequest; 3526 3527 XEvent reply = { SelectionNotify }; 3528 reply.xselection.property = 0; 3529 3530 if (request->target == TARGETS) { 3531 const Atom targets[] = { TARGETS, 3532 MULTIPLE, 3533 UTF8_STRING, 3534 XA_STRING }; 3535 3536 XChangeProperty((Display*) RGFW_root->src.display, 3537 request->requestor, 3538 request->property, 3539 4, 3540 32, 3541 PropModeReplace, 3542 (u8*) targets, 3543 sizeof(targets) / sizeof(targets[0])); 3544 3545 reply.xselection.property = request->property; 3546 } 3547 3548 if (request->target == MULTIPLE) { 3549 Atom* targets = NULL; 3550 3551 Atom actualType = 0; 3552 int actualFormat = 0; 3553 unsigned long count = 0, bytesAfter = 0; 3554 3555 XGetWindowProperty((Display*) RGFW_root->src.display, request->requestor, request->property, 0, LONG_MAX, False, ATOM_PAIR, &actualType, &actualFormat, &count, &bytesAfter, (u8**) &targets); 3556 3557 unsigned long i; 3558 for (i = 0; i < (u32)count; i += 2) { 3559 if (targets[i] == UTF8_STRING || targets[i] == XA_STRING) { 3560 XChangeProperty((Display*) RGFW_root->src.display, 3561 request->requestor, 3562 targets[i + 1], 3563 targets[i], 3564 8, 3565 PropModeReplace, 3566 (u8*) text, 3567 textLen); 3568 XFlush(RGFW_root->src.display); 3569 } else { 3570 targets[i + 1] = None; 3571 } 3572 } 3573 3574 XChangeProperty((Display*) RGFW_root->src.display, 3575 request->requestor, 3576 request->property, 3577 ATOM_PAIR, 3578 32, 3579 PropModeReplace, 3580 (u8*) targets, 3581 count); 3582 3583 XFlush(RGFW_root->src.display); 3584 XFree(targets); 3585 3586 reply.xselection.property = request->property; 3587 } 3588 3589 reply.xselection.display = request->display; 3590 reply.xselection.requestor = request->requestor; 3591 reply.xselection.selection = request->selection; 3592 reply.xselection.target = request->target; 3593 reply.xselection.time = request->time; 3594 3595 XSendEvent((Display*) RGFW_root->src.display, request->requestor, False, 0, &reply); 3596 XFlush(RGFW_root->src.display); 3597 } 3598 } 3599 3600 u8 RGFW_window_isFullscreen(RGFW_window* win) { 3601 assert(win != NULL); 3602 3603 XWindowAttributes windowAttributes; 3604 XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes); 3605 3606 /* check if the window is visable */ 3607 if (windowAttributes.map_state != IsViewable) 3608 return 0; 3609 3610 /* check if the window covers the full screen */ 3611 return (windowAttributes.x == 0 && windowAttributes.y == 0 && 3612 windowAttributes.width == XDisplayWidth(win->src.display, DefaultScreen(win->src.display)) && 3613 windowAttributes.height == XDisplayHeight(win->src.display, DefaultScreen(win->src.display))); 3614 } 3615 3616 u8 RGFW_window_isHidden(RGFW_window* win) { 3617 assert(win != NULL); 3618 3619 XWindowAttributes windowAttributes; 3620 XGetWindowAttributes(win->src.display, (Window) win->src.window, &windowAttributes); 3621 3622 return (windowAttributes.map_state == IsUnmapped && !RGFW_window_isMinimized(win)); 3623 } 3624 3625 u8 RGFW_window_isMinimized(RGFW_window* win) { 3626 assert(win != NULL); 3627 3628 static Atom prop = 0; 3629 if (prop == 0) 3630 prop = XInternAtom(win->src.display, "WM_STATE", False); 3631 3632 Atom actual_type; 3633 i32 actual_format; 3634 unsigned long nitems, bytes_after; 3635 unsigned char* prop_data; 3636 3637 i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, prop, 0, 2, False, 3638 AnyPropertyType, &actual_type, &actual_format, 3639 &nitems, &bytes_after, &prop_data); 3640 3641 if (status == Success && nitems >= 1 && *((int*) prop_data) == IconicState) { 3642 XFree(prop_data); 3643 return 1; 3644 } 3645 3646 if (prop_data != NULL) 3647 XFree(prop_data); 3648 3649 return 0; 3650 } 3651 3652 u8 RGFW_window_isMaximized(RGFW_window* win) { 3653 assert(win != NULL); 3654 3655 static Atom net_wm_state = 0; 3656 static Atom net_wm_state_maximized_horz = 0; 3657 static Atom net_wm_state_maximized_vert = 0; 3658 3659 if (net_wm_state == 0) { 3660 net_wm_state = XInternAtom(win->src.display, "_NET_WM_STATE", False); 3661 net_wm_state_maximized_vert = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_VERT", False); 3662 net_wm_state_maximized_horz = XInternAtom(win->src.display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); 3663 } 3664 3665 Atom actual_type; 3666 i32 actual_format; 3667 unsigned long nitems, bytes_after; 3668 unsigned char* prop_data; 3669 3670 i16 status = XGetWindowProperty(win->src.display, (Window) win->src.window, net_wm_state, 0, 1024, False, 3671 XA_ATOM, &actual_type, &actual_format, 3672 &nitems, &bytes_after, &prop_data); 3673 3674 if (status != Success) { 3675 if (prop_data != NULL) 3676 XFree(prop_data); 3677 3678 return 0; 3679 } 3680 3681 Atom* atoms = (Atom*) prop_data; 3682 u64 i; 3683 for (i = 0; i < nitems; ++i) { 3684 if (atoms[i] == net_wm_state_maximized_horz || 3685 atoms[i] == net_wm_state_maximized_vert) { 3686 XFree(prop_data); 3687 return 1; 3688 } 3689 } 3690 3691 return 0; 3692 } 3693 3694 static void XGetSystemContentScale(Display* display, float* xscale, float* yscale) { 3695 float xdpi = 96.f, ydpi = 96.f; 3696 3697 #ifndef RGFW_NO_DPI 3698 char* rms = XResourceManagerString(display); 3699 XrmDatabase db = NULL; 3700 3701 if (rms && db) 3702 db = XrmGetStringDatabase(rms); 3703 3704 if (db == 0) { 3705 *xscale = xdpi / 96.f; 3706 *yscale = ydpi / 96.f; 3707 return; 3708 } 3709 3710 XrmValue value; 3711 char* type = NULL; 3712 3713 if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value) && type && strncmp(type, "String", 7) == 0) 3714 xdpi = ydpi = atof(value.addr); 3715 XrmDestroyDatabase(db); 3716 #endif 3717 3718 * xscale = xdpi / 96.f; 3719 *yscale = ydpi / 96.f; 3720 } 3721 3722 RGFW_monitor RGFW_XCreateMonitor(i32 screen) { 3723 RGFW_monitor monitor; 3724 3725 Display* display = XOpenDisplay(NULL); 3726 3727 RGFW_area size = RGFW_getScreenSize(); 3728 3729 monitor.rect = RGFW_RECT(0, 0, size.w, size.h); 3730 monitor.physW = DisplayWidthMM(display, screen); 3731 monitor.physH = DisplayHeightMM(display, screen); 3732 3733 XGetSystemContentScale(display, &monitor.scaleX, &monitor.scaleY); 3734 XRRScreenResources* sr = XRRGetScreenResourcesCurrent(display, RootWindow(display, screen)); 3735 3736 XRRCrtcInfo* ci = NULL; 3737 int crtc = screen; 3738 3739 if (sr->ncrtc > crtc) { 3740 ci = XRRGetCrtcInfo(display, sr, sr->crtcs[crtc]); 3741 } 3742 3743 if (ci == NULL) { 3744 float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4)); 3745 float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4)); 3746 3747 monitor.scaleX = (float) (dpi_width) / (float) 96; 3748 monitor.scaleY = (float) (dpi_height) / (float) 96; 3749 XRRFreeScreenResources(sr); 3750 XCloseDisplay(display); 3751 return monitor; 3752 } 3753 3754 XRROutputInfo* info = XRRGetOutputInfo (display, sr, sr->outputs[screen]); 3755 monitor.physW = info->mm_width; 3756 monitor.physH = info->mm_height; 3757 3758 monitor.rect.x = ci->x; 3759 monitor.rect.y = ci->y; 3760 monitor.rect.w = ci->width; 3761 monitor.rect.h = ci->height; 3762 3763 float dpi_width = round((double)monitor.rect.w/(((double)monitor.physW)/25.4)); 3764 float dpi_height = round((double)monitor.rect.h/(((double)monitor.physH)/25.4)); 3765 3766 monitor.scaleX = (float) (dpi_width) / (float) 96; 3767 monitor.scaleY = (float) (dpi_height) / (float) 96; 3768 3769 if (monitor.scaleX > 1 && monitor.scaleX < 1.1) 3770 monitor.scaleX = 1; 3771 3772 if (monitor.scaleY > 1 && monitor.scaleY < 1.1) 3773 monitor.scaleY = 1; 3774 3775 XRRFreeCrtcInfo(ci); 3776 XRRFreeScreenResources(sr); 3777 3778 XCloseDisplay(display); 3779 3780 return monitor; 3781 } 3782 3783 RGFW_monitor RGFW_monitors[6]; 3784 RGFW_monitor* RGFW_getMonitors(void) { 3785 size_t i; 3786 for (i = 0; i < (size_t)ScreenCount(RGFW_root->src.display) && i < 6; i++) 3787 RGFW_monitors[i] = RGFW_XCreateMonitor(i); 3788 3789 return RGFW_monitors; 3790 } 3791 3792 RGFW_monitor RGFW_getPrimaryMonitor(void) { 3793 assert(RGFW_root != NULL); 3794 3795 i32 primary = -1; 3796 Window root = DefaultRootWindow(RGFW_root->src.display); 3797 XRRScreenResources* res = XRRGetScreenResources(RGFW_root->src.display, root); 3798 3799 for (int i = 0; i < res->noutput; i++) { 3800 XRROutputInfo* output_info = XRRGetOutputInfo(RGFW_root->src.display, res, res->outputs[i]); 3801 if (output_info->connection == RR_Connected && output_info->crtc) { 3802 XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(RGFW_root->src.display, res, output_info->crtc); 3803 if (crtc_info->mode != None && crtc_info->x == 0 && crtc_info->y == 0) { 3804 primary = i; 3805 XRRFreeCrtcInfo(crtc_info); 3806 XRRFreeOutputInfo(output_info); 3807 break; 3808 } 3809 XRRFreeCrtcInfo(crtc_info); 3810 } 3811 XRRFreeOutputInfo(output_info); 3812 } 3813 3814 XRRFreeScreenResources(res); 3815 3816 return RGFW_XCreateMonitor(primary); 3817 } 3818 3819 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { 3820 return RGFW_XCreateMonitor(DefaultScreen(win->src.display)); 3821 } 3822 3823 #ifdef RGFW_OPENGL 3824 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { 3825 if (win == NULL) 3826 glXMakeCurrent((Display*) NULL, (Drawable)NULL, (GLXContext) NULL); 3827 else 3828 glXMakeCurrent((Display*) win->src.display, (Drawable) win->src.window, (GLXContext) win->src.ctx); 3829 } 3830 #endif 3831 3832 3833 void RGFW_window_swapBuffers(RGFW_window* win) { 3834 assert(win != NULL); 3835 3836 /* clear the window*/ 3837 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { 3838 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 3839 #ifdef RGFW_OSMESA 3840 RGFW_OSMesa_reorganize(); 3841 #endif 3842 RGFW_area area = RGFW_bufferSize; 3843 3844 #ifndef RGFW_X11_DONT_CONVERT_BGR 3845 win->src.bitmap->data = (char*) win->buffer; 3846 u32 x, y; 3847 for (y = 0; y < (u32)win->r.h; y++) { 3848 for (x = 0; x < (u32)win->r.w; x++) { 3849 u32 index = (y * 4 * area.w) + x * 4; 3850 3851 u8 red = win->src.bitmap->data[index]; 3852 win->src.bitmap->data[index] = win->buffer[index + 2]; 3853 win->src.bitmap->data[index + 2] = red; 3854 3855 } 3856 } 3857 #endif 3858 XPutImage(win->src.display, (Window) win->src.window, win->src.gc, win->src.bitmap, 0, 0, 0, 0, RGFW_bufferSize.w, RGFW_bufferSize.h); 3859 #endif 3860 } 3861 3862 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) { 3863 #ifdef RGFW_EGL 3864 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); 3865 #elif defined(RGFW_OPENGL) 3866 glXSwapBuffers((Display*) win->src.display, (Window) win->src.window); 3867 #endif 3868 } 3869 } 3870 3871 #if !defined(RGFW_EGL) 3872 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { 3873 assert(win != NULL); 3874 3875 #if defined(RGFW_OPENGL) 3876 ((PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress((GLubyte*) "glXSwapIntervalEXT"))((Display*) win->src.display, (Window) win->src.window, swapInterval); 3877 #else 3878 RGFW_UNUSED(swapInterval); 3879 #endif 3880 } 3881 #endif 3882 3883 3884 void RGFW_window_close(RGFW_window* win) { 3885 /* ungrab pointer if it was grabbed */ 3886 if (win->_winArgs & RGFW_HOLD_MOUSE) 3887 XUngrabPointer(win->src.display, CurrentTime); 3888 3889 assert(win != NULL); 3890 #ifdef RGFW_EGL 3891 RGFW_closeEGL(win); 3892 #endif 3893 3894 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 3895 if (win->buffer != NULL) { 3896 XDestroyImage((XImage*) win->src.bitmap); 3897 XFreeGC(win->src.display, win->src.gc); 3898 } 3899 #endif 3900 3901 if ((Display*) win->src.display) { 3902 #ifdef RGFW_OPENGL 3903 glXDestroyContext((Display*) win->src.display, win->src.ctx); 3904 #endif 3905 3906 if (win == RGFW_root) 3907 RGFW_root = NULL; 3908 3909 if ((Drawable) win->src.window) 3910 XDestroyWindow((Display*) win->src.display, (Drawable) win->src.window); /*!< close the window*/ 3911 3912 XCloseDisplay((Display*) win->src.display); /*!< kill the display*/ 3913 } 3914 3915 #ifdef RGFW_ALLOC_DROPFILES 3916 { 3917 u32 i; 3918 for (i = 0; i < RGFW_MAX_DROPS; i++) 3919 RGFW_FREE(win->event.droppedFiles[i]); 3920 3921 3922 RGFW_FREE(win->event.droppedFiles); 3923 } 3924 #endif 3925 3926 RGFW_windowsOpen--; 3927 #if !defined(RGFW_NO_X11_CURSOR_PRELOAD) && !defined(RGFW_NO_X11_CURSOR) 3928 if (X11Cursorhandle != NULL && RGFW_windowsOpen <= 0) { 3929 dlclose(X11Cursorhandle); 3930 3931 X11Cursorhandle = NULL; 3932 } 3933 #endif 3934 #if !defined(RGFW_NO_X11_XI_PRELOAD) 3935 if (X11Xihandle != NULL && RGFW_windowsOpen <= 0) { 3936 dlclose(X11Xihandle); 3937 3938 X11Xihandle = NULL; 3939 } 3940 #endif 3941 3942 if (RGFW_libxshape != NULL && RGFW_windowsOpen <= 0) { 3943 dlclose(RGFW_libxshape); 3944 RGFW_libxshape = NULL; 3945 } 3946 3947 if (RGFW_windowsOpen <= 0) { 3948 if (RGFW_eventWait_forceStop[0] || RGFW_eventWait_forceStop[1]){ 3949 close(RGFW_eventWait_forceStop[0]); 3950 close(RGFW_eventWait_forceStop[1]); 3951 } 3952 3953 u8 i; 3954 for (i = 0; i < RGFW_joystickCount; i++) 3955 close(RGFW_joysticks[i]); 3956 } 3957 3958 /* set cleared display / window to NULL for error checking */ 3959 win->src.display = (Display*) 0; 3960 win->src.window = (Window) 0; 3961 3962 RGFW_FREE(win); /*!< free collected window data */ 3963 } 3964 3965 3966 /* 3967 End of X11 linux / unix defines 3968 */ 3969 3970 #endif /* RGFW_X11 */ 3971 3972 3973 /* wayland or X11 defines*/ 3974 #if defined(RGFW_WAYLAND) || defined(RGFW_X11) 3975 #include <fcntl.h> 3976 #include <poll.h> 3977 #include <unistd.h> 3978 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) { 3979 assert(win != NULL); 3980 3981 #ifdef __linux__ 3982 3983 i32 js = open(file, O_RDONLY); 3984 3985 if (js && RGFW_joystickCount < 4) { 3986 RGFW_joystickCount++; 3987 3988 RGFW_joysticks[RGFW_joystickCount - 1] = open(file, O_RDONLY); 3989 3990 u8 i; 3991 for (i = 0; i < 16; i++) 3992 RGFW_jsPressed[RGFW_joystickCount - 1][i] = 0; 3993 3994 } 3995 3996 else { 3997 #ifdef RGFW_PRINT_ERRORS 3998 RGFW_error = 1; 3999 fprintf(stderr, "Error RGFW_registerJoystickF : Cannot open file %s\n", file); 4000 #endif 4001 } 4002 4003 return RGFW_joystickCount - 1; 4004 #endif 4005 } 4006 4007 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) { 4008 assert(win != NULL); 4009 4010 #ifdef __linux__ 4011 char file[15]; 4012 sprintf(file, "/dev/input/js%i", jsNumber); 4013 4014 return RGFW_registerJoystickF(win, file); 4015 #endif 4016 } 4017 4018 void RGFW_stopCheckEvents(void) { 4019 RGFW_eventWait_forceStop[2] = 1; 4020 while (1) { 4021 const char byte = 0; 4022 const ssize_t result = write(RGFW_eventWait_forceStop[1], &byte, 1); 4023 if (result == 1 || result == -1) 4024 break; 4025 } 4026 } 4027 4028 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { 4029 if (waitMS == 0) 4030 return; 4031 4032 u8 i; 4033 4034 if (RGFW_eventWait_forceStop[0] == 0 || RGFW_eventWait_forceStop[1] == 0) { 4035 if (pipe(RGFW_eventWait_forceStop) != -1) { 4036 fcntl(RGFW_eventWait_forceStop[0], F_GETFL, 0); 4037 fcntl(RGFW_eventWait_forceStop[0], F_GETFD, 0); 4038 fcntl(RGFW_eventWait_forceStop[1], F_GETFL, 0); 4039 fcntl(RGFW_eventWait_forceStop[1], F_GETFD, 0); 4040 } 4041 } 4042 4043 struct pollfd fds[] = { 4044 #ifdef RGFW_WAYLAND 4045 { wl_display_get_fd(win->src.display), POLLIN, 0 }, 4046 #else 4047 { ConnectionNumber(win->src.display), POLLIN, 0 }, 4048 #endif 4049 { RGFW_eventWait_forceStop[0], POLLIN, 0 }, 4050 #ifdef __linux__ /* blank space for 4 joystick files*/ 4051 { -1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0 }, {-1, POLLIN, 0} 4052 #endif 4053 }; 4054 4055 u8 index = 2; 4056 4057 #if defined(__linux__) 4058 for (i = 0; i < RGFW_joystickCount; i++) { 4059 if (RGFW_joysticks[i] == 0) 4060 continue; 4061 4062 fds[index].fd = RGFW_joysticks[i]; 4063 index++; 4064 } 4065 #endif 4066 4067 4068 u64 start = RGFW_getTimeNS(); 4069 4070 #ifdef RGFW_WAYLAND 4071 while (wl_display_dispatch(win->src.display) <= 0 && waitMS >= -1) { 4072 #else 4073 while (XPending(win->src.display) == 0 && waitMS >= -1) { 4074 #endif 4075 if (poll(fds, index, waitMS) <= 0) 4076 break; 4077 4078 if (waitMS > 0) { 4079 waitMS -= (RGFW_getTimeNS() - start) / 1e+6; 4080 } 4081 } 4082 4083 /* drain any data in the stop request */ 4084 if (RGFW_eventWait_forceStop[2]) { 4085 char data[64]; 4086 (void)!read(RGFW_eventWait_forceStop[0], data, sizeof(data)); 4087 4088 RGFW_eventWait_forceStop[2] = 0; 4089 } 4090 } 4091 4092 u64 RGFW_getTimeNS(void) { 4093 struct timespec ts = { 0 }; 4094 clock_gettime(1, &ts); 4095 unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; 4096 4097 return nanoSeconds; 4098 } 4099 4100 u64 RGFW_getTime(void) { 4101 struct timespec ts = { 0 }; 4102 clock_gettime(1, &ts); 4103 unsigned long long int nanoSeconds = (unsigned long long int)ts.tv_sec*1000000000LLU + (unsigned long long int)ts.tv_nsec; 4104 4105 return (double)(nanoSeconds) * 1e-9; 4106 } 4107 #endif /* end of wayland or X11 time defines*/ 4108 4109 4110 /* 4111 4112 Start of Wayland defines 4113 4114 4115 */ 4116 4117 #ifdef RGFW_WAYLAND 4118 /* 4119 Wayland TODO: 4120 - fix RGFW_keyPressed lock state 4121 4122 RGFW_windowMoved, the window was moved (by the user) 4123 RGFW_windowResized the window was resized (by the user), [on webASM this means the browser was resized] 4124 RGFW_windowRefresh The window content needs to be refreshed 4125 4126 RGFW_dnd a file has been dropped into the window 4127 RGFW_dnd_init 4128 4129 - window args: 4130 #define RGFW_NO_RESIZE the window cannot be resized by the user 4131 #define RGFW_ALLOW_DND the window supports drag and drop 4132 #define RGFW_SCALE_TO_MONITOR scale the window to the screen 4133 4134 - other missing functions functions ("TODO wayland") (~30 functions) 4135 - fix buffer rendering weird behavior 4136 */ 4137 #include <errno.h> 4138 #include <unistd.h> 4139 #include <sys/mman.h> 4140 #include <xkbcommon/xkbcommon.h> 4141 #include <xkbcommon/xkbcommon-keysyms.h> 4142 #include <dirent.h> 4143 #include <linux/kd.h> 4144 #include <wayland-cursor.h> 4145 4146 RGFW_window* RGFW_key_win = NULL; 4147 4148 void RGFW_eventPipe_push(RGFW_window* win, RGFW_Event event) { 4149 if (win == NULL) { 4150 win = RGFW_key_win; 4151 4152 if (win == NULL) return; 4153 } 4154 4155 if (win->src.eventLen >= (i32)(sizeof(win->src.events) / sizeof(win->src.events[0]))) 4156 return; 4157 4158 win->src.events[win->src.eventLen] = event; 4159 win->src.eventLen += 1; 4160 } 4161 4162 RGFW_Event RGFW_eventPipe_pop(RGFW_window* win) { 4163 RGFW_Event ev; 4164 ev.type = 0; 4165 4166 if (win->src.eventLen > -1) 4167 win->src.eventLen -= 1; 4168 4169 if (win->src.eventLen >= 0) 4170 ev = win->src.events[win->src.eventLen]; 4171 4172 return ev; 4173 } 4174 4175 /* wayland global garbage (wayland bad, X11 is fine (ish) (not really)) */ 4176 #include "xdg-shell.h" 4177 #include "xdg-decoration-unstable-v1.h" 4178 4179 struct xdg_wm_base *xdg_wm_base; 4180 struct wl_compositor* RGFW_compositor = NULL; 4181 struct wl_shm* shm = NULL; 4182 struct wl_shell* RGFW_shell = NULL; 4183 static struct wl_seat *seat = NULL; 4184 static struct xkb_context *xkb_context; 4185 static struct xkb_keymap *keymap = NULL; 4186 static struct xkb_state *xkb_state = NULL; 4187 enum zxdg_toplevel_decoration_v1_mode client_preferred_mode, RGFW_current_mode; 4188 static struct zxdg_decoration_manager_v1 *decoration_manager = NULL; 4189 4190 struct wl_cursor_theme* RGFW_wl_cursor_theme = NULL; 4191 struct wl_surface* RGFW_cursor_surface = NULL; 4192 struct wl_cursor_image* RGFW_cursor_image = NULL; 4193 4194 static void xdg_wm_base_ping_handler(void *data, 4195 struct xdg_wm_base *wm_base, uint32_t serial) 4196 { 4197 RGFW_UNUSED(data); 4198 xdg_wm_base_pong(wm_base, serial); 4199 } 4200 4201 static const struct xdg_wm_base_listener xdg_wm_base_listener = { 4202 .ping = xdg_wm_base_ping_handler, 4203 }; 4204 4205 b8 RGFW_wl_configured = 0; 4206 4207 static void xdg_surface_configure_handler(void *data, 4208 struct xdg_surface *xdg_surface, uint32_t serial) 4209 { 4210 RGFW_UNUSED(data); 4211 xdg_surface_ack_configure(xdg_surface, serial); 4212 #ifdef RGFW_DEBUG 4213 printf("Surface configured\n"); 4214 #endif 4215 RGFW_wl_configured = 1; 4216 } 4217 4218 static const struct xdg_surface_listener xdg_surface_listener = { 4219 .configure = xdg_surface_configure_handler, 4220 }; 4221 4222 static void xdg_toplevel_configure_handler(void *data, 4223 struct xdg_toplevel *toplevel, int32_t width, int32_t height, 4224 struct wl_array *states) 4225 { 4226 RGFW_UNUSED(data); RGFW_UNUSED(toplevel); RGFW_UNUSED(states) 4227 fprintf(stderr, "XDG toplevel configure: %dx%d\n", width, height); 4228 } 4229 4230 static void xdg_toplevel_close_handler(void *data, 4231 struct xdg_toplevel *toplevel) 4232 { 4233 RGFW_UNUSED(data); 4234 RGFW_window* win = (RGFW_window*)xdg_toplevel_get_user_data(toplevel); 4235 if (win == NULL) 4236 win = RGFW_key_win; 4237 4238 RGFW_Event ev; 4239 ev.type = RGFW_quit; 4240 4241 RGFW_eventPipe_push(win, ev); 4242 4243 RGFW_windowQuitCallback(win); 4244 } 4245 4246 static void shm_format_handler(void *data, 4247 struct wl_shm *shm, uint32_t format) 4248 { 4249 RGFW_UNUSED(data); RGFW_UNUSED(shm); 4250 fprintf(stderr, "Format %d\n", format); 4251 } 4252 4253 static const struct wl_shm_listener shm_listener = { 4254 .format = shm_format_handler, 4255 }; 4256 4257 static const struct xdg_toplevel_listener xdg_toplevel_listener = { 4258 .configure = xdg_toplevel_configure_handler, 4259 .close = xdg_toplevel_close_handler, 4260 }; 4261 4262 RGFW_window* RGFW_mouse_win = NULL; 4263 4264 static void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { 4265 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface_x); RGFW_UNUSED(surface_y); 4266 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); 4267 RGFW_mouse_win = win; 4268 4269 RGFW_Event ev; 4270 ev.type = RGFW_mouseEnter; 4271 ev.point = win->event.point; 4272 4273 RGFW_eventPipe_push(win, ev); 4274 4275 RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_TRUE); 4276 } 4277 static void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { 4278 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(serial); RGFW_UNUSED(surface); 4279 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); 4280 if (RGFW_mouse_win == win) 4281 RGFW_mouse_win = NULL; 4282 4283 RGFW_Event ev; 4284 ev.type = RGFW_mouseLeave; 4285 ev.point = win->event.point; 4286 RGFW_eventPipe_push(win, ev); 4287 4288 RGFW_mouseNotifyCallBack(win, win->event.point, RGFW_FALSE); 4289 } 4290 static void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) { 4291 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(x); RGFW_UNUSED(y); 4292 4293 assert(RGFW_mouse_win != NULL); 4294 4295 RGFW_Event ev; 4296 ev.type = RGFW_mousePosChanged; 4297 ev.point = RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y)); 4298 RGFW_eventPipe_push(RGFW_mouse_win, ev); 4299 4300 RGFW_mousePosCallback(RGFW_mouse_win, RGFW_POINT(wl_fixed_to_double(x), wl_fixed_to_double(y))); 4301 } 4302 static void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { 4303 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(serial); 4304 assert(RGFW_mouse_win != NULL); 4305 4306 u32 b = (button - 0x110) + 1; 4307 4308 /* flip right and middle button codes */ 4309 if (b == 2) b = 3; 4310 else if (b == 3) b = 2; 4311 4312 RGFW_mouseButtons[b].prev = RGFW_mouseButtons[b].current; 4313 RGFW_mouseButtons[b].current = state; 4314 4315 RGFW_Event ev; 4316 ev.type = RGFW_mouseButtonPressed + state; 4317 ev.button = b; 4318 RGFW_eventPipe_push(RGFW_mouse_win, ev); 4319 4320 RGFW_mouseButtonCallback(RGFW_mouse_win, b, 0, state); 4321 } 4322 static void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { 4323 RGFW_UNUSED(data); RGFW_UNUSED(pointer); RGFW_UNUSED(time); RGFW_UNUSED(axis); 4324 assert(RGFW_mouse_win != NULL); 4325 4326 double scroll = wl_fixed_to_double(value); 4327 4328 RGFW_Event ev; 4329 ev.type = RGFW_mouseButtonPressed; 4330 ev.button = RGFW_mouseScrollUp + (scroll < 0); 4331 RGFW_eventPipe_push(RGFW_mouse_win, ev); 4332 4333 RGFW_mouseButtonCallback(RGFW_mouse_win, RGFW_mouseScrollUp + (scroll < 0), scroll, 1); 4334 } 4335 4336 void RGFW_doNothing(void) { } 4337 static struct wl_pointer_listener pointer_listener = (struct wl_pointer_listener){&pointer_enter, &pointer_leave, &pointer_motion, &pointer_button, &pointer_axis, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing, (void*)&RGFW_doNothing}; 4338 4339 static void keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { 4340 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(format); 4341 4342 char *keymap_string = mmap (NULL, size, PROT_READ, MAP_SHARED, fd, 0); 4343 xkb_keymap_unref (keymap); 4344 keymap = xkb_keymap_new_from_string (xkb_context, keymap_string, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); 4345 4346 munmap (keymap_string, size); 4347 close (fd); 4348 xkb_state_unref (xkb_state); 4349 xkb_state = xkb_state_new (keymap); 4350 } 4351 static void keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { 4352 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(keys); 4353 4354 RGFW_key_win = (RGFW_window*)wl_surface_get_user_data(surface); 4355 4356 RGFW_Event ev; 4357 ev.type = RGFW_focusIn; 4358 ev.inFocus = RGFW_TRUE; 4359 RGFW_key_win->event.inFocus = RGFW_TRUE; 4360 4361 RGFW_eventPipe_push((RGFW_window*)RGFW_mouse_win, ev); 4362 4363 RGFW_focusCallback(RGFW_key_win, RGFW_TRUE); 4364 } 4365 static void keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) { 4366 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); 4367 4368 RGFW_window* win = (RGFW_window*)wl_surface_get_user_data(surface); 4369 if (RGFW_key_win == win) 4370 RGFW_key_win = NULL; 4371 4372 RGFW_Event ev; 4373 ev.type = RGFW_focusOut; 4374 ev.inFocus = RGFW_FALSE; 4375 win->event.inFocus = RGFW_FALSE; 4376 RGFW_eventPipe_push(win, ev); 4377 4378 RGFW_focusCallback(win, RGFW_FALSE); 4379 } 4380 static void keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { 4381 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); 4382 4383 assert(RGFW_key_win != NULL); 4384 4385 xkb_keysym_t keysym = xkb_state_key_get_one_sym (xkb_state, key+8); 4386 char name[16]; 4387 xkb_keysym_get_name(keysym, name, 16); 4388 4389 u32 RGFW_key = RGFW_apiKeyCodeToRGFW(key); 4390 RGFW_keyboard[RGFW_key].prev = RGFW_keyboard[RGFW_key].current; 4391 RGFW_keyboard[RGFW_key].current = state; 4392 RGFW_Event ev; 4393 ev.type = RGFW_keyPressed + state; 4394 ev.keyCode = RGFW_key; 4395 strcpy(ev.keyName, name); 4396 ev.repeat = RGFW_isHeld(RGFW_key_win, RGFW_key); 4397 RGFW_eventPipe_push(RGFW_key_win, ev); 4398 4399 RGFW_updateLockState(RGFW_key_win, xkb_keymap_mod_get_index(keymap, "Lock"), xkb_keymap_mod_get_index(keymap, "Mod2")); 4400 4401 RGFW_keyCallback(RGFW_key_win, RGFW_key, name, RGFW_key_win->event.lockState, state); 4402 } 4403 static void keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { 4404 RGFW_UNUSED(data); RGFW_UNUSED(keyboard); RGFW_UNUSED(serial); RGFW_UNUSED(time); 4405 xkb_state_update_mask (xkb_state, mods_depressed, mods_latched, mods_locked, 0, 0, group); 4406 } 4407 static struct wl_keyboard_listener keyboard_listener = {&keyboard_keymap, &keyboard_enter, &keyboard_leave, &keyboard_key, &keyboard_modifiers, (void*)&RGFW_doNothing}; 4408 4409 static void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) { 4410 RGFW_UNUSED(data); 4411 4412 if (capabilities & WL_SEAT_CAPABILITY_POINTER) { 4413 struct wl_pointer *pointer = wl_seat_get_pointer (seat); 4414 wl_pointer_add_listener (pointer, &pointer_listener, NULL); 4415 } 4416 if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { 4417 struct wl_keyboard *keyboard = wl_seat_get_keyboard (seat); 4418 wl_keyboard_add_listener (keyboard, &keyboard_listener, NULL); 4419 } 4420 } 4421 static struct wl_seat_listener seat_listener = {&seat_capabilities, (void*)&RGFW_doNothing}; 4422 4423 static void wl_global_registry_handler(void *data, 4424 struct wl_registry *registry, uint32_t id, const char *interface, 4425 uint32_t version) 4426 { 4427 RGFW_UNUSED(data); RGFW_UNUSED(version); 4428 4429 if (strcmp(interface, "wl_compositor") == 0) { 4430 RGFW_compositor = wl_registry_bind(registry, 4431 id, &wl_compositor_interface, 4); 4432 } else if (strcmp(interface, "xdg_wm_base") == 0) { 4433 xdg_wm_base = wl_registry_bind(registry, 4434 id, &xdg_wm_base_interface, 1); 4435 } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { 4436 decoration_manager = wl_registry_bind(registry, id, &zxdg_decoration_manager_v1_interface, 1); 4437 } else if (strcmp(interface, "wl_shm") == 0) { 4438 shm = wl_registry_bind(registry, 4439 id, &wl_shm_interface, 1); 4440 wl_shm_add_listener(shm, &shm_listener, NULL); 4441 } else if (strcmp(interface,"wl_seat") == 0) { 4442 seat = wl_registry_bind(registry, id, &wl_seat_interface, 1); 4443 wl_seat_add_listener(seat, &seat_listener, NULL); 4444 } 4445 4446 else { 4447 #ifdef RGFW_DEBUG 4448 printf("did not register %s\n", interface); 4449 return; 4450 #endif 4451 } 4452 4453 #ifdef RGFW_DEBUG 4454 printf("registered %s\n", interface); 4455 #endif 4456 } 4457 4458 static void wl_global_registry_remove(void *data, struct wl_registry *registry, uint32_t name) { RGFW_UNUSED(data); RGFW_UNUSED(registry); RGFW_UNUSED(name); } 4459 static const struct wl_registry_listener registry_listener = { 4460 .global = wl_global_registry_handler, 4461 .global_remove = wl_global_registry_remove, 4462 }; 4463 4464 static const char *get_mode_name(enum zxdg_toplevel_decoration_v1_mode mode) { 4465 switch (mode) { 4466 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE: 4467 return "client-side decorations"; 4468 case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE: 4469 return "server-side decorations"; 4470 } 4471 abort(); 4472 } 4473 4474 4475 static void decoration_handle_configure(void *data, 4476 struct zxdg_toplevel_decoration_v1 *decoration, 4477 enum zxdg_toplevel_decoration_v1_mode mode) { 4478 RGFW_UNUSED(data); RGFW_UNUSED(decoration); 4479 printf("Using %s\n", get_mode_name(mode)); 4480 RGFW_current_mode = mode; 4481 } 4482 4483 static const struct zxdg_toplevel_decoration_v1_listener decoration_listener = { 4484 .configure = decoration_handle_configure, 4485 }; 4486 4487 static void randname(char *buf) { 4488 struct timespec ts; 4489 clock_gettime(CLOCK_REALTIME, &ts); 4490 long r = ts.tv_nsec; 4491 for (int i = 0; i < 6; ++i) { 4492 buf[i] = 'A'+(r&15)+(r&16)*2; 4493 r >>= 5; 4494 } 4495 } 4496 4497 static int anonymous_shm_open(void) { 4498 char name[] = "/RGFW-wayland-XXXXXX"; 4499 int retries = 100; 4500 4501 do { 4502 randname(name + strlen(name) - 6); 4503 4504 --retries; 4505 // shm_open guarantees that O_CLOEXEC is set 4506 int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); 4507 if (fd >= 0) { 4508 shm_unlink(name); 4509 return fd; 4510 } 4511 } while (retries > 0 && errno == EEXIST); 4512 4513 return -1; 4514 } 4515 4516 int create_shm_file(off_t size) { 4517 int fd = anonymous_shm_open(); 4518 if (fd < 0) { 4519 return fd; 4520 } 4521 4522 if (ftruncate(fd, size) < 0) { 4523 close(fd); 4524 return -1; 4525 } 4526 4527 return fd; 4528 } 4529 4530 static void wl_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { 4531 #ifdef RGFW_BUFFER 4532 RGFW_window* win = (RGFW_window*)data; 4533 if ((win->_winArgs & RGFW_NO_CPU_RENDER)) 4534 return; 4535 4536 #ifndef RGFW_X11_DONT_CONVERT_BGR 4537 u32 x, y; 4538 for (y = 0; y < (u32)win->r.h; y++) { 4539 for (x = 0; x < (u32)win->r.w; x++) { 4540 u32 index = (y * 4 * win->r.w) + x * 4; 4541 4542 u8 red = win->buffer[index]; 4543 win->buffer[index] = win->buffer[index + 2]; 4544 win->buffer[index + 2] = red; 4545 4546 } 4547 } 4548 #endif 4549 4550 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); 4551 wl_surface_damage_buffer(win->src.surface, 0, 0, win->r.w, win->r.h); 4552 wl_surface_commit(win->src.surface); 4553 #endif 4554 } 4555 4556 static const struct wl_callback_listener wl_surface_frame_listener = { 4557 .done = wl_surface_frame_done, 4558 }; 4559 4560 4561 /* normal wayland RGFW stuff */ 4562 4563 RGFW_area RGFW_getScreenSize(void) { 4564 RGFW_area area = {}; 4565 4566 if (RGFW_root != NULL) 4567 /* this isn't right but it's here for buffers */ 4568 area = RGFW_AREA(RGFW_root->r.w, RGFW_root->r.h); 4569 4570 /* TODO wayland */ 4571 return area; 4572 } 4573 4574 void RGFW_releaseCursor(RGFW_window* win) { 4575 RGFW_UNUSED(win); 4576 } 4577 4578 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { 4579 RGFW_UNUSED(win); RGFW_UNUSED(r); 4580 4581 /* TODO wayland */ 4582 } 4583 4584 4585 RGFWDEF void RGFW_init_buffer(RGFW_window* win); 4586 void RGFW_init_buffer(RGFW_window* win) { 4587 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 4588 size_t size = win->r.w * win->r.h * 4; 4589 int fd = create_shm_file(size); 4590 if (fd < 0) { 4591 fprintf(stderr, "Failed to create a buffer. size: %ld\n", size); 4592 exit(1); 4593 } 4594 4595 win->buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 4596 if (win->buffer == MAP_FAILED) { 4597 fprintf(stderr, "mmap failed!\n"); 4598 close(fd); 4599 exit(1); 4600 } 4601 4602 struct wl_shm_pool* pool = wl_shm_create_pool(shm, fd, size); 4603 win->src.wl_buffer = wl_shm_pool_create_buffer(pool, 0, win->r.w, win->r.h, win->r.w * 4, 4604 WL_SHM_FORMAT_ARGB8888); 4605 wl_shm_pool_destroy(pool); 4606 4607 close(fd); 4608 4609 wl_surface_attach(win->src.surface, win->src.wl_buffer, 0, 0); 4610 wl_surface_commit(win->src.surface); 4611 4612 u8 color[] = {0x00, 0x00, 0x00, 0xFF}; 4613 4614 size_t i; 4615 for (i = 0; i < size; i += 4) { 4616 memcpy(&win->buffer[i], color, 4); 4617 } 4618 4619 #if defined(RGFW_OSMESA) 4620 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); 4621 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); 4622 #endif 4623 #else 4624 RGFW_UNUSED(win); 4625 #endif 4626 } 4627 4628 4629 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { 4630 RGFW_window* win = RGFW_window_basic_init(rect, args); 4631 4632 fprintf(stderr, "Warning: RGFW Wayland support is experimental\n"); 4633 4634 win->src.display = wl_display_connect(NULL); 4635 if (win->src.display == NULL) { 4636 #ifdef RGFW_DEBUG 4637 fprintf(stderr, "Failed to load Wayland display\n"); 4638 #endif 4639 return NULL; 4640 } 4641 4642 struct wl_registry *registry = wl_display_get_registry(win->src.display); 4643 wl_registry_add_listener(registry, ®istry_listener, NULL); 4644 4645 wl_display_dispatch(win->src.display); 4646 wl_display_roundtrip(win->src.display); 4647 4648 if (RGFW_compositor == NULL) { 4649 #ifdef RGFW_DEBUG 4650 fprintf(stderr, "Can't find compositor.\n"); 4651 #endif 4652 4653 return NULL; 4654 } 4655 4656 if (RGFW_wl_cursor_theme == NULL) { 4657 RGFW_wl_cursor_theme = wl_cursor_theme_load(NULL, 24, shm); 4658 RGFW_cursor_surface = wl_compositor_create_surface(RGFW_compositor); 4659 4660 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, "left_ptr"); 4661 RGFW_cursor_image = cursor->images[0]; 4662 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); 4663 4664 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); 4665 wl_surface_commit(RGFW_cursor_surface); 4666 } 4667 4668 if (RGFW_root == NULL) 4669 xdg_wm_base_add_listener(xdg_wm_base, &xdg_wm_base_listener, NULL); 4670 4671 xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); 4672 4673 win->src.surface = wl_compositor_create_surface(RGFW_compositor); 4674 wl_surface_set_user_data(win->src.surface, win); 4675 4676 win->src.xdg_surface = xdg_wm_base_get_xdg_surface(xdg_wm_base, win->src.surface); 4677 xdg_surface_add_listener(win->src.xdg_surface, &xdg_surface_listener, NULL); 4678 4679 xdg_wm_base_set_user_data(xdg_wm_base, win); 4680 4681 win->src.xdg_toplevel = xdg_surface_get_toplevel(win->src.xdg_surface); 4682 xdg_toplevel_set_user_data(win->src.xdg_toplevel, win); 4683 xdg_toplevel_set_title(win->src.xdg_toplevel, name); 4684 xdg_toplevel_add_listener(win->src.xdg_toplevel, &xdg_toplevel_listener, NULL); 4685 4686 xdg_surface_set_window_geometry(win->src.xdg_surface, 0, 0, win->r.w, win->r.h); 4687 4688 if (!(args & RGFW_NO_BORDER)) { 4689 win->src.decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( 4690 decoration_manager, win->src.xdg_toplevel); 4691 } 4692 4693 if (args & RGFW_CENTER) { 4694 RGFW_area screenR = RGFW_getScreenSize(); 4695 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); 4696 } 4697 4698 if (args & RGFW_OPENGL_SOFTWARE) 4699 setenv("LIBGL_ALWAYS_SOFTWARE", "1", 1); 4700 4701 wl_display_roundtrip(win->src.display); 4702 4703 wl_surface_commit(win->src.surface); 4704 4705 /* wait for the surface to be configured */ 4706 while (wl_display_dispatch(win->src.display) != -1 && !RGFW_wl_configured) { } 4707 4708 4709 #ifdef RGFW_OPENGL 4710 if ((args & RGFW_NO_INIT_API) == 0) { 4711 win->src.window = wl_egl_window_create(win->src.surface, win->r.w, win->r.h); 4712 RGFW_createOpenGLContext(win); 4713 } 4714 #endif 4715 4716 RGFW_init_buffer(win); 4717 4718 struct wl_callback* callback = wl_surface_frame(win->src.surface); 4719 wl_callback_add_listener(callback, &wl_surface_frame_listener, win); 4720 wl_surface_commit(win->src.surface); 4721 4722 if (args & RGFW_HIDE_MOUSE) { 4723 RGFW_window_showMouse(win, 0); 4724 } 4725 4726 if (RGFW_root == NULL) { 4727 RGFW_root = win; 4728 } 4729 4730 win->src.eventIndex = 0; 4731 win->src.eventLen = 0; 4732 4733 return win; 4734 } 4735 4736 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { 4737 if (win->_winArgs & RGFW_WINDOW_HIDE) 4738 return NULL; 4739 4740 if (win->src.eventIndex == 0) { 4741 if (wl_display_roundtrip(win->src.display) == -1) { 4742 return NULL; 4743 } 4744 RGFW_resetKey(); 4745 } 4746 4747 #ifdef __linux__ 4748 RGFW_Event* event = RGFW_linux_updateJoystick(win); 4749 if (event != NULL) 4750 return event; 4751 #endif 4752 4753 if (win->src.eventLen == 0) { 4754 return NULL; 4755 } 4756 4757 RGFW_Event ev = RGFW_eventPipe_pop(win); 4758 4759 if (ev.type == 0 || win->event.type == RGFW_quit) { 4760 return NULL; 4761 } 4762 4763 ev.frameTime = win->event.frameTime; 4764 ev.frameTime2 = win->event.frameTime2; 4765 ev.inFocus = win->event.inFocus; 4766 win->event = ev; 4767 4768 return &win->event; 4769 } 4770 4771 4772 void RGFW_window_resize(RGFW_window* win, RGFW_area a) { 4773 RGFW_UNUSED(win); RGFW_UNUSED(a); 4774 4775 /* TODO wayland */ 4776 } 4777 4778 void RGFW_window_move(RGFW_window* win, RGFW_point v) { 4779 RGFW_UNUSED(win); RGFW_UNUSED(v); 4780 4781 /* TODO wayland */ 4782 } 4783 4784 void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) { 4785 RGFW_UNUSED(win); RGFW_UNUSED(src); RGFW_UNUSED(a); RGFW_UNUSED(channels) 4786 /* TODO wayland */ 4787 } 4788 4789 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { 4790 RGFW_UNUSED(win); RGFW_UNUSED(v); 4791 4792 /* TODO wayland */ 4793 } 4794 4795 void RGFW_window_showMouse(RGFW_window* win, i8 show) { 4796 RGFW_UNUSED(win); 4797 4798 if (show) { 4799 4800 } 4801 else { 4802 4803 } 4804 4805 /* TODO wayland */ 4806 } 4807 4808 b8 RGFW_window_isMaximized(RGFW_window* win) { 4809 RGFW_UNUSED(win); 4810 /* TODO wayland */ 4811 return 0; 4812 } 4813 4814 b8 RGFW_window_isMinimized(RGFW_window* win) { 4815 RGFW_UNUSED(win); 4816 /* TODO wayland */ 4817 return 0; 4818 } 4819 4820 b8 RGFW_window_isHidden(RGFW_window* win) { 4821 RGFW_UNUSED(win); 4822 /* TODO wayland */ 4823 return 0; 4824 } 4825 4826 b8 RGFW_window_isFullscreen(RGFW_window* win) { 4827 RGFW_UNUSED(win); 4828 /* TODO wayland */ 4829 return 0; 4830 } 4831 4832 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { 4833 RGFW_UNUSED(win); 4834 /* TODO wayland */ 4835 return RGFW_POINT(0, 0); 4836 } 4837 4838 RGFW_point RGFW_getGlobalMousePoint(void) { 4839 /* TODO wayland */ 4840 return RGFW_POINT(0, 0); 4841 } 4842 4843 void RGFW_window_show(RGFW_window* win) { 4844 //wl_surface_attach(win->src.surface, win->rc., 0, 0); 4845 wl_surface_commit(win->src.surface); 4846 4847 if (win->_winArgs & RGFW_WINDOW_HIDE) 4848 win->_winArgs ^= RGFW_WINDOW_HIDE; 4849 } 4850 4851 void RGFW_window_hide(RGFW_window* win) { 4852 wl_surface_attach(win->src.surface, NULL, 0, 0); 4853 wl_surface_commit(win->src.surface); 4854 win->_winArgs |= RGFW_WINDOW_HIDE; 4855 } 4856 4857 void RGFW_window_setMouseDefault(RGFW_window* win) { 4858 RGFW_UNUSED(win); 4859 4860 RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL); 4861 } 4862 4863 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { 4864 RGFW_UNUSED(win); 4865 4866 static const char* iconStrings[] = { "left_ptr", "left_ptr", "text", "cross", "pointer", "e-resize", "n-resize", "nw-resize", "ne-resize", "all-resize", "not-allowed" }; 4867 4868 struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]); 4869 RGFW_cursor_image = cursor->images[0]; 4870 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); 4871 4872 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); 4873 wl_surface_commit(RGFW_cursor_surface); 4874 } 4875 4876 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { 4877 RGFW_UNUSED(win); RGFW_UNUSED(image); RGFW_UNUSED(a); RGFW_UNUSED(channels) 4878 //struct wl_cursor* cursor = wl_cursor_theme_get_cursor(RGFW_wl_cursor_theme, iconStrings[mouse]); 4879 //RGFW_cursor_image = image; 4880 struct wl_buffer* cursor_buffer = wl_cursor_image_get_buffer(RGFW_cursor_image); 4881 4882 wl_surface_attach(RGFW_cursor_surface, cursor_buffer, 0, 0); 4883 wl_surface_commit(RGFW_cursor_surface); 4884 } 4885 4886 void RGFW_window_setName(RGFW_window* win, char* name) { 4887 xdg_toplevel_set_title(win->src.xdg_toplevel, name); 4888 } 4889 4890 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { 4891 RGFW_UNUSED(win); RGFW_UNUSED(passthrough); 4892 4893 /* TODO wayland */ 4894 } 4895 4896 void RGFW_window_setBorder(RGFW_window* win, b8 border) { 4897 RGFW_UNUSED(win); RGFW_UNUSED(border); 4898 4899 /* TODO wayland */ 4900 } 4901 4902 void RGFW_window_restore(RGFW_window* win) { 4903 RGFW_UNUSED(win); 4904 4905 /* TODO wayland */ 4906 } 4907 4908 void RGFW_window_minimize(RGFW_window* win) { 4909 RGFW_UNUSED(win); 4910 4911 /* TODO wayland */ 4912 } 4913 4914 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { 4915 RGFW_UNUSED(win); RGFW_UNUSED(a); 4916 4917 /* TODO wayland */ 4918 } 4919 4920 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { 4921 RGFW_UNUSED(win); RGFW_UNUSED(a); 4922 4923 /* TODO wayland */ 4924 } 4925 4926 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { 4927 RGFW_monitor m = {}; 4928 RGFW_UNUSED(win); 4929 RGFW_UNUSED(m); 4930 /* TODO wayland */ 4931 4932 return m; 4933 } 4934 4935 4936 #ifndef RGFW_EGL 4937 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } 4938 #endif 4939 4940 void RGFW_window_swapBuffers(RGFW_window* win) { 4941 assert(win != NULL); 4942 4943 /* clear the window*/ 4944 #ifdef RGFW_BUFFER 4945 wl_surface_frame_done(win, NULL, 0); 4946 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) 4947 #endif 4948 { 4949 #ifdef RGFW_OPENGL 4950 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); 4951 #endif 4952 } 4953 4954 wl_display_flush(win->src.display); 4955 } 4956 4957 void RGFW_window_close(RGFW_window* win) { 4958 #ifdef RGFW_EGL 4959 RGFW_closeEGL(win); 4960 #endif 4961 4962 if (RGFW_root == win) { 4963 RGFW_root = NULL; 4964 } 4965 4966 xdg_toplevel_destroy(win->src.xdg_toplevel); 4967 xdg_surface_destroy(win->src.xdg_surface); 4968 wl_surface_destroy(win->src.surface); 4969 4970 #ifdef RGFW_BUFFER 4971 wl_buffer_destroy(win->src.wl_buffer); 4972 #endif 4973 4974 wl_display_disconnect(win->src.display); 4975 RGFW_FREE(win); 4976 } 4977 4978 RGFW_monitor RGFW_getPrimaryMonitor(void) { 4979 /* TODO wayland */ 4980 4981 return (RGFW_monitor){}; 4982 } 4983 4984 RGFW_monitor* RGFW_getMonitors(void) { 4985 /* TODO wayland */ 4986 4987 return NULL; 4988 } 4989 4990 void RGFW_writeClipboard(const char* text, u32 textLen) { 4991 RGFW_UNUSED(text); RGFW_UNUSED(textLen); 4992 4993 /* TODO wayland */ 4994 } 4995 4996 char* RGFW_readClipboard(size_t* size) { 4997 RGFW_UNUSED(size); 4998 4999 /* TODO wayland */ 5000 5001 return NULL; 5002 } 5003 #endif /* RGFW_WAYLAND */ 5004 5005 /* 5006 End of Wayland defines 5007 */ 5008 5009 5010 /* 5011 5012 Start of Windows defines 5013 5014 5015 */ 5016 5017 #ifdef RGFW_WINDOWS 5018 #define WIN32_LEAN_AND_MEAN 5019 #define OEMRESOURCE 5020 #include <windows.h> 5021 5022 #include <processthreadsapi.h> 5023 #include <wchar.h> 5024 #include <locale.h> 5025 #include <windowsx.h> 5026 #include <shellapi.h> 5027 #include <shellscalingapi.h> 5028 5029 #include <winuser.h> 5030 5031 __declspec(dllimport) int __stdcall WideCharToMultiByte( UINT CodePage, DWORD dwFlags, const WCHAR* lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar); 5032 5033 #ifndef RGFW_NO_XINPUT 5034 typedef DWORD (WINAPI * PFN_XInputGetState)(DWORD,XINPUT_STATE*); 5035 PFN_XInputGetState XInputGetStateSRC = NULL; 5036 #define XInputGetState XInputGetStateSRC 5037 5038 typedef DWORD (WINAPI * PFN_XInputGetKeystroke)(DWORD, DWORD, PXINPUT_KEYSTROKE); 5039 PFN_XInputGetKeystroke XInputGetKeystrokeSRC = NULL; 5040 #define XInputGetKeystroke XInputGetKeystrokeSRC 5041 5042 static HMODULE RGFW_XInput_dll = NULL; 5043 #endif 5044 5045 u32 RGFW_mouseIconSrc[] = {OCR_NORMAL, OCR_NORMAL, OCR_IBEAM, OCR_CROSS, OCR_HAND, OCR_SIZEWE, OCR_SIZENS, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEALL, OCR_NO}; 5046 5047 char* createUTF8FromWideStringWin32(const WCHAR* source); 5048 5049 #define GL_FRONT 0x0404 5050 #define GL_BACK 0x0405 5051 #define GL_LEFT 0x0406 5052 #define GL_RIGHT 0x0407 5053 5054 #if defined(RGFW_OSMESA) && defined(RGFW_LINK_OSMESA) 5055 5056 typedef void (GLAPIENTRY* PFN_OSMesaDestroyContext)(OSMesaContext); 5057 typedef i32(GLAPIENTRY* PFN_OSMesaMakeCurrent)(OSMesaContext, void*, int, int, int); 5058 typedef OSMesaContext(GLAPIENTRY* PFN_OSMesaCreateContext)(GLenum, OSMesaContext); 5059 5060 PFN_OSMesaMakeCurrent OSMesaMakeCurrentSource; 5061 PFN_OSMesaCreateContext OSMesaCreateContextSource; 5062 PFN_OSMesaDestroyContext OSMesaDestroyContextSource; 5063 5064 #define OSMesaCreateContext OSMesaCreateContextSource 5065 #define OSMesaMakeCurrent OSMesaMakeCurrentSource 5066 #define OSMesaDestroyContext OSMesaDestroyContextSource 5067 #endif 5068 5069 typedef int (*PFN_wglGetSwapIntervalEXT)(void); 5070 PFN_wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc = NULL; 5071 #define wglGetSwapIntervalEXT wglGetSwapIntervalEXTSrc 5072 5073 5074 void* RGFWjoystickApi = NULL; 5075 5076 /* these two wgl functions need to be preloaded */ 5077 typedef HGLRC (WINAPI *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hdc, HGLRC hglrc, const int *attribList); 5078 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL; 5079 5080 /* defines for creating ARB attributes */ 5081 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 5082 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 5083 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 5084 #define WGL_DRAW_TO_WINDOW_ARB 0x2001 5085 #define WGL_ACCELERATION_ARB 0x2003 5086 #define WGL_NO_ACCELERATION_ARB 0x2025 5087 #define WGL_DOUBLE_BUFFER_ARB 0x2011 5088 #define WGL_COLOR_BITS_ARB 0x2014 5089 #define WGL_RED_BITS_ARB 0x2015 5090 #define WGL_RED_SHIFT_ARB 0x2016 5091 #define WGL_GREEN_BITS_ARB 0x2017 5092 #define WGL_GREEN_SHIFT_ARB 0x2018 5093 #define WGL_BLUE_BITS_ARB 0x2019 5094 #define WGL_BLUE_SHIFT_ARB 0x201a 5095 #define WGL_ALPHA_BITS_ARB 0x201b 5096 #define WGL_ALPHA_SHIFT_ARB 0x201c 5097 #define WGL_ACCUM_BITS_ARB 0x201d 5098 #define WGL_ACCUM_RED_BITS_ARB 0x201e 5099 #define WGL_ACCUM_GREEN_BITS_ARB 0x201f 5100 #define WGL_ACCUM_BLUE_BITS_ARB 0x2020 5101 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 5102 #define WGL_DEPTH_BITS_ARB 0x2022 5103 #define WGL_AUX_BUFFERS_ARB 0x2024 5104 #define WGL_STEREO_ARB 0x2012 5105 #define WGL_DEPTH_BITS_ARB 0x2022 5106 #define WGL_STENCIL_BITS_ARB 0x2023 5107 #define WGL_FULL_ACCELERATION_ARB 0x2027 5108 #define WGL_CONTEXT_FLAGS_ARB 0x2094 5109 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 5110 #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002 5111 #define WGL_SAMPLE_BUFFERS_ARB 0x2041 5112 #define WGL_SAMPLES_ARB 0x2042 5113 #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9 5114 5115 #ifndef RGFW_EGL 5116 static HMODULE wglinstance = NULL; 5117 #endif 5118 5119 #ifdef RGFW_WGL_LOAD 5120 typedef HGLRC(WINAPI* PFN_wglCreateContext)(HDC); 5121 typedef BOOL(WINAPI* PFN_wglDeleteContext)(HGLRC); 5122 typedef PROC(WINAPI* PFN_wglGetProcAddress)(LPCSTR); 5123 typedef BOOL(WINAPI* PFN_wglMakeCurrent)(HDC, HGLRC); 5124 typedef HDC(WINAPI* PFN_wglGetCurrentDC)(); 5125 typedef HGLRC(WINAPI* PFN_wglGetCurrentContext)(); 5126 5127 PFN_wglCreateContext wglCreateContextSRC; 5128 PFN_wglDeleteContext wglDeleteContextSRC; 5129 PFN_wglGetProcAddress wglGetProcAddressSRC; 5130 PFN_wglMakeCurrent wglMakeCurrentSRC; 5131 PFN_wglGetCurrentDC wglGetCurrentDCSRC; 5132 PFN_wglGetCurrentContext wglGetCurrentContextSRC; 5133 5134 #define wglCreateContext wglCreateContextSRC 5135 #define wglDeleteContext wglDeleteContextSRC 5136 #define wglGetProcAddress wglGetProcAddressSRC 5137 #define wglMakeCurrent wglMakeCurrentSRC 5138 5139 #define wglGetCurrentDC wglGetCurrentDCSRC 5140 #define wglGetCurrentContext wglGetCurrentContextSRC 5141 #endif 5142 5143 #ifdef RGFW_OPENGL 5144 void* RGFW_getProcAddress(const char* procname) { 5145 void* proc = (void*) wglGetProcAddress(procname); 5146 if (proc) 5147 return proc; 5148 5149 return (void*) GetProcAddress(wglinstance, procname); 5150 } 5151 5152 typedef HRESULT (APIENTRY* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats); 5153 static PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL; 5154 #endif 5155 5156 RGFW_window RGFW_eventWindow; 5157 5158 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 5159 switch (message) { 5160 case WM_MOVE: 5161 RGFW_eventWindow.r.x = LOWORD(lParam); 5162 RGFW_eventWindow.r.y = HIWORD(lParam); 5163 RGFW_eventWindow.src.window = hWnd; 5164 return DefWindowProcA(hWnd, message, wParam, lParam); 5165 case WM_SIZE: 5166 RGFW_eventWindow.r.w = LOWORD(lParam); 5167 RGFW_eventWindow.r.h = HIWORD(lParam); 5168 RGFW_eventWindow.src.window = hWnd; 5169 return DefWindowProcA(hWnd, message, wParam, lParam); // Call DefWindowProc after handling 5170 default: 5171 return DefWindowProcA(hWnd, message, wParam, lParam); 5172 } 5173 } 5174 5175 #ifndef RGFW_NO_DPI 5176 static HMODULE RGFW_Shcore_dll = NULL; 5177 typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,UINT*); 5178 PFN_GetDpiForMonitor GetDpiForMonitorSRC = NULL; 5179 #define GetDpiForMonitor GetDpiForMonitorSRC 5180 #endif 5181 5182 __declspec(dllimport) u32 __stdcall timeBeginPeriod(u32 uPeriod); 5183 5184 #ifndef RGFW_NO_XINPUT 5185 void RGFW_loadXInput(void) { 5186 u32 i; 5187 static const char* names[] = { 5188 "xinput1_4.dll", 5189 "xinput1_3.dll", 5190 "xinput9_1_0.dll", 5191 "xinput1_2.dll", 5192 "xinput1_1.dll" 5193 }; 5194 5195 for (i = 0; i < sizeof(names) / sizeof(const char*); i++) { 5196 RGFW_XInput_dll = LoadLibraryA(names[i]); 5197 5198 if (RGFW_XInput_dll) { 5199 XInputGetStateSRC = (PFN_XInputGetState)(void*)GetProcAddress(RGFW_XInput_dll, "XInputGetState"); 5200 5201 if (XInputGetStateSRC == NULL) 5202 printf("Failed to load XInputGetState"); 5203 } 5204 } 5205 } 5206 #endif 5207 5208 RGFWDEF void RGFW_init_buffer(RGFW_window* win); 5209 void RGFW_init_buffer(RGFW_window* win) { 5210 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 5211 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) 5212 RGFW_bufferSize = RGFW_getScreenSize(); 5213 5214 BITMAPV5HEADER bi = { 0 }; 5215 ZeroMemory(&bi, sizeof(bi)); 5216 bi.bV5Size = sizeof(bi); 5217 bi.bV5Width = RGFW_bufferSize.w; 5218 bi.bV5Height = -((LONG) RGFW_bufferSize.h); 5219 bi.bV5Planes = 1; 5220 bi.bV5BitCount = 32; 5221 bi.bV5Compression = BI_BITFIELDS; 5222 bi.bV5BlueMask = 0x00ff0000; 5223 bi.bV5GreenMask = 0x0000ff00; 5224 bi.bV5RedMask = 0x000000ff; 5225 bi.bV5AlphaMask = 0xff000000; 5226 5227 win->src.bitmap = CreateDIBSection(win->src.hdc, 5228 (BITMAPINFO*) &bi, 5229 DIB_RGB_COLORS, 5230 (void**) &win->buffer, 5231 NULL, 5232 (DWORD) 0); 5233 5234 win->src.hdcMem = CreateCompatibleDC(win->src.hdc); 5235 5236 #if defined(RGFW_OSMESA) 5237 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); 5238 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); 5239 #endif 5240 #else 5241 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ 5242 #endif 5243 } 5244 5245 void RGFW_window_setDND(RGFW_window* win, b8 allow) { 5246 DragAcceptFiles(win->src.window, allow); 5247 } 5248 5249 void RGFW_releaseCursor(RGFW_window* win) { 5250 RGFW_UNUSED(win); 5251 ClipCursor(NULL); 5252 const RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL }; 5253 RegisterRawInputDevices(&id, 1, sizeof(id)); 5254 } 5255 5256 void RGFW_captureCursor(RGFW_window* win, RGFW_rect rect) { 5257 RGFW_UNUSED(win); RGFW_UNUSED(rect); 5258 5259 RECT clipRect; 5260 GetClientRect(win->src.window, &clipRect); 5261 ClientToScreen(win->src.window, (POINT*) &clipRect.left); 5262 ClientToScreen(win->src.window, (POINT*) &clipRect.right); 5263 ClipCursor(&clipRect); 5264 5265 const RAWINPUTDEVICE id = { 0x01, 0x02, 0, win->src.window }; 5266 RegisterRawInputDevices(&id, 1, sizeof(id)); 5267 } 5268 5269 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { 5270 #ifndef RGFW_NO_XINPUT 5271 if (RGFW_XInput_dll == NULL) 5272 RGFW_loadXInput(); 5273 #endif 5274 5275 #ifndef RGFW_NO_DPI 5276 if (RGFW_Shcore_dll == NULL) { 5277 RGFW_Shcore_dll = LoadLibraryA("shcore.dll"); 5278 GetDpiForMonitorSRC = (PFN_GetDpiForMonitor)(void*)GetProcAddress(RGFW_Shcore_dll, "GetDpiForMonitor"); 5279 SetProcessDPIAware(); 5280 } 5281 #endif 5282 5283 if (wglinstance == NULL) { 5284 wglinstance = LoadLibraryA("opengl32.dll"); 5285 #ifdef RGFW_WGL_LOAD 5286 wglCreateContextSRC = (PFN_wglCreateContext) GetProcAddress(wglinstance, "wglCreateContext"); 5287 wglDeleteContextSRC = (PFN_wglDeleteContext) GetProcAddress(wglinstance, "wglDeleteContext"); 5288 wglGetProcAddressSRC = (PFN_wglGetProcAddress) GetProcAddress(wglinstance, "wglGetProcAddress"); 5289 wglMakeCurrentSRC = (PFN_wglMakeCurrent) GetProcAddress(wglinstance, "wglMakeCurrent"); 5290 wglGetCurrentDCSRC = (PFN_wglGetCurrentDC) GetProcAddress(wglinstance, "wglGetCurrentDC"); 5291 wglGetCurrentContextSRC = (PFN_wglGetCurrentContext) GetProcAddress(wglinstance, "wglGetCurrentContext"); 5292 #endif 5293 } 5294 5295 if (name[0] == 0) name = (char*) " "; 5296 5297 RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1); 5298 RGFW_eventWindow.src.window = NULL; 5299 5300 RGFW_window* win = RGFW_window_basic_init(rect, args); 5301 5302 win->src.maxSize = RGFW_AREA(0, 0); 5303 win->src.minSize = RGFW_AREA(0, 0); 5304 5305 5306 HINSTANCE inh = GetModuleHandleA(NULL); 5307 5308 #ifndef __cplusplus 5309 WNDCLASSA Class = { 0 }; /*!< Setup the Window class. */ 5310 #else 5311 WNDCLASSA Class = { }; 5312 #endif 5313 5314 if (RGFW_className == NULL) 5315 RGFW_className = (char*)name; 5316 5317 Class.lpszClassName = RGFW_className; 5318 Class.hInstance = inh; 5319 Class.hCursor = LoadCursor(NULL, IDC_ARROW); 5320 Class.lpfnWndProc = WndProc; 5321 5322 RegisterClassA(&Class); 5323 5324 DWORD window_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 5325 5326 RECT windowRect, clientRect; 5327 5328 if (!(args & RGFW_NO_BORDER)) { 5329 window_style |= WS_CAPTION | WS_SYSMENU | WS_BORDER | WS_MINIMIZEBOX; 5330 5331 if (!(args & RGFW_NO_RESIZE)) 5332 window_style |= WS_SIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME; 5333 } else 5334 window_style |= WS_POPUP | WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX; 5335 5336 HWND dummyWin = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h, 0, 0, inh, 0); 5337 5338 GetWindowRect(dummyWin, &windowRect); 5339 GetClientRect(dummyWin, &clientRect); 5340 5341 win->src.hOffset = (windowRect.bottom - windowRect.top) - (clientRect.bottom - clientRect.top); 5342 win->src.window = CreateWindowA(Class.lpszClassName, name, window_style, win->r.x, win->r.y, win->r.w, win->r.h + win->src.hOffset, 0, 0, inh, 0); 5343 5344 if (args & RGFW_ALLOW_DND) { 5345 win->_winArgs |= RGFW_ALLOW_DND; 5346 RGFW_window_setDND(win, 1); 5347 } 5348 win->src.hdc = GetDC(win->src.window); 5349 5350 if ((args & RGFW_NO_INIT_API) == 0) { 5351 #ifdef RGFW_DIRECTX 5352 assert(FAILED(CreateDXGIFactory(&__uuidof(IDXGIFactory), (void**) &RGFW_dxInfo.pFactory)) == 0); 5353 5354 if (FAILED(RGFW_dxInfo.pFactory->lpVtbl->EnumAdapters(RGFW_dxInfo.pFactory, 0, &RGFW_dxInfo.pAdapter))) { 5355 fprintf(stderr, "Failed to enumerate DXGI adapters\n"); 5356 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory); 5357 return NULL; 5358 } 5359 5360 D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 }; 5361 5362 if (FAILED(D3D11CreateDevice(RGFW_dxInfo.pAdapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, 0, featureLevels, 1, D3D11_SDK_VERSION, &RGFW_dxInfo.pDevice, NULL, &RGFW_dxInfo.pDeviceContext))) { 5363 fprintf(stderr, "Failed to create Direct3D device\n"); 5364 RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter); 5365 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory); 5366 return NULL; 5367 } 5368 5369 DXGI_SWAP_CHAIN_DESC swapChainDesc = { 0 }; 5370 swapChainDesc.BufferCount = 1; 5371 swapChainDesc.BufferDesc.Width = win->r.w; 5372 swapChainDesc.BufferDesc.Height = win->r.h; 5373 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 5374 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 5375 swapChainDesc.OutputWindow = win->src.window; 5376 swapChainDesc.SampleDesc.Count = 1; 5377 swapChainDesc.SampleDesc.Quality = 0; 5378 swapChainDesc.Windowed = TRUE; 5379 RGFW_dxInfo.pFactory->lpVtbl->CreateSwapChain(RGFW_dxInfo.pFactory, (IUnknown*) RGFW_dxInfo.pDevice, &swapChainDesc, &win->src.swapchain); 5380 5381 ID3D11Texture2D* pBackBuffer; 5382 win->src.swapchain->lpVtbl->GetBuffer(win->src.swapchain, 0, &__uuidof(ID3D11Texture2D), (LPVOID*) &pBackBuffer); 5383 RGFW_dxInfo.pDevice->lpVtbl->CreateRenderTargetView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pBackBuffer, NULL, &win->src.renderTargetView); 5384 pBackBuffer->lpVtbl->Release(pBackBuffer); 5385 5386 D3D11_TEXTURE2D_DESC depthStencilDesc = { 0 }; 5387 depthStencilDesc.Width = win->r.w; 5388 depthStencilDesc.Height = win->r.h; 5389 depthStencilDesc.MipLevels = 1; 5390 depthStencilDesc.ArraySize = 1; 5391 depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 5392 depthStencilDesc.SampleDesc.Count = 1; 5393 depthStencilDesc.SampleDesc.Quality = 0; 5394 depthStencilDesc.Usage = D3D11_USAGE_DEFAULT; 5395 depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; 5396 5397 ID3D11Texture2D* pDepthStencilTexture = NULL; 5398 RGFW_dxInfo.pDevice->lpVtbl->CreateTexture2D(RGFW_dxInfo.pDevice, &depthStencilDesc, NULL, &pDepthStencilTexture); 5399 5400 D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = { 0 }; 5401 depthStencilViewDesc.Format = depthStencilDesc.Format; 5402 depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; 5403 depthStencilViewDesc.Texture2D.MipSlice = 0; 5404 5405 RGFW_dxInfo.pDevice->lpVtbl->CreateDepthStencilView(RGFW_dxInfo.pDevice, (ID3D11Resource*) pDepthStencilTexture, &depthStencilViewDesc, &win->src.pDepthStencilView); 5406 5407 pDepthStencilTexture->lpVtbl->Release(pDepthStencilTexture); 5408 5409 RGFW_dxInfo.pDeviceContext->lpVtbl->OMSetRenderTargets(RGFW_dxInfo.pDeviceContext, 1, &win->src.renderTargetView, win->src.pDepthStencilView); 5410 #endif 5411 5412 #ifdef RGFW_OPENGL 5413 HDC dummy_dc = GetDC(dummyWin); 5414 5415 u32 pfd_flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; 5416 5417 //if (RGFW_DOUBLE_BUFFER) 5418 pfd_flags |= PFD_DOUBLEBUFFER; 5419 5420 PIXELFORMATDESCRIPTOR pfd = { 5421 sizeof(pfd), 5422 1, /* version */ 5423 pfd_flags, 5424 PFD_TYPE_RGBA, /* ipixel type */ 5425 24, /* color bits */ 5426 0, 0, 0, 0, 0, 0, 5427 8, /* alpha bits */ 5428 0, 0, 0, 0, 0, 0, 5429 32, /* depth bits */ 5430 8, /* stencil bits */ 5431 0, 5432 PFD_MAIN_PLANE, /* Layer type */ 5433 0, 0, 0, 0 5434 }; 5435 5436 int pixel_format = ChoosePixelFormat(dummy_dc, &pfd); 5437 SetPixelFormat(dummy_dc, pixel_format, &pfd); 5438 5439 HGLRC dummy_context = wglCreateContext(dummy_dc); 5440 wglMakeCurrent(dummy_dc, dummy_context); 5441 5442 if (wglChoosePixelFormatARB == NULL) { 5443 wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) (void*) wglGetProcAddress("wglCreateContextAttribsARB"); 5444 wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) (void*)wglGetProcAddress("wglChoosePixelFormatARB"); 5445 } 5446 5447 wglMakeCurrent(dummy_dc, 0); 5448 wglDeleteContext(dummy_context); 5449 ReleaseDC(dummyWin, dummy_dc); 5450 5451 /* try to create the pixel format we want for opengl and then try to create an opengl context for the specified version */ 5452 if (wglCreateContextAttribsARB != NULL) { 5453 PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd), 1, pfd_flags, PFD_TYPE_RGBA, 32, 8, PFD_MAIN_PLANE, 24, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 5454 5455 if (args & RGFW_OPENGL_SOFTWARE) 5456 pfd.dwFlags |= PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED; 5457 5458 if (wglChoosePixelFormatARB != NULL) { 5459 i32* pixel_format_attribs = (i32*)RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE); 5460 5461 int pixel_format; 5462 UINT num_formats; 5463 wglChoosePixelFormatARB(win->src.hdc, pixel_format_attribs, 0, 1, &pixel_format, &num_formats); 5464 if (!num_formats) { 5465 printf("Failed to create a pixel format for WGL.\n"); 5466 } 5467 5468 DescribePixelFormat(win->src.hdc, pixel_format, sizeof(pfd), &pfd); 5469 if (!SetPixelFormat(win->src.hdc, pixel_format, &pfd)) { 5470 printf("Failed to set the WGL pixel format.\n"); 5471 } 5472 } 5473 5474 /* create opengl/WGL context for the specified version */ 5475 u32 index = 0; 5476 i32 attribs[40]; 5477 5478 if (RGFW_profile == RGFW_GL_CORE) { 5479 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB); 5480 } 5481 else { 5482 SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB); 5483 } 5484 5485 if (RGFW_majorVersion || RGFW_minorVersion) { 5486 SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, RGFW_majorVersion); 5487 SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, RGFW_minorVersion); 5488 } 5489 5490 SET_ATTRIB(0, 0); 5491 5492 win->src.ctx = (HGLRC)wglCreateContextAttribsARB(win->src.hdc, NULL, attribs); 5493 } else { /* fall back to a default context (probably opengl 2 or something) */ 5494 fprintf(stderr, "Failed to create an accelerated OpenGL Context\n"); 5495 5496 int pixel_format = ChoosePixelFormat(win->src.hdc, &pfd); 5497 SetPixelFormat(win->src.hdc, pixel_format, &pfd); 5498 5499 win->src.ctx = wglCreateContext(win->src.hdc); 5500 } 5501 5502 wglMakeCurrent(win->src.hdc, win->src.ctx); 5503 #endif 5504 } 5505 5506 #ifdef RGFW_OSMESA 5507 #ifdef RGFW_LINK_OSM ESA 5508 OSMesaMakeCurrentSource = (PFN_OSMesaMakeCurrent) GetProcAddress(win->src.hdc, "OSMesaMakeCurrent"); 5509 OSMesaCreateContextSource = (PFN_OSMesaCreateContext) GetProcAddress(win->src.hdc, "OSMesaCreateContext"); 5510 OSMesaDestroyContextSource = (PFN_OSMesaDestroyContext) GetProcAddress(win->src.hdc, "OSMesaDestroyContext"); 5511 #endif 5512 #endif 5513 5514 #ifdef RGFW_OPENGL 5515 if ((args & RGFW_NO_INIT_API) == 0) { 5516 ReleaseDC(win->src.window, win->src.hdc); 5517 win->src.hdc = GetDC(win->src.window); 5518 wglMakeCurrent(win->src.hdc, win->src.ctx); 5519 } 5520 #endif 5521 5522 DestroyWindow(dummyWin); 5523 RGFW_init_buffer(win); 5524 5525 5526 #ifndef RGFW_NO_MONITOR 5527 if (args & RGFW_SCALE_TO_MONITOR) 5528 RGFW_window_scaleToMonitor(win); 5529 #endif 5530 5531 if (args & RGFW_CENTER) { 5532 RGFW_area screenR = RGFW_getScreenSize(); 5533 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); 5534 } 5535 5536 #ifdef RGFW_EGL 5537 if ((args & RGFW_NO_INIT_API) == 0) 5538 RGFW_createOpenGLContext(win); 5539 #endif 5540 5541 if (args & RGFW_HIDE_MOUSE) 5542 RGFW_window_showMouse(win, 0); 5543 5544 if (args & RGFW_TRANSPARENT_WINDOW) { 5545 SetWindowLong(win->src.window, GWL_EXSTYLE, GetWindowLong(win->src.window, GWL_EXSTYLE) | WS_EX_LAYERED); 5546 SetLayeredWindowAttributes(win->src.window, RGB(255, 255, 255), RGFW_ALPHA, LWA_ALPHA); 5547 } 5548 5549 ShowWindow(win->src.window, SW_SHOWNORMAL); 5550 5551 if (RGFW_root == NULL) 5552 RGFW_root = win; 5553 5554 #ifdef RGFW_OPENGL 5555 else 5556 wglShareLists(RGFW_root->src.ctx, win->src.ctx); 5557 #endif 5558 5559 return win; 5560 } 5561 5562 void RGFW_window_setBorder(RGFW_window* win, u8 border) { 5563 DWORD style = GetWindowLong(win->src.window, GWL_STYLE); 5564 5565 if (border == 0) { 5566 SetWindowLong(win->src.window, GWL_STYLE, style & ~WS_OVERLAPPEDWINDOW); 5567 SetWindowPos( 5568 win->src.window, HWND_TOP, 0, 0, 0, 0, 5569 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE 5570 ); 5571 } 5572 else { 5573 SetWindowLong(win->src.window, GWL_STYLE, style | WS_OVERLAPPEDWINDOW); 5574 SetWindowPos( 5575 win->src.window, HWND_TOP, 0, 0, 0, 0, 5576 SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE 5577 ); 5578 } 5579 } 5580 5581 5582 RGFW_area RGFW_getScreenSize(void) { 5583 return RGFW_AREA(GetDeviceCaps(GetDC(NULL), HORZRES), GetDeviceCaps(GetDC(NULL), VERTRES)); 5584 } 5585 5586 RGFW_point RGFW_getGlobalMousePoint(void) { 5587 POINT p; 5588 GetCursorPos(&p); 5589 5590 return RGFW_POINT(p.x, p.y); 5591 } 5592 5593 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { 5594 POINT p; 5595 GetCursorPos(&p); 5596 ScreenToClient(win->src.window, &p); 5597 5598 return RGFW_POINT(p.x, p.y); 5599 } 5600 5601 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { 5602 assert(win != NULL); 5603 win->src.minSize = a; 5604 } 5605 5606 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { 5607 assert(win != NULL); 5608 win->src.maxSize = a; 5609 } 5610 5611 5612 void RGFW_window_minimize(RGFW_window* win) { 5613 assert(win != NULL); 5614 5615 ShowWindow(win->src.window, SW_MINIMIZE); 5616 } 5617 5618 void RGFW_window_restore(RGFW_window* win) { 5619 assert(win != NULL); 5620 5621 ShowWindow(win->src.window, SW_RESTORE); 5622 } 5623 5624 5625 u8 RGFW_xinput2RGFW[] = { 5626 RGFW_JS_A, /* or PS X button */ 5627 RGFW_JS_B, /* or PS circle button */ 5628 RGFW_JS_X, /* or PS square button */ 5629 RGFW_JS_Y, /* or PS triangle button */ 5630 RGFW_JS_R1, /* right bumper */ 5631 RGFW_JS_L1, /* left bump */ 5632 RGFW_JS_L2, /* left trigger*/ 5633 RGFW_JS_R2, /* right trigger */ 5634 0, 0, 0, 0, 0, 0, 0, 0, 5635 RGFW_JS_UP, /* dpad up */ 5636 RGFW_JS_DOWN, /* dpad down*/ 5637 RGFW_JS_LEFT, /* dpad left */ 5638 RGFW_JS_RIGHT, /* dpad right */ 5639 RGFW_JS_START, /* start button */ 5640 RGFW_JS_SELECT/* select button */ 5641 }; 5642 5643 static i32 RGFW_checkXInput(RGFW_window* win, RGFW_Event* e) { 5644 RGFW_UNUSED(win) 5645 5646 size_t i; 5647 for (i = 0; i < 4; i++) { 5648 XINPUT_KEYSTROKE keystroke; 5649 5650 if (XInputGetKeystroke == NULL) 5651 return 0; 5652 5653 DWORD result = XInputGetKeystroke((DWORD)i, 0, &keystroke); 5654 5655 if ((keystroke.Flags & XINPUT_KEYSTROKE_REPEAT) == 0 && result != ERROR_EMPTY) { 5656 if (result != ERROR_SUCCESS) 5657 return 0; 5658 5659 if (keystroke.VirtualKey > VK_PAD_BACK) 5660 continue; 5661 5662 // RGFW_jsButtonPressed + 1 = RGFW_jsButtonReleased 5663 e->type = RGFW_jsButtonPressed + !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); 5664 e->button = RGFW_xinput2RGFW[keystroke.VirtualKey - 0x5800]; 5665 RGFW_jsPressed[i][e->button] = !(keystroke.Flags & XINPUT_KEYSTROKE_KEYDOWN); 5666 5667 return 1; 5668 } 5669 5670 XINPUT_STATE state; 5671 if (XInputGetState == NULL || 5672 XInputGetState((DWORD) i, &state) == ERROR_DEVICE_NOT_CONNECTED 5673 ) 5674 return 0; 5675 #define INPUT_DEADZONE ( 0.24f * (float)(0x7FFF) ) // Default to 24% of the +/- 32767 range. This is a reasonable default value but can be altered if needed. 5676 5677 if ((state.Gamepad.sThumbLX < INPUT_DEADZONE && 5678 state.Gamepad.sThumbLX > -INPUT_DEADZONE) && 5679 (state.Gamepad.sThumbLY < INPUT_DEADZONE && 5680 state.Gamepad.sThumbLY > -INPUT_DEADZONE)) 5681 { 5682 state.Gamepad.sThumbLX = 0; 5683 state.Gamepad.sThumbLY = 0; 5684 } 5685 5686 if ((state.Gamepad.sThumbRX < INPUT_DEADZONE && 5687 state.Gamepad.sThumbRX > -INPUT_DEADZONE) && 5688 (state.Gamepad.sThumbRY < INPUT_DEADZONE && 5689 state.Gamepad.sThumbRY > -INPUT_DEADZONE)) 5690 { 5691 state.Gamepad.sThumbRX = 0; 5692 state.Gamepad.sThumbRY = 0; 5693 } 5694 5695 e->axisesCount = 2; 5696 RGFW_point axis1 = RGFW_POINT(state.Gamepad.sThumbLX, state.Gamepad.sThumbLY); 5697 RGFW_point axis2 = RGFW_POINT(state.Gamepad.sThumbRX, state.Gamepad.sThumbRY); 5698 5699 if (axis1.x != e->axis[0].x || axis1.y != e->axis[0].y || axis2.x != e->axis[1].x || axis2.y != e->axis[1].y) { 5700 e->type = RGFW_jsAxisMove; 5701 5702 e->axis[0] = axis1; 5703 e->axis[1] = axis2; 5704 5705 return 1; 5706 } 5707 5708 e->axis[0] = axis1; 5709 e->axis[1] = axis2; 5710 } 5711 5712 return 0; 5713 } 5714 5715 void RGFW_stopCheckEvents(void) { 5716 PostMessageW(RGFW_root->src.window, WM_NULL, 0, 0); 5717 } 5718 5719 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { 5720 RGFW_UNUSED(win); 5721 5722 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (waitMS * 1e3), QS_ALLINPUT); 5723 } 5724 5725 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { 5726 assert(win != NULL); 5727 5728 if (win->event.type == RGFW_quit) { 5729 return NULL; 5730 } 5731 5732 MSG msg; 5733 5734 if (RGFW_eventWindow.src.window == win->src.window) { 5735 if (RGFW_eventWindow.r.x != -1) { 5736 win->r.x = RGFW_eventWindow.r.x; 5737 win->r.y = RGFW_eventWindow.r.y; 5738 win->event.type = RGFW_windowMoved; 5739 RGFW_windowMoveCallback(win, win->r); 5740 } 5741 5742 if (RGFW_eventWindow.r.w != -1) { 5743 win->r.w = RGFW_eventWindow.r.w; 5744 win->r.h = RGFW_eventWindow.r.h; 5745 win->event.type = RGFW_windowResized; 5746 RGFW_windowResizeCallback(win, win->r); 5747 } 5748 5749 RGFW_eventWindow.src.window = NULL; 5750 RGFW_eventWindow.r = RGFW_RECT(-1, -1, -1, -1); 5751 5752 return &win->event; 5753 } 5754 5755 5756 static HDROP drop; 5757 5758 if (win->event.type == RGFW_dnd_init) { 5759 if (win->event.droppedFilesCount) { 5760 u32 i; 5761 for (i = 0; i < win->event.droppedFilesCount; i++) 5762 win->event.droppedFiles[i][0] = '\0'; 5763 } 5764 5765 win->event.droppedFilesCount = 0; 5766 win->event.droppedFilesCount = DragQueryFileW(drop, 0xffffffff, NULL, 0); 5767 //win->event.droppedFiles = (char**)RGFW_CALLOC(win->event.droppedFilesCount, sizeof(char*)); 5768 5769 u32 i; 5770 for (i = 0; i < win->event.droppedFilesCount; i++) { 5771 const UINT length = DragQueryFileW(drop, i, NULL, 0); 5772 WCHAR* buffer = (WCHAR*) RGFW_CALLOC((size_t) length + 1, sizeof(WCHAR)); 5773 5774 DragQueryFileW(drop, i, buffer, length + 1); 5775 strncpy(win->event.droppedFiles[i], createUTF8FromWideStringWin32(buffer), RGFW_MAX_PATH); 5776 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; 5777 RGFW_FREE(buffer); 5778 } 5779 5780 DragFinish(drop); 5781 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); 5782 5783 win->event.type = RGFW_dnd; 5784 return &win->event; 5785 } 5786 5787 win->event.inFocus = (GetForegroundWindow() == win->src.window); 5788 5789 if (RGFW_checkXInput(win, &win->event)) 5790 return &win->event; 5791 5792 static BYTE keyboardState[256]; 5793 5794 if (PeekMessageA(&msg, win->src.window, 0u, 0u, PM_REMOVE)) { 5795 switch (msg.message) { 5796 case WM_CLOSE: 5797 case WM_QUIT: 5798 RGFW_windowQuitCallback(win); 5799 win->event.type = RGFW_quit; 5800 break; 5801 5802 case WM_ACTIVATE: 5803 win->event.inFocus = (LOWORD(msg.wParam) == WA_INACTIVE); 5804 5805 if (win->event.inFocus) { 5806 win->event.type = RGFW_focusIn; 5807 RGFW_focusCallback(win, 1); 5808 } 5809 else { 5810 win->event.type = RGFW_focusOut; 5811 RGFW_focusCallback(win, 0); 5812 } 5813 5814 break; 5815 5816 case WM_PAINT: 5817 win->event.type = RGFW_windowRefresh; 5818 RGFW_windowRefreshCallback(win); 5819 break; 5820 5821 case WM_MOUSELEAVE: 5822 win->event.type = RGFW_mouseLeave; 5823 win->_winArgs |= RGFW_MOUSE_LEFT; 5824 RGFW_mouseNotifyCallBack(win, win->event.point, 0); 5825 break; 5826 5827 case WM_KEYUP: { 5828 win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam); 5829 5830 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); 5831 5832 static char keyName[16]; 5833 5834 { 5835 GetKeyNameTextA((LONG) msg.lParam, keyName, 16); 5836 5837 if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) || 5838 ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) { 5839 CharLowerBuffA(keyName, 16); 5840 } 5841 } 5842 5843 RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001)); 5844 5845 strncpy(win->event.keyName, keyName, 16); 5846 5847 if (RGFW_isPressed(win, RGFW_ShiftL)) { 5848 ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR), 5849 keyboardState, (LPWORD) win->event.keyName, 0); 5850 } 5851 5852 win->event.type = RGFW_keyReleased; 5853 RGFW_keyboard[win->event.keyCode].current = 0; 5854 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0); 5855 break; 5856 } 5857 case WM_KEYDOWN: { 5858 win->event.keyCode = RGFW_apiKeyCodeToRGFW((u32) msg.wParam); 5859 5860 RGFW_keyboard[win->event.keyCode].prev = RGFW_isPressed(win, win->event.keyCode); 5861 5862 static char keyName[16]; 5863 5864 { 5865 GetKeyNameTextA((LONG) msg.lParam, keyName, 16); 5866 5867 if ((!(GetKeyState(VK_CAPITAL) & 0x0001) && !(GetKeyState(VK_SHIFT) & 0x8000)) || 5868 ((GetKeyState(VK_CAPITAL) & 0x0001) && (GetKeyState(VK_SHIFT) & 0x8000))) { 5869 CharLowerBuffA(keyName, 16); 5870 } 5871 } 5872 5873 RGFW_updateLockState(win, (GetKeyState(VK_CAPITAL) & 0x0001), (GetKeyState(VK_NUMLOCK) & 0x0001)); 5874 5875 strncpy(win->event.keyName, keyName, 16); 5876 5877 if (RGFW_isPressed(win, RGFW_ShiftL) & 0x8000) { 5878 ToAscii((UINT) msg.wParam, MapVirtualKey((UINT) msg.wParam, MAPVK_VK_TO_CHAR), 5879 keyboardState, (LPWORD) win->event.keyName, 0); 5880 } 5881 5882 win->event.type = RGFW_keyPressed; 5883 win->event.repeat = RGFW_isPressed(win, win->event.keyCode); 5884 RGFW_keyboard[win->event.keyCode].current = 1; 5885 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1); 5886 break; 5887 } 5888 5889 case WM_MOUSEMOVE: 5890 if ((win->_winArgs & RGFW_HOLD_MOUSE)) 5891 break; 5892 5893 win->event.type = RGFW_mousePosChanged; 5894 5895 win->event.point.x = GET_X_LPARAM(msg.lParam); 5896 win->event.point.y = GET_Y_LPARAM(msg.lParam); 5897 5898 RGFW_mousePosCallback(win, win->event.point); 5899 5900 if (win->_winArgs & RGFW_MOUSE_LEFT) { 5901 win->_winArgs ^= RGFW_MOUSE_LEFT; 5902 win->event.type = RGFW_mouseEnter; 5903 RGFW_mouseNotifyCallBack(win, win->event.point, 1); 5904 } 5905 5906 break; 5907 5908 case WM_INPUT: { 5909 if (!(win->_winArgs & RGFW_HOLD_MOUSE)) 5910 break; 5911 5912 unsigned size = sizeof(RAWINPUT); 5913 static RAWINPUT raw[sizeof(RAWINPUT)]; 5914 GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); 5915 5916 if (raw->header.dwType != RIM_TYPEMOUSE || (raw->data.mouse.lLastX == 0 && raw->data.mouse.lLastY == 0) ) 5917 break; 5918 5919 win->event.type = RGFW_mousePosChanged; 5920 win->event.point.x = raw->data.mouse.lLastX; 5921 win->event.point.y = raw->data.mouse.lLastY; 5922 break; 5923 } 5924 5925 case WM_LBUTTONDOWN: 5926 win->event.button = RGFW_mouseLeft; 5927 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 5928 RGFW_mouseButtons[win->event.button].current = 1; 5929 win->event.type = RGFW_mouseButtonPressed; 5930 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 5931 break; 5932 case WM_RBUTTONDOWN: 5933 win->event.button = RGFW_mouseRight; 5934 win->event.type = RGFW_mouseButtonPressed; 5935 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 5936 RGFW_mouseButtons[win->event.button].current = 1; 5937 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 5938 break; 5939 case WM_MBUTTONDOWN: 5940 win->event.button = RGFW_mouseMiddle; 5941 win->event.type = RGFW_mouseButtonPressed; 5942 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 5943 RGFW_mouseButtons[win->event.button].current = 1; 5944 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 5945 break; 5946 5947 case WM_MOUSEWHEEL: 5948 if (msg.wParam > 0) 5949 win->event.button = RGFW_mouseScrollUp; 5950 else 5951 win->event.button = RGFW_mouseScrollDown; 5952 5953 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 5954 RGFW_mouseButtons[win->event.button].current = 1; 5955 5956 win->event.scroll = (SHORT) HIWORD(msg.wParam) / (double) WHEEL_DELTA; 5957 5958 win->event.type = RGFW_mouseButtonPressed; 5959 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 5960 break; 5961 5962 case WM_LBUTTONUP: 5963 5964 win->event.button = RGFW_mouseLeft; 5965 win->event.type = RGFW_mouseButtonReleased; 5966 5967 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 5968 RGFW_mouseButtons[win->event.button].current = 0; 5969 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); 5970 break; 5971 case WM_RBUTTONUP: 5972 win->event.button = RGFW_mouseRight; 5973 win->event.type = RGFW_mouseButtonReleased; 5974 5975 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 5976 RGFW_mouseButtons[win->event.button].current = 0; 5977 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); 5978 break; 5979 case WM_MBUTTONUP: 5980 win->event.button = RGFW_mouseMiddle; 5981 win->event.type = RGFW_mouseButtonReleased; 5982 5983 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 5984 RGFW_mouseButtons[win->event.button].current = 0; 5985 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); 5986 break; 5987 5988 /* 5989 much of this event is source from glfw 5990 */ 5991 case WM_DROPFILES: { 5992 win->event.type = RGFW_dnd_init; 5993 5994 drop = (HDROP) msg.wParam; 5995 POINT pt; 5996 5997 /* Move the mouse to the position of the drop */ 5998 DragQueryPoint(drop, &pt); 5999 6000 win->event.point.x = pt.x; 6001 win->event.point.y = pt.y; 6002 6003 RGFW_dndInitCallback(win, win->event.point); 6004 } 6005 break; 6006 case WM_GETMINMAXINFO: 6007 { 6008 if (win->src.maxSize.w == 0 && win->src.maxSize.h == 0) 6009 break; 6010 6011 MINMAXINFO* mmi = (MINMAXINFO*) msg.lParam; 6012 mmi->ptMinTrackSize.x = win->src.minSize.w; 6013 mmi->ptMinTrackSize.y = win->src.minSize.h; 6014 mmi->ptMaxTrackSize.x = win->src.maxSize.w; 6015 mmi->ptMaxTrackSize.y = win->src.maxSize.h; 6016 return 0; 6017 } 6018 default: 6019 win->event.type = 0; 6020 break; 6021 } 6022 6023 TranslateMessage(&msg); 6024 DispatchMessageA(&msg); 6025 } 6026 6027 else 6028 win->event.type = 0; 6029 6030 if (!IsWindow(win->src.window)) { 6031 win->event.type = RGFW_quit; 6032 RGFW_windowQuitCallback(win); 6033 } 6034 6035 if (win->event.type) 6036 return &win->event; 6037 else 6038 return NULL; 6039 } 6040 6041 u8 RGFW_window_isFullscreen(RGFW_window* win) { 6042 assert(win != NULL); 6043 6044 #ifndef __cplusplus 6045 WINDOWPLACEMENT placement = { 0 }; 6046 #else 6047 WINDOWPLACEMENT placement = { }; 6048 #endif 6049 GetWindowPlacement(win->src.window, &placement); 6050 return placement.showCmd == SW_SHOWMAXIMIZED; 6051 } 6052 6053 u8 RGFW_window_isHidden(RGFW_window* win) { 6054 assert(win != NULL); 6055 6056 return IsWindowVisible(win->src.window) == 0 && !RGFW_window_isMinimized(win); 6057 } 6058 6059 u8 RGFW_window_isMinimized(RGFW_window* win) { 6060 assert(win != NULL); 6061 6062 #ifndef __cplusplus 6063 WINDOWPLACEMENT placement = { 0 }; 6064 #else 6065 WINDOWPLACEMENT placement = { }; 6066 #endif 6067 GetWindowPlacement(win->src.window, &placement); 6068 return placement.showCmd == SW_SHOWMINIMIZED; 6069 } 6070 6071 u8 RGFW_window_isMaximized(RGFW_window* win) { 6072 assert(win != NULL); 6073 6074 #ifndef __cplusplus 6075 WINDOWPLACEMENT placement = { 0 }; 6076 #else 6077 WINDOWPLACEMENT placement = { }; 6078 #endif 6079 GetWindowPlacement(win->src.window, &placement); 6080 return placement.showCmd == SW_SHOWMAXIMIZED; 6081 } 6082 6083 typedef struct { int iIndex; HMONITOR hMonitor; } RGFW_mInfo; 6084 BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { 6085 RGFW_UNUSED(hdcMonitor) 6086 RGFW_UNUSED(lprcMonitor) 6087 6088 RGFW_mInfo* info = (RGFW_mInfo*) dwData; 6089 if (info->hMonitor == hMonitor) 6090 return FALSE; 6091 6092 info->iIndex++; 6093 return TRUE; 6094 } 6095 6096 #ifndef RGFW_NO_MONITOR 6097 RGFW_monitor win32CreateMonitor(HMONITOR src) { 6098 RGFW_monitor monitor; 6099 MONITORINFO monitorInfo; 6100 6101 monitorInfo.cbSize = sizeof(MONITORINFO); 6102 GetMonitorInfoA(src, &monitorInfo); 6103 6104 RGFW_mInfo info; 6105 info.iIndex = 0; 6106 info.hMonitor = src; 6107 6108 /* get the monitor's index */ 6109 if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM) &info)) { 6110 DISPLAY_DEVICEA dd; 6111 dd.cb = sizeof(dd); 6112 6113 /* loop through the devices until you find a device with the monitor's index */ 6114 size_t deviceIndex; 6115 for (deviceIndex = 0; EnumDisplayDevicesA(0, (DWORD) deviceIndex, &dd, 0); deviceIndex++) { 6116 char* deviceName = dd.DeviceName; 6117 if (EnumDisplayDevicesA(deviceName, info.iIndex, &dd, 0)) { 6118 strncpy(monitor.name, dd.DeviceString, 128); /*!< copy the monitor's name */ 6119 break; 6120 } 6121 } 6122 } 6123 6124 monitor.rect.x = monitorInfo.rcWork.left; 6125 monitor.rect.y = monitorInfo.rcWork.top; 6126 monitor.rect.w = monitorInfo.rcWork.right - monitorInfo.rcWork.left; 6127 monitor.rect.h = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top; 6128 6129 #ifndef RGFW_NO_DPI 6130 #ifndef USER_DEFAULT_SCREEN_DPI 6131 #define USER_DEFAULT_SCREEN_DPI 96 6132 #endif 6133 6134 if (GetDpiForMonitor != NULL) { 6135 u32 x, y; 6136 GetDpiForMonitor(src, MDT_EFFECTIVE_DPI, &x, &y); 6137 6138 monitor.scaleX = (float) (x) / (float) USER_DEFAULT_SCREEN_DPI; 6139 monitor.scaleY = (float) (y) / (float) USER_DEFAULT_SCREEN_DPI; 6140 } 6141 #endif 6142 6143 HDC hdc = GetDC(NULL); 6144 /* get pixels per inch */ 6145 i32 ppiX = GetDeviceCaps(hdc, LOGPIXELSX); 6146 i32 ppiY = GetDeviceCaps(hdc, LOGPIXELSY); 6147 ReleaseDC(NULL, hdc); 6148 6149 /* Calculate physical height in inches */ 6150 monitor.physW = GetSystemMetrics(SM_CYSCREEN) / (float) ppiX; 6151 monitor.physH = GetSystemMetrics(SM_CXSCREEN) / (float) ppiY; 6152 6153 return monitor; 6154 } 6155 #endif /* RGFW_NO_MONITOR */ 6156 6157 6158 #ifndef RGFW_NO_MONITOR 6159 RGFW_monitor RGFW_monitors[6]; 6160 BOOL CALLBACK GetMonitorHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { 6161 RGFW_UNUSED(hdcMonitor) 6162 RGFW_UNUSED(lprcMonitor) 6163 6164 RGFW_mInfo* info = (RGFW_mInfo*) dwData; 6165 6166 if (info->iIndex >= 6) 6167 return FALSE; 6168 6169 RGFW_monitors[info->iIndex] = win32CreateMonitor(hMonitor); 6170 info->iIndex++; 6171 6172 return TRUE; 6173 } 6174 6175 RGFW_monitor RGFW_getPrimaryMonitor(void) { 6176 #ifdef __cplusplus 6177 return win32CreateMonitor(MonitorFromPoint({ 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); 6178 #else 6179 return win32CreateMonitor(MonitorFromPoint((POINT) { 0, 0 }, MONITOR_DEFAULTTOPRIMARY)); 6180 #endif 6181 } 6182 6183 RGFW_monitor* RGFW_getMonitors(void) { 6184 RGFW_mInfo info; 6185 info.iIndex = 0; 6186 while (EnumDisplayMonitors(NULL, NULL, GetMonitorHandle, (LPARAM) &info)); 6187 6188 return RGFW_monitors; 6189 } 6190 6191 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { 6192 HMONITOR src = MonitorFromWindow(win->src.window, MONITOR_DEFAULTTOPRIMARY); 6193 return win32CreateMonitor(src); 6194 } 6195 #endif 6196 6197 HICON RGFW_loadHandleImage(RGFW_window* win, u8* src, RGFW_area a, BOOL icon) { 6198 assert(win != NULL); 6199 6200 u32 i; 6201 HDC dc; 6202 HICON handle; 6203 HBITMAP color, mask; 6204 BITMAPV5HEADER bi; 6205 ICONINFO ii; 6206 u8* target = NULL; 6207 u8* source = src; 6208 6209 ZeroMemory(&bi, sizeof(bi)); 6210 bi.bV5Size = sizeof(bi); 6211 bi.bV5Width = a.w; 6212 bi.bV5Height = -((LONG) a.h); 6213 bi.bV5Planes = 1; 6214 bi.bV5BitCount = 32; 6215 bi.bV5Compression = BI_BITFIELDS; 6216 bi.bV5RedMask = 0x00ff0000; 6217 bi.bV5GreenMask = 0x0000ff00; 6218 bi.bV5BlueMask = 0x000000ff; 6219 bi.bV5AlphaMask = 0xff000000; 6220 6221 dc = GetDC(NULL); 6222 color = CreateDIBSection(dc, 6223 (BITMAPINFO*) &bi, 6224 DIB_RGB_COLORS, 6225 (void**) &target, 6226 NULL, 6227 (DWORD) 0); 6228 ReleaseDC(NULL, dc); 6229 6230 mask = CreateBitmap(a.w, a.h, 1, 1, NULL); 6231 6232 for (i = 0; i < a.w * a.h; i++) { 6233 target[0] = source[2]; 6234 target[1] = source[1]; 6235 target[2] = source[0]; 6236 target[3] = source[3]; 6237 target += 4; 6238 source += 4; 6239 } 6240 6241 ZeroMemory(&ii, sizeof(ii)); 6242 ii.fIcon = icon; 6243 ii.xHotspot = 0; 6244 ii.yHotspot = 0; 6245 ii.hbmMask = mask; 6246 ii.hbmColor = color; 6247 6248 handle = CreateIconIndirect(&ii); 6249 6250 DeleteObject(color); 6251 DeleteObject(mask); 6252 6253 return handle; 6254 } 6255 6256 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { 6257 assert(win != NULL); 6258 RGFW_UNUSED(channels) 6259 6260 HCURSOR cursor = (HCURSOR) RGFW_loadHandleImage(win, image, a, FALSE); 6261 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) cursor); 6262 SetCursor(cursor); 6263 DestroyCursor(cursor); 6264 } 6265 6266 void RGFW_window_setMouseDefault(RGFW_window* win) { 6267 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW); 6268 } 6269 6270 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { 6271 assert(win != NULL); 6272 6273 if (mouse > (sizeof(RGFW_mouseIconSrc) / sizeof(u32))) 6274 return; 6275 6276 char* icon = MAKEINTRESOURCEA(RGFW_mouseIconSrc[mouse]); 6277 6278 SetClassLongPtrA(win->src.window, GCLP_HCURSOR, (LPARAM) LoadCursorA(NULL, icon)); 6279 SetCursor(LoadCursorA(NULL, icon)); 6280 } 6281 6282 void RGFW_window_hide(RGFW_window* win) { 6283 ShowWindow(win->src.window, SW_HIDE); 6284 } 6285 6286 void RGFW_window_show(RGFW_window* win) { 6287 ShowWindow(win->src.window, SW_RESTORE); 6288 } 6289 6290 void RGFW_window_close(RGFW_window* win) { 6291 assert(win != NULL); 6292 6293 #ifdef RGFW_EGL 6294 RGFW_closeEGL(win); 6295 #endif 6296 6297 if (win == RGFW_root) { 6298 #ifdef RGFW_DIRECTX 6299 RGFW_dxInfo.pDeviceContext->lpVtbl->Release(RGFW_dxInfo.pDeviceContext); 6300 RGFW_dxInfo.pDevice->lpVtbl->Release(RGFW_dxInfo.pDevice); 6301 RGFW_dxInfo.pAdapter->lpVtbl->Release(RGFW_dxInfo.pAdapter); 6302 RGFW_dxInfo.pFactory->lpVtbl->Release(RGFW_dxInfo.pFactory); 6303 #endif 6304 6305 if (RGFW_XInput_dll != NULL) { 6306 FreeLibrary(RGFW_XInput_dll); 6307 RGFW_XInput_dll = NULL; 6308 } 6309 6310 #ifndef RGFW_NO_DPI 6311 if (RGFW_Shcore_dll != NULL) { 6312 FreeLibrary(RGFW_Shcore_dll); 6313 RGFW_Shcore_dll = NULL; 6314 } 6315 #endif 6316 6317 if (wglinstance != NULL) { 6318 FreeLibrary(wglinstance); 6319 wglinstance = NULL; 6320 } 6321 6322 RGFW_root = NULL; 6323 } 6324 6325 #ifdef RGFW_DIRECTX 6326 win->src.swapchain->lpVtbl->Release(win->src.swapchain); 6327 win->src.renderTargetView->lpVtbl->Release(win->src.renderTargetView); 6328 win->src.pDepthStencilView->lpVtbl->Release(win->src.pDepthStencilView); 6329 #endif 6330 6331 #ifdef RGFW_BUFFER 6332 DeleteDC(win->src.hdcMem); 6333 DeleteObject(win->src.bitmap); 6334 #endif 6335 6336 #ifdef RGFW_OPENGL 6337 wglDeleteContext((HGLRC) win->src.ctx); /*!< delete opengl context */ 6338 #endif 6339 DeleteDC(win->src.hdc); /*!< delete device context */ 6340 DestroyWindow(win->src.window); /*!< delete window */ 6341 6342 #if defined(RGFW_OSMESA) 6343 if (win->buffer != NULL) 6344 RGFW_FREE(win->buffer); 6345 #endif 6346 6347 #ifdef RGFW_ALLOC_DROPFILES 6348 { 6349 u32 i; 6350 for (i = 0; i < RGFW_MAX_DROPS; i++) 6351 RGFW_FREE(win->event.droppedFiles[i]); 6352 6353 6354 RGFW_FREE(win->event.droppedFiles); 6355 } 6356 #endif 6357 6358 RGFW_FREE(win); 6359 } 6360 6361 void RGFW_window_move(RGFW_window* win, RGFW_point v) { 6362 assert(win != NULL); 6363 6364 win->r.x = v.x; 6365 win->r.y = v.y; 6366 SetWindowPos(win->src.window, HWND_TOP, win->r.x, win->r.y, 0, 0, SWP_NOSIZE); 6367 } 6368 6369 void RGFW_window_resize(RGFW_window* win, RGFW_area a) { 6370 assert(win != NULL); 6371 6372 win->r.w = a.w; 6373 win->r.h = a.h; 6374 SetWindowPos(win->src.window, HWND_TOP, 0, 0, win->r.w, win->r.h + win->src.hOffset, SWP_NOMOVE); 6375 } 6376 6377 6378 void RGFW_window_setName(RGFW_window* win, char* name) { 6379 assert(win != NULL); 6380 6381 SetWindowTextA(win->src.window, name); 6382 } 6383 6384 /* sourced from GLFW */ 6385 #ifndef RGFW_NO_PASSTHROUGH 6386 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { 6387 assert(win != NULL); 6388 6389 COLORREF key = 0; 6390 BYTE alpha = 0; 6391 DWORD flags = 0; 6392 DWORD exStyle = GetWindowLongW(win->src.window, GWL_EXSTYLE); 6393 6394 if (exStyle & WS_EX_LAYERED) 6395 GetLayeredWindowAttributes(win->src.window, &key, &alpha, &flags); 6396 6397 if (passthrough) 6398 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED); 6399 else 6400 { 6401 exStyle &= ~WS_EX_TRANSPARENT; 6402 // NOTE: Window opacity also needs the layered window style so do not 6403 // remove it if the window is alpha blended 6404 if (exStyle & WS_EX_LAYERED) 6405 { 6406 if (!(flags & LWA_ALPHA)) 6407 exStyle &= ~WS_EX_LAYERED; 6408 } 6409 } 6410 6411 SetWindowLongW(win->src.window, GWL_EXSTYLE, exStyle); 6412 6413 if (passthrough) { 6414 SetLayeredWindowAttributes(win->src.window, key, alpha, flags); 6415 } 6416 } 6417 #endif 6418 6419 /* much of this function is sourced from GLFW */ 6420 void RGFW_window_setIcon(RGFW_window* win, u8* src, RGFW_area a, i32 channels) { 6421 assert(win != NULL); 6422 #ifndef RGFW_WIN95 6423 RGFW_UNUSED(channels) 6424 6425 HICON handle = RGFW_loadHandleImage(win, src, a, TRUE); 6426 6427 SetClassLongPtrA(win->src.window, GCLP_HICON, (LPARAM) handle); 6428 6429 DestroyIcon(handle); 6430 #else 6431 RGFW_UNUSED(src) 6432 RGFW_UNUSED(a) 6433 RGFW_UNUSED(channels) 6434 #endif 6435 } 6436 6437 char* RGFW_readClipboard(size_t* size) { 6438 /* Open the clipboard */ 6439 if (OpenClipboard(NULL) == 0) 6440 return (char*) ""; 6441 6442 /* Get the clipboard data as a Unicode string */ 6443 HANDLE hData = GetClipboardData(CF_UNICODETEXT); 6444 if (hData == NULL) { 6445 CloseClipboard(); 6446 return (char*) ""; 6447 } 6448 6449 wchar_t* wstr = (wchar_t*) GlobalLock(hData); 6450 6451 char* text; 6452 6453 { 6454 setlocale(LC_ALL, "en_US.UTF-8"); 6455 6456 size_t textLen = wcstombs(NULL, wstr, 0); 6457 if (textLen == 0) 6458 return (char*) ""; 6459 6460 text = (char*) RGFW_MALLOC((textLen * sizeof(char)) + 1); 6461 6462 wcstombs(text, wstr, (textLen) +1); 6463 6464 if (size != NULL) 6465 *size = textLen + 1; 6466 6467 text[textLen] = '\0'; 6468 } 6469 6470 /* Release the clipboard data */ 6471 GlobalUnlock(hData); 6472 CloseClipboard(); 6473 6474 return text; 6475 } 6476 6477 void RGFW_writeClipboard(const char* text, u32 textLen) { 6478 HANDLE object; 6479 WCHAR* buffer; 6480 6481 object = GlobalAlloc(GMEM_MOVEABLE, (1 + textLen) * sizeof(WCHAR)); 6482 if (!object) 6483 return; 6484 6485 buffer = (WCHAR*) GlobalLock(object); 6486 if (!buffer) { 6487 GlobalFree(object); 6488 return; 6489 } 6490 6491 MultiByteToWideChar(CP_UTF8, 0, text, -1, buffer, textLen); 6492 GlobalUnlock(object); 6493 6494 if (!OpenClipboard(RGFW_root->src.window)) { 6495 GlobalFree(object); 6496 return; 6497 } 6498 6499 EmptyClipboard(); 6500 SetClipboardData(CF_UNICODETEXT, object); 6501 CloseClipboard(); 6502 } 6503 6504 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) { 6505 assert(win != NULL); 6506 6507 RGFW_UNUSED(jsNumber) 6508 6509 return RGFW_registerJoystickF(win, (char*) ""); 6510 } 6511 6512 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) { 6513 assert(win != NULL); 6514 RGFW_UNUSED(file) 6515 6516 return RGFW_joystickCount - 1; 6517 } 6518 6519 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point p) { 6520 assert(win != NULL); 6521 6522 SetCursorPos(p.x, p.y); 6523 } 6524 6525 #ifdef RGFW_OPENGL 6526 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { 6527 if (win == NULL) 6528 wglMakeCurrent(NULL, NULL); 6529 else 6530 wglMakeCurrent(win->src.hdc, (HGLRC) win->src.ctx); 6531 } 6532 #endif 6533 6534 #ifndef RGFW_EGL 6535 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { 6536 assert(win != NULL); 6537 6538 #if defined(RGFW_OPENGL) 6539 typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALEXTPROC)(int interval); 6540 static PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; 6541 static void* loadSwapFunc = (void*) 1; 6542 6543 if (loadSwapFunc == NULL) { 6544 fprintf(stderr, "wglSwapIntervalEXT not supported\n"); 6545 return; 6546 } 6547 6548 if (wglSwapIntervalEXT == NULL) { 6549 loadSwapFunc = (void*) wglGetProcAddress("wglSwapIntervalEXT"); 6550 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) loadSwapFunc; 6551 } 6552 6553 if (wglSwapIntervalEXT(swapInterval) == FALSE) 6554 fprintf(stderr, "Failed to set swap interval\n"); 6555 #else 6556 RGFW_UNUSED(swapInterval); 6557 #endif 6558 6559 } 6560 #endif 6561 6562 void RGFW_window_swapBuffers(RGFW_window* win) { 6563 //assert(win != NULL); 6564 /* clear the window*/ 6565 6566 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { 6567 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 6568 #ifdef RGFW_OSMESA 6569 RGFW_OSMesa_reorganize(); 6570 #endif 6571 6572 HGDIOBJ oldbmp = SelectObject(win->src.hdcMem, win->src.bitmap); 6573 BitBlt(win->src.hdc, 0, 0, win->r.w, win->r.h, win->src.hdcMem, 0, 0, SRCCOPY); 6574 SelectObject(win->src.hdcMem, oldbmp); 6575 #endif 6576 } 6577 6578 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) { 6579 #ifdef RGFW_EGL 6580 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); 6581 #elif defined(RGFW_OPENGL) 6582 SwapBuffers(win->src.hdc); 6583 #endif 6584 6585 #if defined(RGFW_WINDOWS) && defined(RGFW_DIRECTX) 6586 win->src.swapchain->lpVtbl->Present(win->src.swapchain, 0, 0); 6587 #endif 6588 } 6589 } 6590 6591 char* createUTF8FromWideStringWin32(const WCHAR* source) { 6592 char* target; 6593 i32 size; 6594 6595 size = WideCharToMultiByte(CP_UTF8, 0, source, -1, NULL, 0, NULL, NULL); 6596 if (!size) { 6597 return NULL; 6598 } 6599 6600 target = (char*) RGFW_CALLOC(size, 1); 6601 6602 if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, size, NULL, NULL)) { 6603 RGFW_FREE(target); 6604 return NULL; 6605 } 6606 6607 return target; 6608 } 6609 6610 static inline LARGE_INTEGER RGFW_win32_initTimer(void) { 6611 static LARGE_INTEGER frequency = {{0, 0}}; 6612 if (frequency.QuadPart == 0) { 6613 timeBeginPeriod(1); 6614 QueryPerformanceFrequency(&frequency); 6615 } 6616 6617 return frequency; 6618 } 6619 6620 u64 RGFW_getTimeNS(void) { 6621 LARGE_INTEGER frequency = RGFW_win32_initTimer(); 6622 6623 LARGE_INTEGER counter; 6624 QueryPerformanceCounter(&counter); 6625 6626 return (u64) ((counter.QuadPart * 1e9) / frequency.QuadPart); 6627 } 6628 6629 u64 RGFW_getTime(void) { 6630 LARGE_INTEGER frequency = RGFW_win32_initTimer(); 6631 6632 LARGE_INTEGER counter; 6633 QueryPerformanceCounter(&counter); 6634 return (u64) (counter.QuadPart / (double) frequency.QuadPart); 6635 } 6636 6637 void RGFW_sleep(u64 ms) { 6638 Sleep(ms); 6639 } 6640 6641 #ifndef RGFW_NO_THREADS 6642 RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { return CreateThread(NULL, 0, ptr, args, 0, NULL); } 6643 void RGFW_cancelThread(RGFW_thread thread) { CloseHandle((HANDLE) thread); } 6644 void RGFW_joinThread(RGFW_thread thread) { WaitForSingleObject((HANDLE) thread, INFINITE); } 6645 void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { SetThreadPriority((HANDLE) thread, priority); } 6646 #endif 6647 #endif /* RGFW_WINDOWS */ 6648 6649 /* 6650 End of Windows defines 6651 */ 6652 6653 6654 6655 /* 6656 6657 Start of MacOS defines 6658 6659 6660 */ 6661 6662 #if defined(RGFW_MACOS) 6663 /* 6664 based on silicon.h 6665 start of cocoa wrapper 6666 */ 6667 6668 #include <CoreVideo/CVDisplayLink.h> 6669 #include <ApplicationServices/ApplicationServices.h> 6670 #include <objc/runtime.h> 6671 #include <objc/message.h> 6672 #include <mach/mach_time.h> 6673 6674 typedef CGRect NSRect; 6675 typedef CGPoint NSPoint; 6676 typedef CGSize NSSize; 6677 6678 typedef void NSBitmapImageRep; 6679 typedef void NSCursor; 6680 typedef void NSDraggingInfo; 6681 typedef void NSWindow; 6682 typedef void NSApplication; 6683 typedef void NSScreen; 6684 typedef void NSEvent; 6685 typedef void NSString; 6686 typedef void NSOpenGLContext; 6687 typedef void NSPasteboard; 6688 typedef void NSColor; 6689 typedef void NSArray; 6690 typedef void NSImageRep; 6691 typedef void NSImage; 6692 typedef void NSOpenGLView; 6693 6694 6695 typedef const char* NSPasteboardType; 6696 typedef unsigned long NSUInteger; 6697 typedef long NSInteger; 6698 typedef NSInteger NSModalResponse; 6699 6700 #ifdef __arm64__ 6701 /* ARM just uses objc_msgSend */ 6702 #define abi_objc_msgSend_stret objc_msgSend 6703 #define abi_objc_msgSend_fpret objc_msgSend 6704 #else /* __i386__ */ 6705 /* x86 just uses abi_objc_msgSend_fpret and (NSColor *)objc_msgSend_id respectively */ 6706 #define abi_objc_msgSend_stret objc_msgSend_stret 6707 #define abi_objc_msgSend_fpret objc_msgSend_fpret 6708 #endif 6709 6710 #define NSAlloc(nsclass) objc_msgSend_id((id)nsclass, sel_registerName("alloc")) 6711 #define objc_msgSend_bool ((BOOL (*)(id, SEL))objc_msgSend) 6712 #define objc_msgSend_void ((void (*)(id, SEL))objc_msgSend) 6713 #define objc_msgSend_void_id ((void (*)(id, SEL, id))objc_msgSend) 6714 #define objc_msgSend_uint ((NSUInteger (*)(id, SEL))objc_msgSend) 6715 #define objc_msgSend_void_bool ((void (*)(id, SEL, BOOL))objc_msgSend) 6716 #define objc_msgSend_bool_void ((BOOL (*)(id, SEL))objc_msgSend) 6717 #define objc_msgSend_void_SEL ((void (*)(id, SEL, SEL))objc_msgSend) 6718 #define objc_msgSend_id ((id (*)(id, SEL))objc_msgSend) 6719 #define objc_msgSend_id_id ((id (*)(id, SEL, id))objc_msgSend) 6720 #define objc_msgSend_id_bool ((BOOL (*)(id, SEL, id))objc_msgSend) 6721 #define objc_msgSend_int ((id (*)(id, SEL, int))objc_msgSend) 6722 #define objc_msgSend_arr ((id (*)(id, SEL, int))objc_msgSend) 6723 #define objc_msgSend_ptr ((id (*)(id, SEL, void*))objc_msgSend) 6724 #define objc_msgSend_class ((id (*)(Class, SEL))objc_msgSend) 6725 #define objc_msgSend_class_char ((id (*)(Class, SEL, char*))objc_msgSend) 6726 6727 NSApplication* NSApp = NULL; 6728 6729 void NSRelease(id obj) { 6730 objc_msgSend_void(obj, sel_registerName("release")); 6731 } 6732 6733 #define release NSRelease 6734 6735 NSString* NSString_stringWithUTF8String(const char* str) { 6736 return ((id(*)(id, SEL, const char*))objc_msgSend) 6737 ((id)objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), str); 6738 } 6739 6740 const char* NSString_to_char(NSString* str) { 6741 return ((const char* (*)(id, SEL)) objc_msgSend) (str, sel_registerName("UTF8String")); 6742 } 6743 6744 void si_impl_func_to_SEL_with_name(const char* class_name, const char* register_name, void* function) { 6745 Class selected_class; 6746 6747 if (strcmp(class_name, "NSView") == 0) { 6748 selected_class = objc_getClass("ViewClass"); 6749 } else if (strcmp(class_name, "NSWindow") == 0) { 6750 selected_class = objc_getClass("WindowClass"); 6751 } else { 6752 selected_class = objc_getClass(class_name); 6753 } 6754 6755 class_addMethod(selected_class, sel_registerName(register_name), (IMP) function, 0); 6756 } 6757 6758 /* Header for the array. */ 6759 typedef struct siArrayHeader { 6760 size_t count; 6761 /* TODO(EimaMei): Add a `type_width` later on. */ 6762 } siArrayHeader; 6763 6764 /* Gets the header of the siArray. */ 6765 #define SI_ARRAY_HEADER(s) ((siArrayHeader*)s - 1) 6766 6767 void* si_array_init_reserve(size_t sizeof_element, size_t count) { 6768 siArrayHeader* ptr = malloc(sizeof(siArrayHeader) + (sizeof_element * count)); 6769 void* array = ptr + sizeof(siArrayHeader); 6770 6771 siArrayHeader* header = SI_ARRAY_HEADER(array); 6772 header->count = count; 6773 6774 return array; 6775 } 6776 6777 #define si_array_len(array) (SI_ARRAY_HEADER(array)->count) 6778 #define si_func_to_SEL(class_name, function) si_impl_func_to_SEL_with_name(class_name, #function":", function) 6779 /* Creates an Objective-C method (SEL) from a regular C function with the option to set the register name.*/ 6780 #define si_func_to_SEL_with_name(class_name, register_name, function) si_impl_func_to_SEL_with_name(class_name, register_name":", function) 6781 6782 unsigned char* NSBitmapImageRep_bitmapData(NSBitmapImageRep* imageRep) { 6783 return ((unsigned char* (*)(id, SEL))objc_msgSend) 6784 (imageRep, sel_registerName("bitmapData")); 6785 } 6786 6787 #define NS_ENUM(type, name) type name; enum 6788 6789 typedef NS_ENUM(NSUInteger, NSBitmapFormat) { 6790 NSBitmapFormatAlphaFirst = 1 << 0, // 0 means is alpha last (RGBA, CMYKA, etc.) 6791 NSBitmapFormatAlphaNonpremultiplied = 1 << 1, // 0 means is premultiplied 6792 NSBitmapFormatFloatingPointSamples = 1 << 2, // 0 is integer 6793 6794 NSBitmapFormatSixteenBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 8), 6795 NSBitmapFormatThirtyTwoBitLittleEndian API_AVAILABLE(macos(10.10)) = (1 << 9), 6796 NSBitmapFormatSixteenBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 10), 6797 NSBitmapFormatThirtyTwoBitBigEndian API_AVAILABLE(macos(10.10)) = (1 << 11) 6798 }; 6799 6800 NSBitmapImageRep* NSBitmapImageRep_initWithBitmapData(unsigned char** planes, NSInteger width, NSInteger height, NSInteger bps, NSInteger spp, bool alpha, bool isPlanar, const char* colorSpaceName, NSBitmapFormat bitmapFormat, NSInteger rowBytes, NSInteger pixelBits) { 6801 void* func = sel_registerName("initWithBitmapDataPlanes:pixelsWide:pixelsHigh:bitsPerSample:samplesPerPixel:hasAlpha:isPlanar:colorSpaceName:bitmapFormat:bytesPerRow:bitsPerPixel:"); 6802 6803 return (NSBitmapImageRep*) ((id(*)(id, SEL, unsigned char**, NSInteger, NSInteger, NSInteger, NSInteger, bool, bool, const char*, NSBitmapFormat, NSInteger, NSInteger))objc_msgSend) 6804 (NSAlloc((id)objc_getClass("NSBitmapImageRep")), func, planes, width, height, bps, spp, alpha, isPlanar, NSString_stringWithUTF8String(colorSpaceName), bitmapFormat, rowBytes, pixelBits); 6805 } 6806 6807 NSColor* NSColor_colorWithSRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { 6808 void* nsclass = objc_getClass("NSColor"); 6809 void* func = sel_registerName("colorWithSRGBRed:green:blue:alpha:"); 6810 return ((id(*)(id, SEL, CGFloat, CGFloat, CGFloat, CGFloat))objc_msgSend) 6811 (nsclass, func, red, green, blue, alpha); 6812 } 6813 6814 NSCursor* NSCursor_initWithImage(NSImage* newImage, NSPoint aPoint) { 6815 void* func = sel_registerName("initWithImage:hotSpot:"); 6816 void* nsclass = objc_getClass("NSCursor"); 6817 6818 return (NSCursor*) ((id(*)(id, SEL, id, NSPoint))objc_msgSend) 6819 (NSAlloc(nsclass), func, newImage, aPoint); 6820 } 6821 6822 void NSImage_addRepresentation(NSImage* image, NSImageRep* imageRep) { 6823 void* func = sel_registerName("addRepresentation:"); 6824 objc_msgSend_void_id(image, func, imageRep); 6825 } 6826 6827 NSImage* NSImage_initWithSize(NSSize size) { 6828 void* func = sel_registerName("initWithSize:"); 6829 return ((id(*)(id, SEL, NSSize))objc_msgSend) 6830 (NSAlloc((id)objc_getClass("NSImage")), func, size); 6831 } 6832 #define NS_OPENGL_ENUM_DEPRECATED(minVers, maxVers) API_AVAILABLE(macos(minVers)) 6833 typedef NS_ENUM(NSInteger, NSOpenGLContextParameter) { 6834 NSOpenGLContextParameterSwapInterval NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 222, /* 1 param. 0 -> Don't sync, 1 -> Sync to vertical retrace */ 6835 NSOpenGLContextParametectxaceOrder NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 235, /* 1 param. 1 -> Above Window (default), -1 -> Below Window */ 6836 NSOpenGLContextParametectxaceOpacity NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 236, /* 1 param. 1-> Surface is opaque (default), 0 -> non-opaque */ 6837 NSOpenGLContextParametectxaceBackingSize NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 304, /* 2 params. Width/height of surface backing size */ 6838 NSOpenGLContextParameterReclaimResources NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 308, /* 0 params. */ 6839 NSOpenGLContextParameterCurrentRendererID NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 309, /* 1 param. Retrieves the current renderer ID */ 6840 NSOpenGLContextParameterGPUVertexProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 310, /* 1 param. Currently processing vertices with GPU (get) */ 6841 NSOpenGLContextParameterGPUFragmentProcessing NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 311, /* 1 param. Currently processing fragments with GPU (get) */ 6842 NSOpenGLContextParameterHasDrawable NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 314, /* 1 param. Boolean returned if drawable is attached */ 6843 NSOpenGLContextParameterMPSwapsInFlight NS_OPENGL_ENUM_DEPRECATED(10.0, 10.14) = 315, /* 1 param. Max number of swaps queued by the MP GL engine */ 6844 6845 NSOpenGLContextParameterSwapRectangle API_DEPRECATED("", macos(10.0, 10.14)) = 200, /* 4 params. Set or get the swap rectangle {x, y, w, h} */ 6846 NSOpenGLContextParameterSwapRectangleEnable API_DEPRECATED("", macos(10.0, 10.14)) = 201, /* Enable or disable the swap rectangle */ 6847 NSOpenGLContextParameterRasterizationEnable API_DEPRECATED("", macos(10.0, 10.14)) = 221, /* Enable or disable all rasterization */ 6848 NSOpenGLContextParameterStateValidation API_DEPRECATED("", macos(10.0, 10.14)) = 301, /* Validate state for multi-screen functionality */ 6849 NSOpenGLContextParametectxaceSurfaceVolatile API_DEPRECATED("", macos(10.0, 10.14)) = 306, /* 1 param. Surface volatile state */ 6850 }; 6851 6852 6853 void NSOpenGLContext_setValues(NSOpenGLContext* context, const int* vals, NSOpenGLContextParameter param) { 6854 void* func = sel_registerName("setValues:forParameter:"); 6855 ((void (*)(id, SEL, const int*, NSOpenGLContextParameter))objc_msgSend) 6856 (context, func, vals, param); 6857 } 6858 6859 void* NSOpenGLPixelFormat_initWithAttributes(const uint32_t* attribs) { 6860 void* func = sel_registerName("initWithAttributes:"); 6861 return (void*) ((id(*)(id, SEL, const uint32_t*))objc_msgSend) 6862 (NSAlloc((id)objc_getClass("NSOpenGLPixelFormat")), func, attribs); 6863 } 6864 6865 NSOpenGLView* NSOpenGLView_initWithFrame(NSRect frameRect, uint32_t* format) { 6866 void* func = sel_registerName("initWithFrame:pixelFormat:"); 6867 return (NSOpenGLView*) ((id(*)(id, SEL, NSRect, uint32_t*))objc_msgSend) 6868 (NSAlloc((id)objc_getClass("NSOpenGLView")), func, frameRect, format); 6869 } 6870 6871 void NSCursor_performSelector(NSCursor* cursor, void* selector) { 6872 void* func = sel_registerName("performSelector:"); 6873 objc_msgSend_void_SEL(cursor, func, selector); 6874 } 6875 6876 NSPasteboard* NSPasteboard_generalPasteboard(void) { 6877 return (NSPasteboard*) objc_msgSend_id((id)objc_getClass("NSPasteboard"), sel_registerName("generalPasteboard")); 6878 } 6879 6880 NSString** cstrToNSStringArray(char** strs, size_t len) { 6881 static NSString* nstrs[6]; 6882 size_t i; 6883 for (i = 0; i < len; i++) 6884 nstrs[i] = NSString_stringWithUTF8String(strs[i]); 6885 6886 return nstrs; 6887 } 6888 6889 const char* NSPasteboard_stringForType(NSPasteboard* pasteboard, NSPasteboardType dataType) { 6890 void* func = sel_registerName("stringForType:"); 6891 return (const char*) NSString_to_char(((id(*)(id, SEL, const char*))objc_msgSend)(pasteboard, func, NSString_stringWithUTF8String(dataType))); 6892 } 6893 6894 NSArray* c_array_to_NSArray(void* array, size_t len) { 6895 SEL func = sel_registerName("initWithObjects:count:"); 6896 void* nsclass = objc_getClass("NSArray"); 6897 return ((id (*)(id, SEL, void*, NSUInteger))objc_msgSend) 6898 (NSAlloc(nsclass), func, array, len); 6899 } 6900 6901 void NSregisterForDraggedTypes(void* view, NSPasteboardType* newTypes, size_t len) { 6902 NSString** ntypes = cstrToNSStringArray((char**)newTypes, len); 6903 6904 NSArray* array = c_array_to_NSArray(ntypes, len); 6905 objc_msgSend_void_id(view, sel_registerName("registerForDraggedTypes:"), array); 6906 NSRelease(array); 6907 } 6908 6909 NSInteger NSPasteBoard_declareTypes(NSPasteboard* pasteboard, NSPasteboardType* newTypes, size_t len, void* owner) { 6910 NSString** ntypes = cstrToNSStringArray((char**)newTypes, len); 6911 6912 void* func = sel_registerName("declareTypes:owner:"); 6913 6914 NSArray* array = c_array_to_NSArray(ntypes, len); 6915 6916 NSInteger output = ((NSInteger(*)(id, SEL, id, void*))objc_msgSend) 6917 (pasteboard, func, array, owner); 6918 NSRelease(array); 6919 6920 return output; 6921 } 6922 6923 bool NSPasteBoard_setString(NSPasteboard* pasteboard, const char* stringToWrite, NSPasteboardType dataType) { 6924 void* func = sel_registerName("setString:forType:"); 6925 return ((bool (*)(id, SEL, id, NSPasteboardType))objc_msgSend) 6926 (pasteboard, func, NSString_stringWithUTF8String(stringToWrite), NSString_stringWithUTF8String(dataType)); 6927 } 6928 6929 void NSRetain(id obj) { objc_msgSend_void(obj, sel_registerName("retain")); } 6930 6931 typedef enum NSApplicationActivationPolicy { 6932 NSApplicationActivationPolicyRegular, 6933 NSApplicationActivationPolicyAccessory, 6934 NSApplicationActivationPolicyProhibited 6935 } NSApplicationActivationPolicy; 6936 6937 typedef NS_ENUM(u32, NSBackingStoreType) { 6938 NSBackingStoreRetained = 0, 6939 NSBackingStoreNonretained = 1, 6940 NSBackingStoreBuffered = 2 6941 }; 6942 6943 typedef NS_ENUM(u32, NSWindowStyleMask) { 6944 NSWindowStyleMaskBorderless = 0, 6945 NSWindowStyleMaskTitled = 1 << 0, 6946 NSWindowStyleMaskClosable = 1 << 1, 6947 NSWindowStyleMaskMiniaturizable = 1 << 2, 6948 NSWindowStyleMaskResizable = 1 << 3, 6949 NSWindowStyleMaskTexturedBackground = 1 << 8, /* deprecated */ 6950 NSWindowStyleMaskUnifiedTitleAndToolbar = 1 << 12, 6951 NSWindowStyleMaskFullScreen = 1 << 14, 6952 NSWindowStyleMaskFullSizeContentView = 1 << 15, 6953 NSWindowStyleMaskUtilityWindow = 1 << 4, 6954 NSWindowStyleMaskDocModalWindow = 1 << 6, 6955 NSWindowStyleMaskNonactivatingPanel = 1 << 7, 6956 NSWindowStyleMaskHUDWindow = 1 << 13 6957 }; 6958 6959 NSPasteboardType const NSPasteboardTypeString = "public.utf8-plain-text"; // Replaces NSStringPboardType 6960 6961 6962 typedef NS_ENUM(i32, NSDragOperation) { 6963 NSDragOperationNone = 0, 6964 NSDragOperationCopy = 1, 6965 NSDragOperationLink = 2, 6966 NSDragOperationGeneric = 4, 6967 NSDragOperationPrivate = 8, 6968 NSDragOperationMove = 16, 6969 NSDragOperationDelete = 32, 6970 NSDragOperationEvery = ULONG_MAX, 6971 6972 //NSDragOperationAll_Obsolete API_DEPRECATED("", macos(10.0,10.10)) = 15, // Use NSDragOperationEvery 6973 //NSDragOperationAll API_DEPRECATED("", macos(10.0,10.10)) = NSDragOperationAll_Obsolete, // Use NSDragOperationEvery 6974 }; 6975 6976 void* NSArray_objectAtIndex(NSArray* array, NSUInteger index) { 6977 void* func = sel_registerName("objectAtIndex:"); 6978 return ((id(*)(id, SEL, NSUInteger))objc_msgSend)(array, func, index); 6979 } 6980 6981 const char** NSPasteboard_readObjectsForClasses(NSPasteboard* pasteboard, Class* classArray, size_t len, void* options) { 6982 void* func = sel_registerName("readObjectsForClasses:options:"); 6983 6984 NSArray* array = c_array_to_NSArray(classArray, len); 6985 6986 NSArray* output = (NSArray*) ((id(*)(id, SEL, id, void*))objc_msgSend) 6987 (pasteboard, func, array, options); 6988 6989 NSRelease(array); 6990 NSUInteger count = ((NSUInteger(*)(id, SEL))objc_msgSend)(output, sel_registerName("count")); 6991 6992 const char** res = si_array_init_reserve(sizeof(const char*), count); 6993 6994 void* path_func = sel_registerName("path"); 6995 6996 for (NSUInteger i = 0; i < count; i++) { 6997 void* url = NSArray_objectAtIndex(output, i); 6998 NSString* url_str = ((id(*)(id, SEL))objc_msgSend)(url, path_func); 6999 res[i] = NSString_to_char(url_str); 7000 } 7001 7002 return res; 7003 } 7004 7005 void* NSWindow_contentView(NSWindow* window) { 7006 void* func = sel_registerName("contentView"); 7007 return objc_msgSend_id(window, func); 7008 } 7009 7010 /* 7011 End of cocoa wrapper 7012 */ 7013 7014 char* RGFW_mouseIconSrc[] = {"arrowCursor", "arrowCursor", "IBeamCursor", "crosshairCursor", "pointingHandCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "_windowResizeNorthWestSouthEastCursor", "_windowResizeNorthEastSouthWestCursor", "closedHandCursor", "operationNotAllowedCursor"}; 7015 7016 void* RGFWnsglFramework = NULL; 7017 7018 #ifdef RGFW_OPENGL 7019 void* RGFW_getProcAddress(const char* procname) { 7020 if (RGFWnsglFramework == NULL) 7021 RGFWnsglFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); 7022 7023 CFStringRef symbolName = CFStringCreateWithCString(kCFAllocatorDefault, procname, kCFStringEncodingASCII); 7024 7025 void* symbol = CFBundleGetFunctionPointerForName(RGFWnsglFramework, symbolName); 7026 7027 CFRelease(symbolName); 7028 7029 return symbol; 7030 } 7031 #endif 7032 7033 CVReturn displayCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) { 7034 RGFW_UNUSED(displayLink) RGFW_UNUSED(inNow) RGFW_UNUSED(inOutputTime) RGFW_UNUSED(flagsIn) RGFW_UNUSED(flagsOut) RGFW_UNUSED(displayLinkContext) 7035 return kCVReturnSuccess; 7036 } 7037 7038 id NSWindow_delegate(RGFW_window* win) { 7039 return (id) objc_msgSend_id(win->src.window, sel_registerName("delegate")); 7040 } 7041 7042 u32 RGFW_OnClose(void* self) { 7043 RGFW_window* win = NULL; 7044 object_getInstanceVariable(self, "RGFW_window", (void*)&win); 7045 if (win == NULL) 7046 return true; 7047 7048 win->event.type = RGFW_quit; 7049 RGFW_windowQuitCallback(win); 7050 7051 return true; 7052 } 7053 7054 /* NOTE(EimaMei): Fixes the constant clicking when the app is running under a terminal. */ 7055 bool acceptsFirstResponder(void) { return true; } 7056 bool performKeyEquivalent(NSEvent* event) { RGFW_UNUSED(event); return true; } 7057 7058 NSDragOperation draggingEntered(id self, SEL sel, id sender) { 7059 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); 7060 7061 return NSDragOperationCopy; 7062 } 7063 NSDragOperation draggingUpdated(id self, SEL sel, id sender) { 7064 RGFW_UNUSED(sel); 7065 7066 RGFW_window* win = NULL; 7067 object_getInstanceVariable(self, "RGFW_window", (void*)&win); 7068 if (win == NULL) 7069 return 0; 7070 7071 if (!(win->_winArgs & RGFW_ALLOW_DND)) { 7072 return 0; 7073 } 7074 7075 win->event.type = RGFW_dnd_init; 7076 win->src.dndPassed = 0; 7077 7078 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); 7079 7080 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); 7081 RGFW_dndInitCallback(win, win->event.point); 7082 7083 return NSDragOperationCopy; 7084 } 7085 bool prepareForDragOperation(id self) { 7086 RGFW_window* win = NULL; 7087 object_getInstanceVariable(self, "RGFW_window", (void*)&win); 7088 if (win == NULL) 7089 return true; 7090 7091 if (!(win->_winArgs & RGFW_ALLOW_DND)) { 7092 return false; 7093 } 7094 7095 return true; 7096 } 7097 7098 void RGFW__osxDraggingEnded(id self, SEL sel, id sender) { RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); return; } 7099 7100 /* NOTE(EimaMei): Usually, you never need 'id self, SEL cmd' for C -> Obj-C methods. This isn't the case. */ 7101 bool performDragOperation(id self, SEL sel, id sender) { 7102 RGFW_UNUSED(sender); RGFW_UNUSED(self); RGFW_UNUSED(sel); 7103 7104 RGFW_window* win = NULL; 7105 object_getInstanceVariable(self, "RGFW_window", (void*)&win); 7106 7107 if (win == NULL) 7108 return false; 7109 7110 // NSPasteboard* pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); 7111 7112 ///////////////////////////// 7113 id pasteBoard = objc_msgSend_id(sender, sel_registerName("draggingPasteboard")); 7114 7115 // Get the types of data available on the pasteboard 7116 id types = objc_msgSend_id(pasteBoard, sel_registerName("types")); 7117 7118 // Get the string type for file URLs 7119 id fileURLsType = objc_msgSend_class_char(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "NSFilenamesPboardType"); 7120 7121 // Check if the pasteboard contains file URLs 7122 if (objc_msgSend_id_bool(types, sel_registerName("containsObject:"), fileURLsType) == 0) { 7123 #ifdef RGFW_DEBUG 7124 printf("No files found on the pasteboard.\n"); 7125 #endif 7126 7127 return 0; 7128 } 7129 7130 id fileURLs = objc_msgSend_id_id(pasteBoard, sel_registerName("propertyListForType:"), fileURLsType); 7131 int count = ((int (*)(id, SEL))objc_msgSend)(fileURLs, sel_registerName("count")); 7132 7133 if (count == 0) 7134 return 0; 7135 7136 for (int i = 0; i < count; i++) { 7137 id fileURL = objc_msgSend_arr(fileURLs, sel_registerName("objectAtIndex:"), i); 7138 const char *filePath = ((const char* (*)(id, SEL))objc_msgSend)(fileURL, sel_registerName("UTF8String")); 7139 strncpy(win->event.droppedFiles[i], filePath, RGFW_MAX_PATH); 7140 win->event.droppedFiles[i][RGFW_MAX_PATH - 1] = '\0'; 7141 } 7142 win->event.droppedFilesCount = count; 7143 7144 win->event.type = RGFW_dnd; 7145 win->src.dndPassed = 0; 7146 7147 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(sender, sel_registerName("draggingLocation")); 7148 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); 7149 7150 RGFW_dndCallback(win, win->event.droppedFiles, win->event.droppedFilesCount); 7151 7152 return false; 7153 } 7154 7155 static void NSMoveToResourceDir(void) { 7156 /* sourced from glfw */ 7157 char resourcesPath[255]; 7158 7159 CFBundleRef bundle = CFBundleGetMainBundle(); 7160 if (!bundle) 7161 return; 7162 7163 CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); 7164 CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); 7165 7166 if ( 7167 CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo || 7168 CFURLGetFileSystemRepresentation(resourcesURL, true, (u8*) resourcesPath, 255) == 0 7169 ) { 7170 CFRelease(last); 7171 CFRelease(resourcesURL); 7172 return; 7173 } 7174 7175 CFRelease(last); 7176 CFRelease(resourcesURL); 7177 7178 chdir(resourcesPath); 7179 } 7180 7181 7182 NSSize RGFW__osxWindowResize(void* self, SEL sel, NSSize frameSize) { 7183 RGFW_UNUSED(sel); 7184 7185 RGFW_window* win = NULL; 7186 object_getInstanceVariable(self, "RGFW_window", (void*)&win); 7187 if (win == NULL) 7188 return frameSize; 7189 7190 win->r.w = frameSize.width; 7191 win->r.h = frameSize.height; 7192 win->event.type = RGFW_windowResized; 7193 RGFW_windowResizeCallback(win, win->r); 7194 return frameSize; 7195 } 7196 7197 void RGFW__osxWindowMove(void* self, SEL sel) { 7198 RGFW_UNUSED(sel); 7199 7200 RGFW_window* win = NULL; 7201 object_getInstanceVariable(self, "RGFW_window", (void*)&win); 7202 if (win == NULL) 7203 return; 7204 7205 NSRect frame = ((NSRect(*)(id, SEL))abi_objc_msgSend_stret)(win->src.window, sel_registerName("frame")); 7206 win->r.x = (i32) frame.origin.x; 7207 win->r.y = (i32) frame.origin.y; 7208 7209 win->event.type = RGFW_windowMoved; 7210 RGFW_windowMoveCallback(win, win->r); 7211 } 7212 7213 void RGFW__osxUpdateLayer(void* self, SEL sel) { 7214 RGFW_UNUSED(sel); 7215 7216 RGFW_window* win = NULL; 7217 object_getInstanceVariable(self, "RGFW_window", (void*)&win); 7218 if (win == NULL) 7219 return; 7220 7221 win->event.type = RGFW_windowRefresh; 7222 RGFW_windowRefreshCallback(win); 7223 } 7224 7225 RGFWDEF void RGFW_init_buffer(RGFW_window* win); 7226 void RGFW_init_buffer(RGFW_window* win) { 7227 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 7228 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) 7229 RGFW_bufferSize = RGFW_getScreenSize(); 7230 7231 win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); 7232 7233 #ifdef RGFW_OSMESA 7234 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); 7235 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); 7236 #endif 7237 #else 7238 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ 7239 #endif 7240 } 7241 7242 7243 void RGFW_window_cocoaSetLayer(RGFW_window* win, void* layer) { 7244 objc_msgSend_void_id(win->src.view, sel_registerName("setLayer"), layer); 7245 } 7246 7247 void* RGFW_cocoaGetLayer(void) { 7248 return objc_msgSend_class(objc_getClass("CAMetalLayer"), sel_registerName("layer")); 7249 } 7250 7251 7252 NSPasteboardType const NSPasteboardTypeURL = "public.url"; 7253 NSPasteboardType const NSPasteboardTypeFileURL = "public.file-url"; 7254 7255 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { 7256 static u8 RGFW_loaded = 0; 7257 7258 /* NOTE(EimaMei): Why does Apple hate good code? Like wtf, who thought of methods being a great idea??? 7259 Imagine a universe, where MacOS had a proper system API (we would probably have like 20% better performance). 7260 */ 7261 si_func_to_SEL_with_name("NSObject", "windowShouldClose", RGFW_OnClose); 7262 7263 /* NOTE(EimaMei): Fixes the 'Boop' sfx from constantly playing each time you click a key. Only a problem when running in the terminal. */ 7264 si_func_to_SEL("NSWindow", acceptsFirstResponder); 7265 si_func_to_SEL("NSWindow", performKeyEquivalent); 7266 7267 // RR Create an autorelease pool 7268 id pool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); 7269 pool = objc_msgSend_id(pool, sel_registerName("init")); 7270 7271 if (NSApp == NULL) { 7272 NSApp = objc_msgSend_id((id)objc_getClass("NSApplication"), sel_registerName("sharedApplication")); 7273 7274 ((void (*)(id, SEL, NSUInteger))objc_msgSend) 7275 (NSApp, sel_registerName("setActivationPolicy:"), NSApplicationActivationPolicyRegular); 7276 } 7277 7278 RGFW_window* win = RGFW_window_basic_init(rect, args); 7279 7280 RGFW_window_setMouseDefault(win); 7281 7282 NSRect windowRect; 7283 windowRect.origin.x = win->r.x; 7284 windowRect.origin.y = win->r.y; 7285 windowRect.size.width = win->r.w; 7286 windowRect.size.height = win->r.h; 7287 7288 NSBackingStoreType macArgs = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSBackingStoreBuffered | NSWindowStyleMaskTitled; 7289 7290 if (!(args & RGFW_NO_RESIZE)) 7291 macArgs |= NSWindowStyleMaskResizable; 7292 if (!(args & RGFW_NO_BORDER)) 7293 macArgs |= NSWindowStyleMaskTitled; 7294 else 7295 macArgs = NSWindowStyleMaskBorderless; 7296 { 7297 void* nsclass = objc_getClass("NSWindow"); 7298 void* func = sel_registerName("initWithContentRect:styleMask:backing:defer:"); 7299 7300 win->src.window = ((id(*)(id, SEL, NSRect, NSWindowStyleMask, NSBackingStoreType, bool))objc_msgSend) 7301 (NSAlloc(nsclass), func, windowRect, macArgs, macArgs, false); 7302 } 7303 7304 NSString* str = NSString_stringWithUTF8String(name); 7305 objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str); 7306 7307 #ifdef RGFW_EGL 7308 if ((args & RGFW_NO_INIT_API) == 0) 7309 RGFW_createOpenGLContext(win); 7310 #endif 7311 7312 #ifdef RGFW_OPENGL 7313 if ((args & RGFW_NO_INIT_API) == 0) { 7314 void* attrs = RGFW_initFormatAttribs(args & RGFW_OPENGL_SOFTWARE); 7315 void* format = NSOpenGLPixelFormat_initWithAttributes(attrs); 7316 7317 if (format == NULL) { 7318 printf("Failed to load pixel format for OpenGL\n"); 7319 7320 void* attrs = RGFW_initFormatAttribs(1); 7321 format = NSOpenGLPixelFormat_initWithAttributes(attrs); 7322 if (format == NULL) 7323 printf("and loading software rendering OpenGL failed\n"); 7324 else 7325 printf("Switching to software rendering\n"); 7326 } 7327 7328 /* the pixel format can be passed directly to opengl context creation to create a context 7329 this is because the format also includes information about the opengl version (which may be a bad thing) */ 7330 win->src.view = NSOpenGLView_initWithFrame((NSRect){{0, 0}, {win->r.w, win->r.h}}, format); 7331 objc_msgSend_void(win->src.view, sel_registerName("prepareOpenGL")); 7332 win->src.ctx = objc_msgSend_id(win->src.view, sel_registerName("openGLContext")); 7333 } else 7334 #endif 7335 { 7336 NSRect contentRect = (NSRect){{0, 0}, {win->r.w, win->r.h}}; 7337 win->src.view = ((id(*)(id, SEL, NSRect))objc_msgSend) 7338 (NSAlloc((id)objc_getClass("NSView")), sel_registerName("initWithFrame:"), 7339 contentRect); 7340 } 7341 7342 void* contentView = NSWindow_contentView(win->src.window); 7343 objc_msgSend_void_bool(contentView, sel_registerName("setWantsLayer:"), true); 7344 7345 objc_msgSend_void_id(win->src.window, sel_registerName("setContentView:"), win->src.view); 7346 7347 #ifdef RGFW_OPENGL 7348 if ((args & RGFW_NO_INIT_API) == 0) 7349 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); 7350 #endif 7351 if (args & RGFW_TRANSPARENT_WINDOW) { 7352 #ifdef RGFW_OPENGL 7353 if ((args & RGFW_NO_INIT_API) == 0) { 7354 i32 opacity = 0; 7355 #define NSOpenGLCPSurfaceOpacity 236 7356 NSOpenGLContext_setValues(win->src.ctx, &opacity, NSOpenGLCPSurfaceOpacity); 7357 } 7358 #endif 7359 7360 objc_msgSend_void_bool(win->src.window, sel_registerName("setOpaque:"), false); 7361 7362 objc_msgSend_void_id(win->src.window, sel_registerName("setBackgroundColor:"), 7363 NSColor_colorWithSRGB(0, 0, 0, 0)); 7364 } 7365 7366 win->src.display = CGMainDisplayID(); 7367 CVDisplayLinkCreateWithCGDisplay(win->src.display, (CVDisplayLinkRef*)&win->src.displayLink); 7368 CVDisplayLinkSetOutputCallback(win->src.displayLink, displayCallback, win); 7369 CVDisplayLinkStart(win->src.displayLink); 7370 7371 RGFW_init_buffer(win); 7372 7373 #ifndef RGFW_NO_MONITOR 7374 if (args & RGFW_SCALE_TO_MONITOR) 7375 RGFW_window_scaleToMonitor(win); 7376 #endif 7377 7378 if (args & RGFW_CENTER) { 7379 RGFW_area screenR = RGFW_getScreenSize(); 7380 RGFW_window_move(win, RGFW_POINT((screenR.w - win->r.w) / 2, (screenR.h - win->r.h) / 2)); 7381 } 7382 7383 if (args & RGFW_HIDE_MOUSE) 7384 RGFW_window_showMouse(win, 0); 7385 7386 if (args & RGFW_COCOA_MOVE_TO_RESOURCE_DIR) 7387 NSMoveToResourceDir(); 7388 7389 Class delegateClass = objc_allocateClassPair(objc_getClass("NSObject"), "WindowDelegate", 0); 7390 7391 class_addIvar( 7392 delegateClass, "RGFW_window", 7393 sizeof(RGFW_window*), rint(log2(sizeof(RGFW_window*))), 7394 "L" 7395 ); 7396 7397 class_addMethod(delegateClass, sel_registerName("windowWillResize:toSize:"), (IMP) RGFW__osxWindowResize, "{NSSize=ff}@:{NSSize=ff}"); 7398 class_addMethod(delegateClass, sel_registerName("updateLayer:"), (IMP) RGFW__osxUpdateLayer, ""); 7399 class_addMethod(delegateClass, sel_registerName("windowWillMove:"), (IMP) RGFW__osxWindowMove, ""); 7400 class_addMethod(delegateClass, sel_registerName("windowDidMove:"), (IMP) RGFW__osxWindowMove, ""); 7401 class_addMethod(delegateClass, sel_registerName("draggingEntered:"), (IMP)draggingEntered, "l@:@"); 7402 class_addMethod(delegateClass, sel_registerName("draggingUpdated:"), (IMP)draggingUpdated, "l@:@"); 7403 class_addMethod(delegateClass, sel_registerName("draggingExited:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); 7404 class_addMethod(delegateClass, sel_registerName("draggingEnded:"), (IMP)RGFW__osxDraggingEnded, "v@:@"); 7405 class_addMethod(delegateClass, sel_registerName("prepareForDragOperation:"), (IMP)prepareForDragOperation, "B@:@"); 7406 class_addMethod(delegateClass, sel_registerName("performDragOperation:"), (IMP)performDragOperation, "B@:@"); 7407 7408 id delegate = objc_msgSend_id(NSAlloc(delegateClass), sel_registerName("init")); 7409 7410 object_setInstanceVariable(delegate, "RGFW_window", win); 7411 7412 objc_msgSend_void_id(win->src.window, sel_registerName("setDelegate:"), delegate); 7413 7414 if (args & RGFW_ALLOW_DND) { 7415 win->_winArgs |= RGFW_ALLOW_DND; 7416 7417 NSPasteboardType types[] = {NSPasteboardTypeURL, NSPasteboardTypeFileURL, NSPasteboardTypeString}; 7418 NSregisterForDraggedTypes(win->src.window, types, 3); 7419 } 7420 7421 // Show the window 7422 objc_msgSend_void_bool(NSApp, sel_registerName("activateIgnoringOtherApps:"), true); 7423 ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); 7424 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true); 7425 7426 if (!RGFW_loaded) { 7427 objc_msgSend_void(win->src.window, sel_registerName("makeMainWindow")); 7428 7429 RGFW_loaded = 1; 7430 } 7431 7432 objc_msgSend_void(win->src.window, sel_registerName("makeKeyWindow")); 7433 7434 objc_msgSend_void(NSApp, sel_registerName("finishLaunching")); 7435 7436 if (RGFW_root == NULL) 7437 RGFW_root = win; 7438 7439 NSRetain(win->src.window); 7440 NSRetain(NSApp); 7441 7442 return win; 7443 } 7444 7445 void RGFW_window_setBorder(RGFW_window* win, u8 border) { 7446 NSBackingStoreType storeType = NSWindowStyleMaskBorderless; 7447 if (!border) { 7448 storeType = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable; 7449 } 7450 if (!(win->_winArgs & RGFW_NO_RESIZE)) { 7451 storeType |= NSWindowStyleMaskResizable; 7452 } 7453 7454 ((void (*)(id, SEL, NSBackingStoreType))objc_msgSend)(win->src.window, sel_registerName("setStyleMask:"), storeType); 7455 7456 objc_msgSend_void_bool(win->src.window, sel_registerName("setHasShadow:"), border); 7457 } 7458 7459 RGFW_area RGFW_getScreenSize(void) { 7460 static CGDirectDisplayID display = 0; 7461 7462 if (display == 0) 7463 display = CGMainDisplayID(); 7464 7465 return RGFW_AREA(CGDisplayPixelsWide(display), CGDisplayPixelsHigh(display)); 7466 } 7467 7468 RGFW_point RGFW_getGlobalMousePoint(void) { 7469 assert(RGFW_root != NULL); 7470 7471 CGEventRef e = CGEventCreate(NULL); 7472 CGPoint point = CGEventGetLocation(e); 7473 CFRelease(e); 7474 7475 return RGFW_POINT((u32) point.x, (u32) point.y); /*!< the point is loaded during event checks */ 7476 } 7477 7478 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { 7479 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(win->src.window, sel_registerName("mouseLocationOutsideOfEventStream")); 7480 7481 return RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); 7482 } 7483 7484 u32 RGFW_keysPressed[10]; /*10 keys at a time*/ 7485 typedef NS_ENUM(u32, NSEventType) { /* various types of events */ 7486 NSEventTypeLeftMouseDown = 1, 7487 NSEventTypeLeftMouseUp = 2, 7488 NSEventTypeRightMouseDown = 3, 7489 NSEventTypeRightMouseUp = 4, 7490 NSEventTypeMouseMoved = 5, 7491 NSEventTypeLeftMouseDragged = 6, 7492 NSEventTypeRightMouseDragged = 7, 7493 NSEventTypeMouseEntered = 8, 7494 NSEventTypeMouseExited = 9, 7495 NSEventTypeKeyDown = 10, 7496 NSEventTypeKeyUp = 11, 7497 NSEventTypeFlagsChanged = 12, 7498 NSEventTypeAppKitDefined = 13, 7499 NSEventTypeSystemDefined = 14, 7500 NSEventTypeApplicationDefined = 15, 7501 NSEventTypePeriodic = 16, 7502 NSEventTypeCursorUpdate = 17, 7503 NSEventTypeScrollWheel = 22, 7504 NSEventTypeTabletPoint = 23, 7505 NSEventTypeTabletProximity = 24, 7506 NSEventTypeOtherMouseDown = 25, 7507 NSEventTypeOtherMouseUp = 26, 7508 NSEventTypeOtherMouseDragged = 27, 7509 /* The following event types are available on some hardware on 10.5.2 and later */ 7510 NSEventTypeGesture API_AVAILABLE(macos(10.5)) = 29, 7511 NSEventTypeMagnify API_AVAILABLE(macos(10.5)) = 30, 7512 NSEventTypeSwipe API_AVAILABLE(macos(10.5)) = 31, 7513 NSEventTypeRotate API_AVAILABLE(macos(10.5)) = 18, 7514 NSEventTypeBeginGesture API_AVAILABLE(macos(10.5)) = 19, 7515 NSEventTypeEndGesture API_AVAILABLE(macos(10.5)) = 20, 7516 7517 NSEventTypeSmartMagnify API_AVAILABLE(macos(10.8)) = 32, 7518 NSEventTypeQuickLook API_AVAILABLE(macos(10.8)) = 33, 7519 7520 NSEventTypePressure API_AVAILABLE(macos(10.10.3)) = 34, 7521 NSEventTypeDirectTouch API_AVAILABLE(macos(10.10)) = 37, 7522 7523 NSEventTypeChangeMode API_AVAILABLE(macos(10.15)) = 38, 7524 }; 7525 7526 typedef NS_ENUM(unsigned long long, NSEventMask) { /* masks for the types of events */ 7527 NSEventMaskLeftMouseDown = 1ULL << NSEventTypeLeftMouseDown, 7528 NSEventMaskLeftMouseUp = 1ULL << NSEventTypeLeftMouseUp, 7529 NSEventMaskRightMouseDown = 1ULL << NSEventTypeRightMouseDown, 7530 NSEventMaskRightMouseUp = 1ULL << NSEventTypeRightMouseUp, 7531 NSEventMaskMouseMoved = 1ULL << NSEventTypeMouseMoved, 7532 NSEventMaskLeftMouseDragged = 1ULL << NSEventTypeLeftMouseDragged, 7533 NSEventMaskRightMouseDragged = 1ULL << NSEventTypeRightMouseDragged, 7534 NSEventMaskMouseEntered = 1ULL << NSEventTypeMouseEntered, 7535 NSEventMaskMouseExited = 1ULL << NSEventTypeMouseExited, 7536 NSEventMaskKeyDown = 1ULL << NSEventTypeKeyDown, 7537 NSEventMaskKeyUp = 1ULL << NSEventTypeKeyUp, 7538 NSEventMaskFlagsChanged = 1ULL << NSEventTypeFlagsChanged, 7539 NSEventMaskAppKitDefined = 1ULL << NSEventTypeAppKitDefined, 7540 NSEventMaskSystemDefined = 1ULL << NSEventTypeSystemDefined, 7541 NSEventMaskApplicationDefined = 1ULL << NSEventTypeApplicationDefined, 7542 NSEventMaskPeriodic = 1ULL << NSEventTypePeriodic, 7543 NSEventMaskCursorUpdate = 1ULL << NSEventTypeCursorUpdate, 7544 NSEventMaskScrollWheel = 1ULL << NSEventTypeScrollWheel, 7545 NSEventMaskTabletPoint = 1ULL << NSEventTypeTabletPoint, 7546 NSEventMaskTabletProximity = 1ULL << NSEventTypeTabletProximity, 7547 NSEventMaskOtherMouseDown = 1ULL << NSEventTypeOtherMouseDown, 7548 NSEventMaskOtherMouseUp = 1ULL << NSEventTypeOtherMouseUp, 7549 NSEventMaskOtherMouseDragged = 1ULL << NSEventTypeOtherMouseDragged, 7550 /* The following event masks are available on some hardware on 10.5.2 and later */ 7551 NSEventMaskGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeGesture, 7552 NSEventMaskMagnify API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeMagnify, 7553 NSEventMaskSwipe API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeSwipe, 7554 NSEventMaskRotate API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeRotate, 7555 NSEventMaskBeginGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeBeginGesture, 7556 NSEventMaskEndGesture API_AVAILABLE(macos(10.5)) = 1ULL << NSEventTypeEndGesture, 7557 7558 /* Note: You can only use these event masks on 64 bit. In other words, you cannot setup a local, nor global, event monitor for these event types on 32 bit. Also, you cannot search the event queue for them (nextEventMatchingMask:...) on 32 bit. 7559 */ 7560 NSEventMaskSmartMagnify API_AVAILABLE(macos(10.8)) = 1ULL << NSEventTypeSmartMagnify, 7561 NSEventMaskPressure API_AVAILABLE(macos(10.10.3)) = 1ULL << NSEventTypePressure, 7562 NSEventMaskDirectTouch API_AVAILABLE(macos(10.12.2)) = 1ULL << NSEventTypeDirectTouch, 7563 7564 NSEventMaskChangeMode API_AVAILABLE(macos(10.15)) = 1ULL << NSEventTypeChangeMode, 7565 7566 NSEventMaskAny = ULONG_MAX, 7567 7568 }; 7569 7570 typedef enum NSEventModifierFlags { 7571 NSEventModifierFlagCapsLock = 1 << 16, 7572 NSEventModifierFlagShift = 1 << 17, 7573 NSEventModifierFlagControl = 1 << 18, 7574 NSEventModifierFlagOption = 1 << 19, 7575 NSEventModifierFlagCommand = 1 << 20, 7576 NSEventModifierFlagNumericPad = 1 << 21 7577 } NSEventModifierFlags; 7578 7579 void RGFW_stopCheckEvents(void) { 7580 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); 7581 eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); 7582 7583 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventType, NSPoint, NSEventModifierFlags, void*, NSInteger, void**, short, NSInteger, NSInteger))objc_msgSend) 7584 (NSApp, sel_registerName("otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:"), 7585 NSEventTypeApplicationDefined, (NSPoint){0, 0}, 0, 0, 0, NULL, 0, 0, 0); 7586 7587 ((void (*)(id, SEL, id, bool))objc_msgSend) 7588 (NSApp, sel_registerName("postEvent:atStart:"), e, 1); 7589 7590 objc_msgSend_bool_void(eventPool, sel_registerName("drain")); 7591 } 7592 7593 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { 7594 RGFW_UNUSED(win); 7595 7596 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); 7597 eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); 7598 7599 void* date = (void*) ((id(*)(Class, SEL, double))objc_msgSend) 7600 (objc_getClass("NSDate"), sel_registerName("dateWithTimeIntervalSinceNow:"), waitMS); 7601 7602 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend) 7603 (NSApp, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), 7604 ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); 7605 7606 7607 if (e) { 7608 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); 7609 } 7610 7611 objc_msgSend_bool_void(eventPool, sel_registerName("drain")); 7612 } 7613 7614 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { 7615 assert(win != NULL); 7616 7617 if (win->event.type == RGFW_quit) 7618 return NULL; 7619 7620 if ((win->event.type == RGFW_dnd || win->event.type == RGFW_dnd_init) && win->src.dndPassed == 0) { 7621 win->src.dndPassed = 1; 7622 return &win->event; 7623 } 7624 7625 id eventPool = objc_msgSend_class(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")); 7626 eventPool = objc_msgSend_id(eventPool, sel_registerName("init")); 7627 7628 static void* eventFunc = NULL; 7629 if (eventFunc == NULL) 7630 eventFunc = sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"); 7631 7632 if ((win->event.type == RGFW_windowMoved || win->event.type == RGFW_windowResized || win->event.type == RGFW_windowRefresh) && win->event.keyCode != 120) { 7633 win->event.keyCode = 120; 7634 objc_msgSend_bool_void(eventPool, sel_registerName("drain")); 7635 return &win->event; 7636 } 7637 7638 void* date = NULL; 7639 7640 NSEvent* e = (NSEvent*) ((id(*)(id, SEL, NSEventMask, void*, NSString*, bool))objc_msgSend) 7641 (NSApp, eventFunc, ULONG_MAX, date, NSString_stringWithUTF8String("kCFRunLoopDefaultMode"), true); 7642 7643 if (e == NULL) { 7644 objc_msgSend_bool_void(eventPool, sel_registerName("drain")); 7645 return NULL; 7646 } 7647 7648 if (objc_msgSend_id(e, sel_registerName("window")) != win->src.window) { 7649 ((void (*)(id, SEL, id, bool))objc_msgSend) 7650 (NSApp, sel_registerName("postEvent:atStart:"), e, 0); 7651 7652 objc_msgSend_bool_void(eventPool, sel_registerName("drain")); 7653 return NULL; 7654 } 7655 7656 if (win->event.droppedFilesCount) { 7657 u32 i; 7658 for (i = 0; i < win->event.droppedFilesCount; i++) 7659 win->event.droppedFiles[i][0] = '\0'; 7660 } 7661 7662 win->event.droppedFilesCount = 0; 7663 win->event.type = 0; 7664 7665 switch (objc_msgSend_uint(e, sel_registerName("type"))) { 7666 case NSEventTypeMouseEntered: { 7667 win->event.type = RGFW_mouseEnter; 7668 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); 7669 7670 win->event.point = RGFW_POINT((i32) p.x, (i32) (win->r.h - p.y)); 7671 RGFW_mouseNotifyCallBack(win, win->event.point, 1); 7672 break; 7673 } 7674 7675 case NSEventTypeMouseExited: 7676 win->event.type = RGFW_mouseLeave; 7677 RGFW_mouseNotifyCallBack(win, win->event.point, 0); 7678 break; 7679 7680 case NSEventTypeKeyDown: { 7681 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); 7682 win->event.keyCode = RGFW_apiKeyCodeToRGFW(key); 7683 RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current; 7684 7685 win->event.type = RGFW_keyPressed; 7686 char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); 7687 strncpy(win->event.keyName, str, 16); 7688 win->event.repeat = RGFW_isPressed(win, win->event.keyCode); 7689 RGFW_keyboard[win->event.keyCode].current = 1; 7690 7691 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 1); 7692 break; 7693 } 7694 7695 case NSEventTypeKeyUp: { 7696 u32 key = (u16) objc_msgSend_uint(e, sel_registerName("keyCode")); 7697 win->event.keyCode = RGFW_apiKeyCodeToRGFW(key);; 7698 7699 RGFW_keyboard[win->event.keyCode].prev = RGFW_keyboard[win->event.keyCode].current; 7700 7701 win->event.type = RGFW_keyReleased; 7702 char* str = (char*)(const char*) NSString_to_char(objc_msgSend_id(e, sel_registerName("characters"))); 7703 strncpy(win->event.keyName, str, 16); 7704 7705 RGFW_keyboard[win->event.keyCode].current = 0; 7706 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, 0); 7707 break; 7708 } 7709 7710 case NSEventTypeFlagsChanged: { 7711 u32 flags = objc_msgSend_uint(e, sel_registerName("modifierFlags")); 7712 RGFW_updateLockState(win, ((u32)(flags & NSEventModifierFlagCapsLock) % 255), ((flags & NSEventModifierFlagNumericPad) % 255)); 7713 7714 u8 i; 7715 for (i = 0; i < 9; i++) 7716 RGFW_keyboard[i + RGFW_CapsLock].prev = 0; 7717 7718 for (i = 0; i < 5; i++) { 7719 u32 shift = (1 << (i + 16)); 7720 u32 key = i + RGFW_CapsLock; 7721 7722 if ((flags & shift) && !RGFW_wasPressed(win, key)) { 7723 RGFW_keyboard[key].current = 1; 7724 7725 if (key != RGFW_CapsLock) 7726 RGFW_keyboard[key+ 4].current = 1; 7727 7728 win->event.type = RGFW_keyPressed; 7729 win->event.keyCode = key; 7730 break; 7731 } 7732 7733 if (!(flags & shift) && RGFW_wasPressed(win, key)) { 7734 RGFW_keyboard[key].current = 0; 7735 7736 if (key != RGFW_CapsLock) 7737 RGFW_keyboard[key + 4].current = 0; 7738 7739 win->event.type = RGFW_keyReleased; 7740 win->event.keyCode = key; 7741 break; 7742 } 7743 } 7744 7745 RGFW_keyCallback(win, win->event.keyCode, win->event.keyName, win->event.lockState, win->event.type == RGFW_keyPressed); 7746 7747 break; 7748 } 7749 case NSEventTypeLeftMouseDragged: 7750 case NSEventTypeOtherMouseDragged: 7751 case NSEventTypeRightMouseDragged: 7752 case NSEventTypeMouseMoved: 7753 win->event.type = RGFW_mousePosChanged; 7754 NSPoint p = ((NSPoint(*)(id, SEL)) objc_msgSend)(e, sel_registerName("locationInWindow")); 7755 win->event.point = RGFW_POINT((u32) p.x, (u32) (win->r.h - p.y)); 7756 7757 if ((win->_winArgs & RGFW_HOLD_MOUSE)) { 7758 p.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaX")); 7759 p.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); 7760 7761 win->event.point = RGFW_POINT((i32)p.x, (i32)p.y); 7762 } 7763 7764 RGFW_mousePosCallback(win, win->event.point); 7765 break; 7766 7767 case NSEventTypeLeftMouseDown: 7768 win->event.button = RGFW_mouseLeft; 7769 win->event.type = RGFW_mouseButtonPressed; 7770 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 7771 RGFW_mouseButtons[win->event.button].current = 1; 7772 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 7773 break; 7774 7775 case NSEventTypeOtherMouseDown: 7776 win->event.button = RGFW_mouseMiddle; 7777 win->event.type = RGFW_mouseButtonPressed; 7778 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 7779 RGFW_mouseButtons[win->event.button].current = 1; 7780 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 7781 break; 7782 7783 case NSEventTypeRightMouseDown: 7784 win->event.button = RGFW_mouseRight; 7785 win->event.type = RGFW_mouseButtonPressed; 7786 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 7787 RGFW_mouseButtons[win->event.button].current = 1; 7788 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 7789 break; 7790 7791 case NSEventTypeLeftMouseUp: 7792 win->event.button = RGFW_mouseLeft; 7793 win->event.type = RGFW_mouseButtonReleased; 7794 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 7795 RGFW_mouseButtons[win->event.button].current = 0; 7796 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); 7797 break; 7798 7799 case NSEventTypeOtherMouseUp: 7800 win->event.button = RGFW_mouseMiddle; 7801 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 7802 RGFW_mouseButtons[win->event.button].current = 0; 7803 win->event.type = RGFW_mouseButtonReleased; 7804 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); 7805 break; 7806 7807 case NSEventTypeRightMouseUp: 7808 win->event.button = RGFW_mouseRight; 7809 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 7810 RGFW_mouseButtons[win->event.button].current = 0; 7811 win->event.type = RGFW_mouseButtonReleased; 7812 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 0); 7813 break; 7814 7815 case NSEventTypeScrollWheel: { 7816 double deltaY = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName("deltaY")); 7817 7818 if (deltaY > 0) { 7819 win->event.button = RGFW_mouseScrollUp; 7820 } 7821 else if (deltaY < 0) { 7822 win->event.button = RGFW_mouseScrollDown; 7823 } 7824 7825 RGFW_mouseButtons[win->event.button].prev = RGFW_mouseButtons[win->event.button].current; 7826 RGFW_mouseButtons[win->event.button].current = 1; 7827 7828 win->event.scroll = deltaY; 7829 7830 win->event.type = RGFW_mouseButtonPressed; 7831 RGFW_mouseButtonCallback(win, win->event.button, win->event.scroll, 1); 7832 break; 7833 } 7834 7835 default: 7836 break; 7837 } 7838 7839 objc_msgSend_void_id(NSApp, sel_registerName("sendEvent:"), e); 7840 ((void(*)(id, SEL))objc_msgSend)(NSApp, sel_registerName("updateWindows")); 7841 7842 objc_msgSend_bool_void(eventPool, sel_registerName("drain")); 7843 return &win->event; 7844 } 7845 7846 7847 void RGFW_window_move(RGFW_window* win, RGFW_point v) { 7848 assert(win != NULL); 7849 7850 win->r.x = v.x; 7851 win->r.y = v.y; 7852 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) 7853 (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); 7854 } 7855 7856 void RGFW_window_resize(RGFW_window* win, RGFW_area a) { 7857 assert(win != NULL); 7858 7859 win->r.w = a.w; 7860 win->r.h = a.h; 7861 ((void(*)(id, SEL, NSRect, bool, bool))objc_msgSend) 7862 (win->src.window, sel_registerName("setFrame:display:animate:"), (NSRect){{win->r.x, win->r.y}, {win->r.w, win->r.h}}, true, true); 7863 } 7864 7865 void RGFW_window_minimize(RGFW_window* win) { 7866 assert(win != NULL); 7867 7868 objc_msgSend_void_SEL(win->src.window, sel_registerName("performMiniaturize:"), NULL); 7869 } 7870 7871 void RGFW_window_restore(RGFW_window* win) { 7872 assert(win != NULL); 7873 7874 objc_msgSend_void_SEL(win->src.window, sel_registerName("deminiaturize:"), NULL); 7875 } 7876 7877 void RGFW_window_setName(RGFW_window* win, char* name) { 7878 assert(win != NULL); 7879 7880 NSString* str = NSString_stringWithUTF8String(name); 7881 objc_msgSend_void_id(win->src.window, sel_registerName("setTitle:"), str); 7882 } 7883 7884 #ifndef RGFW_NO_PASSTHROUGH 7885 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { 7886 objc_msgSend_void_bool(win->src.window, sel_registerName("setIgnoresMouseEvents:"), passthrough); 7887 } 7888 #endif 7889 7890 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { 7891 if (a.w == 0 && a.h == 0) 7892 return; 7893 7894 ((void (*)(id, SEL, NSSize))objc_msgSend) 7895 (win->src.window, sel_registerName("setMinSize:"), (NSSize){a.w, a.h}); 7896 } 7897 7898 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { 7899 if (a.w == 0 && a.h == 0) 7900 return; 7901 7902 ((void (*)(id, SEL, NSSize))objc_msgSend) 7903 (win->src.window, sel_registerName("setMaxSize:"), (NSSize){a.w, a.h}); 7904 } 7905 7906 void RGFW_window_setIcon(RGFW_window* win, u8* data, RGFW_area area, i32 channels) { 7907 assert(win != NULL); 7908 7909 /* code by EimaMei */ 7910 // Make a bitmap representation, then copy the loaded image into it. 7911 void* representation = NSBitmapImageRep_initWithBitmapData(NULL, area.w, area.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, area.w * channels, 8 * channels); 7912 memcpy(NSBitmapImageRep_bitmapData(representation), data, area.w * area.h * channels); 7913 7914 // Add ze representation. 7915 void* dock_image = NSImage_initWithSize((NSSize){area.w, area.h}); 7916 NSImage_addRepresentation(dock_image, (void*) representation); 7917 7918 // Finally, set the dock image to it. 7919 objc_msgSend_void_id(NSApp, sel_registerName("setApplicationIconImage:"), dock_image); 7920 // Free the garbage. 7921 release(dock_image); 7922 release(representation); 7923 } 7924 7925 NSCursor* NSCursor_arrowStr(char* str) { 7926 void* nclass = objc_getClass("NSCursor"); 7927 void* func = sel_registerName(str); 7928 return (NSCursor*) objc_msgSend_id(nclass, func); 7929 } 7930 7931 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { 7932 assert(win != NULL); 7933 7934 if (image == NULL) { 7935 objc_msgSend_void(NSCursor_arrowStr("arrowCursor"), sel_registerName("set")); 7936 return; 7937 } 7938 7939 /* NOTE(EimaMei): Code by yours truly. */ 7940 // Make a bitmap representation, then copy the loaded image into it. 7941 void* representation = NSBitmapImageRep_initWithBitmapData(NULL, a.w, a.h, 8, channels, (channels == 4), false, "NSCalibratedRGBColorSpace", 1 << 1, a.w * channels, 8 * channels); 7942 memcpy(NSBitmapImageRep_bitmapData(representation), image, a.w * a.h * channels); 7943 7944 // Add ze representation. 7945 void* cursor_image = NSImage_initWithSize((NSSize){a.w, a.h}); 7946 NSImage_addRepresentation(cursor_image, representation); 7947 7948 // Finally, set the cursor image. 7949 void* cursor = NSCursor_initWithImage(cursor_image, (NSPoint){0.0, 0.0}); 7950 7951 objc_msgSend_void(cursor, sel_registerName("set")); 7952 7953 // Free the garbage. 7954 release(cursor_image); 7955 release(representation); 7956 } 7957 7958 void RGFW_window_setMouseDefault(RGFW_window* win) { 7959 RGFW_window_setMouseStandard(win, RGFW_MOUSE_ARROW); 7960 } 7961 7962 void RGFW_window_showMouse(RGFW_window* win, i8 show) { 7963 RGFW_UNUSED(win); 7964 7965 if (show) { 7966 CGDisplayShowCursor(kCGDirectMainDisplay); 7967 } 7968 else { 7969 CGDisplayHideCursor(kCGDirectMainDisplay); 7970 } 7971 } 7972 7973 void RGFW_window_setMouseStandard(RGFW_window* win, u8 stdMouses) { 7974 if (stdMouses > ((sizeof(RGFW_mouseIconSrc)) / (sizeof(char*)))) 7975 return; 7976 7977 char* mouseStr = RGFW_mouseIconSrc[stdMouses]; 7978 void* mouse = NSCursor_arrowStr(mouseStr); 7979 7980 if (mouse == NULL) 7981 return; 7982 7983 RGFW_UNUSED(win); 7984 CGDisplayShowCursor(kCGDirectMainDisplay); 7985 objc_msgSend_void(mouse, sel_registerName("set")); 7986 } 7987 7988 void RGFW_releaseCursor(RGFW_window* win) { 7989 RGFW_UNUSED(win); 7990 CGAssociateMouseAndMouseCursorPosition(1); 7991 } 7992 7993 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { 7994 RGFW_UNUSED(win) 7995 7996 CGWarpMouseCursorPosition(CGPointMake(r.x + (r.w / 2), r.y + (r.h / 2))); 7997 CGAssociateMouseAndMouseCursorPosition(0); 7998 } 7999 8000 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { 8001 RGFW_UNUSED(win); 8002 8003 CGWarpMouseCursorPosition(CGPointMake(v.x, v.y)); 8004 } 8005 8006 8007 void RGFW_window_hide(RGFW_window* win) { 8008 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), false); 8009 } 8010 8011 void RGFW_window_show(RGFW_window* win) { 8012 ((id(*)(id, SEL, SEL))objc_msgSend)(win->src.window, sel_registerName("makeKeyAndOrderFront:"), NULL); 8013 objc_msgSend_void_bool(win->src.window, sel_registerName("setIsVisible:"), true); 8014 } 8015 8016 u8 RGFW_window_isFullscreen(RGFW_window* win) { 8017 assert(win != NULL); 8018 8019 NSWindowStyleMask mask = (NSWindowStyleMask) objc_msgSend_uint(win->src.window, sel_registerName("styleMask")); 8020 return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen; 8021 } 8022 8023 u8 RGFW_window_isHidden(RGFW_window* win) { 8024 assert(win != NULL); 8025 8026 bool visible = objc_msgSend_bool(win->src.window, sel_registerName("isVisible")); 8027 return visible == NO && !RGFW_window_isMinimized(win); 8028 } 8029 8030 u8 RGFW_window_isMinimized(RGFW_window* win) { 8031 assert(win != NULL); 8032 8033 return objc_msgSend_bool(win->src.window, sel_registerName("isMiniaturized")) == YES; 8034 } 8035 8036 u8 RGFW_window_isMaximized(RGFW_window* win) { 8037 assert(win != NULL); 8038 8039 return objc_msgSend_bool(win->src.window, sel_registerName("isZoomed")); 8040 } 8041 8042 static RGFW_monitor RGFW_NSCreateMonitor(CGDirectDisplayID display) { 8043 RGFW_monitor monitor; 8044 8045 CGRect bounds = CGDisplayBounds(display); 8046 monitor.rect = RGFW_RECT((int) bounds.origin.x, (int) bounds.origin.y, (int) bounds.size.width, (int) bounds.size.height); 8047 8048 CGSize screenSizeMM = CGDisplayScreenSize(display); 8049 monitor.physW = screenSizeMM.width; 8050 monitor.physH = screenSizeMM.height; 8051 8052 monitor.scaleX = ((monitor.rect.w / (screenSizeMM.width / 25.4)) / 96) + 0.25; 8053 monitor.scaleY = ((monitor.rect.h / (screenSizeMM.height / 25.4)) / 96) + 0.25; 8054 8055 return monitor; 8056 } 8057 8058 8059 static RGFW_monitor RGFW_monitors[7]; 8060 8061 RGFW_monitor* RGFW_getMonitors(void) { 8062 static CGDirectDisplayID displays[7]; 8063 u32 count; 8064 8065 if (CGGetActiveDisplayList(6, displays, &count) != kCGErrorSuccess) 8066 return NULL; 8067 8068 for (u32 i = 0; i < count; i++) 8069 RGFW_monitors[i] = RGFW_NSCreateMonitor(displays[i]); 8070 8071 return RGFW_monitors; 8072 } 8073 8074 RGFW_monitor RGFW_getPrimaryMonitor(void) { 8075 CGDirectDisplayID primary = CGMainDisplayID(); 8076 return RGFW_NSCreateMonitor(primary); 8077 } 8078 8079 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { 8080 return RGFW_NSCreateMonitor(win->src.display); 8081 } 8082 8083 char* RGFW_readClipboard(size_t* size) { 8084 char* clip = (char*)NSPasteboard_stringForType(NSPasteboard_generalPasteboard(), NSPasteboardTypeString); 8085 8086 size_t clip_len = 1; 8087 8088 if (clip != NULL) { 8089 clip_len = strlen(clip) + 1; 8090 } 8091 8092 char* str = (char*)RGFW_MALLOC(sizeof(char) * clip_len); 8093 8094 if (clip != NULL) { 8095 strncpy(str, clip, clip_len); 8096 } 8097 8098 str[clip_len] = '\0'; 8099 8100 if (size != NULL) 8101 *size = clip_len; 8102 return str; 8103 } 8104 8105 void RGFW_writeClipboard(const char* text, u32 textLen) { 8106 RGFW_UNUSED(textLen); 8107 8108 NSPasteboardType array[] = { NSPasteboardTypeString, NULL }; 8109 NSPasteBoard_declareTypes(NSPasteboard_generalPasteboard(), array, 1, NULL); 8110 8111 NSPasteBoard_setString(NSPasteboard_generalPasteboard(), text, NSPasteboardTypeString); 8112 } 8113 8114 u16 RGFW_registerJoystick(RGFW_window* win, i32 jsNumber) { 8115 RGFW_UNUSED(jsNumber); 8116 8117 assert(win != NULL); 8118 8119 return RGFW_registerJoystickF(win, (char*) ""); 8120 } 8121 8122 u16 RGFW_registerJoystickF(RGFW_window* win, char* file) { 8123 RGFW_UNUSED(file); 8124 8125 assert(win != NULL); 8126 8127 return RGFW_joystickCount - 1; 8128 } 8129 8130 #ifdef RGFW_OPENGL 8131 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { 8132 assert(win != NULL); 8133 objc_msgSend_void(win->src.ctx, sel_registerName("makeCurrentContext")); 8134 } 8135 #endif 8136 8137 #if !defined(RGFW_EGL) 8138 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { 8139 assert(win != NULL); 8140 #if defined(RGFW_OPENGL) 8141 8142 NSOpenGLContext_setValues(win->src.ctx, &swapInterval, 222); 8143 #else 8144 RGFW_UNUSED(swapInterval); 8145 #endif 8146 } 8147 #endif 8148 8149 // Function to create a CGImageRef from an array of bytes 8150 CGImageRef createImageFromBytes(unsigned char *buffer, int width, int height) 8151 { 8152 // Define color space 8153 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 8154 // Create bitmap context 8155 CGContextRef context = CGBitmapContextCreate( 8156 buffer, 8157 width, height, 8158 8, 8159 RGFW_bufferSize.w * 4, 8160 colorSpace, 8161 kCGImageAlphaPremultipliedLast); 8162 // Create image from bitmap context 8163 CGImageRef image = CGBitmapContextCreateImage(context); 8164 // Release the color space and context 8165 CGColorSpaceRelease(colorSpace); 8166 CGContextRelease(context); 8167 8168 return image; 8169 } 8170 8171 void RGFW_window_swapBuffers(RGFW_window* win) { 8172 assert(win != NULL); 8173 /* clear the window*/ 8174 8175 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { 8176 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 8177 #ifdef RGFW_OSMESA 8178 RGFW_OSMesa_reorganize(); 8179 #endif 8180 8181 void* view = NSWindow_contentView(win->src.window); 8182 void* layer = objc_msgSend_id(view, sel_registerName("layer")); 8183 8184 ((void(*)(id, SEL, NSRect))objc_msgSend)(layer, 8185 sel_registerName("setFrame:"), 8186 (NSRect){{0, 0}, {win->r.w, win->r.h}}); 8187 8188 CGImageRef image = createImageFromBytes(win->buffer, win->r.w, win->r.h); 8189 // Get the current graphics context 8190 id graphicsContext = objc_msgSend_class(objc_getClass("NSGraphicsContext"), sel_registerName("currentContext")); 8191 // Get the CGContext from the current NSGraphicsContext 8192 id cgContext = objc_msgSend_id(graphicsContext, sel_registerName("graphicsPort")); 8193 // Draw the image in the context 8194 NSRect bounds = (NSRect){{0,0}, {win->r.w, win->r.h}}; 8195 CGContextDrawImage((void*)cgContext, *(CGRect*)&bounds, image); 8196 // Flush the graphics context to ensure the drawing is displayed 8197 objc_msgSend_id(graphicsContext, sel_registerName("flushGraphics")); 8198 8199 objc_msgSend_void_id(layer, sel_registerName("setContents:"), (id)image); 8200 objc_msgSend_id(layer, sel_registerName("setNeedsDisplay")); 8201 8202 CGImageRelease(image); 8203 #endif 8204 } 8205 8206 if (!(win->_winArgs & RGFW_NO_GPU_RENDER)) { 8207 #ifdef RGFW_EGL 8208 eglSwapBuffers(win->src.EGL_display, win->src.EGL_surface); 8209 #elif defined(RGFW_OPENGL) 8210 objc_msgSend_void(win->src.ctx, sel_registerName("flushBuffer")); 8211 #endif 8212 } 8213 } 8214 8215 void RGFW_window_close(RGFW_window* win) { 8216 assert(win != NULL); 8217 release(win->src.view); 8218 8219 #ifdef RGFW_ALLOC_DROPFILES 8220 { 8221 u32 i; 8222 for (i = 0; i < RGFW_MAX_DROPS; i++) 8223 RGFW_FREE(win->event.droppedFiles[i]); 8224 8225 8226 RGFW_FREE(win->event.droppedFiles); 8227 } 8228 #endif 8229 8230 #ifdef RGFW_BUFFER 8231 release(win->src.bitmap); 8232 release(win->src.image); 8233 #endif 8234 8235 CVDisplayLinkStop(win->src.displayLink); 8236 CVDisplayLinkRelease(win->src.displayLink); 8237 8238 RGFW_FREE(win); 8239 } 8240 8241 u64 RGFW_getTimeNS(void) { 8242 static mach_timebase_info_data_t timebase_info; 8243 if (timebase_info.denom == 0) { 8244 mach_timebase_info(&timebase_info); 8245 } 8246 return mach_absolute_time() * timebase_info.numer / timebase_info.denom; 8247 } 8248 8249 u64 RGFW_getTime(void) { 8250 static mach_timebase_info_data_t timebase_info; 8251 if (timebase_info.denom == 0) { 8252 mach_timebase_info(&timebase_info); 8253 } 8254 return (double) mach_absolute_time() * (double) timebase_info.numer / ((double) timebase_info.denom * 1e9); 8255 } 8256 #endif /* RGFW_MACOS */ 8257 8258 /* 8259 End of MaOS defines 8260 */ 8261 8262 /* 8263 WEBASM defines 8264 */ 8265 8266 #ifdef RGFW_WEBASM 8267 RGFW_Event RGFW_events[20]; 8268 size_t RGFW_eventLen = 0; 8269 8270 EM_BOOL Emscripten_on_keydown(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { 8271 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8272 8273 RGFW_events[RGFW_eventLen].type = RGFW_keyPressed; 8274 memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16); 8275 RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode); 8276 RGFW_events[RGFW_eventLen].lockState = 0; 8277 RGFW_eventLen++; 8278 8279 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current; 8280 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 1; 8281 RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 1); 8282 8283 return EM_TRUE; 8284 } 8285 8286 EM_BOOL Emscripten_on_keyup(int eventType, const EmscriptenKeyboardEvent* e, void* userData) { 8287 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8288 8289 RGFW_events[RGFW_eventLen].type = RGFW_keyReleased; 8290 memcpy(RGFW_events[RGFW_eventLen].keyName, e->key, 16); 8291 RGFW_events[RGFW_eventLen].keyCode = RGFW_apiKeyCodeToRGFW(e->keyCode); 8292 RGFW_events[RGFW_eventLen].lockState = 0; 8293 RGFW_eventLen++; 8294 8295 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].prev = RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current; 8296 RGFW_keyboard[RGFW_apiKeyCodeToRGFW(e->keyCode)].current = 0; 8297 8298 RGFW_keyCallback(RGFW_root, RGFW_apiKeyCodeToRGFW(e->keyCode), RGFW_events[RGFW_eventLen].keyName, 0, 0); 8299 8300 return EM_TRUE; 8301 } 8302 8303 EM_BOOL Emscripten_on_resize(int eventType, const EmscriptenUiEvent* e, void* userData) { 8304 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8305 8306 RGFW_events[RGFW_eventLen].type = RGFW_windowResized; 8307 RGFW_eventLen++; 8308 8309 RGFW_windowResizeCallback(RGFW_root, RGFW_RECT(0, 0, e->windowInnerWidth, e->windowInnerHeight)); 8310 return EM_TRUE; 8311 } 8312 8313 EM_BOOL Emscripten_on_fullscreenchange(int eventType, const EmscriptenFullscreenChangeEvent* e, void* userData) { 8314 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8315 8316 RGFW_events[RGFW_eventLen].type = RGFW_windowResized; 8317 RGFW_eventLen++; 8318 8319 RGFW_root->r = RGFW_RECT(0, 0, e->elementWidth, e->elementHeight); 8320 RGFW_windowResizeCallback(RGFW_root, RGFW_root->r); 8321 return EM_TRUE; 8322 } 8323 8324 EM_BOOL Emscripten_on_focusin(int eventType, const EmscriptenFocusEvent* e, void* userData) { 8325 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); 8326 8327 RGFW_events[RGFW_eventLen].type = RGFW_focusIn; 8328 RGFW_eventLen++; 8329 8330 RGFW_root->event.inFocus = 1; 8331 RGFW_focusCallback(RGFW_root, 1); 8332 return EM_TRUE; 8333 } 8334 8335 EM_BOOL Emscripten_on_focusout(int eventType, const EmscriptenFocusEvent* e, void* userData) { 8336 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); 8337 8338 RGFW_events[RGFW_eventLen].type = RGFW_focusOut; 8339 RGFW_eventLen++; 8340 8341 RGFW_root->event.inFocus = 0; 8342 RGFW_focusCallback(RGFW_root, 0); 8343 return EM_TRUE; 8344 } 8345 8346 EM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* e, void* userData) { 8347 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8348 8349 RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged; 8350 8351 if ((RGFW_root->_winArgs & RGFW_HOLD_MOUSE)) { 8352 RGFW_point p = RGFW_POINT(e->movementX, e->movementY); 8353 RGFW_events[RGFW_eventLen].point = p; 8354 } 8355 else 8356 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); 8357 RGFW_eventLen++; 8358 8359 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); 8360 return EM_TRUE; 8361 } 8362 8363 EM_BOOL Emscripten_on_mousedown(int eventType, const EmscriptenMouseEvent* e, void* userData) { 8364 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8365 8366 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed; 8367 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); 8368 RGFW_events[RGFW_eventLen].button = e->button + 1; 8369 RGFW_events[RGFW_eventLen].scroll = 0; 8370 8371 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; 8372 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; 8373 8374 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1); 8375 RGFW_eventLen++; 8376 8377 return EM_TRUE; 8378 } 8379 8380 EM_BOOL Emscripten_on_mouseup(int eventType, const EmscriptenMouseEvent* e, void* userData) { 8381 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8382 8383 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased; 8384 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->targetX, e->targetY); 8385 RGFW_events[RGFW_eventLen].button = e->button + 1; 8386 RGFW_events[RGFW_eventLen].scroll = 0; 8387 8388 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; 8389 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0; 8390 8391 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0); 8392 RGFW_eventLen++; 8393 return EM_TRUE; 8394 } 8395 8396 EM_BOOL Emscripten_on_wheel(int eventType, const EmscriptenWheelEvent* e, void* userData) { 8397 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8398 8399 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed; 8400 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->mouse.targetX, e->mouse.targetY); 8401 RGFW_events[RGFW_eventLen].button = RGFW_mouseScrollUp + (e->deltaY < 0); 8402 RGFW_events[RGFW_eventLen].scroll = e->deltaY; 8403 8404 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; 8405 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; 8406 8407 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1); 8408 RGFW_eventLen++; 8409 8410 return EM_TRUE; 8411 } 8412 8413 EM_BOOL Emscripten_on_touchstart(int eventType, const EmscriptenTouchEvent* e, void* userData) { 8414 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8415 8416 size_t i; 8417 for (i = 0; i < (size_t)e->numTouches; i++) { 8418 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonPressed; 8419 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY); 8420 RGFW_events[RGFW_eventLen].button = 1; 8421 RGFW_events[RGFW_eventLen].scroll = 0; 8422 8423 8424 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; 8425 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 1; 8426 8427 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); 8428 8429 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 1); 8430 RGFW_eventLen++; 8431 } 8432 8433 return EM_TRUE; 8434 } 8435 EM_BOOL Emscripten_on_touchmove(int eventType, const EmscriptenTouchEvent* e, void* userData) { 8436 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8437 8438 size_t i; 8439 for (i = 0; i < (size_t)e->numTouches; i++) { 8440 RGFW_events[RGFW_eventLen].type = RGFW_mousePosChanged; 8441 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY); 8442 8443 RGFW_mousePosCallback(RGFW_root, RGFW_events[RGFW_eventLen].point); 8444 RGFW_eventLen++; 8445 } 8446 return EM_TRUE; 8447 } 8448 8449 EM_BOOL Emscripten_on_touchend(int eventType, const EmscriptenTouchEvent* e, void* userData) { 8450 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8451 8452 size_t i; 8453 for (i = 0; i < (size_t)e->numTouches; i++) { 8454 RGFW_events[RGFW_eventLen].type = RGFW_mouseButtonReleased; 8455 RGFW_events[RGFW_eventLen].point = RGFW_POINT(e->touches[i].targetX, e->touches[i].targetY); 8456 RGFW_events[RGFW_eventLen].button = 1; 8457 RGFW_events[RGFW_eventLen].scroll = 0; 8458 8459 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].prev = RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current; 8460 RGFW_mouseButtons[RGFW_events[RGFW_eventLen].button].current = 0; 8461 8462 RGFW_mouseButtonCallback(RGFW_root, RGFW_events[RGFW_eventLen].button, RGFW_events[RGFW_eventLen].scroll, 0); 8463 RGFW_eventLen++; 8464 } 8465 return EM_TRUE; 8466 } 8467 8468 EM_BOOL Emscripten_on_touchcancel(int eventType, const EmscriptenTouchEvent* e, void* userData) { RGFW_UNUSED(eventType); RGFW_UNUSED(userData); RGFW_UNUSED(e); return EM_TRUE; } 8469 8470 EM_BOOL Emscripten_on_gamepad(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData) { 8471 RGFW_UNUSED(eventType); RGFW_UNUSED(userData); 8472 8473 if (gamepadEvent->index >= 4) 8474 return 0; 8475 8476 RGFW_joysticks[gamepadEvent->index] = gamepadEvent->connected; 8477 8478 return 1; // The event was consumed by the callback handler 8479 } 8480 8481 void EMSCRIPTEN_KEEPALIVE Emscripten_onDrop(size_t count) { 8482 if (!(RGFW_root->_winArgs & RGFW_ALLOW_DND)) 8483 return; 8484 8485 RGFW_events[RGFW_eventLen].droppedFilesCount = count; 8486 RGFW_dndCallback(RGFW_root, RGFW_events[RGFW_eventLen].droppedFiles, count); 8487 RGFW_eventLen++; 8488 } 8489 8490 b8 RGFW_stopCheckEvents_bool = RGFW_FALSE; 8491 void RGFW_stopCheckEvents(void) { 8492 RGFW_stopCheckEvents_bool = RGFW_TRUE; 8493 } 8494 8495 void RGFW_window_eventWait(RGFW_window* win, i32 waitMS) { 8496 RGFW_UNUSED(win); 8497 8498 if (waitMS == 0) 8499 return; 8500 8501 u32 start = (u32)(((u64)RGFW_getTimeNS()) / 1e+6); 8502 8503 while ((RGFW_eventLen == 0) && RGFW_stopCheckEvents_bool == RGFW_FALSE && 8504 (waitMS < 0 || (RGFW_getTimeNS() / 1e+6) - start < waitMS) 8505 ) { 8506 emscripten_sleep(0); 8507 } 8508 8509 RGFW_stopCheckEvents_bool = RGFW_FALSE; 8510 } 8511 8512 RGFWDEF void RGFW_init_buffer(RGFW_window* win); 8513 void RGFW_init_buffer(RGFW_window* win) { 8514 #if defined(RGFW_OSMESA) || defined(RGFW_BUFFER) 8515 if (RGFW_bufferSize.w == 0 && RGFW_bufferSize.h == 0) 8516 RGFW_bufferSize = RGFW_getScreenSize(); 8517 8518 win->buffer = RGFW_MALLOC(RGFW_bufferSize.w * RGFW_bufferSize.h * 4); 8519 #ifdef RGFW_OSMESA 8520 win->src.ctx = OSMesaCreateContext(OSMESA_RGBA, NULL); 8521 OSMesaMakeCurrent(win->src.ctx, win->buffer, GL_UNSIGNED_BYTE, win->r.w, win->r.h); 8522 #endif 8523 #else 8524 RGFW_UNUSED(win); /*!< if buffer rendering is not being used */ 8525 #endif 8526 } 8527 8528 void EMSCRIPTEN_KEEPALIVE RGFW_makeSetValue(size_t index, char* file) { 8529 /* This seems like a terrible idea, don't replicate this unless you hate yourself or the OS */ 8530 /* TODO: find a better way to do this, 8531 strcpy doesn't seem to work, maybe because of asyncio 8532 */ 8533 8534 RGFW_events[RGFW_eventLen].type = RGFW_dnd; 8535 char** arr = (char**)&RGFW_events[RGFW_eventLen].droppedFiles[index]; 8536 *arr = file; 8537 } 8538 8539 #include <sys/stat.h> 8540 #include <sys/types.h> 8541 #include <errno.h> 8542 8543 void EMSCRIPTEN_KEEPALIVE RGFW_mkdir(char* name) { mkdir(name, 0755); } 8544 8545 void EMSCRIPTEN_KEEPALIVE RGFW_writeFile(const char *path, const char *data, size_t len) { 8546 FILE* file = fopen(path, "w+"); 8547 if (file == NULL) 8548 return; 8549 8550 fwrite(data, sizeof(char), len, file); 8551 fclose(file); 8552 } 8553 8554 RGFW_window* RGFW_createWindow(const char* name, RGFW_rect rect, u16 args) { 8555 RGFW_UNUSED(name) 8556 8557 RGFW_UNUSED(RGFW_initFormatAttribs); 8558 8559 RGFW_window* win = RGFW_window_basic_init(rect, args); 8560 8561 #ifndef RGFW_WEBGPU 8562 EmscriptenWebGLContextAttributes attrs; 8563 attrs.alpha = EM_TRUE; 8564 attrs.depth = EM_TRUE; 8565 attrs.alpha = EM_TRUE; 8566 attrs.stencil = RGFW_STENCIL; 8567 attrs.antialias = RGFW_SAMPLES; 8568 attrs.premultipliedAlpha = EM_TRUE; 8569 attrs.preserveDrawingBuffer = EM_FALSE; 8570 8571 if (RGFW_DOUBLE_BUFFER == 0) 8572 attrs.renderViaOffscreenBackBuffer = 0; 8573 else 8574 attrs.renderViaOffscreenBackBuffer = RGFW_AUX_BUFFERS; 8575 8576 attrs.failIfMajorPerformanceCaveat = EM_FALSE; 8577 attrs.majorVersion = (RGFW_majorVersion == 0) ? 1 : RGFW_majorVersion; 8578 attrs.minorVersion = RGFW_minorVersion; 8579 8580 attrs.enableExtensionsByDefault = EM_TRUE; 8581 attrs.explicitSwapControl = EM_TRUE; 8582 8583 emscripten_webgl_init_context_attributes(&attrs); 8584 win->src.ctx = emscripten_webgl_create_context("#canvas", &attrs); 8585 emscripten_webgl_make_context_current(win->src.ctx); 8586 8587 #ifdef LEGACY_GL_EMULATION 8588 EM_ASM("Module.useWebGL = true; GLImmediate.init();"); 8589 #endif 8590 #else 8591 win->src.ctx = wgpuCreateInstance(NULL); 8592 win->src.device = emscripten_webgpu_get_device(); 8593 win->src.queue = wgpuDeviceGetQueue(win->src.device); 8594 #endif 8595 8596 emscripten_set_canvas_element_size("#canvas", rect.w, rect.h); 8597 emscripten_set_window_title(name); 8598 8599 /* load callbacks */ 8600 emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keydown); 8601 emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_keyup); 8602 emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_resize); 8603 emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, NULL, EM_FALSE, Emscripten_on_fullscreenchange); 8604 emscripten_set_mousemove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousemove); 8605 emscripten_set_touchstart_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchstart); 8606 emscripten_set_touchend_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchend); 8607 emscripten_set_touchmove_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchmove); 8608 emscripten_set_touchcancel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_touchcancel); 8609 emscripten_set_mousedown_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mousedown); 8610 emscripten_set_mouseup_callback("#canvas", NULL, EM_FALSE, Emscripten_on_mouseup); 8611 emscripten_set_wheel_callback("#canvas", NULL, EM_FALSE, Emscripten_on_wheel); 8612 emscripten_set_focusin_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusin); 8613 emscripten_set_focusout_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, EM_FALSE, Emscripten_on_focusout); 8614 emscripten_set_gamepadconnected_callback(NULL, 1, Emscripten_on_gamepad); 8615 emscripten_set_gamepaddisconnected_callback(NULL, 1, Emscripten_on_gamepad); 8616 8617 if (args & RGFW_ALLOW_DND) { 8618 win->_winArgs |= RGFW_ALLOW_DND; 8619 } 8620 8621 EM_ASM({ 8622 var canvas = document.getElementById('canvas'); 8623 canvas.addEventListener('drop', function(e) { 8624 e.preventDefault(); 8625 if (e.dataTransfer.file < 0) 8626 return; 8627 8628 var filenamesArray = []; 8629 var count = e.dataTransfer.files.length; 8630 8631 /* Read and save the files to emscripten's files */ 8632 var drop_dir = '.rgfw_dropped_files'; 8633 Module._RGFW_mkdir(drop_dir); 8634 8635 for (var i = 0; i < count; i++) { 8636 var file = e.dataTransfer.files[i]; 8637 8638 var path = '/' + drop_dir + '/' + file.name.replace("//", '_'); 8639 var reader = new FileReader(); 8640 8641 reader.onloadend = (e) => { 8642 if (reader.readyState != 2) { 8643 out('failed to read dropped file: '+file.name+': '+reader.error); 8644 } 8645 else { 8646 var data = e.target.result; 8647 8648 _RGFW_writeFile(path, new Uint8Array(data), file.size); 8649 } 8650 }; 8651 8652 reader.readAsArrayBuffer(file); 8653 // This works weird on modern opengl 8654 var filename = stringToNewUTF8(path); 8655 8656 filenamesArray.push(filename); 8657 8658 Module._RGFW_makeSetValue(i, filename); 8659 } 8660 8661 Module._Emscripten_onDrop(count); 8662 8663 for (var i = 0; i < count; ++i) { 8664 _free(filenamesArray[i]); 8665 } 8666 }, true); 8667 8668 canvas.addEventListener('dragover', function(e) { e.preventDefault(); return false; }, true); 8669 }); 8670 8671 RGFW_init_buffer(win); 8672 glViewport(0, 0, rect.w, rect.h); 8673 8674 RGFW_root = win; 8675 8676 if (args & RGFW_HIDE_MOUSE) { 8677 RGFW_window_showMouse(win, 0); 8678 } 8679 8680 if (args & RGFW_FULLSCREEN) { 8681 RGFW_window_resize(win, RGFW_getScreenSize()); 8682 } 8683 8684 return win; 8685 } 8686 8687 RGFW_Event* RGFW_window_checkEvent(RGFW_window* win) { 8688 static u8 index = 0; 8689 8690 if (index == 0) 8691 RGFW_resetKey(); 8692 8693 /* check gamepads */ 8694 for (int i = 0; (i < emscripten_get_num_gamepads()) && (i < 4); i++) { 8695 if (RGFW_joysticks[i] == 0) 8696 continue;; 8697 8698 EmscriptenGamepadEvent gamepadState; 8699 8700 if (emscripten_get_gamepad_status(i, &gamepadState) != EMSCRIPTEN_RESULT_SUCCESS) 8701 break; 8702 8703 // Register buttons data for every connected gamepad 8704 for (int j = 0; (j < gamepadState.numButtons) && (j < 16); j++) { 8705 u32 map[] = { 8706 RGFW_JS_A, RGFW_JS_X, RGFW_JS_B, RGFW_JS_Y, 8707 RGFW_JS_L1, RGFW_JS_R1, RGFW_JS_L2, RGFW_JS_R2, 8708 RGFW_JS_SELECT, RGFW_JS_START, 8709 0, 0, 8710 RGFW_JS_UP, RGFW_JS_DOWN, RGFW_JS_LEFT, RGFW_JS_RIGHT 8711 }; 8712 8713 u32 button = map[j]; 8714 if (RGFW_jsPressed[i][button] != gamepadState.digitalButton[j]) { 8715 win->event.type = RGFW_jsButtonPressed; 8716 win->event.joystick = i; 8717 win->event.button = map[j]; 8718 return &win->event; 8719 } 8720 8721 RGFW_jsPressed[i][button] = gamepadState.digitalButton[j]; 8722 } 8723 8724 for (int j = 0; (j < gamepadState.numAxes) && (j < 4); j += 2) { 8725 win->event.axisesCount = gamepadState.numAxes; 8726 if (win->event.axis[j].x != gamepadState.axis[j] || 8727 win->event.axis[j].y != gamepadState.axis[j + 1] 8728 ) { 8729 win->event.axis[j].x = gamepadState.axis[j]; 8730 win->event.axis[j].y = gamepadState.axis[j + 1]; 8731 win->event.type = RGFW_jsAxisMove; 8732 win->event.joystick = i; 8733 return &win->event; 8734 } 8735 } 8736 } 8737 8738 /* check queued events */ 8739 if (RGFW_eventLen == 0) 8740 return NULL; 8741 8742 RGFW_events[index].frameTime = win->event.frameTime; 8743 RGFW_events[index].frameTime2 = win->event.frameTime2; 8744 RGFW_events[index].inFocus = win->event.inFocus; 8745 8746 win->event = RGFW_events[index]; 8747 8748 RGFW_eventLen--; 8749 8750 if (RGFW_eventLen) 8751 index++; 8752 else 8753 index = 0; 8754 8755 return &win->event; 8756 } 8757 8758 void RGFW_window_resize(RGFW_window* win, RGFW_area a) { 8759 RGFW_UNUSED(win) 8760 emscripten_set_canvas_element_size("#canvas", a.w, a.h); 8761 } 8762 8763 /* NOTE: I don't know if this is possible */ 8764 void RGFW_window_moveMouse(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win); RGFW_UNUSED(v); } 8765 /* this one might be possible but it looks iffy */ 8766 void RGFW_window_setMouse(RGFW_window* win, u8* image, RGFW_area a, i32 channels) { RGFW_UNUSED(win); RGFW_UNUSED(channels) RGFW_UNUSED(a) RGFW_UNUSED(image) } 8767 8768 const char RGFW_CURSORS[11][12] = { 8769 "default", 8770 "default", 8771 "text", 8772 "crosshair", 8773 "pointer", 8774 "ew-resize", 8775 "ns-resize", 8776 "nwse-resize", 8777 "nesw-resize", 8778 "move", 8779 "not-allowed" 8780 }; 8781 8782 void RGFW_window_setMouseStandard(RGFW_window* win, u8 mouse) { 8783 RGFW_UNUSED(win) 8784 EM_ASM( { document.getElementById("canvas").style.cursor = UTF8ToString($0); }, RGFW_CURSORS[mouse]); 8785 } 8786 8787 void RGFW_window_setMouseDefault(RGFW_window* win) { 8788 RGFW_window_setMouseStandard(win, RGFW_MOUSE_NORMAL); 8789 } 8790 8791 void RGFW_window_showMouse(RGFW_window* win, i8 show) { 8792 if (show) 8793 RGFW_window_setMouseDefault(win); 8794 else 8795 EM_ASM(document.getElementById('canvas').style.cursor = 'none';); 8796 } 8797 8798 RGFW_point RGFW_getGlobalMousePoint(void) { 8799 RGFW_point point; 8800 point.x = EM_ASM_INT({ 8801 return window.mouseX || 0; 8802 }); 8803 point.y = EM_ASM_INT({ 8804 return window.mouseY || 0; 8805 }); 8806 return point; 8807 } 8808 8809 RGFW_point RGFW_window_getMousePoint(RGFW_window* win) { 8810 RGFW_UNUSED(win); 8811 8812 EmscriptenMouseEvent mouseEvent; 8813 emscripten_get_mouse_status(&mouseEvent); 8814 return RGFW_POINT( mouseEvent.targetX, mouseEvent.targetY); 8815 } 8816 8817 void RGFW_window_setMousePassthrough(RGFW_window* win, b8 passthrough) { 8818 RGFW_UNUSED(win); 8819 8820 EM_ASM_({ 8821 var canvas = document.getElementById('canvas'); 8822 if ($0) { 8823 canvas.style.pointerEvents = 'none'; 8824 } else { 8825 canvas.style.pointerEvents = 'auto'; 8826 } 8827 }, passthrough); 8828 } 8829 8830 void RGFW_writeClipboard(const char* text, u32 textLen) { 8831 RGFW_UNUSED(textLen) 8832 EM_ASM({ navigator.clipboard.writeText(UTF8ToString($0)); }, text); 8833 } 8834 8835 8836 char* RGFW_readClipboard(size_t* size) { 8837 /* 8838 placeholder code for later 8839 I'm not sure if this is possible do the the async stuff 8840 */ 8841 8842 if (size != NULL) 8843 *size = 0; 8844 8845 char* str = (char*)malloc(1); 8846 str[0] = '\0'; 8847 8848 return str; 8849 } 8850 8851 void RGFW_window_swapBuffers(RGFW_window* win) { 8852 RGFW_UNUSED(win); 8853 8854 #ifdef RGFW_BUFFER 8855 if (!(win->_winArgs & RGFW_NO_CPU_RENDER)) { 8856 glEnable(GL_TEXTURE_2D); 8857 8858 GLuint texture; 8859 glGenTextures(1,&texture); 8860 8861 glBindTexture(GL_TEXTURE_2D,texture); 8862 8863 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 8864 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 8865 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 8866 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 8867 8868 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, RGFW_bufferSize.w, RGFW_bufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, win->buffer); 8869 8870 float ratioX = ((float)win->r.w / (float)RGFW_bufferSize.w); 8871 float ratioY = ((float)win->r.h / (float)RGFW_bufferSize.h); 8872 8873 // Set up the viewport 8874 glClear(GL_COLOR_BUFFER_BIT); 8875 8876 glBegin(GL_TRIANGLES); 8877 glTexCoord2f(0, ratioY); glColor3f(1, 1, 1); glVertex2f(-1, -1); 8878 glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1); 8879 glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1); 8880 8881 glTexCoord2f(ratioX, 0); glColor3f(1, 1, 1); glVertex2f(1, 1); 8882 glTexCoord2f(ratioX, ratioY); glColor3f(1, 1, 1); glVertex2f(1, -1); 8883 glTexCoord2f(0, 0); glColor3f(1, 1, 1); glVertex2f(-1, 1); 8884 glEnd(); 8885 8886 glDeleteTextures(1, &texture); 8887 } 8888 #endif 8889 8890 #ifndef RGFW_WEBGPU 8891 emscripten_webgl_commit_frame(); 8892 #endif 8893 emscripten_sleep(0); 8894 } 8895 8896 8897 void RGFW_window_makeCurrent_OpenGL(RGFW_window* win) { 8898 #ifndef RGFW_WEBGPU 8899 if (win == NULL) 8900 emscripten_webgl_make_context_current(0); 8901 else 8902 emscripten_webgl_make_context_current(win->src.ctx); 8903 #endif 8904 } 8905 8906 #ifndef RGFW_EGL 8907 void RGFW_window_swapInterval(RGFW_window* win, i32 swapInterval) { RGFW_UNUSED(win); RGFW_UNUSED(swapInterval); } 8908 #endif 8909 8910 void RGFW_window_close(RGFW_window* win) { 8911 #ifndef RGFW_WEBGPU 8912 emscripten_webgl_destroy_context(win->src.ctx); 8913 #endif 8914 8915 free(win); 8916 } 8917 8918 int RGFW_innerWidth(void) { return EM_ASM_INT({ return window.innerWidth; }); } 8919 int RGFW_innerHeight(void) { return EM_ASM_INT({ return window.innerHeight; }); } 8920 8921 RGFW_area RGFW_getScreenSize(void) { 8922 return RGFW_AREA(RGFW_innerWidth(), RGFW_innerHeight()); 8923 } 8924 8925 void* RGFW_getProcAddress(const char* procname) { 8926 return emscripten_webgl_get_proc_address(procname); 8927 } 8928 8929 void RGFW_sleep(u64 milisecond) { 8930 emscripten_sleep(milisecond); 8931 } 8932 8933 u64 RGFW_getTimeNS(void) { 8934 return emscripten_get_now() * 1e+6; 8935 } 8936 8937 u64 RGFW_getTime(void) { 8938 return emscripten_get_now() * 1000; 8939 } 8940 8941 void RGFW_releaseCursor(RGFW_window* win) { 8942 RGFW_UNUSED(win); 8943 emscripten_exit_pointerlock(); 8944 } 8945 8946 void RGFW_captureCursor(RGFW_window* win, RGFW_rect r) { 8947 RGFW_UNUSED(win); RGFW_UNUSED(r); 8948 8949 emscripten_request_pointerlock("#canvas", 1); 8950 } 8951 8952 8953 void RGFW_window_setName(RGFW_window* win, char* name) { 8954 RGFW_UNUSED(win); 8955 emscripten_set_window_title(name); 8956 } 8957 8958 /* unsupported functions */ 8959 RGFW_monitor* RGFW_getMonitors(void) { return NULL; } 8960 RGFW_monitor RGFW_getPrimaryMonitor(void) { return (RGFW_monitor){}; } 8961 void RGFW_window_move(RGFW_window* win, RGFW_point v) { RGFW_UNUSED(win) RGFW_UNUSED(v) } 8962 void RGFW_window_setMinSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) } 8963 void RGFW_window_setMaxSize(RGFW_window* win, RGFW_area a) { RGFW_UNUSED(win) RGFW_UNUSED(a) } 8964 void RGFW_window_minimize(RGFW_window* win) { RGFW_UNUSED(win)} 8965 void RGFW_window_restore(RGFW_window* win) { RGFW_UNUSED(win) } 8966 void RGFW_window_setBorder(RGFW_window* win, b8 border) { RGFW_UNUSED(win) RGFW_UNUSED(border) } 8967 void RGFW_window_setIcon(RGFW_window* win, u8* icon, RGFW_area a, i32 channels) { RGFW_UNUSED(win) RGFW_UNUSED(icon) RGFW_UNUSED(a) RGFW_UNUSED(channels) } 8968 void RGFW_window_hide(RGFW_window* win) { RGFW_UNUSED(win) } 8969 void RGFW_window_show(RGFW_window* win) {RGFW_UNUSED(win) } 8970 b8 RGFW_window_isHidden(RGFW_window* win) { RGFW_UNUSED(win) return 0; } 8971 b8 RGFW_window_isMinimized(RGFW_window* win) { RGFW_UNUSED(win) return 0; } 8972 b8 RGFW_window_isMaximized(RGFW_window* win) { RGFW_UNUSED(win) return 0; } 8973 RGFW_monitor RGFW_window_getMonitor(RGFW_window* win) { RGFW_UNUSED(win) return (RGFW_monitor){}; } 8974 8975 #endif 8976 8977 /* end of web asm defines */ 8978 8979 /* unix (macOS, linux, web asm) only stuff */ 8980 #if defined(RGFW_X11) || defined(RGFW_MACOS) || defined(RGFW_WEBASM) || defined(RGFW_WAYLAND) 8981 /* unix threading */ 8982 #ifndef RGFW_NO_THREADS 8983 #include <pthread.h> 8984 8985 RGFW_thread RGFW_createThread(RGFW_threadFunc_ptr ptr, void* args) { 8986 RGFW_UNUSED(args); 8987 8988 RGFW_thread t; 8989 pthread_create((pthread_t*) &t, NULL, *ptr, NULL); 8990 return t; 8991 } 8992 void RGFW_cancelThread(RGFW_thread thread) { pthread_cancel((pthread_t) thread); } 8993 void RGFW_joinThread(RGFW_thread thread) { pthread_join((pthread_t) thread, NULL); } 8994 #ifdef __linux__ 8995 void RGFW_setThreadPriority(RGFW_thread thread, u8 priority) { pthread_setschedprio((pthread_t)thread, priority); } 8996 #endif 8997 #endif 8998 8999 #ifndef RGFW_WEBASM 9000 /* unix sleep */ 9001 void RGFW_sleep(u64 ms) { 9002 struct timespec time; 9003 time.tv_sec = 0; 9004 time.tv_nsec = ms * 1e+6; 9005 9006 nanosleep(&time, NULL); 9007 } 9008 #endif 9009 9010 #endif /* end of unix / mac stuff*/ 9011 #endif /*RGFW_IMPLEMENTATION*/ 9012 9013 #if defined(__cplusplus) && !defined(__EMSCRIPTEN__) 9014 } 9015 #endif