Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: cyclenext hist option #9055

Merged
merged 1 commit into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 47 additions & 32 deletions src/Compositor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1065,7 +1065,7 @@ PHLMONITOR CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) {
return nullptr;
}

void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface) {
void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, bool preserveFocusHistory) {

static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough");
Expand Down Expand Up @@ -1185,12 +1185,13 @@ void CCompositor::focusWindow(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface

g_pInputManager->recheckIdleInhibitorStatus();

// move to front of the window history
const auto HISTORYPIVOT = std::find_if(m_vWindowFocusHistory.begin(), m_vWindowFocusHistory.end(), [&](const auto& other) { return other.lock() == pWindow; });
if (HISTORYPIVOT == m_vWindowFocusHistory.end()) {
Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow);
} else {
std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
if (!preserveFocusHistory) {
// move to front of the window history
const auto HISTORYPIVOT = std::ranges::find_if(m_vWindowFocusHistory, [&](const auto& other) { return other.lock() == pWindow; });
if (HISTORYPIVOT == m_vWindowFocusHistory.end())
Debug::log(ERR, "BUG THIS: {} has no pivot in history", pWindow);
else
std::rotate(m_vWindowFocusHistory.begin(), HISTORYPIVOT, HISTORYPIVOT + 1);
}

if (*PFOLLOWMOUSE == 0)
Expand Down Expand Up @@ -1403,7 +1404,6 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
};

x11Stack(pWindow, top, x11Stack);

for (const auto& it : toMove) {
moveToZ(it, top);
}
Expand Down Expand Up @@ -1654,37 +1654,52 @@ PHLWINDOW CCompositor::getWindowInDirection(const CBox& box, PHLWORKSPACE pWorks
return nullptr;
}

PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating, bool visible) {
auto it = std::ranges::find(m_vWindows, pWindow);
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); };
const auto IN_RIGHT = std::find_if(it, m_vWindows.end(), FINDER);
if (IN_RIGHT != m_vWindows.end())
return *IN_RIGHT;
const auto IN_LEFT = std::find_if(m_vWindows.begin(), it, FINDER);
return *IN_LEFT;
template <typename WINDOWPTR>
static bool isWorkspaceMatches(WINDOWPTR pWindow, const WINDOWPTR w, bool anyWorkspace) {
return anyWorkspace ? w->m_pWorkspace && w->m_pWorkspace->isVisible() : w->m_pWorkspace == pWindow->m_pWorkspace;
}

PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating, bool visible) {
auto it = std::ranges::find(std::ranges::reverse_view(m_vWindows), pWindow);
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(pWindow, w, focusableOnly, floating, visible); };
const auto IN_LEFT = std::find_if(it, m_vWindows.rend(), FINDER);
if (IN_LEFT != m_vWindows.rend())
return *IN_LEFT;
const auto IN_RIGHT = std::find_if(m_vWindows.rbegin(), it, FINDER);
return *IN_RIGHT;
template <typename WINDOWPTR>
static bool isFloatingMatches(WINDOWPTR w, std::optional<bool> floating) {
return !floating.has_value() || w->m_bIsFloating == floating.value();
}

inline static bool isWorkspaceMatches(PHLWINDOW pWindow, const PHLWINDOW w, bool anyWorkspace) {
return anyWorkspace ? w->m_pWorkspace && w->m_pWorkspace->isVisible() : w->m_pWorkspace == pWindow->m_pWorkspace;
template <typename WINDOWPTR>
static bool isWindowAvailableForCycle(WINDOWPTR pWindow, WINDOWPTR w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace = false) {
return isFloatingMatches(w, floating) &&
(w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()));
}

inline static bool isFloatingMatches(PHLWINDOW w, std::optional<bool> floating) {
return !floating.has_value() || w->m_bIsFloating == floating.value();
};
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) {
const auto FINDER = [&](const PHLWINDOWREF& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); };
// also m_vWindowFocusHistory has reverse order, so when it is next - we need to reverse again
return next ?
getWeakWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindowFocusHistory), cur), m_vWindowFocusHistory.rend(), m_vWindowFocusHistory.rbegin(), FINDER) :
getWeakWindowPred(std::ranges::find(m_vWindowFocusHistory, cur), m_vWindowFocusHistory.end(), m_vWindowFocusHistory.begin(), FINDER);
}

