From 41dad381770300fe1015ad8cdd1f370a8fd4e5d5 Mon Sep 17 00:00:00 2001 From: Nikolai Nechaev Date: Sun, 21 Sep 2025 00:57:49 +0900 Subject: [PATCH] config: fix multi-argument gesture dispatcher parsing (#11721) * config: Fix multi-argument gesture dispatchers parsing The `dispatcher` gesture handler used to only handle the first argument to the dispatcher, while some dispatchers (e.g., `sendshortcut`) want multiple arguments. This fixes `ConfigManager` to handle all the arguments provided to the dispatcher gesture handler. Fixes #11684. * test/gestures: Add a test for a gesture with a multi-argument dispatcher * test/gestures: Factor out `waitForWindowCount` Reduce code duplication in the gestures test. --- hyprtester/src/tests/main/gestures.cpp | 49 +++++++++++++++----------- hyprtester/test.conf | 2 ++ src/config/ConfigManager.cpp | 12 ++++--- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/hyprtester/src/tests/main/gestures.cpp b/hyprtester/src/tests/main/gestures.cpp index 37d367d2..94ac1261 100644 --- a/hyprtester/src/tests/main/gestures.cpp +++ b/hyprtester/src/tests/main/gestures.cpp @@ -18,6 +18,20 @@ using namespace Hyprutils::Memory; #define UP CUniquePointer #define SP CSharedPointer +static bool waitForWindowCount(int expectedWindowCnt, std::string_view expectation, int waitMillis = 100, int maxWaitCnt = 50) { + int counter = 0; + while (Tests::windowCount() != expectedWindowCnt) { + counter++; + std::this_thread::sleep_for(std::chrono::milliseconds(waitMillis)); + + if (counter > maxWaitCnt) { + NLog::log("{}Unmet expectation: {}", Colors::RED, expectation); + return false; + } + } + return true; +} + static bool test() { NLog::log("{}Testing gestures", Colors::GREEN); @@ -27,19 +41,21 @@ static bool test() { NLog::log("{}Switching to workspace 1", Colors::YELLOW); getFromSocket("/dispatch workspace 1"); // no OK: we might be on 1 already + Tests::spawnKitty(); + EXPECT(Tests::windowCount(), 1); + + // Give the shell a moment to initialize + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + OK(getFromSocket("/dispatch plugin:test:gesture up,4")); + + EXPECT(waitForWindowCount(0, "Gesture sent ctrl+d to kitty"), true); + + EXPECT(Tests::windowCount(), 0); + OK(getFromSocket("/dispatch plugin:test:gesture left,3")); - // wait while kitty spawns - int counter = 0; - while (Tests::windowCount() != 1) { - counter++; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - if (counter > 50) { - NLog::log("{}Gesture didnt spawn kitty", Colors::RED); - return false; - } - } + EXPECT(waitForWindowCount(1, "Gesture spawned kitty"), true); EXPECT(Tests::windowCount(), 1); @@ -126,16 +142,7 @@ static bool test() { OK(getFromSocket("/dispatch plugin:test:gesture up,3")); - counter = 0; - while (Tests::windowCount() != 0) { - counter++; - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - if (counter > 50) { - NLog::log("{}Gesture didnt close kitty", Colors::RED); - return false; - } - } + EXPECT(waitForWindowCount(0, "Gesture closed kitty"), true); EXPECT(Tests::windowCount(), 0); diff --git a/hyprtester/test.conf b/hyprtester/test.conf index 7b0c53b7..ac0518d1 100644 --- a/hyprtester/test.conf +++ b/hyprtester/test.conf @@ -332,3 +332,5 @@ gesture = 3, down, mod:ALT, float gesture = 3, horizontal, mod:ALT, workspace +gesture = 4, up, dispatcher, sendshortcut, ctrl, d, activewindow + diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index db0dd596..78ca1fe1 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -3229,10 +3229,14 @@ std::optional CConfigManager::handleGesture(const std::string& comm std::expected result; - if (data[startDataIdx] == "dispatcher") - result = g_pTrackpadGestures->addGesture(makeUnique(std::string{data[startDataIdx + 1]}, std::string{data[startDataIdx + 2]}), fingerCount, - direction, modMask, deltaScale); - else if (data[startDataIdx] == "workspace") + if (data[startDataIdx] == "dispatcher") { + auto dispatcherArgsIt = value.begin(); + for (int i = 0; i < startDataIdx + 2 && dispatcherArgsIt < value.end(); ++i) { + dispatcherArgsIt = std::find(dispatcherArgsIt, value.end(), ',') + 1; + } + result = g_pTrackpadGestures->addGesture(makeUnique(std::string{data[startDataIdx + 1]}, std::string(dispatcherArgsIt, value.end())), + fingerCount, direction, modMask, deltaScale); + } else if (data[startDataIdx] == "workspace") result = g_pTrackpadGestures->addGesture(makeUnique(), fingerCount, direction, modMask, deltaScale); else if (data[startDataIdx] == "resize") result = g_pTrackpadGestures->addGesture(makeUnique(), fingerCount, direction, modMask, deltaScale);