summaryrefslogtreecommitdiff
path: root/src/managers
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2026-05-07 22:29:43 +0100
committerGitHub <noreply@github.com>2026-05-07 22:29:43 +0100
commit4c8c45d754c9956d611bbe373b3e33a7d5957d68 (patch)
treeab5c800d548901b79da2e53f9a5393e96b909d4f /src/managers
parent39af3901b389f792a55176041dec9211c82ed1c9 (diff)
gestures: add scroll_move (#14063)
Diffstat (limited to 'src/managers')
-rw-r--r--src/managers/input/trackpad/gestures/ScrollMoveGesture.cpp145
-rw-r--r--src/managers/input/trackpad/gestures/ScrollMoveGesture.hpp27
2 files changed, 172 insertions, 0 deletions
diff --git a/src/managers/input/trackpad/gestures/ScrollMoveGesture.cpp b/src/managers/input/trackpad/gestures/ScrollMoveGesture.cpp
new file mode 100644
index 00000000..032bf679
--- /dev/null
+++ b/src/managers/input/trackpad/gestures/ScrollMoveGesture.cpp
@@ -0,0 +1,145 @@
+#include "ScrollMoveGesture.hpp"
+
+#include "../../../../desktop/state/FocusState.hpp"
+#include "../../../../desktop/Workspace.hpp"
+#include "../../../../helpers/Monitor.hpp"
+#include "../../../../layout/LayoutManager.hpp"
+#include "../../../../layout/algorithm/Algorithm.hpp"
+#include "../../../../layout/algorithm/tiled/scrolling/ScrollingAlgorithm.hpp"
+#include "../../../../layout/space/Space.hpp"
+#include "../../../../config/ConfigValue.hpp"
+#include "../../../../Compositor.hpp"
+
+#include <algorithm>
+#include <cmath>
+
+constexpr double SCROLL_GESTURE_VELOCITY_DECAY = 4.0;
+constexpr double SCROLL_GESTURE_MAX_PROJECTION = 2.0;
+constexpr double SCROLL_GESTURE_VELOCITY_SMOOTH = 0.35;
+
+static Layout::Tiled::CScrollingAlgorithm* currentScrollingLayout() {
+ const auto PMONITOR = Desktop::focusState()->monitor();
+ if (!PMONITOR)
+ return nullptr;
+
+ const auto PWORKSPACE = PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace;
+ if (!PWORKSPACE || !PWORKSPACE->m_space)
+ return nullptr;
+
+ const auto ALGORITHM = PWORKSPACE->m_space->algorithm();
+ if (!ALGORITHM || !ALGORITHM->tiledAlgo())
+ return nullptr;
+
+ return dynamic_cast<Layout::Tiled::CScrollingAlgorithm*>(ALGORITHM->tiledAlgo().get());
+}
+
+static float deltaForUpdate(const ITrackpadGesture::STrackpadGestureUpdate& e) {
+ if (!e.swipe)
+ return 0.F;
+
+ switch (e.direction) {
+ case TRACKPAD_GESTURE_DIR_LEFT:
+ case TRACKPAD_GESTURE_DIR_RIGHT:
+ case TRACKPAD_GESTURE_DIR_HORIZONTAL: return e.swipe->delta.x * e.scale;
+ case TRACKPAD_GESTURE_DIR_UP:
+ case TRACKPAD_GESTURE_DIR_DOWN:
+ case TRACKPAD_GESTURE_DIR_VERTICAL: return e.swipe->delta.y * e.scale;
+ default: return std::abs(e.swipe->delta.x) > std::abs(e.swipe->delta.y) ? e.swipe->delta.x * e.scale : e.swipe->delta.y * e.scale;
+ }
+}
+
+void CScrollMoveTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) {
+ ITrackpadGesture::begin(e);
+
+ const auto LAYOUT = currentScrollingLayout();
+
+ m_wasScrollingLayout = !!LAYOUT;
+ m_hasLastUpdate = false;
+ m_lastUpdateTimeMs = 0;
+ m_velocity = 0.0;
+
+ m_startedOffset = LAYOUT ? LAYOUT->normalizedTapeOffset() : 0.0;
+ m_startedColumn = LAYOUT ? LAYOUT->currentColumn() : nullptr;
+}
+
+void CScrollMoveTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) {
+ if (!m_wasScrollingLayout)
+ return;
+
+ const auto SCROLLING = currentScrollingLayout();
+ if (!SCROLLING)
+ return;
+
+ const float DELTA = deltaForUpdate(e);
+ const double PRIMARY = SCROLLING->primaryViewportSize();
+
+ if (DELTA == 0.F || PRIMARY <= 0.0)
+ return;
+
+ const double NORMALIZED_DELTA = DELTA / PRIMARY;
+ const double NORMALIZED_OFFSET_DELTA = -NORMALIZED_DELTA;
+
+ SCROLLING->moveTapeNormalized(NORMALIZED_DELTA);
+
+ if (!e.swipe)
+ return;
+
+ if (m_hasLastUpdate && e.swipe->timeMs > m_lastUpdateTimeMs) {
+ const double DT = (e.swipe->timeMs - m_lastUpdateTimeMs) / 1000.0;
+
+ if (DT > 0.0) {
+ const double INSTANT_VELOCITY = NORMALIZED_OFFSET_DELTA / DT;
+
+ if (std::isfinite(INSTANT_VELOCITY))
+ m_velocity = m_velocity * (1.0 - SCROLL_GESTURE_VELOCITY_SMOOTH) + INSTANT_VELOCITY * SCROLL_GESTURE_VELOCITY_SMOOTH;
+ }
+ }
+
+ m_hasLastUpdate = true;
+ m_lastUpdateTimeMs = e.swipe->timeMs;
+}
+
+void CScrollMoveTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) {
+ static auto PSNAP = CConfigValue<Config::BOOL>("gestures:scrolling:move_snap_to_grid");
+ static auto PSNAPCURSOR = CConfigValue<Config::BOOL>("gestures:scrolling:move_snap_cursor");
+
+ const auto SCROLLING = currentScrollingLayout();
+ if (!m_wasScrollingLayout || !SCROLLING) {
+ m_wasScrollingLayout = false;
+ m_hasLastUpdate = false;
+ m_velocity = 0.0;
+ return;
+ }
+
+ const auto CURRENT_FOCUS = Desktop::focusState()->window();
+
+ const bool CANCELLED = e.swipe && e.swipe->cancelled;
+ const double Δ = (CANCELLED ? 0.0 : std::clamp(m_velocity / SCROLL_GESTURE_VELOCITY_DECAY, -SCROLL_GESTURE_MAX_PROJECTION, SCROLL_GESTURE_MAX_PROJECTION));
+ const double PROJECTED = SCROLLING->normalizedTapeOffset() + Δ;
+
+ if (*PSNAP) {
+ const auto LANDED = SCROLLING->snapToProjectedOffset(PROJECTED);
+
+ // if we land on the same thing we started, move the tape back
+ if (LANDED == m_startedColumn && LANDED)
+ SCROLLING->moveTapeNormalized(SCROLLING->normalizedTapeOffset() - m_startedOffset);
+ else
+ SCROLLING->focusColumn(LANDED);
+ } else {
+ SCROLLING->moveTape(Δ);
+ const auto COL = SCROLLING->getColumnAtViewportCenter();
+ if (!COL->targetDatas.empty() && COL->targetDatas.front()->target) {
+ if (const auto W = COL->targetDatas.front()->target->window(); W)
+ Desktop::focusState()->fullWindowFocus(W, Desktop::FOCUS_REASON_FFM);
+ }
+ }
+
+ const auto NEW_FOCUS = Desktop::focusState()->window();
+
+ if (*PSNAPCURSOR && CURRENT_FOCUS != NEW_FOCUS && NEW_FOCUS)
+ g_pCompositor->warpCursorTo(NEW_FOCUS->middle());
+
+ m_wasScrollingLayout = false;
+ m_hasLastUpdate = false;
+ m_velocity = 0.0;
+}
diff --git a/src/managers/input/trackpad/gestures/ScrollMoveGesture.hpp b/src/managers/input/trackpad/gestures/ScrollMoveGesture.hpp
new file mode 100644
index 00000000..26e51e00
--- /dev/null
+++ b/src/managers/input/trackpad/gestures/ScrollMoveGesture.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "ITrackpadGesture.hpp"
+
+#include <cstdint>
+
+namespace Layout::Tiled {
+ struct SColumnData;
+}
+
+class CScrollMoveTrackpadGesture : public ITrackpadGesture {
+ public:
+ CScrollMoveTrackpadGesture() = default;
+ virtual ~CScrollMoveTrackpadGesture() = default;
+
+ virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e);
+ virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e);
+ virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e);
+
+ private:
+ bool m_wasScrollingLayout = false;
+ bool m_hasLastUpdate = false;
+ uint32_t m_lastUpdateTimeMs = 0;
+ double m_velocity = 0.0;
+ double m_startedOffset = 0.0;
+ WP<Layout::Tiled::SColumnData> m_startedColumn = nullptr;
+};