mirror of
https://github.com/hyprwm/hyprland-plugins.git
synced 2025-12-20 15:00:02 +01:00
expo: add new gesture
This commit is contained in:
parent
b8d6d36961
commit
5086bd28f4
7 changed files with 142 additions and 98 deletions
22
hyprexpo/ExpoGesture.cpp
Normal file
22
hyprexpo/ExpoGesture.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include "ExpoGesture.hpp"
|
||||||
|
|
||||||
|
#include "overview.hpp"
|
||||||
|
|
||||||
|
void CExpoGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) {
|
||||||
|
ITrackpadGesture::begin(e);
|
||||||
|
|
||||||
|
m_lastDelta = 0.F;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CExpoGesture::update(const ITrackpadGesture::STrackpadGestureUpdate& e) {
|
||||||
|
m_lastDelta += distance(e);
|
||||||
|
|
||||||
|
if (m_lastDelta <= 0.01) // plugin will crash if swipe ends at <= 0
|
||||||
|
m_lastDelta = 0.01;
|
||||||
|
|
||||||
|
g_pOverview->onSwipeUpdate(m_lastDelta);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CExpoGesture::end(const ITrackpadGesture::STrackpadGestureEnd& e) {
|
||||||
|
g_pOverview->onSwipeEnd();
|
||||||
|
}
|
||||||
16
hyprexpo/ExpoGesture.hpp
Normal file
16
hyprexpo/ExpoGesture.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hyprland/src/managers/input/trackpad/gestures/ITrackpadGesture.hpp>
|
||||||
|
|
||||||
|
class CExpoGesture : public ITrackpadGesture {
|
||||||
|
public:
|
||||||
|
CExpoGesture() = default;
|
||||||
|
virtual ~CExpoGesture() = default;
|
||||||
|
|
||||||
|
virtual void begin(const ITrackpadGesture::STrackpadGestureBegin& e);
|
||||||
|
virtual void update(const ITrackpadGesture::STrackpadGestureUpdate& e);
|
||||||
|
virtual void end(const ITrackpadGesture::STrackpadGestureEnd& e);
|
||||||
|
|
||||||
|
private:
|
||||||
|
float m_lastDelta = 0.F;
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
all:
|
all:
|
||||||
$(CXX) -shared -fPIC --no-gnu-unique main.cpp overview.cpp OverviewPassElement.cpp -o hyprexpo.so -g `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` -std=c++2b -Wno-narrowing
|
$(CXX) -shared -fPIC --no-gnu-unique main.cpp overview.cpp ExpoGesture.cpp OverviewPassElement.cpp -o hyprexpo.so -g `pkg-config --cflags pixman-1 libdrm hyprland pangocairo libinput libudev wayland-server xkbcommon` -std=c++2b -Wno-narrowing
|
||||||
clean:
|
clean:
|
||||||
rm ./hyprexpo.so
|
rm ./hyprexpo.so
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,7 @@ plugin {
|
||||||
bg_col = rgb(111111)
|
bg_col = rgb(111111)
|
||||||
workspace_method = center current # [center/first] [workspace] e.g. first 1 or center m+1
|
workspace_method = center current # [center/first] [workspace] e.g. first 1 or center m+1
|
||||||
|
|
||||||
enable_gesture = true # laptop touchpad
|
gesture_distance = 300 # how far is the "max" for the gesture
|
||||||
gesture_fingers = 3 # 3 or 4
|
|
||||||
gesture_distance = 300 # how far is the "max"
|
|
||||||
gesture_positive = true # positive = swipe down. Negative = swipe up.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -31,10 +28,13 @@ gap_size | number | gap between desktops | `5`
|
||||||
bg_col | color | color in gaps (between desktops) | `rgb(000000)`
|
bg_col | color | color in gaps (between desktops) | `rgb(000000)`
|
||||||
workspace_method | [center/first] [workspace] | position of the desktops | `center current`
|
workspace_method | [center/first] [workspace] | position of the desktops | `center current`
|
||||||
skip_empty | boolean | whether the grid displays workspaces sequentially by id using selector "r" (`false`) or skips empty workspaces using selector "m" (`true`) | `false`
|
skip_empty | boolean | whether the grid displays workspaces sequentially by id using selector "r" (`false`) or skips empty workspaces using selector "m" (`true`) | `false`
|
||||||
enable_gesture | boolean | enable touchpad gestures | `true`
|
gesture_distance | number | how far is the max for the gesture | `300`
|
||||||
gesture_fingers | `3` or `4` | how many fingers are needed in the gesture | `3`
|
|
||||||
gesture_distance | number | how far is the max | `300`
|
### Keywords
|
||||||
gesture_positive | boolean | whether to swipe down (true), or up (false) | `true`
|
|
||||||
|
| name | description | arguments |
|
||||||
|
| -- | -- | -- |
|
||||||
|
| hyprexpo-gesture | same as gesture, but for hyprexpo gestures. Supports: `expo`. | Same as gesture |
|
||||||
|
|
||||||
### Binding
|
### Binding
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,15 @@
|
||||||
#include <hyprland/src/config/ConfigManager.hpp>
|
#include <hyprland/src/config/ConfigManager.hpp>
|
||||||
#include <hyprland/src/desktop/DesktopTypes.hpp>
|
#include <hyprland/src/desktop/DesktopTypes.hpp>
|
||||||
#include <hyprland/src/render/Renderer.hpp>
|
#include <hyprland/src/render/Renderer.hpp>
|
||||||
|
#include <hyprland/src/managers/input/trackpad/GestureTypes.hpp>
|
||||||
|
#include <hyprland/src/managers/input/trackpad/TrackpadGestures.hpp>
|
||||||
|
|
||||||
|
#include <hyprutils/string/ConstVarList.hpp>
|
||||||
|
using namespace Hyprutils::String;
|
||||||
|
|
||||||
#include "globals.hpp"
|
#include "globals.hpp"
|
||||||
#include "overview.hpp"
|
#include "overview.hpp"
|
||||||
|
#include "ExpoGesture.hpp"
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
inline CFunctionHook* g_pRenderWorkspaceHook = nullptr;
|
inline CFunctionHook* g_pRenderWorkspaceHook = nullptr;
|
||||||
|
|
@ -56,80 +62,11 @@ static void hkAddDamageB(void* thisptr, const pixman_region32_t* rg) {
|
||||||
g_pOverview->onDamageReported();
|
g_pOverview->onDamageReported();
|
||||||
}
|
}
|
||||||
|
|
||||||
static float gestured = 0;
|
|
||||||
bool swipeActive = false;
|
|
||||||
char swipeDirection = 0; // 0 = no direction, 'v' = vertical, 'h' = horizontal
|
|
||||||
|
|
||||||
static void swipeBegin(void* self, SCallbackInfo& info, std::any param) {
|
|
||||||
swipeActive = false;
|
|
||||||
swipeDirection = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void swipeUpdate(void* self, SCallbackInfo& info, std::any param) {
|
|
||||||
static auto* const* PENABLE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:enable_gesture")->getDataStaticPtr();
|
|
||||||
static auto* const* FINGERS = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:gesture_fingers")->getDataStaticPtr();
|
|
||||||
static auto* const* PPOSITIVE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:gesture_positive")->getDataStaticPtr();
|
|
||||||
static auto* const* PDISTANCE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:gesture_distance")->getDataStaticPtr();
|
|
||||||
auto e = std::any_cast<IPointer::SSwipeUpdateEvent>(param);
|
|
||||||
|
|
||||||
if (!swipeDirection) {
|
|
||||||
if (std::abs(e.delta.x) > std::abs(e.delta.y))
|
|
||||||
swipeDirection = 'h';
|
|
||||||
else if (std::abs(e.delta.y) > std::abs(e.delta.x))
|
|
||||||
swipeDirection = 'v';
|
|
||||||
else
|
|
||||||
swipeDirection = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swipeActive || g_pOverview)
|
|
||||||
info.cancelled = true;
|
|
||||||
|
|
||||||
if (!**PENABLE || e.fingers != **FINGERS || swipeDirection != 'v')
|
|
||||||
return;
|
|
||||||
|
|
||||||
info.cancelled = true;
|
|
||||||
if (!swipeActive) {
|
|
||||||
if (g_pOverview && (**PPOSITIVE ? 1.0 : -1.0) * e.delta.y <= 0) {
|
|
||||||
renderingOverview = true;
|
|
||||||
g_pOverview = std::make_unique<COverview>(g_pCompositor->m_lastMonitor->m_activeWorkspace, true);
|
|
||||||
renderingOverview = false;
|
|
||||||
gestured = **PDISTANCE;
|
|
||||||
swipeActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!g_pOverview && (**PPOSITIVE ? 1.0 : -1.0) * e.delta.y > 0) {
|
|
||||||
renderingOverview = true;
|
|
||||||
g_pOverview = std::make_unique<COverview>(g_pCompositor->m_lastMonitor->m_activeWorkspace, true);
|
|
||||||
renderingOverview = false;
|
|
||||||
gestured = 0;
|
|
||||||
swipeActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gestured += (**PPOSITIVE ? 1.0 : -1.0) * e.delta.y;
|
|
||||||
if (gestured <= 0.01) // plugin will crash if swipe ends at <= 0
|
|
||||||
gestured = 0.01;
|
|
||||||
g_pOverview->onSwipeUpdate(gestured);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void swipeEnd(void* self, SCallbackInfo& info, std::any param) {
|
|
||||||
if (!g_pOverview)
|
|
||||||
return;
|
|
||||||
|
|
||||||
swipeActive = false;
|
|
||||||
info.cancelled = true;
|
|
||||||
|
|
||||||
g_pOverview->onSwipeEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
static SDispatchResult onExpoDispatcher(std::string arg) {
|
static SDispatchResult onExpoDispatcher(std::string arg) {
|
||||||
|
|
||||||
if (swipeActive)
|
if (g_pOverview->m_isSwiping)
|
||||||
return {};
|
return {.success = false, .error = "already swiping"};
|
||||||
|
|
||||||
if (arg == "select") {
|
if (arg == "select") {
|
||||||
if (g_pOverview) {
|
if (g_pOverview) {
|
||||||
g_pOverview->selectHoveredWorkspace();
|
g_pOverview->selectHoveredWorkspace();
|
||||||
|
|
@ -167,6 +104,76 @@ static void failNotif(const std::string& reason) {
|
||||||
HyprlandAPI::addNotification(PHANDLE, "[hyprexpo] Failure in initialization: " + reason, CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000);
|
HyprlandAPI::addNotification(PHANDLE, "[hyprexpo] Failure in initialization: " + reason, CHyprColor{1.0, 0.2, 0.2, 1.0}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Hyprlang::CParseResult expoGestureKeyword(const char* LHS, const char* RHS) {
|
||||||
|
Hyprlang::CParseResult result;
|
||||||
|
|
||||||
|
CConstVarList data(RHS);
|
||||||
|
|
||||||
|
size_t fingerCount = 0;
|
||||||
|
eTrackpadGestureDirection direction = TRACKPAD_GESTURE_DIR_NONE;
|
||||||
|
|
||||||
|
try {
|
||||||
|
fingerCount = std::stoul(std::string{data[0]});
|
||||||
|
} catch (...) {
|
||||||
|
result.setError(std::format("Invalid value {} for finger count", data[0]).c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fingerCount <= 1 || fingerCount >= 10) {
|
||||||
|
result.setError(std::format("Invalid value {} for finger count", data[0]).c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
direction = g_pTrackpadGestures->dirForString(data[1]);
|
||||||
|
|
||||||
|
if (direction == TRACKPAD_GESTURE_DIR_NONE) {
|
||||||
|
result.setError(std::format("Invalid direction: {}", data[1]).c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int startDataIdx = 2;
|
||||||
|
uint32_t modMask = 0;
|
||||||
|
float deltaScale = 1.F;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
if (data[startDataIdx].starts_with("mod:")) {
|
||||||
|
modMask = g_pKeybindManager->stringToModMask(std::string{data[startDataIdx].substr(4)});
|
||||||
|
startDataIdx++;
|
||||||
|
continue;
|
||||||
|
} else if (data[startDataIdx].starts_with("scale:")) {
|
||||||
|
try {
|
||||||
|
deltaScale = std::clamp(std::stof(std::string{data[startDataIdx].substr(6)}), 0.1F, 10.F);
|
||||||
|
startDataIdx++;
|
||||||
|
continue;
|
||||||
|
} catch (...) {
|
||||||
|
result.setError(std::format("Invalid delta scale: {}", std::string{data[startDataIdx].substr(6)}).c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::expected<void, std::string> resultFromGesture;
|
||||||
|
|
||||||
|
if (data[startDataIdx] == "expo")
|
||||||
|
resultFromGesture = g_pTrackpadGestures->addGesture(makeUnique<CExpoGesture>(), fingerCount, direction, modMask, deltaScale);
|
||||||
|
else if (data[startDataIdx] == "unset")
|
||||||
|
resultFromGesture = g_pTrackpadGestures->removeGesture(fingerCount, direction, modMask, deltaScale);
|
||||||
|
else {
|
||||||
|
result.setError(std::format("Invalid gesture: {}", data[startDataIdx]).c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resultFromGesture) {
|
||||||
|
result.setError(resultFromGesture.error().c_str());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
PHANDLE = handle;
|
PHANDLE = handle;
|
||||||
|
|
||||||
|
|
@ -216,11 +223,9 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
g_pOverview->onPreRender();
|
g_pOverview->onPreRender();
|
||||||
});
|
});
|
||||||
|
|
||||||
static auto P2 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "swipeBegin", [](void* self, SCallbackInfo& info, std::any data) { swipeBegin(self, info, data); });
|
HyprlandAPI::addDispatcherV2(PHANDLE, "hyprexpo:expo", ::onExpoDispatcher);
|
||||||
static auto P3 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "swipeEnd", [](void* self, SCallbackInfo& info, std::any data) { swipeEnd(self, info, data); });
|
|
||||||
static auto P4 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "swipeUpdate", [](void* self, SCallbackInfo& info, std::any data) { swipeUpdate(self, info, data); });
|
|
||||||
|
|
||||||
HyprlandAPI::addDispatcherV2(PHANDLE, "hyprexpo:expo", onExpoDispatcher);
|
HyprlandAPI::addConfigKeyword(PHANDLE, "hyprexpo-gesture", ::expoGestureKeyword, {});
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:columns", Hyprlang::INT{3});
|
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:columns", Hyprlang::INT{3});
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gap_size", Hyprlang::INT{5});
|
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gap_size", Hyprlang::INT{5});
|
||||||
|
|
@ -228,10 +233,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:workspace_method", Hyprlang::STRING{"center current"});
|
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:workspace_method", Hyprlang::STRING{"center current"});
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:skip_empty", Hyprlang::INT{0});
|
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:skip_empty", Hyprlang::INT{0});
|
||||||
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:enable_gesture", Hyprlang::INT{1});
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gesture_distance", Hyprlang::INT{200});
|
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gesture_distance", Hyprlang::INT{200});
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gesture_positive", Hyprlang::INT{1});
|
|
||||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gesture_fingers", Hyprlang::INT{4});
|
|
||||||
|
|
||||||
HyprlandAPI::reloadConfig();
|
HyprlandAPI::reloadConfig();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -461,6 +461,8 @@ static Vector2D lerp(const Vector2D& from, const Vector2D& to, const float perc)
|
||||||
}
|
}
|
||||||
|
|
||||||
void COverview::onSwipeUpdate(double delta) {
|
void COverview::onSwipeUpdate(double delta) {
|
||||||
|
m_isSwiping = true;
|
||||||
|
|
||||||
if (swipeWasCommenced)
|
if (swipeWasCommenced)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -495,4 +497,5 @@ void COverview::onSwipeEnd() {
|
||||||
size->setCallbackOnEnd([this](WP<Hyprutils::Animation::CBaseAnimatedVariable> thisptr) { redrawAll(true); });
|
size->setCallbackOnEnd([this](WP<Hyprutils::Animation::CBaseAnimatedVariable> thisptr) { redrawAll(true); });
|
||||||
|
|
||||||
swipeWasCommenced = true;
|
swipeWasCommenced = true;
|
||||||
|
m_isSwiping = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ class COverview {
|
||||||
bool blockDamageReporting = false;
|
bool blockDamageReporting = false;
|
||||||
|
|
||||||
PHLMONITORREF pMonitor;
|
PHLMONITORREF pMonitor;
|
||||||
|
bool m_isSwiping = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void redrawID(int id, bool forcelowres = false);
|
void redrawID(int id, bool forcelowres = false);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue