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