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>
# include <algorithm>
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-01-07 17:55:14 +00:00
# include "../managers/AnimationManager.hpp"
2025-02-18 15:10:40 +00:00
# include "../managers/ANRManager.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-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-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-04-28 22:25:22 +02:00
pWindow - > m_self = pWindow ;
pWindow - > m_isX11 = true ;
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 ;
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-05-04 23:39:00 +02:00
m_listeners . map = m_xdgSurface - > m_events . map . registerListener ( [ this ] ( std : : any d ) { Events : : listener_mapWindow ( this , nullptr ) ; } ) ;
m_listeners . ack = m_xdgSurface - > m_events . ack . registerListener ( [ this ] ( std : : any d ) { onAck ( std : : any_cast < uint32_t > ( d ) ) ; } ) ;
m_listeners . unmap = m_xdgSurface - > m_events . unmap . registerListener ( [ this ] ( std : : any d ) { Events : : listener_unmapWindow ( this , nullptr ) ; } ) ;
m_listeners . destroy = m_xdgSurface - > m_events . destroy . registerListener ( [ this ] ( std : : any d ) { Events : : listener_destroyWindow ( this , nullptr ) ; } ) ;
m_listeners . commit = m_xdgSurface - > m_events . commit . registerListener ( [ this ] ( std : : any d ) { Events : : listener_commitWindow ( this , nullptr ) ; } ) ;
m_listeners . updateState = m_xdgSurface - > m_toplevel - > m_events . stateChanged . registerListener ( [ this ] ( std : : any d ) { onUpdateState ( ) ; } ) ;
m_listeners . updateMetadata = m_xdgSurface - > m_toplevel - > m_events . metadataChanged . registerListener ( [ this ] ( std : : any d ) { 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-04-28 22:25:22 +02:00
m_listeners . map = m_xwaylandSurface - > events . map . registerListener ( [ this ] ( std : : any d ) { Events : : listener_mapWindow ( this , nullptr ) ; } ) ;
m_listeners . unmap = m_xwaylandSurface - > events . unmap . registerListener ( [ this ] ( std : : any d ) { Events : : listener_unmapWindow ( this , nullptr ) ; } ) ;
m_listeners . destroy = m_xwaylandSurface - > events . destroy . registerListener ( [ this ] ( std : : any d ) { Events : : listener_destroyWindow ( this , nullptr ) ; } ) ;
m_listeners . commit = m_xwaylandSurface - > events . commit . registerListener ( [ this ] ( std : : any d ) { Events : : listener_commitWindow ( this , nullptr ) ; } ) ;
m_listeners . configureRequest = m_xwaylandSurface - > events . configureRequest . registerListener ( [ this ] ( std : : any d ) { onX11ConfigureRequest ( std : : any_cast < CBox > ( d ) ) ; } ) ;
m_listeners . updateState = m_xwaylandSurface - > events . stateChanged . registerListener ( [ this ] ( std : : any d ) { onUpdateState ( ) ; } ) ;
m_listeners . updateMetadata = m_xwaylandSurface - > events . metadataChanged . registerListener ( [ this ] ( std : : any d ) { onUpdateMeta ( ) ; } ) ;
m_listeners . resourceChange = m_xwaylandSurface - > events . resourceChange . registerListener ( [ this ] ( std : : any d ) { onResourceChangeX11 ( ) ; } ) ;
m_listeners . activate = m_xwaylandSurface - > events . activate . registerListener ( [ this ] ( std : : any d ) { Events : : listener_activateX11 ( this , nullptr ) ; } ) ;
2024-05-25 22:43:51 +02:00
2025-04-28 22:25:22 +02:00
if ( m_xwaylandSurface - > overrideRedirect )
m_listeners . setGeometry = m_xwaylandSurface - > events . setGeometry . registerListener ( [ this ] ( std : : any d ) { 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-04-28 22:25:22 +02:00
if ( m_windowData . dimAround . valueOrDefault ( ) ) {
if ( const auto PMONITOR = m_monitor . lock ( ) ; PMONITOR )
2025-04-30 23:45:20 +02:00
return { { m_realPosition - > value ( ) . x - PMONITOR - > m_position . x , m_realPosition - > value ( ) . y - PMONITOR - > m_position . y } ,
{ 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
2024-06-19 16:20:06 +02:00
SBoxExtents maxExtents = { { BORDERSIZE + 2 , BORDERSIZE + 2 } , { BORDERSIZE + 2 , BORDERSIZE + 2 } } ;
2022-05-30 14:55:42 +02:00
2025-04-28 22:25:22 +02:00
const auto EXTENTS = g_pDecorationPositioner - > getWindowDecorationExtents ( m_self . lock ( ) ) ;
2022-05-30 14:55:42 +02:00
2023-11-11 14:37:17 +00:00
if ( EXTENTS . topLeft . x > maxExtents . topLeft . x )
maxExtents . topLeft . x = EXTENTS . topLeft . x ;
2022-05-30 14:55:42 +02:00
2023-11-11 14:37:17 +00:00
if ( EXTENTS . topLeft . y > maxExtents . topLeft . y )
maxExtents . topLeft . y = EXTENTS . topLeft . y ;
2022-05-30 14:55:42 +02:00
2023-11-11 14:37:17 +00:00
if ( EXTENTS . bottomRight . x > maxExtents . bottomRight . x )
maxExtents . bottomRight . x = EXTENTS . bottomRight . x ;
2022-05-30 14:55:42 +02:00
2023-11-11 14:37:17 +00:00
if ( EXTENTS . bottomRight . y > maxExtents . bottomRight . y )
maxExtents . bottomRight . y = EXTENTS . 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 ;
2023-11-04 17:03:05 +00:00
CBox * pSurfaceExtents = ( CBox * ) data ;
2024-05-10 23:28:33 +01:00
CBox surf = CBox { popup - > coordsRelativeToParent ( ) , popup - > size ( ) } ;
if ( surf . x < pSurfaceExtents - > x )
pSurfaceExtents - > x = surf . x ;
if ( surf . y < pSurfaceExtents - > y )
pSurfaceExtents - > y = surf . y ;
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 ) ;
if ( - surfaceExtents . x > maxExtents . topLeft . x )
maxExtents . topLeft . x = - surfaceExtents . x ;
if ( - surfaceExtents . y > maxExtents . topLeft . y )
maxExtents . topLeft . y = - surfaceExtents . y ;
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-04-28 22:25:22 +02:00
if ( m_windowData . dimAround . valueOrDefault ( ) ) {
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
2023-11-04 17:03:05 +00:00
return CBox { ( int ) POS . x , ( int ) POS . y , ( int ) SIZE . x , ( 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
}
2023-11-04 17:03:05 +00:00
return CBox { ( int ) POS . x , ( int ) POS . y , ( int ) SIZE . x , ( int ) SIZE . y } ;
2022-06-27 00:25:37 +02:00
}
2024-02-04 15:40:20 +00:00
CBox CWindow : : getWindowBoxUnified ( uint64_t properties ) {
2025-04-28 22:25:22 +02:00
if ( m_windowData . dimAround . valueOrDefault ( ) ) {
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
}
2024-06-19 16:20:06 +02:00
SBoxExtents EXTENTS = { { 0 , 0 } , { 0 , 0 } } ;
2024-02-04 15:40:20 +00:00
if ( properties & RESERVED_EXTENTS )
2025-04-28 22:25:22 +02:00
EXTENTS . addExtents ( g_pDecorationPositioner - > getWindowDecorationReserved ( m_self . lock ( ) ) ) ;
2024-02-04 15:40:20 +00:00
if ( properties & INPUT_EXTENTS )
2025-04-28 22:25:22 +02:00
EXTENTS . addExtents ( g_pDecorationPositioner - > getWindowDecorationExtents ( m_self . lock ( ) , true ) ) ;
2024-02-04 15:40:20 +00:00
if ( properties & FULL_EXTENTS )
2025-04-28 22:25:22 +02:00
EXTENTS . addExtents ( g_pDecorationPositioner - > getWindowDecorationExtents ( m_self . lock ( ) , false ) ) ;
2023-02-28 22:32:42 +00:00
2025-04-28 22:25:22 +02:00
CBox box = { m_realPosition - > value ( ) . x , m_realPosition - > value ( ) . y , m_realSize - > value ( ) . x , m_realSize - > value ( ) . y } ;
2024-02-04 15:40:20 +00:00
box . addExtents ( EXTENTS ) ;
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-04-28 22:25:22 +02:00
return g_pDecorationPositioner - > getWindowDecorationReserved ( m_self . lock ( ) ) ;
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-04-28 22:25:22 +02:00
if ( std : : find_if ( m_windowDecorations . begin ( ) , m_windowDecorations . end ( ) , [ 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-04-28 22:25:22 +02:00
PID = m_xwaylandSurface - > 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-04-25 02:37:12 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " movewindow " , std : : format ( " {:x},{} " , ( uintptr_t ) this , pWorkspace - > m_name ) } ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " movewindowv2 " , std : : format ( " {:x},{},{} " , ( 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-04-28 22:25:22 +02:00
if ( ! m_xwaylandSurface | | ! m_xwaylandSurface - > parent )
2022-08-28 19:47:06 +02:00
return nullptr ;
2025-04-28 22:25:22 +02:00
auto s = m_xwaylandSurface - > 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.
if ( std : : 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 ( ) ) ;
2024-05-25 22:43:51 +02:00
s = s - > 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-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 ;
sendWindowSize ( ) ;
} ,
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-01-07 17:55:14 +00:00
const auto PANIMVAR = dynamic_cast < CAnimatedVariable < float > * > ( PAV . get ( ) ) ;
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
}
2024-12-16 19:05:24 +01:00
void CWindow : : applyDynamicRule ( const SP < CWindowRule > & r ) {
2025-04-28 22:25:22 +02:00
const eOverridePriority priority = r - > m_execRule ? PRIORITY_SET_PROP : PRIORITY_WINDOW_RULE ;
2024-12-16 19:05:24 +01:00
2025-04-28 22:25:22 +02:00
switch ( r - > m_ruleType ) {
2024-12-16 19:05:24 +01:00
case CWindowRule : : RULE_TAG : {
2025-04-28 22:25:22 +02:00
CVarList vars { r - > m_rule , 0 , ' s ' , true } ;
2024-12-16 19:05:24 +01:00
if ( vars . size ( ) = = 2 & & vars [ 0 ] = = " tag " )
m_tags . applyTag ( vars [ 1 ] , true ) ;
else
2025-04-28 22:25:22 +02:00
Debug : : log ( ERR , " Tag rule invalid: {} " , r - > m_rule ) ;
2024-12-16 19:05:24 +01:00
break ;
}
case CWindowRule : : RULE_OPACITY : {
try {
2025-04-28 22:25:22 +02:00
CVarList vars ( r - > m_rule , 0 , ' ' ) ;
2024-12-16 19:05:24 +01:00
int opacityIDX = 0 ;
for ( auto const & r : vars ) {
if ( r = = " opacity " )
continue ;
if ( r = = " override " ) {
if ( opacityIDX = = 1 )
2025-04-28 22:25:22 +02:00
m_windowData . alpha = CWindowOverridableVar ( SAlphaValue { m_windowData . alpha . value ( ) . alpha , true } , priority ) ;
2024-12-16 19:05:24 +01:00
else if ( opacityIDX = = 2 )
2025-04-28 22:25:22 +02:00
m_windowData . alphaInactive = CWindowOverridableVar ( SAlphaValue { m_windowData . alphaInactive . value ( ) . alpha , true } , priority ) ;
2024-12-16 19:05:24 +01:00
else if ( opacityIDX = = 3 )
2025-04-28 22:25:22 +02:00
m_windowData . alphaFullscreen = CWindowOverridableVar ( SAlphaValue { m_windowData . alphaFullscreen . value ( ) . alpha , true } , priority ) ;
2022-12-11 17:15:02 +00:00
} else {
2024-12-16 19:05:24 +01:00
if ( opacityIDX = = 0 ) {
2025-04-28 22:25:22 +02:00
m_windowData . alpha = CWindowOverridableVar ( SAlphaValue { std : : stof ( r ) , false } , priority ) ;
2024-12-16 19:05:24 +01:00
} else if ( opacityIDX = = 1 ) {
2025-04-28 22:25:22 +02:00
m_windowData . alphaInactive = CWindowOverridableVar ( SAlphaValue { std : : stof ( r ) , false } , priority ) ;
2024-12-16 19:05:24 +01:00
} else if ( opacityIDX = = 2 ) {
2025-04-28 22:25:22 +02:00
m_windowData . alphaFullscreen = CWindowOverridableVar ( SAlphaValue { std : : stof ( r ) , false } , priority ) ;
2024-12-16 19:05:24 +01:00
} else {
throw std : : runtime_error ( " more than 3 alpha values " ) ;
}
opacityIDX + + ;
2022-12-11 17:15:02 +00:00
}
}
2024-04-09 18:22:44 +03:00
2024-12-16 19:05:24 +01:00
if ( opacityIDX = = 1 ) {
2025-04-28 22:25:22 +02:00
m_windowData . alphaInactive = m_windowData . alpha ;
m_windowData . alphaFullscreen = m_windowData . alpha ;
2024-12-16 19:05:24 +01:00
}
2025-04-28 22:25:22 +02:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Opacity rule \" {} \" failed with: {} " , r - > m_rule , e . what ( ) ) ; }
2024-12-16 19:05:24 +01:00
break ;
}
case CWindowRule : : RULE_ANIMATION : {
2025-04-28 22:25:22 +02:00
auto STYLE = r - > m_rule . substr ( r - > m_rule . find_first_of ( ' ' ) + 1 ) ;
m_windowData . animationStyle = CWindowOverridableVar ( STYLE , priority ) ;
2024-12-16 19:05:24 +01:00
break ;
}
case CWindowRule : : RULE_BORDERCOLOR : {
try {
// Each vector will only get used if it has at least one color
CGradientValueData activeBorderGradient = { } ;
CGradientValueData inactiveBorderGradient = { } ;
bool active = true ;
2025-04-28 22:25:22 +02:00
CVarList colorsAndAngles = CVarList ( trim ( r - > m_rule . substr ( r - > m_rule . find_first_of ( ' ' ) + 1 ) ) , 0 , ' s ' , true ) ;
2024-12-16 19:05:24 +01:00
// Basic form has only two colors, everything else can be parsed as a gradient
if ( colorsAndAngles . size ( ) = = 2 & & ! colorsAndAngles [ 1 ] . contains ( " deg " ) ) {
2025-04-28 22:25:22 +02:00
m_windowData . activeBorderColor = CWindowOverridableVar ( CGradientValueData ( CHyprColor ( configStringToInt ( colorsAndAngles [ 0 ] ) . value_or ( 0 ) ) ) , priority ) ;
m_windowData . inactiveBorderColor = CWindowOverridableVar ( CGradientValueData ( CHyprColor ( configStringToInt ( colorsAndAngles [ 1 ] ) . value_or ( 0 ) ) ) , priority ) ;
2024-12-16 19:05:24 +01:00
return ;
}
2024-01-14 12:27:32 -05:00
2024-12-16 19:05:24 +01:00
for ( auto const & token : colorsAndAngles ) {
// The first angle, or an explicit "0deg", splits the two gradients
if ( active & & token . contains ( " deg " ) ) {
2025-04-20 20:39:33 +02:00
activeBorderGradient . m_angle = std : : stoi ( token . substr ( 0 , token . size ( ) - 3 ) ) * ( PI / 180.0 ) ;
active = false ;
2024-12-16 19:05:24 +01:00
} else if ( token . contains ( " deg " ) )
2025-04-20 20:39:33 +02:00
inactiveBorderGradient . m_angle = std : : stoi ( token . substr ( 0 , token . size ( ) - 3 ) ) * ( PI / 180.0 ) ;
2024-12-16 19:05:24 +01:00
else if ( active )
2025-04-20 20:39:33 +02:00
activeBorderGradient . m_colors . push_back ( configStringToInt ( token ) . value_or ( 0 ) ) ;
2024-12-16 19:05:24 +01:00
else
2025-04-20 20:39:33 +02:00
inactiveBorderGradient . m_colors . push_back ( configStringToInt ( token ) . value_or ( 0 ) ) ;
2024-12-16 19:05:24 +01:00
}
2024-01-14 12:27:32 -05:00
2024-12-16 19:05:24 +01:00
activeBorderGradient . updateColorsOk ( ) ;
// Includes sanity checks for the number of colors in each gradient
2025-04-20 20:39:33 +02:00
if ( activeBorderGradient . m_colors . size ( ) > 10 | | inactiveBorderGradient . m_colors . size ( ) > 10 )
2025-04-28 22:25:22 +02:00
Debug : : log ( WARN , " Bordercolor rule \" {} \" has more than 10 colors in one gradient, ignoring " , r - > m_rule ) ;
2025-04-20 20:39:33 +02:00
else if ( activeBorderGradient . m_colors . empty ( ) )
2025-04-28 22:25:22 +02:00
Debug : : log ( WARN , " Bordercolor rule \" {} \" has no colors, ignoring " , r - > m_rule ) ;
2025-04-20 20:39:33 +02:00
else if ( inactiveBorderGradient . m_colors . empty ( ) )
2025-04-28 22:25:22 +02:00
m_windowData . activeBorderColor = CWindowOverridableVar ( activeBorderGradient , priority ) ;
2024-12-16 19:05:24 +01:00
else {
2025-04-28 22:25:22 +02:00
m_windowData . activeBorderColor = CWindowOverridableVar ( activeBorderGradient , priority ) ;
m_windowData . inactiveBorderColor = CWindowOverridableVar ( inactiveBorderGradient , priority ) ;
2024-12-16 19:05:24 +01:00
}
2025-04-28 22:25:22 +02:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " BorderColor rule \" {} \" failed with: {} " , r - > m_rule , e . what ( ) ) ; }
2024-12-16 19:05:24 +01:00
break ;
2024-07-11 14:10:42 +00:00
}
2024-12-16 19:05:24 +01:00
case CWindowRule : : RULE_IDLEINHIBIT : {
2025-04-28 22:25:22 +02:00
auto IDLERULE = r - > m_rule . substr ( r - > m_rule . find_first_of ( ' ' ) + 1 ) ;
2024-12-16 19:05:24 +01:00
if ( IDLERULE = = " none " )
2025-04-28 22:25:22 +02:00
m_idleInhibitMode = IDLEINHIBIT_NONE ;
2024-12-16 19:05:24 +01:00
else if ( IDLERULE = = " always " )
2025-04-28 22:25:22 +02:00
m_idleInhibitMode = IDLEINHIBIT_ALWAYS ;
2024-12-16 19:05:24 +01:00
else if ( IDLERULE = = " focus " )
2025-04-28 22:25:22 +02:00
m_idleInhibitMode = IDLEINHIBIT_FOCUS ;
2024-12-16 19:05:24 +01:00
else if ( IDLERULE = = " fullscreen " )
2025-04-28 22:25:22 +02:00
m_idleInhibitMode = IDLEINHIBIT_FULLSCREEN ;
2024-12-16 19:05:24 +01:00
else
Debug : : log ( ERR , " Rule idleinhibit: unknown mode {} " , IDLERULE ) ;
break ;
}
case CWindowRule : : RULE_MAXSIZE : {
try {
2025-04-28 22:25:22 +02:00
if ( ! m_isFloating )
2024-12-16 19:05:24 +01:00
return ;
2025-04-28 22:25:22 +02:00
const auto VEC = configStringToVector2D ( r - > m_rule . substr ( 8 ) ) ;
2024-12-16 19:05:24 +01:00
if ( VEC . x < 1 | | VEC . y < 1 ) {
Debug : : log ( ERR , " Invalid size for maxsize " ) ;
return ;
}
2024-03-08 17:10:38 +00:00
2025-04-28 22:25:22 +02:00
m_windowData . maxSize = CWindowOverridableVar ( VEC , priority ) ;
clampWindowSize ( std : : nullopt , m_windowData . maxSize . value ( ) ) ;
2024-10-07 18:52:49 +00:00
2025-04-28 22:25:22 +02:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " maxsize rule \" {} \" failed with: {} " , r - > m_rule , e . what ( ) ) ; }
2024-12-16 19:05:24 +01:00
break ;
}
case CWindowRule : : RULE_MINSIZE : {
try {
2025-04-28 22:25:22 +02:00
if ( ! m_isFloating )
2024-12-16 19:05:24 +01:00
return ;
2025-04-28 22:25:22 +02:00
const auto VEC = configStringToVector2D ( r - > m_rule . substr ( 8 ) ) ;
2024-12-16 19:05:24 +01:00
if ( VEC . x < 1 | | VEC . y < 1 ) {
Debug : : log ( ERR , " Invalid size for minsize " ) ;
return ;
}
2024-03-08 17:10:38 +00:00
2025-04-28 22:25:22 +02:00
m_windowData . minSize = CWindowOverridableVar ( VEC , priority ) ;
clampWindowSize ( m_windowData . minSize . value ( ) , std : : nullopt ) ;
2024-10-07 18:52:49 +00:00
2025-04-28 22:25:22 +02:00
if ( m_groupData . pNextWindow . expired ( ) )
2024-12-16 19:05:24 +01:00
setHidden ( false ) ;
2025-04-28 22:25:22 +02:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " minsize rule \" {} \" failed with: {} " , r - > m_rule , e . what ( ) ) ; }
2024-12-16 19:05:24 +01:00
break ;
}
case CWindowRule : : RULE_RENDERUNFOCUSED : {
2025-04-28 22:25:22 +02:00
m_windowData . renderUnfocused = CWindowOverridableVar ( true , priority ) ;
g_pHyprRenderer - > addWindowToRenderUnfocused ( m_self . lock ( ) ) ;
2024-12-16 19:05:24 +01:00
break ;
}
case CWindowRule : : RULE_PROP : {
2025-04-28 22:25:22 +02:00
const CVarList VARS ( r - > m_rule , 0 , ' ' ) ;
2025-03-02 02:13:31 +00:00
if ( auto search = NWindowProperties : : intWindowProperties . find ( VARS [ 1 ] ) ; search ! = NWindowProperties : : intWindowProperties . end ( ) ) {
2024-12-16 19:05:24 +01:00
try {
2025-04-28 22:25:22 +02:00
* ( search - > second ( m_self . lock ( ) ) ) = CWindowOverridableVar ( Hyprlang : : INT ( std : : stoi ( VARS [ 2 ] ) ) , priority ) ;
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Rule \" {} \" failed with: {} " , r - > m_rule , e . what ( ) ) ; }
2025-03-02 02:13:31 +00:00
} else if ( auto search = NWindowProperties : : floatWindowProperties . find ( VARS [ 1 ] ) ; search ! = NWindowProperties : : floatWindowProperties . end ( ) ) {
2024-12-16 19:05:24 +01:00
try {
2025-04-28 22:25:22 +02:00
* ( search - > second ( m_self . lock ( ) ) ) = CWindowOverridableVar ( std : : stof ( VARS [ 2 ] ) , priority ) ;
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Rule \" {} \" failed with: {} " , r - > m_rule , e . what ( ) ) ; }
2025-03-02 02:13:31 +00:00
} else if ( auto search = NWindowProperties : : boolWindowProperties . find ( VARS [ 1 ] ) ; search ! = NWindowProperties : : boolWindowProperties . end ( ) ) {
2024-12-16 19:05:24 +01:00
try {
2025-04-28 22:25:22 +02:00
* ( search - > second ( m_self . lock ( ) ) ) = CWindowOverridableVar ( VARS [ 2 ] . empty ( ) ? true : ( bool ) std : : stoi ( VARS [ 2 ] ) , priority ) ;
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Rule \" {} \" failed with: {} " , r - > m_rule , e . what ( ) ) ; }
2024-12-16 19:05:24 +01:00
}
break ;
}
2025-03-07 20:12:02 -05:00
case CWindowRule : : RULE_PERSISTENTSIZE : {
2025-04-28 22:25:22 +02:00
m_windowData . persistentSize = CWindowOverridableVar ( true , PRIORITY_WINDOW_RULE ) ;
2025-03-07 20:12:02 -05:00
break ;
}
2024-12-16 19:05:24 +01:00
default : break ;
2022-11-15 11:21:26 +01:00
}
}
void CWindow : : updateDynamicRules ( ) {
2025-04-28 22:25:22 +02:00
m_windowData . alpha . unset ( PRIORITY_WINDOW_RULE ) ;
m_windowData . alphaInactive . unset ( PRIORITY_WINDOW_RULE ) ;
m_windowData . alphaFullscreen . unset ( PRIORITY_WINDOW_RULE ) ;
2024-07-11 14:10:42 +00:00
unsetWindowData ( PRIORITY_WINDOW_RULE ) ;
2025-04-28 22:25:22 +02:00
m_windowData . animationStyle . unset ( PRIORITY_WINDOW_RULE ) ;
m_windowData . maxSize . unset ( PRIORITY_WINDOW_RULE ) ;
m_windowData . minSize . unset ( PRIORITY_WINDOW_RULE ) ;
2024-07-11 14:10:42 +00:00
2025-04-28 22:25:22 +02:00
m_windowData . activeBorderColor . unset ( PRIORITY_WINDOW_RULE ) ;
m_windowData . inactiveBorderColor . unset ( PRIORITY_WINDOW_RULE ) ;
2024-07-11 14:10:42 +00:00
2025-04-28 22:25:22 +02:00
m_windowData . renderUnfocused . unset ( PRIORITY_WINDOW_RULE ) ;
2024-08-30 17:37:52 +02:00
2025-04-28 22:25:22 +02:00
m_idleInhibitMode = IDLEINHIBIT_NONE ;
2022-11-15 11:21:26 +01:00
2024-05-29 05:37:24 +08:00
m_tags . removeDynamicTags ( ) ;
2025-04-28 22:25:22 +02:00
m_matchedRules = g_pConfigManager - > getMatchingRules ( m_self . lock ( ) ) ;
for ( const auto & r : m_matchedRules ) {
2022-11-15 11:21:26 +01:00
applyDynamicRule ( r ) ;
}
2023-07-18 00:11:43 +02:00
2025-04-28 22:25:22 +02:00
EMIT_HOOK_EVENT ( " windowUpdateRules " , m_self . lock ( ) ) ;
2024-05-02 02:17:55 +01:00
2024-10-27 18:45:38 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitorID ( ) ) ;
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-01-05 12:38:49 -06:00
return std : : pow ( x0 - x , ROUNDINGPOWER ) + std : : pow ( y0 - y , ROUNDINGPOWER ) > std : : pow ( ( double ) ROUNDING , ROUNDINGPOWER ) ;
2023-02-18 23:35:31 +01:00
}
if ( x > x1 & & y < y0 ) {
2025-01-05 12:38:49 -06:00
return std : : pow ( x - x1 , ROUNDINGPOWER ) + std : : pow ( y0 - y , ROUNDINGPOWER ) > std : : pow ( ( double ) ROUNDING , ROUNDINGPOWER ) ;
2023-02-18 23:35:31 +01:00
}
if ( x < x0 & & y > y1 ) {
2025-01-05 12:38:49 -06:00
return std : : pow ( x0 - x , ROUNDINGPOWER ) + std : : pow ( y - y1 , ROUNDINGPOWER ) > std : : pow ( ( double ) ROUNDING , ROUNDINGPOWER ) ;
2023-02-18 23:35:31 +01:00
}
if ( x > x1 & & y > y1 ) {
2025-01-05 12:38:49 -06:00
return std : : pow ( x - x1 , ROUNDINGPOWER ) + std : : pow ( y - y1 , ROUNDINGPOWER ) > std : : pow ( ( 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 ) {
Debug : : log ( LOG , " createGroup: window:{:x},title:{} is denied as a group, ignored " , ( 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
g_pEventManager - > postEvent ( SHyprIPCEvent { " togglegroup " , std : : format ( " 1,{:x} " , ( uintptr_t ) this ) } ) ;
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 ) {
Debug : : log ( LOG , " destoryGroup: window:{:x},title:{} has rule [group set always], ignored " , ( 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
g_pEventManager - > postEvent ( SHyprIPCEvent { " togglegroup " , std : : format ( " 0,{:x} " , ( uintptr_t ) this ) } ) ;
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
addresses + = std : : format ( " {:x}, " , ( 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 ) ;
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 ( ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " togglegroup " , 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-05-01 23:57:11 +02:00
bool disallowDragIntoGroup = g_pInputManager - > m_wasDraggingWindow & & isGroup & & ! 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 ;
}
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
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
2025-04-28 22:25:22 +02:00
const auto PWINDOWSIZE = PCURRENT - > m_realSize - > goal ( ) ;
const auto PWINDOWPOS = PCURRENT - > m_realPosition - > goal ( ) ;
2024-12-27 20:50:38 +05:30
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-04-28 22:25:22 +02:00
if ( PCURRENT - > m_isFloating ) {
pWindow - > m_realPosition - > setValueAndWarp ( PWINDOWPOS ) ;
pWindow - > m_realSize - > setValueAndWarp ( PWINDOWSIZE ) ;
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
if ( FULLSCREEN )
2024-07-31 17:55:52 +00:00
g_pCompositor - > setWindowFullscreenInternal ( pWindow , MODE ) ;
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
2023-09-10 21:59:10 +00:00
if ( ! pWindow - > getDecorationByType ( DECORATION_GROUPBAR ) )
2025-01-23 21:55:41 +01:00
pWindow - > addWindowDeco ( makeUnique < CHyprGroupBarDecoration > ( pWindow ) ) ;
2023-09-10 21:59:10 +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 ;
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-04-25 02:37:12 +02:00
if ( PWORKSPACE - > m_alpha - > value ( ) ! = 1.f )
2023-07-19 16:13:55 +02:00
return false ;
2025-05-03 16:02:49 +02:00
if ( m_isX11 & & m_xwaylandSurface & & m_xwaylandSurface - > surface & & m_xwaylandSurface - > surface - > m_current . texture )
2025-05-05 23:44:49 +02:00
return m_xwaylandSurface - > surface - > m_current . texture - > m_opaque ;
2023-04-22 12:36:50 +01:00
2025-05-03 16:02:49 +02:00
if ( ! m_wlSurface - > resource ( ) | | ! m_wlSurface - > resource ( ) - > 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-05-05 23:44:49 +02:00
return m_wlSurface - > resource ( ) - > 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-04-28 22:25:22 +02:00
float roundingPower = m_windowData . roundingPower . valueOr ( * PROUNDINGPOWER ) ;
float rounding = m_windowData . rounding . valueOr ( * PROUNDING ) * ( roundingPower / 2.0 ) ; /* Make perceived roundness consistent. */
2023-07-19 16:13:55 +02:00
2025-04-28 22:25:22 +02:00
return m_windowData . noRounding . valueOrDefault ( ) ? 0 : 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-04-28 22:25:22 +02:00
return m_windowData . roundingPower . valueOr ( * PROUNDINGPOWER ) ;
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 ) {
2024-03-03 18:39:20 +00:00
static auto PNOBORDERONFLOATING = CConfigValue < Hyprlang : : INT > ( " general:no_border_on_floating " ) ;
2024-02-18 15:00:34 +00:00
2024-07-11 14:10:42 +00:00
if ( * PNOBORDERONFLOATING )
2025-04-28 22:25:22 +02:00
m_windowData . noBorder = CWindowOverridableVar ( m_isFloating , PRIORITY_LAYOUT ) ;
2024-07-11 14:10:42 +00:00
else
2025-04-28 22:25:22 +02:00
m_windowData . noBorder . unset ( PRIORITY_LAYOUT ) ;
2023-08-17 08:13:19 +00:00
2025-04-28 22:25:22 +02:00
m_windowData . borderSize . matchOptional ( workspaceRule . borderSize , PRIORITY_WORKSPACE_RULE ) ;
m_windowData . decorate . matchOptional ( workspaceRule . decorate , PRIORITY_WORKSPACE_RULE ) ;
m_windowData . noBorder . matchOptional ( workspaceRule . noBorder , PRIORITY_WORKSPACE_RULE ) ;
m_windowData . noRounding . matchOptional ( workspaceRule . noRounding , PRIORITY_WORKSPACE_RULE ) ;
m_windowData . noShadow . matchOptional ( workspaceRule . noShadow , PRIORITY_WORKSPACE_RULE ) ;
2023-08-17 08:13:19 +00:00
}
int CWindow : : getRealBorderSize ( ) {
2025-04-28 22:25:22 +02:00
if ( m_windowData . noBorder . valueOrDefault ( ) | | ( m_workspace & & isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) ) )
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-04-28 22:25:22 +02:00
return m_windowData . 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-04-28 22:25:22 +02:00
return m_windowData . 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-04-28 22:25:22 +02:00
return m_windowData . scrollTouchpad . valueOr ( * PTOUCHPADSCROLLFACTOR ) ;
2024-12-06 01:16:58 -05: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-04-28 22:25:22 +02:00
return m_windowData . 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-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-04-28 22:25:22 +02:00
if ( m_isX11 )
2024-05-10 23:28:33 +01:00
return 0 ;
int no = - 1 ;
2025-04-28 22:25:22 +02:00
m_popupHead - > breadthfirst ( [ ] ( WP < CPopup > p , void * d ) { * ( ( 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-04-28 22:25:22 +02:00
m_wlSurface - > resource ( ) - > breadthfirst ( [ ] ( SP < CWLSurfaceResource > r , const Vector2D & offset , void * d ) { * ( ( 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 ( ) ;
2024-10-30 18:58:36 +00:00
const Vector2D NEWSIZE = REALSIZE . clamp ( minSize . value_or ( Vector2D { MIN_WINDOW_SIZE , MIN_WINDOW_SIZE } ) , maxSize . value_or ( Vector2D { INFINITY , INFINITY } ) ) ;
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-04-28 22:25:22 +02:00
return ( eFullscreenMode ) std : : bit_floor ( ( 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
2024-04-25 00:58:40 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " urgent " , std : : format ( " {:x} " , ( 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-04-28 22:25:22 +02:00
if ( ! force & & ( ! m_windowData . 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-04 23:39:00 +02:00
std : : optional < bool > requestsFS = m_xdgSurface ? m_xdgSurface - > m_toplevel - > m_state . requestsFullscreen : m_xwaylandSurface - > state . requestsFullscreen ;
std : : optional < MONITORID > requestsID = m_xdgSurface ? m_xdgSurface - > m_toplevel - > m_state . requestsFullscreenMonitor : MONITOR_INVALID ;
std : : optional < bool > requestsMX = m_xdgSurface ? m_xdgSurface - > m_toplevel - > m_state . requestsMaximize : m_xwaylandSurface - > 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 ) ) {
if ( m_isMapped )
g_pCompositor - > changeWindowFullscreenModeClient ( m_self . lock ( ) , FSMODE_MAXIMIZED , requestsMX . value ( ) ) ;
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 ;
2024-05-10 23:28:33 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " windowtitle " , std : : format ( " {:x} " , ( uintptr_t ) this ) } ) ;
2025-04-28 22:25:22 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " windowtitlev2 " , std : : format ( " {:x},{} " , ( uintptr_t ) this , m_title ) } ) ;
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
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindow " , m_class + " , " + m_title } ) ;
2024-05-10 23:28:33 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindowv2 " , std : : format ( " {:x} " , ( 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-04-28 22:25:22 +02:00
Debug : : log ( LOG , " Window {:x} set title to {} " , ( 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
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindow " , m_class + " , " + m_title } ) ;
2024-05-10 23:28:33 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindowv2 " , std : : format ( " {:x} " , ( 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-04-28 22:25:22 +02:00
Debug : : log ( LOG , " Window {:x} set class to {} " , ( uintptr_t ) this , m_class ) ;
2024-05-29 05:37:24 +08:00
doUpdate = true ;
}
if ( doUpdate ) {
2024-05-10 23:28:33 +01:00
updateDynamicRules ( ) ;
2025-04-28 22:25:22 +02:00
g_pCompositor - > updateWindowAnimatedDecorationValues ( m_self . lock ( ) ) ;
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 )
return m_xwaylandSurface - > 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 )
return m_xwaylandSurface - > state . appid ;
2024-05-10 23:28:33 +01:00
}
return " " ;
}
void CWindow : : onAck ( uint32_t serial ) {
2025-04-28 22:25:22 +02:00
const auto SERIAL = std : : find_if ( m_pendingSizeAcks . rbegin ( ) , m_pendingSizeAcks . rend ( ) , [ 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 ; } ) ;
2024-05-25 22:43:51 +02:00
}
void CWindow : : onResourceChangeX11 ( ) {
2025-04-28 22:25:22 +02:00
if ( m_xwaylandSurface - > surface & & ! m_wlSurface - > resource ( ) )
m_wlSurface - > assign ( m_xwaylandSurface - > surface . lock ( ) , m_self . lock ( ) ) ;
else if ( ! m_xwaylandSurface - > surface & & m_wlSurface - > resource ( ) )
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-04-28 22:25:22 +02:00
Debug : : log ( LOG , " xwayland window {:x} -> association to {:x} " , ( uintptr_t ) m_xwaylandSurface . get ( ) , ( 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-04-28 22:25:22 +02:00
if ( ! m_xwaylandSurface - > surface | | ! m_xwaylandSurface - > mapped | | ! m_isMapped ) {
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-02-06 12:18:04 +01:00
if ( candidates . size ( ) = = 0 )
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-02-06 12:18:04 +01:00
if ( candidates . size ( ) = = 0 )
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 ;
if ( std : : find ( candidates . begin ( ) , candidates . end ( ) , w . lock ( ) ) ! = candidates . end ( ) )
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
void CWindow : : unsetWindowData ( eOverridePriority priority ) {
2025-03-02 02:13:31 +00:00
for ( auto const & element : NWindowProperties : : boolWindowProperties ) {
2025-04-28 22:25:22 +02:00
element . second ( m_self . lock ( ) ) - > unset ( priority ) ;
2024-07-11 14:10:42 +00:00
}
2025-03-02 02:13:31 +00:00
for ( auto const & element : NWindowProperties : : intWindowProperties ) {
2025-04-28 22:25:22 +02:00
element . second ( m_self . lock ( ) ) - > unset ( priority ) ;
2024-07-11 14:10:42 +00:00
}
2025-03-02 02:13:31 +00:00
for ( auto const & element : NWindowProperties : : floatWindowProperties ) {
2025-04-28 22:25:22 +02:00
element . second ( m_self . lock ( ) ) - > unset ( priority ) ;
2024-12-06 01:16:58 -05:00
}
2024-07-11 14:10:42 +00:00
}
2024-08-30 14:12:23 +02:00
bool CWindow : : isX11OverrideRedirect ( ) {
2025-04-28 22:25:22 +02:00
return m_xwaylandSurface & & m_xwaylandSurface - > overrideRedirect ;
2024-08-30 14:12:23 +02:00
}
bool CWindow : : isModal ( ) {
2025-04-28 22:25:22 +02:00
return ( m_xwaylandSurface & & m_xwaylandSurface - > modal ) ;
2024-08-30 14:12:23 +02:00
}
2024-11-17 19:31:54 +00:00
Vector2D CWindow : : requestedMinSize ( ) {
2025-05-04 23:39:00 +02:00
if ( ( m_isX11 & & ! m_xwaylandSurface - > sizeHints ) | | ( ! m_isX11 & & ! m_xdgSurface - > m_toplevel ) )
2024-11-17 19:31:54 +00:00
return Vector2D ( 1 , 1 ) ;
2025-05-04 23:39:00 +02:00
Vector2D minSize = m_isX11 ? Vector2D ( m_xwaylandSurface - > sizeHints - > min_width , m_xwaylandSurface - > 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-05-04 23:39:00 +02:00
if ( ( ( m_isX11 & & ! m_xwaylandSurface - > sizeHints ) | | ( ! m_isX11 & & ( ! m_xdgSurface | | ! m_xdgSurface - > m_toplevel ) ) | | m_windowData . noMaxSize . valueOrDefault ( ) ) )
2024-11-17 19:31:54 +00:00
return Vector2D ( NO_MAX_SIZE_LIMIT , NO_MAX_SIZE_LIMIT ) ;
2025-05-04 23:39:00 +02:00
Vector2D maxSize = m_isX11 ? Vector2D ( m_xwaylandSurface - > sizeHints - > max_width , m_xwaylandSurface - > 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-04-28 22:25:22 +02:00
Debug : : log ( TRACE , " sendWindowSize: window:{:x},title:{} with real pos {}, real size {} (force: {}) " , ( 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 )
m_pendingSizeAcks . emplace_back ( m_xdgSurface - > m_toplevel - > setSize ( REPORTSIZE ) , REPORTPOS . 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?
Debug : : log ( INFO , " ContentType for window {} " , ( 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-04-01 18:51:37 -04:00
// we dont want to deactivate unfocused xwayland windows
// 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
}