From bb05cf3e4db572a66c0e564b26d4cb85adcb8cad Mon Sep 17 00:00:00 2001 From: takase1121 <20792268+takase1121@users.noreply.github.com> Date: Fri, 18 Apr 2025 13:19:15 +0800 Subject: [PATCH] SDL3 port (#1756) * update to SDL 3.2.0 * remove SDL wrap * fix darwin and windows CI * update build box, correct msys sdl3 dependency * port leftovers from renderer backend to SDL3 * remove SDL main dep the main implementation is now included in a header * main.c: use SDL_main.h This needs to be included to work. * ci: use vcpkg and pkgconf to support SDL3 on MSVC * ci: use 7z to create zip * renwindow: create texture and surface suitable for the display * system: remove trailing whitespace * renderer: fix trailing whitespace * system: fix checking the wrong argument * system: port rmdir and stat to SDL3 API * system: remove unneeded API level check * system: fix wrong parameter index * system: make set_window_hit_test and set_window_bordered accept a window * docs/system: update docs * system: restore some comments * docs/system: add missing documentation for system.text_input * system: use SDL_setenv_unsafe * system: add back comment for setenv * system,renderer: remove unnecessary SDL_ClearError calls --------- Co-authored-by: takase1121 <20792268+takase1121@users.noreply.github.com> (cherry picked from commit 2716f14b6903f055f6bdf010a7e4a3d040cf059d) --- .github/workflows/build.yml | 53 ++++- .github/workflows/release.yml | 21 +- meson.build | 2 +- src/api/dirmonitor.c | 4 +- src/api/dirmonitor/fsevents.c | 4 +- src/api/process.c | 26 +-- src/api/system.c | 418 ++++++++++++++-------------------- src/main.c | 63 ++--- src/meson.build | 62 +---- src/rencache.c | 1 + src/renderer.c | 81 ++++--- src/renderer.h | 2 +- src/renwindow.c | 30 +-- src/renwindow.h | 2 +- subprojects/sdl2.wrap | 15 -- 15 files changed, 338 insertions(+), 446 deletions(-) delete mode 100644 subprojects/sdl2.wrap diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6e7d1a..2f9066c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,8 @@ jobs: matrix: config: - { name: "GCC", cc: gcc, cxx: g++ } - - { name: "clang", cc: clang, cxx: clang++ } + # disable this until we have clang in the build box + # - { name: "clang", cc: clang, cxx: clang++ } env: CC: ${{ matrix.config.cc }} CXX: ${{ matrix.config.cxx }} @@ -35,21 +36,30 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + # disabled because this will break our own Python install - name: Python Setup + if: false uses: actions/setup-python@v5 with: python-version: "3.11" + # disabled because the container has up-to-date packages - name: Update Packages + if: false run: sudo apt-get update + # disabled as the dependencies are already installed - name: Install Dependencies + if: false run: bash scripts/install-dependencies.sh --debug - name: Build - run: | - bash --version - bash scripts/build.sh --debug --forcefallback --portable + uses: docker://ghcr.io/lite-xl/lite-xl-build-box-manylinux:v4 + with: + entrypoint: /entrypoint.sh + args: | + bash --version + bash scripts/build.sh --debug --forcefallback --portable - name: Package if: ${{ matrix.config.cc == 'gcc' }} @@ -101,7 +111,7 @@ jobs: # installing md5sha1sum will eliminate a warning with arm64 and libusb - name: Install Dependencies run: | - brew install bash md5sha1sum + brew install bash md5sha1sum sdl3 pip install meson ninja dmgbuild - name: Build @@ -192,11 +202,14 @@ jobs: base-devel git zip - mingw-w64-${{ matrix.config.arch }}-gcc - mingw-w64-${{ matrix.config.arch }}-meson - mingw-w64-${{ matrix.config.arch }}-ninja - mingw-w64-${{ matrix.config.arch }}-ca-certificates - mingw-w64-${{ matrix.config.arch }}-ntldd + patch + pacboy: >- + gcc:p + meson:p + ca-certificates:p + ninja:p + pkg-config:p + sdl3:p - name: Set Environment Variables run: | @@ -251,7 +264,23 @@ jobs: python-version: "3.11" - name: Install meson and ninja - run: pip install meson ninja + run: pip install --no-cache-dir meson ninja + + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Install SDL + env: { VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" } + run: vcpkg install sdl3:x64-windows-static pkgconf:x64-windows-release + + - name: Add environment variables + run: | + echo "PKG_CONFIG_PATH=C:\vcpkg\installed\x64-windows-static\lib\pkgconfig" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "PKG_CONFIG=C:\vcpkg\installed\x64-windows-release\tools\pkgconf\pkgconf.exe" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Set up environment variables run: | @@ -276,7 +305,7 @@ jobs: - name: Package run: | Remove-Item -Recurse -Force -Path "lite-xl/lib","lite-xl/include" - Compress-Archive -Path lite-xl -DestinationPath "$env:INSTALL_NAME.zip" + 7z a -mx=9 "$env:INSTALL_NAME.zip" lite-xl - name: Upload Artifacts uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90efc79..a8233dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,7 +92,7 @@ jobs: sudo apt-get install -y ccache - name: Build Portable - uses: docker://ghcr.io/lite-xl/lite-xl-build-box-manylinux:v3 + uses: docker://ghcr.io/lite-xl/lite-xl-build-box-manylinux:v4 with: entrypoint: /entrypoint.sh args: | @@ -100,7 +100,7 @@ jobs: bash scripts/build.sh --debug --forcefallback --portable --release --lto - name: Package Portables - uses: docker://ghcr.io/lite-xl/lite-xl-build-box-manylinux:v3 + uses: docker://ghcr.io/lite-xl/lite-xl-build-box-manylinux:v4 with: entrypoint: /entrypoint.sh args: | @@ -108,7 +108,7 @@ jobs: bash scripts/package.sh --version ${INSTALL_REF} --debug --addons --binary --release - name: Build AppImages - uses: docker://ghcr.io/lite-xl/lite-xl-build-box-manylinux:v3 + uses: docker://ghcr.io/lite-xl/lite-xl-build-box-manylinux:v4 with: entrypoint: /entrypoint.sh args: | @@ -164,7 +164,7 @@ jobs: - name: Install Dependencies run: | - brew install bash md5sha1sum + brew install bash md5sha1sum sdl3 pip install meson ninja dmgbuild - name: Build @@ -269,11 +269,14 @@ jobs: git zip unzip - mingw-w64-${{ matrix.config.arch }}-gcc - mingw-w64-${{ matrix.config.arch }}-meson - mingw-w64-${{ matrix.config.arch }}-ninja - mingw-w64-${{ matrix.config.arch }}-ca-certificates - mingw-w64-${{ matrix.config.arch }}-ntldd + patch + pacboy: >- + gcc:p + meson:p + ca-certificates:p + ninja:p + pkg-config:p + sdl3:p - name: Set Environment Variables run: | diff --git a/meson.build b/meson.build index d4575bf..7a09d37 100644 --- a/meson.build +++ b/meson.build @@ -43,7 +43,7 @@ conf_data.set('PROJECT_ASSEMBLY_VERSION', meson.project_version() + '.0') cc = meson.get_compiler('c') lite_includes = [] -lite_cargs = ['-DSDL_MAIN_HANDLED', '-DPCRE2_STATIC'] +lite_cargs = ['-DPCRE2_STATIC'] # On macos we need to use the SDL renderer to support retina displays if get_option('renderer') or host_machine.system() == 'darwin' lite_cargs += '-DLITE_USE_SDL_RENDERER' diff --git a/src/api/dirmonitor.c b/src/api/dirmonitor.c index bb3911e..1fcf82d 100644 --- a/src/api/dirmonitor.c +++ b/src/api/dirmonitor.c @@ -1,6 +1,6 @@ #include "api.h" #include "lua.h" -#include +#include #include #include #include @@ -9,7 +9,7 @@ static unsigned int DIR_EVENT_TYPE = 0; struct dirmonitor { SDL_Thread* thread; - SDL_mutex* mutex; + SDL_Mutex* mutex; char buffer[64512]; volatile int length; struct dirmonitor_internal* internal; diff --git a/src/api/dirmonitor/fsevents.c b/src/api/dirmonitor/fsevents.c index 47812f4..60ca16c 100644 --- a/src/api/dirmonitor/fsevents.c +++ b/src/api/dirmonitor/fsevents.c @@ -1,8 +1,8 @@ -#include +#include #include struct dirmonitor_internal { - SDL_mutex* lock; + SDL_Mutex* lock; char** changes; size_t count; FSEventStreamRef stream; diff --git a/src/api/process.c b/src/api/process.c index c5cb80c..91b6a8d 100644 --- a/src/api/process.c +++ b/src/api/process.c @@ -4,8 +4,8 @@ #include #include #include -#include -#include +#include +#include #include #if _WIN32 @@ -85,8 +85,8 @@ typedef struct process_kill_s { typedef struct { bool stop; - SDL_mutex *mutex; - SDL_cond *has_work, *work_done; + SDL_Mutex *mutex; + SDL_Condition *has_work, *work_done; SDL_Thread *worker_thread; process_kill_t *head; process_kill_t *tail; @@ -133,8 +133,8 @@ static void kill_list_free(process_kill_list_t *list) { process_kill_t *node, *temp; SDL_WaitThread(list->worker_thread, NULL); SDL_DestroyMutex(list->mutex); - SDL_DestroyCond(list->has_work); - SDL_DestroyCond(list->work_done); + SDL_DestroyCondition(list->has_work); + SDL_DestroyCondition(list->work_done); node = list->head; while (node) { temp = node; @@ -148,8 +148,8 @@ static void kill_list_free(process_kill_list_t *list) { static bool kill_list_init(process_kill_list_t *list) { memset(list, 0, sizeof(process_kill_list_t)); list->mutex = SDL_CreateMutex(); - list->has_work = SDL_CreateCond(); - list->work_done = SDL_CreateCond(); + list->has_work = SDL_CreateCondition(); + list->work_done = SDL_CreateCondition(); list->head = list->tail = NULL; list->stop = false; if (!list->mutex || !list->has_work || !list->work_done) { @@ -190,10 +190,10 @@ static void kill_list_wait_all(process_kill_list_t *list) { SDL_LockMutex(list->mutex); // wait until list is empty while (list->head) - SDL_CondWait(list->work_done, list->mutex); + SDL_WaitCondition(list->work_done, list->mutex); // tell the worker to stop list->stop = true; - SDL_CondSignal(list->has_work); + SDL_SignalCondition(list->has_work); SDL_UnlockMutex(list->mutex); } @@ -257,7 +257,7 @@ static int kill_list_worker(void *ud) { // wait until we have work to do while (!list->head && !list->stop) - SDL_CondWait(list->has_work, list->mutex); // LOCK MUTEX + SDL_WaitCondition(list->has_work, list->mutex); // LOCK MUTEX if (list->stop) break; @@ -279,7 +279,7 @@ static int kill_list_worker(void *ud) { kill_list_push(list, current_task); } else { free_task: - SDL_CondSignal(list->work_done); + SDL_SignalCondition(list->work_done); process_handle_close(¤t_task->handle); free(current_task); } @@ -759,7 +759,7 @@ static int f_gc(lua_State* L) { p->tries = 1; SDL_LockMutex(list->mutex); kill_list_push(list, p); - SDL_CondSignal(list->has_work); + SDL_SignalCondition(list->has_work); SDL_UnlockMutex(list->mutex); } } diff --git a/src/api/system.c b/src/api/system.c index 7bde177..fc10edb 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -1,4 +1,5 @@ -#include +#include +#include #include #include #include @@ -117,12 +118,12 @@ static SDL_HitTestResult SDLCALL hit_test(SDL_Window *window, const SDL_Point *p static const char *numpad[] = { "end", "down", "pagedown", "left", "", "right", "home", "up", "pageup", "ins", "delete" }; static const char *get_key_name(const SDL_Event *e, char *buf) { - SDL_Scancode scancode = e->key.keysym.scancode; + SDL_Scancode scancode = e->key.scancode; /* Is the scancode from the keypad and the number-lock off? ** We assume that SDL_SCANCODE_KP_1 up to SDL_SCANCODE_KP_9 and SDL_SCANCODE_KP_0 ** and SDL_SCANCODE_KP_PERIOD are declared in SDL2 in that order. */ if (scancode >= SDL_SCANCODE_KP_1 && scancode <= SDL_SCANCODE_KP_1 + 10 && - !(e->key.keysym.mod & KMOD_NUM)) { + !(e->key.mod & SDL_KMOD_NUM)) { return numpad[scancode - SDL_SCANCODE_KP_1]; } else { /* We need to correctly handle non-standard layouts such as dvorak. @@ -135,8 +136,8 @@ static const char *get_key_name(const SDL_Event *e, char *buf) { and others, are masked with SDLK_SCANCODE_MASK, which moves them outside the unicode range (>0x10FFFF). Users can remap these buttons, so we need to return the correct name, not scancode based. */ - if ((e->key.keysym.sym < 128) || (e->key.keysym.sym & SDLK_SCANCODE_MASK)) - strcpy(buf, SDL_GetKeyName(e->key.keysym.sym)); + if ((e->key.key < 128) || (e->key.key & SDLK_SCANCODE_MASK)) + strcpy(buf, SDL_GetKeyName(e->key.key)); else strcpy(buf, SDL_GetScancodeName(scancode)); str_tolower(buf); @@ -171,7 +172,8 @@ static void push_win32_error(lua_State *L, DWORD rc) { static int f_poll_event(lua_State *L) { char buf[16]; - int mx, my, w, h; + float mx, my; + int w, h; SDL_Event e; SDL_Event event_plus; @@ -181,184 +183,205 @@ top: } switch (e.type) { - case SDL_QUIT: + case SDL_EVENT_QUIT: lua_pushstring(L, "quit"); return 1; - case SDL_WINDOWEVENT: - if (e.window.event == SDL_WINDOWEVENT_RESIZED) { + case SDL_EVENT_WINDOW_RESIZED: + { ren_resize_window(&window_renderer); lua_pushstring(L, "resized"); /* The size below will be in points. */ lua_pushinteger(L, e.window.data1); lua_pushinteger(L, e.window.data2); return 3; - } else if (e.window.event == SDL_WINDOWEVENT_EXPOSED) { - rencache_invalidate(); - lua_pushstring(L, "exposed"); - return 1; - } else if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) { - lua_pushstring(L, "minimized"); - return 1; - } else if (e.window.event == SDL_WINDOWEVENT_MAXIMIZED) { - lua_pushstring(L, "maximized"); - return 1; - } else if (e.window.event == SDL_WINDOWEVENT_RESTORED) { - lua_pushstring(L, "restored"); - return 1; - } else if (e.window.event == SDL_WINDOWEVENT_LEAVE) { - lua_pushstring(L, "mouseleft"); - return 1; - } - if (e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) { - lua_pushstring(L, "focuslost"); - return 1; } + + case SDL_EVENT_WINDOW_EXPOSED: + rencache_invalidate(); + lua_pushstring(L, "exposed"); + return 1; + + case SDL_EVENT_WINDOW_MINIMIZED: + lua_pushstring(L, "minimized"); + return 1; + + case SDL_EVENT_WINDOW_MAXIMIZED: + lua_pushstring(L, "maximized"); + return 1; + + case SDL_EVENT_WINDOW_RESTORED: + lua_pushstring(L, "restored"); + return 1; + + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + lua_pushstring(L, "mouseleft"); + return 1; + + case SDL_EVENT_WINDOW_FOCUS_LOST: + lua_pushstring(L, "focuslost"); + return 1; + + case SDL_EVENT_WINDOW_FOCUS_GAINED: /* on some systems, when alt-tabbing to the window SDL will queue up ** several KEYDOWN events for the `tab` key; we flush all keydown ** events on focus so these are discarded */ - if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { - SDL_FlushEvent(SDL_KEYDOWN); - } + SDL_FlushEvent(SDL_EVENT_KEY_DOWN); goto top; - case SDL_DROPFILE: - SDL_GetMouseState(&mx, &my); - lua_pushstring(L, "filedropped"); - lua_pushstring(L, e.drop.file); - lua_pushinteger(L, mx * window_renderer.scale_x); - lua_pushinteger(L, my * window_renderer.scale_y); - SDL_free(e.drop.file); - return 4; - case SDL_KEYDOWN: + case SDL_EVENT_DROP_FILE: + { + SDL_GetMouseState(&mx, &my); + lua_pushstring(L, "filedropped"); + lua_pushstring(L, e.drop.data); + lua_pushinteger(L, mx * window_renderer.scale_x); + lua_pushinteger(L, my * window_renderer.scale_y); + return 4; + } + + case SDL_EVENT_KEY_DOWN: #ifdef __APPLE__ /* on macos 11.2.3 with sdl 2.0.14 the keyup handler for cmd+w below ** was not enough. Maybe the quit event started to be triggered from the ** keydown handler? In any case, flushing the quit event here too helped. */ - if ((e.key.keysym.sym == SDLK_w) && (e.key.keysym.mod & KMOD_GUI)) { - SDL_FlushEvent(SDL_QUIT); + if ((e.key.key == SDLK_W) && (e.key.mod & SDL_KMOD_GUI)) { + SDL_FlushEvent(SDL_EVENT_QUIT); } #endif lua_pushstring(L, "keypressed"); lua_pushstring(L, get_key_name(&e, buf)); return 2; - case SDL_KEYUP: + case SDL_EVENT_KEY_UP: #ifdef __APPLE__ /* on macos command+w will close the current window ** we want to flush this event and let the keymapper ** handle this key combination. ** Thanks to mathewmariani, taken from his lite-macos github repository. */ - if ((e.key.keysym.sym == SDLK_w) && (e.key.keysym.mod & KMOD_GUI)) { - SDL_FlushEvent(SDL_QUIT); + if ((e.key.key == SDLK_W) && (e.key.mod & SDL_KMOD_GUI)) { + SDL_FlushEvent(SDL_EVENT_QUIT); } #endif lua_pushstring(L, "keyreleased"); lua_pushstring(L, get_key_name(&e, buf)); return 2; - case SDL_TEXTINPUT: + case SDL_EVENT_TEXT_INPUT: lua_pushstring(L, "textinput"); lua_pushstring(L, e.text.text); return 2; - case SDL_TEXTEDITING: + case SDL_EVENT_TEXT_EDITING: lua_pushstring(L, "textediting"); lua_pushstring(L, e.edit.text); lua_pushinteger(L, e.edit.start); lua_pushinteger(L, e.edit.length); return 4; -#if SDL_VERSION_ATLEAST(2, 0, 22) - case SDL_TEXTEDITING_EXT: - lua_pushstring(L, "textediting"); - lua_pushstring(L, e.editExt.text); - lua_pushinteger(L, e.editExt.start); - lua_pushinteger(L, e.editExt.length); - SDL_free(e.editExt.text); - return 4; -#endif - - case SDL_MOUSEBUTTONDOWN: - if (e.button.button == 1) { SDL_CaptureMouse(1); } - lua_pushstring(L, "mousepressed"); - lua_pushstring(L, button_name(e.button.button)); - lua_pushinteger(L, e.button.x * window_renderer.scale_x); - lua_pushinteger(L, e.button.y * window_renderer.scale_y); - lua_pushinteger(L, e.button.clicks); - return 5; - - case SDL_MOUSEBUTTONUP: - if (e.button.button == 1) { SDL_CaptureMouse(0); } - lua_pushstring(L, "mousereleased"); - lua_pushstring(L, button_name(e.button.button)); - lua_pushinteger(L, e.button.x * window_renderer.scale_x); - lua_pushinteger(L, e.button.y * window_renderer.scale_y); - return 4; - - case SDL_MOUSEMOTION: - SDL_PumpEvents(); - while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION) > 0) { - e.motion.x = event_plus.motion.x; - e.motion.y = event_plus.motion.y; - e.motion.xrel += event_plus.motion.xrel; - e.motion.yrel += event_plus.motion.yrel; + case SDL_EVENT_MOUSE_BUTTON_DOWN: + { + if (e.button.button == 1) { SDL_CaptureMouse(1); } + lua_pushstring(L, "mousepressed"); + lua_pushstring(L, button_name(e.button.button)); + lua_pushinteger(L, e.button.x * window_renderer.scale_x); + lua_pushinteger(L, e.button.y * window_renderer.scale_y); + lua_pushinteger(L, e.button.clicks); + return 5; } - lua_pushstring(L, "mousemoved"); - lua_pushinteger(L, e.motion.x * window_renderer.scale_x); - lua_pushinteger(L, e.motion.y * window_renderer.scale_y); - lua_pushinteger(L, e.motion.xrel * window_renderer.scale_x); - lua_pushinteger(L, e.motion.yrel * window_renderer.scale_y); - return 5; - case SDL_MOUSEWHEEL: + case SDL_EVENT_MOUSE_BUTTON_UP: + { + if (e.button.button == 1) { SDL_CaptureMouse(0); } + lua_pushstring(L, "mousereleased"); + lua_pushstring(L, button_name(e.button.button)); + lua_pushinteger(L, e.button.x * window_renderer.scale_x); + lua_pushinteger(L, e.button.y * window_renderer.scale_y); + return 4; + } + + case SDL_EVENT_MOUSE_MOTION: + { + SDL_PumpEvents(); + while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_EVENT_MOUSE_MOTION, SDL_EVENT_MOUSE_MOTION) > 0) { + e.motion.x = event_plus.motion.x; + e.motion.y = event_plus.motion.y; + e.motion.xrel += event_plus.motion.xrel; + e.motion.yrel += event_plus.motion.yrel; + } + lua_pushstring(L, "mousemoved"); + lua_pushinteger(L, e.motion.x * window_renderer.scale_x); + lua_pushinteger(L, e.motion.y * window_renderer.scale_y); + lua_pushinteger(L, e.motion.xrel * window_renderer.scale_x); + lua_pushinteger(L, e.motion.yrel * window_renderer.scale_y); + return 5; + } + + case SDL_EVENT_MOUSE_WHEEL: lua_pushstring(L, "mousewheel"); -#if SDL_VERSION_ATLEAST(2, 0, 18) - lua_pushnumber(L, e.wheel.preciseY); + lua_pushnumber(L, e.wheel.y); // Use -x to keep consistency with vertical scrolling values (e.g. shift+scroll) - lua_pushnumber(L, -e.wheel.preciseX); -#else - lua_pushinteger(L, e.wheel.y); - lua_pushinteger(L, -e.wheel.x); -#endif + lua_pushnumber(L, -e.wheel.x); return 3; - case SDL_FINGERDOWN: - SDL_GetWindowSize(window_renderer.window, &w, &h); + case SDL_EVENT_FINGER_DOWN: + { + SDL_GetWindowSize(window_renderer.window, &w, &h); - lua_pushstring(L, "touchpressed"); - lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); - lua_pushinteger(L, e.tfinger.fingerId); - return 4; - - case SDL_FINGERUP: - SDL_GetWindowSize(window_renderer.window, &w, &h); - - lua_pushstring(L, "touchreleased"); - lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); - lua_pushinteger(L, e.tfinger.fingerId); - return 4; - - case SDL_FINGERMOTION: - SDL_PumpEvents(); - while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_FINGERMOTION, SDL_FINGERMOTION) > 0) { - e.tfinger.x = event_plus.tfinger.x; - e.tfinger.y = event_plus.tfinger.y; - e.tfinger.dx += event_plus.tfinger.dx; - e.tfinger.dy += event_plus.tfinger.dy; + lua_pushstring(L, "touchpressed"); + lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); + lua_pushinteger(L, e.tfinger.fingerID); + return 4; } - SDL_GetWindowSize(window_renderer.window, &w, &h); - lua_pushstring(L, "touchmoved"); - lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.dx * w)); - lua_pushinteger(L, (lua_Integer)(e.tfinger.dy * h)); - lua_pushinteger(L, e.tfinger.fingerId); - return 6; + case SDL_EVENT_FINGER_UP: + { + SDL_GetWindowSize(window_renderer.window, &w, &h); + + lua_pushstring(L, "touchreleased"); + lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); + lua_pushinteger(L, e.tfinger.fingerID); + return 4; + } + + case SDL_EVENT_FINGER_MOTION: + { + SDL_PumpEvents(); + while (SDL_PeepEvents(&event_plus, 1, SDL_GETEVENT, SDL_EVENT_FINGER_MOTION, SDL_EVENT_FINGER_MOTION) > 0) { + e.tfinger.x = event_plus.tfinger.x; + e.tfinger.y = event_plus.tfinger.y; + e.tfinger.dx += event_plus.tfinger.dx; + e.tfinger.dy += event_plus.tfinger.dy; + } + SDL_GetWindowSize(window_renderer.window, &w, &h); + + lua_pushstring(L, "touchmoved"); + lua_pushinteger(L, (lua_Integer)(e.tfinger.x * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.y * h)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.dx * w)); + lua_pushinteger(L, (lua_Integer)(e.tfinger.dy * h)); + lua_pushinteger(L, e.tfinger.fingerID); + return 6; + } + case SDL_EVENT_WILL_ENTER_FOREGROUND: + case SDL_EVENT_DID_ENTER_FOREGROUND: + { + #ifdef LITE_USE_SDL_RENDERER + rencache_invalidate(); + #else + SDL_UpdateWindowSurface(window_renderer.window); + #endif + lua_pushstring(L, e.type == SDL_EVENT_WILL_ENTER_FOREGROUND ? "enteringforeground" : "enteredforeground"); + return 1; + } + case SDL_EVENT_WILL_ENTER_BACKGROUND: + lua_pushstring(L, "enteringbackground"); + return 1; + case SDL_EVENT_DID_ENTER_BACKGROUND: + lua_pushstring(L, "enteredbackground"); + return 1; default: goto top; @@ -381,7 +404,7 @@ static int f_wait_event(lua_State *L) { } -static SDL_Cursor* cursor_cache[SDL_SYSTEM_CURSOR_HAND + 1]; +static SDL_Cursor* cursor_cache[SDL_SYSTEM_CURSOR_POINTER + 1]; static const char *cursor_opts[] = { "arrow", @@ -393,11 +416,11 @@ static const char *cursor_opts[] = { }; static const int cursor_enums[] = { - SDL_SYSTEM_CURSOR_ARROW, - SDL_SYSTEM_CURSOR_IBEAM, - SDL_SYSTEM_CURSOR_SIZEWE, - SDL_SYSTEM_CURSOR_SIZENS, - SDL_SYSTEM_CURSOR_HAND + SDL_SYSTEM_CURSOR_DEFAULT, + SDL_SYSTEM_CURSOR_TEXT, + SDL_SYSTEM_CURSOR_EW_RESIZE, + SDL_SYSTEM_CURSOR_NS_RESIZE, + SDL_SYSTEM_CURSOR_POINTER }; static int f_set_cursor(lua_State *L) { @@ -425,8 +448,7 @@ enum { WIN_NORMAL, WIN_MINIMIZED, WIN_MAXIMIZED, WIN_FULLSCREEN }; static int f_set_window_mode(lua_State *L) { int n = luaL_checkoption(L, 1, "normal", window_opts); - SDL_SetWindowFullscreen(window_renderer.window, - n == WIN_FULLSCREEN ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_SetWindowFullscreen(window_renderer.window, n == WIN_FULLSCREEN); if (n == WIN_NORMAL) { SDL_RestoreWindow(window_renderer.window); } if (n == WIN_MAXIMIZED) { SDL_MaximizeWindow(window_renderer.window); } if (n == WIN_MINIMIZED) { SDL_MinimizeWindow(window_renderer.window); } @@ -435,21 +457,20 @@ static int f_set_window_mode(lua_State *L) { static int f_set_window_bordered(lua_State *L) { - int bordered = lua_toboolean(L, 1); - SDL_SetWindowBordered(window_renderer.window, bordered); + SDL_SetWindowBordered(window_renderer.window, lua_toboolean(L, 1)); return 0; } static int f_set_window_hit_test(lua_State *L) { - if (lua_gettop(L) == 0) { + if (lua_isnoneornil(L, 1)) { SDL_SetWindowHitTest(window_renderer.window, NULL, NULL); return 0; } window_hit_info->title_height = luaL_checknumber(L, 1); window_hit_info->controls_width = luaL_checknumber(L, 2); window_hit_info->resize_border = luaL_checknumber(L, 3); - SDL_SetWindowHitTest(window_renderer.window, hit_test, window_hit_info); + SDL_SetWindowHitTest(window_renderer.window, &hit_test, window_hit_info); return 0; } @@ -487,7 +508,7 @@ static int f_window_has_focus(lua_State *L) { static int f_get_window_mode(lua_State *L) { unsigned flags = SDL_GetWindowFlags(window_renderer.window); - if (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { + if (flags & SDL_WINDOW_FULLSCREEN) { lua_pushstring(L, "fullscreen"); } else if (flags & SDL_WINDOW_MINIMIZED) { lua_pushstring(L, "minimized"); @@ -505,26 +526,17 @@ static int f_set_text_input_rect(lua_State *L) { rect.y = luaL_checknumber(L, 2); rect.w = luaL_checknumber(L, 3); rect.h = luaL_checknumber(L, 4); - SDL_SetTextInputRect(&rect); + SDL_SetTextInputArea(window_renderer.window, &rect, 0); return 0; } static int f_clear_ime(lua_State *L) { -#if SDL_VERSION_ATLEAST(2, 0, 22) - SDL_ClearComposition(); -#endif + SDL_ClearComposition(window_renderer.window); return 0; } static int f_raise_window(lua_State *L) { - /* - SDL_RaiseWindow should be enough but on some window managers like the - one used on Gnome the window needs to first have input focus in order - to allow the window to be focused. Also on wayland the raise window event - may not always be obeyed. - */ - SDL_SetWindowInputFocus(window_renderer.window); SDL_RaiseWindow(window_renderer.window); return 0; } @@ -545,31 +557,11 @@ static int f_show_fatal_error(lua_State *L) { // removes an empty directory static int f_rmdir(lua_State *L) { - const char *path = luaL_checkstring(L, 1); - -#ifdef _WIN32 - LPWSTR wpath = utfconv_utf8towc(path); - int deleted = RemoveDirectoryW(wpath); - free(wpath); - if (deleted > 0) { - lua_pushboolean(L, 1); - } else { - lua_pushboolean(L, 0); - push_win32_error(L, GetLastError()); + lua_pushboolean(L, SDL_RemovePath(luaL_checkstring(L, 1))); + if (!lua_toboolean(L, -1)) { + lua_pushstring(L, SDL_GetError()); return 2; } -#else - int deleted = remove(path); - if(deleted < 0) { - lua_pushboolean(L, 0); - lua_pushstring(L, strerror(errno)); - - return 2; - } else { - lua_pushboolean(L, 1); - } -#endif - return 1; } @@ -590,80 +582,24 @@ static int f_chdir(lua_State *L) { static int f_list_dir(lua_State *L) { + int count = 0; const char *path = luaL_checkstring(L, 1); - -#ifdef _WIN32 - lua_settop(L, 1); - if (path[0] == 0 || strchr("\\/", path[strlen(path) - 1]) != NULL) - lua_pushstring(L, "*"); - else - lua_pushstring(L, "/*"); - - lua_concat(L, 2); - path = lua_tostring(L, -1); - - LPWSTR wpath = utfconv_utf8towc(path); - if (wpath == NULL) { - lua_pushnil(L); - lua_pushstring(L, UTFCONV_ERROR_INVALID_CONVERSION); - return 2; - } - - WIN32_FIND_DATAW fd; - HANDLE find_handle = FindFirstFileExW(wpath, FindExInfoBasic, &fd, FindExSearchNameMatch, NULL, 0); - free(wpath); - if (find_handle == INVALID_HANDLE_VALUE) { - lua_pushnil(L); - push_win32_error(L, GetLastError()); - return 2; - } - - char mbpath[MAX_PATH * 4]; // utf-8 spans 4 bytes at most - int len, i = 1; - lua_newtable(L); - - do - { - if (wcscmp(fd.cFileName, L".") == 0) { continue; } - if (wcscmp(fd.cFileName, L"..") == 0) { continue; } - - len = WideCharToMultiByte(CP_UTF8, 0, fd.cFileName, -1, mbpath, MAX_PATH * 4, NULL, NULL); - if (len == 0) { break; } - lua_pushlstring(L, mbpath, len - 1); // len includes \0 - lua_rawseti(L, -2, i++); - } while (FindNextFileW(find_handle, &fd)); - - if (GetLastError() != ERROR_NO_MORE_FILES) { - lua_pushnil(L); - push_win32_error(L, GetLastError()); - FindClose(find_handle); - return 2; - } - - FindClose(find_handle); - return 1; -#else - DIR *dir = opendir(path); + char **dir = SDL_GlobDirectory(path, NULL, 0, &count); if (!dir) { lua_pushnil(L); - lua_pushstring(L, strerror(errno)); + lua_pushstring(L, SDL_GetError()); return 2; } - lua_newtable(L); - int i = 1; - struct dirent *entry; - while ( (entry = readdir(dir)) ) { - if (strcmp(entry->d_name, "." ) == 0) { continue; } - if (strcmp(entry->d_name, "..") == 0) { continue; } - lua_pushstring(L, entry->d_name); - lua_rawseti(L, -2, i); - i++; + lua_createtable(L, count, 0); + for (int ti = 1, i = 0; i < count; i++) { + if (strcmp(dir[i], ".") == 0) continue; + if (strcmp(dir[i], "..") == 0) continue; + lua_pushstring(L, dir[i]); + lua_rawseti(L, -2, ti++); } - - closedir(dir); + SDL_free(dir); return 1; -#endif } diff --git a/src/main.c b/src/main.c index b0f42ad..055dffb 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,7 @@ #include #include -#include +#include +#include #include "api/api.h" #include "rencache.h" #include "renderer.h" @@ -11,7 +12,7 @@ #include #elif defined(__linux__) #include -#elif defined(__APPLE__) +#elif defined(SDL_PLATFORM_APPLE) #include #elif defined(__FreeBSD__) #include @@ -39,7 +40,7 @@ static void get_exe_filename(char *buf, int sz) { ssize_t len = readlink(path, buf, sz - 1); if (len > 0) buf[len] = '\0'; -#elif __APPLE__ +#elif SDL_PLATFORM_APPLE /* use realpath to resolve a symlink if the process was launched from one. ** This happens when Homebrew installs a cack and creates a symlink in ** /usr/loca/bin for launching the executable from the command line. */ @@ -61,15 +62,10 @@ static void init_window_icon(void) { #if !defined(_WIN32) && !defined(__APPLE__) #include "../resources/icons/icon.inl" (void) icon_rgba_len; /* unused */ - SDL_Surface *surf = SDL_CreateRGBSurfaceFrom( - icon_rgba, 64, 64, - 32, 64 * 4, - 0x000000ff, - 0x0000ff00, - 0x00ff0000, - 0xff000000); + SDL_PixelFormat format = SDL_GetPixelFormatForMasks(32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + SDL_Surface *surf = SDL_CreateSurfaceFrom(64, 64, format, icon_rgba, 64 * 4); SDL_SetWindowIcon(window, surf); - SDL_FreeSurface(surf); + SDL_DestroySurface(surf); #endif } @@ -83,7 +79,7 @@ static void init_window_icon(void) { #define LITE_NONPATHSEP_PATTERN "[^/]+" #endif -#ifdef __APPLE__ +#ifdef SDL_PLATFORM_APPLE void enable_momentum_scroll(); #ifdef MACOS_USE_BUNDLE void set_macos_bundle_resources(lua_State *L); @@ -108,7 +104,7 @@ void set_macos_bundle_resources(lua_State *L); #define ARCH_PLATFORM "linux" #elif __FreeBSD__ #define ARCH_PLATFORM "freebsd" - #elif __APPLE__ + #elif SDL_PLATFORM_APPLE #define ARCH_PLATFORM "darwin" #endif @@ -124,53 +120,38 @@ int main(int argc, char **argv) { signal(SIGPIPE, SIG_IGN); #endif - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { - fprintf(stderr, "Error initializing SDL: %s\n", SDL_GetError()); + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) { + fprintf(stderr, "Error initializing SDL: %s", SDL_GetError()); exit(1); } SDL_EnableScreenSaver(); - SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, true); atexit(SDL_Quit); -#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR /* Available since 2.0.8 */ SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); -#endif -#if SDL_VERSION_ATLEAST(2, 0, 5) SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); -#endif -#if SDL_VERSION_ATLEAST(2, 0, 18) - SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); -#endif -#if SDL_VERSION_ATLEAST(2, 0, 22) - SDL_SetHint(SDL_HINT_IME_SUPPORT_EXTENDED_TEXT, "1"); -#endif + SDL_SetHint(SDL_HINT_IME_IMPLEMENTED_UI, "1"); + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); -#if SDL_VERSION_ATLEAST(2, 0, 8) /* This hint tells SDL to respect borderless window as a normal window. ** For example, the window will sit right on top of the taskbar instead ** of obscuring it. */ SDL_SetHint("SDL_BORDERLESS_WINDOWED_STYLE", "1"); -#endif -#if SDL_VERSION_ATLEAST(2, 0, 12) /* This hint tells SDL to allow the user to resize a borderless windoow. ** It also enables aero-snap on Windows apparently. */ SDL_SetHint("SDL_BORDERLESS_RESIZABLE_STYLE", "1"); -#endif -#if SDL_VERSION_ATLEAST(2, 0, 9) - SDL_SetHint("SDL_MOUSE_DOUBLE_CLICK_RADIUS", "4"); -#endif - - SDL_DisplayMode dm; - SDL_GetCurrentDisplayMode(0, &dm); + SDL_SetHint(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, "4"); + const SDL_DisplayMode* dm = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); window = SDL_CreateWindow( - "", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w * 0.8, dm.h * 0.8, - SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); - init_window_icon(); + "", (dm ? dm->w : 2) * 0.8, (dm ? dm->h : 2) * 0.8, + SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_HIDDEN); if (!window) { fprintf(stderr, "Error creating lite-xl window: %s", SDL_GetError()); exit(1); } + init_window_icon(); + if (ren_init(window) != 0) { fprintf(stderr, "Error initializing renderer: %s\n", SDL_GetError()); exit(1); @@ -206,12 +187,14 @@ init_lua: } lua_setglobal(L, "EXEFILE"); -#ifdef __APPLE__ +#ifdef SDL_PLATFORM_APPLE enable_momentum_scroll(); #ifdef MACOS_USE_BUNDLE set_macos_bundle_resources(L); #endif #endif + SDL_SetEventEnabled(SDL_EVENT_TEXT_INPUT, true); + SDL_SetEventEnabled(SDL_EVENT_TEXT_EDITING, true); const char *init_lite_code = \ "local core\n" diff --git a/src/meson.build b/src/meson.build index 05a3feb..459ac33 100644 --- a/src/meson.build +++ b/src/meson.build @@ -59,67 +59,9 @@ freetype_dep = dependency('freetype2', fallback: ['freetype2', 'freetype_dep'], ) -sdl_options = ['default_library=static'] +sdl_dep = dependency('sdl3', static: true) -# we explicitly need these -sdl_options += 'use_loadso=enabled' -sdl_options += 'prefer_dlopen=true' -sdl_options += 'use_video=enabled' -sdl_options += 'use_atomic=enabled' -sdl_options += 'use_threads=enabled' -sdl_options += 'use_timers=enabled' -# investigate if this is truly needed -# Do not remove before https://github.com/libsdl-org/SDL/issues/5413 is released -sdl_options += 'use_events=enabled' - -if host_machine.system() == 'darwin' or host_machine.system() == 'windows' - sdl_options += 'use_video_x11=disabled' - sdl_options += 'use_video_wayland=disabled' -else - sdl_options += 'use_render=enabled' - sdl_options += 'use_video_x11=auto' - sdl_options += 'use_video_wayland=auto' -endif - -# we leave this up to what the host system has except on windows -if host_machine.system() != 'windows' - sdl_options += 'use_video_opengl=auto' - sdl_options += 'use_video_openglesv2=auto' -else - sdl_options += 'use_video_opengl=disabled' - sdl_options += 'use_video_openglesv2=disabled' -endif - -# we don't need these -sdl_options += 'test=false' -sdl_options += 'use_sensor=disabled' -sdl_options += 'use_haptic=disabled' -sdl_options += 'use_hidapi=disabled' -sdl_options += 'use_audio=disabled' -sdl_options += 'use_cpuinfo=disabled' -sdl_options += 'use_joystick=disabled' -sdl_options += 'use_joystick_xinput=disabled' -sdl_options += 'use_video_vulkan=disabled' -sdl_options += 'use_video_offscreen=disabled' -sdl_options += 'use_power=disabled' -sdl_options += 'system_iconv=disabled' - -sdl_dep = dependency('sdl2', fallback: ['sdl2', 'sdl2_dep'], - default_options: default_fallback_options + sdl_options -) - -if host_machine.system() == 'windows' - if sdl_dep.type_name() == 'internal' - sdlmain_dep = dependency('sdl2main', fallback: ['sdl2main_dep']) - else - sdlmain_dep = cc.find_library('SDL2main') - endif -else - sdlmain_dep = dependency('', required: false) - assert(not sdlmain_dep.found(), 'checking if fake dependency has been found') -endif - -lite_deps = [lua_dep, sdl_dep, sdlmain_dep, freetype_dep, pcre2_dep, libm, libdl] +lite_deps = [lua_dep, sdl_dep, freetype_dep, pcre2_dep, libm, libdl] lite_sources += 'api/dirmonitor.c' # dirmonitor backend diff --git a/src/rencache.c b/src/rencache.c index c51e4ed..6bdf0b9 100644 --- a/src/rencache.c +++ b/src/rencache.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/src/renderer.c b/src/renderer.c index f141e6c..6a124f0 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -214,7 +214,7 @@ static unsigned int font_get_glyph_id(RenFont *font, unsigned int codepoint) { #define FONT_BITMAP_COUNT(F) ((F)->antialiasing == FONT_ANTIALIASING_SUBPIXEL ? SUBPIXEL_BITMAPS_CACHED : 1) #define SLOT_BITMAP_TYPE(B) ((B).pixel_mode == FT_PIXEL_MODE_LCD ? EGlyphFormatSubpixel : EGlyphFormatGrayscale) -static inline SDL_PixelFormatEnum glyphformat_to_pixelformat(ERenGlyphFormat format, int *depth) { +static inline SDL_PixelFormat glyphformat_to_pixelformat(ERenGlyphFormat format, int *depth) { switch (format) { case EGlyphFormatSubpixel: *depth = 24; return SDL_PIXELFORMAT_RGB24; case EGlyphFormatGrayscale: *depth = 8; return SDL_PIXELFORMAT_INDEX8; @@ -245,12 +245,14 @@ static SDL_Surface *font_allocate_glyph_surface(RenFont *font, FT_GlyphSlot slot } metric->atlas_idx = atlas_idx; GlyphAtlas *atlas = &font->glyphs.atlas[glyph_format][atlas_idx]; + SDL_PropertiesID userdata; // find the surface with the minimum height that can fit the glyph (limited to last 100 surfaces) int surface_idx = -1, max_surface_idx = (int) atlas->nsurface - 100, min_waste = INT_MAX; for (int i = atlas->nsurface - 1; i >= 0 && i > max_surface_idx; i--) { - assert(atlas->surfaces[i]->userdata); - GlyphMetric *m = (GlyphMetric *) atlas->surfaces[i]->userdata; + userdata = SDL_GetSurfaceProperties(atlas->surfaces[i]); + assert(SDL_HasProperty(userdata, "metric")); + GlyphMetric *m = (GlyphMetric *) SDL_GetPointerProperty(userdata, "metric", NULL); int new_min_waste = (int) atlas->surfaces[i]->h - (int) m->y1; if (new_min_waste >= metric->y1 && new_min_waste < min_waste) { surface_idx = i; @@ -262,19 +264,22 @@ static SDL_Surface *font_allocate_glyph_surface(RenFont *font, FT_GlyphSlot slot int h = FONT_HEIGHT_OVERFLOW_PX + (double) font->face->size->metrics.height / 64.0f; if (h <= FONT_HEIGHT_OVERFLOW_PX) h += slot->bitmap.rows; if (h <= FONT_HEIGHT_OVERFLOW_PX) h += font->size; - int depth = 0; SDL_PixelFormatEnum format = glyphformat_to_pixelformat(glyph_format, &depth); + int depth = 0; + SDL_PixelFormat format = glyphformat_to_pixelformat(glyph_format, &depth); atlas->surfaces = check_alloc(realloc(atlas->surfaces, sizeof(SDL_Surface *) * (atlas->nsurface + 1))); - atlas->surfaces[atlas->nsurface] = check_alloc(SDL_CreateRGBSurfaceWithFormat(0, atlas->width, GLYPHS_PER_ATLAS * h, depth, format)); - atlas->surfaces[atlas->nsurface]->userdata = NULL; + atlas->surfaces[atlas->nsurface] = check_alloc(SDL_CreateSurface(atlas->width, GLYPHS_PER_ATLAS * h, format)); + userdata = SDL_GetSurfaceProperties(atlas->surfaces[atlas->nsurface]); + SDL_SetPointerProperty(userdata, "metric", NULL); surface_idx = atlas->nsurface++; font->glyphs.bytesize += (sizeof(SDL_Surface *) + sizeof(SDL_Surface) + atlas->width * GLYPHS_PER_ATLAS * h * glyph_format); } metric->surface_idx = surface_idx; - if (atlas->surfaces[surface_idx]->userdata) { - GlyphMetric *last_metric = (GlyphMetric *) atlas->surfaces[surface_idx]->userdata; + userdata = SDL_GetSurfaceProperties(atlas->surfaces[surface_idx]); + if (SDL_HasProperty(userdata, "metric")) { + GlyphMetric *last_metric = (GlyphMetric *) SDL_GetPointerProperty(userdata, "metric", NULL); metric->y0 = last_metric->y1; metric->y1 += last_metric->y1; } - atlas->surfaces[surface_idx]->userdata = (void *) metric; + SDL_SetPointerProperty(userdata, "metric", (void *) metric); return atlas->surfaces[surface_idx]; } @@ -387,7 +392,7 @@ static void font_clear_glyph_cache(RenFont* font) { for (int atlas_idx = 0; atlas_idx < font->glyphs.natlas[glyph_format_idx]; atlas_idx++) { GlyphAtlas *atlas = &font->glyphs.atlas[glyph_format_idx][atlas_idx]; for (int surface_idx = 0; surface_idx < atlas->nsurface; surface_idx++) { - SDL_FreeSurface(atlas->surfaces[surface_idx]); + SDL_DestroySurface(atlas->surfaces[surface_idx]); } free(atlas->surfaces); } @@ -408,11 +413,11 @@ static void font_clear_glyph_cache(RenFont* font) { // based on https://github.com/libsdl-org/SDL_ttf/blob/2a094959055fba09f7deed6e1ffeb986188982ae/SDL_ttf.c#L1735 static unsigned long font_file_read(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count) { uint64_t amount; - SDL_RWops *file = (SDL_RWops *) stream->descriptor.pointer; - SDL_RWseek(file, (int) offset, RW_SEEK_SET); + SDL_IOStream *file = (SDL_IOStream *) stream->descriptor.pointer; + SDL_SeekIO(file, (int) offset, SDL_IO_SEEK_SET); if (count == 0) return 0; - amount = SDL_RWread(file, buffer, sizeof(char), count); + amount = SDL_ReadIO(file, buffer, sizeof(char) * count); if (amount <= 0) return 0; return (unsigned long) amount; @@ -420,7 +425,7 @@ static unsigned long font_file_read(FT_Stream stream, unsigned long offset, unsi static void font_file_close(FT_Stream stream) { if (stream && stream->descriptor.pointer) - SDL_RWclose((SDL_RWops *) stream->descriptor.pointer); + SDL_CloseIO((SDL_IOStream *) stream->descriptor.pointer); free(stream); } @@ -453,13 +458,11 @@ static int font_set_face_metrics(RenFont *font, FT_Face face) { RenFont* ren_font_load(RenWindow *window_renderer, const char* path, float size, ERenFontAntialiasing antialiasing, ERenFontHinting hinting, unsigned char style) { FT_Error err = FT_Err_Ok; - SDL_RWops *file = NULL; RenFont *font = NULL; + SDL_IOStream *file = NULL; RenFont *font = NULL; FT_Face face = NULL; FT_Stream stream = NULL; - SDL_ClearError(); - - file = SDL_RWFromFile(path, "rb"); - if (!file) return NULL; // error set by SDL_RWFromFile + file = SDL_IOFromFile(path, "rb"); + if (!file) return NULL; // error set by SDL_IOFromFile int len = strlen(path); font = check_alloc(calloc(1, sizeof(RenFont) + len + 1)); @@ -479,7 +482,7 @@ RenFont* ren_font_load(RenWindow *window_renderer, const char* path, float size, stream->close = &font_file_close; stream->descriptor.pointer = file; stream->pos = 0; - stream->size = (unsigned long) SDL_RWsize(file); + stream->size = (unsigned long) SDL_GetIOSize(file); if ((err = FT_Open_Face(library, &(FT_Open_Args) { .flags = FT_OPEN_STREAM, .stream = stream }, 0, &face)) != 0) goto failure; @@ -488,7 +491,7 @@ RenFont* ren_font_load(RenWindow *window_renderer, const char* path, float size, return font; stream_failure: - if (file) SDL_RWclose(file); + if (file) SDL_CloseIO(file); failure: if (err != FT_Err_Ok) SDL_SetError("%s", get_ft_error(err)); if (face) FT_Done_Face(face); @@ -596,7 +599,7 @@ void ren_font_dump(RenFont *font) { double ren_draw_text(RenSurface *rs, RenFont **fonts, const char *text, size_t len, float x, int y, RenColor color) { SDL_Surface *surface = rs->surface; SDL_Rect clip; - SDL_GetClipRect(surface, &clip); + SDL_GetSurfaceClipRect(surface, &clip); const int surface_scale = rs->scale; double pen_x = x * surface_scale; @@ -637,12 +640,20 @@ double ren_draw_text(RenSurface *rs, RenFont **fonts, const char *text, size_t l start_x += offset; glyph_start += offset; } - uint32_t* destination_pixel = (uint32_t*)&(destination_pixels[surface->pitch * target_y + start_x * surface->format->BytesPerPixel ]); - uint8_t* source_pixel = &source_pixels[line * font_surface->pitch + glyph_start * font_surface->format->BytesPerPixel]; + + const SDL_PixelFormatDetails* surface_format = SDL_GetPixelFormatDetails(surface->format); + const SDL_PixelFormatDetails* font_surface_format = SDL_GetPixelFormatDetails(font_surface->format); + + uint32_t* destination_pixel = (uint32_t*)&(destination_pixels[surface->pitch * target_y + start_x * surface_format->bytes_per_pixel]); + uint8_t* source_pixel = &source_pixels[line * font_surface->pitch + glyph_start * font_surface_format->bytes_per_pixel]; for (int x = glyph_start; x < glyph_end; ++x) { uint32_t destination_color = *destination_pixel; // the standard way of doing this would be SDL_GetRGBA, but that introduces a performance regression. needs to be investigated - SDL_Color dst = { (destination_color & surface->format->Rmask) >> surface->format->Rshift, (destination_color & surface->format->Gmask) >> surface->format->Gshift, (destination_color & surface->format->Bmask) >> surface->format->Bshift, (destination_color & surface->format->Amask) >> surface->format->Ashift }; + SDL_Color dst = { + (destination_color & surface_format->Rmask) >> surface_format->Rshift, + (destination_color & surface_format->Gmask) >> surface_format->Gshift, + (destination_color & surface_format->Bmask) >> surface_format->Bshift, + (destination_color & surface_format->Amask) >> surface_format->Ashift}; SDL_Color src; if (metric->format == EGlyphFormatSubpixel) { @@ -660,7 +671,7 @@ double ren_draw_text(RenSurface *rs, RenFont **fonts, const char *text, size_t l g = (color.g * src.g * color.a + dst.g * (65025 - src.g * color.a) + 32767) / 65025; b = (color.b * src.b * color.a + dst.b * (65025 - src.b * color.a) + 32767) / 65025; // the standard way of doing this would be SDL_GetRGBA, but that introduces a performance regression. needs to be investigated - *destination_pixel++ = (unsigned int) dst.a << surface->format->Ashift | r << surface->format->Rshift | g << surface->format->Gshift | b << surface->format->Bshift; + *destination_pixel++ = (unsigned int) dst.a << surface_format->Ashift | r << surface_format->Rshift | g << surface_format->Gshift | b << surface_format->Bshift; } } } @@ -704,25 +715,25 @@ void ren_draw_rect(RenSurface *rs, RenRect rect, RenColor color) { rect.height * surface_scale }; if (color.a == 0xff) { - uint32_t translated = SDL_MapRGB(surface->format, color.r, color.g, color.b); - SDL_FillRect(surface, &dest_rect, translated); + uint32_t translated = SDL_MapSurfaceRGB(surface, color.r, color.g, color.b); + SDL_FillSurfaceRect(surface, &dest_rect, translated); } else { // Seems like SDL doesn't handle clipping as we expect when using // scaled blitting, so we "clip" manually. SDL_Rect clip; - SDL_GetClipRect(surface, &clip); - if (!SDL_IntersectRect(&clip, &dest_rect, &dest_rect)) return; + SDL_GetSurfaceClipRect(surface, &clip); + if (!SDL_GetRectIntersection(&clip, &dest_rect, &dest_rect)) return; uint32_t *pixel = (uint32_t *)draw_rect_surface->pixels; - *pixel = SDL_MapRGBA(draw_rect_surface->format, color.r, color.g, color.b, color.a); - SDL_BlitScaled(draw_rect_surface, NULL, surface, &dest_rect); + *pixel = SDL_MapSurfaceRGBA(draw_rect_surface, color.r, color.g, color.b, color.a); + SDL_BlitSurfaceScaled(draw_rect_surface, NULL, surface, &dest_rect, SDL_SCALEMODE_LINEAR); } } /*************** Window Management ****************/ void ren_free_window_resources(RenWindow *window_renderer) { renwin_free(window_renderer); - SDL_FreeSurface(draw_rect_surface); + SDL_DestroySurface(draw_rect_surface); free(window_renderer->command_buf); window_renderer->command_buf = NULL; window_renderer->command_buf_size = 0; @@ -734,8 +745,8 @@ int ren_init(SDL_Window *win) { SDL_ClearError(); assert(win); - draw_rect_surface = SDL_CreateRGBSurface(0, 1, 1, 32, - 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); + draw_rect_surface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_RGBA32); + if (!draw_rect_surface) return -1; // error set by SDL_CreateRGBSurface diff --git a/src/renderer.h b/src/renderer.h index 502bf3c..0166161 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -1,7 +1,7 @@ #ifndef RENDERER_H #define RENDERER_H -#include +#include #include #include diff --git a/src/renwindow.c b/src/renwindow.c index 9833090..eac381e 100644 --- a/src/renwindow.c +++ b/src/renwindow.c @@ -1,3 +1,4 @@ +#include #include #include #include "renwindow.h" @@ -6,7 +7,7 @@ static int query_surface_scale(RenWindow *ren) { int w_pixels, h_pixels; int w_points, h_points; - SDL_GL_GetDrawableSize(ren->window, &w_pixels, &h_pixels); + SDL_GetWindowSizeInPixels(ren->window, &w_pixels, &h_pixels); SDL_GetWindowSize(ren->window, &w_points, &h_points); /* We consider that the ratio pixel/point will always be an integer and it is the same along the x and the y axis. */ @@ -16,14 +17,14 @@ static int query_surface_scale(RenWindow *ren) { static void setup_renderer(RenWindow *ren, int w, int h) { /* Note that w and h here should always be in pixels and obtained from - a call to SDL_GL_GetDrawableSize(). */ + a call to SDL_GetWindowSizeInPixels(). */ if (!ren->renderer) { - ren->renderer = SDL_CreateRenderer(ren->window, -1, 0); + ren->renderer = SDL_CreateRenderer(ren->window, NULL); } if (ren->texture) { SDL_DestroyTexture(ren->texture); } - ren->texture = SDL_CreateTexture(ren->renderer, SDL_PIXELFORMAT_BGRA32, SDL_TEXTUREACCESS_STREAMING, w, h); + ren->texture = SDL_CreateTexture(ren->renderer, ren->rensurface.surface->format, SDL_TEXTUREACCESS_STREAMING, w, h); ren->rensurface.scale = query_surface_scale(ren); } #endif @@ -33,11 +34,12 @@ void renwin_init_surface(RenWindow *ren) { ren->scale_x = ren->scale_y = 1; #ifdef LITE_USE_SDL_RENDERER if (ren->rensurface.surface) { - SDL_FreeSurface(ren->rensurface.surface); + SDL_DestroySurface(ren->rensurface.surface); } int w, h; - SDL_GL_GetDrawableSize(ren->window, &w, &h); - ren->rensurface.surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, SDL_PIXELFORMAT_BGRA32); + SDL_GetWindowSizeInPixels(ren->window, &w, &h); + SDL_PixelFormat format = SDL_GetWindowPixelFormat(ren->window); + ren->rensurface.surface = SDL_CreateSurface(w, h, format == SDL_PIXELFORMAT_UNKNOWN ? SDL_PIXELFORMAT_BGRA32 : format); if (!ren->rensurface.surface) { fprintf(stderr, "Error creating surface: %s", SDL_GetError()); exit(1); @@ -59,14 +61,14 @@ static RenRect scaled_rect(const RenRect rect, const int scale) { void renwin_clip_to_surface(RenWindow *ren) { - SDL_SetClipRect(renwin_get_surface(ren).surface, NULL); + SDL_SetSurfaceClipRect(renwin_get_surface(ren).surface, NULL); } void renwin_set_clip_rect(RenWindow *ren, RenRect rect) { RenSurface rs = renwin_get_surface(ren); RenRect sr = scaled_rect(rect, rs.scale); - SDL_SetClipRect(rs.surface, &(SDL_Rect){.x = sr.x, .y = sr.y, .w = sr.width, .h = sr.height}); + SDL_SetSurfaceClipRect(rs.surface, &(SDL_Rect){.x = sr.x, .y = sr.y, .w = sr.width, .h = sr.height}); } @@ -86,7 +88,7 @@ RenSurface renwin_get_surface(RenWindow *ren) { void renwin_resize_surface(RenWindow *ren) { #ifdef LITE_USE_SDL_RENDERER int new_w, new_h, new_scale; - SDL_GL_GetDrawableSize(ren->window, &new_w, &new_h); + SDL_GetWindowSizeInPixels(ren->window, &new_w, &new_h); new_scale = query_surface_scale(ren); /* Note that (w, h) may differ from (new_w, new_h) on retina displays. */ if (new_scale != ren->rensurface.scale || @@ -121,10 +123,10 @@ void renwin_update_rects(RenWindow *ren, RenRect *rects, int count) { const int x = scale * r->x, y = scale * r->y; const int w = scale * r->width, h = scale * r->height; const SDL_Rect sr = {.x = x, .y = y, .w = w, .h = h}; - int32_t *pixels = ((int32_t *) ren->rensurface.surface->pixels) + x + ren->rensurface.surface->w * y; - SDL_UpdateTexture(ren->texture, &sr, pixels, ren->rensurface.surface->w * 4); + uint8_t *pixels = ((uint8_t *) ren->rensurface.surface->pixels) + y * ren->rensurface.surface->pitch + x * SDL_BYTESPERPIXEL(ren->rensurface.surface->format); + SDL_UpdateTexture(ren->texture, &sr, pixels, ren->rensurface.surface->pitch); } - SDL_RenderCopy(ren->renderer, ren->texture, NULL, NULL); + SDL_RenderTexture(ren->renderer, ren->texture, NULL, NULL); SDL_RenderPresent(ren->renderer); #else SDL_UpdateWindowSurfaceRects(ren->window, (SDL_Rect*) rects, count); @@ -135,7 +137,7 @@ void renwin_free(RenWindow *ren) { #ifdef LITE_USE_SDL_RENDERER SDL_DestroyTexture(ren->texture); SDL_DestroyRenderer(ren->renderer); - SDL_FreeSurface(ren->rensurface.surface); + SDL_DestroySurface(ren->rensurface.surface); #endif SDL_DestroyWindow(ren->window); ren->window = NULL; diff --git a/src/renwindow.h b/src/renwindow.h index 364950d..776e353 100644 --- a/src/renwindow.h +++ b/src/renwindow.h @@ -1,4 +1,4 @@ -#include +#include #include "renderer.h" struct RenWindow { diff --git a/subprojects/sdl2.wrap b/subprojects/sdl2.wrap deleted file mode 100644 index ae308d7..0000000 --- a/subprojects/sdl2.wrap +++ /dev/null @@ -1,15 +0,0 @@ -[wrap-file] -directory = SDL2-2.30.3 -source_url = https://github.com/libsdl-org/SDL/releases/download/release-2.30.3/SDL2-2.30.3.tar.gz -source_filename = SDL2-2.30.3.tar.gz -source_hash = 820440072f8f5b50188c1dae104f2ad25984de268785be40c41a099a510f0aec -patch_filename = sdl2_2.30.3-2_patch.zip -patch_url = https://wrapdb.mesonbuild.com/v2/sdl2_2.30.3-2/get_patch -patch_hash = 2c08bde67b3896db88e01481c379322625ea6c928cdb68ead91d0e3749863bc2 -source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sdl2_2.30.3-2/SDL2-2.30.3.tar.gz -wrapdb_version = 2.30.3-2 - -[provide] -sdl2 = sdl2_dep -sdl2main = sdl2main_dep -sdl2_test = sdl2_test_dep