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/input | |
| parent | 378e130f1426648d8d734049800128f9882805bf (diff) | |
input: Add fully configurable trackpad gestures (#11490)
Adds configurable trackpad gestures
Diffstat (limited to 'src/managers/input')
27 files changed, 1586 insertions, 374 deletions
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(); +}; |
