2022-07-27 12:32:00 +02:00
# include "Monitor.hpp"
2024-02-15 15:22:20 +01:00
# include "MiscFunctions.hpp"
2022-07-27 12:32:00 +02:00
# include "../Compositor.hpp"
2024-03-03 19:39:20 +01:00
# include "../config/ConfigValue.hpp"
2023-03-24 20:23:16 +01:00
int ratHandler ( void * data ) {
g_pHyprRenderer - > renderMonitor ( ( CMonitor * ) data ) ;
return 1 ;
}
2024-01-28 02:57:13 +01:00
CMonitor : : CMonitor ( ) : state ( this ) {
2023-04-07 13:18:40 +02:00
wlr_damage_ring_init ( & damage ) ;
}
CMonitor : : ~ CMonitor ( ) {
wlr_damage_ring_finish ( & damage ) ;
2023-07-18 15:36:27 +02:00
hyprListener_monitorDestroy . removeCallback ( ) ;
hyprListener_monitorFrame . removeCallback ( ) ;
hyprListener_monitorStateRequest . removeCallback ( ) ;
hyprListener_monitorDamage . removeCallback ( ) ;
hyprListener_monitorNeedsFrame . removeCallback ( ) ;
hyprListener_monitorCommit . removeCallback ( ) ;
hyprListener_monitorBind . removeCallback ( ) ;
2023-04-07 13:18:40 +02:00
}
2022-07-27 12:32:00 +02:00
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 ( ) ;
2023-04-07 17:31:51 +02:00
hyprListener_monitorDamage . removeCallback ( ) ;
2023-04-07 18:25:56 +02:00
hyprListener_monitorNeedsFrame . removeCallback ( ) ;
2023-04-12 22:40:51 +02:00
hyprListener_monitorCommit . removeCallback ( ) ;
2023-06-23 21:14:04 +02:00
hyprListener_monitorBind . 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 ) ;
2023-04-07 17:31:51 +02:00
hyprListener_monitorDamage . initCallback ( & output - > events . damage , & Events : : listener_monitorDamage , this ) ;
2023-04-07 18:25:56 +02:00
hyprListener_monitorNeedsFrame . initCallback ( & output - > events . needs_frame , & Events : : listener_monitorNeedsFrame , this ) ;
2023-04-12 22:40:51 +02:00
hyprListener_monitorCommit . initCallback ( & output - > events . commit , & Events : : listener_monitorCommit , this ) ;
2023-06-23 21:14:04 +02:00
hyprListener_monitorBind . initCallback ( & output - > events . bind , & Events : : listener_monitorBind , this ) ;
2022-11-19 14:14:55 +01:00
2023-09-30 18:07:50 +02:00
tearingState . canTear = wlr_backend_is_drm ( output - > backend ) ; // tearing only works on drm
2023-09-28 22:48:33 +02:00
2022-11-19 14:14:55 +01:00
if ( m_bEnabled ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_enabled ( state . wlr ( ) , true ) ;
state . commit ( ) ;
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 ;
2023-11-30 02:48:10 +01:00
szDescription = output - > description ? output - > description : " " ;
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
2024-03-05 14:41:51 +01:00
std : : erase ( szDescription , ' , ' ) ;
2023-11-30 02:48:10 +01:00
2024-02-15 15:22:20 +01:00
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
szShortDescription =
removeBeginEndSpacesTabs ( std : : format ( " {} {} {} " , output - > make ? output - > make : " " , output - > model ? output - > model : " " , output - > serial ? output - > serial : " " ) ) ;
2024-03-05 14:41:51 +01:00
std : : erase ( szShortDescription , ' , ' ) ;
2024-02-15 15:22:20 +01:00
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
2024-02-27 23:11:59 +01:00
SMonitorRule monitorRule = g_pConfigManager - > getMonitorRuleFor ( * this ) ;
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
2024-01-28 02:57:13 +01:00
wlr_output_state_set_scale ( state . wlr ( ) , 1 ) ;
wlr_output_state_set_transform ( state . wlr ( ) , WL_OUTPUT_TRANSFORM_NORMAL ) ;
2022-08-10 13:31:58 +02:00
auto PREFSTATE = wlr_output_preferred_mode ( output ) ;
if ( ! PREFSTATE ) {
wlr_output_mode * mode ;
wl_list_for_each ( mode , & output - > modes , link ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( state . wlr ( ) , mode ) ;
2022-08-10 13:31:58 +02:00
2024-01-28 02:57:13 +01:00
if ( ! wlr_output_test_state ( output , state . wlr ( ) ) )
2022-08-10 13:31:58 +02:00
continue ;
2022-09-25 20:07:48 +02:00
2022-08-10 13:31:58 +02:00
PREFSTATE = mode ;
break ;
}
}
if ( PREFSTATE )
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( state . wlr ( ) , PREFSTATE ) ;
2022-08-10 13:44:04 +02:00
else
2023-09-06 12:51:36 +02:00
Debug : : log ( WARN , " No mode found for disabled output {} " , output - > name ) ;
2022-08-10 13:31:58 +02:00
2024-01-28 02:57:13 +01:00
wlr_output_state_set_enabled ( state . wlr ( ) , 0 ) ;
2022-09-25 20:07:48 +02:00
2024-01-28 02:57:13 +01:00
if ( ! state . commit ( ) )
2023-09-06 12:51:36 +02:00
Debug : : log ( ERR , " Couldn't commit disabled state on output {} " , output - > name ) ;
2022-08-10 13:44:04 +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 " ) ;
2022-12-16 18:17:31 +01:00
if ( g_pCompositor - > m_sWRLDRMLeaseMgr ) {
wlr_drm_lease_v1_manager_offer_output ( g_pCompositor - > m_sWRLDRMLeaseMgr , output ) ;
}
return ;
}
2022-08-27 23:10:13 +02:00
2022-08-10 13:44:04 +02:00
if ( ! m_bRenderingInitPassed ) {
2022-09-19 21:45:00 +02:00
output - > allocator = nullptr ;
2022-12-16 18:17:31 +01:00
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 ;
}
2023-11-01 19:53:36 +01:00
std : : shared_ptr < CMonitor > * thisWrapper = nullptr ;
2022-08-03 17:42:19 +02:00
2023-11-01 19:53:36 +01:00
// find the wrap
for ( auto & m : g_pCompositor - > m_vRealMonitors ) {
if ( m - > ID = = ID ) {
thisWrapper = & m ;
break ;
2022-08-03 17:42:19 +02:00
}
}
2023-11-01 19:53:36 +01:00
RASSERT ( thisWrapper - > get ( ) , " CMonitor::onConnect: Had no wrapper??? " ) ;
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 ( * thisWrapper ) ;
2022-09-25 20:07:48 +02:00
2022-07-27 12:32:00 +02:00
m_bEnabled = true ;
2024-01-28 02:57:13 +01:00
wlr_output_state_set_enabled ( state . wlr ( ) , 1 ) ;
2022-07-27 12:32:00 +02:00
// set mode, also applies
if ( ! noRule )
g_pHyprRenderer - > applyMonitorRule ( this , & monitorRule , true ) ;
2024-02-27 23:11:59 +01:00
for ( const auto & PTOUCHDEV : g_pInputManager - > m_lTouchDevices ) {
if ( matchesStaticSelector ( PTOUCHDEV . boundOutput ) ) {
Debug : : log ( LOG , " Binding touch device {} to output {} " , PTOUCHDEV . name , szName ) ;
wlr_cursor_map_input_to_output ( g_pCompositor - > m_sWLRCursor , PTOUCHDEV . pWlrDevice , output ) ;
}
}
for ( const auto & PTABLET : g_pInputManager - > m_lTablets ) {
if ( matchesStaticSelector ( PTABLET . boundOutput ) ) {
Debug : : log ( LOG , " Binding tablet {} to output {} " , PTABLET . name , szName ) ;
wlr_cursor_map_input_to_output ( g_pCompositor - > m_sWLRCursor , PTABLET . wlrDevice , output ) ;
}
}
2024-01-28 02:57:13 +01:00
if ( ! state . commit ( ) )
2024-01-27 14:58:13 +01:00
Debug : : log ( WARN , " wlr_output_commit_state failed in CMonitor::onCommit " ) ;
2023-11-01 19:53:36 +01:00
2023-04-07 13:18:40 +02:00
wlr_damage_ring_set_bounds ( & damage , vecTransformedSize . x , vecTransformedSize . y ) ;
2022-12-15 18:17:15 +01:00
wlr_xcursor_manager_load ( g_pCompositor - > m_sWLRXCursorMgr , scale ) ;
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x} " , output - > name , vecPosition , vecPixelSize , ( uintptr_t ) output ) ;
2022-07-27 12:32:00 +02:00
2022-09-13 15:25:42 +02:00
setupDefaultWS ( monitorRule ) ;
2022-07-27 12:32:00 +02:00
2023-05-03 16:15:56 +02:00
for ( auto & ws : g_pCompositor - > m_vWorkspaces ) {
2023-05-06 17:49:46 +02:00
if ( ws - > m_szLastMonitor = = szName | | g_pCompositor - > m_vMonitors . size ( ) = = 1 /* avoid lost workspaces on recover */ ) {
2023-05-03 16:15:56 +02:00
g_pCompositor - > moveWorkspaceToMonitor ( ws . get ( ) , this ) ;
ws - > startAnim ( true , true , true ) ;
ws - > m_szLastMonitor = " " ;
}
}
2022-07-27 12:32:00 +02:00
scale = monitorRule . scale ;
2023-04-04 23:54:35 +02:00
if ( scale < 0.1 )
scale = getDefaultScale ( ) ;
2022-07-27 12:32:00 +02:00
2022-12-16 18:17:31 +01:00
forceFullFrames = 3 ; // force 3 full frames to make sure there is no blinking due to double-buffering.
2022-07-27 12:32:00 +02:00
//
2022-11-19 17:41:36 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitoradded " , szName } ) ;
2024-02-15 15:22:20 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitoraddedv2 " , std : : format ( " {},{},{} " , ID , szName , szShortDescription ) } ) ;
2023-02-19 21:54:53 +01:00
EMIT_HOOK_EVENT ( " monitorAdded " , this ) ;
2022-11-19 17:41:36 +01:00
2022-12-16 18:17:31 +01: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-12-12 21:51:20 +01:00
// verify last mon valid
bool found = false ;
for ( auto & m : g_pCompositor - > m_vMonitors ) {
if ( m . get ( ) = = g_pCompositor - > m_pLastMonitor ) {
found = true ;
break ;
}
}
if ( ! found )
g_pCompositor - > setActiveMonitor ( this ) ;
2023-03-24 20:23:16 +01:00
renderTimer = wl_event_loop_add_timer ( g_pCompositor - > m_sWLEventLoop , ratHandler , this ) ;
2023-11-01 19:53:36 +01:00
g_pCompositor - > scheduleFrameForMonitor ( this ) ;
2022-07-27 12:32:00 +02:00
}
2023-11-12 14:14:05 +01:00
void CMonitor : : onDisconnect ( bool destroy ) {
2022-08-03 16:05:25 +02:00
2023-03-24 20:23:16 +01:00
if ( renderTimer ) {
wl_event_source_remove ( renderTimer ) ;
renderTimer = nullptr ;
}
2022-10-06 19:43:50 +02:00
if ( ! m_bEnabled | | g_pCompositor - > m_bIsShuttingDown )
2022-08-03 16:05:25 +02:00
return ;
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " onDisconnect called for {} " , output - > name ) ;
2022-11-19 14:01:32 +01:00
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-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
hyprListener_monitorFrame . removeCallback ( ) ;
2023-04-07 17:31:51 +02:00
hyprListener_monitorDamage . removeCallback ( ) ;
2023-04-07 18:25:56 +02:00
hyprListener_monitorNeedsFrame . removeCallback ( ) ;
2023-04-12 22:40:51 +02:00
hyprListener_monitorCommit . removeCallback ( ) ;
2023-07-18 15:22:49 +02:00
hyprListener_monitorBind . removeCallback ( ) ;
2022-07-27 12:32:00 +02:00
2023-01-02 16:16:28 +01:00
for ( size_t i = 0 ; i < 4 ; + + i ) {
2023-01-22 17:03:25 +01:00
for ( auto & ls : m_aLayerSurfaceLayers [ i ] ) {
2023-01-23 19:23:44 +01:00
if ( ls - > layerSurface & & ! ls - > fadingOut )
wlr_layer_surface_v1_destroy ( ls - > layerSurface ) ;
2023-01-02 16:16:28 +01:00
}
2023-01-22 17:03:25 +01:00
m_aLayerSurfaceLayers [ i ] . clear ( ) ;
2023-01-02 16:16:28 +01:00
}
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Removed monitor {}! " , szName ) ;
2023-01-19 16:27:04 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitorremoved " , szName } ) ;
2023-02-19 21:54:53 +01:00
EMIT_HOOK_EVENT ( " monitorRemoved " , this ) ;
2023-01-19 16:27:04 +01:00
2022-08-10 21:54:09 +02:00
if ( ! BACKUPMON ) {
Debug : : log ( WARN , " Unplugged last monitor, entering an unsafe state. Good luck my friend. " ) ;
2023-09-24 19:04:38 +02:00
g_pCompositor - > enterUnsafeState ( ) ;
2022-08-10 21:54:09 +02:00
}
2023-11-01 19:53:36 +01:00
m_bEnabled = false ;
m_bRenderingInitPassed = false ;
2023-09-01 22:03:56 +02:00
if ( BACKUPMON ) {
// snap cursor
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
2023-09-01 22:03:56 +02:00
// move workspaces
std : : deque < CWorkspace * > wspToMove ;
for ( auto & w : g_pCompositor - > m_vWorkspaces ) {
2023-11-01 19:53:36 +01:00
if ( w - > m_iMonitorID = = ID | | ! g_pCompositor - > getMonitorFromID ( w - > m_iMonitorID ) ) {
2023-09-01 22:03:56 +02:00
wspToMove . push_back ( w . get ( ) ) ;
}
2022-07-27 12:32:00 +02:00
}
2023-09-01 22:03:56 +02:00
for ( auto & w : wspToMove ) {
w - > m_szLastMonitor = szName ;
g_pCompositor - > moveWorkspaceToMonitor ( w , BACKUPMON ) ;
w - > startAnim ( true , true , true ) ;
}
} else {
g_pCompositor - > m_pLastFocus = nullptr ;
g_pCompositor - > m_pLastWindow = nullptr ;
g_pCompositor - > m_pLastMonitor = nullptr ;
2022-07-27 12:32:00 +02:00
}
activeWorkspace = - 1 ;
2023-11-12 14:14:05 +01:00
if ( ! destroy )
wlr_output_layout_remove ( g_pCompositor - > m_sWLROutputLayout , output ) ;
2022-07-27 12:32:00 +02:00
2024-01-28 02:57:13 +01:00
wlr_output_state_set_enabled ( state . wlr ( ) , false ) ;
2022-07-27 12:32:00 +02:00
2024-01-28 02:57:13 +01:00
if ( ! state . commit ( ) )
2024-01-27 14:58:13 +01:00
Debug : : log ( WARN , " wlr_output_commit_state failed in CMonitor::onDisconnect " ) ;
2022-07-27 12:32:00 +02:00
2022-12-21 16:17:24 +01:00
if ( g_pCompositor - > m_pLastMonitor = = this )
g_pCompositor - > setActiveMonitor ( BACKUPMON ) ;
2022-12-22 13:15:00 +01:00
if ( g_pHyprRenderer - > m_pMostHzMonitor = = this ) {
int mostHz = 0 ;
CMonitor * pMonitorMostHz = nullptr ;
for ( auto & m : g_pCompositor - > m_vMonitors ) {
if ( m - > refreshRate > mostHz & & m . get ( ) ! = this ) {
pMonitorMostHz = m . get ( ) ;
mostHz = m - > refreshRate ;
}
}
g_pHyprRenderer - > m_pMostHzMonitor = pMonitorMostHz ;
}
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
2023-04-07 17:31:51 +02:00
void CMonitor : : addDamage ( const pixman_region32_t * rg ) {
2024-03-03 19:39:20 +01:00
static auto PZOOMFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " misc:cursor_zoom_factor " ) ;
if ( * PZOOMFACTOR ! = 1.f & & g_pCompositor - > getMonitorFromCursor ( ) = = this ) {
2023-04-16 15:48:38 +02:00
wlr_damage_ring_add_whole ( & damage ) ;
g_pCompositor - > scheduleFrameForMonitor ( this ) ;
2024-02-17 03:09:12 +01:00
} else if ( wlr_damage_ring_add ( & damage , rg ) )
2023-04-07 18:25:56 +02:00
g_pCompositor - > scheduleFrameForMonitor ( this ) ;
2022-08-23 16:07:47 +02:00
}
2023-07-19 20:09:49 +02:00
void CMonitor : : addDamage ( const CRegion * rg ) {
addDamage ( const_cast < CRegion * > ( rg ) - > pixman ( ) ) ;
}
2023-11-04 18:03:05 +01:00
void CMonitor : : addDamage ( const CBox * box ) {
2024-03-03 19:39:20 +01:00
static auto PZOOMFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " misc:cursor_zoom_factor " ) ;
if ( * PZOOMFACTOR ! = 1.f & & g_pCompositor - > getMonitorFromCursor ( ) = = this ) {
2023-04-16 15:48:38 +02:00
wlr_damage_ring_add_whole ( & damage ) ;
g_pCompositor - > scheduleFrameForMonitor ( this ) ;
}
2023-11-04 18:03:05 +01:00
if ( wlr_damage_ring_add_box ( & damage , const_cast < CBox * > ( box ) - > pWlr ( ) ) )
2023-04-07 18:25:56 +02:00
g_pCompositor - > scheduleFrameForMonitor ( this ) ;
2022-08-23 16:07:47 +02:00
}
2022-09-13 15:25:42 +02:00
bool CMonitor : : isMirror ( ) {
return pMirrorOf ! = nullptr ;
}
2024-02-27 23:11:59 +01:00
bool CMonitor : : matchesStaticSelector ( const std : : string & selector ) const {
if ( selector . starts_with ( " desc: " ) ) {
// match by description
const auto DESCRIPTIONSELECTOR = selector . substr ( 5 ) ;
2024-03-05 14:41:51 +01:00
return DESCRIPTIONSELECTOR = = szShortDescription | | DESCRIPTIONSELECTOR = = szDescription ;
2024-02-27 23:11:59 +01:00
} else {
// match by selector
return szName = = selector ;
}
}
2022-12-09 18:17:02 +01:00
int CMonitor : : findAvailableDefaultWS ( ) {
for ( size_t i = 1 ; i < INT32_MAX ; + + i ) {
if ( g_pCompositor - > getWorkspaceByID ( i ) )
continue ;
if ( const auto BOUND = g_pConfigManager - > getBoundMonitorStringForWS ( std : : to_string ( i ) ) ; ! BOUND . empty ( ) & & BOUND ! = szName )
continue ;
2022-12-16 18:17:31 +01:00
2022-12-09 18:17:02 +01:00
return i ;
}
return INT32_MAX ; // shouldn't be reachable
}
2022-09-13 15:25:42 +02:00
void CMonitor : : setupDefaultWS ( const SMonitorRule & monitorRule ) {
// Workspace
std : : string newDefaultWorkspaceName = " " ;
2023-03-18 17:12:43 +01:00
int64_t WORKSPACEID = g_pConfigManager - > getDefaultWorkspaceFor ( szName ) . empty ( ) ?
findAvailableDefaultWS ( ) :
getWorkspaceIDFromString ( g_pConfigManager - > getDefaultWorkspaceFor ( szName ) , newDefaultWorkspaceName ) ;
2022-09-13 15:25:42 +02:00
2023-11-12 14:34:42 +01:00
if ( WORKSPACEID = = WORKSPACE_INVALID | | ( WORKSPACEID > = SPECIAL_WORKSPACE_START & & WORKSPACEID < = - 2 ) ) {
2022-12-16 18:17:31 +01:00
WORKSPACEID = g_pCompositor - > m_vWorkspaces . size ( ) + 1 ;
2022-09-13 15:25:42 +02:00
newDefaultWorkspaceName = std : : to_string ( WORKSPACEID ) ;
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Invalid workspace= directive name in monitor parsing, workspace name \" {} \" is invalid. " , g_pConfigManager - > getDefaultWorkspaceFor ( szName ) ) ;
2022-09-13 15:25:42 +02:00
}
auto PNEWWORKSPACE = g_pCompositor - > getWorkspaceByID ( WORKSPACEID ) ;
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " New monitor: WORKSPACEID {}, exists: {} " , WORKSPACEID , ( int ) ( PNEWWORKSPACE ! = nullptr ) ) ;
2022-09-13 15:25:42 +02:00
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 ( ) ;
PNEWWORKSPACE - > m_iID = WORKSPACEID ;
}
activeWorkspace = PNEWWORKSPACE - > m_iID ;
PNEWWORKSPACE - > setActive ( true ) ;
2023-05-03 16:15:56 +02:00
PNEWWORKSPACE - > m_szLastMonitor = " " ;
2022-09-13 15:25:42 +02:00
}
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
2024-02-27 23:11:59 +01:00
const auto RULE = g_pConfigManager - > getMonitorRuleFor ( * this ) ;
2022-09-13 15:25:42 +02:00
vecPosition = RULE . offset ;
// push to mvmonitors
2023-11-01 19:53:36 +01:00
std : : shared_ptr < CMonitor > * thisWrapper = nullptr ;
// find the wrap
for ( auto & m : g_pCompositor - > m_vRealMonitors ) {
if ( m - > ID = = ID ) {
thisWrapper = & m ;
break ;
2022-09-13 15:25:42 +02:00
}
}
2023-11-01 19:53:36 +01:00
RASSERT ( thisWrapper - > get ( ) , " CMonitor::setMirror: Had no wrapper??? " ) ;
2022-12-16 18:17:31 +01: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 ( ) ) {
2023-11-01 19:53:36 +01:00
g_pCompositor - > m_vMonitors . push_back ( * thisWrapper ) ;
2022-09-13 15:25:42 +02:00
}
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 ) ;
2023-03-04 01:48:02 +01:00
vecPosition = PMIRRORMON - > vecPosition ;
2022-09-13 15:25:42 +02:00
pMirrorOf = PMIRRORMON ;
pMirrorOf - > mirrors . push_back ( this ) ;
// remove from mvmonitors
2022-12-16 18:17:31 +01:00
std : : erase_if ( g_pCompositor - > m_vMonitors , [ & ] ( const auto & other ) { return other . get ( ) = = this ; } ) ;
2022-09-13 15:25:42 +02:00
2023-08-14 14:22:06 +02:00
g_pCompositor - > arrangeMonitors ( ) ;
2022-11-19 17:41:36 +01:00
g_pCompositor - > setActiveMonitor ( g_pCompositor - > m_vMonitors . front ( ) . get ( ) ) ;
2022-12-26 13:26:53 +01:00
g_pCompositor - > sanityCheckWorkspaces ( ) ;
2022-09-13 15:25:42 +02:00
}
2022-09-19 20:44:33 +02:00
}
2022-12-14 18:57:18 +01:00
float CMonitor : : getDefaultScale ( ) {
if ( ! m_bEnabled )
return 1 ;
static constexpr double MMPERINCH = 25.4 ;
2022-12-16 18:17:31 +01:00
const auto DIAGONALPX = sqrt ( pow ( vecPixelSize . x , 2 ) + pow ( vecPixelSize . y , 2 ) ) ;
const auto DIAGONALIN = sqrt ( pow ( output - > phys_width / MMPERINCH , 2 ) + pow ( output - > phys_height / MMPERINCH , 2 ) ) ;
2022-12-14 18:57:18 +01:00
2022-12-16 18:17:31 +01:00
const auto PPI = DIAGONALPX / DIAGONALIN ;
2022-12-14 18:57:18 +01:00
if ( PPI > 200 /* High PPI, 2x*/ )
return 2 ;
2022-12-20 14:33:29 +01:00
else if ( PPI > 140 /* Medium PPI, 1.5x*/ )
2022-12-14 18:57:18 +01:00
return 1.5 ;
return 1 ;
}
2023-04-14 16:03:53 +02:00
2024-01-15 16:30:46 +01:00
void CMonitor : : changeWorkspace ( CWorkspace * const pWorkspace , bool internal , bool noMouseMove , bool noFocus ) {
2023-04-14 16:28:22 +02:00
if ( ! pWorkspace )
2023-04-14 16:03:53 +02:00
return ;
2023-04-17 14:32:35 +02:00
if ( pWorkspace - > m_bIsSpecialWorkspace ) {
2023-05-05 16:01:28 +02:00
if ( specialWorkspaceID ! = pWorkspace - > m_iID ) {
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " changeworkspace on special, togglespecialworkspace to id {} " , pWorkspace - > m_iID ) ;
2023-05-05 16:01:28 +02:00
g_pKeybindManager - > m_mDispatchers [ " togglespecialworkspace " ] ( pWorkspace - > m_szName = = " special " ? " " : pWorkspace - > m_szName ) ;
}
2023-04-17 14:32:35 +02:00
return ;
}
2023-09-03 17:21:55 +02:00
if ( pWorkspace - > m_iID = = activeWorkspace )
return ;
2023-04-14 16:03:53 +02:00
const auto POLDWORKSPACE = g_pCompositor - > getWorkspaceByID ( activeWorkspace ) ;
activeWorkspace = pWorkspace - > m_iID ;
if ( ! internal ) {
const auto ANIMTOLEFT = pWorkspace - > m_iID > POLDWORKSPACE - > m_iID ;
POLDWORKSPACE - > startAnim ( false , ANIMTOLEFT ) ;
pWorkspace - > startAnim ( true , ANIMTOLEFT ) ;
// move pinned windows
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( w - > m_iWorkspaceID = = POLDWORKSPACE - > m_iID & & w - > m_bPinned ) {
w - > m_iWorkspaceID = pWorkspace - > m_iID ;
}
}
2024-01-15 16:30:46 +01:00
if ( ! noFocus & & ! g_pCompositor - > m_pLastMonitor - > specialWorkspaceID ) {
2024-03-03 19:39:20 +01:00
static auto PFOLLOWMOUSE = CConfigValue < Hyprlang : : INT > ( " input:follow_mouse " ) ;
CWindow * pWindow = pWorkspace - > getLastFocusedWindow ( ) ;
2023-08-21 20:54:02 +02:00
2023-12-07 23:12:08 +01:00
if ( ! pWindow ) {
2024-03-03 19:39:20 +01:00
if ( * PFOLLOWMOUSE = = 1 )
2024-02-04 16:40:20 +01:00
pWindow = g_pCompositor - > vectorToWindowUnified ( g_pInputManager - > getMouseCoordsInternal ( ) , RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING ) ;
2023-08-21 20:54:02 +02:00
2023-12-07 23:12:08 +01:00
if ( ! pWindow )
pWindow = g_pCompositor - > getTopLeftWindowOnWorkspace ( pWorkspace - > m_iID ) ;
2023-08-21 20:54:02 +02:00
2023-12-07 23:12:08 +01:00
if ( ! pWindow )
pWindow = g_pCompositor - > getFirstWindowOnWorkspace ( pWorkspace - > m_iID ) ;
}
2023-08-21 20:54:02 +02:00
g_pCompositor - > focusWindow ( pWindow ) ;
2023-04-14 16:03:53 +02:00
}
2023-12-07 23:12:08 +01:00
2023-09-08 19:17:04 +02:00
if ( ! noMouseMove )
g_pInputManager - > simulateMouseMovement ( ) ;
2023-08-21 20:54:02 +02:00
2023-04-16 02:11:57 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( ID ) ;
2023-04-14 16:03:53 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " workspace " , pWorkspace - > m_szName } ) ;
EMIT_HOOK_EVENT ( " workspace " , pWorkspace ) ;
}
2023-04-15 17:16:33 +02:00
g_pHyprRenderer - > damageMonitor ( this ) ;
2023-04-30 02:12:20 +02:00
g_pCompositor - > updateFullscreenFadeOnWorkspace ( pWorkspace ) ;
2023-10-12 18:26:31 +02:00
g_pConfigManager - > ensureVRR ( this ) ;
2023-12-23 22:30:49 +01:00
g_pCompositor - > updateSuspendedStates ( ) ;
2024-03-07 14:27:58 +01:00
if ( specialWorkspaceID ) {
const auto PSPECIALWS = g_pCompositor - > getWorkspaceByID ( specialWorkspaceID ) ;
if ( PSPECIALWS - > m_bHasFullscreenWindow )
g_pCompositor - > updateFullscreenFadeOnWorkspace ( PSPECIALWS ) ;
}
2023-04-14 16:03:53 +02:00
}
2024-02-10 00:47:00 +01:00
void CMonitor : : changeWorkspace ( const int & id , bool internal , bool noMouseMove , bool noFocus ) {
changeWorkspace ( g_pCompositor - > getWorkspaceByID ( id ) , internal , noMouseMove , noFocus ) ;
2023-04-14 16:03:53 +02:00
}
void CMonitor : : setSpecialWorkspace ( CWorkspace * const pWorkspace ) {
2023-04-15 17:16:33 +02:00
g_pHyprRenderer - > damageMonitor ( this ) ;
2023-04-14 16:03:53 +02:00
if ( ! pWorkspace ) {
// remove special if exists
2023-12-13 18:25:19 +01:00
if ( const auto EXISTINGSPECIAL = g_pCompositor - > getWorkspaceByID ( specialWorkspaceID ) ; EXISTINGSPECIAL ) {
2023-04-14 16:03:53 +02:00
EXISTINGSPECIAL - > startAnim ( false , false ) ;
2023-09-04 15:11:51 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activespecial " , " , " + szName } ) ;
}
2023-04-14 16:03:53 +02:00
specialWorkspaceID = 0 ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( ID ) ;
const auto PWORKSPACE = g_pCompositor - > getWorkspaceByID ( activeWorkspace ) ;
if ( const auto PLAST = PWORKSPACE - > getLastFocusedWindow ( ) ; PLAST )
g_pCompositor - > focusWindow ( PLAST ) ;
else
g_pInputManager - > refocus ( ) ;
2024-03-05 00:29:45 +01:00
g_pCompositor - > updateFullscreenFadeOnWorkspace ( PWORKSPACE ) ;
g_pConfigManager - > ensureVRR ( this ) ;
2023-12-23 22:30:49 +01:00
g_pCompositor - > updateSuspendedStates ( ) ;
2023-04-14 16:03:53 +02:00
return ;
}
2023-05-06 17:10:51 +02:00
if ( specialWorkspaceID ) {
if ( const auto EXISTINGSPECIAL = g_pCompositor - > getWorkspaceByID ( specialWorkspaceID ) ; EXISTINGSPECIAL )
EXISTINGSPECIAL - > startAnim ( false , false ) ;
}
2023-09-04 15:11:51 +02:00
bool animate = true ;
//close if open elsewhere
const auto PMONITORWORKSPACEOWNER = g_pCompositor - > getMonitorFromID ( pWorkspace - > m_iMonitorID ) ;
if ( PMONITORWORKSPACEOWNER - > specialWorkspaceID = = pWorkspace - > m_iID ) {
PMONITORWORKSPACEOWNER - > specialWorkspaceID = 0 ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( PMONITORWORKSPACEOWNER - > ID ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " activespecial " , " , " + PMONITORWORKSPACEOWNER - > szName } ) ;
2024-03-07 14:27:58 +01:00
const auto PACTIVEWORKSPACE = g_pCompositor - > getWorkspaceByID ( PMONITORWORKSPACEOWNER - > activeWorkspace ) ;
g_pCompositor - > updateFullscreenFadeOnWorkspace ( PACTIVEWORKSPACE ) ;
2023-09-04 15:11:51 +02:00
animate = false ;
}
2023-04-14 16:03:53 +02:00
// open special
2023-04-17 23:58:59 +02:00
pWorkspace - > m_iMonitorID = ID ;
specialWorkspaceID = pWorkspace - > m_iID ;
2023-09-04 15:11:51 +02:00
if ( animate )
pWorkspace - > startAnim ( true , true ) ;
2023-04-14 16:03:53 +02:00
2023-06-02 20:14:34 +02:00
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( w - > m_iWorkspaceID = = pWorkspace - > m_iID ) {
w - > m_iMonitorID = ID ;
2024-01-09 18:14:08 +01:00
w - > updateSurfaceScaleTransformDetails ( ) ;
2023-12-26 19:44:38 +01:00
const auto MIDDLE = w - > middle ( ) ;
if ( w - > m_bIsFloating & & ! VECINRECT ( MIDDLE , vecPosition . x , vecPosition . y , vecPosition . x + vecSize . x , vecPosition . y + vecSize . y ) & & w - > m_iX11Type ! = 2 ) {
// if it's floating and the middle isnt on the current mon, move it to the center
const auto PMONFROMMIDDLE = g_pCompositor - > getMonitorFromVector ( MIDDLE ) ;
2024-03-02 01:35:17 +01:00
Vector2D pos = w - > m_vRealPosition . goal ( ) ;
2023-12-26 19:44:38 +01:00
if ( ! VECINRECT ( MIDDLE , PMONFROMMIDDLE - > vecPosition . x , PMONFROMMIDDLE - > vecPosition . y , PMONFROMMIDDLE - > vecPosition . x + PMONFROMMIDDLE - > vecSize . x ,
PMONFROMMIDDLE - > vecPosition . y + PMONFROMMIDDLE - > vecSize . y ) ) {
// not on any monitor, center
2024-03-02 01:35:17 +01:00
pos = middle ( ) / 2.f - w - > m_vRealSize . goal ( ) / 2.f ;
2023-12-26 19:44:38 +01:00
} else
pos = pos - PMONFROMMIDDLE - > vecPosition + vecPosition ;
w - > m_vRealPosition = pos ;
w - > m_vPosition = pos ;
}
2023-06-02 20:14:34 +02:00
}
}
2023-04-14 16:03:53 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( ID ) ;
if ( const auto PLAST = pWorkspace - > getLastFocusedWindow ( ) ; PLAST )
g_pCompositor - > focusWindow ( PLAST ) ;
else
g_pInputManager - > refocus ( ) ;
2023-09-04 15:11:51 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activespecial " , pWorkspace - > m_szName + " , " + szName } ) ;
2023-09-23 00:36:28 +02:00
g_pHyprRenderer - > damageMonitor ( this ) ;
2023-12-23 22:30:49 +01:00
2024-03-05 00:29:45 +01:00
g_pCompositor - > updateFullscreenFadeOnWorkspace ( pWorkspace ) ;
g_pConfigManager - > ensureVRR ( this ) ;
2023-12-23 22:30:49 +01:00
g_pCompositor - > updateSuspendedStates ( ) ;
2023-04-14 16:03:53 +02:00
}
void CMonitor : : setSpecialWorkspace ( const int & id ) {
setSpecialWorkspace ( g_pCompositor - > getWorkspaceByID ( id ) ) ;
}
2023-08-14 14:22:06 +02:00
void CMonitor : : moveTo ( const Vector2D & pos ) {
vecPosition = pos ;
if ( ! isMirror ( ) )
wlr_output_layout_add ( g_pCompositor - > m_sWLROutputLayout , output , ( int ) vecPosition . x , ( int ) vecPosition . y ) ;
}
2023-09-11 11:09:34 +02:00
Vector2D CMonitor : : middle ( ) {
return vecPosition + vecSize / 2.f ;
2023-11-12 14:14:05 +01:00
}
2023-11-24 11:54:21 +01:00
void CMonitor : : updateMatrix ( ) {
wlr_matrix_identity ( projMatrix . data ( ) ) ;
if ( transform ! = WL_OUTPUT_TRANSFORM_NORMAL ) {
2023-11-24 14:45:10 +01:00
wlr_matrix_translate ( projMatrix . data ( ) , vecPixelSize . x / 2.0 , vecPixelSize . y / 2.0 ) ;
2023-11-24 11:54:21 +01:00
wlr_matrix_transform ( projMatrix . data ( ) , transform ) ;
wlr_matrix_translate ( projMatrix . data ( ) , - vecTransformedSize . x / 2.0 , - vecTransformedSize . y / 2.0 ) ;
}
2023-11-30 02:48:10 +01:00
}
2024-01-27 20:11:03 +01:00
2024-01-28 02:57:13 +01:00
CMonitorState : : CMonitorState ( CMonitor * owner ) {
m_pOwner = owner ;
wlr_output_state_init ( & m_state ) ;
}
CMonitorState : : ~ CMonitorState ( ) {
wlr_output_state_finish ( & m_state ) ;
}
wlr_output_state * CMonitorState : : wlr ( ) {
return & m_state ;
}
void CMonitorState : : clear ( ) {
wlr_output_state_finish ( & m_state ) ;
m_state = { 0 } ;
wlr_output_state_init ( & m_state ) ;
}
bool CMonitorState : : commit ( ) {
bool ret = wlr_output_commit_state ( m_pOwner - > output , & m_state ) ;
clear ( ) ;
return ret ;
}
2024-01-28 01:41:54 +01:00
2024-01-28 02:57:13 +01:00
bool CMonitorState : : test ( ) {
return wlr_output_test_state ( m_pOwner - > output , & m_state ) ;
2024-01-27 20:11:03 +01:00
}