desktop: cleanup, unify desktop elements as views (#12563)

This commit is contained in:
Vaxry 2025-12-08 15:04:40 +00:00 committed by GitHub
parent 834f019bab
commit 920353370b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
105 changed files with 2636 additions and 2337 deletions

View file

@ -1,26 +1,30 @@
#pragma once
#include "../helpers/memory/Memory.hpp"
class CWorkspace;
class CWindow;
class CLayerSurface;
class CMonitor;
namespace Desktop::View {
class CWindow;
class CLayerSurface;
}
/* Shared pointer to a workspace */
using PHLWORKSPACE = SP<CWorkspace>;
/* Weak pointer to a workspace */
using PHLWORKSPACEREF = WP<CWorkspace>;
/* Shared pointer to a window */
using PHLWINDOW = SP<CWindow>;
using PHLWINDOW = SP<Desktop::View::CWindow>;
/* Weak pointer to a window */
using PHLWINDOWREF = WP<CWindow>;
using PHLWINDOWREF = WP<Desktop::View::CWindow>;
/* Shared pointer to a layer surface */
using PHLLS = SP<CLayerSurface>;
using PHLLS = SP<Desktop::View::CLayerSurface>;
/* Weak pointer to a layer surface */
using PHLLSREF = WP<CLayerSurface>;
using PHLLSREF = WP<Desktop::View::CLayerSurface>;
/* Shared pointer to a monitor */
using PHLMONITOR = SP<CMonitor>;
/* Weak pointer to a monitor */
using PHLMONITORREF = WP<CMonitor>;
using PHLMONITORREF = WP<CMonitor>;

View file

@ -1,95 +0,0 @@
#pragma once
#include <string>
#include "../defines.hpp"
#include "WLSurface.hpp"
#include "rule/layerRule/LayerRuleApplicator.hpp"
#include "../helpers/AnimatedVariable.hpp"
class CLayerShellResource;
class CLayerSurface {
public:
static PHLLS create(SP<CLayerShellResource>);
private:
CLayerSurface(SP<CLayerShellResource>);
public:
~CLayerSurface();
bool isFadedOut();
int popupsCount();
PHLANIMVAR<Vector2D> m_realPosition;
PHLANIMVAR<Vector2D> m_realSize;
PHLANIMVAR<float> m_alpha;
WP<CLayerShellResource> m_layerSurface;
// the header providing the enum type cannot be imported here
int m_interactivity = 0;
SP<CWLSurface> m_surface;
bool m_mapped = false;
uint32_t m_layer = 0;
PHLMONITORREF m_monitor;
bool m_fadingOut = false;
bool m_readyToDelete = false;
bool m_noProcess = false;
UP<Desktop::Rule::CLayerRuleApplicator> m_ruleApplicator;
PHLLSREF m_self;
CBox m_geometry = {0, 0, 0, 0};
Vector2D m_position;
std::string m_namespace = "";
UP<CPopup> m_popupHead;
pid_t getPID();
void onDestroy();
void onMap();
void onUnmap();
void onCommit();
MONITORID monitorID();
private:
struct {
CHyprSignalListener destroy;
CHyprSignalListener map;
CHyprSignalListener unmap;
CHyprSignalListener commit;
} m_listeners;
void registerCallbacks();
// For the list lookup
bool operator==(const CLayerSurface& rhs) const {
return m_layerSurface == rhs.m_layerSurface && m_monitor == rhs.m_monitor;
}
};
inline bool valid(PHLLS l) {
return l;
}
inline bool valid(PHLLSREF l) {
return l;
}
inline bool validMapped(PHLLS l) {
if (!valid(l))
return false;
return l->m_mapped;
}
inline bool validMapped(PHLLSREF l) {
if (!valid(l))
return false;
return l->m_mapped;
}

View file

@ -1,96 +0,0 @@
#pragma once
#include <vector>
#include "Subsurface.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../helpers/memory/Memory.hpp"
#include "../helpers/AnimatedVariable.hpp"
class CXDGPopupResource;
class CPopup {
public:
// dummy head nodes
static UP<CPopup> create(PHLWINDOW pOwner);
static UP<CPopup> create(PHLLS pOwner);
// real nodes
static UP<CPopup> create(SP<CXDGPopupResource> popup, WP<CPopup> pOwner);
~CPopup();
SP<CWLSurface> getT1Owner();
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
PHLMONITOR getMonitor();
Vector2D size();
void onNewPopup(SP<CXDGPopupResource> popup);
void onDestroy();
void onMap();
void onUnmap();
void onCommit(bool ignoreSiblings = false);
void onReposition();
void recheckTree();
bool visible();
bool inert() const;
// will also loop over this node
void breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data);
WP<CPopup> at(const Vector2D& globalCoords, bool allowsInput = false);
//
SP<CWLSurface> m_wlSurface;
WP<CPopup> m_self;
bool m_mapped = false;
// fade in-out
PHLANIMVAR<float> m_alpha;
bool m_fadingOut = false;
private:
CPopup() = default;
// T1 owners, each popup has to have one of these
PHLWINDOWREF m_windowOwner;
PHLLSREF m_layerOwner;
// T2 owners
WP<CPopup> m_parent;
WP<CXDGPopupResource> m_resource;
Vector2D m_lastSize = {};
Vector2D m_lastPos = {};
bool m_requestedReposition = false;
bool m_inert = false;
//
std::vector<UP<CPopup>> m_children;
UP<CSubsurface> m_subsurfaceHead;
struct {
CHyprSignalListener newPopup;
CHyprSignalListener destroy;
CHyprSignalListener map;
CHyprSignalListener unmap;
CHyprSignalListener commit;
CHyprSignalListener dismissed;
CHyprSignalListener reposition;
} m_listeners;
void initAllSignals();
void reposition();
void recheckChildrenRecursive();
void sendScale();
void fullyDestroy();
Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords();
static void bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(WP<CPopup>, void*)> fn, void* data);
};

View file

@ -1,69 +0,0 @@
#pragma once
#include "../defines.hpp"
#include <vector>
#include "WLSurface.hpp"
class CPopup;
class CWLSubsurfaceResource;
class CSubsurface {
public:
// root dummy nodes
static UP<CSubsurface> create(PHLWINDOW pOwner);
static UP<CSubsurface> create(WP<CPopup> pOwner);
// real nodes
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
static UP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner);
~CSubsurface() = default;
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
Vector2D size();
void onCommit();
void onDestroy();
void onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface);
void onMap();
void onUnmap();
bool visible();
void recheckDamageForSubsurfaces();
WP<CSubsurface> m_self;
private:
CSubsurface() = default;
struct {
CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface;
CHyprSignalListener mapSubsurface;
CHyprSignalListener unmapSubsurface;
CHyprSignalListener newSubsurface;
} m_listeners;
WP<CWLSubsurfaceResource> m_subsurface;
SP<CWLSurface> m_wlSurface;
Vector2D m_lastSize = {};
Vector2D m_lastPosition = {};
// if nullptr, means it's a dummy node
WP<CSubsurface> m_parent;
PHLWINDOWREF m_windowParent;
WP<CPopup> m_popupParent;
std::vector<UP<CSubsurface>> m_children;
bool m_inert = false;
void initSignals();
void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface);
void checkSiblingDamage();
void damageLastArea();
};

View file

@ -1,124 +0,0 @@
#pragma once
#include "../defines.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/signal/Signal.hpp"
class CSubsurface;
class CPopup;
class CPointerConstraint;
class CWLSurfaceResource;
class CWLSurface {
public:
static SP<CWLSurface> create() {
auto p = SP<CWLSurface>(new CWLSurface);
p->m_self = p;
return p;
}
~CWLSurface();
// anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD
void assign(SP<CWLSurfaceResource> pSurface);
void assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner);
void assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner);
void assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner);
void assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner);
void unassign();
CWLSurface(const CWLSurface&) = delete;
CWLSurface(CWLSurface&&) = delete;
CWLSurface& operator=(const CWLSurface&) = delete;
CWLSurface& operator=(CWLSurface&&) = delete;
SP<CWLSurfaceResource> resource() const;
bool exists() const;
bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords
Vector2D getViewporterCorrectedSize() const;
CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
bool visible();
bool keyboardFocusable() const;
// getters for owners.
PHLWINDOW getWindow() const;
PHLLS getLayer() const;
CPopup* getPopup() const;
CSubsurface* getSubsurface() const;
// desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal() const;
void appendConstraint(WP<CPointerConstraint> constraint);
SP<CPointerConstraint> constraint() const;
// allow stretching. Useful for plugins.
bool m_fillIgnoreSmall = false;
// track surface data and avoid dupes
float m_lastScaleFloat = 0;
int m_lastScaleInt = 0;
wl_output_transform m_lastTransform = sc<wl_output_transform>(-1);
//
CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) {
destroy();
m_resource = pSurface;
init();
return *this;
}
bool operator==(const CWLSurface& other) const {
return other.resource() == resource();
}
bool operator==(const SP<CWLSurfaceResource> other) const {
return other == resource();
}
explicit operator bool() const {
return exists();
}
static SP<CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface);
// used by the alpha-modifier protocol
float m_alphaModifier = 1.F;
// used by the hyprland-surface protocol
float m_overallOpacity = 1.F;
CRegion m_visibleRegion;
struct {
CSignalT<> destroy;
} m_events;
WP<CWLSurface> m_self;
private:
CWLSurface() = default;
bool m_inert = true;
WP<CWLSurfaceResource> m_resource;
PHLWINDOWREF m_windowOwner;
PHLLSREF m_layerOwner;
CPopup* m_popupOwner = nullptr;
CSubsurface* m_subsurfaceOwner = nullptr;
//
WP<CPointerConstraint> m_constraint;
void destroy();
void init();
bool desktopComponent() const;
struct {
CHyprSignalListener destroy;
} m_listeners;
friend class CPointerConstraint;
friend class CXxColorManagerV4;
};

View file

