#pragma once #include "defines.hpp" #include "helpers/SubsurfaceTree.hpp" #include "helpers/AnimatedVariable.hpp" #include "render/decorations/IHyprWindowDecoration.hpp" #include #include "config/ConfigDataValues.hpp" #include "helpers/Vector2D.hpp" #include "helpers/WLSurface.hpp" #include "macros.hpp" #include "managers/XWaylandManager.hpp" enum eIdleInhibitMode { IDLEINHIBIT_NONE = 0, IDLEINHIBIT_ALWAYS, IDLEINHIBIT_FULLSCREEN, IDLEINHIBIT_FOCUS }; enum eGroupRules { // 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 }; class IWindowTransformer; template class CWindowOverridableVar { public: CWindowOverridableVar(T val) { value = val; } ~CWindowOverridableVar() = default; CWindowOverridableVar& operator=(CWindowOverridableVar other) { if (locked) return *this; locked = other.locked; value = other.value; return *this; } T operator=(T& other) { if (locked) return value; value = other; return other; } void forceSetIgnoreLocked(T val, bool lock = false) { value = val; locked = lock; } T operator*(T& other) { return value * other; } T operator+(T& other) { return value + other; } bool operator==(T& other) { return other == value; } bool operator>=(T& other) { return value >= other; } bool operator<=(T& other) { return value <= other; } bool operator>(T& other) { return value > other; } bool operator<(T& other) { return value < other; } explicit operator bool() { return static_cast(value); } T toUnderlying() { return value; } bool locked = false; private: T value; }; struct SWindowSpecialRenderData { CWindowOverridableVar alphaOverride = false; CWindowOverridableVar alpha = 1.f; CWindowOverridableVar alphaInactiveOverride = false; CWindowOverridableVar alphaInactive = -1.f; // -1 means unset CWindowOverridableVar activeBorderColor = -1; // -1 means unset CWindowOverridableVar inactiveBorderColor = -1; // -1 means unset // set by the layout CWindowOverridableVar borderSize = -1; // -1 means unset bool rounding = true; bool border = true; bool decorate = true; bool shadow = true; }; struct SWindowAdditionalConfigData { std::string animationStyle = std::string(""); CWindowOverridableVar rounding = -1; // -1 means no CWindowOverridableVar forceNoBlur = false; CWindowOverridableVar forceOpaque = false; CWindowOverridableVar forceOpaqueOverridden = false; // if true, a rule will not change the forceOpaque state. This is for the force opaque dispatcher. CWindowOverridableVar forceAllowsInput = false; CWindowOverridableVar forceNoAnims = false; CWindowOverridableVar forceNoBorder = false; CWindowOverridableVar forceNoShadow = false; CWindowOverridableVar forceNoDim = false; CWindowOverridableVar windowDanceCompat = false; CWindowOverridableVar noMaxSize = false; CWindowOverridableVar dimAround = false; CWindowOverridableVar forceRGBX = false; CWindowOverridableVar keepAspectRatio = false; CWindowOverridableVar xray = -1; // -1 means unset, takes precedence over the renderdata one CWindowOverridableVar borderSize = -1; // -1 means unset, takes precedence over the renderdata one CWindowOverridableVar forceTearing = false; }; struct SWindowRule { std::string szRule; std::string szValue; bool v2 = false; std::string szTitle; std::string szClass; int bX11 = -1; // -1 means "ANY" int bFloating = -1; int bFullscreen = -1; int bPinned = -1; std::string szWorkspace = ""; // empty means any }; class CWindow { public: CWindow(); ~CWindow(); DYNLISTENER(commitWindow); DYNLISTENER(mapWindow); DYNLISTENER(unmapWindow); DYNLISTENER(destroyWindow); DYNLISTENER(setTitleWindow); DYNLISTENER(setGeometryX11U); DYNLISTENER(fullscreenWindow); DYNLISTENER(newPopupXDG); DYNLISTENER(requestMove); DYNLISTENER(requestMinimize); DYNLISTENER(requestMaximize); DYNLISTENER(requestResize); DYNLISTENER(activateX11); DYNLISTENER(configureX11); DYNLISTENER(toplevelClose); DYNLISTENER(toplevelActivate); DYNLISTENER(toplevelFullscreen); DYNLISTENER(setOverrideRedirect); DYNLISTENER(associateX11); DYNLISTENER(dissociateX11); // DYNLISTENER(newSubsurfaceWindow); CWLSurface m_pWLSurface; std::list m_lPopupSurfaces; union { wlr_xdg_surface* xdg; wlr_xwayland_surface* xwayland; } m_uSurface; // this is the position and size of the "bounding box" Vector2D m_vPosition = Vector2D(0, 0); Vector2D m_vSize = Vector2D(0, 0); // this is the real position and size used to draw the thing CAnimatedVariable m_vRealPosition; CAnimatedVariable m_vRealSize; // for not spamming the protocols Vector2D m_vReportedPosition; Vector2D m_vReportedSize; Vector2D m_vPendingReportedSize; // for restoring floating statuses Vector2D m_vLastFloatingSize; Vector2D m_vLastFloatingPosition; // this is used for pseudotiling bool m_bIsPseudotiled = false; Vector2D m_vPseudoSize = Vector2D(0, 0); bool m_bFirstMap = false; // for layouts bool m_bIsFloating = false; bool m_bDraggingTiled = false; // for dragging around tiled windows bool m_bIsFullscreen = false; bool m_bWasMaximized = false; uint64_t m_iMonitorID = -1; std::string m_szTitle = ""; std::string m_szInitialTitle = ""; std::string m_szInitialClass = ""; int m_iWorkspaceID = -1; bool m_bIsMapped = false; bool m_bRequestsFloat = false; // This is for fullscreen apps bool m_bCreatedOverFullscreen = false; // XWayland stuff bool m_bIsX11 = false; bool m_bMappedX11 = false; CWindow* m_pX11Parent = nullptr; uint64_t m_iX11Type = 0; bool m_bIsModal = false; bool m_bX11DoesntWantBorders = false; bool m_bX11ShouldntFocus = false; float m_fX11SurfaceScaledBy = 1.f; // // For nofocus bool m_bNoFocus = false; bool m_bNoInitialFocus = false; // Fullscreen and Maximize bool m_bWantsInitialFullscreen = false; bool m_bNoFullscreenRequest = false; bool m_bNoMaximizeRequest = false; SSurfaceTreeNode* m_pSurfaceTree = nullptr; // Animated border CGradientValueData m_cRealBorderColor = {0}; CGradientValueData m_cRealBorderColorPrevious = {0}; CAnimatedVariable m_fBorderFadeAnimationProgress; CAnimatedVariable m_fBorderAngleAnimationProgress; // Fade in-out CAnimatedVariable m_fAlpha; bool m_bFadingOut = false; bool m_bReadyToDelete = false; Vector2D m_vOriginalClosedPos; // these will be used for calculations later on in Vector2D m_vOriginalClosedSize; // drawing the closing animations SWindowDecorationExtents m_eOriginalClosedExtents; // For pinned (sticky) windows bool m_bPinned = false; // urgency hint bool m_bIsUrgent = false; // fakefullscreen bool m_bFakeFullscreenState = false; // for proper cycling. While cycling we can't just move the pointers, so we need to keep track of the last cycled window. CWindow* m_pLastCycledWindow = nullptr; // Foreign Toplevel proto wlr_foreign_toplevel_handle_v1* m_phForeignToplevel = nullptr; // Window decorations std::deque> m_dWindowDecorations; std::vector m_vDecosToRemove; // Special render data, rules, etc SWindowSpecialRenderData m_sSpecialRenderData; SWindowAdditionalConfigData m_sAdditionalConfigData; // Transformers std::vector> m_vTransformers; // for alpha CAnimatedVariable m_fActiveInactiveAlpha; // animated shadow color CAnimatedVariable m_cRealShadowColor; // animated tint CAnimatedVariable m_fDimPercent; // swallowing CWindow* m_pSwallowed = nullptr; // focus stuff bool m_bStayFocused = false; // for toplevel monitor events uint64_t m_iLastToplevelMonitorID = -1; uint64_t m_iLastSurfaceMonitorID = -1; // for idle inhibiting windows eIdleInhibitMode m_eIdleInhibitMode = IDLEINHIBIT_NONE; // for groups struct SGroupData { CWindow* pNextWindow = nullptr; // 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_sGroupData; uint16_t m_eGroupRules = GROUP_NONE; bool m_bTearingHint = false; // For the list lookup bool operator==(const CWindow& rhs) { return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize && m_bFadingOut == rhs.m_bFadingOut; } // methods wlr_box getFullWindowBoundingBox(); SWindowDecorationExtents getFullWindowExtents(); wlr_box getWindowInputBox(); wlr_box getWindowIdealBoundingBoxIgnoreReserved(); void updateWindowDecos(); pid_t getPID(); IHyprWindowDecoration* getDecorationByType(eDecorationType); void removeDecorationByType(eDecorationType); void createToplevelHandle(); void destroyToplevelHandle(); void updateToplevel(); void updateSurfaceOutputs(); void moveToWorkspace(int); CWindow* X11TransientFor(); void onUnmap(); void onMap(); void setHidden(bool hidden); bool isHidden(); void applyDynamicRule(const SWindowRule& r); void updateDynamicRules(); SWindowDecorationExtents getFullWindowReservedArea(); Vector2D middle(); bool opaque(); float rounding(); bool canBeTorn(); int getRealBorderSize(); void updateSpecialRenderData(); void onBorderAngleAnimEnd(void* ptr); bool isInCurvedCorner(double x, double y); bool hasPopupAt(const Vector2D& pos); void applyGroupRules(); void createGroup(); void destroyGroup(); CWindow* getGroupHead(); CWindow* getGroupTail(); CWindow* getGroupCurrent(); CWindow* getGroupPrevious(); CWindow* getGroupWindowByIndex(int); int getGroupSize(); void setGroupCurrent(CWindow* pWindow); void insertWindowToGroup(CWindow* pWindow); void updateGroupOutputs(); void switchWithWindowInGroup(CWindow* pWindow); private: // For hidden windows and stuff bool m_bHidden = false; }; /** 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), CWindow*) template auto format(CWindow* const& w, FormatContext& ctx) const { auto&& out = ctx.out(); if (formatAddressOnly) return std::format_to(out, "{:x}", (uintptr_t)w); if (!w) return std::format_to(out, "[Window nullptr]"); std::format_to(out, "["); std::format_to(out, "Window {:x}: title: \"{}\"", (uintptr_t)w, w->m_szTitle); if (formatWorkspace) std::format_to(out, ", workspace: {}", w->m_iWorkspaceID); if (formatMonitor) std::format_to(out, ", monitor: {}", w->m_iMonitorID); if (formatClass) std::format_to(out, ", class: {}", g_pXWaylandManager->getAppIDClass(w)); return std::format_to(out, "]"); } };