2022-07-27 12:32:00 +02:00
# include "Monitor.hpp"
2024-02-15 15:22:20 +01:00
# include "MiscFunctions.hpp"
2024-07-21 13:09:54 +02:00
# include "math/Math.hpp"
2024-08-06 15:52:19 +02:00
# include "sync/SyncReleaser.hpp"
2022-07-27 12:32:00 +02:00
# include "../Compositor.hpp"
2024-03-03 19:39:20 +01:00
# include "../config/ConfigValue.hpp"
2024-04-22 19:21:03 +02:00
# include "../protocols/GammaControl.hpp"
2024-05-03 23:34:10 +02:00
# include "../devices/ITouch.hpp"
2024-05-09 22:47:21 +02:00
# include "../protocols/LayerShell.hpp"
2024-05-10 03:27:54 +02:00
# include "../protocols/PresentationTime.hpp"
2024-07-21 13:09:54 +02:00
# include "../protocols/DRMLease.hpp"
2024-08-06 15:52:19 +02:00
# include "../protocols/DRMSyncobj.hpp"
2024-07-21 13:09:54 +02:00
# include "../protocols/core/Output.hpp"
2024-06-19 16:24:28 +02:00
# include "../managers/PointerManager.hpp"
2024-07-21 13:09:54 +02:00
# include "../protocols/core/Compositor.hpp"
# include "sync/SyncTimeline.hpp"
# include <aquamarine/output/Output.hpp>
2024-06-11 17:17:45 +02:00
# include <hyprutils/string/String.hpp>
2024-09-21 01:33:48 +02:00
# include <hyprutils/utils/ScopeGuard.hpp>
2024-06-11 17:17:45 +02:00
using namespace Hyprutils : : String ;
2024-09-21 01:33:48 +02:00
using namespace Hyprutils : : Utils ;
2024-03-03 19:39:20 +01:00
2023-03-24 20:23:16 +01:00
int ratHandler ( void * data ) {
g_pHyprRenderer - > renderMonitor ( ( CMonitor * ) data ) ;
return 1 ;
}
2024-08-19 18:44:22 +02:00
CMonitor : : CMonitor ( SP < Aquamarine : : IOutput > output_ ) : state ( this ) , output ( output_ ) {
2024-06-19 18:25:20 +02:00
;
2023-04-07 13:18:40 +02:00
}
CMonitor : : ~ CMonitor ( ) {
2024-04-22 19:21:03 +02:00
events . destroy . emit ( ) ;
2023-04-07 13:18:40 +02:00
}
2024-07-21 13:09:54 +02:00
void CMonitor : : onConnect ( bool noRule ) {
2024-05-10 03:27:54 +02:00
2024-07-21 13:09:54 +02:00
if ( output - > supportsExplicit ) {
inTimeline = CSyncTimeline : : create ( output - > getBackend ( ) - > drmFD ( ) ) ;
outTimeline = CSyncTimeline : : create ( output - > getBackend ( ) - > drmFD ( ) ) ;
}
2024-08-19 18:44:22 +02:00
listeners . frame = output - > events . frame . registerListener ( [ this ] ( std : : any d ) { Events : : listener_monitorFrame ( this , nullptr ) ; } ) ;
listeners . commit = output - > events . commit . registerListener ( [ this ] ( std : : any d ) { Events : : listener_monitorCommit ( this , nullptr ) ; } ) ;
2024-07-21 13:09:54 +02:00
listeners . needsFrame =
output - > events . needsFrame . registerListener ( [ this ] ( std : : any d ) { g_pCompositor - > scheduleFrameForMonitor ( this , Aquamarine : : IOutput : : AQ_SCHEDULE_NEEDS_FRAME ) ; } ) ;
2024-08-19 18:44:22 +02:00
2024-07-21 13:09:54 +02:00
listeners . presented = output - > events . present . registerListener ( [ this ] ( std : : any d ) {
auto E = std : : any_cast < Aquamarine : : IOutput : : SPresentEvent > ( d ) ;
2024-08-30 15:50:25 +02:00
PROTO : : presentation - > onPresented ( self . lock ( ) , E . when , E . refresh , E . seq , E . flags ) ;
2024-07-21 13:09:54 +02:00
} ) ;
2024-08-19 18:44:22 +02:00
listeners . destroy = output - > events . destroy . registerListener ( [ this ] ( std : : any d ) {
Debug : : log ( LOG , " Destroy called for monitor {} " , szName ) ;
onDisconnect ( true ) ;
output = nullptr ;
m_bRenderingInitPassed = false ;
Debug : : log ( LOG , " Removing monitor {} from realMonitors " , szName ) ;
std : : erase_if ( g_pCompositor - > m_vRealMonitors , [ & ] ( SP < CMonitor > & el ) { return el . get ( ) = = this ; } ) ;
} ) ;
2024-07-21 13:09:54 +02:00
listeners . state = output - > events . state . registerListener ( [ this ] ( std : : any d ) {
auto E = std : : any_cast < Aquamarine : : IOutput : : SStateEvent > ( d ) ;
if ( E . size = = Vector2D { } ) {
// an indication to re-set state
// we can't do much for createdByUser displays I think
if ( createdByUser )
return ;
Debug : : log ( LOG , " Reapplying monitor rule for {} from a state request " , szName ) ;
g_pHyprRenderer - > applyMonitorRule ( this , & activeMonitorRule , true ) ;
return ;
}
2024-05-10 03:27:54 +02:00
2024-07-21 13:09:54 +02:00
if ( ! createdByUser )
return ;
const auto SIZE = E . size ;
forceSize = SIZE ;
SMonitorRule rule = activeMonitorRule ;
rule . resolution = SIZE ;
g_pHyprRenderer - > applyMonitorRule ( this , & rule ) ;
} ) ;
tearingState . canTear = output - > getBackend ( ) - > type ( ) = = Aquamarine : : AQ_BACKEND_DRM ;
2023-09-28 22:48:33 +02:00
2022-11-19 14:14:55 +01:00
if ( m_bEnabled ) {
2024-08-06 15:52:19 +02:00
output - > state - > resetExplicitFences ( ) ;
2024-07-21 13:09:54 +02:00
output - > state - > setEnabled ( true ) ;
2024-01-28 02:57:13 +01:00
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 ;
2024-07-21 13:09:54 +02:00
szDescription = output - > description ;
2023-11-30 02:48:10 +01:00
// 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
2024-07-21 13:09:54 +02:00
szShortDescription = trim ( std : : format ( " {} {} {} " , output - > make , output - > model , output - > serial ) ) ;
2024-03-05 14:41:51 +01:00
std : : erase ( szShortDescription , ' , ' ) ;
2024-02-15 15:22:20 +01:00
2024-07-21 13:09:54 +02:00
if ( output - > getBackend ( ) - > type ( ) ! = Aquamarine : : AQ_BACKEND_DRM )
createdByUser = true ; // should be true. WL and Headless backends should be addable / removable
2022-11-05 19:04:44 +01:00
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-08-06 15:52:19 +02:00
output - > state - > resetExplicitFences ( ) ;
2024-07-21 13:09:54 +02:00
output - > state - > setEnabled ( false ) ;
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 ;
2024-07-21 13:09:54 +02:00
listeners . frame . reset ( ) ;
2022-07-27 12:32:00 +02:00
return ;
}
2024-07-21 13:09:54 +02:00
if ( output - > nonDesktop ) {
2022-08-27 23:10:13 +02:00
Debug : : log ( LOG , " Not configuring non-desktop output " ) ;
2024-07-21 13:09:54 +02:00
if ( PROTO : : lease )
PROTO : : lease - > offer ( self . lock ( ) ) ;
2022-08-27 23:10:13 +02:00
2024-07-21 13:09:54 +02:00
return ;
2022-08-10 13:44:04 +02:00
}
2024-05-05 18:16:00 +02:00
SP < 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-08-06 15:52:19 +02:00
output - > state - > resetExplicitFences ( ) ;
2024-07-21 13:09:54 +02:00
output - > state - > setEnabled ( true ) ;
2022-07-27 12:32:00 +02:00
// set mode, also applies
if ( ! noRule )
g_pHyprRenderer - > applyMonitorRule ( this , & monitorRule , true ) ;
2024-01-28 02:57:13 +01:00
if ( ! state . commit ( ) )
2024-07-21 13:09:54 +02:00
Debug : : log ( WARN , " state.commit() failed in CMonitor::onCommit " ) ;
2023-11-01 19:53:36 +01:00
2024-06-19 18:25:20 +02:00
damage . setSize ( vecTransformedSize ) ;
2023-04-07 13:18:40 +02:00
2024-07-22 18:06:11 +02:00
Debug : : log ( LOG , " Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x} " , output - > name , vecPosition , vecPixelSize , ( uintptr_t ) output . get ( ) ) ;
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
2024-08-26 20:24:30 +02:00
for ( auto const & ws : g_pCompositor - > m_vWorkspaces ) {
2024-04-05 17:56:46 +02:00
if ( ! valid ( ws ) )
continue ;
2023-05-06 17:49:46 +02:00
if ( ws - > m_szLastMonitor = = szName | | g_pCompositor - > m_vMonitors . size ( ) = = 1 /* avoid lost workspaces on recover */ ) {
2024-04-02 21:32:39 +02:00
g_pCompositor - > moveWorkspaceToMonitor ( ws , this ) ;
2023-05-03 16:15:56 +02:00
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
//
2024-06-09 22:28:51 +02:00
if ( ! activeMonitorRule . mirrorOf . empty ( ) )
setMirror ( activeMonitorRule . mirrorOf ) ;
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: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 ;
2024-08-26 17:25:39 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2024-05-05 23:18:10 +02:00
if ( m = = g_pCompositor - > m_pLastMonitor ) {
2022-12-12 21:51:20 +01:00
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
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( this , Aquamarine : : IOutput : : AQ_SCHEDULE_NEW_MONITOR ) ;
2024-04-22 19:21:03 +02:00
PROTO : : gamma - > applyGammaToState ( this ) ;
events . connect . emit ( ) ;
2024-09-15 22:03:42 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitoradded " , szName } ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitoraddedv2 " , std : : format ( " {},{},{} " , ID , szName , szShortDescription ) } ) ;
EMIT_HOOK_EVENT ( " monitorAdded " , 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
2024-04-22 19:21:03 +02:00
events . disconnect . emit ( ) ;
2022-07-27 12:32:00 +02:00
// Cleanup everything. Move windows back, snap cursor, shit.
CMonitor * BACKUPMON = nullptr ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2022-07-27 12:32:00 +02:00
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 ; } ) ) ;
2024-06-19 16:24:28 +02:00
// unlock software for mirrored monitor
g_pPointerManager - > unlockSoftwareForMonitor ( pMirrorOf ) ;
2022-09-13 15:25:42 +02:00
pMirrorOf = nullptr ;
}
if ( ! mirrors . empty ( ) ) {
2024-08-26 20:24:30 +02:00
for ( auto const & m : mirrors ) {
2022-09-13 15:25:42 +02:00
m - > setMirror ( " " ) ;
}
g_pConfigManager - > m_bWantsMonitorReload = true ;
}
2024-07-21 13:09:54 +02:00
listeners . frame . reset ( ) ;
listeners . presented . reset ( ) ;
listeners . needsFrame . reset ( ) ;
listeners . commit . reset ( ) ;
2022-07-27 12:32:00 +02:00
2023-01-02 16:16:28 +01:00
for ( size_t i = 0 ; i < 4 ; + + i ) {
2024-08-26 17:25:39 +02:00
for ( auto const & ls : m_aLayerSurfaceLayers [ i ] ) {
2023-01-23 19:23:44 +01:00
if ( ls - > layerSurface & & ! ls - > fadingOut )
2024-05-09 22:47:21 +02:00
ls - > layerSurface - > sendClosed ( ) ;
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
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
2024-05-05 23:18:10 +02:00
g_pCompositor - > warpCursorTo ( BACKUPMON - > vecPosition + BACKUPMON - > vecTransformedSize / 2.F , true ) ;
2022-07-27 12:32:00 +02:00
2023-09-01 22:03:56 +02:00
// move workspaces
2024-04-02 21:32:39 +02:00
std : : deque < PHLWORKSPACE > wspToMove ;
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWorkspaces ) {
2023-11-01 19:53:36 +01:00
if ( w - > m_iMonitorID = = ID | | ! g_pCompositor - > getMonitorFromID ( w - > m_iMonitorID ) ) {
2024-04-02 21:32:39 +02:00
wspToMove . push_back ( w ) ;
2023-09-01 22:03:56 +02:00
}
2022-07-27 12:32:00 +02:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & w : wspToMove ) {
2023-09-01 22:03:56 +02:00
w - > m_szLastMonitor = szName ;
g_pCompositor - > moveWorkspaceToMonitor ( w , BACKUPMON ) ;
w - > startAnim ( true , true , true ) ;
}
} else {
2024-06-08 10:07:59 +02:00
g_pCompositor - > m_pLastFocus . reset ( ) ;
2024-04-27 13:43:12 +02:00
g_pCompositor - > m_pLastWindow . reset ( ) ;
2024-05-05 23:18:10 +02:00
g_pCompositor - > m_pLastMonitor . reset ( ) ;
2022-07-27 12:32:00 +02:00
}
2024-04-10 18:21:39 +02:00
if ( activeWorkspace )
activeWorkspace - > m_bVisible = false ;
2024-04-02 21:32:39 +02:00
activeWorkspace . reset ( ) ;
2022-07-27 12:32:00 +02:00
2024-08-06 15:52:19 +02:00
output - > state - > resetExplicitFences ( ) ;
2024-07-21 13:09:54 +02:00
output - > state - > setEnabled ( false ) ;
2022-07-27 12:32:00 +02:00
2024-01-28 02:57:13 +01:00
if ( ! state . commit ( ) )
2024-07-21 13:09:54 +02:00
Debug : : log ( WARN , " state.commit() failed in CMonitor::onDisconnect " ) ;
2022-07-27 12:32:00 +02:00
2024-05-05 23:18:10 +02:00
if ( g_pCompositor - > m_pLastMonitor . get ( ) = = this )
2024-03-26 03:26:09 +01:00
g_pCompositor - > setActiveMonitor ( BACKUPMON ? BACKUPMON : g_pCompositor - > m_pUnsafeOutput ) ;
2022-12-21 16:17:24 +01:00
2022-12-22 13:15:00 +01:00
if ( g_pHyprRenderer - > m_pMostHzMonitor = = this ) {
int mostHz = 0 ;
CMonitor * pMonitorMostHz = nullptr ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2022-12-22 13:15:00 +01:00
if ( m - > refreshRate > mostHz & & m . get ( ) ! = this ) {
pMonitorMostHz = m . get ( ) ;
mostHz = m - > refreshRate ;
}
}
g_pHyprRenderer - > m_pMostHzMonitor = pMonitorMostHz ;
}
2024-05-05 18:16:00 +02:00
std : : erase_if ( g_pCompositor - > m_vMonitors , [ & ] ( SP < CMonitor > & el ) { return el . get ( ) = = this ; } ) ;
2024-09-15 22:03:42 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " monitorremoved " , szName } ) ;
EMIT_HOOK_EVENT ( " monitorRemoved " , 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-05-09 23:23:01 +02:00
static auto PZOOMFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " cursor:zoom_factor " ) ;
2024-03-03 19:39:20 +01:00
if ( * PZOOMFACTOR ! = 1.f & & g_pCompositor - > getMonitorFromCursor ( ) = = this ) {
2024-06-19 18:25:20 +02:00
damage . damageEntire ( ) ;
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( this , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
2024-06-19 18:25:20 +02:00
} else if ( damage . damage ( rg ) )
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( this , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
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-05-09 23:23:01 +02:00
static auto PZOOMFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " cursor:zoom_factor " ) ;
2024-03-03 19:39:20 +01:00
if ( * PZOOMFACTOR ! = 1.f & & g_pCompositor - > getMonitorFromCursor ( ) = = this ) {
2024-06-19 18:25:20 +02:00
damage . damageEntire ( ) ;
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( this , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
2023-04-16 15:48:38 +02:00
}
2024-06-19 18:25:20 +02:00
if ( damage . damage ( * box ) )
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( this , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
2022-08-23 16:07:47 +02:00
}
2022-09-13 15:25:42 +02:00
2024-06-14 13:45:32 +02:00
bool CMonitor : : shouldSkipScheduleFrameOnMouseEvent ( ) {
static auto PNOBREAK = CConfigValue < Hyprlang : : INT > ( " cursor:no_break_fs_vrr " ) ;
static auto PMINRR = CConfigValue < Hyprlang : : INT > ( " cursor:min_refresh_rate " ) ;
// skip scheduling extra frames for fullsreen apps with vrr
2024-07-21 13:09:54 +02:00
bool shouldSkip =
2024-07-31 19:55:52 +02:00
* PNOBREAK & & output - > state - > state ( ) . adaptiveSync & & activeWorkspace & & activeWorkspace - > m_bHasFullscreenWindow & & activeWorkspace - > m_efFullscreenMode = = FSMODE_FULLSCREEN ;
2024-06-14 13:45:32 +02:00
// keep requested minimum refresh rate
if ( shouldSkip & & * PMINRR & & lastPresentationTimer . getMillis ( ) > 1000 / * PMINRR ) {
// damage whole screen because some previous cursor box damages were skipped
2024-06-19 18:25:20 +02:00
damage . damageEntire ( ) ;
2024-06-14 13:45:32 +02:00
return false ;
}
return shouldSkip ;
}
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 ;
}
}
2024-08-08 21:01:50 +02:00
WORKSPACEID CMonitor : : findAvailableDefaultWS ( ) {
for ( WORKSPACEID i = 1 ; i < LONG_MAX ; + + i ) {
2022-12-09 18:17:02 +01:00
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 ;
}
2024-08-08 21:01:50 +02:00
return LONG_MAX ; // shouldn't be reachable
2022-12-09 18:17:02 +01:00
}
2022-09-13 15:25:42 +02:00
void CMonitor : : setupDefaultWS ( const SMonitorRule & monitorRule ) {
// Workspace
std : : string newDefaultWorkspaceName = " " ;
2024-06-22 23:52:42 +02:00
int64_t wsID = WORKSPACE_INVALID ;
if ( g_pConfigManager - > getDefaultWorkspaceFor ( szName ) . empty ( ) )
wsID = findAvailableDefaultWS ( ) ;
else {
const auto ws = getWorkspaceIDNameFromString ( g_pConfigManager - > getDefaultWorkspaceFor ( szName ) ) ;
wsID = ws . id ;
newDefaultWorkspaceName = ws . name ;
}
2022-09-13 15:25:42 +02:00
2024-06-22 23:52:42 +02:00
if ( wsID = = WORKSPACE_INVALID | | ( wsID > = SPECIAL_WORKSPACE_START & & wsID < = - 2 ) ) {
wsID = g_pCompositor - > m_vWorkspaces . size ( ) + 1 ;
newDefaultWorkspaceName = std : : to_string ( wsID ) ;
2022-09-13 15:25:42 +02:00
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
}
2024-06-22 23:52:42 +02:00
auto PNEWWORKSPACE = g_pCompositor - > getWorkspaceByID ( wsID ) ;
2022-09-13 15:25:42 +02:00
2024-06-22 23:52:42 +02:00
Debug : : log ( LOG , " New monitor: WORKSPACEID {}, exists: {} " , wsID , ( 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 ) ;
2024-04-02 21:32:39 +02:00
activeWorkspace = PNEWWORKSPACE ;
2022-09-13 15:25:42 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( ID ) ;
PNEWWORKSPACE - > startAnim ( true , true , true ) ;
} else {
if ( newDefaultWorkspaceName = = " " )
2024-06-22 23:52:42 +02:00
newDefaultWorkspaceName = std : : to_string ( wsID ) ;
2022-09-13 15:25:42 +02:00
2024-06-22 23:52:42 +02:00
PNEWWORKSPACE = g_pCompositor - > m_vWorkspaces . emplace_back ( CWorkspace : : create ( wsID , ID , newDefaultWorkspaceName ) ) ;
2022-09-13 15:25:42 +02:00
}
2024-04-02 21:32:39 +02:00
activeWorkspace = PNEWWORKSPACE ;
2022-09-13 15:25:42 +02:00
PNEWWORKSPACE - > setActive ( true ) ;
2024-04-03 11:09:42 +02:00
PNEWWORKSPACE - > m_bVisible = 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 ; } ) ) ;
2024-06-19 16:24:28 +02:00
// unlock software for mirrored monitor
g_pPointerManager - > unlockSoftwareForMonitor ( pMirrorOf ) ;
2022-09-13 15:25:42 +02:00
}
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
2024-05-05 18:16:00 +02:00
SP < CMonitor > * thisWrapper = nullptr ;
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-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 ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2022-09-13 15:25:42 +02:00
if ( m . get ( ) ! = this ) {
BACKUPMON = m . get ( ) ;
break ;
}
}
// move all the WS
2024-04-02 21:32:39 +02:00
std : : deque < PHLWORKSPACE > wspToMove ;
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWorkspaces ) {
2022-09-13 15:25:42 +02:00
if ( w - > m_iMonitorID = = ID ) {
2024-04-02 21:32:39 +02:00
wspToMove . push_back ( w ) ;
2022-09-13 15:25:42 +02:00
}
}
2024-08-26 20:24:30 +02:00
for ( auto const & w : wspToMove ) {
2022-09-13 15:25:42 +02:00
g_pCompositor - > moveWorkspaceToMonitor ( w , BACKUPMON ) ;
w - > startAnim ( true , true , true ) ;
}
2024-04-02 21:32:39 +02:00
activeWorkspace . reset ( ) ;
2022-09-13 15:25:42 +02:00
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 ( ) ;
2024-06-19 16:24:28 +02:00
// Software lock mirrored monitor
g_pPointerManager - > lockSoftwareForMonitor ( PMIRRORMON ) ;
2022-09-13 15:25:42 +02:00
}
2024-06-09 22:28:51 +02:00
events . modeChanged . emit ( ) ;
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 ) ) ;
2024-07-21 13:09:54 +02:00
const auto DIAGONALIN = sqrt ( pow ( output - > physicalSize . x / MMPERINCH , 2 ) + pow ( output - > physicalSize . y / 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-04-02 21:32:39 +02:00
void CMonitor : : changeWorkspace ( const PHLWORKSPACE & 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 ) {
2024-04-02 21:32:39 +02:00
if ( activeSpecialWorkspace ! = pWorkspace ) {
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " changeworkspace on special, togglespecialworkspace to id {} " , pWorkspace - > m_iID ) ;
2024-04-13 15:39:20 +02:00
setSpecialWorkspace ( pWorkspace ) ;
2023-05-05 16:01:28 +02:00
}
2023-04-17 14:32:35 +02:00
return ;
}
2024-04-02 21:32:39 +02:00
if ( pWorkspace = = activeWorkspace )
2023-09-03 17:21:55 +02:00
return ;
2024-04-03 11:09:42 +02:00
const auto POLDWORKSPACE = activeWorkspace ;
POLDWORKSPACE - > m_bVisible = false ;
pWorkspace - > m_bVisible = true ;
2023-04-14 16:03:53 +02:00
2024-04-02 21:32:39 +02:00
activeWorkspace = pWorkspace ;
2023-04-14 16:03:53 +02:00
if ( ! internal ) {
const auto ANIMTOLEFT = pWorkspace - > m_iID > POLDWORKSPACE - > m_iID ;
POLDWORKSPACE - > startAnim ( false , ANIMTOLEFT ) ;
pWorkspace - > startAnim ( true , ANIMTOLEFT ) ;
// move pinned windows
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = POLDWORKSPACE & & w - > m_bPinned )
w - > moveToWorkspace ( pWorkspace ) ;
2023-04-14 16:03:53 +02:00
}
2024-04-08 00:13:56 +02:00
if ( ! noFocus & & ! g_pCompositor - > m_pLastMonitor - > activeSpecialWorkspace & &
2024-05-05 18:16:00 +02:00
! ( g_pCompositor - > m_pLastWindow . lock ( ) & & g_pCompositor - > m_pLastWindow - > m_bPinned & & g_pCompositor - > m_pLastWindow - > m_iMonitorID = = ID ) ) {
2024-03-03 19:39:20 +01:00
static auto PFOLLOWMOUSE = CConfigValue < Hyprlang : : INT > ( " input:follow_mouse " ) ;
2024-04-27 13:43:12 +02:00
auto 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 } ) ;
2024-03-08 18:39:53 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " workspacev2 " , std : : format ( " {},{} " , pWorkspace - > m_iID , pWorkspace - > m_szName ) } ) ;
2023-04-14 16:03:53 +02:00
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
2024-04-02 21:32:39 +02:00
if ( activeSpecialWorkspace )
g_pCompositor - > updateFullscreenFadeOnWorkspace ( activeSpecialWorkspace ) ;
2023-04-14 16:03:53 +02:00
}
2024-08-08 21:01:50 +02:00
void CMonitor : : changeWorkspace ( const WORKSPACEID & id , bool internal , bool noMouseMove , bool noFocus ) {
2024-02-10 00:47:00 +01:00
changeWorkspace ( g_pCompositor - > getWorkspaceByID ( id ) , internal , noMouseMove , noFocus ) ;
2023-04-14 16:03:53 +02:00
}
2024-04-02 21:32:39 +02:00
void CMonitor : : setSpecialWorkspace ( const PHLWORKSPACE & pWorkspace ) {
2024-07-07 21:27:18 +02:00
if ( activeSpecialWorkspace = = pWorkspace )
return ;
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
2024-04-02 21:32:39 +02:00
if ( activeSpecialWorkspace ) {
2024-04-03 11:09:42 +02:00
activeSpecialWorkspace - > m_bVisible = false ;
2024-04-02 21:32:39 +02:00
activeSpecialWorkspace - > startAnim ( false , false ) ;
2023-09-04 15:11:51 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activespecial " , " , " + szName } ) ;
}
2024-04-02 21:32:39 +02:00
activeSpecialWorkspace . reset ( ) ;
2023-04-14 16:03:53 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( ID ) ;
2024-05-05 18:16:00 +02:00
if ( ! ( g_pCompositor - > m_pLastWindow . lock ( ) & & g_pCompositor - > m_pLastWindow - > m_bPinned & & g_pCompositor - > m_pLastWindow - > m_iMonitorID = = ID ) ) {
2024-04-08 00:13:56 +02:00
if ( const auto PLAST = activeWorkspace - > getLastFocusedWindow ( ) ; PLAST )
g_pCompositor - > focusWindow ( PLAST ) ;
else
g_pInputManager - > refocus ( ) ;
}
2023-04-14 16:03:53 +02:00
2024-04-02 21:32:39 +02:00
g_pCompositor - > updateFullscreenFadeOnWorkspace ( activeWorkspace ) ;
2024-03-05 00:29:45 +01:00
g_pConfigManager - > ensureVRR ( this ) ;
2023-12-23 22:30:49 +01:00
g_pCompositor - > updateSuspendedStates ( ) ;
2023-04-14 16:03:53 +02:00
return ;
}
2024-04-03 11:09:42 +02:00
if ( activeSpecialWorkspace ) {
activeSpecialWorkspace - > m_bVisible = false ;
2024-04-02 21:32:39 +02:00
activeSpecialWorkspace - > startAnim ( false , false ) ;
2024-04-03 11:09:42 +02:00
}
2023-05-06 17:10:51 +02:00
2023-09-04 15:11:51 +02:00
bool animate = true ;
//close if open elsewhere
const auto PMONITORWORKSPACEOWNER = g_pCompositor - > getMonitorFromID ( pWorkspace - > m_iMonitorID ) ;
2024-04-02 21:32:39 +02:00
if ( PMONITORWORKSPACEOWNER - > activeSpecialWorkspace = = pWorkspace ) {
PMONITORWORKSPACEOWNER - > activeSpecialWorkspace . reset ( ) ;
2023-09-04 15:11:51 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( PMONITORWORKSPACEOWNER - > ID ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " activespecial " , " , " + PMONITORWORKSPACEOWNER - > szName } ) ;
2024-03-07 14:27:58 +01:00
2024-04-02 21:32:39 +02:00
const auto PACTIVEWORKSPACE = PMONITORWORKSPACEOWNER - > activeWorkspace ;
2024-03-07 14:27:58 +01:00
g_pCompositor - > updateFullscreenFadeOnWorkspace ( PACTIVEWORKSPACE ) ;
2023-09-04 15:11:51 +02:00
animate = false ;
}
2023-04-14 16:03:53 +02:00
// open special
2024-04-03 11:09:42 +02:00
pWorkspace - > m_iMonitorID = ID ;
activeSpecialWorkspace = pWorkspace ;
activeSpecialWorkspace - > m_bVisible = true ;
2023-09-04 15:11:51 +02:00
if ( animate )
pWorkspace - > startAnim ( true , true ) ;
2023-04-14 16:03:53 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = pWorkspace ) {
2023-06-02 20:14:34 +02:00
w - > m_iMonitorID = ID ;
2024-01-09 18:14:08 +01:00
w - > updateSurfaceScaleTransformDetails ( ) ;
2024-03-23 23:14:50 +01:00
w - > setAnimationsToMove ( ) ;
2023-12-26 19:44:38 +01:00
const auto MIDDLE = w - > middle ( ) ;
2024-08-30 14:12:23 +02:00
if ( w - > m_bIsFloating & & ! VECINRECT ( MIDDLE , vecPosition . x , vecPosition . y , vecPosition . x + vecSize . x , vecPosition . y + vecSize . y ) & & ! w - > isX11OverrideRedirect ( ) ) {
2023-12-26 19:44:38 +01:00
// 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 ) ;
2024-05-05 18:16:00 +02:00
if ( ! ( g_pCompositor - > m_pLastWindow . lock ( ) & & g_pCompositor - > m_pLastWindow - > m_bPinned & & g_pCompositor - > m_pLastWindow - > m_iMonitorID = = ID ) ) {
2024-04-08 00:13:56 +02:00
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
}
2024-08-08 21:01:50 +02:00
void CMonitor : : setSpecialWorkspace ( const WORKSPACEID & id ) {
2023-04-14 16:03:53 +02:00
setSpecialWorkspace ( g_pCompositor - > getWorkspaceByID ( id ) ) ;
}
2023-08-14 14:22:06 +02:00
void CMonitor : : moveTo ( const Vector2D & pos ) {
vecPosition = pos ;
}
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 ( ) {
2024-09-25 11:01:13 +02:00
projMatrix = Mat3x3 : : identity ( ) ;
if ( transform ! = WL_OUTPUT_TRANSFORM_NORMAL )
projMatrix . translate ( vecPixelSize / 2.0 ) . transform ( wlTransformToHyprutils ( transform ) ) . translate ( - vecTransformedSize / 2.0 ) ;
2023-11-30 02:48:10 +01:00
}
2024-01-27 20:11:03 +01:00
2024-08-08 21:01:50 +02:00
WORKSPACEID CMonitor : : activeWorkspaceID ( ) {
2024-04-02 21:32:39 +02:00
return activeWorkspace ? activeWorkspace - > m_iID : 0 ;
}
2024-05-05 23:18:10 +02:00
2024-08-08 21:01:50 +02:00
WORKSPACEID CMonitor : : activeSpecialWorkspaceID ( ) {
2024-04-02 21:32:39 +02:00
return activeSpecialWorkspace ? activeSpecialWorkspace - > m_iID : 0 ;
}
2024-05-05 23:18:10 +02:00
CBox CMonitor : : logicalBox ( ) {
return { vecPosition , vecSize } ;
}
2024-07-21 13:09:54 +02:00
static void onDoneSource ( void * data ) {
auto pMonitor = ( CMonitor * ) data ;
if ( ! PROTO : : outputs . contains ( pMonitor - > szName ) )
return ;
PROTO : : outputs . at ( pMonitor - > szName ) - > sendDone ( ) ;
}
void CMonitor : : scheduleDone ( ) {
if ( doneSource )
return ;
doneSource = wl_event_loop_add_idle ( g_pCompositor - > m_sWLEventLoop , : : onDoneSource , this ) ;
}
bool CMonitor : : attemptDirectScanout ( ) {
if ( ! mirrors . empty ( ) | | isMirror ( ) | | g_pHyprRenderer - > m_bDirectScanoutBlocked )
return false ; // do not DS if this monitor is being mirrored. Will break the functionality.
if ( g_pPointerManager - > softwareLockedFor ( self . lock ( ) ) )
return false ;
const auto PCANDIDATE = solitaryClient . lock ( ) ;
if ( ! PCANDIDATE )
return false ;
const auto PSURFACE = g_pXWaylandManager - > getWindowSurface ( PCANDIDATE ) ;
2024-07-31 21:47:26 +02:00
if ( ! PSURFACE | | ! PSURFACE - > current . buffer | | PSURFACE - > current . bufferSize ! = vecPixelSize | | PSURFACE - > current . transform ! = transform )
2024-07-21 13:09:54 +02:00
return false ;
// we can't scanout shm buffers.
2024-07-31 21:47:26 +02:00
if ( ! PSURFACE - > current . buffer | | ! PSURFACE - > current . texture | | ! PSURFACE - > current . texture - > m_pEglImage /* dmabuf */ )
2024-07-21 13:09:54 +02:00
return false ;
2024-08-06 15:52:19 +02:00
Debug : : log ( TRACE , " attemptDirectScanout: surface {:x} passed, will attempt " , ( uintptr_t ) PSURFACE . get ( ) ) ;
2024-07-21 13:09:54 +02:00
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
// and comes from the appropriate device. This may implode on multi-gpu!!
2024-08-31 15:07:52 +02:00
const auto params = PSURFACE - > current . buffer - > buffer - > dmabuf ( ) ;
// scanout buffer isn't dmabuf, so no scanout
if ( ! params . success )
return false ;
// entering into scanout, so save monitor format
if ( lastScanout . expired ( ) )
prevDrmFormat = drmFormat ;
if ( drmFormat ! = params . format ) {
output - > state - > setFormat ( params . format ) ;
drmFormat = params . format ;
}
2024-07-31 21:47:26 +02:00
output - > state - > setBuffer ( PSURFACE - > current . buffer - > buffer . lock ( ) ) ;
2024-07-30 15:50:14 +02:00
output - > state - > setPresentationMode ( tearingState . activelyTearing ? Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_VSYNC ) ;
2024-07-21 13:09:54 +02:00
2024-08-06 15:52:19 +02:00
if ( ! state . test ( ) ) {
Debug : : log ( TRACE , " attemptDirectScanout: failed basic test " ) ;
2024-07-21 13:09:54 +02:00
return false ;
2024-08-06 15:52:19 +02:00
}
auto explicitOptions = g_pHyprRenderer - > getExplicitSyncSettings ( ) ;
// wait for the explicit fence if present, and if kms explicit is allowed
bool DOEXPLICIT = PSURFACE - > syncobj & & PSURFACE - > syncobj - > current . acquireTimeline & & PSURFACE - > syncobj - > current . acquireTimeline - > timeline & & explicitOptions . explicitKMSEnabled ;
int explicitWaitFD = - 1 ;
if ( DOEXPLICIT ) {
explicitWaitFD = PSURFACE - > syncobj - > current . acquireTimeline - > timeline - > exportAsSyncFileFD ( PSURFACE - > syncobj - > current . acquirePoint ) ;
if ( explicitWaitFD < 0 )
Debug : : log ( TRACE , " attemptDirectScanout: failed to acquire an explicit wait fd " ) ;
}
DOEXPLICIT = DOEXPLICIT & & explicitWaitFD > = 0 ;
auto cleanup = CScopeGuard ( [ explicitWaitFD , this ] ( ) {
output - > state - > resetExplicitFences ( ) ;
if ( explicitWaitFD > = 0 )
close ( explicitWaitFD ) ;
} ) ;
2024-07-21 13:09:54 +02:00
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
2024-08-30 15:50:25 +02:00
PSURFACE - > presentFeedback ( & now , self . lock ( ) ) ;
2024-07-21 13:09:54 +02:00
2024-07-30 15:46:35 +02:00
output - > state - > addDamage ( CBox { { } , vecPixelSize } ) ;
2024-08-06 15:52:19 +02:00
output - > state - > resetExplicitFences ( ) ;
if ( DOEXPLICIT ) {
Debug : : log ( TRACE , " attemptDirectScanout: setting IN_FENCE for aq to {} " , explicitWaitFD ) ;
output - > state - > setExplicitInFence ( explicitWaitFD ) ;
}
bool ok = output - > commit ( ) ;
if ( ! ok & & DOEXPLICIT ) {
Debug : : log ( TRACE , " attemptDirectScanout: EXPLICIT SYNC FAILED: commit() returned false. Resetting fences and retrying, might result in glitches. " ) ;
output - > state - > resetExplicitFences ( ) ;
ok = output - > commit ( ) ;
}
2024-07-30 15:46:35 +02:00
2024-08-06 15:52:19 +02:00
if ( ok ) {
2024-07-21 13:09:54 +02:00
if ( lastScanout . expired ( ) ) {
lastScanout = PCANDIDATE ;
Debug : : log ( LOG , " Entered a direct scanout to {:x}: \" {} \" " , ( uintptr_t ) PCANDIDATE . get ( ) , PCANDIDATE - > m_szTitle ) ;
}
2024-08-06 15:52:19 +02:00
// delay explicit sync feedback until kms release of the buffer
if ( DOEXPLICIT ) {
Debug : : log ( TRACE , " attemptDirectScanout: Delaying explicit sync release feedback until kms release " ) ;
PSURFACE - > current . buffer - > releaser - > drop ( ) ;
PSURFACE - > current . buffer - > buffer - > hlEvents . backendRelease2 = PSURFACE - > current . buffer - > buffer - > events . backendRelease . registerListener ( [ PSURFACE ] ( std : : any d ) {
const bool DOEXPLICIT = PSURFACE - > syncobj & & PSURFACE - > syncobj - > current . releaseTimeline & & PSURFACE - > syncobj - > current . releaseTimeline - > timeline ;
if ( DOEXPLICIT )
PSURFACE - > syncobj - > current . releaseTimeline - > timeline - > signal ( PSURFACE - > syncobj - > current . releasePoint ) ;
} ) ;
}
2024-07-21 13:09:54 +02:00
} else {
2024-08-06 15:52:19 +02:00
Debug : : log ( TRACE , " attemptDirectScanout: failed to scanout surface " ) ;
2024-07-21 13:09:54 +02:00
lastScanout . reset ( ) ;
return false ;
}
return true ;
}
2024-01-28 02:57:13 +01:00
CMonitorState : : CMonitorState ( CMonitor * owner ) {
m_pOwner = owner ;
}
CMonitorState : : ~ CMonitorState ( ) {
2024-07-21 13:09:54 +02:00
;
2024-01-28 02:57:13 +01:00
}
2024-07-21 13:09:54 +02:00
void CMonitorState : : ensureBufferPresent ( ) {
2024-08-28 15:07:13 +02:00
const auto STATE = m_pOwner - > output - > state - > state ( ) ;
if ( ! STATE . enabled ) {
2024-07-21 13:09:54 +02:00
Debug : : log ( TRACE , " CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled " ) ;
return ;
}
2024-08-28 15:07:13 +02:00
if ( STATE . buffer ) {
if ( const auto params = STATE . buffer - > dmabuf ( ) ; params . success & & params . format = = m_pOwner - > drmFormat )
return ;
}
2024-01-28 02:57:13 +01:00
2024-07-21 13:09:54 +02:00
// this is required for modesetting being possible and might be missing in case of first tests in the renderer
// where we test modes and buffers
2024-08-28 15:07:13 +02:00
Debug : : log ( LOG , " CMonitorState::ensureBufferPresent: no buffer or mismatched format, attaching one from the swapchain for modeset being possible " ) ;
2024-07-21 13:09:54 +02:00
m_pOwner - > output - > state - > setBuffer ( m_pOwner - > output - > swapchain - > next ( nullptr ) ) ;
m_pOwner - > output - > swapchain - > rollback ( ) ; // restore the counter, don't advance the swapchain
2024-01-28 02:57:13 +01:00
}
bool CMonitorState : : commit ( ) {
2024-07-21 13:09:54 +02:00
if ( ! updateSwapchain ( ) )
return false ;
2024-07-30 15:32:38 +02:00
EMIT_HOOK_EVENT ( " preMonitorCommit " , m_pOwner ) ;
2024-07-21 13:09:54 +02:00
ensureBufferPresent ( ) ;
bool ret = m_pOwner - > output - > commit ( ) ;
2024-01-28 02:57:13 +01:00
return ret ;
}
2024-01-28 01:41:54 +01:00
2024-01-28 02:57:13 +01:00
bool CMonitorState : : test ( ) {
2024-07-21 13:09:54 +02:00
if ( ! updateSwapchain ( ) )
return false ;
ensureBufferPresent ( ) ;
return m_pOwner - > output - > test ( ) ;
}
bool CMonitorState : : updateSwapchain ( ) {
auto options = m_pOwner - > output - > swapchain - > currentOptions ( ) ;
const auto & STATE = m_pOwner - > output - > state - > state ( ) ;
const auto & MODE = STATE . mode ? STATE . mode : STATE . customMode ;
if ( ! MODE ) {
Debug : : log ( WARN , " updateSwapchain: No mode? " ) ;
return true ;
}
2024-08-17 19:27:11 +02:00
options . format = m_pOwner - > drmFormat ;
2024-07-21 13:09:54 +02:00
options . scanout = true ;
options . length = 2 ;
options . size = MODE - > pixelSize ;
return m_pOwner - > output - > swapchain - > reconfigure ( options ) ;
2024-01-27 20:11:03 +01:00
}