mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-13 11:05:46 -07:00
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:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user