layout: rethonk layouts from the ground up (#12890)
Rewrites layouts to be much smaller, and deal with much less annoying BS. Improves the overall architecture, unifies handling of pseudotiling, and various other improvements.
This commit is contained in:
parent
51f8849e54
commit
723870337f
82 changed files with 8431 additions and 5527 deletions
|
|
@ -1,10 +1,13 @@
|
|||
#include "Workspace.hpp"
|
||||
#include "view/Group.hpp"
|
||||
#include "../Compositor.hpp"
|
||||
#include "../config/ConfigValue.hpp"
|
||||
#include "config/ConfigManager.hpp"
|
||||
#include "managers/animation/AnimationManager.hpp"
|
||||
#include "../managers/EventManager.hpp"
|
||||
#include "../managers/HookSystemManager.hpp"
|
||||
#include "../layout/space/Space.hpp"
|
||||
#include "../layout/supplementary/WorkspaceAlgoMatcher.hpp"
|
||||
|
||||
#include <hyprutils/animation/AnimatedVariable.hpp>
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
|
@ -41,6 +44,9 @@ void CWorkspace::init(PHLWORKSPACE self) {
|
|||
m_lastFocusedWindow.reset();
|
||||
});
|
||||
|
||||
m_space = Layout::CSpace::create(m_self.lock());
|
||||
m_space->setAlgorithmProvider(Layout::Supplementary::algoMatcher()->createAlgorithmForWorkspace(m_self.lock()));
|
||||
|
||||
m_inert = false;
|
||||
|
||||
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(self);
|
||||
|
|
@ -406,14 +412,19 @@ bool CWorkspace::isVisibleNotCovered() {
|
|||
|
||||
int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
|
||||
int no = 0;
|
||||
for (auto const& w : g_pCompositor->m_windows) {
|
||||
if (w->workspaceID() != m_id || !w->m_isMapped)
|
||||
|
||||
if (!m_space)
|
||||
return 0;
|
||||
|
||||
for (auto const& t : m_space->targets()) {
|
||||
if (!t)
|
||||
continue;
|
||||
if (onlyTiled.has_value() && w->m_isFloating == onlyTiled.value())
|
||||
|
||||
if (onlyTiled.has_value() && t->floating() == onlyTiled.value())
|
||||
continue;
|
||||
if (onlyPinned.has_value() && w->m_pinned != onlyPinned.value())
|
||||
if (onlyPinned.has_value() && (!t->window() || t->window()->m_pinned != onlyPinned.value()))
|
||||
continue;
|
||||
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
|
||||
if (onlyVisible.has_value() && (!t->window() || t->window()->isHidden() == onlyVisible.value()))
|
||||
continue;
|
||||
no++;
|
||||
}
|
||||
|
|
@ -423,16 +434,16 @@ int CWorkspace::getWindows(std::optional<bool> onlyTiled, std::optional<bool> on
|
|||
|
||||
int CWorkspace::getGroups(std::optional<bool> onlyTiled, std::optional<bool> onlyPinned, std::optional<bool> onlyVisible) {
|
||||
int no = 0;
|
||||
for (auto const& w : g_pCompositor->m_windows) {
|
||||
if (w->workspaceID() != m_id || !w->m_isMapped)
|
||||
for (auto const& g : Desktop::View::groups()) {
|
||||
const auto HEAD = g->head();
|
||||
|
||||
if (HEAD->workspaceID() != m_id || !HEAD->m_isMapped)
|
||||
continue;
|
||||
if (!w->m_groupData.head)
|
||||
if (onlyTiled.has_value() && HEAD->m_isFloating == onlyTiled.value())
|
||||
continue;
|
||||
if (onlyTiled.has_value() && w->m_isFloating == onlyTiled.value())
|
||||
if (onlyPinned.has_value() && HEAD->m_pinned != onlyPinned.value())
|
||||
continue;
|
||||
if (onlyPinned.has_value() && w->m_pinned != onlyPinned.value())
|
||||
continue;
|
||||
if (onlyVisible.has_value() && w->isHidden() == onlyVisible.value())
|
||||
if (onlyVisible.has_value() && g->current()->isHidden() == onlyVisible.value())
|
||||
continue;
|
||||
no++;
|
||||
}
|
||||
|
|
@ -514,13 +525,11 @@ void CWorkspace::rename(const std::string& name) {
|
|||
}
|
||||
|
||||
void CWorkspace::updateWindows() {
|
||||
m_hasFullscreenWindow = std::ranges::any_of(g_pCompositor->m_windows, [this](const auto& w) { return w->m_isMapped && w->m_workspace == m_self && w->isFullscreen(); });
|
||||
m_hasFullscreenWindow = std::ranges::any_of(m_space->targets(), [](const auto& t) { return t->fullscreenMode() != FSMODE_NONE; });
|
||||
|
||||
for (auto const& w : g_pCompositor->m_windows) {
|
||||
if (!w->m_isMapped || w->m_workspace != m_self)
|
||||
continue;
|
||||
|
||||
w->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
for (auto const& t : m_space->targets()) {
|
||||
if (t->window())
|
||||
t->window()->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@
|
|||
#include "../helpers/MiscFunctions.hpp"
|
||||
#include "../helpers/signal/Signal.hpp"
|
||||
|
||||
namespace Layout {
|
||||
class CSpace;
|
||||
};
|
||||
|
||||
enum eFullscreenMode : int8_t {
|
||||
FSMODE_NONE = 0,
|
||||
FSMODE_MAXIMIZED = 1 << 0,
|
||||
|
|
@ -20,7 +24,9 @@ class CWorkspace {
|
|||
CWorkspace(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true);
|
||||
~CWorkspace();
|
||||
|
||||
WP<CWorkspace> m_self;
|
||||
WP<CWorkspace> m_self;
|
||||
|
||||
SP<Layout::CSpace> m_space;
|
||||
|
||||
// Workspaces ID-based have IDs > 0
|
||||
// and workspaces name-based have IDs starting with -1337
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ CWindowHistoryTracker::CWindowHistoryTracker() {
|
|||
});
|
||||
|
||||
static auto P1 = g_pHookSystem->hookDynamic("activeWindow", [this](void* self, SCallbackInfo& info, std::any data) {
|
||||
auto window = std::any_cast<PHLWINDOW>(data);
|
||||
auto window = std::any_cast<Desktop::View::SWindowActiveEvent>(data).window;
|
||||
|
||||
track(window);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ bool CWindowRule::matches(PHLWINDOW w, bool allowEnvLookup) {
|
|||
return false;
|
||||
break;
|
||||
case RULE_PROP_GROUP:
|
||||
if (!engine->match(w->m_groupData.pNextWindow))
|
||||
if (!engine->match(!!w->m_group))
|
||||
return false;
|
||||
break;
|
||||
case RULE_PROP_MODAL:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
#include "../utils/SetUtils.hpp"
|
||||
#include "../../view/Window.hpp"
|
||||
#include "../../types/OverridableVar.hpp"
|
||||
#include "../../../managers/LayoutManager.hpp"
|
||||
#include "../../../managers/HookSystemManager.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
|
|
|||
|
|
@ -3,15 +3,19 @@
|
|||
#include "../../Compositor.hpp"
|
||||
#include "../../protocols/XDGShell.hpp"
|
||||
#include "../../render/Renderer.hpp"
|
||||
#include "../../managers/LayoutManager.hpp"
|
||||
#include "../../managers/EventManager.hpp"
|
||||
#include "../../managers/HookSystemManager.hpp"
|
||||
#include "../../managers/input/InputManager.hpp"
|
||||
#include "../../managers/SeatManager.hpp"
|
||||
#include "../../xwayland/XSurface.hpp"
|
||||
#include "../../protocols/PointerConstraints.hpp"
|
||||
#include "managers/animation/DesktopAnimationManager.hpp"
|
||||
#include "../../layout/LayoutManager.hpp"
|
||||
|
||||
using namespace Desktop;
|
||||
|
||||
#define COMMA ,
|
||||
|
||||
SP<CFocusState> Desktop::focusState() {
|
||||
static SP<CFocusState> state = makeShared<CFocusState>();
|
||||
return state;
|
||||
|
|
@ -63,7 +67,7 @@ static SFullscreenWorkspaceFocusResult onFullscreenWorkspaceFocusWindow(PHLWINDO
|
|||
return {};
|
||||
}
|
||||
|
||||
void CFocusState::fullWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surface, bool forceFSCycle) {
|
||||
void CFocusState::fullWindowFocus(PHLWINDOW pWindow, eFocusReason reason, SP<CWLSurfaceResource> surface, bool forceFSCycle) {
|
||||
if (pWindow) {
|
||||
if (!pWindow->m_workspace)
|
||||
return;
|
||||
|
|
@ -83,10 +87,10 @@ void CFocusState::fullWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surf
|
|||
return;
|
||||
}
|
||||
|
||||
rawWindowFocus(pWindow, surface);
|
||||
rawWindowFocus(pWindow, reason, surface);
|
||||
}
|
||||
|
||||
void CFocusState::rawWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surface) {
|
||||
void CFocusState::rawWindowFocus(PHLWINDOW pWindow, eFocusReason reason, SP<CWLSurfaceResource> surface) {
|
||||
static auto PFOLLOWMOUSE = CConfigValue<Hyprlang::INT>("input:follow_mouse");
|
||||
static auto PSPECIALFALLTHROUGH = CConfigValue<Hyprlang::INT>("input:special_fallthrough");
|
||||
|
||||
|
|
@ -105,7 +109,9 @@ void CFocusState::rawWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surfa
|
|||
if (pWindow && pWindow->m_isX11 && pWindow->isX11OverrideRedirect() && !pWindow->m_xwaylandSurface->wantsFocus())
|
||||
return;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->bringWindowToTop(pWindow);
|
||||
// m_target on purpose, this avoids the group
|
||||
if (pWindow)
|
||||
g_layoutManager->bringTargetToTop(pWindow->m_target);
|
||||
|
||||
if (!pWindow || !validMapped(pWindow)) {
|
||||
|
||||
|
|
@ -127,9 +133,7 @@ void CFocusState::rawWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surfa
|
|||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""});
|
||||
|
||||
EMIT_HOOK_EVENT("activeWindow", PHLWINDOW{nullptr});
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(nullptr);
|
||||
EMIT_HOOK_EVENT("activeWindow", Desktop::View::SWindowActiveEvent{nullptr COMMA reason});
|
||||
|
||||
m_focusSurface.reset();
|
||||
|
||||
|
|
@ -196,16 +200,14 @@ void CFocusState::rawWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surfa
|
|||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = pWindow->m_class + "," + pWindow->m_title});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(pWindow.get()))});
|
||||
|
||||
EMIT_HOOK_EVENT("activeWindow", pWindow);
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowFocusChange(pWindow);
|
||||
EMIT_HOOK_EVENT("activeWindow", Desktop::View::SWindowActiveEvent{pWindow COMMA reason});
|
||||
|
||||
g_pInputManager->recheckIdleInhibitorStatus();
|
||||
|
||||
if (*PFOLLOWMOUSE == 0)
|
||||
g_pInputManager->sendMotionEventsToFocused();
|
||||
|
||||
if (pWindow->m_groupData.pNextWindow)
|
||||
if (pWindow->m_group)
|
||||
pWindow->deactivateGroupMembers();
|
||||
}
|
||||
|
||||
|
|
@ -296,3 +298,7 @@ void CFocusState::resetWindowFocus() {
|
|||
m_focusWindow.reset();
|
||||
m_focusSurface.reset();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,19 @@
|
|||
class CWLSurfaceResource;
|
||||
|
||||
namespace Desktop {
|
||||
enum eFocusReason : uint8_t {
|
||||
FOCUS_REASON_UNKNOWN = 0,
|
||||
FOCUS_REASON_FFM,
|
||||
FOCUS_REASON_KEYBIND,
|
||||
FOCUS_REASON_CLICK,
|
||||
FOCUS_REASON_OTHER,
|
||||
FOCUS_REASON_DESKTOP_STATE_CHANGE,
|
||||
FOCUS_REASON_NEW_WINDOW,
|
||||
FOCUS_REASON_GHOSTS,
|
||||
};
|
||||
|
||||
bool isHardInputFocusReason(eFocusReason r);
|
||||
|
||||
class CFocusState {
|
||||
public:
|
||||
CFocusState();
|
||||
|
|
@ -15,8 +28,8 @@ namespace Desktop {
|
|||
CFocusState(CFocusState&) = delete;
|
||||
CFocusState(const CFocusState&) = delete;
|
||||
|
||||
void fullWindowFocus(PHLWINDOW w, SP<CWLSurfaceResource> surface = nullptr, bool forceFSCycle = false);
|
||||
void rawWindowFocus(PHLWINDOW w, SP<CWLSurfaceResource> surface = nullptr);
|
||||
void fullWindowFocus(PHLWINDOW w, eFocusReason reason, SP<CWLSurfaceResource> surface = nullptr, bool forceFSCycle = false);
|
||||
void rawWindowFocus(PHLWINDOW w, eFocusReason reason, SP<CWLSurfaceResource> surface = nullptr);
|
||||
void rawSurfaceFocus(SP<CWLSurfaceResource> s, PHLWINDOW pWindowOwner = nullptr);
|
||||
void rawMonitorFocus(PHLMONITOR m);
|
||||
|
||||
|
|
|
|||
337
src/desktop/view/Group.cpp
Normal file
337
src/desktop/view/Group.cpp
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
#include "Group.hpp"
|
||||
#include "Window.hpp"
|
||||
|
||||
#include "../../render/decorations/CHyprGroupBarDecoration.hpp"
|
||||
#include "../../layout/target/WindowGroupTarget.hpp"
|
||||
#include "../../layout/target/WindowTarget.hpp"
|
||||
#include "../../layout/target/Target.hpp"
|
||||
#include "../../layout/space/Space.hpp"
|
||||
#include "../../layout/LayoutManager.hpp"
|
||||
#include "../../desktop/state/FocusState.hpp"
|
||||
#include "../../Compositor.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Desktop;
|
||||
using namespace Desktop::View;
|
||||
|
||||
std::vector<WP<CGroup>>& View::groups() {
|
||||
static std::vector<WP<CGroup>> g;
|
||||
return g;
|
||||
}
|
||||
|
||||
SP<CGroup> CGroup::create(std::vector<PHLWINDOWREF>&& windows) {
|
||||
auto x = SP<CGroup>(new CGroup(std::move(windows)));
|
||||
x->m_self = x;
|
||||
x->m_target = Layout::CWindowGroupTarget::create(x);
|
||||
groups().emplace_back(x);
|
||||
|
||||
x->init();
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
CGroup::CGroup(std::vector<PHLWINDOWREF>&& windows) : m_windows(std::move(windows)) {
|
||||
;
|
||||
}
|
||||
|
||||
void CGroup::init() {
|
||||
// for proper group logic:
|
||||
// - add all windows to us
|
||||
// - replace the first window with our target
|
||||
// - remove all window targets from layout
|
||||
// - apply updates
|
||||
|
||||
// FIXME: what if some windows are grouped? For now we only do 1-window but YNK
|
||||
for (const auto& w : m_windows) {
|
||||
RASSERT(!w->m_group, "CGroup: windows cannot contain grouped in init, this will explode");
|
||||
w->m_group = m_self.lock();
|
||||
}
|
||||
|
||||
g_layoutManager->switchTargets(m_windows.at(0)->m_target, m_target);
|
||||
|
||||
for (const auto& w : m_windows) {
|
||||
w->m_target->setSpaceGhost(m_target->space());
|
||||
}
|
||||
|
||||
for (const auto& w : m_windows) {
|
||||
applyWindowDecosAndUpdates(w.lock());
|
||||
}
|
||||
|
||||
updateWindowVisibility();
|
||||
}
|
||||
|
||||
void CGroup::destroy() {
|
||||
while (true) {
|
||||
if (m_windows.size() == 1) {
|
||||
remove(m_windows.at(0).lock());
|
||||
break;
|
||||
}
|
||||
|
||||
remove(m_windows.at(0).lock());
|
||||
}
|
||||
}
|
||||
|
||||
CGroup::~CGroup() {
|
||||
if (m_target->space())
|
||||
m_target->assignToSpace(nullptr);
|
||||
std::erase_if(groups(), [this](const auto& e) { return !e || e == m_self; });
|
||||
}
|
||||
|
||||
bool CGroup::has(PHLWINDOW w) const {
|
||||
return std::ranges::contains(m_windows, w);
|
||||
}
|
||||
|
||||
void CGroup::add(PHLWINDOW w) {
|
||||
static auto INSERT_AFTER_CURRENT = CConfigValue<Hyprlang::INT>("group:insert_after_current");
|
||||
|
||||
if (w->m_group) {
|
||||
if (w->m_group == m_self)
|
||||
return;
|
||||
|
||||
const auto WINDOWS = w->m_group->windows();
|
||||
for (const auto& w : WINDOWS) {
|
||||
w->m_group->remove(w.lock());
|
||||
add(w.lock());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (w->layoutTarget()->space()) {
|
||||
// remove the target from a space if it is in one
|
||||
g_layoutManager->removeTarget(w->layoutTarget());
|
||||
}
|
||||
|
||||
w->m_group = m_self.lock();
|
||||
w->m_target->setSpaceGhost(m_target->space());
|
||||
w->m_target->setFloating(m_target->floating());
|
||||
|
||||
if (*INSERT_AFTER_CURRENT) {
|
||||
m_windows.insert(m_windows.begin() + m_current + 1, w);
|
||||
m_current++;
|
||||
} else {
|
||||
m_windows.emplace_back(w);
|
||||
m_current = m_windows.size() - 1;
|
||||
}
|
||||
|
||||
applyWindowDecosAndUpdates(w);
|
||||
updateWindowVisibility();
|
||||
m_target->recalc();
|
||||
}
|
||||
|
||||
void CGroup::remove(PHLWINDOW w) {
|
||||
std::optional<size_t> idx;
|
||||
for (size_t i = 0; i < m_windows.size(); ++i) {
|
||||
if (m_windows.at(i) == w) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!idx)
|
||||
return;
|
||||
|
||||
if ((m_current >= *idx && idx != 0) || (m_current >= m_windows.size() - 1 && m_current > 0))
|
||||
m_current--;
|
||||
|
||||
auto g = m_self.lock(); // keep ref to avoid uaf after w->m_group.reset()
|
||||
|
||||
w->m_group.reset();
|
||||
removeWindowDecos(w);
|
||||
|
||||
w->setHidden(false);
|
||||
|
||||
const bool REMOVING_GROUP = m_windows.size() <= 1;
|
||||
|
||||
if (REMOVING_GROUP) {
|
||||
w->m_target->assignToSpace(nullptr);
|
||||
g_layoutManager->switchTargets(m_target, w->m_target);
|
||||
}
|
||||
|
||||
// we do it after the above because switchTargets expects this to be a valid group
|
||||
m_windows.erase(m_windows.begin() + *idx);
|
||||
|
||||
if (!m_windows.empty())
|
||||
updateWindowVisibility();
|
||||
|
||||
// do this here: otherwise the new current is hidden and workspace rules get wrong data
|
||||
if (!REMOVING_GROUP)
|
||||
w->m_target->assignToSpace(m_target->space());
|
||||
}
|
||||
|
||||
void CGroup::moveCurrent(bool next) {
|
||||
size_t idx = m_current;
|
||||
|
||||
if (next) {
|
||||
idx++;
|
||||
if (idx >= m_windows.size())
|
||||
idx = 0;
|
||||
} else {
|
||||
if (idx == 0)
|
||||
idx = m_windows.size() - 1;
|
||||
else
|
||||
idx--;
|
||||
}
|
||||
|
||||
setCurrent(idx);
|
||||
}
|
||||
|
||||
void CGroup::setCurrent(size_t idx) {
|
||||
if (idx == m_current)
|
||||
return;
|
||||
|
||||
const auto FS_STATE = m_target->fullscreenMode();
|
||||
const auto WASFOCUS = Desktop::focusState()->window() == current();
|
||||
auto oldWindow = m_windows.at(m_current).lock();
|
||||
|
||||
if (FS_STATE != FSMODE_NONE)
|
||||
g_pCompositor->setWindowFullscreenInternal(oldWindow, FSMODE_NONE);
|
||||
|
||||
m_current = std::clamp(idx, sc<size_t>(0), m_windows.size() - 1);
|
||||
updateWindowVisibility();
|
||||
|
||||
auto newWindow = m_windows.at(m_current).lock();
|
||||
|
||||
if (FS_STATE != FSMODE_NONE) {
|
||||
g_pCompositor->setWindowFullscreenInternal(newWindow, FS_STATE);
|
||||
newWindow->m_target->warpPositionSize();
|
||||
oldWindow->m_target->setPositionGlobal(newWindow->m_target->position()); // TODO: this is a hack and sucks
|
||||
}
|
||||
|
||||
if (WASFOCUS)
|
||||
Desktop::focusState()->rawWindowFocus(current(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
|
||||
}
|
||||
|
||||
void CGroup::setCurrent(PHLWINDOW w) {
|
||||
if (w == current())
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < m_windows.size(); ++i) {
|
||||
if (m_windows.at(i) == w) {
|
||||
setCurrent(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t CGroup::getCurrentIdx() const {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
PHLWINDOW CGroup::head() const {
|
||||
return m_windows.front().lock();
|
||||
}
|
||||
|
||||
PHLWINDOW CGroup::tail() const {
|
||||
return m_windows.back().lock();
|
||||
}
|
||||
|
||||
PHLWINDOW CGroup::current() const {
|
||||
return m_windows.at(m_current).lock();
|
||||
}
|
||||
|
||||
PHLWINDOW CGroup::next() const {
|
||||
return (m_current >= m_windows.size() - 1 ? m_windows.front() : m_windows.at(m_current + 1)).lock();
|
||||
}
|
||||
|
||||
PHLWINDOW CGroup::fromIndex(size_t idx) const {
|
||||
if (idx >= m_windows.size())
|
||||
return nullptr;
|
||||
|
||||
return m_windows.at(idx).lock();
|
||||
}
|
||||
|
||||
const std::vector<PHLWINDOWREF>& CGroup::windows() const {
|
||||
return m_windows;
|
||||
}
|
||||
|
||||
void CGroup::applyWindowDecosAndUpdates(PHLWINDOW x) {
|
||||
x->addWindowDeco(makeUnique<CHyprGroupBarDecoration>(x));
|
||||
|
||||
x->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
x->updateWindowDecos();
|
||||
x->updateDecorationValues();
|
||||
}
|
||||
|
||||
void CGroup::removeWindowDecos(PHLWINDOW x) {
|
||||
x->removeWindowDeco(x->getDecorationByType(DECORATION_GROUPBAR));
|
||||
|
||||
x->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
x->updateWindowDecos();
|
||||
x->updateDecorationValues();
|
||||
}
|
||||
|
||||
void CGroup::updateWindowVisibility() {
|
||||
for (size_t i = 0; i < m_windows.size(); ++i) {
|
||||
if (i == m_current) {
|
||||
auto& x = m_windows.at(i);
|
||||
x->setHidden(false);
|
||||
x->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
x->updateWindowDecos();
|
||||
x->updateDecorationValues();
|
||||
} else
|
||||
m_windows.at(i)->setHidden(true);
|
||||
}
|
||||
|
||||
m_target->recalc();
|
||||
|
||||
m_target->damageEntire();
|
||||
}
|
||||
|
||||
size_t CGroup::size() const {
|
||||
return m_windows.size();
|
||||
}
|
||||
|
||||
bool CGroup::locked() const {
|
||||
return m_locked;
|
||||
}
|
||||
|
||||
void CGroup::setLocked(bool x) {
|
||||
m_locked = x;
|
||||
}
|
||||
|
||||
bool CGroup::denied() const {
|
||||
return m_deny;
|
||||
}
|
||||
|
||||
void CGroup::setDenied(bool x) {
|
||||
m_deny = x;
|
||||
}
|
||||
|
||||
void CGroup::updateWorkspace(PHLWORKSPACE ws) {
|
||||
if (!ws)
|
||||
return;
|
||||
|
||||
for (const auto& w : windows()) {
|
||||
w->m_monitor = ws->m_monitor;
|
||||
w->moveToWorkspace(ws);
|
||||
w->updateToplevel();
|
||||
w->updateWindowDecos();
|
||||
w->m_target->setSpaceGhost(ws->m_space);
|
||||
}
|
||||
}
|
||||
|
||||
void CGroup::swapWithNext() {
|
||||
const bool HAD_FOCUS = Desktop::focusState()->window() == m_windows.at(m_current);
|
||||
|
||||
size_t idx = m_current + 1 >= m_windows.size() ? 0 : m_current + 1;
|
||||
std::iter_swap(m_windows.begin() + m_current, m_windows.begin() + idx);
|
||||
|
||||
updateWindowVisibility();
|
||||
|
||||
if (HAD_FOCUS)
|
||||
Desktop::focusState()->fullWindowFocus(m_windows.at(m_current).lock(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
|
||||
}
|
||||
|
||||
void CGroup::swapWithLast() {
|
||||
const bool HAD_FOCUS = Desktop::focusState()->window() == m_windows.at(m_current);
|
||||
|
||||
size_t idx = m_current == 0 ? m_windows.size() - 1 : m_current - 1;
|
||||
std::iter_swap(m_windows.begin() + m_current, m_windows.begin() + idx);
|
||||
|
||||
updateWindowVisibility();
|
||||
|
||||
if (HAD_FOCUS)
|
||||
Desktop::focusState()->fullWindowFocus(m_windows.at(m_current).lock(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
|
||||
}
|
||||
68
src/desktop/view/Group.hpp
Normal file
68
src/desktop/view/Group.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#pragma once
|
||||
|
||||
#include "../DesktopTypes.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Layout {
|
||||
class CWindowGroupTarget;
|
||||
};
|
||||
|
||||
namespace Desktop::View {
|
||||
class CGroup {
|
||||
public:
|
||||
static SP<CGroup> create(std::vector<PHLWINDOWREF>&& windows);
|
||||
~CGroup();
|
||||
|
||||
bool has(PHLWINDOW w) const;
|
||||
|
||||
void add(PHLWINDOW w);
|
||||
void remove(PHLWINDOW w);
|
||||
void moveCurrent(bool next);
|
||||
void setCurrent(size_t idx);
|
||||
void setCurrent(PHLWINDOW w);
|
||||
size_t getCurrentIdx() const;
|
||||
size_t size() const;
|
||||
void destroy();
|
||||
void updateWorkspace(PHLWORKSPACE);
|
||||
|
||||
void swapWithNext();
|
||||
void swapWithLast();
|
||||
|
||||
PHLWINDOW head() const;
|
||||
PHLWINDOW tail() const;
|
||||
PHLWINDOW current() const;
|
||||
PHLWINDOW next() const;
|
||||
|
||||
PHLWINDOW fromIndex(size_t idx) const;
|
||||
|
||||
bool locked() const;
|
||||
void setLocked(bool x);
|
||||
|
||||
bool denied() const;
|
||||
void setDenied(bool x);
|
||||
|
||||
const std::vector<PHLWINDOWREF>& windows() const;
|
||||
|
||||
SP<Layout::CWindowGroupTarget> m_target;
|
||||
|
||||
private:
|
||||
CGroup(std::vector<PHLWINDOWREF>&& windows);
|
||||
|
||||
void applyWindowDecosAndUpdates(PHLWINDOW x);
|
||||
void removeWindowDecos(PHLWINDOW x);
|
||||
void init();
|
||||
void updateWindowVisibility();
|
||||
|
||||
WP<CGroup> m_self;
|
||||
|
||||
std::vector<PHLWINDOWREF> m_windows;
|
||||
|
||||
bool m_locked = false;
|
||||
bool m_deny = false;
|
||||
|
||||
size_t m_current = 0;
|
||||
};
|
||||
|
||||
std::vector<WP<CGroup>>& groups();
|
||||
};
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
#include <hyprutils/animation/AnimatedVariable.hpp>
|
||||
#include <re2/re2.h>
|
||||
|
||||
#include "Group.hpp"
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
|
@ -37,12 +39,15 @@
|
|||
#include "../../helpers/math/Expression.hpp"
|
||||
#include "../../managers/XWaylandManager.hpp"
|
||||
#include "../../render/Renderer.hpp"
|
||||
#include "../../managers/LayoutManager.hpp"
|
||||
#include "../../managers/HookSystemManager.hpp"
|
||||
#include "../../managers/EventManager.hpp"
|
||||
#include "../../managers/input/InputManager.hpp"
|
||||
#include "../../managers/PointerManager.hpp"
|
||||
#include "../../managers/animation/DesktopAnimationManager.hpp"
|
||||
#include "../../layout/space/Space.hpp"
|
||||
#include "../../layout/LayoutManager.hpp"
|
||||
#include "../../layout/target/WindowTarget.hpp"
|
||||
#include "../../layout/target/WindowGroupTarget.hpp"
|
||||
|
||||
#include <hyprutils/string/String.hpp>
|
||||
|
||||
|
|
@ -57,6 +62,9 @@ using namespace Desktop::View;
|
|||
static uint64_t windowIDCounter = 0x18000000;
|
||||
|
||||
//
|
||||
#define COMMA ,
|
||||
//
|
||||
|
||||
PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
|
||||
PHLWINDOW pWindow = SP<CWindow>(new CWindow(surface));
|
||||
|
||||
|
|
@ -79,6 +87,8 @@ PHLWINDOW CWindow::create(SP<CXWaylandSurface> surface) {
|
|||
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
|
||||
|
||||
pWindow->m_target = Layout::CWindowTarget::create(pWindow);
|
||||
|
||||
return pWindow;
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +114,8 @@ PHLWINDOW CWindow::create(SP<CXDGSurfaceResource> resource) {
|
|||
pWindow->addWindowDeco(makeUnique<CHyprDropShadowDecoration>(pWindow));
|
||||
pWindow->addWindowDeco(makeUnique<CHyprBorderDecoration>(pWindow));
|
||||
|
||||
pWindow->m_target = Layout::CWindowTarget::create(pWindow);
|
||||
|
||||
pWindow->wlSurface()->assign(pWindow->m_xdgSurface->m_surface.lock(), pWindow);
|
||||
|
||||
return pWindow;
|
||||
|
|
@ -263,23 +275,24 @@ CBox CWindow::getWindowIdealBoundingBoxIgnoreReserved() {
|
|||
return CBox{sc<int>(POS.x), sc<int>(POS.y), sc<int>(SIZE.x), sc<int>(SIZE.y)};
|
||||
}
|
||||
|
||||
// get work area
|
||||
const auto WORKAREA = g_pLayoutManager->getCurrentLayout()->workAreaOnWorkspace(m_workspace);
|
||||
const auto RESERVED = CReservedArea{PMONITOR->logicalBox(), WORKAREA};
|
||||
// fucker fucking fuck
|
||||
const auto WORKAREA = m_workspace->m_space->workArea();
|
||||
const auto& RESERVED = PMONITOR->m_reservedArea;
|
||||
|
||||
if (DELTALESSTHAN(POS.y - PMONITOR->m_position.y, RESERVED.top(), 1)) {
|
||||
POS.y = PMONITOR->m_position.y;
|
||||
SIZE.y += RESERVED.top();
|
||||
}
|
||||
if (DELTALESSTHAN(POS.x - PMONITOR->m_position.x, RESERVED.left(), 1)) {
|
||||
POS.x = PMONITOR->m_position.x;
|
||||
if (DELTALESSTHAN(POS.x, WORKAREA.x, 1)) {
|
||||
POS.x -= RESERVED.left();
|
||||
SIZE.x += RESERVED.left();
|
||||
}
|
||||
|
||||
if (DELTALESSTHAN(POS.x + SIZE.x - PMONITOR->m_position.x, PMONITOR->m_size.x - RESERVED.right(), 1))
|
||||
if (DELTALESSTHAN(POS.y, WORKAREA.y, 1)) {
|
||||
POS.y -= RESERVED.top();
|
||||
SIZE.y += RESERVED.top();
|
||||
}
|
||||
|
||||
if (DELTALESSTHAN(POS.x + SIZE.x, WORKAREA.x + WORKAREA.width, 1))
|
||||
SIZE.x += RESERVED.right();
|
||||
|
||||
if (DELTALESSTHAN(POS.y + SIZE.y - PMONITOR->m_position.y, PMONITOR->m_size.y - RESERVED.bottom(), 1))
|
||||
if (DELTALESSTHAN(POS.y + SIZE.y, WORKAREA.y + WORKAREA.height, 1))
|
||||
SIZE.y += RESERVED.bottom();
|
||||
|
||||
return CBox{sc<int>(POS.x), sc<int>(POS.y), sc<int>(SIZE.x), sc<int>(SIZE.y)};
|
||||
|
|
@ -357,14 +370,18 @@ void CWindow::addWindowDeco(UP<IHyprWindowDecoration> deco) {
|
|||
m_windowDecorations.emplace_back(std::move(deco));
|
||||
g_pDecorationPositioner->forceRecalcFor(m_self.lock());
|
||||
updateWindowDecos();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_self.lock());
|
||||
|
||||
if (layoutTarget())
|
||||
layoutTarget()->recalc();
|
||||
}
|
||||
|
||||
void CWindow::removeWindowDeco(IHyprWindowDecoration* deco) {
|
||||
m_decosToRemove.push_back(deco);
|
||||
g_pDecorationPositioner->forceRecalcFor(m_self.lock());
|
||||
updateWindowDecos();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_self.lock());
|
||||
|
||||
if (layoutTarget())
|
||||
layoutTarget()->recalc();
|
||||
}
|
||||
|
||||
void CWindow::uncacheWindowDecos() {
|
||||
|
|
@ -495,11 +512,9 @@ void CWindow::moveToWorkspace(PHLWORKSPACE pWorkspace) {
|
|||
|
||||
OLDWORKSPACE->updateWindows();
|
||||
OLDWORKSPACE->updateWindowData();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(OLDWORKSPACE->monitorID());
|
||||
|
||||
pWorkspace->updateWindows();
|
||||
pWorkspace->updateWindowData();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
|
||||
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
|
|
@ -591,7 +606,7 @@ void CWindow::onUnmap() {
|
|||
m_workspace->updateWindows();
|
||||
m_workspace->updateWindowData();
|
||||
}
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
|
||||
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
m_workspace.reset();
|
||||
|
|
@ -723,311 +738,6 @@ bool CWindow::hasPopupAt(const Vector2D& pos) {
|
|||
return popup && popup->wlSurface()->resource();
|
||||
}
|
||||
|
||||
void CWindow::applyGroupRules() {
|
||||
if ((m_groupRules & GROUP_SET && m_firstMap) || m_groupRules & GROUP_SET_ALWAYS)
|
||||
createGroup();
|
||||
|
||||
if (m_groupData.pNextWindow.lock() && ((m_groupRules & GROUP_LOCK && m_firstMap) || m_groupRules & GROUP_LOCK_ALWAYS))
|
||||
getGroupHead()->m_groupData.locked = true;
|
||||
}
|
||||
|
||||
void CWindow::createGroup() {
|
||||
if (m_groupData.deny) {
|
||||
Log::logger->log(Log::DEBUG, "createGroup: window:{:x},title:{} is denied as a group, ignored", rc<uintptr_t>(this), this->m_title);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_groupData.pNextWindow.expired()) {
|
||||
m_groupData.pNextWindow = m_self;
|
||||
m_groupData.head = true;
|
||||
m_groupData.locked = false;
|
||||
m_groupData.deny = false;
|
||||
|
||||
addWindowDeco(makeUnique<CHyprGroupBarDecoration>(m_self.lock()));
|
||||
|
||||
if (m_workspace) {
|
||||
m_workspace->updateWindows();
|
||||
m_workspace->updateWindowData();
|
||||
}
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("1,{:x}", rc<uintptr_t>(this))});
|
||||
}
|
||||
|
||||
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
}
|
||||
|
||||
void CWindow::destroyGroup() {
|
||||
if (m_groupData.pNextWindow == m_self) {
|
||||
if (m_groupRules & GROUP_SET_ALWAYS) {
|
||||
Log::logger->log(Log::DEBUG, "destoryGroup: window:{:x},title:{} has rule [group set always], ignored", rc<uintptr_t>(this), this->m_title);
|
||||
return;
|
||||
}
|
||||
m_groupData.pNextWindow.reset();
|
||||
m_groupData.head = false;
|
||||
updateWindowDecos();
|
||||
if (m_workspace) {
|
||||
m_workspace->updateWindows();
|
||||
m_workspace->updateWindowData();
|
||||
}
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("0,{:x}", rc<uintptr_t>(this))});
|
||||
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string addresses;
|
||||
PHLWINDOW curr = m_self.lock();
|
||||
std::vector<PHLWINDOW> members;
|
||||
do {
|
||||
const auto PLASTWIN = curr;
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
PLASTWIN->m_groupData.pNextWindow.reset();
|
||||
curr->setHidden(false);
|
||||
members.push_back(curr);
|
||||
|
||||
addresses += std::format("{:x},", rc<uintptr_t>(curr.get()));
|
||||
} while (curr.get() != this);
|
||||
|
||||
for (auto const& w : members) {
|
||||
if (w->m_groupData.head)
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(curr);
|
||||
w->m_groupData.head = false;
|
||||
}
|
||||
|
||||
const bool GROUPSLOCKEDPREV = g_pKeybindManager->m_groupsLocked;
|
||||
g_pKeybindManager->m_groupsLocked = true;
|
||||
for (auto const& w : members) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(w);
|
||||
w->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
w->updateWindowDecos();
|
||||
}
|
||||
g_pKeybindManager->m_groupsLocked = GROUPSLOCKEDPREV;
|
||||
|
||||
if (m_workspace) {
|
||||
m_workspace->updateWindows();
|
||||
m_workspace->updateWindowData();
|
||||
}
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
if (!addresses.empty())
|
||||
addresses.pop_back();
|
||||
|
||||
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "togglegroup", .data = std::format("0,{}", addresses)});
|
||||
}
|
||||
|
||||
PHLWINDOW CWindow::getGroupHead() {
|
||||
PHLWINDOW curr = m_self.lock();
|
||||
while (!curr->m_groupData.head)
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
return curr;
|
||||
}
|
||||
|
||||
PHLWINDOW CWindow::getGroupTail() {
|
||||
PHLWINDOW curr = m_self.lock();
|
||||
while (!curr->m_groupData.pNextWindow->m_groupData.head)
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
return curr;
|
||||
}
|
||||
|
||||
PHLWINDOW CWindow::getGroupCurrent() {
|
||||
PHLWINDOW curr = m_self.lock();
|
||||
while (curr->isHidden())
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
return curr;
|
||||
}
|
||||
|
||||
int CWindow::getGroupSize() {
|
||||
int size = 1;
|
||||
PHLWINDOW curr = m_self.lock();
|
||||
while (curr->m_groupData.pNextWindow != m_self) {
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
size++;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
bool CWindow::canBeGroupedInto(PHLWINDOW pWindow) {
|
||||
static auto ALLOWGROUPMERGE = CConfigValue<Hyprlang::INT>("group:merge_groups_on_drag");
|
||||
bool isGroup = m_groupData.pNextWindow;
|
||||
bool disallowDragIntoGroup = g_pInputManager->m_wasDraggingWindow && isGroup && !sc<bool>(*ALLOWGROUPMERGE);
|
||||
return !g_pKeybindManager->m_groupsLocked // global group lock disengaged
|
||||
&& ((m_groupRules & GROUP_INVADE && m_firstMap) // window ignore local group locks, or
|
||||
|| (!pWindow->getGroupHead()->m_groupData.locked // target unlocked
|
||||
&& !(m_groupData.pNextWindow.lock() && getGroupHead()->m_groupData.locked))) // source unlocked or isn't group
|
||||
&& !m_groupData.deny // source is not denied entry
|
||||
&& !(m_groupRules & GROUP_BARRED && m_firstMap) // group rule doesn't prevent adding window
|
||||
&& !disallowDragIntoGroup; // config allows groups to be merged
|
||||
}
|
||||
|
||||
PHLWINDOW CWindow::getGroupWindowByIndex(int index) {
|
||||
const int SIZE = getGroupSize();
|
||||
index = ((index % SIZE) + SIZE) % SIZE;
|
||||
PHLWINDOW curr = getGroupHead();
|
||||
while (index > 0) {
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
index--;
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
|
||||
bool CWindow::hasInGroup(PHLWINDOW w) {
|
||||
PHLWINDOW curr = m_groupData.pNextWindow.lock();
|
||||
while (curr && curr != m_self) {
|
||||
if (curr == w)
|
||||
return true;
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CWindow::setGroupCurrent(PHLWINDOW pWindow) {
|
||||
PHLWINDOW curr = m_groupData.pNextWindow.lock();
|
||||
bool isMember = false;
|
||||
while (curr.get() != this) {
|
||||
if (curr == pWindow) {
|
||||
isMember = true;
|
||||
break;
|
||||
}
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
}
|
||||
|
||||
if (!isMember && pWindow.get() != this)
|
||||
return;
|
||||
|
||||
const auto PCURRENT = getGroupCurrent();
|
||||
const bool FULLSCREEN = PCURRENT->isFullscreen();
|
||||
const auto WORKSPACE = PCURRENT->m_workspace;
|
||||
const auto MODE = PCURRENT->m_fullscreenState.internal;
|
||||
|
||||
const auto CURRENTISFOCUS = PCURRENT == Desktop::focusState()->window();
|
||||
|
||||
const auto PWINDOWSIZE = PCURRENT->m_realSize->value();
|
||||
const auto PWINDOWPOS = PCURRENT->m_realPosition->value();
|
||||
const auto PWINDOWSIZEGOAL = PCURRENT->m_realSize->goal();
|
||||
const auto PWINDOWPOSGOAL = PCURRENT->m_realPosition->goal();
|
||||
const auto PWINDOWLASTFLOATINGSIZE = PCURRENT->m_lastFloatingSize;
|
||||
const auto PWINDOWLASTFLOATINGPOSITION = PCURRENT->m_lastFloatingPosition;
|
||||
|
||||
if (FULLSCREEN)
|
||||
g_pCompositor->setWindowFullscreenInternal(PCURRENT, FSMODE_NONE);
|
||||
|
||||
PCURRENT->setHidden(true);
|
||||
pWindow->setHidden(false); // can remove m_pLastWindow
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->replaceWindowDataWith(PCURRENT, pWindow);
|
||||
|
||||
if (PCURRENT->m_isFloating) {
|
||||
pWindow->m_realPosition->setValueAndWarp(PWINDOWPOSGOAL);
|
||||
pWindow->m_realSize->setValueAndWarp(PWINDOWSIZEGOAL);
|
||||
pWindow->sendWindowSize();
|
||||
}
|
||||
|
||||
pWindow->m_realPosition->setValue(PWINDOWPOS);
|
||||
pWindow->m_realSize->setValue(PWINDOWSIZE);
|
||||
|
||||
if (FULLSCREEN)
|
||||
g_pCompositor->setWindowFullscreenInternal(pWindow, MODE);
|
||||
|
||||
pWindow->m_lastFloatingSize = PWINDOWLASTFLOATINGSIZE;
|
||||
pWindow->m_lastFloatingPosition = PWINDOWLASTFLOATINGPOSITION;
|
||||
|
||||
g_pCompositor->updateAllWindowsAnimatedDecorationValues();
|
||||
|
||||
if (CURRENTISFOCUS)
|
||||
Desktop::focusState()->rawWindowFocus(pWindow);
|
||||
|
||||
g_pHyprRenderer->damageWindow(pWindow);
|
||||
|
||||
pWindow->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
pWindow->updateWindowDecos();
|
||||
}
|
||||
|
||||
void CWindow::insertWindowToGroup(PHLWINDOW pWindow) {
|
||||
const auto BEGINAT = m_self.lock();
|
||||
const auto ENDAT = m_groupData.pNextWindow.lock();
|
||||
|
||||
if (!pWindow->m_groupData.pNextWindow.lock()) {
|
||||
BEGINAT->m_groupData.pNextWindow = pWindow;
|
||||
pWindow->m_groupData.pNextWindow = ENDAT;
|
||||
pWindow->m_groupData.head = false;
|
||||
pWindow->addWindowDeco(makeUnique<CHyprGroupBarDecoration>(pWindow));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto SHEAD = pWindow->getGroupHead();
|
||||
const auto STAIL = pWindow->getGroupTail();
|
||||
|
||||
SHEAD->m_groupData.head = false;
|
||||
BEGINAT->m_groupData.pNextWindow = SHEAD;
|
||||
STAIL->m_groupData.pNextWindow = ENDAT;
|
||||
|
||||
pWindow->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
pWindow->updateWindowDecos();
|
||||
}
|
||||
|
||||
PHLWINDOW CWindow::getGroupPrevious() {
|
||||
PHLWINDOW curr = m_groupData.pNextWindow.lock();
|
||||
|
||||
while (curr != m_self && curr->m_groupData.pNextWindow != m_self)
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
void CWindow::switchWithWindowInGroup(PHLWINDOW pWindow) {
|
||||
if (!m_groupData.pNextWindow.lock() || !pWindow->m_groupData.pNextWindow.lock())
|
||||
return;
|
||||
|
||||
if (m_groupData.pNextWindow.lock() == pWindow) { // A -> this -> pWindow -> B >> A -> pWindow -> this -> B
|
||||
getGroupPrevious()->m_groupData.pNextWindow = pWindow;
|
||||
m_groupData.pNextWindow = pWindow->m_groupData.pNextWindow;
|
||||
pWindow->m_groupData.pNextWindow = m_self;
|
||||
|
||||
} else if (pWindow->m_groupData.pNextWindow == m_self) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
|
||||
pWindow->getGroupPrevious()->m_groupData.pNextWindow = m_self;
|
||||
pWindow->m_groupData.pNextWindow = m_groupData.pNextWindow;
|
||||
m_groupData.pNextWindow = pWindow;
|
||||
|
||||
} else { // A -> this -> B | C -> pWindow -> D >> A -> pWindow -> B | C -> this -> D
|
||||
std::swap(m_groupData.pNextWindow, pWindow->m_groupData.pNextWindow);
|
||||
std::swap(getGroupPrevious()->m_groupData.pNextWindow, pWindow->getGroupPrevious()->m_groupData.pNextWindow);
|
||||
}
|
||||
|
||||
std::swap(m_groupData.head, pWindow->m_groupData.head);
|
||||
std::swap(m_groupData.locked, pWindow->m_groupData.locked);
|
||||
|
||||
pWindow->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_GROUP | Desktop::Rule::RULE_PROP_ON_WORKSPACE);
|
||||
pWindow->updateWindowDecos();
|
||||
}
|
||||
|
||||
void CWindow::updateGroupOutputs() {
|
||||
if (m_groupData.pNextWindow.expired())
|
||||
return;
|
||||
|
||||
PHLWINDOW curr = m_groupData.pNextWindow.lock();
|
||||
|
||||
const auto WS = m_workspace;
|
||||
|
||||
while (curr.get() != this) {
|
||||
curr->m_monitor = m_monitor;
|
||||
curr->moveToWorkspace(WS);
|
||||
|
||||
*curr->m_realPosition = m_realPosition->goal();
|
||||
*curr->m_realSize = m_realSize->goal();
|
||||
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
}
|
||||
}
|
||||
|
||||
Vector2D CWindow::middle() {
|
||||
return m_realPosition->goal() + m_realSize->goal() / 2.f;
|
||||
}
|
||||
|
|
@ -1148,7 +858,7 @@ void CWindow::setAnimationsToMove() {
|
|||
|
||||
void CWindow::onWorkspaceAnimUpdate() {
|
||||
// clip box for animated offsets
|
||||
if (!m_isFloating || m_pinned || isFullscreen() || m_draggingTiled) {
|
||||
if (!m_isFloating || m_pinned || isFullscreen()) {
|
||||
m_floatingOffset = Vector2D(0, 0);
|
||||
return;
|
||||
}
|
||||
|
|
@ -1326,7 +1036,7 @@ void CWindow::activate(bool force) {
|
|||
if (m_isFloating)
|
||||
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
|
||||
|
||||
Desktop::focusState()->fullWindowFocus(m_self.lock());
|
||||
Desktop::focusState()->fullWindowFocus(m_self.lock(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
|
||||
warpCursor();
|
||||
}
|
||||
|
||||
|
|
@ -1378,7 +1088,8 @@ void CWindow::onUpdateMeta() {
|
|||
if (m_self == Desktop::focusState()->window()) { // if it's the active, let's post an event to update others
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = m_class + "," + m_title});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(this))});
|
||||
EMIT_HOOK_EVENT("activeWindow", m_self.lock());
|
||||
|
||||
// no need for a hook event
|
||||
}
|
||||
|
||||
Log::logger->log(Log::DEBUG, "Window {:x} set title to {}", rc<uintptr_t>(this), m_title);
|
||||
|
|
@ -1392,7 +1103,8 @@ void CWindow::onUpdateMeta() {
|
|||
if (m_self == Desktop::focusState()->window()) { // if it's the active, let's post an event to update others
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindow", .data = m_class + "," + m_title});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{.event = "activewindowv2", .data = std::format("{:x}", rc<uintptr_t>(this))});
|
||||
EMIT_HOOK_EVENT("activeWindow", m_self.lock());
|
||||
|
||||
// no need for a hook event
|
||||
}
|
||||
|
||||
Log::logger->log(Log::DEBUG, "Window {:x} set class to {}", rc<uintptr_t>(this), m_class);
|
||||
|
|
@ -1472,7 +1184,7 @@ void CWindow::onX11ConfigureRequest(CBox box) {
|
|||
|
||||
g_pHyprRenderer->damageWindow(m_self.lock());
|
||||
|
||||
if (!m_isFloating || isFullscreen() || g_pInputManager->m_currentlyDraggedWindow == m_self) {
|
||||
if (!m_isFloating || isFullscreen() || g_layoutManager->dragController()->target() == m_self) {
|
||||
sendWindowSize(true);
|
||||
g_pInputManager->refocus();
|
||||
g_pHyprRenderer->damageWindow(m_self.lock());
|
||||
|
|
@ -1689,20 +1401,17 @@ void CWindow::setContentType(NContentType::eContentType contentType) {
|
|||
}
|
||||
|
||||
void CWindow::deactivateGroupMembers() {
|
||||
auto curr = getGroupHead();
|
||||
while (curr) {
|
||||
if (curr != m_self.lock()) {
|
||||
if (!m_group)
|
||||
return;
|
||||
for (const auto& w : m_group->windows()) {
|
||||
if (w != m_self.lock()) {
|
||||
// we don't want to deactivate unfocused xwayland windows
|
||||
// because X is weird, keep the behavior for wayland windows
|
||||
// also its not really needed for xwayland windows
|
||||
// ref: #9760 #9294
|
||||
if (!curr->m_isX11 && curr->m_xdgSurface && curr->m_xdgSurface->m_toplevel)
|
||||
curr->m_xdgSurface->m_toplevel->setActive(false);
|
||||
if (!w->m_isX11 && w->m_xdgSurface && w->m_xdgSurface->m_toplevel)
|
||||
w->m_xdgSurface->m_toplevel->setActive(false);
|
||||
}
|
||||
|
||||
curr = curr->m_groupData.pNextWindow.lock();
|
||||
if (curr == getGroupHead())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1827,21 +1536,13 @@ void CWindow::updateDecorationValues() {
|
|||
|
||||
const bool IS_SHADOWED_BY_MODAL = m_xdgSurface && m_xdgSurface->m_toplevel && m_xdgSurface->m_toplevel->anyChildModal();
|
||||
|
||||
// border
|
||||
const auto RENDERDATA = g_pLayoutManager->getCurrentLayout()->requestRenderHints(m_self.lock());
|
||||
if (RENDERDATA.isBorderGradient)
|
||||
setBorderColor(*RENDERDATA.borderGradient);
|
||||
else {
|
||||
const bool GROUPLOCKED = m_groupData.pNextWindow.lock() ? getGroupHead()->m_groupData.locked : false;
|
||||
if (m_self == Desktop::focusState()->window()) {
|
||||
const auto* const ACTIVECOLOR =
|
||||
!m_groupData.pNextWindow.lock() ? (!m_groupData.deny ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
|
||||
setBorderColor(m_ruleApplicator->activeBorderColor().valueOr(*ACTIVECOLOR));
|
||||
} else {
|
||||
const auto* const INACTIVECOLOR =
|
||||
!m_groupData.pNextWindow.lock() ? (!m_groupData.deny ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
|
||||
setBorderColor(m_ruleApplicator->inactiveBorderColor().valueOr(*INACTIVECOLOR));
|
||||
}
|
||||
const bool GROUPLOCKED = m_group ? m_group->locked() : false;
|
||||
if (m_self == Desktop::focusState()->window()) {
|
||||
const auto* const ACTIVECOLOR = !m_group ? (!(m_groupRules & GROUP_DENY) ? ACTIVECOL : NOGROUPACTIVECOL) : (GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL);
|
||||
setBorderColor(m_ruleApplicator->activeBorderColor().valueOr(*ACTIVECOLOR));
|
||||
} else {
|
||||
const auto* const INACTIVECOLOR = !m_group ? (!(m_groupRules & GROUP_DENY) ? INACTIVECOL : NOGROUPINACTIVECOL) : (GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL);
|
||||
setBorderColor(m_ruleApplicator->inactiveBorderColor().valueOr(*INACTIVECOLOR));
|
||||
}
|
||||
|
||||
// opacity
|
||||
|
|
@ -1929,6 +1630,7 @@ void CWindow::mapWindow() {
|
|||
static auto PDIMSTRENGTH = CConfigValue<Hyprlang::FLOAT>("decoration:dim_strength");
|
||||
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:on_focus_under_fullscreen");
|
||||
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
|
||||
static auto PAUTOGROUP = CConfigValue<Hyprlang::INT>("group:auto_group");
|
||||
|
||||
const auto LAST_FOCUS_WINDOW = Desktop::focusState()->window();
|
||||
const bool IS_LAST_IN_FS = LAST_FOCUS_WINDOW ? LAST_FOCUS_WINDOW->m_fullscreenState.internal != FSMODE_NONE : false;
|
||||
|
|
@ -2053,8 +1755,8 @@ void CWindow::mapWindow() {
|
|||
requestedFSMonitor = MONITOR_INVALID;
|
||||
}
|
||||
|
||||
m_isFloating = m_ruleApplicator->static_.floating.value_or(m_isFloating);
|
||||
m_isPseudotiled = m_ruleApplicator->static_.pseudo.value_or(m_isPseudotiled);
|
||||
m_isFloating = m_ruleApplicator->static_.floating.value_or(m_isFloating);
|
||||
m_target->setPseudo(m_ruleApplicator->static_.pseudo.value_or(m_target->isPseudo()));
|
||||
m_noInitialFocus = m_ruleApplicator->static_.noInitialFocus.value_or(m_noInitialFocus);
|
||||
m_pinned = m_ruleApplicator->static_.pin.value_or(m_pinned);
|
||||
|
||||
|
|
@ -2109,7 +1811,7 @@ void CWindow::mapWindow() {
|
|||
} else if (v == "barred") {
|
||||
m_groupRules |= Desktop::View::GROUP_BARRED;
|
||||
} else if (v == "deny") {
|
||||
m_groupData.deny = true;
|
||||
m_groupRules |= Desktop::View::GROUP_DENY;
|
||||
} else if (v == "override") {
|
||||
// Clear existing rules
|
||||
m_groupRules = Desktop::View::GROUP_OVERRIDE;
|
||||
|
|
@ -2213,9 +1915,9 @@ void CWindow::mapWindow() {
|
|||
m_isFloating = true;
|
||||
|
||||
if (PWORKSPACE->m_defaultPseudo) {
|
||||
m_isPseudotiled = true;
|
||||
CBox desiredGeometry = g_pXWaylandManager->getGeometryForWindow(m_self.lock());
|
||||
m_pseudoSize = Vector2D(desiredGeometry.width, desiredGeometry.height);
|
||||
m_target->setPseudoSize(Vector2D{desiredGeometry.width, desiredGeometry.height});
|
||||
m_target->setPseudo(true);
|
||||
}
|
||||
|
||||
updateWindowData();
|
||||
|
|
@ -2230,43 +1932,29 @@ void CWindow::mapWindow() {
|
|||
g_pEventManager->postEvent(SHyprIPCEvent{"openwindow", std::format("{:x},{},{},{}", m_self.lock(), PWORKSPACE->m_name, m_class, m_title)});
|
||||
EMIT_HOOK_EVENT("openWindowEarly", m_self.lock());
|
||||
|
||||
if (*PAUTOGROUP // auto_group enabled
|
||||
&& Desktop::focusState()->window() // focused window exists
|
||||
&& canBeGroupedInto(Desktop::focusState()->window()->m_group) // we can group
|
||||
&& Desktop::focusState()->window()->m_workspace == m_workspace // workspaces match, we're not opening on another ws
|
||||
&& !isModal() && !(parent() && m_isFloating) && !isX11OverrideRedirect() // not a modal, floating child or X11 OR
|
||||
) {
|
||||
// add to group if we are focused on one
|
||||
Desktop::focusState()->window()->m_group->add(m_self.lock());
|
||||
} else
|
||||
g_layoutManager->newTarget(m_target, m_workspace->m_space);
|
||||
|
||||
if (!m_group && (m_groupRules & GROUP_SET))
|
||||
m_group = CGroup::create({m_self});
|
||||
|
||||
if (m_isFloating) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(m_self.lock());
|
||||
m_createdOverFullscreen = true;
|
||||
|
||||
if (!m_ruleApplicator->static_.size.empty()) {
|
||||
const auto COMPUTED = calculateExpression(m_ruleApplicator->static_.size);
|
||||
if (!COMPUTED)
|
||||
Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.size);
|
||||
else {
|
||||
*m_realSize = *COMPUTED;
|
||||
setHidden(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_ruleApplicator->static_.position.empty()) {
|
||||
const auto COMPUTED = calculateExpression(m_ruleApplicator->static_.position);
|
||||
if (!COMPUTED)
|
||||
Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.position);
|
||||
else {
|
||||
*m_realPosition = *COMPUTED + PMONITOR->m_position;
|
||||
setHidden(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ruleApplicator->static_.center.value_or(false)) {
|
||||
const auto WORKAREA = PMONITOR->logicalBoxMinusReserved();
|
||||
*m_realPosition = WORKAREA.middle() - m_realSize->goal() / 2.f;
|
||||
}
|
||||
|
||||
// set the pseudo size to the GOAL of our current size
|
||||
// because the windows are animated on RealSize
|
||||
m_pseudoSize = m_realSize->goal();
|
||||
m_target->setPseudoSize(m_realSize->goal());
|
||||
|
||||
g_pCompositor->changeWindowZOrder(m_self.lock(), true);
|
||||
} else {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(m_self.lock());
|
||||
|
||||
bool setPseudo = false;
|
||||
|
||||
if (!m_ruleApplicator->static_.size.empty()) {
|
||||
|
|
@ -2274,14 +1962,14 @@ void CWindow::mapWindow() {
|
|||
if (!COMPUTED)
|
||||
Log::logger->log(Log::ERR, "failed to parse {} as an expression", m_ruleApplicator->static_.size);
|
||||
else {
|
||||
setPseudo = true;
|
||||
m_pseudoSize = *COMPUTED;
|
||||
setPseudo = true;
|
||||
m_target->setPseudoSize(*COMPUTED);
|
||||
setHidden(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!setPseudo)
|
||||
m_pseudoSize = m_realSize->goal() - Vector2D(10, 10);
|
||||
m_target->setPseudoSize(m_realSize->goal() - Vector2D(10, 10));
|
||||
}
|
||||
|
||||
const auto PFOCUSEDWINDOWPREV = Desktop::focusState()->window();
|
||||
|
|
@ -2311,13 +1999,13 @@ void CWindow::mapWindow() {
|
|||
(!PFORCEFOCUS || PFORCEFOCUS == m_self.lock()) && !g_pInputManager->isConstrained()) {
|
||||
|
||||
// this window should gain focus: if it's grouped, preserve fullscreen state.
|
||||
const bool SAME_GROUP = hasInGroup(LAST_FOCUS_WINDOW);
|
||||
const bool SAME_GROUP = m_group && m_group->has(LAST_FOCUS_WINDOW);
|
||||
|
||||
if (IS_LAST_IN_FS && SAME_GROUP) {
|
||||
Desktop::focusState()->rawWindowFocus(m_self.lock());
|
||||
Desktop::focusState()->rawWindowFocus(m_self.lock(), FOCUS_REASON_NEW_WINDOW);
|
||||
g_pCompositor->setWindowFullscreenInternal(m_self.lock(), LAST_FS_MODE);
|
||||
} else
|
||||
Desktop::focusState()->fullWindowFocus(m_self.lock());
|
||||
Desktop::focusState()->fullWindowFocus(m_self.lock(), FOCUS_REASON_NEW_WINDOW);
|
||||
|
||||
m_activeInactiveAlpha->setValueAndWarp(*PACTIVEALPHA);
|
||||
m_dimPercent->setValueAndWarp(m_ruleApplicator->noDim().valueOrDefault() ? 0.f : *PDIMSTRENGTH);
|
||||
|
|
@ -2358,18 +2046,16 @@ void CWindow::mapWindow() {
|
|||
|
||||
if (workspaceSilent) {
|
||||
if (validMapped(PFOCUSEDWINDOWPREV)) {
|
||||
Desktop::focusState()->rawWindowFocus(PFOCUSEDWINDOWPREV);
|
||||
Desktop::focusState()->rawWindowFocus(PFOCUSEDWINDOWPREV, FOCUS_REASON_NEW_WINDOW);
|
||||
PFOCUSEDWINDOWPREV->updateWindowDecos(); // need to for some reason i cba to find out why
|
||||
} else if (!PFOCUSEDWINDOWPREV)
|
||||
Desktop::focusState()->rawWindowFocus(nullptr);
|
||||
Desktop::focusState()->rawWindowFocus(nullptr, FOCUS_REASON_NEW_WINDOW);
|
||||
}
|
||||
|
||||
// swallow
|
||||
if (SWALLOWER) {
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(SWALLOWER);
|
||||
g_pHyprRenderer->damageWindow(SWALLOWER);
|
||||
g_layoutManager->removeTarget(SWALLOWER->layoutTarget());
|
||||
SWALLOWER->setHidden(true);
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(monitorID());
|
||||
}
|
||||
|
||||
m_firstMap = false;
|
||||
|
|
@ -2382,7 +2068,7 @@ void CWindow::mapWindow() {
|
|||
// apply data from default decos. Borders, shadows.
|
||||
g_pDecorationPositioner->forceRecalcFor(m_self.lock());
|
||||
updateWindowDecos();
|
||||
g_pLayoutManager->getCurrentLayout()->recalculateWindow(m_self.lock());
|
||||
layoutTarget()->recalc();
|
||||
|
||||
// do animations
|
||||
g_pDesktopAnimationManager->startAnimation(m_self.lock(), CDesktopAnimationManager::ANIMATION_TYPE_IN);
|
||||
|
|
@ -2454,10 +2140,10 @@ void CWindow::unmapWindow() {
|
|||
m_swallowed->m_currentlySwallowed = false;
|
||||
m_swallowed->setHidden(false);
|
||||
|
||||
if (m_groupData.pNextWindow.lock())
|
||||
if (m_group)
|
||||
m_swallowed->m_groupSwallowed = true; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowCreated(m_swallowed.lock());
|
||||
g_layoutManager->newTarget(m_swallowed->layoutTarget(), m_workspace->m_space);
|
||||
}
|
||||
|
||||
m_swallowed->m_groupSwallowed = false;
|
||||
|
|
@ -2466,7 +2152,7 @@ void CWindow::unmapWindow() {
|
|||
|
||||
bool wasLastWindow = false;
|
||||
PHLWINDOW nextInGroup = [this] -> PHLWINDOW {
|
||||
if (!m_groupData.pNextWindow)
|
||||
if (!m_group)
|
||||
return nullptr;
|
||||
|
||||
// walk the history to find a suitable window
|
||||
|
|
@ -2475,7 +2161,7 @@ void CWindow::unmapWindow() {
|
|||
if (!w || !w->m_isMapped || w == m_self)
|
||||
continue;
|
||||
|
||||
if (!hasInGroup(w.lock()))
|
||||
if (!m_group->has(w.lock()))
|
||||
continue;
|
||||
|
||||
return w.lock();
|
||||
|
|
@ -2491,7 +2177,7 @@ void CWindow::unmapWindow() {
|
|||
g_pInputManager->releaseAllMouseButtons();
|
||||
}
|
||||
|
||||
if (m_self.lock() == g_pInputManager->m_currentlyDraggedWindow.lock())
|
||||
if (m_self.lock() == g_layoutManager->dragController()->target())
|
||||
CKeybindManager::changeMouseBindMode(MBIND_INVALID);
|
||||
|
||||
// remove the fullscreen window status from workspace if we closed it
|
||||
|
|
@ -2500,7 +2186,10 @@ void CWindow::unmapWindow() {
|
|||
if (PWORKSPACE->m_hasFullscreenWindow && isFullscreen())
|
||||
PWORKSPACE->m_hasFullscreenWindow = false;
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(m_self.lock());
|
||||
if (m_group)
|
||||
m_group->remove(m_self.lock());
|
||||
|
||||
g_layoutManager->removeTarget(m_target);
|
||||
|
||||
g_pHyprRenderer->damageWindow(m_self.lock());
|
||||
|
||||
|
|
@ -2516,17 +2205,20 @@ void CWindow::unmapWindow() {
|
|||
if (*FOCUSONCLOSE)
|
||||
candidate = (g_pCompositor->vectorToWindowUnified(g_pInputManager->getMouseCoordsInternal(),
|
||||
Desktop::View::RESERVED_EXTENTS | Desktop::View::INPUT_EXTENTS | Desktop::View::ALLOW_FLOATING));
|
||||
else
|
||||
candidate = g_pLayoutManager->getCurrentLayout()->getNextWindowCandidate(m_self.lock());
|
||||
else {
|
||||
const auto CAND = g_layoutManager->getNextCandidate(m_workspace->m_space, layoutTarget());
|
||||
if (CAND)
|
||||
candidate = CAND->window();
|
||||
}
|
||||
}
|
||||
|
||||
Log::logger->log(Log::DEBUG, "On closed window, new focused candidate is {}", candidate);
|
||||
|
||||
if (candidate != Desktop::focusState()->window() && candidate) {
|
||||
if (candidate == nextInGroup)
|
||||
Desktop::focusState()->rawWindowFocus(candidate);
|
||||
Desktop::focusState()->rawWindowFocus(candidate, FOCUS_REASON_DESKTOP_STATE_CHANGE);
|
||||
else
|
||||
Desktop::focusState()->fullWindowFocus(candidate);
|
||||
Desktop::focusState()->fullWindowFocus(candidate, FOCUS_REASON_DESKTOP_STATE_CHANGE);
|
||||
|
||||
if ((*PEXITRETAINSFS || candidate == nextInGroup) && CURRENTWINDOWFSSTATE)
|
||||
g_pCompositor->setWindowFullscreenInternal(candidate, CURRENTFSMODE);
|
||||
|
|
@ -2541,7 +2233,8 @@ void CWindow::unmapWindow() {
|
|||
if (m_self.lock() == Desktop::focusState()->window() || !Desktop::focusState()->window()) {
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindow", ","});
|
||||
g_pEventManager->postEvent(SHyprIPCEvent{"activewindowv2", ""});
|
||||
EMIT_HOOK_EVENT("activeWindow", PHLWINDOW{nullptr});
|
||||
|
||||
EMIT_HOOK_EVENT("activeWindow", Desktop::View::SWindowActiveEvent{nullptr COMMA FOCUS_REASON_OTHER});
|
||||
}
|
||||
} else {
|
||||
Log::logger->log(Log::DEBUG, "Unmapped was not focused, ignoring a refocus.");
|
||||
|
|
@ -2573,7 +2266,13 @@ void CWindow::commitWindow() {
|
|||
// try to calculate static rules already for any floats
|
||||
m_ruleApplicator->readStaticRules(true);
|
||||
|
||||
Vector2D predSize = g_pLayoutManager->getCurrentLayout()->predictSizeForNewWindow(m_self.lock());
|
||||
const Vector2D predSize = !m_ruleApplicator->static_.floating.value_or(false) // no float rule
|
||||
&& !m_isFloating // not floating
|
||||
&& !parent() // no parents
|
||||
&& !g_pXWaylandManager->shouldBeFloated(m_self.lock(), true) // should not be floated
|
||||
?
|
||||
g_layoutManager->predictSizeForNewTiledTarget().value_or(Vector2D{}) :
|
||||
Vector2D{};
|
||||
|
||||
Log::logger->log(Log::DEBUG, "Layout predicts size {} for {}", predSize, m_self.lock());
|
||||
|
||||
|
|
@ -2634,7 +2333,7 @@ void CWindow::destroyWindow() {
|
|||
|
||||
m_listeners = {};
|
||||
|
||||
g_pLayoutManager->getCurrentLayout()->onWindowRemoved(m_self.lock());
|
||||
g_layoutManager->removeTarget(m_target);
|
||||
|
||||
m_readyToDelete = true;
|
||||
|
||||
|
|
@ -2664,7 +2363,7 @@ void CWindow::activateX11() {
|
|||
if (!m_xwaylandSurface->wantsFocus())
|
||||
return;
|
||||
|
||||
Desktop::focusState()->fullWindowFocus(m_self.lock());
|
||||
Desktop::focusState()->fullWindowFocus(m_self.lock(), FOCUS_REASON_DESKTOP_STATE_CHANGE);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2764,3 +2463,26 @@ std::optional<Vector2D> CWindow::maxSize() {
|
|||
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
SP<Layout::ITarget> CWindow::layoutTarget() {
|
||||
return m_group ? m_group->m_target : m_target;
|
||||
}
|
||||
|
||||
bool CWindow::canBeGroupedInto(SP<CGroup> group) {
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
if (isX11OverrideRedirect())
|
||||
return false;
|
||||
|
||||
static auto ALLOWGROUPMERGE = CConfigValue<Hyprlang::INT>("group:merge_groups_on_drag");
|
||||
bool isGroup = m_group;
|
||||
bool disallowDragIntoGroup = g_layoutManager->dragController()->wasDraggingWindow() && isGroup && !sc<bool>(*ALLOWGROUPMERGE);
|
||||
return !g_pKeybindManager->m_groupsLocked // global group lock disengaged
|
||||
&& ((m_groupRules & GROUP_INVADE && m_firstMap) // window ignore local group locks, or
|
||||
|| (!group->locked() // target unlocked
|
||||
&& !(m_group && m_group->locked()))) // source unlocked or isn't group
|
||||
&& !(m_groupRules & GROUP_DENY) // source is not denied entry
|
||||
&& !(m_groupRules & GROUP_BARRED && m_firstMap) // group rule doesn't prevent adding window
|
||||
&& !disallowDragIntoGroup; // config allows groups to be merged
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,19 @@ struct SWorkspaceRule;
|
|||
|
||||
class IWindowTransformer;
|
||||
|
||||
namespace Layout {
|
||||
class ITarget;
|
||||
class CWindowTarget;
|
||||
}
|
||||
|
||||
namespace Desktop {
|
||||
enum eFocusReason : uint8_t;
|
||||
}
|
||||
|
||||
namespace Desktop::View {
|
||||
|
||||
class CGroup;
|
||||
|
||||
enum eGroupRules : uint8_t {
|
||||
// effective only during first map, except for _ALWAYS variant
|
||||
GROUP_NONE = 0,
|
||||
|
|
@ -38,6 +49,7 @@ namespace Desktop::View {
|
|||
GROUP_LOCK_ALWAYS = 1 << 4,
|
||||
GROUP_INVADE = 1 << 5, // Force enter a group, event if lock is engaged
|
||||
GROUP_OVERRIDE = 1 << 6, // Override other rules
|
||||
GROUP_DENY = 1 << 7, // deny
|
||||
};
|
||||
|
||||
enum eGetWindowProperties : uint8_t {
|
||||
|
|
@ -61,6 +73,11 @@ namespace Desktop::View {
|
|||
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
|
||||
};
|
||||
|
||||
struct SWindowActiveEvent {
|
||||
PHLWINDOW window = nullptr;
|
||||
eFocusReason reason = sc<eFocusReason>(0) /* unknown */;
|
||||
};
|
||||
|
||||
struct SInitialWorkspaceToken {
|
||||
PHLWINDOWREF primaryOwner;
|
||||
std::string workspace;
|
||||
|
|
@ -97,6 +114,8 @@ namespace Desktop::View {
|
|||
WP<CXDGSurfaceResource> m_xdgSurface;
|
||||
WP<CXWaylandSurface> m_xwaylandSurface;
|
||||
|
||||
SP<Layout::ITarget> m_target;
|
||||
|
||||
// this is the position and size of the "bounding box"
|
||||
Vector2D m_position = Vector2D(0, 0);
|
||||
Vector2D m_size = Vector2D(0, 0);
|
||||
|
|
@ -112,23 +131,14 @@ namespace Desktop::View {
|
|||
std::optional<std::pair<uint32_t, Vector2D>> m_pendingSizeAck;
|
||||
std::vector<std::pair<uint32_t, Vector2D>> m_pendingSizeAcks;
|
||||
|
||||
// for restoring floating statuses
|
||||
Vector2D m_lastFloatingSize;
|
||||
Vector2D m_lastFloatingPosition;
|
||||
|
||||
// for floating window offset in workspace animations
|
||||
Vector2D m_floatingOffset = Vector2D(0, 0);
|
||||
|
||||
// this is used for pseudotiling
|
||||
bool m_isPseudotiled = false;
|
||||
Vector2D m_pseudoSize = Vector2D(1280, 720);
|
||||
|
||||
// for recovering relative cursor position
|
||||
Vector2D m_relativeCursorCoordsOnLastWarp = Vector2D(-1, -1);
|
||||
|
||||
bool m_firstMap = false; // for layouts
|
||||
bool m_isFloating = false;
|
||||
bool m_draggingTiled = false; // for dragging around tiled windows
|
||||
SFullscreenState m_fullscreenState = {.internal = FSMODE_NONE, .client = FSMODE_NONE};
|
||||
std::string m_title = "";
|
||||
std::string m_class = "";
|
||||
|
|
@ -229,15 +239,10 @@ namespace Desktop::View {
|
|||
std::string m_initialWorkspaceToken = "";
|
||||
|
||||
// for groups
|
||||
struct SGroupData {
|
||||
PHLWINDOWREF pNextWindow; // nullptr means no grouping. Self means single group.
|
||||
bool head = false;
|
||||
bool locked = false; // per group lock
|
||||
bool deny = false; // deny window from enter a group or made a group
|
||||
} m_groupData;
|
||||
uint16_t m_groupRules = Desktop::View::GROUP_NONE;
|
||||
SP<CGroup> m_group;
|
||||
uint16_t m_groupRules = Desktop::View::GROUP_NONE;
|
||||
|
||||
bool m_tearingHint = false;
|
||||
bool m_tearingHint = false;
|
||||
|
||||
// Stable ID for ext_foreign_toplevel_list
|
||||
const uint64_t m_stableID = 0x2137;
|
||||
|
|
@ -303,21 +308,6 @@ namespace Desktop::View {
|
|||
bool isInCurvedCorner(double x, double y);
|
||||
bool hasPopupAt(const Vector2D& pos);
|
||||
int popupsCount();
|
||||
void applyGroupRules();
|
||||
void createGroup();
|
||||
void destroyGroup();
|
||||
PHLWINDOW getGroupHead();
|
||||
PHLWINDOW getGroupTail();
|
||||
PHLWINDOW getGroupCurrent();
|
||||
PHLWINDOW getGroupPrevious();
|
||||
PHLWINDOW getGroupWindowByIndex(int);
|
||||
bool hasInGroup(PHLWINDOW);
|
||||
int getGroupSize();
|
||||
bool canBeGroupedInto(PHLWINDOW pWindow);
|
||||
void setGroupCurrent(PHLWINDOW pWindow);
|
||||
void insertWindowToGroup(PHLWINDOW pWindow);
|
||||
void updateGroupOutputs();
|
||||
void switchWithWindowInGroup(PHLWINDOW pWindow);
|
||||
void setAnimationsToMove();
|
||||
void onWorkspaceAnimUpdate();
|
||||
void onFocusAnimUpdate();
|
||||
|
|
@ -350,6 +340,8 @@ namespace Desktop::View {
|
|||
std::optional<Vector2D> calculateExpression(const std::string& s);
|
||||
std::optional<Vector2D> minSize();
|
||||
std::optional<Vector2D> maxSize();
|
||||
SP<Layout::ITarget> layoutTarget();
|
||||
bool canBeGroupedInto(SP<CGroup> group);
|
||||
|
||||
CBox getWindowMainSurfaceBox() const {
|
||||
return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue