2022-03-16 21:37:21 +01:00
# include "Compositor.hpp"
2022-07-10 15:41:26 +02:00
# include "helpers/Splashes.hpp"
2024-03-03 19:39:20 +01:00
# include "config/ConfigValue.hpp"
2024-03-09 17:52:59 +01:00
# include "managers/CursorManager.hpp"
2024-04-23 02:27:08 +02:00
# include "managers/TokenManager.hpp"
2024-05-05 23:18:10 +02:00
# include "managers/PointerManager.hpp"
2024-05-10 19:27:57 +02:00
# include "managers/SeatManager.hpp"
2024-04-07 04:31:51 +02:00
# include "managers/eventLoop/EventLoopManager.hpp"
2022-07-10 15:41:26 +02:00
# include <random>
2023-07-09 23:08:40 +02:00
# include <unordered_set>
2022-07-31 00:27:32 +02:00
# include "debug/HyprCtl.hpp"
2023-02-19 14:45:56 +01:00
# include "debug/CrashReporter.hpp"
2023-01-05 20:17:55 +01:00
# ifdef USES_SYSTEMD
2024-04-20 19:50:07 +02:00
# include <helpers/SdDaemon.hpp> // for SdNotify
2023-01-05 20:17:55 +01:00
# endif
2023-03-01 15:06:52 +01:00
# include <ranges>
2024-06-11 17:17:45 +02:00
# include "helpers/varlist/VarList.hpp"
2024-04-20 15:14:54 +02:00
# include "protocols/FractionalScale.hpp"
2024-04-27 00:55:41 +02:00
# include "protocols/PointerConstraints.hpp"
2024-05-09 22:47:21 +02:00
# include "protocols/LayerShell.hpp"
2024-05-11 00:28:33 +02:00
# include "protocols/XDGShell.hpp"
2024-06-08 10:07:59 +02:00
# include "protocols/core/Compositor.hpp"
# include "protocols/core/Subcompositor.hpp"
2024-04-30 03:41:27 +02:00
# include "desktop/LayerSurface.hpp"
2024-05-25 22:43:51 +02:00
# include "xwayland/XWayland.hpp"
2022-03-16 21:37:21 +01:00
2024-06-11 17:17:45 +02:00
# include <hyprutils/string/String.hpp>
2024-06-20 18:05:35 +02:00
# include <aquamarine/input/Input.hpp>
2024-06-11 17:17:45 +02:00
2024-04-28 19:58:31 +02:00
# include <sys/types.h>
2024-04-28 23:25:24 +02:00
# include <sys/stat.h>
2024-06-18 21:52:55 +02:00
# include <sys/resource.h>
2024-04-28 19:58:31 +02:00
2024-06-20 18:05:35 +02:00
using namespace Hyprutils : : String ;
using namespace Aquamarine ;
2022-07-13 18:18:23 +02:00
int handleCritSignal ( int signo , void * data ) {
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Hyprland received signal {} " , signo ) ;
2022-07-13 18:18:23 +02:00
2023-08-19 19:24:48 +02:00
if ( signo = = SIGTERM | | signo = = SIGINT | | signo = = SIGKILL )
2022-07-13 18:18:23 +02:00
g_pCompositor - > cleanup ( ) ;
2023-08-19 19:24:48 +02:00
return 0 ;
2022-07-13 18:18:23 +02:00
}
2023-03-01 16:08:44 +01:00
void handleUnrecoverableSignal ( int sig ) {
2023-02-27 13:32:38 +01:00
2023-03-01 22:55:30 +01:00
// remove our handlers
signal ( SIGABRT , SIG_DFL ) ;
signal ( SIGSEGV , SIG_DFL ) ;
2023-12-20 23:54:52 +01:00
if ( g_pHookSystem & & g_pHookSystem - > m_bCurrentEventPlugin ) {
2023-02-27 13:32:38 +01:00
longjmp ( g_pHookSystem - > m_jbHookFaultJumpBuf , 1 ) ;
return ;
}
2024-04-27 18:38:48 +02:00
// Kill the program if the crash-reporter is caught in a deadlock.
signal ( SIGALRM , [ ] ( int _ ) {
char const * msg = " \n CrashReporter exceeded timeout, forcefully exiting \n " ;
write ( 2 , msg , strlen ( msg ) ) ;
abort ( ) ;
} ) ;
alarm ( 15 ) ;
2023-03-01 16:08:44 +01:00
CrashReporter : : createAndSaveCrash ( sig ) ;
2023-03-01 22:55:30 +01:00
2023-02-20 12:02:44 +01:00
abort ( ) ;
2023-02-19 14:45:56 +01:00
}
2023-09-29 17:38:13 +02:00
void handleUserSignal ( int sig ) {
if ( sig = = SIGUSR1 ) {
// means we have to unwind a timed out event
throw std : : exception ( ) ;
}
}
2024-06-20 18:05:35 +02:00
static LogLevel aqLevelToHl ( Aquamarine : : eBackendLogLevel level ) {
switch ( level ) {
case Aquamarine : : eBackendLogLevel : : AQ_LOG_TRACE : return TRACE ;
case Aquamarine : : eBackendLogLevel : : AQ_LOG_DEBUG : return LOG ;
case Aquamarine : : eBackendLogLevel : : AQ_LOG_ERROR : return ERR ;
case Aquamarine : : eBackendLogLevel : : AQ_LOG_WARNING : return WARN ;
case Aquamarine : : eBackendLogLevel : : AQ_LOG_CRITICAL : return CRIT ;
default : break ;
}
return NONE ;
}
void aqLog ( Aquamarine : : eBackendLogLevel level , std : : string msg ) {
Debug : : log ( aqLevelToHl ( level ) , " [AQ] {} " , msg ) ;
}
2024-06-19 18:36:40 +02:00
void CCompositor : : bumpNofile ( ) {
if ( ! getrlimit ( RLIMIT_NOFILE , & m_sOriginalNofile ) )
Debug : : log ( LOG , " Old rlimit: soft -> {}, hard -> {} " , m_sOriginalNofile . rlim_cur , m_sOriginalNofile . rlim_max ) ;
else {
Debug : : log ( ERR , " Failed to get NOFILE rlimits " ) ;
m_sOriginalNofile . rlim_max = 0 ;
return ;
}
2024-06-18 21:52:55 +02:00
2024-06-19 18:36:40 +02:00
rlimit newLimit = m_sOriginalNofile ;
2024-06-18 21:52:55 +02:00
2024-06-19 18:36:40 +02:00
newLimit . rlim_cur = newLimit . rlim_max ;
2024-06-18 21:52:55 +02:00
2024-06-19 18:36:40 +02:00
if ( setrlimit ( RLIMIT_NOFILE , & newLimit ) < 0 ) {
Debug : : log ( ERR , " Failed bumping NOFILE limits higher " ) ;
m_sOriginalNofile . rlim_max = 0 ;
return ;
}
2024-06-18 21:52:55 +02:00
2024-06-19 18:36:40 +02:00
if ( ! getrlimit ( RLIMIT_NOFILE , & newLimit ) )
Debug : : log ( LOG , " New rlimit: soft -> {}, hard -> {} " , newLimit . rlim_cur , newLimit . rlim_max ) ;
}
2024-06-18 21:52:55 +02:00
2024-06-19 18:36:40 +02:00
void CCompositor : : restoreNofile ( ) {
if ( m_sOriginalNofile . rlim_max < = 0 )
return ;
2024-06-18 21:52:55 +02:00
2024-06-19 18:36:40 +02:00
if ( setrlimit ( RLIMIT_NOFILE , & m_sOriginalNofile ) < 0 )
Debug : : log ( ERR , " Failed restoring NOFILE limits " ) ;
2024-06-18 21:52:55 +02:00
}
2022-03-16 21:37:21 +01:00
CCompositor : : CCompositor ( ) {
2022-08-28 11:19:08 +02:00
m_iHyprlandPID = getpid ( ) ;
2024-04-28 23:25:24 +02:00
m_szHyprTempDataRoot = std : : string { getenv ( " XDG_RUNTIME_DIR " ) } + " /hypr " ;
if ( m_szHyprTempDataRoot . starts_with ( " /hypr " ) ) {
std : : cout < < " Bailing out, XDG_RUNTIME_DIR is invalid \n " ;
throw std : : runtime_error ( " CCompositor() failed " ) ;
}
if ( ! m_szHyprTempDataRoot . starts_with ( " /run/user " ) )
std : : cout < < " [!!WARNING!!] XDG_RUNTIME_DIR looks non-standard. Proceeding anyways... \n " ;
2024-04-28 21:06:40 +02:00
std : : random_device dev ;
std : : mt19937 engine ( dev ( ) ) ;
std : : uniform_int_distribution < > distribution ( 0 , INT32_MAX ) ;
m_szInstanceSignature = GIT_COMMIT_HASH + std : : string ( " _ " ) + std : : to_string ( time ( NULL ) ) + " _ " + std : : to_string ( distribution ( engine ) ) ;
2022-03-18 23:52:36 +01:00
2022-06-29 12:58:49 +02:00
setenv ( " HYPRLAND_INSTANCE_SIGNATURE " , m_szInstanceSignature . c_str ( ) , true ) ;
2024-04-28 23:25:24 +02:00
if ( ! std : : filesystem : : exists ( m_szHyprTempDataRoot ) )
mkdir ( m_szHyprTempDataRoot . c_str ( ) , S_IRWXU ) ;
else if ( ! std : : filesystem : : is_directory ( m_szHyprTempDataRoot ) ) {
std : : cout < < " Bailing out, " < < m_szHyprTempDataRoot < < " is not a directory \n " ;
throw std : : runtime_error ( " CCompositor() failed " ) ;
2024-04-28 21:06:40 +02:00
}
2022-12-21 16:41:02 +01:00
2024-04-28 23:25:24 +02:00
m_szInstancePath = m_szHyprTempDataRoot + " / " + m_szInstanceSignature ;
2024-04-28 21:06:40 +02:00
2024-04-28 23:25:24 +02:00
if ( std : : filesystem : : exists ( m_szInstancePath ) ) {
std : : cout < < " Bailing out, " < < m_szInstancePath < < " exists?? \n " ;
throw std : : runtime_error ( " CCompositor() failed " ) ;
2024-04-28 21:06:40 +02:00
}
2024-04-28 23:25:24 +02:00
if ( mkdir ( m_szInstancePath . c_str ( ) , S_IRWXU ) < 0 ) {
std : : cout < < " Bailing out, couldn't create " < < m_szInstancePath < < " \n " ;
throw std : : runtime_error ( " CCompositor() failed " ) ;
2024-04-28 21:06:40 +02:00
}
2022-06-29 12:58:49 +02:00
2024-04-28 23:25:24 +02:00
Debug : : init ( m_szInstancePath ) ;
2022-06-03 17:48:07 +02:00
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Instance Signature: {} " , m_szInstanceSignature ) ;
2022-06-03 17:41:57 +02:00
2024-04-28 23:25:24 +02:00
Debug : : log ( LOG , " Runtime directory: {} " , m_szInstancePath ) ;
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Hyprland PID: {} " , m_iHyprlandPID ) ;
2022-08-28 11:19:08 +02:00
2022-06-25 20:49:06 +02:00
Debug : : log ( LOG , " ===== SYSTEM INFO: ===== " ) ;
logSystemInfo ( ) ;
Debug : : log ( LOG , " ======================== " ) ;
2022-06-25 21:16:52 +02:00
Debug : : log ( NONE , " \n \n " ) ; // pad
2023-01-07 12:33:36 +01:00
Debug : : log ( INFO , " If you are crashing, or encounter any bugs, please consult https://wiki.hyprland.org/Crashes-and-Bugs/ \n \n " ) ;
2022-06-25 21:16:52 +02:00
2022-07-10 15:41:26 +02:00
setRandomSplash ( ) ;
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " \n Current splash: {} \n \n " , m_szCurrentSplash ) ;
2024-06-18 21:52:55 +02:00
bumpNofile ( ) ;
2023-03-05 14:37:21 +01:00
}
CCompositor : : ~ CCompositor ( ) {
cleanup ( ) ;
}
2022-07-10 15:41:26 +02:00
2023-03-05 14:37:21 +01:00
void CCompositor : : setRandomSplash ( ) {
std : : random_device dev ;
std : : mt19937 engine ( dev ( ) ) ;
std : : uniform_int_distribution < > distribution ( 0 , SPLASHES . size ( ) - 1 ) ;
m_szCurrentSplash = SPLASHES [ distribution ( engine ) ] ;
}
2024-06-20 18:05:35 +02:00
static std : : vector < SP < Aquamarine : : IOutput > > pendingOutputs ;
//
2023-03-05 14:37:21 +01:00
void CCompositor : : initServer ( ) {
2023-03-24 14:00:54 +01:00
2022-03-16 21:37:21 +01:00
m_sWLDisplay = wl_display_create ( ) ;
2022-07-13 18:18:23 +02:00
m_sWLEventLoop = wl_display_get_event_loop ( m_sWLDisplay ) ;
// register crit signal handler
2024-06-06 20:27:09 +02:00
m_critSigSource = wl_event_loop_add_signal ( m_sWLEventLoop , SIGTERM , handleCritSignal , nullptr ) ;
2024-02-23 00:10:59 +01:00
if ( ! envEnabled ( " HYPRLAND_NO_CRASHREPORTER " ) ) {
signal ( SIGSEGV , handleUnrecoverableSignal ) ;
signal ( SIGABRT , handleUnrecoverableSignal ) ;
}
2023-09-29 17:38:13 +02:00
signal ( SIGUSR1 , handleUserSignal ) ;
2022-07-13 18:18:23 +02:00
2023-03-05 14:37:21 +01:00
initManagers ( STAGE_PRIORITY ) ;
2023-12-21 22:27:12 +01:00
if ( envEnabled ( " HYPRLAND_TRACE " ) )
2023-08-21 19:36:09 +02:00
Debug : : trace = true ;
2024-06-20 18:05:35 +02:00
Aquamarine : : SBackendOptions options ;
options . logFunction = aqLog ;
2023-03-05 14:37:21 +01:00
2024-06-20 18:05:35 +02:00
std : : vector < Aquamarine : : SBackendImplementationOptions > implementations ;
2024-06-23 19:38:56 +02:00
Aquamarine : : SBackendImplementationOptions option ;
option . backendType = Aquamarine : : eBackendType : : AQ_BACKEND_DRM ;
option . backendRequestMode = Aquamarine : : eBackendRequestMode : : AQ_BACKEND_REQUEST_IF_AVAILABLE ;
implementations . emplace_back ( option ) ;
option . backendType = Aquamarine : : eBackendType : : AQ_BACKEND_WAYLAND ;
option . backendRequestMode = Aquamarine : : eBackendRequestMode : : AQ_BACKEND_REQUEST_FALLBACK ;
implementations . emplace_back ( option ) ;
2023-03-05 14:37:21 +01:00
2024-06-20 18:05:35 +02:00
m_pAqBackend = CBackend : : create ( implementations , options ) ;
2022-03-16 21:37:21 +01:00
2024-06-20 18:05:35 +02:00
if ( ! m_pAqBackend ) {
Debug : : log ( CRIT ,
" m_pAqBackend was null! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a Wayland "
" session, NOT an X11 one. " ) ;
throwError ( " CBackend::create() failed! " ) ;
2022-03-16 21:37:21 +01:00
}
2024-06-20 18:05:35 +02:00
// TODO: headless only
2022-03-16 21:37:21 +01:00
2024-06-20 18:05:35 +02:00
initAllSignals ( ) ;
2022-03-16 21:37:21 +01:00
2024-06-20 18:05:35 +02:00
if ( ! m_pAqBackend - > start ( ) ) {
Debug : : log ( CRIT ,
" m_pAqBackend couldn't start! This usually means aquamarine could not find a GPU or enountered some issues. Make sure you're running either on a tty or on a "
" Wayland session, NOT an X11 one. " ) ;
throwError ( " CBackend::create() failed! " ) ;
2022-03-16 21:37:21 +01:00
}
2024-06-20 18:05:35 +02:00
m_bInitialized = true ;
2022-03-24 17:17:08 +01:00
2024-06-20 18:05:35 +02:00
m_iDRMFD = m_pAqBackend - > drmFD ( ) ;
2022-03-16 21:37:21 +01:00
2024-06-08 10:07:59 +02:00
initManagers ( STAGE_BASICINIT ) ;
2022-03-19 14:09:11 +01:00
2024-06-20 18:05:35 +02:00
initManagers ( STAGE_LATE ) ;
2022-11-05 19:04:44 +01:00
2024-06-20 18:05:35 +02:00
for ( auto & o : pendingOutputs ) {
onNewMonitor ( o ) ;
2022-11-05 19:04:44 +01:00
}
2024-06-20 18:05:35 +02:00
pendingOutputs . clear ( ) ;
2022-07-10 15:41:26 +02:00
}
2022-03-18 23:52:36 +01:00
void CCompositor : : initAllSignals ( ) {
2024-06-20 18:05:35 +02:00
m_pAqBackend - > events . newOutput . registerStaticListener (
[ this ] ( void * p , std : : any data ) {
auto output = std : : any_cast < SP < Aquamarine : : IOutput > > ( data ) ;
Debug : : log ( LOG , " New aquamarine output with name {} " , output - > name ) ;
if ( m_bInitialized )
onNewMonitor ( output ) ;
else
pendingOutputs . emplace_back ( output ) ;
} ,
nullptr ) ;
m_pAqBackend - > events . newPointer . registerStaticListener (
[ ] ( void * data , std : : any d ) {
auto dev = std : : any_cast < SP < Aquamarine : : IPointer > > ( d ) ;
Debug : : log ( LOG , " New aquamarine pointer with name {} " , dev - > getName ( ) ) ;
g_pInputManager - > newMouse ( dev ) ;
g_pInputManager - > updateCapabilities ( ) ;
} ,
nullptr ) ;
m_pAqBackend - > events . newKeyboard . registerStaticListener (
[ ] ( void * data , std : : any d ) {
auto dev = std : : any_cast < SP < Aquamarine : : IKeyboard > > ( d ) ;
Debug : : log ( LOG , " New aquamarine keyboard with name {} " , dev - > getName ( ) ) ;
g_pInputManager - > newKeyboard ( dev ) ;
g_pInputManager - > updateCapabilities ( ) ;
} ,
nullptr ) ;
m_pAqBackend - > events . newTouch . registerStaticListener (
[ ] ( void * data , std : : any d ) {
auto dev = std : : any_cast < SP < Aquamarine : : ITouch > > ( d ) ;
Debug : : log ( LOG , " New aquamarine touch with name {} " , dev - > getName ( ) ) ;
g_pInputManager - > newTouchDevice ( dev ) ;
g_pInputManager - > updateCapabilities ( ) ;
} ,
nullptr ) ;
2022-04-21 15:59:28 +02:00
}
2024-01-19 16:20:22 +01:00
void CCompositor : : removeAllSignals ( ) {
2024-06-20 18:05:35 +02:00
;
2024-01-19 16:20:22 +01:00
}
2024-05-08 19:11:08 +02:00
void CCompositor : : cleanEnvironment ( ) {
// in compositor constructor
unsetenv ( " WAYLAND_DISPLAY " ) ;
// in startCompositor
unsetenv ( " HYPRLAND_INSTANCE_SIGNATURE " ) ;
// in main
unsetenv ( " HYPRLAND_CMD " ) ;
unsetenv ( " XDG_BACKEND " ) ;
unsetenv ( " XDG_CURRENT_DESKTOP " ) ;
2024-06-20 18:05:35 +02:00
if ( false /* TODO: */ ) {
2024-05-08 19:11:08 +02:00
const auto CMD =
# ifdef USES_SYSTEMD
2024-06-23 09:13:17 +02:00
" systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
2024-05-08 19:11:08 +02:00
" dbus-update-activation-environment 2>/dev/null && "
# endif
2024-06-23 09:13:17 +02:00
" dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS " ;
2024-05-08 19:11:08 +02:00
g_pKeybindManager - > spawn ( CMD ) ;
}
}
2022-07-13 18:18:23 +02:00
void CCompositor : : cleanup ( ) {
2022-08-25 21:35:47 +02:00
if ( ! m_sWLDisplay | | m_bIsShuttingDown )
2022-04-21 15:59:28 +02:00
return ;
2024-02-23 17:48:27 +01:00
signal ( SIGABRT , SIG_DFL ) ;
signal ( SIGSEGV , SIG_DFL ) ;
2023-08-08 16:16:34 +02:00
removeLockFile ( ) ;
2023-12-06 15:46:18 +01:00
m_bIsShuttingDown = true ;
Debug : : shuttingDown = true ;
2022-10-24 01:14:42 +02:00
2023-07-06 15:24:49 +02:00
# ifdef USES_SYSTEMD
2024-04-20 19:50:07 +02:00
if ( Systemd : : SdBooted ( ) > 0 & & ! envEnabled ( " HYPRLAND_NO_SD_NOTIFY " ) )
Systemd : : SdNotify ( 0 , " STOPPING=1 " ) ;
2023-07-06 15:24:49 +02:00
# endif
2024-05-08 19:11:08 +02:00
cleanEnvironment ( ) ;
2023-03-01 00:11:49 +01:00
// unload all remaining plugins while the compositor is
// still in a normal working state.
g_pPluginSystem - > unloadAllPlugins ( ) ;
2024-06-08 10:07:59 +02:00
m_pLastFocus . reset ( ) ;
2024-04-27 13:43:12 +02:00
m_pLastWindow . reset ( ) ;
2022-05-29 00:07:31 +02:00
2022-06-30 15:44:26 +02:00
m_vWorkspaces . clear ( ) ;
m_vWindows . clear ( ) ;
2022-05-29 00:00:47 +02:00
2022-08-25 21:35:47 +02:00
for ( auto & m : m_vMonitors ) {
2022-08-22 14:17:25 +02:00
g_pHyprOpenGL - > destroyMonitorResources ( m . get ( ) ) ;
2024-06-20 18:05:35 +02:00
m - > output - > state - > setEnabled ( false ) ;
2024-01-28 02:57:13 +01:00
m - > state . commit ( ) ;
2022-08-25 21:35:47 +02:00
}
2024-05-25 22:43:51 +02:00
g_pXWayland . reset ( ) ;
2022-10-06 19:43:50 +02:00
2024-05-25 22:43:51 +02:00
m_vMonitors . clear ( ) ;
2022-04-21 15:59:28 +02:00
2024-04-08 16:32:31 +02:00
wl_display_destroy_clients ( g_pCompositor - > m_sWLDisplay ) ;
2024-01-19 16:20:22 +01:00
removeAllSignals ( ) ;
2024-02-24 03:50:54 +01:00
g_pInputManager . reset ( ) ;
2024-01-19 16:20:22 +01:00
g_pDecorationPositioner . reset ( ) ;
2024-03-09 17:52:59 +01:00
g_pCursorManager . reset ( ) ;
2024-01-19 16:20:22 +01:00
g_pPluginSystem . reset ( ) ;
g_pHyprNotificationOverlay . reset ( ) ;
g_pDebugOverlay . reset ( ) ;
g_pEventManager . reset ( ) ;
g_pSessionLockManager . reset ( ) ;
g_pProtocolManager . reset ( ) ;
g_pHyprRenderer . reset ( ) ;
g_pHyprOpenGL . reset ( ) ;
g_pThreadManager . reset ( ) ;
g_pConfigManager . reset ( ) ;
g_pLayoutManager . reset ( ) ;
g_pHyprError . reset ( ) ;
g_pConfigManager . reset ( ) ;
g_pAnimationManager . reset ( ) ;
g_pKeybindManager . reset ( ) ;
g_pHookSystem . reset ( ) ;
g_pWatchdog . reset ( ) ;
g_pXWaylandManager . reset ( ) ;
2024-05-10 19:27:57 +02:00
g_pPointerManager . reset ( ) ;
g_pSeatManager . reset ( ) ;
2024-06-13 12:08:02 +02:00
g_pHyprCtl . reset ( ) ;
g_pEventLoopManager . reset ( ) ;
2024-05-03 15:42:08 +02:00
2024-06-20 18:05:35 +02:00
if ( m_pAqBackend )
m_pAqBackend . reset ( ) ;
2024-05-03 15:42:08 +02:00
2024-06-06 20:27:09 +02:00
if ( m_critSigSource )
wl_event_source_remove ( m_critSigSource ) ;
2024-06-13 12:08:02 +02:00
wl_event_loop_destroy ( m_sWLEventLoop ) ;
2024-05-03 15:42:08 +02:00
wl_display_terminate ( m_sWLDisplay ) ;
2023-03-09 15:19:41 +01:00
m_sWLDisplay = nullptr ;
2024-05-09 14:39:15 +02:00
std : : string waylandSocket = std : : string { getenv ( " XDG_RUNTIME_DIR " ) } + " / " + m_szWLDisplaySocket ;
std : : filesystem : : remove ( waylandSocket ) ;
std : : filesystem : : remove ( waylandSocket + " .lock " ) ;
2022-03-18 23:52:36 +01:00
}
2022-03-17 17:08:54 +01:00
2023-03-05 14:37:21 +01:00
void CCompositor : : initManagers ( eManagersInitStage stage ) {
switch ( stage ) {
case STAGE_PRIORITY : {
2024-04-07 04:31:51 +02:00
Debug : : log ( LOG , " Creating the EventLoopManager! " ) ;
2024-07-05 23:05:03 +02:00
g_pEventLoopManager = std : : make_unique < CEventLoopManager > ( m_sWLDisplay , m_sWLEventLoop ) ;
2024-04-07 04:31:51 +02:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the HookSystem! " ) ;
g_pHookSystem = std : : make_unique < CHookSystemManager > ( ) ;
2022-03-19 17:48:18 +01:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the KeybindManager! " ) ;
g_pKeybindManager = std : : make_unique < CKeybindManager > ( ) ;
2022-04-23 21:47:16 +02:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the AnimationManager! " ) ;
g_pAnimationManager = std : : make_unique < CAnimationManager > ( ) ;
2022-07-16 15:57:31 +02:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the ConfigManager! " ) ;
g_pConfigManager = std : : make_unique < CConfigManager > ( ) ;
2022-03-17 17:08:54 +01:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the CHyprError! " ) ;
g_pHyprError = std : : make_unique < CHyprError > ( ) ;
2023-01-20 20:48:07 +01:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the LayoutManager! " ) ;
g_pLayoutManager = std : : make_unique < CLayoutManager > ( ) ;
2022-03-17 17:08:54 +01:00
2024-04-23 02:27:08 +02:00
Debug : : log ( LOG , " Creating the TokenManager! " ) ;
g_pTokenManager = std : : make_unique < CTokenManager > ( ) ;
2023-03-05 14:37:21 +01:00
g_pConfigManager - > init ( ) ;
2023-09-29 18:04:20 +02:00
g_pWatchdog = std : : make_unique < CWatchdog > ( ) ; // requires config
2024-05-05 23:18:10 +02:00
Debug : : log ( LOG , " Creating the PointerManager! " ) ;
g_pPointerManager = std : : make_unique < CPointerManager > ( ) ;
2024-06-20 18:05:35 +02:00
Debug : : log ( LOG , " Creating the EventManager! " ) ;
g_pEventManager = std : : make_unique < CEventManager > ( ) ;
2023-03-05 14:37:21 +01:00
} break ;
2024-06-08 10:07:59 +02:00
case STAGE_BASICINIT : {
2024-06-09 21:10:46 +02:00
Debug : : log ( LOG , " Creating the CHyprOpenGLImpl! " ) ;
g_pHyprOpenGL = std : : make_unique < CHyprOpenGLImpl > ( ) ;
2024-06-08 10:07:59 +02:00
Debug : : log ( LOG , " Creating the ProtocolManager! " ) ;
g_pProtocolManager = std : : make_unique < CProtocolManager > ( ) ;
Debug : : log ( LOG , " Creating the SeatManager! " ) ;
g_pSeatManager = std : : make_unique < CSeatManager > ( ) ;
} break ;
2023-03-05 14:37:21 +01:00
case STAGE_LATE : {
Debug : : log ( LOG , " Creating the ThreadManager! " ) ;
g_pThreadManager = std : : make_unique < CThreadManager > ( ) ;
2022-03-17 20:22:29 +01:00
2024-02-05 02:43:45 +01:00
Debug : : log ( LOG , " Creating CHyprCtl " ) ;
g_pHyprCtl = std : : make_unique < CHyprCtl > ( ) ;
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the InputManager! " ) ;
g_pInputManager = std : : make_unique < CInputManager > ( ) ;
2022-04-04 19:44:25 +02:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the HyprRenderer! " ) ;
g_pHyprRenderer = std : : make_unique < CHyprRenderer > ( ) ;
2022-03-19 15:59:53 +01:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the XWaylandManager! " ) ;
g_pXWaylandManager = std : : make_unique < CHyprXWaylandManager > ( ) ;
2022-12-05 18:05:15 +01:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the SessionLockManager! " ) ;
g_pSessionLockManager = std : : make_unique < CSessionLockManager > ( ) ;
2022-05-28 17:32:19 +02:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the HyprDebugOverlay! " ) ;
g_pDebugOverlay = std : : make_unique < CHyprDebugOverlay > ( ) ;
2023-02-27 13:32:38 +01:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the HyprNotificationOverlay! " ) ;
g_pHyprNotificationOverlay = std : : make_unique < CHyprNotificationOverlay > ( ) ;
2022-03-17 17:08:54 +01:00
2023-03-05 14:37:21 +01:00
Debug : : log ( LOG , " Creating the PluginSystem! " ) ;
g_pPluginSystem = std : : make_unique < CPluginSystem > ( ) ;
2023-05-01 16:10:53 +02:00
g_pConfigManager - > handlePluginLoads ( ) ;
2023-11-11 15:37:17 +01:00
Debug : : log ( LOG , " Creating the DecorationPositioner! " ) ;
g_pDecorationPositioner = std : : make_unique < CDecorationPositioner > ( ) ;
2024-03-09 17:52:59 +01:00
Debug : : log ( LOG , " Creating the CursorManager! " ) ;
g_pCursorManager = std : : make_unique < CCursorManager > ( ) ;
2024-05-25 22:43:51 +02:00
Debug : : log ( LOG , " Starting XWayland " ) ;
g_pXWayland = std : : make_unique < CXWayland > ( ) ;
2023-03-05 14:37:21 +01:00
} break ;
default : UNREACHABLE ( ) ;
}
}
2022-08-01 23:31:25 +02:00
2023-08-08 16:16:34 +02:00
void CCompositor : : createLockFile ( ) {
2024-04-28 23:25:24 +02:00
const auto PATH = m_szInstancePath + " /hyprland.lock " ;
2023-08-08 16:16:34 +02:00
std : : ofstream ofs ( PATH , std : : ios : : trunc ) ;
ofs < < m_iHyprlandPID < < " \n " < < m_szWLDisplaySocket < < " \n " ;
ofs . close ( ) ;
}
void CCompositor : : removeLockFile ( ) {
2024-04-28 23:25:24 +02:00
const auto PATH = m_szInstancePath + " /hyprland.lock " ;
2023-08-08 16:16:34 +02:00
if ( std : : filesystem : : exists ( PATH ) )
std : : filesystem : : remove ( PATH ) ;
}
2023-11-01 19:53:36 +01:00
void CCompositor : : prepareFallbackOutput ( ) {
2024-06-20 18:05:35 +02:00
// TODO:
// // create a backup monitor
// wlr_backend* headless = nullptr;
// wlr_multi_for_each_backend(
// m_sWLRBackend,
// [](wlr_backend* b, void* data) {
// if (wlr_backend_is_headless(b))
// *((wlr_backend**)data) = b;
// },
// &headless);
2023-11-01 19:53:36 +01:00
2024-06-20 18:05:35 +02:00
// if (!headless) {
// Debug::log(WARN, "Unsafe state will be ineffective, no fallback output");
// return;
// }
2023-11-01 19:53:36 +01:00
2024-06-20 18:05:35 +02:00
// wlr_headless_add_output(headless, 1920, 1080);
2023-11-01 19:53:36 +01:00
}
2023-03-05 14:37:21 +01:00
void CCompositor : : startCompositor ( ) {
2022-12-05 18:21:09 +01:00
// get socket, avoid using 0
for ( int candidate = 1 ; candidate < = 32 ; candidate + + ) {
2023-01-19 16:44:23 +01:00
const auto CANDIDATESTR = ( " wayland- " + std : : to_string ( candidate ) ) ;
const auto RETVAL = wl_display_add_socket ( m_sWLDisplay , CANDIDATESTR . c_str ( ) ) ;
if ( RETVAL > = 0 ) {
m_szWLDisplaySocket = CANDIDATESTR ;
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " wl_display_add_socket for {} succeeded with {} " , CANDIDATESTR , RETVAL ) ;
2022-12-05 18:21:09 +01:00
break ;
2023-01-19 16:44:23 +01:00
} else {
2023-09-06 21:45:37 +02:00
Debug : : log ( WARN , " wl_display_add_socket for {} returned {}: skipping candidate {} " , CANDIDATESTR , RETVAL , candidate ) ;
2022-12-05 18:21:09 +01:00
}
}
2022-03-16 21:37:21 +01:00
2023-01-19 16:44:23 +01:00
if ( m_szWLDisplaySocket . empty ( ) ) {
Debug : : log ( WARN , " All candidates failed, trying wl_display_add_socket_auto " ) ;
const auto SOCKETSTR = wl_display_add_socket_auto ( m_sWLDisplay ) ;
if ( SOCKETSTR )
m_szWLDisplaySocket = SOCKETSTR ;
}
2022-12-05 18:21:09 +01:00
if ( m_szWLDisplaySocket . empty ( ) ) {
2022-03-16 21:37:21 +01:00
Debug : : log ( CRIT , " m_szWLDisplaySocket NULL! " ) ;
2023-08-20 13:58:46 +02:00
throwError ( " m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed) " ) ;
2022-03-16 21:37:21 +01:00
}
2022-12-05 18:21:09 +01:00
setenv ( " WAYLAND_DISPLAY " , m_szWLDisplaySocket . c_str ( ) , 1 ) ;
2022-03-16 21:37:21 +01:00
signal ( SIGPIPE , SIG_IGN ) ;
2024-06-20 18:05:35 +02:00
// TODO:
if ( false /* Session-less Hyprland usually means a nest, don't update the env in that case */ ) {
2023-12-26 18:16:59 +01:00
const auto CMD =
2023-04-15 21:03:09 +02:00
# ifdef USES_SYSTEMD
2024-06-23 09:13:17 +02:00
" systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
2023-12-26 18:16:59 +01:00
" dbus-update-activation-environment 2>/dev/null && "
2023-04-15 21:03:09 +02:00
# endif
2024-06-23 09:13:17 +02:00
" dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP HYPRLAND_INSTANCE_SIGNATURE QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS " ;
2023-12-26 18:16:59 +01:00
g_pKeybindManager - > spawn ( CMD ) ;
}
2022-11-04 11:37:14 +01:00
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Running on WAYLAND_DISPLAY: {} " , m_szWLDisplaySocket ) ;
2022-03-16 21:37:21 +01:00
2023-11-01 19:53:36 +01:00
prepareFallbackOutput ( ) ;
2023-09-29 18:51:07 +02:00
g_pHyprRenderer - > setCursorFromName ( " left_ptr " ) ;
2022-03-16 21:37:21 +01:00
2023-01-05 20:17:55 +01:00
# ifdef USES_SYSTEMD
2024-04-20 19:50:07 +02:00
if ( Systemd : : SdBooted ( ) > 0 ) {
2023-01-05 20:17:55 +01:00
// tell systemd that we are ready so it can start other bond, following, related units
2023-12-21 22:27:12 +01:00
if ( ! envEnabled ( " HYPRLAND_NO_SD_NOTIFY " ) )
2024-04-20 19:50:07 +02:00
Systemd : : SdNotify ( 0 , " READY=1 " ) ;
2023-12-21 22:27:12 +01:00
} else
2023-01-05 20:17:55 +01:00
Debug : : log ( LOG , " systemd integration is baked in but system itself is not booted à la systemd! " ) ;
# endif
2023-08-08 16:16:34 +02:00
createLockFile ( ) ;
2024-06-08 10:07:59 +02:00
EMIT_HOOK_EVENT ( " ready " , nullptr ) ;
2022-03-16 21:37:21 +01:00
// This blocks until we are done.
Debug : : log ( LOG , " Hyprland is ready, running the event loop! " ) ;
2024-07-05 23:05:03 +02:00
g_pEventLoopManager - > enterLoop ( ) ;
2022-03-17 20:22:29 +01:00
}
2022-07-27 12:32:00 +02:00
CMonitor * CCompositor : : getMonitorFromID ( const int & id ) {
2022-06-30 15:44:26 +02:00
for ( auto & m : m_vMonitors ) {
if ( m - > ID = = ( uint64_t ) id ) {
return m . get ( ) ;
2022-03-17 20:22:29 +01:00
}
}
return nullptr ;
}
2022-07-27 12:32:00 +02:00
CMonitor * CCompositor : : getMonitorFromName ( const std : : string & name ) {
2022-06-30 15:44:26 +02:00
for ( auto & m : m_vMonitors ) {
if ( m - > szName = = name ) {
2023-07-09 23:10:35 +02:00
return m . get ( ) ;
}
}
return nullptr ;
}
CMonitor * CCompositor : : getMonitorFromDesc ( const std : : string & desc ) {
for ( auto & m : m_vMonitors ) {
2023-11-30 02:48:10 +01:00
if ( m - > szDescription . starts_with ( desc ) )
2022-06-30 15:44:26 +02:00
return m . get ( ) ;
2022-05-29 20:15:34 +02:00
}
return nullptr ;
}
2022-07-27 12:32:00 +02:00
CMonitor * CCompositor : : getMonitorFromCursor ( ) {
2024-05-05 23:18:10 +02:00
return getMonitorFromVector ( g_pPointerManager - > position ( ) ) ;
2022-03-18 22:35:51 +01:00
}
2022-07-27 12:32:00 +02:00
CMonitor * CCompositor : : getMonitorFromVector ( const Vector2D & point ) {
2024-05-05 23:18:10 +02:00
SP < CMonitor > mon ;
for ( auto & m : m_vMonitors ) {
if ( CBox { m - > vecPosition , m - > vecSize } . containsPoint ( point ) ) {
mon = m ;
break ;
}
}
2022-03-20 11:22:55 +01:00
2024-05-05 23:18:10 +02:00
if ( ! mon ) {
float bestDistance = 0.f ;
SP < CMonitor > pBestMon ;
2022-05-25 18:40:03 +02:00
2022-06-30 15:44:26 +02:00
for ( auto & m : m_vMonitors ) {
float dist = vecToRectDistanceSquared ( point , m - > vecPosition , m - > vecPosition + m - > vecSize ) ;
2022-05-25 18:40:03 +02:00
if ( dist < bestDistance | | ! pBestMon ) {
bestDistance = dist ;
2024-05-05 23:18:10 +02:00
pBestMon = m ;
2022-05-25 18:40:03 +02:00
}
}
if ( ! pBestMon ) { // ?????
Debug : : log ( WARN , " getMonitorFromVector no close mon??? " ) ;
2022-06-30 15:44:26 +02:00
return m_vMonitors . front ( ) . get ( ) ;
2022-05-25 18:40:03 +02:00
}
2024-05-05 23:18:10 +02:00
return pBestMon . get ( ) ;
2022-03-20 11:22:55 +01:00
}
2024-05-05 23:18:10 +02:00
return mon . get ( ) ;
2022-03-20 11:22:55 +01:00
}
2024-04-27 13:43:12 +02:00
void CCompositor : : removeWindowFromVectorSafe ( PHLWINDOW pWindow ) {
if ( ! pWindow - > m_bFadingOut ) {
2024-04-19 23:16:35 +02:00
EMIT_HOOK_EVENT ( " destroyWindow " , pWindow ) ;
2024-04-27 13:43:12 +02:00
std : : erase_if ( m_vWindows , [ & ] ( SP < CWindow > & el ) { return el = = pWindow ; } ) ;
std : : erase_if ( m_vWindowsFadingOut , [ & ] ( PHLWINDOWREF el ) { return el . lock ( ) = = pWindow ; } ) ;
2024-04-06 15:51:35 +02:00
}
2022-03-18 22:53:27 +01:00
}
2024-02-07 01:18:47 +01:00
bool CCompositor : : monitorExists ( CMonitor * pMonitor ) {
for ( auto & m : m_vRealMonitors ) {
if ( m . get ( ) = = pMonitor )
return true ;
}
return false ;
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : vectorToWindowUnified ( const Vector2D & pos , uint8_t properties , PHLWINDOW pIgnoreWindow ) {
2024-03-03 19:39:20 +01:00
const auto PMONITOR = getMonitorFromVector ( pos ) ;
static auto PRESIZEONBORDER = CConfigValue < Hyprlang : : INT > ( " general:resize_on_border " ) ;
static auto PBORDERSIZE = CConfigValue < Hyprlang : : INT > ( " general:border_size " ) ;
static auto PBORDERGRABEXTEND = CConfigValue < Hyprlang : : INT > ( " general:extend_border_grab_area " ) ;
static auto PSPECIALFALLTHRU = CConfigValue < Hyprlang : : INT > ( " input:special_fallthrough " ) ;
const auto BORDER_GRAB_AREA = * PRESIZEONBORDER ? * PBORDERSIZE + * PBORDERGRABEXTEND : 0 ;
2022-05-31 14:01:00 +02:00
2022-09-10 13:11:02 +02:00
// pinned windows on top of floating regardless
2024-02-04 16:40:20 +01:00
if ( properties & ALLOW_FLOATING ) {
for ( auto & w : m_vWindows | std : : views : : reverse ) {
const auto BB = w - > getWindowBoxUnified ( properties ) ;
2024-05-25 22:43:51 +02:00
CBox box = BB . copy ( ) . expand ( w - > m_iX11Type = = 2 ? BORDER_GRAB_AREA : 0 ) ;
2024-04-27 13:43:12 +02:00
if ( w - > m_bIsFloating & & w - > m_bIsMapped & & ! w - > isHidden ( ) & & ! w - > m_bX11ShouldntFocus & & w - > m_bPinned & & ! w - > m_sAdditionalConfigData . noFocus & & w ! = pIgnoreWindow ) {
2024-05-05 23:18:10 +02:00
if ( box . containsPoint ( g_pPointerManager - > position ( ) ) )
2024-04-27 13:43:12 +02:00
return w ;
2024-02-04 16:40:20 +01:00
if ( ! w - > m_bIsX11 ) {
if ( w - > hasPopupAt ( pos ) )
2024-04-27 13:43:12 +02:00
return w ;
2024-02-04 16:40:20 +01:00
}
2022-09-10 13:11:02 +02:00
}
2022-09-25 20:07:48 +02:00
}
2022-09-10 13:11:02 +02:00
}
2024-04-27 13:43:12 +02:00
auto windowForWorkspace = [ & ] ( bool special ) - > PHLWINDOW {
auto floating = [ & ] ( bool aboveFullscreen ) - > PHLWINDOW {
2024-02-04 16:40:20 +01:00
for ( auto & w : m_vWindows | std : : views : : reverse ) {
2023-11-18 18:00:24 +01:00
2024-04-02 21:32:39 +02:00
if ( special & & ! w - > onSpecialWorkspace ( ) ) // because special floating may creep up into regular
2023-11-18 18:00:24 +01:00
continue ;
2024-03-03 18:04:39 +01:00
const auto BB = w - > getWindowBoxUnified ( properties ) ;
const auto PWINDOWMONITOR = getMonitorFromID ( w - > m_iMonitorID ) ;
// to avoid focusing windows behind special workspaces from other monitors
2024-04-02 21:32:39 +02:00
if ( ! * PSPECIALFALLTHRU & & PWINDOWMONITOR & & PWINDOWMONITOR - > activeSpecialWorkspace & & w - > m_pWorkspace ! = PWINDOWMONITOR - > activeSpecialWorkspace & &
2024-03-03 18:04:39 +01:00
BB . x > = PWINDOWMONITOR - > vecPosition . x & & BB . y > = PWINDOWMONITOR - > vecPosition . y & &
BB . x + BB . width < = PWINDOWMONITOR - > vecPosition . x + PWINDOWMONITOR - > vecSize . x & & BB . y + BB . height < = PWINDOWMONITOR - > vecPosition . y + PWINDOWMONITOR - > vecSize . y )
continue ;
2024-05-25 22:43:51 +02:00
CBox box = BB . copy ( ) . expand ( w - > m_iX11Type = = 2 ? BORDER_GRAB_AREA : 0 ) ;
2024-04-03 11:09:42 +02:00
if ( w - > m_bIsFloating & & w - > m_bIsMapped & & isWorkspaceVisible ( w - > m_pWorkspace ) & & ! w - > isHidden ( ) & & ! w - > m_bPinned & & ! w - > m_sAdditionalConfigData . noFocus & &
2024-04-27 13:43:12 +02:00
w ! = pIgnoreWindow & & ( ! aboveFullscreen | | w - > m_bCreatedOverFullscreen ) ) {
2024-02-04 16:40:20 +01:00
// OR windows should add focus to parent
if ( w - > m_bX11ShouldntFocus & & w - > m_iX11Type ! = 2 )
continue ;
2022-10-01 19:25:02 +02:00
2024-05-05 23:18:10 +02:00
if ( box . containsPoint ( g_pPointerManager - > position ( ) ) ) {
2023-11-18 18:00:24 +01:00
2024-05-25 22:43:51 +02:00
if ( w - > m_bIsX11 & & w - > m_iX11Type = = 2 & & ! w - > m_pXWaylandSurface - > wantsFocus ( ) ) {
2024-02-04 16:40:20 +01:00
// Override Redirect
2024-04-27 13:43:12 +02:00
return g_pCompositor - > m_pLastWindow . lock ( ) ; // we kinda trick everything here.
// TODO: this is wrong, we should focus the parent, but idk how to get it considering it's nullptr in most cases.
2024-02-04 16:40:20 +01:00
}
2022-10-01 19:25:02 +02:00
2024-04-27 13:43:12 +02:00
return w ;
2024-02-04 16:40:20 +01:00
}
if ( ! w - > m_bIsX11 ) {
if ( w - > hasPopupAt ( pos ) )
2024-04-27 13:43:12 +02:00
return w ;
2024-02-04 16:40:20 +01:00
}
2023-11-18 18:00:24 +01:00
}
2022-10-01 19:25:02 +02:00
}
2024-02-22 16:42:17 +01:00
return nullptr ;
} ;
if ( properties & ALLOW_FLOATING ) {
// first loop over floating cuz they're above, m_lWindows should be sorted bottom->top, for tiled it doesn't matter.
auto found = floating ( true ) ;
if ( found )
return found ;
2023-11-18 18:00:24 +01:00
}
2022-07-12 09:49:56 +02:00
2024-02-04 16:40:20 +01:00
if ( properties & FLOATING_ONLY )
2024-02-22 16:42:17 +01:00
return floating ( false ) ;
2024-02-04 16:40:20 +01:00
2024-04-02 21:32:39 +02:00
const int64_t WORKSPACEID = special ? PMONITOR - > activeSpecialWorkspaceID ( ) : PMONITOR - > activeWorkspaceID ( ) ;
2023-12-03 13:53:12 +01:00
const auto PWORKSPACE = getWorkspaceByID ( WORKSPACEID ) ;
if ( PWORKSPACE - > m_bHasFullscreenWindow )
return getFullscreenWindowOnWorkspace ( PWORKSPACE - > m_iID ) ;
2024-02-22 16:42:17 +01:00
auto found = floating ( false ) ;
if ( found )
return found ;
2023-11-18 18:00:24 +01:00
// for windows, we need to check their extensions too, first.
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( special ! = w - > onSpecialWorkspace ( ) )
2023-11-18 18:00:24 +01:00
continue ;
2024-04-02 21:32:39 +02:00
if ( ! w - > m_bIsX11 & & ! w - > m_bIsFloating & & w - > m_bIsMapped & & w - > workspaceID ( ) = = WORKSPACEID & & ! w - > isHidden ( ) & & ! w - > m_bX11ShouldntFocus & &
2024-04-27 13:43:12 +02:00
! w - > m_sAdditionalConfigData . noFocus & & w ! = pIgnoreWindow ) {
2023-12-03 13:53:12 +01:00
if ( w - > hasPopupAt ( pos ) )
2024-04-27 13:43:12 +02:00
return w ;
2022-07-12 09:49:56 +02:00
}
2022-09-25 20:07:48 +02:00
}
2023-12-03 13:53:12 +01:00
2023-11-18 18:00:24 +01:00
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( special ! = w - > onSpecialWorkspace ( ) )
2023-11-18 18:00:24 +01:00
continue ;
2022-03-20 11:14:24 +01:00
2024-02-04 16:40:20 +01:00
CBox box = ( properties & USE_PROP_TILED ) ? w - > getWindowBoxUnified ( properties ) : CBox { w - > m_vPosition , w - > m_vSize } ;
2024-04-02 21:32:39 +02:00
if ( ! w - > m_bIsFloating & & w - > m_bIsMapped & & box . containsPoint ( pos ) & & w - > workspaceID ( ) = = WORKSPACEID & & ! w - > isHidden ( ) & & ! w - > m_bX11ShouldntFocus & &
2024-04-27 13:43:12 +02:00
! w - > m_sAdditionalConfigData . noFocus & & w ! = pIgnoreWindow )
return w ;
2022-07-12 09:49:56 +02:00
}
2022-03-19 20:30:21 +01:00
2023-11-18 18:00:24 +01:00
return nullptr ;
} ;
// special workspace
2024-04-02 21:32:39 +02:00
if ( PMONITOR - > activeSpecialWorkspace & & ! * PSPECIALFALLTHRU )
2023-11-18 18:00:24 +01:00
return windowForWorkspace ( true ) ;
2024-04-02 21:32:39 +02:00
if ( PMONITOR - > activeSpecialWorkspace ) {
2024-01-09 13:17:55 +01:00
const auto PWINDOW = windowForWorkspace ( true ) ;
if ( PWINDOW )
return PWINDOW ;
}
2023-11-18 18:00:24 +01:00
return windowForWorkspace ( false ) ;
2022-03-19 20:30:21 +01:00
}
2024-06-08 10:07:59 +02:00
SP < CWLSurfaceResource > CCompositor : : vectorWindowToSurface ( const Vector2D & pos , PHLWINDOW pWindow , Vector2D & sl ) {
2022-04-02 13:02:16 +02:00
2024-04-27 13:43:12 +02:00
if ( ! validMapped ( pWindow ) )
2022-04-02 13:02:16 +02:00
return nullptr ;
RASSERT ( ! pWindow - > m_bIsX11 , " Cannot call vectorWindowToSurface on an X11 window! " ) ;
2024-05-11 00:28:33 +02:00
// try popups first
2024-06-08 10:07:59 +02:00
const auto PPOPUP = pWindow - > m_pPopupHead - > at ( pos ) ;
2022-04-02 13:02:16 +02:00
2024-06-08 10:07:59 +02:00
if ( PPOPUP ) {
2024-05-11 00:28:33 +02:00
const auto OFF = PPOPUP - > coordsRelativeToParent ( ) ;
2024-06-08 10:07:59 +02:00
sl = pos - pWindow - > m_vRealPosition . goal ( ) - OFF ;
return PPOPUP - > m_pWLSurface - > resource ( ) ;
2024-05-11 00:28:33 +02:00
}
2022-04-02 13:02:16 +02:00
2024-06-08 10:07:59 +02:00
auto [ surf , local ] = pWindow - > m_pWLSurface - > resource ( ) - > at ( pos - pWindow - > m_vRealPosition . goal ( ) , true ) ;
if ( surf ) {
sl = local ;
return surf ;
2022-04-02 13:02:16 +02:00
}
2024-06-08 10:07:59 +02:00
return nullptr ;
2022-04-02 13:02:16 +02:00
}
2024-06-08 10:07:59 +02:00
Vector2D CCompositor : : vectorToSurfaceLocal ( const Vector2D & vec , PHLWINDOW pWindow , SP < CWLSurfaceResource > pSurface ) {
2024-04-27 13:43:12 +02:00
if ( ! validMapped ( pWindow ) )
2023-09-23 02:21:59 +02:00
return { } ;
if ( pWindow - > m_bIsX11 )
2024-03-02 01:35:17 +01:00
return vec - pWindow - > m_vRealPosition . goal ( ) ;
2023-09-23 02:21:59 +02:00
2024-05-11 00:28:33 +02:00
const auto PPOPUP = pWindow - > m_pPopupHead - > at ( vec ) ;
if ( PPOPUP )
return vec - PPOPUP - > coordsGlobal ( ) ;
2023-09-23 02:21:59 +02:00
2024-06-08 10:07:59 +02:00
std : : tuple < SP < CWLSurfaceResource > , Vector2D > iterData = { pSurface , { - 1337 , - 1337 } } ;
2023-09-23 02:21:59 +02:00
2024-06-08 10:07:59 +02:00
pWindow - > m_pWLSurface - > resource ( ) - > breadthfirst (
[ ] ( SP < CWLSurfaceResource > surf , const Vector2D & offset , void * data ) {
const auto PDATA = ( std : : tuple < SP < CWLSurfaceResource > , Vector2D > * ) data ;
if ( surf = = std : : get < 0 > ( * PDATA ) )
std : : get < 1 > ( * PDATA ) = offset ;
2023-09-23 02:21:59 +02:00
} ,
& iterData ) ;
2024-05-11 00:28:33 +02:00
CBox geom = pWindow - > m_pXDGSurface - > current . geometry ;
2023-10-30 20:36:34 +01:00
2024-06-08 10:07:59 +02:00
if ( std : : get < 1 > ( iterData ) = = Vector2D { - 1337 , - 1337 } )
2024-03-02 01:35:17 +01:00
return vec - pWindow - > m_vRealPosition . goal ( ) ;
2023-09-23 02:21:59 +02:00
2024-06-08 10:07:59 +02:00
return vec - pWindow - > m_vRealPosition . goal ( ) - std : : get < 1 > ( iterData ) + Vector2D { geom . x , geom . y } ;
2023-09-23 02:21:59 +02:00
}
2024-06-20 18:05:35 +02:00
CMonitor * CCompositor : : getMonitorFromOutput ( SP < Aquamarine : : IOutput > out ) {
2022-06-30 15:44:26 +02:00
for ( auto & m : m_vMonitors ) {
if ( m - > output = = out ) {
return m . get ( ) ;
2022-03-19 20:56:19 +01:00
}
}
return nullptr ;
}
2024-06-20 18:05:35 +02:00
CMonitor * CCompositor : : getRealMonitorFromOutput ( SP < Aquamarine : : IOutput > out ) {
2024-02-18 03:24:01 +01:00
for ( auto & m : m_vRealMonitors ) {
if ( m - > output = = out ) {
return m . get ( ) ;
}
}
return nullptr ;
}
2024-06-08 10:07:59 +02:00
void CCompositor : : focusWindow ( PHLWINDOW pWindow , SP < CWLSurfaceResource > pSurface ) {
2022-03-18 22:53:27 +01:00
2024-03-03 19:39:20 +01:00
static auto PFOLLOWMOUSE = CConfigValue < Hyprlang : : INT > ( " input:follow_mouse " ) ;
static auto PSPECIALFALLTHROUGH = CConfigValue < Hyprlang : : INT > ( " input:special_fallthrough " ) ;
2023-10-26 23:17:49 +02:00
2024-05-10 19:27:57 +02:00
if ( g_pSessionLockManager - > isSessionLocked ( ) ) {
Debug : : log ( LOG , " Refusing a keyboard focus to a window because of a sessionlock " ) ;
2022-04-18 17:16:01 +02:00
return ;
}
2024-01-19 16:45:34 +01:00
if ( ! g_pInputManager - > m_dExclusiveLSes . empty ( ) ) {
Debug : : log ( LOG , " Refusing a keyboard focus to a window because of an exclusive ls " ) ;
return ;
}
2024-05-25 22:43:51 +02:00
if ( pWindow & & pWindow - > m_bIsX11 & & pWindow - > m_iX11Type = = 2 & & ! pWindow - > m_pXWaylandSurface - > wantsFocus ( ) )
2024-03-09 23:39:23 +01:00
return ;
2023-09-12 23:37:08 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > bringWindowToTop ( pWindow ) ;
2023-08-11 17:27:09 +02:00
2024-04-27 13:43:12 +02:00
if ( ! pWindow | | ! validMapped ( pWindow ) ) {
2023-10-06 02:11:47 +02:00
2024-04-27 13:43:12 +02:00
if ( m_pLastWindow . expired ( ) & & ! pWindow )
2023-10-06 02:11:47 +02:00
return ;
2024-04-27 13:43:12 +02:00
const auto PLASTWINDOW = m_pLastWindow . lock ( ) ;
m_pLastWindow . reset ( ) ;
2022-08-08 20:42:14 +02:00
2024-04-27 13:43:12 +02:00
if ( PLASTWINDOW & & PLASTWINDOW - > m_bIsMapped ) {
2022-08-08 20:42:14 +02:00
updateWindowAnimatedDecorationValues ( PLASTWINDOW ) ;
2022-08-08 20:21:11 +02:00
2022-10-28 20:18:10 +02:00
g_pXWaylandManager - > activateWindow ( PLASTWINDOW , false ) ;
2022-08-08 20:21:11 +02:00
}
2024-05-10 19:27:57 +02:00
g_pSeatManager - > setKeyboardFocus ( nullptr ) ;
2022-08-08 20:21:11 +02:00
2022-08-21 18:34:38 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindow " , " , " } ) ;
2024-05-01 14:57:27 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindowv2 " , " " } ) ;
2022-08-21 18:34:38 +02:00
2024-04-27 13:43:12 +02:00
EMIT_HOOK_EVENT ( " activeWindow " , ( PHLWINDOW ) nullptr ) ;
2023-02-19 21:54:53 +01:00
2022-10-24 13:25:36 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowFocusChange ( nullptr ) ;
2024-06-08 10:07:59 +02:00
m_pLastFocus . reset ( ) ;
2022-10-31 13:26:07 +01:00
g_pInputManager - > recheckIdleInhibitorStatus ( ) ;
2022-05-14 14:37:57 +02:00
return ;
}
2024-02-13 19:07:19 +01:00
if ( pWindow - > m_sAdditionalConfigData . noFocus ) {
2022-05-14 20:56:21 +02:00
Debug : : log ( LOG , " Ignoring focus to nofocus window! " ) ;
2022-03-18 22:53:27 +01:00
return ;
}
2024-05-10 19:27:57 +02:00
if ( m_pLastWindow . lock ( ) = = pWindow & & g_pSeatManager - > state . keyboardFocus = = pSurface )
2022-04-05 18:29:58 +02:00
return ;
2022-09-10 13:11:02 +02:00
if ( pWindow - > m_bPinned )
2024-04-02 21:32:39 +02:00
pWindow - > m_pWorkspace = m_pLastMonitor - > activeWorkspace ;
2022-09-10 13:11:02 +02:00
2024-01-07 12:06:33 +01:00
const auto PMONITOR = getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2024-04-03 11:09:42 +02:00
if ( ! isWorkspaceVisible ( pWindow - > m_pWorkspace ) ) {
2024-04-02 21:32:39 +02:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2023-01-20 20:57:35 +01:00
// This is to fix incorrect feedback on the focus history.
PWORKSPACE - > m_pLastFocusedWindow = pWindow ;
2024-04-02 21:32:39 +02:00
PWORKSPACE - > rememberPrevWorkspace ( m_pLastMonitor - > activeWorkspace ) ;
2024-04-13 15:39:20 +02:00
if ( PWORKSPACE - > m_bIsSpecialWorkspace )
m_pLastMonitor - > changeWorkspace ( PWORKSPACE , false , true ) ; // if special ws, open on current monitor
else
PMONITOR - > changeWorkspace ( PWORKSPACE , false , true ) ;
2023-01-20 20:57:35 +01:00
// changeworkspace already calls focusWindow
return ;
}
2022-08-06 21:05:19 +02:00
2024-04-27 13:43:12 +02:00
const auto PLASTWINDOW = m_pLastWindow . lock ( ) ;
2022-12-16 18:17:31 +01:00
m_pLastWindow = pWindow ;
2022-04-23 14:16:02 +02:00
2024-01-09 13:17:55 +01:00
/* If special fallthrough is enabled, this behavior will be disabled, as I have no better idea of nicely tracking which
window focuses are " via keybinds " and which ones aren ' t . */
2024-04-02 21:32:39 +02:00
if ( PMONITOR - > activeSpecialWorkspace & & PMONITOR - > activeSpecialWorkspace ! = pWindow - > m_pWorkspace & & ! pWindow - > m_bPinned & & ! * PSPECIALFALLTHROUGH )
2024-01-07 12:06:33 +01:00
PMONITOR - > setSpecialWorkspace ( nullptr ) ;
2022-04-23 14:16:02 +02:00
// we need to make the PLASTWINDOW not equal to m_pLastWindow so that RENDERDATA is correct for an unfocused window
2024-04-27 13:43:12 +02:00
if ( PLASTWINDOW & & PLASTWINDOW - > m_bIsMapped ) {
2023-12-08 17:02:16 +01:00
PLASTWINDOW - > updateDynamicRules ( ) ;
2022-07-12 13:40:55 +02:00
updateWindowAnimatedDecorationValues ( PLASTWINDOW ) ;
2022-04-23 14:16:02 +02:00
2022-10-28 21:12:17 +02:00
if ( ! pWindow - > m_bIsX11 | | pWindow - > m_iX11Type = = 1 )
g_pXWaylandManager - > activateWindow ( PLASTWINDOW , false ) ;
2022-04-05 18:29:58 +02:00
}
2022-04-23 14:16:02 +02:00
m_pLastWindow = PLASTWINDOW ;
2024-06-08 10:07:59 +02:00
const auto PWINDOWSURFACE = pSurface ? pSurface : pWindow - > m_pWLSurface - > resource ( ) ;
2022-03-18 22:53:27 +01:00
2022-04-02 18:57:09 +02:00
focusSurface ( PWINDOWSURFACE , pWindow ) ;
2022-04-23 14:16:02 +02:00
g_pXWaylandManager - > activateWindow ( pWindow , true ) ; // sets the m_pLastWindow
2022-04-02 18:57:09 +02:00
2023-12-08 17:02:16 +01:00
pWindow - > updateDynamicRules ( ) ;
2022-07-12 13:40:55 +02:00
updateWindowAnimatedDecorationValues ( pWindow ) ;
2022-05-24 22:21:31 +02:00
2023-09-01 17:10:03 +02:00
if ( pWindow - > m_bIsUrgent )
2023-01-14 20:31:11 +01:00
pWindow - > m_bIsUrgent = false ;
2022-05-24 22:21:31 +02:00
// Send an event
2024-05-11 00:28:33 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindow " , pWindow - > m_szClass + " , " + pWindow - > m_szTitle } ) ;
2024-04-27 13:43:12 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindowv2 " , std : : format ( " {:x} " , ( uintptr_t ) pWindow . get ( ) ) } ) ;
2022-05-29 11:24:42 +02:00
2023-02-19 21:54:53 +01:00
EMIT_HOOK_EVENT ( " activeWindow " , pWindow ) ;
2022-10-24 13:25:36 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowFocusChange ( pWindow ) ;
2022-10-31 13:26:07 +01:00
g_pInputManager - > recheckIdleInhibitorStatus ( ) ;
2023-01-20 19:15:15 +01:00
// move to front of the window history
2024-04-27 13:43:12 +02:00
const auto HISTORYPIVOT = std : : find_if ( m_vWindowFocusHistory . begin ( ) , m_vWindowFocusHistory . end ( ) , [ & ] ( const auto & other ) { return other . lock ( ) = = pWindow ; } ) ;
2023-01-20 19:15:15 +01:00
if ( HISTORYPIVOT = = m_vWindowFocusHistory . end ( ) ) {
2023-09-20 17:25:03 +02:00
Debug : : log ( ERR , " BUG THIS: {} has no pivot in history " , pWindow ) ;
2023-01-20 19:15:15 +01:00
} else {
std : : rotate ( m_vWindowFocusHistory . begin ( ) , HISTORYPIVOT , HISTORYPIVOT + 1 ) ;
}
2023-10-26 23:17:49 +02:00
2024-03-03 19:39:20 +01:00
if ( * PFOLLOWMOUSE = = 0 )
2023-10-26 23:17:49 +02:00
g_pInputManager - > sendMotionEventsToFocused ( ) ;
2022-03-20 14:36:55 +01:00
}
2024-06-08 10:07:59 +02:00
void CCompositor : : focusSurface ( SP < CWLSurfaceResource > pSurface , PHLWINDOW pWindowOwner ) {
2022-04-18 17:16:01 +02:00
2024-06-08 10:07:59 +02:00
if ( g_pSeatManager - > state . keyboardFocus = = pSurface | | ( pWindowOwner & & g_pSeatManager - > state . keyboardFocus = = pWindowOwner - > m_pWLSurface - > resource ( ) ) )
2022-12-16 18:17:31 +01:00
return ; // Don't focus when already focused on this.
2022-03-20 14:36:55 +01:00
2024-01-07 14:04:25 +01:00
if ( g_pSessionLockManager - > isSessionLocked ( ) & & ! g_pSessionLockManager - > isSurfaceSessionLock ( pSurface ) )
return ;
2023-02-12 20:20:13 +01:00
2024-05-11 02:02:57 +02:00
if ( g_pSeatManager - > seatGrab & & ! g_pSeatManager - > seatGrab - > accepts ( pSurface ) ) {
Debug : : log ( LOG , " surface {:x} won't receive kb focus becuase grab rejected it " , ( uintptr_t ) pSurface ) ;
return ;
}
2024-06-08 10:07:59 +02:00
const auto PLASTSURF = m_pLastFocus . lock ( ) ;
2024-03-02 22:04:55 +01:00
2022-07-07 21:47:59 +02:00
// Unfocus last surface if should
2022-10-28 20:18:10 +02:00
if ( m_pLastFocus & & ! pWindowOwner )
2024-06-08 10:07:59 +02:00
g_pXWaylandManager - > activateSurface ( m_pLastFocus . lock ( ) , false ) ;
2022-07-07 21:47:59 +02:00
2022-07-11 12:29:50 +02:00
if ( ! pSurface ) {
2024-05-10 19:27:57 +02:00
g_pSeatManager - > setKeyboardFocus ( nullptr ) ;
2022-07-20 18:39:08 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindow " , " , " } ) ; // unfocused
2024-05-01 14:57:27 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " activewindowv2 " , " " } ) ;
2024-06-08 10:07:59 +02:00
EMIT_HOOK_EVENT ( " keyboardFocus " , ( SP < CWLSurfaceResource > ) nullptr ) ;
m_pLastFocus . reset ( ) ;
2022-03-27 19:16:33 +02:00
return ;
2022-07-11 12:29:50 +02:00
}
2022-09-25 20:07:48 +02:00
2024-05-10 19:27:57 +02:00
if ( g_pSeatManager - > keyboard )
g_pSeatManager - > setKeyboardFocus ( pSurface ) ;
2022-04-02 19:09:27 +02:00
2022-04-10 11:17:06 +02:00
if ( pWindowOwner )
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Set keyboard focus to surface {:x}, with {} " , ( uintptr_t ) pSurface , pWindowOwner ) ;
2022-03-31 19:41:55 +02:00
else
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Set keyboard focus to surface {:x} " , ( uintptr_t ) pSurface ) ;
2022-07-08 13:19:57 +02:00
2022-11-02 19:54:41 +01:00
g_pXWaylandManager - > activateSurface ( pSurface , true ) ;
2022-07-08 13:19:57 +02:00
m_pLastFocus = pSurface ;
2023-02-19 21:54:53 +01:00
EMIT_HOOK_EVENT ( " keyboardFocus " , pSurface ) ;
2024-03-02 22:04:55 +01:00
2024-06-08 10:07:59 +02:00
const auto SURF = CWLSurface : : fromResource ( pSurface ) ;
const auto OLDSURF = CWLSurface : : fromResource ( PLASTSURF ) ;
2024-03-02 22:04:55 +01:00
if ( OLDSURF & & OLDSURF - > constraint ( ) )
OLDSURF - > constraint ( ) - > deactivate ( ) ;
if ( SURF & & SURF - > constraint ( ) )
SURF - > constraint ( ) - > activate ( ) ;
2022-03-18 23:16:15 +01:00
}
2024-06-08 10:07:59 +02:00
SP < CWLSurfaceResource > CCompositor : : vectorToLayerPopupSurface ( const Vector2D & pos , CMonitor * monitor , Vector2D * sCoords , PHLLS * ppLayerSurfaceFound ) {
2024-03-25 17:20:30 +01:00
for ( auto & lsl : monitor - > m_aLayerSurfaceLayers | std : : views : : reverse ) {
for ( auto & ls : lsl | std : : views : : reverse ) {
2024-05-09 22:47:21 +02:00
if ( ls - > fadingOut | | ! ls - > layerSurface | | ( ls - > layerSurface & & ! ls - > layerSurface - > mapped ) | | ls - > alpha . value ( ) = = 0.f )
2024-03-25 17:20:30 +01:00
continue ;
2024-05-09 22:47:21 +02:00
auto SURFACEAT = ls - > popupHead - > at ( pos , true ) ;
2024-03-25 17:20:30 +01:00
if ( SURFACEAT ) {
2024-05-09 22:47:21 +02:00
* ppLayerSurfaceFound = ls . lock ( ) ;
* sCoords = pos - SURFACEAT - > coordsGlobal ( ) ;
2024-06-08 10:07:59 +02:00
return SURFACEAT - > m_pWLSurface - > resource ( ) ;
2024-03-25 17:20:30 +01:00
}
}
}
return nullptr ;
}
2024-06-08 10:07:59 +02:00
SP < CWLSurfaceResource > CCompositor : : vectorToLayerSurface ( const Vector2D & pos , std : : vector < PHLLSREF > * layerSurfaces , Vector2D * sCoords , PHLLS * ppLayerSurfaceFound ) {
2023-03-01 15:06:52 +01:00
for ( auto & ls : * layerSurfaces | std : : views : : reverse ) {
2024-03-02 01:35:17 +01:00
if ( ls - > fadingOut | | ! ls - > layerSurface | | ( ls - > layerSurface & & ! ls - > layerSurface - > surface - > mapped ) | | ls - > alpha . value ( ) = = 0.f )
2022-03-20 14:36:55 +01:00
continue ;
2024-06-11 17:01:25 +02:00
auto [ surf , local ] = ls - > layerSurface - > surface - > at ( pos - ls - > geometry . pos ( ) , true ) ;
2022-11-18 21:35:15 +01:00
2024-06-08 10:07:59 +02:00
if ( surf ) {
if ( surf - > current . input . empty ( ) )
2022-12-22 16:03:32 +01:00
continue ;
2024-05-09 22:47:21 +02:00
* ppLayerSurfaceFound = ls . lock ( ) ;
2024-06-08 10:07:59 +02:00
* sCoords = local ;
return surf ;
2022-07-01 20:14:33 +02:00
}
2022-03-20 14:36:55 +01:00
}
return nullptr ;
}
2024-06-08 10:07:59 +02:00
PHLWINDOW CCompositor : : getWindowFromSurface ( SP < CWLSurfaceResource > pSurface ) {
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
2023-12-17 21:00:18 +01:00
if ( ! w - > m_bIsMapped | | w - > m_bFadingOut )
2022-12-08 18:43:15 +01:00
continue ;
2024-06-08 10:07:59 +02:00
if ( w - > m_pWLSurface - > resource ( ) = = pSurface )
2024-04-27 13:43:12 +02:00
return w ;
2022-03-20 14:36:55 +01:00
}
2022-03-20 15:55:47 +01:00
return nullptr ;
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getWindowFromHandle ( uint32_t handle ) {
2022-12-05 18:05:15 +01:00
for ( auto & w : m_vWindows ) {
2022-12-05 18:57:59 +01:00
if ( ( uint32_t ) ( ( ( uint64_t ) w . get ( ) ) & 0xFFFFFFFF ) = = handle ) {
2024-04-27 13:43:12 +02:00
return w ;
2022-12-05 18:57:59 +01:00
}
2022-12-05 18:05:15 +01:00
}
return nullptr ;
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getFullscreenWindowOnWorkspace ( const int & ID ) {
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > workspaceID ( ) = = ID & & w - > m_bIsFullscreen )
2024-04-27 13:43:12 +02:00
return w ;
2022-03-21 19:18:33 +01:00
}
return nullptr ;
}
2024-04-03 11:09:42 +02:00
bool CCompositor : : isWorkspaceVisible ( PHLWORKSPACE w ) {
2024-04-03 21:42:38 +02:00
return valid ( w ) & & w - > m_bVisible ;
2022-03-20 15:55:47 +01:00
}
2024-06-11 22:56:35 +02:00
bool CCompositor : : isWorkspaceVisibleNotCovered ( PHLWORKSPACE w ) {
if ( ! valid ( w ) )
return false ;
const auto PMONITOR = getMonitorFromID ( w - > m_iMonitorID ) ;
if ( PMONITOR - > activeSpecialWorkspace )
return PMONITOR - > activeSpecialWorkspace - > m_iID = = w - > m_iID ;
return PMONITOR - > activeWorkspace - > m_iID = = w - > m_iID ;
}
2024-04-02 21:32:39 +02:00
PHLWORKSPACE CCompositor : : getWorkspaceByID ( const int & id ) {
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWorkspaces ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_iID = = id & & ! w - > inert ( ) )
return w ;
2022-03-20 15:55:47 +01:00
}
return nullptr ;
}
void CCompositor : : sanityCheckWorkspaces ( ) {
2022-12-29 17:06:30 +01:00
auto it = m_vWorkspaces . begin ( ) ;
while ( it ! = m_vWorkspaces . end ( ) ) {
2024-04-06 16:53:32 +02:00
const auto & WORKSPACE = * it ;
2024-04-05 20:32:05 +02:00
// If ref == 1, only the compositor holds a ref, which means it's inactive and has no mapped windows.
2024-05-05 18:16:00 +02:00
if ( ! WORKSPACE - > m_bPersistent & & WORKSPACE . strongRef ( ) = = 1 ) {
2024-04-05 20:32:05 +02:00
it = m_vWorkspaces . erase ( it ) ;
2023-04-13 22:09:50 +02:00
continue ;
2023-10-09 21:28:22 +02:00
}
2023-04-13 22:09:50 +02:00
2022-12-29 17:06:30 +01:00
+ + it ;
2022-03-20 15:55:47 +01:00
}
}
2024-04-19 03:44:51 +02:00
int CCompositor : : getWindowsOnWorkspace ( const int & id , std : : optional < bool > onlyTiled , std : : optional < bool > onlyVisible ) {
2022-03-20 15:55:47 +01:00
int no = 0 ;
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
2024-04-19 03:44:51 +02:00
if ( w - > workspaceID ( ) ! = id | | ! w - > m_bIsMapped )
continue ;
if ( onlyTiled . has_value ( ) & & w - > m_bIsFloating = = onlyTiled . value ( ) )
continue ;
if ( onlyVisible . has_value ( ) & & w - > isHidden ( ) = = onlyVisible . value ( ) )
continue ;
no + + ;
2022-03-20 15:55:47 +01:00
}
return no ;
}
2024-04-19 03:44:51 +02:00
int CCompositor : : getGroupsOnWorkspace ( const int & id , std : : optional < bool > onlyTiled , std : : optional < bool > onlyVisible ) {
2024-04-09 13:08:38 +02:00
int no = 0 ;
for ( auto & w : m_vWindows ) {
2024-04-19 03:44:51 +02:00
if ( w - > workspaceID ( ) ! = id | | ! w - > m_bIsMapped )
continue ;
if ( ! w - > m_sGroupData . head )
continue ;
if ( onlyTiled . has_value ( ) & & w - > m_bIsFloating = = onlyTiled . value ( ) )
continue ;
if ( onlyVisible . has_value ( ) & & w - > isHidden ( ) = = onlyVisible . value ( ) )
continue ;
no + + ;
2024-04-09 13:08:38 +02:00
}
return no ;
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getUrgentWindow ( ) {
2023-01-21 11:18:55 +01:00
for ( auto & w : m_vWindows ) {
if ( w - > m_bIsMapped & & w - > m_bIsUrgent )
2024-04-27 13:43:12 +02:00
return w ;
2023-01-21 11:18:55 +01:00
}
return nullptr ;
}
2023-01-14 20:31:11 +01:00
bool CCompositor : : hasUrgentWindowOnWorkspace ( const int & id ) {
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > workspaceID ( ) = = id & & w - > m_bIsMapped & & w - > m_bIsUrgent )
2023-01-14 20:31:11 +01:00
return true ;
}
return false ;
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getFirstWindowOnWorkspace ( const int & id ) {
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > workspaceID ( ) = = id & & w - > m_bIsMapped & & ! w - > isHidden ( ) )
2024-04-27 13:43:12 +02:00
return w ;
2022-03-20 15:55:47 +01:00
}
2022-03-20 14:00:46 +01:00
return nullptr ;
2022-03-20 19:14:17 +01:00
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getTopLeftWindowOnWorkspace ( const int & id ) {
2023-08-21 20:54:02 +02:00
const auto PWORKSPACE = getWorkspaceByID ( id ) ;
if ( ! PWORKSPACE )
return nullptr ;
const auto PMONITOR = getMonitorFromID ( PWORKSPACE - > m_iMonitorID ) ;
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > workspaceID ( ) ! = id | | ! w - > m_bIsMapped | | w - > isHidden ( ) )
2023-08-21 20:54:02 +02:00
continue ;
const auto WINDOWIDEALBB = w - > getWindowIdealBoundingBoxIgnoreReserved ( ) ;
if ( WINDOWIDEALBB . x < = PMONITOR - > vecPosition . x + 1 & & WINDOWIDEALBB . y < = PMONITOR - > vecPosition . y + 1 )
2024-04-27 13:43:12 +02:00
return w ;
2023-08-21 20:54:02 +02:00
}
return nullptr ;
}
2024-04-27 13:43:12 +02:00
bool CCompositor : : isWindowActive ( PHLWINDOW pWindow ) {
if ( m_pLastWindow . expired ( ) & & ! m_pLastFocus )
2022-05-29 00:07:31 +02:00
return false ;
2024-04-02 02:15:58 +02:00
if ( ! pWindow - > m_bIsMapped )
2022-04-02 18:57:09 +02:00
return false ;
2024-06-08 10:07:59 +02:00
const auto PSURFACE = pWindow - > m_pWLSurface - > resource ( ) ;
2022-04-02 13:02:16 +02:00
2024-04-27 13:43:12 +02:00
return PSURFACE = = m_pLastFocus | | pWindow = = m_pLastWindow . lock ( ) ;
2022-04-04 16:25:30 +02:00
}
2024-04-27 13:43:12 +02:00
void CCompositor : : changeWindowZOrder ( PHLWINDOW pWindow , bool top ) {
if ( ! validMapped ( pWindow ) )
2022-04-04 16:25:30 +02:00
return ;
2024-04-27 13:43:12 +02:00
auto moveToZ = [ & ] ( PHLWINDOW pw , bool top ) - > void {
2023-09-21 23:18:26 +02:00
if ( top ) {
for ( auto it = m_vWindows . begin ( ) ; it ! = m_vWindows . end ( ) ; + + it ) {
2024-04-27 13:43:12 +02:00
if ( * it = = pw ) {
2023-09-21 23:18:26 +02:00
std : : rotate ( it , it + 1 , m_vWindows . end ( ) ) ;
break ;
}
}
} else {
for ( auto it = m_vWindows . rbegin ( ) ; it ! = m_vWindows . rend ( ) ; + + it ) {
2024-04-27 13:43:12 +02:00
if ( * it = = pw ) {
2023-09-21 23:18:26 +02:00
std : : rotate ( it , it + 1 , m_vWindows . rend ( ) ) ;
break ;
}
2022-08-28 19:47:06 +02:00
}
}
2023-01-11 17:57:54 +01:00
if ( pw - > m_bIsMapped )
g_pHyprRenderer - > damageMonitor ( getMonitorFromID ( pw - > m_iMonitorID ) ) ;
2022-08-28 19:47:06 +02:00
} ;
2023-09-21 23:18:26 +02:00
if ( top )
pWindow - > m_bCreatedOverFullscreen = true ;
2022-08-28 19:47:06 +02:00
2024-05-25 22:43:51 +02:00
if ( ! pWindow - > m_bIsX11 )
2023-09-21 23:18:26 +02:00
moveToZ ( pWindow , top ) ;
2024-05-25 22:43:51 +02:00
else {
2023-09-21 23:18:26 +02:00
// move X11 window stack
2022-08-28 19:47:06 +02:00
2024-04-27 13:43:12 +02:00
std : : deque < PHLWINDOW > toMove ;
2022-08-28 19:47:06 +02:00
2024-04-27 13:43:12 +02:00
auto x11Stack = [ & ] ( PHLWINDOW pw , bool top , auto & & x11Stack ) - > void {
2023-09-21 23:18:26 +02:00
if ( top )
toMove . emplace_back ( pw ) ;
else
toMove . emplace_front ( pw ) ;
2022-08-28 19:47:06 +02:00
2023-09-21 23:18:26 +02:00
for ( auto & w : m_vWindows ) {
2024-05-25 22:43:51 +02:00
if ( w - > m_bIsMapped & & ! w - > isHidden ( ) & & w - > m_bIsX11 & & w - > X11TransientFor ( ) = = pw & & w ! = pw & & std : : find ( toMove . begin ( ) , toMove . end ( ) , w ) = = toMove . end ( ) ) {
2024-04-27 13:43:12 +02:00
x11Stack ( w , top , x11Stack ) ;
2023-09-21 23:18:26 +02:00
}
}
} ;
2022-08-28 19:47:06 +02:00
2023-09-21 23:18:26 +02:00
x11Stack ( pWindow , top , x11Stack ) ;
2022-08-28 19:47:06 +02:00
2023-09-21 23:18:26 +02:00
for ( auto it : toMove ) {
moveToZ ( it , top ) ;
}
2022-08-28 19:47:06 +02:00
}
2022-04-05 19:28:10 +02:00
}
2022-07-12 23:11:34 +02:00
void CCompositor : : cleanupFadingOut ( const int & monid ) {
2024-04-27 13:43:12 +02:00
for ( auto & ww : m_vWindowsFadingOut ) {
2024-05-09 22:47:21 +02:00
auto w = ww . lock ( ) ;
2022-04-26 17:51:00 +02:00
2022-07-12 23:11:34 +02:00
if ( w - > m_iMonitorID ! = ( long unsigned int ) monid )
continue ;
2024-04-06 15:59:30 +02:00
if ( ! w - > m_bFadingOut | | w - > m_fAlpha . value ( ) = = 0.f ) {
2022-06-30 15:44:26 +02:00
2024-04-06 15:59:30 +02:00
w - > m_bFadingOut = false ;
2024-03-14 19:25:28 +01:00
2024-04-06 15:59:30 +02:00
if ( ! w - > m_bReadyToDelete )
continue ;
2023-03-01 14:15:51 +01:00
2024-04-06 15:59:30 +02:00
removeWindowFromVectorSafe ( w ) ;
2022-04-10 11:17:06 +02:00
2024-05-09 22:47:21 +02:00
w . reset ( ) ;
2022-04-10 11:17:06 +02:00
Debug : : log ( LOG , " Cleanup: destroyed a window " ) ;
2022-04-05 19:28:10 +02:00
return ;
}
}
2022-05-14 17:23:46 +02:00
2024-04-30 03:41:27 +02:00
for ( auto & lsr : m_vSurfacesFadingOut ) {
2022-07-25 22:40:34 +02:00
2024-04-30 03:41:27 +02:00
auto ls = lsr . lock ( ) ;
2022-07-25 22:40:34 +02:00
2024-04-30 03:41:27 +02:00
if ( ! ls )
continue ;
2022-07-25 22:40:34 +02:00
2022-07-12 23:11:34 +02:00
if ( ls - > monitorID ! = monid )
continue ;
2022-08-01 12:16:33 +02:00
// mark blur for recalc
if ( ls - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND | | ls - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM )
g_pHyprOpenGL - > markBlurDirtyForMonitor ( getMonitorFromID ( monid ) ) ;
2024-02-28 16:00:34 +01:00
if ( ls - > fadingOut & & ls - > readyToDelete & & ls - > isFadedOut ( ) ) {
2022-07-23 15:48:08 +02:00
for ( auto & m : m_vMonitors ) {
2023-01-22 17:03:25 +01:00
for ( auto & lsl : m - > m_aLayerSurfaceLayers ) {
2024-04-30 03:41:27 +02:00
if ( ! lsl . empty ( ) & & std : : find_if ( lsl . begin ( ) , lsl . end ( ) , [ & ] ( auto & other ) { return other = = ls ; } ) ! = lsl . end ( ) ) {
std : : erase_if ( lsl , [ & ] ( auto & other ) { return other = = ls ; } ) ;
2022-07-25 21:08:54 +02:00
}
2022-07-23 15:48:08 +02:00
}
}
2024-04-30 03:41:27 +02:00
std : : erase_if ( m_vSurfacesFadingOut , [ ls ] ( const auto & el ) { return el . lock ( ) = = ls ; } ) ;
2024-05-09 22:47:21 +02:00
std : : erase_if ( m_vLayers , [ ls ] ( const auto & el ) { return el = = ls ; } ) ;
ls . reset ( ) ;
2022-07-25 22:00:46 +02:00
2022-05-14 17:28:55 +02:00
Debug : : log ( LOG , " Cleanup: destroyed a layersurface " ) ;
2022-12-16 18:17:31 +01:00
glFlush ( ) ; // to free mem NOW.
2022-05-14 17:23:46 +02:00
return ;
}
}
2022-04-09 13:26:55 +02:00
}
2024-04-30 03:41:27 +02:00
void CCompositor : : addToFadingOutSafe ( PHLLS pLS ) {
const auto FOUND = std : : find_if ( m_vSurfacesFadingOut . begin ( ) , m_vSurfacesFadingOut . end ( ) , [ & ] ( auto & other ) { return other . lock ( ) = = pLS ; } ) ;
2022-07-25 21:08:54 +02:00
if ( FOUND ! = m_vSurfacesFadingOut . end ( ) )
2022-12-16 18:17:31 +01:00
return ; // if it's already added, don't add it.
2022-07-25 21:08:54 +02:00
m_vSurfacesFadingOut . emplace_back ( pLS ) ;
}
2024-06-12 22:57:06 +02:00
void CCompositor : : removeFromFadingOutSafe ( PHLLS ls ) {
std : : erase ( m_vSurfacesFadingOut , ls ) ;
}
2024-04-27 13:43:12 +02:00
void CCompositor : : addToFadingOutSafe ( PHLWINDOW pWindow ) {
const auto FOUND = std : : find_if ( m_vWindowsFadingOut . begin ( ) , m_vWindowsFadingOut . end ( ) , [ & ] ( PHLWINDOWREF & other ) { return other . lock ( ) = = pWindow ; } ) ;
2022-07-25 21:08:54 +02:00
if ( FOUND ! = m_vWindowsFadingOut . end ( ) )
2022-12-16 18:17:31 +01:00
return ; // if it's already added, don't add it.
2022-07-25 21:08:54 +02:00
m_vWindowsFadingOut . emplace_back ( pWindow ) ;
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getWindowInDirection ( PHLWINDOW pWindow , char dir ) {
2022-06-23 20:39:48 +02:00
2023-11-05 17:18:41 +01:00
if ( ! isDirection ( dir ) )
return nullptr ;
2023-01-26 15:36:22 +01:00
// 0 -> history, 1 -> shared length
2024-05-22 21:51:46 +02:00
static auto PMETHOD = CConfigValue < Hyprlang : : INT > ( " binds:focus_preferred_method " ) ;
static auto PMONITORFALLBACK = CConfigValue < Hyprlang : : INT > ( " binds:window_direction_monitor_fallback " ) ;
2022-06-23 20:39:48 +02:00
2024-03-03 19:39:20 +01:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2022-04-09 13:26:55 +02:00
2023-11-04 22:03:08 +01:00
if ( ! PMONITOR )
return nullptr ; // ??
2023-01-26 15:36:22 +01:00
2024-06-19 16:20:06 +02:00
const auto WINDOWIDEALBB = pWindow - > m_bIsFullscreen ? CBox { PMONITOR - > vecPosition , PMONITOR - > vecSize } : pWindow - > getWindowIdealBoundingBoxIgnoreReserved ( ) ;
2023-11-04 22:03:08 +01:00
const auto POSA = Vector2D ( WINDOWIDEALBB . x , WINDOWIDEALBB . y ) ;
const auto SIZEA = Vector2D ( WINDOWIDEALBB . width , WINDOWIDEALBB . height ) ;
2024-04-02 21:32:39 +02:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2023-11-04 22:03:08 +01:00
auto leaderValue = - 1 ;
2024-04-27 13:43:12 +02:00
PHLWINDOW leaderWindow = nullptr ;
2022-04-09 13:26:55 +02:00
2023-11-05 17:18:41 +01:00
if ( ! pWindow - > m_bIsFloating ) {
2022-04-09 13:26:55 +02:00
2023-11-05 17:18:41 +01:00
// for tiled windows, we calc edges
for ( auto & w : m_vWindows ) {
2024-04-27 13:43:12 +02:00
if ( w = = pWindow | | ! w - > m_bIsMapped | | w - > isHidden ( ) | | ( ! w - > m_bIsFullscreen & & w - > m_bIsFloating ) | | ! isWorkspaceVisible ( w - > m_pWorkspace ) )
2023-11-05 17:18:41 +01:00
continue ;
2023-10-20 11:53:37 +02:00
2024-04-02 21:32:39 +02:00
if ( pWindow - > m_iMonitorID = = w - > m_iMonitorID & & pWindow - > m_pWorkspace ! = w - > m_pWorkspace )
2023-11-05 17:18:41 +01:00
continue ;
2022-11-24 00:40:05 +01:00
2023-11-05 17:18:41 +01:00
if ( PWORKSPACE - > m_bHasFullscreenWindow & & ! w - > m_bIsFullscreen & & ! w - > m_bCreatedOverFullscreen )
continue ;
2022-06-23 20:39:48 +02:00
2024-05-22 21:51:46 +02:00
if ( ! * PMONITORFALLBACK & & pWindow - > m_iMonitorID ! = w - > m_iMonitorID )
continue ;
2023-11-05 17:18:41 +01:00
const auto BWINDOWIDEALBB = w - > getWindowIdealBoundingBoxIgnoreReserved ( ) ;
2022-06-23 20:39:48 +02:00
2023-11-05 17:18:41 +01:00
const auto POSB = Vector2D ( BWINDOWIDEALBB . x , BWINDOWIDEALBB . y ) ;
const auto SIZEB = Vector2D ( BWINDOWIDEALBB . width , BWINDOWIDEALBB . height ) ;
2023-01-26 15:36:22 +01:00
2023-11-05 17:18:41 +01:00
double intersectLength = - 1 ;
2023-01-26 15:36:22 +01:00
2023-11-05 17:18:41 +01:00
switch ( dir ) {
case ' l ' :
if ( STICKS ( POSA . x , POSB . x + SIZEB . x ) ) {
intersectLength = std : : max ( 0.0 , std : : min ( POSA . y + SIZEA . y , POSB . y + SIZEB . y ) - std : : max ( POSA . y , POSB . y ) ) ;
}
break ;
case ' r ' :
if ( STICKS ( POSA . x + SIZEA . x , POSB . x ) ) {
intersectLength = std : : max ( 0.0 , std : : min ( POSA . y + SIZEA . y , POSB . y + SIZEB . y ) - std : : max ( POSA . y , POSB . y ) ) ;
}
break ;
case ' t ' :
case ' u ' :
if ( STICKS ( POSA . y , POSB . y + SIZEB . y ) ) {
intersectLength = std : : max ( 0.0 , std : : min ( POSA . x + SIZEA . x , POSB . x + SIZEB . x ) - std : : max ( POSA . x , POSB . x ) ) ;
}
break ;
case ' b ' :
case ' d ' :
if ( STICKS ( POSA . y + SIZEA . y , POSB . y ) ) {
intersectLength = std : : max ( 0.0 , std : : min ( POSA . x + SIZEA . x , POSB . x + SIZEB . x ) - std : : max ( POSA . x , POSB . x ) ) ;
}
break ;
}
2023-01-26 15:36:22 +01:00
2024-03-03 19:39:20 +01:00
if ( * PMETHOD = = 0 /* history */ ) {
2023-11-05 17:18:41 +01:00
if ( intersectLength > 0 ) {
// get idx
int windowIDX = - 1 ;
for ( size_t i = 0 ; i < g_pCompositor - > m_vWindowFocusHistory . size ( ) ; + + i ) {
2024-04-27 13:43:12 +02:00
if ( g_pCompositor - > m_vWindowFocusHistory [ i ] . lock ( ) = = w ) {
2023-11-05 17:18:41 +01:00
windowIDX = i ;
break ;
}
2023-01-26 15:36:22 +01:00
}
2023-11-05 17:18:41 +01:00
windowIDX = g_pCompositor - > m_vWindowFocusHistory . size ( ) - windowIDX ;
2023-01-26 15:36:22 +01:00
2023-11-05 17:18:41 +01:00
if ( windowIDX > leaderValue ) {
leaderValue = windowIDX ;
2024-04-27 13:43:12 +02:00
leaderWindow = w ;
2023-11-05 17:18:41 +01:00
}
}
} else /* length */ {
if ( intersectLength > leaderValue ) {
leaderValue = intersectLength ;
2024-04-27 13:43:12 +02:00
leaderWindow = w ;
2023-01-26 15:36:22 +01:00
}
}
2023-11-05 17:18:41 +01:00
}
} else {
// for floating windows, we calculate best distance and angle.
// if there is a window with angle better than THRESHOLD, only distance counts
if ( dir = = ' u ' )
dir = ' t ' ;
if ( dir = = ' d ' )
dir = ' b ' ;
static const std : : unordered_map < char , Vector2D > VECTORS = { { ' r ' , { 1 , 0 } } , { ' t ' , { 0 , - 1 } } , { ' b ' , { 0 , 1 } } , { ' l ' , { - 1 , 0 } } } ;
//
auto vectorAngles = [ ] ( Vector2D a , Vector2D b ) - > double {
double dot = a . x * b . x + a . y * b . y ;
double ang = std : : acos ( dot / ( a . size ( ) * b . size ( ) ) ) ;
return ang ;
} ;
float bestAngleAbs = 2.0 * M_PI ;
constexpr float THRESHOLD = 0.3 * M_PI ;
for ( auto & w : m_vWindows ) {
2024-04-27 13:43:12 +02:00
if ( w = = pWindow | | ! w - > m_bIsMapped | | w - > isHidden ( ) | | ( ! w - > m_bIsFullscreen & & ! w - > m_bIsFloating ) | | ! isWorkspaceVisible ( w - > m_pWorkspace ) )
2023-11-05 17:18:41 +01:00
continue ;
2024-04-02 21:32:39 +02:00
if ( pWindow - > m_iMonitorID = = w - > m_iMonitorID & & pWindow - > m_pWorkspace ! = w - > m_pWorkspace )
2023-11-05 17:18:41 +01:00
continue ;
if ( PWORKSPACE - > m_bHasFullscreenWindow & & ! w - > m_bIsFullscreen & & ! w - > m_bCreatedOverFullscreen )
continue ;
2024-05-22 21:51:46 +02:00
if ( ! * PMONITORFALLBACK & & pWindow - > m_iMonitorID ! = w - > m_iMonitorID )
continue ;
2023-11-05 17:18:41 +01:00
const auto DIST = w - > middle ( ) . distance ( pWindow - > middle ( ) ) ;
const auto ANGLE = vectorAngles ( Vector2D { w - > middle ( ) - pWindow - > middle ( ) } , VECTORS . at ( dir ) ) ;
if ( ANGLE > M_PI_2 )
continue ; // if the angle is over 90 degrees, ignore. Wrong direction entirely.
if ( ( bestAngleAbs < THRESHOLD & & DIST < leaderValue & & ANGLE < THRESHOLD ) | | ( ANGLE < bestAngleAbs & & bestAngleAbs > THRESHOLD ) | | leaderValue = = - 1 ) {
leaderValue = DIST ;
bestAngleAbs = ANGLE ;
2024-04-27 13:43:12 +02:00
leaderWindow = w ;
2023-01-26 15:36:22 +01:00
}
}
2023-11-05 17:18:41 +01:00
if ( ! leaderWindow & & PWORKSPACE - > m_bHasFullscreenWindow )
leaderWindow = g_pCompositor - > getFullscreenWindowOnWorkspace ( PWORKSPACE - > m_iID ) ;
2022-04-09 13:26:55 +02:00
}
2023-01-26 15:36:22 +01:00
if ( leaderValue ! = - 1 )
return leaderWindow ;
2022-04-09 13:26:55 +02:00
return nullptr ;
2022-04-11 19:51:37 +02:00
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getNextWindowOnWorkspace ( PHLWINDOW pWindow , bool focusableOnly , std : : optional < bool > floating ) {
2022-04-13 20:45:06 +02:00
bool gotToWindow = false ;
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
2024-04-27 13:43:12 +02:00
if ( w ! = pWindow & & ! gotToWindow )
2022-04-13 20:45:06 +02:00
continue ;
2024-04-27 13:43:12 +02:00
if ( w = = pWindow ) {
2022-04-13 20:45:06 +02:00
gotToWindow = true ;
continue ;
}
2023-12-24 15:08:48 +01:00
if ( floating . has_value ( ) & & w - > m_bIsFloating ! = floating . value ( ) )
continue ;
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = pWindow - > m_pWorkspace & & w - > m_bIsMapped & & ! w - > isHidden ( ) & & ( ! focusableOnly | | ! w - > m_sAdditionalConfigData . noFocus ) )
2024-04-27 13:43:12 +02:00
return w ;
2022-04-13 20:45:06 +02:00
}
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
2023-12-24 15:08:48 +01:00
if ( floating . has_value ( ) & & w - > m_bIsFloating ! = floating . value ( ) )
continue ;
2024-04-27 13:43:12 +02:00
if ( w ! = pWindow & & w - > m_pWorkspace = = pWindow - > m_pWorkspace & & w - > m_bIsMapped & & ! w - > isHidden ( ) & & ( ! focusableOnly | | ! w - > m_sAdditionalConfigData . noFocus ) )
return w ;
2022-04-13 20:45:06 +02:00
}
2022-04-21 16:38:48 +02:00
return nullptr ;
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getPrevWindowOnWorkspace ( PHLWINDOW pWindow , bool focusableOnly , std : : optional < bool > floating ) {
2022-07-09 18:39:41 +02:00
bool gotToWindow = false ;
2023-03-01 15:06:52 +01:00
for ( auto & w : m_vWindows | std : : views : : reverse ) {
2024-04-27 13:43:12 +02:00
if ( w ! = pWindow & & ! gotToWindow )
2022-07-09 18:39:41 +02:00
continue ;
2024-04-27 13:43:12 +02:00
if ( w = = pWindow ) {
2022-07-09 18:39:41 +02:00
gotToWindow = true ;
continue ;
}
2023-12-24 15:08:48 +01:00
if ( floating . has_value ( ) & & w - > m_bIsFloating ! = floating . value ( ) )
continue ;
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = pWindow - > m_pWorkspace & & w - > m_bIsMapped & & ! w - > isHidden ( ) & & ( ! focusableOnly | | ! w - > m_sAdditionalConfigData . noFocus ) )
2024-04-27 13:43:12 +02:00
return w ;
2022-07-09 18:39:41 +02:00
}
2023-03-01 15:06:52 +01:00
for ( auto & w : m_vWindows | std : : views : : reverse ) {
2023-12-24 15:08:48 +01:00
if ( floating . has_value ( ) & & w - > m_bIsFloating ! = floating . value ( ) )
continue ;
2024-04-27 13:43:12 +02:00
if ( w ! = pWindow & & w - > m_pWorkspace = = pWindow - > m_pWorkspace & & w - > m_bIsMapped & & ! w - > isHidden ( ) & & ( ! focusableOnly | | ! w - > m_sAdditionalConfigData . noFocus ) )
return w ;
2022-07-09 18:39:41 +02:00
}
return nullptr ;
}
2022-04-21 16:38:48 +02:00
int CCompositor : : getNextAvailableNamedWorkspace ( ) {
2022-04-21 21:35:08 +02:00
int lowest = - 1337 + 1 ;
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWorkspaces ) {
if ( w - > m_iID < - 1 & & w - > m_iID < lowest )
lowest = w - > m_iID ;
2022-04-21 16:38:48 +02:00
}
2022-04-21 21:35:08 +02:00
return lowest - 1 ;
2022-04-21 16:38:48 +02:00
}
2024-04-02 21:32:39 +02:00
PHLWORKSPACE CCompositor : : getWorkspaceByName ( const std : : string & name ) {
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWorkspaces ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_szName = = name & & ! w - > inert ( ) )
return w ;
2022-04-21 16:38:48 +02:00
}
return nullptr ;
}
2024-04-02 21:32:39 +02:00
PHLWORKSPACE CCompositor : : getWorkspaceByString ( const std : : string & str ) {
2023-10-15 20:07:23 +02:00
if ( str . starts_with ( " name: " ) ) {
2022-04-21 16:38:48 +02:00
return getWorkspaceByName ( str . substr ( str . find_first_of ( ' : ' ) + 1 ) ) ;
}
try {
2024-06-22 23:52:42 +02:00
return getWorkspaceByID ( getWorkspaceIDNameFromString ( str ) . id ) ;
2022-12-16 18:17:31 +01:00
} catch ( std : : exception & e ) { Debug : : log ( ERR , " Error in getWorkspaceByString, invalid id " ) ; }
2022-04-21 16:38:48 +02:00
2022-04-13 20:45:06 +02:00
return nullptr ;
2022-04-23 14:16:02 +02:00
}
2022-04-24 17:53:50 +02:00
bool CCompositor : : isPointOnAnyMonitor ( const Vector2D & point ) {
2022-06-30 15:44:26 +02:00
for ( auto & m : m_vMonitors ) {
if ( VECINRECT ( point , m - > vecPosition . x , m - > vecPosition . y , m - > vecSize . x + m - > vecPosition . x , m - > vecSize . y + m - > vecPosition . y ) )
2022-04-24 17:53:50 +02:00
return true ;
}
return false ;
2022-04-25 13:40:46 +02:00
}
2023-12-26 17:24:31 +01:00
bool CCompositor : : isPointOnReservedArea ( const Vector2D & point , const CMonitor * pMonitor ) {
const auto PMONITOR = pMonitor ? pMonitor : getMonitorFromVector ( point ) ;
const auto XY1 = PMONITOR - > vecPosition + PMONITOR - > vecReservedTopLeft ;
const auto XY2 = PMONITOR - > vecPosition + PMONITOR - > vecSize - PMONITOR - > vecReservedBottomRight ;
return ! VECINRECT ( point , XY1 . x , XY1 . y , XY2 . x , XY2 . y ) ;
}
2022-07-27 12:32:00 +02:00
CMonitor * CCompositor : : getMonitorInDirection ( const char & dir ) {
2024-05-05 23:18:10 +02:00
return this - > getMonitorInDirection ( m_pLastMonitor . get ( ) , dir ) ;
2024-02-25 15:03:00 +01:00
}
CMonitor * CCompositor : : getMonitorInDirection ( CMonitor * pSourceMonitor , const char & dir ) {
2024-02-26 01:05:20 +01:00
if ( ! pSourceMonitor )
return nullptr ;
2024-02-25 15:03:00 +01:00
const auto POSA = pSourceMonitor - > vecPosition ;
const auto SIZEA = pSourceMonitor - > vecSize ;
2022-05-05 12:50:25 +02:00
2022-12-16 18:17:31 +01:00
auto longestIntersect = - 1 ;
CMonitor * longestIntersectMonitor = nullptr ;
2022-05-05 12:50:25 +02:00
2022-06-30 15:44:26 +02:00
for ( auto & m : m_vMonitors ) {
2024-05-05 23:18:10 +02:00
if ( m = = m_pLastMonitor )
2022-05-05 12:50:25 +02:00
continue ;
2022-12-16 18:17:31 +01:00
const auto POSB = m - > vecPosition ;
2022-06-30 15:44:26 +02:00
const auto SIZEB = m - > vecSize ;
2022-05-05 12:50:25 +02:00
switch ( dir ) {
case ' l ' :
if ( STICKS ( POSA . x , POSB . x + SIZEB . x ) ) {
2022-09-28 19:43:35 +02:00
const auto INTERSECTLEN = std : : max ( 0.0 , std : : min ( POSA . y + SIZEA . y , POSB . y + SIZEB . y ) - std : : max ( POSA . y , POSB . y ) ) ;
2022-05-05 12:50:25 +02:00
if ( INTERSECTLEN > longestIntersect ) {
2022-12-16 18:17:31 +01:00
longestIntersect = INTERSECTLEN ;
2022-06-30 15:44:26 +02:00
longestIntersectMonitor = m . get ( ) ;
2022-05-05 12:50:25 +02:00
}
}
break ;
case ' r ' :
if ( STICKS ( POSA . x + SIZEA . x , POSB . x ) ) {
2022-09-28 19:43:35 +02:00
const auto INTERSECTLEN = std : : max ( 0.0 , std : : min ( POSA . y + SIZEA . y , POSB . y + SIZEB . y ) - std : : max ( POSA . y , POSB . y ) ) ;
2022-05-05 12:50:25 +02:00
if ( INTERSECTLEN > longestIntersect ) {
2022-12-16 18:17:31 +01:00
longestIntersect = INTERSECTLEN ;
2022-06-30 15:44:26 +02:00
longestIntersectMonitor = m . get ( ) ;
2022-05-05 12:50:25 +02:00
}
}
break ;
case ' t ' :
case ' u ' :
if ( STICKS ( POSA . y , POSB . y + SIZEB . y ) ) {
2022-09-28 19:43:35 +02:00
const auto INTERSECTLEN = std : : max ( 0.0 , std : : min ( POSA . x + SIZEA . x , POSB . x + SIZEB . x ) - std : : max ( POSA . x , POSB . x ) ) ;
2022-05-05 12:50:25 +02:00
if ( INTERSECTLEN > longestIntersect ) {
2022-12-16 18:17:31 +01:00
longestIntersect = INTERSECTLEN ;
2022-06-30 15:44:26 +02:00
longestIntersectMonitor = m . get ( ) ;
2022-05-05 12:50:25 +02:00
}
}
break ;
case ' b ' :
case ' d ' :
if ( STICKS ( POSA . y + SIZEA . y , POSB . y ) ) {
2022-09-28 19:43:35 +02:00
const auto INTERSECTLEN = std : : max ( 0.0 , std : : min ( POSA . x + SIZEA . x , POSB . x + SIZEB . x ) - std : : max ( POSA . x , POSB . x ) ) ;
2022-05-05 12:50:25 +02:00
if ( INTERSECTLEN > longestIntersect ) {
2022-12-16 18:17:31 +01:00
longestIntersect = INTERSECTLEN ;
2022-06-30 15:44:26 +02:00
longestIntersectMonitor = m . get ( ) ;
2022-05-05 12:50:25 +02:00
}
}
break ;
}
}
if ( longestIntersect ! = - 1 )
return longestIntersectMonitor ;
2022-04-25 13:40:46 +02:00
return nullptr ;
2022-05-14 17:23:46 +02:00
}
2022-05-26 21:23:13 +02:00
2022-07-12 13:40:55 +02:00
void CCompositor : : updateAllWindowsAnimatedDecorationValues ( ) {
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
if ( ! w - > m_bIsMapped )
2022-05-26 21:23:13 +02:00
continue ;
2024-04-27 13:43:12 +02:00
updateWindowAnimatedDecorationValues ( w ) ;
2022-05-26 21:23:13 +02:00
}
}
2023-12-20 23:52:18 +01:00
void CCompositor : : updateWorkspaceWindows ( const int64_t & id ) {
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( ! w - > m_bIsMapped | | w - > workspaceID ( ) ! = id )
2023-12-20 23:52:18 +01:00
continue ;
w - > updateDynamicRules ( ) ;
}
}
2024-04-27 13:43:12 +02:00
void CCompositor : : updateWindowAnimatedDecorationValues ( PHLWINDOW pWindow ) {
2022-05-26 21:23:13 +02:00
// optimization
2024-03-03 19:39:20 +01:00
static auto PACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.active_border " ) ;
static auto PINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.inactive_border " ) ;
static auto PNOGROUPACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.nogroup_border_active " ) ;
static auto PNOGROUPINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " general:col.nogroup_border " ) ;
static auto PGROUPACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_active " ) ;
static auto PGROUPINACTIVECOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_inactive " ) ;
static auto PGROUPACTIVELOCKEDCOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_locked_active " ) ;
static auto PGROUPINACTIVELOCKEDCOL = CConfigValue < Hyprlang : : CUSTOMTYPE > ( " group:col.border_locked_inactive " ) ;
static auto PINACTIVEALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:inactive_opacity " ) ;
static auto PACTIVEALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:active_opacity " ) ;
static auto PFULLSCREENALPHA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:fullscreen_opacity " ) ;
static auto PSHADOWCOL = CConfigValue < Hyprlang : : INT > ( " decoration:col.shadow " ) ;
static auto PSHADOWCOLINACTIVE = CConfigValue < Hyprlang : : INT > ( " decoration:col.shadow_inactive " ) ;
static auto PDIMSTRENGTH = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_strength " ) ;
static auto PDIMENABLED = CConfigValue < Hyprlang : : INT > ( " decoration:dim_inactive " ) ;
auto * const ACTIVECOL = ( CGradientValueData * ) ( PACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const INACTIVECOL = ( CGradientValueData * ) ( PINACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const NOGROUPACTIVECOL = ( CGradientValueData * ) ( PNOGROUPACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const NOGROUPINACTIVECOL = ( CGradientValueData * ) ( PNOGROUPINACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPACTIVECOL = ( CGradientValueData * ) ( PGROUPACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPINACTIVECOL = ( CGradientValueData * ) ( PGROUPINACTIVECOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPACTIVELOCKEDCOL = ( CGradientValueData * ) ( PGROUPACTIVELOCKEDCOL . ptr ( ) ) - > getData ( ) ;
auto * const GROUPINACTIVELOCKEDCOL = ( CGradientValueData * ) ( PGROUPINACTIVELOCKEDCOL . ptr ( ) ) - > getData ( ) ;
auto setBorderColor = [ & ] ( CGradientValueData grad ) - > void {
2022-11-26 18:56:43 +01:00
if ( grad = = pWindow - > m_cRealBorderColor )
return ;
pWindow - > m_cRealBorderColorPrevious = pWindow - > m_cRealBorderColor ;
2022-12-16 18:17:31 +01:00
pWindow - > m_cRealBorderColor = grad ;
2023-02-01 22:06:01 +01:00
pWindow - > m_fBorderFadeAnimationProgress . setValueAndWarp ( 0.f ) ;
pWindow - > m_fBorderFadeAnimationProgress = 1.f ;
2022-11-26 18:56:43 +01:00
} ;
2022-07-12 13:40:55 +02:00
// border
2022-05-26 21:23:13 +02:00
const auto RENDERDATA = g_pLayoutManager - > getCurrentLayout ( ) - > requestRenderHints ( pWindow ) ;
2022-12-31 16:23:56 +01:00
if ( RENDERDATA . isBorderGradient )
setBorderColor ( * RENDERDATA . borderGradient ) ;
2023-02-19 22:07:32 +01:00
else {
2024-04-27 13:43:12 +02:00
const bool GROUPLOCKED = pWindow - > m_sGroupData . pNextWindow . lock ( ) ? pWindow - > getGroupHead ( ) - > m_sGroupData . locked : false ;
2024-05-05 18:16:00 +02:00
if ( pWindow = = m_pLastWindow ) {
2023-09-22 01:42:00 +02:00
const auto * const ACTIVECOLOR =
2024-04-27 13:43:12 +02:00
! pWindow - > m_sGroupData . pNextWindow . lock ( ) ? ( ! pWindow - > m_sGroupData . deny ? ACTIVECOL : NOGROUPACTIVECOL ) : ( GROUPLOCKED ? GROUPACTIVELOCKEDCOL : GROUPACTIVECOL ) ;
2024-01-14 18:27:32 +01:00
setBorderColor ( pWindow - > m_sSpecialRenderData . activeBorderColor . toUnderlying ( ) . m_vColors . empty ( ) ? * ACTIVECOLOR :
pWindow - > m_sSpecialRenderData . activeBorderColor . toUnderlying ( ) ) ;
2023-02-19 22:07:32 +01:00
} else {
2024-04-27 13:43:12 +02:00
const auto * const INACTIVECOLOR = ! pWindow - > m_sGroupData . pNextWindow . lock ( ) ? ( ! pWindow - > m_sGroupData . deny ? INACTIVECOL : NOGROUPINACTIVECOL ) :
( GROUPLOCKED ? GROUPINACTIVELOCKEDCOL : GROUPINACTIVECOL ) ;
2024-01-14 18:27:32 +01:00
setBorderColor ( pWindow - > m_sSpecialRenderData . inactiveBorderColor . toUnderlying ( ) . m_vColors . empty ( ) ? * INACTIVECOLOR :
pWindow - > m_sSpecialRenderData . inactiveBorderColor . toUnderlying ( ) ) ;
2023-02-19 22:07:32 +01:00
}
}
2022-07-12 13:40:55 +02:00
2023-02-01 22:06:01 +01:00
// tick angle if it's not running (aka dead)
if ( ! pWindow - > m_fBorderAngleAnimationProgress . isBeingAnimated ( ) )
pWindow - > m_fBorderAngleAnimationProgress . setValueAndWarp ( 0.f ) ;
2022-07-12 13:40:55 +02:00
// opacity
2024-04-02 21:32:39 +02:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2022-12-11 18:15:02 +01:00
if ( pWindow - > m_bIsFullscreen & & PWORKSPACE - > m_efFullscreenMode = = FULLSCREEN_FULL ) {
2024-04-08 00:19:02 +02:00
pWindow - > m_fActiveInactiveAlpha = pWindow - > m_sSpecialRenderData . alphaFullscreen . toUnderlying ( ) ! = - 1 ?
( pWindow - > m_sSpecialRenderData . alphaFullscreenOverride . toUnderlying ( ) ? pWindow - > m_sSpecialRenderData . alphaFullscreen . toUnderlying ( ) :
pWindow - > m_sSpecialRenderData . alphaFullscreen . toUnderlying ( ) * * PFULLSCREENALPHA ) :
* PFULLSCREENALPHA ;
2022-07-12 13:40:55 +02:00
} else {
2024-05-05 18:16:00 +02:00
if ( pWindow = = m_pLastWindow )
2023-01-26 15:36:22 +01:00
pWindow - > m_fActiveInactiveAlpha = pWindow - > m_sSpecialRenderData . alphaOverride . toUnderlying ( ) ? pWindow - > m_sSpecialRenderData . alpha . toUnderlying ( ) :
2024-03-03 19:39:20 +01:00
pWindow - > m_sSpecialRenderData . alpha . toUnderlying ( ) * * PACTIVEALPHA ;
2022-07-12 13:40:55 +02:00
else
2023-01-24 20:05:34 +01:00
pWindow - > m_fActiveInactiveAlpha = pWindow - > m_sSpecialRenderData . alphaInactive . toUnderlying ( ) ! = - 1 ?
( pWindow - > m_sSpecialRenderData . alphaInactiveOverride . toUnderlying ( ) ? pWindow - > m_sSpecialRenderData . alphaInactive . toUnderlying ( ) :
2024-03-03 19:39:20 +01:00
pWindow - > m_sSpecialRenderData . alphaInactive . toUnderlying ( ) * * PINACTIVEALPHA ) :
* PINACTIVEALPHA ;
2022-07-12 13:40:55 +02:00
}
2022-07-16 12:44:45 +02:00
2022-08-30 12:46:17 +02:00
// dim
2024-04-27 13:43:12 +02:00
if ( pWindow = = m_pLastWindow . lock ( ) | | pWindow - > m_sAdditionalConfigData . forceNoDim | | ! * PDIMENABLED ) {
2022-08-30 12:46:17 +02:00
pWindow - > m_fDimPercent = 0 ;
} else {
2024-03-03 19:39:20 +01:00
pWindow - > m_fDimPercent = * PDIMSTRENGTH ;
2022-08-30 12:46:17 +02:00
}
2022-07-16 12:44:45 +02:00
// shadow
2022-07-18 12:39:57 +02:00
if ( pWindow - > m_iX11Type ! = 2 & & ! pWindow - > m_bX11DoesntWantBorders ) {
2024-05-05 18:16:00 +02:00
if ( pWindow = = m_pLastWindow ) {
2024-03-03 19:39:20 +01:00
pWindow - > m_cRealShadowColor = CColor ( * PSHADOWCOL ) ;
2022-07-18 12:39:57 +02:00
} else {
2024-03-03 19:39:20 +01:00
pWindow - > m_cRealShadowColor = CColor ( * PSHADOWCOLINACTIVE ! = INT_MAX ? * PSHADOWCOLINACTIVE : * PSHADOWCOL ) ;
2022-07-18 12:39:57 +02:00
}
2022-07-16 12:44:45 +02:00
} else {
2022-07-18 12:39:57 +02:00
pWindow - > m_cRealShadowColor . setValueAndWarp ( CColor ( 0 , 0 , 0 , 0 ) ) ; // no shadow
2022-07-16 12:44:45 +02:00
}
2023-02-28 00:34:41 +01:00
2023-11-11 15:37:17 +01:00
pWindow - > updateWindowDecos ( ) ;
2022-05-30 17:11:35 +02:00
}
2023-07-09 23:08:40 +02:00
int CCompositor : : getNextAvailableMonitorID ( std : : string const & name ) {
2023-07-18 12:12:05 +02:00
// reuse ID if it's already in the map, and the monitor with that ID is not being used by another monitor
if ( m_mMonitorIDMap . contains ( name ) & & ! std : : any_of ( m_vRealMonitors . begin ( ) , m_vRealMonitors . end ( ) , [ & ] ( auto m ) { return m - > ID = = m_mMonitorIDMap [ name ] ; } ) )
2023-07-09 23:08:40 +02:00
return m_mMonitorIDMap [ name ] ;
// otherwise, find minimum available ID that is not in the map
2023-07-18 12:12:05 +02:00
std : : unordered_set < uint64_t > usedIDs ;
2023-07-09 23:08:40 +02:00
for ( auto const & monitor : m_vRealMonitors ) {
usedIDs . insert ( monitor - > ID ) ;
2022-05-30 17:11:35 +02:00
}
2023-07-18 12:12:05 +02:00
uint64_t nextID = 0 ;
2023-07-09 23:08:40 +02:00
while ( usedIDs . count ( nextID ) > 0 ) {
nextID + + ;
}
m_mMonitorIDMap [ name ] = nextID ;
return nextID ;
2022-05-30 17:11:35 +02:00
}
2022-05-30 20:05:38 +02:00
2022-08-25 21:25:28 +02:00
void CCompositor : : swapActiveWorkspaces ( CMonitor * pMonitorA , CMonitor * pMonitorB ) {
2024-04-02 21:32:39 +02:00
const auto PWORKSPACEA = pMonitorA - > activeWorkspace ;
const auto PWORKSPACEB = pMonitorB - > activeWorkspace ;
2022-08-25 21:25:28 +02:00
PWORKSPACEA - > m_iMonitorID = pMonitorB - > ID ;
PWORKSPACEA - > moveToMonitor ( pMonitorB - > ID ) ;
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = PWORKSPACEA ) {
2023-03-20 02:50:46 +01:00
if ( w - > m_bPinned ) {
2024-04-02 21:32:39 +02:00
w - > m_pWorkspace = PWORKSPACEB ;
2023-03-20 02:50:46 +01:00
continue ;
}
2022-08-25 21:25:28 +02:00
w - > m_iMonitorID = pMonitorB - > ID ;
2022-08-27 19:11:21 +02:00
// additionally, move floating and fs windows manually
if ( w - > m_bIsFloating )
2024-03-30 17:57:43 +01:00
w - > m_vRealPosition = w - > m_vRealPosition . goal ( ) - pMonitorA - > vecPosition + pMonitorB - > vecPosition ;
2022-08-27 19:11:21 +02:00
if ( w - > m_bIsFullscreen ) {
w - > m_vRealPosition = pMonitorB - > vecPosition ;
2022-12-16 18:17:31 +01:00
w - > m_vRealSize = pMonitorB - > vecSize ;
2022-08-25 21:25:28 +02:00
}
w - > updateToplevel ( ) ;
}
}
PWORKSPACEB - > m_iMonitorID = pMonitorA - > ID ;
PWORKSPACEB - > moveToMonitor ( pMonitorA - > ID ) ;
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = PWORKSPACEB ) {
2023-03-20 02:50:46 +01:00
if ( w - > m_bPinned ) {
2024-04-02 21:32:39 +02:00
w - > m_pWorkspace = PWORKSPACEA ;
2023-03-20 02:50:46 +01:00
continue ;
}
2022-08-25 21:25:28 +02:00
w - > m_iMonitorID = pMonitorA - > ID ;
2022-08-27 19:11:21 +02:00
// additionally, move floating and fs windows manually
if ( w - > m_bIsFloating )
2024-03-30 17:57:43 +01:00
w - > m_vRealPosition = w - > m_vRealPosition . goal ( ) - pMonitorB - > vecPosition + pMonitorA - > vecPosition ;
2022-08-27 19:11:21 +02:00
if ( w - > m_bIsFullscreen ) {
w - > m_vRealPosition = pMonitorA - > vecPosition ;
2022-12-16 18:17:31 +01:00
w - > m_vRealSize = pMonitorA - > vecSize ;
2022-08-25 21:25:28 +02:00
}
w - > updateToplevel ( ) ;
}
}
2024-04-02 21:32:39 +02:00
pMonitorA - > activeWorkspace = PWORKSPACEB ;
pMonitorB - > activeWorkspace = PWORKSPACEA ;
2022-08-25 21:25:28 +02:00
2024-03-04 18:05:20 +01:00
PWORKSPACEA - > rememberPrevWorkspace ( PWORKSPACEB ) ;
PWORKSPACEB - > rememberPrevWorkspace ( PWORKSPACEA ) ;
2022-08-25 21:25:28 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitorA - > ID ) ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitorB - > ID ) ;
2023-04-25 00:21:51 +02:00
updateFullscreenFadeOnWorkspace ( PWORKSPACEB ) ;
updateFullscreenFadeOnWorkspace ( PWORKSPACEA ) ;
2024-02-13 18:53:50 +01:00
if ( pMonitorA - > ID = = g_pCompositor - > m_pLastMonitor - > ID | | pMonitorB - > ID = = g_pCompositor - > m_pLastMonitor - > ID ) {
const auto LASTWIN = pMonitorA - > ID = = g_pCompositor - > m_pLastMonitor - > ID ? PWORKSPACEB - > getLastFocusedWindow ( ) : PWORKSPACEA - > getLastFocusedWindow ( ) ;
g_pCompositor - > focusWindow ( LASTWIN ? LASTWIN :
( g_pCompositor - > vectorToWindowUnified ( g_pInputManager - > getMouseCoordsInternal ( ) , RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING ) ) ) ;
2024-03-25 02:50:41 +01:00
const auto PNEWWORKSPACE = pMonitorA - > ID = = g_pCompositor - > m_pLastMonitor - > ID ? PWORKSPACEB : PWORKSPACEA ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " workspace " , PNEWWORKSPACE - > m_szName } ) ;
g_pEventManager - > postEvent ( SHyprIPCEvent { " workspacev2 " , std : : format ( " {},{} " , PNEWWORKSPACE - > m_iID , PNEWWORKSPACE - > m_szName ) } ) ;
EMIT_HOOK_EVENT ( " workspace " , PNEWWORKSPACE ) ;
2024-02-13 18:53:50 +01:00
}
2022-08-26 16:05:02 +02:00
// event
g_pEventManager - > postEvent ( SHyprIPCEvent { " moveworkspace " , PWORKSPACEA - > m_szName + " , " + pMonitorB - > szName } ) ;
2024-03-08 18:39:53 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " moveworkspacev2 " , std : : format ( " {},{},{} " , PWORKSPACEA - > m_iID , PWORKSPACEA - > m_szName , pMonitorB - > szName ) } ) ;
2024-04-02 21:32:39 +02:00
EMIT_HOOK_EVENT ( " moveWorkspace " , ( std : : vector < std : : any > { PWORKSPACEA , pMonitorB } ) ) ;
2022-08-26 16:05:02 +02:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " moveworkspace " , PWORKSPACEB - > m_szName + " , " + pMonitorA - > szName } ) ;
2024-03-08 18:39:53 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " moveworkspacev2 " , std : : format ( " {},{},{} " , PWORKSPACEB - > m_iID , PWORKSPACEB - > m_szName , pMonitorA - > szName ) } ) ;
2024-04-02 21:32:39 +02:00
EMIT_HOOK_EVENT ( " moveWorkspace " , ( std : : vector < std : : any > { PWORKSPACEB , pMonitorA } ) ) ;
2022-08-25 21:25:28 +02:00
}
CMonitor * CCompositor : : getMonitorFromString ( const std : : string & name ) {
2024-02-27 23:11:59 +01:00
if ( name = = " current " )
2024-05-05 23:18:10 +02:00
return g_pCompositor - > m_pLastMonitor . get ( ) ;
2024-02-27 23:11:59 +01:00
else if ( isDirection ( name ) )
return getMonitorInDirection ( name [ 0 ] ) ;
else if ( name [ 0 ] = = ' + ' | | name [ 0 ] = = ' - ' ) {
2022-11-10 13:22:19 +01:00
// relative
2023-01-14 20:45:24 +01:00
if ( m_vMonitors . size ( ) = = 1 )
return m_vMonitors . begin ( ) - > get ( ) ;
2022-11-10 13:22:19 +01:00
const auto OFFSET = name [ 0 ] = = ' - ' ? name : name . substr ( 1 ) ;
if ( ! isNumber ( OFFSET ) ) {
Debug : : log ( ERR , " Error in getMonitorFromString: Not a number in relative. " ) ;
return nullptr ;
}
2022-12-08 13:09:48 +01:00
int offsetLeft = std : : stoi ( OFFSET ) ;
2022-12-16 18:17:31 +01:00
offsetLeft = offsetLeft < 0 ? - ( ( - offsetLeft ) % m_vMonitors . size ( ) ) : offsetLeft % m_vMonitors . size ( ) ;
2022-11-10 13:22:19 +01:00
int currentPlace = 0 ;
for ( int i = 0 ; i < ( int ) m_vMonitors . size ( ) ; i + + ) {
2024-05-05 23:18:10 +02:00
if ( m_vMonitors [ i ] = = m_pLastMonitor ) {
2022-11-10 13:22:19 +01:00
currentPlace = i ;
break ;
}
}
currentPlace + = offsetLeft ;
if ( currentPlace < 0 ) {
2023-01-23 21:56:05 +01:00
currentPlace = m_vMonitors . size ( ) + currentPlace ;
2022-11-10 13:22:19 +01:00
} else {
currentPlace = currentPlace % m_vMonitors . size ( ) ;
}
2023-01-23 21:56:43 +01:00
if ( currentPlace ! = std : : clamp ( currentPlace , 0 , ( int ) m_vMonitors . size ( ) - 1 ) ) {
2022-11-10 13:22:19 +01:00
Debug : : log ( WARN , " Error in getMonitorFromString: Vaxry's code sucks. " ) ;
2023-01-14 20:45:24 +01:00
currentPlace = std : : clamp ( currentPlace , 0 , ( int ) m_vMonitors . size ( ) - 1 ) ;
2022-11-10 13:22:19 +01:00
}
return m_vMonitors [ currentPlace ] . get ( ) ;
} else if ( isNumber ( name ) ) {
2022-08-25 21:25:28 +02:00
// change by ID
int monID = - 1 ;
try {
monID = std : : stoi ( name ) ;
} catch ( std : : exception & e ) {
// shouldn't happen but jic
Debug : : log ( ERR , " Error in getMonitorFromString: invalid num " ) ;
return nullptr ;
}
2023-03-02 13:04:41 +01:00
if ( monID > - 1 & & monID < ( int ) m_vMonitors . size ( ) ) {
return getMonitorFromID ( monID ) ;
2022-08-25 21:25:28 +02:00
} else {
Debug : : log ( ERR , " Error in getMonitorFromString: invalid arg 1 " ) ;
return nullptr ;
}
2024-02-27 23:11:59 +01:00
} else {
2023-03-02 13:04:41 +01:00
for ( auto & m : m_vMonitors ) {
2023-03-16 15:03:40 +01:00
if ( ! m - > output )
continue ;
2024-02-27 23:11:59 +01:00
if ( m - > matchesStaticSelector ( name ) ) {
2023-03-02 13:04:41 +01:00
return m . get ( ) ;
}
}
2022-08-25 21:25:28 +02:00
}
return nullptr ;
}
2024-04-02 21:32:39 +02:00
void CCompositor : : moveWorkspaceToMonitor ( PHLWORKSPACE pWorkspace , CMonitor * pMonitor , bool noWarpCursor ) {
2022-05-30 20:05:38 +02:00
2024-04-02 21:32:39 +02:00
// We trust the monitor to be correct.
2022-05-30 20:05:38 +02:00
if ( pWorkspace - > m_iMonitorID = = pMonitor - > ID )
return ;
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " moveWorkspaceToMonitor: Moving {} to monitor {} " , pWorkspace - > m_iID , pMonitor - > ID ) ;
2022-05-30 20:05:38 +02:00
const auto POLDMON = getMonitorFromID ( pWorkspace - > m_iMonitorID ) ;
2024-04-02 21:32:39 +02:00
const bool SWITCHINGISACTIVE = POLDMON ? POLDMON - > activeWorkspace = = pWorkspace : false ;
2022-05-30 20:05:38 +02:00
// fix old mon
2022-12-20 03:18:47 +01:00
int nextWorkspaceOnMonitorID = - 1 ;
2024-03-04 18:05:20 +01:00
if ( ! SWITCHINGISACTIVE )
2023-04-28 22:40:40 +02:00
nextWorkspaceOnMonitorID = pWorkspace - > m_iID ;
else {
for ( auto & w : m_vWorkspaces ) {
if ( w - > m_iMonitorID = = POLDMON - > ID & & w - > m_iID ! = pWorkspace - > m_iID & & ! w - > m_bIsSpecialWorkspace ) {
nextWorkspaceOnMonitorID = w - > m_iID ;
break ;
}
2022-05-30 20:05:38 +02:00
}
2023-04-28 22:40:40 +02:00
if ( nextWorkspaceOnMonitorID = = - 1 ) {
nextWorkspaceOnMonitorID = 1 ;
2022-05-30 20:05:38 +02:00
2023-04-28 22:40:40 +02:00
while ( getWorkspaceByID ( nextWorkspaceOnMonitorID ) | | [ & ] ( ) - > bool {
const auto B = g_pConfigManager - > getBoundMonitorForWS ( std : : to_string ( nextWorkspaceOnMonitorID ) ) ;
return B & & B ! = POLDMON ;
} ( ) )
nextWorkspaceOnMonitorID + + ;
2022-05-30 20:05:38 +02:00
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " moveWorkspaceToMonitor: Plugging gap with new {} " , nextWorkspaceOnMonitorID ) ;
2023-04-14 16:03:53 +02:00
2023-04-28 22:40:40 +02:00
g_pCompositor - > createNewWorkspace ( nextWorkspaceOnMonitorID , POLDMON - > ID ) ;
}
2022-05-30 20:05:38 +02:00
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " moveWorkspaceToMonitor: Plugging gap with existing {} " , nextWorkspaceOnMonitorID ) ;
2024-02-10 00:47:00 +01:00
POLDMON - > changeWorkspace ( nextWorkspaceOnMonitorID , false , true , true ) ;
2023-04-28 22:40:40 +02:00
}
2023-04-13 22:09:50 +02:00
2022-05-30 20:05:38 +02:00
// move the workspace
pWorkspace - > m_iMonitorID = pMonitor - > ID ;
2022-05-30 20:51:45 +02:00
pWorkspace - > moveToMonitor ( pMonitor - > ID ) ;
2022-05-30 20:05:38 +02:00
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = pWorkspace ) {
2023-03-20 02:50:46 +01:00
if ( w - > m_bPinned ) {
2024-04-02 21:32:39 +02:00
w - > m_pWorkspace = g_pCompositor - > getWorkspaceByID ( nextWorkspaceOnMonitorID ) ;
2023-03-20 02:50:46 +01:00
continue ;
}
2022-06-30 15:44:26 +02:00
w - > m_iMonitorID = pMonitor - > ID ;
2022-07-25 14:22:32 +02:00
2022-08-27 19:11:21 +02:00
// additionally, move floating and fs windows manually
2022-10-14 21:46:32 +02:00
if ( w - > m_bIsMapped & & ! w - > isHidden ( ) ) {
2023-05-06 17:49:46 +02:00
if ( POLDMON ) {
if ( w - > m_bIsFloating )
2024-03-30 17:57:43 +01:00
w - > m_vRealPosition = w - > m_vRealPosition . goal ( ) - POLDMON - > vecPosition + pMonitor - > vecPosition ;
2022-08-27 19:11:21 +02:00
2023-05-06 17:49:46 +02:00
if ( w - > m_bIsFullscreen ) {
w - > m_vRealPosition = pMonitor - > vecPosition ;
w - > m_vRealSize = pMonitor - > vecSize ;
}
} else {
2024-03-02 01:35:17 +01:00
w - > m_vRealPosition = Vector2D { ( int ) w - > m_vRealPosition . goal ( ) . x % ( int ) pMonitor - > vecSize . x , ( int ) w - > m_vRealPosition . goal ( ) . y % ( int ) pMonitor - > vecSize . y } ;
2022-08-27 19:11:21 +02:00
}
2022-07-25 14:22:32 +02:00
}
2022-08-06 20:57:38 +02:00
w - > updateToplevel ( ) ;
2022-07-25 14:22:32 +02:00
}
2022-05-30 20:05:38 +02:00
}
2024-05-05 23:18:10 +02:00
if ( SWITCHINGISACTIVE & & POLDMON = = g_pCompositor - > m_pLastMonitor . get ( ) ) { // if it was active, preserve its' status. If it wasn't, don't.
2024-04-02 21:32:39 +02:00
Debug : : log ( LOG , " moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {} " , pMonitor - > activeWorkspaceID ( ) , pWorkspace - > m_iID ) ;
2022-05-31 17:17:44 +02:00
2024-04-04 19:30:32 +02:00
if ( valid ( pMonitor - > activeWorkspace ) ) {
pMonitor - > activeWorkspace - > m_bVisible = false ;
2024-04-02 21:32:39 +02:00
pMonitor - > activeWorkspace - > startAnim ( false , false ) ;
2024-04-04 19:30:32 +02:00
}
2022-05-30 20:05:38 +02:00
2024-02-10 00:47:00 +01:00
setActiveMonitor ( pMonitor ) ;
2024-04-02 21:32:39 +02:00
pMonitor - > activeWorkspace = pWorkspace ;
2022-05-30 20:05:38 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitor - > ID ) ;
pWorkspace - > startAnim ( true , true , true ) ;
2024-04-04 19:30:32 +02:00
pWorkspace - > m_bVisible = true ;
2022-05-30 20:05:38 +02:00
2024-01-15 16:30:46 +01:00
if ( ! noWarpCursor )
2024-05-05 23:18:10 +02:00
g_pPointerManager - > warpTo ( pMonitor - > vecPosition + pMonitor - > vecTransformedSize / 2.F ) ;
2023-05-06 17:13:26 +02:00
2023-12-12 15:58:43 +01:00
g_pInputManager - > sendMotionEventsToFocused ( ) ;
2022-05-30 20:05:38 +02:00
}
// finalize
2023-05-06 17:49:46 +02:00
if ( POLDMON ) {
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( POLDMON - > ID ) ;
2024-04-02 21:32:39 +02:00
updateFullscreenFadeOnWorkspace ( POLDMON - > activeWorkspace ) ;
2024-06-12 16:02:19 +02:00
updateSuspendedStates ( ) ;
2023-05-06 17:49:46 +02:00
}
2022-05-30 20:05:38 +02:00
2023-04-25 00:23:12 +02:00
updateFullscreenFadeOnWorkspace ( pWorkspace ) ;
2024-06-12 16:02:19 +02:00
updateSuspendedStates ( ) ;
2023-04-25 00:23:12 +02:00
2022-08-26 16:05:02 +02:00
// event
g_pEventManager - > postEvent ( SHyprIPCEvent { " moveworkspace " , pWorkspace - > m_szName + " , " + pMonitor - > szName } ) ;
2024-03-08 18:39:53 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " moveworkspacev2 " , std : : format ( " {},{},{} " , pWorkspace - > m_iID , pWorkspace - > m_szName , pMonitor - > szName ) } ) ;
2024-04-02 21:32:39 +02:00
EMIT_HOOK_EVENT ( " moveWorkspace " , ( std : : vector < std : : any > { pWorkspace , pMonitor } ) ) ;
2022-05-31 12:33:08 +02:00
}
2023-05-09 15:07:58 +02:00
bool CCompositor : : workspaceIDOutOfBounds ( const int64_t & id ) {
int64_t lowestID = INT64_MAX ;
int64_t highestID = INT64_MIN ;
2022-05-31 12:33:08 +02:00
2022-06-30 15:44:26 +02:00
for ( auto & w : m_vWorkspaces ) {
2022-11-27 23:42:22 +01:00
if ( w - > m_bIsSpecialWorkspace )
2022-09-17 16:05:12 +02:00
continue ;
2022-06-30 15:44:26 +02:00
if ( w - > m_iID < lowestID )
lowestID = w - > m_iID ;
2022-09-25 20:07:48 +02:00
2022-06-30 15:44:26 +02:00
if ( w - > m_iID > highestID )
highestID = w - > m_iID ;
2022-05-31 12:33:08 +02:00
}
return std : : clamp ( id , lowestID , highestID ) ! = id ;
2022-06-26 12:12:29 +02:00
}
2024-04-02 21:32:39 +02:00
void CCompositor : : updateFullscreenFadeOnWorkspace ( PHLWORKSPACE pWorkspace ) {
2023-04-25 00:21:51 +02:00
const auto FULLSCREEN = pWorkspace - > m_bHasFullscreenWindow ;
for ( auto & w : g_pCompositor - > m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = pWorkspace ) {
2023-04-25 00:21:51 +02:00
2023-05-10 19:36:13 +02:00
if ( w - > m_bFadingOut | | w - > m_bPinned | | w - > m_bIsFullscreen )
2023-04-25 00:21:51 +02:00
continue ;
if ( ! FULLSCREEN )
w - > m_fAlpha = 1.f ;
else if ( ! w - > m_bIsFullscreen )
w - > m_fAlpha = ! w - > m_bCreatedOverFullscreen ? 0.f : 1.f ;
}
}
const auto PMONITOR = getMonitorFromID ( pWorkspace - > m_iMonitorID ) ;
2024-04-02 21:32:39 +02:00
if ( pWorkspace - > m_iID = = PMONITOR - > activeWorkspaceID ( ) | | pWorkspace - > m_iID = = PMONITOR - > activeSpecialWorkspaceID ( ) ) {
2023-08-21 20:55:57 +02:00
for ( auto & ls : PMONITOR - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
if ( ! ls - > fadingOut )
ls - > alpha = FULLSCREEN & & pWorkspace - > m_efFullscreenMode = = FULLSCREEN_FULL ? 0.f : 1.f ;
}
2023-04-25 00:21:51 +02:00
}
}
2024-04-27 13:43:12 +02:00
void CCompositor : : setWindowFullscreen ( PHLWINDOW pWindow , bool on , eFullscreenMode mode ) {
if ( ! validMapped ( pWindow ) | | g_pCompositor - > m_bUnsafeState )
2022-06-26 12:12:29 +02:00
return ;
2022-09-21 15:09:26 +02:00
if ( pWindow - > m_bPinned ) {
Debug : : log ( LOG , " Pinned windows cannot be fullscreen'd " ) ;
return ;
}
2024-03-13 03:09:20 +01:00
if ( pWindow - > m_bIsFullscreen = = on ) {
Debug : : log ( LOG , " Window is already in the required fullscreen state " ) ;
return ;
}
2022-09-29 11:20:12 +02:00
const auto PMONITOR = getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2024-04-02 21:32:39 +02:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2022-09-29 11:20:12 +02:00
2023-09-28 18:49:33 +02:00
const auto MODE = mode = = FULLSCREEN_INVALID ? PWORKSPACE - > m_efFullscreenMode : mode ;
2022-09-29 11:20:12 +02:00
if ( PWORKSPACE - > m_bHasFullscreenWindow & & on ) {
Debug : : log ( LOG , " Rejecting fullscreen ON on a fullscreen workspace " ) ;
return ;
}
2023-09-28 18:49:33 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > fullscreenRequestForWindow ( pWindow , MODE , on ) ;
2022-06-26 12:12:29 +02:00
2023-12-11 17:51:10 +01:00
g_pXWaylandManager - > setWindowFullscreen ( pWindow , pWindow - > shouldSendFullscreenState ( ) ) ;
2022-09-25 20:07:48 +02:00
2023-05-10 19:36:13 +02:00
updateWindowAnimatedDecorationValues ( pWindow ) ;
2022-11-15 11:21:26 +01:00
2022-06-26 12:12:29 +02:00
// make all windows on the same workspace under the fullscreen window
2023-04-25 00:21:51 +02:00
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = PWORKSPACE & & ! w - > m_bIsFullscreen & & ! w - > m_bFadingOut & & ! w - > m_bPinned )
2022-06-30 15:44:26 +02:00
w - > m_bCreatedOverFullscreen = false ;
2022-09-19 11:23:13 +02:00
}
2023-04-25 00:21:51 +02:00
updateFullscreenFadeOnWorkspace ( PWORKSPACE ) ;
2022-09-25 20:07:48 +02:00
2024-03-02 01:35:17 +01:00
g_pXWaylandManager - > setWindowSize ( pWindow , pWindow - > m_vRealSize . goal ( ) , true ) ;
2022-08-22 14:22:21 +02:00
2024-04-02 21:32:39 +02:00
forceReportSizesToWindowsOnWorkspace ( pWindow - > workspaceID ( ) ) ;
2022-10-31 13:26:07 +01:00
g_pInputManager - > recheckIdleInhibitorStatus ( ) ;
2022-11-05 13:50:47 +01:00
// DMAbuf stuff for direct scanout
g_pHyprRenderer - > setWindowScanoutMode ( pWindow ) ;
2023-02-14 18:08:42 +01:00
g_pConfigManager - > ensureVRR ( PMONITOR ) ;
2022-06-30 15:44:26 +02:00
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getX11Parent ( PHLWINDOW pWindow ) {
2022-06-30 15:44:26 +02:00
if ( ! pWindow - > m_bIsX11 )
return nullptr ;
for ( auto & w : m_vWindows ) {
if ( ! w - > m_bIsX11 )
continue ;
2024-05-25 22:43:51 +02:00
if ( w - > m_pXWaylandSurface = = pWindow - > m_pXWaylandSurface - > parent )
2024-04-27 13:43:12 +02:00
return w ;
2022-06-30 15:44:26 +02:00
}
2022-09-25 20:07:48 +02:00
2022-06-30 15:44:26 +02:00
return nullptr ;
2022-07-07 11:52:12 +02:00
}
void CCompositor : : updateWorkspaceWindowDecos ( const int & id ) {
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > workspaceID ( ) ! = id )
2022-07-07 11:52:12 +02:00
continue ;
w - > updateWindowDecos ( ) ;
}
}
2022-07-13 18:18:23 +02:00
2024-04-10 18:26:11 +02:00
void CCompositor : : updateWorkspaceSpecialRenderData ( const int & id ) {
const auto PWORKSPACE = getWorkspaceByID ( id ) ;
const auto WORKSPACERULE = PWORKSPACE ? g_pConfigManager - > getWorkspaceRuleFor ( PWORKSPACE ) : SWorkspaceRule { } ;
for ( auto & w : m_vWindows ) {
if ( w - > workspaceID ( ) ! = id )
continue ;
w - > updateSpecialRenderData ( WORKSPACERULE ) ;
}
}
2022-07-27 12:32:00 +02:00
void CCompositor : : scheduleFrameForMonitor ( CMonitor * pMonitor ) {
2024-06-20 18:05:35 +02:00
// FIXME:
// if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
// return;
2022-07-13 18:18:23 +02:00
2022-11-19 14:01:32 +01:00
if ( ! pMonitor - > m_bEnabled )
return ;
2023-02-27 13:32:38 +01:00
if ( pMonitor - > renderingActive )
pMonitor - > pendingFrame = true ;
2024-06-20 18:05:35 +02:00
pMonitor - > output - > scheduleFrame ( ) ;
2022-07-26 17:30:30 +02:00
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getWindowByRegex ( const std : : string & regexp ) {
2024-04-21 16:19:59 +02:00
if ( regexp . starts_with ( " active " ) )
2024-04-27 13:43:12 +02:00
return m_pLastWindow . lock ( ) ;
2024-04-21 16:19:59 +02:00
2022-07-26 17:30:30 +02:00
eFocusWindowMode mode = MODE_CLASS_REGEX ;
2022-12-16 18:17:31 +01:00
std : : regex regexCheck ( regexp ) ;
std : : string matchCheck ;
2024-04-21 16:19:59 +02:00
if ( regexp . starts_with ( " class: " ) ) {
regexCheck = std : : regex ( regexp . substr ( 6 ) ) ;
} else if ( regexp . starts_with ( " initialclass: " ) ) {
mode = MODE_INITIAL_CLASS_REGEX ;
regexCheck = std : : regex ( regexp . substr ( 13 ) ) ;
} else if ( regexp . starts_with ( " title: " ) ) {
2022-12-16 18:17:31 +01:00
mode = MODE_TITLE_REGEX ;
2022-07-26 17:30:30 +02:00
regexCheck = std : : regex ( regexp . substr ( 6 ) ) ;
2024-04-21 16:19:59 +02:00
} else if ( regexp . starts_with ( " initialtitle: " ) ) {
mode = MODE_INITIAL_TITLE_REGEX ;
regexCheck = std : : regex ( regexp . substr ( 13 ) ) ;
2023-10-15 20:07:23 +02:00
} else if ( regexp . starts_with ( " address: " ) ) {
2022-12-16 18:17:31 +01:00
mode = MODE_ADDRESS ;
2022-07-26 17:30:30 +02:00
matchCheck = regexp . substr ( 8 ) ;
2023-10-15 20:07:23 +02:00
} else if ( regexp . starts_with ( " pid: " ) ) {
2022-12-16 18:17:31 +01:00
mode = MODE_PID ;
2022-07-26 17:30:30 +02:00
matchCheck = regexp . substr ( 4 ) ;
2023-11-05 17:22:43 +01:00
} else if ( regexp . starts_with ( " floating " ) | | regexp . starts_with ( " tiled " ) ) {
2023-11-05 17:21:47 +01:00
// first floating on the current ws
2024-04-27 13:43:12 +02:00
if ( ! valid ( m_pLastWindow ) )
2023-11-05 17:21:47 +01:00
return nullptr ;
2023-11-05 17:22:43 +01:00
const bool FLOAT = regexp . starts_with ( " floating " ) ;
2023-11-05 17:21:47 +01:00
for ( auto & w : m_vWindows ) {
2024-05-05 18:16:00 +02:00
if ( ! w - > m_bIsMapped | | w - > m_bIsFloating ! = FLOAT | | w - > m_pWorkspace ! = m_pLastWindow - > m_pWorkspace | | w - > isHidden ( ) )
2023-11-05 17:21:47 +01:00
continue ;
2024-04-27 13:43:12 +02:00
return w ;
2023-11-05 17:21:47 +01:00
}
return nullptr ;
2022-07-26 17:30:30 +02:00
}
for ( auto & w : g_pCompositor - > m_vWindows ) {
2024-04-27 13:43:12 +02:00
if ( ! w - > m_bIsMapped | | ( w - > isHidden ( ) & & ! g_pLayoutManager - > getCurrentLayout ( ) - > isWindowReachable ( w ) ) )
2022-07-26 17:30:30 +02:00
continue ;
switch ( mode ) {
case MODE_CLASS_REGEX : {
2024-05-11 00:28:33 +02:00
const auto windowClass = w - > m_szClass ;
2024-04-21 16:19:59 +02:00
if ( ! std : : regex_search ( windowClass , regexCheck ) )
continue ;
break ;
}
case MODE_INITIAL_CLASS_REGEX : {
const auto initialWindowClass = w - > m_szInitialClass ;
if ( ! std : : regex_search ( initialWindowClass , regexCheck ) )
2022-07-26 17:30:30 +02:00
continue ;
break ;
}
case MODE_TITLE_REGEX : {
2024-05-11 00:28:33 +02:00
const auto windowTitle = w - > m_szTitle ;
2022-07-26 17:30:30 +02:00
if ( ! std : : regex_search ( windowTitle , regexCheck ) )
continue ;
break ;
}
2024-04-21 16:19:59 +02:00
case MODE_INITIAL_TITLE_REGEX : {
const auto initialWindowTitle = w - > m_szInitialTitle ;
if ( ! std : : regex_search ( initialWindowTitle , regexCheck ) )
continue ;
break ;
}
2022-07-26 17:30:30 +02:00
case MODE_ADDRESS : {
2023-09-20 09:26:20 +02:00
std : : string addr = std : : format ( " 0x{:x} " , ( uintptr_t ) w . get ( ) ) ;
2022-07-26 17:30:30 +02:00
if ( matchCheck ! = addr )
continue ;
break ;
}
case MODE_PID : {
2023-09-20 09:26:20 +02:00
std : : string pid = std : : format ( " {} " , w - > getPID ( ) ) ;
2022-07-26 17:30:30 +02:00
if ( matchCheck ! = pid )
continue ;
break ;
}
2022-12-16 18:17:31 +01:00
default : break ;
2022-07-26 17:30:30 +02:00
}
2024-04-27 13:43:12 +02:00
return w ;
2022-07-26 17:30:30 +02:00
}
return nullptr ;
2022-07-31 00:27:32 +02:00
}
2023-01-28 13:26:33 +01:00
void CCompositor : : warpCursorTo ( const Vector2D & pos , bool force ) {
2022-08-01 18:50:16 +02:00
// warpCursorTo should only be used for warps that
2024-05-09 23:23:01 +02:00
// should be disabled with no_warps
2022-08-01 18:50:16 +02:00
2024-05-09 23:23:01 +02:00
static auto PNOWARPS = CConfigValue < Hyprlang : : INT > ( " cursor:no_warps " ) ;
2022-08-01 18:50:16 +02:00
2024-05-27 22:45:14 +02:00
if ( * PNOWARPS & & ! force ) {
const auto PMONITORNEW = getMonitorFromVector ( pos ) ;
if ( PMONITORNEW ! = m_pLastMonitor . get ( ) )
setActiveMonitor ( PMONITORNEW ) ;
2022-08-01 18:50:16 +02:00
return ;
2024-05-27 22:45:14 +02:00
}
2022-08-01 18:50:16 +02:00
2024-05-05 23:18:10 +02:00
g_pPointerManager - > warpTo ( pos ) ;
2022-09-03 11:55:14 +02:00
const auto PMONITORNEW = getMonitorFromVector ( pos ) ;
2024-05-05 23:18:10 +02:00
if ( PMONITORNEW ! = m_pLastMonitor . get ( ) )
2022-11-19 17:41:36 +01:00
setActiveMonitor ( PMONITORNEW ) ;
2022-08-01 18:50:16 +02:00
}
2024-04-27 13:43:12 +02:00
void CCompositor : : closeWindow ( PHLWINDOW pWindow ) {
if ( pWindow & & validMapped ( pWindow ) ) {
2022-08-06 20:57:38 +02:00
g_pXWaylandManager - > sendCloseWindow ( pWindow ) ;
}
2022-08-10 17:46:01 +02:00
}
2024-06-08 10:07:59 +02:00
PHLLS CCompositor : : getLayerSurfaceFromSurface ( SP < CWLSurfaceResource > pSurface ) {
std : : pair < SP < CWLSurfaceResource > , bool > result = { pSurface , false } ;
2023-04-02 14:30:45 +02:00
2024-05-09 22:47:21 +02:00
for ( auto & ls : m_vLayers ) {
if ( ls - > layerSurface & & ls - > layerSurface - > surface = = pSurface )
return ls ;
2023-04-02 14:42:57 +02:00
2024-05-09 22:47:21 +02:00
if ( ! ls - > layerSurface | | ! ls - > mapped )
continue ;
2023-04-02 14:30:45 +02:00
2024-06-08 10:07:59 +02:00
ls - > layerSurface - > surface - > breadthfirst (
[ ] ( SP < CWLSurfaceResource > surf , const Vector2D & offset , void * data ) {
if ( surf = = ( ( std : : pair < SP < CWLSurfaceResource > , bool > * ) data ) - > first ) {
* ( bool * ) data = true ;
return ;
}
} ,
& result ) ;
2024-05-09 22:47:21 +02:00
if ( result . second )
return ls ;
2022-08-10 17:46:01 +02:00
}
return nullptr ;
2022-08-15 15:59:07 +02:00
}
// returns a delta
Vector2D CCompositor : : parseWindowVectorArgsRelative ( const std : : string & args , const Vector2D & relativeTo ) {
2024-03-31 01:48:39 +01:00
if ( ! args . contains ( ' ' ) & & ! args . contains ( ' \t ' ) )
2022-08-15 15:59:07 +02:00
return relativeTo ;
2023-09-11 00:26:14 +02:00
const auto PMONITOR = m_pLastMonitor ;
bool xIsPercent = false ;
bool yIsPercent = false ;
bool isExact = false ;
2024-03-31 01:48:39 +01:00
CVarList varList ( args , 0 , ' s ' , true ) ;
std : : string x = varList [ 0 ] ;
std : : string y = varList [ 1 ] ;
2022-08-15 15:59:07 +02:00
if ( x = = " exact " ) {
2024-03-31 01:48:39 +01:00
x = varList [ 1 ] ;
y = varList [ 2 ] ;
2023-09-11 00:26:14 +02:00
isExact = true ;
}
2022-08-15 15:59:07 +02:00
2023-09-11 00:26:14 +02:00
if ( x . contains ( ' % ' ) ) {
xIsPercent = true ;
x = x . substr ( 0 , x . length ( ) - 1 ) ;
}
2022-08-15 15:59:07 +02:00
2023-09-11 00:26:14 +02:00
if ( y . contains ( ' % ' ) ) {
yIsPercent = true ;
y = y . substr ( 0 , y . length ( ) - 1 ) ;
2022-08-15 15:59:07 +02:00
}
if ( ! isNumber ( x ) | | ! isNumber ( y ) ) {
Debug : : log ( ERR , " parseWindowVectorArgsRelative: args not numbers " ) ;
return relativeTo ;
}
2023-09-11 00:26:14 +02:00
int X = 0 ;
int Y = 0 ;
if ( isExact ) {
X = xIsPercent ? std : : stof ( x ) * 0.01 * PMONITOR - > vecSize . x : std : : stoi ( x ) ;
Y = yIsPercent ? std : : stof ( y ) * 0.01 * PMONITOR - > vecSize . y : std : : stoi ( y ) ;
} else {
X = xIsPercent ? std : : stof ( x ) * 0.01 * relativeTo . x + relativeTo . x : std : : stoi ( x ) + relativeTo . x ;
Y = yIsPercent ? std : : stof ( y ) * 0.01 * relativeTo . y + relativeTo . y : std : : stoi ( y ) + relativeTo . y ;
}
2022-08-15 15:59:07 +02:00
2023-09-11 00:26:14 +02:00
return Vector2D ( X , Y ) ;
2022-08-22 14:22:21 +02:00
}
void CCompositor : : forceReportSizesToWindowsOnWorkspace ( const int & wid ) {
for ( auto & w : m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > workspaceID ( ) = = wid & & w - > m_bIsMapped & & ! w - > isHidden ( ) ) {
2024-04-27 13:43:12 +02:00
g_pXWaylandManager - > setWindowSize ( w , w - > m_vRealSize . value ( ) , true ) ;
2022-08-22 14:22:21 +02:00
}
}
2022-09-03 15:35:53 +02:00
}
2024-05-12 01:03:32 +02:00
PHLWORKSPACE CCompositor : : createNewWorkspace ( const int & id , const int & monid , const std : : string & name , bool isEmtpy ) {
2022-12-16 18:17:31 +01:00
const auto NAME = name = = " " ? std : : to_string ( id ) : name ;
auto monID = monid ;
2022-10-25 11:30:25 +02:00
// check if bound
if ( const auto PMONITOR = g_pConfigManager - > getBoundMonitorForWS ( NAME ) ; PMONITOR ) {
monID = PMONITOR - > ID ;
}
2022-11-27 23:42:22 +01:00
const bool SPECIAL = id > = SPECIAL_WORKSPACE_START & & id < = - 2 ;
2024-05-12 01:03:32 +02:00
const auto PWORKSPACE = m_vWorkspaces . emplace_back ( CWorkspace : : create ( id , monID , NAME , SPECIAL , isEmtpy ) ) ;
2022-10-24 19:36:31 +02:00
2023-11-18 18:00:24 +01:00
PWORKSPACE - > m_fAlpha . setValueAndWarp ( 0 ) ;
2022-10-24 19:36:31 +02:00
return PWORKSPACE ;
}
2022-11-19 17:41:36 +01:00
2023-01-08 14:19:18 +01:00
void CCompositor : : renameWorkspace ( const int & id , const std : : string & name ) {
const auto PWORKSPACE = getWorkspaceByID ( id ) ;
if ( ! PWORKSPACE )
return ;
if ( isWorkspaceSpecial ( id ) )
return ;
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " renameWorkspace: Renaming workspace {} to '{}' " , id , name ) ;
2023-01-08 14:19:18 +01:00
PWORKSPACE - > m_szName = name ;
2023-09-05 15:55:20 +02:00
g_pEventManager - > postEvent ( { " renameworkspace " , std : : to_string ( PWORKSPACE - > m_iID ) + " , " + PWORKSPACE - > m_szName } ) ;
2023-01-08 14:19:18 +01:00
}
2022-11-19 17:41:36 +01:00
void CCompositor : : setActiveMonitor ( CMonitor * pMonitor ) {
2024-05-05 23:18:10 +02:00
if ( m_pLastMonitor . get ( ) = = pMonitor )
2022-11-19 17:41:36 +01:00
return ;
2022-11-23 00:17:10 +01:00
if ( ! pMonitor ) {
2024-05-05 23:18:10 +02:00
m_pLastMonitor . reset ( ) ;
2022-11-23 00:17:10 +01:00
return ;
}
2024-04-02 21:32:39 +02:00
const auto PWORKSPACE = pMonitor - > activeWorkspace ;
2022-11-19 17:41:36 +01:00
2024-02-22 16:12:51 +01:00
g_pEventManager - > postEvent ( SHyprIPCEvent { " focusedmon " , pMonitor - > szName + " , " + ( PWORKSPACE ? PWORKSPACE - > m_szName : " ? " ) } ) ;
2023-02-19 21:54:53 +01:00
EMIT_HOOK_EVENT ( " focusedMon " , pMonitor ) ;
2024-05-05 23:18:10 +02:00
m_pLastMonitor = pMonitor - > self ;
2022-11-19 17:41:36 +01:00
}
2022-11-27 23:42:22 +01:00
bool CCompositor : : isWorkspaceSpecial ( const int & id ) {
return id > = SPECIAL_WORKSPACE_START & & id < = - 2 ;
}
int CCompositor : : getNewSpecialID ( ) {
2023-07-16 21:00:38 +02:00
int highest = SPECIAL_WORKSPACE_START ;
2022-11-27 23:42:22 +01:00
for ( auto & ws : m_vWorkspaces ) {
if ( ws - > m_bIsSpecialWorkspace & & ws - > m_iID > highest ) {
highest = ws - > m_iID ;
}
}
return highest + 1 ;
}
2023-03-20 16:02:47 +01:00
void CCompositor : : performUserChecks ( ) {
2024-01-27 14:58:13 +01:00
; // intentional
2023-03-20 16:02:47 +01:00
}
2023-04-14 16:03:53 +02:00
2024-04-27 13:43:12 +02:00
void CCompositor : : moveWindowToWorkspaceSafe ( PHLWINDOW pWindow , PHLWORKSPACE pWorkspace ) {
2023-04-14 16:03:53 +02:00
if ( ! pWindow | | ! pWorkspace )
return ;
2023-05-29 17:46:06 +02:00
if ( pWindow - > m_bPinned & & pWorkspace - > m_bIsSpecialWorkspace )
return ;
2023-04-30 00:39:09 +02:00
const bool FULLSCREEN = pWindow - > m_bIsFullscreen ;
2024-04-02 21:32:39 +02:00
const auto FULLSCREENMODE = pWindow - > m_pWorkspace - > m_efFullscreenMode ;
2023-04-14 16:03:53 +02:00
if ( FULLSCREEN )
setWindowFullscreen ( pWindow , false , FULLSCREEN_FULL ) ;
if ( ! pWindow - > m_bIsFloating ) {
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowRemovedTiling ( pWindow ) ;
2024-04-23 17:38:12 +02:00
pWindow - > moveToWorkspace ( pWorkspace ) ;
2024-04-02 21:32:39 +02:00
pWindow - > m_iMonitorID = pWorkspace - > m_iMonitorID ;
2023-04-14 16:03:53 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > onWindowCreatedTiling ( pWindow ) ;
} else {
const auto PWINDOWMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2024-03-02 01:35:17 +01:00
const auto POSTOMON = pWindow - > m_vRealPosition . goal ( ) - PWINDOWMONITOR - > vecPosition ;
2023-04-14 16:03:53 +02:00
const auto PWORKSPACEMONITOR = g_pCompositor - > getMonitorFromID ( pWorkspace - > m_iMonitorID ) ;
2024-04-23 17:38:12 +02:00
pWindow - > moveToWorkspace ( pWorkspace ) ;
2024-04-02 21:32:39 +02:00
pWindow - > m_iMonitorID = pWorkspace - > m_iMonitorID ;
2023-04-14 16:03:53 +02:00
pWindow - > m_vRealPosition = POSTOMON + PWORKSPACEMONITOR - > vecPosition ;
}
2024-03-06 22:33:50 +01:00
pWindow - > updateToplevel ( ) ;
pWindow - > updateDynamicRules ( ) ;
pWindow - > uncacheWindowDecos ( ) ;
2024-04-27 13:43:12 +02:00
if ( ! pWindow - > m_sGroupData . pNextWindow . expired ( ) ) {
PHLWINDOW next = pWindow - > m_sGroupData . pNextWindow . lock ( ) ;
2023-06-21 20:51:18 +02:00
while ( next ! = pWindow ) {
2024-04-02 21:32:39 +02:00
next - > moveToWorkspace ( pWorkspace ) ;
2023-06-21 20:51:18 +02:00
next - > updateToplevel ( ) ;
2024-04-27 13:43:12 +02:00
next = next - > m_sGroupData . pNextWindow . lock ( ) ;
2023-06-21 20:51:18 +02:00
}
}
2023-04-14 16:03:53 +02:00
if ( FULLSCREEN )
2023-04-30 00:39:09 +02:00
setWindowFullscreen ( pWindow , true , FULLSCREENMODE ) ;
2023-12-20 23:52:18 +01:00
g_pCompositor - > updateWorkspaceWindows ( pWorkspace - > m_iID ) ;
2024-04-02 21:32:39 +02:00
g_pCompositor - > updateWorkspaceWindows ( pWindow - > workspaceID ( ) ) ;
2023-04-14 16:03:53 +02:00
}
2023-07-04 12:05:25 +02:00
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : getForceFocus ( ) {
2023-07-04 12:05:25 +02:00
for ( auto & w : m_vWindows ) {
2024-04-03 11:09:42 +02:00
if ( ! w - > m_bIsMapped | | w - > isHidden ( ) | | ! isWorkspaceVisible ( w - > m_pWorkspace ) )
2023-07-04 12:05:25 +02:00
continue ;
if ( ! w - > m_bStayFocused )
continue ;
2024-04-27 13:43:12 +02:00
return w ;
2023-07-04 12:05:25 +02:00
}
return nullptr ;
}
2023-07-13 18:05:34 +02:00
2023-08-14 14:22:06 +02:00
void CCompositor : : arrangeMonitors ( ) {
2024-02-18 16:00:34 +01:00
static auto * const PXWLFORCESCALEZERO = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " xwayland:force_zero_scaling " ) ;
2023-08-15 19:15:37 +02:00
2023-08-14 14:22:06 +02:00
std : : vector < CMonitor * > toArrange ;
std : : vector < CMonitor * > arranged ;
for ( auto & m : m_vMonitors )
toArrange . push_back ( m . get ( ) ) ;
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " arrangeMonitors: {} to arrange " , toArrange . size ( ) ) ;
2023-08-21 19:52:30 +02:00
2023-08-14 19:27:33 +02:00
for ( auto it = toArrange . begin ( ) ; it ! = toArrange . end ( ) ; ) {
2023-08-14 14:22:06 +02:00
auto m = * it ;
2023-08-16 18:16:36 +02:00
if ( m - > activeMonitorRule . offset ! = Vector2D { - INT32_MAX , - INT32_MAX } ) {
2023-08-14 14:22:06 +02:00
// explicit.
2024-04-25 23:07:50 +02:00
Debug : : log ( LOG , " arrangeMonitors: {} explicit {:j} " , m - > szName , m - > activeMonitorRule . offset ) ;
2023-08-21 19:52:30 +02:00
2023-08-14 14:22:06 +02:00
m - > moveTo ( m - > activeMonitorRule . offset ) ;
arranged . push_back ( m ) ;
it = toArrange . erase ( it ) ;
if ( it = = toArrange . end ( ) )
break ;
2023-08-14 19:27:33 +02:00
continue ;
2023-08-14 14:22:06 +02:00
}
2023-08-14 19:27:33 +02:00
+ + it ;
2023-08-14 14:22:06 +02:00
}
2024-04-23 02:40:03 +02:00
// Variables to store the max and min values of monitors on each axis.
int maxXOffsetRight = 0 ;
int maxXOffsetLeft = 0 ;
int maxYOffsetUp = 0 ;
int maxYOffsetDown = 0 ;
// Finds the max and min values of explicitely placed monitors.
2023-08-14 14:22:06 +02:00
for ( auto & m : arranged ) {
2024-04-23 02:40:03 +02:00
if ( m - > vecPosition . x + m - > vecSize . x > maxXOffsetRight )
maxXOffsetRight = m - > vecPosition . x + m - > vecSize . x ;
if ( m - > vecPosition . x < maxXOffsetLeft )
maxXOffsetLeft = m - > vecPosition . x ;
if ( m - > vecPosition . y + m - > vecSize . y > maxYOffsetDown )
maxYOffsetDown = m - > vecPosition . y + m - > vecSize . y ;
if ( m - > vecPosition . y < maxYOffsetUp )
maxYOffsetUp = m - > vecPosition . y ;
2023-08-14 14:22:06 +02:00
}
2024-04-23 02:40:03 +02:00
// Iterates through all non-explicitly placed monitors.
2023-08-14 14:22:06 +02:00
for ( auto & m : toArrange ) {
2024-04-23 02:40:03 +02:00
// Moves the monitor to their appropriate position on the x/y axis and
// increments/decrements the corresponding max offset.
2024-04-25 23:07:50 +02:00
Vector2D newPosition = { 0 , 0 } ;
switch ( m - > activeMonitorRule . autoDir ) {
case eAutoDirs : : DIR_AUTO_UP :
newPosition . y = maxYOffsetUp - m - > vecSize . y ;
maxYOffsetUp = newPosition . y ;
break ;
case eAutoDirs : : DIR_AUTO_DOWN :
newPosition . y = maxYOffsetDown ;
maxYOffsetDown + = m - > vecSize . y ;
break ;
case eAutoDirs : : DIR_AUTO_LEFT :
newPosition . x = maxXOffsetLeft - m - > vecSize . x ;
maxXOffsetLeft = newPosition . x ;
break ;
case eAutoDirs : : DIR_AUTO_RIGHT :
2024-05-24 20:56:42 +02:00
case eAutoDirs : : DIR_AUTO_NONE :
2024-04-25 23:07:50 +02:00
newPosition . x = maxXOffsetRight ;
maxXOffsetRight + = m - > vecSize . x ;
break ;
default : UNREACHABLE ( ) ;
2024-04-23 02:40:03 +02:00
}
2024-04-25 23:07:50 +02:00
Debug : : log ( LOG , " arrangeMonitors: {} auto {:j} " , m - > szName , m - > vecPosition ) ;
m - > moveTo ( newPosition ) ;
2023-08-14 14:22:06 +02:00
}
2023-08-15 19:15:37 +02:00
2024-04-23 02:40:03 +02:00
// reset maxXOffsetRight (reuse)
2023-08-15 19:15:37 +02:00
// and set xwayland positions aka auto for all
2024-04-23 02:40:03 +02:00
maxXOffsetRight = 0 ;
2023-08-15 19:15:37 +02:00
for ( auto & m : m_vMonitors ) {
2024-04-25 23:07:50 +02:00
Debug : : log ( LOG , " arrangeMonitors: {} xwayland [{}, {}] " , m - > szName , maxXOffsetRight , 0 ) ;
2024-04-23 02:40:03 +02:00
m - > vecXWaylandPosition = { maxXOffsetRight , 0 } ;
maxXOffsetRight + = ( * PXWLFORCESCALEZERO ? m - > vecTransformedSize . x : m - > vecSize . x ) ;
2023-09-20 17:47:05 +02:00
2024-03-03 19:39:20 +01:00
if ( * PXWLFORCESCALEZERO )
2023-09-20 17:47:05 +02:00
m - > xwaylandScale = m - > scale ;
else
m - > xwaylandScale = 1.f ;
2023-08-15 19:15:37 +02:00
}
2023-08-14 14:22:06 +02:00
}
2023-09-24 19:04:38 +02:00
void CCompositor : : enterUnsafeState ( ) {
if ( m_bUnsafeState )
return ;
Debug : : log ( LOG , " Entering unsafe state " ) ;
2023-11-01 19:53:36 +01:00
if ( ! m_pUnsafeOutput - > m_bEnabled )
m_pUnsafeOutput - > onConnect ( false ) ;
2023-09-24 19:04:38 +02:00
2023-11-01 19:53:36 +01:00
m_bUnsafeState = true ;
2024-03-26 03:26:09 +01:00
setActiveMonitor ( m_pUnsafeOutput ) ;
2023-09-24 19:04:38 +02:00
}
void CCompositor : : leaveUnsafeState ( ) {
if ( ! m_bUnsafeState )
return ;
Debug : : log ( LOG , " Leaving unsafe state " ) ;
m_bUnsafeState = false ;
2023-11-01 19:53:36 +01:00
CMonitor * pNewMonitor = nullptr ;
for ( auto & pMonitor : m_vMonitors ) {
if ( pMonitor - > output ! = m_pUnsafeOutput - > output ) {
pNewMonitor = pMonitor . get ( ) ;
break ;
}
}
RASSERT ( pNewMonitor , " Tried to leave unsafe without a monitor " ) ;
if ( m_pUnsafeOutput - > m_bEnabled )
m_pUnsafeOutput - > onDisconnect ( ) ;
2023-09-24 19:04:38 +02:00
2023-11-01 19:53:36 +01:00
for ( auto & m : m_vMonitors ) {
scheduleFrameForMonitor ( m . get ( ) ) ;
}
2023-09-24 19:04:38 +02:00
}
2023-10-22 17:58:06 +02:00
2024-06-08 10:07:59 +02:00
void CCompositor : : setPreferredScaleForSurface ( SP < CWLSurfaceResource > pSurface , double scale ) {
2024-04-20 15:14:54 +02:00
PROTO : : fractional - > sendScale ( pSurface , scale ) ;
2024-06-08 10:07:59 +02:00
pSurface - > sendPreferredScale ( std : : ceil ( scale ) ) ;
2024-01-11 13:15:20 +01:00
2024-06-08 10:07:59 +02:00
const auto PSURFACE = CWLSurface : : fromResource ( pSurface ) ;
2024-01-11 13:15:20 +01:00
if ( ! PSURFACE ) {
2024-06-08 10:07:59 +02:00
Debug : : log ( WARN , " Orphaned CWLSurfaceResource {:x} in setPreferredScaleForSurface " , ( uintptr_t ) pSurface ) ;
2024-01-11 13:15:20 +01:00
return ;
}
PSURFACE - > m_fLastScale = scale ;
PSURFACE - > m_iLastScale = static_cast < int32_t > ( std : : ceil ( scale ) ) ;
2023-10-22 17:58:06 +02:00
}
2024-06-08 10:07:59 +02:00
void CCompositor : : setPreferredTransformForSurface ( SP < CWLSurfaceResource > pSurface , wl_output_transform transform ) {
pSurface - > sendPreferredTransform ( transform ) ;
2024-01-11 13:15:20 +01:00
2024-06-08 10:07:59 +02:00
const auto PSURFACE = CWLSurface : : fromResource ( pSurface ) ;
2024-01-11 13:15:20 +01:00
if ( ! PSURFACE ) {
2024-06-08 10:07:59 +02:00
Debug : : log ( WARN , " Orphaned CWLSurfaceResource {:x} in setPreferredTransformForSurface " , ( uintptr_t ) pSurface ) ;
2024-01-11 13:15:20 +01:00
return ;
}
PSURFACE - > m_eLastTransform = transform ;
2023-12-13 18:25:19 +01:00
}
2023-12-23 22:30:49 +01:00
void CCompositor : : updateSuspendedStates ( ) {
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( ! w - > m_bIsMapped )
continue ;
2024-04-03 11:09:42 +02:00
w - > setSuspended ( w - > isHidden ( ) | | ! isWorkspaceVisible ( w - > m_pWorkspace ) ) ;
2023-12-23 22:30:49 +01:00
}
}
2024-04-27 13:43:12 +02:00
PHLWINDOW CCompositor : : windowForCPointer ( CWindow * pWindow ) {
for ( auto & w : m_vWindows ) {
if ( w . get ( ) ! = pWindow )
continue ;
return w ;
}
return { } ;
}
2024-06-20 18:05:35 +02:00
static void checkDefaultCursorWarp ( SP < CMonitor > PNEWMONITOR , std : : string monitorName ) {
static auto PCURSORMONITOR = CConfigValue < std : : string > ( " cursor:default_monitor " ) ;
static auto firstMonitorAdded = std : : chrono : : system_clock : : now ( ) ;
static bool cursorDefaultDone = false ;
static bool firstLaunch = true ;
const auto POS = PNEWMONITOR - > middle ( ) ;
// by default, cursor should be set to first monitor detected
// this is needed as a default if the monitor given in config above doesn't exist
if ( firstLaunch ) {
firstLaunch = false ;
g_pCompositor - > warpCursorTo ( POS , true ) ;
g_pInputManager - > refocus ( ) ;
}
if ( cursorDefaultDone | | * PCURSORMONITOR = = STRVAL_EMPTY )
return ;
// after 10s, don't set cursor to default monitor
auto timePassedSec = std : : chrono : : duration_cast < std : : chrono : : seconds > ( std : : chrono : : system_clock : : now ( ) - firstMonitorAdded ) ;
if ( timePassedSec . count ( ) > 10 ) {
cursorDefaultDone = true ;
return ;
}
if ( * PCURSORMONITOR = = monitorName ) {
cursorDefaultDone = true ;
g_pCompositor - > warpCursorTo ( POS , true ) ;
g_pInputManager - > refocus ( ) ;
}
}
void CCompositor : : onNewMonitor ( SP < Aquamarine : : IOutput > output ) {
// add it to real
auto PNEWMONITOR = g_pCompositor - > m_vRealMonitors . emplace_back ( makeShared < CMonitor > ( ) ) ;
if ( std : : string ( " HEADLESS-1 " ) = = output - > name )
g_pCompositor - > m_pUnsafeOutput = PNEWMONITOR . get ( ) ;
PNEWMONITOR - > szName = output - > name ;
PNEWMONITOR - > output = output ;
PNEWMONITOR - > self = PNEWMONITOR ;
const bool FALLBACK = g_pCompositor - > m_pUnsafeOutput ? output = = g_pCompositor - > m_pUnsafeOutput - > output : false ;
PNEWMONITOR - > ID = FALLBACK ? - 1 : g_pCompositor - > getNextAvailableMonitorID ( output - > name ) ;
PNEWMONITOR - > isUnsafeFallback = FALLBACK ;
EMIT_HOOK_EVENT ( " newMonitor " , PNEWMONITOR ) ;
if ( ! FALLBACK )
PNEWMONITOR - > onConnect ( false ) ;
if ( ! PNEWMONITOR - > m_bEnabled | | FALLBACK )
return ;
// ready to process if we have a real monitor
if ( ( ! g_pHyprRenderer - > m_pMostHzMonitor | | PNEWMONITOR - > refreshRate > g_pHyprRenderer - > m_pMostHzMonitor - > refreshRate ) & & PNEWMONITOR - > m_bEnabled )
g_pHyprRenderer - > m_pMostHzMonitor = PNEWMONITOR . get ( ) ;
g_pCompositor - > m_bReadyToProcess = true ;
g_pConfigManager - > m_bWantsMonitorReload = true ;
g_pCompositor - > scheduleFrameForMonitor ( PNEWMONITOR . get ( ) ) ;
checkDefaultCursorWarp ( PNEWMONITOR , output - > name ) ;
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( w - > m_iMonitorID = = PNEWMONITOR - > ID ) {
w - > m_iLastSurfaceMonitorID = - 1 ;
w - > updateSurfaceScaleTransformDetails ( ) ;
}
}
g_pHyprRenderer - > damageMonitor ( PNEWMONITOR . get ( ) ) ;
Events : : listener_monitorFrame ( PNEWMONITOR . get ( ) , nullptr ) ;
}