2024-05-03 17:58:40 +01:00
# include "OutputManagement.hpp"
# include <algorithm>
# include "../Compositor.hpp"
2025-01-17 15:21:35 +00:00
# include "../managers/input/InputManager.hpp"
# include "../managers/HookSystemManager.hpp"
# include "../config/ConfigManager.hpp"
2024-05-03 17:58:40 +01:00
2024-07-21 13:09:54 +02:00
using namespace Aquamarine ;
2025-05-04 19:21:36 +02:00
COutputManager : : COutputManager ( SP < CZwlrOutputManagerV1 > resource_ ) : m_resource ( resource_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-03 17:58:40 +01:00
return ;
LOGM ( LOG , " New OutputManager registered " ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setOnDestroy ( [ this ] ( CZwlrOutputManagerV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
m_resource - > setStop ( [ this ] ( CZwlrOutputManagerV1 * r ) { m_stopped = true ; } ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
m_resource - > setCreateConfiguration ( [ this ] ( CZwlrOutputManagerV1 * r , uint32_t id , uint32_t serial ) {
2024-05-03 17:58:40 +01:00
LOGM ( LOG , " Creating new configuration " ) ;
2025-05-04 19:21:36 +02:00
const auto RESOURCE = PROTO : : outputManagement - > m_configurations . emplace_back (
makeShared < COutputConfiguration > ( makeShared < CZwlrOutputConfigurationV1 > ( m_resource - > client ( ) , m_resource - > version ( ) , id ) , m_self . lock ( ) ) ) ;
2024-05-03 17:58:40 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2025-05-04 19:21:36 +02:00
m_resource - > noMemory ( ) ;
PROTO : : outputManagement - > m_configurations . pop_back ( ) ;
2024-05-03 17:58:40 +01:00
return ;
}
} ) ;
// send all heads at start
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_realMonitors ) {
if ( m = = g_pCompositor - > m_unsafeOutput )
2024-05-03 17:58:40 +01:00
continue ;
2025-04-30 23:45:20 +02:00
LOGM ( LOG , " | sending output head for {} " , m - > m_name ) ;
2024-05-03 17:58:40 +01:00
2024-10-19 23:03:29 +01:00
makeAndSendNewHead ( m ) ;
2024-05-03 17:58:40 +01:00
}
sendDone ( ) ;
}
bool COutputManager : : good ( ) {
2025-05-04 19:21:36 +02:00
return m_resource - > resource ( ) ;
2024-05-03 17:58:40 +01:00
}
2024-10-19 23:03:29 +01:00
void COutputManager : : makeAndSendNewHead ( PHLMONITOR pMonitor ) {
2025-05-04 19:21:36 +02:00
if UNLIKELY ( m_stopped )
2024-05-03 17:58:40 +01:00
return ;
const auto RESOURCE =
2025-05-04 19:21:36 +02:00
PROTO : : outputManagement - > m_heads . emplace_back ( makeShared < COutputHead > ( makeShared < CZwlrOutputHeadV1 > ( m_resource - > client ( ) , m_resource - > version ( ) , 0 ) , pMonitor ) ) ;
2024-05-03 17:58:40 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2025-05-04 19:21:36 +02:00
m_resource - > noMemory ( ) ;
PROTO : : outputManagement - > m_heads . pop_back ( ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_heads . emplace_back ( RESOURCE ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
m_resource - > sendHead ( RESOURCE - > m_resource . get ( ) ) ;
2024-05-03 17:58:40 +01:00
RESOURCE - > sendAllData ( ) ;
}
2024-10-19 23:03:29 +01:00
void COutputManager : : ensureMonitorSent ( PHLMONITOR pMonitor ) {
2025-04-22 15:23:29 +02:00
if ( pMonitor = = g_pCompositor - > m_unsafeOutput )
2024-05-03 17:58:40 +01:00
return ;
2025-05-04 19:21:36 +02:00
for ( auto const & hw : m_heads ) {
2024-05-03 17:58:40 +01:00
auto h = hw . lock ( ) ;
if ( ! h )
continue ;
2025-05-04 19:21:36 +02:00
if ( h - > m_monitor = = pMonitor )
2024-05-03 17:58:40 +01:00
return ;
}
makeAndSendNewHead ( pMonitor ) ;
sendDone ( ) ;
}
void COutputManager : : sendDone ( ) {
2025-05-04 19:21:36 +02:00
m_resource - > sendDone ( wl_display_next_serial ( g_pCompositor - > m_wlDisplay ) ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
COutputHead : : COutputHead ( SP < CZwlrOutputHeadV1 > resource_ , PHLMONITOR pMonitor_ ) : m_resource ( resource_ ) , m_monitor ( pMonitor_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-03 17:58:40 +01:00
return ;
2025-05-04 19:21:36 +02:00
m_resource - > setRelease ( [ this ] ( CZwlrOutputHeadV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
m_resource - > setOnDestroy ( [ this ] ( CZwlrOutputHeadV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
2024-05-03 17:58:40 +01:00
2025-07-08 09:56:40 -07:00
m_listeners . monitorDestroy = m_monitor - > m_events . destroy . listen ( [ this ] {
2025-05-04 19:21:36 +02:00
m_resource - > sendFinished ( ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
for ( auto const & mw : m_modes ) {
2024-05-03 17:58:40 +01:00
auto m = mw . lock ( ) ;
if ( ! m )
continue ;
2025-05-04 19:21:36 +02:00
m - > m_resource - > sendFinished ( ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
m_monitor . reset ( ) ;
for ( auto const & m : PROTO : : outputManagement - > m_managers ) {
2024-05-23 21:15:31 +02:00
m - > sendDone ( ) ;
}
2024-05-03 17:58:40 +01:00
} ) ;
2025-07-08 09:56:40 -07:00
m_listeners . monitorModeChange = m_monitor - > m_events . modeChanged . listen ( [ this ] { updateMode ( ) ; } ) ;
2024-05-03 17:58:40 +01:00
}
bool COutputHead : : good ( ) {
2025-05-04 19:21:36 +02:00
return m_resource - > resource ( ) ;
2024-05-03 17:58:40 +01:00
}
void COutputHead : : sendAllData ( ) {
2025-05-04 19:21:36 +02:00
const auto VERSION = m_resource - > version ( ) ;
m_resource - > sendName ( m_monitor - > m_name . c_str ( ) ) ;
m_resource - > sendDescription ( m_monitor - > m_description . c_str ( ) ) ;
if ( m_monitor - > m_output - > physicalSize . x > 0 & & m_monitor - > m_output - > physicalSize . y > 0 )
m_resource - > sendPhysicalSize ( m_monitor - > m_output - > physicalSize . x , m_monitor - > m_output - > physicalSize . y ) ;
m_resource - > sendEnabled ( m_monitor - > m_enabled ) ;
if ( m_monitor - > m_enabled ) {
m_resource - > sendPosition ( m_monitor - > m_position . x , m_monitor - > m_position . y ) ;
m_resource - > sendTransform ( m_monitor - > m_transform ) ;
m_resource - > sendScale ( wl_fixed_from_double ( m_monitor - > m_scale ) ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
if ( ! m_monitor - > m_output - > make . empty ( ) & & VERSION > = 2 )
m_resource - > sendMake ( m_monitor - > m_output - > make . c_str ( ) ) ;
if ( ! m_monitor - > m_output - > model . empty ( ) & & VERSION > = 2 )
m_resource - > sendModel ( m_monitor - > m_output - > model . c_str ( ) ) ;
if ( ! m_monitor - > m_output - > serial . empty ( ) & & VERSION > = 2 )
m_resource - > sendSerialNumber ( m_monitor - > m_output - > serial . c_str ( ) ) ;
2024-05-03 17:58:40 +01:00
if ( VERSION > = 4 )
2025-05-04 19:21:36 +02:00
m_resource - > sendAdaptiveSync ( m_monitor - > m_vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED ) ;
2024-05-03 17:58:40 +01:00
// send all available modes
2025-05-04 19:21:36 +02:00
if ( m_modes . empty ( ) ) {
if ( ! m_monitor - > m_output - > modes . empty ( ) ) {
for ( auto const & m : m_monitor - > m_output - > modes ) {
2024-07-21 13:09:54 +02:00
makeAndSendNewMode ( m ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
} else if ( m_monitor - > m_output - > state - > state ( ) . customMode ) {
makeAndSendNewMode ( m_monitor - > m_output - > state - > state ( ) . customMode ) ;
2024-05-03 17:58:40 +01:00
} else
makeAndSendNewMode ( nullptr ) ;
}
// send current mode
2025-05-04 19:21:36 +02:00
if ( m_monitor - > m_enabled ) {
for ( auto const & mw : m_modes ) {
2024-05-03 17:58:40 +01:00
auto m = mw . lock ( ) ;
if ( ! m )
continue ;
2025-05-04 19:21:36 +02:00
if ( m - > m_mode = = m_monitor - > m_output - > state - > state ( ) . mode ) {
if ( m - > m_mode )
LOGM ( LOG , " | sending current mode for {}: {}x{}@{} " , m_monitor - > m_name , m - > m_mode - > pixelSize . x , m - > m_mode - > pixelSize . y , m - > m_mode - > refreshRate ) ;
2024-05-03 17:58:40 +01:00
else
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | sending current mode for {}: null (fake) " , m_monitor - > m_name ) ;
m_resource - > sendCurrentMode ( m - > m_resource . get ( ) ) ;
2024-05-03 17:58:40 +01:00
break ;
}
}
}
}
void COutputHead : : updateMode ( ) {
2025-05-04 19:21:36 +02:00
m_resource - > sendEnabled ( m_monitor - > m_enabled ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
if ( m_monitor - > m_enabled ) {
m_resource - > sendPosition ( m_monitor - > m_position . x , m_monitor - > m_position . y ) ;
m_resource - > sendTransform ( m_monitor - > m_transform ) ;
m_resource - > sendScale ( wl_fixed_from_double ( m_monitor - > m_scale ) ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
if ( m_resource - > version ( ) > = 4 )
m_resource - > sendAdaptiveSync ( m_monitor - > m_vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
if ( m_monitor - > m_enabled ) {
for ( auto const & mw : m_modes ) {
2024-05-03 17:58:40 +01:00
auto m = mw . lock ( ) ;
if ( ! m )
continue ;
2025-05-04 19:21:36 +02:00
if ( m - > m_mode = = m_monitor - > m_currentMode ) {
if ( m - > m_mode )
LOGM ( LOG , " | sending current mode for {}: {}x{}@{} " , m_monitor - > m_name , m - > m_mode - > pixelSize . x , m - > m_mode - > pixelSize . y , m - > m_mode - > refreshRate ) ;
2024-05-03 17:58:40 +01:00
else
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | sending current mode for {}: null (fake) " , m_monitor - > m_name ) ;
m_resource - > sendCurrentMode ( m - > m_resource . get ( ) ) ;
2024-05-03 17:58:40 +01:00
break ;
}
}
}
}
2024-07-21 13:09:54 +02:00
void COutputHead : : makeAndSendNewMode ( SP < Aquamarine : : SOutputMode > mode ) {
2025-05-04 19:21:36 +02:00
const auto RESOURCE =
PROTO : : outputManagement - > m_modes . emplace_back ( makeShared < COutputMode > ( makeShared < CZwlrOutputModeV1 > ( m_resource - > client ( ) , m_resource - > version ( ) , 0 ) , mode ) ) ;
2024-05-03 17:58:40 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2025-05-04 19:21:36 +02:00
m_resource - > noMemory ( ) ;
PROTO : : outputManagement - > m_modes . pop_back ( ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_modes . emplace_back ( RESOURCE ) ;
m_resource - > sendMode ( RESOURCE - > m_resource . get ( ) ) ;
2024-05-03 17:58:40 +01:00
RESOURCE - > sendAllData ( ) ;
}
2024-10-19 23:03:29 +01:00
PHLMONITOR COutputHead : : monitor ( ) {
2025-05-04 19:21:36 +02:00
return m_monitor . lock ( ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
COutputMode : : COutputMode ( SP < CZwlrOutputModeV1 > resource_ , SP < Aquamarine : : SOutputMode > mode_ ) : m_resource ( resource_ ) , m_mode ( mode_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-03 17:58:40 +01:00
return ;
2025-05-04 19:21:36 +02:00
m_resource - > setRelease ( [ this ] ( CZwlrOutputModeV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
m_resource - > setOnDestroy ( [ this ] ( CZwlrOutputModeV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
2024-05-03 17:58:40 +01:00
}
void COutputMode : : sendAllData ( ) {
2025-05-04 19:21:36 +02:00
if ( ! m_mode )
2024-05-03 17:58:40 +01:00
return ;
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | sending mode {}x{}@{}mHz, pref: {} " , m_mode - > pixelSize . x , m_mode - > pixelSize . y , m_mode - > refreshRate , m_mode - > preferred ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
m_resource - > sendSize ( m_mode - > pixelSize . x , m_mode - > pixelSize . y ) ;
if ( m_mode - > refreshRate > 0 )
m_resource - > sendRefresh ( m_mode - > refreshRate ) ;
if ( m_mode - > preferred )
m_resource - > sendPreferred ( ) ;
2024-05-03 17:58:40 +01:00
}
bool COutputMode : : good ( ) {
2025-05-04 19:21:36 +02:00
return m_resource - > resource ( ) ;
2024-05-03 17:58:40 +01:00
}
2024-07-21 13:09:54 +02:00
SP < Aquamarine : : SOutputMode > COutputMode : : getMode ( ) {
2025-05-04 19:21:36 +02:00
return m_mode . lock ( ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
COutputConfiguration : : COutputConfiguration ( SP < CZwlrOutputConfigurationV1 > resource_ , SP < COutputManager > owner_ ) : m_resource ( resource_ ) , m_owner ( owner_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-03 17:58:40 +01:00
return ;
2025-05-04 19:21:36 +02:00
m_resource - > setDestroy ( [ this ] ( CZwlrOutputConfigurationV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
m_resource - > setOnDestroy ( [ this ] ( CZwlrOutputConfigurationV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
m_resource - > setEnableHead ( [ this ] ( CZwlrOutputConfigurationV1 * r , uint32_t id , wl_resource * outputHead ) {
2024-05-03 17:58:40 +01:00
const auto HEAD = PROTO : : outputManagement - > headFromResource ( outputHead ) ;
if ( ! HEAD ) {
LOGM ( ERR , " No head in setEnableHead?? " ) ;
return ;
}
const auto PMONITOR = HEAD - > monitor ( ) ;
if ( ! PMONITOR ) {
LOGM ( ERR , " No monitor in setEnableHead?? " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
const auto RESOURCE = PROTO : : outputManagement - > m_configurationHeads . emplace_back (
makeShared < COutputConfigurationHead > ( makeShared < CZwlrOutputConfigurationHeadV1 > ( m_resource - > client ( ) , m_resource - > version ( ) , id ) , PMONITOR ) ) ;
2024-05-03 17:58:40 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2025-05-04 19:21:36 +02:00
m_resource - > noMemory ( ) ;
PROTO : : outputManagement - > m_configurationHeads . pop_back ( ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_heads . emplace_back ( RESOURCE ) ;
2024-05-03 17:58:40 +01:00
2025-04-30 23:45:20 +02:00
LOGM ( LOG , " enableHead on {}. For now, doing nothing. Waiting for apply(). " , PMONITOR - > m_name ) ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setDisableHead ( [ this ] ( CZwlrOutputConfigurationV1 * r , wl_resource * outputHead ) {
2024-05-03 17:58:40 +01:00
const auto HEAD = PROTO : : outputManagement - > headFromResource ( outputHead ) ;
if ( ! HEAD ) {
LOGM ( ERR , " No head in setDisableHead?? " ) ;
return ;
}
const auto PMONITOR = HEAD - > monitor ( ) ;
if ( ! PMONITOR ) {
LOGM ( ERR , " No monitor in setDisableHead?? " ) ;
return ;
}
2025-04-30 23:45:20 +02:00
LOGM ( LOG , " disableHead on {} " , PMONITOR - > m_name ) ;
2024-05-03 17:58:40 +01:00
2024-09-26 11:10:53 +01:00
SWlrManagerSavedOutputState newState ;
2025-05-04 19:21:36 +02:00
if ( m_owner - > m_monitorStates . contains ( PMONITOR - > m_name ) )
newState = m_owner - > m_monitorStates . at ( PMONITOR - > m_name ) ;
2024-09-26 11:10:53 +01:00
newState . enabled = false ;
2025-04-20 20:39:33 +02:00
g_pConfigManager - > m_wantsMonitorReload = true ;
2024-09-26 11:10:53 +01:00
2025-05-04 19:21:36 +02:00
m_owner - > m_monitorStates [ PMONITOR - > m_name ] = newState ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setTest ( [ this ] ( CZwlrOutputConfigurationV1 * r ) {
2024-05-03 17:58:40 +01:00
const auto SUCCESS = applyTestConfiguration ( true ) ;
if ( SUCCESS )
2025-05-04 19:21:36 +02:00
m_resource - > sendSucceeded ( ) ;
2024-05-03 17:58:40 +01:00
else
2025-05-04 19:21:36 +02:00
m_resource - > sendFailed ( ) ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setApply ( [ this ] ( CZwlrOutputConfigurationV1 * r ) {
2024-05-03 17:58:40 +01:00
const auto SUCCESS = applyTestConfiguration ( false ) ;
if ( SUCCESS )
2025-05-04 19:21:36 +02:00
m_resource - > sendSucceeded ( ) ;
2024-05-03 17:58:40 +01:00
else
2025-05-04 19:21:36 +02:00
m_resource - > sendFailed ( ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
m_owner - > sendDone ( ) ;
2024-05-03 17:58:40 +01:00
} ) ;
}
bool COutputConfiguration : : good ( ) {
2025-05-04 19:21:36 +02:00
return m_resource - > resource ( ) ;
2024-05-03 17:58:40 +01:00
}
bool COutputConfiguration : : applyTestConfiguration ( bool test ) {
if ( test ) {
LOGM ( WARN , " TODO: STUB: applyTestConfiguration for test not implemented, returning true. " ) ;
return true ;
}
LOGM ( LOG , " Applying configuration " ) ;
2025-05-04 19:21:36 +02:00
if ( ! m_owner ) {
2024-09-26 11:10:53 +01:00
LOGM ( ERR , " applyTestConfiguration: no owner?! " ) ;
return false ;
}
2025-05-04 19:21:36 +02:00
for ( auto const & headw : m_heads ) {
2024-05-03 17:58:40 +01:00
auto head = headw . lock ( ) ;
if ( ! head )
continue ;
2025-05-04 19:21:36 +02:00
const auto PMONITOR = head - > m_monitor ;
2024-05-03 17:58:40 +01:00
if ( ! PMONITOR )
continue ;
2025-04-30 23:45:20 +02:00
LOGM ( LOG , " Saving config for monitor {} " , PMONITOR - > m_name ) ;
2024-09-26 11:10:53 +01:00
SWlrManagerSavedOutputState newState ;
2025-05-04 19:21:36 +02:00
if ( m_owner - > m_monitorStates . contains ( PMONITOR - > m_name ) )
newState = m_owner - > m_monitorStates . at ( PMONITOR - > m_name ) ;
2024-05-03 17:58:40 +01:00
2024-09-26 11:10:53 +01:00
newState . enabled = true ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
if ( head - > m_state . committedProperties & eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_MODE ) {
newState . resolution = head - > m_state . mode - > getMode ( ) - > pixelSize ;
newState . refresh = head - > m_state . mode - > getMode ( ) - > refreshRate ;
2024-09-26 11:10:53 +01:00
newState . committedProperties | = eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_MODE ;
LOGM ( LOG , " > Mode: {:.0f}x{:.0f}@{}mHz " , newState . resolution . x , newState . resolution . y , newState . refresh ) ;
2025-05-04 19:21:36 +02:00
} else if ( head - > m_state . committedProperties & eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_CUSTOM_MODE ) {
newState . resolution = head - > m_state . customMode . size ;
newState . refresh = head - > m_state . customMode . refresh ;
2024-09-26 11:10:53 +01:00
newState . committedProperties | = eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_CUSTOM_MODE ;
LOGM ( LOG , " > Custom mode: {:.0f}x{:.0f}@{}mHz " , newState . resolution . x , newState . resolution . y , newState . refresh ) ;
2024-05-03 17:58:40 +01:00
}
2025-05-04 19:21:36 +02:00
if ( head - > m_state . committedProperties & eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_POSITION ) {
newState . position = head - > m_state . position ;
2024-09-26 11:10:53 +01:00
newState . committedProperties | = eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_POSITION ;
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " > Position: {:.0f}, {:.0f} " , head - > m_state . position . x , head - > m_state . position . y ) ;
2024-09-26 11:10:53 +01:00
}
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
if ( head - > m_state . committedProperties & eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC ) {
newState . adaptiveSync = head - > m_state . adaptiveSync ;
2024-09-26 11:10:53 +01:00
newState . committedProperties | = eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC ;
LOGM ( LOG , " > vrr: {} " , newState . adaptiveSync ) ;
}
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
if ( head - > m_state . committedProperties & eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_SCALE ) {
newState . scale = head - > m_state . scale ;
2024-09-26 11:10:53 +01:00
newState . committedProperties | = eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_SCALE ;
LOGM ( LOG , " > scale: {:.2f} " , newState . scale ) ;
}
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
if ( head - > m_state . committedProperties & eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_TRANSFORM ) {
newState . transform = head - > m_state . transform ;
2024-09-26 11:10:53 +01:00
newState . committedProperties | = eWlrOutputCommittedProperties : : OUTPUT_HEAD_COMMITTED_TRANSFORM ;
LOGM ( LOG , " > transform: {} " , ( uint8_t ) newState . transform ) ;
}
2024-05-03 17:58:40 +01:00
// reset properties for next set.
2025-05-04 19:21:36 +02:00
head - > m_state . committedProperties = 0 ;
2024-05-03 17:58:40 +01:00
2025-04-20 20:39:33 +02:00
g_pConfigManager - > m_wantsMonitorReload = true ;
2024-09-26 11:10:53 +01:00
2025-05-04 19:21:36 +02:00
m_owner - > m_monitorStates [ PMONITOR - > m_name ] = newState ;
2024-05-03 17:58:40 +01:00
}
2024-09-26 11:10:53 +01:00
LOGM ( LOG , " Saved configuration " ) ;
2024-05-03 17:58:40 +01:00
return true ;
}
2025-05-04 19:21:36 +02:00
COutputConfigurationHead : : COutputConfigurationHead ( SP < CZwlrOutputConfigurationHeadV1 > resource_ , PHLMONITOR pMonitor_ ) : m_resource ( resource_ ) , m_monitor ( pMonitor_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-03 17:58:40 +01:00
return ;
2025-05-04 19:21:36 +02:00
m_resource - > setOnDestroy ( [ this ] ( CZwlrOutputConfigurationHeadV1 * r ) { PROTO : : outputManagement - > destroyResource ( this ) ; } ) ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
m_resource - > setSetMode ( [ this ] ( CZwlrOutputConfigurationHeadV1 * r , wl_resource * outputMode ) {
2024-05-03 17:58:40 +01:00
const auto MODE = PROTO : : outputManagement - > modeFromResource ( outputMode ) ;
if ( ! MODE | | ! MODE - > getMode ( ) ) {
LOGM ( ERR , " No mode in setMode?? " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
if ( ! m_monitor ) {
2024-05-03 17:58:40 +01:00
LOGM ( ERR , " setMode on inert resource " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
if ( m_state . committedProperties & OUTPUT_HEAD_COMMITTED_MODE ) {
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET , " Property already set " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_state . committedProperties | = OUTPUT_HEAD_COMMITTED_MODE ;
m_state . mode = MODE ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | configHead for {}: set mode to {}x{}@{} " , m_monitor - > m_name , MODE - > getMode ( ) - > pixelSize . x , MODE - > getMode ( ) - > pixelSize . y , MODE - > getMode ( ) - > refreshRate ) ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setSetCustomMode ( [ this ] ( CZwlrOutputConfigurationHeadV1 * r , int32_t w , int32_t h , int32_t refresh ) {
if ( ! m_monitor ) {
2024-05-03 17:58:40 +01:00
LOGM ( ERR , " setCustomMode on inert resource " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
if ( m_state . committedProperties & OUTPUT_HEAD_COMMITTED_CUSTOM_MODE ) {
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET , " Property already set " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2024-09-30 17:40:38 +01:00
if ( w < = 0 | | h < = 0 | | refresh < 0 ) {
2025-05-04 19:21:36 +02:00
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE , " Invalid mode " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2024-09-30 17:40:38 +01:00
if ( refresh = = 0 ) {
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | configHead for {}: refreshRate 0, using old refresh rate of {:.2f}Hz " , m_monitor - > m_name , m_monitor - > m_refreshRate ) ;
refresh = std : : round ( m_monitor - > m_refreshRate * 1000.F ) ;
2024-09-30 17:40:38 +01:00
}
2025-05-04 19:21:36 +02:00
m_state . committedProperties | = OUTPUT_HEAD_COMMITTED_CUSTOM_MODE ;
m_state . customMode = { { w , h } , ( uint32_t ) refresh } ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | configHead for {}: set custom mode to {}x{}@{} " , m_monitor - > m_name , w , h , refresh ) ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setSetPosition ( [ this ] ( CZwlrOutputConfigurationHeadV1 * r , int32_t x , int32_t y ) {
if ( ! m_monitor ) {
2024-05-03 17:58:40 +01:00
LOGM ( ERR , " setMode on inert resource " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
if ( m_state . committedProperties & OUTPUT_HEAD_COMMITTED_POSITION ) {
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET , " Property already set " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_state . committedProperties | = OUTPUT_HEAD_COMMITTED_POSITION ;
m_state . position = { x , y } ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | configHead for {}: set pos to {}, {} " , m_monitor - > m_name , x , y ) ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setSetTransform ( [ this ] ( CZwlrOutputConfigurationHeadV1 * r , int32_t transform ) {
if ( ! m_monitor ) {
2024-05-03 17:58:40 +01:00
LOGM ( ERR , " setMode on inert resource " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
if ( m_state . committedProperties & OUTPUT_HEAD_COMMITTED_TRANSFORM ) {
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET , " Property already set " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
if ( transform < 0 | | transform > 7 ) {
2025-05-04 19:21:36 +02:00
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_TRANSFORM , " Invalid transform " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_state . committedProperties | = OUTPUT_HEAD_COMMITTED_TRANSFORM ;
m_state . transform = ( wl_output_transform ) transform ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | configHead for {}: set transform to {} " , m_monitor - > m_name , transform ) ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setSetScale ( [ this ] ( CZwlrOutputConfigurationHeadV1 * r , wl_fixed_t scale_ ) {
if ( ! m_monitor ) {
2024-05-03 17:58:40 +01:00
LOGM ( ERR , " setMode on inert resource " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
if ( m_state . committedProperties & OUTPUT_HEAD_COMMITTED_SCALE ) {
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET , " Property already set " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
double scale = wl_fixed_to_double ( scale_ ) ;
if ( scale < 0.1 | | scale > 10.0 ) {
2025-05-04 19:21:36 +02:00
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_SCALE , " Invalid scale " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_state . committedProperties | = OUTPUT_HEAD_COMMITTED_SCALE ;
m_state . scale = scale ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | configHead for {}: set scale to {:.2f} " , m_monitor - > m_name , scale ) ;
2024-05-03 17:58:40 +01:00
} ) ;
2025-05-04 19:21:36 +02:00
m_resource - > setSetAdaptiveSync ( [ this ] ( CZwlrOutputConfigurationHeadV1 * r , uint32_t as ) {
if ( ! m_monitor ) {
2024-05-03 17:58:40 +01:00
LOGM ( ERR , " setMode on inert resource " ) ;
return ;
}
2025-05-04 19:21:36 +02:00
if ( m_state . committedProperties & OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC ) {
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET , " Property already set " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
if ( as > 1 ) {
2025-05-04 19:21:36 +02:00
m_resource - > error ( ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_ADAPTIVE_SYNC_STATE , " Invalid adaptive sync state " ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
m_state . committedProperties | = OUTPUT_HEAD_COMMITTED_ADAPTIVE_SYNC ;
m_state . adaptiveSync = as ;
2024-05-03 17:58:40 +01:00
2025-05-04 19:21:36 +02:00
LOGM ( LOG , " | configHead for {}: set adaptiveSync to {} " , m_monitor - > m_name , as ) ;
2024-05-03 17:58:40 +01:00
} ) ;
}
bool COutputConfigurationHead : : good ( ) {
2025-05-04 19:21:36 +02:00
return m_resource - > resource ( ) ;
2024-05-03 17:58:40 +01:00
}
COutputManagementProtocol : : COutputManagementProtocol ( const wl_interface * iface , const int & ver , const std : : string & name ) : IWaylandProtocol ( iface , ver , name ) {
static auto P = g_pHookSystem - > hookDynamic ( " monitorLayoutChanged " , [ this ] ( void * self , SCallbackInfo & info , std : : any param ) { this - > updateAllOutputs ( ) ; } ) ;
}
void COutputManagementProtocol : : bindManager ( wl_client * client , void * data , uint32_t ver , uint32_t id ) {
2025-05-04 19:21:36 +02:00
const auto RESOURCE = m_managers . emplace_back ( makeShared < COutputManager > ( makeShared < CZwlrOutputManagerV1 > ( client , ver , id ) ) ) ;
2024-05-03 17:58:40 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2024-05-03 17:58:40 +01:00
wl_client_post_no_memory ( client ) ;
2025-05-04 19:21:36 +02:00
m_managers . pop_back ( ) ;
2024-05-03 17:58:40 +01:00
return ;
}
2025-05-04 19:21:36 +02:00
RESOURCE - > m_self = RESOURCE ;
2024-05-03 17:58:40 +01:00
}
void COutputManagementProtocol : : destroyResource ( COutputManager * resource ) {
2025-05-04 19:21:36 +02:00
std : : erase_if ( m_managers , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-03 17:58:40 +01:00
}
void COutputManagementProtocol : : destroyResource ( COutputHead * resource ) {
2025-05-04 19:21:36 +02:00
std : : erase_if ( m_heads , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-03 17:58:40 +01:00
}
void COutputManagementProtocol : : destroyResource ( COutputMode * resource ) {
2025-05-04 19:21:36 +02:00
std : : erase_if ( m_modes , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-03 17:58:40 +01:00
}
void COutputManagementProtocol : : destroyResource ( COutputConfiguration * resource ) {
2025-05-04 19:21:36 +02:00
std : : erase_if ( m_configurations , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-03 17:58:40 +01:00
}
void COutputManagementProtocol : : destroyResource ( COutputConfigurationHead * resource ) {
2025-05-04 19:21:36 +02:00
std : : erase_if ( m_configurationHeads , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-03 17:58:40 +01:00
}
void COutputManagementProtocol : : updateAllOutputs ( ) {
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_realMonitors ) {
2025-05-04 19:21:36 +02:00
for ( auto const & mgr : m_managers ) {
2024-10-19 23:03:29 +01:00
mgr - > ensureMonitorSent ( m ) ;
2024-05-03 17:58:40 +01:00
}
}
}
SP < COutputHead > COutputManagementProtocol : : headFromResource ( wl_resource * r ) {
2025-05-04 19:21:36 +02:00
for ( auto const & h : m_heads ) {
if ( h - > m_resource - > resource ( ) = = r )
2024-05-03 17:58:40 +01:00
return h ;
}
return nullptr ;
}
SP < COutputMode > COutputManagementProtocol : : modeFromResource ( wl_resource * r ) {
2025-05-04 19:21:36 +02:00
for ( auto const & h : m_modes ) {
if ( h - > m_resource - > resource ( ) = = r )
2024-05-03 17:58:40 +01:00
return h ;
}
return nullptr ;
}
2024-09-26 11:10:53 +01:00
2024-10-26 02:06:13 +01:00
SP < SWlrManagerSavedOutputState > COutputManagementProtocol : : getOutputStateFor ( PHLMONITOR pMonitor ) {
2025-05-04 19:21:36 +02:00
for ( auto const & m : m_managers ) {
if ( ! m - > m_monitorStates . contains ( pMonitor - > m_name ) )
2024-09-26 11:10:53 +01:00
continue ;
2025-05-04 19:21:36 +02:00
return makeShared < SWlrManagerSavedOutputState > ( m - > m_monitorStates . at ( pMonitor - > m_name ) ) ;
2024-09-26 11:10:53 +01:00
}
return nullptr ;
}