desktop: move window manipulation functions out of compositor (#15256)

This commit is contained in:
Vaxry
2026-06-27 22:37:59 +02:00
committed by GitHub
parent f048359d22
commit ca877badde
18 changed files with 498 additions and 430 deletions
-352
View File
@@ -807,343 +807,6 @@ void CCompositor::startCompositor() {
g_pEventLoopManager->enterLoop();
}
bool CCompositor::isWindowActive(PHLWINDOW pWindow) {
if (!Desktop::focusState()->window() && !Desktop::focusState()->surface())
return false;
if (!pWindow->m_isMapped)
return false;
const auto PSURFACE = pWindow->wlSurface()->resource();
return PSURFACE == Desktop::focusState()->surface() || pWindow == Desktop::focusState()->window();
}
void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
if (!validMapped(pWindow))
return;
if (top)
pWindow->m_createdOverFullscreen = true;
else
pWindow->m_createdOverFullscreen = false;
pWindow->updateFullscreenInputState();
*pWindow->alpha(WINDOW_ALPHA_FULLSCREEN) = pWindow->isBlockedByFullscreen() ? 0.F : 1.F;
const auto& WINDOWS = Desktop::windowState()->windows();
if (pWindow == (top ? WINDOWS.back() : WINDOWS.front()))
return;
auto moveToZ = [&](PHLWINDOW pw, bool top) -> void {
if (top)
Desktop::windowState()->moveToTop(pw);
else
Desktop::windowState()->moveToBottom(pw);
if (pw->m_isMapped)
g_pHyprRenderer->damageMonitor(pw->m_monitor.lock());
};
if (!pWindow->m_isX11)
moveToZ(pWindow, top);
else {
// move X11 window stack
std::vector<PHLWINDOW> toMove;
auto x11Stack = [&](PHLWINDOW pw, bool top, auto&& x11Stack) -> void {
if (top)
toMove.emplace_back(pw);
else
toMove.insert(toMove.begin(), pw);
for (auto const& w : WINDOWS) {
if (w->m_isMapped && !w->isHidden() && w->m_isX11 && w->x11TransientFor() == pw && w != pw && std::ranges::find(toMove, w) == toMove.end()) {
x11Stack(w, top, x11Stack);
}
}
};
x11Stack(pWindow, top, x11Stack);
for (const auto& it : toMove) {
moveToZ(it, top);
}
}
}
PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, Math::eDirection dir) {
if (dir == Math::DIRECTION_DEFAULT)
return nullptr;
const auto PMONITOR = pWindow->m_monitor.lock();
if (!PMONITOR)
return nullptr; // ??
const auto WINDOWIDEALBB = pWindow->isFullscreen() ? CBox{PMONITOR->m_position, PMONITOR->m_size} : pWindow->getWindowIdealBoundingBoxIgnoreReserved();
const auto PWORKSPACE = pWindow->m_workspace;
if (!PWORKSPACE)
return nullptr; // ??
return getWindowInDirection(WINDOWIDEALBB, PWORKSPACE, dir, pWindow->m_isFloating, pWindow, pWindow->m_isFloating);
}
PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, Math::eDirection dir, bool floatingPreference, PHLWINDOW ignoreWindow, bool useVectorAngles) {
if (dir == Math::DIRECTION_DEFAULT)
return nullptr;
// 0 -> history, 1 -> shared length
static auto PMETHOD = CConfigValue<Config::INTEGER>("binds:focus_preferred_method");
static auto PMONITORFALLBACK = CConfigValue<Config::INTEGER>("binds:window_direction_monitor_fallback");
const auto POSA = box.pos();
const auto SIZEA = box.size();
auto leaderValue = -1;
PHLWINDOW leaderWindow = nullptr;
if (!useVectorAngles) {
// helper to check if two rectangles are adjacent along an axis, considering slight overlaps.
// returns true if: STICKS (delta <= 2) OR rectangles overlap but no more than 50% of the smaller dimension.
static auto isAdjacent = [](const double aMin, const double aMax, const double bMin, const double bMax) -> bool {
constexpr double STICK_THRESHOLD = 2.0;
constexpr double MAX_OVERLAP_RATIO = 0.5;
const double aEdge = aMin;
const double bEdge = bMax;
const double delta = aEdge - bEdge;
// old STICKS check for 2px
if (std::abs(delta) < STICK_THRESHOLD)
return true;
if (delta >= 0)
return false;
const double overlap = -delta;
const double sizeA = aMax - aMin;
const double sizeB = bMax - bMin;
// reject if one rectangle fully contains the other
if ((bMin <= aMin && bMax >= aMax) || (aMin <= bMin && aMax >= bMax))
return false;
// accept if overlap is at most 50% of the smaller dimension
return overlap <= std::min(sizeA, sizeB) * MAX_OVERLAP_RATIO;
};
auto find = [&]() {
for (auto const& w : Desktop::windowState()->windows()) {
if (w == ignoreWindow || !w->m_workspace || !w->m_isMapped || (!w->isFullscreen() && w->m_isFloating) || !w->m_workspace->isVisible())
continue;
if (w->isHidden())
continue;
// check if the input is blocked by anything except BELOW_FULLSCREEN
if (w->isInputBlocked(INPUT_BLOCK_ALL & (~INPUT_BLOCK_BELOW_FULLSCREEN)))
continue;
if (pWorkspace->m_monitor == w->m_monitor && pWorkspace != w->m_workspace)
continue;
if (pWorkspace->m_hasFullscreenWindow && !w->isAllowedOverFullscreen())
continue;
if (!*PMONITORFALLBACK && pWorkspace->m_monitor != w->m_monitor)
continue;
if (w->m_isFloating != floatingPreference)
continue;
// prioritize windows on the same workspace.
// this is especially important for scrolling layouts - we want to first move to a window
// on the same workspace before moving onto another.
const auto LEADER_IS_ON_SAME_WORKSPACE = leaderWindow && leaderWindow->m_workspace == pWorkspace;
if (LEADER_IS_ON_SAME_WORKSPACE && w->m_workspace != pWorkspace)
continue;
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
double intersectLength = -1;
switch (dir) {
case Math::DIRECTION_LEFT:
if (isAdjacent(POSA.x, POSA.x + SIZEA.x, POSB.x, POSB.x + SIZEB.x))
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
break;
case Math::DIRECTION_RIGHT:
if (isAdjacent(POSB.x, POSB.x + SIZEB.x, POSA.x, POSA.x + SIZEA.x))
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
break;
case Math::DIRECTION_UP:
if (isAdjacent(POSA.y, POSA.y + SIZEA.y, POSB.y, POSB.y + SIZEB.y))
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
break;
case Math::DIRECTION_DOWN:
if (isAdjacent(POSB.y, POSB.y + SIZEB.y, POSA.y, POSA.y + SIZEA.y))
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
break;
default: break;
}
// if we have a leader on another workspace, and this window is on the same workspace,
// override minimum requirements and always select this as the new leader
const bool OVERRIDE_MIN_REQ = leaderWindow && !LEADER_IS_ON_SAME_WORKSPACE && w->m_workspace == pWorkspace;
// ...as long as there is any intersect.
if (intersectLength <= 1)
continue;
if (*PMETHOD == 0 /* history */) {
// get idx
int windowIDX = -1;
const auto& HISTORY = Desktop::History::windowTracker()->fullHistory();
for (int64_t i = HISTORY.size() - 1; i >= 0; --i) {
if (HISTORY[i] == w) {
windowIDX = i;
break;
}
}
if (windowIDX > leaderValue || OVERRIDE_MIN_REQ) {
leaderValue = windowIDX;
leaderWindow = w;
}
} else /* length */ {
if (intersectLength > leaderValue || OVERRIDE_MIN_REQ) {
leaderValue = intersectLength;
leaderWindow = w;
}
}
}
};
// Find the window, then if we don't find one with preferred
// float status, try the opposite.
find();
if (!leaderWindow) {
floatingPreference = !floatingPreference;
find();
}
} else {
static const std::unordered_map<Math::eDirection, Vector2D> VECTORS = {
{Math::DIRECTION_RIGHT, {1, 0}}, {Math::DIRECTION_UP, {0, -1}}, {Math::DIRECTION_DOWN, {0, 1}}, {Math::DIRECTION_LEFT, {-1, 0}}};
//
auto vectorAngles = [](const Vector2D& a, const Vector2D& b) -> double {
double dot = (a.x * b.x) + (a.y * b.y);
double ang = std::acos(dot / (a.size() * b.size()));
return ang;
};
float bestAngleAbs = 2.0 * M_PI;
constexpr float THRESHOLD = 0.3 * M_PI;
for (auto const& w : Desktop::windowState()->windows()) {
if (w == ignoreWindow || !w->m_isMapped || !w->m_workspace || !w->acceptsInput() || (!w->isFullscreen() && !w->m_isFloating) || !w->m_workspace->isVisible())
continue;
if (pWorkspace->m_monitor == w->m_monitor && pWorkspace != w->m_workspace)
continue;
if (pWorkspace->m_hasFullscreenWindow && !w->isAllowedOverFullscreen())
continue;
if (!*PMONITORFALLBACK && pWorkspace->m_monitor != w->m_monitor)
continue;
const auto DIST = w->middle().distance(box.middle());
const auto ANGLE = vectorAngles(Vector2D{w->middle() - box.middle()}, VECTORS.at(dir));
if (ANGLE > M_PI_2)
continue; // if the angle is over 90 degrees, ignore. Wrong direction entirely.
if ((bestAngleAbs < THRESHOLD && DIST < leaderValue && ANGLE < THRESHOLD) || (ANGLE < bestAngleAbs && bestAngleAbs > THRESHOLD) || leaderValue == -1) {
leaderValue = DIST;
bestAngleAbs = ANGLE;
leaderWindow = w;
}
}
if (!leaderWindow && pWorkspace->m_hasFullscreenWindow)
leaderWindow = pWorkspace->getFullscreenWindow();
}
if (leaderValue != -1)
return leaderWindow;
return nullptr;
}
template <typename WINDOWPTR>
static bool isWorkspaceMatches(WINDOWPTR pWindow, const WINDOWPTR w, bool anyWorkspace) {
return anyWorkspace ? w->m_workspace && w->m_workspace->isVisible() : w->m_workspace == pWindow->m_workspace;
}
template <typename WINDOWPTR>
static bool isFloatingMatches(WINDOWPTR w, std::optional<bool> floating) {
return !floating.has_value() || w->m_isFloating == floating.value();
}
template <typename WINDOWPTR>
static bool acceptsInputForCycle(WINDOWPTR w, bool allowFullscreenBlocked) {
if (w->acceptsInput())
return true;
return allowFullscreenBlocked && !w->isHidden() && w->isInputBlockedOnly(INPUT_BLOCK_BELOW_FULLSCREEN);
}
template <typename WINDOWPTR>
static bool isWindowAvailableForCycle(WINDOWPTR pWindow, WINDOWPTR w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace = false,
bool allowFullscreenBlocked = false) {
return isFloatingMatches(w, floating) &&
(w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_isMapped && acceptsInputForCycle(w, allowFullscreenBlocked) &&
(!focusableOnly || !w->m_ruleApplicator->noFocus().valueOrDefault()));
}
template <typename Iterator>
static PHLWINDOW getWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function<bool(const PHLWINDOW&)> PRED) {
const auto IN_ONE_SIDE = std::find_if(cur, end, PRED);
if (IN_ONE_SIDE != end)
return *IN_ONE_SIDE;
const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED);
return *IN_OTHER_SIDE;
}
template <typename Iterator>
static PHLWINDOW getWeakWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function<bool(const PHLWINDOWREF&)> PRED) {
const auto IN_ONE_SIDE = std::find_if(cur, end, PRED);
if (IN_ONE_SIDE != end)
return IN_ONE_SIDE->lock();
const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED);
return IN_OTHER_SIDE->lock();
}
PHLWINDOW CCompositor::getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly, std::optional<bool> floating, bool visible, bool next, bool allowFullscreenBlocked) {
const auto FINDER = [&](const PHLWINDOWREF& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible, allowFullscreenBlocked); };
// also m_vWindowFocusHistory has reverse order, so when it is next - we need to reverse again
const auto& HISTORY = Desktop::History::windowTracker()->fullHistory();
return next ? getWeakWindowPred(std::ranges::find(HISTORY, cur), HISTORY.end(), HISTORY.begin(), FINDER) :
getWeakWindowPred(std::ranges::find(HISTORY | std::views::reverse, cur), HISTORY.rend(), HISTORY.rbegin(), FINDER);
}
PHLWINDOW CCompositor::getWindowCycle(PHLWINDOW cur, bool focusableOnly, std::optional<bool> floating, bool visible, bool prev, bool allowFullscreenBlocked) {
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible, allowFullscreenBlocked); };
const auto& WINDOWS = Desktop::windowState()->windows();
return prev ? getWindowPred(std::ranges::find(WINDOWS | std::views::reverse, cur), WINDOWS.rend(), WINDOWS.rbegin(), FINDER) :
getWindowPred(std::ranges::find(WINDOWS, cur), WINDOWS.end(), WINDOWS.begin(), FINDER);
}
bool CCompositor::isPointOnAnyMonitor(const Vector2D& point) {
return std::ranges::any_of(State::monitorState()->monitors(), [&](const PHLMONITOR& m) {
return VECINRECT(point, m->m_position.x, m->m_position.y, m->m_size.x + m->m_position.x, m->m_size.y + m->m_position.y);
@@ -1565,21 +1228,6 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, Desktop::Vie
Config::monitorRuleMgr()->ensureVRR(PMONITOR);
}
PHLWINDOW CCompositor::getX11Parent(PHLWINDOW pWindow) {
if (!pWindow->m_isX11)
return nullptr;
for (auto const& w : Desktop::windowState()->windows()) {
if (!w->m_isX11)
continue;
if (w->m_xwaylandSurface == pWindow->m_xwaylandSurface->m_parent)
return w;
}
return nullptr;
}
void CCompositor::warpCursorTo(const Vector2D& pos, bool force) {
// warpCursorTo should only be used for warps that
+17 -27
View File
@@ -73,33 +73,23 @@ class CCompositor {
// ------------------------------------------------- //
bool isWindowActive(PHLWINDOW);
void changeWindowZOrder(PHLWINDOW, bool);
PHLWINDOW getWindowInDirection(PHLWINDOW, Math::eDirection);
PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, Math::eDirection dir, bool floatingPreference, PHLWINDOW ignoreWindow = nullptr,
bool useVectorAngles = false);
PHLWINDOW getWindowCycle(PHLWINDOW cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool prev = false,
bool allowFullscreenBlocked = false);
PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool next = false,
bool allowFullscreenBlocked = false);
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
std::optional<CBox> calculateX11WorkArea();
void updateAllWindowsAnimatedDecorationValues();
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false);
void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR);
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const Desktop::View::SFullscreenState state);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
PHLWINDOW getX11Parent(PHLWINDOW);
void warpCursorTo(const Vector2D&, bool force = false);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void performUserChecks();
void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
void setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale);
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
std::optional<CBox> calculateX11WorkArea();
void updateAllWindowsAnimatedDecorationValues();
void moveWorkspaceToMonitor(PHLWORKSPACE, PHLMONITOR, bool noWarpCursor = false);
void swapActiveWorkspaces(PHLMONITOR, PHLMONITOR);
void setWindowFullscreenInternal(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE);
void setWindowFullscreenState(const PHLWINDOW PWINDOW, const Desktop::View::SFullscreenState state);
void changeWindowFullscreenModeClient(const PHLWINDOW PWINDOW, const eFullscreenMode MODE, const bool ON);
void warpCursorTo(const Vector2D&, bool force = false);
Vector2D parseWindowVectorArgsRelative(const std::string&, const Vector2D&);
void performUserChecks();
void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
void setPreferredScaleForSurface(SP<CWLSurfaceResource> pSurface, double scale);
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates();
std::optional<unsigned int> getVTNr();
bool isVRRActiveOnAnyMonitor() const;
+23 -14
View File
@@ -1,6 +1,7 @@
#include "ConfigActions.hpp"
#include "../parserUtils/ParserUtils.hpp"
#include "../../../desktop/state/FocusState.hpp"
#include "../../../desktop/state/WindowState.hpp"
#include "../../../desktop/view/Window.hpp"
#include "../../../desktop/view/Group.hpp"
#include "../../../desktop/history/WindowHistoryTracker.hpp"
@@ -186,7 +187,7 @@ ActionResult Actions::floatWindow(eTogglableAction action, std::optional<PHLWIND
g_layoutManager->changeFloatingMode(window->layoutTarget());
if (window->m_isFloating)
g_pCompositor->changeWindowZOrder(window, true);
Desktop::windowState()->raise(window);
if (window->m_workspace) {
window->m_workspace->updateWindows();
@@ -362,8 +363,9 @@ ActionResult Actions::moveFocus(Math::eDirection dir) {
}
const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ?
g_pCompositor->getWindowCycle(PLASTWINDOW, true, {}, false, dir != Math::DIRECTION_DOWN && dir != Math::DIRECTION_RIGHT, true) :
g_pCompositor->getWindowInDirection(PLASTWINDOW, dir);
Desktop::windowState()->query().cycle(PLASTWINDOW,
{.focusableOnly = true, .previous = dir != Math::DIRECTION_DOWN && dir != Math::DIRECTION_RIGHT, .allowFullscreenBlocked = true}) :
Desktop::windowState()->query().inDirection(PLASTWINDOW, dir);
if (*PGROUPCYCLE && PLASTWINDOW->m_group) {
auto isTheOnlyGroupOnWs = !PWINDOWTOCHANGETO && State::monitorState()->monitors().size() == 1;
@@ -421,8 +423,13 @@ ActionResult Actions::moveFocus(Math::eDirection dir) {
default: break;
}
const auto PWINDOWCANDIDATE = g_pCompositor->getWindowInDirection(box, PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace,
dir, PLASTWINDOW->m_isFloating, PLASTWINDOW, PLASTWINDOW->m_isFloating);
const auto PWINDOWCANDIDATE =
Desktop::windowState()->query().inDirection({.origin = box,
.workspace = PMONITOR->m_activeSpecialWorkspace ? PMONITOR->m_activeSpecialWorkspace : PMONITOR->m_activeWorkspace,
.direction = dir,
.floatingPreference = PLASTWINDOW->m_isFloating,
.ignoreWindow = PLASTWINDOW,
.useVectorAngles = PLASTWINDOW->m_isFloating});
if (PWINDOWCANDIDATE)
switchToWindow(PWINDOWCANDIDATE);
@@ -473,7 +480,7 @@ ActionResult Actions::swapInDirection(Math::eDirection dir, std::optional<PHLWIN
if (window->isFullscreen())
return actionError("Can't swap fullscreen window", eActionErrorLevel::WARNING, eActionErrorCode::INVALID_STATE);
const auto PWINDOWTOCHANGETO = g_pCompositor->getWindowInDirection(window, dir);
const auto PWINDOWTOCHANGETO = Desktop::windowState()->query().inDirection(window, dir);
if (!PWINDOWTOCHANGETO || PWINDOWTOCHANGETO == window)
return actionError("No window to swap with in that direction", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND);
@@ -639,10 +646,10 @@ ActionResult Actions::swapNext(const bool next, std::optional<PHLWINDOW> w) {
const auto PLASTCYCLED =
validMapped(window->m_lastCycledWindow) && window->m_lastCycledWindow->m_workspace == window->m_workspace ? window->m_lastCycledWindow.lock() : nullptr;
auto toSwap = g_pCompositor->getWindowCycle(PLASTCYCLED ? PLASTCYCLED : window, true, std::nullopt, false, !next);
auto toSwap = Desktop::windowState()->query().cycle(PLASTCYCLED ? PLASTCYCLED : window, {.focusableOnly = true, .previous = !next});
if (toSwap == window)
toSwap = g_pCompositor->getWindowCycle(window, true, std::nullopt, false, !next);
toSwap = Desktop::windowState()->query().cycle(window, {.focusableOnly = true, .previous = !next});
if (!toSwap)
return actionError("No window to swap with", eActionErrorLevel::INFO, eActionErrorCode::NOT_FOUND);
@@ -660,9 +667,9 @@ ActionResult Actions::alterZOrder(const std::string& mode, std::optional<PHLWIND
return {};
if (mode == "top")
g_pCompositor->changeWindowZOrder(window, true);
Desktop::windowState()->raise(window);
else if (mode == "bottom")
g_pCompositor->changeWindowZOrder(window, false);
Desktop::windowState()->lower(window);
else
return std::unexpected(std::format("Bad z-order position: {}", mode));
@@ -1309,7 +1316,7 @@ ActionResult Actions::moveIntoGroup(Math::eDirection direction, std::optional<PH
if (!window)
return {};
auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(window, direction);
auto PWINDOWINDIR = Desktop::windowState()->query().inDirection(window, direction);
if (!PWINDOWINDIR || !PWINDOWINDIR->m_group)
return {};
@@ -1371,7 +1378,7 @@ ActionResult Actions::moveWindowOrGroup(Math::eDirection direction, std::optiona
return {};
}
const auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(window, direction);
const auto PWINDOWINDIR = Desktop::windowState()->query().inDirection(window, direction);
const bool ISWINDOWGROUP = !!window->m_group;
const bool ISWINDOWGROUPLOCKED = ISWINDOWGROUP && window->m_group->locked();
@@ -1675,7 +1682,9 @@ ActionResult Actions::cycleNext(const bool next, std::optional<bool> onlyTiled,
if (onlyTiled.value_or(false) != onlyFloating.value_or(false))
tileOrFloatOnly = onlyFloating.value_or(false);
const auto& cycled = g_pCompositor->getWindowCycle(window, true, tileOrFloatOnly, false, !next, window->m_workspace && window->m_workspace->m_hasFullscreenWindow);
const auto& cycled = Desktop::windowState()->query().cycle(
window,
{.focusableOnly = true, .floating = tileOrFloatOnly, .previous = !next, .allowFullscreenBlocked = window->m_workspace && window->m_workspace->m_hasFullscreenWindow});
switchToWindow(cycled);
@@ -1698,7 +1707,7 @@ ActionResult Actions::moveIntoOrCreateGroup(Math::eDirection dir, std::optional<
if (!PWINDOW)
return {};
auto PWINDOWINDIR = g_pCompositor->getWindowInDirection(PWINDOW, dir);
auto PWINDOWINDIR = Desktop::windowState()->query().inDirection(PWINDOW, dir);
if (!PWINDOWINDIR)
return {};
+15
View File
@@ -307,6 +307,21 @@ void CFocusState::resetWindowFocus() {
m_focusSurface.reset();
}
bool CFocusState::isWindowActive(PHLWINDOW pWindow) const {
const auto FOCUSWINDOW = m_focusWindow.lock();
const auto FOCUSSURFACE = m_focusSurface.lock();
if (!FOCUSWINDOW && !FOCUSSURFACE)
return false;
if (!pWindow || !pWindow->m_isMapped)
return false;
const auto PSURFACE = pWindow->wlSurface()->resource();
return PSURFACE == FOCUSSURFACE || pWindow == FOCUSWINDOW;
}
bool Desktop::isHardInputFocusReason(eFocusReason r) {
return r == FOCUS_REASON_NEW_WINDOW || r == FOCUS_REASON_KEYBIND || r == FOCUS_REASON_GHOSTS || r == FOCUS_REASON_CLICK || r == FOCUS_REASON_DESKTOP_STATE_CHANGE ||
r == FOCUS_REASON_UNMAP_WINDOW_TILING || r == FOCUS_REASON_SWITCH_TO_WINDOW_HARD;
+2
View File
@@ -45,6 +45,8 @@ namespace Desktop {
void resetWindowFocus();
bool isWindowActive(PHLWINDOW w) const;
SP<CWLSurfaceResource> surface();
PHLWINDOW window();
PHLMONITOR monitor();
+1 -1
View File
@@ -186,7 +186,7 @@ PHLWINDOW CViewHitTester::windowAt(const Vector2D& pos, uint16_t properties, PHL
if ((properties & INPUT_EXTENTS) && BORDER_GRAB_AREA > 0 && !w->isX11OverrideRedirect()) {
const auto WORKAREA = PWORKSPACE->m_space->workArea();
auto isWindowCloseToWorkAreaEdge = [&](const Math::eDirection dir) -> bool {
constexpr double STICK_THRESHOLD = 2.0; // This constant is taken from isAdjacent in CCompositor::getWindowInDirection
constexpr double STICK_THRESHOLD = 2.0; // This constant is taken from isAdjacent in CWindowQuery::inDirection
double aEdge = -1;
double bEdge = -1;
+300
View File
@@ -0,0 +1,300 @@
#include "WindowQuery.hpp"
#include "WindowState.hpp"
#include "../Workspace.hpp"
#include "../history/WindowHistoryTracker.hpp"
#include "../view/Window.hpp"
#include "../../config/ConfigValue.hpp"
#include "../../output/Monitor.hpp"
#include <algorithm>
#include <cmath>
#include <functional>
#include <ranges>
#include <unordered_map>
using namespace Desktop;
using namespace Desktop::View;
CWindowQuery::CWindowQuery(const CWindowState& state) : m_state(state) {
;
}
PHLWINDOW CWindowQuery::inDirection(PHLWINDOW window, Math::eDirection direction) const {
if (direction == Math::DIRECTION_DEFAULT)
return nullptr;
if (!window)
return nullptr;
const auto PMONITOR = window->m_monitor.lock();
if (!PMONITOR)
return nullptr; // ??
const auto WINDOWIDEALBB = window->isFullscreen() ? CBox{PMONITOR->m_position, PMONITOR->m_size} : window->getWindowIdealBoundingBoxIgnoreReserved();
const auto PWORKSPACE = window->m_workspace;
if (!PWORKSPACE)
return nullptr; // ??
return inDirection({.origin = WINDOWIDEALBB,
.workspace = PWORKSPACE,
.direction = direction,
.floatingPreference = window->m_isFloating,
.ignoreWindow = window,
.useVectorAngles = window->m_isFloating});
}
PHLWINDOW CWindowQuery::inDirection(const SWindowDirectionQuery& query) const {
if (query.direction == Math::DIRECTION_DEFAULT)
return nullptr;
if (!query.workspace)
return nullptr;
// 0 -> history, 1 -> shared length
static auto PMETHOD = CConfigValue<Config::INTEGER>("binds:focus_preferred_method");
static auto PMONITORFALLBACK = CConfigValue<Config::INTEGER>("binds:window_direction_monitor_fallback");
const auto POSA = query.origin.pos();
const auto SIZEA = query.origin.size();
auto leaderValue = -1;
auto floatingPreference = query.floatingPreference;
PHLWINDOW leaderWindow = nullptr;
if (!query.useVectorAngles) {
// helper to check if two rectangles are adjacent along an axis, considering slight overlaps.
// returns true if: STICKS (delta <= 2) OR rectangles overlap but no more than 50% of the smaller dimension.
static auto isAdjacent = [](const double aMin, const double aMax, const double bMin, const double bMax) -> bool {
constexpr double STICK_THRESHOLD = 2.0;
constexpr double MAX_OVERLAP_RATIO = 0.5;
const double aEdge = aMin;
const double bEdge = bMax;
const double delta = aEdge - bEdge;
// old STICKS check for 2px
if (std::abs(delta) < STICK_THRESHOLD)
return true;
if (delta >= 0)
return false;
const double overlap = -delta;
const double sizeA = aMax - aMin;
const double sizeB = bMax - bMin;
// reject if one rectangle fully contains the other
if ((bMin <= aMin && bMax >= aMax) || (aMin <= bMin && aMax >= bMax))
return false;
// accept if overlap is at most 50% of the smaller dimension
return overlap <= std::min(sizeA, sizeB) * MAX_OVERLAP_RATIO;
};
auto find = [&]() {
for (auto const& w : m_state.windows()) {
if (w == query.ignoreWindow || !w->m_workspace || !w->m_isMapped || (!w->isFullscreen() && w->m_isFloating) || !w->m_workspace->isVisible())
continue;
if (w->isHidden())
continue;
// check if the input is blocked by anything except BELOW_FULLSCREEN
if (w->isInputBlocked(INPUT_BLOCK_ALL & (~INPUT_BLOCK_BELOW_FULLSCREEN)))
continue;
if (query.workspace->m_monitor == w->m_monitor && query.workspace != w->m_workspace)
continue;
if (query.workspace->m_hasFullscreenWindow && !w->isAllowedOverFullscreen())
continue;
if (!*PMONITORFALLBACK && query.workspace->m_monitor != w->m_monitor)
continue;
if (w->m_isFloating != floatingPreference)
continue;
// prioritize windows on the same workspace.
// this is especially important for scrolling layouts - we want to first move to a window
// on the same workspace before moving onto another.
const auto LEADER_IS_ON_SAME_WORKSPACE = leaderWindow && leaderWindow->m_workspace == query.workspace;
if (LEADER_IS_ON_SAME_WORKSPACE && w->m_workspace != query.workspace)
continue;
const auto BWINDOWIDEALBB = w->getWindowIdealBoundingBoxIgnoreReserved();
const auto POSB = Vector2D(BWINDOWIDEALBB.x, BWINDOWIDEALBB.y);
const auto SIZEB = Vector2D(BWINDOWIDEALBB.width, BWINDOWIDEALBB.height);
double intersectLength = -1;
switch (query.direction) {
case Math::DIRECTION_LEFT:
if (isAdjacent(POSA.x, POSA.x + SIZEA.x, POSB.x, POSB.x + SIZEB.x))
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
break;
case Math::DIRECTION_RIGHT:
if (isAdjacent(POSB.x, POSB.x + SIZEB.x, POSA.x, POSA.x + SIZEA.x))
intersectLength = std::max(0.0, std::min(POSA.y + SIZEA.y, POSB.y + SIZEB.y) - std::max(POSA.y, POSB.y));
break;
case Math::DIRECTION_UP:
if (isAdjacent(POSA.y, POSA.y + SIZEA.y, POSB.y, POSB.y + SIZEB.y))
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
break;
case Math::DIRECTION_DOWN:
if (isAdjacent(POSB.y, POSB.y + SIZEB.y, POSA.y, POSA.y + SIZEA.y))
intersectLength = std::max(0.0, std::min(POSA.x + SIZEA.x, POSB.x + SIZEB.x) - std::max(POSA.x, POSB.x));
break;
default: break;
}
// if we have a leader on another workspace, and this window is on the same workspace,
// override minimum requirements and always select this as the new leader
const bool OVERRIDE_MIN_REQ = leaderWindow && !LEADER_IS_ON_SAME_WORKSPACE && w->m_workspace == query.workspace;
// ...as long as there is any intersect.
if (intersectLength <= 1)
continue;
if (*PMETHOD == 0 /* history */) {
// get idx
int windowIDX = -1;
const auto& HISTORY = Desktop::History::windowTracker()->fullHistory();
for (int64_t i = HISTORY.size() - 1; i >= 0; --i) {
if (HISTORY[i] == w) {
windowIDX = i;
break;
}
}
if (windowIDX > leaderValue || OVERRIDE_MIN_REQ) {
leaderValue = windowIDX;
leaderWindow = w;
}
} else /* length */ {
if (intersectLength > leaderValue || OVERRIDE_MIN_REQ) {
leaderValue = intersectLength;
leaderWindow = w;
}
}
}
};
// Find the window, then if we don't find one with preferred
// float status, try the opposite.
find();
if (!leaderWindow) {
floatingPreference = !floatingPreference;
find();
}
} else {
static const std::unordered_map<Math::eDirection, Vector2D> VECTORS = {
{Math::DIRECTION_RIGHT, {1, 0}}, {Math::DIRECTION_UP, {0, -1}}, {Math::DIRECTION_DOWN, {0, 1}}, {Math::DIRECTION_LEFT, {-1, 0}}};
auto vectorAngles = [](const Vector2D& a, const Vector2D& b) -> double {
double dot = (a.x * b.x) + (a.y * b.y);
double ang = std::acos(dot / (a.size() * b.size()));
return ang;
};
float bestAngleAbs = 2.0 * M_PI;
constexpr float THRESHOLD = 0.3 * M_PI;
for (auto const& w : m_state.windows()) {
if (w == query.ignoreWindow || !w->m_isMapped || !w->m_workspace || !w->acceptsInput() || (!w->isFullscreen() && !w->m_isFloating) || !w->m_workspace->isVisible())
continue;
if (query.workspace->m_monitor == w->m_monitor && query.workspace != w->m_workspace)
continue;
if (query.workspace->m_hasFullscreenWindow && !w->isAllowedOverFullscreen())
continue;
if (!*PMONITORFALLBACK && query.workspace->m_monitor != w->m_monitor)
continue;
const auto DIST = w->middle().distance(query.origin.middle());
const auto ANGLE = vectorAngles(Vector2D{w->middle() - query.origin.middle()}, VECTORS.at(query.direction));
if (ANGLE > M_PI_2)
continue; // if the angle is over 90 degrees, ignore. Wrong direction entirely.
if ((bestAngleAbs < THRESHOLD && DIST < leaderValue && ANGLE < THRESHOLD) || (ANGLE < bestAngleAbs && bestAngleAbs > THRESHOLD) || leaderValue == -1) {
leaderValue = DIST;
bestAngleAbs = ANGLE;
leaderWindow = w;
}
}
if (!leaderWindow && query.workspace->m_hasFullscreenWindow)
leaderWindow = query.workspace->getFullscreenWindow();
}
if (leaderValue != -1)
return leaderWindow;
return nullptr;
}
template <typename WINDOWPTR>
static bool isWorkspaceMatches(WINDOWPTR pWindow, const WINDOWPTR w, bool anyWorkspace) {
return anyWorkspace ? w->m_workspace && w->m_workspace->isVisible() : w->m_workspace == pWindow->m_workspace;
}
template <typename WINDOWPTR>
static bool isFloatingMatches(WINDOWPTR w, std::optional<bool> floating) {
return !floating.has_value() || w->m_isFloating == floating.value();
}
template <typename WINDOWPTR>
static bool acceptsInputForCycle(WINDOWPTR w, bool allowFullscreenBlocked) {
if (w->acceptsInput())
return true;
return allowFullscreenBlocked && !w->isHidden() && w->isInputBlockedOnly(INPUT_BLOCK_BELOW_FULLSCREEN);
}
template <typename WINDOWPTR>
static bool isWindowAvailableForCycle(WINDOWPTR pWindow, WINDOWPTR w, const SWindowCycleOptions& options) {
return isFloatingMatches(w, options.floating) &&
(w != pWindow && isWorkspaceMatches(pWindow, w, options.visible) && w->m_isMapped && acceptsInputForCycle(w, options.allowFullscreenBlocked) &&
(!options.focusableOnly || !w->m_ruleApplicator->noFocus().valueOrDefault()));
}
template <typename Iterator>
static PHLWINDOW getWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function<bool(const PHLWINDOW&)> PRED) {
const auto IN_ONE_SIDE = std::find_if(cur, end, PRED);
if (IN_ONE_SIDE != end)
return *IN_ONE_SIDE;
const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED);
return *IN_OTHER_SIDE;
}
template <typename Iterator>
static PHLWINDOW getWeakWindowPred(Iterator cur, Iterator end, Iterator begin, const std::function<bool(const PHLWINDOWREF&)> PRED) {
const auto IN_ONE_SIDE = std::find_if(cur, end, PRED);
if (IN_ONE_SIDE != end)
return IN_ONE_SIDE->lock();
const auto IN_OTHER_SIDE = std::find_if(begin, cur, PRED);
return IN_OTHER_SIDE->lock();
}
PHLWINDOW CWindowQuery::cycleHistory(PHLWINDOWREF current, const SWindowCycleOptions& options) const {
const auto FINDER = [&](const PHLWINDOWREF& w) { return isWindowAvailableForCycle(current, w, options); };
// also m_vWindowFocusHistory has reverse order, so when it is next - we need to reverse again
const auto& HISTORY = Desktop::History::windowTracker()->fullHistory();
return !options.previous ? getWeakWindowPred(std::ranges::find(HISTORY, current), HISTORY.end(), HISTORY.begin(), FINDER) :
getWeakWindowPred(std::ranges::find(HISTORY | std::views::reverse, current), HISTORY.rend(), HISTORY.rbegin(), FINDER);
}
PHLWINDOW CWindowQuery::cycle(PHLWINDOW current, const SWindowCycleOptions& options) const {
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(current, w, options); };
return options.previous ? getWindowPred(std::ranges::find(m_state.windows() | std::views::reverse, current), m_state.windows().rend(), m_state.windows().rbegin(), FINDER) :
getWindowPred(std::ranges::find(m_state.windows(), current), m_state.windows().end(), m_state.windows().begin(), FINDER);
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include "../DesktopTypes.hpp"
#include "../../helpers/math/Direction.hpp"
#include "../../helpers/math/Math.hpp"
#include <optional>
namespace Desktop {
class CWindowState;
struct SWindowDirectionQuery {
CBox origin = {};
PHLWORKSPACE workspace = nullptr;
Math::eDirection direction = Math::DIRECTION_DEFAULT;
bool floatingPreference = false;
PHLWINDOW ignoreWindow = nullptr;
bool useVectorAngles = false;
};
struct SWindowCycleOptions {
bool focusableOnly = false;
std::optional<bool> floating = std::nullopt;
bool visible = false;
bool previous = false;
bool allowFullscreenBlocked = false;
};
class CWindowQuery {
public:
CWindowQuery(const CWindowState& state);
~CWindowQuery() = default;
PHLWINDOW inDirection(PHLWINDOW window, Math::eDirection direction) const;
PHLWINDOW inDirection(const SWindowDirectionQuery& query) const;
PHLWINDOW cycle(PHLWINDOW current, const SWindowCycleOptions& options = {}) const;
PHLWINDOW cycleHistory(PHLWINDOWREF current, const SWindowCycleOptions& options = {}) const;
private:
const CWindowState& m_state;
};
}
+61
View File
@@ -1,8 +1,10 @@
#include "WindowState.hpp"
#include "../../event/EventBus.hpp"
#include "../../render/Renderer.hpp"
#include "../view/Window.hpp"
#include <algorithm>
#include <ranges>
using namespace Desktop;
@@ -31,6 +33,65 @@ const std::vector<PHLWINDOW>& CWindowState::windows() const {
return m_windows;
}
CWindowQuery CWindowState::query() const {
return CWindowQuery{*this};
}
void CWindowState::raise(PHLWINDOW w) {
moveToZ(w, true);
}
void CWindowState::lower(PHLWINDOW w) {
moveToZ(w, false);
}
void CWindowState::moveToZ(PHLWINDOW w, bool top) {
if (!View::validMapped(w) || m_windows.empty())
return;
w->m_createdOverFullscreen = top;
w->updateFullscreenInputState();
*w->alpha(View::WINDOW_ALPHA_FULLSCREEN) = w->isBlockedByFullscreen() ? 0.F : 1.F;
if (w == (top ? m_windows.back() : m_windows.front()))
return;
auto moveSingleToZ = [&](PHLWINDOW pw) -> void {
if (top)
moveToTop(pw);
else
moveToBottom(pw);
if (pw->m_isMapped)
g_pHyprRenderer->damageMonitor(pw->m_monitor.lock());
};
if (!w->m_isX11) {
moveSingleToZ(w);
return;
}
// move X11 transient stack
std::vector<PHLWINDOW> toMove;
auto collectX11Stack = [&](PHLWINDOW pw, auto&& collectX11Stack) -> void {
if (top)
toMove.emplace_back(pw);
else
toMove.insert(toMove.begin(), pw);
for (auto const& other : m_windows) {
if (other->m_isMapped && !other->isHidden() && other->m_isX11 && other->x11Parent() == pw && other != pw && std::ranges::find(toMove, other) == toMove.end())
collectX11Stack(other, collectX11Stack);
}
};
collectX11Stack(w, collectX11Stack);
for (auto const& it : toMove) {
moveSingleToZ(it);
}
}
void CWindowState::moveToTop(PHLWINDOW w) {
if (!w || m_windows.empty() || m_windows.back() == w)
return;
+8 -2
View File
@@ -3,6 +3,7 @@
#include "../../helpers/memory/Memory.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../DesktopTypes.hpp"
#include "WindowQuery.hpp"
#include <vector>
@@ -14,8 +15,9 @@ namespace Desktop {
const std::vector<PHLWINDOW>& windows() const;
void moveToTop(PHLWINDOW w);
void moveToBottom(PHLWINDOW w);
CWindowQuery query() const;
void raise(PHLWINDOW w);
void lower(PHLWINDOW w);
void clear();
// kept for compat with old code, should be removed ASAP
@@ -25,6 +27,10 @@ namespace Desktop {
private:
std::vector<PHLWINDOW> m_windows;
void moveToTop(PHLWINDOW w);
void moveToBottom(PHLWINDOW w);
void moveToZ(PHLWINDOW w, bool top);
struct {
CHyprSignalListener viewCreate, viewDestroy;
} m_listeners;
+12 -24
View File
@@ -21,6 +21,7 @@
#include "LayerSurface.hpp"
#include "../state/FocusState.hpp"
#include "../state/FloatState.hpp"
#include "../state/WindowState.hpp"
#include "../history/WindowHistoryTracker.hpp"
#include "../../Compositor.hpp"
#include "../../render/decorations/CHyprDropShadowDecoration.hpp"
@@ -580,29 +581,16 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
}
}
PHLWINDOW CWindow::x11TransientFor() {
if (!m_xwaylandSurface || !m_xwaylandSurface->m_parent)
PHLWINDOW CWindow::x11Parent() const {
if (!m_isX11 || !m_xwaylandSurface || !m_xwaylandSurface->m_parent)
return nullptr;
auto s = m_xwaylandSurface->m_parent;
std::vector<SP<CXWaylandSurface>> visited;
while (s) {
// break loops. Some X apps make them, and it seems like it's valid behavior?!?!?!
// TODO: we should reject loops being created in the first place.
if (std::ranges::find(visited.begin(), visited.end(), s) != visited.end())
break;
visited.emplace_back(s.lock());
s = s->m_parent;
}
if (s == m_xwaylandSurface)
return nullptr; // dead-ass circle
for (auto const& w : Desktop::windowState()->windows()) {
if (w->m_xwaylandSurface != s)
if (!w->m_isX11)
continue;
return w;
if (w->m_xwaylandSurface == m_xwaylandSurface->m_parent)
return w;
}
return nullptr;
@@ -1388,7 +1376,7 @@ void CWindow::activate(bool force) {
}
if (m_isFloating)
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
Desktop::windowState()->raise(m_self.lock());
Desktop::focusState()->fullWindowFocus(m_self.lock(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
warpCursor();
@@ -1589,7 +1577,7 @@ void CWindow::onX11ConfigureRequest(CBox box) {
m_workspace = monitorByRequestedPosition->m_activeWorkspace;
}
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
Desktop::windowState()->raise(m_self.lock());
m_createdOverFullscreen = true;
@@ -1794,7 +1782,7 @@ std::optional<std::string> CWindow::xdgDescription() {
PHLWINDOW CWindow::parent() {
if (m_isX11) {
auto t = x11TransientFor();
auto t = x11Parent();
// don't return a parent that's not mapped
if (!validMapped(t))
@@ -2385,7 +2373,7 @@ void CWindow::mapWindow() {
// because the windows are animated on RealSize
m_target->setPseudoSize(m_realSize->goal());
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
Desktop::windowState()->raise(m_self.lock());
} else {
bool setPseudo = false;
@@ -2849,7 +2837,7 @@ void CWindow::unmanagedSetGeometry() {
m_workspace = State::monitorState()->query().vec(m_realPosition->value() + m_realSize->value() / 2.f).run()->m_activeWorkspace;
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
Desktop::windowState()->raise(m_self.lock());
updateWindowDecos();
g_pHyprRenderer->damageWindow(m_self.lock());
+1 -1
View File
@@ -314,7 +314,7 @@ namespace Desktop::View {
void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW x11TransientFor();
PHLWINDOW x11Parent() const;
void onUnmap();
void onMap();
void setHidden(bool hidden);
@@ -6,6 +6,7 @@
#include "../../../space/Space.hpp"
#include "../../../../Compositor.hpp"
#include "../../../../desktop/state/WindowState.hpp"
#include "../../../../output/Monitor.hpp"
#include "../../../../state/MonitorState.hpp"
@@ -111,7 +112,7 @@ void CDefaultFloatingAlgorithm::newTarget(SP<ITarget> target) {
}
if (!PWINDOW->isX11OverrideRedirect())
g_pCompositor->changeWindowZOrder(PWINDOW, true);
Desktop::windowState()->raise(PWINDOW);
else {
PWINDOW->m_pendingReportedSize = PWINDOW->m_realSize->goal();
PWINDOW->m_reportedSize = PWINDOW->m_pendingReportedSize;
@@ -8,6 +8,7 @@
#include "../../../../config/shared/actions/ConfigActions.hpp"
#include "../../../../config/shared/workspace/WorkspaceRuleManager.hpp"
#include "../../../../desktop/state/FocusState.hpp"
#include "../../../../desktop/state/WindowState.hpp"
#include "../../../../output/Monitor.hpp"
#include "../../../../Compositor.hpp"
#include "../../../../render/Renderer.hpp"
@@ -464,7 +465,7 @@ void CMasterAlgorithm::swapTargets(SP<ITarget> a, SP<ITarget> b) {
void CMasterAlgorithm::moveTargetInDirection(SP<ITarget> t, Math::eDirection dir, bool silent) {
static auto PMONITORFALLBACK = CConfigValue<Config::INTEGER>("binds:window_direction_monitor_fallback");
const auto PWINDOW2 = g_pCompositor->getWindowInDirection(t->window(), dir);
const auto PWINDOW2 = Desktop::windowState()->query().inDirection(t->window(), dir);
if (!t->window())
return;
+2 -1
View File
@@ -5,6 +5,7 @@
#include "../../Compositor.hpp"
#include "../../managers/cursor/CursorShapeOverrideController.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "../../desktop/state/WindowState.hpp"
#include "../../desktop/view/Group.hpp"
#include "../../render/Renderer.hpp"
#include "../../state/MonitorState.hpp"
@@ -160,7 +161,7 @@ void CDragStateController::dragBegin(SP<ITarget> target, eMouseBindMode mode) {
if (DRAGGINGTARGET->window()) {
Desktop::focusState()->rawWindowFocus(DRAGGINGTARGET->window(), Desktop::FOCUS_REASON_DESKTOP_STATE_CHANGE);
g_pCompositor->changeWindowZOrder(DRAGGINGTARGET->window(), true);
Desktop::windowState()->raise(DRAGGINGTARGET->window());
}
}
void CDragStateController::dragEnd() {
+2 -1
View File
@@ -1,5 +1,6 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "../../protocols/IdleInhibit.hpp"
#include "../../protocols/IdleNotify.hpp"
#include "../../protocols/core/Compositor.hpp"
@@ -64,7 +65,7 @@ bool CInputManager::isWindowInhibiting(const PHLWINDOW& w, bool onlyHl) {
if (w->m_ruleApplicator->idleInhibitMode().valueOrDefault() == Desktop::Rule::IDLEINHIBIT_ALWAYS)
return true;
if (w->m_ruleApplicator->idleInhibitMode().valueOrDefault() == Desktop::Rule::IDLEINHIBIT_FOCUS && g_pCompositor->isWindowActive(w))
if (w->m_ruleApplicator->idleInhibitMode().valueOrDefault() == Desktop::Rule::IDLEINHIBIT_FOCUS && Desktop::focusState()->isWindowActive(w))
return true;
if (w->m_ruleApplicator->idleInhibitMode().valueOrDefault() == Desktop::Rule::IDLEINHIBIT_FULLSCREEN && w->isFullscreen() && w->m_workspace && w->m_workspace->isVisible())
+2 -1
View File
@@ -10,6 +10,7 @@
#include "../../config/legacy/ConfigManager.hpp"
#include "../../desktop/view/WLSurface.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "../../desktop/state/WindowState.hpp"
#include "../../protocols/CursorShape.hpp"
#include "../../protocols/IdleInhibit.hpp"
#include "../../protocols/RelativePointer.hpp"
@@ -893,7 +894,7 @@ void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e, SP<I
// pointerFocus can target a surface without a Desktop::View (e.g. IME popups), so view() may be null.
const auto PVIEW = HLSurf ? HLSurf->view() : nullptr;
if (PVIEW && PVIEW->type() == Desktop::View::VIEW_TYPE_WINDOW)
g_pCompositor->changeWindowZOrder(dynamicPointerCast<Desktop::View::CWindow>(PVIEW), true);
Desktop::windowState()->raise(dynamicPointerCast<Desktop::View::CWindow>(PVIEW));
break;
}
@@ -2,6 +2,7 @@
#include "../../Compositor.hpp"
#include "../../config/ConfigValue.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "../../desktop/state/WindowState.hpp"
#include "../../desktop/view/Group.hpp"
#include <ranges>
#include <pango/pangocairo.h>
@@ -406,7 +407,7 @@ bool CHyprGroupBarDecoration::onBeginWindowDragOnDeco(const Vector2D& pos) {
// start a move drag on it
g_layoutManager->dragController()->dragBegin(pWindow->layoutTarget(), MBIND_MOVE);
if (!g_pCompositor->isWindowActive(pWindow))
if (!Desktop::focusState()->isWindowActive(pWindow))
Desktop::focusState()->rawWindowFocus(pWindow, Desktop::FOCUS_REASON_CLICK);
return true;
@@ -465,7 +466,7 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPo
const auto TABPAD = !*PSTACKED && (BARRELATIVEX - (m_barWidth + *PINNERGAP) * WINDOWINDEX > m_barWidth);
const auto STACKPAD = *PSTACKED && (BARRELATIVEY - (m_barHeight + *POUTERGAP) * WINDOWINDEX < *POUTERGAP);
if (TABPAD || STACKPAD) {
if (!g_pCompositor->isWindowActive(m_window.lock()))
if (!Desktop::focusState()->isWindowActive(m_window.lock()))
Desktop::focusState()->rawWindowFocus(m_window.lock(), Desktop::FOCUS_REASON_CLICK);
return true;
}
@@ -475,11 +476,11 @@ bool CHyprGroupBarDecoration::onMouseButtonOnDeco(const Vector2D& pos, const IPo
if (pWindow != m_window)
pWindow->m_group->setCurrent(pWindow);
if (!g_pCompositor->isWindowActive(pWindow) && *PFOLLOWMOUSE != 3)
if (!Desktop::focusState()->isWindowActive(pWindow) && *PFOLLOWMOUSE != 3)
Desktop::focusState()->rawWindowFocus(pWindow, Desktop::FOCUS_REASON_CLICK);
if (pWindow->m_isFloating)
g_pCompositor->changeWindowZOrder(pWindow, true);
Desktop::windowState()->raise(pWindow);
return true;
}