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:
Vaxry 2026-02-21 21:30:39 +00:00 committed by GitHub
parent 51f8849e54
commit 723870337f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 8431 additions and 5527 deletions

View file

@ -0,0 +1,146 @@
#include "Target.hpp"
#include "../space/Space.hpp"
#include "../../debug/log/Logger.hpp"
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Layout;
using namespace Hyprutils::Utils;
void ITarget::setPositionGlobal(const CBox& box) {
m_box = box;
m_box.round();
}
void ITarget::assignToSpace(const SP<CSpace>& space, std::optional<Vector2D> focalPoint) {
if (m_space == space && !m_ghostSpace)
return;
const bool HAD_SPACE = !!m_space;
if (m_space && !m_ghostSpace)
m_space->remove(m_self.lock());
m_space = space;
if (space && HAD_SPACE)
space->move(m_self.lock(), focalPoint);
else if (space)
space->add(m_self.lock());
if (!space)
Log::logger->log(Log::WARN, "ITarget: assignToSpace with a null space?");
m_ghostSpace = false;
onUpdateSpace();
}
void ITarget::setSpaceGhost(const SP<CSpace>& space) {
if (m_space)
assignToSpace(nullptr);
m_space = space;
m_ghostSpace = true;
}
SP<CSpace> ITarget::space() const {
return m_space;
}
PHLWORKSPACE ITarget::workspace() const {
if (!m_space)
return nullptr;
return m_space->workspace();
}
CBox ITarget::position() const {
return m_box;
}
void ITarget::rememberFloatingSize(const Vector2D& size) {
m_floatingSize = size;
}
Vector2D ITarget::lastFloatingSize() const {
return m_floatingSize;
}
void ITarget::recalc() {
setPositionGlobal(m_box);
}
void ITarget::setPseudo(bool x) {
if (m_pseudo == x)
return;
m_pseudo = x;
recalc();
}
bool ITarget::isPseudo() const {
return m_pseudo;
}
void ITarget::setPseudoSize(const Vector2D& size) {
m_pseudoSize = size;
recalc();
}
Vector2D ITarget::pseudoSize() {
return m_pseudoSize;
}
void ITarget::swap(SP<ITarget> b) {
const auto IS_FLOATING = floating();
const auto IS_FLOATING_B = b->floating();
// Keep workspaces alive during a swap: moving one window will unref the ws
// NOLINTNEXTLINE
const auto PWS1 = workspace();
// NOLINTNEXTLINE
const auto PWS2 = b->workspace();
CScopeGuard x([&] {
b->setFloating(IS_FLOATING);
setFloating(IS_FLOATING_B);
// update the spaces
b->onUpdateSpace();
onUpdateSpace();
});
if (b->space() == m_space) {
// simplest
m_space->swap(m_self.lock(), b);
m_space->recalculate();
return;
}
// spaces differ
if (m_space)
m_space->swap(m_self.lock(), b);
if (b->space())
b->space()->swap(b, m_self.lock());
std::swap(m_space, b->m_space);
// recalc both
if (m_space)
m_space->recalculate();
if (b->space())
b->space()->recalculate();
}
bool ITarget::wasTiling() const {
return m_wasTiling;
}
void ITarget::setWasTiling(bool x) {
m_wasTiling = x;
}

View file