bool CCompositor::isWindowAvailableForCycle(PHLWINDOW pWindow, const PHLWINDOW w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace) {
return isFloatingMatches(w, floating) && w != pWindow && isWorkspaceMatches(pWindow, w, anyWorkspace) && w->m_bIsMapped && !w->isHidden() &&
(!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault());
PHLWINDOW CCompositor::getWindowCycle(PHLWINDOW cur, bool focusableOnly, std::optional<bool> floating, bool visible, bool prev) {
const auto FINDER = [&](const PHLWINDOW& w) { return isWindowAvailableForCycle(cur, w, focusableOnly, floating, visible); };
return prev ? getWindowPred(std::ranges::find(std::ranges::reverse_view(m_vWindows), cur), m_vWindows.rend(), m_vWindows.rbegin(), FINDER) :
getWindowPred(std::ranges::find(m_vWindows, cur), m_vWindows.end(), m_vWindows.begin(), FINDER);
}

WORKSPACEID CCompositor::getNextAvailableNamedWorkspace() {
Expand Down
7 changes: 3 additions & 4 deletions src/Compositor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class CCompositor {
PHLMONITOR getMonitorFromCursor();
PHLMONITOR getMonitorFromVector(const Vector2D&);
void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr, bool preserveFocusHistory = false);
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
bool monitorExists(PHLMONITOR);
PHLWINDOW vectorToWindowUnified(const Vector2D&, uint8_t properties, PHLWINDOW pIgnoreWindow = nullptr);
Expand All @@ -108,8 +108,8 @@ class CCompositor {
void cleanupFadingOut(const MONITORID& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getWindowInDirection(const CBox& box, PHLWORKSPACE pWorkspace, char dir, PHLWINDOW ignoreWindow = nullptr, bool useVectorAngles = false);
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}, bool visible = false);
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {}, bool visible = false);
PHLWINDOW getWindowCycle(PHLWINDOW cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool prev = false);
PHLWINDOW getWindowCycleHist(PHLWINDOWREF cur, bool focusableOnly = false, std::optional<bool> floating = std::nullopt, bool visible = false, bool next = false);
WORKSPACEID getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const PHLMONITOR monitor = nullptr);
Expand Down Expand Up @@ -166,7 +166,6 @@ class CCompositor {
void setRandomSplash();
void initManagers(eManagersInitStage stage);
void prepareFallbackOutput();
bool isWindowAvailableForCycle(PHLWINDOW pWindow, PHLWINDOW w, bool focusableOnly, std::optional<bool> floating, bool anyWorkspace = false);

uint64_t m_iHyprlandPID = 0;
wl_event_source* m_critSigSource = nullptr;
Expand Down
32 changes: 14 additions & 18 deletions src/managers/KeybindManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(PHLMONITOR monitor) {
return true;
}

void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory) {
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
static auto PNOWARPS = CConfigValue<Hyprlang::INT>("cursor:no_warps");

Expand All @@ -386,7 +386,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreenInternal(PLASTWINDOW, FSMODE_NONE);

g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory);

if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreenInternal(PWINDOWTOCHANGETO, MODE);
Expand All @@ -396,7 +396,7 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
PWINDOWTOCHANGETO->m_vRealSize->warp();
} else {
updateRelativeCursorCoords();
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
g_pCompositor->focusWindow(PWINDOWTOCHANGETO, nullptr, preserveFocusHistory);
PWINDOWTOCHANGETO->warpCursor();

// Move mouse focus to the new window if required by current follow_mouse and warp modes
Expand Down Expand Up @@ -1480,7 +1480,7 @@ SDispatchResult CKeybindManager::moveFocusTo(std::string args) {
}

const auto PWINDOWTOCHANGETO = *PFULLCYCLE && PLASTWINDOW->isFullscreen() ?
(arg == 'd' || arg == 'b' || arg == 'r' ? g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true) : g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true)) :
g_pCompositor->getWindowCycle(PLASTWINDOW, true, {}, false, arg != 'd' && arg != 'b' && arg != 'r') :
g_pCompositor->getWindowInDirection(PLASTWINDOW, arg);

// Prioritize focus change within groups if the window is a part of it.
Expand Down Expand Up @@ -2228,11 +2228,13 @@ SDispatchResult CKeybindManager::circleNext(std::string arg) {
floatStatus = true;

const auto VISIBLE = args.contains("visible") || args.contains("v");
const auto& w = (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l")) ?
g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE) :
g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE);
const auto PREV = args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l");
const auto NEXT = args.contains("next") || args.contains("n"); // prev is default in classic alt+tab
const auto HIST = args.contains("hist") || args.contains("h");
const auto& w = HIST ? g_pCompositor->getWindowCycleHist(g_pCompositor->m_pLastWindow, true, floatStatus, VISIBLE, NEXT) :
g_pCompositor->getWindowCycle(g_pCompositor->m_pLastWindow.lock(), true, floatStatus, VISIBLE, PREV);

switchToWindow(w);
switchToWindow(w, HIST);

return {};
}
Expand Down Expand Up @@ -2627,18 +2629,12 @@ SDispatchResult CKeybindManager::swapnext(std::string arg) {
g_pCompositor->m_pLastWindow->m_pLastCycledWindow.lock() :
nullptr;

if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true);
else
toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true);
const bool NEED_PREV = arg == "last" || arg == "l" || arg == "prev" || arg == "p";
toSwap = g_pCompositor->getWindowCycle(PLASTCYCLED ? PLASTCYCLED : PLASTWINDOW, true, std::nullopt, false, NEED_PREV);

// sometimes we may come back to ourselves.
if (toSwap == PLASTWINDOW) {
if (arg == "last" || arg == "l" || arg == "prev" || arg == "p")
toSwap = g_pCompositor->getPrevWindowOnWorkspace(PLASTWINDOW, true);
else
toSwap = g_pCompositor->getNextWindowOnWorkspace(PLASTWINDOW, true);
}
if (toSwap == PLASTWINDOW)
toSwap = g_pCompositor->getWindowCycle(PLASTWINDOW, true, std::nullopt, false, NEED_PREV);

g_pLayoutManager->getCurrentLayout()->switchWindows(PLASTWINDOW, toSwap);

Expand Down
2 changes: 1 addition & 1 deletion src/managers/KeybindManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class CKeybindManager {
static bool tryMoveFocusToMonitor(PHLMONITOR monitor);
static void moveWindowOutOfGroup(PHLWINDOW pWindow, const std::string& dir = "");
static void moveWindowIntoGroup(PHLWINDOW pWindow, PHLWINDOW pWindowInDirection);
static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO);
static void switchToWindow(PHLWINDOW PWINDOWTOCHANGETO, bool preserveFocusHistory = false);
static uint64_t spawnRawProc(std::string, PHLWORKSPACE pInitialWorkspace);
static uint64_t spawnWithRules(std::string, PHLWORKSPACE pInitialWorkspace);

Expand Down
Loading