2022-03-30 21:18:42 +02:00
# include "Window.hpp"
# include "Compositor.hpp"
2022-06-25 20:28:40 +02:00
# include "render/decorations/CHyprDropShadowDecoration.hpp"
2022-03-30 21:18:42 +02:00
2022-04-23 14:16:02 +02:00
CWindow : : CWindow ( ) {
2022-11-04 16:56:31 +01:00
m_vRealPosition . create ( AVARTYPE_VECTOR , g_pConfigManager - > getAnimationPropertyConfig ( " windowsIn " ) , ( void * ) this , AVARDAMAGE_ENTIRE ) ;
2022-07-28 13:28:43 +02:00
m_vRealSize . create ( AVARTYPE_VECTOR , g_pConfigManager - > getAnimationPropertyConfig ( " windowsIn " ) , ( void * ) this , AVARDAMAGE_ENTIRE ) ;
2023-02-01 22:06:01 +01:00
m_fBorderFadeAnimationProgress . create ( AVARTYPE_FLOAT , g_pConfigManager - > getAnimationPropertyConfig ( " border " ) , ( void * ) this , AVARDAMAGE_BORDER ) ;
m_fBorderAngleAnimationProgress . create ( AVARTYPE_FLOAT , g_pConfigManager - > getAnimationPropertyConfig ( " borderangle " ) , ( void * ) this , AVARDAMAGE_BORDER ) ;
2022-07-28 13:28:43 +02:00
m_fAlpha . create ( AVARTYPE_FLOAT , g_pConfigManager - > getAnimationPropertyConfig ( " fadeIn " ) , ( void * ) this , AVARDAMAGE_ENTIRE ) ;
m_fActiveInactiveAlpha . create ( AVARTYPE_FLOAT , g_pConfigManager - > getAnimationPropertyConfig ( " fadeSwitch " ) , ( void * ) this , AVARDAMAGE_ENTIRE ) ;
m_cRealShadowColor . create ( AVARTYPE_COLOR , g_pConfigManager - > getAnimationPropertyConfig ( " fadeShadow " ) , ( void * ) this , AVARDAMAGE_SHADOW ) ;
2022-08-30 12:46:17 +02:00
m_fDimPercent . create ( AVARTYPE_FLOAT , g_pConfigManager - > getAnimationPropertyConfig ( " fadeDim " ) , ( void * ) this , AVARDAMAGE_ENTIRE ) ;
2022-06-25 20:28:40 +02:00
m_dWindowDecorations . emplace_back ( std : : make_unique < CHyprDropShadowDecoration > ( this ) ) ; // put the shadow so it's the first deco (has to be rendered first)
2022-04-23 14:16:02 +02:00
}
2022-03-30 21:18:42 +02:00
CWindow : : ~ CWindow ( ) {
2022-04-02 18:57:09 +02:00
if ( g_pCompositor - > isWindowActive ( this ) ) {
2022-12-16 18:17:31 +01:00
g_pCompositor - > m_pLastFocus = nullptr ;
2022-04-02 18:57:09 +02:00
g_pCompositor - > m_pLastWindow = nullptr ;
}
2022-05-30 14:55:42 +02:00
}
wlr_box CWindow : : getFullWindowBoundingBox ( ) {
2022-12-31 19:23:02 +01:00
static auto * const PBORDERSIZE = & g_pConfigManager - > getConfigValuePtr ( " general:border_size " ) - > intValue ;
if ( m_sAdditionalConfigData . dimAround ) {
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( m_iMonitorID ) ;
return { PMONITOR - > vecPosition . x , PMONITOR - > vecPosition . y , PMONITOR - > vecSize . x , PMONITOR - > vecSize . y } ;
}
2022-05-30 14:55:42 +02:00
2022-08-24 13:44:48 +02:00
SWindowDecorationExtents maxExtents = { { * PBORDERSIZE + 2 , * PBORDERSIZE + 2 } , { * PBORDERSIZE + 2 , * PBORDERSIZE + 2 } } ;
2022-05-30 14:55:42 +02:00
for ( auto & wd : m_dWindowDecorations ) {
const auto EXTENTS = wd - > getWindowDecorationExtents ( ) ;
if ( EXTENTS . topLeft . x > maxExtents . topLeft . x )
maxExtents . topLeft . x = EXTENTS . topLeft . x ;
if ( EXTENTS . topLeft . y > maxExtents . topLeft . y )
maxExtents . topLeft . y = EXTENTS . topLeft . y ;
if ( EXTENTS . bottomRight . x > maxExtents . bottomRight . x )
maxExtents . bottomRight . x = EXTENTS . bottomRight . x ;
if ( EXTENTS . bottomRight . y > maxExtents . bottomRight . y )
maxExtents . bottomRight . y = EXTENTS . bottomRight . y ;
}
2023-06-23 13:54:01 +02:00
if ( m_pWLSurface . exists ( ) & & ! m_bIsX11 ) {
wlr_box surfaceExtents = { 0 , 0 , 0 , 0 } ;
// TODO: this could be better, perhaps make a getFullWindowRegion?
wlr_xdg_surface_for_each_popup_surface (
m_uSurface . xdg ,
[ ] ( wlr_surface * surf , int sx , int sy , void * data ) {
wlr_box * pSurfaceExtents = ( wlr_box * ) data ;
if ( sx < pSurfaceExtents - > x )
pSurfaceExtents - > x = sx ;
if ( sy < pSurfaceExtents - > y )
pSurfaceExtents - > y = sy ;
if ( sx + surf - > current . width > pSurfaceExtents - > width )
pSurfaceExtents - > width = sx + surf - > current . width - pSurfaceExtents - > x ;
if ( sy + surf - > current . height > pSurfaceExtents - > height )
pSurfaceExtents - > height = sy + surf - > current . height - pSurfaceExtents - > y ;
} ,
& surfaceExtents ) ;
if ( - surfaceExtents . x > maxExtents . topLeft . x )
maxExtents . topLeft . x = - surfaceExtents . x ;
if ( - surfaceExtents . y > maxExtents . topLeft . y )
maxExtents . topLeft . y = - surfaceExtents . y ;
if ( surfaceExtents . x + surfaceExtents . width > m_pWLSurface . wlr ( ) - > current . width + maxExtents . bottomRight . x )
maxExtents . bottomRight . x = surfaceExtents . x + surfaceExtents . width - m_pWLSurface . wlr ( ) - > current . width ;
if ( surfaceExtents . y + surfaceExtents . height > m_pWLSurface . wlr ( ) - > current . height + maxExtents . bottomRight . y )
maxExtents . bottomRight . y = surfaceExtents . y + surfaceExtents . height - m_pWLSurface . wlr ( ) - > current . height ;
}
2022-05-30 14:55:42 +02:00
// Add extents to the real base BB and return
2022-12-16 18:17:31 +01:00
wlr_box finalBox = { m_vRealPosition . vec ( ) . x - maxExtents . topLeft . x , m_vRealPosition . vec ( ) . y - maxExtents . topLeft . y ,
m_vRealSize . vec ( ) . x + maxExtents . topLeft . x + maxExtents . bottomRight . x , m_vRealSize . vec ( ) . 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
}
wlr_box CWindow : : getWindowIdealBoundingBoxIgnoreReserved ( ) {
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( m_iMonitorID ) ;
2022-12-16 18:17:31 +01:00
auto POS = m_vPosition ;
auto SIZE = m_vSize ;
2022-06-23 20:39:48 +02:00
2022-11-22 00:33:23 +01:00
if ( m_bIsFullscreen ) {
2022-12-16 18:17:31 +01:00
POS = PMONITOR - > vecPosition ;
2022-11-22 00:33:23 +01:00
SIZE = PMONITOR - > vecSize ;
return wlr_box { ( int ) POS . x , ( int ) POS . y , ( int ) SIZE . x , ( int ) SIZE . y } ;
}
2022-06-23 20:39:48 +02:00
if ( DELTALESSTHAN ( POS . y - PMONITOR - > vecPosition . y , PMONITOR - > vecReservedTopLeft . y , 1 ) ) {
POS . y = PMONITOR - > vecPosition . y ;
SIZE . y + = PMONITOR - > vecReservedTopLeft . y ;
}
if ( DELTALESSTHAN ( POS . x - PMONITOR - > vecPosition . x , PMONITOR - > vecReservedTopLeft . x , 1 ) ) {
POS . x = PMONITOR - > vecPosition . x ;
SIZE . x + = PMONITOR - > vecReservedTopLeft . x ;
}
if ( DELTALESSTHAN ( POS . x + SIZE . x - PMONITOR - > vecPosition . x , PMONITOR - > vecSize . x - PMONITOR - > vecReservedBottomRight . x , 1 ) ) {
SIZE . x + = PMONITOR - > vecReservedBottomRight . x ;
}
if ( DELTALESSTHAN ( POS . y + SIZE . y - PMONITOR - > vecPosition . y , PMONITOR - > vecSize . y - PMONITOR - > vecReservedBottomRight . y , 1 ) ) {
SIZE . y + = PMONITOR - > vecReservedBottomRight . y ;
}
return wlr_box { ( int ) POS . x , ( int ) POS . y , ( int ) SIZE . x , ( int ) SIZE . y } ;
2022-06-27 00:25:37 +02:00
}
2023-02-28 23:32:42 +01:00
wlr_box CWindow : : getWindowInputBox ( ) {
static auto * const PBORDERSIZE = & g_pConfigManager - > getConfigValuePtr ( " general:border_size " ) - > intValue ;
if ( m_sAdditionalConfigData . dimAround ) {
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( m_iMonitorID ) ;
return { PMONITOR - > vecPosition . x , PMONITOR - > vecPosition . y , PMONITOR - > vecSize . x , PMONITOR - > vecSize . y } ;
}
SWindowDecorationExtents maxExtents = { { * PBORDERSIZE + 2 , * PBORDERSIZE + 2 } , { * PBORDERSIZE + 2 , * PBORDERSIZE + 2 } } ;
for ( auto & wd : m_dWindowDecorations ) {
if ( ! wd - > allowsInput ( ) )
continue ;
const auto EXTENTS = wd - > getWindowDecorationExtents ( ) ;
if ( EXTENTS . topLeft . x > maxExtents . topLeft . x )
maxExtents . topLeft . x = EXTENTS . topLeft . x ;
if ( EXTENTS . topLeft . y > maxExtents . topLeft . y )
maxExtents . topLeft . y = EXTENTS . topLeft . y ;
if ( EXTENTS . bottomRight . x > maxExtents . bottomRight . x )
maxExtents . bottomRight . x = EXTENTS . bottomRight . x ;
if ( EXTENTS . bottomRight . y > maxExtents . bottomRight . y )
maxExtents . bottomRight . y = EXTENTS . bottomRight . y ;
}
// Add extents to the real base BB and return
wlr_box finalBox = { m_vRealPosition . vec ( ) . x - maxExtents . topLeft . x , m_vRealPosition . vec ( ) . y - maxExtents . topLeft . y ,
m_vRealSize . vec ( ) . x + maxExtents . topLeft . x + maxExtents . bottomRight . x , m_vRealSize . vec ( ) . y + maxExtents . topLeft . y + maxExtents . bottomRight . y } ;
return finalBox ;
}
2023-02-28 20:36:36 +01:00
SWindowDecorationExtents CWindow : : getFullWindowReservedArea ( ) {
SWindowDecorationExtents extents ;
for ( auto & wd : m_dWindowDecorations ) {
const auto RESERVED = wd - > getWindowDecorationReservedArea ( ) ;
if ( RESERVED . bottomRight = = Vector2D { } & & RESERVED . topLeft = = Vector2D { } )
continue ;
extents . topLeft = extents . topLeft + RESERVED . topLeft ;
extents . bottomRight = extents . bottomRight + RESERVED . bottomRight ;
}
return extents ;
}
2022-06-27 00:25:37 +02:00
void CWindow : : updateWindowDecos ( ) {
for ( auto & wd : m_dWindowDecorations )
wd - > updateWindow ( this ) ;
2022-07-05 17:31:47 +02:00
2023-06-05 09:49:17 +02:00
bool recalc = false ;
2022-07-05 17:31:47 +02:00
for ( auto & wd : m_vDecosToRemove ) {
for ( auto it = m_dWindowDecorations . begin ( ) ; it ! = m_dWindowDecorations . end ( ) ; it + + ) {
if ( it - > get ( ) = = wd ) {
2023-06-05 09:49:17 +02:00
it = m_dWindowDecorations . erase ( it ) ;
recalc = true ;
2022-07-05 17:31:47 +02:00
if ( it = = m_dWindowDecorations . end ( ) )
break ;
}
}
}
2023-06-05 09:49:17 +02:00
if ( recalc )
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateWindow ( this ) ;
2022-07-05 17:31:47 +02:00
m_vDecosToRemove . clear ( ) ;
2022-06-27 13:42:20 +02:00
}
pid_t CWindow : : getPID ( ) {
pid_t PID = - 1 ;
if ( ! m_bIsX11 ) {
2023-03-03 12:17:43 +01:00
if ( ! m_bIsMapped )
return - 1 ;
2022-09-21 16:10:57 +02:00
wl_client_get_credentials ( wl_resource_get_client ( m_uSurface . xdg - > resource ) , & PID , nullptr , nullptr ) ;
2022-06-27 13:42:20 +02:00
} else {
PID = m_uSurface . xwayland - > pid ;
}
return PID ;
}
2022-07-16 12:44:45 +02:00
IHyprWindowDecoration * CWindow : : getDecorationByType ( eDecorationType type ) {
for ( auto & wd : m_dWindowDecorations ) {
if ( wd - > getDecorationType ( ) = = type )
return wd . get ( ) ;
}
return nullptr ;
2022-08-06 20:57:38 +02:00
}
void CWindow : : createToplevelHandle ( ) {
if ( m_bIsX11 & & ( m_bX11DoesntWantBorders | | m_iX11Type = = 2 ) )
return ; // don't create a toplevel
m_phForeignToplevel = wlr_foreign_toplevel_handle_v1_create ( g_pCompositor - > m_sWLRToplevelMgr ) ;
2022-09-25 20:07:48 +02:00
2022-08-06 20:57:38 +02:00
wlr_foreign_toplevel_handle_v1_set_app_id ( m_phForeignToplevel , g_pXWaylandManager - > getAppIDClass ( this ) . c_str ( ) ) ;
wlr_foreign_toplevel_handle_v1_output_enter ( m_phForeignToplevel , g_pCompositor - > getMonitorFromID ( m_iMonitorID ) - > output ) ;
wlr_foreign_toplevel_handle_v1_set_title ( m_phForeignToplevel , m_szTitle . c_str ( ) ) ;
wlr_foreign_toplevel_handle_v1_set_maximized ( m_phForeignToplevel , false ) ;
wlr_foreign_toplevel_handle_v1_set_minimized ( m_phForeignToplevel , false ) ;
wlr_foreign_toplevel_handle_v1_set_fullscreen ( m_phForeignToplevel , false ) ;
// handle events
2022-12-16 18:17:31 +01:00
hyprListener_toplevelActivate . initCallback (
2023-07-19 12:39:45 +02:00
& m_phForeignToplevel - > events . request_activate , [ & ] ( void * owner , void * data ) { g_pLayoutManager - > getCurrentLayout ( ) - > requestFocusForWindow ( this ) ; } , this , " Toplevel " ) ;
2022-12-16 18:17:31 +01:00
hyprListener_toplevelFullscreen . initCallback (
& m_phForeignToplevel - > events . request_fullscreen ,
[ & ] ( void * owner , void * data ) {
const auto EV = ( wlr_foreign_toplevel_handle_v1_fullscreen_event * ) data ;
g_pCompositor - > setWindowFullscreen ( this , EV - > fullscreen , FULLSCREEN_FULL ) ;
} ,
this , " Toplevel " ) ;
hyprListener_toplevelClose . initCallback (
2022-12-20 03:18:47 +01:00
& m_phForeignToplevel - > events . request_close , [ & ] ( void * owner , void * data ) { g_pCompositor - > closeWindow ( this ) ; } , this , " Toplevel " ) ;
2022-08-06 20:57:38 +02:00
m_iLastToplevelMonitorID = m_iMonitorID ;
}
void CWindow : : destroyToplevelHandle ( ) {
2022-08-06 21:10:37 +02:00
if ( ! m_phForeignToplevel )
return ;
2022-08-06 20:57:38 +02:00
hyprListener_toplevelActivate . removeCallback ( ) ;
hyprListener_toplevelClose . removeCallback ( ) ;
hyprListener_toplevelFullscreen . removeCallback ( ) ;
wlr_foreign_toplevel_handle_v1_destroy ( m_phForeignToplevel ) ;
m_phForeignToplevel = nullptr ;
}
void CWindow : : updateToplevel ( ) {
2022-08-08 21:20:41 +02:00
updateSurfaceOutputs ( ) ;
2022-08-06 21:10:37 +02:00
if ( ! m_phForeignToplevel )
return ;
2022-08-06 20:57:38 +02:00
wlr_foreign_toplevel_handle_v1_set_title ( m_phForeignToplevel , m_szTitle . c_str ( ) ) ;
wlr_foreign_toplevel_handle_v1_set_fullscreen ( m_phForeignToplevel , m_bIsFullscreen ) ;
if ( m_iLastToplevelMonitorID ! = m_iMonitorID ) {
2022-08-10 08:51:59 +02:00
if ( const auto PMONITOR = g_pCompositor - > getMonitorFromID ( m_iLastToplevelMonitorID ) ; PMONITOR & & PMONITOR - > m_bEnabled )
wlr_foreign_toplevel_handle_v1_output_leave ( m_phForeignToplevel , PMONITOR - > output ) ;
2022-08-06 20:57:38 +02:00
wlr_foreign_toplevel_handle_v1_output_enter ( m_phForeignToplevel , g_pCompositor - > getMonitorFromID ( m_iMonitorID ) - > output ) ;
m_iLastToplevelMonitorID = m_iMonitorID ;
}
2022-08-08 21:20:41 +02:00
}
void sendEnterIter ( wlr_surface * pSurface , int x , int y , void * data ) {
const auto OUTPUT = ( wlr_output * ) data ;
wlr_surface_send_enter ( pSurface , OUTPUT ) ;
}
void sendLeaveIter ( wlr_surface * pSurface , int x , int y , void * data ) {
const auto OUTPUT = ( wlr_output * ) data ;
wlr_surface_send_leave ( pSurface , OUTPUT ) ;
}
void CWindow : : updateSurfaceOutputs ( ) {
2022-08-10 08:51:59 +02:00
if ( m_iLastSurfaceMonitorID = = m_iMonitorID | | ! m_bIsMapped | | m_bHidden | | ! m_bMappedX11 )
2022-08-08 21:20:41 +02:00
return ;
const auto PLASTMONITOR = g_pCompositor - > getMonitorFromID ( m_iLastSurfaceMonitorID ) ;
m_iLastSurfaceMonitorID = m_iMonitorID ;
const auto PNEWMONITOR = g_pCompositor - > getMonitorFromID ( m_iMonitorID ) ;
2022-08-10 08:51:59 +02:00
if ( PLASTMONITOR & & PLASTMONITOR - > m_bEnabled )
2023-03-20 16:00:58 +01:00
wlr_surface_for_each_surface ( m_pWLSurface . wlr ( ) , sendLeaveIter , PLASTMONITOR - > output ) ;
2022-08-08 21:20:41 +02:00
2023-03-20 16:00:58 +01:00
wlr_surface_for_each_surface ( m_pWLSurface . wlr ( ) , sendEnterIter , PNEWMONITOR - > output ) ;
2023-06-06 09:48:07 +02:00
wlr_surface_for_each_surface (
m_pWLSurface . wlr ( ) ,
[ ] ( wlr_surface * surf , int x , int y , void * data ) {
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( ( ( CWindow * ) data ) - > m_iMonitorID ) ;
g_pProtocolManager - > m_pFractionalScaleProtocolManager - > setPreferredScaleForSurface ( surf , PMONITOR ? PMONITOR - > scale : 1.f ) ;
} ,
this ) ;
2022-08-21 17:01:26 +02:00
}
void CWindow : : moveToWorkspace ( int workspaceID ) {
2023-03-18 17:30:29 +01:00
if ( m_iWorkspaceID = = workspaceID )
return ;
2022-08-21 17:01:26 +02:00
2023-03-18 17:30:29 +01:00
m_iWorkspaceID = workspaceID ;
2023-01-20 19:44:30 +01:00
2023-03-18 17:30:29 +01:00
const auto PWORKSPACE = g_pCompositor - > getWorkspaceByID ( m_iWorkspaceID ) ;
if ( PWORKSPACE ) {
2023-04-17 18:35:28 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " movewindow " , getFormat ( " %lx,%s " , this , PWORKSPACE - > m_szName . c_str ( ) ) } ) ;
2023-03-18 17:30:29 +01:00
EMIT_HOOK_EVENT ( " moveWindow " , ( std : : vector < void * > { this , PWORKSPACE } ) ) ;
2022-08-21 17:01:26 +02:00
}
2023-03-18 17:30:29 +01:00
2023-04-02 11:24:17 +02:00
if ( m_pSwallowed ) {
m_pSwallowed - > moveToWorkspace ( workspaceID ) ;
m_pSwallowed - > m_iMonitorID = m_iMonitorID ;
}
2022-08-28 19:47:06 +02:00
}
CWindow * CWindow : : X11TransientFor ( ) {
if ( ! m_bIsX11 )
return nullptr ;
if ( ! m_uSurface . xwayland - > parent )
return nullptr ;
auto PPARENT = g_pCompositor - > getWindowFromSurface ( m_uSurface . xwayland - > parent - > surface ) ;
2022-09-01 10:15:55 +02:00
while ( g_pCompositor - > windowValidMapped ( PPARENT ) & & PPARENT - > m_uSurface . xwayland - > parent ) {
2022-08-28 19:47:06 +02:00
PPARENT = g_pCompositor - > getWindowFromSurface ( PPARENT - > m_uSurface . xwayland - > parent - > surface ) ;
}
2022-09-01 10:16:23 +02:00
if ( ! g_pCompositor - > windowValidMapped ( PPARENT ) )
return nullptr ;
2022-08-28 19:47:06 +02:00
return PPARENT ;
}
2022-08-29 19:52:35 +02:00
void CWindow : : removeDecorationByType ( eDecorationType type ) {
for ( auto & wd : m_dWindowDecorations ) {
if ( wd - > getDecorationType ( ) = = type )
m_vDecosToRemove . push_back ( wd . get ( ) ) ;
}
updateWindowDecos ( ) ;
}
2022-10-14 21:46:32 +02:00
2022-11-04 16:56:31 +01:00
void unregisterVar ( void * ptr ) {
( ( CAnimatedVariable * ) ptr ) - > unregister ( ) ;
}
2022-10-14 21:46:32 +02:00
void CWindow : : onUnmap ( ) {
if ( g_pCompositor - > m_pLastWindow = = this )
g_pCompositor - > m_pLastWindow = nullptr ;
2022-11-04 16:56:31 +01:00
m_vRealPosition . setCallbackOnEnd ( unregisterVar ) ;
m_vRealSize . setCallbackOnEnd ( unregisterVar ) ;
2023-02-01 22:06:01 +01:00
m_fBorderFadeAnimationProgress . setCallbackOnEnd ( unregisterVar ) ;
m_fBorderAngleAnimationProgress . setCallbackOnEnd ( unregisterVar ) ;
2022-11-04 16:56:31 +01:00
m_fActiveInactiveAlpha . setCallbackOnEnd ( unregisterVar ) ;
m_fAlpha . setCallbackOnEnd ( unregisterVar ) ;
m_cRealShadowColor . setCallbackOnEnd ( unregisterVar ) ;
m_fDimPercent . setCallbackOnEnd ( unregisterVar ) ;
2022-11-06 18:52:09 +01:00
m_vRealSize . setCallbackOnBegin ( nullptr ) ;
2023-01-20 19:15:15 +01:00
std : : erase_if ( g_pCompositor - > m_vWindowFocusHistory , [ & ] ( const auto & other ) { return other = = this ; } ) ;
2023-03-23 01:39:32 +01:00
m_pWLSurface . unassign ( ) ;
2023-03-28 21:17:47 +02:00
hyprListener_unmapWindow . removeCallback ( ) ;
2022-11-04 16:56:31 +01:00
}
void CWindow : : onMap ( ) {
2022-11-18 14:53:54 +01:00
2023-03-20 16:00:58 +01:00
m_pWLSurface . assign ( g_pXWaylandManager - > getWindowSurface ( this ) ) ;
2022-11-18 14:53:54 +01: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)
m_vRealPosition . resetAllCallbacks ( ) ;
m_vRealSize . resetAllCallbacks ( ) ;
2023-02-01 22:06:01 +01:00
m_fBorderFadeAnimationProgress . resetAllCallbacks ( ) ;
m_fBorderAngleAnimationProgress . resetAllCallbacks ( ) ;
2022-11-18 14:53:54 +01:00
m_fActiveInactiveAlpha . resetAllCallbacks ( ) ;
m_fAlpha . resetAllCallbacks ( ) ;
m_cRealShadowColor . resetAllCallbacks ( ) ;
m_fDimPercent . resetAllCallbacks ( ) ;
2022-11-04 16:56:31 +01:00
m_vRealPosition . registerVar ( ) ;
m_vRealSize . registerVar ( ) ;
2023-02-01 22:06:01 +01:00
m_fBorderFadeAnimationProgress . registerVar ( ) ;
m_fBorderAngleAnimationProgress . registerVar ( ) ;
2022-11-04 16:56:31 +01:00
m_fActiveInactiveAlpha . registerVar ( ) ;
m_fAlpha . registerVar ( ) ;
m_cRealShadowColor . registerVar ( ) ;
m_fDimPercent . registerVar ( ) ;
2022-11-06 18:52:09 +01:00
2023-02-01 22:06:01 +01:00
m_fBorderAngleAnimationProgress . setCallbackOnEnd ( [ & ] ( void * ptr ) { onBorderAngleAnimEnd ( ptr ) ; } , false ) ;
m_fBorderAngleAnimationProgress . setValueAndWarp ( 0.f ) ;
m_fBorderAngleAnimationProgress = 1.f ;
2023-01-20 19:15:15 +01:00
g_pCompositor - > m_vWindowFocusHistory . push_back ( this ) ;
2023-03-28 21:17:47 +02:00
2023-06-03 12:20:23 +02:00
hyprListener_unmapWindow . initCallback ( m_bIsX11 ? & m_uSurface . xwayland - > surface - > events . unmap : & m_uSurface . xdg - > surface - > events . unmap , & Events : : listener_unmapWindow , this ,
" CWindow " ) ;
2022-10-14 21:46:32 +02:00
}
2023-02-01 22:06:01 +01:00
void CWindow : : onBorderAngleAnimEnd ( void * ptr ) {
const auto PANIMVAR = ( CAnimatedVariable * ) ptr ;
const std : : string STYLE = PANIMVAR - > getConfig ( ) - > pValues - > internalStyle ;
2023-02-14 18:10:17 +01:00
if ( STYLE ! = " loop " | | ! PANIMVAR - > getConfig ( ) - > pValues - > internalEnabled )
2023-02-01 22:06:01 +01:00
return ;
PANIMVAR - > setCallbackOnEnd ( nullptr ) ; // we remove the callback here because otherwise setvalueandwarp will recurse this
PANIMVAR - > setValueAndWarp ( 0 ) ;
* PANIMVAR = 1.f ;
PANIMVAR - > setCallbackOnEnd ( [ & ] ( void * ptr ) { onBorderAngleAnimEnd ( ptr ) ; } , false ) ;
}
2022-10-14 21:46:32 +02:00
void CWindow : : setHidden ( bool hidden ) {
m_bHidden = hidden ;
2022-11-05 14:37:57 +01:00
if ( hidden & & g_pCompositor - > m_pLastWindow = = this ) {
g_pCompositor - > m_pLastWindow = nullptr ;
2022-10-14 21:46:32 +02:00
}
}
bool CWindow : : isHidden ( ) {
return m_bHidden ;
2022-11-15 11:21:26 +01:00
}
void CWindow : : applyDynamicRule ( const SWindowRule & r ) {
if ( r . szRule = = " noblur " ) {
m_sAdditionalConfigData . forceNoBlur = true ;
} else if ( r . szRule = = " noborder " ) {
m_sAdditionalConfigData . forceNoBorder = true ;
} else if ( r . szRule = = " noshadow " ) {
m_sAdditionalConfigData . forceNoShadow = true ;
2023-05-31 21:11:20 +02:00
} else if ( r . szRule = = " nodim " ) {
m_sAdditionalConfigData . forceNoDim = true ;
2023-03-26 03:00:24 +02:00
} else if ( r . szRule = = " forcergbx " ) {
m_sAdditionalConfigData . forceRGBX = true ;
2022-11-15 11:21:26 +01:00
} else if ( r . szRule = = " opaque " ) {
2023-03-30 00:44:25 +02:00
if ( ! m_sAdditionalConfigData . forceOpaqueOverridden )
2022-11-23 10:55:46 +01:00
m_sAdditionalConfigData . forceOpaque = true ;
2022-11-15 11:21:26 +01:00
} else if ( r . szRule . find ( " rounding " ) = = 0 ) {
try {
m_sAdditionalConfigData . rounding = std : : stoi ( r . szRule . substr ( r . szRule . find_first_of ( ' ' ) + 1 ) ) ;
2022-12-16 18:17:31 +01:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Rounding rule \" %s \" failed with: %s " , r . szRule . c_str ( ) , e . what ( ) ) ; }
2023-07-18 00:11:29 +02:00
} else if ( r . szRule . find ( " bordersize " ) = = 0 ) {
try {
m_sAdditionalConfigData . borderSize = std : : stoi ( r . szRule . substr ( r . szRule . find_first_of ( ' ' ) + 1 ) ) ;
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Bordersize rule \" %s \" failed with: %s " , r . szRule . c_str ( ) , e . what ( ) ) ; }
2022-11-15 11:21:26 +01:00
} else if ( r . szRule . find ( " opacity " ) = = 0 ) {
try {
2022-12-11 18:15:02 +01:00
CVarList vars ( r . szRule , 0 , ' ' ) ;
for ( size_t i = 1 /* first item is "opacity" */ ; i < vars . size ( ) ; + + i ) {
if ( i = = 1 ) {
// first arg, alpha
m_sSpecialRenderData . alpha = std : : stof ( vars [ i ] ) ;
} else {
if ( vars [ i ] = = " override " ) {
if ( i = = 2 ) {
m_sSpecialRenderData . alphaOverride = true ;
} else {
m_sSpecialRenderData . alphaInactiveOverride = true ;
}
} else {
m_sSpecialRenderData . alphaInactive = std : : stof ( vars [ i ] ) ;
}
}
2022-11-15 11:21:26 +01:00
}
2022-12-16 18:17:31 +01:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Opacity rule \" %s \" failed with: %s " , r . szRule . c_str ( ) , e . what ( ) ) ; }
} else if ( r . szRule = = " noanim " ) {
m_sAdditionalConfigData . forceNoAnims = true ;
} else if ( r . szRule . find ( " animation " ) = = 0 ) {
auto STYLE = r . szRule . substr ( r . szRule . find_first_of ( ' ' ) + 1 ) ;
m_sAdditionalConfigData . animationStyle = STYLE ;
} else if ( r . szRule . find ( " bordercolor " ) = = 0 ) {
2022-11-15 11:21:26 +01:00
try {
std : : string colorPart = removeBeginEndSpacesTabs ( r . szRule . substr ( r . szRule . find_first_of ( ' ' ) + 1 ) ) ;
if ( colorPart . contains ( ' ' ) ) {
// we have a space, 2 values
2022-12-16 18:17:31 +01:00
m_sSpecialRenderData . activeBorderColor = configStringToInt ( colorPart . substr ( 0 , colorPart . find_first_of ( ' ' ) ) ) ;
2022-11-15 11:21:26 +01:00
m_sSpecialRenderData . inactiveBorderColor = configStringToInt ( colorPart . substr ( colorPart . find_first_of ( ' ' ) + 1 ) ) ;
} else {
m_sSpecialRenderData . activeBorderColor = configStringToInt ( colorPart ) ;
}
2022-12-16 18:17:31 +01:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " BorderColor rule \" %s \" failed with: %s " , r . szRule . c_str ( ) , e . what ( ) ) ; }
2022-12-28 15:39:17 +01:00
} else if ( r . szRule = = " dimaround " ) {
m_sAdditionalConfigData . dimAround = true ;
2022-11-15 11:21:26 +01:00
}
}
void CWindow : : updateDynamicRules ( ) {
2022-12-16 18:17:31 +01:00
m_sSpecialRenderData . activeBorderColor = - 1 ;
2022-11-15 11:21:26 +01:00
m_sSpecialRenderData . inactiveBorderColor = - 1 ;
2022-12-16 18:17:31 +01:00
m_sSpecialRenderData . alpha = 1.f ;
m_sSpecialRenderData . alphaInactive = - 1.f ;
m_sAdditionalConfigData . forceNoBlur = false ;
m_sAdditionalConfigData . forceNoBorder = false ;
m_sAdditionalConfigData . forceNoShadow = false ;
2023-05-31 21:11:20 +02:00
m_sAdditionalConfigData . forceNoDim = false ;
2023-03-30 00:44:25 +02:00
if ( ! m_sAdditionalConfigData . forceOpaqueOverridden )
2022-11-23 10:55:46 +01:00
m_sAdditionalConfigData . forceOpaque = false ;
2022-12-16 18:17:31 +01:00
m_sAdditionalConfigData . forceNoAnims = false ;
2023-01-24 20:05:34 +01:00
m_sAdditionalConfigData . animationStyle = std : : string ( " " ) ;
2022-12-16 18:17:31 +01:00
m_sAdditionalConfigData . rounding = - 1 ;
2022-12-28 15:39:17 +01:00
m_sAdditionalConfigData . dimAround = false ;
2023-03-26 03:00:24 +02:00
m_sAdditionalConfigData . forceRGBX = false ;
2023-07-18 00:11:29 +02:00
m_sAdditionalConfigData . borderSize = - 1 ;
2022-11-15 11:21:26 +01:00
const auto WINDOWRULES = g_pConfigManager - > getMatchingRules ( this ) ;
for ( auto & r : WINDOWRULES ) {
applyDynamicRule ( r ) ;
}
2023-07-18 00:11:43 +02:00
2023-07-18 11:49:57 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( m_iMonitorID ) ;
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 ) {
static auto * const ROUNDING = & g_pConfigManager - > getConfigValuePtr ( " decoration:rounding " ) - > intValue ;
static auto * const BORDERSIZE = & g_pConfigManager - > getConfigValuePtr ( " general:border_size " ) - > intValue ;
if ( BORDERSIZE > = ROUNDING | | ROUNDING = = 0 )
return false ;
// (x0, y0), (x0, y1), ... are the center point of rounding at each corner
double x0 = m_vRealPosition . vec ( ) . x + * ROUNDING ;
double y0 = m_vRealPosition . vec ( ) . y + * ROUNDING ;
double x1 = m_vRealPosition . vec ( ) . x + m_vRealSize . vec ( ) . x - * ROUNDING ;
double y1 = m_vRealPosition . vec ( ) . y + m_vRealSize . vec ( ) . y - * ROUNDING ;
if ( x < x0 & & y < y0 ) {
return Vector2D { x0 , y0 } . distance ( Vector2D { x , y } ) > ( double ) * ROUNDING ;
}
if ( x > x1 & & y < y0 ) {
return Vector2D { x1 , y0 } . distance ( Vector2D { x , y } ) > ( double ) * ROUNDING ;
}
if ( x < x0 & & y > y1 ) {
return Vector2D { x0 , y1 } . distance ( Vector2D { x , y } ) > ( double ) * ROUNDING ;
}
if ( x > x1 & & y > y1 ) {
return Vector2D { x1 , y1 } . distance ( Vector2D { x , y } ) > ( double ) * ROUNDING ;
}
return false ;
}
void findExtensionForVector2D ( wlr_surface * surface , int x , int y , void * data ) {
const auto DATA = ( SExtensionFindingData * ) data ;
wlr_box box = { DATA - > origin . x + x , DATA - > origin . y + y , surface - > current . width , surface - > current . height } ;
if ( wlr_box_contains_point ( & box , DATA - > vec . x , DATA - > vec . y ) )
* DATA - > found = surface ;
}
// checks if the wayland window has a popup at pos
bool CWindow : : hasPopupAt ( const Vector2D & pos ) {
if ( m_bIsX11 )
return false ;
wlr_surface * resultSurf = nullptr ;
Vector2D origin = m_vRealPosition . vec ( ) ;
SExtensionFindingData data = { origin , pos , & resultSurf } ;
wlr_xdg_surface_for_each_popup_surface ( m_uSurface . xdg , findExtensionForVector2D , & data ) ;
return resultSurf ;
}
2023-02-19 22:07:32 +01:00
CWindow * CWindow : : getGroupHead ( ) {
CWindow * curr = this ;
while ( ! curr - > m_sGroupData . head )
curr = curr - > m_sGroupData . pNextWindow ;
return curr ;
}
CWindow * CWindow : : getGroupTail ( ) {
CWindow * curr = this ;
while ( ! curr - > m_sGroupData . pNextWindow - > m_sGroupData . head )
curr = curr - > m_sGroupData . pNextWindow ;
return curr ;
}
CWindow * CWindow : : getGroupCurrent ( ) {
CWindow * curr = this ;
while ( curr - > isHidden ( ) )
curr = curr - > m_sGroupData . pNextWindow ;
return curr ;
}
void CWindow : : setGroupCurrent ( CWindow * pWindow ) {
CWindow * curr = this - > m_sGroupData . pNextWindow ;
bool isMember = false ;
while ( curr ! = this ) {
if ( curr = = pWindow ) {
isMember = true ;
break ;
}
curr = curr - > m_sGroupData . pNextWindow ;
}
if ( ! isMember & & pWindow ! = this )
return ;
2023-03-10 16:19:02 +01:00
const auto PCURRENT = getGroupCurrent ( ) ;
const bool FULLSCREEN = PCURRENT - > m_bIsFullscreen ;
const auto WORKSPACE = g_pCompositor - > getWorkspaceByID ( PCURRENT - > m_iWorkspaceID ) ;
2023-02-19 22:07:32 +01:00
const auto PWINDOWSIZE = PCURRENT - > m_vRealSize . goalv ( ) ;
const auto PWINDOWPOS = PCURRENT - > m_vRealPosition . goalv ( ) ;
const auto CURRENTISFOCUS = PCURRENT = = g_pCompositor - > m_pLastWindow ;
2023-03-10 16:19:02 +01:00
if ( FULLSCREEN )
g_pCompositor - > setWindowFullscreen ( PCURRENT , false , WORKSPACE - > m_efFullscreenMode ) ;
2023-02-19 22:07:32 +01:00
PCURRENT - > setHidden ( true ) ;
pWindow - > setHidden ( false ) ;
g_pLayoutManager - > getCurrentLayout ( ) - > replaceWindowDataWith ( PCURRENT , pWindow ) ;
if ( PCURRENT - > m_bIsFloating ) {
pWindow - > m_vRealPosition . setValueAndWarp ( PWINDOWPOS ) ;
pWindow - > m_vRealSize . setValueAndWarp ( PWINDOWSIZE ) ;
}
g_pCompositor - > updateAllWindowsAnimatedDecorationValues ( ) ;
if ( CURRENTISFOCUS )
g_pCompositor - > focusWindow ( pWindow ) ;
2023-03-10 16:19:02 +01:00
if ( FULLSCREEN )
g_pCompositor - > setWindowFullscreen ( pWindow , true , WORKSPACE - > m_efFullscreenMode ) ;
2023-06-14 19:44:51 +02:00
g_pHyprRenderer - > damageWindow ( pWindow ) ;
2023-02-19 22:07:32 +01:00
}
void CWindow : : insertWindowToGroup ( CWindow * pWindow ) {
const auto PHEAD = getGroupHead ( ) ;
const auto PTAIL = getGroupTail ( ) ;
2023-02-19 23:19:40 +01:00
if ( pWindow - > m_sGroupData . pNextWindow ) {
2023-07-03 12:49:56 +02:00
const auto PHEAD = pWindow - > getGroupHead ( ) ;
2023-02-19 23:19:40 +01:00
std : : vector < CWindow * > members ;
2023-07-03 12:49:56 +02:00
CWindow * curr = PHEAD ;
2023-02-19 23:19:40 +01:00
do {
const auto PLAST = curr ;
members . push_back ( curr ) ;
curr = curr - > m_sGroupData . pNextWindow ;
PLAST - > m_sGroupData . pNextWindow = nullptr ;
PLAST - > m_sGroupData . head = false ;
2023-06-09 23:44:18 +02:00
PLAST - > m_sGroupData . locked = false ;
2023-07-03 12:49:56 +02:00
} while ( curr ! = PHEAD ) ;
2023-02-19 23:19:40 +01:00
for ( auto & w : members ) {
insertWindowToGroup ( w ) ;
}
return ;
}
2023-02-19 22:07:32 +01:00
PTAIL - > m_sGroupData . pNextWindow = pWindow ;
pWindow - > m_sGroupData . pNextWindow = PHEAD ;
2023-03-18 17:30:29 +01:00
}
2023-07-13 17:55:20 +02:00
CWindow * CWindow : : getGroupPrevious ( ) {
CWindow * curr = m_sGroupData . pNextWindow ;
while ( curr ! = this & & curr - > m_sGroupData . pNextWindow ! = this )
curr = curr - > m_sGroupData . pNextWindow ;
return curr ;
}
void CWindow : : switchWithWindowInGroup ( CWindow * pWindow ) {
if ( ! m_sGroupData . pNextWindow | | ! pWindow - > m_sGroupData . pNextWindow )
return ;
// TODO: probably can be done more easily but I let C++ do the algorithm stuff for us
std : : vector < CWindow * > group ;
group . push_back ( this ) ;
CWindow * curr = this - > m_sGroupData . pNextWindow ;
while ( curr ! = this ) {
group . push_back ( curr ) ;
curr = curr - > m_sGroupData . pNextWindow ;
}
auto it1 = std : : find ( group . begin ( ) , group . end ( ) , this ) ;
auto it2 = std : : find ( group . begin ( ) , group . end ( ) , pWindow ) ;
std : : iter_swap ( it1 , it2 ) ;
for ( auto it = group . begin ( ) ; it ! = group . end ( ) ; + + it ) {
if ( std : : next ( it ) = = group . end ( ) ) {
( * it ) - > m_sGroupData . pNextWindow = * group . begin ( ) ;
} else {
( * it ) - > m_sGroupData . pNextWindow = * std : : next ( it ) ;
}
}
std : : swap ( m_sGroupData . head , pWindow - > m_sGroupData . head ) ;
}
2023-03-18 17:30:29 +01:00
void CWindow : : updateGroupOutputs ( ) {
if ( ! m_sGroupData . pNextWindow )
return ;
CWindow * curr = m_sGroupData . pNextWindow ;
while ( curr ! = this ) {
curr - > m_iMonitorID = m_iMonitorID ;
curr - > moveToWorkspace ( m_iWorkspaceID ) ;
curr - > m_vRealPosition = m_vRealPosition . goalv ( ) ;
curr - > m_vRealSize = m_vRealSize . goalv ( ) ;
curr = curr - > m_sGroupData . pNextWindow ;
}
2023-04-14 16:03:53 +02:00
}
Vector2D CWindow : : middle ( ) {
return m_vRealPosition . goalv ( ) + m_vRealSize . goalv ( ) / 2.f ;
}
2023-04-22 13:36:50 +02:00
bool CWindow : : opaque ( ) {
if ( m_bIsX11 )
return ! m_uSurface . xwayland - > has_alpha ;
if ( m_uSurface . xdg - > surface - > opaque )
return true ;
const auto EXTENTS = pixman_region32_extents ( & m_uSurface . xdg - > surface - > opaque_region ) ;
2023-05-26 13:44:59 +02:00
if ( EXTENTS - > x2 - EXTENTS - > x1 > = m_uSurface . xdg - > surface - > current . buffer_width & & EXTENTS - > y2 - EXTENTS - > y1 > = m_uSurface . xdg - > surface - > current . buffer_height )
2023-04-22 13:36:50 +02:00
return true ;
return false ;
}