@ -1,438 +0,0 @@
#pragma once
#include <vector>
#include <string>
#include <optional>
#include "../config/ConfigDataValues.hpp"
#include "../helpers/AnimatedVariable.hpp"
#include "../helpers/TagKeeper.hpp"
#include "../macros.hpp"
#include "../managers/XWaylandManager.hpp"
#include "../render/decorations/IHyprWindowDecoration.hpp"
#include "../render/Transformer.hpp"
#include "DesktopTypes.hpp"
#include "Popup.hpp"
#include "Subsurface.hpp"
#include "WLSurface.hpp"
#include "Workspace.hpp"
#include "rule/windowRule/WindowRuleApplicator.hpp"
#include "../protocols/types/ContentType.hpp"
class CXDGSurfaceResource;
class CXWaylandSurface;
enum eGroupRules : uint8_t {
// effective only during first map, except for _ALWAYS variant
GROUP_NONE = 0,
GROUP_SET = 1 << 0, // Open as new group or add to focused group
GROUP_SET_ALWAYS = 1 << 1,
GROUP_BARRED = 1 << 2, // Don't insert to focused group.
GROUP_LOCK = 1 << 3, // Lock m_sGroupData.lock
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
};
enum eGetWindowProperties : uint8_t {
WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1,
FULL_EXTENTS = 1 << 2,
FLOATING_ONLY = 1 << 3,
ALLOW_FLOATING = 1 << 4,
USE_PROP_TILED = 1 << 5,
SKIP_FULLSCREEN_PRIORITY = 1 << 6,
FOCUS_PRIORITY = 1 << 7,
};
enum eSuppressEvents : uint8_t {
SUPPRESS_NONE = 0,
SUPPRESS_FULLSCREEN = 1 << 0,
SUPPRESS_MAXIMIZE = 1 << 1,
SUPPRESS_ACTIVATE = 1 << 2,
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
};
class IWindowTransformer;
struct SInitialWorkspaceToken {
PHLWINDOWREF primaryOwner;
std::string workspace;
};
struct SFullscreenState {
eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE;
};
class CWindow {
public:
static PHLWINDOW create(SP<CXDGSurfaceResource>);
static PHLWINDOW create(SP<CXWaylandSurface>);
private:
CWindow(SP<CXDGSurfaceResource> resource);
CWindow(SP<CXWaylandSurface> surface);
public:
~CWindow();
SP<CWLSurface> m_wlSurface;
struct {
CSignalT<> destroy;
} m_events;
WP<CXDGSurfaceResource> m_xdgSurface;
WP<CXWaylandSurface> m_xwaylandSurface;
// this is the position and size of the "bounding box"
Vector2D m_position = Vector2D(0, 0);
Vector2D m_size = Vector2D(0, 0);
// this is the real position and size used to draw the thing
PHLANIMVAR<Vector2D> m_realPosition;
PHLANIMVAR<Vector2D> m_realSize;
// for not spamming the protocols
Vector2D m_reportedPosition;
Vector2D m_reportedSize;
Vector2D m_pendingReportedSize;
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 = "";
std::string m_initialTitle = "";
std::string m_initialClass = "";
PHLWORKSPACE m_workspace;
PHLMONITORREF m_monitor;
bool m_isMapped = false;
bool m_requestsFloat = false;
// This is for fullscreen apps
bool m_createdOverFullscreen = false;
// XWayland stuff
bool m_isX11 = false;
bool m_X11DoesntWantBorders = false;
bool m_X11ShouldntFocus = false;
float m_X11SurfaceScaledBy = 1.f;
//
// For nofocus
bool m_noInitialFocus = false;
// Fullscreen and Maximize
bool m_wantsInitialFullscreen = false;
MONITORID m_wantsInitialFullscreenMonitor = MONITOR_INVALID;
// bitfield suppressEvents
uint64_t m_suppressedEvents = SUPPRESS_NONE;
// desktop components
UP<CSubsurface> m_subsurfaceHead;
UP<CPopup> m_popupHead;
// Animated border
CGradientValueData m_realBorderColor = {0};
CGradientValueData m_realBorderColorPrevious = {0};
PHLANIMVAR<float> m_borderFadeAnimationProgress;
PHLANIMVAR<float> m_borderAngleAnimationProgress;
// Fade in-out
PHLANIMVAR<float> m_alpha;
bool m_fadingOut = false;
bool m_readyToDelete = false;
Vector2D m_originalClosedPos; // these will be used for calculations later on in
Vector2D m_originalClosedSize; // drawing the closing animations
SBoxExtents m_originalClosedExtents;
bool m_animatingIn = false;
// For pinned (sticky) windows
bool m_pinned = false;
// For preserving pinned state when fullscreening a pinned window
bool m_pinFullscreened = false;
// urgency hint
bool m_isUrgent = false;
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
PHLWINDOWREF m_lastCycledWindow;
// Window decorations
// TODO: make this a SP.
std::vector<UP<IHyprWindowDecoration>> m_windowDecorations;
std::vector<IHyprWindowDecoration*> m_decosToRemove;
// Special render data, rules, etc
UP<Desktop::Rule::CWindowRuleApplicator> m_ruleApplicator;
// Transformers
std::vector<UP<IWindowTransformer>> m_transformers;
// for alpha
PHLANIMVAR<float> m_activeInactiveAlpha;
PHLANIMVAR<float> m_movingFromWorkspaceAlpha;
// animated shadow color
PHLANIMVAR<CHyprColor> m_realShadowColor;
// animated tint
PHLANIMVAR<float> m_dimPercent;
// animate moving to an invisible workspace
int m_monitorMovedFrom = -1; // -1 means not moving
PHLANIMVAR<float> m_movingToWorkspaceAlpha;
// swallowing
PHLWINDOWREF m_swallowed;
bool m_currentlySwallowed = false;
bool m_groupSwallowed = false;
// for toplevel monitor events
MONITORID m_lastSurfaceMonitorID = -1;
// initial token. Will be unregistered on workspace change or timeout of 2 minutes
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 = GROUP_NONE;
bool m_tearingHint = false;
// ANR
PHLANIMVAR<float> m_notRespondingTint;
// For the noclosefor windowrule
Time::steady_tp m_closeableSince = Time::steadyNow();
// For the list lookup
bool operator==(const CWindow& rhs) const {
return m_xdgSurface == rhs.m_xdgSurface && m_xwaylandSurface == rhs.m_xwaylandSurface && m_position == rhs.m_position && m_size == rhs.m_size &&
m_fadingOut == rhs.m_fadingOut;
}
// methods
CBox getFullWindowBoundingBox();
SBoxExtents getFullWindowExtents();
CBox getWindowBoxUnified(uint64_t props);
SBoxExtents getWindowExtentsUnified(uint64_t props);
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(UP<IHyprWindowDecoration> deco);
void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco);
void uncacheWindowDecos();
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW x11TransientFor();
void onUnmap();
void onMap();
void setHidden(bool hidden);
bool isHidden();
void updateDecorationValues();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();
bool opaque();
float rounding();
float roundingPower();
bool canBeTorn();
void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor);
WORKSPACEID workspaceID();
MONITORID monitorID();
bool onSpecialWorkspace();
void activate(bool force = false);
int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode);
int getRealBorderSize();
float getScrollMouse();
float getScrollTouchpad();
bool isScrollMouseOverridden();
bool isScrollTouchpadOverridden();
void updateWindowData();
void updateWindowData(const struct SWorkspaceRule&);
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav);
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();
void onUpdateState();
void onUpdateMeta();
void onX11ConfigureRequest(CBox box);
void onResourceChangeX11();
std::string fetchTitle();
std::string fetchClass();
void warpCursor(bool force = false);
PHLWINDOW getSwallower();
bool isX11OverrideRedirect();
bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
Vector2D realToReportSize();
Vector2D realToReportPosition();
Vector2D xwaylandSizeToReal(Vector2D size);
Vector2D xwaylandPositionToReal(Vector2D size);
void updateX11SurfaceScale();
void sendWindowSize(bool force = false);
NContentType::eContentType getContentType();
void setContentType(NContentType::eContentType contentType);
void deactivateGroupMembers();
bool isNotResponding();
std::optional<std::string> xdgTag();
std::optional<std::string> xdgDescription();
PHLWINDOW parent();
bool priorityFocus();
SP<CWLSurfaceResource> getSolitaryResource();
Vector2D getReportedSize();
std::optional<Vector2D> calculateExpression(const std::string& s);
CBox getWindowMainSurfaceBox() const {
return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y};
}
// listeners
void onAck(uint32_t serial);
//
std::unordered_map<std::string, std::string> getEnv();
//
PHLWINDOWREF m_self;
// make private once we move listeners to inside CWindow
struct {
CHyprSignalListener map;
CHyprSignalListener ack;
CHyprSignalListener unmap;
CHyprSignalListener commit;
CHyprSignalListener destroy;
CHyprSignalListener activate;
CHyprSignalListener configureRequest;
CHyprSignalListener setGeometry;
CHyprSignalListener updateState;
CHyprSignalListener updateMetadata;
CHyprSignalListener resourceChange;
} m_listeners;
private:
std::optional<double> calculateSingleExpr(const std::string& s);
// For hidden windows and stuff
bool m_hidden = false;
bool m_suspended = false;
WORKSPACEID m_lastWorkspace = WORKSPACE_INVALID;
};
inline bool valid(PHLWINDOW w) {
return w.get();
}
inline bool valid(PHLWINDOWREF w) {
return !w.expired();
}
inline bool validMapped(PHLWINDOW w) {
if (!valid(w))
return false;
return w->m_isMapped;
}
inline bool validMapped(PHLWINDOWREF w) {
if (!valid(w))
return false;
return w->m_isMapped;
}
/**
format specification
- 'x', only address, equivalent of (uintpr_t)CWindow*
- 'm', with monitor id
- 'w', with workspace id
- 'c', with application class
*/
template <typename CharT>
struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
bool formatAddressOnly = false;
bool formatWorkspace = false;
bool formatMonitor = false;
bool formatClass = false;
FORMAT_PARSE( //
FORMAT_FLAG('x', formatAddressOnly) //
FORMAT_FLAG('m', formatMonitor) //
FORMAT_FLAG('w', formatWorkspace) //
FORMAT_FLAG('c', formatClass),
PHLWINDOW)
template <typename FormatContext>
auto format(PHLWINDOW const& w, FormatContext& ctx) const {
auto&& out = ctx.out();
if (formatAddressOnly)
return std::format_to(out, "{:x}", rc<uintptr_t>(w.get()));
if (!w)
return std::format_to(out, "[Window nullptr]");
std::format_to(out, "[");
std::format_to(out, "Window {:x}: title: \"{}\"", rc<uintptr_t>(w.get()), w->m_title);
if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID);
if (formatMonitor)
std::format_to(out, ", monitor: {}", w->monitorID());
if (formatClass)
std::format_to(out, ", class: {}", w->m_class);
return std::format_to(out, "]");
}
};

View file

