mirror of
https://github.com/hyprwm/hyprland-plugins.git
synced 2026-05-04 17:57:58 +02:00
Merge 53f9568ac9 into 9b2b156197
This commit is contained in:
commit
e00f7673a5
10 changed files with 711 additions and 31 deletions
|
|
@ -13,7 +13,7 @@ void CExpoGesture::begin(const ITrackpadGesture::STrackpadGestureBegin& e) {
|
|||
m_firstUpdate = true;
|
||||
|
||||
if (!g_pOverview)
|
||||
g_pOverview = std::make_unique<COverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
g_pOverview = makeShared<COverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
else {
|
||||
g_pOverview->selectHoveredWorkspace();
|
||||
g_pOverview->setClosing(true);
|
||||
|
|
|
|||
32
hyprexpo/IOverview.hpp
Normal file
32
hyprexpo/IOverview.hpp
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
#include <hyprland/src/helpers/memory/Memory.hpp>
|
||||
|
||||
class IOverview {
|
||||
public:
|
||||
IOverview() = default;
|
||||
virtual ~IOverview() = default;
|
||||
|
||||
virtual void render() = 0;
|
||||
virtual void damage() = 0;
|
||||
virtual void onDamageReported() = 0;
|
||||
virtual void onPreRender() = 0;
|
||||
|
||||
virtual void setClosing(bool closing) = 0;
|
||||
|
||||
virtual void resetSwipe() = 0;
|
||||
virtual void onSwipeUpdate(double delta) = 0;
|
||||
virtual void onSwipeEnd() = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
virtual void selectHoveredWorkspace() = 0;
|
||||
|
||||
virtual void fullRender() = 0;
|
||||
|
||||
bool blockOverviewRendering = false;
|
||||
bool blockDamageReporting = false;
|
||||
|
||||
PHLMONITORREF pMonitor;
|
||||
bool m_isSwiping = false;
|
||||
};
|
||||
|
||||
inline SP<IOverview> g_pOverview;
|
||||
|
|
@ -6,6 +6,6 @@ else
|
|||
endif
|
||||
|
||||
all:
|
||||
$(CXX) -shared -fPIC $(EXTRA_FLAGS) 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
|
||||
$(CXX) -shared -fPIC $(EXTRA_FLAGS) main.cpp overview.cpp ExpoGesture.cpp OverviewPassElement.cpp scrollOverview.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
|
||||
|
|
|
|||
|
|
@ -23,12 +23,21 @@ plugin {
|
|||
|
||||
| property | type | description | default |
|
||||
| --- | --- | --- | --- |
|
||||
columns | number | how many desktops are displayed on one line | `3`
|
||||
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`
|
||||
gesture_distance | number | how far is the max for the gesture | `300`
|
||||
|columns | number | how many desktops are displayed on one line | `3`|
|
||||
|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`|
|
||||
|gesture_distance | number | how far is the max for the gesture | `300`|
|
||||
|
||||
#### Subcategory `scrolling`
|
||||
|
||||
Applies to the scrolling layout overview
|
||||
| property | type | description | default |
|
||||
| --- | --- | --- | --- |
|
||||
| scroll_moves_up_down | bool | if enabled, scrolling will move workspaces up/down instead of zooming | true |
|
||||
| default_zoom | float | default zoom out value, [0.1 - 0.9] | 0.5 |
|
||||
|
||||
|
||||
### Keywords
|
||||
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
#include <hyprland/src/plugins/PluginAPI.hpp>
|
||||
|
||||
inline HANDLE PHANDLE = nullptr;
|
||||
inline HANDLE PHANDLE = nullptr;
|
||||
inline bool IS_SCROLLING = false;
|
||||
|
|
@ -10,12 +10,14 @@
|
|||
#include <hyprland/src/render/Renderer.hpp>
|
||||
#include <hyprland/src/managers/input/trackpad/GestureTypes.hpp>
|
||||
#include <hyprland/src/managers/input/trackpad/TrackpadGestures.hpp>
|
||||
#include <hyprland/src/managers/LayoutManager.hpp>
|
||||
|
||||
#include <hyprutils/string/ConstVarList.hpp>
|
||||
using namespace Hyprutils::String;
|
||||
|
||||
#include "globals.hpp"
|
||||
#include "overview.hpp"
|
||||
#include "scrollOverview.hpp"
|
||||
#include "ExpoGesture.hpp"
|
||||
|
||||
// Methods
|
||||
|
|
@ -67,6 +69,8 @@ static void hkAddDamageB(void* thisptr, const pixman_region32_t* rg) {
|
|||
|
||||
static SDispatchResult onExpoDispatcher(std::string arg) {
|
||||
|
||||
IS_SCROLLING = g_pLayoutManager->getCurrentLayout()->getLayoutName() == "scrolling";
|
||||
|
||||
if (g_pOverview && g_pOverview->m_isSwiping)
|
||||
return {.success = false, .error = "already swiping"};
|
||||
|
||||
|
|
@ -82,7 +86,12 @@ static SDispatchResult onExpoDispatcher(std::string arg) {
|
|||
g_pOverview->close();
|
||||
else {
|
||||
renderingOverview = true;
|
||||
g_pOverview = std::make_unique<COverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
|
||||
if (IS_SCROLLING)
|
||||
g_pOverview = makeShared<CScrollOverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
else
|
||||
g_pOverview = makeShared<COverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
|
||||
renderingOverview = false;
|
||||
}
|
||||
return {};
|
||||
|
|
@ -98,7 +107,10 @@ static SDispatchResult onExpoDispatcher(std::string arg) {
|
|||
return {};
|
||||
|
||||
renderingOverview = true;
|
||||
g_pOverview = std::make_unique<COverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
if (IS_SCROLLING)
|
||||
g_pOverview = makeShared<CScrollOverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
else
|
||||
g_pOverview = makeShared<COverview>(Desktop::focusState()->monitor()->m_activeWorkspace);
|
||||
renderingOverview = false;
|
||||
return {};
|
||||
}
|
||||
|
|
@ -239,6 +251,8 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
|
|||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:bg_col", Hyprlang::INT{0xFF111111});
|
||||
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:scrolling:scroll_moves_up_down", Hyprlang::INT{1});
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:scrolling:default_zoom", Hyprlang::FLOAT{0.5});
|
||||
|
||||
HyprlandAPI::addConfigValue(PHANDLE, "plugin:hyprexpo:gesture_distance", Hyprlang::INT{200});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <hyprland/src/managers/animation/DesktopAnimationManager.hpp>
|
||||
#include <hyprland/src/managers/cursor/CursorShapeOverrideController.hpp>
|
||||
#include <hyprland/src/managers/input/InputManager.hpp>
|
||||
#include <hyprland/src/managers/LayoutManager.hpp>
|
||||
#include <hyprland/src/helpers/time/Time.hpp>
|
||||
#undef private
|
||||
#include "OverviewPassElement.hpp"
|
||||
|
|
|
|||
|
|
@ -9,43 +9,40 @@
|
|||
#include <hyprland/src/managers/HookSystemManager.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "IOverview.hpp"
|
||||
|
||||
// saves on resources, but is a bit broken rn with blur.
|
||||
// hyprland's fault, but cba to fix.
|
||||
constexpr bool ENABLE_LOWRES = false;
|
||||
|
||||
class CMonitor;
|
||||
|
||||
class COverview {
|
||||
class COverview : public IOverview {
|
||||
public:
|
||||
COverview(PHLWORKSPACE startedOn_, bool swipe = false);
|
||||
~COverview();
|
||||
virtual ~COverview();
|
||||
|
||||
void render();
|
||||
void damage();
|
||||
void onDamageReported();
|
||||
void onPreRender();
|
||||
virtual void render();
|
||||
virtual void damage();
|
||||
virtual void onDamageReported();
|
||||
virtual void onPreRender();
|
||||
|
||||
void setClosing(bool closing);
|
||||
virtual void setClosing(bool closing);
|
||||
|
||||
void resetSwipe();
|
||||
void onSwipeUpdate(double delta);
|
||||
void onSwipeEnd();
|
||||
virtual void resetSwipe();
|
||||
virtual void onSwipeUpdate(double delta);
|
||||
virtual void onSwipeEnd();
|
||||
|
||||
// close without a selection
|
||||
void close();
|
||||
void selectHoveredWorkspace();
|
||||
virtual void close();
|
||||
virtual void selectHoveredWorkspace();
|
||||
|
||||
bool blockOverviewRendering = false;
|
||||
bool blockDamageReporting = false;
|
||||
|
||||
PHLMONITORREF pMonitor;
|
||||
bool m_isSwiping = false;
|
||||
virtual void fullRender();
|
||||
|
||||
private:
|
||||
void redrawID(int id, bool forcelowres = false);
|
||||
void redrawAll(bool forcelowres = false);
|
||||
void onWorkspaceChange();
|
||||
void fullRender();
|
||||
|
||||
int SIDE_LENGTH = 3;
|
||||
int GAP_WIDTH = 5;
|
||||
|
|
@ -84,5 +81,3 @@ class COverview {
|
|||
|
||||
friend class COverviewPassElement;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<COverview> g_pOverview;
|
||||
|
|
|
|||
533
hyprexpo/scrollOverview.cpp
Normal file
533
hyprexpo/scrollOverview.cpp
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
#include "scrollOverview.hpp"
|
||||
#include <any>
|
||||
#define private public
|
||||
#include <hyprland/src/render/Renderer.hpp>
|
||||
#include <hyprland/src/Compositor.hpp>
|
||||
#include <hyprland/src/config/ConfigValue.hpp>
|
||||
#include <hyprland/src/config/ConfigManager.hpp>
|
||||
#include <hyprland/src/managers/animation/AnimationManager.hpp>
|
||||
#include <hyprland/src/managers/animation/DesktopAnimationManager.hpp>
|
||||
#include <hyprland/src/managers/input/InputManager.hpp>
|
||||
#include <hyprland/src/managers/LayoutManager.hpp>
|
||||
#include <hyprland/src/managers/cursor/CursorShapeOverrideController.hpp>
|
||||
#include <hyprland/src/desktop/state/FocusState.hpp>
|
||||
#include <hyprland/src/helpers/time/Time.hpp>
|
||||
#undef private
|
||||
#include "OverviewPassElement.hpp"
|
||||
|
||||
static void damageMonitor(WP<Hyprutils::Animation::CBaseAnimatedVariable> thisptr) {
|
||||
g_pOverview->damage();
|
||||
}
|
||||
|
||||
static void removeOverview(WP<Hyprutils::Animation::CBaseAnimatedVariable> thisptr) {
|
||||
g_pOverview.reset();
|
||||
}
|
||||
|
||||
CScrollOverview::~CScrollOverview() {
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
images.clear(); // otherwise we get a vram leak
|
||||
Cursor::overrideController->unsetOverride(Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
|
||||
g_pHyprOpenGL->markBlurDirtyForMonitor(pMonitor.lock());
|
||||
}
|
||||
|
||||
CScrollOverview::CScrollOverview(PHLWORKSPACE startedOn_, bool swipe_) : startedOn(startedOn_), swipe(swipe_) {
|
||||
static auto* const* PDEFAULTZOOM = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:scrolling:default_zoom")->getDataStaticPtr();
|
||||
|
||||
const auto PMONITOR = Desktop::focusState()->monitor();
|
||||
pMonitor = PMONITOR;
|
||||
|
||||
for (const auto& w : g_pCompositor->getWorkspaces()) {
|
||||
if (w && w->m_monitor == pMonitor && !w->m_isSpecialWorkspace)
|
||||
images.emplace_back(makeShared<SWorkspaceImage>(w.lock()));
|
||||
}
|
||||
|
||||
std::sort(images.begin(), images.end(), [](const auto& a, const auto& b) { return a->pWorkspace->m_id < b->pWorkspace->m_id; });
|
||||
|
||||
g_pAnimationManager->createAnimation(1.F, scale, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE);
|
||||
g_pAnimationManager->createAnimation({}, viewOffset, g_pConfigManager->getAnimationPropertyConfig("windowsMove"), AVARDAMAGE_NONE);
|
||||
|
||||
scale->setUpdateCallback(damageMonitor);
|
||||
viewOffset->setUpdateCallback(damageMonitor);
|
||||
|
||||
if (!swipe)
|
||||
*scale = std::clamp(**PDEFAULTZOOM, 0.1F, 0.9F);
|
||||
|
||||
lastMousePosLocal = g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position;
|
||||
|
||||
auto onCursorMove = [this](void* self, SCallbackInfo& info, std::any param) {
|
||||
if (closing)
|
||||
return;
|
||||
|
||||
info.cancelled = true;
|
||||
lastMousePosLocal = g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position;
|
||||
|
||||
// highlightHoverDebug();
|
||||
};
|
||||
|
||||
auto onCursorSelect = [this](void* self, SCallbackInfo& info, std::any param) {
|
||||
if (closing)
|
||||
return;
|
||||
|
||||
info.cancelled = true;
|
||||
|
||||
selectHoveredWorkspace();
|
||||
|
||||
close();
|
||||
};
|
||||
|
||||
auto onMouseAxis = [this](void* self, SCallbackInfo& info, std::any param) {
|
||||
if (closing)
|
||||
return;
|
||||
|
||||
info.cancelled = true;
|
||||
|
||||
auto data = std::any_cast<std::unordered_map<std::string, std::any>>(param);
|
||||
auto e = std::any_cast<IPointer::SAxisEvent>(data["event"]);
|
||||
|
||||
static auto* const* PZOOM = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:scrolling:scroll_moves_up_down")->getDataStaticPtr();
|
||||
|
||||
if (!**PZOOM) {
|
||||
const auto VAL = std::clamp(sc<float>(scale->value() + e.delta / -500.F), 0.05F, 0.95F);
|
||||
*scale = VAL;
|
||||
} else
|
||||
moveViewportWorkspace(e.delta > 0);
|
||||
};
|
||||
|
||||
auto onWindowOpen = [this](void* self, SCallbackInfo& info, std::any param) {
|
||||
if (closing)
|
||||
return;
|
||||
|
||||
redrawAll();
|
||||
};
|
||||
|
||||
mouseMoveHook = g_pHookSystem->hookDynamic("mouseMove", onCursorMove);
|
||||
touchMoveHook = g_pHookSystem->hookDynamic("touchMove", onCursorMove);
|
||||
mouseAxisHook = g_pHookSystem->hookDynamic("mouseAxis", onMouseAxis);
|
||||
|
||||
mouseButtonHook = g_pHookSystem->hookDynamic("mouseButton", onCursorSelect);
|
||||
touchDownHook = g_pHookSystem->hookDynamic("touchDown", onCursorSelect);
|
||||
|
||||
windowOpenHook = g_pHookSystem->hookDynamic("openWindow", onWindowOpen);
|
||||
|
||||
Cursor::overrideController->setOverride("left_ptr", Cursor::CURSOR_OVERRIDE_SPECIAL_ACTION);
|
||||
|
||||
redrawAll();
|
||||
|
||||
size_t activeIdx = 0;
|
||||
for (size_t i = 0; i < images.size(); ++i) {
|
||||
if (images[i]->pWorkspace && images[i]->pWorkspace == startedOn) {
|
||||
activeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
viewportCurrentWorkspace = activeIdx;
|
||||
}
|
||||
|
||||
void CScrollOverview::selectHoveredWorkspace() {
|
||||
size_t activeIdx = 0;
|
||||
for (size_t i = 0; i < images.size(); ++i) {
|
||||
if (images[i]->pWorkspace && images[i]->pWorkspace == startedOn) {
|
||||
activeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto VIEWPORT_CENTER = CBox{{}, pMonitor->m_size}.middle();
|
||||
|
||||
float yoff = -(float)activeIdx * pMonitor->m_size.y * scale->value();
|
||||
bool found = false;
|
||||
for (const auto& wimg : images) {
|
||||
for (const auto& img : wimg->windowImages) {
|
||||
CBox texbox = {img->pWindow->m_realPosition->value() - pMonitor->m_position, img->pWindow->m_realSize->value()};
|
||||
|
||||
// scale the box to the viewport center
|
||||
texbox.translate(-VIEWPORT_CENTER).scale(scale->value()).translate(VIEWPORT_CENTER).translate(-viewOffset->value() * scale->value());
|
||||
|
||||
texbox.translate({0.F, yoff});
|
||||
|
||||
// texbox.scale(pMonitor->m_scale).round();
|
||||
|
||||
if (texbox.containsPoint(lastMousePosLocal)) {
|
||||
closeOnWindow = img->pWindow;
|
||||
// *viewOffset = CBox{img->pWindow->m_realPosition->value(), img->pWindow->m_realSize->value()}.translate({0.F, yoff / scale->value()}).middle() -
|
||||
// CBox{pMonitor->m_position, pMonitor->m_size}.middle();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
yoff += pMonitor->m_size.y * scale->value();
|
||||
}
|
||||
}
|
||||
|
||||
void CScrollOverview::moveViewportWorkspace(bool up) {
|
||||
size_t activeIdx = 0;
|
||||
for (size_t i = 0; i < images.size(); ++i) {
|
||||
if (images[i]->pWorkspace && images[i]->pWorkspace == startedOn) {
|
||||
activeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (viewportCurrentWorkspace == 0 && !up)
|
||||
return;
|
||||
if (viewportCurrentWorkspace == images.size() - 1 && up)
|
||||
return;
|
||||
|
||||
if (up)
|
||||
viewportCurrentWorkspace++;
|
||||
else
|
||||
viewportCurrentWorkspace--;
|
||||
|
||||
*viewOffset = {viewOffset->value().x, (sc<long>(viewportCurrentWorkspace) - sc<long>(activeIdx)) * pMonitor->m_size.y};
|
||||
}
|
||||
|
||||
void CScrollOverview::highlightHoverDebug() {
|
||||
size_t activeIdx = 0;
|
||||
for (size_t i = 0; i < images.size(); ++i) {
|
||||
if (images[i]->pWorkspace && images[i]->pWorkspace == startedOn) {
|
||||
activeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto VIEWPORT_CENTER = CBox{{}, pMonitor->m_size}.middle();
|
||||
|
||||
float yoff = -(float)activeIdx * pMonitor->m_size.y * scale->value();
|
||||
for (const auto& wimg : images) {
|
||||
for (const auto& img : wimg->windowImages) {
|
||||
CBox texbox = {img->pWindow->m_realPosition->value() - pMonitor->m_position, img->pWindow->m_realSize->value()};
|
||||
|
||||
// scale the box to the viewport center
|
||||
texbox.translate(-VIEWPORT_CENTER).scale(scale->value()).translate(VIEWPORT_CENTER).translate(-viewOffset->value() * scale->value());
|
||||
|
||||
texbox.translate({0.F, yoff});
|
||||
|
||||
// texbox.scale(pMonitor->m_scale).round();
|
||||
|
||||
if (texbox.containsPoint(lastMousePosLocal)) {
|
||||
img->highlight = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
img->highlight = false;
|
||||
}
|
||||
yoff += pMonitor->m_size.y * scale->value();
|
||||
}
|
||||
}
|
||||
|
||||
SP<CScrollOverview::SWorkspaceImage> CScrollOverview::imageForWorkspace(PHLWORKSPACE w) {
|
||||
for (const auto& i : images) {
|
||||
if (i->pWorkspace == w)
|
||||
return i;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CScrollOverview::redrawWorkspace(PHLWORKSPACE workspace, bool forcelowres) {
|
||||
if (pMonitor->m_activeWorkspace != startedOn && !closing) {
|
||||
// likely user changed.
|
||||
onWorkspaceChange();
|
||||
}
|
||||
|
||||
blockOverviewRendering = true;
|
||||
|
||||
g_pHyprRenderer->makeEGLCurrent();
|
||||
|
||||
auto image = imageForWorkspace(workspace);
|
||||
|
||||
if (!image)
|
||||
return;
|
||||
|
||||
// get all tiled windows on the workspace and max dim
|
||||
// TODO: float
|
||||
std::vector<PHLWINDOW> windows;
|
||||
for (const auto& w : g_pCompositor->m_windows) {
|
||||
if (!validMapped(w) || w->m_isFloating || w->m_workspace != workspace)
|
||||
continue;
|
||||
windows.emplace_back(w);
|
||||
}
|
||||
|
||||
for (const auto& w : windows) {
|
||||
auto img = image->windowImages.emplace_back(makeShared<SWindowImage>());
|
||||
img->pWindow = w;
|
||||
img->fb.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, pMonitor->m_output->state->state().drmFormat);
|
||||
if (!w->m_isX11 && w->wlSurface()) {
|
||||
img->windowCommit = makeUnique<CHyprSignalListener>(w->wlSurface()->resource()->m_events.commit.listen([wk = WP<SWindowImage>{img}] {
|
||||
if (!wk || !wk->pWindow)
|
||||
return;
|
||||
|
||||
if (wk->pWindow->wlSurface()->resource()->m_current.accumulateBufferDamage().empty())
|
||||
return;
|
||||
|
||||
reinterpretPointerCast<CScrollOverview>(g_pOverview)->redrawWindowImage(wk.lock());
|
||||
g_pOverview->damage();
|
||||
}));
|
||||
}
|
||||
|
||||
redrawWindowImage(img);
|
||||
}
|
||||
|
||||
blockOverviewRendering = false;
|
||||
}
|
||||
|
||||
void CScrollOverview::redrawWindowImage(SP<SWindowImage> img) {
|
||||
if (!img->pWindow)
|
||||
return;
|
||||
|
||||
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
|
||||
g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &img->fb);
|
||||
|
||||
g_pHyprOpenGL->clear(CHyprColor{0, 0, 0, 0});
|
||||
|
||||
g_pHyprRenderer->renderWindow(img->pWindow.lock(), pMonitor.lock(), Time::steadyNow(), true, RENDER_PASS_ALL, true, true);
|
||||
|
||||
g_pHyprOpenGL->m_renderData.blockScreenShader = true;
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
img->lastWindowPosition = img->pWindow->m_realPosition->value();
|
||||
img->lastWindowSize = img->pWindow->m_realSize->value();
|
||||
}
|
||||
|
||||
void CScrollOverview::redrawAll(bool forcelowres) {
|
||||
|
||||
for (const auto& img : images) {
|
||||
redrawWorkspace(img->pWorkspace);
|
||||
}
|
||||
|
||||
// redraw bg
|
||||
if (backgroundFb.m_size != pMonitor->m_pixelSize) {
|
||||
backgroundFb.release();
|
||||
backgroundFb.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, pMonitor->m_output->state->state().drmFormat);
|
||||
floatingFb.alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, pMonitor->m_output->state->state().drmFormat);
|
||||
}
|
||||
|
||||
CRegion fakeDamage{0, 0, INT16_MAX, INT16_MAX};
|
||||
g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &backgroundFb);
|
||||
|
||||
g_pHyprOpenGL->clear(CHyprColor{0, 0, 0, 1.0});
|
||||
|
||||
g_pHyprRenderer->renderAllClientsForWorkspace(pMonitor.lock(), nullptr, Time::steadyNow());
|
||||
|
||||
g_pHyprOpenGL->m_renderData.blockScreenShader = true;
|
||||
g_pHyprRenderer->endRender();
|
||||
|
||||
// render floating as well. For these, we disable decos to match tiled ones.
|
||||
g_pHyprRenderer->beginRender(pMonitor.lock(), fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &floatingFb);
|
||||
|
||||
g_pHyprOpenGL->clear(CHyprColor{0, 0, 0, 0});
|
||||
|
||||
for (const auto& w : g_pCompositor->m_windows) {
|
||||
if (!validMapped(w) || !w->m_isFloating || w->m_workspace != startedOn)
|
||||
continue;
|
||||
|
||||
g_pHyprRenderer->renderWindow(w, pMonitor.lock(), Time::steadyNow(), false, RENDER_PASS_ALL);
|
||||
}
|
||||
|
||||
g_pHyprOpenGL->m_renderData.blockScreenShader = true;
|
||||
g_pHyprRenderer->endRender();
|
||||
}
|
||||
|
||||
void CScrollOverview::damage() {
|
||||
blockDamageReporting = true;
|
||||
g_pHyprRenderer->damageMonitor(pMonitor.lock());
|
||||
blockDamageReporting = false;
|
||||
}
|
||||
|
||||
void CScrollOverview::onDamageReported() {
|
||||
; // TODO:
|
||||
}
|
||||
|
||||
void CScrollOverview::close() {
|
||||
closing = true;
|
||||
|
||||
if (!closeOnWindow)
|
||||
closeOnWindow = Desktop::focusState()->window();
|
||||
|
||||
if (closeOnWindow == Desktop::focusState()->window())
|
||||
*viewOffset = Vector2D{};
|
||||
else {
|
||||
|
||||
if (closeOnWindow->m_workspace != pMonitor->m_activeWorkspace) {
|
||||
g_pDesktopAnimationManager->startAnimation(pMonitor->m_activeWorkspace, CDesktopAnimationManager::ANIMATION_TYPE_OUT, true, true);
|
||||
g_pDesktopAnimationManager->startAnimation(closeOnWindow->m_workspace, CDesktopAnimationManager::ANIMATION_TYPE_IN, false, true);
|
||||
pMonitor->changeWorkspace(closeOnWindow->m_workspace, true, true, true);
|
||||
}
|
||||
|
||||
Desktop::focusState()->fullWindowFocus(closeOnWindow.lock());
|
||||
|
||||
size_t activeIdx = 0;
|
||||
for (size_t i = 0; i < images.size(); ++i) {
|
||||
if (images[i]->pWorkspace && images[i]->pWorkspace == startedOn) {
|
||||
activeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float yoff = -(float)activeIdx * pMonitor->m_size.y * scale->value();
|
||||
bool found = false;
|
||||
for (const auto& wimg : images) {
|
||||
for (const auto& img : wimg->windowImages) {
|
||||
if (img->pWindow == closeOnWindow && closeOnWindow) {
|
||||
Vector2D middleOfWindow = CBox{img->pWindow->m_realPosition->value(), img->pWindow->m_realSize->value()}.translate({0.F, yoff / scale->value()}).middle() -
|
||||
CBox{pMonitor->m_position, pMonitor->m_size}.middle();
|
||||
|
||||
// we need to do this because the window doesnt have to be centered after click
|
||||
*viewOffset = middleOfWindow +
|
||||
(CBox{pMonitor->m_position, pMonitor->m_size}.middle() - CBox{img->pWindow->m_realPosition->value(), img->pWindow->m_realSize->value()}.middle());
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
yoff += pMonitor->m_size.y * scale->value();
|
||||
}
|
||||
}
|
||||
|
||||
*scale = 1.F;
|
||||
|
||||
scale->setCallbackOnEnd(removeOverview);
|
||||
}
|
||||
|
||||
void CScrollOverview::onPreRender() {
|
||||
;
|
||||
}
|
||||
|
||||
void CScrollOverview::onWorkspaceChange() {
|
||||
; // TODO:
|
||||
}
|
||||
|
||||
void CScrollOverview::render() {
|
||||
bool needsDamage = false;
|
||||
for (const auto& img : images) {
|
||||
for (const auto& i : img->windowImages) {
|
||||
if (!i->pWindow)
|
||||
continue;
|
||||
|
||||
if (i->lastWindowSize != i->pWindow->m_realSize->value() || i->lastWindowPosition != i->pWindow->m_realPosition->value()) {
|
||||
needsDamage = true;
|
||||
i->lastWindowPosition = i->pWindow->m_realPosition->value();
|
||||
i->lastWindowSize = i->pWindow->m_realSize->value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needsDamage)
|
||||
damage();
|
||||
|
||||
g_pHyprRenderer->m_renderPass.add(makeUnique<COverviewPassElement>());
|
||||
}
|
||||
|
||||
void CScrollOverview::fullRender() {
|
||||
|
||||
g_pHyprOpenGL->clear(CHyprColor{0, 0, 0, 1});
|
||||
|
||||
CBox texbox = {{}, pMonitor->m_size};
|
||||
texbox.scale(pMonitor->m_scale);
|
||||
texbox.round();
|
||||
CRegion damage{0, 0, INT16_MAX, INT16_MAX};
|
||||
g_pHyprOpenGL->renderTextureInternal(backgroundFb.getTexture(), texbox, {.damage = &damage, .a = 1.0});
|
||||
|
||||
const auto VIEWPORT_CENTER = CBox{{}, pMonitor->m_size}.middle();
|
||||
|
||||
size_t activeIdx = 0;
|
||||
for (size_t i = 0; i < images.size(); ++i) {
|
||||
if (images[i]->pWorkspace && images[i]->pWorkspace == startedOn) {
|
||||
activeIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// render all views
|
||||
float yoff = -(float)activeIdx * pMonitor->m_size.y * scale->value();
|
||||
for (const auto& wimg : images) {
|
||||
bool dirty = false;
|
||||
|
||||
for (const auto& img : wimg->windowImages) {
|
||||
if (!img->pWindow) {
|
||||
dirty = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
CBox texbox = CBox{img->pWindow->m_realPosition->value() - pMonitor->m_position, pMonitor->m_size};
|
||||
|
||||
// scale the box to the viewport center
|
||||
texbox.translate(-VIEWPORT_CENTER).scale(scale->value()).translate(VIEWPORT_CENTER).translate(-viewOffset->value() * scale->value());
|
||||
|
||||
texbox.translate({0.F, yoff});
|
||||
|
||||
texbox.scale(pMonitor->m_scale).round();
|
||||
CRegion damage{0, 0, INT16_MAX, INT16_MAX};
|
||||
g_pHyprOpenGL->renderTextureInternal(img->fb.getTexture(), texbox, {.damage = &damage, .a = 1.0 * img->pWindow->m_alpha->value()});
|
||||
|
||||
if (img->highlight) {
|
||||
CBox texbox2 = CBox{img->pWindow->m_realPosition->value(), img->pWindow->m_realSize->value()}
|
||||
.translate(-VIEWPORT_CENTER)
|
||||
.scale(scale->value())
|
||||
.translate(VIEWPORT_CENTER)
|
||||
.translate({0.F, yoff});
|
||||
g_pHyprOpenGL->renderRect(texbox2, CHyprColor{0.5, 0.0, 0.0, 0.5}, CHyprOpenGLImpl::SRectRenderData{.round = 5});
|
||||
}
|
||||
}
|
||||
CBox floatbox = CBox{pMonitor->m_position + Vector2D{0.F, yoff / scale->value()}, pMonitor->m_size};
|
||||
floatbox.translate(-VIEWPORT_CENTER).scale(scale->value()).translate(VIEWPORT_CENTER).translate(-viewOffset->value() * scale->value());
|
||||
floatbox.translate({0.F, yoff});
|
||||
floatbox.scale(pMonitor->m_scale).round();
|
||||
g_pHyprOpenGL->renderTextureInternal(floatingFb.getTexture(), floatbox, {.damage = &damage, .a = 1.0});
|
||||
|
||||
yoff += pMonitor->m_size.y * scale->value();
|
||||
|
||||
if (dirty)
|
||||
std::erase_if(wimg->windowImages, [](const auto& e) { return !e->pWindow; });
|
||||
}
|
||||
}
|
||||
|
||||
static float hyprlerp(const float& from, const float& to, const float perc) {
|
||||
return (to - from) * perc + from;
|
||||
}
|
||||
|
||||
static Vector2D hyprlerp(const Vector2D& from, const Vector2D& to, const float perc) {
|
||||
return Vector2D{hyprlerp(from.x, to.x, perc), hyprlerp(from.y, to.y, perc)};
|
||||
}
|
||||
|
||||
void CScrollOverview::setClosing(bool closing_) {
|
||||
closing = closing_;
|
||||
}
|
||||
|
||||
void CScrollOverview::resetSwipe() {
|
||||
static auto* const* PDEFAULTZOOM = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:scrolling:default_zoom")->getDataStaticPtr();
|
||||
|
||||
if (closing) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
(*scale) = **PDEFAULTZOOM;
|
||||
m_isSwiping = false;
|
||||
}
|
||||
|
||||
void CScrollOverview::onSwipeUpdate(double delta) {
|
||||
static auto* const* PDEFAULTZOOM = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:scrolling:default_zoom")->getDataStaticPtr();
|
||||
static auto* const* PDISTANCE = (Hyprlang::INT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:gesture_distance")->getDataStaticPtr();
|
||||
|
||||
m_isSwiping = true;
|
||||
|
||||
const float PERC = closing ? std::clamp(delta / (double)**PDISTANCE, 0.0, 1.0) : 1.0 - std::clamp(delta / (double)**PDISTANCE, 0.0, 1.0);
|
||||
|
||||
scale->setValueAndWarp(hyprlerp(1.F, **PDEFAULTZOOM, PERC));
|
||||
}
|
||||
|
||||
void CScrollOverview::onSwipeEnd() {
|
||||
static auto* const* PDEFAULTZOOM = (Hyprlang::FLOAT* const*)HyprlandAPI::getConfigValue(PHANDLE, "plugin:hyprexpo:scrolling:default_zoom")->getDataStaticPtr();
|
||||
|
||||
if (closing) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
(*scale) = **PDEFAULTZOOM;
|
||||
m_isSwiping = false;
|
||||
}
|
||||
95
hyprexpo/scrollOverview.hpp
Normal file
95
hyprexpo/scrollOverview.hpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#define WLR_USE_UNSTABLE
|
||||
|
||||
#include "globals.hpp"
|
||||
#include <hyprland/src/desktop/DesktopTypes.hpp>
|
||||
#include <hyprland/src/render/Framebuffer.hpp>
|
||||
#include <hyprland/src/helpers/AnimatedVariable.hpp>
|
||||
#include <hyprland/src/managers/HookSystemManager.hpp>
|
||||
#include <hyprland/src/helpers/signal/Signal.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "IOverview.hpp"
|
||||
|
||||
class CMonitor;
|
||||
|
||||
class CScrollOverview : public IOverview {
|
||||
public:
|
||||
CScrollOverview(PHLWORKSPACE startedOn_, bool swipe = false);
|
||||
virtual ~CScrollOverview();
|
||||
|
||||
virtual void render();
|
||||
virtual void damage();
|
||||
virtual void onDamageReported();
|
||||
virtual void onPreRender();
|
||||
|
||||
virtual void setClosing(bool closing);
|
||||
|
||||
virtual void resetSwipe();
|
||||
virtual void onSwipeUpdate(double delta);
|
||||
virtual void onSwipeEnd();
|
||||
|
||||
// close without a selection
|
||||
virtual void close();
|
||||
virtual void selectHoveredWorkspace();
|
||||
|
||||
virtual void fullRender();
|
||||
|
||||
private:
|
||||
void redrawWorkspace(PHLWORKSPACE w, bool forcelowres = false);
|
||||
void redrawAll(bool forcelowres = false);
|
||||
void onWorkspaceChange();
|
||||
void highlightHoverDebug();
|
||||
void moveViewportWorkspace(bool up);
|
||||
|
||||
bool damageDirty = false;
|
||||
size_t viewportCurrentWorkspace = 0;
|
||||
|
||||
struct SWindowImage {
|
||||
PHLWINDOWREF pWindow;
|
||||
CFramebuffer fb;
|
||||
bool highlight = false;
|
||||
UP<CHyprSignalListener> windowCommit;
|
||||
Vector2D lastWindowPosition, lastWindowSize;
|
||||
};
|
||||
|
||||
void redrawWindowImage(SP<SWindowImage>);
|
||||
|
||||
struct SWorkspaceImage {
|
||||
PHLWORKSPACE pWorkspace;
|
||||
CBox box;
|
||||
std::vector<SP<SWindowImage>> windowImages;
|
||||
};
|
||||
|
||||
CFramebuffer backgroundFb;
|
||||
CFramebuffer floatingFb;
|
||||
|
||||
Vector2D lastMousePosLocal = Vector2D{};
|
||||
|
||||
PHLWINDOWREF closeOnWindow;
|
||||
|
||||
std::vector<SP<SWorkspaceImage>> images;
|
||||
SP<SWorkspaceImage> imageForWorkspace(PHLWORKSPACE w);
|
||||
|
||||
PHLWORKSPACE startedOn;
|
||||
|
||||
PHLANIMVAR<float> scale;
|
||||
PHLANIMVAR<Vector2D> viewOffset;
|
||||
|
||||
bool closing = false;
|
||||
|
||||
SP<HOOK_CALLBACK_FN> mouseMoveHook;
|
||||
SP<HOOK_CALLBACK_FN> mouseButtonHook;
|
||||
SP<HOOK_CALLBACK_FN> touchMoveHook;
|
||||
SP<HOOK_CALLBACK_FN> touchDownHook;
|
||||
SP<HOOK_CALLBACK_FN> mouseAxisHook;
|
||||
SP<HOOK_CALLBACK_FN> windowOpenHook;
|
||||
|
||||
bool swipe = false;
|
||||
bool swipeWasCommenced = false;
|
||||
|
||||
friend class CScrollOverviewPassElement;
|
||||
};
|
||||
|
||||
inline std::unique_ptr<CScrollOverview> g_pScrollOverview;
|
||||
Loading…
Add table
Reference in a new issue