#pragma once #include #include #include #include "View.hpp" #include "../../config/shared/complex/ComplexDataTypes.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 "../types/MultiAnimatedVariable.hpp" #include "Popup.hpp" #include "Subsurface.hpp" #include "WLSurface.hpp" #include "../Workspace.hpp" #include "../rule/windowRule/WindowRuleApplicator.hpp" #include "../../protocols/types/ContentType.hpp" #include "../../render/Framebuffer.hpp" class CXDGSurfaceResource; class CXWaylandSurface; class IWindowTransformer; namespace Config { class CWorkspaceRule; } namespace Layout { class ITarget; class CWindowTarget; } namespace Desktop { enum eFocusReason : uint8_t; } namespace Desktop::View { class CGroup; enum eGroupRules : uint8_t { // effective only during first map, except for _ALWAYS variant GROUP_NONE = 0, 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 GROUP_DENY = 1 << 7, // deny }; enum eGetWindowProperties : uint16_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, FOLLOW_MOUSE_CHECK = 1 << 8, }; 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, }; enum eWindowAlpha : uint8_t { WINDOW_ALPHA_FADE = 0, WINDOW_ALPHA_ACTIVE, WINDOW_ALPHA_FULLSCREEN, WINDOW_ALPHA_LAYOUT, WINDOW_ALPHA_MOVE_TO_WORKSPACE, WINDOW_ALPHA_MOVE_FROM_WORKSPACE, WINDOW_ALPHA_LAST, }; enum eWindowInputBlockReason : uint8_t { INPUT_BLOCK_NONE = 0, INPUT_BLOCK_GROUP_INACTIVE = (1 << 0), INPUT_BLOCK_MONOCLE_INACTIVE = (1 << 1), INPUT_BLOCK_BELOW_FULLSCREEN = (1 << 2), INPUT_BLOCK_ALL = std::numeric_limits>::max(), }; struct SWindowActiveEvent { PHLWINDOW window = nullptr; eFocusReason reason = sc(0) /* unknown */; }; 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); static PHLWINDOW create(SP); static PHLWINDOW fromView(SP); private: CWindow(SP resource); CWindow(SP surface); public: virtual ~CWindow(); virtual eViewType type() const; virtual bool visible() const; virtual std::optional logicalBox() const; virtual bool desktopComponent() const; virtual std::optional surfaceLogicalBox() const; struct { CSignalT<> destroy; CSignalT<> unmap; CSignalT<> hide; CSignalT<> resize; CSignalT<> monitorChanged; } m_events; WP m_xdgSurface; WP m_xwaylandSurface; SP m_target; // 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 m_realPosition; PHLANIMVAR m_realSize; // for not spamming the protocols Vector2D m_reportedPosition; Vector2D m_reportedSize; Vector2D m_pendingReportedSize; std::optional> m_pendingSizeAck; std::vector> m_pendingSizeAcks; // for floating window offset in workspace animations Vector2D m_floatingOffset = Vector2D(0, 0); // for recovering relative cursor position Vector2D m_relativeCursorCoordsOnLastWarp = Vector2D(-1, -1); bool m_firstMap = false; // for layouts bool m_isFloating = false; 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, m_prevMonitor; 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 m_subsurfaceHead; SP m_popupHead; // Animated border Config::CGradientValueData m_realBorderColor = {0}; Config::CGradientValueData m_realBorderColorPrevious = {0}; PHLANIMVAR m_borderFadeAnimationProgress; PHLANIMVAR m_borderAngleAnimationProgress; // Cached border size (invalidated by updateWindowData) mutable int m_cachedBorderSize = -1; mutable bool m_borderSizeCacheDirty = true; // Fade in-out Desktop::Types::CMultiAVarContainer 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> m_windowDecorations; std::vector m_decosToRemove; // Special render data, rules, etc UP m_ruleApplicator; // Transformers std::vector> m_transformers; // animated shadow color PHLANIMVAR m_realShadowColor; // animated glow color PHLANIMVAR m_realGlowColor; // animated tint PHLANIMVAR m_dimPercent; // animate moving to an invisible workspace int m_monitorMovedFrom = -1; // -1 means not moving // 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 SP m_group; uint16_t m_groupRules = Desktop::View::GROUP_NONE; bool m_tearingHint = false; // Stable ID for ext_foreign_toplevel_list const uint64_t m_stableID = 0x2137; // snapshots SP m_snapshotFB; // ANR PHLANIMVAR m_notRespondingTint; // For the noclosefor windowrule Time::steady_tp m_closeableSince = Time::steadyNow(); // layout-settable flags. These are reset when layout changes. struct { bool cantLockCursor = false; } m_layoutFlags; // 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 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() const; void setInputBlocked(eWindowInputBlockReason reason, bool blocked); bool isInputBlocked() const; bool isInputBlocked(std::underlying_type_t reasons) const; bool isInputBlockedOnly(eWindowInputBlockReason reason) const; bool acceptsInput() const; bool isAllowedOverFullscreen() const; bool isBlockedByFullscreen() const; bool isFadingOutUnderFullscreen() const; bool shouldRenderOverFullscreen() const; void updateFullscreenInputState(); PHLANIMVAR& alpha(eWindowAlpha type); const PHLANIMVAR& alpha(eWindowAlpha type) const; float alphaValue(eWindowAlpha type) const; float alphaGoal(eWindowAlpha type) const; float alphaTotal() const; float alphaTotalGoal() const; float alphaTotalWithout(eWindowAlpha type) const; float effectiveAlpha() const; bool visibleByAlpha() const; bool visibleByAlphaGoal() const; bool targetVisible() const; 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(); bool clampWindowSize(const std::optional minSize, const std::optional maxSize); bool isFullscreen() const; bool isEffectiveInternalFSMode(const eFullscreenMode) const; int getRealBorderSize() const; float getScrollMouse(); float getScrollTouchpad(); bool isScrollMouseOverridden(); bool isScrollTouchpadOverridden(); void updateWindowData(); void updateWindowData(const Config::CWorkspaceRule&); void onBorderAngleAnimEnd(WP pav); bool isInCurvedCorner(double x, double y); bool hasPopupAt(const Vector2D& pos); int popupsCount(); 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 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 xdgTag(); std::optional xdgDescription(); PHLWINDOW parent(); bool priorityFocus(); SP getSolitaryResource(); Vector2D getReportedSize(); std::optional calculateExpression(const std::string& s); std::optional calculateExpression(const Math::SExpressionVec2& expr); std::optional minSize(); std::optional maxSize(); SP layoutTarget(); bool canBeGroupedInto(SP group); void sendClose(); 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 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 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; uint32_t m_inputBlockReasons = INPUT_BLOCK_NONE; }; 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 struct std::formatter : std::formatter { 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 auto format(PHLWINDOW const& w, FormatContext& ctx) const { auto&& out = ctx.out(); if (formatAddressOnly) return std::format_to(out, "{:x}", rc(w.get())); if (!w) return std::format_to(out, "[Window nullptr]"); std::format_to(out, "["); std::format_to(out, "Window {:x}: title: \"{}\"", rc(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, "]"); } };