@ -0,0 +1,79 @@
#pragma once
#include "../../helpers/math/Math.hpp"
#include "../../helpers/memory/Memory.hpp"
#include "../../desktop/Workspace.hpp"
#include <expected>
#include <cstdint>
namespace Layout {
enum eTargetType : uint8_t {
TARGET_TYPE_WINDOW = 0,
TARGET_TYPE_GROUP,
};
enum eGeometryFailure : uint8_t {
GEOMETRY_NO_DESIRED = 0,
GEOMETRY_INVALID_DESIRED = 1,
};
class CSpace;
struct SGeometryRequested {
Vector2D size;
std::optional<Vector2D> pos;
};
class ITarget {
public:
virtual ~ITarget() = default;
virtual eTargetType type() = 0;
// position is within its space
virtual void setPositionGlobal(const CBox& box);
virtual CBox position() const;
virtual void assignToSpace(const SP<CSpace>& space, std::optional<Vector2D> focalPoint = std::nullopt);
virtual void setSpaceGhost(const SP<CSpace>& space);
virtual SP<CSpace> space() const;
virtual PHLWORKSPACE workspace() const;
virtual PHLWINDOW window() const = 0;
virtual void recalc();
virtual bool wasTiling() const;
virtual void setWasTiling(bool x);
virtual void rememberFloatingSize(const Vector2D& size);
virtual Vector2D lastFloatingSize() const;
virtual void setPseudo(bool x);
virtual bool isPseudo() const;
virtual void setPseudoSize(const Vector2D& size);
virtual Vector2D pseudoSize();
virtual void swap(SP<ITarget> b);
//
virtual bool floating() = 0;
virtual void setFloating(bool x) = 0;
virtual std::expected<SGeometryRequested, eGeometryFailure> desiredGeometry() = 0;
virtual eFullscreenMode fullscreenMode() = 0;
virtual void setFullscreenMode(eFullscreenMode mode) = 0;
virtual std::optional<Vector2D> minSize() = 0;
virtual std::optional<Vector2D> maxSize() = 0;
virtual void damageEntire() = 0;
virtual void warpPositionSize() = 0;
virtual void onUpdateSpace() = 0;
protected:
ITarget() = default;
CBox m_box;
SP<CSpace> m_space;
WP<ITarget> m_self;
Vector2D m_floatingSize;
bool m_pseudo = false;
bool m_ghostSpace = false; // ghost space means a target belongs to a space, but isn't sent to the layout
Vector2D m_pseudoSize = {1280, 720};
bool m_wasTiling = false;
};
};

View file

@ -0,0 +1,92 @@
#include "WindowGroupTarget.hpp"
#include "../space/Space.hpp"
#include "../algorithm/Algorithm.hpp"
#include "WindowTarget.hpp"
#include "Target.hpp"
#include "../../render/Renderer.hpp"
using namespace Layout;
SP<CWindowGroupTarget> CWindowGroupTarget::create(SP<Desktop::View::CGroup> g) {
auto target = SP<CWindowGroupTarget>(new CWindowGroupTarget(g));
target->m_self = target;
return target;
}
CWindowGroupTarget::CWindowGroupTarget(SP<Desktop::View::CGroup> g) : m_group(g) {
;
}
eTargetType CWindowGroupTarget::type() {
return TARGET_TYPE_GROUP;
}
void CWindowGroupTarget::setPositionGlobal(const CBox& box) {
ITarget::setPositionGlobal(box);
updatePos();
}
void CWindowGroupTarget::updatePos() {
for (const auto& w : m_group->windows()) {
w->m_target->setPositionGlobal(m_box);
}
}
void CWindowGroupTarget::assignToSpace(const SP<CSpace>& space, std::optional<Vector2D> focalPoint) {
ITarget::assignToSpace(space, focalPoint);
m_group->updateWorkspace(space->workspace());
}
bool CWindowGroupTarget::floating() {
return m_group->current()->m_target->floating();
}
void CWindowGroupTarget::setFloating(bool x) {
for (const auto& w : m_group->windows()) {
w->m_target->setFloating(x);
}
}
std::expected<SGeometryRequested, eGeometryFailure> CWindowGroupTarget::desiredGeometry() {
return m_group->current()->m_target->desiredGeometry();
}
PHLWINDOW CWindowGroupTarget::window() const {
return m_group->current();
}
eFullscreenMode CWindowGroupTarget::fullscreenMode() {
return m_group->current()->m_fullscreenState.internal;
}
void CWindowGroupTarget::setFullscreenMode(eFullscreenMode mode) {
m_group->current()->m_fullscreenState.internal = mode;
}
std::optional<Vector2D> CWindowGroupTarget::minSize() {
return m_group->current()->minSize();
}
std::optional<Vector2D> CWindowGroupTarget::maxSize() {
return m_group->current()->maxSize();
}
void CWindowGroupTarget::damageEntire() {
g_pHyprRenderer->damageWindow(m_group->current());
}
void CWindowGroupTarget::warpPositionSize() {
for (const auto& w : m_group->windows()) {
w->m_target->warpPositionSize();
}
}
void CWindowGroupTarget::onUpdateSpace() {
for (const auto& w : m_group->windows()) {
w->m_target->onUpdateSpace();
}
}

View file

