Files
waylight/src/App.hpp
2025-10-15 03:33:35 +03:00

232 lines
5.6 KiB
C++

#pragma once
#include <cassert>
#include <filesystem>
#include <string>
#include <unordered_set>
#include <vector>
#include <EGL/egl.h>
#include <libportal/portal.h>
#include <wayland-client-protocol.h>
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 <libportal/settings.h>
#undef namespace
}
#include <wayland-client.h>
#include <wayland-egl.h>
#include <xkbcommon/xkbcommon.h>
#include "IconRegistry.hpp"
#include "ImGui.hpp"
#include "TextRenderer.hpp"
#include "Theme.hpp"
#include "common.hpp"
struct TypingBuffer : std::pmr::vector<u32> {
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<u32> held;
std::unordered_set<u32> pressed_syms;
std::unordered_set<u32> 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<xkb_keycode_t>(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<TextRenderer> m_tr { nullptr };
FontHandle m_font;
std::shared_ptr<ImGui> 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<std::filesystem::path, Texture2D> 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<Theme, ColorScheme> m_themes { make_default_themes() };
Theme m_active_theme { Theme::Light };
IconRegistry m_ir;
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 };
};