Point hyprexpo at window drag branch

This commit is contained in:
2026-05-19 03:23:39 -07:00
parent 9eef758ba2
commit 3269e803fd
5 changed files with 7 additions and 216 deletions

7
nixos/flake.lock generated
View File

@@ -745,15 +745,16 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1778877751, "lastModified": 1779186703,
"narHash": "sha256-EWGEw2wvflMzTcKxo5cLYL5Cw4KqYGpRl1nQGp2VpiM=", "narHash": "sha256-LQ3zJ2AZdCszTztOJOHueAU+LHQbbFTM5ci0Dc6GpIc=",
"owner": "colonelpanic8", "owner": "colonelpanic8",
"repo": "hyprexpo", "repo": "hyprexpo",
"rev": "bb53c1d9ed635ad88eaf5db287692d9babef9963", "rev": "3460ba85c3507a191c5623c0a67b96b4c8f689cb",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "colonelpanic8", "owner": "colonelpanic8",
"ref": "codex/window-drag-workspaces",
"repo": "hyprexpo", "repo": "hyprexpo",
"type": "github" "type": "github"
} }

View File

@@ -121,7 +121,7 @@
}; };
hyprexpo = { hyprexpo = {
url = "github:colonelpanic8/hyprexpo"; url = "github:colonelpanic8/hyprexpo?ref=codex/window-drag-workspaces";
inputs.hyprland.follows = "hyprland"; inputs.hyprland.follows = "hyprland";
}; };

View File

@@ -26,13 +26,7 @@
hyprlang = inputs.hyprlang.packages.${system}.hyprlang; hyprlang = inputs.hyprlang.packages.${system}.hyprlang;
hyprutils = inputs.hyprutils.packages.${system}.hyprutils; hyprutils = inputs.hyprutils.packages.${system}.hyprutils;
}; };
hyprexpo = inputs.hyprexpo.packages.${system}.hyprexpo.overrideAttrs (old: { hyprexpo = inputs.hyprexpo.packages.${system}.hyprexpo;
patches =
(old.patches or [])
++ [
../packages/hyprexpo-drag-windows.patch
];
});
tangledConfig = dotfilesOrgApi.org-agenda-custom-config; tangledConfig = dotfilesOrgApi.org-agenda-custom-config;
# Import container build logic # Import container build logic

View File

