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: cycle visible windows #6695

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
128 changes: 107 additions & 21 deletions src/Compositor.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
#include "Compositor.hpp"
#include "desktop/DesktopTypes.hpp"
#include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp"
#include "managers/TokenManager.hpp"
#include "managers/PointerManager.hpp"
#include "managers/SeatManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include <cstdint>
#include <random>
#include <ranges>
#include <unordered_set>
#include "debug/HyprCtl.hpp"
#include "debug/CrashReporter.hpp"
#ifdef USES_SYSTEMD
#include <helpers/SdDaemon.hpp> // for SdNotify
#endif
#include <ranges>
#include "helpers/varlist/VarList.hpp"
#include "protocols/FractionalScale.hpp"
#include "protocols/PointerConstraints.hpp"
#include "protocols/LayerShell.hpp"
Expand Down Expand Up @@ -671,6 +673,30 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
return mon.get();
}

SP<CMonitor> CCompositor::getNextMonitor(uint64_t curID, bool reverse) {
const auto LN = m_vMonitors.size();
if (LN == 1) {
return m_vMonitors[0];
}

size_t curPos = LN + 1;
for (size_t i = 0; i < LN; i++) {
if (m_vMonitors[i]->ID == curID) {
curPos = i;
}
}

if (curPos == LN && !reverse) {
return m_vMonitors[0];
}

if (curPos == 0 && reverse) {
return m_vMonitors[LN - 1];
}

return reverse ? m_vMonitors[curPos - 1] : m_vMonitors[curPos + 1];
}

