diff --git a/flake.nix b/flake.nix index 85fc6e9..593d013 100644 --- a/flake.nix +++ b/flake.nix @@ -10,6 +10,9 @@ inherit (hyprland.inputs) nixpkgs; withPkgsFor = fn: nixpkgs.lib.genAttrs (builtins.attrNames hyprland.packages) (system: fn system nixpkgs.legacyPackages.${system}); in { + # for debugging + inherit inputs; + packages = withPkgsFor (system: pkgs: let hyprgrassPackage = pkgs.callPackage ./nix/default.nix { inherit (hyprland.packages.${system}) hyprland; diff --git a/src/TouchVisualizer.cpp b/src/TouchVisualizer.cpp new file mode 100644 index 0000000..3a339a6 --- /dev/null +++ b/src/TouchVisualizer.cpp @@ -0,0 +1,95 @@ +#include "TouchVisualizer.hpp" +#include "src/devices/ITouch.hpp" +#include "src/macros.hpp" +#include "src/render/OpenGL.hpp" +#include "src/render/Renderer.hpp" +#include +#include +#include +#include + +CBox boxAroundCenter(Vector2D center, double radius) { + return CBox(center.x - radius, center.y - radius, 2 * radius, 2 * radius); +} + +Visualizer::Visualizer() { + const int R = TOUCH_POINT_RADIUS; + + this->cairoSurface = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 2 * TOUCH_POINT_RADIUS, 2 * TOUCH_POINT_RADIUS); + auto cairo = cairo_create(cairoSurface); + + cairo_arc(cairo, R, R, R, 0, 2 * PI); + cairo_set_source_rgba(cairo, 0.8, 0.8, 0.1, 0.6); + cairo_fill(cairo); + + cairo_destroy(cairo); + + const unsigned char* data = cairo_image_surface_get_data(this->cairoSurface); + + this->texture->allocate(); + glBindTexture(GL_TEXTURE_2D, this->texture->m_iTexID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2 * TOUCH_POINT_RADIUS, 2 * TOUCH_POINT_RADIUS, 0, GL_RGBA, + GL_UNSIGNED_BYTE, data); +} + +Visualizer::~Visualizer() { + if (this->cairoSurface) + cairo_surface_destroy(this->cairoSurface); +} + +void Visualizer::onPreRender() {} + +void Visualizer::onRender() { + if (this->finger_positions.size() < 1) { + return; + } + + const auto monitor = g_pCompositor->m_pLastMonitor.lock(); + + // HACK: should not damage monitor, however, I don't understand jackshit + // about damage so here we are. + // If you know how to do damage properly I BEG OF YOU PLEASE ABSOLVE ME + // OF MY SINS + if (this->finger_positions.size()) { + g_pHyprRenderer->damageMonitor(monitor); + } + + for (auto& finger : this->finger_positions) { + CBox dmg = boxAroundCenter(finger.second.curr, TOUCH_POINT_RADIUS); + g_pHyprOpenGL->renderTexture(this->texture, &dmg, 1.f, 0, true); + } +} + +void Visualizer::onTouchDown(ITouch::SDownEvent ev) { + auto mon = g_pCompositor->m_pLastMonitor.lock(); + this->finger_positions.emplace(ev.touchID, FingerPos{ev.pos * mon->vecPixelSize + mon->vecPosition, std::nullopt}); + g_pCompositor->scheduleFrameForMonitor(mon); +} + +void Visualizer::onTouchUp(ITouch::SUpEvent ev) { + this->damageFinger(ev.touchID); + this->finger_positions.erase(ev.touchID); + g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.lock()); +} + +void Visualizer::onTouchMotion(ITouch::SMotionEvent ev) { + auto mon = g_pCompositor->m_pLastMonitor.lock(); + this->finger_positions[ev.touchID] = {ev.pos * mon->vecPixelSize + mon->vecPosition, std::nullopt}; + g_pCompositor->scheduleFrameForMonitor(mon); +} + +void Visualizer::damageFinger(int32_t id) { + auto finger = this->finger_positions.at(id); + + CBox dm = boxAroundCenter(finger.curr, TOUCH_POINT_RADIUS); + g_pHyprRenderer->damageBox(&dm); + + if (finger.last_rendered.has_value()) { + dm = boxAroundCenter(finger.last_rendered.value(), TOUCH_POINT_RADIUS); + g_pHyprRenderer->damageBox(&dm); + } +} diff --git a/src/TouchVisualizer.hpp b/src/TouchVisualizer.hpp new file mode 100644 index 0000000..6483501 --- /dev/null +++ b/src/TouchVisualizer.hpp @@ -0,0 +1,33 @@ +#include "src/devices/ITouch.hpp" +#include "src/render/Texture.hpp" +#include +#include +#include +#include +#include +#include + +struct FingerPos { + Vector2D curr; + std::optional last_rendered; +}; + +class Visualizer { + public: + Visualizer(); + ~Visualizer(); + void onPreRender(); + void onRender(); + void damageFinger(int32_t id); + + void onTouchDown(ITouch::SDownEvent); + void onTouchUp(ITouch::SUpEvent); + void onTouchMotion(ITouch::SMotionEvent); + + private: + SP texture = makeShared(); + cairo_surface_t* cairoSurface; + bool tempDamaged = false; + const int TOUCH_POINT_RADIUS = 30; + std::unordered_map finger_positions; +}; diff --git a/src/main.cpp b/src/main.cpp index ebc7464..5700b55 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,10 @@ #include "GestureManager.hpp" +#include "TouchVisualizer.hpp" #include "globals.hpp" +#include "src/SharedDefs.hpp" #include "version.hpp" +#include #include #include #include @@ -11,25 +14,46 @@ #include #include +#include #include const CHyprColor s_pluginColor = {0x61 / 255.0f, 0xAF / 255.0f, 0xEF / 255.0f, 1.0f}; +inline std::unique_ptr g_pVisualizer; + void hkOnTouchDown(void* _, SCallbackInfo& cbinfo, std::any e) { auto ev = std::any_cast(e); + static auto const VISUALIZE = + (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:debug:visualize_touch") + ->getDataStaticPtr(); + + if (**VISUALIZE) + g_pVisualizer->onTouchDown(ev); cbinfo.cancelled = g_pGestureManager->onTouchDown(ev); } void hkOnTouchUp(void* _, SCallbackInfo& cbinfo, std::any e) { auto ev = std::any_cast(e); + static auto const VISUALIZE = + (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:debug:visualize_touch") + ->getDataStaticPtr(); + + if (**VISUALIZE) + g_pVisualizer->onTouchUp(ev); cbinfo.cancelled = g_pGestureManager->onTouchUp(ev); } void hkOnTouchMove(void* _, SCallbackInfo& cbinfo, std::any e) { auto ev = std::any_cast(e); + static auto const VISUALIZE = + (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:debug:visualize_touch") + ->getDataStaticPtr(); + + if (**VISUALIZE) + g_pVisualizer->onTouchMotion(ev); cbinfo.cancelled = g_pGestureManager->onTouchMove(ev); } @@ -37,6 +61,16 @@ static void onPreConfigReload() { g_pGestureManager->internalBinds.clear(); } +void onRenderStage(eRenderStage stage) { + static auto const VISUALIZE = + (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:touch_gestures:debug:visualize_touch") + ->getDataStaticPtr(); + + if (stage == RENDER_LAST_MOMENT && **VISUALIZE) { + g_pVisualizer->onRender(); + } +} + void listInternalBinds(std::string) { Debug::log(LOG, "[hyprgrass] Listing internal binds:"); for (const auto& bind : g_pGestureManager->internalBinds) { @@ -90,8 +124,6 @@ APICALL EXPORT std::string PLUGIN_API_VERSION() { APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { PHANDLE = handle; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmissing-field-initializers" HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_fingers", Hyprlang::CConfigValue((Hyprlang::INT)3)); HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:workspace_swipe_edge", @@ -108,7 +140,8 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { Hyprlang::CConfigValue((Hyprlang::INT)1)); HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:emulate_touchpad_swipe", Hyprlang::CConfigValue((Hyprlang::INT)0)); -#pragma GCC diagnostic pop + HyprlandAPI::addConfigValue(PHANDLE, "plugin:touch_gestures:debug:visualize_touch", + Hyprlang::CConfigValue((Hyprlang::INT)0)); HyprlandAPI::addConfigKeyword(PHANDLE, "hyprgrass-bind", onNewBind, Hyprlang::SHandlerOptions{}); HyprlandAPI::addConfigKeyword(PHANDLE, "hyprgrass-bindm", onNewBind, Hyprlang::SHandlerOptions{}); @@ -138,10 +171,13 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) { static auto P1 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "touchDown", hkOnTouchDown); static auto P2 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "touchUp", hkOnTouchUp); static auto P3 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "touchMove", hkOnTouchMove); + static auto P4 = HyprlandAPI::registerCallbackDynamic( + PHANDLE, "render", [](void*, SCallbackInfo, std::any arg) { onRenderStage(std::any_cast(arg)); }); HyprlandAPI::reloadConfig(); g_pGestureManager = std::make_unique(); + g_pVisualizer = std::make_unique(); return {"hyprgrass", "Touchscreen gestures", "horriblename", HYPRGRASS_VERSION}; } diff --git a/src/meson.build b/src/meson.build index 74510dd..157bd04 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,7 @@ shared_module('hyprgrass', 'main.cpp', 'GestureManager.cpp', 'VecSet.cpp', + 'TouchVisualizer.cpp', cpp_args: ['-DWLR_USE_UNSTABLE'], link_with: [gestures], dependencies: [