@ -0,0 +1,39 @@
#pragma once
#include "Target.hpp"
#include "../../desktop/view/Window.hpp"
#include "../../desktop/view/Group.hpp"
namespace Layout {
class CWindowGroupTarget : public ITarget {
public:
static SP<CWindowGroupTarget> create(SP<Desktop::View::CGroup> g);
virtual ~CWindowGroupTarget() = default;
virtual eTargetType type();
virtual void setPositionGlobal(const CBox& box);
virtual void assignToSpace(const SP<CSpace>& space, std::optional<Vector2D> focalPoint = std::nullopt);
virtual PHLWINDOW window() const;
virtual bool floating();
virtual void setFloating(bool x);
virtual std::expected<SGeometryRequested, eGeometryFailure> desiredGeometry();
virtual eFullscreenMode fullscreenMode();
virtual void setFullscreenMode(eFullscreenMode mode);
virtual std::optional<Vector2D> minSize();
virtual std::optional<Vector2D> maxSize();
virtual void damageEntire();
virtual void warpPositionSize();
virtual void onUpdateSpace();
private:
CWindowGroupTarget(SP<Desktop::View::CGroup> g);
void updatePos();
WP<Desktop::View::CGroup> m_group;
};
};

View file

@ -0,0 +1,363 @@
#include "WindowTarget.hpp"
#include "../space/Space.hpp"
#include "../algorithm/Algorithm.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../config/ConfigManager.hpp"
#include "../../helpers/Monitor.hpp"
#include "../../xwayland/XSurface.hpp"
#include "../../Compositor.hpp"
#include "../../render/Renderer.hpp"
using namespace Layout;
SP<ITarget> CWindowTarget::create(PHLWINDOW w) {
auto target = SP<CWindowTarget>(new CWindowTarget(w));
target->m_self = target;
return target;
}
CWindowTarget::CWindowTarget(PHLWINDOW w) : m_window(w) {
;
}
eTargetType CWindowTarget::type() {
return TARGET_TYPE_WINDOW;
}
void CWindowTarget::setPositionGlobal(const CBox& box) {
ITarget::setPositionGlobal(box);
updatePos();
}
void CWindowTarget::updatePos() {
if (!m_space)
return;
if (fullscreenMode() == FSMODE_FULLSCREEN)
return;
if (floating() && fullscreenMode() != FSMODE_MAXIMIZED) {
m_window->m_position = m_box.pos();
m_window->m_size = m_box.size();
*m_window->m_realPosition = m_box.pos();
*m_window->m_realSize = m_box.size();
m_window->sendWindowSize();
m_window->updateWindowDecos();
return;
}
// Tiled is more complicated.
const auto PMONITOR = m_space->workspace()->m_monitor;
const auto PWORKSPACE = m_space->workspace();
// for gaps outer
const auto MONITOR_WORKAREA = m_space->workArea();
const bool DISPLAYLEFT = STICKS(m_box.x, MONITOR_WORKAREA.x);
const bool DISPLAYRIGHT = STICKS(m_box.x + m_box.w, MONITOR_WORKAREA.x + MONITOR_WORKAREA.w);
const bool DISPLAYTOP = STICKS(m_box.y, MONITOR_WORKAREA.y);
const bool DISPLAYBOTTOM = STICKS(m_box.y + m_box.h, MONITOR_WORKAREA.y + MONITOR_WORKAREA.h);
// this is used for scrolling, so that the gaps are correct when a window is the full width and has neighbors
const bool DISPLAYINVERSELEFT = STICKS(m_box.x, MONITOR_WORKAREA.x + MONITOR_WORKAREA.w);
const bool DISPLAYINVERSERIGHT = STICKS(m_box.x + m_box.w, MONITOR_WORKAREA.x);
// get specific gaps and rules for this workspace,
// if user specified them in config
const auto WORKSPACERULE = g_pConfigManager->getWorkspaceRuleFor(PWORKSPACE);
if (!validMapped(m_window)) {
if (m_window)
g_layoutManager->removeTarget(m_window->layoutTarget());
return;
}
if (fullscreenMode() == FSMODE_FULLSCREEN)
return;
g_pHyprRenderer->damageWindow(window());
static auto PGAPSINDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_in");
auto* const PGAPSIN = sc<CCssGapData*>((PGAPSINDATA.ptr())->getData());
auto gapsIn = WORKSPACERULE.gapsIn.value_or(*PGAPSIN);
CBox nodeBox = m_box;
nodeBox.round();
m_window->m_size = nodeBox.size();
m_window->m_position = nodeBox.pos();
m_window->updateWindowDecos();
auto calcPos = m_window->m_position;
auto calcSize = m_window->m_size;
const static auto REQUESTEDRATIO = CConfigValue<Hyprlang::VEC2>("layout:single_window_aspect_ratio");
const static auto REQUESTEDRATIOTOLERANCE = CConfigValue<Hyprlang::FLOAT>("layout:single_window_aspect_ratio_tolerance");
Vector2D ratioPadding;
if ((*REQUESTEDRATIO).y != 0 && m_space->algorithm()->tiledTargets() <= 1) {
const Vector2D originalSize = MONITOR_WORKAREA.size();
const double requestedRatio = (*REQUESTEDRATIO).x / (*REQUESTEDRATIO).y;
const double originalRatio = originalSize.x / originalSize.y;
if (requestedRatio > originalRatio) {
double padding = originalSize.y - (originalSize.x / requestedRatio);
if (padding / 2 > (*REQUESTEDRATIOTOLERANCE) * originalSize.y)
ratioPadding = Vector2D{0., padding};
} else if (requestedRatio < originalRatio) {
double padding = originalSize.x - (originalSize.y * requestedRatio);
if (padding / 2 > (*REQUESTEDRATIOTOLERANCE) * originalSize.x)
ratioPadding = Vector2D{padding, 0.};
}
}
const auto GAPOFFSETTOPLEFT = Vector2D(sc<double>(DISPLAYLEFT ? 0 : (DISPLAYINVERSELEFT ? 2 * gapsIn.m_left : gapsIn.m_left)), sc<double>(DISPLAYTOP ? 0 : gapsIn.m_top));
const auto GAPOFFSETBOTTOMRIGHT =
Vector2D(sc<double>(DISPLAYRIGHT ? 0 : (DISPLAYINVERSERIGHT ? 2 * gapsIn.m_right : gapsIn.m_right)), sc<double>(DISPLAYBOTTOM ? 0 : gapsIn.m_bottom));
calcPos = calcPos + GAPOFFSETTOPLEFT + ratioPadding / 2;
calcSize = calcSize - GAPOFFSETTOPLEFT - GAPOFFSETBOTTOMRIGHT - ratioPadding;
if (isPseudo()) {
// Calculate pseudo
float scale = 1;
// adjust if doesn't fit
if (m_pseudoSize.x > calcSize.x || m_pseudoSize.y > calcSize.y) {
if (m_pseudoSize.x > calcSize.x)
scale = calcSize.x / m_pseudoSize.x;
if (m_pseudoSize.y * scale > calcSize.y)
scale = calcSize.y / m_pseudoSize.y;
auto DELTA = calcSize - m_pseudoSize * scale;
calcSize = m_pseudoSize * scale;
calcPos = calcPos + DELTA / 2.f; // center
} else {
auto DELTA = calcSize - m_pseudoSize;
calcPos = calcPos + DELTA / 2.f; // center
calcSize = m_pseudoSize;
}
}
const auto RESERVED = m_window->getFullWindowReservedArea();
calcPos = calcPos + RESERVED.topLeft;
calcSize = calcSize - (RESERVED.topLeft + RESERVED.bottomRight);
Vector2D availableSpace = calcSize;
static auto PCLAMP_TILED = CConfigValue<Hyprlang::INT>("misc:size_limits_tiled");
if (*PCLAMP_TILED) {
const auto borderSize = m_window->getRealBorderSize();
Vector2D monitorAvailable = MONITOR_WORKAREA.size() - Vector2D{2.0 * borderSize, 2.0 * borderSize};
Vector2D minSize = m_window->m_ruleApplicator->minSize().valueOr(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}).clamp(Vector2D{0, 0}, monitorAvailable);
Vector2D maxSize = m_window->isFullscreen() ? Vector2D{INFINITY, INFINITY} :
m_window->m_ruleApplicator->maxSize().valueOr(Vector2D{INFINITY, INFINITY}).clamp(Vector2D{0, 0}, monitorAvailable);
calcSize = calcSize.clamp(minSize, maxSize);
calcPos += (availableSpace - calcSize) / 2.0;
calcPos.x = std::clamp(calcPos.x, MONITOR_WORKAREA.x + borderSize, MONITOR_WORKAREA.x + MONITOR_WORKAREA.w - calcSize.x - borderSize);
calcPos.y = std::clamp(calcPos.y, MONITOR_WORKAREA.y + borderSize, MONITOR_WORKAREA.y + MONITOR_WORKAREA.h - calcSize.y - borderSize);
}
if (m_window->onSpecialWorkspace() && !m_window->isFullscreen()) {
// if special, we adjust the coords a bit
static auto PSCALEFACTOR = CConfigValue<Hyprlang::FLOAT>("dwindle:special_scale_factor");
CBox wb = {calcPos + (calcSize - calcSize * *PSCALEFACTOR) / 2.f, calcSize * *PSCALEFACTOR};
wb.round(); // avoid rounding mess
*m_window->m_realPosition = wb.pos();
*m_window->m_realSize = wb.size();
} else {
CBox wb = {calcPos, calcSize};
wb.round(); // avoid rounding mess
*m_window->m_realSize = wb.size();
*m_window->m_realPosition = wb.pos();
}
m_window->updateWindowDecos();
}
void CWindowTarget::assignToSpace(const SP<CSpace>& space, std::optional<Vector2D> focalPoint) {
if (!space) {
ITarget::assignToSpace(space, focalPoint);
return;
}
// keep the ref here so that moveToWorkspace doesn't unref the workspace
// and assignToSpace doesn't think this is a new target because space wp is dead
const auto WSREF = space->workspace();
m_window->m_monitor = space->workspace()->m_monitor;
m_window->moveToWorkspace(space->workspace());
// layout and various update fns want the target to already have m_workspace set
ITarget::assignToSpace(space, focalPoint);
m_window->updateToplevel();
m_window->updateWindowDecos();
}
bool CWindowTarget::floating() {
return m_window->m_isFloating;
}
void CWindowTarget::setFloating(bool x) {
if (x == m_window->m_isFloating)
return;
m_window->m_isFloating = x;
m_window->m_pinned = false;
m_window->m_ruleApplicator->propertiesChanged(Desktop::Rule::RULE_PROP_FLOATING);
}
Vector2D CWindowTarget::clampSizeForDesired(const Vector2D& size) const {
Vector2D newSize = size;
if (const auto m = m_window->minSize(); m)
newSize = newSize.clamp(*m);
if (const auto m = m_window->maxSize(); m)
newSize = newSize.clamp(Vector2D{MIN_WINDOW_SIZE, MIN_WINDOW_SIZE}, *m);
return newSize;
}
std::expected<SGeometryRequested, eGeometryFailure> CWindowTarget::desiredGeometry() {
SGeometryRequested requested;
CBox DESIRED_GEOM = g_pXWaylandManager->getGeometryForWindow(m_window.lock());
const auto PMONITOR = m_window->m_monitor.lock();
requested.size = clampSizeForDesired(DESIRED_GEOM.size());
if (m_window->m_isX11) {
Vector2D xy = {DESIRED_GEOM.x, DESIRED_GEOM.y};
xy = g_pXWaylandManager->xwaylandToWaylandCoords(xy);
requested.pos = xy;
}
const auto STOREDSIZE = m_window->m_ruleApplicator->persistentSize().valueOrDefault() ? g_pConfigManager->getStoredFloatingSize(m_window.lock()) : std::nullopt;
if (STOREDSIZE)
requested.size = clampSizeForDesired(*STOREDSIZE);
if (!PMONITOR) {
Log::logger->log(Log::ERR, "{:m} has an invalid monitor in desiredGeometry!", m_window.lock());
return std::unexpected(GEOMETRY_NO_DESIRED);
}
if (DESIRED_GEOM.width <= 2 || DESIRED_GEOM.height <= 2) {
const auto SURFACE = m_window->wlSurface()->resource();
if (SURFACE->m_current.size.x > 5 && SURFACE->m_current.size.y > 5) {
// center on mon and call it a day
requested.pos.reset();
requested.size = clampSizeForDesired(SURFACE->m_current.size);
return requested;
}
if (m_window->m_isX11 && m_window->isX11OverrideRedirect()) {
// check OR windows, they like their shit
const auto SIZE = clampSizeForDesired(m_window->m_xwaylandSurface->m_geometry.w > 0 && m_window->m_xwaylandSurface->m_geometry.h > 0 ?
m_window->m_xwaylandSurface->m_geometry.size() :
Vector2D{600, 400});
if (m_window->m_xwaylandSurface->m_geometry.x != 0 && m_window->m_xwaylandSurface->m_geometry.y != 0) {
requested.size = SIZE;
requested.pos = g_pXWaylandManager->xwaylandToWaylandCoords(m_window->m_xwaylandSurface->m_geometry.pos());
return requested;
}
}
return std::unexpected(m_window->m_isX11 && m_window->isX11OverrideRedirect() ? GEOMETRY_INVALID_DESIRED : GEOMETRY_NO_DESIRED);
}
// TODO: detect a popup in a more consistent way.
if ((DESIRED_GEOM.x == 0 && DESIRED_GEOM.y == 0) || !m_window->m_isX11) {
// middle of parent if available
if (!m_window->m_isX11) {
if (const auto PARENT = m_window->parent(); PARENT) {
const auto POS = PARENT->m_realPosition->goal() + PARENT->m_realSize->goal() / 2.F - DESIRED_GEOM.size() / 2.F;
requested.pos = POS;
}
}
} else {
// if it is, we respect where it wants to put itself, but apply monitor offset if outside
// most of these are popups
Vector2D pos;
if (const auto POPENMON = g_pCompositor->getMonitorFromVector(DESIRED_GEOM.middle()); POPENMON->m_id != PMONITOR->m_id)
pos = Vector2D(DESIRED_GEOM.x, DESIRED_GEOM.y) - POPENMON->m_position + PMONITOR->m_position;
else
pos = Vector2D(DESIRED_GEOM.x, DESIRED_GEOM.y);
requested.pos = pos;
}
if (DESIRED_GEOM.w <= 2 || DESIRED_GEOM.h <= 2)
return std::unexpected(GEOMETRY_NO_DESIRED);
return requested;
}
PHLWINDOW CWindowTarget::window() const {
return m_window.lock();
}
eFullscreenMode CWindowTarget::fullscreenMode() {
return m_window->m_fullscreenState.internal;
}
void CWindowTarget::setFullscreenMode(eFullscreenMode mode) {
if (floating() && m_window->m_fullscreenState.internal == FSMODE_NONE)
rememberFloatingSize(m_box.size());
m_window->m_fullscreenState.internal = mode;
}
std::optional<Vector2D> CWindowTarget::minSize() {
return m_window->minSize();
}
std::optional<Vector2D> CWindowTarget::maxSize() {
return m_window->maxSize();
}
void CWindowTarget::damageEntire() {
g_pHyprRenderer->damageWindow(m_window.lock());
}
void CWindowTarget::warpPositionSize() {
m_window->m_realSize->warp();
m_window->m_realPosition->warp();
m_window->updateWindowDecos();
}
void CWindowTarget::onUpdateSpace() {
if (!space())
return;
m_window->m_monitor = space()->workspace()->m_monitor;
m_window->moveToWorkspace(space()->workspace());
m_window->updateToplevel();
m_window->updateWindowDecos();
}

View file

@ -0,0 +1,40 @@
#pragma once
#include "Target.hpp"
#include "../../desktop/view/Window.hpp"
namespace Layout {
class CWindowTarget : public ITarget {
public:
static SP<ITarget> create(PHLWINDOW w);
virtual ~CWindowTarget() = default;
virtual eTargetType type();
virtual void setPositionGlobal(const CBox& box);
virtual void assignToSpace(const SP<CSpace>& space, std::optional<Vector2D> focalPoint = std::nullopt);
virtual PHLWINDOW window() const;
virtual bool floating();
virtual void setFloating(bool x);
virtual std::expected<SGeometryRequested, eGeometryFailure> desiredGeometry();
virtual eFullscreenMode fullscreenMode();
virtual void setFullscreenMode(eFullscreenMode mode);
virtual std::optional<Vector2D> minSize();
virtual std::optional<Vector2D> maxSize();
virtual void damageEntire();
virtual void warpPositionSize();
virtual void onUpdateSpace();
private:
CWindowTarget(PHLWINDOW w);
Vector2D clampSizeForDesired(const Vector2D& size) const;
void updatePos();
PHLWINDOWREF m_window;
};
};