summaryrefslogtreecommitdiff
path: root/src/managers/input/UnifiedWorkspaceSwipeGesture.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2025-08-28 11:20:29 +0200
committerGitHub <noreply@github.com>2025-08-28 11:20:29 +0200
commit81bf4eccba449bfe2b6adfb51260108aec710d4f (patch)
tree215c5b536cbcf1df9888081aadd3de16eb4b3ebe /src/managers/input/UnifiedWorkspaceSwipeGesture.cpp
parent378e130f1426648d8d734049800128f9882805bf (diff)
input: Add fully configurable trackpad gestures (#11490)
Adds configurable trackpad gestures
Diffstat (limited to 'src/managers/input/UnifiedWorkspaceSwipeGesture.cpp')
-rw-r--r--src/managers/input/UnifiedWorkspaceSwipeGesture.cpp313
1 files changed, 313 insertions, 0 deletions
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