summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hyprtester/plugin/src/main.cpp122
-rw-r--r--hyprtester/src/tests/main/gestures.cpp38
-rw-r--r--hyprtester/src/tests/main/groups.cpp2
-rw-r--r--hyprtester/test.lua1
-rw-r--r--src/helpers/MonitorZoomController.cpp21
-rw-r--r--src/helpers/MonitorZoomController.hpp15
-rw-r--r--src/managers/input/trackpad/gestures/CursorZoomGesture.cpp57
-rw-r--r--src/managers/input/trackpad/gestures/CursorZoomGesture.hpp5
8 files changed, 249 insertions, 12 deletions
diff --git a/hyprtester/plugin/src/main.cpp b/hyprtester/plugin/src/main.cpp
index c7d6f4fd..3bb6e2b2 100644
--- a/hyprtester/plugin/src/main.cpp
+++ b/hyprtester/plugin/src/main.cpp
@@ -2,11 +2,13 @@
#include <src/includes.hpp>
#include <sstream>
#include <any>
+#include <cmath>
#define private public
#include <src/managers/input/InputManager.hpp>
#include <src/managers/PointerManager.hpp>
#include <src/managers/input/trackpad/TrackpadGestures.hpp>
+#include <src/helpers/Monitor.hpp>
#include <src/desktop/rule/windowRule/WindowRuleEffectContainer.hpp>
#include <src/desktop/rule/layerRule/LayerRuleEffectContainer.hpp>
#include <src/desktop/rule/windowRule/WindowRuleApplicator.hpp>
@@ -17,6 +19,7 @@
#undef private
#include <hyprutils/utils/ScopeGuard.hpp>
+#include <hyprutils/string/Numeric.hpp>
#include <hyprutils/string/VarList.hpp>
using namespace Hyprutils::Utils;
using namespace Hyprutils::String;
@@ -156,6 +159,96 @@ static SDispatchResult simulateGesture(std::string in) {
return {.success = true};
}
+static SDispatchResult pinchUpdate(std::string in) {
+ CVarList data(in);
+ uint32_t fingers = 2;
+ double scale = 1.0;
+ Vector2D delta = {};
+ double rotation{};
+
+ if (data.size() < 2)
+ return {.success = false, .error = "invalid input"};
+
+ if (const auto n = strToNumber<uint32_t>(data[0]); n)
+ fingers = n.value();
+ else
+ return {.success = false, .error = "invalid input"};
+
+ if (const auto n = strToNumber<double>(data[1]); n)
+ scale = n.value();
+ else
+ return {.success = false, .error = "invalid input"};
+
+ if (data.size() > 2) {
+ if (const auto n = strToNumber<double>(data[2]); n)
+ delta.x = n.value();
+ else
+ return {.success = false, .error = "invalid input"};
+ }
+
+ if (data.size() > 3) {
+ if (const auto n = strToNumber<double>(data[3]); n)
+ delta.y = n.value();
+ else
+ return {.success = false, .error = "invalid input"};
+ }
+
+ if (data.size() > 4) {
+ if (const auto n = strToNumber<double>(data[4]); n)
+ rotation = n.value();
+ else
+ return {.success = false, .error = "invalid input"};
+ }
+
+ g_pTrackpadGestures->gestureUpdate(IPointer::SPinchUpdateEvent{
+ .fingers = fingers,
+ .delta = delta,
+ .scale = scale,
+ .rotation = rotation,
+ });
+
+ return {};
+}
+
+static SDispatchResult pinchEnd(std::string in) {
+ g_pTrackpadGestures->gestureEnd(IPointer::SPinchEndEvent{});
+
+ return {};
+}
+
+static SDispatchResult expectCursorZoom(std::string in) {
+ CVarList data(in);
+ float expected = 1.F;
+ float delta = 0.01F;
+
+ if (data.size() < 1)
+ return {.success = false, .error = "invalid input"};
+
+ if (const auto n = strToNumber<float>(data[0]); n)
+ expected = n.value();
+ else
+ return {.success = false, .error = "invalid input"};
+
+ if (data.size() > 1) {
+ if (const auto n = strToNumber<float>(data[1]); n)
+ delta = n.value();
+ else
+ return {.success = false, .error = "invalid input"};
+ }
+
+ const auto PMONITOR = g_pCompositor->getMonitorFromVector(g_pInputManager->getMouseCoordsInternal());
+
+ if (!PMONITOR)
+ return {.success = false, .error = "No monitor under cursor"};
+
+ const auto actual = PMONITOR->m_cursorZoom->value();
+
+ if (std::abs(actual - expected) > delta)
+ return {.success = false, .error = std::format("Expected cursor zoom {} ± {}, got {}", expected, delta, actual)};
+
+ return {};
+}
+
static SDispatchResult vkb(std::string in) {
auto tkb0 = CTestKeyboard::create(false);
auto tkb1 = CTestKeyboard::create(false);
@@ -375,6 +468,32 @@ static int luaGesture(lua_State* L) {
return luaResult(L, ::simulateGesture(std::format("{},{}", direction, fingers)));
}
+static int luaPinchUpdate(lua_State* L) {
+ std::string in = std::format("{},{}", (int)luaL_checkinteger(L, 1), (double)luaL_checknumber(L, 2));
+
+ if (lua_gettop(L) > 2)
+ in += std::format(",{}", (double)luaL_checknumber(L, 3));
+ if (lua_gettop(L) > 3)
+ in += std::format(",{}", (double)luaL_checknumber(L, 4));
+ if (lua_gettop(L) > 4)
+ in += std::format(",{}", (double)luaL_checknumber(L, 5));
+
+ return luaResult(L, ::pinchUpdate(in));
+}
+
+static int luaPinchEnd(lua_State* L) {
+ return luaResult(L, ::pinchEnd(""));
+}
+
+static int luaExpectCursorZoom(lua_State* L) {
+ const auto expected = (double)luaL_checknumber(L, 1);
+
+ if (lua_gettop(L) > 1)
+ return luaResult(L, ::expectCursorZoom(std::format("{},{}", expected, (double)luaL_checknumber(L, 2))));
+
+ return luaResult(L, ::expectCursorZoom(std::format("{}", expected)));
+}
+
static int luaScroll(lua_State* L) {
return luaResult(L, ::scroll(std::to_string((double)luaL_checknumber(L, 1))));
}
@@ -425,6 +544,9 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
addLuaFn("vkb", ::luaVkb);
addLuaFn("alt", ::luaAlt);
addLuaFn("gesture", ::luaGesture);
+ addLuaFn("pinch_update", ::luaPinchUpdate);
+ addLuaFn("pinch_end", ::luaPinchEnd);
+ addLuaFn("expect_cursor_zoom", ::luaExpectCursorZoom);
addLuaFn("scroll", ::luaScroll);
addLuaFn("click", ::luaClick);
addLuaFn("keybind", ::luaKeybind);
diff --git a/hyprtester/src/tests/main/gestures.cpp b/hyprtester/src/tests/main/gestures.cpp
index f8324712..f82a1613 100644
--- a/hyprtester/src/tests/main/gestures.cpp
+++ b/hyprtester/src/tests/main/gestures.cpp
@@ -6,12 +6,14 @@
#include <chrono>
#include <hyprutils/os/Process.hpp>
#include <hyprutils/memory/WeakPtr.hpp>
+#include <hyprutils/string/Numeric.hpp>
#include <csignal>
#include <cerrno>
#include "../shared.hpp"
using namespace Hyprutils::OS;
using namespace Hyprutils::Memory;
+using namespace Hyprutils::String;
#define UP CUniquePointer
#define SP CSharedPointer
@@ -178,4 +180,40 @@ TEST_CASE(gestures) {
OK(getFromSocket("/dispatch hl.dsp.focus({ workspace = '1' })"));
}
+ const std::string cursorPosBeforePinch = getFromSocket("/cursorpos");
+
+ OK(getFromSocket("/dispatch hl.dsp.cursor.move({ x = 500, y = 500 })"));
+ OK(getFromSocket("/eval hl.config({ cursor = { zoom_factor = 1 } })"));
+ OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1, 0.01)"));
+
+ OK(getFromSocket("/eval hl.plugin.test.pinch_update(2, 1.2)"));
+ OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1.2, 0.01)"));
+ OK(getFromSocket("/eval hl.plugin.test.pinch_update(2, 1.6)"));
+ OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1.6, 0.01)"));
+ OK(getFromSocket("/eval hl.plugin.test.pinch_end()"));
+ OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1.6, 0.01)"));
+
+ OK(getFromSocket("/eval hl.plugin.test.pinch_update(2, 0.64)"));
+ OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1, 0.01)"));
+ OK(getFromSocket("/eval hl.plugin.test.pinch_end()"));
+ OK(getFromSocket("/eval hl.plugin.test.expect_cursor_zoom(1, 0.01)"));
+
+ const auto comma = cursorPosBeforePinch.find(',');
+
+ if (comma != std::string::npos) {
+ auto xSv = std::string_view(cursorPosBeforePinch).substr(0, comma);
+ auto ySv = std::string_view(cursorPosBeforePinch).substr(comma + 1);
+ while (!xSv.empty() && xSv.front() == ' ')
+ xSv.remove_prefix(1);
+ while (!ySv.empty() && ySv.front() == ' ')
+ ySv.remove_prefix(1);
+
+ const auto x = strToNumber<int>(xSv);
+ const auto y = strToNumber<int>(ySv);
+
+ if (!x || !y)
+ FAIL_TEST("Failed to restore cursor pos");
+
+ OK(getFromSocket(std::format("/dispatch hl.dsp.cursor.move({{ x = {}, y = {} }})", x.value(), y.value())));
+ }
}
diff --git a/hyprtester/src/tests/main/groups.cpp b/hyprtester/src/tests/main/groups.cpp
index 7e1c63b6..e1d4dd9b 100644
--- a/hyprtester/src/tests/main/groups.cpp
+++ b/hyprtester/src/tests/main/groups.cpp
@@ -192,6 +192,7 @@ TEST_CASE(groups) {
NLog::log("{}Disable autogrouping", Colors::YELLOW);
OK(getFromSocket("/eval hl.config({ group = { auto_group = false } })"));
+ OK(getFromSocket("/eval hl.config({ dwindle = { force_split = 2 } })"));
NLog::log("{}Spawn kittyProcC", Colors::YELLOW);
auto kittyProcC = Tests::spawnKitty();
@@ -206,6 +207,7 @@ TEST_CASE(groups) {
EXPECT_COUNT_STRING(str, "at: 22,22", 2);
}
+ OK(getFromSocket("/eval hl.config({ dwindle = { force_split = 0 } })"));
OK(getFromSocket("/dispatch hl.dsp.focus({ direction = 'left' })"));
OK(getFromSocket("/dispatch hl.dsp.group.active({ index = 1 })"));
OK(getFromSocket("/eval hl.config({ group = { auto_group = true } })"));
diff --git a/hyprtester/test.lua b/hyprtester/test.lua
index 6f39b34a..d1f8657e 100644
--- a/hyprtester/test.lua
+++ b/hyprtester/test.lua
@@ -290,5 +290,6 @@ hl.gesture({ fingers = 5, direction = "left", action = function() hl.dispatch(hl
hl.gesture({ fingers = 5, direction = "right", action = function() hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "t", window = "activewindow" })) end })
hl.gesture({ fingers = 4, direction = "right", action = function() hl.dispatch(hl.dsp.send_shortcut({ mods = "", key = "return", window = "activewindow" })) end })
hl.gesture({ fingers = 4, direction = "left", action = function() hl.dispatch(hl.dsp.cursor.move_to_corner({ corner = 1, window = "activewindow" })) end })
+hl.gesture({ fingers = 2, direction = "pinch", action = "cursorZoom", zoom_level = "1", mode = "live" })
hl.gesture({ fingers = 2, direction = "right", action = "float", disable_inhibit = true })
diff --git a/src/helpers/MonitorZoomController.cpp b/src/helpers/MonitorZoomController.cpp
index c1b6cc6a..b59e1eb2 100644
--- a/src/helpers/MonitorZoomController.cpp
+++ b/src/helpers/MonitorZoomController.cpp
@@ -7,11 +7,27 @@
#include "desktop/DesktopTypes.hpp"
#include "render/Renderer.hpp"
+void CMonitorZoomController::pinAnchor(const Vector2D& anchor) {
+ m_pinnedAnchor = anchor;
+ m_anchorPinned = true;
+}
+
+void CMonitorZoomController::clearAnchor() {
+ m_anchorPinned = false;
+}
+
+Vector2D CMonitorZoomController::getAnchor(const PHLMONITORREF& monitor) {
+ if (m_anchorPinned)
+ return m_pinnedAnchor;
+
+ return g_pInputManager->getMouseCoordsInternal() - monitor->m_position;
+}
+
void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData) {
const auto m = m_renderData.pMonitor;
auto monbox = CBox(0, 0, m->m_size.x, m->m_size.y);
const auto ZOOM = g_pHyprRenderer->m_renderData.mouseZoomFactor;
- const auto MOUSE = g_pInputManager->getMouseCoordsInternal() - m->m_position;
+ const auto MOUSE = getAnchor(m);
if (m_lastZoomLevel != ZOOM) {
if (m_resetCameraState) {
@@ -83,8 +99,7 @@ void CMonitorZoomController::applyZoomTransform(CBox& monbox, const Render::SRen
if (*PZOOMDETACHEDCAMERA && !INITANIM)
zoomWithDetachedCamera(monbox, m_renderData);
else {
- const auto ZOOMCENTER =
- g_pHyprRenderer->m_renderData.mouseZoomUseMouse ? (g_pInputManager->getMouseCoordsInternal() - m->m_position) * m->m_scale : m->m_transformedSize / 2.f;
+ const auto ZOOMCENTER = g_pHyprRenderer->m_renderData.mouseZoomUseMouse ? getAnchor(m) * m->m_scale : m->m_transformedSize / 2.f;
monbox.translate(-ZOOMCENTER).scale(ZOOM).translate(*PZOOMRIGID ? m->m_transformedSize / 2.0 : ZOOMCENTER);
}
diff --git a/src/helpers/MonitorZoomController.hpp b/src/helpers/MonitorZoomController.hpp
index 94373baf..ce3ad554 100644
--- a/src/helpers/MonitorZoomController.hpp
+++ b/src/helpers/MonitorZoomController.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "./math/Math.hpp"
+#include "../desktop/DesktopTypes.hpp"
namespace Render {
struct SRenderData;
@@ -10,12 +11,18 @@ class CMonitorZoomController {
public:
bool m_resetCameraState = true;
+ void pinAnchor(const Vector2D& anchor);
+ void clearAnchor();
+
void applyZoomTransform(CBox& monbox, const Render::SRenderData& m_renderData);
private:
- void zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData);
+ void zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData);
+ Vector2D getAnchor(const PHLMONITORREF& monitor);
- CBox m_camera;
- float m_lastZoomLevel = 1.0f;
- bool m_padCamEdges = true;
+ CBox m_camera;
+ Vector2D m_pinnedAnchor = {};
+ float m_lastZoomLevel = 1.0f;
+ bool m_padCamEdges = true;
+ bool m_anchorPinned = false;
};
diff --git a/src/managers/input/trackpad/gestures/CursorZoomGesture.cpp b/src/managers/input/trackpad/gestures/CursorZoomGesture.cpp
index 515edbb6..418b8f7a 100644
--- a/src/managers/input/trackpad/gestures/CursorZoomGesture.cpp
+++ b/src/managers/input/trackpad/gestures/CursorZoomGesture.cpp
@@ -2,19 +2,40 @@
#include "../../../../Compositor.hpp"
#include "../../../../helpers/Monitor.hpp"
+#include "../../../../managers/input/InputManager.hpp"
+#include <hyprutils/string/Numeric.hpp>
CCursorZoomTrackpadGesture::CCursorZoomTrackpadGesture(const std::string& first, const std::string& second) {
- try {
- m_zoomValue = std::stof(first);
- } catch (...) { ; }
+ if (const auto n = Hyprutils::String::strToNumber<float>(first); n)
+ m_zoomValue = n.value();
if (second == "mult")
m_mode = MODE_MULT;
+ else if (second == "live")
+ m_mode = MODE_LIVE;
}
void CCursorZoomTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) {
ITrackpadGesture::begin(e);
+ if (m_mode == MODE_LIVE) {
+ if (!e.pinch)
+ return;
+
+ m_monitor = g_pCompositor->getMonitorFromCursor();
+ if (!m_monitor)
+ return;
+
+ const auto PMONITOR = m_monitor.lock();
+ if (!PMONITOR)
+ return;
+
+ m_zoomBegin = std::clamp(PMONITOR->m_cursorZoom->value(), 1.0F, 100.0F);
+ PMONITOR->m_cursorZoom->setValueAndWarp(m_zoomBegin);
+ PMONITOR->m_zoomController.pinAnchor(g_pInputManager->getMouseCoordsInternal() - PMONITOR->m_position);
+ return;
+ }
+
if (m_mode == MODE_TOGGLE)
m_zoomed = !m_zoomed;
@@ -25,9 +46,35 @@ void CCursorZoomTrackpadGesture::begin(const ITrackpadGesture::STrackpadGestureB
*m->m_cursorZoom = m_zoomed ? m_zoomValue : *PZOOMFACTOR;
break;
case MODE_MULT: *m->m_cursorZoom = std::clamp(m->m_cursorZoom->goal() * m_zoomValue, 1.0F, 100.0F); break;
+ case MODE_LIVE: break;
}
}
}
-void CCursorZoomTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) {}
-void CCursorZoomTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) {}
+void CCursorZoomTrackpadGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) {
+ if (m_mode != MODE_LIVE || !m_monitor || !e.pinch)
+ return;
+
+ const auto PMONITOR = m_monitor.lock();
+ if (!PMONITOR)
+ return;
+
+ auto zoom = std::clamp(m_zoomBegin * static_cast<float>(e.pinch->scale), 1.0F, 100.0F);
+
+ if (zoom < 1.05F)
+ zoom = 1.0F;
+
+ PMONITOR->m_cursorZoom->setValueAndWarp(zoom);
+}
+
+void CCursorZoomTrackpadGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) {
+ if (m_mode != MODE_LIVE || !m_monitor)
+ return;
+
+ const auto PMONITOR = m_monitor.lock();
+ if (!PMONITOR)
+ return;
+
+ PMONITOR->m_zoomController.clearAnchor();
+ m_monitor.reset();
+}
diff --git a/src/managers/input/trackpad/gestures/CursorZoomGesture.hpp b/src/managers/input/trackpad/gestures/CursorZoomGesture.hpp
index b53c81e9..3def907f 100644
--- a/src/managers/input/trackpad/gestures/CursorZoomGesture.hpp
+++ b/src/managers/input/trackpad/gestures/CursorZoomGesture.hpp
@@ -2,6 +2,8 @@
#include "ITrackpadGesture.hpp"
+#include "../../../../desktop/DesktopTypes.hpp"
+
class CCursorZoomTrackpadGesture : public ITrackpadGesture {
public:
CCursorZoomTrackpadGesture(const std::string& zoomLevel, const std::string& mode);
@@ -14,10 +16,13 @@ class CCursorZoomTrackpadGesture : public ITrackpadGesture {
private:
float m_zoomValue = 1.0;
inline static bool m_zoomed = false;
+ PHLMONITORREF m_monitor;
+ float m_zoomBegin = 1.0;
enum eMode : uint8_t {
MODE_TOGGLE = 0,
MODE_MULT,
+ MODE_LIVE,
};
eMode m_mode = MODE_TOGGLE;