diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2025-08-28 11:20:29 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-28 11:20:29 +0200 |
| commit | 81bf4eccba449bfe2b6adfb51260108aec710d4f (patch) | |
| tree | 215c5b536cbcf1df9888081aadd3de16eb4b3ebe /src/managers | |
| parent | 378e130f1426648d8d734049800128f9882805bf (diff) | |
input: Add fully configurable trackpad gestures (#11490)
Adds configurable trackpad gestures
Diffstat (limited to 'src/managers')
33 files changed, 2134 insertions, 575 deletions
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 1e4e5710..0eab9689 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -14,6 +14,7 @@ #include "debug/Log.hpp" #include "../managers/HookSystemManager.hpp" #include "../managers/input/InputManager.hpp" +#include "../managers/animation/DesktopAnimationManager.hpp" #include "../managers/LayoutManager.hpp" #include "../managers/EventManager.hpp" #include "../render/Renderer.hpp" @@ -2327,7 +2328,8 @@ SDispatchResult CKeybindManager::focusWindow(std::string regexp) { // don't make floating implicitly fs if (!PWINDOW->m_createdOverFullscreen) { g_pCompositor->changeWindowZOrder(PWINDOW, true); - g_pCompositor->updateFullscreenFadeOnWorkspace(PWORKSPACE); + g_pDesktopAnimationManager->setFullscreenFadeAnimation( + PWORKSPACE, PWORKSPACE->m_hasFullscreenWindow ? CDesktopAnimationManager::ANIMATION_TYPE_IN : CDesktopAnimationManager::ANIMATION_TYPE_OUT); } g_pCompositor->focusWindow(PWINDOW); diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index f5635810..093c751d 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -902,7 +902,7 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) { PROTO::idle->onActivity(); if (!g_pCompositor->m_dpmsStateOn && *PMOUSEDPMS) - g_pKeybindManager->dpms("on"); + CKeybindManager::dpms("on"); }); listener->motionAbsolute = pointer->m_pointerEvents.motionAbsolute.listen([](const IPointer::SMotionAbsoluteEvent& event) { @@ -911,7 +911,7 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) { PROTO::idle->onActivity(); if (!g_pCompositor->m_dpmsStateOn && *PMOUSEDPMS) - g_pKeybindManager->dpms("on"); + CKeybindManager::dpms("on"); }); listener->button = pointer->m_pointerEvents.button.listen([](const IPointer::SButtonEvent& event) { @@ -941,7 +941,7 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) { PROTO::idle->onActivity(); if (!g_pCompositor->m_dpmsStateOn && *PMOUSEDPMS) - g_pKeybindManager->dpms("on"); + CKeybindManager::dpms("on"); }); listener->swipeEnd = pointer->m_pointerEvents.swipeEnd.listen([](const IPointer::SSwipeEndEvent& event) { @@ -955,21 +955,23 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) { }); listener->pinchBegin = pointer->m_pointerEvents.pinchBegin.listen([](const IPointer::SPinchBeginEvent& event) { - PROTO::pointerGestures->pinchBegin(event.timeMs, event.fingers); + g_pInputManager->onPinchBegin(event); PROTO::idle->onActivity(); if (!g_pCompositor->m_dpmsStateOn && *PMOUSEDPMS) - g_pKeybindManager->dpms("on"); + CKeybindManager::dpms("on"); }); listener->pinchEnd = pointer->m_pointerEvents.pinchEnd.listen([](const IPointer::SPinchEndEvent& event) { - PROTO::pointerGestures->pinchEnd(event.timeMs, event.cancelled); + g_pInputManager->onPinchEnd(event); + PROTO::idle->onActivity(); }); listener->pinchUpdate = pointer->m_pointerEvents.pinchUpdate.listen([](const IPointer::SPinchUpdateEvent& event) { - PROTO::pointerGestures->pinchUpdate(event.timeMs, event.delta, event.scale, event.rotation); + g_pInputManager->onPinchUpdate(event); + PROTO::idle->onActivity(); }); @@ -1005,7 +1007,7 @@ void CPointerManager::attachTouch(SP<ITouch> touch) { PROTO::idle->onActivity(); if (!g_pCompositor->m_dpmsStateOn && *PMOUSEDPMS) - g_pKeybindManager->dpms("on"); + CKeybindManager::dpms("on"); }); listener->up = touch->m_touchEvents.up.listen([](const ITouch::SUpEvent& event) { @@ -1046,7 +1048,7 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) { PROTO::idle->onActivity(); if (!g_pCompositor->m_dpmsStateOn && *PMOUSEDPMS) - g_pKeybindManager->dpms("on"); + CKeybindManager::dpms("on"); }); listener->proximity = tablet->m_tabletEvents.proximity.listen([](const CTablet::SProximityEvent& event) { @@ -1060,7 +1062,7 @@ void CPointerManager::attachTablet(SP<CTablet> tablet) { PROTO::idle->onActivity(); if (!g_pCompositor->m_dpmsStateOn && *PMOUSEDPMS) - g_pKeybindManager->dpms("on"); + CKeybindManager::dpms("on"); }); listener->button = tablet->m_tabletEvents.button.listen([](const CTablet::SButtonEvent& event) { diff --git a/src/managers/AnimationManager.cpp b/src/managers/animation/AnimationManager.cpp index aac4a869..6675216a 100644 --- a/src/managers/AnimationManager.cpp +++ b/src/managers/animation/AnimationManager.cpp @@ -1,16 +1,16 @@ #include "AnimationManager.hpp" -#include "../Compositor.hpp" -#include "HookSystemManager.hpp" -#include "../config/ConfigManager.hpp" -#include "../desktop/DesktopTypes.hpp" -#include "../helpers/AnimatedVariable.hpp" -#include "../macros.hpp" -#include "../config/ConfigValue.hpp" -#include "../desktop/Window.hpp" -#include "../desktop/LayerSurface.hpp" -#include "eventLoop/EventLoopManager.hpp" -#include "../helpers/varlist/VarList.hpp" -#include "../render/Renderer.hpp" +#include "../../Compositor.hpp" +#include "../HookSystemManager.hpp" +#include "../../config/ConfigManager.hpp" +#include "../../desktop/DesktopTypes.hpp" +#include "../../helpers/AnimatedVariable.hpp" +#include "../../macros.hpp" +#include "../../config/ConfigValue.hpp" +#include "../../desktop/Window.hpp" +#include "../../desktop/LayerSurface.hpp" +#include "../eventLoop/EventLoopManager.hpp" +#include "../../helpers/varlist/VarList.hpp" +#include "../../render/Renderer.hpp" #include <hyprgraphics/color/Color.hpp> #include <hyprutils/animation/AnimatedVariable.hpp> @@ -275,173 +275,6 @@ void CHyprAnimationManager::onTicked() { m_tickScheduled = false; } -// -// Anims -// -// - -void CHyprAnimationManager::animationPopin(PHLWINDOW pWindow, bool close, float minPerc) { - const auto GOALPOS = pWindow->m_realPosition->goal(); - const auto GOALSIZE = pWindow->m_realSize->goal(); - - if (!close) { - pWindow->m_realSize->setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y})); - pWindow->m_realPosition->setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_realSize->value() / 2.f); - } else { - *pWindow->m_realSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}); - *pWindow->m_realPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_realSize->goal() / 2.f; - } -} - -void CHyprAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, bool close) { - pWindow->m_realSize->warp(false); // size we preserve in slide - - const auto GOALPOS = pWindow->m_realPosition->goal(); - const auto GOALSIZE = pWindow->m_realSize->goal(); - - const auto PMONITOR = pWindow->m_monitor.lock(); - - if (!PMONITOR) - return; // unsafe state most likely - - Vector2D posOffset; - - if (!force.empty()) { - if (force == "bottom") - posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y + PMONITOR->m_size.y); - else if (force == "left") - posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0.0); - else if (force == "right") - posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0.0); - else - posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y - GOALSIZE.y); - - if (!close) - pWindow->m_realPosition->setValue(posOffset); - else - *pWindow->m_realPosition = posOffset; - - return; - } - - const auto MIDPOINT = GOALPOS + GOALSIZE / 2.f; - - // check sides it touches - const bool DISPLAYLEFT = STICKS(pWindow->m_position.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x); - const bool DISPLAYRIGHT = STICKS(pWindow->m_position.x + pWindow->m_size.x, PMONITOR->m_position.x + PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x); - const bool DISPLAYTOP = STICKS(pWindow->m_position.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y); - const bool DISPLAYBOTTOM = STICKS(pWindow->m_position.y + pWindow->m_size.y, PMONITOR->m_position.y + PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y); - - if (DISPLAYBOTTOM && DISPLAYTOP) { - if (DISPLAYLEFT && DISPLAYRIGHT) { - posOffset = GOALPOS + Vector2D(0.0, GOALSIZE.y); - } else if (DISPLAYLEFT) { - posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0.0); - } else { - posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0.0); - } - } else if (DISPLAYTOP) { - posOffset = GOALPOS - Vector2D(0.0, GOALSIZE.y); - } else if (DISPLAYBOTTOM) { - posOffset = GOALPOS + Vector2D(0.0, GOALSIZE.y); - } else { - if (MIDPOINT.y > PMONITOR->m_position.y + PMONITOR->m_size.y / 2.f) - posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y + PMONITOR->m_size.y); - else - posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y - GOALSIZE.y); - } - - if (!close) - pWindow->m_realPosition->setValue(posOffset); - else - *pWindow->m_realPosition = posOffset; -} - -void CHyprAnimationManager::animationGnomed(PHLWINDOW pWindow, bool close) { - const auto GOALPOS = pWindow->m_realPosition->goal(); - const auto GOALSIZE = pWindow->m_realSize->goal(); - - if (close) { - *pWindow->m_realPosition = GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}; - *pWindow->m_realSize = Vector2D{GOALSIZE.x, 0.F}; - } else { - pWindow->m_realPosition->setValueAndWarp(GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}); - pWindow->m_realSize->setValueAndWarp(Vector2D{GOALSIZE.x, 0.F}); - *pWindow->m_realPosition = GOALPOS; - *pWindow->m_realSize = GOALSIZE; - } -} - -void CHyprAnimationManager::onWindowPostCreateClose(PHLWINDOW pWindow, bool close) { - if (!close) { - pWindow->m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); - pWindow->m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); - pWindow->m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); - } else { - pWindow->m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); - pWindow->m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); - pWindow->m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); - } - - std::string ANIMSTYLE = pWindow->m_realPosition->getStyle(); - std::ranges::transform(ANIMSTYLE, ANIMSTYLE.begin(), ::tolower); - - CVarList animList(ANIMSTYLE, 0, 's'); - - // if the window is not being animated, that means the layout set a fixed size for it, don't animate. - if (!pWindow->m_realPosition->isBeingAnimated() && !pWindow->m_realSize->isBeingAnimated()) - return; - - // if the animation is disabled and we are leaving, ignore the anim to prevent the snapshot being fucked - if (!pWindow->m_realPosition->enabled()) - return; - - if (pWindow->m_windowData.animationStyle.hasValue()) { - const auto STYLE = pWindow->m_windowData.animationStyle.value(); - // the window has config'd special anim - if (STYLE.starts_with("slide")) { - CVarList animList2(STYLE, 0, 's'); - animationSlide(pWindow, animList2[1], close); - } else if (STYLE == "gnomed" || STYLE == "gnome") - animationGnomed(pWindow, close); - else { - // anim popin, fallback - - float minPerc = 0.f; - if (STYLE.find("%") != std::string::npos) { - try { - auto percstr = STYLE.substr(STYLE.find_last_of(' ')); - minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); - } catch (std::exception& e) { - ; // oops - } - } - - animationPopin(pWindow, close, minPerc / 100.f); - } - } else { - if (animList[0] == "slide") - animationSlide(pWindow, animList[1], close); - else if (animList[0] == "gnomed" || animList[0] == "gnome") - animationGnomed(pWindow, close); - else { - // anim popin, fallback - - float minPerc = 0.f; - if (!ANIMSTYLE.starts_with("%")) { - try { - auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ')); - minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); - } catch (std::exception& e) { - ; // oops - } - } - - animationPopin(pWindow, close, minPerc / 100.f); - } - } -} - std::string CHyprAnimationManager::styleValidInConfigVar(const std::string& config, const std::string& style) { if (config.starts_with("window")) { if (style.starts_with("slide") || style == "gnome" || style == "gnomed") diff --git a/src/managers/AnimationManager.hpp b/src/managers/animation/AnimationManager.hpp index b5e42036..0631e7c7 100644 --- a/src/managers/AnimationManager.hpp +++ b/src/managers/animation/AnimationManager.hpp @@ -3,10 +3,10 @@ #include <hyprutils/animation/AnimationManager.hpp> #include <hyprutils/animation/AnimatedVariable.hpp> -#include "../defines.hpp" -#include "../helpers/AnimatedVariable.hpp" -#include "../desktop/DesktopTypes.hpp" -#include "eventLoop/EventLoopTimer.hpp" +#include "../../defines.hpp" +#include "../../helpers/AnimatedVariable.hpp" +#include "../../desktop/DesktopTypes.hpp" +#include "../eventLoop/EventLoopTimer.hpp" class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { public: @@ -45,8 +45,6 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { pav->m_Context.pLayer = pLayer; } - void onWindowPostCreateClose(PHLWINDOW, bool close = false); - std::string styleValidInConfigVar(const std::string&, const std::string&); SP<CEventLoopTimer> m_animationTimer; @@ -55,11 +53,6 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager { private: bool m_tickScheduled = false; - - // Anim stuff - void animationPopin(PHLWINDOW, bool close = false, float minPerc = 0.f); - void animationSlide(PHLWINDOW, std::string force = "", bool close = false); - void animationGnomed(PHLWINDOW, bool close = false); }; inline UP<CHyprAnimationManager> g_pAnimationManager; diff --git a/src/managers/animation/DesktopAnimationManager.cpp b/src/managers/animation/DesktopAnimationManager.cpp new file mode 100644 index 00000000..e55a0439 --- /dev/null +++ b/src/managers/animation/DesktopAnimationManager.cpp @@ -0,0 +1,491 @@ +#include "DesktopAnimationManager.hpp" + +#include "../../desktop/LayerSurface.hpp" +#include "../../desktop/Window.hpp" +#include "../../desktop/Workspace.hpp" + +#include "../../config/ConfigManager.hpp" +#include "../../Compositor.hpp" +#include "wlr-layer-shell-unstable-v1.hpp" + +void CDesktopAnimationManager::startAnimation(PHLWINDOW pWindow, eAnimationType type, bool force) { + const bool CLOSE = type == ANIMATION_TYPE_OUT; + + if (CLOSE) + *pWindow->m_alpha = 0.F; + else { + pWindow->m_alpha->setValueAndWarp(0.F); + *pWindow->m_alpha = 1.F; + } + + if (!CLOSE) { + pWindow->m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); + pWindow->m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsIn")); + pWindow->m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeIn")); + } else { + pWindow->m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); + pWindow->m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("windowsOut")); + pWindow->m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeOut")); + } + + std::string ANIMSTYLE = pWindow->m_realPosition->getStyle(); + std::ranges::transform(ANIMSTYLE, ANIMSTYLE.begin(), ::tolower); + + CVarList animList(ANIMSTYLE, 0, 's'); + + // if the window is not being animated, that means the layout set a fixed size for it, don't animate. + if (!pWindow->m_realPosition->isBeingAnimated() && !pWindow->m_realSize->isBeingAnimated() && !force) + return; + + // if the animation is disabled and we are leaving, ignore the anim to prevent the snapshot being fucked + if (!pWindow->m_realPosition->enabled() && !force) + return; + + if (pWindow->m_windowData.animationStyle.hasValue()) { + const auto STYLE = pWindow->m_windowData.animationStyle.value(); + // the window has config'd special anim + if (STYLE.starts_with("slide")) { + CVarList animList2(STYLE, 0, 's'); + animationSlide(pWindow, animList2[1], CLOSE); + } else if (STYLE == "gnomed" || STYLE == "gnome") + animationGnomed(pWindow, CLOSE); + else { + // anim popin, fallback + + float minPerc = 0.f; + if (STYLE.find("%") != std::string::npos) { + try { + auto percstr = STYLE.substr(STYLE.find_last_of(' ')); + minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); + } catch (std::exception& e) { + ; // oops + } + } + + animationPopin(pWindow, CLOSE, minPerc / 100.f); + } + } else { + if (animList[0] == "slide") + animationSlide(pWindow, animList[1], CLOSE); + else if (animList[0] == "gnomed" || animList[0] == "gnome") + animationGnomed(pWindow, CLOSE); + else { + // anim popin, fallback + + float minPerc = 0.f; + if (!ANIMSTYLE.starts_with("%")) { + try { + auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ')); + minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); + } catch (std::exception& e) { + ; // oops + } + } + + animationPopin(pWindow, CLOSE, minPerc / 100.f); + } + } +} + +void CDesktopAnimationManager::startAnimation(PHLLS ls, eAnimationType type, bool instant) { + const bool IN = type == ANIMATION_TYPE_IN; + + if (IN) { + ls->m_alpha->setValueAndWarp(0.F); + *ls->m_alpha = 1.F; + } else + *ls->m_alpha = 0.F; + + if (IN) { + ls->m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); + ls->m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersIn")); + ls->m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersIn")); + } else { + ls->m_realPosition->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); + ls->m_realSize->setConfig(g_pConfigManager->getAnimationPropertyConfig("layersOut")); + ls->m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig("fadeLayersOut")); + } + + const auto ANIMSTYLE = ls->m_animationStyle.value_or(ls->m_realPosition->getStyle()); + if (ANIMSTYLE.starts_with("slide")) { + // get closest edge + const auto MIDDLE = ls->m_geometry.middle(); + + const auto PMONITOR = g_pCompositor->getMonitorFromVector(MIDDLE); + + if (!PMONITOR) { // can rarely happen on exit + ls->m_alpha->setValueAndWarp(IN ? 1.F : 0.F); + return; + } + + int force = -1; + + CVarList args(ANIMSTYLE, 0, 's'); + if (args.size() > 1) { + const auto ARG2 = args[1]; + if (ARG2 == "top") + force = 0; + else if (ARG2 == "bottom") + force = 1; + else if (ARG2 == "left") + force = 2; + else if (ARG2 == "right") + force = 3; + } + + const std::array<Vector2D, 4> edgePoints = { + PMONITOR->m_position + Vector2D{PMONITOR->m_size.x / 2, 0.0}, + PMONITOR->m_position + Vector2D{PMONITOR->m_size.x / 2, PMONITOR->m_size.y}, + PMONITOR->m_position + Vector2D{0.0, PMONITOR->m_size.y}, + PMONITOR->m_position + Vector2D{PMONITOR->m_size.x, PMONITOR->m_size.y / 2}, + }; + + float closest = std::numeric_limits<float>::max(); + int leader = force; + if (leader == -1) { + for (size_t i = 0; i < 4; ++i) { + float dist = MIDDLE.distance(edgePoints[i]); + if (dist < closest) { + leader = i; + closest = dist; + } + } + } + + ls->m_realSize->setValueAndWarp(ls->m_geometry.size()); + + Vector2D prePos; + + switch (leader) { + case 0: + // TOP + prePos = {ls->m_geometry.x, PMONITOR->m_position.y - ls->m_geometry.h}; + break; + case 1: + // BOTTOM + prePos = {ls->m_geometry.x, PMONITOR->m_position.y + PMONITOR->m_size.y}; + break; + case 2: + // LEFT + prePos = {PMONITOR->m_position.x - ls->m_geometry.w, ls->m_geometry.y}; + break; + case 3: + // RIGHT + prePos = {PMONITOR->m_position.x + PMONITOR->m_size.x, ls->m_geometry.y}; + break; + default: UNREACHABLE(); + } + + if (IN) { + ls->m_realPosition->setValueAndWarp(prePos); + *ls->m_realPosition = ls->m_geometry.pos(); + } else { + ls->m_realPosition->setValueAndWarp(ls->m_geometry.pos()); + *ls->m_realPosition = prePos; + } + + } else if (ANIMSTYLE.starts_with("popin")) { + float minPerc = 0.f; + if (ANIMSTYLE.find("%") != std::string::npos) { + try { + auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ')); + minPerc = std::stoi(percstr.substr(0, percstr.length() - 1)); + } catch (std::exception& e) { + ; // oops + } + } + + minPerc *= 0.01; + + const auto GOALSIZE = (ls->m_geometry.size() * minPerc).clamp({5, 5}); + const auto GOALPOS = ls->m_geometry.pos() + (ls->m_geometry.size() - GOALSIZE) / 2.f; + + ls->m_alpha->setValueAndWarp(IN ? 0.f : 1.f); + *ls->m_alpha = IN ? 1.f : 0.f; + + if (IN) { + ls->m_realSize->setValueAndWarp(GOALSIZE); + ls->m_realPosition->setValueAndWarp(GOALPOS); + *ls->m_realSize = ls->m_geometry.size(); + *ls->m_realPosition = ls->m_geometry.pos(); + } else { + ls->m_realSize->setValueAndWarp(ls->m_geometry.size()); + ls->m_realPosition->setValueAndWarp(ls->m_geometry.pos()); + *ls->m_realSize = GOALSIZE; + *ls->m_realPosition = GOALPOS; + } + } else { + // fade + ls->m_realPosition->setValueAndWarp(ls->m_geometry.pos()); + ls->m_realSize->setValueAndWarp(ls->m_geometry.size()); + *ls->m_alpha = IN ? 1.f : 0.f; + } + + if (instant) { + ls->m_realPosition->warp(); + ls->m_realSize->warp(); + ls->m_alpha->warp(); + } +} + +void CDesktopAnimationManager::startAnimation(PHLWORKSPACE ws, eAnimationType type, bool left, bool instant) { + const bool IN = type == ANIMATION_TYPE_IN; + + if (!instant) { + const std::string ANIMNAME = std::format("{}{}", ws->m_isSpecialWorkspace ? "specialWorkspace" : "workspaces", IN ? "In" : "Out"); + + ws->m_alpha->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); + ws->m_renderOffset->setConfig(g_pConfigManager->getAnimationPropertyConfig(ANIMNAME)); + } + + const auto ANIMSTYLE = ws->m_alpha->getStyle(); + static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); + + // set floating windows offset callbacks + ws->m_renderOffset->setUpdateCallback([weak = PHLWORKSPACEREF{ws}](auto) { + if (!weak) + return; + + for (auto const& w : g_pCompositor->m_windows) { + if (!validMapped(w) || w->workspaceID() != weak->m_id) + continue; + + w->onWorkspaceAnimUpdate(); + }; + }); + + if (ANIMSTYLE.starts_with("slidefade")) { + const auto PMONITOR = ws->m_monitor.lock(); + float movePerc = 100.f; + + if (ANIMSTYLE.find('%') != std::string::npos) { + try { + auto percstr = ANIMSTYLE.substr(ANIMSTYLE.find_last_of(' ') + 1); + movePerc = std::stoi(percstr.substr(0, percstr.length() - 1)); + } catch (std::exception& e) { Debug::log(ERR, "Error in startAnim: invalid percentage"); } + } + + ws->m_alpha->setValueAndWarp(1.f); + ws->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); + + if (ANIMSTYLE.starts_with("slidefadevert")) { + if (IN) { + ws->m_alpha->setValueAndWarp(0.f); + ws->m_renderOffset->setValueAndWarp(Vector2D(0.0, (left ? PMONITOR->m_size.y : -PMONITOR->m_size.y) * (movePerc / 100.f))); + *ws->m_alpha = 1.f; + *ws->m_renderOffset = Vector2D(0, 0); + } else { + ws->m_alpha->setValueAndWarp(1.f); + *ws->m_alpha = 0.f; + *ws->m_renderOffset = Vector2D(0.0, (left ? -PMONITOR->m_size.y : PMONITOR->m_size.y) * (movePerc / 100.f)); + } + } else { + if (IN) { + ws->m_alpha->setValueAndWarp(0.f); + ws->m_renderOffset->setValueAndWarp(Vector2D((left ? PMONITOR->m_size.x : -PMONITOR->m_size.x) * (movePerc / 100.f), 0.0)); + *ws->m_alpha = 1.f; + *ws->m_renderOffset = Vector2D(0, 0); + } else { + ws->m_alpha->setValueAndWarp(1.f); + *ws->m_alpha = 0.f; + *ws->m_renderOffset = Vector2D((left ? -PMONITOR->m_size.x : PMONITOR->m_size.x) * (movePerc / 100.f), 0.0); + } + } + } else if (ANIMSTYLE == "fade") { + ws->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); // fix a bug, if switching from slide -> fade. + + if (IN) { + ws->m_alpha->setValueAndWarp(0.f); + *ws->m_alpha = 1.f; + } else { + ws->m_alpha->setValueAndWarp(1.f); + *ws->m_alpha = 0.f; + } + } else if (ANIMSTYLE == "slidevert") { + // fallback is slide + const auto PMONITOR = ws->m_monitor.lock(); + const auto YDISTANCE = PMONITOR->m_size.y + *PWORKSPACEGAP; + + ws->m_alpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. + + if (IN) { + ws->m_renderOffset->setValueAndWarp(Vector2D(0.0, left ? YDISTANCE : -YDISTANCE)); + *ws->m_renderOffset = Vector2D(0, 0); + } else { + *ws->m_renderOffset = Vector2D(0.0, left ? -YDISTANCE : YDISTANCE); + } + } else { + // fallback is slide + const auto PMONITOR = ws->m_monitor.lock(); + const auto XDISTANCE = PMONITOR->m_size.x + *PWORKSPACEGAP; + + ws->m_alpha->setValueAndWarp(1.f); // fix a bug, if switching from fade -> slide. + + if (IN) { + ws->m_renderOffset->setValueAndWarp(Vector2D(left ? XDISTANCE : -XDISTANCE, 0.0)); + *ws->m_renderOffset = Vector2D(0, 0); + } else { + *ws->m_renderOffset = Vector2D(left ? -XDISTANCE : XDISTANCE, 0.0); + } + } + + if (ws->m_isSpecialWorkspace) { + // required for open/close animations + if (IN) { + ws->m_alpha->setValueAndWarp(0.f); + *ws->m_alpha = 1.f; + } else { + ws->m_alpha->setValueAndWarp(1.f); + *ws->m_alpha = 0.f; + } + } + + if (instant) { + ws->m_renderOffset->warp(); + ws->m_alpha->warp(); + } +} + +void CDesktopAnimationManager::animationPopin(PHLWINDOW pWindow, bool close, float minPerc) { + const auto GOALPOS = pWindow->m_realPosition->goal(); + const auto GOALSIZE = pWindow->m_realSize->goal(); + + if (!close) { + pWindow->m_realSize->setValue((GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y})); + pWindow->m_realPosition->setValue(GOALPOS + GOALSIZE / 2.f - pWindow->m_realSize->value() / 2.f); + } else { + *pWindow->m_realSize = (GOALSIZE * minPerc).clamp({5, 5}, {GOALSIZE.x, GOALSIZE.y}); + *pWindow->m_realPosition = GOALPOS + GOALSIZE / 2.f - pWindow->m_realSize->goal() / 2.f; + } +} + +void CDesktopAnimationManager::animationSlide(PHLWINDOW pWindow, std::string force, bool close) { + pWindow->m_realSize->warp(false); // size we preserve in slide + + const auto GOALPOS = pWindow->m_realPosition->goal(); + const auto GOALSIZE = pWindow->m_realSize->goal(); + + const auto PMONITOR = pWindow->m_monitor.lock(); + + if (!PMONITOR) + return; // unsafe state most likely + + Vector2D posOffset; + + if (!force.empty()) { + if (force == "bottom") + posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y + PMONITOR->m_size.y); + else if (force == "left") + posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0.0); + else if (force == "right") + posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0.0); + else + posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y - GOALSIZE.y); + + if (!close) + pWindow->m_realPosition->setValue(posOffset); + else + *pWindow->m_realPosition = posOffset; + + return; + } + + const auto MIDPOINT = GOALPOS + GOALSIZE / 2.f; + + // check sides it touches + const bool DISPLAYLEFT = STICKS(pWindow->m_position.x, PMONITOR->m_position.x + PMONITOR->m_reservedTopLeft.x); + const bool DISPLAYRIGHT = STICKS(pWindow->m_position.x + pWindow->m_size.x, PMONITOR->m_position.x + PMONITOR->m_size.x - PMONITOR->m_reservedBottomRight.x); + const bool DISPLAYTOP = STICKS(pWindow->m_position.y, PMONITOR->m_position.y + PMONITOR->m_reservedTopLeft.y); + const bool DISPLAYBOTTOM = STICKS(pWindow->m_position.y + pWindow->m_size.y, PMONITOR->m_position.y + PMONITOR->m_size.y - PMONITOR->m_reservedBottomRight.y); + + if (DISPLAYBOTTOM && DISPLAYTOP) { + if (DISPLAYLEFT && DISPLAYRIGHT) { + posOffset = GOALPOS + Vector2D(0.0, GOALSIZE.y); + } else if (DISPLAYLEFT) { + posOffset = GOALPOS - Vector2D(GOALSIZE.x, 0.0); + } else { + posOffset = GOALPOS + Vector2D(GOALSIZE.x, 0.0); + } + } else if (DISPLAYTOP) { + posOffset = GOALPOS - Vector2D(0.0, GOALSIZE.y); + } else if (DISPLAYBOTTOM) { + posOffset = GOALPOS + Vector2D(0.0, GOALSIZE.y); + } else { + if (MIDPOINT.y > PMONITOR->m_position.y + PMONITOR->m_size.y / 2.f) + posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y + PMONITOR->m_size.y); + else + posOffset = Vector2D(GOALPOS.x, PMONITOR->m_position.y - GOALSIZE.y); + } + + if (!close) + pWindow->m_realPosition->setValue(posOffset); + else + *pWindow->m_realPosition = posOffset; +} + +void CDesktopAnimationManager::animationGnomed(PHLWINDOW pWindow, bool close) { + const auto GOALPOS = pWindow->m_realPosition->goal(); + const auto GOALSIZE = pWindow->m_realSize->goal(); + + if (close) { + *pWindow->m_realPosition = GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}; + *pWindow->m_realSize = Vector2D{GOALSIZE.x, 0.F}; + } else { + pWindow->m_realPosition->setValueAndWarp(GOALPOS + Vector2D{0.F, GOALSIZE.y / 2.F}); + pWindow->m_realSize->setValueAndWarp(Vector2D{GOALSIZE.x, 0.F}); + *pWindow->m_realPosition = GOALPOS; + *pWindow->m_realSize = GOALSIZE; + } +} + +void CDesktopAnimationManager::setFullscreenFadeAnimation(PHLWORKSPACE ws, eAnimationType type) { + if (!ws) + return; + + const auto FULLSCREEN = type == ANIMATION_TYPE_IN; + + for (auto const& w : g_pCompositor->m_windows) { + if (w->m_workspace == ws) { + + if (w->m_fadingOut || w->m_pinned || w->isFullscreen()) + continue; + + if (!FULLSCREEN) + *w->m_alpha = 1.F; + else if (!w->isFullscreen()) + *w->m_alpha = !w->m_createdOverFullscreen ? 0.f : 1.f; + } + } + + const auto PMONITOR = ws->m_monitor.lock(); + + if (ws->m_id == PMONITOR->activeWorkspaceID() || ws->m_id == PMONITOR->activeSpecialWorkspaceID()) { + for (auto const& ls : PMONITOR->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + if (!ls->m_fadingOut) + *ls->m_alpha = FULLSCREEN && ws->m_fullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; + } + } +} + +void CDesktopAnimationManager::overrideFullscreenFadeAmount(PHLWORKSPACE ws, float fade, PHLWINDOW exclude) { + for (auto const& w : g_pCompositor->m_windows) { + if (w == exclude) + continue; + + if (w->m_workspace == ws) { + if (w->m_fadingOut || w->m_pinned || w->isFullscreen()) + continue; + + *w->m_alpha = fade; + } + } + + const auto PMONITOR = ws->m_monitor.lock(); + + if (ws->m_id == PMONITOR->activeWorkspaceID() || ws->m_id == PMONITOR->activeSpecialWorkspaceID()) { + for (auto const& ls : PMONITOR->m_layerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) { + if (!ls->m_fadingOut) + *ls->m_alpha = fade; + } + } +} diff --git a/src/managers/animation/DesktopAnimationManager.hpp b/src/managers/animation/DesktopAnimationManager.hpp new file mode 100644 index 00000000..623fc5e9 --- /dev/null +++ b/src/managers/animation/DesktopAnimationManager.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include "../../helpers/memory/Memory.hpp" +#include "../../desktop/DesktopTypes.hpp" + +class CDesktopAnimationManager { + public: + enum eAnimationType : uint8_t { + ANIMATION_TYPE_IN = 0, + ANIMATION_TYPE_OUT, + }; + + void startAnimation(PHLWINDOW w, eAnimationType type, bool force = false); + void startAnimation(PHLLS ls, eAnimationType type, bool instant = false); + void startAnimation(PHLWORKSPACE ws, eAnimationType type, bool left = true, bool instant = false); + + void setFullscreenFadeAnimation(PHLWORKSPACE ws, eAnimationType type); + void overrideFullscreenFadeAmount(PHLWORKSPACE ws, float fade, PHLWINDOW exclude = nullptr); + + private: + void animationPopin(PHLWINDOW w, bool close = false, float minPerc = 0.f); + void animationSlide(PHLWINDOW w, std::string force = "", bool close = false); + void animationGnomed(PHLWINDOW w, bool close = false); +}; + +inline UP<CDesktopAnimationManager> g_pDesktopAnimationManager = makeUnique<CDesktopAnimationManager>(); diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index dff97166..5224f940 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -12,6 +12,7 @@ #include "../../protocols/IdleInhibit.hpp" #include "../../protocols/RelativePointer.hpp" #include "../../protocols/PointerConstraints.hpp" +#include "../../protocols/PointerGestures.hpp" #include "../../protocols/IdleNotify.hpp" #include "../../protocols/SessionLock.hpp" #include "../../protocols/InputMethodV2.hpp" @@ -41,6 +42,8 @@ #include "../../helpers/time/Time.hpp" #include "../../helpers/MiscFunctions.hpp" +#include "trackpad/TrackpadGestures.hpp" + #include <aquamarine/input/Input.hpp> CInputManager::CInputManager() { @@ -1946,3 +1949,51 @@ void CInputManager::recheckMouseWarpOnMouseInput() { if (!m_lastInputMouse && *PWARPFORNONMOUSE) g_pPointerManager->warpTo(m_lastMousePos); } + +void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { + EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e); + + g_pTrackpadGestures->gestureBegin(e); + + PROTO::pointerGestures->swipeBegin(e.timeMs, e.fingers); +} + +void CInputManager::onSwipeUpdate(IPointer::SSwipeUpdateEvent e) { + EMIT_HOOK_EVENT_CANCELLABLE("swipeUpdate", e); + + g_pTrackpadGestures->gestureUpdate(e); + + PROTO::pointerGestures->swipeUpdate(e.timeMs, e.delta); +} + +void CInputManager::onSwipeEnd(IPointer::SSwipeEndEvent e) { + EMIT_HOOK_EVENT_CANCELLABLE("swipeEnd", e); + + g_pTrackpadGestures->gestureEnd(e); + + PROTO::pointerGestures->swipeEnd(e.timeMs, e.cancelled); +} + +void CInputManager::onPinchBegin(IPointer::SPinchBeginEvent e) { + EMIT_HOOK_EVENT_CANCELLABLE("pinchBegin", e); + + g_pTrackpadGestures->gestureBegin(e); + + PROTO::pointerGestures->pinchBegin(e.timeMs, e.fingers); +} + +void CInputManager::onPinchUpdate(IPointer::SPinchUpdateEvent e) { + EMIT_HOOK_EVENT_CANCELLABLE("pinchUpdate", e); + + g_pTrackpadGestures->gestureUpdate(e); + + PROTO::pointerGestures->pinchUpdate(e.timeMs, e.delta, e.scale, e.rotation); +} + +void CInputManager::onPinchEnd(IPointer::SPinchEndEvent e) { + EMIT_HOOK_EVENT_CANCELLABLE("pinchEnd", e); + + g_pTrackpadGestures->gestureEnd(e); + + PROTO::pointerGestures->pinchEnd(e.timeMs, e.cancelled); +} diff --git a/src/managers/input/InputManager.hpp b/src/managers/input/InputManager.hpp index 7a0a308f..56751cf5 100644 --- a/src/managers/input/InputManager.hpp +++ b/src/managers/input/InputManager.hpp @@ -141,6 +141,10 @@ class CInputManager { void onSwipeEnd(IPointer::SSwipeEndEvent); void onSwipeUpdate(IPointer::SSwipeUpdateEvent); + void onPinchBegin(IPointer::SPinchBeginEvent); + void onPinchUpdate(IPointer::SPinchUpdateEvent); + void onPinchEnd(IPointer::SPinchEndEvent); + void onTabletAxis(CTablet::SAxisEvent); void onTabletProximity(CTablet::SProximityEvent); void onTabletTip(CTablet::STipEvent); @@ -179,8 +183,6 @@ class CInputManager { void recheckIdleInhibitorStatus(); bool isWindowInhibiting(const PHLWINDOW& pWindow, bool onlyHl = true); - SSwipeGesture m_activeSwipe; - CTimer m_lastCursorMovement; CInputMethodRelay m_relay; @@ -276,13 +278,8 @@ class CInputManager { }; std::vector<UP<SIdleInhibitor>> m_idleInhibitors; - // swipe - void beginWorkspaceSwipe(); - void updateWorkspaceSwipe(double); - void endWorkspaceSwipe(); - - void setBorderCursorIcon(eBorderIconDirection); - void setCursorIconOnBorder(PHLWINDOW w); + void setBorderCursorIcon(eBorderIconDirection); + void setCursorIconOnBorder(PHLWINDOW w); // temporary. Obeys setUntilUnset. void setCursorImageOverride(const std::string& name); @@ -313,6 +310,7 @@ class CInputManager { friend class CKeybindManager; friend class CWLSurface; + friend class CWorkspaceSwipeGesture; }; inline UP<CInputManager> g_pInputManager; diff --git a/src/managers/input/Swipe.cpp b/src/managers/input/Swipe.cpp deleted file mode 100644 index 1d9b80e2..00000000 --- a/src/managers/input/Swipe.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include "InputManager.hpp" -#include "../../Compositor.hpp" -#include "../../desktop/LayerSurface.hpp" -#include "../../config/ConfigValue.hpp" -#include "../../managers/HookSystemManager.hpp" -#include "../../render/Renderer.hpp" - -void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) { - static auto PSWIPE = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe"); - static auto PSWIPEFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_fingers"); - static auto PSWIPEMINFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_min_fingers"); - static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); - - EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e); - - if ((!*PSWIPEMINFINGERS && e.fingers != *PSWIPEFINGERS) || (*PSWIPEMINFINGERS && e.fingers < *PSWIPEFINGERS) || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked()) - return; - - int onMonitor = 0; - for (auto const& w : g_pCompositor->getWorkspaces()) { - if (w->m_monitor == g_pCompositor->m_lastMonitor && !g_pCompositor->isWorkspaceSpecial(w->m_id)) - onMonitor++; - } - - if (onMonitor < 2 && !*PSWIPENEW) - return; // disallow swiping when there's 1 workspace on a monitor - - beginWorkspaceSwipe(); -} - -void CInputManager::beginWorkspaceSwipe() { - const auto PWORKSPACE = g_pCompositor->m_lastMonitor->m_activeWorkspace; - - Debug::log(LOG, "Starting a swipe from {}", PWORKSPACE->m_name); - - m_activeSwipe.pWorkspaceBegin = PWORKSPACE; - m_activeSwipe.delta = 0; - m_activeSwipe.pMonitor = g_pCompositor->m_lastMonitor; - m_activeSwipe.avgSpeed = 0; - m_activeSwipe.speedPoints = 0; - - if (PWORKSPACE->m_hasFullscreenWindow) { - for (auto const& ls : g_pCompositor->m_lastMonitor->m_layerSurfaceLayers[2]) { - *ls->m_alpha = 1.f; - } - } -} - -void CInputManager::onSwipeEnd(IPointer::SSwipeEndEvent e) { - EMIT_HOOK_EVENT_CANCELLABLE("swipeEnd", e); - - if (!m_activeSwipe.pWorkspaceBegin) - return; // no valid swipe - endWorkspaceSwipe(); -} - -void CInputManager::endWorkspaceSwipe() { - static auto PSWIPEPERC = CConfigValue<Hyprlang::FLOAT>("gestures:workspace_swipe_cancel_ratio"); - static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance"); - static auto PSWIPEFORC = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_min_speed_to_force"); - static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); - static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r"); - static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); - const auto ANIMSTYLE = m_activeSwipe.pWorkspaceBegin->m_renderOffset->getStyle(); - const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); - - // commit - auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; - auto workspaceIDRight = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r+1" : "m+1")).id; - const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, sc<int64_t>(1LL), sc<int64_t>(UINT32_MAX)); - - // If we've been swiping off the right end with PSWIPENEW enabled, there is - // no workspace there yet, and we need to choose an ID for a new one now. - if (workspaceIDRight <= m_activeSwipe.pWorkspaceBegin->m_id && *PSWIPENEW) { - workspaceIDRight = getWorkspaceIDNameFromString("r+1").id; - } - - auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER - auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER - - const auto RENDEROFFSETMIDDLE = m_activeSwipe.pWorkspaceBegin->m_renderOffset->value(); - const auto XDISTANCE = m_activeSwipe.pMonitor->m_size.x + *PWORKSPACEGAP; - const auto YDISTANCE = m_activeSwipe.pMonitor->m_size.y + *PWORKSPACEGAP; - - PHLWORKSPACE pSwitchedTo = nullptr; - - if ((abs(m_activeSwipe.delta) < SWIPEDISTANCE * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_activeSwipe.avgSpeed < *PSWIPEFORC))) || - abs(m_activeSwipe.delta) < 2) { - // revert - if (abs(m_activeSwipe.delta) < 2) { - if (PWORKSPACEL) - PWORKSPACEL->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); - if (PWORKSPACER) - PWORKSPACER->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); - } else { - if (m_activeSwipe.delta < 0) { - // to left - - if (PWORKSPACEL) { - if (VERTANIMS) - *PWORKSPACEL->m_renderOffset = Vector2D{0.0, -YDISTANCE}; - else - *PWORKSPACEL->m_renderOffset = Vector2D{-XDISTANCE, 0.0}; - } - } else if (PWORKSPACER) { - // to right - if (VERTANIMS) - *PWORKSPACER->m_renderOffset = Vector2D{0.0, YDISTANCE}; - else - *PWORKSPACER->m_renderOffset = Vector2D{XDISTANCE, 0.0}; - } - - *m_activeSwipe.pWorkspaceBegin->m_renderOffset = Vector2D(); - } - - pSwitchedTo = m_activeSwipe.pWorkspaceBegin; - } else if (m_activeSwipe.delta < 0) { - // switch to left - const auto RENDEROFFSET = PWORKSPACEL ? PWORKSPACEL->m_renderOffset->value() : Vector2D(); - - if (PWORKSPACEL) - m_activeSwipe.pMonitor->changeWorkspace(workspaceIDLeft); - else { - m_activeSwipe.pMonitor->changeWorkspace(g_pCompositor->createNewWorkspace(workspaceIDLeft, m_activeSwipe.pMonitor->m_id)); - PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); - PWORKSPACEL->rememberPrevWorkspace(m_activeSwipe.pWorkspaceBegin); - } - - PWORKSPACEL->m_renderOffset->setValue(RENDEROFFSET); - PWORKSPACEL->m_alpha->setValueAndWarp(1.f); - - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValue(RENDEROFFSETMIDDLE); - if (VERTANIMS) - *m_activeSwipe.pWorkspaceBegin->m_renderOffset = Vector2D(0.0, YDISTANCE); - else - *m_activeSwipe.pWorkspaceBegin->m_renderOffset = Vector2D(XDISTANCE, 0.0); - m_activeSwipe.pWorkspaceBegin->m_alpha->setValueAndWarp(1.f); - - g_pInputManager->unconstrainMouse(); - - Debug::log(LOG, "Ended swipe to the left"); - - pSwitchedTo = PWORKSPACEL; - } else { - // switch to right - const auto RENDEROFFSET = PWORKSPACER ? PWORKSPACER->m_renderOffset->value() : Vector2D(); - - if (PWORKSPACER) - m_activeSwipe.pMonitor->changeWorkspace(workspaceIDRight); - else { - m_activeSwipe.pMonitor->changeWorkspace(g_pCompositor->createNewWorkspace(workspaceIDRight, m_activeSwipe.pMonitor->m_id)); - PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); - PWORKSPACER->rememberPrevWorkspace(m_activeSwipe.pWorkspaceBegin); - } - - PWORKSPACER->m_renderOffset->setValue(RENDEROFFSET); - PWORKSPACER->m_alpha->setValueAndWarp(1.f); - - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValue(RENDEROFFSETMIDDLE); - if (VERTANIMS) - *m_activeSwipe.pWorkspaceBegin->m_renderOffset = Vector2D(0.0, -YDISTANCE); - else - *m_activeSwipe.pWorkspaceBegin->m_renderOffset = Vector2D(-XDISTANCE, 0.0); - m_activeSwipe.pWorkspaceBegin->m_alpha->setValueAndWarp(1.f); - - g_pInputManager->unconstrainMouse(); - - Debug::log(LOG, "Ended swipe to the right"); - - pSwitchedTo = PWORKSPACER; - } - m_activeSwipe.pWorkspaceBegin->rememberPrevWorkspace(pSwitchedTo); - - g_pHyprRenderer->damageMonitor(m_activeSwipe.pMonitor.lock()); - - if (PWORKSPACEL) - PWORKSPACEL->m_forceRendering = false; - if (PWORKSPACER) - PWORKSPACER->m_forceRendering = false; - m_activeSwipe.pWorkspaceBegin->m_forceRendering = false; - - m_activeSwipe.pWorkspaceBegin = nullptr; - m_activeSwipe.initialDirection = 0; - - g_pInputManager->refocus(); - - // apply alpha - for (auto const& ls : g_pCompositor->m_lastMonitor->m_layerSurfaceLayers[2]) { - *ls->m_alpha = pSwitchedTo->m_hasFullscreenWindow && pSwitchedTo->m_fullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; - } -} - -void CInputManager::onSwipeUpdate(IPointer::SSwipeUpdateEvent e) { - EMIT_HOOK_EVENT_CANCELLABLE("swipeUpdate", e); - - if (!m_activeSwipe.pWorkspaceBegin) - return; - static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert"); - const auto ANIMSTYLE = m_activeSwipe.pWorkspaceBegin->m_renderOffset->getStyle(); - const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); - - const double delta = m_activeSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e.delta.y : e.delta.y) : (*PSWIPEINVR ? -e.delta.x : e.delta.x)); - updateWorkspaceSwipe(delta); -} - -void CInputManager::updateWorkspaceSwipe(double delta) { - static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance"); - static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); - static auto PSWIPEDIRLOCK = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock"); - static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock_threshold"); - static auto PSWIPEFOREVER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_forever"); - static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r"); - static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); - - const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, sc<int64_t>(1LL), sc<int64_t>(UINT32_MAX)); - const auto XDISTANCE = m_activeSwipe.pMonitor->m_size.x + *PWORKSPACEGAP; - const auto YDISTANCE = m_activeSwipe.pMonitor->m_size.y + *PWORKSPACEGAP; - const auto ANIMSTYLE = m_activeSwipe.pWorkspaceBegin->m_renderOffset->getStyle(); - const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); - const double d = m_activeSwipe.delta - delta; - m_activeSwipe.delta = delta; - - m_activeSwipe.avgSpeed = (m_activeSwipe.avgSpeed * m_activeSwipe.speedPoints + abs(d)) / (m_activeSwipe.speedPoints + 1); - m_activeSwipe.speedPoints++; - - auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; - auto workspaceIDRight = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r+1" : "m+1")).id; - - if ((workspaceIDLeft == WORKSPACE_INVALID || workspaceIDRight == WORKSPACE_INVALID || workspaceIDLeft == m_activeSwipe.pWorkspaceBegin->m_id) && !*PSWIPENEW) { - m_activeSwipe.pWorkspaceBegin = nullptr; // invalidate the swipe - return; - } - - m_activeSwipe.pWorkspaceBegin->m_forceRendering = true; - - m_activeSwipe.delta = std::clamp(m_activeSwipe.delta, sc<double>(-SWIPEDISTANCE), sc<double>(SWIPEDISTANCE)); - - if ((m_activeSwipe.pWorkspaceBegin->m_id == workspaceIDLeft && *PSWIPENEW && (m_activeSwipe.delta < 0)) || - (m_activeSwipe.delta > 0 && m_activeSwipe.pWorkspaceBegin->getWindows() == 0 && workspaceIDRight <= m_activeSwipe.pWorkspaceBegin->m_id) || - (m_activeSwipe.delta < 0 && m_activeSwipe.pWorkspaceBegin->m_id <= workspaceIDLeft)) { - - m_activeSwipe.delta = 0; - g_pHyprRenderer->damageMonitor(m_activeSwipe.pMonitor.lock()); - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, 0.0)); - return; - } - - if (*PSWIPEDIRLOCK) { - if (m_activeSwipe.initialDirection != 0 && m_activeSwipe.initialDirection != (m_activeSwipe.delta < 0 ? -1 : 1)) - m_activeSwipe.delta = 0; - else if (m_activeSwipe.initialDirection == 0 && abs(m_activeSwipe.delta) > *PSWIPEDIRLOCKTHRESHOLD) - m_activeSwipe.initialDirection = m_activeSwipe.delta < 0 ? -1 : 1; - } - - if (m_activeSwipe.delta < 0) { - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft); - - if (workspaceIDLeft > m_activeSwipe.pWorkspaceBegin->m_id || !PWORKSPACE) { - if (*PSWIPENEW) { - g_pHyprRenderer->damageMonitor(m_activeSwipe.pMonitor.lock()); - - if (VERTANIMS) - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_activeSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); - else - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_activeSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); - - m_activeSwipe.pWorkspaceBegin->updateWindowDecos(); - return; - } - m_activeSwipe.delta = 0; - return; - } - - PWORKSPACE->m_forceRendering = true; - PWORKSPACE->m_alpha->setValueAndWarp(1.f); - - if (workspaceIDLeft != workspaceIDRight && workspaceIDRight != m_activeSwipe.pWorkspaceBegin->m_id) { - const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); - - if (PWORKSPACER) { - PWORKSPACER->m_forceRendering = false; - PWORKSPACER->m_alpha->setValueAndWarp(0.f); - } - } - - if (VERTANIMS) { - PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_activeSwipe.delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_activeSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); - } else { - PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(((-m_activeSwipe.delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0.0)); - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_activeSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); - } - - PWORKSPACE->updateWindowDecos(); - } else { - const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight); - - if (workspaceIDRight < m_activeSwipe.pWorkspaceBegin->m_id || !PWORKSPACE) { - if (*PSWIPENEW) { - g_pHyprRenderer->damageMonitor(m_activeSwipe.pMonitor.lock()); - - if (VERTANIMS) - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_activeSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); - else - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_activeSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); - - m_activeSwipe.pWorkspaceBegin->updateWindowDecos(); - return; - } - m_activeSwipe.delta = 0; - return; - } - - PWORKSPACE->m_forceRendering = true; - PWORKSPACE->m_alpha->setValueAndWarp(1.f); - - if (workspaceIDLeft != workspaceIDRight && workspaceIDLeft != m_activeSwipe.pWorkspaceBegin->m_id) { - const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); - - if (PWORKSPACEL) { - PWORKSPACEL->m_forceRendering = false; - PWORKSPACEL->m_alpha->setValueAndWarp(0.f); - } - } - - if (VERTANIMS) { - PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_activeSwipe.delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_activeSwipe.delta) / SWIPEDISTANCE) * YDISTANCE)); - } else { - PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(((-m_activeSwipe.delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0.0)); - m_activeSwipe.pWorkspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_activeSwipe.delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); - } - - PWORKSPACE->updateWindowDecos(); - } - - g_pHyprRenderer->damageMonitor(m_activeSwipe.pMonitor.lock()); - - m_activeSwipe.pWorkspaceBegin->updateWindowDecos(); - - if (*PSWIPEFOREVER) { - if (abs(m_activeSwipe.delta) >= SWIPEDISTANCE) { - onSwipeEnd({}); - beginWorkspaceSwipe(); - } - } -} diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp index c01b8b41..2d3842f9 100644 --- a/src/managers/input/Touch.cpp +++ b/src/managers/input/Touch.cpp @@ -7,9 +7,10 @@ #include "../../helpers/Monitor.hpp" #include "../../devices/ITouch.hpp" #include "../SeatManager.hpp" -#include "managers/AnimationManager.hpp" +#include "managers/animation/AnimationManager.hpp" #include "../HookSystemManager.hpp" #include "debug/Log.hpp" +#include "UnifiedWorkspaceSwipeGesture.hpp" void CInputManager::onTouchDown(ITouch::SDownEvent e) { m_lastInputTouch = true; @@ -39,7 +40,7 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { } // Don't propagate new touches when a workspace swipe is in progress. - if (m_activeSwipe.pWorkspaceBegin) { + if (g_pUnifiedWorkspaceSwipe->isGestureInProgress()) { return; // TODO: Don't swipe if you touched a floating window. } else if (*PSWIPETOUCH && (m_foundLSToFocus.expired() || m_foundLSToFocus->m_layer <= 1) && !g_pSessionLockManager->isSessionLocked()) { @@ -50,13 +51,13 @@ void CInputManager::onTouchDown(ITouch::SDownEvent e) { const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.m_bottom : gapsOut.m_right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->m_size.y : PMONITOR->m_size.x)); const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x); if (POSITION < TARGETLEFT || POSITION > TARGETRIGHT) { - beginWorkspaceSwipe(); - m_activeSwipe.touch_id = e.touchID; + g_pUnifiedWorkspaceSwipe->begin(); + g_pUnifiedWorkspaceSwipe->m_touchID = e.touchID; // Set the initial direction based on which edge you started from if (POSITION > 0.5) - m_activeSwipe.initialDirection = *PSWIPEINVR ? -1 : 1; + g_pUnifiedWorkspaceSwipe->m_initialDirection = *PSWIPEINVR ? -1 : 1; else - m_activeSwipe.initialDirection = *PSWIPEINVR ? 1 : -1; + g_pUnifiedWorkspaceSwipe->m_initialDirection = *PSWIPEINVR ? 1 : -1; return; } } @@ -109,10 +110,10 @@ void CInputManager::onTouchUp(ITouch::SUpEvent e) { m_lastInputTouch = true; EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e); - if (m_activeSwipe.pWorkspaceBegin) { + if (g_pUnifiedWorkspaceSwipe->isGestureInProgress()) { // If there was a swipe from this finger, end it. - if (e.touchID == m_activeSwipe.touch_id) - endWorkspaceSwipe(); + if (e.touchID == g_pUnifiedWorkspaceSwipe->m_touchID) + g_pUnifiedWorkspaceSwipe->end(); return; } @@ -124,30 +125,30 @@ void CInputManager::onTouchMove(ITouch::SMotionEvent e) { m_lastInputTouch = true; EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e); - if (m_activeSwipe.pWorkspaceBegin) { + if (g_pUnifiedWorkspaceSwipe->isGestureInProgress()) { // Do nothing if this is using a different finger. - if (e.touchID != m_activeSwipe.touch_id) + if (e.touchID != g_pUnifiedWorkspaceSwipe->m_touchID) return; - const auto ANIMSTYLE = m_activeSwipe.pWorkspaceBegin->m_renderOffset->getStyle(); + const auto ANIMSTYLE = g_pUnifiedWorkspaceSwipe->m_workspaceBegin->m_renderOffset->getStyle(); const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch_invert"); static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance"); const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, sc<int64_t>(1LL), sc<int64_t>(UINT32_MAX)); // Handle the workspace swipe if there is one - if (m_activeSwipe.initialDirection == -1) { + if (g_pUnifiedWorkspaceSwipe->m_initialDirection == -1) { if (*PSWIPEINVR) // go from 0 to -SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * ((VERTANIMS ? e.pos.y : e.pos.x) - 1)); + g_pUnifiedWorkspaceSwipe->update(SWIPEDISTANCE * ((VERTANIMS ? e.pos.y : e.pos.x) - 1)); else // go from 0 to -SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (-1 * (VERTANIMS ? e.pos.y : e.pos.x))); + g_pUnifiedWorkspaceSwipe->update(SWIPEDISTANCE * (-1 * (VERTANIMS ? e.pos.y : e.pos.x))); } else if (*PSWIPEINVR) // go from 0 to SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (VERTANIMS ? e.pos.y : e.pos.x)); + g_pUnifiedWorkspaceSwipe->update(SWIPEDISTANCE * (VERTANIMS ? e.pos.y : e.pos.x)); else // go from 0 to SWIPEDISTANCE - updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e.pos.y : e.pos.x))); + g_pUnifiedWorkspaceSwipe->update(SWIPEDISTANCE * (1 - (VERTANIMS ? e.pos.y : e.pos.x))); return; } if (m_touchData.touchFocusLockSurface) { diff --git a/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp b/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp new file mode 100644 index 00000000..01b92b48 --- /dev/null +++ b/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp @@ -0,0 +1,313 @@ +#include "UnifiedWorkspaceSwipeGesture.hpp" + +#include "../../Compositor.hpp" +#include "../../render/Renderer.hpp" +#include "InputManager.hpp" + +bool CUnifiedWorkspaceSwipeGesture::isGestureInProgress() { + return m_workspaceBegin; +} + +void CUnifiedWorkspaceSwipeGesture::begin() { + if (isGestureInProgress()) + return; + + const auto PWORKSPACE = g_pCompositor->m_lastMonitor->m_activeWorkspace; + + Debug::log(LOG, "CUnifiedWorkspaceSwipeGesture::begin: Starting a swipe from {}", PWORKSPACE->m_name); + + m_workspaceBegin = PWORKSPACE; + m_delta = 0; + m_monitor = g_pCompositor->m_lastMonitor; + m_avgSpeed = 0; + m_speedPoints = 0; + + if (PWORKSPACE->m_hasFullscreenWindow) { + for (auto const& ls : g_pCompositor->m_lastMonitor->m_layerSurfaceLayers[2]) { + *ls->m_alpha = 1.f; + } + } +} + +void CUnifiedWorkspaceSwipeGesture::update(double delta) { + if (!isGestureInProgress()) + return; + + static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance"); + static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); + static auto PSWIPEDIRLOCK = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock"); + static auto PSWIPEDIRLOCKTHRESHOLD = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_direction_lock_threshold"); + static auto PSWIPEFOREVER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_forever"); + static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r"); + static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); + + const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, sc<int64_t>(1LL), sc<int64_t>(UINT32_MAX)); + const auto XDISTANCE = m_monitor->m_size.x + *PWORKSPACEGAP; + const auto YDISTANCE = m_monitor->m_size.y + *PWORKSPACEGAP; + const auto ANIMSTYLE = m_workspaceBegin->m_renderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); + const double d = m_delta - delta; + m_delta = delta; + + m_avgSpeed = (m_avgSpeed * m_speedPoints + abs(d)) / (m_speedPoints + 1); + m_speedPoints++; + + auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; + auto workspaceIDRight = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r+1" : "m+1")).id; + + if ((workspaceIDLeft == WORKSPACE_INVALID || workspaceIDRight == WORKSPACE_INVALID || workspaceIDLeft == m_workspaceBegin->m_id) && !*PSWIPENEW) { + m_workspaceBegin = nullptr; // invalidate the swipe + return; + } + + m_workspaceBegin->m_forceRendering = true; + + m_delta = std::clamp(m_delta, sc<double>(-SWIPEDISTANCE), sc<double>(SWIPEDISTANCE)); + + if ((m_workspaceBegin->m_id == workspaceIDLeft && *PSWIPENEW && (m_delta < 0)) || + (m_delta > 0 && m_workspaceBegin->getWindows() == 0 && workspaceIDRight <= m_workspaceBegin->m_id) || (m_delta < 0 && m_workspaceBegin->m_id <= workspaceIDLeft)) { + + m_delta = 0; + g_pHyprRenderer->damageMonitor(m_monitor.lock()); + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, 0.0)); + return; + } + + if (*PSWIPEDIRLOCK) { + if (m_initialDirection != 0 && m_initialDirection != (m_delta < 0 ? -1 : 1)) + m_delta = 0; + else if (m_initialDirection == 0 && abs(m_delta) > *PSWIPEDIRLOCKTHRESHOLD) + m_initialDirection = m_delta < 0 ? -1 : 1; + } + + if (m_delta < 0) { + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + + if (workspaceIDLeft > m_workspaceBegin->m_id || !PWORKSPACE) { + if (*PSWIPENEW) { + g_pHyprRenderer->damageMonitor(m_monitor.lock()); + + if (VERTANIMS) + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_delta) / SWIPEDISTANCE) * YDISTANCE)); + else + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + + m_workspaceBegin->updateWindowDecos(); + return; + } + m_delta = 0; + return; + } + + PWORKSPACE->m_forceRendering = true; + PWORKSPACE->m_alpha->setValueAndWarp(1.f); + + if (workspaceIDLeft != workspaceIDRight && workspaceIDRight != m_workspaceBegin->m_id) { + const auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); + + if (PWORKSPACER) { + PWORKSPACER->m_forceRendering = false; + PWORKSPACER->m_alpha->setValueAndWarp(0.f); + } + } + + if (VERTANIMS) { + PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_delta) / SWIPEDISTANCE) * YDISTANCE - YDISTANCE)); + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_delta) / SWIPEDISTANCE) * YDISTANCE)); + } else { + PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(((-m_delta) / SWIPEDISTANCE) * XDISTANCE - XDISTANCE, 0.0)); + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + } + + PWORKSPACE->updateWindowDecos(); + } else { + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceIDRight); + + if (workspaceIDRight < m_workspaceBegin->m_id || !PWORKSPACE) { + if (*PSWIPENEW) { + g_pHyprRenderer->damageMonitor(m_monitor.lock()); + + if (VERTANIMS) + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_delta) / SWIPEDISTANCE) * YDISTANCE)); + else + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + + m_workspaceBegin->updateWindowDecos(); + return; + } + m_delta = 0; + return; + } + + PWORKSPACE->m_forceRendering = true; + PWORKSPACE->m_alpha->setValueAndWarp(1.f); + + if (workspaceIDLeft != workspaceIDRight && workspaceIDLeft != m_workspaceBegin->m_id) { + const auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + + if (PWORKSPACEL) { + PWORKSPACEL->m_forceRendering = false; + PWORKSPACEL->m_alpha->setValueAndWarp(0.f); + } + } + + if (VERTANIMS) { + PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_delta) / SWIPEDISTANCE) * YDISTANCE + YDISTANCE)); + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0.0, ((-m_delta) / SWIPEDISTANCE) * YDISTANCE)); + } else { + PWORKSPACE->m_renderOffset->setValueAndWarp(Vector2D(((-m_delta) / SWIPEDISTANCE) * XDISTANCE + XDISTANCE, 0.0)); + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(((-m_delta) / SWIPEDISTANCE) * XDISTANCE, 0.0)); + } + + PWORKSPACE->updateWindowDecos(); + } + + g_pHyprRenderer->damageMonitor(m_monitor.lock()); + + m_workspaceBegin->updateWindowDecos(); + + if (*PSWIPEFOREVER) { + if (abs(m_delta) >= SWIPEDISTANCE) { + end(); + begin(); + } + } +} + +void CUnifiedWorkspaceSwipeGesture::end() { + if (!isGestureInProgress()) + return; + + static auto PSWIPEPERC = CConfigValue<Hyprlang::FLOAT>("gestures:workspace_swipe_cancel_ratio"); + static auto PSWIPEDIST = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_distance"); + static auto PSWIPEFORC = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_min_speed_to_force"); + static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); + static auto PSWIPEUSER = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_use_r"); + static auto PWORKSPACEGAP = CConfigValue<Hyprlang::INT>("general:gaps_workspaces"); + const auto ANIMSTYLE = m_workspaceBegin->m_renderOffset->getStyle(); + const bool VERTANIMS = ANIMSTYLE == "slidevert" || ANIMSTYLE.starts_with("slidefadevert"); + + // commit + auto workspaceIDLeft = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r-1" : "m-1")).id; + auto workspaceIDRight = getWorkspaceIDNameFromString((*PSWIPEUSER ? "r+1" : "m+1")).id; + const auto SWIPEDISTANCE = std::clamp(*PSWIPEDIST, sc<int64_t>(1LL), sc<int64_t>(UINT32_MAX)); + + // If we've been swiping off the right end with PSWIPENEW enabled, there is + // no workspace there yet, and we need to choose an ID for a new one now. + if (workspaceIDRight <= m_workspaceBegin->m_id && *PSWIPENEW) + workspaceIDRight = getWorkspaceIDNameFromString("r+1").id; + + auto PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); // not guaranteed if PSWIPENEW || PSWIPENUMBER + auto PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); // not guaranteed if PSWIPENUMBER + + const auto RENDEROFFSETMIDDLE = m_workspaceBegin->m_renderOffset->value(); + const auto XDISTANCE = m_monitor->m_size.x + *PWORKSPACEGAP; + const auto YDISTANCE = m_monitor->m_size.y + *PWORKSPACEGAP; + + PHLWORKSPACE pSwitchedTo = nullptr; + + if ((abs(m_delta) < SWIPEDISTANCE * *PSWIPEPERC && (*PSWIPEFORC == 0 || (*PSWIPEFORC != 0 && m_avgSpeed < *PSWIPEFORC))) || abs(m_delta) < 2) { + // revert + if (abs(m_delta) < 2) { + if (PWORKSPACEL) + PWORKSPACEL->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); + if (PWORKSPACER) + PWORKSPACER->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); + m_workspaceBegin->m_renderOffset->setValueAndWarp(Vector2D(0, 0)); + } else { + if (m_delta < 0) { + // to left + + if (PWORKSPACEL) { + if (VERTANIMS) + *PWORKSPACEL->m_renderOffset = Vector2D{0.0, -YDISTANCE}; + else + *PWORKSPACEL->m_renderOffset = Vector2D{-XDISTANCE, 0.0}; + } + } else if (PWORKSPACER) { + // to right + if (VERTANIMS) + *PWORKSPACER->m_renderOffset = Vector2D{0.0, YDISTANCE}; + else + *PWORKSPACER->m_renderOffset = Vector2D{XDISTANCE, 0.0}; + } + + *m_workspaceBegin->m_renderOffset = Vector2D(); + } + + pSwitchedTo = m_workspaceBegin; + } else if (m_delta < 0) { + // switch to left + const auto RENDEROFFSET = PWORKSPACEL ? PWORKSPACEL->m_renderOffset->value() : Vector2D(); + + if (PWORKSPACEL) + m_monitor->changeWorkspace(workspaceIDLeft); + else { + m_monitor->changeWorkspace(g_pCompositor->createNewWorkspace(workspaceIDLeft, m_monitor->m_id)); + PWORKSPACEL = g_pCompositor->getWorkspaceByID(workspaceIDLeft); + PWORKSPACEL->rememberPrevWorkspace(m_workspaceBegin); + } + + PWORKSPACEL->m_renderOffset->setValue(RENDEROFFSET); + PWORKSPACEL->m_alpha->setValueAndWarp(1.f); + + m_workspaceBegin->m_renderOffset->setValue(RENDEROFFSETMIDDLE); + if (VERTANIMS) + *m_workspaceBegin->m_renderOffset = Vector2D(0.0, YDISTANCE); + else + *m_workspaceBegin->m_renderOffset = Vector2D(XDISTANCE, 0.0); + m_workspaceBegin->m_alpha->setValueAndWarp(1.f); + + g_pInputManager->unconstrainMouse(); + + Debug::log(LOG, "Ended swipe to the left"); + + pSwitchedTo = PWORKSPACEL; + } else { + // switch to right + const auto RENDEROFFSET = PWORKSPACER ? PWORKSPACER->m_renderOffset->value() : Vector2D(); + + if (PWORKSPACER) + m_monitor->changeWorkspace(workspaceIDRight); + else { + m_monitor->changeWorkspace(g_pCompositor->createNewWorkspace(workspaceIDRight, m_monitor->m_id)); + PWORKSPACER = g_pCompositor->getWorkspaceByID(workspaceIDRight); + PWORKSPACER->rememberPrevWorkspace(m_workspaceBegin); + } + + PWORKSPACER->m_renderOffset->setValue(RENDEROFFSET); + PWORKSPACER->m_alpha->setValueAndWarp(1.f); + + m_workspaceBegin->m_renderOffset->setValue(RENDEROFFSETMIDDLE); + if (VERTANIMS) + *m_workspaceBegin->m_renderOffset = Vector2D(0.0, -YDISTANCE); + else + *m_workspaceBegin->m_renderOffset = Vector2D(-XDISTANCE, 0.0); + m_workspaceBegin->m_alpha->setValueAndWarp(1.f); + + g_pInputManager->unconstrainMouse(); + + Debug::log(LOG, "Ended swipe to the right"); + + pSwitchedTo = PWORKSPACER; + } + m_workspaceBegin->rememberPrevWorkspace(pSwitchedTo); + + g_pHyprRenderer->damageMonitor(m_monitor.lock()); + + if (PWORKSPACEL) + PWORKSPACEL->m_forceRendering = false; + if (PWORKSPACER) + PWORKSPACER->m_forceRendering = false; + m_workspaceBegin->m_forceRendering = false; + + m_workspaceBegin = nullptr; + m_initialDirection = 0; + + g_pInputManager->refocus(); + + // apply alpha + for (auto const& ls : g_pCompositor->m_lastMonitor->m_layerSurfaceLayers[2]) { + *ls->m_alpha = pSwitchedTo->m_hasFullscreenWindow && pSwitchedTo->m_fullscreenMode == FSMODE_FULLSCREEN ? 0.f : 1.f; + } +}
\ No newline at end of file diff --git a/src/managers/input/UnifiedWorkspaceSwipeGesture.hpp b/src/managers/input/UnifiedWorkspaceSwipeGesture.hpp new file mode 100644 index 00000000..4dbb6c5d --- /dev/null +++ b/src/managers/input/UnifiedWorkspaceSwipeGesture.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "../../helpers/memory/Memory.hpp" +#include "../../desktop/DesktopTypes.hpp" + +class CUnifiedWorkspaceSwipeGesture { + public: + void begin(); + void update(double delta); + void end(); + + bool isGestureInProgress(); + + private: + PHLWORKSPACE m_workspaceBegin = nullptr; + PHLMONITORREF m_monitor; + + double m_delta = 0; + int m_initialDirection = 0; + float m_avgSpeed = 0; + int m_speedPoints = 0; + int m_touchID = 0; + + friend class CWorkspaceSwipeGesture; + friend class CInputManager; +}; + +inline UP<CUnifiedWorkspaceSwipeGesture> g_pUnifiedWorkspaceSwipe = makeUnique<CUnifiedWorkspaceSwipeGesture>(); diff --git a/src/managers/input/trackpad/GestureTypes.hpp b/src/managers/input/trackpad/GestureTypes.hpp new file mode 100644 index 00000000..89f69638 --- /dev/null +++ b/src/managers/input/trackpad/GestureTypes.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include <cstdint> + +enum eTrackpadGestureDirection : uint8_t { + TRACKPAD_GESTURE_DIR_NONE = 0, + TRACKPAD_GESTURE_DIR_SWIPE, + TRACKPAD_GESTURE_DIR_LEFT, + TRACKPAD_GESTURE_DIR_RIGHT, + TRACKPAD_GESTURE_DIR_UP, + TRACKPAD_GESTURE_DIR_DOWN, + TRACKPAD_GESTURE_DIR_VERTICAL, + TRACKPAD_GESTURE_DIR_HORIZONTAL, + TRACKPAD_GESTURE_DIR_PINCH, + TRACKPAD_GESTURE_DIR_PINCH_OUT, + TRACKPAD_GESTURE_DIR_PINCH_IN, +};
\ No newline at end of file diff --git a/src/managers/input/trackpad/TrackpadGestures.cpp b/src/managers/input/trackpad/TrackpadGestures.cpp new file mode 100644 index 00000000..1d628da4 --- /dev/null +++ b/src/managers/input/trackpad/TrackpadGestures.cpp @@ -0,0 +1,221 @@ +#include "TrackpadGestures.hpp" + +#include "../InputManager.hpp" + +#include <ranges> + +void CTrackpadGestures::clearGestures() { + m_gestures.clear(); +} + +eTrackpadGestureDirection CTrackpadGestures::dirForString(const std::string_view& s) { + std::string lc = std::string{s}; + std::ranges::transform(lc, lc.begin(), ::tolower); + + if (lc == "swipe") + return TRACKPAD_GESTURE_DIR_SWIPE; + if (lc == "left" || lc == "l") + return TRACKPAD_GESTURE_DIR_LEFT; + if (lc == "right" || lc == "r") + return TRACKPAD_GESTURE_DIR_RIGHT; + if (lc == "up" || lc == "u" || lc == "top" || lc == "t") + return TRACKPAD_GESTURE_DIR_UP; + if (lc == "down" || lc == "d" || lc == "bottom" || lc == "b") + return TRACKPAD_GESTURE_DIR_DOWN; + if (lc == "horizontal" || lc == "horiz") + return TRACKPAD_GESTURE_DIR_HORIZONTAL; + if (lc == "vertical" || lc == "vert") + return TRACKPAD_GESTURE_DIR_VERTICAL; + if (lc == "pinch") + return TRACKPAD_GESTURE_DIR_PINCH; + if (lc == "pinchin" || lc == "zoomin") + return TRACKPAD_GESTURE_DIR_PINCH_IN; + if (lc == "pinchout" || lc == "zoomout") + return TRACKPAD_GESTURE_DIR_PINCH_OUT; + + return TRACKPAD_GESTURE_DIR_NONE; +} + +const char* CTrackpadGestures::stringForDir(eTrackpadGestureDirection dir) { + switch (dir) { + case TRACKPAD_GESTURE_DIR_HORIZONTAL: return "HORIZONTAL"; + case TRACKPAD_GESTURE_DIR_VERTICAL: return "VERTICAL"; + case TRACKPAD_GESTURE_DIR_LEFT: return "LEFT"; + case TRACKPAD_GESTURE_DIR_RIGHT: return "RIGHT"; + case TRACKPAD_GESTURE_DIR_UP: return "UP"; + case TRACKPAD_GESTURE_DIR_DOWN: return "DOWN"; + case TRACKPAD_GESTURE_DIR_SWIPE: return "SWIPE"; + case TRACKPAD_GESTURE_DIR_PINCH: return "PINCH"; + case TRACKPAD_GESTURE_DIR_PINCH_IN: return "PINCH_IN"; + case TRACKPAD_GESTURE_DIR_PINCH_OUT: return "PINCH_OUT"; + default: return "ERROR"; + } + return "ERROR"; +} + +std::expected<void, std::string> CTrackpadGestures::addGesture(UP<ITrackpadGesture>&& gesture, size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, + float deltaScale) { + for (const auto& g : m_gestures) { + if (g->fingerCount != fingerCount) + continue; + + if (g->modMask != modMask) + continue; + + eTrackpadGestureDirection axis = TRACKPAD_GESTURE_DIR_NONE; + switch (direction) { + case TRACKPAD_GESTURE_DIR_UP: + case TRACKPAD_GESTURE_DIR_DOWN: + case TRACKPAD_GESTURE_DIR_VERTICAL: axis = TRACKPAD_GESTURE_DIR_VERTICAL; break; + case TRACKPAD_GESTURE_DIR_LEFT: + case TRACKPAD_GESTURE_DIR_RIGHT: + case TRACKPAD_GESTURE_DIR_HORIZONTAL: axis = TRACKPAD_GESTURE_DIR_HORIZONTAL; break; + case TRACKPAD_GESTURE_DIR_SWIPE: axis = TRACKPAD_GESTURE_DIR_SWIPE; break; + case TRACKPAD_GESTURE_DIR_PINCH: + case TRACKPAD_GESTURE_DIR_PINCH_IN: + case TRACKPAD_GESTURE_DIR_PINCH_OUT: axis = TRACKPAD_GESTURE_DIR_PINCH; break; + default: TRACKPAD_GESTURE_DIR_NONE; break; + } + + if (g->direction == axis || g->direction == direction || + ((axis == TRACKPAD_GESTURE_DIR_VERTICAL || axis == TRACKPAD_GESTURE_DIR_HORIZONTAL) && g->direction == TRACKPAD_GESTURE_DIR_SWIPE)) { + return std::unexpected( + std::format("Gesture will be overshadowed by a previous gesture. Previous {} shadows new {}", stringForDir(g->direction), stringForDir(direction))); + } + } + + m_gestures.emplace_back(makeShared<CTrackpadGestures::SGestureData>(std::move(gesture), fingerCount, modMask, direction, deltaScale)); + + return {}; +} + +void CTrackpadGestures::gestureBegin(const IPointer::SSwipeBeginEvent& e) { + if (m_activeGesture) { + Debug::log(ERR, "CTrackpadGestures::gestureBegin (swipe) but m_activeGesture is already present"); + return; + } + + m_gestureFindFailed = false; + + // nothing here. We need to wait for the first update to determine the delta. +} + +void CTrackpadGestures::gestureUpdate(const IPointer::SSwipeUpdateEvent& e) { + if (m_gestureFindFailed) + return; + + // 5 was chosen because I felt like that's a good number. + if (!m_activeGesture && (std::abs(e.delta.x) < 5 && std::abs(e.delta.y) < 5)) { + Debug::log(TRACE, "CTrackpadGestures::gestureUpdate (swipe): gesture delta too small to start considering, waiting"); + return; + } + + if (!m_activeGesture) { + // try to find a gesture that matches our current state + + auto direction = TRACKPAD_GESTURE_DIR_NONE; + auto axis = std::abs(e.delta.x) > std::abs(e.delta.y) ? TRACKPAD_GESTURE_DIR_HORIZONTAL : TRACKPAD_GESTURE_DIR_VERTICAL; + + if (axis == TRACKPAD_GESTURE_DIR_HORIZONTAL) + direction = e.delta.x < 0 ? TRACKPAD_GESTURE_DIR_LEFT : TRACKPAD_GESTURE_DIR_RIGHT; + else + direction = e.delta.y < 0 ? TRACKPAD_GESTURE_DIR_UP : TRACKPAD_GESTURE_DIR_DOWN; + + const auto MODS = g_pInputManager->getModsFromAllKBs(); + + for (const auto& g : m_gestures) { + if (g->direction != axis && g->direction != direction && g->direction != TRACKPAD_GESTURE_DIR_SWIPE) + continue; + + if (g->fingerCount != e.fingers) + continue; + + if (g->modMask != MODS) + continue; + + m_activeGesture = g; + g->currentDirection = g->gesture->isDirectionSensitive() ? g->direction : direction; + m_activeGesture->gesture->begin({.swipe = &e, .direction = direction, .scale = g->deltaScale}); + break; + } + + if (!m_activeGesture) { + m_gestureFindFailed = true; + return; + } + } + + m_activeGesture->gesture->update({.swipe = &e, .direction = m_activeGesture->currentDirection, .scale = m_activeGesture->deltaScale}); +} + +void CTrackpadGestures::gestureEnd(const IPointer::SSwipeEndEvent& e) { + if (!m_activeGesture) + return; + + m_activeGesture->gesture->end({.swipe = &e, .direction = m_activeGesture->direction, .scale = m_activeGesture->deltaScale}); + + m_activeGesture.reset(); +} + +void CTrackpadGestures::gestureBegin(const IPointer::SPinchBeginEvent& e) { + if (m_activeGesture) { + Debug::log(ERR, "CTrackpadGestures::gestureBegin (pinch) but m_activeGesture is already present"); + return; + } + + m_gestureFindFailed = false; + + // nothing here. We need to wait for the first update to determine the delta. +} + +void CTrackpadGestures::gestureUpdate(const IPointer::SPinchUpdateEvent& e) { + if (m_gestureFindFailed) + return; + + // 0.1 was chosen because I felt like that's a good number. + if (!m_activeGesture && std::abs(e.scale - 1.F) < 0.1) { + Debug::log(TRACE, "CTrackpadGestures::gestureUpdate (pinch): gesture delta too small to start considering, waiting"); + return; + } + + if (!m_activeGesture) { + // try to find a gesture that matches our current state + + auto direction = e.scale < 1.F ? TRACKPAD_GESTURE_DIR_PINCH_OUT : TRACKPAD_GESTURE_DIR_PINCH_IN; + auto axis = TRACKPAD_GESTURE_DIR_PINCH; + + const auto MODS = g_pInputManager->getModsFromAllKBs(); + + for (const auto& g : m_gestures) { + if (g->direction != axis && g->direction != direction) + continue; + + if (g->fingerCount != e.fingers) + continue; + + if (g->modMask != MODS) + continue; + + m_activeGesture = g; + g->currentDirection = g->gesture->isDirectionSensitive() ? g->direction : direction; + m_activeGesture->gesture->begin({.pinch = &e, .direction = direction}); + break; + } + + if (!m_activeGesture) { + m_gestureFindFailed = true; + return; + } + } + + m_activeGesture->gesture->update({.pinch = &e, .direction = m_activeGesture->currentDirection}); +} + +void CTrackpadGestures::gestureEnd(const IPointer::SPinchEndEvent& e) { + if (!m_activeGesture) + return; + + m_activeGesture->gesture->end({.pinch = &e, .direction = m_activeGesture->direction}); + + m_activeGesture.reset(); +} diff --git a/src/managers/input/trackpad/TrackpadGestures.hpp b/src/managers/input/trackpad/TrackpadGestures.hpp new file mode 100644 index 00000000..3d0745df --- /dev/null +++ b/src/managers/input/trackpad/TrackpadGestures.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "../../../devices/IPointer.hpp" + +#include "gestures/ITrackpadGesture.hpp" +#include "GestureTypes.hpp" + +#include <vector> +#include <expected> + +class CTrackpadGestures { + public: + void clearGestures(); + std::expected<void, std::string> addGesture(UP<ITrackpadGesture>&& gesture, size_t fingerCount, eTrackpadGestureDirection direction, uint32_t modMask, float deltaScale); + + void gestureBegin(const IPointer::SSwipeBeginEvent& e); + void gestureUpdate(const IPointer::SSwipeUpdateEvent& e); + void gestureEnd(const IPointer::SSwipeEndEvent& e); + + void gestureBegin(const IPointer::SPinchBeginEvent& e); + void gestureUpdate(const IPointer::SPinchUpdateEvent& e); + void gestureEnd(const IPointer::SPinchEndEvent& e); + + eTrackpadGestureDirection dirForString(const std::string_view& s); + const char* stringForDir(eTrackpadGestureDirection dir); + + private: + struct SGestureData { + UP<ITrackpadGesture> gesture; + size_t fingerCount = 0; + uint32_t modMask = 0; + eTrackpadGestureDirection direction = TRACKPAD_GESTURE_DIR_NONE; // configured dir + float deltaScale = 1.F; + eTrackpadGestureDirection currentDirection = TRACKPAD_GESTURE_DIR_NONE; // actual dir of that select swipe + }; + + std::vector<SP<SGestureData>> m_gestures; + + SP<SGestureData> m_activeGesture = nullptr; + bool m_gestureFindFailed = false; +}; + +inline UP<CTrackpadGestures> g_pTrackpadGestures = makeUnique<CTrackpadGestures>(); diff --git a/src/managers/input/trackpad/gestures/CloseGesture.cpp b/src/managers/input/trackpad/gestures/CloseGesture.cpp new file mode 100644 index 00000000..59beb712 --- /dev/null +++ b/src/managers/input/trackpad/gestures/CloseGesture.cpp @@ -0,0 +1,145 @@ +#include "CloseGesture.hpp" + +#include "../../../../Compositor.hpp" +#include "../../../../managers/LayoutManager.hpp" +#include "../../../../managers/animation/DesktopAnimationManager.hpp" +#include "../../../../render/Renderer.hpp" +#include "../../../../managers/eventLoop/EventLoopManager.hpp" +#include "../../../../managers/eventLoop/EventLoopTimer.hpp" +#include "../../../../config/ConfigValue.hpp" + +constexpr const float MAX_DISTANCE = 200.F; + +static std::vector<SP<CEventLoopTimer>> trackpadCloseTimers; + +// +static Vector2D lerpVal(const Vector2D& from, const Vector2D& to, const float& t) { + return Vector2D{ + from.x + ((to.x - from.x) * t), + from.y + ((to.y - from.y) * t), + }; +} + +static float lerpVal(const float& from, const float& to, const float& t) { + return from + ((to - from) * t); +} + +void CCloseTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ITrackpadGesture::begin(e); + + m_window = g_pCompositor->m_lastWindow; + + if (!m_window) + return; + + m_alphaFrom = m_window->m_alpha->goal(); + m_posFrom = m_window->m_realPosition->goal(); + m_sizeFrom = m_window->m_realSize->goal(); + + g_pDesktopAnimationManager->startAnimation(m_window.lock(), CDesktopAnimationManager::ANIMATION_TYPE_OUT, true); + *m_window->m_alpha = 0.f; + + m_alphaTo = m_window->m_alpha->goal(); + m_posTo = m_window->m_realPosition->goal(); + m_sizeTo = m_window->m_realSize->goal(); + + m_window->m_alpha->setValueAndWarp(m_alphaFrom); + m_window->m_realPosition->setValueAndWarp(m_posFrom); + m_window->m_realSize->setValueAndWarp(m_sizeFrom); + + m_lastDelta = 0.F; +} + +void CCloseTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + if (!m_window) + return; + + g_pHyprRenderer->damageWindow(m_window.lock()); + + m_lastDelta += distance(e); + + const auto FADEPERCENT = std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + m_window->m_alpha->setValueAndWarp(lerpVal(m_alphaFrom, m_alphaTo, FADEPERCENT)); + m_window->m_realPosition->setValueAndWarp(lerpVal(m_posFrom, m_posTo, FADEPERCENT)); + m_window->m_realSize->setValueAndWarp(lerpVal(m_sizeFrom, m_sizeTo, FADEPERCENT)); + + g_pDecorationPositioner->onWindowUpdate(m_window.lock()); + + g_pHyprRenderer->damageWindow(m_window.lock()); +} + +void CCloseTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + static const auto PTIMEOUT = CConfigValue<Hyprlang::INT>("gestures:close_max_timeout"); + + if (!m_window) + return; + + const auto COMPLETION = std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + if (COMPLETION < 0.2F) { + // revert the animation + g_pHyprRenderer->damageWindow(m_window.lock()); + *m_window->m_alpha = m_alphaFrom; + *m_window->m_realPosition = m_posFrom; + *m_window->m_realSize = m_sizeFrom; + return; + } + + // commence. Close the window and restore our current state to avoid a harsh anim + const auto CURRENT_ALPHA = m_window->m_alpha->value(); + const auto CURRENT_POS = m_window->m_realPosition->value(); + const auto CURRENT_SIZE = m_window->m_realSize->value(); + + g_pCompositor->closeWindow(m_window.lock()); + + m_window->m_alpha->setValueAndWarp(CURRENT_ALPHA); + m_window->m_realPosition->setValueAndWarp(CURRENT_POS); + m_window->m_realSize->setValueAndWarp(CURRENT_SIZE); + + // this is a kinda hack, but oh well. + m_window->m_realPosition->setCallbackOnBegin( + [CURRENT_POS, window = m_window](auto) { + if (!window || !window->m_isMapped) + return; + + window->m_realPosition->setValueAndWarp(CURRENT_POS); + }, + false); + + m_window->m_realSize->setCallbackOnBegin( + [CURRENT_SIZE, window = m_window](auto) { + if (!window || !window->m_isMapped) + return; + + window->m_realSize->setValueAndWarp(CURRENT_SIZE); + }, + false); + + // we give windows 2s to close. If they don't, pop them back in. + auto timer = makeShared<CEventLoopTimer>( + std::chrono::milliseconds(*PTIMEOUT), + [window = m_window](SP<CEventLoopTimer> self, void* data) { + std::erase(trackpadCloseTimers, self); + + // if after 2 seconds the window is still alive and mapped, we revert our changes. + if (!window) + return; + + window->m_realPosition->setCallbackOnBegin(nullptr); + window->m_realSize->setCallbackOnBegin(nullptr); + + if (!window->m_isMapped) + return; + + g_pLayoutManager->getCurrentLayout()->recalculateWindow(window.lock()); + g_pCompositor->updateWindowAnimatedDecorationValues(window.lock()); + window->sendWindowSize(true); + *window->m_alpha = 1.F; + }, + nullptr); + trackpadCloseTimers.emplace_back(timer); + g_pEventLoopManager->addTimer(timer); + + m_window.reset(); +} diff --git a/src/managers/input/trackpad/gestures/CloseGesture.hpp b/src/managers/input/trackpad/gestures/CloseGesture.hpp new file mode 100644 index 00000000..a8e18fd2 --- /dev/null +++ b/src/managers/input/trackpad/gestures/CloseGesture.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "ITrackpadGesture.hpp" + +#include "../../../../desktop/DesktopTypes.hpp" + +class CCloseTrackpadGesture : public ITrackpadGesture { + public: + CCloseTrackpadGesture() = default; + virtual ~CCloseTrackpadGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + private: + PHLWINDOWREF m_window; + + Vector2D m_posFrom, m_posTo, m_sizeFrom, m_sizeTo; + float m_alphaFrom = 0.F, m_alphaTo = 0.F; + + float m_lastDelta = 0.F; +}; diff --git a/src/managers/input/trackpad/gestures/DispatcherGesture.cpp b/src/managers/input/trackpad/gestures/DispatcherGesture.cpp new file mode 100644 index 00000000..4d76a671 --- /dev/null +++ b/src/managers/input/trackpad/gestures/DispatcherGesture.cpp @@ -0,0 +1,22 @@ +#include "DispatcherGesture.hpp" + +#include "../../../../managers/KeybindManager.hpp" + +CDispatcherTrackpadGesture::CDispatcherTrackpadGesture(const std::string& dispatcher, const std::string& data) : m_dispatcher(dispatcher), m_data(data) { + ; +} + +void CDispatcherTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ; // intentionally blank +} + +void CDispatcherTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + ; // intentionally blank +} + +void CDispatcherTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + if (!g_pKeybindManager->m_dispatchers.contains(m_dispatcher)) + return; + + g_pKeybindManager->m_dispatchers.at(m_dispatcher)(m_data); +} diff --git a/src/managers/input/trackpad/gestures/DispatcherGesture.hpp b/src/managers/input/trackpad/gestures/DispatcherGesture.hpp new file mode 100644 index 00000000..b15abbed --- /dev/null +++ b/src/managers/input/trackpad/gestures/DispatcherGesture.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "ITrackpadGesture.hpp" + +class CDispatcherTrackpadGesture : public ITrackpadGesture { + public: + CDispatcherTrackpadGesture(const std::string& dispatcher, const std::string& data); + virtual ~CDispatcherTrackpadGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + private: + std::string m_dispatcher, m_data; +}; diff --git a/src/managers/input/trackpad/gestures/FloatGesture.cpp b/src/managers/input/trackpad/gestures/FloatGesture.cpp new file mode 100644 index 00000000..97e4c98f --- /dev/null +++ b/src/managers/input/trackpad/gestures/FloatGesture.cpp @@ -0,0 +1,88 @@ +#include "FloatGesture.hpp" + +#include "../../../../Compositor.hpp" +#include "../../../../managers/LayoutManager.hpp" +#include "../../../../render/Renderer.hpp" + +constexpr const float MAX_DISTANCE = 250.F; + +// +static Vector2D lerpVal(const Vector2D& from, const Vector2D& to, const float& t) { + return Vector2D{ + from.x + ((to.x - from.x) * t), + from.y + ((to.y - from.y) * t), + }; +} + +CFloatTrackpadGesture::CFloatTrackpadGesture(const std::string_view& data) { + std::string lc = std::string{data}; + std::ranges::transform(lc, lc.begin(), ::tolower); + + if (lc.starts_with("float")) + m_mode = FLOAT_MODE_FLOAT; + else if (lc.starts_with("tile")) + m_mode == FLOAT_MODE_TILE; + else + m_mode = FLOAT_MODE_TOGGLE; +} + +void CFloatTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ITrackpadGesture::begin(e); + + m_window = g_pCompositor->m_lastWindow; + + if (!m_window) + return; + + if ((m_window->m_isFloating && m_mode == FLOAT_MODE_FLOAT) || (!m_window->m_isFloating && m_mode == FLOAT_MODE_TILE)) { + m_window.reset(); + return; + } + + m_window->m_isFloating = !m_window->m_isFloating; + g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(m_window.lock()); + + m_posFrom = m_window->m_realPosition->begun(); + m_sizeFrom = m_window->m_realSize->begun(); + + m_posTo = m_window->m_realPosition->goal(); + m_sizeTo = m_window->m_realSize->goal(); + + m_lastDelta = 0.F; +} + +void CFloatTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + if (!m_window) + return; + + g_pHyprRenderer->damageWindow(m_window.lock()); + + m_lastDelta += distance(e); + + const auto FADEPERCENT = std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + m_window->m_realPosition->setValueAndWarp(lerpVal(m_posFrom, m_posTo, FADEPERCENT)); + m_window->m_realSize->setValueAndWarp(lerpVal(m_sizeFrom, m_sizeTo, FADEPERCENT)); + + g_pDecorationPositioner->onWindowUpdate(m_window.lock()); + + g_pHyprRenderer->damageWindow(m_window.lock()); +} + +void CFloatTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + if (!m_window) + return; + + const auto COMPLETION = std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + if (COMPLETION < 0.2F) { + // revert the animation + g_pHyprRenderer->damageWindow(m_window.lock()); + m_window->m_isFloating = !m_window->m_isFloating; + g_pLayoutManager->getCurrentLayout()->changeWindowFloatingMode(m_window.lock()); + return; + } + + *m_window->m_realPosition = m_posTo; + *m_window->m_realSize = m_sizeTo; +} diff --git a/src/managers/input/trackpad/gestures/FloatGesture.hpp b/src/managers/input/trackpad/gestures/FloatGesture.hpp new file mode 100644 index 00000000..4132a1ac --- /dev/null +++ b/src/managers/input/trackpad/gestures/FloatGesture.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "ITrackpadGesture.hpp" + +#include "../../../../desktop/DesktopTypes.hpp" + +class CFloatTrackpadGesture : public ITrackpadGesture { + public: + CFloatTrackpadGesture(const std::string_view& mode); + virtual ~CFloatTrackpadGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + private: + PHLWINDOWREF m_window; + + Vector2D m_posFrom, m_posTo, m_sizeFrom, m_sizeTo; + + float m_lastDelta = 0; + + enum eMode : uint8_t { + FLOAT_MODE_TOGGLE = 0, + FLOAT_MODE_FLOAT, + FLOAT_MODE_TILE, + }; + + eMode m_mode = FLOAT_MODE_TOGGLE; +}; diff --git a/src/managers/input/trackpad/gestures/FullscreenGesture.cpp b/src/managers/input/trackpad/gestures/FullscreenGesture.cpp new file mode 100644 index 00000000..14e99238 --- /dev/null +++ b/src/managers/input/trackpad/gestures/FullscreenGesture.cpp @@ -0,0 +1,97 @@ +#include "FullscreenGesture.hpp" + +#include "../../../../Compositor.hpp" +#include "../../../../render/Renderer.hpp" +#include "../../../animation/DesktopAnimationManager.hpp" + +constexpr const float MAX_DISTANCE = 250.F; + +// +static Vector2D lerpVal(const Vector2D& from, const Vector2D& to, const float& t) { + return Vector2D{ + from.x + ((to.x - from.x) * t), + from.y + ((to.y - from.y) * t), + }; +} + +CFullscreenTrackpadGesture::CFullscreenTrackpadGesture(const std::string_view& mode) { + std::string lc = std::string{mode}; + std::ranges::transform(lc, lc.begin(), ::tolower); + + if (lc.starts_with("fullscreen")) + m_mode = MODE_FULLSCREEN; + else if (lc.starts_with("maximize")) + m_mode == MODE_MAXIMIZE; + else + m_mode = MODE_FULLSCREEN; +} + +void CFullscreenTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ITrackpadGesture::begin(e); + + m_window = g_pCompositor->m_lastWindow; + + if (!m_window) + return; + + m_posFrom = m_window->m_realPosition->goal(); + m_sizeFrom = m_window->m_realSize->goal(); + + m_originalMode = m_window->m_fullscreenState.internal; + + g_pCompositor->setWindowFullscreenInternal(m_window.lock(), m_window->m_fullscreenState.internal == FSMODE_NONE ? fsModeForMode(m_mode) : FSMODE_NONE); + + m_posTo = m_window->m_realPosition->goal(); + m_sizeTo = m_window->m_realSize->goal(); + + m_lastDelta = 0.F; +} + +void CFullscreenTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + if (!m_window) + return; + + g_pHyprRenderer->damageWindow(m_window.lock()); + + m_lastDelta += distance(e); + + const auto FADEPERCENT = std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + m_window->m_realPosition->setValueAndWarp(lerpVal(m_posFrom, m_posTo, FADEPERCENT)); + m_window->m_realSize->setValueAndWarp(lerpVal(m_sizeFrom, m_sizeTo, FADEPERCENT)); + + g_pDesktopAnimationManager->overrideFullscreenFadeAmount(m_window->m_workspace, m_originalMode == FSMODE_NONE ? 1.F - FADEPERCENT : FADEPERCENT, m_window.lock()); + + g_pDecorationPositioner->onWindowUpdate(m_window.lock()); + + g_pHyprRenderer->damageWindow(m_window.lock()); +} + +void CFullscreenTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + if (!m_window) + return; + + const auto COMPLETION = std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + if (COMPLETION < 0.2F) { + // revert the animation + g_pHyprRenderer->damageWindow(m_window.lock()); + m_window->m_isFloating = !m_window->m_isFloating; + g_pDesktopAnimationManager->overrideFullscreenFadeAmount(m_window->m_workspace, m_originalMode == FSMODE_NONE ? 1.F : 0.F, m_window.lock()); + g_pCompositor->setWindowFullscreenInternal(m_window.lock(), m_window->m_fullscreenState.internal == FSMODE_NONE ? m_originalMode : FSMODE_NONE); + return; + } + + *m_window->m_realPosition = m_posTo; + *m_window->m_realSize = m_sizeTo; + g_pDesktopAnimationManager->overrideFullscreenFadeAmount(m_window->m_workspace, m_originalMode == FSMODE_NONE ? 0.F : 1.F); +} + +eFullscreenMode CFullscreenTrackpadGesture::fsModeForMode(eMode mode) { + switch (mode) { + case MODE_FULLSCREEN: return FSMODE_FULLSCREEN; + case MODE_MAXIMIZE: return FSMODE_MAXIMIZED; + default: break; + } + return FSMODE_FULLSCREEN; +} diff --git a/src/managers/input/trackpad/gestures/FullscreenGesture.hpp b/src/managers/input/trackpad/gestures/FullscreenGesture.hpp new file mode 100644 index 00000000..dd125e5b --- /dev/null +++ b/src/managers/input/trackpad/gestures/FullscreenGesture.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "ITrackpadGesture.hpp" + +#include "../../../../desktop/DesktopTypes.hpp" +#include "../../../../desktop/Workspace.hpp" + +class CFullscreenTrackpadGesture : public ITrackpadGesture { + public: + CFullscreenTrackpadGesture(const std::string_view& mode); + virtual ~CFullscreenTrackpadGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + private: + PHLWINDOWREF m_window; + + Vector2D m_posFrom, m_posTo, m_sizeFrom, m_sizeTo; + + float m_lastDelta = 0; + + enum eMode : uint8_t { + MODE_FULLSCREEN = 0, + MODE_MAXIMIZE, + }; + + eMode m_mode = MODE_FULLSCREEN; + eFullscreenMode m_originalMode = FSMODE_NONE; + + eFullscreenMode fsModeForMode(eMode mode); +}; diff --git a/src/managers/input/trackpad/gestures/ITrackpadGesture.cpp b/src/managers/input/trackpad/gestures/ITrackpadGesture.cpp new file mode 100644 index 00000000..afc96627 --- /dev/null +++ b/src/managers/input/trackpad/gestures/ITrackpadGesture.cpp @@ -0,0 +1,40 @@ +#include "ITrackpadGesture.hpp" + +// scale the pinch "scale" to match our imaginary delta units +constexpr const float PINCH_DELTA_SCALE = 400.F; +constexpr const float PINCH_DELTA_SCALE_OUT_ADD = 1.6F; + +// +void ITrackpadGesture::begin(const STrackpadGestureBegin& e) { + m_lastPinchScale = 1.F; + m_scale = e.scale; +} + +float ITrackpadGesture::distance(const STrackpadGestureBegin& e) { + if (e.direction == TRACKPAD_GESTURE_DIR_LEFT || e.direction == TRACKPAD_GESTURE_DIR_RIGHT || e.direction == TRACKPAD_GESTURE_DIR_HORIZONTAL) + return m_scale * (e.direction == TRACKPAD_GESTURE_DIR_LEFT ? -e.swipe->delta.x : e.swipe->delta.x); + if (e.direction == TRACKPAD_GESTURE_DIR_UP || e.direction == TRACKPAD_GESTURE_DIR_DOWN || e.direction == TRACKPAD_GESTURE_DIR_VERTICAL) + return m_scale * (e.direction == TRACKPAD_GESTURE_DIR_UP ? -e.swipe->delta.y : e.swipe->delta.y); + if (e.direction == TRACKPAD_GESTURE_DIR_SWIPE) + return m_scale * (e.swipe->delta.size()); + if (e.direction == TRACKPAD_GESTURE_DIR_PINCH || e.direction == TRACKPAD_GESTURE_DIR_PINCH_IN || e.direction == TRACKPAD_GESTURE_DIR_PINCH_OUT) { + const auto Δ = m_lastPinchScale - e.pinch->scale; + m_lastPinchScale = e.pinch->scale; + return m_scale * ((e.direction == TRACKPAD_GESTURE_DIR_PINCH_IN ? -Δ : Δ * PINCH_DELTA_SCALE_OUT_ADD) * PINCH_DELTA_SCALE); + } + + return m_scale * (e.swipe ? e.swipe->delta.size() : e.pinch->delta.size()); +} + +float ITrackpadGesture::distance(const STrackpadGestureUpdate& e) { + return ITrackpadGesture::distance(STrackpadGestureBegin{ + .swipe = e.swipe, + .pinch = e.pinch, + .direction = e.direction, + .scale = e.scale, + }); +} + +bool ITrackpadGesture::isDirectionSensitive() { + return false; +} diff --git a/src/managers/input/trackpad/gestures/ITrackpadGesture.hpp b/src/managers/input/trackpad/gestures/ITrackpadGesture.hpp new file mode 100644 index 00000000..a5108a2c --- /dev/null +++ b/src/managers/input/trackpad/gestures/ITrackpadGesture.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include "../../../../devices/IPointer.hpp" +#include "../GestureTypes.hpp" + +class ITrackpadGesture { + public: + virtual ~ITrackpadGesture() = default; + + struct STrackpadGestureBegin { + // this has update because we wait for the delta + const IPointer::SSwipeUpdateEvent* swipe = nullptr; + const IPointer::SPinchUpdateEvent* pinch = nullptr; + eTrackpadGestureDirection direction = TRACKPAD_GESTURE_DIR_NONE; + float scale = 1.F; + }; + + struct STrackpadGestureUpdate { + const IPointer::SSwipeUpdateEvent* swipe = nullptr; + const IPointer::SPinchUpdateEvent* pinch = nullptr; + eTrackpadGestureDirection direction = TRACKPAD_GESTURE_DIR_NONE; + float scale = 1.F; + }; + + struct STrackpadGestureEnd { + const IPointer::SSwipeEndEvent* swipe = nullptr; + const IPointer::SPinchEndEvent* pinch = nullptr; + eTrackpadGestureDirection direction = TRACKPAD_GESTURE_DIR_NONE; + float scale = 1.F; + }; + + virtual void begin(const STrackpadGestureBegin& e); + virtual void update(const STrackpadGestureUpdate& e) = 0; + virtual void end(const STrackpadGestureEnd& e) = 0; + + virtual float distance(const STrackpadGestureBegin& e); + virtual float distance(const STrackpadGestureUpdate& e); + + virtual bool isDirectionSensitive(); + + protected: + float m_lastPinchScale = 1.F, m_scale = 1.F; +};
\ No newline at end of file diff --git a/src/managers/input/trackpad/gestures/MoveGesture.cpp b/src/managers/input/trackpad/gestures/MoveGesture.cpp new file mode 100644 index 00000000..6ceb02ec --- /dev/null +++ b/src/managers/input/trackpad/gestures/MoveGesture.cpp @@ -0,0 +1,66 @@ +#include "MoveGesture.hpp" + +#include "../../../../Compositor.hpp" +#include "../../../../managers/LayoutManager.hpp" +#include "../../../../render/Renderer.hpp" + +void CMoveTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ITrackpadGesture::begin(e); + + m_window = g_pCompositor->m_lastWindow; + m_lastDelta = {}; +} + +void CMoveTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + if (!m_window) + return; + + const auto DELTA = e.swipe ? e.swipe->delta : e.pinch->delta; + + if (m_window->m_isFloating) { + g_pLayoutManager->getCurrentLayout()->moveActiveWindow(DELTA, m_window.lock()); + m_window->m_realSize->warp(); + m_window->m_realPosition->warp(); + return; + } + + // tiled window -> displace, then execute a move dispatcher on end. + + g_pHyprRenderer->damageWindow(m_window.lock()); + + // funny name but works on tiled too lmao + m_lastDelta += DELTA; + m_window->m_floatingOffset = (m_lastDelta * 0.5F).clamp(Vector2D{-100.F, -100.F}, Vector2D{100.F, 100.F}); + + g_pHyprRenderer->damageWindow(m_window.lock()); +} + +void CMoveTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + + if (!m_window) + return; + + if (m_window->m_isFloating || m_lastDelta.size() < 0.1F) + return; + + // tiled: attempt to move window in the given direction + + const auto WINDOWPOS = m_window->m_realPosition->goal() + m_window->m_floatingOffset; + + m_window->m_floatingOffset = {}; + + if (std::abs(m_lastDelta.x) > std::abs(m_lastDelta.y)) { + // horizontal + g_pLayoutManager->getCurrentLayout()->moveWindowTo(m_window.lock(), m_lastDelta.x > 0 ? "r" : "l"); + } else { + // vertical + g_pLayoutManager->getCurrentLayout()->moveWindowTo(m_window.lock(), m_lastDelta.y > 0 ? "b" : "t"); + } + + const auto GOAL = m_window->m_realPosition->goal(); + + m_window->m_realPosition->setValueAndWarp(WINDOWPOS); + *m_window->m_realPosition = GOAL; + + m_window.reset(); +} diff --git a/src/managers/input/trackpad/gestures/MoveGesture.hpp b/src/managers/input/trackpad/gestures/MoveGesture.hpp new file mode 100644 index 00000000..3a045561 --- /dev/null +++ b/src/managers/input/trackpad/gestures/MoveGesture.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "ITrackpadGesture.hpp" + +#include "../../../../desktop/DesktopTypes.hpp" + +class CMoveTrackpadGesture : public ITrackpadGesture { + public: + CMoveTrackpadGesture() = default; + virtual ~CMoveTrackpadGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + private: + PHLWINDOWREF m_window; + Vector2D m_lastDelta; +}; diff --git a/src/managers/input/trackpad/gestures/ResizeGesture.cpp b/src/managers/input/trackpad/gestures/ResizeGesture.cpp new file mode 100644 index 00000000..d788257a --- /dev/null +++ b/src/managers/input/trackpad/gestures/ResizeGesture.cpp @@ -0,0 +1,29 @@ +#include "ResizeGesture.hpp" + +#include "../../../../Compositor.hpp" +#include "../../../../managers/LayoutManager.hpp" +#include "../../../../render/Renderer.hpp" + +void CResizeTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ITrackpadGesture::begin(e); + + m_window = g_pCompositor->m_lastWindow; +} + +void CResizeTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + if (!m_window) + return; + + g_pHyprRenderer->damageWindow(m_window.lock()); + + g_pLayoutManager->getCurrentLayout()->resizeActiveWindow((e.swipe ? e.swipe->delta : e.pinch->delta), + cornerFromBox(m_window->getWindowMainSurfaceBox(), g_pInputManager->getMouseCoordsInternal()), m_window.lock()); + m_window->m_realSize->warp(); + m_window->m_realPosition->warp(); + + g_pHyprRenderer->damageWindow(m_window.lock()); +} + +void CResizeTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + m_window.reset(); +} diff --git a/src/managers/input/trackpad/gestures/ResizeGesture.hpp b/src/managers/input/trackpad/gestures/ResizeGesture.hpp new file mode 100644 index 00000000..0b47a224 --- /dev/null +++ b/src/managers/input/trackpad/gestures/ResizeGesture.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "ITrackpadGesture.hpp" + +#include "../../../../desktop/DesktopTypes.hpp" + +class CResizeTrackpadGesture : public ITrackpadGesture { + public: + CResizeTrackpadGesture() = default; + virtual ~CResizeTrackpadGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + private: + PHLWINDOWREF m_window; +}; diff --git a/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.cpp b/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.cpp new file mode 100644 index 00000000..146d3b50 --- /dev/null +++ b/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.cpp @@ -0,0 +1,126 @@ +#include "SpecialWorkspaceGesture.hpp" + +#include "../../../../Compositor.hpp" +#include "../../../../managers/LayoutManager.hpp" +#include "../../../../render/Renderer.hpp" + +#include <hyprutils/memory/Casts.hpp> +using namespace Hyprutils::Memory; + +constexpr const float MAX_DISTANCE = 150.F; + +// +static Vector2D lerpVal(const Vector2D& from, const Vector2D& to, const float& t) { + return Vector2D{ + from.x + ((to.x - from.x) * t), + from.y + ((to.y - from.y) * t), + }; +} + +static float lerpVal(const float& from, const float& to, const float& t) { + return from + ((to - from) * t); +} + +CSpecialWorkspaceGesture::CSpecialWorkspaceGesture(const std::string& workspaceName) : m_specialWorkspaceName(workspaceName) { + ; +} + +void CSpecialWorkspaceGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ITrackpadGesture::begin(e); + + m_specialWorkspace.reset(); + m_lastDelta = 0.F; + m_monitor.reset(); + + m_specialWorkspace = g_pCompositor->getWorkspaceByName("special:" + m_specialWorkspaceName); + + if (m_specialWorkspace) { + m_animatingOut = m_specialWorkspace->isVisible(); + m_monitor = m_animatingOut ? m_specialWorkspace->m_monitor : g_pCompositor->m_lastMonitor; + + if (!m_monitor) + return; + + if (!m_animatingOut) + m_monitor->setSpecialWorkspace(m_specialWorkspace); + } else { + m_monitor = g_pCompositor->m_lastMonitor; + + if (!m_monitor) + return; + + m_animatingOut = false; + + const auto& [workspaceID, workspaceName] = getWorkspaceIDNameFromString("special:" + m_specialWorkspaceName); + const auto WS = g_pCompositor->createNewWorkspace(workspaceID, m_monitor->m_id, workspaceName); + m_monitor->setSpecialWorkspace(WS); + m_specialWorkspace = WS; + } + + if (!m_specialWorkspace) + return; + + m_monitorDimFrom = m_monitor->m_specialFade->begun(); + m_monitorDimTo = m_monitor->m_specialFade->goal(); + m_workspaceAlphaFrom = m_specialWorkspace->m_alpha->begun(); + m_workspaceAlphaTo = m_specialWorkspace->m_alpha->goal(); + m_workspaceOffsetFrom = m_specialWorkspace->m_renderOffset->begun(); + m_workspaceOffsetTo = m_specialWorkspace->m_renderOffset->goal(); +} + +void CSpecialWorkspaceGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + if (!m_specialWorkspace || !m_monitor) + return; + + g_pHyprRenderer->damageMonitor(m_specialWorkspace->m_monitor.lock()); + + m_lastDelta += distance(e); + + const auto FADEPERCENT = m_animatingOut ? 1.F - std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F) : std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + m_monitor->m_specialFade->setValueAndWarp(lerpVal(m_monitorDimFrom, m_monitorDimTo, FADEPERCENT)); + m_specialWorkspace->m_alpha->setValueAndWarp(lerpVal(m_workspaceAlphaFrom, m_workspaceAlphaTo, FADEPERCENT)); + m_specialWorkspace->m_renderOffset->setValueAndWarp(lerpVal(m_workspaceOffsetFrom, m_workspaceOffsetTo, FADEPERCENT)); +} + +void CSpecialWorkspaceGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + if (!m_specialWorkspace || !m_monitor) + return; + + const auto COMPLETION = std::clamp(m_lastDelta / MAX_DISTANCE, 0.F, 1.F); + + if (COMPLETION < 0.3F) { + // cancel the operation, which effectively means just flip the animation direction + // also flip goals if animating in + m_animatingOut = !m_animatingOut; + + if (m_animatingOut) { + m_workspaceOffsetTo = m_workspaceOffsetFrom; + m_workspaceAlphaTo = m_workspaceAlphaFrom; + m_monitorDimTo = m_monitorDimFrom; + } + } + + if (m_animatingOut) { + const auto CURR_WS_ALPHA = m_specialWorkspace->m_alpha->value(); + const auto CURR_WS_OFFSET = m_specialWorkspace->m_renderOffset->value(); + const auto CURR_MON_FADE = m_monitor->m_specialFade->value(); + + m_monitor->setSpecialWorkspace(nullptr); + + const auto GOAL_WS_ALPHA = m_specialWorkspace->m_alpha->goal(); + const auto GOAL_WS_OFFSET = m_specialWorkspace->m_renderOffset->goal(); + + m_monitor->m_specialFade->setValueAndWarp(CURR_MON_FADE); + m_specialWorkspace->m_alpha->setValueAndWarp(CURR_WS_ALPHA); + m_specialWorkspace->m_renderOffset->setValueAndWarp(CURR_WS_OFFSET); + + *m_monitor->m_specialFade = 0.F; + *m_specialWorkspace->m_alpha = GOAL_WS_ALPHA; + *m_specialWorkspace->m_renderOffset = GOAL_WS_OFFSET; + } else { + *m_monitor->m_specialFade = m_monitorDimTo; + *m_specialWorkspace->m_renderOffset = m_workspaceOffsetTo; + *m_specialWorkspace->m_alpha = m_workspaceAlphaTo; + } +} diff --git a/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.hpp b/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.hpp new file mode 100644 index 00000000..0cc62529 --- /dev/null +++ b/src/managers/input/trackpad/gestures/SpecialWorkspaceGesture.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "ITrackpadGesture.hpp" + +#include "../../../../desktop/DesktopTypes.hpp" + +class CSpecialWorkspaceGesture : public ITrackpadGesture { + public: + CSpecialWorkspaceGesture(const std::string& workspaceName); + virtual ~CSpecialWorkspaceGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + private: + std::string m_specialWorkspaceName; + PHLWORKSPACE m_specialWorkspace; + PHLMONITORREF m_monitor; + bool m_animatingOut = false; + float m_lastDelta = 0.F; + + // animated properties, kinda sucks + float m_monitorDimFrom = 0.F, m_monitorDimTo = 0.F; + float m_workspaceAlphaFrom = 0.F, m_workspaceAlphaTo = 0.F; + Vector2D m_workspaceOffsetFrom = {}, m_workspaceOffsetTo = {}; +}; diff --git a/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.cpp b/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.cpp new file mode 100644 index 00000000..793bfd77 --- /dev/null +++ b/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.cpp @@ -0,0 +1,50 @@ +#include "WorkspaceSwipeGesture.hpp" + +#include "../../../../Compositor.hpp" +#include "../../../../managers/input/InputManager.hpp" +#include "../../../../render/Renderer.hpp" + +#include "../../UnifiedWorkspaceSwipeGesture.hpp" + +void CWorkspaceSwipeGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) { + ITrackpadGesture::begin(e); + + static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new"); + + if (g_pSessionLockManager->isSessionLocked() || g_pUnifiedWorkspaceSwipe->isGestureInProgress()) + return; + + int onMonitor = 0; + for (auto const& w : g_pCompositor->getWorkspaces()) { + if (w->m_monitor == g_pCompositor->m_lastMonitor && !g_pCompositor->isWorkspaceSpecial(w->m_id)) + onMonitor++; + } + + if (onMonitor < 2 && !*PSWIPENEW) + return; // disallow swiping when there's 1 workspace on a monitor + + g_pUnifiedWorkspaceSwipe->begin(); +} + +void CWorkspaceSwipeGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) { + if (!g_pUnifiedWorkspaceSwipe->isGestureInProgress()) + return; + + const float DELTA = distance(e); + + static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert"); + + const double D = g_pUnifiedWorkspaceSwipe->m_delta + (*PSWIPEINVR ? -DELTA : DELTA); + g_pUnifiedWorkspaceSwipe->update(D); +} + +void CWorkspaceSwipeGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) { + if (!g_pUnifiedWorkspaceSwipe->isGestureInProgress()) + return; + + g_pUnifiedWorkspaceSwipe->end(); +} + +bool CWorkspaceSwipeGesture::isDirectionSensitive() { + return true; +} diff --git a/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.hpp b/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.hpp new file mode 100644 index 00000000..203fc329 --- /dev/null +++ b/src/managers/input/trackpad/gestures/WorkspaceSwipeGesture.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "ITrackpadGesture.hpp" +#include "../../../../desktop/DesktopTypes.hpp" + +class CWorkspaceSwipeGesture : public ITrackpadGesture { + public: + CWorkspaceSwipeGesture() = default; + virtual ~CWorkspaceSwipeGesture() = default; + + virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e); + virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e); + virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e); + + virtual bool isDirectionSensitive(); +}; |
