mirror of
https://github.com/hyprwm/hyprland-plugins.git
synced 2025-12-19 22:50:01 +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:
|
||||
$(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:
|
||||
rm ./hyprexpo.so
|
||||
|
|
|
|||
|
|
@ -14,10 +14,7 @@ plugin {
|
|||
bg_col = rgb(111111)
|
||||
workspace_method = center current # [center/first] [workspace] e.g. first 1 or center m+1
|
||||
|
||||
enable_gesture = true # laptop touchpad
|
||||
gesture_fingers = 3 # 3 or 4
|
||||
gesture_distance = 300 # how far is the "max"
|
||||
gesture_positive = true # positive = swipe down. Negative = swipe up.
|
||||
gesture_distance = 300 # how far is the "max" for the gesture
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -31,10 +28,13 @@ gap_size | number | gap between desktops | `5`
|
|||
bg_col | color | color in gaps (between desktops) | `rgb(000000)`
|
||||
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`
|
||||
enable_gesture | boolean | enable touchpad gestures | `true`
|
||||
gesture_fingers | `3` or `4` | how many fingers are needed in the gesture | `3`
|
||||
gesture_distance | number | how far is the max | `300`
|
||||
gesture_positive | boolean | whether to swipe down (true), or up (false) | `true`
|
||||
gesture_distance | number | how far is the max for the gesture | `300`
|
||||
|
||||
### Keywords
|
||||
|
||||
| name | description | arguments |
|
||||
| -- | -- | -- |
|
||||
| hyprexpo-gesture | same as gesture, but for hyprexpo gestures. Supports: `expo`. | Same as gesture |
|
||||
|
||||
### Binding
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -7,9 +7,15 @@
|
|||
#include <hyprland/src/config/ConfigManager.hpp>
|
||||
#include <hyprland/src/desktop/DesktopTypes.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 "overview.hpp"
|
||||
#include "ExpoGesture.hpp"
|
||||
|
||||
// Methods
|
||||
inline CFunctionHook* g_pRenderWorkspaceHook = nullptr;
|
||||
|
|
@ -56,81 +62,12 @@ static void hkAddDamageB(void* thisptr, const pixman_region32_t* rg) {
|
|||
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) {
|
||||
|
||||
if (swipeActive)
|
||||
return {};
|
||||
if (arg == "select") {
|
||||
if (g_pOverview->m_isSwiping)
|
||||
return {.success = false, .error = "already swiping"};
|
||||
|
||||
if (arg == "select") {
|
||||
if (g_pOverview) {
|
||||
g_pOverview->selectHoveredWorkspace();
|
||||
g_pOverview->close();
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
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) {
|
||||
PHANDLE = handle;
|
||||
|
||||
|
|
@ -216,11 +223,9 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
g_pOverview->onPreRender();
|
||||
});
|
||||
|
||||
static auto P2 = HyprlandAPI::registerCallbackDynamic(PHANDLE, "swipeBegin", [](void* self, SCallbackInfo& info, std::any data) { swipeBegin(self, info, data); });
|
||||
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::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: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: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_positive", Hyprlang::INT{1});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gesture_fingers", Hyprlang::INT{4});
|
||||
|
||||
HyprlandAPI::reloadConfig();
|
||||
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@ COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn
|
|||
// (skip_empty), stop when we wrap, leaving the rest of the workspace
|
||||
// ID's set to WORKSPACE_INVALID
|
||||
for (size_t i = 1; i < (size_t)(SIDE_LENGTH * SIDE_LENGTH); ++i) {
|
||||
auto& image = images[i];
|
||||
currentID = getWorkspaceIDNameFromString(selector + "+" + std::to_string(i)).id;
|
||||
auto& image = images[i];
|
||||
currentID = getWorkspaceIDNameFromString(selector + "+" + std::to_string(i)).id;
|
||||
if (currentID <= methodStartID)
|
||||
break;
|
||||
image.workspaceID = currentID;
|
||||
|
|
@ -155,7 +155,7 @@ COverview::COverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn
|
|||
currentid = i;
|
||||
|
||||
if (PWORKSPACE) {
|
||||
image.pWorkspace = PWORKSPACE;
|
||||
image.pWorkspace = PWORKSPACE;
|
||||
PMONITOR->m_activeWorkspace = PWORKSPACE;
|
||||
g_pDesktopAnimationManager->startAnimation(PWORKSPACE, CDesktopAnimationManager::ANIMATION_TYPE_IN, true, true);
|
||||
PWORKSPACE->m_visible = true;
|
||||
|
|
@ -246,8 +246,8 @@ void COverview::selectHoveredWorkspace() {
|
|||
return;
|
||||
|
||||
// get tile x,y
|
||||
int x = lastMousePosLocal.x / pMonitor->m_size.x * SIDE_LENGTH;
|
||||
int y = lastMousePosLocal.y / pMonitor->m_size.y * SIDE_LENGTH;
|
||||
int x = lastMousePosLocal.x / pMonitor->m_size.x * SIDE_LENGTH;
|
||||
int y = lastMousePosLocal.y / pMonitor->m_size.y * SIDE_LENGTH;
|
||||
closeOnID = x + y * SIDE_LENGTH;
|
||||
}
|
||||
|
||||
|
|
@ -337,12 +337,12 @@ void COverview::damage() {
|
|||
void COverview::onDamageReported() {
|
||||
damageDirty = true;
|
||||
|
||||
Vector2D SIZE = size->value();
|
||||
Vector2D SIZE = size->value();
|
||||
|
||||
Vector2D tileSize = (SIZE / SIDE_LENGTH);
|
||||
Vector2D tileRenderSize = (SIZE - Vector2D{GAP_WIDTH, GAP_WIDTH} * (SIDE_LENGTH - 1)) / SIDE_LENGTH;
|
||||
Vector2D tileSize = (SIZE / SIDE_LENGTH);
|
||||
Vector2D tileRenderSize = (SIZE - Vector2D{GAP_WIDTH, GAP_WIDTH} * (SIDE_LENGTH - 1)) / SIDE_LENGTH;
|
||||
// const auto& TILE = images[std::clamp(openedID, 0, SIDE_LENGTH * SIDE_LENGTH)];
|
||||
CBox texbox = CBox{(openedID % SIDE_LENGTH) * tileRenderSize.x + (openedID % SIDE_LENGTH) * GAP_WIDTH,
|
||||
CBox texbox = CBox{(openedID % SIDE_LENGTH) * tileRenderSize.x + (openedID % SIDE_LENGTH) * GAP_WIDTH,
|
||||
(openedID / SIDE_LENGTH) * tileRenderSize.y + (openedID / SIDE_LENGTH) * GAP_WIDTH, tileRenderSize.x, tileRenderSize.y}
|
||||
.translate(pMonitor->m_position);
|
||||
|
||||
|
|
@ -461,6 +461,8 @@ static Vector2D lerp(const Vector2D& from, const Vector2D& to, const float perc)
|
|||
}
|
||||
|
||||
void COverview::onSwipeUpdate(double delta) {
|
||||
m_isSwiping = true;
|
||||
|
||||
if (swipeWasCommenced)
|
||||
return;
|
||||
|
||||
|
|
@ -495,4 +497,5 @@ void COverview::onSwipeEnd() {
|
|||
size->setCallbackOnEnd([this](WP<Hyprutils::Animation::CBaseAnimatedVariable> thisptr) { redrawAll(true); });
|
||||
|
||||
swipeWasCommenced = true;
|
||||
m_isSwiping = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class COverview {
|
|||
bool blockDamageReporting = false;
|
||||
|
||||
PHLMONITORREF pMonitor;
|
||||
bool m_isSwiping = false;
|
||||
|
||||
private:
|
||||
void redrawID(int id, bool forcelowres = false);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue