2025-05-09 00:31:49 +05:30
# include <algorithm>
2025-05-30 18:25:59 +05:00
# include <ranges>
2025-01-07 17:55:14 +00:00
# include <hyprutils/animation/AnimatedVariable.hpp>
2024-12-16 19:21:44 +01:00
# include <re2/re2.h>
2025-11-27 07:12:50 +09:00
# if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
# include <sys/types.h>
# include <sys/sysctl.h>
# endif
2024-05-29 05:37:24 +08:00
# include <any>
2024-08-03 12:02:10 +00:00
# include <bit>
2024-05-29 05:37:24 +08:00
# include <string_view>
2022-03-30 21:18:42 +02:00
# include "Window.hpp"
2025-12-08 15:04:40 +00:00
# include "LayerSurface.hpp"
# include "../state/FocusState.hpp"
# include "../../Compositor.hpp"
# include "../../render/decorations/CHyprDropShadowDecoration.hpp"
# include "../../render/decorations/CHyprGroupBarDecoration.hpp"
# include "../../render/decorations/CHyprBorderDecoration.hpp"
# include "../../config/ConfigValue.hpp"
# include "../../config/ConfigManager.hpp"
# include "../../managers/TokenManager.hpp"
# include "../../managers/animation/AnimationManager.hpp"
# include "../../managers/ANRManager.hpp"
# include "../../managers/eventLoop/EventLoopManager.hpp"
# include "../../protocols/XDGShell.hpp"
# include "../../protocols/core/Compositor.hpp"
# include "../../protocols/core/Subcompositor.hpp"
# include "../../protocols/ContentType.hpp"
# include "../../protocols/FractionalScale.hpp"
# include "../../protocols/LayerShell.hpp"
# include "../../xwayland/XWayland.hpp"
# include "../../helpers/Color.hpp"
# include "../../helpers/math/Expression.hpp"
# include "../../managers/XWaylandManager.hpp"
# include "../../render/Renderer.hpp"
# include "../../managers/LayoutManager.hpp"
# include "../../managers/HookSystemManager.hpp"
# include "../../managers/EventManager.hpp"
# include "../../managers/input/InputManager.hpp"
# include "../../managers/PointerManager.hpp"
# include "../../managers/animation/DesktopAnimationManager.hpp"
2022-03-30 21:18:42 +02:00
2024-06-11 17:17:45 +02:00
# include <hyprutils/string/String.hpp>
2025-01-07 17:55:14 +00:00
2024-06-11 17:17:45 +02:00
using namespace Hyprutils : : String ;
2025-01-07 17:55:14 +00:00
using namespace Hyprutils : : Animation ;
2025-02-02 22:25:29 +03:00
using enum NContentType : : eContentType ;
2024-06-11 17:17:45 +02:00
2025-12-08 15:04:40 +00:00
using namespace Desktop ;
using namespace Desktop : : View ;
2024-05-25 22:43:51 +02:00
PHLWINDOW CWindow : : create ( SP < CXWaylandSurface > surface ) {
PHLWINDOW pWindow = SP < CWindow > ( new CWindow ( surface ) ) ;
2024-04-27 12:43:12 +01:00
2025-11-17 18:34:02 +00:00
pWindow - > m_self = pWindow ;
pWindow - > m_isX11 = true ;
pWindow - > m_ruleApplicator = makeUnique < Desktop : : Rule : : CWindowRuleApplicator > ( pWindow ) ;
2025-04-28 22:25:22 +02:00
g_pAnimationManager - > createAnimation ( Vector2D ( 0 , 0 ) , pWindow - > m_realPosition , g_pConfigManager - > getAnimationPropertyConfig ( " windowsIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( Vector2D ( 0 , 0 ) , pWindow - > m_realSize , g_pConfigManager - > getAnimationPropertyConfig ( " windowsIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_borderFadeAnimationProgress , g_pConfigManager - > getAnimationPropertyConfig ( " border " ) , pWindow , AVARDAMAGE_BORDER ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_borderAngleAnimationProgress , g_pConfigManager - > getAnimationPropertyConfig ( " borderangle " ) , pWindow , AVARDAMAGE_BORDER ) ;
g_pAnimationManager - > createAnimation ( 1.f , pWindow - > m_alpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 1.f , pWindow - > m_activeInactiveAlpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeSwitch " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( CHyprColor ( ) , pWindow - > m_realShadowColor , g_pConfigManager - > getAnimationPropertyConfig ( " fadeShadow " ) , pWindow , AVARDAMAGE_SHADOW ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_dimPercent , g_pConfigManager - > getAnimationPropertyConfig ( " fadeDim " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_movingToWorkspaceAlpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeOut " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_movingFromWorkspaceAlpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
2025-02-18 15:10:40 +00:00
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_notRespondingTint , g_pConfigManager - > getAnimationPropertyConfig ( " fade " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
2024-04-27 12:43:12 +01:00
2025-01-23 21:55:41 +01:00
pWindow - > addWindowDeco ( makeUnique < CHyprDropShadowDecoration > ( pWindow ) ) ;
pWindow - > addWindowDeco ( makeUnique < CHyprBorderDecoration > ( pWindow ) ) ;
2022-06-25 20:28:40 +02:00
2024-04-27 12:43:12 +01:00
return pWindow ;
}
2024-05-10 23:28:33 +01:00
PHLWINDOW CWindow : : create ( SP < CXDGSurfaceResource > resource ) {
PHLWINDOW pWindow = SP < CWindow > ( new CWindow ( resource ) ) ;
2025-05-04 23:39:00 +02:00
pWindow - > m_self = pWindow ;
resource - > m_toplevel - > m_window = pWindow ;
2025-11-17 18:34:02 +00:00
pWindow - > m_ruleApplicator = makeUnique < Desktop : : Rule : : CWindowRuleApplicator > ( pWindow ) ;
2024-05-10 23:28:33 +01:00
2025-04-28 22:25:22 +02:00
g_pAnimationManager - > createAnimation ( Vector2D ( 0 , 0 ) , pWindow - > m_realPosition , g_pConfigManager - > getAnimationPropertyConfig ( " windowsIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( Vector2D ( 0 , 0 ) , pWindow - > m_realSize , g_pConfigManager - > getAnimationPropertyConfig ( " windowsIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_borderFadeAnimationProgress , g_pConfigManager - > getAnimationPropertyConfig ( " border " ) , pWindow , AVARDAMAGE_BORDER ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_borderAngleAnimationProgress , g_pConfigManager - > getAnimationPropertyConfig ( " borderangle " ) , pWindow , AVARDAMAGE_BORDER ) ;
g_pAnimationManager - > createAnimation ( 1.f , pWindow - > m_alpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 1.f , pWindow - > m_activeInactiveAlpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeSwitch " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( CHyprColor ( ) , pWindow - > m_realShadowColor , g_pConfigManager - > getAnimationPropertyConfig ( " fadeShadow " ) , pWindow , AVARDAMAGE_SHADOW ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_dimPercent , g_pConfigManager - > getAnimationPropertyConfig ( " fadeDim " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_movingToWorkspaceAlpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeOut " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_movingFromWorkspaceAlpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeIn " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
2025-02-18 15:10:40 +00:00
g_pAnimationManager - > createAnimation ( 0.f , pWindow - > m_notRespondingTint , g_pConfigManager - > getAnimationPropertyConfig ( " fade " ) , pWindow , AVARDAMAGE_ENTIRE ) ;
2024-05-10 23:28:33 +01:00
2025-01-23 21:55:41 +01:00
pWindow - > addWindowDeco ( makeUnique < CHyprDropShadowDecoration > ( pWindow ) ) ;
pWindow - > addWindowDeco ( makeUnique < CHyprBorderDecoration > ( pWindow ) ) ;
2024-05-10 23:28:33 +01:00
2025-12-08 15:04:40 +00:00
pWindow - > wlSurface ( ) - > assign ( pWindow - > m_xdgSurface - > m_surface . lock ( ) , pWindow ) ;
2024-05-10 23:28:33 +01:00
return pWindow ;
}
2025-12-08 15:04:40 +00:00
CWindow : : CWindow ( SP < CXDGSurfaceResource > resource ) : IView ( CWLSurface : : create ( ) ) , m_xdgSurface ( resource ) {
m_listeners . map = m_xdgSurface - > m_events . map . listen ( [ this ] { mapWindow ( ) ; } ) ;
2025-07-08 09:56:40 -07:00
m_listeners . ack = m_xdgSurface - > m_events . ack . listen ( [ this ] ( uint32_t d ) { onAck ( d ) ; } ) ;
2025-12-08 15:04:40 +00:00
m_listeners . unmap = m_xdgSurface - > m_events . unmap . listen ( [ this ] { unmapWindow ( ) ; } ) ;
m_listeners . destroy = m_xdgSurface - > m_events . destroy . listen ( [ this ] { destroyWindow ( ) ; } ) ;
m_listeners . commit = m_xdgSurface - > m_events . commit . listen ( [ this ] { commitWindow ( ) ; } ) ;
2025-07-08 09:56:40 -07:00
m_listeners . updateState = m_xdgSurface - > m_toplevel - > m_events . stateChanged . listen ( [ this ] { onUpdateState ( ) ; } ) ;
m_listeners . updateMetadata = m_xdgSurface - > m_toplevel - > m_events . metadataChanged . listen ( [ this ] { onUpdateMeta ( ) ; } ) ;
2024-05-10 23:28:33 +01:00
}
2025-12-08 15:04:40 +00:00
CWindow : : CWindow ( SP < CXWaylandSurface > surface ) : IView ( CWLSurface : : create ( ) ) , m_xwaylandSurface ( surface ) {
m_listeners . map = m_xwaylandSurface - > m_events . map . listen ( [ this ] { mapWindow ( ) ; } ) ;
m_listeners . unmap = m_xwaylandSurface - > m_events . unmap . listen ( [ this ] { unmapWindow ( ) ; } ) ;
m_listeners . destroy = m_xwaylandSurface - > m_events . destroy . listen ( [ this ] { destroyWindow ( ) ; } ) ;
m_listeners . commit = m_xwaylandSurface - > m_events . commit . listen ( [ this ] { commitWindow ( ) ; } ) ;
2025-07-08 09:56:40 -07:00
m_listeners . configureRequest = m_xwaylandSurface - > m_events . configureRequest . listen ( [ this ] ( const CBox & box ) { onX11ConfigureRequest ( box ) ; } ) ;
m_listeners . updateState = m_xwaylandSurface - > m_events . stateChanged . listen ( [ this ] { onUpdateState ( ) ; } ) ;
m_listeners . updateMetadata = m_xwaylandSurface - > m_events . metadataChanged . listen ( [ this ] { onUpdateMeta ( ) ; } ) ;
m_listeners . resourceChange = m_xwaylandSurface - > m_events . resourceChange . listen ( [ this ] { onResourceChangeX11 ( ) ; } ) ;
2025-12-08 15:04:40 +00:00
m_listeners . activate = m_xwaylandSurface - > m_events . activate . listen ( [ this ] { activateX11 ( ) ; } ) ;
2024-05-25 22:43:51 +02:00
2025-05-07 15:21:44 +02:00
if ( m_xwaylandSurface - > m_overrideRedirect )
2025-12-08 15:04:40 +00:00
m_listeners . setGeometry = m_xwaylandSurface - > m_events . setGeometry . listen ( [ this ] { unmanagedSetGeometry ( ) ; } ) ;
}
SP < CWindow > CWindow : : fromView ( SP < IView > v ) {
if ( ! v | | v - > type ( ) ! = VIEW_TYPE_WINDOW )
return nullptr ;
return dynamicPointerCast < CWindow > ( v ) ;
2022-04-23 14:16:02 +02:00
}
2022-03-30 21:18:42 +02:00
CWindow : : ~ CWindow ( ) {
2025-11-26 07:44:26 +09:00
if ( Desktop : : focusState ( ) - > window ( ) = = m_self ) {
Desktop : : focusState ( ) - > surface ( ) . reset ( ) ;
Desktop : : focusState ( ) - > window ( ) . reset ( ) ;
2022-04-02 18:57:09 +02:00
}
2023-12-04 01:44:06 +00:00
2025-04-28 22:25:22 +02:00
m_events . destroy . emit ( ) ;
2024-04-21 16:28:50 +01:00
2023-12-06 14:46:18 +00:00
if ( ! g_pHyprOpenGL )
return ;
2023-12-04 01:44:06 +00:00
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2025-05-05 23:44:49 +02:00
std : : erase_if ( g_pHyprOpenGL - > m_windowFramebuffers , [ & ] ( const auto & other ) { return other . first . expired ( ) | | other . first . get ( ) = = this ; } ) ;
2022-05-30 14:55:42 +02:00
}
2025-12-08 15:04:40 +00:00
eViewType CWindow : : type ( ) const {
return VIEW_TYPE_WINDOW ;
}
bool CWindow : : visible ( ) const {
return m_isMapped & & ! m_hidden & & m_wlSurface & & m_wlSurface - > resource ( ) ;
}
std : : optional < CBox > CWindow : : logicalBox ( ) const {
return getFullWindowBoundingBox ( ) ;
}
bool CWindow : : desktopComponent ( ) const {
return true ;
}
std : : optional < CBox > CWindow : : surfaceLogicalBox ( ) const {
return getWindowMainSurfaceBox ( ) ;
}
SBoxExtents CWindow : : getFullWindowExtents ( ) const {
2025-04-28 22:25:22 +02:00
if ( m_fadingOut )
return m_originalClosedExtents ;
2023-08-09 14:28:04 +02:00
2023-08-17 08:13:19 +00:00
const int BORDERSIZE = getRealBorderSize ( ) ;
2023-07-23 13:49:49 +00:00
2025-11-17 18:34:02 +00:00
if ( m_ruleApplicator - > dimAround ( ) . valueOrDefault ( ) ) {
2025-04-28 22:25:22 +02:00
if ( const auto PMONITOR = m_monitor . lock ( ) ; PMONITOR )
2025-05-09 00:31:49 +05:30
return { . topLeft = { m_realPosition - > value ( ) . x - PMONITOR - > m_position . x , m_realPosition - > value ( ) . y - PMONITOR - > m_position . y } ,
. bottomRight = { PMONITOR - > m_size . x - ( m_realPosition - > value ( ) . x - PMONITOR - > m_position . x ) ,
PMONITOR - > m_size . y - ( m_realPosition - > value ( ) . y - PMONITOR - > m_position . y ) } } ;
2022-12-31 19:23:02 +01:00
}
2022-05-30 14:55:42 +02:00
2025-05-09 00:31:49 +05:30
SBoxExtents maxExtents = { . topLeft = { BORDERSIZE + 2 , BORDERSIZE + 2 } , . bottomRight = { BORDERSIZE + 2 , BORDERSIZE + 2 } } ;
2022-05-30 14:55:42 +02:00
2025-09-27 02:50:40 +02:00
const auto EXTENTS = g_pDecorationPositioner - > getWindowDecorationExtents ( m_self ) ;
2022-05-30 14:55:42 +02:00
2025-05-09 00:31:49 +05:30
maxExtents . topLeft . x = std : : max ( EXTENTS . topLeft . x , maxExtents . topLeft . x ) ;
2022-05-30 14:55:42 +02:00
2025-05-09 00:31:49 +05:30
maxExtents . topLeft . y = std : : max ( EXTENTS . topLeft . y , maxExtents . topLeft . y ) ;
2022-05-30 14:55:42 +02:00
2025-05-09 00:31:49 +05:30
maxExtents . bottomRight . x = std : : max ( EXTENTS . bottomRight . x , maxExtents . bottomRight . x ) ;
2022-05-30 14:55:42 +02:00
2025-05-09 00:31:49 +05:30
maxExtents . bottomRight . y = std : : max ( EXTENTS . bottomRight . y , maxExtents . bottomRight . y ) ;
2022-05-30 14:55:42 +02:00
2025-04-28 22:25:22 +02:00
if ( m_wlSurface - > exists ( ) & & ! m_isX11 & & m_popupHead ) {
2023-11-04 17:03:05 +00:00
CBox surfaceExtents = { 0 , 0 , 0 , 0 } ;
2023-06-23 13:54:01 +02:00
// TODO: this could be better, perhaps make a getFullWindowRegion?
2025-04-28 22:25:22 +02:00
m_popupHead - > breadthfirst (
2025-12-08 15:04:40 +00:00
[ ] ( WP < Desktop : : View : : CPopup > popup , void * data ) {
if ( ! popup - > wlSurface ( ) | | ! popup - > wlSurface ( ) - > resource ( ) )
2024-05-10 23:28:33 +01:00
return ;
2025-08-14 19:44:56 +05:00
CBox * pSurfaceExtents = sc < CBox * > ( data ) ;
2024-05-10 23:28:33 +01:00
CBox surf = CBox { popup - > coordsRelativeToParent ( ) , popup - > size ( ) } ;
2025-05-09 00:31:49 +05:30
pSurfaceExtents - > x = std : : min ( surf . x , pSurfaceExtents - > x ) ;
pSurfaceExtents - > y = std : : min ( surf . y , pSurfaceExtents - > y ) ;
2024-05-10 23:28:33 +01:00
if ( surf . x + surf . w > pSurfaceExtents - > width )
pSurfaceExtents - > width = surf . x + surf . w - pSurfaceExtents - > x ;
if ( surf . y + surf . h > pSurfaceExtents - > height )
pSurfaceExtents - > height = surf . y + surf . h - pSurfaceExtents - > y ;
2023-06-23 13:54:01 +02:00
} ,
& surfaceExtents ) ;
2025-05-09 00:31:49 +05:30
maxExtents . topLeft . x = std : : max ( - surfaceExtents . x , maxExtents . topLeft . x ) ;
2023-06-23 13:54:01 +02:00
2025-05-09 00:31:49 +05:30
maxExtents . topLeft . y = std : : max ( - surfaceExtents . y , maxExtents . topLeft . y ) ;
2023-06-23 13:54:01 +02:00
2025-05-03 16:02:49 +02:00
if ( surfaceExtents . x + surfaceExtents . width > m_wlSurface - > resource ( ) - > m_current . size . x + maxExtents . bottomRight . x )
maxExtents . bottomRight . x = surfaceExtents . x + surfaceExtents . width - m_wlSurface - > resource ( ) - > m_current . size . x ;
2023-06-23 13:54:01 +02:00
2025-05-03 16:02:49 +02:00
if ( surfaceExtents . y + surfaceExtents . height > m_wlSurface - > resource ( ) - > m_current . size . y + maxExtents . bottomRight . y )
maxExtents . bottomRight . y = surfaceExtents . y + surfaceExtents . height - m_wlSurface - > resource ( ) - > m_current . size . y ;
2023-06-23 13:54:01 +02:00
}
2023-08-09 14:28:04 +02:00
return maxExtents ;
}
2025-12-08 15:04:40 +00:00
CBox CWindow : : getFullWindowBoundingBox ( ) const {
2025-11-17 18:34:02 +00:00
if ( m_ruleApplicator - > dimAround ( ) . valueOrDefault ( ) ) {
2025-04-28 22:25:22 +02:00
if ( const auto PMONITOR = m_monitor . lock ( ) ; PMONITOR )
2025-04-30 23:45:20 +02:00
return { PMONITOR - > m_position . x , PMONITOR - > m_position . y , PMONITOR - > m_size . x , PMONITOR - > m_size . y } ;
2023-08-09 14:28:04 +02:00
}
2023-11-04 17:03:05 +00:00
auto maxExtents = getFullWindowExtents ( ) ;
2023-08-09 14:28:04 +02:00
2025-04-28 22:25:22 +02:00
CBox finalBox = { m_realPosition - > value ( ) . x - maxExtents . topLeft . x , m_realPosition - > value ( ) . y - maxExtents . topLeft . y ,
m_realSize - > value ( ) . x + maxExtents . topLeft . x + maxExtents . bottomRight . x , m_realSize - > value ( ) . y + maxExtents . topLeft . y + maxExtents . bottomRight . y } ;
2022-09-25 20:07:48 +02:00
2022-05-30 14:55:42 +02:00
return finalBox ;
2022-06-23 20:39:48 +02:00
}
2023-11-04 17:03:05 +00:00
CBox CWindow : : getWindowIdealBoundingBoxIgnoreReserved ( ) {
2025-04-28 22:25:22 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2022-06-23 20:39:48 +02:00
2024-06-03 21:09:18 +02:00
if ( ! PMONITOR )
2025-04-28 22:25:22 +02:00
return { m_position , m_size } ;
2024-06-03 21:09:18 +02:00
2025-04-28 22:25:22 +02:00
auto POS = m_position ;
auto SIZE = m_size ;
2022-06-23 20:39:48 +02:00
2024-07-31 17:55:52 +00:00
if ( isFullscreen ( ) ) {
2025-04-30 23:45:20 +02:00
POS = PMONITOR - > m_position ;
SIZE = PMONITOR - > m_size ;
2022-11-21 23:33:23 +00:00
2025-08-14 19:44:56 +05:00
return CBox { sc < int > ( POS . x ) , sc < int > ( POS . y ) , sc < int > ( SIZE . x ) , sc < int > ( SIZE . y ) } ;
2022-11-21 23:33:23 +00:00
}
2025-12-05 14:16:22 +00:00
if ( DELTALESSTHAN ( POS . y - PMONITOR - > m_position . y , PMONITOR - > m_reservedArea . top ( ) , 1 ) ) {
2025-04-30 23:45:20 +02:00
POS . y = PMONITOR - > m_position . y ;
2025-12-05 14:16:22 +00:00
SIZE . y + = PMONITOR - > m_reservedArea . top ( ) ;
2022-06-23 20:39:48 +02:00
}
2025-12-05 14:16:22 +00:00
if ( DELTALESSTHAN ( POS . x - PMONITOR - > m_position . x , PMONITOR - > m_reservedArea . left ( ) , 1 ) ) {
2025-04-30 23:45:20 +02:00
POS . x = PMONITOR - > m_position . x ;
2025-12-05 14:16:22 +00:00
SIZE . x + = PMONITOR - > m_reservedArea . left ( ) ;
2022-06-23 20:39:48 +02:00
}
2025-12-05 14:16:22 +00:00
if ( DELTALESSTHAN ( POS . x + SIZE . x - PMONITOR - > m_position . x , PMONITOR - > m_size . x - PMONITOR - > m_reservedArea . right ( ) , 1 ) ) {
SIZE . x + = PMONITOR - > m_reservedArea . right ( ) ;
2022-06-23 20:39:48 +02:00
}
2025-12-05 14:16:22 +00:00
if ( DELTALESSTHAN ( POS . y + SIZE . y - PMONITOR - > m_position . y , PMONITOR - > m_size . y - PMONITOR - > m_reservedArea . bottom ( ) , 1 ) ) {
SIZE . y + = PMONITOR - > m_reservedArea . bottom ( ) ;
2022-06-23 20:39:48 +02:00
}
2025-08-14 19:44:56 +05:00
return CBox { sc < int > ( POS . x ) , sc < int > ( POS . y ) , sc < int > ( SIZE . x ) , sc < int > ( SIZE . y ) } ;
2022-06-27 00:25:37 +02:00
}
2025-07-18 11:35:43 -04:00
SBoxExtents CWindow : : getWindowExtentsUnified ( uint64_t properties ) {
SBoxExtents extents = { . topLeft = { 0 , 0 } , . bottomRight = { 0 , 0 } } ;
2025-12-08 15:04:40 +00:00
if ( properties & Desktop : : View : : RESERVED_EXTENTS )
2025-09-27 02:50:40 +02:00
extents . addExtents ( g_pDecorationPositioner - > getWindowDecorationReserved ( m_self ) ) ;
2025-12-08 15:04:40 +00:00
if ( properties & Desktop : : View : : INPUT_EXTENTS )
2025-09-27 02:50:40 +02:00
extents . addExtents ( g_pDecorationPositioner - > getWindowDecorationExtents ( m_self , true ) ) ;
2025-07-18 11:35:43 -04:00
if ( properties & FULL_EXTENTS )
2025-09-27 02:50:40 +02:00
extents . addExtents ( g_pDecorationPositioner - > getWindowDecorationExtents ( m_self , false ) ) ;
2025-07-18 11:35:43 -04:00
return extents ;
}
2024-02-04 15:40:20 +00:00
CBox CWindow : : getWindowBoxUnified ( uint64_t properties ) {
2025-11-17 18:34:02 +00:00
if ( m_ruleApplicator - > dimAround ( ) . valueOrDefault ( ) ) {
2025-04-28 22:25:22 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2024-06-03 21:09:18 +02:00
if ( PMONITOR )
2025-04-30 23:45:20 +02:00
return { PMONITOR - > m_position . x , PMONITOR - > m_position . y , PMONITOR - > m_size . x , PMONITOR - > m_size . y } ;
2023-02-28 22:32:42 +00:00
}
2025-10-29 23:21:28 +00:00
const auto POS = m_realPosition - > value ( ) ;
const auto SIZE = m_realSize - > value ( ) ;
CBox box { POS , SIZE } ;
2025-07-18 11:35:43 -04:00
box . addExtents ( getWindowExtentsUnified ( properties ) ) ;
2023-02-28 22:32:42 +00:00
2024-02-04 15:40:20 +00:00
return box ;
2023-02-28 22:32:42 +00:00
}
2024-06-19 16:20:06 +02:00
SBoxExtents CWindow : : getFullWindowReservedArea ( ) {
2025-09-27 02:50:40 +02:00
return g_pDecorationPositioner - > getWindowDecorationReserved ( m_self ) ;
2023-02-28 19:36:36 +00:00
}
2022-06-27 00:25:37 +02:00
void CWindow : : updateWindowDecos ( ) {
2023-06-05 09:49:17 +02:00
2025-04-28 22:25:22 +02:00
if ( ! m_isMapped | | isHidden ( ) )
2023-11-11 14:37:17 +00:00
return ;
2025-04-28 22:25:22 +02:00
for ( auto const & wd : m_decosToRemove ) {
for ( auto it = m_windowDecorations . begin ( ) ; it ! = m_windowDecorations . end ( ) ; it + + ) {
2022-07-05 17:31:47 +02:00
if ( it - > get ( ) = = wd ) {
2023-11-11 14:37:17 +00:00
g_pDecorationPositioner - > uncacheDecoration ( it - > get ( ) ) ;
2025-04-28 22:25:22 +02:00
it = m_windowDecorations . erase ( it ) ;
if ( it = = m_windowDecorations . end ( ) )
2022-07-05 17:31:47 +02:00
break ;
}
}
}
2025-04-28 22:25:22 +02:00
g_pDecorationPositioner - > onWindowUpdate ( m_self . lock ( ) ) ;
2023-11-11 14:37:17 +00:00
2025-04-28 22:25:22 +02:00
m_decosToRemove . clear ( ) ;
2023-11-11 14:37:17 +00:00
2024-03-10 16:56:32 +00:00
// make a copy because updateWindow can remove decos.
std : : vector < IHyprWindowDecoration * > decos ;
2025-01-19 10:38:42 +00:00
// reserve to avoid reallocations
2025-04-28 22:25:22 +02:00
decos . reserve ( m_windowDecorations . size ( ) ) ;
2024-03-10 16:56:32 +00:00
2025-04-28 22:25:22 +02:00
for ( auto const & wd : m_windowDecorations ) {
2024-03-10 16:56:32 +00:00
decos . push_back ( wd . get ( ) ) ;
}
2024-08-26 17:25:39 +02:00
for ( auto const & wd : decos ) {
2025-05-09 00:31:49 +05:30
if ( std : : ranges : : find_if ( m_windowDecorations , [ wd ] ( const auto & other ) { return other . get ( ) = = wd ; } ) = = m_windowDecorations . end ( ) )
2024-05-07 16:50:30 +01:00
continue ;
2025-04-28 22:25:22 +02:00
wd - > updateWindow ( m_self . lock ( ) ) ;
2023-11-11 14:37:17 +00:00
}
}
2025-01-23 21:55:41 +01:00
void CWindow : : addWindowDeco ( UP < IHyprWindowDecoration > deco ) {
2025-04-28 22:25:22 +02:00
m_windowDecorations . emplace_back ( std : : move ( deco ) ) ;
g_pDecorationPositioner - > forceRecalcFor ( m_self . lock ( ) ) ;
2023-11-11 14:37:17 +00:00
updateWindowDecos ( ) ;
2025-04-28 22:25:22 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateWindow ( m_self . lock ( ) ) ;
2023-11-11 14:37:17 +00:00
}
void CWindow : : removeWindowDeco ( IHyprWindowDecoration * deco ) {
2025-04-28 22:25:22 +02:00
m_decosToRemove . push_back ( deco ) ;
g_pDecorationPositioner - > forceRecalcFor ( m_self . lock ( ) ) ;
2023-11-11 14:37:17 +00:00
updateWindowDecos ( ) ;
2025-04-28 22:25:22 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateWindow ( m_self . lock ( ) ) ;
2022-06-27 13:42:20 +02:00
}
2023-12-30 14:18:53 +00:00
void CWindow : : uncacheWindowDecos ( ) {
2025-04-28 22:25:22 +02:00
for ( auto const & wd : m_windowDecorations ) {
2023-12-30 14:18:53 +00:00
g_pDecorationPositioner - > uncacheDecoration ( wd . get ( ) ) ;
}
}
2023-12-28 22:54:41 +00:00
bool CWindow : : checkInputOnDecos ( const eInputType type , const Vector2D & mouseCoords , std : : any data ) {
if ( type ! = INPUT_TYPE_DRAG_END & & hasPopupAt ( mouseCoords ) )
return false ;
2025-04-28 22:25:22 +02:00
for ( auto const & wd : m_windowDecorations ) {
2023-12-28 22:54:41 +00:00
if ( ! ( wd - > getDecorationFlags ( ) & DECORATION_ALLOWS_MOUSE_INPUT ) )
continue ;
if ( ! g_pDecorationPositioner - > getWindowDecorationBox ( wd . get ( ) ) . containsPoint ( mouseCoords ) )
continue ;
if ( wd - > onInputOnDeco ( type , mouseCoords , data ) )
return true ;
}
return false ;
}
2022-06-27 13:42:20 +02:00
pid_t CWindow : : getPID ( ) {
pid_t PID = - 1 ;
2025-04-28 22:25:22 +02:00
if ( ! m_isX11 ) {
2025-05-04 23:39:00 +02:00
if ( ! m_xdgSurface | | ! m_xdgSurface - > m_owner /* happens at unmap */ )
2023-03-03 11:17:43 +00:00
return - 1 ;
2025-05-04 23:39:00 +02:00
wl_client_get_credentials ( m_xdgSurface - > m_owner - > client ( ) , & PID , nullptr , nullptr ) ;
2022-06-27 13:42:20 +02:00
} else {
2025-04-28 22:25:22 +02:00
if ( ! m_xwaylandSurface )
2023-11-01 18:53:36 +00:00
return - 1 ;
2025-05-07 15:21:44 +02:00
PID = m_xwaylandSurface - > m_pid ;
2022-06-27 13:42:20 +02:00
}
return PID ;
}
2022-07-16 12:44:45 +02:00
IHyprWindowDecoration * CWindow : : getDecorationByType ( eDecorationType type ) {
2025-04-28 22:25:22 +02:00
for ( auto const & wd : m_windowDecorations ) {
2022-07-16 12:44:45 +02:00
if ( wd - > getDecorationType ( ) = = type )
return wd . get ( ) ;
}
return nullptr ;
2022-08-06 20:57:38 +02:00
}
void CWindow : : updateToplevel ( ) {
2024-01-09 18:14:08 +01:00
updateSurfaceScaleTransformDetails ( ) ;
2022-08-08 21:20:41 +02:00
}
2024-06-08 10:07:59 +02:00
void CWindow : : updateSurfaceScaleTransformDetails ( bool force ) {
2025-04-28 22:25:22 +02:00
if ( ! m_isMapped | | m_hidden | | g_pCompositor - > m_unsafeState )
2022-08-08 21:20:41 +02:00
return ;
2025-04-28 22:25:22 +02:00
const auto PLASTMONITOR = g_pCompositor - > getMonitorFromID ( m_lastSurfaceMonitorID ) ;
2022-08-08 21:20:41 +02:00
2025-04-28 22:25:22 +02:00
m_lastSurfaceMonitorID = monitorID ( ) ;
2022-08-08 21:20:41 +02:00
2025-04-28 22:25:22 +02:00
const auto PNEWMONITOR = m_monitor . lock ( ) ;
2022-08-08 21:20:41 +02:00
2024-03-05 20:46:08 +00:00
if ( ! PNEWMONITOR )
return ;
2024-06-08 10:07:59 +02:00
if ( PNEWMONITOR ! = PLASTMONITOR | | force ) {
2025-04-30 23:45:20 +02:00
if ( PLASTMONITOR & & PLASTMONITOR - > m_enabled & & PNEWMONITOR ! = PLASTMONITOR )
m_wlSurface - > resource ( ) - > breadthfirst ( [ PLASTMONITOR ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * d ) { s - > leave ( PLASTMONITOR - > m_self . lock ( ) ) ; } , nullptr ) ;
2022-08-08 21:20:41 +02:00
2025-04-30 23:45:20 +02:00
m_wlSurface - > resource ( ) - > breadthfirst ( [ PNEWMONITOR ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * d ) { s - > enter ( PNEWMONITOR - > m_self . lock ( ) ) ; } , nullptr ) ;
2024-01-09 18:14:08 +01:00
}
2023-06-06 09:48:07 +02:00
2025-04-28 22:25:22 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2024-01-11 13:15:20 +01:00
2025-04-28 22:25:22 +02:00
m_wlSurface - > resource ( ) - > breadthfirst (
2024-10-27 18:45:38 +00:00
[ PMONITOR ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * d ) {
2024-06-08 10:07:59 +02:00
const auto PSURFACE = CWLSurface : : fromResource ( s ) ;
2025-04-30 23:45:20 +02:00
if ( PSURFACE & & PSURFACE - > m_lastScaleFloat = = PMONITOR - > m_scale )
2024-01-11 13:15:20 +01:00
return ;
2025-04-30 23:45:20 +02:00
PROTO : : fractional - > sendScale ( s , PMONITOR - > m_scale ) ;
g_pCompositor - > setPreferredScaleForSurface ( s , PMONITOR - > m_scale ) ;
g_pCompositor - > setPreferredTransformForSurface ( s , PMONITOR - > m_transform ) ;
2023-06-06 09:48:07 +02:00
} ,
2024-06-08 10:07:59 +02:00
nullptr ) ;
2022-08-21 18:01:26 +03:00
}
2024-04-02 20:32:39 +01:00
void CWindow : : moveToWorkspace ( PHLWORKSPACE pWorkspace ) {
2025-04-28 22:25:22 +02:00
if ( m_workspace = = pWorkspace )
2023-03-18 16:30:29 +00:00
return ;
2022-08-21 18:01:26 +03:00
2024-04-24 16:16:46 +01:00
static auto PINITIALWSTRACKING = CConfigValue < Hyprlang : : INT > ( " misc:initial_workspace_tracking " ) ;
2025-04-28 22:25:22 +02:00
if ( ! m_initialWorkspaceToken . empty ( ) ) {
const auto TOKEN = g_pTokenManager - > getToken ( m_initialWorkspaceToken ) ;
2024-04-24 16:16:46 +01:00
if ( TOKEN ) {
if ( * PINITIALWSTRACKING = = 2 ) {
// persistent
2025-04-16 01:37:48 +01:00
SInitialWorkspaceToken token = std : : any_cast < SInitialWorkspaceToken > ( TOKEN - > m_data ) ;
2025-04-28 22:25:22 +02:00
if ( token . primaryOwner = = m_self ) {
2024-04-24 16:16:46 +01:00
token . workspace = pWorkspace - > getConfigName ( ) ;
2025-04-16 01:37:48 +01:00
TOKEN - > m_data = token ;
2024-04-24 16:16:46 +01:00
}
}
}
2024-04-23 01:28:20 +01:00
}
2024-03-03 18:39:20 +00:00
static auto PCLOSEONLASTSPECIAL = CConfigValue < Hyprlang : : INT > ( " misc:close_special_on_empty " ) ;
2023-10-24 00:58:44 +01:00
2025-04-28 22:25:22 +02:00
const auto OLDWORKSPACE = m_workspace ;
2023-10-24 00:58:44 +01:00
2025-01-26 13:00:52 +00:00
if ( OLDWORKSPACE - > isVisible ( ) ) {
2025-04-28 22:25:22 +02:00
m_movingToWorkspaceAlpha - > setValueAndWarp ( 1.F ) ;
* m_movingToWorkspaceAlpha = 0.F ;
m_movingToWorkspaceAlpha - > setCallbackOnEnd ( [ this ] ( auto ) { m_monitorMovedFrom = - 1 ; } ) ;
m_monitorMovedFrom = OLDWORKSPACE ? OLDWORKSPACE - > monitorID ( ) : - 1 ;
2025-01-26 13:00:52 +00:00
}
2024-08-28 21:54:49 +02:00
2025-04-28 22:25:22 +02:00
m_workspace = pWorkspace ;
2023-03-18 16:30:29 +00:00
2024-03-18 19:52:52 -07:00
setAnimationsToMove ( ) ;
2024-11-22 16:01:02 +00:00
OLDWORKSPACE - > updateWindows ( ) ;
OLDWORKSPACE - > updateWindowData ( ) ;
2024-10-27 18:45:38 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( OLDWORKSPACE - > monitorID ( ) ) ;
2024-04-20 02:46:16 +09:00
2024-11-22 16:01:02 +00:00
pWorkspace - > updateWindows ( ) ;
pWorkspace - > updateWindowData ( ) ;
2024-10-27 18:45:38 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitorID ( ) ) ;
2024-04-20 02:46:16 +09:00
2024-04-11 01:26:11 +09:00
g_pCompositor - > updateAllWindowsAnimatedDecorationValues ( ) ;
2023-08-17 08:13:19 +00:00
2024-04-02 20:32:39 +01:00
if ( valid ( pWorkspace ) ) {
2025-08-14 19:44:56 +05:00
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " movewindow " , . data = std : : format ( " {:x},{} " , rc < uintptr_t > ( this ) , pWorkspace - > m_name ) } ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " movewindowv2 " , . data = std : : format ( " {:x},{},{} " , rc < uintptr_t > ( this ) , pWorkspace - > m_id , pWorkspace - > m_name ) } ) ;
2025-04-28 22:25:22 +02:00
EMIT_HOOK_EVENT ( " moveWindow " , ( std : : vector < std : : any > { m_self . lock ( ) , pWorkspace } ) ) ;
2022-08-21 18:01:26 +03:00
}
2023-03-18 16:30:29 +00:00
2025-04-28 22:25:22 +02:00
if ( const auto SWALLOWED = m_swallowed . lock ( ) ) {
if ( SWALLOWED - > m_currentlySwallowed ) {
2025-02-05 10:56:41 +01:00
SWALLOWED - > moveToWorkspace ( pWorkspace ) ;
2025-04-28 22:25:22 +02:00
SWALLOWED - > m_monitor = m_monitor ;
2025-02-05 10:56:41 +01:00
}
2023-04-02 10:24:17 +01:00
}
2023-08-15 19:15:37 +02:00
2025-04-25 02:37:12 +02:00
if ( OLDWORKSPACE & & g_pCompositor - > isWorkspaceSpecial ( OLDWORKSPACE - > m_id ) & & OLDWORKSPACE - > getWindows ( ) = = 0 & & * PCLOSEONLASTSPECIAL ) {
if ( const auto PMONITOR = OLDWORKSPACE - > m_monitor . lock ( ) ; PMONITOR )
2024-04-02 20:32:39 +01:00
PMONITOR - > setSpecialWorkspace ( nullptr ) ;
2023-10-24 00:58:44 +01:00
}
2022-08-28 19:47:06 +02:00
}
2024-12-07 18:51:18 +01:00
PHLWINDOW CWindow : : x11TransientFor ( ) {
2025-05-07 15:21:44 +02:00
if ( ! m_xwaylandSurface | | ! m_xwaylandSurface - > m_parent )
2022-08-28 19:47:06 +02:00
return nullptr ;
2025-05-07 15:21:44 +02:00
auto s = m_xwaylandSurface - > m_parent ;
2024-10-16 22:22:36 +01:00
std : : vector < SP < CXWaylandSurface > > visited ;
2024-05-25 22:43:51 +02:00
while ( s ) {
2024-10-16 22:22:36 +01:00
// break loops. Some X apps make them, and it seems like it's valid behavior?!?!?!
// TODO: we should reject loops being created in the first place.
2025-05-09 00:31:49 +05:30
if ( std : : ranges : : find ( visited . begin ( ) , visited . end ( ) , s ) ! = visited . end ( ) )
2024-05-25 22:43:51 +02:00
break ;
2024-10-16 22:22:36 +01:00
visited . emplace_back ( s . lock ( ) ) ;
2025-05-07 15:21:44 +02:00
s = s - > m_parent ;
2022-08-28 19:47:06 +02:00
}
2025-04-28 22:25:22 +02:00
if ( s = = m_xwaylandSurface )
2024-10-16 22:22:36 +01:00
return nullptr ; // dead-ass circle
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( w - > m_xwaylandSurface ! = s )
2024-05-25 22:43:51 +02:00
continue ;
return w ;
}
2022-09-01 10:16:23 +02:00
2024-05-25 22:43:51 +02:00
return nullptr ;
2022-08-28 19:47:06 +02:00
}
2022-08-29 19:52:35 +02:00
2022-10-14 20:46:32 +01:00
void CWindow : : onUnmap ( ) {
2024-03-03 18:39:20 +00:00
static auto PCLOSEONLASTSPECIAL = CConfigValue < Hyprlang : : INT > ( " misc:close_special_on_empty " ) ;
2024-07-27 16:46:19 +00:00
static auto PINITIALWSTRACKING = CConfigValue < Hyprlang : : INT > ( " misc:initial_workspace_tracking " ) ;
2024-04-24 16:16:46 +01:00
2025-04-28 22:25:22 +02:00
if ( ! m_initialWorkspaceToken . empty ( ) ) {
const auto TOKEN = g_pTokenManager - > getToken ( m_initialWorkspaceToken ) ;
2024-04-24 16:16:46 +01:00
if ( TOKEN ) {
if ( * PINITIALWSTRACKING = = 2 ) {
// persistent token, but the first window got removed so the token is gone
2025-04-16 01:37:48 +01:00
SInitialWorkspaceToken token = std : : any_cast < SInitialWorkspaceToken > ( TOKEN - > m_data ) ;
2025-04-28 22:25:22 +02:00
if ( token . primaryOwner = = m_self )
2024-04-24 16:16:46 +01:00
g_pTokenManager - > removeToken ( TOKEN ) ;
}
}
}
2025-04-28 22:25:22 +02:00
m_lastWorkspace = m_workspace - > m_id ;
2024-04-02 20:32:39 +01:00
2025-06-11 17:52:16 +02:00
// if the special workspace now has 0 windows, it will be closed, and this
// window will no longer pass render checks, cuz the workspace will be nuked.
// throw it into the main one for the fadeout.
if ( m_workspace - > m_isSpecialWorkspace & & m_workspace - > getWindows ( ) = = 0 )
m_lastWorkspace = m_monitor - > activeWorkspaceID ( ) ;
2025-04-28 22:25:22 +02:00
if ( * PCLOSEONLASTSPECIAL & & m_workspace & & m_workspace - > getWindows ( ) = = 0 & & onSpecialWorkspace ( ) ) {
const auto PMONITOR = m_monitor . lock ( ) ;
2025-04-30 23:45:20 +02:00
if ( PMONITOR & & PMONITOR - > m_activeSpecialWorkspace & & PMONITOR - > m_activeSpecialWorkspace = = m_workspace )
2023-09-03 13:00:02 +02:00
PMONITOR - > setSpecialWorkspace ( nullptr ) ;
}
2023-09-28 21:48:33 +01:00
2025-04-28 22:25:22 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2023-09-28 21:48:33 +01:00
2025-04-30 23:45:20 +02:00
if ( PMONITOR & & PMONITOR - > m_solitaryClient = = m_self )
PMONITOR - > m_solitaryClient . reset ( ) ;
2023-12-20 23:52:18 +01:00
2025-04-28 22:25:22 +02:00
if ( m_workspace ) {
m_workspace - > updateWindows ( ) ;
m_workspace - > updateWindowData ( ) ;
2024-11-22 16:01:02 +00:00
}
2024-10-27 18:45:38 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitorID ( ) ) ;
2024-04-11 01:26:11 +09:00
g_pCompositor - > updateAllWindowsAnimatedDecorationValues ( ) ;
2024-02-29 00:03:28 +00:00
2025-04-28 22:25:22 +02:00
m_workspace . reset ( ) ;
2024-04-12 19:52:01 +01:00
2025-04-28 22:25:22 +02:00
if ( m_isX11 )
2024-02-29 14:26:02 +00:00
return ;
2025-04-28 22:25:22 +02:00
m_subsurfaceHead . reset ( ) ;
m_popupHead . reset ( ) ;
2022-11-04 15:56:31 +00:00
}
void CWindow : : onMap ( ) {
2022-11-18 13:53:54 +00:00
// JIC, reset the callbacks. If any are set, we'll make sure they are cleared so we don't accidentally unset them. (In case a window got remapped)
2025-04-28 22:25:22 +02:00
m_realPosition - > resetAllCallbacks ( ) ;
m_realSize - > resetAllCallbacks ( ) ;
m_borderFadeAnimationProgress - > resetAllCallbacks ( ) ;
m_borderAngleAnimationProgress - > resetAllCallbacks ( ) ;
m_activeInactiveAlpha - > resetAllCallbacks ( ) ;
m_alpha - > resetAllCallbacks ( ) ;
m_realShadowColor - > resetAllCallbacks ( ) ;
m_dimPercent - > resetAllCallbacks ( ) ;
m_movingToWorkspaceAlpha - > resetAllCallbacks ( ) ;
m_movingFromWorkspaceAlpha - > resetAllCallbacks ( ) ;
m_movingFromWorkspaceAlpha - > setValueAndWarp ( 1.F ) ;
if ( m_borderAngleAnimationProgress - > enabled ( ) ) {
m_borderAngleAnimationProgress - > setValueAndWarp ( 0.f ) ;
m_borderAngleAnimationProgress - > setCallbackOnEnd ( [ & ] ( WP < CBaseAnimatedVariable > p ) { onBorderAngleAnimEnd ( p ) ; } , false ) ;
* m_borderAngleAnimationProgress = 1.f ;
}
m_realSize - > setCallbackOnBegin (
2025-02-06 11:21:04 +00:00
[ this ] ( auto ) {
2025-04-28 22:25:22 +02:00
if ( ! m_isMapped | | isX11OverrideRedirect ( ) )
2025-02-06 11:21:04 +00:00
return ;
2025-09-21 19:27:56 +02:00
g_pEventLoopManager - > doLater ( [ this , self = m_self ] {
if ( ! self )
return ;
sendWindowSize ( ) ;
} ) ;
2025-02-06 11:21:04 +00:00
} ,
false ) ;
2025-04-28 22:25:22 +02:00
m_movingFromWorkspaceAlpha - > setValueAndWarp ( 1.F ) ;
2024-12-22 16:04:10 +00:00
2025-04-28 22:25:22 +02:00
m_reportedSize = m_pendingReportedSize ;
m_animatingIn = true ;
2024-02-01 00:55:17 +00:00
2024-06-08 10:07:59 +02:00
updateSurfaceScaleTransformDetails ( true ) ;
2025-04-28 22:25:22 +02:00
if ( m_isX11 )
2024-02-29 14:26:02 +00:00
return ;
2025-04-28 22:25:22 +02:00
m_subsurfaceHead = CSubsurface : : create ( m_self . lock ( ) ) ;
m_popupHead = CPopup : : create ( m_self . lock ( ) ) ;
2022-10-14 20:46:32 +01:00
}
2025-01-07 17:55:14 +00:00
void CWindow : : onBorderAngleAnimEnd ( WP < CBaseAnimatedVariable > pav ) {
const auto PAV = pav . lock ( ) ;
if ( ! PAV )
return ;
2023-02-01 16:06:01 -05:00
2025-01-07 17:55:14 +00:00
if ( PAV - > getStyle ( ) ! = " loop " | | ! PAV - > enabled ( ) )
2023-02-01 16:06:01 -05:00
return ;
2025-08-14 19:44:56 +05:00
const auto PANIMVAR = dc < CAnimatedVariable < float > * > ( PAV . get ( ) ) ;
2025-01-07 17:55:14 +00:00
2023-02-01 16:06:01 -05:00
PANIMVAR - > setCallbackOnEnd ( nullptr ) ; // we remove the callback here because otherwise setvalueandwarp will recurse this
PANIMVAR - > setValueAndWarp ( 0 ) ;
* PANIMVAR = 1.f ;
2025-01-07 17:55:14 +00:00
PANIMVAR - > setCallbackOnEnd ( [ & ] ( WP < CBaseAnimatedVariable > pav ) { onBorderAngleAnimEnd ( pav ) ; } , false ) ;
2023-02-01 16:06:01 -05:00
}
2022-10-14 20:46:32 +01:00
void CWindow : : setHidden ( bool hidden ) {
2025-04-28 22:25:22 +02:00
m_hidden = hidden ;
2022-10-14 20:46:32 +01:00
2025-11-26 07:44:26 +09:00
if ( hidden & & Desktop : : focusState ( ) - > window ( ) = = m_self )
Desktop : : focusState ( ) - > window ( ) . reset ( ) ;
2023-12-23 22:30:49 +01:00
setSuspended ( hidden ) ;
2022-10-14 20:46:32 +01:00
}
bool CWindow : : isHidden ( ) {
2025-04-28 22:25:22 +02:00
return m_hidden ;
2022-11-15 11:21:26 +01:00
}
2023-02-18 23:35:31 +01:00
// check if the point is "hidden" under a rounded corner of the window
// it is assumed that the point is within the real window box (m_vRealPosition, m_vRealSize)
// otherwise behaviour is undefined
bool CWindow : : isInCurvedCorner ( double x , double y ) {
2025-01-05 12:38:49 -06:00
const int ROUNDING = rounding ( ) ;
const int ROUNDINGPOWER = roundingPower ( ) ;
2023-08-17 08:13:19 +00:00
if ( getRealBorderSize ( ) > = ROUNDING )
2023-02-18 23:35:31 +01:00
return false ;
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner
2025-04-28 22:25:22 +02:00
double x0 = m_realPosition - > value ( ) . x + ROUNDING ;
double y0 = m_realPosition - > value ( ) . y + ROUNDING ;
double x1 = m_realPosition - > value ( ) . x + m_realSize - > value ( ) . x - ROUNDING ;
double y1 = m_realPosition - > value ( ) . y + m_realSize - > value ( ) . y - ROUNDING ;
2023-02-18 23:35:31 +01:00
if ( x < x0 & & y < y0 ) {
2025-08-14 19:44:56 +05:00
return std : : pow ( x0 - x , ROUNDINGPOWER ) + std : : pow ( y0 - y , ROUNDINGPOWER ) > std : : pow ( sc < double > ( ROUNDING ) , ROUNDINGPOWER ) ;
2023-02-18 23:35:31 +01:00
}
if ( x > x1 & & y < y0 ) {
2025-08-14 19:44:56 +05:00
return std : : pow ( x - x1 , ROUNDINGPOWER ) + std : : pow ( y0 - y , ROUNDINGPOWER ) > std : : pow ( sc < double > ( ROUNDING ) , ROUNDINGPOWER ) ;
2023-02-18 23:35:31 +01:00
}
if ( x < x0 & & y > y1 ) {
2025-08-14 19:44:56 +05:00
return std : : pow ( x0 - x , ROUNDINGPOWER ) + std : : pow ( y - y1 , ROUNDINGPOWER ) > std : : pow ( sc < double > ( ROUNDING ) , ROUNDINGPOWER ) ;
2023-02-18 23:35:31 +01:00
}
if ( x > x1 & & y > y1 ) {
2025-08-14 19:44:56 +05:00
return std : : pow ( x - x1 , ROUNDINGPOWER ) + std : : pow ( y - y1 , ROUNDINGPOWER ) > std : : pow ( sc < double > ( ROUNDING ) , ROUNDINGPOWER ) ;
2023-02-18 23:35:31 +01:00
}
return false ;
}
// checks if the wayland window has a popup at pos
bool CWindow : : hasPopupAt ( const Vector2D & pos ) {
2025-04-28 22:25:22 +02:00
if ( m_isX11 )
2023-02-18 23:35:31 +01:00
return false ;
2025-04-28 22:25:22 +02:00
auto popup = m_popupHead - > at ( pos ) ;
2023-02-18 23:35:31 +01:00
2025-12-08 15:04:40 +00:00
return popup & & popup - > wlSurface ( ) - > resource ( ) ;
2023-02-18 23:35:31 +01:00
}
2023-02-19 21:07:32 +00:00
2023-09-21 23:42:00 +00:00
void CWindow : : applyGroupRules ( ) {
2025-04-28 22:25:22 +02:00
if ( ( m_groupRules & GROUP_SET & & m_firstMap ) | | m_groupRules & GROUP_SET_ALWAYS )
2023-09-21 23:42:00 +00:00
createGroup ( ) ;
2025-04-28 22:25:22 +02:00
if ( m_groupData . pNextWindow . lock ( ) & & ( ( m_groupRules & GROUP_LOCK & & m_firstMap ) | | m_groupRules & GROUP_LOCK_ALWAYS ) )
getGroupHead ( ) - > m_groupData . locked = true ;
2023-09-21 23:42:00 +00:00
}
void CWindow : : createGroup ( ) {
2025-04-28 22:25:22 +02:00
if ( m_groupData . deny ) {
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " createGroup: window:{:x},title:{} is denied as a group, ignored " , rc < uintptr_t > ( this ) , this - > m_title ) ;
2023-09-21 23:42:00 +00:00
return ;
}
2023-11-11 14:37:17 +00:00
2025-04-28 22:25:22 +02:00
if ( m_groupData . pNextWindow . expired ( ) ) {
m_groupData . pNextWindow = m_self ;
m_groupData . head = true ;
m_groupData . locked = false ;
m_groupData . deny = false ;
2023-09-21 23:42:00 +00:00
2025-04-28 22:25:22 +02:00
addWindowDeco ( makeUnique < CHyprGroupBarDecoration > ( m_self . lock ( ) ) ) ;
2023-09-21 23:42:00 +00:00
2025-04-28 22:25:22 +02:00
if ( m_workspace ) {
m_workspace - > updateWindows ( ) ;
m_workspace - > updateWindowData ( ) ;
2024-11-22 16:01:02 +00:00
}
2024-10-27 18:45:38 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitorID ( ) ) ;
2023-09-21 23:42:00 +00:00
g_pCompositor - > updateAllWindowsAnimatedDecorationValues ( ) ;
2024-05-07 15:00:55 +04:00
2025-08-14 19:44:56 +05:00
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " togglegroup " , . data = std : : format ( " 1,{:x} " , rc < uintptr_t > ( this ) ) } ) ;
2023-09-21 23:42:00 +00:00
}
2025-11-17 18:34:02 +00:00
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
2023-09-21 23:42:00 +00:00
}
void CWindow : : destroyGroup ( ) {
2025-04-28 22:25:22 +02:00
if ( m_groupData . pNextWindow = = m_self ) {
if ( m_groupRules & GROUP_SET_ALWAYS ) {
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " destoryGroup: window:{:x},title:{} has rule [group set always], ignored " , rc < uintptr_t > ( this ) , this - > m_title ) ;
2023-09-21 23:42:00 +00:00
return ;
}
2025-04-28 22:25:22 +02:00
m_groupData . pNextWindow . reset ( ) ;
m_groupData . head = false ;
2023-09-21 23:42:00 +00:00
updateWindowDecos ( ) ;
2025-04-28 22:25:22 +02:00
if ( m_workspace ) {
m_workspace - > updateWindows ( ) ;
m_workspace - > updateWindowData ( ) ;
2024-11-22 16:01:02 +00:00
}
2024-10-27 18:45:38 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitorID ( ) ) ;
2024-04-11 01:26:11 +09:00
g_pCompositor - > updateAllWindowsAnimatedDecorationValues ( ) ;
2024-05-07 15:00:55 +04:00
2025-08-14 19:44:56 +05:00
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " togglegroup " , . data = std : : format ( " 0,{:x} " , rc < uintptr_t > ( this ) ) } ) ;
2025-11-17 18:34:02 +00:00
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
2023-09-21 23:42:00 +00:00
return ;
}
2024-05-07 15:00:55 +04:00
std : : string addresses ;
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_self . lock ( ) ;
2024-04-27 12:43:12 +01:00
std : : vector < PHLWINDOW > members ;
2023-09-21 23:42:00 +00:00
do {
2024-04-27 12:43:12 +01:00
const auto PLASTWIN = curr ;
2025-04-28 22:25:22 +02:00
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
PLASTWIN - > m_groupData . pNextWindow . reset ( ) ;
2023-09-21 23:42:00 +00:00
curr - > setHidden ( false ) ;
members . push_back ( curr ) ;
2024-05-07 15:00:55 +04:00
2025-08-14 19:44:56 +05:00
addresses + = std : : format ( " {:x}, " , rc < uintptr_t > ( curr . get ( ) ) ) ;
2024-04-27 12:43:12 +01:00
} while ( curr . get ( ) ! = this ) ;
2023-09-21 23:42:00 +00:00
2024-08-26 17:25:39 +02:00
for ( auto const & w : members ) {
2025-04-28 22:25:22 +02:00
if ( w - > m_groupData . head )
2023-09-21 23:42:00 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowRemoved ( curr ) ;
2025-04-28 22:25:22 +02:00
w - > m_groupData . head = false ;
2023-09-21 23:42:00 +00:00
}
2025-05-02 17:07:20 +02:00
const bool GROUPSLOCKEDPREV = g_pKeybindManager - > m_groupsLocked ;
g_pKeybindManager - > m_groupsLocked = true ;
2024-08-26 20:24:30 +02:00
for ( auto const & w : members ) {
2023-09-21 23:42:00 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowCreated ( w ) ;
2025-11-17 18:34:02 +00:00
w - > m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
2023-09-21 23:42:00 +00:00
w - > updateWindowDecos ( ) ;
}
2025-05-02 17:07:20 +02:00
g_pKeybindManager - > m_groupsLocked = GROUPSLOCKEDPREV ;
2024-04-11 01:26:11 +09:00
2025-04-28 22:25:22 +02:00
if ( m_workspace ) {
m_workspace - > updateWindows ( ) ;
m_workspace - > updateWindowData ( ) ;
2024-11-22 16:01:02 +00:00
}
2024-10-27 18:45:38 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitorID ( ) ) ;
2024-04-11 01:26:11 +09:00
g_pCompositor - > updateAllWindowsAnimatedDecorationValues ( ) ;
2024-05-07 15:00:55 +04:00
if ( ! addresses . empty ( ) )
addresses . pop_back ( ) ;
2025-11-17 18:34:02 +00:00
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
2025-05-09 00:31:49 +05:30
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " togglegroup " , . data = std : : format ( " 0,{} " , addresses ) } ) ;
2023-09-21 23:42:00 +00:00
}
2024-04-27 12:43:12 +01:00
PHLWINDOW CWindow : : getGroupHead ( ) {
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_self . lock ( ) ;
while ( ! curr - > m_groupData . head )
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-02-19 21:07:32 +00:00
return curr ;
}
2024-04-27 12:43:12 +01:00
PHLWINDOW CWindow : : getGroupTail ( ) {
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_self . lock ( ) ;
while ( ! curr - > m_groupData . pNextWindow - > m_groupData . head )
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-02-19 21:07:32 +00:00
return curr ;
}
2024-04-27 12:43:12 +01:00
PHLWINDOW CWindow : : getGroupCurrent ( ) {
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_self . lock ( ) ;
2023-02-19 21:07:32 +00:00
while ( curr - > isHidden ( ) )
2025-04-28 22:25:22 +02:00
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-02-19 21:07:32 +00:00
return curr ;
}
2023-08-30 15:39:22 +00:00
int CWindow : : getGroupSize ( ) {
2024-04-27 12:43:12 +01:00
int size = 1 ;
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_self . lock ( ) ;
while ( curr - > m_groupData . pNextWindow ! = m_self ) {
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-08-30 15:39:22 +00:00
size + + ;
}
return size ;
}
2024-04-27 12:43:12 +01:00
bool CWindow : : canBeGroupedInto ( PHLWINDOW pWindow ) {
2024-09-05 18:29:33 +02:00
static auto ALLOWGROUPMERGE = CConfigValue < Hyprlang : : INT > ( " group:merge_groups_on_drag " ) ;
2025-04-28 22:25:22 +02:00
bool isGroup = m_groupData . pNextWindow ;
2025-08-14 19:44:56 +05:00
bool disallowDragIntoGroup = g_pInputManager - > m_wasDraggingWindow & & isGroup & & ! sc < bool > ( * ALLOWGROUPMERGE ) ;
2025-05-02 17:07:20 +02:00
return ! g_pKeybindManager - > m_groupsLocked // global group lock disengaged
2025-04-28 22:25:22 +02:00
& & ( ( m_groupRules & GROUP_INVADE & & m_firstMap ) // window ignore local group locks, or
| | ( ! pWindow - > getGroupHead ( ) - > m_groupData . locked // target unlocked
& & ! ( m_groupData . pNextWindow . lock ( ) & & getGroupHead ( ) - > m_groupData . locked ) ) ) // source unlocked or isn't group
& & ! m_groupData . deny // source is not denied entry
& & ! ( m_groupRules & GROUP_BARRED & & m_firstMap ) // group rule doesn't prevent adding window
& & ! disallowDragIntoGroup ; // config allows groups to be merged
2023-10-30 14:54:12 +00:00
}
2024-04-27 12:43:12 +01:00
PHLWINDOW CWindow : : getGroupWindowByIndex ( int index ) {
2023-08-30 15:39:22 +00:00
const int SIZE = getGroupSize ( ) ;
index = ( ( index % SIZE ) + SIZE ) % SIZE ;
2024-04-27 12:43:12 +01:00
PHLWINDOW curr = getGroupHead ( ) ;
2023-08-30 15:39:22 +00:00
while ( index > 0 ) {
2025-04-28 22:25:22 +02:00
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-08-30 15:39:22 +00:00
index - - ;
}
return curr ;
}
2025-10-22 11:32:42 +01:00
bool CWindow : : hasInGroup ( PHLWINDOW w ) {
PHLWINDOW curr = m_groupData . pNextWindow . lock ( ) ;
while ( curr & & curr ! = m_self ) {
if ( curr = = w )
return true ;
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
}
return false ;
}
2024-04-27 12:43:12 +01:00
void CWindow : : setGroupCurrent ( PHLWINDOW pWindow ) {
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_groupData . pNextWindow . lock ( ) ;
2024-04-27 12:43:12 +01:00
bool isMember = false ;
while ( curr . get ( ) ! = this ) {
2023-02-19 21:07:32 +00:00
if ( curr = = pWindow ) {
isMember = true ;
break ;
}
2025-04-28 22:25:22 +02:00
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-02-19 21:07:32 +00:00
}
2024-04-27 12:43:12 +01:00
if ( ! isMember & & pWindow . get ( ) ! = this )
2023-02-19 21:07:32 +00:00
return ;
2023-03-10 15:19:02 +00:00
const auto PCURRENT = getGroupCurrent ( ) ;
2024-07-31 17:55:52 +00:00
const bool FULLSCREEN = PCURRENT - > isFullscreen ( ) ;
2025-04-28 22:25:22 +02:00
const auto WORKSPACE = PCURRENT - > m_workspace ;
const auto MODE = PCURRENT - > m_fullscreenState . internal ;
2023-02-19 21:07:32 +00:00
2025-11-26 07:44:26 +09:00
const auto CURRENTISFOCUS = PCURRENT = = Desktop : : focusState ( ) - > window ( ) ;
2023-02-19 21:07:32 +00:00
2025-07-20 15:00:17 +00:00
const auto PWINDOWSIZE = PCURRENT - > m_realSize - > value ( ) ;
const auto PWINDOWPOS = PCURRENT - > m_realPosition - > value ( ) ;
const auto PWINDOWSIZEGOAL = PCURRENT - > m_realSize - > goal ( ) ;
const auto PWINDOWPOSGOAL = PCURRENT - > m_realPosition - > goal ( ) ;
2025-07-04 22:16:25 +00:00
const auto PWINDOWLASTFLOATINGSIZE = PCURRENT - > m_lastFloatingSize ;
const auto PWINDOWLASTFLOATINGPOSITION = PCURRENT - > m_lastFloatingPosition ;
2023-03-10 15:19:02 +00:00
if ( FULLSCREEN )
2024-07-31 17:55:52 +00:00
g_pCompositor - > setWindowFullscreenInternal ( PCURRENT , FSMODE_NONE ) ;
2023-03-10 15:19:02 +00:00
2023-02-19 21:07:32 +00:00
PCURRENT - > setHidden ( true ) ;
2023-08-15 19:15:37 +02:00
pWindow - > setHidden ( false ) ; // can remove m_pLastWindow
2023-02-19 21:07:32 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > replaceWindowDataWith ( PCURRENT , pWindow ) ;
2025-07-20 15:00:17 +00:00
if ( PCURRENT - > m_isFloating ) {
pWindow - > m_realPosition - > setValueAndWarp ( PWINDOWPOSGOAL ) ;
pWindow - > m_realSize - > setValueAndWarp ( PWINDOWSIZEGOAL ) ;
pWindow - > sendWindowSize ( ) ;
}
pWindow - > m_realPosition - > setValue ( PWINDOWPOS ) ;
pWindow - > m_realSize - > setValue ( PWINDOWSIZE ) ;
2025-07-04 22:16:25 +00:00
if ( FULLSCREEN )
g_pCompositor - > setWindowFullscreenInternal ( pWindow , MODE ) ;
pWindow - > m_lastFloatingSize = PWINDOWLASTFLOATINGSIZE ;
pWindow - > m_lastFloatingPosition = PWINDOWLASTFLOATINGPOSITION ;
2023-02-19 21:07:32 +00:00
g_pCompositor - > updateAllWindowsAnimatedDecorationValues ( ) ;
if ( CURRENTISFOCUS )
2025-11-26 07:44:26 +09:00
Desktop : : focusState ( ) - > rawWindowFocus ( pWindow ) ;
2023-03-10 15:19:02 +00:00
2023-06-14 19:44:51 +02:00
g_pHyprRenderer - > damageWindow ( pWindow ) ;
2023-11-11 14:37:17 +00:00
2025-11-20 16:57:31 +00:00
pWindow - > m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
2023-11-11 14:37:17 +00:00
pWindow - > updateWindowDecos ( ) ;
2023-02-19 21:07:32 +00:00
}
2024-04-27 12:43:12 +01:00
void CWindow : : insertWindowToGroup ( PHLWINDOW pWindow ) {
2025-04-28 22:25:22 +02:00
const auto BEGINAT = m_self . lock ( ) ;
const auto ENDAT = m_groupData . pNextWindow . lock ( ) ;
2023-02-19 22:19:40 +00:00
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_groupData . pNextWindow . lock ( ) ) {
BEGINAT - > m_groupData . pNextWindow = pWindow ;
pWindow - > m_groupData . pNextWindow = ENDAT ;
pWindow - > m_groupData . head = false ;
2025-07-20 15:00:17 +00:00
pWindow - > addWindowDeco ( makeUnique < CHyprGroupBarDecoration > ( pWindow ) ) ;
2023-02-19 22:19:40 +00:00
return ;
}
2023-07-20 17:48:32 +00:00
const auto SHEAD = pWindow - > getGroupHead ( ) ;
const auto STAIL = pWindow - > getGroupTail ( ) ;
2025-04-28 22:25:22 +02:00
SHEAD - > m_groupData . head = false ;
BEGINAT - > m_groupData . pNextWindow = SHEAD ;
STAIL - > m_groupData . pNextWindow = ENDAT ;
2025-11-20 16:57:31 +00:00
pWindow - > m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
pWindow - > updateWindowDecos ( ) ;
2023-03-18 16:30:29 +00:00
}
2024-04-27 12:43:12 +01:00
PHLWINDOW CWindow : : getGroupPrevious ( ) {
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_groupData . pNextWindow . lock ( ) ;
2023-07-13 17:55:20 +02:00
2025-04-28 22:25:22 +02:00
while ( curr ! = m_self & & curr - > m_groupData . pNextWindow ! = m_self )
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-07-13 17:55:20 +02:00
return curr ;
}
2024-04-27 12:43:12 +01:00
void CWindow : : switchWithWindowInGroup ( PHLWINDOW pWindow ) {
2025-04-28 22:25:22 +02:00
if ( ! m_groupData . pNextWindow . lock ( ) | | ! pWindow - > m_groupData . pNextWindow . lock ( ) )
2023-07-13 17:55:20 +02:00
return ;
2025-04-28 22:25:22 +02:00
if ( m_groupData . pNextWindow . lock ( ) = = pWindow ) { // A -> this -> pWindow -> B >> A -> pWindow -> this -> B
getGroupPrevious ( ) - > m_groupData . pNextWindow = pWindow ;
m_groupData . pNextWindow = pWindow - > m_groupData . pNextWindow ;
pWindow - > m_groupData . pNextWindow = m_self ;
2023-07-13 17:55:20 +02:00
2025-04-28 22:25:22 +02:00
} else if ( pWindow - > m_groupData . pNextWindow = = m_self ) { // A -> pWindow -> this -> B >> A -> this -> pWindow -> B
pWindow - > getGroupPrevious ( ) - > m_groupData . pNextWindow = m_self ;
pWindow - > m_groupData . pNextWindow = m_groupData . pNextWindow ;
m_groupData . pNextWindow = pWindow ;
2023-07-13 17:55:20 +02:00
2023-07-20 17:48:32 +00:00
} else { // A -> this -> B | C -> pWindow -> D >> A -> pWindow -> B | C -> this -> D
2025-04-28 22:25:22 +02:00
std : : swap ( m_groupData . pNextWindow , pWindow - > m_groupData . pNextWindow ) ;
std : : swap ( getGroupPrevious ( ) - > m_groupData . pNextWindow , pWindow - > getGroupPrevious ( ) - > m_groupData . pNextWindow ) ;
2023-07-13 17:55:20 +02:00
}
2025-04-28 22:25:22 +02:00
std : : swap ( m_groupData . head , pWindow - > m_groupData . head ) ;
std : : swap ( m_groupData . locked , pWindow - > m_groupData . locked ) ;
2025-11-20 16:57:31 +00:00
pWindow - > m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_GROUP | Desktop : : Rule : : RULE_PROP_ON_WORKSPACE ) ;
pWindow - > updateWindowDecos ( ) ;
2023-07-13 17:55:20 +02:00
}
2023-03-18 16:30:29 +00:00
void CWindow : : updateGroupOutputs ( ) {
2025-04-28 22:25:22 +02:00
if ( m_groupData . pNextWindow . expired ( ) )
2023-03-18 16:30:29 +00:00
return ;
2025-04-28 22:25:22 +02:00
PHLWINDOW curr = m_groupData . pNextWindow . lock ( ) ;
2024-04-02 20:32:39 +01:00
2025-04-28 22:25:22 +02:00
const auto WS = m_workspace ;
2023-03-18 16:30:29 +00:00
2024-04-27 12:43:12 +01:00
while ( curr . get ( ) ! = this ) {
2025-04-28 22:25:22 +02:00
curr - > m_monitor = m_monitor ;
2024-04-02 20:32:39 +01:00
curr - > moveToWorkspace ( WS ) ;
2023-03-18 16:30:29 +00:00
2025-04-28 22:25:22 +02:00
* curr - > m_realPosition = m_realPosition - > goal ( ) ;
* curr - > m_realSize = m_realSize - > goal ( ) ;
2023-03-18 16:30:29 +00:00
2025-04-28 22:25:22 +02:00
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2023-03-18 16:30:29 +00:00
}
2023-04-14 15:03:53 +01:00
}
Vector2D CWindow : : middle ( ) {
2025-04-28 22:25:22 +02:00
return m_realPosition - > goal ( ) + m_realSize - > goal ( ) / 2.f ;
2023-04-14 15:03:53 +01:00
}
2023-04-22 12:36:50 +01:00
bool CWindow : : opaque ( ) {
2025-04-28 22:25:22 +02:00
if ( m_alpha - > value ( ) ! = 1.f | | m_activeInactiveAlpha - > value ( ) ! = 1.f )
2023-07-19 16:13:55 +02:00
return false ;
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = m_workspace ;
2023-07-19 16:13:55 +02:00
2025-04-28 22:25:22 +02:00
if ( m_wlSurface - > small ( ) & & ! m_wlSurface - > m_fillIgnoreSmall )
2023-10-20 20:15:41 +01:00
return false ;
2025-05-10 18:31:26 +01:00
if ( PWORKSPACE & & PWORKSPACE - > m_alpha - > value ( ) ! = 1.f )
2023-07-19 16:13:55 +02:00
return false ;
2025-05-07 15:21:44 +02:00
if ( m_isX11 & & m_xwaylandSurface & & m_xwaylandSurface - > m_surface & & m_xwaylandSurface - > m_surface - > m_current . texture )
return m_xwaylandSurface - > m_surface - > m_current . texture - > m_opaque ;
2023-04-22 12:36:50 +01:00
2025-08-22 20:24:25 +03:00
auto solitaryResource = getSolitaryResource ( ) ;
if ( ! solitaryResource | | ! solitaryResource - > m_current . texture )
2024-06-08 10:07:59 +02:00
return false ;
2023-04-22 12:36:50 +01:00
2024-06-08 10:07:59 +02:00
// TODO: this is wrong
2025-05-04 23:39:00 +02:00
const auto EXTENTS = m_xdgSurface - > m_surface - > m_current . opaque . getExtents ( ) ;
if ( EXTENTS . w > = m_xdgSurface - > m_surface - > m_current . bufferSize . x & & EXTENTS . h > = m_xdgSurface - > m_surface - > m_current . bufferSize . y )
2023-04-22 12:36:50 +01:00
return true ;
2025-08-22 20:24:25 +03:00
return solitaryResource - > m_current . texture - > m_opaque ;
2023-04-22 12:36:50 +01:00
}
2023-07-19 16:13:55 +02:00
float CWindow : : rounding ( ) {
2025-01-05 12:38:49 -06:00
static auto PROUNDING = CConfigValue < Hyprlang : : INT > ( " decoration:rounding " ) ;
static auto PROUNDINGPOWER = CConfigValue < Hyprlang : : FLOAT > ( " decoration:rounding_power " ) ;
2023-07-19 16:13:55 +02:00
2025-11-17 18:34:02 +00:00
float roundingPower = m_ruleApplicator - > roundingPower ( ) . valueOr ( * PROUNDINGPOWER ) ;
float rounding = m_ruleApplicator - > rounding ( ) . valueOr ( * PROUNDING ) * ( roundingPower / 2.0 ) ; /* Make perceived roundness consistent. */
2023-07-19 16:13:55 +02:00
2025-11-17 18:34:02 +00:00
return rounding ;
2023-07-19 16:13:55 +02:00
}
2023-08-17 08:13:19 +00:00
2025-01-05 12:38:49 -06:00
float CWindow : : roundingPower ( ) {
static auto PROUNDINGPOWER = CConfigValue < Hyprlang : : FLOAT > ( " decoration:rounding_power " ) ;
2025-11-17 18:34:02 +00:00
return m_ruleApplicator - > roundingPower ( ) . valueOr ( std : : clamp ( * PROUNDINGPOWER , 1.F , 10.F ) ) ;
2025-01-05 12:38:49 -06:00
}
2024-07-11 14:10:42 +00:00
void CWindow : : updateWindowData ( ) {
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = m_workspace ;
2024-04-11 01:26:11 +09:00
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager - > getWorkspaceRuleFor ( PWORKSPACE ) : SWorkspaceRule { } ;
2024-07-11 14:10:42 +00:00
updateWindowData ( WORKSPACERULE ) ;
2024-04-11 01:26:11 +09:00
}
2023-08-17 08:13:19 +00:00
2024-07-11 14:10:42 +00:00
void CWindow : : updateWindowData ( const SWorkspaceRule & workspaceRule ) {
2025-11-17 18:34:02 +00:00
m_ruleApplicator - > borderSize ( ) . matchOptional ( workspaceRule . borderSize , Desktop : : Types : : PRIORITY_WORKSPACE_RULE ) ;
m_ruleApplicator - > decorate ( ) . matchOptional ( workspaceRule . decorate , Desktop : : Types : : PRIORITY_WORKSPACE_RULE ) ;
m_ruleApplicator - > borderSize ( ) . matchOptional ( workspaceRule . noBorder ? std : : optional < Hyprlang : : INT > ( 0 ) : std : : nullopt , Desktop : : Types : : PRIORITY_WORKSPACE_RULE ) ;
m_ruleApplicator - > rounding ( ) . matchOptional ( workspaceRule . noRounding . value_or ( false ) ? std : : optional < Hyprlang : : INT > ( 0 ) : std : : nullopt , Desktop : : Types : : PRIORITY_WORKSPACE_RULE ) ;
m_ruleApplicator - > noShadow ( ) . matchOptional ( workspaceRule . noShadow , Desktop : : Types : : PRIORITY_WORKSPACE_RULE ) ;
2023-08-17 08:13:19 +00:00
}
2025-12-08 15:04:40 +00:00
int CWindow : : getRealBorderSize ( ) const {
2025-11-17 18:34:02 +00:00
if ( ( m_workspace & & isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) ) | | ! m_ruleApplicator - > decorate ( ) . valueOrDefault ( ) )
2023-08-17 08:13:19 +00:00
return 0 ;
2024-03-03 18:39:20 +00:00
static auto PBORDERSIZE = CConfigValue < Hyprlang : : INT > ( " general:border_size " ) ;
2024-02-18 15:00:34 +00:00
2025-11-17 18:34:02 +00:00
return m_ruleApplicator - > borderSize ( ) . valueOr ( * PBORDERSIZE ) ;
2023-08-17 08:13:19 +00:00
}
2023-09-28 21:48:33 +01:00
2024-12-06 01:16:58 -05:00
float CWindow : : getScrollMouse ( ) {
static auto PINPUTSCROLLFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " input:scroll_factor " ) ;
2025-11-17 18:34:02 +00:00
return m_ruleApplicator - > scrollMouse ( ) . valueOr ( * PINPUTSCROLLFACTOR ) ;
2024-12-06 01:16:58 -05:00
}
float CWindow : : getScrollTouchpad ( ) {
static auto PTOUCHPADSCROLLFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " input:touchpad:scroll_factor " ) ;
2025-11-17 18:34:02 +00:00
return m_ruleApplicator - > scrollTouchpad ( ) . valueOr ( * PTOUCHPADSCROLLFACTOR ) ;
2024-12-06 01:16:58 -05:00
}
2025-09-02 13:16:43 +02:00
bool CWindow : : isScrollMouseOverridden ( ) {
2025-11-17 18:34:02 +00:00
return m_ruleApplicator - > scrollMouse ( ) . hasValue ( ) ;
2025-09-02 13:16:43 +02:00
}
bool CWindow : : isScrollTouchpadOverridden ( ) {
2025-11-17 18:34:02 +00:00
return m_ruleApplicator - > scrollTouchpad ( ) . hasValue ( ) ;
2025-09-02 13:16:43 +02:00
}
2023-09-28 21:48:33 +01:00
bool CWindow : : canBeTorn ( ) {
2024-07-21 13:09:54 +02:00
static auto PTEARING = CConfigValue < Hyprlang : : INT > ( " general:allow_tearing " ) ;
2025-11-17 18:34:02 +00:00
return m_ruleApplicator - > tearing ( ) . valueOr ( m_tearingHint ) & & * PTEARING ;
2023-09-28 21:48:33 +01:00
}
2023-12-11 17:51:10 +01:00
2023-12-23 22:30:49 +01:00
void CWindow : : setSuspended ( bool suspend ) {
2025-04-28 22:25:22 +02:00
if ( suspend = = m_suspended )
2023-12-23 22:30:49 +01:00
return ;
2025-05-04 23:39:00 +02:00
if ( m_isX11 | | ! m_xdgSurface | | ! m_xdgSurface - > m_toplevel )
2023-12-23 22:30:49 +01:00
return ;
2025-05-04 23:39:00 +02:00
m_xdgSurface - > m_toplevel - > setSuspeneded ( suspend ) ;
2025-04-28 22:25:22 +02:00
m_suspended = suspend ;
2023-12-23 22:30:49 +01:00
}
2024-03-14 18:25:28 +00:00
2024-10-19 23:03:29 +01:00
bool CWindow : : visibleOnMonitor ( PHLMONITOR pMonitor ) {
2025-04-28 22:25:22 +02:00
CBox wbox = { m_realPosition - > value ( ) , m_realSize - > value ( ) } ;
2024-03-14 18:25:28 +00:00
2025-07-27 08:11:07 -05:00
if ( m_isFloating )
wbox = getFullWindowBoundingBox ( ) ;
2025-04-30 23:45:20 +02:00
return ! wbox . intersection ( { pMonitor - > m_position , pMonitor - > m_size } ) . empty ( ) ;
2024-03-14 18:25:28 +00:00
}
2024-03-18 19:52:52 -07:00
void CWindow : : setAnimationsToMove ( ) {
2025-04-28 22:25:22 +02:00
m_realPosition - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " windowsMove " ) ) ;
m_animatingIn = false ;
2024-03-18 19:52:52 -07:00
}
2024-03-25 16:08:55 +00:00
2024-03-30 18:14:26 -07:00
void CWindow : : onWorkspaceAnimUpdate ( ) {
// clip box for animated offsets
2025-04-28 22:25:22 +02:00
if ( ! m_isFloating | | m_pinned | | isFullscreen ( ) | | m_draggingTiled ) {
m_floatingOffset = Vector2D ( 0 , 0 ) ;
2024-03-30 18:14:26 -07:00
return ;
}
Vector2D offset ;
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = m_workspace ;
2024-03-30 18:14:26 -07:00
if ( ! PWORKSPACE )
return ;
2025-04-28 22:25:22 +02:00
const auto PWSMON = m_monitor . lock ( ) ;
2024-03-30 18:14:26 -07:00
if ( ! PWSMON )
return ;
const auto WINBB = getFullWindowBoundingBox ( ) ;
2025-04-25 02:37:12 +02:00
if ( PWORKSPACE - > m_renderOffset - > value ( ) . x ! = 0 ) {
2025-04-30 23:45:20 +02:00
const auto PROGRESS = PWORKSPACE - > m_renderOffset - > value ( ) . x / PWSMON - > m_size . x ;
2024-03-30 18:14:26 -07:00
2025-04-30 23:45:20 +02:00
if ( WINBB . x < PWSMON - > m_position . x )
offset . x + = ( PWSMON - > m_position . x - WINBB . x ) * PROGRESS ;
2024-03-30 18:14:26 -07:00
2025-04-30 23:45:20 +02:00
if ( WINBB . x + WINBB . width > PWSMON - > m_position . x + PWSMON - > m_size . x )
offset . x + = ( WINBB . x + WINBB . width - PWSMON - > m_position . x - PWSMON - > m_size . x ) * PROGRESS ;
2025-04-25 02:37:12 +02:00
} else if ( PWORKSPACE - > m_renderOffset - > value ( ) . y ! = 0 ) {
2025-04-30 23:45:20 +02:00
const auto PROGRESS = PWORKSPACE - > m_renderOffset - > value ( ) . y / PWSMON - > m_size . y ;
2024-03-30 18:14:26 -07:00
2025-04-30 23:45:20 +02:00
if ( WINBB . y < PWSMON - > m_position . y )
offset . y + = ( PWSMON - > m_position . y - WINBB . y ) * PROGRESS ;
2024-03-30 18:14:26 -07:00
2025-04-30 23:45:20 +02:00
if ( WINBB . y + WINBB . height > PWSMON - > m_position . y + PWSMON - > m_size . y )
offset . y + = ( WINBB . y + WINBB . height - PWSMON - > m_position . y - PWSMON - > m_size . y ) * PROGRESS ;
2024-03-30 18:14:26 -07:00
}
2025-04-28 22:25:22 +02:00
m_floatingOffset = offset ;
2024-03-30 18:14:26 -07:00
}
2025-01-24 18:22:05 +00:00
void CWindow : : onFocusAnimUpdate ( ) {
// borderangle once
2025-04-28 22:25:22 +02:00
if ( m_borderAngleAnimationProgress - > enabled ( ) & & ! m_borderAngleAnimationProgress - > isBeingAnimated ( ) ) {
m_borderAngleAnimationProgress - > setValueAndWarp ( 0.f ) ;
* m_borderAngleAnimationProgress = 1.f ;
2025-01-24 18:22:05 +00:00
}
}
2024-03-25 16:08:55 +00:00
int CWindow : : popupsCount ( ) {
2025-08-22 20:24:25 +03:00
if ( m_isX11 | | ! m_popupHead )
2024-05-10 23:28:33 +01:00
return 0 ;
int no = - 1 ;
2025-12-08 15:04:40 +00:00
m_popupHead - > breadthfirst ( [ ] ( WP < Desktop : : View : : CPopup > p , void * d ) { * sc < int * > ( d ) + = 1 ; } , & no ) ;
2024-05-10 23:28:33 +01:00
return no ;
}
int CWindow : : surfacesCount ( ) {
2025-04-28 22:25:22 +02:00
if ( m_isX11 )
2024-03-25 16:08:55 +00:00
return 1 ;
int no = 0 ;
2025-08-14 19:44:56 +05:00
m_wlSurface - > resource ( ) - > breadthfirst ( [ ] ( SP < CWLSurfaceResource > r , const Vector2D & offset , void * d ) { * sc < int * > ( d ) + = 1 ; } , & no ) ;
2024-03-25 16:08:55 +00:00
return no ;
}
2024-04-02 20:32:39 +01:00
2024-10-07 18:52:49 +00:00
void CWindow : : clampWindowSize ( const std : : optional < Vector2D > minSize , const std : : optional < Vector2D > maxSize ) {
2025-04-28 22:25:22 +02:00
const Vector2D REALSIZE = m_realSize - > goal ( ) ;
2025-10-13 06:08:40 -06:00
const Vector2D MAX = isFullscreen ( ) ? Vector2D { INFINITY , INFINITY } : maxSize . value_or ( Vector2D { INFINITY , INFINITY } ) ;
const Vector2D NEWSIZE = REALSIZE . clamp ( minSize . value_or ( Vector2D { MIN_WINDOW_SIZE , MIN_WINDOW_SIZE } ) , MAX ) ;
2024-10-07 18:52:49 +00:00
const Vector2D DELTA = REALSIZE - NEWSIZE ;
2025-04-28 22:25:22 +02:00
* m_realPosition = m_realPosition - > goal ( ) + DELTA / 2.0 ;
* m_realSize = NEWSIZE ;
2024-10-07 18:52:49 +00:00
}
2024-07-31 17:55:52 +00:00
bool CWindow : : isFullscreen ( ) {
2025-04-28 22:25:22 +02:00
return m_fullscreenState . internal ! = FSMODE_NONE ;
2024-07-31 17:55:52 +00:00
}
2025-12-08 15:04:40 +00:00
bool CWindow : : isEffectiveInternalFSMode ( const eFullscreenMode MODE ) const {
2025-08-14 19:44:56 +05:00
return sc < eFullscreenMode > ( std : : bit_floor ( sc < uint8_t > ( m_fullscreenState . internal ) ) ) = = MODE ;
2024-07-31 17:55:52 +00:00
}
2024-08-08 21:01:50 +02:00
WORKSPACEID CWindow : : workspaceID ( ) {
2025-04-28 22:25:22 +02:00
return m_workspace ? m_workspace - > m_id : m_lastWorkspace ;
2024-04-02 20:32:39 +01:00
}
2024-10-27 18:45:38 +00:00
MONITORID CWindow : : monitorID ( ) {
2025-04-30 23:45:20 +02:00
return m_monitor ? m_monitor - > m_id : MONITOR_INVALID ;
2024-10-27 18:45:38 +00:00
}
2024-04-02 20:32:39 +01:00
bool CWindow : : onSpecialWorkspace ( ) {
2025-04-28 22:25:22 +02:00
return m_workspace ? m_workspace - > m_isSpecialWorkspace : g_pCompositor - > isWorkspaceSpecial ( m_lastWorkspace ) ;
2024-04-02 20:32:39 +01:00
}
2024-04-23 01:28:20 +01:00
std : : unordered_map < std : : string , std : : string > CWindow : : getEnv ( ) {
const auto PID = getPID ( ) ;
if ( PID < = 1 )
return { } ;
std : : unordered_map < std : : string , std : : string > results ;
2025-11-27 07:12:50 +09:00
std : : vector < char > buffer ;
size_t needle = 0 ;
# if defined(__linux__)
2024-04-23 01:28:20 +01:00
//
2024-04-23 00:40:03 +00:00
std : : string environFile = " /proc/ " + std : : to_string ( PID ) + " /environ " ;
std : : ifstream ifs ( environFile , std : : ios : : binary ) ;
2024-04-23 01:28:20 +01:00
if ( ! ifs . good ( ) )
return { } ;
buffer . resize ( 512 , ' \0 ' ) ;
while ( ifs . read ( buffer . data ( ) + needle , 512 ) ) {
buffer . resize ( buffer . size ( ) + 512 , ' \0 ' ) ;
needle + = 512 ;
}
2025-11-27 07:12:50 +09:00
# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
int mib [ 4 ] = { CTL_KERN , KERN_PROC , KERN_PROC_ENV , static_cast < int > ( PID ) } ;
size_t len = 0 ;
if ( sysctl ( mib , 4 , nullptr , & len , nullptr , 0 ) < 0 | | len = = 0 )
return { } ;
buffer . resize ( len , ' \0 ' ) ;
if ( sysctl ( mib , 4 , buffer . data ( ) , & len , nullptr , 0 ) < 0 )
return { } ;
needle = len ;
# endif
2024-04-23 01:28:20 +01:00
2024-05-24 20:40:15 +02:00
if ( needle < = 1 )
return { } ;
2024-04-23 01:28:20 +01:00
std : : replace ( buffer . begin ( ) , buffer . end ( ) - 1 , ' \0 ' , ' \n ' ) ;
2024-05-24 20:40:15 +02:00
CVarList envs ( std : : string { buffer . data ( ) , buffer . size ( ) - 1 } , 0 , ' \n ' , true ) ;
2024-04-23 01:28:20 +01:00
2024-08-26 20:24:30 +02:00
for ( auto const & e : envs ) {
2024-04-23 01:28:20 +01:00
if ( ! e . contains ( ' = ' ) )
continue ;
const auto EQ = e . find_first_of ( ' = ' ) ;
results [ e . substr ( 0 , EQ ) ] = e . substr ( EQ + 1 ) ;
}
return results ;
}
2024-04-25 00:58:40 +01:00
2024-05-08 01:31:16 +01:00
void CWindow : : activate ( bool force ) {
2025-11-26 07:44:26 +09:00
if ( Desktop : : focusState ( ) - > window ( ) = = m_self )
2024-05-10 23:28:33 +01:00
return ;
2024-04-25 00:58:40 +01:00
static auto PFOCUSONACTIVATE = CConfigValue < Hyprlang : : INT > ( " misc:focus_on_activate " ) ;
2025-04-28 22:25:22 +02:00
m_isUrgent = true ;
2025-04-24 20:37:49 -04:00
2025-08-14 19:44:56 +05:00
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " urgent " , . data = std : : format ( " {:x} " , rc < uintptr_t > ( this ) ) } ) ;
2025-04-28 22:25:22 +02:00
EMIT_HOOK_EVENT ( " urgent " , m_self . lock ( ) ) ;
2024-04-25 00:58:40 +01:00
2025-11-17 18:34:02 +00:00
if ( ! force & &
( ! m_ruleApplicator - > focusOnActivate ( ) . valueOr ( * PFOCUSONACTIVATE ) | | ( m_suppressedEvents & SUPPRESS_ACTIVATE_FOCUSONLY ) | | ( m_suppressedEvents & SUPPRESS_ACTIVATE ) ) )
2024-04-25 00:58:40 +01:00
return ;
2025-04-28 22:25:22 +02:00
if ( ! m_isMapped ) {
2024-08-28 20:33:29 +02:00
Debug : : log ( LOG , " Ignoring CWindow::activate focus/warp, window is not mapped yet. " ) ;
return ;
}
2025-04-28 22:25:22 +02:00
if ( m_isFloating )
g_pCompositor - > changeWindowZOrder ( m_self . lock ( ) , true ) ;
2024-04-25 00:58:40 +01:00
2025-11-26 07:44:26 +09:00
Desktop : : focusState ( ) - > fullWindowFocus ( m_self . lock ( ) ) ;
2024-06-07 17:52:15 +00:00
warpCursor ( ) ;
2024-04-25 00:58:40 +01:00
}
2024-05-10 23:28:33 +01:00
void CWindow : : onUpdateState ( ) {
2025-05-07 15:21:44 +02:00
std : : optional < bool > requestsFS = m_xdgSurface ? m_xdgSurface - > m_toplevel - > m_state . requestsFullscreen : m_xwaylandSurface - > m_state . requestsFullscreen ;
2025-05-04 23:39:00 +02:00
std : : optional < MONITORID > requestsID = m_xdgSurface ? m_xdgSurface - > m_toplevel - > m_state . requestsFullscreenMonitor : MONITOR_INVALID ;
2025-05-07 15:21:44 +02:00
std : : optional < bool > requestsMX = m_xdgSurface ? m_xdgSurface - > m_toplevel - > m_state . requestsMaximize : m_xwaylandSurface - > m_state . requestsMaximize ;
2024-05-10 23:28:33 +01:00
2025-04-28 22:25:22 +02:00
if ( requestsFS . has_value ( ) & & ! ( m_suppressedEvents & SUPPRESS_FULLSCREEN ) ) {
if ( requestsID . has_value ( ) & & ( requestsID . value ( ) ! = MONITOR_INVALID ) & & ! ( m_suppressedEvents & SUPPRESS_FULLSCREEN_OUTPUT ) ) {
if ( m_isMapped ) {
2025-01-09 17:38:38 -05:00
const auto monitor = g_pCompositor - > getMonitorFromID ( requestsID . value ( ) ) ;
2025-04-30 23:45:20 +02:00
g_pCompositor - > moveWindowToWorkspaceSafe ( m_self . lock ( ) , monitor - > m_activeWorkspace ) ;
2025-11-26 07:44:26 +09:00
Desktop : : focusState ( ) - > rawMonitorFocus ( monitor ) ;
2025-01-09 17:38:38 -05:00
}
2025-04-28 22:25:22 +02:00
if ( ! m_isMapped )
m_wantsInitialFullscreenMonitor = requestsID . value ( ) ;
2025-01-09 17:38:38 -05:00
}
2024-05-25 22:43:51 +02:00
bool fs = requestsFS . value ( ) ;
2025-04-28 22:25:22 +02:00
if ( m_isMapped )
g_pCompositor - > changeWindowFullscreenModeClient ( m_self . lock ( ) , FSMODE_FULLSCREEN , requestsFS . value ( ) ) ;
2024-05-10 23:28:33 +01:00
2025-04-28 22:25:22 +02:00
if ( ! m_isMapped )
m_wantsInitialFullscreen = fs ;
2024-05-10 23:28:33 +01:00
}
2025-04-28 22:25:22 +02:00
if ( requestsMX . has_value ( ) & & ! ( m_suppressedEvents & SUPPRESS_MAXIMIZE ) ) {
2025-09-01 15:44:41 -05:00
if ( m_isMapped ) {
auto window = m_self . lock ( ) ;
auto state = sc < int8_t > ( window - > m_fullscreenState . client ) ;
bool maximized = ( state & sc < uint8_t > ( FSMODE_MAXIMIZED ) ) ! = 0 ;
g_pCompositor - > changeWindowFullscreenModeClient ( window , FSMODE_MAXIMIZED , ! maximized ) ;
}
2024-05-10 23:28:33 +01:00
}
}
void CWindow : : onUpdateMeta ( ) {
const auto NEWTITLE = fetchTitle ( ) ;
2024-05-29 05:37:24 +08:00
bool doUpdate = false ;
2024-05-10 23:28:33 +01:00
2025-04-28 22:25:22 +02:00
if ( m_title ! = NEWTITLE ) {
m_title = NEWTITLE ;
2025-08-14 19:44:56 +05:00
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " windowtitle " , . data = std : : format ( " {:x} " , rc < uintptr_t > ( this ) ) } ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " windowtitlev2 " , . data = std : : format ( " {:x},{} " , rc < uintptr_t > ( this ) , m_title ) } ) ;
2025-04-28 22:25:22 +02:00
EMIT_HOOK_EVENT ( " windowTitle " , m_self . lock ( ) ) ;
2024-05-10 23:28:33 +01:00
2025-11-26 07:44:26 +09:00
if ( m_self = = Desktop : : focusState ( ) - > window ( ) ) { // if it's the active, let's post an event to update others
2025-05-09 00:31:49 +05:30
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " activewindow " , . data = m_class + " , " + m_title } ) ;
2025-08-14 19:44:56 +05:00
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " activewindowv2 " , . data = std : : format ( " {:x} " , rc < uintptr_t > ( this ) ) } ) ;
2025-04-28 22:25:22 +02:00
EMIT_HOOK_EVENT ( " activeWindow " , m_self . lock ( ) ) ;
2024-05-10 23:28:33 +01:00
}
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " Window {:x} set title to {} " , rc < uintptr_t > ( this ) , m_title ) ;
2024-05-29 05:37:24 +08:00
doUpdate = true ;
2024-05-10 23:28:33 +01:00
}
const auto NEWCLASS = fetchClass ( ) ;
2025-04-28 22:25:22 +02:00
if ( m_class ! = NEWCLASS ) {
m_class = NEWCLASS ;
2024-05-10 23:28:33 +01:00
2025-11-26 07:44:26 +09:00
if ( m_self = = Desktop : : focusState ( ) - > window ( ) ) { // if it's the active, let's post an event to update others
2025-05-09 00:31:49 +05:30
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " activewindow " , . data = m_class + " , " + m_title } ) ;
2025-08-14 19:44:56 +05:00
g_pEventManager - > postEvent ( SHyprIPCEvent { . event = " activewindowv2 " , . data = std : : format ( " {:x} " , rc < uintptr_t > ( this ) ) } ) ;
2025-04-28 22:25:22 +02:00
EMIT_HOOK_EVENT ( " activeWindow " , m_self . lock ( ) ) ;
2024-05-10 23:28:33 +01:00
}
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " Window {:x} set class to {} " , rc < uintptr_t > ( this ) , m_class ) ;
2024-05-29 05:37:24 +08:00
doUpdate = true ;
}
if ( doUpdate ) {
2025-11-17 18:34:02 +00:00
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_TITLE | Desktop : : Rule : : RULE_PROP_CLASS ) ;
2024-05-10 23:28:33 +01:00
updateToplevel ( ) ;
}
}
std : : string CWindow : : fetchTitle ( ) {
2025-04-28 22:25:22 +02:00
if ( ! m_isX11 ) {
2025-05-04 23:39:00 +02:00
if ( m_xdgSurface & & m_xdgSurface - > m_toplevel )
return m_xdgSurface - > m_toplevel - > m_state . title ;
2024-05-10 23:28:33 +01:00
} else {
2025-04-28 22:25:22 +02:00
if ( m_xwaylandSurface )
2025-05-07 15:21:44 +02:00
return m_xwaylandSurface - > m_state . title ;
2024-05-10 23:28:33 +01:00
}
return " " ;
}
std : : string CWindow : : fetchClass ( ) {
2025-04-28 22:25:22 +02:00
if ( ! m_isX11 ) {
2025-05-04 23:39:00 +02:00
if ( m_xdgSurface & & m_xdgSurface - > m_toplevel )
return m_xdgSurface - > m_toplevel - > m_state . appid ;
2024-05-10 23:28:33 +01:00
} else {
2025-04-28 22:25:22 +02:00
if ( m_xwaylandSurface )
2025-05-07 15:21:44 +02:00
return m_xwaylandSurface - > m_state . appid ;
2024-05-10 23:28:33 +01:00
}
return " " ;
}
void CWindow : : onAck ( uint32_t serial ) {
2025-09-21 19:27:56 +02:00
const auto SERIAL = std : : ranges : : find_if ( m_pendingSizeAcks | std : : views : : reverse , [ serial ] ( const auto & e ) { return e . first < = serial ; } ) ;
2024-05-10 23:28:33 +01:00
2025-04-28 22:25:22 +02:00
if ( SERIAL = = m_pendingSizeAcks . rend ( ) )
2024-05-10 23:28:33 +01:00
return ;
2025-04-28 22:25:22 +02:00
m_pendingSizeAck = * SERIAL ;
std : : erase_if ( m_pendingSizeAcks , [ & ] ( const auto & el ) { return el . first < = SERIAL - > first ; } ) ;
2025-09-21 19:27:56 +02:00
if ( m_isX11 )
return ;
m_wlSurface - > resource ( ) - > m_pending . ackedSize = m_pendingSizeAck - > second ; // apply pending size. We pinged, the window ponged.
m_wlSurface - > resource ( ) - > m_pending . updated . bits . acked = true ;
m_pendingSizeAck . reset ( ) ;
2024-05-25 22:43:51 +02:00
}
void CWindow : : onResourceChangeX11 ( ) {
2025-05-07 15:21:44 +02:00
if ( m_xwaylandSurface - > m_surface & & ! m_wlSurface - > resource ( ) )
m_wlSurface - > assign ( m_xwaylandSurface - > m_surface . lock ( ) , m_self . lock ( ) ) ;
else if ( ! m_xwaylandSurface - > m_surface & & m_wlSurface - > resource ( ) )
2025-04-28 22:25:22 +02:00
m_wlSurface - > unassign ( ) ;
2024-05-25 22:43:51 +02:00
// update metadata as well,
// could be first assoc and we need to catch the class
onUpdateMeta ( ) ;
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " xwayland window {:x} -> association to {:x} " , rc < uintptr_t > ( m_xwaylandSurface . get ( ) ) , rc < uintptr_t > ( m_wlSurface - > resource ( ) . get ( ) ) ) ;
2024-05-25 22:43:51 +02:00
}
2025-02-16 00:20:42 +00:00
void CWindow : : onX11ConfigureRequest ( CBox box ) {
2024-05-25 22:43:51 +02:00
2025-05-07 15:21:44 +02:00
if ( ! m_xwaylandSurface - > m_surface | | ! m_xwaylandSurface - > m_mapped | | ! m_isMapped ) {
2025-04-28 22:25:22 +02:00
m_xwaylandSurface - > configure ( box ) ;
m_pendingReportedSize = box . size ( ) ;
m_reportedSize = box . size ( ) ;
m_reportedPosition = box . pos ( ) ;
2025-02-16 00:20:42 +00:00
updateX11SurfaceScale ( ) ;
2024-05-25 22:43:51 +02:00
return ;
}
2025-04-28 22:25:22 +02:00
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
2024-05-25 22:43:51 +02:00
2025-05-01 23:57:11 +02:00
if ( ! m_isFloating | | isFullscreen ( ) | | g_pInputManager - > m_currentlyDraggedWindow = = m_self ) {
2025-02-06 11:21:04 +00:00
sendWindowSize ( true ) ;
2024-05-25 22:43:51 +02:00
g_pInputManager - > refocus ( ) ;
2025-04-28 22:25:22 +02:00
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
2024-05-25 22:43:51 +02:00
return ;
}
if ( box . size ( ) > Vector2D { 1 , 1 } )
setHidden ( false ) ;
else
setHidden ( true ) ;
2025-04-28 22:25:22 +02:00
m_realPosition - > setValueAndWarp ( xwaylandPositionToReal ( box . pos ( ) ) ) ;
m_realSize - > setValueAndWarp ( xwaylandSizeToReal ( box . size ( ) ) ) ;
2024-05-25 22:43:51 +02:00
2025-04-28 22:25:22 +02:00
m_position = m_realPosition - > goal ( ) ;
m_size = m_realSize - > goal ( ) ;
2024-05-25 22:43:51 +02:00
2025-04-28 22:25:22 +02:00
if ( m_pendingReportedSize ! = box . size ( ) | | m_reportedPosition ! = box . pos ( ) ) {
m_xwaylandSurface - > configure ( box ) ;
m_reportedSize = box . size ( ) ;
m_pendingReportedSize = box . size ( ) ;
m_reportedPosition = box . pos ( ) ;
2025-02-16 00:20:42 +00:00
}
2024-05-25 22:43:51 +02:00
2025-02-16 00:20:42 +00:00
updateX11SurfaceScale ( ) ;
2024-05-25 22:43:51 +02:00
updateWindowDecos ( ) ;
2025-04-28 22:25:22 +02:00
if ( ! m_workspace | | ! m_workspace - > isVisible ( ) )
2024-05-25 22:43:51 +02:00
return ; // further things are only for visible windows
2025-04-30 23:45:20 +02:00
m_workspace = g_pCompositor - > getMonitorFromVector ( m_realPosition - > goal ( ) + m_realSize - > goal ( ) / 2.f ) - > m_activeWorkspace ;
2024-05-25 22:43:51 +02:00
2025-04-28 22:25:22 +02:00
g_pCompositor - > changeWindowZOrder ( m_self . lock ( ) , true ) ;
2024-05-25 22:43:51 +02:00
2025-04-28 22:25:22 +02:00
m_createdOverFullscreen = true ;
2024-05-25 22:43:51 +02:00
2025-04-28 22:25:22 +02:00
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
2024-05-25 22:43:51 +02:00
}
2024-06-07 17:52:15 +00:00
2024-12-10 23:55:05 +03:00
void CWindow : : warpCursor ( bool force ) {
2025-04-28 22:25:22 +02:00
static auto PERSISTENTWARPS = CConfigValue < Hyprlang : : INT > ( " cursor:persistent_warps " ) ;
const auto coords = m_relativeCursorCoordsOnLastWarp ;
m_relativeCursorCoordsOnLastWarp . x = - 1 ; // reset m_vRelativeCursorCoordsOnLastWarp
2024-06-07 17:52:15 +00:00
2025-04-28 22:25:22 +02:00
if ( * PERSISTENTWARPS & & coords . x > 0 & & coords . y > 0 & & coords < m_size ) // don't warp cursor outside the window
g_pCompositor - > warpCursorTo ( m_position + coords , force ) ;
2024-06-07 17:52:15 +00:00
else
2024-12-10 23:55:05 +03:00
g_pCompositor - > warpCursorTo ( middle ( ) , force ) ;
2024-06-07 17:52:15 +00:00
}
2024-06-15 18:20:09 +02:00
PHLWINDOW CWindow : : getSwallower ( ) {
static auto PSWALLOWREGEX = CConfigValue < std : : string > ( " misc:swallow_regex " ) ;
static auto PSWALLOWEXREGEX = CConfigValue < std : : string > ( " misc:swallow_exception_regex " ) ;
static auto PSWALLOW = CConfigValue < Hyprlang : : INT > ( " misc:enable_swallow " ) ;
2024-10-28 16:52:14 +00:00
if ( ! * PSWALLOW | | std : : string { * PSWALLOWREGEX } = = STRVAL_EMPTY | | ( * PSWALLOWREGEX ) . empty ( ) )
2024-06-15 18:20:09 +02:00
return nullptr ;
// check parent
std : : vector < PHLWINDOW > candidates ;
pid_t currentPid = getPID ( ) ;
// walk up the tree until we find someone, 25 iterations max.
for ( size_t i = 0 ; i < 25 ; + + i ) {
currentPid = getPPIDof ( currentPid ) ;
if ( ! currentPid )
break ;
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( ! w - > m_isMapped | | w - > isHidden ( ) )
2024-06-15 18:20:09 +02:00
continue ;
if ( w - > getPID ( ) = = currentPid )
candidates . push_back ( w ) ;
}
}
if ( ! ( * PSWALLOWREGEX ) . empty ( ) )
2025-04-28 22:25:22 +02:00
std : : erase_if ( candidates , [ & ] ( const auto & other ) { return ! RE2 : : FullMatch ( other - > m_class , * PSWALLOWREGEX ) ; } ) ;
2024-06-15 18:20:09 +02:00
2025-05-31 23:49:50 +05:00
if ( candidates . empty ( ) )
2024-06-15 18:20:09 +02:00
return nullptr ;
if ( ! ( * PSWALLOWEXREGEX ) . empty ( ) )
2025-04-28 22:25:22 +02:00
std : : erase_if ( candidates , [ & ] ( const auto & other ) { return RE2 : : FullMatch ( other - > m_title , * PSWALLOWEXREGEX ) ; } ) ;
2024-06-15 18:20:09 +02:00
2025-05-31 23:49:50 +05:00
if ( candidates . empty ( ) )
2024-06-15 18:20:09 +02:00
return nullptr ;
if ( candidates . size ( ) = = 1 )
2025-02-06 12:18:04 +01:00
return candidates [ 0 ] ;
2024-06-15 18:20:09 +02:00
// walk up the focus history and find the last focused
2025-11-26 07:44:26 +09:00
for ( auto const & w : Desktop : : focusState ( ) - > windowHistory ( ) ) {
2024-06-15 18:20:09 +02:00
if ( ! w )
continue ;
2025-05-09 00:31:49 +05:30
if ( std : : ranges : : find ( candidates . begin ( ) , candidates . end ( ) , w . lock ( ) ) ! = candidates . end ( ) )
2024-06-15 18:20:09 +02:00
return w . lock ( ) ;
}
// if none are found (??) then just return the first one
2025-02-06 12:18:04 +01:00
return candidates [ 0 ] ;
2024-06-15 18:20:09 +02:00
}
2024-07-11 14:10:42 +00:00
2024-08-30 14:12:23 +02:00
bool CWindow : : isX11OverrideRedirect ( ) {
2025-05-07 15:21:44 +02:00
return m_xwaylandSurface & & m_xwaylandSurface - > m_overrideRedirect ;
2024-08-30 14:12:23 +02:00
}
bool CWindow : : isModal ( ) {
2025-05-07 15:21:44 +02:00
return ( m_xwaylandSurface & & m_xwaylandSurface - > m_modal ) ;
2024-08-30 14:12:23 +02:00
}
2024-11-17 19:31:54 +00:00
Vector2D CWindow : : requestedMinSize ( ) {
2025-08-22 02:25:27 -05:00
bool hasSizeHints = m_xwaylandSurface ? m_xwaylandSurface - > m_sizeHints : false ;
bool hasTopLevel = m_xdgSurface ? m_xdgSurface - > m_toplevel : false ;
if ( ( m_isX11 & & ! hasSizeHints ) | | ( ! m_isX11 & & ! hasTopLevel ) )
2024-11-17 19:31:54 +00:00
return Vector2D ( 1 , 1 ) ;
2025-05-07 15:21:44 +02:00
Vector2D minSize = m_isX11 ? Vector2D ( m_xwaylandSurface - > m_sizeHints - > min_width , m_xwaylandSurface - > m_sizeHints - > min_height ) : m_xdgSurface - > m_toplevel - > layoutMinSize ( ) ;
2024-11-17 19:31:54 +00:00
minSize = minSize . clamp ( { 1 , 1 } ) ;
return minSize ;
}
Vector2D CWindow : : requestedMaxSize ( ) {
constexpr int NO_MAX_SIZE_LIMIT = 99999 ;
2025-11-17 18:34:02 +00:00
if ( ( ( m_isX11 & & ! m_xwaylandSurface - > m_sizeHints ) | | ( ! m_isX11 & & ( ! m_xdgSurface | | ! m_xdgSurface - > m_toplevel ) ) | | m_ruleApplicator - > noMaxSize ( ) . valueOrDefault ( ) ) )
2024-11-17 19:31:54 +00:00
return Vector2D ( NO_MAX_SIZE_LIMIT , NO_MAX_SIZE_LIMIT ) ;
2025-05-07 15:21:44 +02:00
Vector2D maxSize = m_isX11 ? Vector2D ( m_xwaylandSurface - > m_sizeHints - > max_width , m_xwaylandSurface - > m_sizeHints - > max_height ) : m_xdgSurface - > m_toplevel - > layoutMaxSize ( ) ;
2024-11-17 19:31:54 +00:00
if ( maxSize . x < 5 )
maxSize . x = NO_MAX_SIZE_LIMIT ;
if ( maxSize . y < 5 )
maxSize . y = NO_MAX_SIZE_LIMIT ;
return maxSize ;
}
2025-01-25 20:36:44 +00:00
2025-02-16 00:20:42 +00:00
Vector2D CWindow : : realToReportSize ( ) {
2025-04-28 22:25:22 +02:00
if ( ! m_isX11 )
return m_realSize - > goal ( ) . clamp ( Vector2D { 0 , 0 } , Vector2D { std : : numeric_limits < double > : : infinity ( ) , std : : numeric_limits < double > : : infinity ( ) } ) ;
2025-02-16 00:20:42 +00:00
static auto PXWLFORCESCALEZERO = CConfigValue < Hyprlang : : INT > ( " xwayland:force_zero_scaling " ) ;
2025-04-28 22:25:22 +02:00
const auto REPORTSIZE = m_realSize - > goal ( ) . clamp ( Vector2D { 1 , 1 } , Vector2D { std : : numeric_limits < double > : : infinity ( ) , std : : numeric_limits < double > : : infinity ( ) } ) ;
const auto PMONITOR = m_monitor . lock ( ) ;
2025-02-16 00:20:42 +00:00
if ( * PXWLFORCESCALEZERO & & PMONITOR )
2025-04-30 23:45:20 +02:00
return REPORTSIZE * PMONITOR - > m_scale ;
2025-02-16 00:20:42 +00:00
return REPORTSIZE ;
}
Vector2D CWindow : : realToReportPosition ( ) {
2025-04-28 22:25:22 +02:00
if ( ! m_isX11 )
return m_realPosition - > goal ( ) ;
2025-02-16 00:20:42 +00:00
2025-04-28 22:25:22 +02:00
return g_pXWaylandManager - > waylandToXWaylandCoords ( m_realPosition - > goal ( ) ) ;
2025-02-16 00:20:42 +00:00
}
Vector2D CWindow : : xwaylandSizeToReal ( Vector2D size ) {
static auto PXWLFORCESCALEZERO = CConfigValue < Hyprlang : : INT > ( " xwayland:force_zero_scaling " ) ;
2025-04-28 22:25:22 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2025-02-16 00:20:42 +00:00
const auto SIZE = size . clamp ( Vector2D { 1 , 1 } , Vector2D { std : : numeric_limits < double > : : infinity ( ) , std : : numeric_limits < double > : : infinity ( ) } ) ;
2025-04-30 23:45:20 +02:00
const auto SCALE = * PXWLFORCESCALEZERO ? PMONITOR - > m_scale : 1.0f ;
2025-02-16 00:20:42 +00:00
return SIZE / SCALE ;
}
Vector2D CWindow : : xwaylandPositionToReal ( Vector2D pos ) {
return g_pXWaylandManager - > xwaylandToWaylandCoords ( pos ) ;
}
void CWindow : : updateX11SurfaceScale ( ) {
2025-01-25 20:36:44 +00:00
static auto PXWLFORCESCALEZERO = CConfigValue < Hyprlang : : INT > ( " xwayland:force_zero_scaling " ) ;
2025-02-16 00:20:42 +00:00
2025-04-28 22:25:22 +02:00
m_X11SurfaceScaledBy = 1.0f ;
if ( m_isX11 & & * PXWLFORCESCALEZERO ) {
if ( const auto PMONITOR = m_monitor . lock ( ) ; PMONITOR )
2025-04-30 23:45:20 +02:00
m_X11SurfaceScaledBy = PMONITOR - > m_scale ;
2025-02-16 00:20:42 +00:00
}
}
void CWindow : : sendWindowSize ( bool force ) {
2025-04-28 22:25:22 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2025-01-25 20:36:44 +00:00
2025-08-14 19:44:56 +05:00
Debug : : log ( TRACE , " sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {}) " , rc < uintptr_t > ( this ) , this - > m_title , m_realPosition - > goal ( ) ,
m_realSize - > goal ( ) , force ) ;
2025-01-25 20:36:44 +00:00
// TODO: this should be decoupled from setWindowSize IMO
2025-02-16 00:20:42 +00:00
const auto REPORTPOS = realToReportPosition ( ) ;
2025-01-25 20:36:44 +00:00
2025-02-16 00:20:42 +00:00
const auto REPORTSIZE = realToReportSize ( ) ;
2025-01-25 20:36:44 +00:00
2025-04-28 22:25:22 +02:00
if ( ! force & & m_pendingReportedSize = = REPORTSIZE & & ( m_reportedPosition = = REPORTPOS | | ! m_isX11 ) )
2025-01-25 20:36:44 +00:00
return ;
2025-04-28 22:25:22 +02:00
m_reportedPosition = REPORTPOS ;
m_pendingReportedSize = REPORTSIZE ;
2025-02-16 00:20:42 +00:00
updateX11SurfaceScale ( ) ;
2025-01-25 20:36:44 +00:00
2025-04-28 22:25:22 +02:00
if ( m_isX11 & & m_xwaylandSurface )
m_xwaylandSurface - > configure ( { REPORTPOS , REPORTSIZE } ) ;
2025-05-04 23:39:00 +02:00
else if ( m_xdgSurface & & m_xdgSurface - > m_toplevel )
2025-09-21 19:27:56 +02:00
m_pendingSizeAcks . emplace_back ( m_xdgSurface - > m_toplevel - > setSize ( REPORTSIZE ) , REPORTSIZE . floor ( ) ) ;
2025-01-25 20:36:44 +00:00
}
2025-02-02 22:25:29 +03:00
NContentType : : eContentType CWindow : : getContentType ( ) {
2025-05-03 16:02:49 +02:00
if ( ! m_wlSurface | | ! m_wlSurface - > resource ( ) | | ! m_wlSurface - > resource ( ) - > m_contentType . valid ( ) )
2025-02-06 06:16:47 -05:00
return CONTENT_TYPE_NONE ;
2025-05-04 00:13:29 +02:00
return m_wlSurface - > resource ( ) - > m_contentType - > m_value ;
2025-02-02 22:25:29 +03:00
}
void CWindow : : setContentType ( NContentType : : eContentType contentType ) {
2025-05-03 16:02:49 +02:00
if ( ! m_wlSurface - > resource ( ) - > m_contentType . valid ( ) )
m_wlSurface - > resource ( ) - > m_contentType = PROTO : : contentType - > getContentType ( m_wlSurface - > resource ( ) ) ;
2025-02-02 22:25:29 +03:00
// else disallow content type change if proto is used?
2025-08-14 19:44:56 +05:00
Debug : : log ( INFO , " ContentType for window {} " , sc < int > ( contentType ) ) ;
2025-05-04 00:13:29 +02:00
m_wlSurface - > resource ( ) - > m_contentType - > m_value = contentType ;
2025-02-02 22:25:29 +03:00
}
2025-02-08 09:05:44 -05:00
void CWindow : : deactivateGroupMembers ( ) {
auto curr = getGroupHead ( ) ;
while ( curr ) {
2025-04-28 22:25:22 +02:00
if ( curr ! = m_self . lock ( ) ) {
2025-07-25 15:19:23 +00:00
// we don't want to deactivate unfocused xwayland windows
2025-04-01 18:51:37 -04:00
// because X is weird, keep the behavior for wayland windows
// also its not really needed for xwayland windows
// ref: #9760 #9294
2025-05-04 23:39:00 +02:00
if ( ! curr - > m_isX11 & & curr - > m_xdgSurface & & curr - > m_xdgSurface - > m_toplevel )
curr - > m_xdgSurface - > m_toplevel - > setActive ( false ) ;
2025-02-08 09:05:44 -05:00
}
2025-04-28 22:25:22 +02:00
curr = curr - > m_groupData . pNextWindow . lock ( ) ;
2025-02-08 09:05:44 -05:00
if ( curr = = getGroupHead ( ) )
break ;
}
}
2025-02-18 15:10:40 +00:00
bool CWindow : : isNotResponding ( ) {
2025-04-28 22:25:22 +02:00
return g_pANRManager - > isNotResponding ( m_self . lock ( ) ) ;
2025-02-18 15:10:40 +00:00
}
2025-04-21 22:22:06 +01:00
std : : optional < std : : string > CWindow : : xdgTag ( ) {
2025-05-04 23:39:00 +02:00
if ( ! m_xdgSurface | | ! m_xdgSurface - > m_toplevel )
2025-04-21 22:22:06 +01:00
return std : : nullopt ;
2025-05-04 23:39:00 +02:00
return m_xdgSurface - > m_toplevel - > m_toplevelTag ;
2025-04-21 22:22:06 +01:00
}
std : : optional < std : : string > CWindow : : xdgDescription ( ) {
2025-05-04 23:39:00 +02:00
if ( ! m_xdgSurface | | ! m_xdgSurface - > m_toplevel )
2025-04-21 22:22:06 +01:00
return std : : nullopt ;
2025-05-04 23:39:00 +02:00
return m_xdgSurface - > m_toplevel - > m_toplevelDescription ;
2025-04-21 22:22:06 +01:00
}
2025-05-08 21:00:28 +02:00
PHLWINDOW CWindow : : parent ( ) {
if ( m_isX11 ) {
auto t = x11TransientFor ( ) ;
// don't return a parent that's not mapped
if ( ! validMapped ( t ) )
return nullptr ;
return t ;
}
if ( ! m_xdgSurface | | ! m_xdgSurface - > m_toplevel | | ! m_xdgSurface - > m_toplevel - > m_parent )
return nullptr ;
// don't return a parent that's not mapped
if ( ! m_xdgSurface - > m_toplevel - > m_parent - > m_window | | ! validMapped ( m_xdgSurface - > m_toplevel - > m_parent - > m_window ) )
return nullptr ;
return m_xdgSurface - > m_toplevel - > m_parent - > m_window . lock ( ) ;
}
2025-05-18 19:34:14 +02:00
bool CWindow : : priorityFocus ( ) {
return ! m_isX11 & & CAsyncDialogBox : : isPriorityDialogBox ( getPID ( ) ) ;
}
2025-08-22 20:24:25 +03:00
SP < CWLSurfaceResource > CWindow : : getSolitaryResource ( ) {
if ( ! m_wlSurface | | ! m_wlSurface - > resource ( ) )
return nullptr ;
auto res = m_wlSurface - > resource ( ) ;
if ( m_isX11 )
return res ;
if ( popupsCount ( ) )
return nullptr ;
if ( res - > m_subsurfaces . size ( ) = = 0 )
return res ;
2025-11-11 07:18:15 -05:00
if ( res - > m_subsurfaces . size ( ) > = 1 ) {
if ( ! res - > hasVisibleSubsurface ( ) )
return res ;
if ( res - > m_subsurfaces . size ( ) = = 1 ) {
if ( res - > m_subsurfaces [ 0 ] . expired ( ) | | res - > m_subsurfaces [ 0 ] - > m_surface . expired ( ) )
return nullptr ;
auto surf = res - > m_subsurfaces [ 0 ] - > m_surface . lock ( ) ;
if ( ! surf | | surf - > m_subsurfaces . size ( ) ! = 0 | | surf - > extends ( ) ! = res - > extends ( ) | | ! surf - > m_current . texture | | ! surf - > m_current . texture - > m_opaque )
return nullptr ;
return surf ;
}
2025-08-22 20:24:25 +03:00
}
return nullptr ;
2025-09-13 16:37:02 +02:00
}
2025-09-21 19:27:56 +02:00
Vector2D CWindow : : getReportedSize ( ) {
if ( m_isX11 )
return m_reportedSize ;
if ( m_wlSurface & & m_wlSurface - > resource ( ) )
return m_wlSurface - > resource ( ) - > m_current . ackedSize ;
return m_reportedSize ;
}
2025-11-17 18:34:02 +00:00
void CWindow : : updateDecorationValues ( ) {
static auto PACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.active_border " ) ;
static auto PINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.inactive_border " ) ;
static auto PNOGROUPACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.nogroup_border_active " ) ;
static auto PNOGROUPINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.nogroup_border " ) ;
static auto PGROUPACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_active " ) ;
static auto PGROUPINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_inactive " ) ;
static auto PGROUPACTIVELOCKEDCOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_locked_active " ) ;
static auto PGROUPINACTIVELOCKEDCOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_locked_inactive " ) ;
static auto PINACTIVEALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:inactive_opacity " ) ;
static auto PACTIVEALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:active_opacity " ) ;
static auto PFULLSCREENALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:fullscreen_opacity " ) ;
static auto PSHADOWCOL = CConfigValue < Hyprlang : : INT > ( " decoration:shadow:color " ) ;
static auto PSHADOWCOLINACTIVE = CConfigValue < Hyprlang : : INT > ( " decoration:shadow:color_inactive " ) ;
static auto PDIMSTRENGTH = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_strength " ) ;
static auto PDIMENABLED = CConfigValue < Hyprlang : : INT > ( " decoration:dim_inactive " ) ;
static auto PDIMMODAL = CConfigValue < Hyprlang : : INT > ( " decoration:dim_modal " ) ;
auto * const ACTIVECOL = sc < CGradientValueData * > ( ( PACTIVECOL . ptr ( ) ) - > getData ( ) ) ;
auto * const INACTIVECOL = sc < CGradientValueData * > ( ( PINACTIVECOL . ptr ( ) ) - > getData ( ) ) ;
auto * const NOGROUPACTIVECOL = sc < CGradientValueData * > ( ( PNOGROUPACTIVECOL . ptr ( ) ) - > getData ( ) ) ;
auto * const NOGROUPINACTIVECOL = sc < CGradientValueData * > ( ( PNOGROUPINACTIVECOL . ptr ( ) ) - > getData ( ) ) ;
auto * const GROUPACTIVECOL = sc < CGradientValueData * > ( ( PGROUPACTIVECOL . ptr ( ) ) - > getData ( ) ) ;
auto * const GROUPINACTIVECOL = sc < CGradientValueData * > ( ( PGROUPINACTIVECOL . ptr ( ) ) - > getData ( ) ) ;
auto * const GROUPACTIVELOCKEDCOL = sc < CGradientValueData * > ( ( PGROUPACTIVELOCKEDCOL . ptr ( ) ) - > getData ( ) ) ;
auto * const GROUPINACTIVELOCKEDCOL = sc < CGradientValueData * > ( ( PGROUPINACTIVELOCKEDCOL . ptr ( ) ) - > getData ( ) ) ;
auto setBorderColor = [ & ] ( CGradientValueData grad ) - > void {
if ( grad = = m_realBorderColor )
return ;
m_realBorderColorPrevious = m_realBorderColor ;
m_realBorderColor = grad ;
m_borderFadeAnimationProgress - > setValueAndWarp ( 0.f ) ;
* m_borderFadeAnimationProgress = 1.f ;
} ;
const bool IS_SHADOWED_BY_MODAL = m_xdgSurface & & m_xdgSurface - > m_toplevel & & m_xdgSurface - > m_toplevel - > anyChildModal ( ) ;
// border
const auto RENDERDATA = g_pLayoutManager - > getCurrentLayout ( ) - > requestRenderHints ( m_self . lock ( ) ) ;
if ( RENDERDATA . isBorderGradient )
setBorderColor ( * RENDERDATA . borderGradient ) ;
else {
const bool GROUPLOCKED = m_groupData . pNextWindow . lock ( ) ? getGroupHead ( ) - > m_groupData . locked : false ;
2025-11-26 07:44:26 +09:00
if ( m_self = = Desktop : : focusState ( ) - > window ( ) ) {
2025-11-17 18:34:02 +00:00
const auto * const ACTIVECOLOR =
! m_groupData . pNextWindow . lock ( ) ? ( ! m_groupData . deny ? ACTIVECOL : NOGROUPACTIVECOL ) : ( GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL ) ;
setBorderColor ( m_ruleApplicator - > activeBorderColor ( ) . valueOr ( * ACTIVECOLOR ) ) ;
} else {
const auto * const INACTIVECOLOR =
! m_groupData . pNextWindow . lock ( ) ? ( ! m_groupData . deny ? INACTIVECOL : NOGROUPINACTIVECOL ) : ( GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL ) ;
setBorderColor ( m_ruleApplicator - > inactiveBorderColor ( ) . valueOr ( * INACTIVECOLOR ) ) ;
}
}
// opacity
const auto PWORKSPACE = m_workspace ;
if ( isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) ) {
* m_activeInactiveAlpha = m_ruleApplicator - > alphaFullscreen ( ) . valueOrDefault ( ) . applyAlpha ( * PFULLSCREENALPHA ) ;
} else {
2025-11-26 07:44:26 +09:00
if ( m_self = = Desktop : : focusState ( ) - > window ( ) )
2025-11-17 18:34:02 +00:00
* m_activeInactiveAlpha = m_ruleApplicator - > alpha ( ) . valueOrDefault ( ) . applyAlpha ( * PACTIVEALPHA ) ;
else
* m_activeInactiveAlpha = m_ruleApplicator - > alphaInactive ( ) . valueOrDefault ( ) . applyAlpha ( * PINACTIVEALPHA ) ;
}
// dim
float goalDim = 1.F ;
2025-11-26 07:44:26 +09:00
if ( m_self = = Desktop : : focusState ( ) - > window ( ) | | m_ruleApplicator - > noDim ( ) . valueOrDefault ( ) | | ! * PDIMENABLED )
2025-11-17 18:34:02 +00:00
goalDim = 0 ;
else
goalDim = * PDIMSTRENGTH ;
if ( IS_SHADOWED_BY_MODAL & & * PDIMMODAL )
goalDim + = ( 1.F - goalDim ) / 2.F ;
* m_dimPercent = goalDim ;
// shadow
if ( ! isX11OverrideRedirect ( ) & & ! m_X11DoesntWantBorders ) {
2025-11-26 07:44:26 +09:00
if ( m_self = = Desktop : : focusState ( ) - > window ( ) )
2025-11-17 18:34:02 +00:00
* m_realShadowColor = CHyprColor ( * PSHADOWCOL ) ;
else
* m_realShadowColor = CHyprColor ( * PSHADOWCOLINACTIVE ! = - 1 ? * PSHADOWCOLINACTIVE : * PSHADOWCOL ) ;
} else
m_realShadowColor - > setValueAndWarp ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // no shadow
updateWindowDecos ( ) ;
}
std : : optional < double > CWindow : : calculateSingleExpr ( const std : : string & s ) {
2025-11-26 07:44:26 +09:00
const auto PMONITOR = m_monitor ? m_monitor : Desktop : : focusState ( ) - > monitor ( ) ;
2025-11-17 18:34:02 +00:00
const auto CURSOR_LOCAL = g_pInputManager - > getMouseCoordsInternal ( ) - ( PMONITOR ? PMONITOR - > m_position : Vector2D { } ) ;
Math : : CExpression expr ;
expr . addVariable ( " window_w " , m_realSize - > goal ( ) . x ) ;
expr . addVariable ( " window_h " , m_realSize - > goal ( ) . y ) ;
expr . addVariable ( " window_x " , m_realPosition - > goal ( ) . x - ( PMONITOR ? PMONITOR - > m_position . x : 0 ) ) ;
expr . addVariable ( " window_y " , m_realPosition - > goal ( ) . y - ( PMONITOR ? PMONITOR - > m_position . y : 0 ) ) ;
expr . addVariable ( " monitor_w " , PMONITOR ? PMONITOR - > m_size . x : 1920 ) ;
expr . addVariable ( " monitor_h " , PMONITOR ? PMONITOR - > m_size . y : 1080 ) ;
expr . addVariable ( " cursor_x " , CURSOR_LOCAL . x ) ;
expr . addVariable ( " cursor_y " , CURSOR_LOCAL . y ) ;
return expr . compute ( s ) ;
}
std : : optional < Vector2D > CWindow : : calculateExpression ( const std : : string & s ) {
auto spacePos = s . find ( ' ' ) ;
if ( spacePos = = std : : string : : npos )
return std : : nullopt ;
const auto LHS = calculateSingleExpr ( s . substr ( 0 , spacePos ) ) ;
const auto RHS = calculateSingleExpr ( s . substr ( spacePos + 1 ) ) ;
if ( ! LHS | | ! RHS )
return std : : nullopt ;
return Vector2D { * LHS , * RHS } ;
}
2025-12-08 15:04:40 +00:00
static void setVector2DAnimToMove ( WP < CBaseAnimatedVariable > pav ) {
const auto PAV = pav . lock ( ) ;
if ( ! PAV )
return ;
CAnimatedVariable < Vector2D > * animvar = dc < CAnimatedVariable < Vector2D > * > ( PAV . get ( ) ) ;
animvar - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " windowsMove " ) ) ;
const auto PHLWINDOW = animvar - > m_Context . pWindow . lock ( ) ;
if ( PHLWINDOW )
PHLWINDOW - > m_animatingIn = false ;
}
void CWindow : : mapWindow ( ) {
static auto PINACTIVEALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:inactive_opacity " ) ;
static auto PACTIVEALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:active_opacity " ) ;
static auto PDIMSTRENGTH = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_strength " ) ;
static auto PNEWTAKESOVERFS = CConfigValue < Hyprlang : : INT > ( " misc:on_focus_under_fullscreen " ) ;
static auto PINITIALWSTRACKING = CConfigValue < Hyprlang : : INT > ( " misc:initial_workspace_tracking " ) ;
auto PMONITOR = Desktop : : focusState ( ) - > monitor ( ) ;
if ( ! Desktop : : focusState ( ) - > monitor ( ) ) {
Desktop : : focusState ( ) - > rawMonitorFocus ( g_pCompositor - > getMonitorFromVector ( { } ) ) ;
PMONITOR = Desktop : : focusState ( ) - > monitor ( ) ;
}
auto PWORKSPACE = PMONITOR - > m_activeSpecialWorkspace ? PMONITOR - > m_activeSpecialWorkspace : PMONITOR - > m_activeWorkspace ;
m_monitor = PMONITOR ;
m_workspace = PWORKSPACE ;
m_isMapped = true ;
m_readyToDelete = false ;
m_fadingOut = false ;
m_title = fetchTitle ( ) ;
m_firstMap = true ;
m_initialTitle = m_title ;
m_initialClass = fetchClass ( ) ;
// check for token
std : : string requestedWorkspace = " " ;
bool workspaceSilent = false ;
if ( * PINITIALWSTRACKING ) {
const auto WINDOWENV = getEnv ( ) ;
if ( WINDOWENV . contains ( " HL_INITIAL_WORKSPACE_TOKEN " ) ) {
const auto SZTOKEN = WINDOWENV . at ( " HL_INITIAL_WORKSPACE_TOKEN " ) ;
Debug : : log ( LOG , " New window contains HL_INITIAL_WORKSPACE_TOKEN: {} " , SZTOKEN ) ;
const auto TOKEN = g_pTokenManager - > getToken ( SZTOKEN ) ;
if ( TOKEN ) {
// find workspace and use it
Desktop : : View : : SInitialWorkspaceToken WS = std : : any_cast < Desktop : : View : : SInitialWorkspaceToken > ( TOKEN - > m_data ) ;
Debug : : log ( LOG , " HL_INITIAL_WORKSPACE_TOKEN {} -> {} " , SZTOKEN , WS . workspace ) ;
if ( g_pCompositor - > getWorkspaceByString ( WS . workspace ) ! = m_workspace ) {
requestedWorkspace = WS . workspace ;
workspaceSilent = true ;
}
if ( * PINITIALWSTRACKING = = 1 ) // one-shot token
g_pTokenManager - > removeToken ( TOKEN ) ;
else if ( * PINITIALWSTRACKING = = 2 ) { // persistent
if ( WS . primaryOwner . expired ( ) ) {
WS . primaryOwner = m_self . lock ( ) ;
TOKEN - > m_data = WS ;
}
m_initialWorkspaceToken = SZTOKEN ;
}
}
}
}
if ( g_pInputManager - > m_lastFocusOnLS ) // waybar fix
g_pInputManager - > releaseAllMouseButtons ( ) ;
// checks if the window wants borders and sets the appropriate flag
g_pXWaylandManager - > checkBorders ( m_self . lock ( ) ) ;
// registers the animated vars and stuff
onMap ( ) ;
if ( g_pXWaylandManager - > shouldBeFloated ( m_self . lock ( ) ) ) {
m_isFloating = true ;
m_requestsFloat = true ;
}
m_X11ShouldntFocus = m_X11ShouldntFocus | | ( m_isX11 & & isX11OverrideRedirect ( ) & & ! m_xwaylandSurface - > wantsFocus ( ) ) ;
// window rules
std : : optional < eFullscreenMode > requestedInternalFSMode , requestedClientFSMode ;
std : : optional < Desktop : : View : : SFullscreenState > requestedFSState ;
if ( m_wantsInitialFullscreen | | ( m_isX11 & & m_xwaylandSurface - > m_fullscreen ) )
requestedClientFSMode = FSMODE_FULLSCREEN ;
MONITORID requestedFSMonitor = m_wantsInitialFullscreenMonitor ;
m_ruleApplicator - > readStaticRules ( ) ;
{
if ( ! m_ruleApplicator - > static_ . monitor . empty ( ) ) {
const auto & MONITORSTR = m_ruleApplicator - > static_ . monitor ;
if ( MONITORSTR = = " unset " )
m_monitor = PMONITOR ;
else {
const auto MONITOR = g_pCompositor - > getMonitorFromString ( MONITORSTR ) ;
if ( MONITOR ) {
m_monitor = MONITOR ;
const auto PMONITORFROMID = m_monitor . lock ( ) ;
if ( m_monitor ! = PMONITOR ) {
g_pKeybindManager - > m_dispatchers [ " focusmonitor " ] ( std : : to_string ( monitorID ( ) ) ) ;
PMONITOR = PMONITORFROMID ;
}
m_workspace = PMONITOR - > m_activeSpecialWorkspace ? PMONITOR - > m_activeSpecialWorkspace : PMONITOR - > m_activeWorkspace ;
PWORKSPACE = m_workspace ;
Debug : : log ( LOG , " Rule monitor, applying to {:mw} " , m_self . lock ( ) ) ;
requestedFSMonitor = MONITOR_INVALID ;
} else
Debug : : log ( ERR , " No monitor in monitor {} rule " , MONITORSTR ) ;
}
}
if ( ! m_ruleApplicator - > static_ . workspace . empty ( ) ) {
const auto WORKSPACERQ = m_ruleApplicator - > static_ . workspace ;
if ( WORKSPACERQ = = " unset " )
requestedWorkspace = " " ;
else
requestedWorkspace = WORKSPACERQ ;
const auto JUSTWORKSPACE = WORKSPACERQ . contains ( ' ' ) ? WORKSPACERQ . substr ( 0 , WORKSPACERQ . find_first_of ( ' ' ) ) : WORKSPACERQ ;
if ( JUSTWORKSPACE = = PWORKSPACE - > m_name | | JUSTWORKSPACE = = " name: " + PWORKSPACE - > m_name )
requestedWorkspace = " " ;
Debug : : log ( LOG , " Rule workspace matched by {}, {} applied. " , m_self . lock ( ) , m_ruleApplicator - > static_ . workspace ) ;
requestedFSMonitor = MONITOR_INVALID ;
}
if ( m_ruleApplicator - > static_ . floating . has_value ( ) )
m_isFloating = m_ruleApplicator - > static_ . floating . value ( ) ;
if ( m_ruleApplicator - > static_ . pseudo )
m_isPseudotiled = true ;
if ( m_ruleApplicator - > static_ . noInitialFocus )
m_noInitialFocus = true ;
if ( m_ruleApplicator - > static_ . fullscreenStateClient | | m_ruleApplicator - > static_ . fullscreenStateInternal ) {
requestedFSState = Desktop : : View : : SFullscreenState {
. internal = sc < eFullscreenMode > ( m_ruleApplicator - > static_ . fullscreenStateInternal . value_or ( 0 ) ) ,
. client = sc < eFullscreenMode > ( m_ruleApplicator - > static_ . fullscreenStateClient . value_or ( 0 ) ) ,
} ;
}
if ( ! m_ruleApplicator - > static_ . suppressEvent . empty ( ) ) {
for ( const auto & var : m_ruleApplicator - > static_ . suppressEvent ) {
if ( var = = " fullscreen " )
m_suppressedEvents | = Desktop : : View : : SUPPRESS_FULLSCREEN ;
else if ( var = = " maximize " )
m_suppressedEvents | = Desktop : : View : : SUPPRESS_MAXIMIZE ;
else if ( var = = " activate " )
m_suppressedEvents | = Desktop : : View : : SUPPRESS_ACTIVATE ;
else if ( var = = " activatefocus " )
m_suppressedEvents | = Desktop : : View : : SUPPRESS_ACTIVATE_FOCUSONLY ;
else if ( var = = " fullscreenoutput " )
m_suppressedEvents | = Desktop : : View : : SUPPRESS_FULLSCREEN_OUTPUT ;
else
Debug : : log ( ERR , " Error while parsing suppressevent windowrule: unknown event type {} " , var ) ;
}
}
if ( m_ruleApplicator - > static_ . pin )
m_pinned = true ;
if ( m_ruleApplicator - > static_ . fullscreen )
requestedInternalFSMode = FSMODE_FULLSCREEN ;
if ( m_ruleApplicator - > static_ . maximize )
requestedInternalFSMode = FSMODE_MAXIMIZED ;
if ( ! m_ruleApplicator - > static_ . group . empty ( ) ) {
if ( ! ( m_groupRules & Desktop : : View : : GROUP_OVERRIDE ) & & trim ( m_ruleApplicator - > static_ . group ) ! = " group " ) {
CVarList2 vars ( std : : string { m_ruleApplicator - > static_ . group } , 0 , ' s ' ) ;
std : : string vPrev = " " ;
for ( auto const & v : vars ) {
if ( v = = " group " )
continue ;
if ( v = = " set " ) {
m_groupRules | = Desktop : : View : : GROUP_SET ;
} else if ( v = = " new " ) {
// shorthand for `group barred set`
m_groupRules | = ( Desktop : : View : : GROUP_SET | Desktop : : View : : GROUP_BARRED ) ;
} else if ( v = = " lock " ) {
m_groupRules | = Desktop : : View : : GROUP_LOCK ;
} else if ( v = = " invade " ) {
m_groupRules | = Desktop : : View : : GROUP_INVADE ;
} else if ( v = = " barred " ) {
m_groupRules | = Desktop : : View : : GROUP_BARRED ;
} else if ( v = = " deny " ) {
m_groupData . deny = true ;
} else if ( v = = " override " ) {
// Clear existing rules
m_groupRules = Desktop : : View : : GROUP_OVERRIDE ;
} else if ( v = = " unset " ) {
// Clear existing rules and stop processing
m_groupRules = Desktop : : View : : GROUP_OVERRIDE ;
break ;
} else if ( v = = " always " ) {
if ( vPrev = = " set " | | vPrev = = " group " )
m_groupRules | = Desktop : : View : : GROUP_SET_ALWAYS ;
else if ( vPrev = = " lock " )
m_groupRules | = Desktop : : View : : GROUP_LOCK_ALWAYS ;
else
Debug : : log ( ERR , " windowrule `group` does not support `{} always` " , vPrev ) ;
}
vPrev = v ;
}
}
}
if ( m_ruleApplicator - > static_ . content )
setContentType ( sc < NContentType : : eContentType > ( m_ruleApplicator - > static_ . content . value ( ) ) ) ;
if ( m_ruleApplicator - > static_ . noCloseFor )
m_closeableSince = Time : : steadyNow ( ) + std : : chrono : : milliseconds ( m_ruleApplicator - > static_ . noCloseFor . value ( ) ) ;
}
// make it uncloseable if it's a Hyprland dialog
// TODO: make some closeable?
if ( CAsyncDialogBox : : isAsyncDialogBox ( getPID ( ) ) )
m_closeableSince = Time : : steadyNow ( ) + std : : chrono : : years ( 10 /* Should be enough, no? */ ) ;
// disallow tiled pinned
if ( m_pinned & & ! m_isFloating )
m_pinned = false ;
CVarList2 WORKSPACEARGS = CVarList2 ( std : : move ( requestedWorkspace ) , 0 , ' ' , false , false ) ;
if ( ! WORKSPACEARGS [ 0 ] . empty ( ) ) {
WORKSPACEID requestedWorkspaceID ;
std : : string requestedWorkspaceName ;
if ( WORKSPACEARGS . contains ( " silent " ) )
workspaceSilent = true ;
if ( WORKSPACEARGS . contains ( " empty " ) & & PWORKSPACE - > getWindows ( ) < = 1 ) {
requestedWorkspaceID = PWORKSPACE - > m_id ;
requestedWorkspaceName = PWORKSPACE - > m_name ;
} else {
auto result = getWorkspaceIDNameFromString ( WORKSPACEARGS . join ( " " , 0 , workspaceSilent ? WORKSPACEARGS . size ( ) - 1 : 0 ) ) ;
requestedWorkspaceID = result . id ;
requestedWorkspaceName = result . name ;
}
if ( requestedWorkspaceID ! = WORKSPACE_INVALID ) {
auto pWorkspace = g_pCompositor - > getWorkspaceByID ( requestedWorkspaceID ) ;
if ( ! pWorkspace )
pWorkspace = g_pCompositor - > createNewWorkspace ( requestedWorkspaceID , monitorID ( ) , requestedWorkspaceName , false ) ;
PWORKSPACE = pWorkspace ;
m_workspace = pWorkspace ;
m_monitor = pWorkspace - > m_monitor ;
if ( m_monitor . lock ( ) - > m_activeSpecialWorkspace & & ! pWorkspace - > m_isSpecialWorkspace )
workspaceSilent = true ;
if ( ! workspaceSilent ) {
if ( pWorkspace - > m_isSpecialWorkspace )
pWorkspace - > m_monitor - > setSpecialWorkspace ( pWorkspace ) ;
else if ( PMONITOR - > activeWorkspaceID ( ) ! = requestedWorkspaceID & & ! m_noInitialFocus )
g_pKeybindManager - > m_dispatchers [ " workspace " ] ( requestedWorkspaceName ) ;
PMONITOR = Desktop : : focusState ( ) - > monitor ( ) ;
}
requestedFSMonitor = MONITOR_INVALID ;
} else
workspaceSilent = false ;
}
if ( m_suppressedEvents & Desktop : : View : : SUPPRESS_FULLSCREEN_OUTPUT )
requestedFSMonitor = MONITOR_INVALID ;
else if ( requestedFSMonitor ! = MONITOR_INVALID ) {
if ( const auto PM = g_pCompositor - > getMonitorFromID ( requestedFSMonitor ) ; PM )
m_monitor = PM ;
const auto PMONITORFROMID = m_monitor . lock ( ) ;
if ( m_monitor ! = PMONITOR ) {
g_pKeybindManager - > m_dispatchers [ " focusmonitor " ] ( std : : to_string ( monitorID ( ) ) ) ;
PMONITOR = PMONITORFROMID ;
}
m_workspace = PMONITOR - > m_activeSpecialWorkspace ? PMONITOR - > m_activeSpecialWorkspace : PMONITOR - > m_activeWorkspace ;
PWORKSPACE = m_workspace ;
Debug : : log ( LOG , " Requested monitor, applying to {:mw} " , m_self . lock ( ) ) ;
}
if ( PWORKSPACE - > m_defaultFloating )
m_isFloating = true ;
if ( PWORKSPACE - > m_defaultPseudo ) {
m_isPseudotiled = true ;
CBox desiredGeometry = g_pXWaylandManager - > getGeometryForWindow ( m_self . lock ( ) ) ;
m_pseudoSize = Vector2D ( desiredGeometry . width , desiredGeometry . height ) ;
}
updateWindowData ( ) ;
// Verify window swallowing. Get the swallower before calling onWindowCreated(m_self.lock()) because getSwallower() wouldn't get it after if m_self.lock() gets auto grouped.
const auto SWALLOWER = getSwallower ( ) ;
m_swallowed = SWALLOWER ;
if ( m_swallowed )
m_swallowed - > m_currentlySwallowed = true ;
// emit the IPC event before the layout might focus the window to avoid a focus event first
g_pEventManager - > postEvent ( SHyprIPCEvent { " openwindow " , std : : format ( " {:x},{},{},{} " , m_self . lock ( ) , PWORKSPACE - > m_name , m_class , m_title ) } ) ;
EMIT_HOOK_EVENT ( " openWindowEarly " , m_self . lock ( ) ) ;
if ( m_isFloating ) {
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowCreated ( m_self . lock ( ) ) ;
m_createdOverFullscreen = true ;
if ( ! m_ruleApplicator - > static_ . size . empty ( ) ) {
const auto COMPUTED = calculateExpression ( m_ruleApplicator - > static_ . size ) ;
if ( ! COMPUTED )
Debug : : log ( ERR , " failed to parse {} as an expression " , m_ruleApplicator - > static_ . size ) ;
else {
* m_realSize = * COMPUTED ;
setHidden ( false ) ;
}
}
if ( ! m_ruleApplicator - > static_ . position . empty ( ) ) {
const auto COMPUTED = calculateExpression ( m_ruleApplicator - > static_ . position ) ;
if ( ! COMPUTED )
Debug : : log ( ERR , " failed to parse {} as an expression " , m_ruleApplicator - > static_ . position ) ;
else {
* m_realPosition = * COMPUTED + PMONITOR - > m_position ;
setHidden ( false ) ;
}
}
if ( m_ruleApplicator - > static_ . center ) {
const auto WORKAREA = PMONITOR - > logicalBoxMinusReserved ( ) ;
* m_realPosition = WORKAREA . middle ( ) - m_realSize - > goal ( ) / 2.f ;
}
// set the pseudo size to the GOAL of our current size
// because the windows are animated on RealSize
m_pseudoSize = m_realSize - > goal ( ) ;
g_pCompositor - > changeWindowZOrder ( m_self . lock ( ) , true ) ;
} else {
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowCreated ( m_self . lock ( ) ) ;
bool setPseudo = false ;
if ( ! m_ruleApplicator - > static_ . size . empty ( ) ) {
const auto COMPUTED = calculateExpression ( m_ruleApplicator - > static_ . size ) ;
if ( ! COMPUTED )
Debug : : log ( ERR , " failed to parse {} as an expression " , m_ruleApplicator - > static_ . size ) ;
else {
setPseudo = true ;
m_pseudoSize = * COMPUTED ;
setHidden ( false ) ;
}
}
if ( ! setPseudo )
m_pseudoSize = m_realSize - > goal ( ) - Vector2D ( 10 , 10 ) ;
}
const auto PFOCUSEDWINDOWPREV = Desktop : : focusState ( ) - > window ( ) ;
if ( m_ruleApplicator - > allowsInput ( ) . valueOrDefault ( ) ) { // if default value wasn't set to false getPriority() would throw an exception
m_ruleApplicator - > noFocusOverride ( Desktop : : Types : : COverridableVar ( false , m_ruleApplicator - > allowsInput ( ) . getPriority ( ) ) ) ;
m_noInitialFocus = false ;
m_X11ShouldntFocus = false ;
}
// check LS focus grab
const auto PFORCEFOCUS = g_pCompositor - > getForceFocus ( ) ;
const auto PLSFROMFOCUS = g_pCompositor - > getLayerSurfaceFromSurface ( Desktop : : focusState ( ) - > surface ( ) ) ;
if ( PLSFROMFOCUS & & PLSFROMFOCUS - > m_layerSurface - > m_current . interactivity ! = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE )
m_noInitialFocus = true ;
if ( m_workspace - > m_hasFullscreenWindow & & ! requestedInternalFSMode . has_value ( ) & & ! requestedClientFSMode . has_value ( ) & & ! m_isFloating ) {
if ( * PNEWTAKESOVERFS = = 0 )
m_noInitialFocus = true ;
else if ( * PNEWTAKESOVERFS = = 1 )
requestedInternalFSMode = m_workspace - > m_fullscreenMode ;
else if ( * PNEWTAKESOVERFS = = 2 )
g_pCompositor - > setWindowFullscreenInternal ( m_workspace - > getFullscreenWindow ( ) , FSMODE_NONE ) ;
}
if ( ! m_ruleApplicator - > noFocus ( ) . valueOrDefault ( ) & & ! m_noInitialFocus & & ( ! isX11OverrideRedirect ( ) | | ( m_isX11 & & m_xwaylandSurface - > wantsFocus ( ) ) ) & & ! workspaceSilent & &
( ! PFORCEFOCUS | | PFORCEFOCUS = = m_self . lock ( ) ) & & ! g_pInputManager - > isConstrained ( ) ) {
Desktop : : focusState ( ) - > fullWindowFocus ( m_self . lock ( ) ) ;
m_activeInactiveAlpha - > setValueAndWarp ( * PACTIVEALPHA ) ;
m_dimPercent - > setValueAndWarp ( m_ruleApplicator - > noDim ( ) . valueOrDefault ( ) ? 0.f : * PDIMSTRENGTH ) ;
} else {
m_activeInactiveAlpha - > setValueAndWarp ( * PINACTIVEALPHA ) ;
m_dimPercent - > setValueAndWarp ( 0 ) ;
}
if ( requestedClientFSMode . has_value ( ) & & ( m_suppressedEvents & Desktop : : View : : SUPPRESS_FULLSCREEN ) )
requestedClientFSMode = sc < eFullscreenMode > ( sc < uint8_t > ( requestedClientFSMode . value_or ( FSMODE_NONE ) ) & ~ sc < uint8_t > ( FSMODE_FULLSCREEN ) ) ;
if ( requestedClientFSMode . has_value ( ) & & ( m_suppressedEvents & Desktop : : View : : SUPPRESS_MAXIMIZE ) )
requestedClientFSMode = sc < eFullscreenMode > ( sc < uint8_t > ( requestedClientFSMode . value_or ( FSMODE_NONE ) ) & ~ sc < uint8_t > ( FSMODE_MAXIMIZED ) ) ;
if ( ! m_noInitialFocus & & ( requestedInternalFSMode . has_value ( ) | | requestedClientFSMode . has_value ( ) | | requestedFSState . has_value ( ) ) ) {
// fix fullscreen on requested (basically do a switcheroo)
if ( m_workspace - > m_hasFullscreenWindow )
g_pCompositor - > setWindowFullscreenInternal ( m_workspace - > getFullscreenWindow ( ) , FSMODE_NONE ) ;
m_realPosition - > warp ( ) ;
m_realSize - > warp ( ) ;
if ( requestedFSState . has_value ( ) ) {
m_ruleApplicator - > syncFullscreenOverride ( Desktop : : Types : : COverridableVar ( false , Desktop : : Types : : PRIORITY_WINDOW_RULE ) ) ;
g_pCompositor - > setWindowFullscreenState ( m_self . lock ( ) , requestedFSState . value ( ) ) ;
} else if ( requestedInternalFSMode . has_value ( ) & & requestedClientFSMode . has_value ( ) & & ! m_ruleApplicator - > syncFullscreen ( ) . valueOrDefault ( ) )
g_pCompositor - > setWindowFullscreenState ( m_self . lock ( ) ,
Desktop : : View : : SFullscreenState { . internal = requestedInternalFSMode . value ( ) , . client = requestedClientFSMode . value ( ) } ) ;
else if ( requestedInternalFSMode . has_value ( ) )
g_pCompositor - > setWindowFullscreenInternal ( m_self . lock ( ) , requestedInternalFSMode . value ( ) ) ;
else if ( requestedClientFSMode . has_value ( ) )
g_pCompositor - > setWindowFullscreenClient ( m_self . lock ( ) , requestedClientFSMode . value ( ) ) ;
}
// recheck idle inhibitors
g_pInputManager - > recheckIdleInhibitorStatus ( ) ;
updateToplevel ( ) ;
m_ruleApplicator - > propertiesChanged ( Desktop : : Rule : : RULE_PROP_ALL ) ;
if ( workspaceSilent ) {
if ( validMapped ( PFOCUSEDWINDOWPREV ) ) {
Desktop : : focusState ( ) - > rawWindowFocus ( PFOCUSEDWINDOWPREV ) ;
PFOCUSEDWINDOWPREV - > updateWindowDecos ( ) ; // need to for some reason i cba to find out why
} else if ( ! PFOCUSEDWINDOWPREV )
Desktop : : focusState ( ) - > rawWindowFocus ( nullptr ) ;
}
// swallow
if ( SWALLOWER ) {
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowRemoved ( SWALLOWER ) ;
g_pHyprRenderer - > damageWindow ( SWALLOWER ) ;
SWALLOWER - > setHidden ( true ) ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitorID ( ) ) ;
}
m_firstMap = false ;
Debug : : log ( LOG , " Map request dispatched, monitor {}, window pos: {:5j}, window size: {:5j} " , PMONITOR - > m_name , m_realPosition - > goal ( ) , m_realSize - > goal ( ) ) ;
// emit the hook event here after basic stuff has been initialized
EMIT_HOOK_EVENT ( " openWindow " , m_self . lock ( ) ) ;
// apply data from default decos. Borders, shadows.
g_pDecorationPositioner - > forceRecalcFor ( m_self . lock ( ) ) ;
updateWindowDecos ( ) ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateWindow ( m_self . lock ( ) ) ;
// do animations
g_pDesktopAnimationManager - > startAnimation ( m_self . lock ( ) , CDesktopAnimationManager : : ANIMATION_TYPE_IN ) ;
m_realPosition - > setCallbackOnEnd ( setVector2DAnimToMove ) ;
m_realSize - > setCallbackOnEnd ( setVector2DAnimToMove ) ;
// recalc the values for this window
updateDecorationValues ( ) ;
// avoid this window being visible
if ( PWORKSPACE - > m_hasFullscreenWindow & & ! isFullscreen ( ) & & ! m_isFloating )
m_alpha - > setValueAndWarp ( 0.f ) ;
g_pCompositor - > setPreferredScaleForSurface ( wlSurface ( ) - > resource ( ) , PMONITOR - > m_scale ) ;
g_pCompositor - > setPreferredTransformForSurface ( wlSurface ( ) - > resource ( ) , PMONITOR - > m_transform ) ;
if ( g_pSeatManager - > m_mouse . expired ( ) | | ! g_pInputManager - > isConstrained ( ) )
g_pInputManager - > sendMotionEventsToFocused ( ) ;
// fix some xwayland apps that don't behave nicely
m_reportedSize = m_pendingReportedSize ;
if ( m_workspace )
m_workspace - > updateWindows ( ) ;
if ( PMONITOR & & isX11OverrideRedirect ( ) )
m_X11SurfaceScaledBy = PMONITOR - > m_scale ;
}
void CWindow : : unmapWindow ( ) {
Debug : : log ( LOG , " {:c} unmapped " , m_self . lock ( ) ) ;
static auto PEXITRETAINSFS = CConfigValue < Hyprlang : : INT > ( " misc:exit_window_retains_fullscreen " ) ;
const auto CURRENTWINDOWFSSTATE = isFullscreen ( ) ;
const auto CURRENTFSMODE = m_fullscreenState . internal ;
if ( ! wlSurface ( ) - > exists ( ) | | ! m_isMapped ) {
Debug : : log ( WARN , " {} unmapped without being mapped?? " , m_self . lock ( ) ) ;
m_fadingOut = false ;
return ;
}
const auto PMONITOR = m_monitor . lock ( ) ;
if ( PMONITOR ) {
m_originalClosedPos = m_realPosition - > value ( ) - PMONITOR - > m_position ;
m_originalClosedSize = m_realSize - > value ( ) ;
m_originalClosedExtents = getFullWindowExtents ( ) ;
}
g_pEventManager - > postEvent ( SHyprIPCEvent { " closewindow " , std : : format ( " {:x} " , m_self . lock ( ) ) } ) ;
EMIT_HOOK_EVENT ( " closeWindow " , m_self . lock ( ) ) ;
if ( m_isFloating & & ! m_isX11 & & m_ruleApplicator - > persistentSize ( ) . valueOrDefault ( ) ) {
Debug : : log ( LOG , " storing floating size {}x{} for window {}::{} on close " , m_realSize - > value ( ) . x , m_realSize - > value ( ) . y , m_class , m_title ) ;
g_pConfigManager - > storeFloatingSize ( m_self . lock ( ) , m_realSize - > value ( ) ) ;
}
if ( isFullscreen ( ) )
g_pCompositor - > setWindowFullscreenInternal ( m_self . lock ( ) , FSMODE_NONE ) ;
// Allow the renderer to catch the last frame.
if ( g_pHyprRenderer - > shouldRenderWindow ( m_self . lock ( ) ) )
g_pHyprRenderer - > makeSnapshot ( m_self . lock ( ) ) ;
// swallowing
if ( valid ( m_swallowed ) ) {
if ( m_swallowed - > m_currentlySwallowed ) {
m_swallowed - > m_currentlySwallowed = false ;
m_swallowed - > setHidden ( false ) ;
if ( m_groupData . pNextWindow . lock ( ) )
m_swallowed - > m_groupSwallowed = true ; // flag for the swallowed window to be created into the group where it belongs when auto_group = false.
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowCreated ( m_swallowed . lock ( ) ) ;
}
m_swallowed - > m_groupSwallowed = false ;
m_swallowed . reset ( ) ;
}
bool wasLastWindow = false ;
if ( m_self . lock ( ) = = Desktop : : focusState ( ) - > window ( ) ) {
wasLastWindow = true ;
Desktop : : focusState ( ) - > window ( ) . reset ( ) ;
Desktop : : focusState ( ) - > surface ( ) . reset ( ) ;
g_pInputManager - > releaseAllMouseButtons ( ) ;
}
if ( m_self . lock ( ) = = g_pInputManager - > m_currentlyDraggedWindow . lock ( ) )
CKeybindManager : : changeMouseBindMode ( MBIND_INVALID ) ;
// remove the fullscreen window status from workspace if we closed it
const auto PWORKSPACE = m_workspace ;
if ( PWORKSPACE - > m_hasFullscreenWindow & & isFullscreen ( ) )
PWORKSPACE - > m_hasFullscreenWindow = false ;
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowRemoved ( m_self . lock ( ) ) ;
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
// do this after onWindowRemoved because otherwise it'll think the window is invalid
m_isMapped = false ;
// refocus on a new window if needed
if ( wasLastWindow ) {
static auto FOCUSONCLOSE = CConfigValue < Hyprlang : : INT > ( " input:focus_on_close " ) ;
PHLWINDOW PWINDOWCANDIDATE = nullptr ;
if ( * FOCUSONCLOSE )
PWINDOWCANDIDATE = ( g_pCompositor - > vectorToWindowUnified ( g_pInputManager - > getMouseCoordsInternal ( ) ,
Desktop : : View : : RESERVED_EXTENTS | Desktop : : View : : INPUT_EXTENTS | Desktop : : View : : ALLOW_FLOATING ) ) ;
else
PWINDOWCANDIDATE = g_pLayoutManager - > getCurrentLayout ( ) - > getNextWindowCandidate ( m_self . lock ( ) ) ;
Debug : : log ( LOG , " On closed window, new focused candidate is {} " , PWINDOWCANDIDATE ) ;
if ( PWINDOWCANDIDATE ! = Desktop : : focusState ( ) - > window ( ) & & PWINDOWCANDIDATE ) {
Desktop : : focusState ( ) - > fullWindowFocus ( PWINDOWCANDIDATE ) ;
if ( * PEXITRETAINSFS & & CURRENTWINDOWFSSTATE )
g_pCompositor - > setWindowFullscreenInternal ( PWINDOWCANDIDATE , CURRENTFSMODE ) ;
}
if ( ! PWINDOWCANDIDATE & & m_workspace & & m_workspace - > getWindows ( ) = = 0 )
g_pInputManager - > refocus ( ) ;
g_pInputManager - > sendMotionEventsToFocused ( ) ;
// CWindow::onUnmap will remove this window's active status, but we can't really do it above.
if ( m_self . lock ( ) = = Desktop : : focusState ( ) - > window ( ) | | ! Desktop : : focusState ( ) - > window ( ) ) {
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindow " , " , " } ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindowv2 " , " " } ) ;
EMIT_HOOK_EVENT ( " activeWindow " , PHLWINDOW { nullptr } ) ;
}
} else {
Debug : : log ( LOG , " Unmapped was not focused, ignoring a refocus. " ) ;
}
m_fadingOut = true ;
g_pCompositor - > addToFadingOutSafe ( m_self . lock ( ) ) ;
if ( ! m_X11DoesntWantBorders ) // don't animate out if they weren't animated in.
* m_realPosition = m_realPosition - > value ( ) + Vector2D ( 0.01f , 0.01f ) ; // it has to be animated, otherwise CesktopAnimationManager will ignore it
// anims
g_pDesktopAnimationManager - > startAnimation ( m_self . lock ( ) , CDesktopAnimationManager : : ANIMATION_TYPE_OUT ) ;
// recheck idle inhibitors
g_pInputManager - > recheckIdleInhibitorStatus ( ) ;
// force report all sizes (QT sometimes has an issue with this)
if ( m_workspace )
m_workspace - > forceReportSizesToWindows ( ) ;
// update lastwindow after focus
onUnmap ( ) ;
}
void CWindow : : commitWindow ( ) {
if ( ! m_isX11 & & m_xdgSurface - > m_initialCommit ) {
Vector2D predSize = g_pLayoutManager - > getCurrentLayout ( ) - > predictSizeForNewWindow ( m_self . lock ( ) ) ;
Debug : : log ( LOG , " Layout predicts size {} for {} " , predSize , m_self . lock ( ) ) ;
m_xdgSurface - > m_toplevel - > setSize ( predSize ) ;
return ;
}
if ( ! m_isMapped | | isHidden ( ) )
return ;
if ( m_isX11 )
m_reportedSize = m_pendingReportedSize ;
if ( ! m_isX11 & & ! isFullscreen ( ) & & m_isFloating ) {
const auto MINSIZE = m_xdgSurface - > m_toplevel - > layoutMinSize ( ) ;
const auto MAXSIZE = m_xdgSurface - > m_toplevel - > layoutMaxSize ( ) ;
clampWindowSize ( MINSIZE , MAXSIZE > Vector2D { 1 , 1 } ? std : : optional < Vector2D > { MAXSIZE } : std : : nullopt ) ;
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
}
if ( ! m_workspace - > m_visible )
return ;
const auto PMONITOR = m_monitor . lock ( ) ;
if ( PMONITOR )
PMONITOR - > debugLastPresentation ( g_pSeatManager - > m_isPointerFrameCommit ? " listener_commitWindow skip " : " listener_commitWindow " ) ;
if ( g_pSeatManager - > m_isPointerFrameCommit ) {
g_pSeatManager - > m_isPointerFrameSkipped = false ;
g_pSeatManager - > m_isPointerFrameCommit = false ;
} else
g_pHyprRenderer - > damageSurface ( wlSurface ( ) - > resource ( ) , m_realPosition - > goal ( ) . x , m_realPosition - > goal ( ) . y , m_isX11 ? 1.0 / m_X11SurfaceScaledBy : 1.0 ) ;
if ( g_pSeatManager - > m_isPointerFrameSkipped ) {
g_pPointerManager - > sendStoredMovement ( ) ;
g_pSeatManager - > sendPointerFrame ( ) ;
g_pSeatManager - > m_isPointerFrameCommit = true ;
}
if ( ! m_isX11 ) {
m_subsurfaceHead - > recheckDamageForSubsurfaces ( ) ;
m_popupHead - > recheckTree ( ) ;
}
// tearing: if solitary, redraw it. This still might be a single surface window
if ( PMONITOR & & PMONITOR - > m_solitaryClient . lock ( ) = = m_self . lock ( ) & & canBeTorn ( ) & & PMONITOR - > m_tearingState . canTear & & wlSurface ( ) - > resource ( ) - > m_current . texture ) {
CRegion damageBox { wlSurface ( ) - > resource ( ) - > m_current . accumulateBufferDamage ( ) } ;
if ( ! damageBox . empty ( ) ) {
if ( PMONITOR - > m_tearingState . busy ) {
PMONITOR - > m_tearingState . frameScheduledWhileBusy = true ;
} else {
PMONITOR - > m_tearingState . nextRenderTorn = true ;
g_pHyprRenderer - > renderMonitor ( PMONITOR ) ;
}
}
}
}
void CWindow : : destroyWindow ( ) {
Debug : : log ( LOG , " {:c} destroyed, queueing. " , m_self . lock ( ) ) ;
if ( m_self . lock ( ) = = Desktop : : focusState ( ) - > window ( ) ) {
Desktop : : focusState ( ) - > window ( ) . reset ( ) ;
Desktop : : focusState ( ) - > surface ( ) . reset ( ) ;
}
wlSurface ( ) - > unassign ( ) ;
m_listeners = { } ;
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowRemoved ( m_self . lock ( ) ) ;
m_readyToDelete = true ;
m_xdgSurface . reset ( ) ;
if ( ! m_fadingOut ) {
Debug : : log ( LOG , " Unmapped {} removed instantly " , m_self . lock ( ) ) ;
g_pCompositor - > removeWindowFromVectorSafe ( m_self . lock ( ) ) ; // most likely X11 unmanaged or sumn
}
m_listeners . unmap . reset ( ) ;
m_listeners . destroy . reset ( ) ;
m_listeners . map . reset ( ) ;
m_listeners . commit . reset ( ) ;
}
void CWindow : : activateX11 ( ) {
Debug : : log ( LOG , " X11 Activate request for window {} " , m_self . lock ( ) ) ;
if ( isX11OverrideRedirect ( ) ) {
Debug : : log ( LOG , " Unmanaged X11 {} requests activate " , m_self . lock ( ) ) ;
if ( Desktop : : focusState ( ) - > window ( ) & & Desktop : : focusState ( ) - > window ( ) - > getPID ( ) ! = getPID ( ) )
return ;
if ( ! m_xwaylandSurface - > wantsFocus ( ) )
return ;
Desktop : : focusState ( ) - > fullWindowFocus ( m_self . lock ( ) ) ;
return ;
}
if ( m_self . lock ( ) = = Desktop : : focusState ( ) - > window ( ) | | ( m_suppressedEvents & Desktop : : View : : SUPPRESS_ACTIVATE ) )
return ;
activate ( ) ;
}
void CWindow : : unmanagedSetGeometry ( ) {
if ( ! m_isMapped | | ! m_xwaylandSurface | | ! m_xwaylandSurface - > m_overrideRedirect )
return ;
const auto POS = m_realPosition - > goal ( ) ;
const auto SIZ = m_realSize - > goal ( ) ;
if ( m_xwaylandSurface - > m_geometry . size ( ) > Vector2D { 1 , 1 } )
setHidden ( false ) ;
else
setHidden ( true ) ;
if ( isFullscreen ( ) | | ! m_isFloating ) {
sendWindowSize ( true ) ;
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
return ;
}
static auto PXWLFORCESCALEZERO = CConfigValue < Hyprlang : : INT > ( " xwayland:force_zero_scaling " ) ;
const auto LOGICALPOS = g_pXWaylandManager - > xwaylandToWaylandCoords ( m_xwaylandSurface - > m_geometry . pos ( ) ) ;
if ( abs ( std : : floor ( POS . x ) - LOGICALPOS . x ) > 2 | | abs ( std : : floor ( POS . y ) - LOGICALPOS . y ) > 2 | | abs ( std : : floor ( SIZ . x ) - m_xwaylandSurface - > m_geometry . width ) > 2 | |
abs ( std : : floor ( SIZ . y ) - m_xwaylandSurface - > m_geometry . height ) > 2 ) {
Debug : : log ( LOG , " Unmanaged window {} requests geometry update to {:j} {:j} " , m_self . lock ( ) , LOGICALPOS , m_xwaylandSurface - > m_geometry . size ( ) ) ;
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
m_realPosition - > setValueAndWarp ( Vector2D ( LOGICALPOS . x , LOGICALPOS . y ) ) ;
if ( abs ( std : : floor ( SIZ . x ) - m_xwaylandSurface - > m_geometry . w ) > 2 | | abs ( std : : floor ( SIZ . y ) - m_xwaylandSurface - > m_geometry . h ) > 2 )
m_realSize - > setValueAndWarp ( m_xwaylandSurface - > m_geometry . size ( ) ) ;
if ( * PXWLFORCESCALEZERO ) {
if ( const auto PMONITOR = m_monitor . lock ( ) ; PMONITOR ) {
m_realSize - > setValueAndWarp ( m_realSize - > goal ( ) / PMONITOR - > m_scale ) ;
}
}
m_position = m_realPosition - > goal ( ) ;
m_size = m_realSize - > goal ( ) ;
m_workspace = g_pCompositor - > getMonitorFromVector ( m_realPosition - > value ( ) + m_realSize - > value ( ) / 2.f ) - > m_activeWorkspace ;
g_pCompositor - > changeWindowZOrder ( m_self . lock ( ) , true ) ;
updateWindowDecos ( ) ;
g_pHyprRenderer - > damageWindow ( m_self . lock ( ) ) ;
m_reportedPosition = m_realPosition - > goal ( ) ;
m_pendingReportedSize = m_realSize - > goal ( ) ;
}
}