#pragma once #include #include #include #include #include #include #include #include extern "C" { #include "blur-client-protocol.h" #define namespace namespace_ #include "ext-background-effect-v1-client-protocol.h" #include "text-input-unstable-v3-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include #undef namespace } #include #include #include #include "ImGui.hpp" #include "TextRenderer.hpp" #include "Theme.hpp" #include "common.hpp" struct TypingBuffer : std::pmr::vector { void push_utf8(char const *s); }; struct App { App(); ~App(); auto run() -> void; auto set_visible(bool visible) -> void; auto visible() const -> bool { return m_visible; } auto stop() -> void { m_running = false; } private: auto init_wayland() -> void; auto init_egl() -> void; auto init_signal() -> void; auto init_theme_portal() -> void; auto pump_events() -> void; auto tick() -> void; auto create_layer_surface() -> void; auto destroy_layer_surface() -> void; auto ensure_egl_surface() -> void; auto update_blur_region() -> void; auto process_pending_text_input() -> void; auto update_text_input_state( std::pmr::string const &text, usize id, Rectangle field_rect) -> void; auto theme() const -> ColorScheme const & { return m_themes[m_active_theme]; } auto clipboard() const -> std::pmr::string const & { return m_clipboard_cache; } auto clipboard(std::string_view const &str) -> void; static void on_settings_changed(XdpSettings * /*self*/, char const *ns, char const *key, GVariant * /*value*/, gpointer data); struct { wl_display *display {}; wl_registry *registry {}; wl_compositor *compositor {}; wl_seat *seat {}; wl_keyboard *kbd {}; wl_surface *surface {}; zwlr_layer_shell_v1 *layer_shell {}; zwlr_layer_surface_v1 *layer_surface {}; ext_background_effect_manager_v1 *mgr {}; ext_background_effect_surface_v1 *eff {}; org_kde_kwin_blur_manager *kde_blur_mgr {}; org_kde_kwin_blur *kde_blur {}; zwp_text_input_manager_v3 *text_input_mgr {}; zwp_text_input_v3 *text_input {}; wl_data_device_manager *ddm {}; wl_data_device *ddev {}; wl_data_offer *curr_offer {}; wl_data_source *curr_source {}; } m_wayland; std::pmr::string m_clipboard_cache; u32 m_last_serial { 0 }; struct { EGLDisplay edpy { EGL_NO_DISPLAY }; EGLConfig ecfg {}; EGLContext ectx { EGL_NO_CONTEXT }; EGLSurface esurf { EGL_NO_SURFACE }; wl_egl_window *wegl {}; } m_gl; struct { XdpPortal *portal {}; XdpSettings *settings {}; } m_xdp; struct { TypingBuffer typing {}; xkb_context *xkb_ctx_v {}; xkb_keymap *xkb_keymap_v {}; xkb_state *xkb_state_v {}; std::unordered_set held; std::unordered_set pressed_syms; std::unordered_set released_syms; auto is_down_evdev(u32 evdev) const -> bool { return held.find(evdev) != held.end(); } auto is_down_sym(xkb_keysym_t sym) const -> bool { if (!xkb_state_v) return false; for (auto k : held) { if (xkb_state_key_get_one_sym( xkb_state_v, static_cast(k + 8)) == sym) return true; } return false; } auto is_sym_pressed(xkb_keysym_t sym) const -> bool { return pressed_syms.find(sym) != pressed_syms.end(); } auto is_sym_released(xkb_keysym_t sym) const -> bool { return released_syms.find(sym) != released_syms.end(); } auto mod_active(char const *name) const -> bool { return xkb_state_v && xkb_state_mod_name_is_active( xkb_state_v, name, XKB_STATE_MODS_EFFECTIVE) > 0; } auto ctrl() const -> bool { return mod_active("Control"); } auto shift() const -> bool { return mod_active("Shift"); } void clear_transients() { pressed_syms.clear(); released_syms.clear(); } } m_kbd; std::shared_ptr m_tr { nullptr }; FontHandle m_font; std::shared_ptr m_gui { nullptr }; struct { bool supported { false }; bool seat_focus { false }; bool enabled { false }; bool pending_done { false }; uint32_t pending_serial { 0 }; uint32_t sent_serial { 0 }; std::pmr::string *bound_text { nullptr }; usize bound_id { 0 }; Rectangle bound_rect {}; struct { bool has_preedit { false }; std::string preedit_text; int cursor_begin { 0 }; int cursor_end { 0 }; bool has_commit { false }; std::string commit_text; bool has_delete { false }; uint32_t before { 0 }; uint32_t after { 0 }; } pending; std::string last_surrounding; int last_cursor { 0 }; int last_anchor { 0 }; Rectangle last_cursor_rect {}; bool last_cursor_visible { false }; bool surrounding_dirty { false }; } m_ime; // NOTE: Canonicalize first! std::unordered_map m_textures; auto get_texture(std::filesystem::path const &path) -> Texture2D const & { if (m_textures.contains(path)) { return m_textures[path]; } auto fname = path.c_str(); assert(fname); TraceLog(LOG_INFO, std::format("loading texture at {}", fname).c_str()); auto const tex = LoadTexture(fname); assert(IsTextureValid(tex)); m_textures[path] = tex; return m_textures[path]; } enum_array m_themes { make_default_themes() }; Theme m_active_theme { Theme::Light }; int m_win_w { 800 }; int m_win_h { 600 }; bool m_running { true }; bool m_visible { true }; Color m_accent_color { 127, 127, 255, 255 }; int m_sfd { -1 }; };