From 59acba3264bc3d6b581f9238df6f2603c5dcd96d Mon Sep 17 00:00:00 2001 From: Slendi Date: Sun, 5 Oct 2025 05:42:05 +0300 Subject: [PATCH] Font search Signed-off-by: Slendi --- CMakeLists.txt | 4 +- flake.nix | 67 ++-- src/App.cpp | 978 ++++++++++++++++++++++++++----------------------- src/App.hpp | 18 +- src/Frame.cpp | 39 -- src/Tick.cpp | 42 +++ 6 files changed, 603 insertions(+), 545 deletions(-) delete mode 100644 src/Frame.cpp create mode 100644 src/Tick.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fb4404..3f2b0e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,7 @@ pkg_check_modules(GLES2 REQUIRED IMPORTED_TARGET glesv2) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(LIBPORTAL REQUIRED IMPORTED_TARGET libportal) pkg_check_modules(XKBCOMMON REQUIRED IMPORTED_TARGET xkbcommon) +pkg_check_modules(FONTCONFIG REQUIRED IMPORTED_TARGET fontconfig) pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols) pkg_check_modules(WLR_PROTOCOLS REQUIRED wlr-protocols) @@ -117,7 +118,7 @@ add_executable(waylight ${GEN_C_PRIVATES} ${CMAKE_CURRENT_SOURCE_DIR}/src/App.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Frame.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Tick.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp ) add_dependencies(waylight generate_protocols) @@ -134,6 +135,7 @@ target_link_libraries(waylight PRIVATE PkgConfig::GLIB PkgConfig::LIBPORTAL PkgConfig::XKBCOMMON + PkgConfig::FONTCONFIG raylib diff --git a/flake.nix b/flake.nix index 9cd5067..1295607 100644 --- a/flake.nix +++ b/flake.nix @@ -23,41 +23,44 @@ ]; in { - devShells.default = pkgs.mkShell.override { stdenv = pkgs.llvmPackages_21.libcxxStdenv; } { - packages = - with pkgs; - [ - llvmPackages_21.clang-tools - lldb - codespell - doxygen - gtest - cppcheck - inotify-tools + devShells.default = + pkgs.mkShell.override { stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.gcc15Stdenv; } + { + packages = + with pkgs; + [ + llvmPackages_21.clang-tools + lldb + codespell + doxygen + gtest + cppcheck + inotify-tools - pkg-config - wayland - wayland-protocols - wlr-protocols - wayland-scanner - libGL - libportal - glib - libxkbcommon - ] - ++ buildInputs - ++ nativeBuildInputs - ++ pkgs.lib.optionals pkgs.stdenv.isLinux ( - with pkgs; - [ - valgrind-light - ] - ); + pkg-config + wayland + wayland-protocols + wlr-protocols + wayland-scanner + libGL + libportal + glib + libxkbcommon + fontconfig + ] + ++ buildInputs + ++ nativeBuildInputs + ++ pkgs.lib.optionals pkgs.stdenv.isLinux ( + with pkgs; + [ + valgrind-light + ] + ); - env = { }; + env = { }; - shellHook = ''''; - }; + shellHook = ''''; + }; } ); } diff --git a/src/App.cpp b/src/App.cpp index acd4035..378462e 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include +#include #include #include #include @@ -25,528 +27,576 @@ #include "blur-client-protocol.h" #include "ext-background-effect-v1-client-protocol.h" -auto TypingBuffer::push_utf8(const char *s) -> void { - for (const unsigned char *p = reinterpret_cast(s); *p;) { - u32 cp = 0; - int len = 0; - if (*p < 0x80) { - cp = *p++; - len = 1; - } else if ((*p & 0xE0) == 0xC0) { - cp = *p++ & 0x1F; - len = 2; - } else if ((*p & 0xF0) == 0xE0) { - cp = *p++ & 0x0F; - len = 3; - } else { - cp = *p++ & 0x07; - len = 4; - } - for (int i = 1; i < len; i++) - cp = (cp << 6) | ((*p++) & 0x3F); - push_back(cp); - } +auto find_font_path(std::string_view path = "sans-serif:style=Regular") + -> std::optional +{ + if (!FcInit()) + return std::nullopt; + + std::string query(path); + FcPattern *pattern + = FcNameParse(reinterpret_cast(query.c_str())); + FcConfigSubstitute(nullptr, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern *font = FcFontMatch(nullptr, pattern, &result); + + std::optional final_path; + + if (font) { + FcChar8 *file; + if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) + final_path = reinterpret_cast(file); + FcPatternDestroy(font); + } + + FcPatternDestroy(pattern); + FcFini(); + return final_path; } -App::App() { - init_wayland(); - init_egl(); - init_signal(); - init_theme_portal(); +auto TypingBuffer::push_utf8(char const *s) -> void +{ + for (unsigned char const *p = reinterpret_cast(s); + *p;) { + u32 cp = 0; + int len = 0; + if (*p < 0x80) { + cp = *p++; + len = 1; + } else if ((*p & 0xE0) == 0xC0) { + cp = *p++ & 0x1F; + len = 2; + } else if ((*p & 0xF0) == 0xE0) { + cp = *p++ & 0x0F; + len = 3; + } else { + cp = *p++ & 0x07; + len = 4; + } + for (int i = 1; i < len; i++) + cp = (cp << 6) | ((*p++) & 0x3F); + push_back(cp); + } } -App::~App() { - if (m_sfd != -1) - close(m_sfd); - - destroy_layer_surface(); - - if (m_gl.edpy != EGL_NO_DISPLAY) { - if (m_gl.ectx != EGL_NO_CONTEXT) - eglDestroyContext(m_gl.edpy, m_gl.ectx); - eglTerminate(m_gl.edpy); - } - - if (m_kbd.xkb_state) - xkb_state_unref(m_kbd.xkb_state); - if (m_kbd.xkb_keymap) - xkb_keymap_unref(m_kbd.xkb_keymap); - if (m_kbd.xkb_ctx) - xkb_context_unref(m_kbd.xkb_ctx); - if (m_wayland.kbd) - wl_keyboard_destroy(m_wayland.kbd); - if (m_wayland.seat) - wl_seat_destroy(m_wayland.seat); - if (m_wayland.compositor) - wl_compositor_destroy(m_wayland.compositor); - if (m_wayland.registry) - wl_registry_destroy(m_wayland.registry); - if (m_wayland.display) - wl_display_disconnect(m_wayland.display); - - if (m_xdp.settings) - g_object_unref(m_xdp.settings); - if (m_xdp.portal) - g_object_unref(m_xdp.portal); +App::App() +{ + { + auto const path = find_font_path(); + if (path) + std::println("font path = {}", *path); + } + init_wayland(); + init_egl(); + init_signal(); + init_theme_portal(); } -auto App::run() -> void { - SetWindowSize(m_win_w, m_win_h); - while (m_running) { - pump_events(); - render_frame(); - std::this_thread::sleep_for(std::chrono::milliseconds(16)); - } +App::~App() +{ + if (m_sfd != -1) + close(m_sfd); + + destroy_layer_surface(); + + if (m_gl.edpy != EGL_NO_DISPLAY) { + if (m_gl.ectx != EGL_NO_CONTEXT) + eglDestroyContext(m_gl.edpy, m_gl.ectx); + eglTerminate(m_gl.edpy); + } + + if (m_kbd.xkb_state_v) + xkb_state_unref(m_kbd.xkb_state_v); + if (m_kbd.xkb_keymap_v) + xkb_keymap_unref(m_kbd.xkb_keymap_v); + if (m_kbd.xkb_ctx_v) + xkb_context_unref(m_kbd.xkb_ctx_v); + if (m_wayland.kbd) + wl_keyboard_destroy(m_wayland.kbd); + if (m_wayland.seat) + wl_seat_destroy(m_wayland.seat); + if (m_wayland.compositor) + wl_compositor_destroy(m_wayland.compositor); + if (m_wayland.registry) + wl_registry_destroy(m_wayland.registry); + if (m_wayland.display) + wl_display_disconnect(m_wayland.display); + + if (m_xdp.settings) + g_object_unref(m_xdp.settings); + if (m_xdp.portal) + g_object_unref(m_xdp.portal); } -auto App::set_visible(bool visible) -> void { - if (visible == m_visible) - return; - - if (visible) { - create_layer_surface(); - ensure_egl_surface(); - } else { - destroy_layer_surface(); - } - - if (m_wayland.display) - wl_display_flush(m_wayland.display); +auto App::run() -> void +{ + SetWindowSize(m_win_w, m_win_h); + while (m_running) { + pump_events(); + tick(); + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + } } -auto App::init_wayland() -> void { - m_wayland.display = wl_display_connect(nullptr); - if (!m_wayland.display) { - std::fprintf(stderr, "failed to connect to Wayland display\n"); - std::exit(EXIT_FAILURE); - } +auto App::set_visible(bool visible) -> void +{ + if (visible == m_visible) + return; - static wl_keyboard_listener keyboard_listener{}; - { - auto kb_keymap = [](void *data, wl_keyboard *, u32 format, i32 fd, - u32 size) -> void { - auto *app = static_cast(data); - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { - close(fd); - return; - } - void *map = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - close(fd); - return; - } - if (app->m_kbd.xkb_keymap) - xkb_keymap_unref(app->m_kbd.xkb_keymap); - if (app->m_kbd.xkb_state) { - xkb_state_unref(app->m_kbd.xkb_state); - app->m_kbd.xkb_state = nullptr; - } - app->m_kbd.xkb_keymap = xkb_keymap_new_from_string( - app->m_kbd.xkb_ctx, static_cast(map), - XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); - app->m_kbd.xkb_state = app->m_kbd.xkb_keymap - ? xkb_state_new(app->m_kbd.xkb_keymap) - : nullptr; - munmap(map, size); - close(fd); - }; + if (visible) { + create_layer_surface(); + ensure_egl_surface(); + } else { + destroy_layer_surface(); + } - auto kb_enter = [](void *, wl_keyboard *, u32, wl_surface *, wl_array *) -> void {}; - auto kb_leave = [](void *data, wl_keyboard *, u32, wl_surface *) -> void { - static_cast(data)->m_kbd.held.clear(); - }; - - auto kb_key = [](void *data, wl_keyboard *, u32, u32, u32 key, - u32 state) -> void { - auto *app = static_cast(data); - if (!app->m_kbd.xkb_state) - return; - - xkb_keycode_t kc = key + 8; - - if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - app->m_kbd.held.insert(key); - - xkb_state_update_key(app->m_kbd.xkb_state, kc, XKB_KEY_DOWN); - xkb_keysym_t sym = xkb_state_key_get_one_sym(app->m_kbd.xkb_state, kc); - app->m_kbd.pressed_syms.insert(sym); - - bool ctrl = app->m_kbd.mod_active("Control"); - bool alt = app->m_kbd.mod_active("Mod1"); - bool meta = app->m_kbd.mod_active("Mod4"); - if (!(ctrl || alt || meta)) { - u32 cp = xkb_keysym_to_utf32(sym); - if (cp >= 0x20) { - char buf[8]; - int n = xkb_keysym_to_utf8(sym, buf, sizeof(buf)); - if (n > 0) - app->m_kbd.typing.push_utf8(buf); - } - } - } else { - xkb_keysym_t sym = xkb_state_key_get_one_sym(app->m_kbd.xkb_state, kc); - app->m_kbd.released_syms.insert(sym); - - app->m_kbd.held.erase(key); - xkb_state_update_key(app->m_kbd.xkb_state, kc, XKB_KEY_UP); - } - }; - - auto kb_mods = [](void *data, wl_keyboard *, u32, u32 depressed, u32 latched, - u32 locked, u32 group) -> void { - auto *app = static_cast(data); - if (!app->m_kbd.xkb_state) - return; - xkb_state_update_mask(app->m_kbd.xkb_state, depressed, latched, locked, 0, - 0, group); - }; - - auto kb_repeat_info = [](void *, wl_keyboard *, i32, i32) -> void {}; - - keyboard_listener = {kb_keymap, kb_enter, kb_leave, - kb_key, kb_mods, kb_repeat_info}; - } - - auto handle_registry_global = [](void *data, wl_registry *registry, u32 name, - const char *interface, u32 version) -> void { - auto *app = static_cast(data); - if (std::strcmp(interface, wl_compositor_interface.name) == 0) { - app->m_wayland.compositor = static_cast( - wl_registry_bind(registry, name, &wl_compositor_interface, 4)); - } else if (std::strcmp(interface, wl_seat_interface.name) == 0) { - app->m_wayland.seat = static_cast( - wl_registry_bind(registry, name, &wl_seat_interface, 9)); - static struct wl_seat_listener const seat_listener = { - .capabilities = [](void *data, struct wl_seat *seat, u32 caps) { - auto *app = static_cast(data); - if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { - app->m_wayland.kbd = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(app->m_wayland.kbd, &keyboard_listener, - data); - } - }, - .name = [](void *, struct wl_seat *, const char *) {}, - }; - wl_seat_add_listener(app->m_wayland.seat, &seat_listener, data); - } else if (std::strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { - app->m_wayland.layer_shell = static_cast( - wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, - version >= 4 ? 4 : version)); - } else if (std::strcmp(interface, - ext_background_effect_manager_v1_interface.name) == 0) { - app->m_wayland.mgr = static_cast( - wl_registry_bind(registry, name, - &ext_background_effect_manager_v1_interface, 1)); - } else if (std::strcmp(interface, "org_kde_kwin_blur_manager") == 0) { - app->m_wayland.kde_blur_mgr = static_cast( - wl_registry_bind(registry, name, &org_kde_kwin_blur_manager_interface, - 1)); - } - }; - - static wl_registry_listener const registry_listener{ - .global = handle_registry_global, - .global_remove = [](void *, wl_registry *, u32) {}, - }; - - m_wayland.registry = wl_display_get_registry(m_wayland.display); - wl_registry_add_listener(m_wayland.registry, ®istry_listener, this); - - m_kbd.xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - - wl_display_roundtrip(m_wayland.display); - - create_layer_surface(); + if (m_wayland.display) + wl_display_flush(m_wayland.display); } -auto App::init_egl() -> void { - m_gl.edpy = - eglGetDisplay(reinterpret_cast(m_wayland.display)); - eglInitialize(m_gl.edpy, nullptr, nullptr); +auto App::init_wayland() -> void +{ + m_wayland.display = wl_display_connect(nullptr); + if (!m_wayland.display) { + std::fprintf(stderr, "failed to connect to Wayland display\n"); + std::exit(EXIT_FAILURE); + } - const EGLint cfgAttribs[]{EGL_SURFACE_TYPE, - EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, - 8, - EGL_GREEN_SIZE, - 8, - EGL_BLUE_SIZE, - 8, - EGL_ALPHA_SIZE, - 8, - EGL_NONE}; - EGLint n = 0; - eglChooseConfig(m_gl.edpy, cfgAttribs, &m_gl.ecfg, 1, &n); + static wl_keyboard_listener keyboard_listener {}; + { + auto kb_keymap = [](void *data, wl_keyboard *, u32 format, i32 fd, + u32 size) -> void { + auto *app = static_cast(data); + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + void *map = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + close(fd); + return; + } + if (app->m_kbd.xkb_keymap_v) + xkb_keymap_unref(app->m_kbd.xkb_keymap_v); + if (app->m_kbd.xkb_state_v) { + xkb_state_unref(app->m_kbd.xkb_state_v); + app->m_kbd.xkb_state_v = nullptr; + } + app->m_kbd.xkb_keymap_v = xkb_keymap_new_from_string( + app->m_kbd.xkb_ctx_v, static_cast(map), + XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); + app->m_kbd.xkb_state_v = app->m_kbd.xkb_keymap_v + ? xkb_state_new(app->m_kbd.xkb_keymap_v) + : nullptr; + munmap(map, size); + close(fd); + }; - const EGLint ctxAttribs[] = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE}; - m_gl.ectx = - eglCreateContext(m_gl.edpy, m_gl.ecfg, EGL_NO_CONTEXT, ctxAttribs); + auto kb_enter = [](void *, wl_keyboard *, u32, wl_surface *, + wl_array *) -> void { }; + auto kb_leave + = [](void *data, wl_keyboard *, u32, wl_surface *) -> void { + static_cast(data)->m_kbd.held.clear(); + }; - ensure_egl_surface(); + auto kb_key = [](void *data, wl_keyboard *, u32, u32, u32 key, + u32 state) -> void { + auto *app = static_cast(data); + if (!app->m_kbd.xkb_state_v) + return; - InitWindow(m_win_w, m_win_h, ""); + xkb_keycode_t kc = key + 8; + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + app->m_kbd.held.insert(key); + + xkb_state_update_key(app->m_kbd.xkb_state_v, kc, XKB_KEY_DOWN); + xkb_keysym_t sym + = xkb_state_key_get_one_sym(app->m_kbd.xkb_state_v, kc); + app->m_kbd.pressed_syms.insert(sym); + + bool ctrl = app->m_kbd.mod_active("Control"); + bool alt = app->m_kbd.mod_active("Mod1"); + bool meta = app->m_kbd.mod_active("Mod4"); + if (!(ctrl || alt || meta)) { + u32 cp = xkb_keysym_to_utf32(sym); + if (cp >= 0x20) { + char buf[8]; + int n = xkb_keysym_to_utf8(sym, buf, sizeof(buf)); + if (n > 0) + app->m_kbd.typing.push_utf8(buf); + } + } + } else { + xkb_keysym_t sym + = xkb_state_key_get_one_sym(app->m_kbd.xkb_state_v, kc); + app->m_kbd.released_syms.insert(sym); + + app->m_kbd.held.erase(key); + xkb_state_update_key(app->m_kbd.xkb_state_v, kc, XKB_KEY_UP); + } + }; + + auto kb_mods = [](void *data, wl_keyboard *, u32, u32 depressed, + u32 latched, u32 locked, u32 group) -> void { + auto *app = static_cast(data); + if (!app->m_kbd.xkb_state_v) + return; + xkb_state_update_mask(app->m_kbd.xkb_state_v, depressed, latched, + locked, 0, 0, group); + }; + + auto kb_repeat_info = [](void *, wl_keyboard *, i32, i32) -> void { }; + + keyboard_listener = { kb_keymap, kb_enter, kb_leave, kb_key, kb_mods, + kb_repeat_info }; + } + + auto handle_registry_global + = [](void *data, wl_registry *registry, u32 name, char const *interface, + u32 version) -> void { + auto *app = static_cast(data); + if (std::strcmp(interface, wl_compositor_interface.name) == 0) { + app->m_wayland.compositor = static_cast( + wl_registry_bind(registry, name, &wl_compositor_interface, 4)); + } else if (std::strcmp(interface, wl_seat_interface.name) == 0) { + app->m_wayland.seat = static_cast( + wl_registry_bind(registry, name, &wl_seat_interface, 9)); + static struct wl_seat_listener const seat_listener = { + .capabilities = + [](void *data, struct wl_seat *seat, u32 caps) { + auto *app = static_cast(data); + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) { + app->m_wayland.kbd = wl_seat_get_keyboard(seat); + wl_keyboard_add_listener( + app->m_wayland.kbd, &keyboard_listener, data); + } + }, + .name = [](void *, struct wl_seat *, char const *) {}, + }; + wl_seat_add_listener(app->m_wayland.seat, &seat_listener, data); + } else if (std::strcmp(interface, zwlr_layer_shell_v1_interface.name) + == 0) { + app->m_wayland.layer_shell = static_cast( + wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, + version >= 4 ? 4 : version)); + } else if (std::strcmp(interface, + ext_background_effect_manager_v1_interface.name) + == 0) { + app->m_wayland.mgr + = static_cast( + wl_registry_bind(registry, name, + &ext_background_effect_manager_v1_interface, 1)); + } else if (std::strcmp(interface, "org_kde_kwin_blur_manager") == 0) { + app->m_wayland.kde_blur_mgr + = static_cast(wl_registry_bind( + registry, name, &org_kde_kwin_blur_manager_interface, 1)); + } + }; + + static wl_registry_listener const registry_listener { + .global = handle_registry_global, + .global_remove = [](void *, wl_registry *, u32) { }, + }; + + m_wayland.registry = wl_display_get_registry(m_wayland.display); + wl_registry_add_listener(m_wayland.registry, ®istry_listener, this); + + m_kbd.xkb_ctx_v = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + wl_display_roundtrip(m_wayland.display); + + create_layer_surface(); } -auto App::init_signal() -> void { - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGUSR1); +auto App::init_egl() -> void +{ + m_gl.edpy = eglGetDisplay( + reinterpret_cast(m_wayland.display)); + eglInitialize(m_gl.edpy, nullptr, nullptr); - if (pthread_sigmask(SIG_BLOCK, &mask, nullptr) != 0) { - std::perror("pthread_sigmask"); - std::exit(EXIT_FAILURE); - } + EGLint const cfgAttribs[] { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; + EGLint n = 0; + eglChooseConfig(m_gl.edpy, cfgAttribs, &m_gl.ecfg, 1, &n); - m_sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); - if (m_sfd == -1) { - std::perror("signalfd"); - std::exit(EXIT_FAILURE); - } + EGLint const ctxAttribs[] = { EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE }; + m_gl.ectx + = eglCreateContext(m_gl.edpy, m_gl.ecfg, EGL_NO_CONTEXT, ctxAttribs); + + ensure_egl_surface(); + + InitWindow(m_win_w, m_win_h, ""); } -void App::on_settings_changed(XdpSettings * /*self*/, const char *ns, - const char *key, GVariant * /*value*/, - gpointer data) { - auto *app = static_cast(data); - if (g_strcmp0(ns, "org.freedesktop.appearance") == 0 && - g_strcmp0(key, "color-scheme") == 0) { - guint v = xdp_settings_read_uint(app->m_xdp.settings, - "org.freedesktop.appearance", - "color-scheme", NULL, NULL); +auto App::init_signal() -> void +{ + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); - if (v == 1) - app->m_active_theme = Theme::Dark; - else - app->m_active_theme = Theme::Light; - } + if (pthread_sigmask(SIG_BLOCK, &mask, nullptr) != 0) { + std::perror("pthread_sigmask"); + std::exit(EXIT_FAILURE); + } + + m_sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC); + if (m_sfd == -1) { + std::perror("signalfd"); + std::exit(EXIT_FAILURE); + } } -auto App::init_theme_portal() -> void { - m_xdp.portal = xdp_portal_new(); - m_xdp.settings = xdp_portal_get_settings(m_xdp.portal); +void App::on_settings_changed(XdpSettings * /*self*/, char const *ns, + char const *key, GVariant * /*value*/, gpointer data) +{ + auto *app = static_cast(data); + if (g_strcmp0(ns, "org.freedesktop.appearance") == 0 + && g_strcmp0(key, "color-scheme") == 0) { + guint v = xdp_settings_read_uint(app->m_xdp.settings, + "org.freedesktop.appearance", "color-scheme", NULL, NULL); - guint v = xdp_settings_read_uint(m_xdp.settings, "org.freedesktop.appearance", - "color-scheme", NULL, NULL); - if (v == 1) - m_active_theme = Theme::Dark; - else - m_active_theme = Theme::Light; - - g_signal_connect(m_xdp.settings, "changed", G_CALLBACK(on_settings_changed), - this); + if (v == 1) + app->m_active_theme = Theme::Dark; + else + app->m_active_theme = Theme::Light; + } } -auto App::create_layer_surface() -> void { - if (m_wayland.layer_surface) - return; +auto App::init_theme_portal() -> void +{ + m_xdp.portal = xdp_portal_new(); + m_xdp.settings = xdp_portal_get_settings(m_xdp.portal); - if (!m_wayland.compositor || !m_wayland.layer_shell) - return; + guint v = xdp_settings_read_uint(m_xdp.settings, + "org.freedesktop.appearance", "color-scheme", NULL, NULL); + if (v == 1) + m_active_theme = Theme::Dark; + else + m_active_theme = Theme::Light; - m_wayland.wl_surface = wl_compositor_create_surface(m_wayland.compositor); - - if (m_wayland.mgr) { - m_wayland.eff = ext_background_effect_manager_v1_get_background_effect( - m_wayland.mgr, m_wayland.wl_surface); - } - if (m_wayland.kde_blur_mgr) { - m_wayland.kde_blur = org_kde_kwin_blur_manager_create( - m_wayland.kde_blur_mgr, m_wayland.wl_surface); - } - - m_wayland.layer_surface = zwlr_layer_shell_v1_get_layer_surface( - m_wayland.layer_shell, m_wayland.wl_surface, nullptr, - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "waylight-overlay"); - - if (!m_wayland.layer_surface) { - if (m_wayland.eff) { - ext_background_effect_surface_v1_destroy(m_wayland.eff); - m_wayland.eff = nullptr; - } - if (m_wayland.kde_blur) { - org_kde_kwin_blur_destroy(m_wayland.kde_blur); - m_wayland.kde_blur = nullptr; - } - if (m_wayland.wl_surface) { - wl_surface_destroy(m_wayland.wl_surface); - m_wayland.wl_surface = nullptr; - } - return; - } - - zwlr_layer_surface_v1_set_anchor(m_wayland.layer_surface, 0); - zwlr_layer_surface_v1_set_size(m_wayland.layer_surface, m_win_w, m_win_h); - zwlr_layer_surface_v1_set_exclusive_zone(m_wayland.layer_surface, 0); - - if (zwlr_layer_shell_v1_get_version(m_wayland.layer_shell) >= 3) { - zwlr_layer_surface_v1_set_keyboard_interactivity( - m_wayland.layer_surface, - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND); - } - - auto handle_layer_configure = [](void *data, zwlr_layer_surface_v1 *ls, - u32 serial, u32 w, u32 h) -> void { - auto *app = static_cast(data); - if (w) - app->m_win_w = static_cast(w); - if (h) - app->m_win_h = static_cast(h); - - zwlr_layer_surface_v1_ack_configure(ls, serial); - - if (app->m_gl.edpy != EGL_NO_DISPLAY) { - if (!app->m_gl.wegl || app->m_gl.esurf == EGL_NO_SURFACE) { - app->ensure_egl_surface(); - } else { - wl_egl_window_resize(app->m_gl.wegl, app->m_win_w, app->m_win_h, 0, 0); - eglMakeCurrent(app->m_gl.edpy, app->m_gl.esurf, app->m_gl.esurf, - app->m_gl.ectx); - } - } - - app->update_blur_region(); - - if (app->m_wayland.wl_surface) - wl_surface_commit(app->m_wayland.wl_surface); - }; - - auto handle_layer_closed = [](void *data, zwlr_layer_surface_v1 *) -> void { - static_cast(data)->m_running = false; - }; - - static const zwlr_layer_surface_v1_listener lsl = { - .configure = handle_layer_configure, - .closed = handle_layer_closed, - }; - - zwlr_layer_surface_v1_add_listener(m_wayland.layer_surface, &lsl, this); - - update_blur_region(); - - if (m_wayland.wl_surface) - wl_surface_commit(m_wayland.wl_surface); - - if (m_wayland.display) - wl_display_roundtrip(m_wayland.display); - - ensure_egl_surface(); - - m_visible = true; + g_signal_connect( + m_xdp.settings, "changed", G_CALLBACK(on_settings_changed), this); } -auto App::destroy_layer_surface() -> void { - if (m_gl.edpy != EGL_NO_DISPLAY && m_gl.esurf != EGL_NO_SURFACE) { - eglMakeCurrent(m_gl.edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(m_gl.edpy, m_gl.esurf); - m_gl.esurf = EGL_NO_SURFACE; - } +auto App::create_layer_surface() -> void +{ + if (m_wayland.layer_surface) + return; - if (m_gl.wegl) { - wl_egl_window_destroy(m_gl.wegl); - m_gl.wegl = nullptr; - } + if (!m_wayland.compositor || !m_wayland.layer_shell) + return; - if (m_wayland.eff) { - ext_background_effect_surface_v1_destroy(m_wayland.eff); - m_wayland.eff = nullptr; - } + m_wayland.surface = wl_compositor_create_surface(m_wayland.compositor); - if (m_wayland.kde_blur) { - org_kde_kwin_blur_destroy(m_wayland.kde_blur); - m_wayland.kde_blur = nullptr; - } + if (m_wayland.mgr) { + m_wayland.eff = ext_background_effect_manager_v1_get_background_effect( + m_wayland.mgr, m_wayland.surface); + } + if (m_wayland.kde_blur_mgr) { + m_wayland.kde_blur = org_kde_kwin_blur_manager_create( + m_wayland.kde_blur_mgr, m_wayland.surface); + } - if (m_wayland.layer_surface) { - zwlr_layer_surface_v1_destroy(m_wayland.layer_surface); - m_wayland.layer_surface = nullptr; - } + m_wayland.layer_surface = zwlr_layer_shell_v1_get_layer_surface( + m_wayland.layer_shell, m_wayland.surface, nullptr, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "waylight-overlay"); - if (m_wayland.wl_surface) { - wl_surface_destroy(m_wayland.wl_surface); - m_wayland.wl_surface = nullptr; - } + if (!m_wayland.layer_surface) { + if (m_wayland.eff) { + ext_background_effect_surface_v1_destroy(m_wayland.eff); + m_wayland.eff = nullptr; + } + if (m_wayland.kde_blur) { + org_kde_kwin_blur_destroy(m_wayland.kde_blur); + m_wayland.kde_blur = nullptr; + } + if (m_wayland.surface) { + wl_surface_destroy(m_wayland.surface); + m_wayland.surface = nullptr; + } + return; + } - if (m_wayland.display) - wl_display_flush(m_wayland.display); + zwlr_layer_surface_v1_set_anchor(m_wayland.layer_surface, 0); + zwlr_layer_surface_v1_set_size(m_wayland.layer_surface, m_win_w, m_win_h); + zwlr_layer_surface_v1_set_exclusive_zone(m_wayland.layer_surface, 0); - m_visible = false; + if (zwlr_layer_shell_v1_get_version(m_wayland.layer_shell) >= 3) { + zwlr_layer_surface_v1_set_keyboard_interactivity( + m_wayland.layer_surface, + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND); + } + + auto handle_layer_configure = [](void *data, zwlr_layer_surface_v1 *ls, + u32 serial, u32 w, u32 h) -> void { + auto *app = static_cast(data); + if (w) + app->m_win_w = static_cast(w); + if (h) + app->m_win_h = static_cast(h); + + zwlr_layer_surface_v1_ack_configure(ls, serial); + + if (app->m_gl.edpy != EGL_NO_DISPLAY) { + if (!app->m_gl.wegl || app->m_gl.esurf == EGL_NO_SURFACE) { + app->ensure_egl_surface(); + } else { + wl_egl_window_resize( + app->m_gl.wegl, app->m_win_w, app->m_win_h, 0, 0); + eglMakeCurrent(app->m_gl.edpy, app->m_gl.esurf, app->m_gl.esurf, + app->m_gl.ectx); + } + } + + app->update_blur_region(); + + if (app->m_wayland.surface) + wl_surface_commit(app->m_wayland.surface); + }; + + auto handle_layer_closed = [](void *data, zwlr_layer_surface_v1 *) -> void { + static_cast(data)->m_running = false; + }; + + static zwlr_layer_surface_v1_listener const lsl = { + .configure = handle_layer_configure, + .closed = handle_layer_closed, + }; + + zwlr_layer_surface_v1_add_listener(m_wayland.layer_surface, &lsl, this); + + update_blur_region(); + + if (m_wayland.surface) + wl_surface_commit(m_wayland.surface); + + if (m_wayland.display) + wl_display_roundtrip(m_wayland.display); + + ensure_egl_surface(); + + m_visible = true; } -auto App::ensure_egl_surface() -> void { - if (m_gl.edpy == EGL_NO_DISPLAY || m_gl.ectx == EGL_NO_CONTEXT) - return; - if (!m_wayland.wl_surface) - return; +auto App::destroy_layer_surface() -> void +{ + if (m_gl.edpy != EGL_NO_DISPLAY && m_gl.esurf != EGL_NO_SURFACE) { + eglMakeCurrent( + m_gl.edpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(m_gl.edpy, m_gl.esurf); + m_gl.esurf = EGL_NO_SURFACE; + } - if (!m_gl.wegl) - m_gl.wegl = wl_egl_window_create(m_wayland.wl_surface, m_win_w, m_win_h); + if (m_gl.wegl) { + wl_egl_window_destroy(m_gl.wegl); + m_gl.wegl = nullptr; + } - if (!m_gl.wegl) - return; + if (m_wayland.eff) { + ext_background_effect_surface_v1_destroy(m_wayland.eff); + m_wayland.eff = nullptr; + } - if (m_gl.esurf == EGL_NO_SURFACE) { - m_gl.esurf = eglCreateWindowSurface( - m_gl.edpy, m_gl.ecfg, reinterpret_cast(m_gl.wegl), - nullptr); - } + if (m_wayland.kde_blur) { + org_kde_kwin_blur_destroy(m_wayland.kde_blur); + m_wayland.kde_blur = nullptr; + } - if (m_gl.esurf == EGL_NO_SURFACE) - return; + if (m_wayland.layer_surface) { + zwlr_layer_surface_v1_destroy(m_wayland.layer_surface); + m_wayland.layer_surface = nullptr; + } - eglMakeCurrent(m_gl.edpy, m_gl.esurf, m_gl.esurf, m_gl.ectx); - eglSwapInterval(m_gl.edpy, 1); + if (m_wayland.surface) { + wl_surface_destroy(m_wayland.surface); + m_wayland.surface = nullptr; + } + + if (m_wayland.display) + wl_display_flush(m_wayland.display); + + m_visible = false; } -auto App::update_blur_region() -> void { - if (!m_wayland.compositor) - return; - if (!m_wayland.eff && !m_wayland.kde_blur) - return; +auto App::ensure_egl_surface() -> void +{ + if (m_gl.edpy == EGL_NO_DISPLAY || m_gl.ectx == EGL_NO_CONTEXT) + return; + if (!m_wayland.surface) + return; - wl_region *region = wl_compositor_create_region(m_wayland.compositor); - if (!region) - return; + if (!m_gl.wegl) + m_gl.wegl = wl_egl_window_create(m_wayland.surface, m_win_w, m_win_h); - wl_region_add(region, 0, 0, m_win_w - 50, m_win_h); + if (!m_gl.wegl) + return; - if (m_wayland.eff) - ext_background_effect_surface_v1_set_blur_region(m_wayland.eff, region); - if (m_wayland.kde_blur) - org_kde_kwin_blur_set_region(m_wayland.kde_blur, region); + if (m_gl.esurf == EGL_NO_SURFACE) { + m_gl.esurf = eglCreateWindowSurface(m_gl.edpy, m_gl.ecfg, + reinterpret_cast(m_gl.wegl), nullptr); + } - wl_region_destroy(region); + if (m_gl.esurf == EGL_NO_SURFACE) + return; + + eglMakeCurrent(m_gl.edpy, m_gl.esurf, m_gl.esurf, m_gl.ectx); + eglSwapInterval(m_gl.edpy, 1); } -auto App::pump_events() -> void { - while (g_main_context_iteration(nullptr, false)) - ; +auto App::update_blur_region() -> void +{ + if (!m_wayland.compositor) + return; + if (!m_wayland.eff && !m_wayland.kde_blur) + return; - wl_display_dispatch_pending(m_wayland.display); - wl_display_flush(m_wayland.display); + wl_region *region = wl_compositor_create_region(m_wayland.compositor); + if (!region) + return; - pollfd fds[2]{{wl_display_get_fd(m_wayland.display), POLLIN, 0}, - {m_sfd, POLLIN, 0}}; + wl_region_add(region, 0, 0, m_win_w - 50, m_win_h); - auto prepared = (wl_display_prepare_read(m_wayland.display) == 0); - auto ret = poll(fds, 2, 0); + if (m_wayland.eff) + ext_background_effect_surface_v1_set_blur_region(m_wayland.eff, region); + if (m_wayland.kde_blur) + org_kde_kwin_blur_set_region(m_wayland.kde_blur, region); - if (ret > 0 && (fds[0].revents & POLLIN)) { - if (prepared) { - wl_display_read_events(m_wayland.display); - prepared = false; - } - } else if (prepared) { - wl_display_cancel_read(m_wayland.display); - } - - if (ret > 0 && (fds[1].revents & POLLIN)) { - signalfd_siginfo si; - while (read(m_sfd, &si, sizeof(si)) == sizeof(si)) { - if (si.ssi_signo == SIGUSR1) { - set_visible(!visible()); - } - } - } + wl_region_destroy(region); +} + +auto App::pump_events() -> void +{ + while (g_main_context_iteration(nullptr, false)) + ; + + wl_display_dispatch_pending(m_wayland.display); + wl_display_flush(m_wayland.display); + + pollfd fds[2] { { wl_display_get_fd(m_wayland.display), POLLIN, 0 }, + { m_sfd, POLLIN, 0 } }; + + auto prepared = (wl_display_prepare_read(m_wayland.display) == 0); + auto ret = poll(fds, 2, 0); + + if (ret > 0 && (fds[0].revents & POLLIN)) { + if (prepared) { + wl_display_read_events(m_wayland.display); + prepared = false; + } + } else if (prepared) { + wl_display_cancel_read(m_wayland.display); + } + + if (ret > 0 && (fds[1].revents & POLLIN)) { + signalfd_siginfo si; + while (read(m_sfd, &si, sizeof(si)) == sizeof(si)) { + if (si.ssi_signo == SIGUSR1) { + set_visible(!visible()); + } + } + } } diff --git a/src/App.hpp b/src/App.hpp index 0203323..e3995b8 100644 --- a/src/App.hpp +++ b/src/App.hpp @@ -41,7 +41,7 @@ private: auto init_signal() -> void; auto init_theme_portal() -> void; auto pump_events() -> void; - auto render_frame() -> void; + auto tick() -> void; auto create_layer_surface() -> void; auto destroy_layer_surface() -> void; auto ensure_egl_surface() -> void; @@ -60,7 +60,7 @@ private: wl_compositor *compositor {}; wl_seat *seat {}; wl_keyboard *kbd {}; - wl_surface *wl_surface {}; + wl_surface *surface {}; zwlr_layer_shell_v1 *layer_shell {}; zwlr_layer_surface_v1 *layer_surface {}; ext_background_effect_manager_v1 *mgr {}; @@ -85,9 +85,9 @@ private: struct { TypingBuffer typing {}; - xkb_context *xkb_ctx {}; - xkb_keymap *xkb_keymap {}; - xkb_state *xkb_state {}; + xkb_context *xkb_ctx_v {}; + xkb_keymap *xkb_keymap_v {}; + xkb_state *xkb_state_v {}; std::unordered_set held; std::unordered_set pressed_syms; @@ -100,11 +100,11 @@ private: auto is_down_sym(xkb_keysym_t sym) const -> bool { - if (!xkb_state) + if (!xkb_state_v) return false; for (auto k : held) { if (xkb_state_key_get_one_sym( - xkb_state, static_cast(k + 8)) + xkb_state_v, static_cast(k + 8)) == sym) return true; } @@ -123,9 +123,9 @@ private: auto mod_active(char const *name) const -> bool { - return xkb_state + return xkb_state_v && xkb_state_mod_name_is_active( - xkb_state, name, XKB_STATE_MODS_EFFECTIVE) + xkb_state_v, name, XKB_STATE_MODS_EFFECTIVE) > 0; } diff --git a/src/Frame.cpp b/src/Frame.cpp deleted file mode 100644 index 4273a8f..0000000 --- a/src/Frame.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "App.hpp" - -#include -#include -#include -#include -#include -#include - -auto App::render_frame() -> void { - if (!m_visible || m_gl.edpy == EGL_NO_DISPLAY || m_gl.esurf == EGL_NO_SURFACE) - return; - - glViewport(0, 0, m_win_w, m_win_h); - - for (auto const cp : m_kbd.typing) { - std::println("Char typed: {} ({}) shift={} ctrl={}", rune_to_string(cp), cp, - m_kbd.shift() ? 'y' : 'n', m_kbd.ctrl() ? 'y' : 'n'); - } - - if (m_kbd.is_sym_pressed(XKB_KEY_Escape)) { - set_visible(!visible()); - if (m_kbd.ctrl() && m_kbd.shift()) { - m_running = false; - } - } - - BeginDrawing(); - - ClearBackground(BLANK); - - DrawFPS(10, 10); - - EndDrawing(); - - eglSwapBuffers(m_gl.edpy, m_gl.esurf); - m_kbd.typing.clear(); - m_kbd.clear_transients(); -} diff --git a/src/Tick.cpp b/src/Tick.cpp new file mode 100644 index 0000000..15453b3 --- /dev/null +++ b/src/Tick.cpp @@ -0,0 +1,42 @@ +#include "App.hpp" + +#include +#include +#include +#include +#include +#include + +auto App::tick() -> void +{ + if (!m_visible || m_gl.edpy == EGL_NO_DISPLAY + || m_gl.esurf == EGL_NO_SURFACE) + return; + + glViewport(0, 0, m_win_w, m_win_h); + + for (auto const cp : m_kbd.typing) { + std::println("Char typed: {} ({}) shift={} ctrl={}", + rune_to_string(cp), cp, m_kbd.shift() ? 'y' : 'n', + m_kbd.ctrl() ? 'y' : 'n'); + } + + if (m_kbd.is_sym_pressed(XKB_KEY_Escape)) { + set_visible(!visible()); + if (m_kbd.ctrl() && m_kbd.shift()) { + m_running = false; + } + } + + BeginDrawing(); + + ClearBackground(BLANK); + + DrawFPS(10, 10); + + EndDrawing(); + + eglSwapBuffers(m_gl.edpy, m_gl.esurf); + m_kbd.typing.clear(); + m_kbd.clear_transients(); +}