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>
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"
2024-03-20 01:44:51 +00:00
# include "../Compositor.hpp"
# include "../render/decorations/CHyprDropShadowDecoration.hpp"
# include "../render/decorations/CHyprGroupBarDecoration.hpp"
# include "../render/decorations/CHyprBorderDecoration.hpp"
# include "../config/ConfigValue.hpp"
2025-04-15 23:00:40 +00:00
# include "../config/ConfigManager.hpp"
2024-04-23 01:28:20 +01:00
# include "../managers/TokenManager.hpp"
2025-08-28 11:20:29 +02:00
# include "../managers/animation/AnimationManager.hpp"
2025-02-18 15:10:40 +00:00
# include "../managers/ANRManager.hpp"
2025-09-21 19:27:56 +02:00
# include "../managers/eventLoop/EventLoopManager.hpp"
2024-05-10 23:28:33 +01:00
# include "../protocols/XDGShell.hpp"
2024-06-08 10:07:59 +02:00
# include "../protocols/core/Compositor.hpp"
2025-08-22 20:24:25 +03:00
# include "../protocols/core/Subcompositor.hpp"
2025-02-02 22:25:29 +03:00
# include "../protocols/ContentType.hpp"
2025-04-06 00:30:13 +01:00
# include "../protocols/FractionalScale.hpp"
2024-05-25 22:43:51 +02:00
# include "../xwayland/XWayland.hpp"
2025-01-07 17:55:14 +00:00
# include "../helpers/Color.hpp"
2025-11-17 18:34:02 +00:00
# include "../helpers/math/Expression.hpp"
2025-01-17 15:21:35 +00:00
# include "../events/Events.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"
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
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-05-04 23:39:00 +02:00
pWindow - > m_wlSurface - > assign ( pWindow - > m_xdgSurface - > m_surface . lock ( ) , pWindow ) ;
2024-05-10 23:28:33 +01:00
return pWindow ;
}
2025-04-28 22:25:22 +02:00
CWindow : : CWindow ( SP < CXDGSurfaceResource > resource ) : m_xdgSurface ( resource ) {
m_wlSurface = CWLSurface : : create ( ) ;
2024-06-08 10:07:59 +02:00
2025-07-08 09:56:40 -07:00
m_listeners . map = m_xdgSurface - > m_events . map . listen ( [ this ] { Events : : listener_mapWindow ( this , nullptr ) ; } ) ;
m_listeners . ack = m_xdgSurface - > m_events . ack . listen ( [ this ] ( uint32_t d ) { onAck ( d ) ; } ) ;
m_listeners . unmap = m_xdgSurface - > m_events . unmap . listen ( [ this ] { Events : : listener_unmapWindow ( this , nullptr ) ; } ) ;
m_listeners . destroy = m_xdgSurface - > m_events . destroy . listen ( [ this ] { Events : : listener_destroyWindow ( this , nullptr ) ; } ) ;
m_listeners . commit = m_xdgSurface - > m_events . commit . listen ( [ this ] { Events : : listener_commitWindow ( this , nullptr ) ; } ) ;
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-04-28 22:25:22 +02:00
CWindow : : CWindow ( SP < CXWaylandSurface > surface ) : m_xwaylandSurface ( surface ) {
m_wlSurface = CWLSurface : : create ( ) ;
2024-06-08 10:07:59 +02:00
2025-07-08 09:56:40 -07:00
m_listeners . map = m_xwaylandSurface - > m_events . map . listen ( [ this ] { Events : : listener_mapWindow ( this , nullptr ) ; } ) ;
m_listeners . unmap = m_xwaylandSurface - > m_events . unmap . listen ( [ this ] { Events : : listener_unmapWindow ( this , nullptr ) ; } ) ;
m_listeners . destroy = m_xwaylandSurface - > m_events . destroy . listen ( [ this ] { Events : : listener_destroyWindow ( this , nullptr ) ; } ) ;
m_listeners . commit = m_xwaylandSurface - > m_events . commit . listen ( [ this ] { Events : : listener_commitWindow ( this , nullptr ) ; } ) ;
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 ( ) ; } ) ;
m_listeners . activate = m_xwaylandSurface - > m_events . activate . listen ( [ this ] { Events : : listener_activateX11 ( this , nullptr ) ; } ) ;
2024-05-25 22:43:51 +02:00
2025-05-07 15:21:44 +02:00
if ( m_xwaylandSurface - > m_overrideRedirect )
2025-07-08 09:56:40 -07:00
m_listeners . setGeometry = m_xwaylandSurface - > m_events . setGeometry . listen ( [ this ] { Events : : listener_unmanagedSetGeometry ( this , nullptr ) ; } ) ;
2022-04-23 14:16:02 +02:00
}
2022-03-30 21:18:42 +02:00
CWindow : : ~ CWindow ( ) {
2025-04-28 22:25:22 +02:00
if ( g_pCompositor - > m_lastWindow = = m_self ) {
2025-04-22 15:23:29 +02:00
g_pCompositor - > m_lastFocus . reset ( ) ;
g_pCompositor - > m_lastWindow . 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
}
2024-06-19 16:20:06 +02:00
SBoxExtents CWindow : : getFullWindowExtents ( ) {
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-01-26 12:54:32 +00:00
[ ] ( WP < CPopup > popup , void * data ) {
2025-04-24 20:49:49 +02:00
if ( ! popup - > m_wlSurface | | ! popup - > m_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 ;
}
2023-11-04 17:03:05 +00:00
CBox CWindow : : getFullWindowBoundingBox ( ) {
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-04-30 23:45:20 +02:00
if ( DELTALESSTHAN ( POS . y - PMONITOR - > m_position . y , PMONITOR - > m_reservedTopLeft . y , 1 ) ) {
POS . y = PMONITOR - > m_position . y ;
SIZE . y + = PMONITOR - > m_reservedTopLeft . y ;
2022-06-23 20:39:48 +02:00
}
2025-04-30 23:45:20 +02:00
if ( DELTALESSTHAN ( POS . x - PMONITOR - > m_position . x , PMONITOR - > m_reservedTopLeft . x , 1 ) ) {
POS . x = PMONITOR - > m_position . x ;
SIZE . x + = PMONITOR - > m_reservedTopLeft . x ;
2022-06-23 20:39:48 +02:00
}
2025-04-30 23:45:20 +02:00
if ( DELTALESSTHAN ( POS . x + SIZE . x - PMONITOR - > m_position . x , PMONITOR - > m_size . x - PMONITOR - > m_reservedBottomRight . x , 1 ) ) {
SIZE . x + = PMONITOR - > m_reservedBottomRight . x ;
2022-06-23 20:39:48 +02:00
}
2025-04-30 23:45:20 +02:00
if ( DELTALESSTHAN ( POS . y + SIZE . y - PMONITOR - > m_position . y , PMONITOR - > m_size . y - PMONITOR - > m_reservedBottomRight . y , 1 ) ) {
SIZE . y + = PMONITOR - > m_reservedBottomRight . y ;
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 } } ;
if ( properties & RESERVED_EXTENTS )
2025-09-27 02:50:40 +02:00
extents . addExtents ( g_pDecorationPositioner - > getWindowDecorationReserved ( m_self ) ) ;
2025-07-18 11:35:43 -04:00
if ( properties & 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
std : : erase_if ( g_pCompositor - > m_windowFocusHistory , [ this ] ( const auto & other ) { return other . expired ( ) | | other = = m_self ; } ) ;
2023-03-23 00:39:32 +00:00
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
g_pCompositor - > m_windowFocusHistory . push_back ( m_self ) ;
2023-03-28 20:17:47 +01: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-04-28 22:25:22 +02:00
if ( hidden & & g_pCompositor - > m_lastWindow = = m_self )
2025-04-22 15:23:29 +02:00
g_pCompositor - > m_lastWindow . 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-04-24 20:49:49 +02:00
return popup & & popup - > m_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-04-22 15:23:29 +02:00
const auto CURRENTISFOCUS = PCURRENT = = g_pCompositor - > m_lastWindow . lock ( ) ;
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 )
g_pCompositor - > focusWindow ( 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
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 ;
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 ) ;
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
}
int CWindow : : getRealBorderSize ( ) {
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-08-14 19:44:56 +05:00
m_popupHead - > breadthfirst ( [ ] ( WP < 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
}
bool CWindow : : isEffectiveInternalFSMode ( const eFullscreenMode MODE ) {
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 ;
//
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 { } ;
std : : vector < char > buffer ;
size_t needle = 0 ;
buffer . resize ( 512 , ' \0 ' ) ;
while ( ifs . read ( buffer . data ( ) + needle , 512 ) ) {
buffer . resize ( buffer . size ( ) + 512 , ' \0 ' ) ;
needle + = 512 ;
}
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-04-28 22:25:22 +02:00
if ( g_pCompositor - > m_lastWindow = = 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-04-28 22:25:22 +02:00
g_pCompositor - > focusWindow ( 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-01-09 17:38:38 -05:00
g_pCompositor - > setActiveMonitor ( monitor ) ;
}
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-04-28 22:25:22 +02:00
if ( m_self = = g_pCompositor - > m_lastWindow ) { // 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-04-28 22:25:22 +02:00
if ( m_self = = g_pCompositor - > m_lastWindow ) { // 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-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windowFocusHistory ) {
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 ;
if ( m_self = = g_pCompositor - > m_lastWindow ) {
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 {
if ( m_self = = g_pCompositor - > m_lastWindow )
* m_activeInactiveAlpha = m_ruleApplicator - > alpha ( ) . valueOrDefault ( ) . applyAlpha ( * PACTIVEALPHA ) ;
else
* m_activeInactiveAlpha = m_ruleApplicator - > alphaInactive ( ) . valueOrDefault ( ) . applyAlpha ( * PINACTIVEALPHA ) ;
}
// dim
float goalDim = 1.F ;
if ( m_self = = g_pCompositor - > m_lastWindow . lock ( ) | | m_ruleApplicator - > noDim ( ) . valueOrDefault ( ) | | ! * PDIMENABLED )
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 ) {
if ( m_self = = g_pCompositor - > m_lastWindow )
* 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 ) {
const auto PMONITOR = m_monitor ? m_monitor : g_pCompositor - > m_lastMonitor ;
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 } ;
}