2024-04-30 02:41:27 +01:00
# include "LayerSurface.hpp"
# include "../Compositor.hpp"
# include "../events/Events.hpp"
2024-05-09 21:47:21 +01:00
# include "../protocols/LayerShell.hpp"
2024-06-08 10:07:59 +02:00
# include "../protocols/core/Compositor.hpp"
2024-05-10 18:27:57 +01:00
# include "../managers/SeatManager.hpp"
2025-01-07 17:55:14 +00:00
# include "../managers/AnimationManager.hpp"
2025-01-17 15:21:35 +00:00
# include "../render/Renderer.hpp"
# include "../config/ConfigManager.hpp"
# include "../helpers/Monitor.hpp"
# include "../managers/input/InputManager.hpp"
# include "../managers/HookSystemManager.hpp"
# include "../managers/EventManager.hpp"
2024-04-30 02:41:27 +01:00
2024-05-09 21:47:21 +01:00
PHLLS CLayerSurface : : create ( SP < CLayerShellResource > resource ) {
2024-10-19 23:03:29 +01:00
PHLLS pLS = SP < CLayerSurface > ( new CLayerSurface ( resource ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-22 15:23:29 +02:00
auto pMonitor = resource - > monitor . empty ( ) ? g_pCompositor - > m_lastMonitor . lock ( ) : g_pCompositor - > getMonitorFromName ( resource - > monitor ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
pLS - > m_surface - > assign ( resource - > surface . lock ( ) , pLS ) ;
2024-06-08 10:07:59 +02:00
2024-05-09 21:47:21 +01:00
if ( ! pMonitor ) {
Debug : : log ( ERR , " New LS has no monitor?? " ) ;
return pLS ;
2024-04-30 02:41:27 +01:00
}
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_mirrorOf )
2025-04-22 15:23:29 +02:00
pMonitor = g_pCompositor - > m_monitors . front ( ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
pLS - > m_self = pLS ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
pLS - > m_namespace = resource - > layerNamespace ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
pLS - > m_layer = resource - > current . layer ;
pLS - > m_popupHead = CPopup : : create ( pLS ) ;
pLS - > m_monitor = pMonitor ;
2025-04-30 23:45:20 +02:00
pMonitor - > m_layerSurfaceLayers [ resource - > current . layer ] . emplace_back ( pLS ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
pLS - > m_forceBlur = g_pConfigManager - > shouldBlurLS ( pLS - > m_namespace ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
g_pAnimationManager - > createAnimation ( 0.f , pLS - > m_alpha , g_pConfigManager - > getAnimationPropertyConfig ( " fadeLayersIn " ) , pLS , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( Vector2D ( 0 , 0 ) , pLS - > m_realPosition , g_pConfigManager - > getAnimationPropertyConfig ( " layersIn " ) , pLS , AVARDAMAGE_ENTIRE ) ;
g_pAnimationManager - > createAnimation ( Vector2D ( 0 , 0 ) , pLS - > m_realSize , g_pConfigManager - > getAnimationPropertyConfig ( " layersIn " ) , pLS , AVARDAMAGE_ENTIRE ) ;
2024-04-30 02:41:27 +01:00
pLS - > registerCallbacks ( ) ;
2025-04-24 20:49:49 +02:00
pLS - > m_alpha - > setValueAndWarp ( 0.f ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
Debug : : log ( LOG , " LayerSurface {:x} (namespace {} layer {}) created on monitor {} " , ( uintptr_t ) resource . get ( ) , resource - > layerNamespace , ( int ) pLS - > m_layer , pMonitor - > m_name ) ;
2024-04-30 02:41:27 +01:00
return pLS ;
}
void CLayerSurface : : registerCallbacks ( ) {
2025-04-24 20:49:49 +02:00
m_alpha - > setUpdateCallback ( [ this ] ( auto ) {
if ( m_dimAround )
g_pHyprRenderer - > damageMonitor ( m_monitor . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
} ) ;
}
2025-04-24 20:49:49 +02:00
CLayerSurface : : CLayerSurface ( SP < CLayerShellResource > resource_ ) : m_layerSurface ( resource_ ) {
m_listeners . commit = m_layerSurface - > events . commit . registerListener ( [ this ] ( std : : any d ) { onCommit ( ) ; } ) ;
m_listeners . map = m_layerSurface - > events . map . registerListener ( [ this ] ( std : : any d ) { onMap ( ) ; } ) ;
m_listeners . unmap = m_layerSurface - > events . unmap . registerListener ( [ this ] ( std : : any d ) { onUnmap ( ) ; } ) ;
m_listeners . destroy = m_layerSurface - > events . destroy . registerListener ( [ this ] ( std : : any d ) { onDestroy ( ) ; } ) ;
2024-06-08 10:07:59 +02:00
2025-04-24 20:49:49 +02:00
m_surface = CWLSurface : : create ( ) ;
2024-04-30 02:41:27 +01:00
}
CLayerSurface : : ~ CLayerSurface ( ) {
if ( ! g_pHyprOpenGL )
return ;
2025-04-24 20:49:49 +02:00
if ( m_surface )
m_surface - > unassign ( ) ;
2024-04-30 02:41:27 +01:00
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2025-04-24 20:49:49 +02:00
std : : erase_if ( g_pHyprOpenGL - > m_mLayerFramebuffers , [ & ] ( const auto & other ) { return other . first . expired ( ) | | other . first . lock ( ) = = m_self . lock ( ) ; } ) ;
2024-08-24 15:22:10 +02:00
2025-04-22 15:23:29 +02:00
for ( auto const & mon : g_pCompositor - > m_realMonitors ) {
2025-04-30 23:45:20 +02:00
for ( auto & lsl : mon - > m_layerSurfaceLayers ) {
2024-08-24 15:22:10 +02:00
std : : erase_if ( lsl , [ this ] ( auto & ls ) { return ls . expired ( ) | | ls . get ( ) = = this ; } ) ;
}
}
2024-04-30 02:41:27 +01:00
}
void CLayerSurface : : onDestroy ( ) {
2025-04-24 20:49:49 +02:00
Debug : : log ( LOG , " LayerSurface {:x} destroyed " , ( uintptr_t ) m_layerSurface . get ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2024-04-30 02:41:27 +01:00
2024-10-27 18:45:38 +00:00
if ( ! PMONITOR )
2024-04-30 02:41:27 +01:00
Debug : : log ( WARN , " Layersurface destroyed on an invalid monitor (removed?) " ) ;
2025-04-24 20:49:49 +02:00
if ( ! m_fadingOut ) {
if ( m_mapped ) {
2024-04-30 02:41:27 +01:00
Debug : : log ( LOG , " Forcing an unmap of a LS that did a straight destroy! " ) ;
onUnmap ( ) ;
} else {
Debug : : log ( LOG , " Removing LayerSurface that wasn't mapped. " ) ;
2025-04-24 20:49:49 +02:00
if ( m_alpha )
m_alpha - > setValueAndWarp ( 0.f ) ;
m_fadingOut = true ;
g_pCompositor - > addToFadingOutSafe ( m_self . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
}
}
2025-04-24 20:49:49 +02:00
m_popupHead . reset ( ) ;
2024-05-10 12:03:38 +01:00
2025-04-24 20:49:49 +02:00
m_noProcess = true ;
2024-04-30 02:41:27 +01:00
// rearrange to fix the reserved areas
if ( PMONITOR ) {
2025-04-30 23:45:20 +02:00
g_pHyprRenderer - > arrangeLayersForMonitor ( PMONITOR - > m_id ) ;
PMONITOR - > m_scheduledRecalc = true ;
2024-04-30 02:41:27 +01:00
// and damage
2025-04-30 23:45:20 +02:00
CBox geomFixed = { m_geometry . x + PMONITOR - > m_position . x , m_geometry . y + PMONITOR - > m_position . y , m_geometry . width , m_geometry . height } ;
2025-01-26 15:05:34 +00:00
g_pHyprRenderer - > damageBox ( geomFixed ) ;
2024-04-30 02:41:27 +01:00
}
2025-04-24 20:49:49 +02:00
m_readyToDelete = true ;
m_layerSurface . reset ( ) ;
if ( m_surface )
m_surface - > unassign ( ) ;
2024-08-02 00:31:44 +02:00
2025-04-24 20:49:49 +02:00
m_listeners . unmap . reset ( ) ;
m_listeners . destroy . reset ( ) ;
m_listeners . map . reset ( ) ;
m_listeners . commit . reset ( ) ;
2024-04-30 02:41:27 +01:00
}
void CLayerSurface : : onMap ( ) {
2025-04-24 20:49:49 +02:00
Debug : : log ( LOG , " LayerSurface {:x} mapped " , ( uintptr_t ) m_layerSurface . get ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
m_mapped = true ;
m_interactivity = m_layerSurface - > current . interactivity ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
m_layerSurface - > surface - > map ( ) ;
2024-07-27 18:08:22 +02:00
2024-06-12 22:57:06 +02:00
// this layer might be re-mapped.
2025-04-24 20:49:49 +02:00
m_fadingOut = false ;
g_pCompositor - > removeFromFadingOutSafe ( m_self . lock ( ) ) ;
2024-06-12 22:57:06 +02:00
2024-04-30 02:41:27 +01:00
// fix if it changed its mon
2025-04-24 20:49:49 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2024-04-30 02:41:27 +01:00
if ( ! PMONITOR )
return ;
applyRules ( ) ;
2025-04-30 23:45:20 +02:00
PMONITOR - > m_scheduledRecalc = true ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
g_pHyprRenderer - > arrangeLayersForMonitor ( PMONITOR - > m_id ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
m_surface - > resource ( ) - > enter ( PMONITOR - > m_self . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
const bool ISEXCLUSIVE = m_layerSurface - > current . interactivity = = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE ;
2024-06-11 10:35:30 -07:00
if ( ISEXCLUSIVE )
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_exclusiveLSes . push_back ( m_self ) ;
2024-04-30 02:41:27 +01:00
2024-06-11 10:35:30 -07:00
const bool GRABSFOCUS = ISEXCLUSIVE | |
2025-04-24 20:49:49 +02:00
( m_layerSurface - > current . interactivity ! = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE & &
2024-06-11 10:35:30 -07:00
// don't focus if constrained
2025-05-02 17:07:20 +02:00
( g_pSeatManager - > m_mouse . expired ( ) | | ! g_pInputManager - > isConstrained ( ) ) ) ;
2024-04-30 02:41:27 +01:00
if ( GRABSFOCUS ) {
2024-05-11 01:02:57 +01:00
// TODO: use the new superb really very cool grab
g_pSeatManager - > setGrab ( nullptr ) ;
2024-04-30 02:41:27 +01:00
g_pInputManager - > releaseAllMouseButtons ( ) ;
2025-04-24 20:49:49 +02:00
g_pCompositor - > focusSurface ( m_surface - > resource ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
const auto LOCAL = g_pInputManager - > getMouseCoordsInternal ( ) - Vector2D ( m_geometry . x + PMONITOR - > m_position . x , m_geometry . y + PMONITOR - > m_position . y ) ;
2025-04-24 20:49:49 +02:00
g_pSeatManager - > setPointerFocus ( m_surface - > resource ( ) , LOCAL ) ;
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_emptyFocusCursorSet = false ;
2024-04-30 02:41:27 +01:00
}
2025-04-24 20:49:49 +02:00
m_position = Vector2D ( m_geometry . x , m_geometry . y ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
CBox geomFixed = { m_geometry . x + PMONITOR - > m_position . x , m_geometry . y + PMONITOR - > m_position . y , m_geometry . width , m_geometry . height } ;
2025-01-26 15:05:34 +00:00
g_pHyprRenderer - > damageBox ( geomFixed ) ;
2025-04-30 23:45:20 +02:00
const bool FULLSCREEN = PMONITOR - > m_activeWorkspace & & PMONITOR - > m_activeWorkspace - > m_hasFullscreenWindow & & PMONITOR - > m_activeWorkspace - > m_fullscreenMode = = FSMODE_FULLSCREEN ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
startAnimation ( ! ( m_layer = = ZWLR_LAYER_SHELL_V1_LAYER_TOP & & FULLSCREEN & & ! GRABSFOCUS ) ) ;
m_readyToDelete = false ;
m_fadingOut = false ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " openlayer " , m_namespace } ) ;
EMIT_HOOK_EVENT ( " openLayer " , m_self . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
g_pCompositor - > setPreferredScaleForSurface ( m_surface - > resource ( ) , PMONITOR - > m_scale ) ;
g_pCompositor - > setPreferredTransformForSurface ( m_surface - > resource ( ) , PMONITOR - > m_transform ) ;
2024-04-30 02:41:27 +01:00
}
void CLayerSurface : : onUnmap ( ) {
2025-04-24 20:49:49 +02:00
Debug : : log ( LOG , " LayerSurface {:x} unmapped " , ( uintptr_t ) m_layerSurface . get ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " closelayer " , m_layerSurface - > layerNamespace } ) ;
EMIT_HOOK_EVENT ( " closeLayer " , m_self . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-05-01 23:57:11 +02:00
std : : erase_if ( g_pInputManager - > m_exclusiveLSes , [ this ] ( const auto & other ) { return ! other | | other = = m_self ; } ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
if ( ! m_monitor | | g_pCompositor - > m_unsafeState ) {
2024-04-30 02:41:27 +01:00
Debug : : log ( WARN , " Layersurface unmapping on invalid monitor (removed?) ignoring. " ) ;
2025-04-24 20:49:49 +02:00
g_pCompositor - > addToFadingOutSafe ( m_self . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
m_mapped = false ;
if ( m_layerSurface & & m_layerSurface - > surface )
m_layerSurface - > surface - > unmap ( ) ;
2024-04-30 02:41:27 +01:00
startAnimation ( false ) ;
return ;
}
2025-04-13 17:56:20 +02:00
// end any pending animations so that snapshot has right dimensions
2025-04-24 20:49:49 +02:00
m_realPosition - > warp ( ) ;
m_realSize - > warp ( ) ;
2025-04-13 17:56:20 +02:00
2024-04-30 02:41:27 +01:00
// make a snapshot and start fade
2025-04-24 20:49:49 +02:00
g_pHyprRenderer - > makeLayerSnapshot ( m_self . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
startAnimation ( false ) ;
2025-04-24 20:49:49 +02:00
m_mapped = false ;
if ( m_layerSurface & & m_layerSurface - > surface )
m_layerSurface - > surface - > unmap ( ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
g_pCompositor - > addToFadingOutSafe ( m_self . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2024-04-30 02:41:27 +01:00
2025-05-02 17:07:20 +02:00
const bool WASLASTFOCUS = g_pSeatManager - > m_state . keyboardFocus = = m_surface - > resource ( ) | | g_pSeatManager - > m_state . pointerFocus = = m_surface - > resource ( ) ;
2024-04-30 02:41:27 +01:00
if ( ! PMONITOR )
return ;
// refocus if needed
2024-07-27 15:03:52 +02:00
// vvvvvvvvvvvvv if there is a last focus and the last focus is not keyboard focusable, fallback to window
2025-04-22 15:23:29 +02:00
if ( WASLASTFOCUS | | ( g_pCompositor - > m_lastFocus & & g_pCompositor - > m_lastFocus - > hlSurface & & ! g_pCompositor - > m_lastFocus - > hlSurface - > keyboardFocusable ( ) ) ) {
2025-04-07 20:52:11 +02:00
if ( ! g_pInputManager - > refocusLastWindow ( PMONITOR ) )
g_pInputManager - > refocus ( ) ;
2025-04-24 20:49:49 +02:00
} else if ( g_pCompositor - > m_lastFocus & & g_pCompositor - > m_lastFocus ! = m_surface - > resource ( ) )
2025-04-22 15:23:29 +02:00
g_pSeatManager - > setKeyboardFocus ( g_pCompositor - > m_lastFocus . lock ( ) ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
CBox geomFixed = { m_geometry . x + PMONITOR - > m_position . x , m_geometry . y + PMONITOR - > m_position . y , m_geometry . width , m_geometry . height } ;
2025-01-26 15:05:34 +00:00
g_pHyprRenderer - > damageBox ( geomFixed ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
geomFixed = { m_geometry . x + ( int ) PMONITOR - > m_position . x , m_geometry . y + ( int ) PMONITOR - > m_position . y , ( int ) m_layerSurface - > surface - > current . size . x ,
2025-04-24 20:49:49 +02:00
( int ) m_layerSurface - > surface - > current . size . y } ;
2025-01-26 15:05:34 +00:00
g_pHyprRenderer - > damageBox ( geomFixed ) ;
2024-04-30 02:41:27 +01:00
2025-01-01 17:28:04 +01:00
g_pInputManager - > simulateMouseMovement ( ) ;
2024-06-12 22:57:06 +02:00
2025-04-30 23:45:20 +02:00
g_pHyprRenderer - > arrangeLayersForMonitor ( PMONITOR - > m_id ) ;
2024-04-30 02:41:27 +01:00
}
void CLayerSurface : : onCommit ( ) {
2025-04-24 20:49:49 +02:00
if ( ! m_layerSurface )
2024-04-30 02:41:27 +01:00
return ;
2025-04-24 20:49:49 +02:00
if ( ! m_mapped ) {
2024-06-12 22:57:06 +02:00
// we're re-mapping if this is the case
2025-04-24 20:49:49 +02:00
if ( m_layerSurface - > surface & & ! m_layerSurface - > surface - > current . texture ) {
m_fadingOut = false ;
m_geometry = { } ;
2024-10-27 18:45:38 +00:00
g_pHyprRenderer - > arrangeLayersForMonitor ( monitorID ( ) ) ;
2024-06-12 22:57:06 +02:00
}
return ;
}
2025-04-24 20:49:49 +02:00
const auto PMONITOR = m_monitor . lock ( ) ;
2024-04-30 02:41:27 +01:00
if ( ! PMONITOR )
return ;
2025-04-24 20:49:49 +02:00
if ( m_layer = = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND | | m_layer = = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM )
2024-04-30 02:41:27 +01:00
g_pHyprOpenGL - > markBlurDirtyForMonitor ( PMONITOR ) ; // so that blur is recalc'd
2025-04-24 20:49:49 +02:00
CBox geomFixed = { m_geometry . x , m_geometry . y , m_geometry . width , m_geometry . height } ;
2025-01-26 15:05:34 +00:00
g_pHyprRenderer - > damageBox ( geomFixed ) ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
if ( m_layerSurface - > current . committed ! = 0 ) {
if ( m_layerSurface - > current . committed & CLayerShellResource : : eCommittedState : : STATE_LAYER ) {
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
for ( auto it = PMONITOR - > m_layerSurfaceLayers [ m_layer ] . begin ( ) ; it ! = PMONITOR - > m_layerSurfaceLayers [ m_layer ] . end ( ) ; it + + ) {
2025-04-24 20:49:49 +02:00
if ( * it = = m_self ) {
if ( m_layerSurface - > current . layer = = m_layer )
2024-05-11 18:31:50 +01:00
break ;
2025-04-30 23:45:20 +02:00
PMONITOR - > m_layerSurfaceLayers [ m_layerSurface - > current . layer ] . emplace_back ( * it ) ;
PMONITOR - > m_layerSurfaceLayers [ m_layer ] . erase ( it ) ;
2024-04-30 02:41:27 +01:00
break ;
}
}
2025-04-24 20:49:49 +02:00
m_layer = m_layerSurface - > current . layer ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
if ( m_layer = = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND | | m_layer = = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM )
2024-04-30 02:41:27 +01:00
g_pHyprOpenGL - > markBlurDirtyForMonitor ( PMONITOR ) ; // so that blur is recalc'd
}
2025-04-30 23:45:20 +02:00
g_pHyprRenderer - > arrangeLayersForMonitor ( PMONITOR - > m_id ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
PMONITOR - > m_scheduledRecalc = true ;
2024-04-30 02:41:27 +01:00
} else {
2025-04-24 20:49:49 +02:00
m_position = Vector2D ( m_geometry . x , m_geometry . y ) ;
2024-04-30 02:41:27 +01:00
// update geom if it changed
2025-04-30 23:45:20 +02:00
if ( m_layerSurface - > surface - > current . scale = = 1 & & PMONITOR - > m_scale ! = 1.f & & m_layerSurface - > surface - > current . viewport . hasDestination ) {
2024-04-30 02:41:27 +01:00
// fractional scaling. Dirty hack.
2025-04-24 20:49:49 +02:00
m_geometry = { m_geometry . pos ( ) , m_layerSurface - > surface - > current . viewport . destination } ;
2024-04-30 02:41:27 +01:00
} else {
// this is because some apps like e.g. rofi-lbonn can't fucking use the protocol correctly.
2025-04-24 20:49:49 +02:00
m_geometry = { m_geometry . pos ( ) , m_layerSurface - > surface - > current . size } ;
2024-04-30 02:41:27 +01:00
}
}
2025-04-24 20:49:49 +02:00
if ( m_realPosition - > goal ( ) ! = m_geometry . pos ( ) ) {
if ( m_realPosition - > isBeingAnimated ( ) )
* m_realPosition = m_geometry . pos ( ) ;
2024-04-30 02:41:27 +01:00
else
2025-04-24 20:49:49 +02:00
m_realPosition - > setValueAndWarp ( m_geometry . pos ( ) ) ;
2024-04-30 02:41:27 +01:00
}
2025-04-24 20:49:49 +02:00
if ( m_realSize - > goal ( ) ! = m_geometry . size ( ) ) {
if ( m_realSize - > isBeingAnimated ( ) )
* m_realSize = m_geometry . size ( ) ;
2024-04-30 02:41:27 +01:00
else
2025-04-24 20:49:49 +02:00
m_realSize - > setValueAndWarp ( m_geometry . size ( ) ) ;
2024-04-30 02:41:27 +01:00
}
2025-04-24 20:49:49 +02:00
if ( m_mapped & & ( m_layerSurface - > current . committed & CLayerShellResource : : eCommittedState : : STATE_INTERACTIVITY ) ) {
2024-11-09 02:25:34 +00:00
bool WASLASTFOCUS = false ;
2025-04-24 20:49:49 +02:00
m_layerSurface - > surface - > breadthfirst (
2025-05-02 17:07:20 +02:00
[ & WASLASTFOCUS ] ( SP < CWLSurfaceResource > surf , const Vector2D & offset , void * data ) { WASLASTFOCUS = WASLASTFOCUS | | g_pSeatManager - > m_state . keyboardFocus = = surf ; } ,
2024-11-09 02:25:34 +00:00
nullptr ) ;
2025-04-24 20:49:49 +02:00
if ( ! WASLASTFOCUS & & m_popupHead ) {
m_popupHead - > breadthfirst (
2025-01-26 12:54:32 +00:00
[ & WASLASTFOCUS ] ( WP < CPopup > popup , void * data ) {
2025-05-02 17:07:20 +02:00
WASLASTFOCUS = WASLASTFOCUS | | ( popup - > m_wlSurface & & g_pSeatManager - > m_state . keyboardFocus = = popup - > m_wlSurface - > resource ( ) ) ;
2024-11-09 02:34:04 +00:00
} ,
nullptr ) ;
2024-11-09 02:25:34 +00:00
}
2025-04-24 20:49:49 +02:00
const bool WASEXCLUSIVE = m_interactivity = = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE ;
const bool ISEXCLUSIVE = m_layerSurface - > current . interactivity = = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE ;
2024-06-11 10:35:30 -07:00
if ( ! WASEXCLUSIVE & & ISEXCLUSIVE )
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_exclusiveLSes . push_back ( m_self ) ;
2024-06-11 10:35:30 -07:00
else if ( WASEXCLUSIVE & & ! ISEXCLUSIVE )
2025-05-01 23:57:11 +02:00
std : : erase_if ( g_pInputManager - > m_exclusiveLSes , [ this ] ( const auto & other ) { return ! other . lock ( ) | | other . lock ( ) = = m_self . lock ( ) ; } ) ;
2024-06-11 10:35:30 -07:00
// if the surface was focused and interactive but now isn't, refocus
2025-04-24 20:49:49 +02:00
if ( WASLASTFOCUS & & m_layerSurface - > current . interactivity = = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE ) {
2024-06-11 10:35:30 -07:00
// moveMouseUnified won't focus non interactive layers but it won't unfocus them either,
// so unfocus the surface here.
g_pCompositor - > focusSurface ( nullptr ) ;
2025-04-24 20:49:49 +02:00
g_pInputManager - > refocusLastWindow ( m_monitor . lock ( ) ) ;
} else if ( WASLASTFOCUS & & WASEXCLUSIVE & & m_layerSurface - > current . interactivity = = ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND ) {
2024-11-09 02:25:34 +00:00
g_pInputManager - > simulateMouseMovement ( ) ;
2024-06-14 02:52:37 -07:00
} else if ( ! WASEXCLUSIVE & & ISEXCLUSIVE ) {
// if now exclusive and not previously
2024-06-11 10:35:30 -07:00
g_pSeatManager - > setGrab ( nullptr ) ;
g_pInputManager - > releaseAllMouseButtons ( ) ;
2025-04-24 20:49:49 +02:00
g_pCompositor - > focusSurface ( m_surface - > resource ( ) ) ;
2024-06-11 10:35:30 -07:00
2025-04-30 23:45:20 +02:00
const auto LOCAL = g_pInputManager - > getMouseCoordsInternal ( ) - Vector2D ( m_geometry . x + PMONITOR - > m_position . x , m_geometry . y + PMONITOR - > m_position . y ) ;
2025-04-24 20:49:49 +02:00
g_pSeatManager - > setPointerFocus ( m_surface - > resource ( ) , LOCAL ) ;
2025-05-01 23:57:11 +02:00
g_pInputManager - > m_emptyFocusCursorSet = false ;
2024-06-11 10:35:30 -07:00
}
2024-04-30 02:41:27 +01:00
}
2025-04-24 20:49:49 +02:00
m_interactivity = m_layerSurface - > current . interactivity ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
g_pHyprRenderer - > damageSurface ( m_surface - > resource ( ) , m_position . x , m_position . y ) ;
2024-04-30 02:41:27 +01:00
2025-04-30 23:45:20 +02:00
g_pCompositor - > setPreferredScaleForSurface ( m_surface - > resource ( ) , PMONITOR - > m_scale ) ;
g_pCompositor - > setPreferredTransformForSurface ( m_surface - > resource ( ) , PMONITOR - > m_transform ) ;
2024-04-30 02:41:27 +01:00
}
void CLayerSurface : : applyRules ( ) {
2025-04-24 20:49:49 +02:00
m_noAnimations = false ;
m_forceBlur = false ;
m_ignoreAlpha = false ;
m_ignoreAlphaValue = 0.f ;
m_dimAround = false ;
m_xray = - 1 ;
m_animationStyle . reset ( ) ;
for ( auto const & rule : g_pConfigManager - > getMatchingRules ( m_self . lock ( ) ) ) {
switch ( rule - > m_ruleType ) {
2024-12-16 19:05:24 +01:00
case CLayerRule : : RULE_NOANIM : {
2025-04-24 20:49:49 +02:00
m_noAnimations = true ;
2024-12-16 19:05:24 +01:00
break ;
}
case CLayerRule : : RULE_BLUR : {
2025-04-24 20:49:49 +02:00
m_forceBlur = true ;
2024-12-16 19:05:24 +01:00
break ;
}
case CLayerRule : : RULE_BLURPOPUPS : {
2025-04-24 20:49:49 +02:00
m_forceBlurPopups = true ;
2024-12-16 19:05:24 +01:00
break ;
}
2024-12-16 18:37:34 +00:00
case CLayerRule : : RULE_IGNOREALPHA :
case CLayerRule : : RULE_IGNOREZERO : {
2025-04-24 20:49:49 +02:00
const auto FIRST_SPACE_POS = rule - > m_rule . find_first_of ( ' ' ) ;
2024-12-16 19:05:24 +01:00
std : : string alphaValue = " " ;
if ( FIRST_SPACE_POS ! = std : : string : : npos )
2025-04-24 20:49:49 +02:00
alphaValue = rule - > m_rule . substr ( FIRST_SPACE_POS + 1 ) ;
2024-12-16 19:05:24 +01:00
try {
2025-04-24 20:49:49 +02:00
m_ignoreAlpha = true ;
2024-12-16 19:05:24 +01:00
if ( ! alphaValue . empty ( ) )
2025-04-24 20:49:49 +02:00
m_ignoreAlphaValue = std : : stof ( alphaValue ) ;
2024-12-16 19:05:24 +01:00
} catch ( . . . ) { Debug : : log ( ERR , " Invalid value passed to ignoreAlpha " ) ; }
break ;
}
case CLayerRule : : RULE_DIMAROUND : {
2025-04-24 20:49:49 +02:00
m_dimAround = true ;
2024-12-16 19:05:24 +01:00
break ;
}
case CLayerRule : : RULE_XRAY : {
2025-04-24 20:49:49 +02:00
CVarList vars { rule - > m_rule , 0 , ' ' } ;
2025-04-25 16:38:31 +02:00
m_xray = configStringToInt ( vars [ 1 ] ) . value_or ( false ) ;
2024-12-16 19:05:24 +01:00
break ;
}
case CLayerRule : : RULE_ANIMATION : {
2025-04-24 20:49:49 +02:00
CVarList vars { rule - > m_rule , 2 , ' s ' } ;
m_animationStyle = vars [ 1 ] ;
2024-12-16 19:05:24 +01:00
break ;
}
case CLayerRule : : RULE_ORDER : {
2025-04-24 20:49:49 +02:00
CVarList vars { rule - > m_rule , 2 , ' s ' } ;
2024-12-16 19:05:24 +01:00
try {
2025-04-24 20:49:49 +02:00
m_order = std : : stoi ( vars [ 1 ] ) ;
2024-12-16 19:05:24 +01:00
} catch ( . . . ) { Debug : : log ( ERR , " Invalid value passed to order " ) ; }
break ;
}
2025-04-25 16:38:31 +02:00
case CLayerRule : : RULE_ABOVELOCK : {
m_aboveLockscreen = true ;
CVarList vars { rule - > m_rule , 0 , ' ' } ;
m_aboveLockscreenInteractable = configStringToInt ( vars [ 1 ] ) . value_or ( false ) ;
break ;
}
2024-12-16 19:05:24 +01:00
default : break ;
2024-04-30 02:41:27 +01:00
}
}
}
void CLayerSurface : : startAnimation ( bool in , bool instant ) {
if ( in ) {
2025-04-24 20:49:49 +02:00
m_realPosition - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " layersIn " ) ) ;
m_realSize - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " layersIn " ) ) ;
m_alpha - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " fadeLayersIn " ) ) ;
2024-04-30 02:41:27 +01:00
} else {
2025-04-24 20:49:49 +02:00
m_realPosition - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " layersOut " ) ) ;
m_realSize - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " layersOut " ) ) ;
m_alpha - > setConfig ( g_pConfigManager - > getAnimationPropertyConfig ( " fadeLayersOut " ) ) ;
2024-04-30 02:41:27 +01:00
}
2025-04-24 20:49:49 +02:00
const auto ANIMSTYLE = m_animationStyle . value_or ( m_realPosition - > getStyle ( ) ) ;
2024-04-30 02:41:27 +01:00
if ( ANIMSTYLE . starts_with ( " slide " ) ) {
// get closest edge
2025-04-24 20:49:49 +02:00
const auto MIDDLE = m_geometry . middle ( ) ;
2024-04-30 02:41:27 +01:00
const auto PMONITOR = g_pCompositor - > getMonitorFromVector ( MIDDLE ) ;
int force = - 1 ;
CVarList args ( ANIMSTYLE , 0 , ' s ' ) ;
if ( args . size ( ) > 1 ) {
const auto ARG2 = args [ 1 ] ;
if ( ARG2 = = " top " )
force = 0 ;
else if ( ARG2 = = " bottom " )
force = 1 ;
else if ( ARG2 = = " left " )
force = 2 ;
else if ( ARG2 = = " right " )
force = 3 ;
}
const std : : array < Vector2D , 4 > edgePoints = {
2025-04-30 23:45:20 +02:00
PMONITOR - > m_position + Vector2D { PMONITOR - > m_size . x / 2 , 0.0 } ,
PMONITOR - > m_position + Vector2D { PMONITOR - > m_size . x / 2 , PMONITOR - > m_size . y } ,
PMONITOR - > m_position + Vector2D { 0.0 , PMONITOR - > m_size . y } ,
PMONITOR - > m_position + Vector2D { PMONITOR - > m_size . x , PMONITOR - > m_size . y / 2 } ,
2024-04-30 02:41:27 +01:00
} ;
2024-08-21 23:05:03 +02:00
float closest = std : : numeric_limits < float > : : max ( ) ;
int leader = force ;
2024-04-30 02:41:27 +01:00
if ( leader = = - 1 ) {
for ( size_t i = 0 ; i < 4 ; + + i ) {
float dist = MIDDLE . distance ( edgePoints [ i ] ) ;
if ( dist < closest ) {
leader = i ;
closest = dist ;
}
}
}
2025-04-24 20:49:49 +02:00
m_realSize - > setValueAndWarp ( m_geometry . size ( ) ) ;
m_alpha - > setValueAndWarp ( in ? 0.f : 1.f ) ;
* m_alpha = in ? 1.f : 0.f ;
2024-04-30 02:41:27 +01:00
Vector2D prePos ;
switch ( leader ) {
case 0 :
// TOP
2025-04-30 23:45:20 +02:00
prePos = { m_geometry . x , PMONITOR - > m_position . y - m_geometry . h } ;
2024-04-30 02:41:27 +01:00
break ;
case 1 :
// BOTTOM
2025-04-30 23:45:20 +02:00
prePos = { m_geometry . x , PMONITOR - > m_position . y + PMONITOR - > m_size . y } ;
2024-04-30 02:41:27 +01:00
break ;
case 2 :
// LEFT
2025-04-30 23:45:20 +02:00
prePos = { PMONITOR - > m_position . x - m_geometry . w , m_geometry . y } ;
2024-04-30 02:41:27 +01:00
break ;
case 3 :
// RIGHT
2025-04-30 23:45:20 +02:00
prePos = { PMONITOR - > m_position . x + PMONITOR - > m_size . x , m_geometry . y } ;
2024-04-30 02:41:27 +01:00
break ;
default : UNREACHABLE ( ) ;
}
if ( in ) {
2025-04-24 20:49:49 +02:00
m_realPosition - > setValueAndWarp ( prePos ) ;
* m_realPosition = m_geometry . pos ( ) ;
2024-04-30 02:41:27 +01:00
} else {
2025-04-24 20:49:49 +02:00
m_realPosition - > setValueAndWarp ( m_geometry . pos ( ) ) ;
* m_realPosition = prePos ;
2024-04-30 02:41:27 +01:00
}
} else if ( ANIMSTYLE . starts_with ( " popin " ) ) {
float minPerc = 0.f ;
if ( ANIMSTYLE . find ( " % " ) ! = std : : string : : npos ) {
try {
auto percstr = ANIMSTYLE . substr ( ANIMSTYLE . find_last_of ( ' ' ) ) ;
minPerc = std : : stoi ( percstr . substr ( 0 , percstr . length ( ) - 1 ) ) ;
} catch ( std : : exception & e ) {
; // oops
}
}
minPerc * = 0.01 ;
2025-04-24 20:49:49 +02:00
const auto GOALSIZE = ( m_geometry . size ( ) * minPerc ) . clamp ( { 5 , 5 } ) ;
const auto GOALPOS = m_geometry . pos ( ) + ( m_geometry . size ( ) - GOALSIZE ) / 2.f ;
2024-04-30 02:41:27 +01:00
2025-04-24 20:49:49 +02:00
m_alpha - > setValueAndWarp ( in ? 0.f : 1.f ) ;
* m_alpha = in ? 1.f : 0.f ;
2024-04-30 02:41:27 +01:00
if ( in ) {
2025-04-24 20:49:49 +02:00
m_realSize - > setValueAndWarp ( GOALSIZE ) ;
m_realPosition - > setValueAndWarp ( GOALPOS ) ;
* m_realSize = m_geometry . size ( ) ;
* m_realPosition = m_geometry . pos ( ) ;
2024-04-30 02:41:27 +01:00
} else {
2025-04-24 20:49:49 +02:00
m_realSize - > setValueAndWarp ( m_geometry . size ( ) ) ;
m_realPosition - > setValueAndWarp ( m_geometry . pos ( ) ) ;
* m_realSize = GOALSIZE ;
* m_realPosition = GOALPOS ;
2024-04-30 02:41:27 +01:00
}
} else {
// fade
2025-04-24 20:49:49 +02:00
m_realPosition - > setValueAndWarp ( m_geometry . pos ( ) ) ;
m_realSize - > setValueAndWarp ( m_geometry . size ( ) ) ;
* m_alpha = in ? 1.f : 0.f ;
2024-04-30 02:41:27 +01:00
}
if ( ! in )
2025-04-24 20:49:49 +02:00
m_fadingOut = true ;
2024-04-30 02:41:27 +01:00
}
bool CLayerSurface : : isFadedOut ( ) {
2025-04-24 20:49:49 +02:00
if ( ! m_fadingOut )
2024-04-30 02:41:27 +01:00
return false ;
2025-04-24 20:49:49 +02:00
return ! m_realPosition - > isBeingAnimated ( ) & & ! m_realSize - > isBeingAnimated ( ) & & ! m_alpha - > isBeingAnimated ( ) ;
2024-04-30 02:41:27 +01:00
}
int CLayerSurface : : popupsCount ( ) {
2025-04-24 20:49:49 +02:00
if ( ! m_layerSurface | | ! m_mapped | | m_fadingOut )
2024-04-30 02:41:27 +01:00
return 0 ;
2024-05-09 21:47:21 +01:00
int no = - 1 ; // we have one dummy
2025-04-24 20:49:49 +02:00
m_popupHead - > breadthfirst ( [ ] ( WP < CPopup > p , void * data ) { * ( int * ) data + = 1 ; } , & no ) ;
2024-04-30 02:41:27 +01:00
return no ;
2024-06-11 10:35:30 -07:00
}
2024-10-27 18:45:38 +00:00
MONITORID CLayerSurface : : 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
}
2025-02-26 23:03:06 +08:00
pid_t CLayerSurface : : getPID ( ) {
pid_t PID = - 1 ;
2025-04-24 20:49:49 +02:00
if ( ! m_layerSurface | | ! m_layerSurface - > surface | | ! m_layerSurface - > surface - > getResource ( ) | | ! m_layerSurface - > surface - > getResource ( ) - > resource ( ) | |
! m_layerSurface - > surface - > getResource ( ) - > resource ( ) - > client )
2025-02-26 23:03:06 +08:00
return - 1 ;
2025-04-24 20:49:49 +02:00
wl_client_get_credentials ( m_layerSurface - > surface - > getResource ( ) - > resource ( ) - > client , & PID , nullptr , nullptr ) ;
2025-02-26 23:03:06 +08:00
return PID ;
}