void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) {
if (!pWindow->m_bFadingOut) {
EMIT_HOOK_EVENT("destroyWindow", pWindow);
Expand Down Expand Up @@ -1567,15 +1593,42 @@ PHLWINDOW CCompositor::getWindowInDirection(PHLWINDOW pWindow, char dir) {
}

PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating) {
bool gotToWindow = false;
// going through all windows in the workspace after current, from current
for (auto it = std::find(m_vWindows.begin(), m_vWindows.end(), pWindow); it != m_vWindows.end(); ++it) {
auto& w = *it;
if ((!floating.has_value() || w->m_bIsFloating == floating.value()) && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() &&
(!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;
}

// going through all windows in the workspace before current, from first
for (auto& w : m_vWindows) {
if (w != pWindow && !gotToWindow)
continue;
if (w == pWindow)
return nullptr;

if (w == pWindow) {
gotToWindow = true;
if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
}

if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;
}

return nullptr;
}

PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating) {
// going through all windows in the workspace before current, from current
for (auto it = std::find(m_vWindows.rbegin(), m_vWindows.rend(), pWindow); it != m_vWindows.rend(); ++it) {
auto& w = *it;
if ((!floating.has_value() || w->m_bIsFloating == floating.value()) && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() &&
(!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;
}

// going through all windows in the workspace after current, from last
for (auto& w : m_vWindows | std::views::reverse) {
if (w == pWindow)
return nullptr;

if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;
Expand All @@ -1584,41 +1637,74 @@ PHLWINDOW CCompositor::getNextWindowOnWorkspace(PHLWINDOW pWindow, bool focusabl
return w;
}

return nullptr;
}

PHLWINDOW CCompositor::getNextVisibleWindow(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating) {
// going through all windows in the workspace after current, from current
for (auto it = std::find(m_vWindows.begin(), m_vWindows.end(), pWindow); it != m_vWindows.end(); ++it) {
auto& w = *it;
if ((!floating.has_value() || w->m_bIsFloating == floating.value()) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;
}

if (const auto& w = getWindowOnAnotherMonitor(pWindow->m_iMonitorID, floating, true);
w && (!floating.has_value() || w->m_bIsFloating == floating.value()) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;

// going through all windows in the workspace before current, from first
for (auto& w : m_vWindows) {
if (w == pWindow)
return nullptr;

if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;

if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
if (w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;
}

return nullptr;
}

PHLWINDOW CCompositor::getPrevWindowOnWorkspace(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating) {
bool gotToWindow = false;
for (auto& w : m_vWindows | std::views::reverse) {
if (w != pWindow && !gotToWindow)
continue;
PHLWINDOW CCompositor::getPrevVisibleWindow(PHLWINDOW pWindow, bool focusableOnly, std::optional<bool> floating) {
// going through all windows in the workspace before current, from current
for (auto it = std::find(m_vWindows.rbegin(), m_vWindows.rend(), pWindow); it != m_vWindows.rend(); ++it) {
auto& w = *it;
if ((!floating.has_value() || w->m_bIsFloating == floating.value()) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;
}

if (w == pWindow) {
gotToWindow = true;
continue;
}
if (const auto& w = getWindowOnAnotherMonitor(pWindow->m_iMonitorID, floating, true);
w && (!floating.has_value() || w->m_bIsFloating == floating.value()) && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;

// going through all windows in the workspace after current, from last
for (auto& w : m_vWindows | std::views::reverse) {
if (w == pWindow)
return nullptr;

if (floating.has_value() && w->m_bIsFloating != floating.value())
continue;

if (w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
if (w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
return w;
}

for (auto& w : m_vWindows | std::views::reverse) {
if (floating.has_value() && w->m_bIsFloating != floating.value())
return nullptr;
}

PHLWINDOW CCompositor::getWindowOnAnotherMonitor(uint64_t curMonID, std::optional<bool> floating, bool reverse) {
auto monID = curMonID;
for (auto mon = getNextMonitor(monID, reverse); mon->ID != monID; mon = getNextMonitor(monID, reverse)) {
if (mon->activeWorkspace == nullptr) {
monID = mon->ID;
continue;
}

if (w != pWindow && w->m_pWorkspace == pWindow->m_pWorkspace && w->m_bIsMapped && !w->isHidden() && (!focusableOnly || !w->m_sWindowData.noFocus.valueOrDefault()))
if (const auto w = mon->activeWorkspace->getLastFocusedWindow(); w && (!floating.has_value() || floating.value() == w->m_bIsFloating)) {
return w;
}
}

return nullptr;
Expand Down
4 changes: 4 additions & 0 deletions src/Compositor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class CCompositor {
CMonitor* getMonitorFromDesc(const std::string&);
CMonitor* getMonitorFromCursor();
CMonitor* getMonitorFromVector(const Vector2D&);
SP<CMonitor> getNextMonitor(uint64_t cur, bool reverse = false);
void removeWindowFromVectorSafe(PHLWINDOW);
void focusWindow(PHLWINDOW, SP<CWLSurfaceResource> pSurface = nullptr);
void focusSurface(SP<CWLSurfaceResource>, PHLWINDOW pWindowOwner = nullptr);
Expand Down Expand Up @@ -139,8 +140,11 @@ class CCompositor {
void changeWindowZOrder(PHLWINDOW, bool);
void cleanupFadingOut(const int& monid);
PHLWINDOW getWindowInDirection(PHLWINDOW, char);
PHLWINDOW getNextVisibleWindow(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getPrevVisibleWindow(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getNextWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getPrevWindowOnWorkspace(PHLWINDOW, bool focusableOnly = false, std::optional<bool> floating = {});
PHLWINDOW getWindowOnAnotherMonitor(uint64_t curMonID, std::optional<bool> floating = {}, bool reverse = false);
int getNextAvailableNamedWorkspace();
bool isPointOnAnyMonitor(const Vector2D&);
bool isPointOnReservedArea(const Vector2D& point, const CMonitor* monitor = nullptr);
Expand Down
103 changes: 65 additions & 38 deletions src/managers/KeybindManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "debug/Log.hpp"
#include "helpers/varlist/VarList.hpp"

#include <hyprutils/string/VarList.hpp>
#include <optional>
#include <iterator>
#include <string>
Expand Down Expand Up @@ -91,6 +92,7 @@ CKeybindManager::CKeybindManager() {
m_mDispatchers["resizeactive"] = resizeActive;
m_mDispatchers["moveactive"] = moveActive;
m_mDispatchers["cyclenext"] = circleNext;
m_mDispatchers["cyclenextvisible"] = circleNextVisible;
m_mDispatchers["focuswindowbyclass"] = focusWindow;
m_mDispatchers["focuswindow"] = focusWindow;
m_mDispatchers["tagwindow"] = tagWindow;
Expand Down Expand Up @@ -311,8 +313,10 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
}

void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {
const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (PWINDOWTOCHANGETO == nullptr)
return;

const auto PLASTWINDOW = g_pCompositor->m_pLastWindow.lock();
if (PWINDOWTOCHANGETO == PLASTWINDOW || !PWINDOWTOCHANGETO)
return;

Expand All @@ -330,23 +334,23 @@ void CKeybindManager::switchToWindow(PHLWINDOW PWINDOWTOCHANGETO) {

if (!PWINDOWTOCHANGETO->m_bPinned)
g_pCompositor->setWindowFullscreen(PWINDOWTOCHANGETO, true, FSMODE);
} else {
updateRelativeCursorCoords();
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
PWINDOWTOCHANGETO->warpCursor();
return;
}
updateRelativeCursorCoords();
g_pCompositor->focusWindow(PWINDOWTOCHANGETO);
PWINDOWTOCHANGETO->warpCursor();

g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
g_pInputManager->simulateMouseMovement();
g_pInputManager->m_pForcedFocus.reset();
g_pInputManager->m_pForcedFocus = PWINDOWTOCHANGETO;
g_pInputManager->simulateMouseMovement();
g_pInputManager->m_pForcedFocus.reset();

if (PLASTWINDOW && PLASTWINDOW->m_iMonitorID != PWINDOWTOCHANGETO->m_iMonitorID) {
// event
const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID);
if (!PLASTWINDOW || PLASTWINDOW->m_iMonitorID == PWINDOWTOCHANGETO->m_iMonitorID)
return;

g_pCompositor->setActiveMonitor(PNEWMON);
}
}
};
// event
const auto PNEWMON = g_pCompositor->getMonitorFromID(PWINDOWTOCHANGETO->m_iMonitorID);
g_pCompositor->setActiveMonitor(PNEWMON);
}

bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
if (!g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Expand Down Expand Up @@ -1037,14 +1041,20 @@ SWorkspaceIDName getWorkspaceToChangeFromArgs(std::string args, PHLWORKSPACE PCU
return {WORKSPACE_NOT_CHANGED, ""};
}

const auto ID = PCURRENTWORKSPACE->m_iID;
if (const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id); PWORKSPACETOCHANGETO) {
if (PER_MON && PCURRENTWORKSPACE->m_iMonitorID != PWORKSPACETOCHANGETO->m_iMonitorID)
return {WORKSPACE_NOT_CHANGED, ""};
const auto ID = PCURRENTWORKSPACE->m_iID;
const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(PPREVWS.id);
if (!PWORKSPACETOCHANGETO)
return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name};

if (!PER_MON || PCURRENTWORKSPACE->m_iMonitorID == PWORKSPACETOCHANGETO->m_iMonitorID)
return {ID, PWORKSPACETOCHANGETO->m_szName};
}

return {ID, PPREVWS.name.empty() ? std::to_string(PPREVWS.id) : PPREVWS.name};
// PER_MON and cur ws is not on same monitor with prev per monitor
const auto POTHERWSTOCHANGETO = g_pCompositor->getWorkspaceByID(PCURRENTWORKSPACE->getPrevWorkspaceIDName(false).id);
if (POTHERWSTOCHANGETO && POTHERWSTOCHANGETO->m_iMonitorID == PCURRENTWORKSPACE->m_iMonitorID)
return {ID, POTHERWSTOCHANGETO->m_szName};

return {WORKSPACE_NOT_CHANGED, ""};
}

void CKeybindManager::changeworkspace(std::string args) {
Expand Down Expand Up @@ -1888,31 +1898,48 @@ void CKeybindManager::resizeWindow(std::string args) {
PWINDOW->setHidden(false);
}

void CKeybindManager::circleNext(std::string arg) {
std::optional<bool> getFloatStatus(CVarList args) {
if (args.contains("tile") || args.contains("tiled"))
return false;
if (args.contains("float") || args.contains("floating"))
return true;

if (g_pCompositor->m_pLastWindow.expired()) {
// if we have a clear focus, find the first window and get the next focusable.
if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) > 0) {
const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID());
return std::nullopt;
}

switchToWindow(PWINDOW);
}
bool argsIsPrevious(CVarList args) {
return args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l");
}

return;
void CKeybindManager::circleNext(std::string arg) {
if (g_pCompositor->m_pLastWindow.expired()) {
if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) <= 0)
return; // if we have a clear focus, find the first window and get the next focusable.

const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID());
switchToWindow(PWINDOW);
}

CVarList args{arg, 0, 's', true};
CVarList args{arg, 0, 's', true};
if (argsIsPrevious(arg))
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(arg)));
else
switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(arg)));
}

std::optional<bool> floatStatus = {};
if (args.contains("tile") || args.contains("tiled"))
floatStatus = false;
else if (args.contains("float") || args.contains("floating"))
floatStatus = true;
void CKeybindManager::circleNextVisible(std::string arg) {
if (g_pCompositor->m_pLastWindow.expired()) {
if (g_pCompositor->getWindowsOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID()) <= 0)
return; // if we have a clear focus, find the first window and get the next focusable.
const auto PWINDOW = g_pCompositor->getFirstWindowOnWorkspace(g_pCompositor->m_pLastMonitor->activeWorkspaceID());
switchToWindow(PWINDOW);
}

if (args.contains("prev") || args.contains("p") || args.contains("last") || args.contains("l"))
switchToWindow(g_pCompositor->getPrevWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus));
CVarList args{arg, 0, 's', true};
if (argsIsPrevious(args))
switchToWindow(g_pCompositor->getPrevVisibleWindow(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(args)));
else
switchToWindow(g_pCompositor->getNextWindowOnWorkspace(g_pCompositor->m_pLastWindow.lock(), true, floatStatus));
switchToWindow(g_pCompositor->getNextVisibleWindow(g_pCompositor->m_pLastWindow.lock(), true, getFloatStatus(args)));
}

void CKeybindManager::focusWindow(std::string regexp) {
Expand Down
1 change: 1 addition & 0 deletions src/managers/KeybindManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ class CKeybindManager {
static void moveWindow(std::string);
static void resizeWindow(std::string);
static void circleNext(std::string);
static void circleNextVisible(std::string);
static void focusWindow(std::string);
static void tagWindow(std::string);
static void setSubmap(std::string);
Expand Down
Loading