Core: Move to aquamarine (#6608)

Moves Hyprland from wlroots to aquamarine for the backend.

---------

Signed-off-by: Vaxry <vaxry@vaxry.net>
Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
Co-authored-by: Jan Beich <jbeich@FreeBSD.org>
Co-authored-by: vaxerski <vaxerski@users.noreply.github.com>
Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com>
Co-authored-by: Tom Englund <tomenglund26@gmail.com>
Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com>
Co-authored-by: diniamo <diniamo53@gmail.com>
This commit is contained in:
Vaxry
2024-07-21 13:09:54 +02:00
committed by GitHub
parent f642fb97df
commit 016da234d0
131 changed files with 4755 additions and 3460 deletions

View File

@@ -6,7 +6,10 @@
#include "managers/PointerManager.hpp"
#include "managers/SeatManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include <aquamarine/output/Output.hpp>
#include <random>
#include <cstring>
#include <filesystem>
#include <unordered_set>
#include "debug/HyprCtl.hpp"
#include "debug/CrashReporter.hpp"
@@ -22,16 +25,20 @@
#include "protocols/core/Compositor.hpp"
#include "protocols/core/Subcompositor.hpp"
#include "desktop/LayerSurface.hpp"
#include "render/Renderer.hpp"
#include "xwayland/XWayland.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
#include <aquamarine/input/Input.hpp>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>
using namespace Hyprutils::String;
using namespace Aquamarine;
int handleCritSignal(int signo, void* data) {
Debug::log(LOG, "Hyprland received signal {}", signo);
@@ -72,6 +79,23 @@ void handleUserSignal(int sig) {
}
}
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);
}
void CCompositor::bumpNofile() {
if (!getrlimit(RLIMIT_NOFILE, &m_sOriginalNofile))
Debug::log(LOG, "Old rlimit: soft -> {}, hard -> {}", m_sOriginalNofile.rlim_cur, m_sOriginalNofile.rlim_max);
@@ -180,6 +204,9 @@ void CCompositor::setRandomSplash() {
m_szCurrentSplash = SPLASHES[distribution(engine)];
}
static std::vector<SP<Aquamarine::IOutput>> pendingOutputs;
//
void CCompositor::initServer() {
m_sWLDisplay = wl_display_create();
@@ -200,102 +227,179 @@ void CCompositor::initServer() {
if (envEnabled("HYPRLAND_TRACE"))
Debug::trace = true;
wlr_log_init(WLR_INFO, NULL);
Aquamarine::SBackendOptions options;
options.logFunction = aqLog;
if (envEnabled("HYPRLAND_LOG_WLR"))
wlr_log_init(WLR_DEBUG, Debug::wlrLog);
else
wlr_log_init(WLR_ERROR, Debug::wlrLog);
std::vector<Aquamarine::SBackendImplementationOptions> implementations;
Aquamarine::SBackendImplementationOptions option;
option.backendType = Aquamarine::eBackendType::AQ_BACKEND_HEADLESS;
option.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_MANDATORY;
implementations.emplace_back(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);
m_sWLRBackend = wlr_backend_autocreate(m_sWLEventLoop, &m_sWLRSession);
m_pAqBackend = CBackend::create(implementations, options);
if (!m_sWLRBackend) {
Debug::log(CRIT, "m_sWLRBackend was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_backend_autocreate() failed!");
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!");
}
bool isHeadlessOnly = true;
wlr_multi_for_each_backend(
m_sWLRBackend,
[](wlr_backend* backend, void* isHeadlessOnly) {
if (!wlr_backend_is_headless(backend) && !wlr_backend_is_libinput(backend))
*(bool*)isHeadlessOnly = false;
},
&isHeadlessOnly);
// TODO: headless only
if (isHeadlessOnly) {
m_sWLRRenderer = wlr_renderer_autocreate(m_sWLRBackend); // TODO: remove this, it's barely needed now.
} else {
m_iDRMFD = wlr_backend_get_drm_fd(m_sWLRBackend);
if (m_iDRMFD < 0) {
Debug::log(CRIT, "Couldn't query the DRM FD!");
throwError("wlr_backend_get_drm_fd() failed!");
initAllSignals();
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!");
}
m_bInitialized = true;
m_iDRMFD = m_pAqBackend->drmFD();
Debug::log(LOG, "Running on DRMFD: {}", m_iDRMFD);
// get socket, avoid using 0
for (int candidate = 1; candidate <= 32; candidate++) {
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;
Debug::log(LOG, "wl_display_add_socket for {} succeeded with {}", CANDIDATESTR, RETVAL);
break;
} else {
Debug::log(WARN, "wl_display_add_socket for {} returned {}: skipping candidate {}", CANDIDATESTR, RETVAL, candidate);
}
m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
}
if (!m_sWLRRenderer) {
Debug::log(CRIT, "m_sWLRRenderer was NULL! This usually means wlroots could not find a GPU or enountered some issues.");
throwError("wlr_gles2_renderer_create_with_drm_fd() failed!");
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;
}
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
if (!m_sWLRAllocator) {
Debug::log(CRIT, "m_sWLRAllocator was NULL!");
throwError("wlr_allocator_autocreate() failed!");
if (m_szWLDisplaySocket.empty()) {
Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
}
m_sWLREGL = wlr_gles2_renderer_get_egl(m_sWLRRenderer);
if (!m_sWLREGL) {
Debug::log(CRIT, "m_sWLREGL was NULL!");
throwError("wlr_gles2_renderer_get_egl() failed!");
}
Debug::log(LOG, "Setting WAYLAND_DISPLAY to {}", m_szWLDisplaySocket);
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
setenv("XDG_SESSION_TYPE", "wayland", 1);
initManagers(STAGE_BASICINIT);
m_sWRLDRMLeaseMgr = wlr_drm_lease_v1_manager_create(m_sWLDisplay, m_sWLRBackend);
if (!m_sWRLDRMLeaseMgr) {
Debug::log(INFO, "Failed to create wlr_drm_lease_v1_manager");
Debug::log(INFO, "VR will not be available");
}
m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop);
if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend");
throwError("wlr_headless_backend_create() failed!");
}
wlr_multi_backend_add(m_sWLRBackend, m_sWLRHeadlessBackend);
initManagers(STAGE_LATE);
for (auto& o : pendingOutputs) {
onNewMonitor(o);
}
pendingOutputs.clear();
}
void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend");
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend");
addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer");
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);
if (m_sWRLDRMLeaseMgr)
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
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);
if (m_sWLRSession)
addWLSignal(&m_sWLRSession->events.active, &Events::listen_sessionActive, m_sWLRSession, "Session");
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);
m_pAqBackend->events.newSwitch.registerStaticListener(
[](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::ISwitch>>(d);
Debug::log(LOG, "New aquamarine switch with name {}", dev->getName());
g_pInputManager->newSwitch(dev);
},
nullptr);
m_pAqBackend->events.newTablet.registerStaticListener(
[](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::ITablet>>(d);
Debug::log(LOG, "New aquamarine tablet with name {}", dev->getName());
g_pInputManager->newTablet(dev);
},
nullptr);
m_pAqBackend->events.newTabletPad.registerStaticListener(
[](void* data, std::any d) {
auto dev = std::any_cast<SP<Aquamarine::ITabletPad>>(d);
Debug::log(LOG, "New aquamarine tablet pad with name {}", dev->getName());
g_pInputManager->newTabletPad(dev);
},
nullptr);
if (m_pAqBackend->hasSession()) {
m_pAqBackend->session->events.changeActive.registerStaticListener(
[this](void*, std::any) {
if (m_pAqBackend->session->active) {
Debug::log(LOG, "Session got activated!");
m_bSessionActive = true;
for (auto& m : m_vMonitors) {
scheduleFrameForMonitor(m.get());
g_pHyprRenderer->applyMonitorRule(m.get(), &m->activeMonitorRule, true);
}
g_pConfigManager->m_bWantsMonitorReload = true;
} else {
Debug::log(LOG, "Session got deactivated!");
m_bSessionActive = false;
for (auto& m : m_vMonitors) {
m->noFrameSchedule = true;
m->framesToSkip = 1;
}
}
},
nullptr);
}
}
void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_newOutput);
removeWLSignal(&Events::listen_newInput);
removeWLSignal(&Events::listen_RendererDestroy);
if (m_sWRLDRMLeaseMgr)
removeWLSignal(&Events::listen_leaseRequest);
if (m_sWLRSession)
removeWLSignal(&Events::listen_sessionActive);
;
}
void CCompositor::cleanEnvironment() {
@@ -309,7 +413,7 @@ void CCompositor::cleanEnvironment() {
unsetenv("XDG_BACKEND");
unsetenv("XDG_CURRENT_DESKTOP");
if (m_sWLRSession) {
if (m_pAqBackend->hasSession()) {
const auto CMD =
#ifdef USES_SYSTEMD
"systemctl --user unset-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
@@ -352,7 +456,7 @@ void CCompositor::cleanup() {
for (auto& m : m_vMonitors) {
g_pHyprOpenGL->destroyMonitorResources(m.get());
wlr_output_state_set_enabled(m->state.wlr(), false);
m->output->state->setEnabled(false);
m->state.commit();
}
@@ -389,14 +493,8 @@ void CCompositor::cleanup() {
g_pHyprCtl.reset();
g_pEventLoopManager.reset();
if (m_sWLRRenderer)
wlr_renderer_destroy(m_sWLRRenderer);
if (m_sWLRAllocator)
wlr_allocator_destroy(m_sWLRAllocator);
if (m_sWLRBackend)
wlr_backend_destroy(m_sWLRBackend);
if (m_pAqBackend)
m_pAqBackend.reset();
if (m_critSigSource)
wl_event_source_remove(m_critSigSource);
@@ -442,6 +540,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the PointerManager!");
g_pPointerManager = std::make_unique<CPointerManager>();
Debug::log(LOG, "Creating the EventManager!");
g_pEventManager = std::make_unique<CEventManager>();
} break;
case STAGE_BASICINIT: {
Debug::log(LOG, "Creating the CHyprOpenGLImpl!");
@@ -472,9 +573,6 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Debug::log(LOG, "Creating the SessionLockManager!");
g_pSessionLockManager = std::make_unique<CSessionLockManager>();
Debug::log(LOG, "Creating the EventManager!");
g_pEventManager = std::make_unique<CEventManager>();
Debug::log(LOG, "Creating the HyprDebugOverlay!");
g_pDebugOverlay = std::make_unique<CHyprDebugOverlay>();
@@ -517,26 +615,23 @@ void CCompositor::removeLockFile() {
void CCompositor::prepareFallbackOutput() {
// 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);
SP<Aquamarine::IBackendImplementation> headless;
for (auto& impl : m_pAqBackend->getImplementations()) {
if (impl->type() == Aquamarine::AQ_BACKEND_HEADLESS) {
headless = impl;
break;
}
}
if (!headless) {
Debug::log(WARN, "Unsafe state will be ineffective, no fallback output");
Debug::log(WARN, "No headless in prepareFallbackOutput?!");
return;
}
wlr_headless_add_output(headless, 1920, 1080);
headless->createOutput();
}
void CCompositor::startCompositor(std::string socketName, int socketFd) {
initAllSignals();
if (!socketName.empty() && socketFd != -1) {
fcntl(socketFd, F_SETFD, FD_CLOEXEC);
const auto RETVAL = wl_display_add_socket_fd(m_sWLDisplay, socketFd);
@@ -568,15 +663,15 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) {
if (m_szWLDisplaySocket.empty()) {
Debug::log(CRIT, "m_szWLDisplaySocket NULL!");
wlr_backend_destroy(m_sWLRBackend);
throwError("m_szWLDisplaySocket was null! (wl_display_add_socket and wl_display_add_socket_auto failed)");
}
setenv("WAYLAND_DISPLAY", m_szWLDisplaySocket.c_str(), 1);
setenv("XDG_SESSION_TYPE", "wayland", 1);
signal(SIGPIPE, SIG_IGN);
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
if (m_pAqBackend->hasSession() /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
const auto CMD =
#ifdef USES_SYSTEMD
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
@@ -588,13 +683,6 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) {
Debug::log(LOG, "Running on WAYLAND_DISPLAY: {}", m_szWLDisplaySocket);
if (!wlr_backend_start(m_sWLRBackend)) {
Debug::log(CRIT, "Backend did not start!");
wlr_backend_destroy(m_sWLRBackend);
wl_display_destroy(m_sWLDisplay);
throwError("The backend could not start!");
}
prepareFallbackOutput();
g_pHyprRenderer->setCursorFromName("left_ptr");
@@ -882,7 +970,7 @@ Vector2D CCompositor::vectorToSurfaceLocal(const Vector2D& vec, PHLWINDOW pWindo
return vec - pWindow->m_vRealPosition.goal() - std::get<1>(iterData) + Vector2D{geom.x, geom.y};
}
CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
CMonitor* CCompositor::getMonitorFromOutput(SP<Aquamarine::IOutput> out) {
for (auto& m : m_vMonitors) {
if (m->output == out) {
return m.get();
@@ -892,7 +980,7 @@ CMonitor* CCompositor::getMonitorFromOutput(wlr_output* out) {
return nullptr;
}
CMonitor* CCompositor::getRealMonitorFromOutput(wlr_output* out) {
CMonitor* CCompositor::getRealMonitorFromOutput(SP<Aquamarine::IOutput> out) {
for (auto& m : m_vRealMonitors) {
if (m->output == out) {
return m.get();
@@ -2240,8 +2328,12 @@ void CCompositor::setWindowFullscreen(PHLWINDOW pWindow, bool on, eFullscreenMod
g_pInputManager->recheckIdleInhibitorStatus();
// DMAbuf stuff for direct scanout
g_pHyprRenderer->setWindowScanoutMode(pWindow);
// further updates require a monitor
if (!PMONITOR)
return;
// send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't.
g_pHyprRenderer->setSurfaceScanoutMode(pWindow->m_pWLSurface->resource(), on ? PMONITOR->self.lock() : nullptr);
g_pConfigManager->ensureVRR(PMONITOR);
}
@@ -2282,8 +2374,8 @@ void CCompositor::updateWorkspaceWindowData(const int& id) {
}
}
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor, IOutput::scheduleFrameReason reason) {
if ((m_pAqBackend->hasSession() && !m_pAqBackend->session->active) || !m_bSessionActive)
return;
if (!pMonitor->m_bEnabled)
@@ -2292,7 +2384,7 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if (pMonitor->renderingActive)
pMonitor->pendingFrame = true;
wlr_output_schedule_frame(pMonitor->output);
pMonitor->output->scheduleFrame(reason);
}
PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) {
@@ -2808,3 +2900,84 @@ PHLWINDOW CCompositor::windowForCPointer(CWindow* pWindow) {
return {};
}
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();
output->name = "FALLBACK"; // we are allowed to do this :)
}
Debug::log(LOG, "New output with name {}", output->name);
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(), IOutput::AQ_SCHEDULE_NEW_MONITOR);
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);
}