2022-03-21 15:17:04 +01:00
# include "../Compositor.hpp"
# include "../helpers/WLClasses.hpp"
# include "../managers/InputManager.hpp"
# include "../render/Renderer.hpp"
# include "Events.hpp"
2022-04-21 22:00:03 +02:00
# include "../debug/HyprCtl.hpp"
2022-03-21 15:17:04 +01:00
// --------------------------------------------------------- //
// __ __ ____ _ _ _____ _______ ____ _____ _____ //
// | \/ |/ __ \| \ | |_ _|__ __/ __ \| __ \ / ____| //
// | \ / | | | | \| | | | | | | | | | |__) | (___ //
// | |\/| | | | | . ` | | | | | | | | | _ / \___ \ //
// | | | | |__| | |\ |_| |_ | | | |__| | | \ \ ____) | //
// |_| |_|\____/|_| \_|_____| |_| \____/|_| \_\_____/ //
// //
// --------------------------------------------------------- //
2022-04-19 18:00:54 +02:00
SMonitor * pMostHzMonitor = nullptr ;
2022-03-21 15:17:04 +01:00
void Events : : listener_change ( wl_listener * listener , void * data ) {
// layout got changed, let's update monitors.
const auto CONFIG = wlr_output_configuration_v1_create ( ) ;
for ( auto & m : g_pCompositor - > m_lMonitors ) {
const auto CONFIGHEAD = wlr_output_configuration_head_v1_create ( CONFIG , m . output ) ;
// TODO: clients off of disabled
wlr_box BOX ;
wlr_output_layout_get_box ( g_pCompositor - > m_sWLROutputLayout , m . output , & BOX ) ;
2022-05-16 20:45:27 +02:00
//m.vecSize.x = BOX.width;
// m.vecSize.y = BOX.height;
2022-03-21 15:17:04 +01:00
m . vecPosition . x = BOX . x ;
m . vecPosition . y = BOX . y ;
CONFIGHEAD - > state . enabled = m . output - > enabled ;
CONFIGHEAD - > state . mode = m . output - > current_mode ;
CONFIGHEAD - > state . x = m . vecPosition . x ;
CONFIGHEAD - > state . y = m . vecPosition . y ;
2022-05-16 20:45:27 +02:00
wlr_output_set_custom_mode ( m . output , m . vecPixelSize . x , m . vecPixelSize . y , ( int ) ( round ( m . refreshRate * 1000 ) ) ) ;
2022-03-21 15:17:04 +01:00
}
wlr_output_manager_v1_set_configuration ( g_pCompositor - > m_sWLROutputMgr , CONFIG ) ;
}
void Events : : listener_newOutput ( wl_listener * listener , void * data ) {
// new monitor added, let's accomodate for that.
const auto OUTPUT = ( wlr_output * ) data ;
2022-04-17 10:19:46 +02:00
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager - > getMonitorRuleFor ( OUTPUT - > name ) ;
// if it's disabled, disable and ignore
if ( monitorRule . disabled ) {
wlr_output_enable ( OUTPUT , 0 ) ;
wlr_output_commit ( OUTPUT ) ;
return ;
}
2022-03-21 15:17:04 +01:00
SMonitor newMonitor ;
newMonitor . output = OUTPUT ;
newMonitor . ID = g_pCompositor - > m_lMonitors . size ( ) ;
newMonitor . szName = OUTPUT - > name ;
wlr_output_init_render ( OUTPUT , g_pCompositor - > m_sWLRAllocator , g_pCompositor - > m_sWLRRenderer ) ;
wlr_output_set_scale ( OUTPUT , monitorRule . scale ) ;
wlr_xcursor_manager_load ( g_pCompositor - > m_sWLRXCursorMgr , monitorRule . scale ) ;
wlr_output_set_transform ( OUTPUT , WL_OUTPUT_TRANSFORM_NORMAL ) ; // TODO: support other transforms
wlr_output_enable_adaptive_sync ( OUTPUT , 1 ) ;
// create it in the arr
newMonitor . vecPosition = monitorRule . offset ;
newMonitor . vecSize = monitorRule . resolution ;
newMonitor . refreshRate = monitorRule . refreshRate ;
g_pCompositor - > m_lMonitors . push_back ( newMonitor ) ;
2022-04-11 19:51:37 +02:00
const auto PNEWMONITOR = & g_pCompositor - > m_lMonitors . back ( ) ;
2022-03-21 15:17:04 +01:00
2022-04-11 19:51:37 +02:00
PNEWMONITOR - > hyprListener_monitorFrame . initCallback ( & OUTPUT - > events . frame , & Events : : listener_monitorFrame , PNEWMONITOR ) ;
PNEWMONITOR - > hyprListener_monitorDestroy . initCallback ( & OUTPUT - > events . destroy , & Events : : listener_monitorDestroy , PNEWMONITOR ) ;
2022-03-21 15:17:04 +01:00
wlr_output_enable ( OUTPUT , 1 ) ;
2022-04-10 16:47:19 +02:00
// TODO: this doesn't seem to set the X and Y correctly,
// wlr_output_layout_output_coords returns invalid values, I think...
2022-03-21 15:17:04 +01:00
wlr_output_layout_add ( g_pCompositor - > m_sWLROutputLayout , OUTPUT , monitorRule . offset . x , monitorRule . offset . y ) ;
2022-04-19 19:01:23 +02:00
// set mode, also applies
g_pHyprRenderer - > applyMonitorRule ( PNEWMONITOR , & monitorRule , true ) ;
2022-03-21 15:17:04 +01:00
2022-04-19 18:00:54 +02:00
Debug : : log ( LOG , " Added new monitor with name %s at %i,%i with size %ix%i, pointer %x " , OUTPUT - > name , ( int ) monitorRule . offset . x , ( int ) monitorRule . offset . y , ( int ) monitorRule . resolution . x , ( int ) monitorRule . resolution . y , OUTPUT ) ;
2022-04-11 19:51:37 +02:00
2022-04-19 19:01:23 +02:00
PNEWMONITOR - > damage = wlr_output_damage_create ( PNEWMONITOR - > output ) ;
2022-04-11 19:51:37 +02:00
// add a WLR workspace group
PNEWMONITOR - > pWLRWorkspaceGroupHandle = wlr_ext_workspace_group_handle_v1_create ( g_pCompositor - > m_sWLREXTWorkspaceMgr ) ;
2022-04-28 18:06:25 +02:00
wlr_ext_workspace_group_handle_v1_output_enter ( PNEWMONITOR - > pWLRWorkspaceGroupHandle , PNEWMONITOR - > output ) ;
2022-04-11 19:51:37 +02:00
// Workspace
2022-04-14 20:11:46 +02:00
const auto WORKSPACEID = monitorRule . defaultWorkspaceID = = - 1 ? g_pCompositor - > m_lWorkspaces . size ( ) + 1 /* Cuz workspaces doesnt have the new one yet and we start with 1 */ : monitorRule . defaultWorkspaceID ;
2022-04-11 19:51:37 +02:00
g_pCompositor - > m_lWorkspaces . emplace_back ( newMonitor . ID ) ;
const auto PNEWWORKSPACE = & g_pCompositor - > m_lWorkspaces . back ( ) ;
// We are required to set the name here immediately
wlr_ext_workspace_handle_v1_set_name ( PNEWWORKSPACE - > m_pWlrHandle , std : : to_string ( WORKSPACEID ) . c_str ( ) ) ;
PNEWWORKSPACE - > m_iID = WORKSPACEID ;
PNEWMONITOR - > activeWorkspace = PNEWWORKSPACE - > m_iID ;
2022-04-17 18:47:10 +02:00
PNEWMONITOR - > scale = monitorRule . scale ;
2022-04-28 17:55:25 +02:00
g_pCompositor - > deactivateAllWLRWorkspaces ( PNEWWORKSPACE - > m_pWlrHandle ) ;
2022-04-11 19:51:37 +02:00
wlr_ext_workspace_handle_v1_set_active ( PNEWWORKSPACE - > m_pWlrHandle , true ) ;
2022-04-19 18:00:54 +02:00
if ( ! pMostHzMonitor | | monitorRule . refreshRate > pMostHzMonitor - > refreshRate )
pMostHzMonitor = PNEWMONITOR ;
2022-04-11 19:51:37 +02:00
//
2022-04-20 19:36:05 +02:00
if ( ! g_pCompositor - > m_pLastMonitor ) // set the last monitor if it isnt set yet
g_pCompositor - > m_pLastMonitor = PNEWMONITOR ;
2022-04-28 17:57:24 +02:00
// ready to process cuz we have a monitor
g_pCompositor - > m_bReadyToProcess = true ;
2022-03-21 15:17:04 +01:00
}
2022-03-28 22:31:39 +02:00
void Events : : listener_monitorFrame ( void * owner , void * data ) {
SMonitor * const PMONITOR = ( SMonitor * ) owner ;
2022-03-21 15:17:04 +01:00
2022-04-19 18:00:54 +02:00
// Hack: only check when monitor with top hz refreshes, saves a bit of resources.
2022-03-23 22:01:59 +01:00
// This is for stuff that should be run every frame
2022-04-19 18:00:54 +02:00
if ( PMONITOR - > ID = = pMostHzMonitor - > ID ) {
2022-03-23 22:01:59 +01:00
g_pCompositor - > sanityCheckWorkspaces ( ) ;
g_pAnimationManager - > tick ( ) ;
2022-05-14 17:26:34 +02:00
g_pCompositor - > cleanupFadingOut ( ) ;
2022-04-12 20:02:57 +02:00
2022-04-21 22:00:03 +02:00
HyprCtl : : tickHyprCtl ( ) ; // so that we dont get that race condition multithread bullshit
2022-04-12 20:02:57 +02:00
g_pConfigManager - > dispatchExecOnce ( ) ; // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
2022-04-19 19:01:23 +02:00
if ( g_pConfigManager - > m_bWantsMonitorReload )
g_pConfigManager - > performMonitorReload ( ) ;
2022-03-23 22:01:59 +01:00
}
2022-04-21 18:11:28 +02:00
if ( PMONITOR - > needsFrameSkip ) {
PMONITOR - > needsFrameSkip = false ;
wlr_output_schedule_frame ( PMONITOR - > output ) ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( PMONITOR - > ID ) ;
return ;
}
2022-03-21 15:17:04 +01:00
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
2022-04-14 16:43:29 +02:00
// check the damage
pixman_region32_t damage ;
bool hasChanged ;
pixman_region32_init ( & damage ) ;
const auto DTMODE = g_pConfigManager - > getInt ( " general:damage_tracking_internal " ) ;
if ( DTMODE = = - 1 ) {
Debug : : log ( CRIT , " Damage tracking mode -1 ???? " ) ;
2022-03-21 15:17:04 +01:00
return ;
2022-04-14 16:43:29 +02:00
}
2022-03-21 15:17:04 +01:00
2022-04-14 16:43:29 +02:00
if ( ! wlr_output_damage_attach_render ( PMONITOR - > damage , & hasChanged , & damage ) ) {
Debug : : log ( ERR , " Couldn't attach render to display %s ??? " , PMONITOR - > szName . c_str ( ) ) ;
return ;
}
if ( ! hasChanged & & DTMODE ! = DAMAGE_TRACKING_NONE ) {
pixman_region32_fini ( & damage ) ;
wlr_output_rollback ( PMONITOR - > output ) ;
wlr_output_schedule_frame ( PMONITOR - > output ) ; // we update shit at the monitor's Hz so we need to schedule frames because rollback wont
return ;
}
// if we have no tracking or full tracking, invalidate the entire monitor
if ( DTMODE = = DAMAGE_TRACKING_NONE | | DTMODE = = DAMAGE_TRACKING_MONITOR ) {
2022-05-16 20:45:27 +02:00
pixman_region32_union_rect ( & damage , & damage , 0 , 0 , ( int ) PMONITOR - > vecPixelSize . x , ( int ) PMONITOR - > vecPixelSize . y ) ;
2022-05-06 16:06:21 +02:00
pixman_region32_copy ( & g_pHyprOpenGL - > m_rOriginalDamageRegion , & damage ) ;
} else {
2022-05-16 20:45:27 +02:00
2022-05-06 16:06:21 +02:00
// if we use blur we need to expand the damage for proper blurring
if ( g_pConfigManager - > getInt ( " decoration:blur " ) = = 1 ) {
// TODO: can this be optimized?
const auto BLURSIZE = g_pConfigManager - > getInt ( " decoration:blur_size " ) ;
const auto BLURPASSES = g_pConfigManager - > getInt ( " decoration:blur_passes " ) ;
2022-05-14 20:11:34 +02:00
const auto BLURRADIUS = BLURSIZE * pow ( 2 , BLURPASSES ) ; // is this 2^pass? I don't know but it works... I think.
2022-05-06 16:06:21 +02:00
pixman_region32_copy ( & g_pHyprOpenGL - > m_rOriginalDamageRegion , & damage ) ;
// now, prep the damage, get the extended damage region
wlr_region_expand ( & damage , & damage , BLURRADIUS ) ; // expand for proper blurring
}
2022-04-14 16:43:29 +02:00
}
// TODO: this is getting called with extents being 0,0,0,0 should it be?
// potentially can save on resources.
g_pHyprOpenGL - > begin ( PMONITOR , & damage ) ;
2022-05-16 20:45:27 +02:00
wlr_renderer_begin ( g_pCompositor - > m_sWLRRenderer , PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y ) ; // beginning with wlr here magically fixes some issues with scaling...??
// what the actual fuck in the name of fuck
g_pHyprOpenGL - > clear ( CColor ( 100 , 11 , 11 , 255 ) ) ;
2022-04-10 14:32:18 +02:00
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
2022-03-21 15:17:04 +01:00
2022-04-05 14:33:54 +02:00
g_pHyprRenderer - > renderAllClientsForMonitor ( PMONITOR - > ID , & now ) ;
2022-03-21 15:17:04 +01:00
2022-04-05 14:33:54 +02:00
wlr_output_render_software_cursors ( PMONITOR - > output , NULL ) ;
2022-04-04 19:44:25 +02:00
2022-04-05 14:33:54 +02:00
wlr_renderer_end ( g_pCompositor - > m_sWLRRenderer ) ;
2022-04-04 19:44:25 +02:00
2022-04-05 14:33:54 +02:00
g_pHyprOpenGL - > end ( ) ;
2022-03-21 15:17:04 +01:00
2022-04-14 16:43:29 +02:00
// calc frame damage
pixman_region32_t frameDamage ;
pixman_region32_init ( & frameDamage ) ;
const auto TRANSFORM = wlr_output_transform_invert ( PMONITOR - > output - > transform ) ;
2022-05-16 20:45:27 +02:00
wlr_region_transform ( & frameDamage , & PMONITOR - > damage - > current , TRANSFORM , ( int ) PMONITOR - > vecPixelSize . x , ( int ) PMONITOR - > vecPixelSize . y ) ;
if ( DTMODE = = DAMAGE_TRACKING_NONE | | DTMODE = = DAMAGE_TRACKING_MONITOR )
pixman_region32_union_rect ( & frameDamage , & frameDamage , 0 , 0 , ( int ) PMONITOR - > vecPixelSize . x , ( int ) PMONITOR - > vecPixelSize . y ) ;
2022-04-14 16:43:29 +02:00
wlr_output_set_damage ( PMONITOR - > output , & frameDamage ) ;
pixman_region32_fini ( & frameDamage ) ;
pixman_region32_fini ( & damage ) ;
2022-03-21 15:17:04 +01:00
wlr_output_commit ( PMONITOR - > output ) ;
2022-04-14 16:43:29 +02:00
wlr_output_schedule_frame ( PMONITOR - > output ) ;
2022-03-21 15:17:04 +01:00
}
2022-03-28 22:31:39 +02:00
void Events : : listener_monitorDestroy ( void * owner , void * data ) {
2022-03-21 15:17:04 +01:00
const auto OUTPUT = ( wlr_output * ) data ;
SMonitor * pMonitor = nullptr ;
for ( auto & m : g_pCompositor - > m_lMonitors ) {
if ( m . szName = = OUTPUT - > name ) {
pMonitor = & m ;
break ;
}
}
if ( ! pMonitor )
return ;
g_pCompositor - > m_lMonitors . remove ( * pMonitor ) ;
// TODO: cleanup windows
}