@ -13,8 +13,6 @@ enum eFullscreenMode : int8_t {
FSMODE_MAX = (1 << 2) - 1
};
class CWindow;
class CWorkspace {
public:
static PHLWORKSPACE create(WORKSPACEID id, PHLMONITOR monitor, std::string name, bool special = false, bool isEmpty = true);

View file

@ -1,6 +1,6 @@
#include "Engine.hpp"
#include "Rule.hpp"
#include "../LayerSurface.hpp"
#include "../view/LayerSurface.hpp"
#include "../../Compositor.hpp"
using namespace Desktop;

View file

@ -1,6 +1,6 @@
#include "LayerRule.hpp"
#include "../../../debug/Log.hpp"
#include "../../LayerSurface.hpp"
#include "../../view/LayerSurface.hpp"
using namespace Desktop;
using namespace Desktop::Rule;

View file

@ -1,7 +1,7 @@
#include "LayerRuleApplicator.hpp"
#include "LayerRule.hpp"
#include "../Engine.hpp"
#include "../../LayerSurface.hpp"
#include "../../view/LayerSurface.hpp"
#include "../../types/OverridableVar.hpp"
#include "../../../helpers/MiscFunctions.hpp"

View file

@ -1,5 +1,5 @@
#include "WindowRule.hpp"
#include "../../Window.hpp"
#include "../../view/Window.hpp"
#include "../../../helpers/Monitor.hpp"
#include "../../../Compositor.hpp"
#include "../../../managers/TokenManager.hpp"

View file

@ -2,7 +2,7 @@
#include "WindowRule.hpp"
#include "../Engine.hpp"
#include "../utils/SetUtils.hpp"
#include "../../Window.hpp"
#include "../../view/Window.hpp"
#include "../../types/OverridableVar.hpp"
#include "../../../managers/LayoutManager.hpp"
#include "../../../managers/HookSystemManager.hpp"

View file

@ -1,5 +1,5 @@
#include "FocusState.hpp"
#include "../Window.hpp"
#include "../view/Window.hpp"
#include "../../Compositor.hpp"
#include "../../protocols/XDGShell.hpp"
#include "../../render/Renderer.hpp"
@ -191,7 +191,7 @@ void CFocusState::rawWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surfa
g_pXWaylandManager->activateWindow(PLASTWINDOW, false);
}
const auto PWINDOWSURFACE = surface ? surface : pWindow->m_wlSurface->resource();
const auto PWINDOWSURFACE = surface ? surface : pWindow->wlSurface()->resource();
rawSurfaceFocus(PWINDOWSURFACE, pWindow);
@ -227,7 +227,7 @@ void CFocusState::rawWindowFocus(PHLWINDOW pWindow, SP<CWLSurfaceResource> surfa
}
void CFocusState::rawSurfaceFocus(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWindowOwner) {
if (g_pSeatManager->m_state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->m_state.keyboardFocus == pWindowOwner->m_wlSurface->resource()))
if (g_pSeatManager->m_state.keyboardFocus == pSurface || (pWindowOwner && g_pSeatManager->m_state.keyboardFocus == pWindowOwner->wlSurface()->resource()))
return; // Don't focus when already focused on this.
if (g_pSessionLockManager->isSessionLocked() && pSurface && !g_pSessionLockManager->isSurfaceSessionLock(pSurface))
@ -266,8 +266,8 @@ void CFocusState::rawSurfaceFocus(SP<CWLSurfaceResource> pSurface, PHLWINDOW pWi
EMIT_HOOK_EVENT("keyboardFocus", pSurface);
const auto SURF = CWLSurface::fromResource(pSurface);
const auto OLDSURF = CWLSurface::fromResource(PLASTSURF);
const auto SURF = Desktop::View::CWLSurface::fromResource(pSurface);
const auto OLDSURF = Desktop::View::CWLSurface::fromResource(PLASTSURF);
if (OLDSURF && OLDSURF->constraint())
OLDSURF->constraint()->deactivate();

View file

@ -0,0 +1,82 @@
#include "GlobalViewMethods.hpp"
#include "../../Compositor.hpp"
#include "LayerSurface.hpp"
#include "Window.hpp"
#include "Popup.hpp"
#include "Subsurface.hpp"
#include "SessionLock.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../protocols/core/Subcompositor.hpp"
#include "../../protocols/SessionLock.hpp"
using namespace Desktop;
using namespace Desktop::View;
std::vector<SP<IView>> View::getViewsForWorkspace(PHLWORKSPACE ws) {
std::vector<SP<IView>> views;
for (const auto& w : g_pCompositor->m_windows) {
if (!w->visible() || w->m_workspace != ws)
continue;
views.emplace_back(w);
w->wlSurface()->resource()->breadthfirst(
[&views](SP<CWLSurfaceResource> s, const Vector2D& pos, void* data) {
auto surf = CWLSurface::fromResource(s);
if (!surf || !s->m_mapped)
return;
views.emplace_back(surf->view());
},
nullptr);
// xwl windows dont have this
if (w->m_popupHead) {
w->m_popupHead->breadthfirst(
[&views](SP<CPopup> s, void* data) {
auto surf = s->wlSurface();
if (!surf || !s->visible())
return;
views.emplace_back(surf->view());
},
nullptr);
}
}
for (const auto& l : g_pCompositor->m_layers) {
if (!l->visible() || l->m_monitor != ws->m_monitor)
continue;
views.emplace_back(l);
l->m_popupHead->breadthfirst(
[&views](SP<CPopup> p, void* data) {
auto surf = p->wlSurface();
if (!surf || !p->visible())
return;
views.emplace_back(surf->view());
},
nullptr);
}
for (const auto& v : g_pCompositor->m_otherViews) {
if (!v->visible() || !v->desktopComponent())
continue;
if (v->type() == VIEW_TYPE_LOCK_SCREEN) {
const auto LOCK = Desktop::View::CSessionLock::fromView(v);
if (LOCK->monitor() != ws->m_monitor)
continue;
views.emplace_back(LOCK);
continue;
}
}
return views;
}

View file

@ -0,0 +1,11 @@
#pragma once
#include "View.hpp"
#include "../Workspace.hpp"
#include <vector>
namespace Desktop::View {
std::vector<SP<IView>> getViewsForWorkspace(PHLWORKSPACE ws);
};

View file

@ -1,25 +1,27 @@
#include "LayerSurface.hpp"
#include "state/FocusState.hpp"
#include "../Compositor.hpp"
#include "../events/Events.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "../managers/animation/AnimationManager.hpp"
#include "../managers/animation/DesktopAnimationManager.hpp"
#include "../render/Renderer.hpp"
#include "../config/ConfigManager.hpp"
#include "../helpers/Monitor.hpp"
#include "../managers/input/InputManager.hpp"
#include "../managers/HookSystemManager.hpp"
#include "../managers/EventManager.hpp"
#include "../state/FocusState.hpp"
#include "../../Compositor.hpp"
#include "../../protocols/LayerShell.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../managers/SeatManager.hpp"
#include "../../managers/animation/AnimationManager.hpp"
#include "../../managers/animation/DesktopAnimationManager.hpp"
#include "../../render/Renderer.hpp"
#include "../../config/ConfigManager.hpp"
#include "../../helpers/Monitor.hpp"
#include "../../managers/input/InputManager.hpp"
#include "../../managers/HookSystemManager.hpp"
#include "../../managers/EventManager.hpp"
using namespace Desktop;
using namespace Desktop::View;
PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
PHLLS pLS = SP<CLayerSurface>(new CLayerSurface(resource));
auto pMonitor = resource->m_monitor.empty() ? Desktop::focusState()->monitor() : g_pCompositor->getMonitorFromName(resource->m_monitor);
pLS->m_surface->assign(resource->m_surface.lock(), pLS);
pLS->m_wlSurface->assign(resource->m_surface.lock(), pLS);
if (!pMonitor) {
Debug::log(ERR, "New LS has no monitor??");
@ -54,6 +56,12 @@ PHLLS CLayerSurface::create(SP<CLayerShellResource> resource) {
return pLS;
}
PHLLS CLayerSurface::fromView(SP<IView> v) {
if (!v || v->type() != VIEW_TYPE_LAYER_SURFACE)
return nullptr;
return dynamicPointerCast<CLayerSurface>(v);
}
void CLayerSurface::registerCallbacks() {
m_alpha->setUpdateCallback([this](auto) {
if (m_ruleApplicator->dimAround().valueOrDefault() && m_monitor)
@ -61,21 +69,19 @@ void CLayerSurface::registerCallbacks() {
});
}
CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : m_layerSurface(resource_) {
CLayerSurface::CLayerSurface(SP<CLayerShellResource> resource_) : IView(CWLSurface::create()), m_layerSurface(resource_) {
m_listeners.commit = m_layerSurface->m_events.commit.listen([this] { onCommit(); });
m_listeners.map = m_layerSurface->m_events.map.listen([this] { onMap(); });
m_listeners.unmap = m_layerSurface->m_events.unmap.listen([this] { onUnmap(); });
m_listeners.destroy = m_layerSurface->m_events.destroy.listen([this] { onDestroy(); });
m_surface = CWLSurface::create();
}
CLayerSurface::~CLayerSurface() {
if (!g_pHyprOpenGL)
return;
if (m_surface)
m_surface->unassign();
if (m_wlSurface)
m_wlSurface->unassign();
g_pHyprRenderer->makeEGLCurrent();
std::erase_if(g_pHyprOpenGL->m_layerFramebuffers, [&](const auto& other) { return other.first.expired() || other.first.lock() == m_self.lock(); });
@ -86,6 +92,29 @@ CLayerSurface::~CLayerSurface() {
}
}
eViewType CLayerSurface::type() const {
return VIEW_TYPE_LAYER_SURFACE;
}
bool CLayerSurface::visible() const {
return (m_mapped && m_layerSurface && m_layerSurface->m_mapped && m_wlSurface && m_wlSurface->resource()) || (m_fadingOut && m_alpha->value() > 0.F);
}
std::optional<CBox> CLayerSurface::logicalBox() const {
return surfaceLogicalBox();
}
std::optional<CBox> CLayerSurface::surfaceLogicalBox() const {
if (!visible())
return std::nullopt;
return CBox{m_realPosition->value(), m_realSize->value()};
}
bool CLayerSurface::desktopComponent() const {
return true;
}
void CLayerSurface::onDestroy() {
Debug::log(LOG, "LayerSurface {:x} destroyed", rc<uintptr_t>(m_layerSurface.get()));
@ -123,8 +152,8 @@ void CLayerSurface::onDestroy() {
m_readyToDelete = true;
m_layerSurface.reset();
if (m_surface)
m_surface->unassign();
if (m_wlSurface)
m_wlSurface->unassign();
m_listeners.unmap.reset();
m_listeners.destroy.reset();
@ -156,7 +185,7 @@ void CLayerSurface::onMap() {
g_pHyprRenderer->arrangeLayersForMonitor(PMONITOR->m_id);
m_surface->resource()->enter(PMONITOR->m_self.lock());
m_wlSurface->resource()->enter(PMONITOR->m_self.lock());
const bool ISEXCLUSIVE = m_layerSurface->m_current.interactivity == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE;
@ -170,14 +199,14 @@ void CLayerSurface::onMap() {
if (GRABSFOCUS) {
// TODO: use the new superb really very cool grab
if (g_pSeatManager->m_seatGrab && !g_pSeatManager->m_seatGrab->accepts(m_surface->resource()))
if (g_pSeatManager->m_seatGrab && !g_pSeatManager->m_seatGrab->accepts(m_wlSurface->resource()))
g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons();
Desktop::focusState()->rawSurfaceFocus(m_surface->resource());
Desktop::focusState()->rawSurfaceFocus(m_wlSurface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y);
g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL);
g_pSeatManager->setPointerFocus(m_wlSurface->resource(), LOCAL);
g_pInputManager->m_emptyFocusCursorSet = false;
}
@ -194,8 +223,8 @@ void CLayerSurface::onMap() {
g_pEventManager->postEvent(SHyprIPCEvent{.event = "openlayer", .data = m_namespace});
EMIT_HOOK_EVENT("openLayer", m_self.lock());
g_pCompositor->setPreferredScaleForSurface(m_surface->resource(), PMONITOR->m_scale);
g_pCompositor->setPreferredTransformForSurface(m_surface->resource(), PMONITOR->m_transform);
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), PMONITOR->m_scale);
g_pCompositor->setPreferredTransformForSurface(m_wlSurface->resource(), PMONITOR->m_transform);
}
void CLayerSurface::onUnmap() {
@ -238,7 +267,7 @@ void CLayerSurface::onUnmap() {
const auto PMONITOR = m_monitor.lock();
const bool WASLASTFOCUS = g_pSeatManager->m_state.keyboardFocus == m_surface->resource() || g_pSeatManager->m_state.pointerFocus == m_surface->resource();
const bool WASLASTFOCUS = g_pSeatManager->m_state.keyboardFocus == m_wlSurface->resource() || g_pSeatManager->m_state.pointerFocus == m_wlSurface->resource();
if (!PMONITOR)
return;
@ -249,7 +278,7 @@ void CLayerSurface::onUnmap() {
(Desktop::focusState()->surface() && Desktop::focusState()->surface()->m_hlSurface && !Desktop::focusState()->surface()->m_hlSurface->keyboardFocusable())) {
if (!g_pInputManager->refocusLastWindow(PMONITOR))
g_pInputManager->refocus();
} else if (Desktop::focusState()->surface() && Desktop::focusState()->surface() != m_surface->resource())
} else if (Desktop::focusState()->surface() && Desktop::focusState()->surface() != m_wlSurface->resource())
g_pSeatManager->setKeyboardFocus(Desktop::focusState()->surface());
CBox geomFixed = {m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y, m_geometry.width, m_geometry.height};
@ -359,8 +388,8 @@ void CLayerSurface::onCommit() {
nullptr);
if (!WASLASTFOCUS && m_popupHead) {
m_popupHead->breadthfirst(
[&WASLASTFOCUS](WP<CPopup> popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->m_wlSurface && g_pSeatManager->m_state.keyboardFocus == popup->m_wlSurface->resource());
[&WASLASTFOCUS](WP<Desktop::View::CPopup> popup, void* data) {
WASLASTFOCUS = WASLASTFOCUS || (popup->wlSurface() && g_pSeatManager->m_state.keyboardFocus == popup->wlSurface()->resource());
},
nullptr);
}
@ -384,20 +413,20 @@ void CLayerSurface::onCommit() {
// if now exclusive and not previously
g_pSeatManager->setGrab(nullptr);
g_pInputManager->releaseAllMouseButtons();
Desktop::focusState()->rawSurfaceFocus(m_surface->resource());
Desktop::focusState()->rawSurfaceFocus(m_wlSurface->resource());
const auto LOCAL = g_pInputManager->getMouseCoordsInternal() - Vector2D(m_geometry.x + PMONITOR->m_position.x, m_geometry.y + PMONITOR->m_position.y);
g_pSeatManager->setPointerFocus(m_surface->resource(), LOCAL);
g_pSeatManager->setPointerFocus(m_wlSurface->resource(), LOCAL);
g_pInputManager->m_emptyFocusCursorSet = false;
}
}
m_interactivity = m_layerSurface->m_current.interactivity;
g_pHyprRenderer->damageSurface(m_surface->resource(), m_position.x, m_position.y);
g_pHyprRenderer->damageSurface(m_wlSurface->resource(), m_position.x, m_position.y);
g_pCompositor->setPreferredScaleForSurface(m_surface->resource(), PMONITOR->m_scale);
g_pCompositor->setPreferredTransformForSurface(m_surface->resource(), PMONITOR->m_transform);
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), PMONITOR->m_scale);
g_pCompositor->setPreferredTransformForSurface(m_wlSurface->resource(), PMONITOR->m_transform);
}
bool CLayerSurface::isFadedOut() {
@ -412,7 +441,7 @@ int CLayerSurface::popupsCount() {
return 0;
int no = -1; // we have one dummy
m_popupHead->breadthfirst([](WP<CPopup> p, void* data) { *sc<int*>(data) += 1; }, &no);
m_popupHead->breadthfirst([](WP<Desktop::View::CPopup> p, void* data) { *sc<int*>(data) += 1; }, &no);
return no;
}
@ -424,10 +453,10 @@ pid_t CLayerSurface::getPID() {
pid_t PID = -1;
if (!m_layerSurface || !m_layerSurface->m_surface || !m_layerSurface->m_surface->getResource() || !m_layerSurface->m_surface->getResource()->resource() ||
!m_layerSurface->m_surface->getResource()->resource()->client)
!m_layerSurface->m_surface->getResource()->client())
return -1;
wl_client_get_credentials(m_layerSurface->m_surface->getResource()->resource()->client, &PID, nullptr, nullptr);
wl_client_get_credentials(m_layerSurface->m_surface->getResource()->client(), &PID, nullptr, nullptr);
return PID;
}

View file

@ -0,0 +1,105 @@
#pragma once
#include <string>
#include "../../defines.hpp"
#include "WLSurface.hpp"
#include "View.hpp"
#include "../rule/layerRule/LayerRuleApplicator.hpp"
#include "../../helpers/AnimatedVariable.hpp"
class CLayerShellResource;
namespace Desktop::View {
class CLayerSurface : public IView {
public:
static PHLLS create(SP<CLayerShellResource>);
static PHLLS fromView(SP<IView>);
private:
CLayerSurface(SP<CLayerShellResource>);
public:
virtual ~CLayerSurface();
virtual eViewType type() const;
virtual bool visible() const;
virtual std::optional<CBox> logicalBox() const;
virtual bool desktopComponent() const;
virtual std::optional<CBox> surfaceLogicalBox() const;
bool isFadedOut();
int popupsCount();
PHLANIMVAR<Vector2D> m_realPosition;
PHLANIMVAR<Vector2D> m_realSize;
PHLANIMVAR<float> m_alpha;
WP<CLayerShellResource> m_layerSurface;
// the header providing the enum type cannot be imported here
int m_interactivity = 0;
bool m_mapped = false;
uint32_t m_layer = 0;
PHLMONITORREF m_monitor;
bool m_fadingOut = false;
bool m_readyToDelete = false;
bool m_noProcess = false;
UP<Desktop::Rule::CLayerRuleApplicator> m_ruleApplicator;
PHLLSREF m_self;
CBox m_geometry = {0, 0, 0, 0};
Vector2D m_position;
std::string m_namespace = "";
SP<Desktop::View::CPopup> m_popupHead;
pid_t getPID();
void onDestroy();
void onMap();
void onUnmap();
void onCommit();
MONITORID monitorID();
private:
struct {
CHyprSignalListener destroy;
CHyprSignalListener map;
CHyprSignalListener unmap;
CHyprSignalListener commit;
} m_listeners;
void registerCallbacks();
// For the list lookup
bool operator==(const CLayerSurface& rhs) const {
return m_layerSurface == rhs.m_layerSurface && m_monitor == rhs.m_monitor;
}
};
inline bool valid(PHLLS l) {
return l;
}
inline bool valid(PHLLSREF l) {
return l;
}
inline bool validMapped(PHLLS l) {
if (!valid(l))
return false;
return l->visible();
}
inline bool validMapped(PHLLSREF l) {
if (!valid(l))
return false;
return l->visible();
}
}

View file

@ -1,43 +1,45 @@
#include "Popup.hpp"
#include "../config/ConfigValue.hpp"
#include "../config/ConfigManager.hpp"
#include "../Compositor.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../managers/SeatManager.hpp"
#include "../managers/animation/AnimationManager.hpp"
#include "../desktop/LayerSurface.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../render/OpenGL.hpp"
#include "../../config/ConfigValue.hpp"
#include "../../config/ConfigManager.hpp"
#include "../../Compositor.hpp"
#include "../../protocols/LayerShell.hpp"
#include "../../protocols/XDGShell.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../managers/SeatManager.hpp"
#include "../../managers/animation/AnimationManager.hpp"
#include "LayerSurface.hpp"
#include "../../managers/input/InputManager.hpp"
#include "../../render/Renderer.hpp"
#include "../../render/OpenGL.hpp"
#include <ranges>
UP<CPopup> CPopup::create(PHLWINDOW pOwner) {
auto popup = UP<CPopup>(new CPopup());
using namespace Desktop;
using namespace Desktop::View;
SP<CPopup> CPopup::create(PHLWINDOW pOwner) {
auto popup = SP<CPopup>(new CPopup());
popup->m_windowOwner = pOwner;
popup->m_self = popup;
popup->initAllSignals();
return popup;
}
UP<CPopup> CPopup::create(PHLLS pOwner) {
auto popup = UP<CPopup>(new CPopup());
SP<CPopup> CPopup::create(PHLLS pOwner) {
auto popup = SP<CPopup>(new CPopup());
popup->m_layerOwner = pOwner;
popup->m_self = popup;
popup->initAllSignals();
return popup;
}
UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) {
auto popup = UP<CPopup>(new CPopup());
SP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) {
auto popup = SP<CPopup>(new CPopup());
popup->m_resource = resource;
popup->m_windowOwner = pOwner->m_windowOwner;
popup->m_layerOwner = pOwner->m_layerOwner;
popup->m_parent = pOwner;
popup->m_self = popup;
popup->m_wlSurface = CWLSurface::create();
popup->m_wlSurface->assign(resource->m_surface->m_surface.lock(), popup.get());
popup->wlSurface()->assign(resource->m_surface->m_surface.lock(), popup);
popup->m_lastSize = resource->m_surface->m_current.geometry.size();
popup->reposition();
@ -46,11 +48,56 @@ UP<CPopup> CPopup::create(SP<CXDGPopupResource> resource, WP<CPopup> pOwner) {
return popup;
}
SP<CPopup> CPopup::fromView(SP<IView> v) {
if (!v || v->type() != VIEW_TYPE_POPUP)
return nullptr;
return dynamicPointerCast<CPopup>(v);
}
CPopup::CPopup() : IView(CWLSurface::create()) {
;
}
CPopup::~CPopup() {
if (m_wlSurface)
m_wlSurface->unassign();
}
eViewType CPopup::type() const {
return VIEW_TYPE_POPUP;
}
bool CPopup::visible() const {
if (!m_mapped || !m_wlSurface->resource())
return false;
if (!m_windowOwner.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowOwner.lock());
if (!m_layerOwner.expired())
return true;
if (m_parent)
return m_parent->visible();
return false;
}
std::optional<CBox> CPopup::logicalBox() const {
return surfaceLogicalBox();
}
std::optional<CBox> CPopup::surfaceLogicalBox() const {
if (!visible())
return std::nullopt;
return CBox{t1ParentCoords(), size()};
}
bool CPopup::desktopComponent() const {
return true;
}
void CPopup::initAllSignals() {
g_pAnimationManager->createAnimation(0.f, m_alpha, g_pConfigManager->getAnimationPropertyConfig("fadePopupsIn"), AVARDAMAGE_NONE);
@ -286,11 +333,11 @@ void CPopup::reposition() {
m_resource->applyPositioning(box, COORDS);
}
SP<CWLSurface> CPopup::getT1Owner() {
SP<Desktop::View::CWLSurface> CPopup::getT1Owner() {
if (m_windowOwner)
return m_windowOwner->m_wlSurface;
return m_windowOwner->wlSurface();
else
return m_layerOwner->m_surface;
return m_layerOwner->wlSurface();
}
Vector2D CPopup::coordsRelativeToParent() {
@ -304,7 +351,7 @@ Vector2D CPopup::coordsRelativeToParent() {
while (current->m_parent && current->m_resource) {
offset += current->m_wlSurface->resource()->m_current.offset;
offset += current->wlSurface()->resource()->m_current.offset;
offset += current->m_resource->m_geometry.pos();
current = current->m_parent;
@ -321,7 +368,7 @@ Vector2D CPopup::localToGlobal(const Vector2D& rel) {
return t1ParentCoords() + rel;
}
Vector2D CPopup::t1ParentCoords() {
Vector2D CPopup::t1ParentCoords() const {
if (!m_windowOwner.expired())
return m_windowOwner->m_realPosition->value();
if (!m_layerOwner.expired())
@ -352,36 +399,25 @@ void CPopup::recheckChildrenRecursive() {
}
}
Vector2D CPopup::size() {
Vector2D CPopup::size() const {
return m_lastSize;
}
void CPopup::sendScale() {
if (!m_windowOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_windowOwner->m_wlSurface->m_lastScaleFloat);
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_windowOwner->wlSurface()->m_lastScaleFloat);
else if (!m_layerOwner.expired())
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_layerOwner->m_surface->m_lastScaleFloat);
g_pCompositor->setPreferredScaleForSurface(m_wlSurface->resource(), m_layerOwner->wlSurface()->m_lastScaleFloat);
else
UNREACHABLE();
}
bool CPopup::visible() {
if (!m_windowOwner.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowOwner.lock());
if (!m_layerOwner.expired())
return true;
if (m_parent)
return m_parent->visible();
return false;
}
void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(WP<CPopup>, void*)> fn, void* data) {
void CPopup::bfHelper(std::vector<SP<CPopup>> const& nodes, std::function<void(SP<CPopup>, void*)> fn, void* data) {
for (auto const& n : nodes) {
fn(n, data);
}
std::vector<WP<CPopup>> nodes2;
std::vector<SP<CPopup>> nodes2;
nodes2.reserve(nodes.size() * 2);
for (auto const& n : nodes) {
@ -389,7 +425,7 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
continue;
for (auto const& c : n->m_children) {
nodes2.push_back(c->m_self);
nodes2.emplace_back(c->m_self.lock());
}
}
@ -397,18 +433,18 @@ void CPopup::bfHelper(std::vector<WP<CPopup>> const& nodes, std::function<void(W
bfHelper(nodes2, fn, data);
}
void CPopup::breadthfirst(std::function<void(WP<CPopup>, void*)> fn, void* data) {
void CPopup::breadthfirst(std::function<void(SP<CPopup>, void*)> fn, void* data) {
if (!m_self)
return;
std::vector<WP<CPopup>> popups;
popups.push_back(m_self);
std::vector<SP<CPopup>> popups;
popups.emplace_back(m_self.lock());
bfHelper(popups, fn, data);
}
WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<WP<CPopup>> popups;
breadthfirst([&popups](WP<CPopup> popup, void* data) { popups.push_back(popup); }, &popups);
SP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
std::vector<SP<CPopup>> popups;
breadthfirst([&popups](SP<CPopup> popup, void* data) { popups.push_back(popup); }, &popups);
for (auto const& p : popups | std::views::reverse) {
if (!p->m_resource || !p->m_mapped)
@ -427,7 +463,7 @@ WP<CPopup> CPopup::at(const Vector2D& globalCoords, bool allowsInput) {
if (BOX.containsPoint(globalCoords))
return p;
} else {
const auto REGION = CRegion{p->m_wlSurface->resource()->m_current.input}.intersect(CBox{{}, p->m_wlSurface->resource()->m_current.size}).translate(p->coordsGlobal());
const auto REGION = CRegion{p->wlSurface()->resource()->m_current.input}.intersect(CBox{{}, p->wlSurface()->resource()->m_current.size}).translate(p->coordsGlobal());
if (REGION.containsPoint(globalCoords))
return p;
}

106
src/desktop/view/Popup.hpp Normal file
View file

@ -0,0 +1,106 @@
#pragma once
#include <vector>
#include "Subsurface.hpp"
#include "View.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../helpers/memory/Memory.hpp"
#include "../../helpers/AnimatedVariable.hpp"
class CXDGPopupResource;
namespace Desktop::View {
class CPopup : public IView {
public:
// dummy head nodes
static SP<CPopup> create(PHLWINDOW pOwner);
static SP<CPopup> create(PHLLS pOwner);
// real nodes
static SP<CPopup> create(SP<CXDGPopupResource> popup, WP<CPopup> pOwner);
static SP<CPopup> fromView(SP<IView>);
virtual ~CPopup();
virtual eViewType type() const;
virtual bool visible() const;
virtual std::optional<CBox> logicalBox() const;
virtual bool desktopComponent() const;
virtual std::optional<CBox> surfaceLogicalBox() const;
SP<Desktop::View::CWLSurface> getT1Owner();
Vector2D coordsRelativeToParent();
Vector2D coordsGlobal();
PHLMONITOR getMonitor();
Vector2D size() const;
void onNewPopup(SP<CXDGPopupResource> popup);
void onDestroy();
void onMap();
void onUnmap();
void onCommit(bool ignoreSiblings = false);
void onReposition();
void recheckTree();
bool inert() const;
// will also loop over this node
void breadthfirst(std::function<void(SP<Desktop::View::CPopup>, void*)> fn, void* data);
SP<Desktop::View::CPopup> at(const Vector2D& globalCoords, bool allowsInput = false);
//
WP<Desktop::View::CPopup> m_self;
bool m_mapped = false;
// fade in-out
PHLANIMVAR<float> m_alpha;
bool m_fadingOut = false;
private:
CPopup();
// T1 owners, each popup has to have one of these
PHLWINDOWREF m_windowOwner;
PHLLSREF m_layerOwner;
// T2 owners
WP<Desktop::View::CPopup> m_parent;
WP<CXDGPopupResource> m_resource;
Vector2D m_lastSize = {};
Vector2D m_lastPos = {};
bool m_requestedReposition = false;
bool m_inert = false;
//
std::vector<SP<Desktop::View::CPopup>> m_children;
SP<Desktop::View::CSubsurface> m_subsurfaceHead;
struct {
CHyprSignalListener newPopup;
CHyprSignalListener destroy;
CHyprSignalListener map;
CHyprSignalListener unmap;
CHyprSignalListener commit;
CHyprSignalListener dismissed;
CHyprSignalListener reposition;
} m_listeners;
void initAllSignals();
void reposition();
void recheckChildrenRecursive();
void sendScale();
void fullyDestroy();
Vector2D localToGlobal(const Vector2D& rel);
Vector2D t1ParentCoords() const;
static void bfHelper(std::vector<SP<CPopup>> const& nodes, std::function<void(SP<CPopup>, void*)> fn, void* data);
};
}

View file

@ -0,0 +1,74 @@
#include "SessionLock.hpp"
#include "../../protocols/SessionLock.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../helpers/Monitor.hpp"
#include "../../Compositor.hpp"
using namespace Desktop;
using namespace Desktop::View;
SP<View::CSessionLock> View::CSessionLock::create(SP<CSessionLockSurface> resource) {
auto lock = SP<CSessionLock>(new CSessionLock());
lock->m_surface = resource;
lock->m_self = lock;
lock->init();
return lock;
}
View::CSessionLock::CSessionLock() : IView(CWLSurface::create()) {
;
}
View::CSessionLock::~CSessionLock() {
m_wlSurface->unassign();
}
void View::CSessionLock::init() {
m_listeners.destroy = m_surface->m_events.destroy.listen([this] { std::erase_if(g_pCompositor->m_otherViews, [this](const auto& e) { return e == m_self; }); });
m_wlSurface->assign(m_surface->surface(), m_self.lock());
}
SP<View::CSessionLock> View::CSessionLock::fromView(SP<IView> v) {
if (!v || v->type() != VIEW_TYPE_LOCK_SCREEN)
return nullptr;
return dynamicPointerCast<View::CSessionLock>(v);
}
eViewType View::CSessionLock::type() const {
return VIEW_TYPE_LOCK_SCREEN;
}
bool View::CSessionLock::visible() const {
return m_wlSurface && m_wlSurface->resource() && m_wlSurface->resource()->m_mapped;
}
std::optional<CBox> View::CSessionLock::logicalBox() const {
return surfaceLogicalBox();
}
std::optional<CBox> View::CSessionLock::surfaceLogicalBox() const {
if (!visible())
return std::nullopt;
const auto MON = m_surface->monitor();
if (!MON)
return std::nullopt;
return MON->logicalBox();
}
bool View::CSessionLock::desktopComponent() const {
return true;
}
PHLMONITOR View::CSessionLock::monitor() const {
if (m_surface)
return m_surface->monitor();
return nullptr;
}

View file

@ -0,0 +1,40 @@
#pragma once
#include "../../defines.hpp"
#include <vector>
#include "WLSurface.hpp"
#include "View.hpp"
class CSessionLockSurface;
namespace Desktop::View {
class CSessionLock : public IView {
public:
static SP<CSessionLock> create(SP<CSessionLockSurface> resource);
static SP<CSessionLock> fromView(SP<IView>);
virtual ~CSessionLock();
virtual eViewType type() const;
virtual bool visible() const;
virtual std::optional<CBox> logicalBox() const;
virtual bool desktopComponent() const;
virtual std::optional<CBox> surfaceLogicalBox() const;
PHLMONITOR monitor() const;
WP<CSessionLock> m_self;
private:
CSessionLock();
void init();
struct {
CHyprSignalListener destroy;
} m_listeners;
WP<CSessionLockSurface> m_surface;
};
}

View file

@ -1,56 +1,101 @@
#include "Subsurface.hpp"
#include "../events/Events.hpp"
#include "../desktop/state/FocusState.hpp"
#include "../desktop/Window.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/core/Subcompositor.hpp"
#include "../render/Renderer.hpp"
#include "../managers/input/InputManager.hpp"
#include "../state/FocusState.hpp"
#include "Window.hpp"
#include "../../config/ConfigValue.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../protocols/core/Subcompositor.hpp"
#include "../../render/Renderer.hpp"
#include "../../managers/input/InputManager.hpp"
UP<CSubsurface> CSubsurface::create(PHLWINDOW pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
using namespace Desktop;
using namespace Desktop::View;
SP<CSubsurface> CSubsurface::create(PHLWINDOW pOwner) {
auto subsurface = SP<CSubsurface>(new CSubsurface());
subsurface->m_windowParent = pOwner;
subsurface->m_self = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_wlSurface->resource());
subsurface->initExistingSubsurfaces(pOwner->wlSurface()->resource());
return subsurface;
}
UP<CSubsurface> CSubsurface::create(WP<CPopup> pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
SP<CSubsurface> CSubsurface::create(WP<Desktop::View::CPopup> pOwner) {
auto subsurface = SP<CSubsurface>(new CSubsurface());
subsurface->m_popupParent = pOwner;
subsurface->m_self = subsurface;
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pOwner->m_wlSurface->resource());
subsurface->initExistingSubsurfaces(pOwner->wlSurface()->resource());
return subsurface;
}
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
SP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner) {
auto subsurface = SP<CSubsurface>(new CSubsurface());
subsurface->m_windowParent = pOwner;
subsurface->m_subsurface = pSubsurface;
subsurface->m_self = subsurface;
subsurface->m_wlSurface = CWLSurface::create();
subsurface->m_wlSurface->assign(pSubsurface->m_surface.lock(), subsurface.get());
subsurface->wlSurface() = CWLSurface::create();
subsurface->wlSurface()->assign(pSubsurface->m_surface.lock(), subsurface);
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->m_surface.lock());
return subsurface;
}
UP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<CPopup> pOwner) {
auto subsurface = UP<CSubsurface>(new CSubsurface());
SP<CSubsurface> CSubsurface::create(SP<CWLSubsurfaceResource> pSubsurface, WP<Desktop::View::CPopup> pOwner) {
auto subsurface = SP<CSubsurface>(new CSubsurface());
subsurface->m_popupParent = pOwner;
subsurface->m_subsurface = pSubsurface;
subsurface->m_self = subsurface;
subsurface->m_wlSurface = CWLSurface::create();
subsurface->m_wlSurface->assign(pSubsurface->m_surface.lock(), subsurface.get());
subsurface->wlSurface() = CWLSurface::create();
subsurface->wlSurface()->assign(pSubsurface->m_surface.lock(), subsurface);
subsurface->initSignals();
subsurface->initExistingSubsurfaces(pSubsurface->m_surface.lock());
return subsurface;
}
SP<CSubsurface> CSubsurface::fromView(SP<IView> v) {
if (!v || v->type() != VIEW_TYPE_SUBSURFACE)
return nullptr;
return dynamicPointerCast<CSubsurface>(v);
}
CSubsurface::CSubsurface() : IView(CWLSurface::create()) {
;
}
eViewType CSubsurface::type() const {
return VIEW_TYPE_SUBSURFACE;
}
bool CSubsurface::visible() const {
if (!m_wlSurface || !m_wlSurface->resource() || !m_wlSurface->resource()->m_mapped)
return false;
if (!m_windowParent.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowParent.lock());
if (m_popupParent)
return m_popupParent->visible();
if (m_parent)
return m_parent->visible();
return false;
}
bool CSubsurface::desktopComponent() const {
return true;
}
std::optional<CBox> CSubsurface::logicalBox() const {
return surfaceLogicalBox();
}
std::optional<CBox> CSubsurface::surfaceLogicalBox() const {
if (!visible())
return std::nullopt;
return CBox{coordsGlobal(), m_lastSize};
}
void CSubsurface::initSignals() {
if (m_subsurface) {
m_listeners.commitSubsurface = m_subsurface->m_surface->m_events.commit.listen([this] { onCommit(); });
@ -60,9 +105,9 @@ void CSubsurface::initSignals() {
m_listeners.newSubsurface = m_subsurface->m_surface->m_events.newSubsurface.listen([this](const auto& resource) { onNewSubsurface(resource); });
} else {
if (m_windowParent)
m_listeners.newSubsurface = m_windowParent->m_wlSurface->resource()->m_events.newSubsurface.listen([this](const auto& resource) { onNewSubsurface(resource); });
m_listeners.newSubsurface = m_windowParent->wlSurface()->resource()->m_events.newSubsurface.listen([this](const auto& resource) { onNewSubsurface(resource); });
else if (m_popupParent)
m_listeners.newSubsurface = m_popupParent->m_wlSurface->resource()->m_events.newSubsurface.listen([this](const auto& resource) { onNewSubsurface(resource); });
m_listeners.newSubsurface = m_popupParent->wlSurface()->resource()->m_events.newSubsurface.listen([this](const auto& resource) { onNewSubsurface(resource); });
else
ASSERT(false);
}
@ -79,14 +124,14 @@ void CSubsurface::checkSiblingDamage() {
continue;
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_wlSurface->resource(), COORDS.x, COORDS.y, SCALE);
g_pHyprRenderer->damageSurface(n->wlSurface()->resource(), COORDS.x, COORDS.y, SCALE);
}
}
void CSubsurface::recheckDamageForSubsurfaces() {
for (auto const& n : m_children) {
const auto COORDS = n->coordsGlobal();
g_pHyprRenderer->damageSurface(n->m_wlSurface->resource(), COORDS.x, COORDS.y);
g_pHyprRenderer->damageSurface(n->wlSurface()->resource(), COORDS.x, COORDS.y);
}
}
@ -105,7 +150,7 @@ void CSubsurface::onCommit() {
g_pHyprRenderer->damageSurface(m_wlSurface->resource(), COORDS.x, COORDS.y);
if (m_popupParent && !m_popupParent->inert() && m_popupParent->m_wlSurface)
if (m_popupParent && !m_popupParent->inert() && m_popupParent->wlSurface())
m_popupParent->recheckTree();
if (!m_windowParent.expired()) // I hate you firefox why are you doing this
m_windowParent->m_popupHead->recheckTree();
@ -187,13 +232,13 @@ void CSubsurface::damageLastArea() {
g_pHyprRenderer->damageBox(box);
}
Vector2D CSubsurface::coordsRelativeToParent() {
Vector2D CSubsurface::coordsRelativeToParent() const {
if (!m_subsurface)
return {};
return m_subsurface->posRelativeToParent();
}
Vector2D CSubsurface::coordsGlobal() {
Vector2D CSubsurface::coordsGlobal() const {
Vector2D coords = coordsRelativeToParent();
if (!m_windowParent.expired())
@ -215,14 +260,3 @@ void CSubsurface::initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface) {
Vector2D CSubsurface::size() {
return m_wlSurface->resource()->m_current.size;
}
bool CSubsurface::visible() {
if (!m_windowParent.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowParent.lock());
if (m_popupParent)
return m_popupParent->visible();
if (m_parent)
return m_parent->visible();
return false;
}

View file

@ -0,0 +1,77 @@
#pragma once
#include "../../defines.hpp"
#include <vector>
#include "WLSurface.hpp"
#include "View.hpp"
class CWLSubsurfaceResource;
namespace Desktop::View {
class CPopup;
class CSubsurface : public IView {
public:
// root dummy nodes
static SP<CSubsurface> create(PHLWINDOW pOwner);
static SP<CSubsurface> create(WP<Desktop::View::CPopup> pOwner);
// real nodes
static SP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, PHLWINDOW pOwner);
static SP<CSubsurface> create(SP<CWLSubsurfaceResource> pSubsurface, WP<Desktop::View::CPopup> pOwner);
static SP<CSubsurface> fromView(SP<IView>);
virtual ~CSubsurface() = default;
virtual eViewType type() const;
virtual bool visible() const;
virtual std::optional<CBox> logicalBox() const;
virtual bool desktopComponent() const;
virtual std::optional<CBox> surfaceLogicalBox() const;
Vector2D coordsRelativeToParent() const;
Vector2D coordsGlobal() const;
Vector2D size();
void onCommit();
void onDestroy();
void onNewSubsurface(SP<CWLSubsurfaceResource> pSubsurface);
void onMap();
void onUnmap();
void recheckDamageForSubsurfaces();
WP<Desktop::View::CSubsurface> m_self;
private:
CSubsurface();
struct {
CHyprSignalListener destroySubsurface;
CHyprSignalListener commitSubsurface;
CHyprSignalListener mapSubsurface;
CHyprSignalListener unmapSubsurface;
CHyprSignalListener newSubsurface;
} m_listeners;
WP<CWLSubsurfaceResource> m_subsurface;
Vector2D m_lastSize = {};
Vector2D m_lastPosition = {};
// if nullptr, means it's a dummy node
WP<Desktop::View::CSubsurface> m_parent;
PHLWINDOWREF m_windowParent;
WP<Desktop::View::CPopup> m_popupParent;
std::vector<SP<Desktop::View::CSubsurface>> m_children;
bool m_inert = false;
void initSignals();
void initExistingSubsurfaces(SP<CWLSurfaceResource> pSurface);
void checkSiblingDamage();
void damageLastArea();
};
}

16
src/desktop/view/View.cpp Normal file
View file

@ -0,0 +1,16 @@
#include "View.hpp"
using namespace Desktop;
using namespace Desktop::View;
SP<Desktop::View::CWLSurface> IView::wlSurface() const {
return m_wlSurface;
}
IView::IView(SP<Desktop::View::CWLSurface> pWlSurface) : m_wlSurface(pWlSurface) {
;
}
SP<CWLSurfaceResource> IView::resource() const {
return m_wlSurface ? m_wlSurface->resource() : nullptr;
}

32
src/desktop/view/View.hpp Normal file
View file

@ -0,0 +1,32 @@
#pragma once
#include "WLSurface.hpp"
#include "../../helpers/math/Math.hpp"
namespace Desktop::View {
enum eViewType : uint8_t {
VIEW_TYPE_WINDOW = 0,
VIEW_TYPE_SUBSURFACE,
VIEW_TYPE_POPUP,
VIEW_TYPE_LAYER_SURFACE,
VIEW_TYPE_LOCK_SCREEN,
};
class IView {
public:
virtual ~IView() = default;
virtual SP<Desktop::View::CWLSurface> wlSurface() const;
virtual SP<CWLSurfaceResource> resource() const;
virtual eViewType type() const = 0;
virtual bool visible() const = 0;
virtual bool desktopComponent() const = 0;
virtual std::optional<CBox> logicalBox() const = 0;
virtual std::optional<CBox> surfaceLogicalBox() const = 0;
protected:
IView(SP<Desktop::View::CWLSurface> pWlSurface);
SP<Desktop::View::CWLSurface> m_wlSurface;
};
};

View file

@ -1,9 +1,12 @@
#include "WLSurface.hpp"
#include "LayerSurface.hpp"
#include "../desktop/Window.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/LayerShell.hpp"
#include "../render/Renderer.hpp"
#include "Window.hpp"
#include "../../protocols/core/Compositor.hpp"
#include "../../protocols/LayerShell.hpp"
#include "../../render/Renderer.hpp"
using namespace Desktop;
using namespace Desktop::View;
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_resource = pSurface;
@ -11,30 +14,9 @@ void CWLSurface::assign(SP<CWLSurfaceResource> pSurface) {
m_inert = false;
}
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLWINDOW pOwner) {
m_windowOwner = pOwner;
m_resource = pSurface;
init();
m_inert = false;
}
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, PHLLS pOwner) {
m_layerOwner = pOwner;
m_resource = pSurface;
init();
m_inert = false;
}
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CSubsurface* pOwner) {
m_subsurfaceOwner = pOwner;
m_resource = pSurface;
init();
m_inert = false;
}
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, CPopup* pOwner) {
m_popupOwner = pOwner;
m_resource = pSurface;
void CWLSurface::assign(SP<CWLSurfaceResource> pSurface, SP<IView> pOwner) {
m_view = pOwner;
m_resource = pSurface;
init();
m_inert = false;
}
@ -56,24 +38,24 @@ SP<CWLSurfaceResource> CWLSurface::resource() const {
}
bool CWLSurface::small() const {
if (!validMapped(m_windowOwner) || !exists())
if (!m_view || !m_view->visible() || m_view->type() != VIEW_TYPE_WINDOW || !exists())
return false;
if (!m_resource->m_current.texture)
return false;
const auto O = m_windowOwner.lock();
const auto O = dynamicPointerCast<CWindow>(m_view.lock());
const auto REPORTED_SIZE = O->getReportedSize();
return REPORTED_SIZE.x > m_resource->m_current.size.x + 1 || REPORTED_SIZE.y > m_resource->m_current.size.y + 1;
}
Vector2D CWLSurface::correctSmallVec() const {
if (!validMapped(m_windowOwner) || !exists() || !small() || m_fillIgnoreSmall)
if (!m_view || !m_view->visible() || m_view->type() != VIEW_TYPE_WINDOW || !exists() || !small() || !m_fillIgnoreSmall)
return {};
const auto SIZE = getViewporterCorrectedSize();
const auto O = m_windowOwner.lock();
const auto O = dynamicPointerCast<CWindow>(m_view.lock());
const auto REP = O->getReportedSize();
return Vector2D{(REP.x - SIZE.x) / 2, (REP.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) * (O->m_realSize->value() / REP);
@ -123,8 +105,8 @@ CRegion CWLSurface::computeDamage() const {
damage.scale(SCALE);
if (BOX.has_value()) {
if (m_windowOwner)
damage.intersect(CBox{{}, BOX->size() * m_windowOwner->m_X11SurfaceScaledBy});
if (m_view->type() == VIEW_TYPE_WINDOW)
damage.intersect(CBox{{}, BOX->size() * dynamicPointerCast<CWindow>(m_view.lock())->m_X11SurfaceScaledBy});
else
damage.intersect(CBox{{}, BOX->size()});
}
@ -142,11 +124,8 @@ void CWLSurface::destroy() {
m_listeners.destroy.reset();
m_resource->m_hlSurface.reset();
m_windowOwner.reset();
m_layerOwner.reset();
m_popupOwner = nullptr;
m_subsurfaceOwner = nullptr;
m_inert = true;
m_view.reset();
m_inert = true;
if (g_pHyprRenderer && g_pHyprRenderer->m_lastCursorData.surf && g_pHyprRenderer->m_lastCursorData.surf->get() == this)
g_pHyprRenderer->m_lastCursorData.surf.reset();
@ -169,40 +148,19 @@ void CWLSurface::init() {
Debug::log(LOG, "CWLSurface {:x} called init()", rc<uintptr_t>(this));
}
PHLWINDOW CWLSurface::getWindow() const {
return m_windowOwner.lock();
}
PHLLS CWLSurface::getLayer() const {
return m_layerOwner.lock();
}
CPopup* CWLSurface::getPopup() const {
return m_popupOwner;
}
CSubsurface* CWLSurface::getSubsurface() const {
return m_subsurfaceOwner;
SP<IView> CWLSurface::view() const {
return m_view.lock();
}
bool CWLSurface::desktopComponent() const {
return !m_layerOwner.expired() || !m_windowOwner.expired() || m_subsurfaceOwner || m_popupOwner;
return m_view && m_view->visible();
}
std::optional<CBox> CWLSurface::getSurfaceBoxGlobal() const {
if (!desktopComponent())
return {};
if (!m_windowOwner.expired())
return m_windowOwner->getWindowMainSurfaceBox();
if (!m_layerOwner.expired())
return m_layerOwner->m_geometry;
if (m_popupOwner)
return CBox{m_popupOwner->coordsGlobal(), m_popupOwner->size()};
if (m_subsurfaceOwner)
return CBox{m_subsurfaceOwner->coordsGlobal(), m_subsurfaceOwner->size()};
return {};
return m_view->surfaceLogicalBox();
}
void CWLSurface::appendConstraint(WP<CPointerConstraint> constraint) {
@ -214,27 +172,23 @@ SP<CPointerConstraint> CWLSurface::constraint() const {
}
bool CWLSurface::visible() {
if (!m_windowOwner.expired())
return g_pHyprRenderer->shouldRenderWindow(m_windowOwner.lock());
if (!m_layerOwner.expired())
return true;
if (m_popupOwner)
return m_popupOwner->visible();
if (m_subsurfaceOwner)
return m_subsurfaceOwner->visible();
if (m_view)
return m_view->visible();
return true; // non-desktop, we don't know much.
}
SP<CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
SP<Desktop::View::CWLSurface> CWLSurface::fromResource(SP<CWLSurfaceResource> pSurface) {
if (!pSurface)
return nullptr;
return pSurface->m_hlSurface.lock();
}
bool CWLSurface::keyboardFocusable() const {
if (m_windowOwner || m_popupOwner || m_subsurfaceOwner)
if (!m_view)
return false;
if (m_view->type() == VIEW_TYPE_WINDOW || m_view->type() == VIEW_TYPE_SUBSURFACE || m_view->type() == VIEW_TYPE_POPUP)
return true;
if (m_layerOwner && m_layerOwner->m_layerSurface)
return m_layerOwner->m_layerSurface->m_current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
if (const auto LS = CLayerSurface::fromView(m_view.lock()); LS && LS->m_layerSurface)
return LS->m_layerSurface->m_current.interactivity != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE;
return false;
}

View file

@ -0,0 +1,118 @@
#pragma once
#include "../../defines.hpp"
#include "../../helpers/math/Math.hpp"
#include "../../helpers/signal/Signal.hpp"
class CPointerConstraint;
class CWLSurfaceResource;
namespace Desktop::View {
class CSubsurface;
class CPopup;
class IView;
class CWLSurface {
public:
static SP<Desktop::View::CWLSurface> create() {
auto p = SP<Desktop::View::CWLSurface>(new CWLSurface);
p->m_self = p;
return p;
}
~CWLSurface();
// anonymous surfaces are non-desktop components, e.g. a cursor surface or a DnD
void assign(SP<CWLSurfaceResource> pSurface);
void assign(SP<CWLSurfaceResource> pSurface, SP<IView> pOwner);
void unassign();
CWLSurface(const CWLSurface&) = delete;
CWLSurface(CWLSurface&&) = delete;
CWLSurface& operator=(const CWLSurface&) = delete;
CWLSurface& operator=(CWLSurface&&) = delete;
SP<CWLSurfaceResource> resource() const;
bool exists() const;
bool small() const; // means surface is smaller than the requested size
Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
Vector2D correctSmallVecBuf() const; // returns a corrective vector for small() surfaces, in BL coords
Vector2D getViewporterCorrectedSize() const;
CRegion computeDamage() const; // logical coordinates. May be wrong if the surface is unassigned
bool visible();
bool keyboardFocusable() const;
SP<IView> view() const;
// desktop components misc utils
std::optional<CBox> getSurfaceBoxGlobal() const;
void appendConstraint(WP<CPointerConstraint> constraint);
SP<CPointerConstraint> constraint() const;
// allow stretching. Useful for plugins.
bool m_fillIgnoreSmall = false;
// track surface data and avoid dupes
float m_lastScaleFloat = 0;
int m_lastScaleInt = 0;
wl_output_transform m_lastTransform = sc<wl_output_transform>(-1);
//
CWLSurface& operator=(SP<CWLSurfaceResource> pSurface) {
destroy();
m_resource = pSurface;
init();
return *this;
}
bool operator==(const CWLSurface& other) const {
return other.resource() == resource();
}
bool operator==(const SP<CWLSurfaceResource> other) const {
return other == resource();
}
explicit operator bool() const {
return exists();
}
static SP<Desktop::View::CWLSurface> fromResource(SP<CWLSurfaceResource> pSurface);
// used by the alpha-modifier protocol
float m_alphaModifier = 1.F;
// used by the hyprland-surface protocol
float m_overallOpacity = 1.F;
CRegion m_visibleRegion;
struct {
CSignalT<> destroy;
} m_events;
WP<Desktop::View::CWLSurface> m_self;
private:
CWLSurface() = default;
bool m_inert = true;
WP<CWLSurfaceResource> m_resource;
WP<IView> m_view;
//
WP<CPointerConstraint> m_constraint;
void destroy();
void init();
bool desktopComponent() const;
struct {
CHyprSignalListener destroy;
} m_listeners;
friend class ::CPointerConstraint;
friend class CXxColorManagerV4;
};
}

File diff suppressed because it is too large Load diff

454
src/desktop/view/Window.hpp Normal file
View file

@ -0,0 +1,454 @@
#pragma once
#include <vector>
#include <string>
#include <optional>
#include "View.hpp"
#include "../../config/ConfigDataValues.hpp"
#include "../../helpers/AnimatedVariable.hpp"
#include "../../helpers/TagKeeper.hpp"
#include "../../macros.hpp"
#include "../../managers/XWaylandManager.hpp"
#include "../../render/decorations/IHyprWindowDecoration.hpp"
#include "../../render/Transformer.hpp"
#include "../DesktopTypes.hpp"
#include "Popup.hpp"
#include "Subsurface.hpp"
#include "WLSurface.hpp"
#include "../Workspace.hpp"
#include "../rule/windowRule/WindowRuleApplicator.hpp"
#include "../../protocols/types/ContentType.hpp"
class CXDGSurfaceResource;
class CXWaylandSurface;
struct SWorkspaceRule;
class IWindowTransformer;
namespace Desktop::View {
enum eGroupRules : uint8_t {
// effective only during first map, except for _ALWAYS variant
GROUP_NONE = 0,
GROUP_SET = 1 << 0, // Open as new group or add to focused group
GROUP_SET_ALWAYS = 1 << 1,
GROUP_BARRED = 1 << 2, // Don't insert to focused group.
GROUP_LOCK = 1 << 3, // Lock m_sGroupData.lock
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
};
enum eGetWindowProperties : uint8_t {
WINDOW_ONLY = 0,
RESERVED_EXTENTS = 1 << 0,
INPUT_EXTENTS = 1 << 1,
FULL_EXTENTS = 1 << 2,
FLOATING_ONLY = 1 << 3,
ALLOW_FLOATING = 1 << 4,
USE_PROP_TILED = 1 << 5,
SKIP_FULLSCREEN_PRIORITY = 1 << 6,
FOCUS_PRIORITY = 1 << 7,
};
enum eSuppressEvents : uint8_t {
SUPPRESS_NONE = 0,
SUPPRESS_FULLSCREEN = 1 << 0,
SUPPRESS_MAXIMIZE = 1 << 1,
SUPPRESS_ACTIVATE = 1 << 2,
SUPPRESS_ACTIVATE_FOCUSONLY = 1 << 3,
SUPPRESS_FULLSCREEN_OUTPUT = 1 << 4,
};
struct SInitialWorkspaceToken {
PHLWINDOWREF primaryOwner;
std::string workspace;
};
struct SFullscreenState {
eFullscreenMode internal = FSMODE_NONE;
eFullscreenMode client = FSMODE_NONE;
};
class CWindow : public IView {
public:
static PHLWINDOW create(SP<CXDGSurfaceResource>);
static PHLWINDOW create(SP<CXWaylandSurface>);
static PHLWINDOW fromView(SP<IView>);
private:
CWindow(SP<CXDGSurfaceResource> resource);
CWindow(SP<CXWaylandSurface> surface);
public:
virtual ~CWindow();
virtual eViewType type() const;
virtual bool visible() const;
virtual std::optional<CBox> logicalBox() const;
virtual bool desktopComponent() const;
virtual std::optional<CBox> surfaceLogicalBox() const;
struct {
CSignalT<> destroy;
} m_events;
WP<CXDGSurfaceResource> m_xdgSurface;
WP<CXWaylandSurface> m_xwaylandSurface;
// this is the position and size of the "bounding box"
Vector2D m_position = Vector2D(0, 0);
Vector2D m_size = Vector2D(0, 0);
// this is the real position and size used to draw the thing
PHLANIMVAR<Vector2D> m_realPosition;
PHLANIMVAR<Vector2D> m_realSize;
// for not spamming the protocols
Vector2D m_reportedPosition;
Vector2D m_reportedSize;
Vector2D m_pendingReportedSize;
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 = "";
std::string m_initialTitle = "";
std::string m_initialClass = "";
PHLWORKSPACE m_workspace;
PHLMONITORREF m_monitor;
bool m_isMapped = false;
bool m_requestsFloat = false;
// This is for fullscreen apps
bool m_createdOverFullscreen = false;
// XWayland stuff
bool m_isX11 = false;
bool m_X11DoesntWantBorders = false;
bool m_X11ShouldntFocus = false;
float m_X11SurfaceScaledBy = 1.f;
//
// For nofocus
bool m_noInitialFocus = false;
// Fullscreen and Maximize
bool m_wantsInitialFullscreen = false;
MONITORID m_wantsInitialFullscreenMonitor = MONITOR_INVALID;
// bitfield suppressEvents
uint64_t m_suppressedEvents = SUPPRESS_NONE;
// desktop components
SP<Desktop::View::CSubsurface> m_subsurfaceHead;
SP<Desktop::View::CPopup> m_popupHead;
// Animated border
CGradientValueData m_realBorderColor = {0};
CGradientValueData m_realBorderColorPrevious = {0};
PHLANIMVAR<float> m_borderFadeAnimationProgress;
PHLANIMVAR<float> m_borderAngleAnimationProgress;
// Fade in-out
PHLANIMVAR<float> m_alpha;
bool m_fadingOut = false;
bool m_readyToDelete = false;
Vector2D m_originalClosedPos; // these will be used for calculations later on in
Vector2D m_originalClosedSize; // drawing the closing animations
SBoxExtents m_originalClosedExtents;
bool m_animatingIn = false;
// For pinned (sticky) windows
bool m_pinned = false;
// For preserving pinned state when fullscreening a pinned window
bool m_pinFullscreened = false;
// urgency hint
bool m_isUrgent = false;
// for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window.
PHLWINDOWREF m_lastCycledWindow;
// Window decorations
// TODO: make this a SP.
std::vector<UP<IHyprWindowDecoration>> m_windowDecorations;
std::vector<IHyprWindowDecoration*> m_decosToRemove;
// Special render data, rules, etc
UP<Desktop::Rule::CWindowRuleApplicator> m_ruleApplicator;
// Transformers
std::vector<UP<IWindowTransformer>> m_transformers;
// for alpha
PHLANIMVAR<float> m_activeInactiveAlpha;
PHLANIMVAR<float> m_movingFromWorkspaceAlpha;
// animated shadow color
PHLANIMVAR<CHyprColor> m_realShadowColor;
// animated tint
PHLANIMVAR<float> m_dimPercent;
// animate moving to an invisible workspace
int m_monitorMovedFrom = -1; // -1 means not moving
PHLANIMVAR<float> m_movingToWorkspaceAlpha;
// swallowing
PHLWINDOWREF m_swallowed;
bool m_currentlySwallowed = false;
bool m_groupSwallowed = false;
// for toplevel monitor events
MONITORID m_lastSurfaceMonitorID = -1;
// initial token. Will be unregistered on workspace change or timeout of 2 minutes
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;
bool m_tearingHint = false;
// ANR
PHLANIMVAR<float> m_notRespondingTint;
// For the noclosefor windowrule
Time::steady_tp m_closeableSince = Time::steadyNow();
// For the list lookup
bool operator==(const CWindow& rhs) const {
return m_xdgSurface == rhs.m_xdgSurface && m_xwaylandSurface == rhs.m_xwaylandSurface && m_position == rhs.m_position && m_size == rhs.m_size &&
m_fadingOut == rhs.m_fadingOut;
}
// methods
CBox getFullWindowBoundingBox() const;
SBoxExtents getFullWindowExtents() const;
CBox getWindowBoxUnified(uint64_t props);
SBoxExtents getWindowExtentsUnified(uint64_t props);
CBox getWindowIdealBoundingBoxIgnoreReserved();
void addWindowDeco(UP<IHyprWindowDecoration> deco);
void updateWindowDecos();
void removeWindowDeco(IHyprWindowDecoration* deco);
void uncacheWindowDecos();
bool checkInputOnDecos(const eInputType, const Vector2D&, std::any = {});
pid_t getPID();
IHyprWindowDecoration* getDecorationByType(eDecorationType);
void updateToplevel();
void updateSurfaceScaleTransformDetails(bool force = false);
void moveToWorkspace(PHLWORKSPACE);
PHLWINDOW x11TransientFor();
void onUnmap();
void onMap();
void setHidden(bool hidden);
bool isHidden();
void updateDecorationValues();
SBoxExtents getFullWindowReservedArea();
Vector2D middle();
bool opaque();
float rounding();
float roundingPower();
bool canBeTorn();
void setSuspended(bool suspend);
bool visibleOnMonitor(PHLMONITOR pMonitor);
WORKSPACEID workspaceID();
MONITORID monitorID();
bool onSpecialWorkspace();
void activate(bool force = false);
int surfacesCount();
void clampWindowSize(const std::optional<Vector2D> minSize, const std::optional<Vector2D> maxSize);
bool isFullscreen();
bool isEffectiveInternalFSMode(const eFullscreenMode) const;
int getRealBorderSize() const;
float getScrollMouse();
float getScrollTouchpad();
bool isScrollMouseOverridden();
bool isScrollTouchpadOverridden();
void updateWindowData();
void updateWindowData(const SWorkspaceRule&);
void onBorderAngleAnimEnd(WP<Hyprutils::Animation::CBaseAnimatedVariable> pav);
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();
void onUpdateState();
void onUpdateMeta();
void onX11ConfigureRequest(CBox box);
void onResourceChangeX11();
std::string fetchTitle();
std::string fetchClass();
void warpCursor(bool force = false);
PHLWINDOW getSwallower();
bool isX11OverrideRedirect();
bool isModal();
Vector2D requestedMinSize();
Vector2D requestedMaxSize();
Vector2D realToReportSize();
Vector2D realToReportPosition();
Vector2D xwaylandSizeToReal(Vector2D size);
Vector2D xwaylandPositionToReal(Vector2D size);
void updateX11SurfaceScale();
void sendWindowSize(bool force = false);
NContentType::eContentType getContentType();
void setContentType(NContentType::eContentType contentType);
void deactivateGroupMembers();
bool isNotResponding();
std::optional<std::string> xdgTag();
std::optional<std::string> xdgDescription();
PHLWINDOW parent();
bool priorityFocus();
SP<CWLSurfaceResource> getSolitaryResource();
Vector2D getReportedSize();
std::optional<Vector2D> calculateExpression(const std::string& s);
CBox getWindowMainSurfaceBox() const {
return {m_realPosition->value().x, m_realPosition->value().y, m_realSize->value().x, m_realSize->value().y};
}
// listeners
void onAck(uint32_t serial);
//
std::unordered_map<std::string, std::string> getEnv();
//
PHLWINDOWREF m_self;
// make private once we move listeners to inside CWindow
struct {
CHyprSignalListener map;
CHyprSignalListener ack;
CHyprSignalListener unmap;
CHyprSignalListener commit;
CHyprSignalListener destroy;
CHyprSignalListener activate;
CHyprSignalListener configureRequest;
CHyprSignalListener setGeometry;
CHyprSignalListener updateState;
CHyprSignalListener updateMetadata;
CHyprSignalListener resourceChange;
} m_listeners;
private:
std::optional<double> calculateSingleExpr(const std::string& s);
void mapWindow();
void unmapWindow();
void commitWindow();
void destroyWindow();
void activateX11();
void unmanagedSetGeometry();
// For hidden windows and stuff
bool m_hidden = false;
bool m_suspended = false;
WORKSPACEID m_lastWorkspace = WORKSPACE_INVALID;
};
inline bool valid(PHLWINDOW w) {
return w.get();
}
inline bool valid(PHLWINDOWREF w) {
return !w.expired();
}
inline bool validMapped(PHLWINDOW w) {
if (!valid(w))
return false;
return w->m_isMapped;
}
inline bool validMapped(PHLWINDOWREF w) {
if (!valid(w))
return false;
return w->m_isMapped;
}
}
/**
format specification
- 'x', only address, equivalent of (uintpr_t)CWindow*
- 'm', with monitor id
- 'w', with workspace id
- 'c', with application class
*/
template <typename CharT>
struct std::formatter<PHLWINDOW, CharT> : std::formatter<CharT> {
bool formatAddressOnly = false;
bool formatWorkspace = false;
bool formatMonitor = false;
bool formatClass = false;
FORMAT_PARSE( //
FORMAT_FLAG('x', formatAddressOnly) //
FORMAT_FLAG('m', formatMonitor) //
FORMAT_FLAG('w', formatWorkspace) //
FORMAT_FLAG('c', formatClass),
PHLWINDOW)
template <typename FormatContext>
auto format(PHLWINDOW const& w, FormatContext& ctx) const {
auto&& out = ctx.out();
if (formatAddressOnly)
return std::format_to(out, "{:x}", rc<uintptr_t>(w.get()));
if (!w)
return std::format_to(out, "[Window nullptr]");
std::format_to(out, "[");
std::format_to(out, "Window {:x}: title: \"{}\"", rc<uintptr_t>(w.get()), w->m_title);
if (formatWorkspace)
std::format_to(out, ", workspace: {}", w->m_workspace ? w->workspaceID() : WORKSPACE_INVALID);
if (formatMonitor)
std::format_to(out, ", monitor: {}", w->monitorID());
if (formatClass)
std::format_to(out, ", class: {}", w->m_class);
return std::format_to(out, "]");
}
};