2022-07-27 12:32:00 +02:00
# include "Monitor.hpp"
# include "../Compositor.hpp"
void CMonitor : : onConnect ( bool noRule ) {
2022-11-19 14:14:55 +01:00
hyprListener_monitorDestroy . removeCallback ( ) ;
hyprListener_monitorFrame . removeCallback ( ) ;
2022-11-19 17:28:04 +01:00
hyprListener_monitorStateRequest . removeCallback ( ) ;
2022-11-19 14:14:55 +01:00
hyprListener_monitorFrame . initCallback ( & output - > events . frame , & Events : : listener_monitorFrame , this ) ;
hyprListener_monitorDestroy . initCallback ( & output - > events . destroy , & Events : : listener_monitorDestroy , this ) ;
2022-11-19 17:28:04 +01:00
hyprListener_monitorStateRequest . initCallback ( & output - > events . request_state , & Events : : listener_monitorStateRequest , this ) ;
2022-11-19 14:14:55 +01:00
if ( m_bEnabled ) {
wlr_output_enable ( output , 1 ) ;
wlr_output_commit ( output ) ;
2022-08-03 16:05:25 +02:00
return ;
2022-11-19 14:14:55 +01:00
}
2022-08-03 16:05:25 +02:00
2022-08-10 13:44:04 +02:00
szName = output - > name ;
2022-11-05 19:04:44 +01:00
if ( ! wlr_backend_is_drm ( output - > backend ) )
createdByUser = true ; // should be true. WL, X11 and Headless backends should be addable / removable
2022-07-27 12:32:00 +02:00
// get monitor rule that matches
2022-10-05 11:22:33 +02:00
SMonitorRule monitorRule = g_pConfigManager - > getMonitorRuleFor ( output - > name , output - > description ? output - > description : " " ) ;
2022-07-27 12:32:00 +02:00
// if it's disabled, disable and ignore
if ( monitorRule . disabled ) {
2022-08-10 13:31:58 +02:00
wlr_output_set_scale ( output , 1 ) ;
wlr_output_set_transform ( output , WL_OUTPUT_TRANSFORM_NORMAL ) ;
auto PREFSTATE = wlr_output_preferred_mode ( output ) ;
if ( ! PREFSTATE ) {
wlr_output_mode * mode ;
wl_list_for_each ( mode , & output - > modes , link ) {
wlr_output_set_mode ( output , PREFSTATE ) ;
if ( ! wlr_output_test ( output ) )
continue ;
2022-09-25 20:07:48 +02:00
2022-08-10 13:31:58 +02:00
PREFSTATE = mode ;
break ;
}
}
if ( PREFSTATE )
wlr_output_set_mode ( output , PREFSTATE ) ;
2022-08-10 13:44:04 +02:00
else
2022-08-10 13:45:20 +02:00
Debug : : log ( WARN , " No mode found for disabled output %s " , output - > name ) ;
2022-08-10 13:31:58 +02:00
2022-07-27 12:32:00 +02:00
wlr_output_enable ( output , 0 ) ;
2022-09-25 20:07:48 +02:00
2022-08-10 13:44:04 +02:00
if ( ! wlr_output_commit ( output ) ) {
Debug : : log ( ERR , " Couldn't commit disabled state on output %s " , output - > name ) ;
}
Events : : listener_change ( nullptr , nullptr ) ;
2022-07-27 12:32:00 +02:00
2022-08-10 13:31:58 +02:00
m_bEnabled = false ;
2022-07-27 12:32:00 +02:00
hyprListener_monitorFrame . removeCallback ( ) ;
return ;
}
2022-08-27 23:10:13 +02:00
if ( output - > non_desktop ) {
Debug : : log ( LOG , " Not configuring non-desktop output " ) ;
if ( g_pCompositor - > m_sWRLDRMLeaseMgr ) {
wlr_drm_lease_v1_manager_offer_output ( g_pCompositor - > m_sWRLDRMLeaseMgr , output ) ;
}
return ;
}
2022-08-10 13:44:04 +02:00
if ( ! m_bRenderingInitPassed ) {
2022-09-19 21:45:00 +02:00
output - > allocator = nullptr ;
output - > renderer = nullptr ;
2022-08-10 13:44:04 +02:00
wlr_output_init_render ( output , g_pCompositor - > m_sWLRAllocator , g_pCompositor - > m_sWLRRenderer ) ;
m_bRenderingInitPassed = true ;
}
2022-08-03 17:42:19 +02:00
if ( ! m_pThisWrap ) {
// find the wrap
for ( auto & m : g_pCompositor - > m_vRealMonitors ) {
if ( m - > ID = = ID ) {
m_pThisWrap = & m ;
break ;
}
}
}
2022-07-27 12:32:00 +02:00
if ( std : : find_if ( g_pCompositor - > m_vMonitors . begin ( ) , g_pCompositor - > m_vMonitors . end ( ) , [ & ] ( auto & other ) { return other . get ( ) = = this ; } ) = = g_pCompositor - > m_vMonitors . end ( ) ) {
g_pCompositor - > m_vMonitors . push_back ( * m_pThisWrap ) ;
}
2022-09-25 20:07:48 +02:00
2022-07-27 12:32:00 +02:00
m_bEnabled = true ;
2022-11-18 15:15:19 +01:00
2022-07-27 12:32:00 +02:00
wlr_xcursor_manager_load ( g_pCompositor - > m_sWLRXCursorMgr , monitorRule . scale ) ;
// create it in the arr
vecPosition = monitorRule . offset ;
vecSize = monitorRule . resolution ;
refreshRate = monitorRule . refreshRate ;
wlr_output_enable ( output , 1 ) ;
// set mode, also applies
if ( ! noRule )
g_pHyprRenderer - > applyMonitorRule ( this , & monitorRule , true ) ;
2022-08-10 18:27:57 +02:00
Debug : : log ( LOG , " Added new monitor with name %s at %i,%i with size %ix%i, pointer %x " , output - > name , ( int ) vecPosition . x , ( int ) vecPosition . y , ( int ) vecPixelSize . x , ( int ) vecPixelSize . y , output ) ;
2022-07-27 12:32:00 +02:00
damage = wlr_output_damage_create ( output ) ;
// add a WLR workspace group
if ( ! pWLRWorkspaceGroupHandle ) {
pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create ( g_pCompositor - > m_sWLREXTWorkspaceMgr ) ;
}
2022-09-25 20:07:48 +02:00
2022-07-27 12:32:00 +02:00
wlr_ext_workspace_group_handle_v1_output_enter ( pWLRWorkspaceGroupHandle , output ) ;
2022-09-25 20:07:48 +02:00
2022-09-13 15:25:42 +02:00
setupDefaultWS ( monitorRule ) ;
2022-07-27 12:32:00 +02:00
scale = monitorRule . scale ;
2022-08-03 17:42:19 +02:00
m_pThisWrap = nullptr ;
2022-07-27 12:32:00 +02:00
forceFullFrames = 3 ; // force 3 full frames to make sure there is no blinking due to double-buffering.
//
2022-11-19 17:41:36 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitoradded " , szName } ) ;
2022-07-27 12:32:00 +02:00
if ( ! g_pCompositor - > m_pLastMonitor ) // set the last monitor if it isnt set yet
2022-11-19 17:41:36 +01:00
g_pCompositor - > setActiveMonitor ( this ) ;
2022-07-27 12:32:00 +02:00
2022-08-10 21:22:11 +02:00
wlr_xcursor_manager_load ( g_pCompositor - > m_sWLRXCursorMgr , scale ) ;
2022-08-10 21:54:09 +02:00
g_pHyprRenderer - > arrangeLayersForMonitor ( ID ) ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( ID ) ;
2022-10-22 22:45:17 +02:00
// ensure VRR (will enable if necessary)
2022-10-29 00:48:48 +02:00
g_pConfigManager - > ensureVRR ( this ) ;
2022-07-27 12:32:00 +02:00
}
void CMonitor : : onDisconnect ( ) {
2022-08-03 16:05:25 +02:00
2022-10-06 19:43:50 +02:00
if ( ! m_bEnabled | | g_pCompositor - > m_bIsShuttingDown )
2022-08-03 16:05:25 +02:00
return ;
2022-11-19 14:01:32 +01:00
Debug : : log ( LOG , " onDisconnect called for %s " , output - > name ) ;
2022-07-27 12:32:00 +02:00
// Cleanup everything. Move windows back, snap cursor, shit.
CMonitor * BACKUPMON = nullptr ;
for ( auto & m : g_pCompositor - > m_vMonitors ) {
if ( m . get ( ) ! = this ) {
BACKUPMON = m . get ( ) ;
break ;
}
}
2022-10-29 23:45:01 +02:00
if ( g_pCompositor - > m_pLastMonitor = = this )
2022-11-19 17:41:36 +01:00
g_pCompositor - > setActiveMonitor ( BACKUPMON ) ;
2022-10-29 23:45:01 +02:00
2022-09-13 15:25:42 +02:00
// remove mirror
if ( pMirrorOf ) {
pMirrorOf - > mirrors . erase ( std : : find_if ( pMirrorOf - > mirrors . begin ( ) , pMirrorOf - > mirrors . end ( ) , [ & ] ( const auto & other ) { return other = = this ; } ) ) ;
pMirrorOf = nullptr ;
}
if ( ! mirrors . empty ( ) ) {
for ( auto & m : mirrors ) {
m - > setMirror ( " " ) ;
}
g_pConfigManager - > m_bWantsMonitorReload = true ;
}
2022-07-27 12:32:00 +02:00
m_bEnabled = false ;
2022-08-10 23:19:15 +02:00
m_bRenderingInitPassed = false ;
2022-07-27 12:32:00 +02:00
hyprListener_monitorFrame . removeCallback ( ) ;
2022-08-10 21:54:09 +02:00
if ( ! BACKUPMON ) {
Debug : : log ( WARN , " Unplugged last monitor, entering an unsafe state. Good luck my friend. " ) ;
2022-11-19 17:28:04 +01:00
hyprListener_monitorStateRequest . removeCallback ( ) ;
2022-08-10 21:54:09 +02:00
hyprListener_monitorDestroy . removeCallback ( ) ;
g_pCompositor - > m_bUnsafeState = true ;
return ;
}
2022-07-27 12:32:00 +02:00
// snap cursor
2022-11-17 22:52:45 +01:00
wlr_cursor_warp ( g_pCompositor - > m_sWLRCursor , nullptr , BACKUPMON - > vecPosition . x + BACKUPMON - > vecTransformedSize . x / 2.f , BACKUPMON - > vecPosition . y + BACKUPMON - > vecTransformedSize . y / 2.f ) ;
2022-07-27 12:32:00 +02:00
// move workspaces
std : : deque < CWorkspace * > wspToMove ;
for ( auto & w : g_pCompositor - > m_vWorkspaces ) {
if ( w - > m_iMonitorID = = ID ) {
wspToMove . push_back ( w . get ( ) ) ;
}
}
for ( auto & w : wspToMove ) {
g_pCompositor - > moveWorkspaceToMonitor ( w , BACKUPMON ) ;
w - > startAnim ( true , true , true ) ;
}
activeWorkspace = - 1 ;
wlr_output_damage_destroy ( damage ) ;
wlr_output_layout_remove ( g_pCompositor - > m_sWLROutputLayout , output ) ;
wlr_output_enable ( output , false ) ;
wlr_output_commit ( output ) ;
2022-11-17 22:52:45 +01:00
std : : erase_if ( g_pCompositor - > m_vWorkspaces , [ & ] ( std : : unique_ptr < CWorkspace > & el ) { return el - > m_iMonitorID = = ID ; } ) ;
2022-07-27 12:32:00 +02:00
Debug : : log ( LOG , " Removed monitor %s! " , szName . c_str ( ) ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitorremoved " , szName } ) ;
2022-11-17 22:52:45 +01:00
std : : erase_if ( g_pCompositor - > m_vMonitors , [ & ] ( std : : shared_ptr < CMonitor > & el ) { return el . get ( ) = = this ; } ) ;
2022-07-27 12:32:00 +02:00
}
2022-08-23 16:07:47 +02:00
void CMonitor : : addDamage ( pixman_region32_t * rg ) {
wlr_output_damage_add ( damage , rg ) ;
}
void CMonitor : : addDamage ( wlr_box * box ) {
wlr_output_damage_add_box ( damage , box ) ;
}
2022-09-13 15:25:42 +02:00
bool CMonitor : : isMirror ( ) {
return pMirrorOf ! = nullptr ;
}
void CMonitor : : setupDefaultWS ( const SMonitorRule & monitorRule ) {
// Workspace
std : : string newDefaultWorkspaceName = " " ;
auto WORKSPACEID = monitorRule . defaultWorkspace = = " " ? g_pCompositor - > m_vWorkspaces . size ( ) + 1 : getWorkspaceIDFromString ( monitorRule . defaultWorkspace , newDefaultWorkspaceName ) ;
2022-11-27 23:42:22 +01:00
if ( WORKSPACEID = = INT_MAX | | ( WORKSPACEID > = SPECIAL_WORKSPACE_START & & WORKSPACEID < = - 2 ) ) {
2022-09-13 15:25:42 +02:00
WORKSPACEID = g_pCompositor - > m_vWorkspaces . size ( ) + 1 ;
newDefaultWorkspaceName = std : : to_string ( WORKSPACEID ) ;
Debug : : log ( LOG , " Invalid workspace= directive name in monitor parsing, workspace name \" %s \" is invalid. " , monitorRule . defaultWorkspace . c_str ( ) ) ;
}
auto PNEWWORKSPACE = g_pCompositor - > getWorkspaceByID ( WORKSPACEID ) ;
Debug : : log ( LOG , " New monitor: WORKSPACEID %d, exists: %d " , WORKSPACEID , ( int ) ( PNEWWORKSPACE ! = nullptr ) ) ;
if ( PNEWWORKSPACE ) {
// workspace exists, move it to the newly connected monitor
g_pCompositor - > moveWorkspaceToMonitor ( PNEWWORKSPACE , this ) ;
activeWorkspace = PNEWWORKSPACE - > m_iID ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( ID ) ;
PNEWWORKSPACE - > startAnim ( true , true , true ) ;
} else {
if ( newDefaultWorkspaceName = = " " )
newDefaultWorkspaceName = std : : to_string ( WORKSPACEID ) ;
PNEWWORKSPACE = g_pCompositor - > m_vWorkspaces . emplace_back ( std : : make_unique < CWorkspace > ( ID , newDefaultWorkspaceName ) ) . get ( ) ;
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name ( PNEWWORKSPACE - > m_pWlrHandle , newDefaultWorkspaceName . c_str ( ) ) ;
PNEWWORKSPACE - > m_iID = WORKSPACEID ;
}
activeWorkspace = PNEWWORKSPACE - > m_iID ;
g_pCompositor - > deactivateAllWLRWorkspaces ( PNEWWORKSPACE - > m_pWlrHandle ) ;
PNEWWORKSPACE - > setActive ( true ) ;
}
void CMonitor : : setMirror ( const std : : string & mirrorOf ) {
const auto PMIRRORMON = g_pCompositor - > getMonitorFromString ( mirrorOf ) ;
if ( PMIRRORMON = = pMirrorOf )
return ;
if ( PMIRRORMON & & PMIRRORMON - > isMirror ( ) ) {
Debug : : log ( ERR , " Cannot mirror a mirror! " ) ;
return ;
}
if ( PMIRRORMON = = this ) {
Debug : : log ( ERR , " Cannot mirror self! " ) ;
return ;
}
if ( ! PMIRRORMON ) {
// disable mirroring
if ( pMirrorOf ) {
pMirrorOf - > mirrors . erase ( std : : find_if ( pMirrorOf - > mirrors . begin ( ) , pMirrorOf - > mirrors . end ( ) , [ & ] ( const auto & other ) { return other = = this ; } ) ) ;
}
pMirrorOf = nullptr ;
// set rule
2022-10-05 11:22:33 +02:00
const auto RULE = g_pConfigManager - > getMonitorRuleFor ( this - > szName , this - > output - > description ? this - > output - > description : " " ) ;
2022-09-13 15:25:42 +02:00
vecPosition = RULE . offset ;
// push to mvmonitors
if ( ! m_pThisWrap ) {
// find the wrap
for ( auto & m : g_pCompositor - > m_vRealMonitors ) {
if ( m - > ID = = ID ) {
m_pThisWrap = & m ;
break ;
}
}
}
if ( std : : find_if ( g_pCompositor - > m_vMonitors . begin ( ) , g_pCompositor - > m_vMonitors . end ( ) , [ & ] ( auto & other ) { return other . get ( ) = = this ; } ) = = g_pCompositor - > m_vMonitors . end ( ) ) {
g_pCompositor - > m_vMonitors . push_back ( * m_pThisWrap ) ;
}
setupDefaultWS ( RULE ) ;
2022-11-19 17:58:14 +01:00
g_pHyprRenderer - > applyMonitorRule ( this , ( SMonitorRule * ) & RULE , true ) ; // will apply the offset and stuff
2022-09-13 15:25:42 +02:00
} else {
CMonitor * BACKUPMON = nullptr ;
for ( auto & m : g_pCompositor - > m_vMonitors ) {
if ( m . get ( ) ! = this ) {
BACKUPMON = m . get ( ) ;
break ;
}
}
// move all the WS
std : : deque < CWorkspace * > wspToMove ;
for ( auto & w : g_pCompositor - > m_vWorkspaces ) {
if ( w - > m_iMonitorID = = ID ) {
wspToMove . push_back ( w . get ( ) ) ;
}
}
for ( auto & w : wspToMove ) {
g_pCompositor - > moveWorkspaceToMonitor ( w , BACKUPMON ) ;
w - > startAnim ( true , true , true ) ;
}
activeWorkspace = - 1 ;
wlr_output_layout_remove ( g_pCompositor - > m_sWLROutputLayout , output ) ;
vecPosition = Vector2D ( - 1337420 , - 1337420 ) ;
pMirrorOf = PMIRRORMON ;
pMirrorOf - > mirrors . push_back ( this ) ;
// remove from mvmonitors
if ( std : : find_if ( g_pCompositor - > m_vMonitors . begin ( ) , g_pCompositor - > m_vMonitors . end ( ) , [ & ] ( auto & other ) { return other . get ( ) = = this ; } ) ! = g_pCompositor - > m_vMonitors . end ( ) ) {
g_pCompositor - > m_vMonitors . erase ( std : : remove_if ( g_pCompositor - > m_vMonitors . begin ( ) , g_pCompositor - > m_vMonitors . end ( ) , [ & ] ( const auto & other ) { return other . get ( ) = = this ; } ) ) ;
}
2022-11-19 17:41:36 +01:00
g_pCompositor - > setActiveMonitor ( g_pCompositor - > m_vMonitors . front ( ) . get ( ) ) ;
2022-09-13 15:25:42 +02:00
}
2022-09-19 20:44:33 +02:00
}