@@ -106,13 +106,7 @@
./packages/hyprwobbly-safe-geometry-and-idle-timer.patch ./packages/hyprwobbly-safe-geometry-and-idle-timer.patch
]; ];
}); });
hyprexpo = inputs.hyprexpo.packages.${system}.hyprexpo.overrideAttrs (old: { hyprexpo = inputs.hyprexpo.packages.${system}.hyprexpo;
patches =
(old.patches or [])
++ [
./packages/hyprexpo-drag-windows.patch
];
});
hyprlandPluginPackages = hyprlandPluginPackages =
[ [
inputs.hyprNStack.packages.${system}.hyprNStack inputs.hyprNStack.packages.${system}.hyprNStack

View File

@@ -1,198 +0,0 @@
--- a/Overview.hpp
+++ b/Overview.hpp
@@ -80,6 +80,12 @@
void updateHoveredFromMouse();
bool isTileValid(int id) const;
void ensureKeyboardFocus();
+ void beginWindowDrag();
+ bool finishWindowDrag();
+ void updateWindowDrag();
+ PHLWINDOW windowAtTilePoint(int id, const Vector2D& localPoint) const;
+ Vector2D tilePointToWorkspacePoint(int id, const Vector2D& localPoint) const;
+ PHLWORKSPACE ensureWorkspaceForTile(int id);
int SIDE_LENGTH = 3;
int GAP_WIDTH = 5;
@@ -94,6 +100,11 @@
int hoveredID = -1;
int kbFocusID = -1;
+ Vector2D dragStartLocal = Vector2D{};
+ int dragSourceID = -1;
+ bool dragMoved = false;
+ PHLWINDOW dragWindow;
+
std::vector<SWorkspaceImage> images;
PHLWORKSPACE startedOn;
--- a/Overview.cpp
+++ b/Overview.cpp
@@ -5,6 +5,7 @@
#include <cctype>
#include <cmath>
#include <optional>
+#include <string>
#define private public
#define protected public
#include <hyprland/src/render/Renderer.hpp>
@@ -79,6 +80,10 @@
return grad;
}
+static bool windowVisibleOnWorkspace(const PHLWINDOW& window, const PHLWORKSPACE& workspace) {
+ return window && workspace && window->m_workspace == workspace && window->m_isMapped && !window->isHidden() && !window->m_pinned;
+}
+
static void ensureFramebuffer(COverview::SWorkspaceImage& image, const CBox& monbox, uint32_t drmFormat) {
if (!image.fb)
image.fb = g_pHyprRenderer->createFB("hyprexpo");
@@ -337,9 +342,29 @@
info.cancelled = true;
lastMousePosLocal = g_pInputManager->getMouseCoordsInternal() - pMonitor->m_position;
updateHoveredFromMouse();
+ updateWindowDrag();
+ };
+
+ auto onCursorSelect = [this](IPointer::SButtonEvent event, Event::SCallbackInfo& info) {
+ if (closing)
+ return;
+
+ info.cancelled = true;
+
+ if (event.state == WL_POINTER_BUTTON_STATE_PRESSED) {
+ beginWindowDrag();
+ return;
+ }
+
+ if (finishWindowDrag())
+ return;
+
+ selectHoveredWorkspace();
+
+ close();
};
- auto onCursorSelect = [this](Event::SCallbackInfo& info) {
+ auto onTouchSelect = [this](Event::SCallbackInfo& info) {
if (closing)
return;
@@ -353,8 +378,107 @@
mouseMoveHook = Event::bus()->m_events.input.mouse.move.listen([onCursorMove](Vector2D, Event::SCallbackInfo& info) { onCursorMove(info); });
touchMoveHook = Event::bus()->m_events.input.touch.motion.listen([onCursorMove](ITouch::SMotionEvent, Event::SCallbackInfo& info) { onCursorMove(info); });
- mouseButtonHook = Event::bus()->m_events.input.mouse.button.listen([onCursorSelect](IPointer::SButtonEvent, Event::SCallbackInfo& info) { onCursorSelect(info); });
- touchDownHook = Event::bus()->m_events.input.touch.down.listen([onCursorSelect](ITouch::SDownEvent, Event::SCallbackInfo& info) { onCursorSelect(info); });
+ mouseButtonHook = Event::bus()->m_events.input.mouse.button.listen([onCursorSelect](IPointer::SButtonEvent event, Event::SCallbackInfo& info) { onCursorSelect(event, info); });
+ touchDownHook = Event::bus()->m_events.input.touch.down.listen([onTouchSelect](ITouch::SDownEvent, Event::SCallbackInfo& info) { onTouchSelect(info); });
+}
+
+Vector2D COverview::tilePointToWorkspacePoint(int id, const Vector2D& localPoint) const {
+ const Vector2D tileSize = pMonitor->m_size / SIDE_LENGTH;
+ const Vector2D tilePos = tileSize * Vector2D{id % SIDE_LENGTH, id / SIDE_LENGTH};
+ const Vector2D inTile = localPoint - tilePos;
+
+ return pMonitor->m_position + Vector2D{std::clamp(inTile.x / tileSize.x, 0.0, 1.0) * pMonitor->m_size.x, std::clamp(inTile.y / tileSize.y, 0.0, 1.0) * pMonitor->m_size.y};
+}
+
+PHLWINDOW COverview::windowAtTilePoint(int id, const Vector2D& localPoint) const {
+ if (!isTileValid(id))
+ return nullptr;
+
+ const auto WORKSPACE = images[id].pWorkspace ? images[id].pWorkspace : g_pCompositor->getWorkspaceByID(images[id].workspaceID);
+ if (!WORKSPACE)
+ return nullptr;
+
+ const auto POINT = tilePointToWorkspacePoint(id, localPoint);
+ for (auto it = g_pCompositor->m_windows.rbegin(); it != g_pCompositor->m_windows.rend(); ++it) {
+ const auto& window = *it;
+ if (!windowVisibleOnWorkspace(window, WORKSPACE))
+ continue;
+
+ if (window->getWindowMainSurfaceBox().containsPoint(POINT))
+ return window;
+ }
+
+ return nullptr;
+}
+
+void COverview::beginWindowDrag() {
+ updateHoveredFromMouse();
+ dragStartLocal = lastMousePosLocal;
+ dragSourceID = hoveredID;
+ dragMoved = false;
+ dragWindow = windowAtTilePoint(dragSourceID, dragStartLocal);
+}
+
+void COverview::updateWindowDrag() {
+ if (!dragWindow || dragMoved)
+ return;
+
+ const auto DX = lastMousePosLocal.x - dragStartLocal.x;
+ const auto DY = lastMousePosLocal.y - dragStartLocal.y;
+ if (std::hypot(DX, DY) < 12.0)
+ return;
+
+ dragMoved = true;
+ damage();
+}
+
+PHLWORKSPACE COverview::ensureWorkspaceForTile(int id) {
+ if (!isTileValid(id))
+ return nullptr;
+
+ auto& image = images[id];
+ if (image.pWorkspace)
+ return image.pWorkspace;
+
+ auto workspace = g_pCompositor->getWorkspaceByID(image.workspaceID);
+ if (!workspace)
+ workspace = g_pCompositor->createNewWorkspace(image.workspaceID, pMonitor->m_id, std::to_string(image.workspaceID), false);
+
+ image.pWorkspace = workspace;
+ return workspace;
+}
+
+bool COverview::finishWindowDrag() {
+ const auto WINDOW = dragWindow;
+ const int SOURCE = dragSourceID;
+ const bool MOVED = dragMoved;
+
+ dragWindow = nullptr;
+ dragSourceID = -1;
+ dragMoved = false;
+
+ if (!WINDOW)
+ return false;
+
+ if (!MOVED)
+ return false;
+
+ updateHoveredFromMouse();
+
+ const int TARGET = hoveredID;
+ if (!isTileValid(SOURCE) || !isTileValid(TARGET) || SOURCE == TARGET)
+ return true;
+
+ const auto SOURCEWS = images[SOURCE].pWorkspace;
+ const auto TARGETWS = ensureWorkspaceForTile(TARGET);
+ if (!windowVisibleOnWorkspace(WINDOW, SOURCEWS) || !TARGETWS || TARGETWS == SOURCEWS)
+ return true;
+
+ g_pCompositor->moveWindowToWorkspaceSafe(WINDOW, TARGETWS);
+ redrawID(SOURCE);
+ redrawID(TARGET);
+ damage();
+ return true;
}
void COverview::selectHoveredWorkspace() {
@@ -954,6 +1078,8 @@
drawBorder(openedID, *PBORDERCURRENT);
if (kbFocusID != -1)
drawBorder(kbFocusID, *PBORDERFOCUS);
+ if (dragMoved && dragSourceID != -1)
+ drawBorder(dragSourceID, *PBORDERFOCUS);
}
static float lerp(const float& from, const float& to, const float perc) {