Core: Move to aquamarine

This commit is contained in:
Vaxry 2024-06-20 18:05:35 +02:00
parent f642fb97df
commit d93791e25d
75 changed files with 1888 additions and 2051 deletions

View file

@ -109,6 +109,7 @@ endif()
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(deps REQUIRED IMPORTED_TARGET
aquamarine
xkbcommon uuid
wayland-server wayland-client wayland-cursor wayland-protocols
cairo pango pangocairo pixman-1

View file

@ -88,7 +88,7 @@ asan:
@pidof Hyprland > /dev/null && exit 1 || echo ""
rm -rf ./wayland
git reset --hard
#git reset --hard
@echo -en "If you want to apply a patch, input its path (leave empty for none):\n"
@read patchvar

View file

@ -25,13 +25,16 @@
#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 +75,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 +200,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 +223,91 @@ 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 waylandOptions;
waylandOptions.backendType = Aquamarine::eBackendType::AQ_BACKEND_WAYLAND;
waylandOptions.backendRequestMode = Aquamarine::eBackendRequestMode::AQ_BACKEND_REQUEST_IF_AVAILABLE;
implementations.emplace_back(waylandOptions);
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();
m_sWLRRenderer = wlr_gles2_renderer_create_with_drm_fd(m_iDRMFD);
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!");
}
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!");
}
m_bInitialized = true;
m_sWLRAllocator = wlr_allocator_autocreate(m_sWLRBackend, m_sWLRRenderer);
if (!m_sWLRAllocator) {
Debug::log(CRIT, "m_sWLRAllocator was NULL!");
throwError("wlr_allocator_autocreate() 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!");
}
m_iDRMFD = m_pAqBackend->drmFD();
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);
}
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 +321,7 @@ void CCompositor::cleanEnvironment() {
unsetenv("XDG_BACKEND");
unsetenv("XDG_CURRENT_DESKTOP");
if (m_sWLRSession) {
if (false /* TODO: */) {
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 +364,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 +401,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 +448,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 +481,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>();
@ -516,22 +522,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);
// 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);
if (!headless) {
Debug::log(WARN, "Unsafe state will be ineffective, no fallback output");
return;
}
// if (!headless) {
// Debug::log(WARN, "Unsafe state will be ineffective, no fallback output");
// return;
// }
wlr_headless_add_output(headless, 1920, 1080);
// wlr_headless_add_output(headless, 1920, 1080);
}
void CCompositor::startCompositor(std::string socketName, int socketFd) {
@ -568,7 +575,6 @@ 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)");
}
@ -576,7 +582,8 @@ void CCompositor::startCompositor(std::string socketName, int socketFd) {
signal(SIGPIPE, SIG_IGN);
if (m_sWLRSession /* Session-less Hyprland usually means a nest, don't update the env in that case */) {
// TODO:
if (false /* 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 +595,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 +882,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 +892,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();
@ -2283,8 +2283,9 @@ void CCompositor::updateWorkspaceWindowData(const int& id) {
}
void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
return;
// FIXME:
// if ((m_sWLRSession && !m_sWLRSession->active) || !m_bSessionActive)
// return;
if (!pMonitor->m_bEnabled)
return;
@ -2292,7 +2293,7 @@ void CCompositor::scheduleFrameForMonitor(CMonitor* pMonitor) {
if (pMonitor->renderingActive)
pMonitor->pendingFrame = true;
wlr_output_schedule_frame(pMonitor->output);
pMonitor->output->scheduleFrame();
}
PHLWINDOW CCompositor::getWindowByRegex(const std::string& regexp) {
@ -2808,3 +2809,80 @@ 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();
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);
}

View file

@ -30,6 +30,9 @@
#include "plugins/PluginSystem.hpp"
#include "helpers/Watchdog.hpp"
#include <aquamarine/backend/Backend.hpp>
#include <aquamarine/output/Output.hpp>
class CWLSurfaceResource;
enum eManagersInitStage {
@ -43,22 +46,11 @@ class CCompositor {
CCompositor();
~CCompositor();
// ------------------ WLR BASICS ------------------ //
wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop;
wlr_backend* m_sWLRBackend;
wlr_session* m_sWLRSession;
wlr_renderer* m_sWLRRenderer;
wlr_allocator* m_sWLRAllocator;
wlr_compositor* m_sWLRCompositor;
wlr_subcompositor* m_sWLRSubCompositor;
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
wlr_backend* m_sWLRHeadlessBackend;
// ------------------------------------------------- //
wl_display* m_sWLDisplay;
wl_event_loop* m_sWLEventLoop;
int m_iDRMFD = -1;
bool m_bInitialized = false;
SP<Aquamarine::CBackend> m_pAqBackend;
std::string m_szHyprTempDataRoot = "";
@ -116,8 +108,8 @@ class CCompositor {
SP<CWLSurfaceResource> vectorToLayerPopupSurface(const Vector2D&, CMonitor* monitor, Vector2D*, PHLLS*);
SP<CWLSurfaceResource> vectorWindowToSurface(const Vector2D&, PHLWINDOW, Vector2D& sl);
Vector2D vectorToSurfaceLocal(const Vector2D&, PHLWINDOW, SP<CWLSurfaceResource>);
CMonitor* getMonitorFromOutput(wlr_output*);
CMonitor* getRealMonitorFromOutput(wlr_output*);
CMonitor* getMonitorFromOutput(SP<Aquamarine::IOutput>);
CMonitor* getRealMonitorFromOutput(SP<Aquamarine::IOutput>);
PHLWINDOW getWindowFromSurface(SP<CWLSurfaceResource>);
PHLWINDOW getWindowFromHandle(uint32_t);
bool isWorkspaceVisible(PHLWORKSPACE);
@ -182,6 +174,7 @@ class CCompositor {
void setPreferredTransformForSurface(SP<CWLSurfaceResource> pSurface, wl_output_transform transform);
void updateSuspendedStates();
PHLWINDOW windowForCPointer(CWindow*);
void onNewMonitor(SP<Aquamarine::IOutput> output);
std::string explicitConfigPath;

View file

@ -1285,7 +1285,7 @@ void CConfigManager::dispatchExecOnce() {
return;
// update dbus env
if (g_pCompositor->m_sWLRSession)
if (g_pCompositor->m_pAqBackend->hasSession())
handleRawExec("",
#ifdef USES_SYSTEMD
"systemctl --user import-environment DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP QT_QPA_PLATFORMTHEME PATH XDG_DATA_DIRS && hash "
@ -1410,7 +1410,8 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
if (USEVRR == 0) {
if (m->vrrActive) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
m->output->state->setAdaptiveSync(false);
if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);
@ -1419,11 +1420,11 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
return;
} else if (USEVRR == 1) {
if (!m->vrrActive) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
m->output->state->setAdaptiveSync(true);
if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
m->output->state->setAdaptiveSync(false);
}
if (!m->state.commit())
@ -1442,19 +1443,19 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL;
if (WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_DISABLED) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 1);
if (WORKSPACEFULL) {
m->output->state->setAdaptiveSync(true);
if (!m->state.test()) {
Debug::log(LOG, "Pending output {} does not accept VRR.", m->output->name);
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
m->output->state->setAdaptiveSync(false);
}
if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL && m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED) {
wlr_output_state_set_adaptive_sync_enabled(m->state.wlr(), 0);
} else if (!WORKSPACEFULL) {
m->output->state->setAdaptiveSync(false);
if (!m->state.commit())
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> false", m->output->name);

View file

@ -20,6 +20,7 @@
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
#include <aquamarine/input/Input.hpp>
#include "../config/ConfigDataValues.hpp"
#include "../config/ConfigValue.hpp"
@ -53,18 +54,11 @@ static std::string formatToString(uint32_t drmFormat) {
static std::string availableModesForOutput(CMonitor* pMonitor, eHyprCtlOutputFormat format) {
std::string result;
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
wl_list_for_each(mode, &pMonitor->output->modes, link) {
if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", mode->width, mode->height, mode->refresh / 1000.0);
else
result += std::format("\"{}x{}@{:.2f}Hz\",", mode->width, mode->height, mode->refresh / 1000.0);
}
result.pop_back();
for (auto& m : pMonitor->output->modes) {
if (format == FORMAT_NORMAL)
result += std::format("{}x{}@{:.2f}Hz ", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
else
result += std::format("\"{}x{}@{:.2f}Hz\",", m->pixelSize.x, m->pixelSize.y, m->refreshRate / 1000.0);
}
return result;
@ -75,8 +69,11 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
if (!m->output || m->ID == -1ull)
return "";
result += std::format(
R"#({{
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
result += std::format(
R"#({{
"id": {},
"name": "{}",
"description": "{}",
@ -107,54 +104,28 @@ std::string CHyprCtl::getMonitorData(Hyprutils::Memory::CSharedPointer<CMonitor>
"currentFormat": "{}",
"availableModes": [{}]
}},)#",
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make ? m->output->make : ""),
escapeJSONStrings(m->output->model ? m->output->model : ""), escapeJSONStrings(m->output->serial ? m->output->serial : ""), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y,
m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)),
m->activeSpecialWorkspaceID(), escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "true" : "false"), (m->dpmsStatus ? "true" : "false"),
(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"),
(m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
return result;
}
std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
CVarList vars(request, 0, ' ');
auto allMonitors = false;
if (vars.size() > 2)
return "too many args";
if (vars.size() == 2 && vars[1] == "all")
allMonitors = true;
std::string result = "";
if (format == eHyprCtlOutputFormat::FORMAT_JSON) {
result += "[";
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
result += CHyprCtl::getMonitorData(m, format);
}
m->ID, escapeJSONStrings(m->szName), escapeJSONStrings(m->szShortDescription), escapeJSONStrings(m->output->make), escapeJSONStrings(m->output->model),
escapeJSONStrings(m->output->serial), (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y,
m->activeWorkspaceID(), (!m->activeWorkspace ? "" : escapeJSONStrings(m->activeWorkspace->m_szName)), m->activeSpecialWorkspaceID(),
escapeJSONStrings(m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y,
(int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform, (m == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(m->dpmsStatus ? "true" : "false"), (m->output->state->state().adaptiveSync ? "true" : "false"), (m->tearingState.activelyTearing ? "true" : "false"),
(m->m_bEnabled ? "false" : "true"), formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
trimTrailingComma(result);
result += "]";
} else {
for (auto& m : allMonitors ? g_pCompositor->m_vRealMonitors : g_pCompositor->m_vMonitors) {
if (!m->output || m->ID == -1ull)
continue;
result += std::format(
"Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
(m->output->make ? m->output->make : ""), (m->output->model ? m->output->model : ""), (m->output->serial ? m->output->serial : ""), m->activeWorkspaceID(),
(!m->activeWorkspace ? "" : m->activeWorkspace->m_szName), m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""),
(int)m->vecReservedTopLeft.x, (int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED),
m->tearingState.activelyTearing, !m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
}
result += std::format("Monitor {} (ID {}):\n\t{}x{}@{:.5f} at {}x{}\n\tdescription: {}\n\tmake: {}\n\tmodel: {}\n\tserial: {}\n\tactive workspace: {} ({})\n\t"
"special workspace: {} ({})\n\treserved: {} {} {} {}\n\tscale: {:.2f}\n\ttransform: {}\n\tfocused: {}\n\t"
"dpmsStatus: {}\n\tvrr: {}\n\tactivelyTearing: {}\n\tdisabled: {}\n\tcurrentFormat: {}\n\tavailableModes: {}\n\n",
m->szName, m->ID, (int)m->vecPixelSize.x, (int)m->vecPixelSize.y, m->refreshRate, (int)m->vecPosition.x, (int)m->vecPosition.y, m->szShortDescription,
m->output->make, m->output->model, m->output->serial, m->activeWorkspaceID(), (!m->activeWorkspace ? "" : m->activeWorkspace->m_szName),
m->activeSpecialWorkspaceID(), (m->activeSpecialWorkspace ? m->activeSpecialWorkspace->m_szName : ""), (int)m->vecReservedTopLeft.x,
(int)m->vecReservedTopLeft.y, (int)m->vecReservedBottomRight.x, (int)m->vecReservedBottomRight.y, m->scale, (int)m->transform,
(m == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, m->output->state->state().adaptiveSync, m->tearingState.activelyTearing,
!m->m_bEnabled, formatToString(m->drmFormat), availableModesForOutput(m.get(), format));
}
return result;
@ -552,8 +523,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
"defaultSpeed": {:.5f}
}},)#",
(uintptr_t)m.get(), escapeJSONStrings(m->hlName),
wlr_input_device_is_libinput(&m->wlr()->base) ? libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) :
0.f);
m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f);
}
trimTrailingComma(result);
@ -654,9 +624,7 @@ std::string devicesRequest(eHyprCtlOutputFormat format, std::string request) {
for (auto& m : g_pInputManager->m_vPointers) {
result += std::format("\tMouse at {:x}:\n\t\t{}\n\t\t\tdefault speed: {:.5f}\n", (uintptr_t)m.get(), m->hlName,
(wlr_input_device_is_libinput(&m->wlr()->base) ?
libinput_device_config_accel_get_default_speed((libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base)) :
0.f));
(m->aq() && m->aq()->getLibinputHandle() ? libinput_device_config_accel_get_default_speed(m->aq()->getLibinputHandle()) : 0.f));
}
result += "\n\nKeyboards:\n";
@ -1125,24 +1093,22 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
if (PKEYBOARD == g_pInputManager->m_vKeyboards.end())
return "device not found";
const auto PWLRKEYBOARD = (*PKEYBOARD)->wlr();
const auto LAYOUTS = xkb_keymap_num_layouts(PWLRKEYBOARD->keymap);
const auto KEEB = *PKEYBOARD;
const auto LAYOUTS = xkb_keymap_num_layouts(KEEB->xkbKeymap);
xkb_layout_index_t activeLayout = 0;
while (activeLayout < LAYOUTS) {
if (xkb_state_layout_index_is_active(PWLRKEYBOARD->xkb_state, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1)
if (xkb_state_layout_index_is_active(KEEB->xkbTranslationState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1)
break;
activeLayout++;
}
if (CMD == "next") {
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked,
activeLayout > LAYOUTS ? 0 : activeLayout + 1);
} else if (CMD == "prev") {
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked,
activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
} else {
if (CMD == "next")
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout > LAYOUTS ? 0 : activeLayout + 1);
else if (CMD == "prev")
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, activeLayout == 0 ? LAYOUTS - 1 : activeLayout - 1);
else {
int requestedLayout = 0;
try {
requestedLayout = std::stoi(CMD);
@ -1152,7 +1118,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
return "layout idx out of range of " + std::to_string(LAYOUTS);
}
wlr_keyboard_notify_modifiers(PWLRKEYBOARD, PWLRKEYBOARD->modifiers.depressed, PWLRKEYBOARD->modifiers.latched, PWLRKEYBOARD->modifiers.locked, requestedLayout);
KEEB->updateModifiers(KEEB->modifiersState.depressed, KEEB->modifiersState.latched, KEEB->modifiersState.locked, requestedLayout);
}
return "ok";
@ -1368,26 +1334,26 @@ std::string decorationRequest(eHyprCtlOutputFormat format, std::string request)
return result;
}
static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) {
wlr_output* output = nullptr;
// static bool addOutput(wlr_backend* backend, const std::string& type, const std::string& name) {
// wlr_output* output = nullptr;
if (type.empty() || type == "auto") {
if (wlr_backend_is_wl(backend))
output = wlr_wl_output_create(backend);
else if (wlr_backend_is_headless(backend))
output = wlr_headless_add_output(backend, 1920, 1080);
} else {
if (wlr_backend_is_wl(backend) && type == "wayland")
output = wlr_wl_output_create(backend);
else if (wlr_backend_is_headless(backend) && type == "headless")
output = wlr_headless_add_output(backend, 1920, 1080);
}
// if (type.empty() || type == "auto") {
// if (wlr_backend_is_wl(backend))
// output = wlr_wl_output_create(backend);
// else if (wlr_backend_is_headless(backend))
// output = wlr_headless_add_output(backend, 1920, 1080);
// } else {
// if (wlr_backend_is_wl(backend) && type == "wayland")
// output = wlr_wl_output_create(backend);
// else if (wlr_backend_is_headless(backend) && type == "headless")
// output = wlr_headless_add_output(backend, 1920, 1080);
// }
if (output && !name.empty())
g_pCompositor->getMonitorFromOutput(output)->szName = name;
// if (output && !name.empty())
// g_pCompositor->getMonitorFromOutput(output)->szName = name;
return output != nullptr;
}
// return output != nullptr;
// }
struct outputData {
std::string type;
@ -1401,8 +1367,8 @@ void createOutputIter(wlr_backend* backend, void* data) {
if (DATA->added)
return;
if (addOutput(backend, DATA->type, DATA->name))
DATA->added = true;
// if (addOutput(backend, DATA->type, DATA->name))
// DATA->added = true;
}
std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
@ -1413,13 +1379,15 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
const auto MODE = vars[1];
// FIXME:
if (MODE == "create" || MODE == "add") {
if (g_pCompositor->getMonitorFromName(vars[3]))
return "A real monitor already uses that name.";
outputData result{vars[2], vars[3], false};
wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
// wlr_multi_for_each_backend(g_pCompositor->m_sWLRBackend, createOutputIter, &result);
if (!result.added)
return "no backend replied to the request";
@ -1433,7 +1401,7 @@ std::string dispatchOutput(eHyprCtlOutputFormat format, std::string request) {
if (!PMONITOR->createdByUser)
return "cannot remove a real display. Use the monitor keyword.";
wlr_output_destroy(PMONITOR->output);
//wlr_output_destroy(PMONITOR->output);
}
return "ok";

View file

@ -2,7 +2,16 @@
#include "../defines.hpp"
#include "../helpers/varlist/VarList.hpp"
#include "../managers/input/InputManager.hpp"
#include <sys/mman.h>
#include <aquamarine/input/Input.hpp>
constexpr static std::array<const char*, 8> MODNAMES = {
XKB_MOD_NAME_SHIFT, XKB_MOD_NAME_CAPS, XKB_MOD_NAME_CTRL, XKB_MOD_NAME_ALT, XKB_MOD_NAME_NUM, "Mod3", XKB_MOD_NAME_LOGO, "Mod5",
};
constexpr static std::array<const char*, 3> LEDNAMES = {XKB_LED_NAME_NUM, XKB_LED_NAME_CAPS, XKB_LED_NAME_SCROLL};
//
uint32_t IKeyboard::getCapabilities() {
return HID_INPUT_CAPABILITY_KEYBOARD;
}
@ -14,11 +23,130 @@ eHIDType IKeyboard::getType() {
IKeyboard::~IKeyboard() {
events.destroy.emit();
if (!xkbTranslationState)
return;
clearManuallyAllocd();
}
xkb_state_unref(xkbTranslationState);
void IKeyboard::clearManuallyAllocd() {
if (xkbTranslationState)
xkb_state_unref(xkbTranslationState);
if (xkbInternalTranslationState)
xkb_state_unref(xkbInternalTranslationState);
if (xkbKeymap)
xkb_keymap_unref(xkbKeymap);
if (xkbKeymapFD >= 0)
close(xkbKeymapFD);
xkbKeymap = nullptr;
xkbTranslationState = nullptr;
xkbKeymapFD = -1;
}
void IKeyboard::setKeymap(const SStringRuleNames& rules) {
currentRules = rules;
xkb_rule_names XKBRULES = {
.rules = rules.rules.c_str(),
.model = rules.model.c_str(),
.layout = rules.layout.c_str(),
.variant = rules.variant.c_str(),
.options = rules.options.c_str(),
};
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!CONTEXT) {
Debug::log(ERR, "setKeymap: CONTEXT null??");
return;
}
clearManuallyAllocd();
Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
if (!xkbFilePath.empty()) {
auto path = absolutePath(xkbFilePath, g_pConfigManager->configCurrentPath);
if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE)
Debug::log(ERR, "Cannot open input:kb_file= file for reading");
else {
xkbKeymap = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(KEYMAPFILE);
}
}
if (!xkbKeymap)
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!xkbKeymap) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + rules.rules + ", model: " + rules.model + ", variant: " + rules.variant +
", options: " + rules.options + ", layout: " + rules.layout + " )");
Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
memset(&XKBRULES, 0, sizeof(XKBRULES));
currentRules.rules = "";
currentRules.model = "";
currentRules.variant = "";
currentRules.options = "";
currentRules.layout = "us";
xkbKeymap = xkb_keymap_new_from_names(CONTEXT, &XKBRULES, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
// set internal translation state
// demo sunao ni ienai
xkbInternalTranslationState = xkb_state_new(xkbKeymap);
updateXKBTranslationState();
const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
if (NUMLOCKON == 1) {
// lock numlock
const auto IDX = xkb_map_mod_get_index(xkbKeymap, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID)
modifiersState.locked |= (uint32_t)1 << IDX;
}
if (modifiersState.locked != 0)
keyboardEvents.modifiers.emit(SModifiersEvent{.locked = modifiersState.locked});
for (size_t i = 0; i < LEDNAMES.size(); ++i) {
ledIndexes.at(i) = xkb_map_led_get_index(xkbKeymap, LEDNAMES.at(i));
Debug::log(LOG, "xkb: LED index {} (name {}) got index {}", i, LEDNAMES.at(i), modIndexes.at(i));
}
for (size_t i = 0; i < MODNAMES.size(); ++i) {
modIndexes.at(i) = xkb_map_mod_get_index(xkbKeymap, MODNAMES.at(i));
Debug::log(LOG, "xkb: Mod index {} (name {}) got index {}", i, MODNAMES.at(i), modIndexes.at(i));
}
auto cKeymapStr = xkb_keymap_get_as_string(xkbKeymap, XKB_KEYMAP_FORMAT_TEXT_V1);
xkbKeymapString = cKeymapStr;
free(cKeymapStr);
int rw, ro;
if (!allocateSHMFilePair(xkbKeymapString.length() + 1, &rw, &ro))
Debug::log(ERR, "IKeyboard: failed to allocate shm pair for the keymap");
else {
auto keymapFDDest = mmap(nullptr, xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, rw, 0);
close(rw);
if (keymapFDDest == MAP_FAILED) {
Debug::log(ERR, "IKeyboard: failed to mmap a shm pair for the keymap");
close(ro);
} else {
memcpy(keymapFDDest, xkbKeymapString.c_str(), xkbKeymapString.length());
munmap(keymapFDDest, xkbKeymapString.length() + 1);
xkbKeymapFD = ro;
}
}
xkb_context_unref(CONTEXT);
}
void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
@ -32,9 +160,8 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
return;
}
const auto WLRKB = wlr();
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto KEYMAP = xkbKeymap;
const auto STATE = xkbInternalTranslationState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@ -101,9 +228,8 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
}
std::string IKeyboard::getActiveLayout() {
const auto WLRKB = wlr();
const auto KEYMAP = WLRKB->keymap;
const auto STATE = WLRKB->xkb_state;
const auto KEYMAP = xkbKeymap;
const auto STATE = xkbTranslationState;
const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
@ -120,14 +246,12 @@ std::string IKeyboard::getActiveLayout() {
}
void IKeyboard::updateLEDs() {
auto keyboard = wlr();
if (!keyboard || keyboard->xkb_state == nullptr)
if (xkbTranslationState == nullptr)
return;
uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i]))
if (xkb_state_led_index_is_active(xkbTranslationState, ledIndexes.at(i)))
leds |= (1 << i);
}
@ -135,13 +259,62 @@ void IKeyboard::updateLEDs() {
}
void IKeyboard::updateLEDs(uint32_t leds) {
auto keyboard = wlr();
if (!keyboard || keyboard->xkb_state == nullptr)
if (!xkbTranslationState)
return;
if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock()))
return;
wlr_keyboard_led_update(keyboard, leds);
if (!aq())
return;
aq()->updateLEDs(leds);
}
uint32_t IKeyboard::getModifiers() {
uint32_t modMask = modifiersState.depressed | modifiersState.latched;
uint32_t mods = 0;
for (size_t i = 0; i < modIndexes.size(); ++i) {
if (modIndexes.at(i) == XKB_MOD_INVALID)
continue;
if (!(modMask & (1 << modIndexes.at(i))))
continue;
mods |= (1 << i);
}
return mods;
}
void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
if (!xkbTranslationState)
return;
xkb_state_update_mask(xkbTranslationState, depressed, latched, locked, 0, 0, group);
if (!updateModifiersState())
return;
updateLEDs();
}
bool IKeyboard::updateModifiersState() {
if (!xkbTranslationState)
return false;
auto depressed = xkb_state_serialize_mods(xkbTranslationState, XKB_STATE_MODS_DEPRESSED);
auto latched = xkb_state_serialize_mods(xkbTranslationState, XKB_STATE_MODS_LATCHED);
auto locked = xkb_state_serialize_mods(xkbTranslationState, XKB_STATE_MODS_LOCKED);
auto group = xkb_state_serialize_layout(xkbTranslationState, XKB_STATE_LAYOUT_EFFECTIVE);
if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group)
return false;
modifiersState.depressed = depressed;
modifiersState.latched = latched;
modifiersState.locked = locked;
modifiersState.group = group;
return true;
}

View file

@ -7,15 +7,15 @@
#include <xkbcommon/xkbcommon.h>
struct wlr_keyboard;
AQUAMARINE_FORWARD(IKeyboard);
class IKeyboard : public IHID {
public:
virtual ~IKeyboard();
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual wlr_keyboard* wlr() = 0;
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual SP<Aquamarine::IKeyboard> aq() = 0;
struct SKeyEvent {
uint32_t timeMs = 0;
@ -24,6 +24,17 @@ class IKeyboard : public IHID {
wl_keyboard_key_state state = WL_KEYBOARD_KEY_STATE_PRESSED;
};
struct SKeymapEvent {
xkb_keymap* keymap = nullptr;
};
struct SModifiersEvent {
uint32_t depressed = 0;
uint32_t latched = 0;
uint32_t locked = 0;
uint32_t group = 0;
};
struct {
CSignal key;
CSignal modifiers;
@ -39,25 +50,43 @@ class IKeyboard : public IHID {
std::string rules = "";
};
void setKeymap(const SStringRuleNames& rules);
void updateXKBTranslationState(xkb_keymap* const keymap = nullptr);
std::string getActiveLayout();
void updateLEDs();
void updateLEDs(uint32_t leds);
uint32_t getModifiers();
void updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
bool active = false;
bool enabled = true;
xkb_layout_index_t activeLayout = 0;
xkb_state* xkbTranslationState = nullptr;
xkb_state * xkbTranslationState = nullptr, *xkbInternalTranslationState = nullptr;
xkb_keymap* xkbKeymap = nullptr;
std::string hlName = "";
std::string xkbFilePath = "";
struct {
uint32_t depressed = 0, latched = 0, locked = 0, group = 0;
} modifiersState;
SStringRuleNames currentRules;
int repeatRate = 0;
int repeatDelay = 0;
int numlockOn = -1;
bool resolveBindsBySym = false;
std::array<xkb_led_index_t, 3> ledIndexes;
std::array<xkb_mod_index_t, 8> modIndexes;
uint32_t leds = 0;
WP<IKeyboard> self;
std::string hlName = "";
std::string xkbFilePath = "";
std::string xkbKeymapString = "";
int xkbKeymapFD = -1;
SStringRuleNames currentRules;
int repeatRate = 0;
int repeatDelay = 0;
int numlockOn = -1;
bool resolveBindsBySym = false;
WP<IKeyboard> self;
private:
void clearManuallyAllocd();
bool updateModifiersState(); // rets whether changed
};

View file

@ -5,17 +5,17 @@
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"
struct wlr_pointer;
AQUAMARINE_FORWARD(IPointer);
/*
Base class for a pointer.
*/
class IPointer : public IHID {
public:
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual wlr_pointer* wlr() = 0;
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual SP<Aquamarine::IPointer> aq() = 0;
struct SMotionEvent {
uint32_t timeMs = 0;

View file

@ -5,14 +5,14 @@
#include "../macros.hpp"
#include "../helpers/math/Math.hpp"
struct wlr_touch;
AQUAMARINE_FORWARD(ITouch);
class ITouch : public IHID {
public:
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual wlr_touch* wlr() = 0;
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual SP<Aquamarine::ITouch> aq() = 0;
struct SDownEvent {
uint32_t timeMs = 0;

View file

@ -1,7 +1,9 @@
#include "Keyboard.hpp"
#include "../defines.hpp"
SP<CKeyboard> CKeyboard::create(wlr_keyboard* keeb) {
#include <aquamarine/input/Input.hpp>
SP<CKeyboard> CKeyboard::create(SP<Aquamarine::IKeyboard> keeb) {
SP<CKeyboard> pKeeb = SP<CKeyboard>(new CKeyboard(keeb));
pKeeb->self = pKeeb;
@ -13,52 +15,41 @@ bool CKeyboard::isVirtual() {
return false;
}
wlr_keyboard* CKeyboard::wlr() {
return keyboard;
SP<Aquamarine::IKeyboard> CKeyboard::aq() {
return keyboard.lock();
}
CKeyboard::CKeyboard(wlr_keyboard* keeb) : keyboard(keeb) {
CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
if (!keeb)
return;
// clang-format off
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
keyboard = nullptr;
events.destroy.emit();
}, this, "CKeyboard");
listeners.destroy = keeb->events.destroy.registerListener([this](std::any d) {
keyboard.reset();
events.destroy.emit();
});
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) {
auto E = (wlr_keyboard_key_event*)data;
listeners.key = keeb->events.key.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
keyboardEvents.key.emit(SKeyEvent{
.timeMs = E->time_msec,
.keycode = E->keycode,
.updateMods = E->update_state,
.state = E->state,
.timeMs = E.timeMs,
.keycode = E.key,
.state = E.pressed ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED,
});
}, this, "CKeyboard");
});
hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) {
keyboardEvents.keymap.emit();
}, this, "CKeyboard");
listeners.modifiers = keeb->events.modifiers.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IKeyboard::SModifiersEvent>(d);
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) {
keyboardEvents.modifiers.emit();
}, this, "CKeyboard");
updateModifiers(E.depressed, E.latched, E.locked, E.group);
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) {
keyboardEvents.repeatInfo.emit();
}, this, "CKeyboard");
// clang-format on
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,
.locked = modifiersState.locked,
.group = modifiersState.group,
});
});
deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN";
}
void CKeyboard::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_key.removeCallback();
hyprListener_keymap.removeCallback();
hyprListener_repeatInfo.removeCallback();
hyprListener_modifiers.removeCallback();
deviceName = keeb->getName();
}

View file

@ -4,21 +4,19 @@
class CKeyboard : public IKeyboard {
public:
static SP<CKeyboard> create(wlr_keyboard* keeb);
static SP<CKeyboard> create(SP<Aquamarine::IKeyboard> keeb);
virtual bool isVirtual();
virtual wlr_keyboard* wlr();
virtual bool isVirtual();
virtual SP<Aquamarine::IKeyboard> aq();
private:
CKeyboard(wlr_keyboard* keeb);
CKeyboard(SP<Aquamarine::IKeyboard> keeb);
wlr_keyboard* keyboard = nullptr;
WP<Aquamarine::IKeyboard> keyboard;
void disconnectCallbacks();
DYNLISTENER(destroy);
DYNLISTENER(key);
DYNLISTENER(modifiers);
DYNLISTENER(keymap);
DYNLISTENER(repeatInfo);
struct {
CHyprSignalListener destroy;
CHyprSignalListener key;
CHyprSignalListener modifiers;
} listeners;
};

View file

@ -1,7 +1,8 @@
#include "Mouse.hpp"
#include "../defines.hpp"
#include <aquamarine/input/Input.hpp>
SP<CMouse> CMouse::create(wlr_pointer* mouse) {
SP<CMouse> CMouse::create(SP<Aquamarine::IPointer> mouse) {
SP<CMouse> pMouse = SP<CMouse>(new CMouse(mouse));
pMouse->self = pMouse;
@ -9,166 +10,143 @@ SP<CMouse> CMouse::create(wlr_pointer* mouse) {
return pMouse;
}
CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) {
CMouse::CMouse(SP<Aquamarine::IPointer> mouse_) : mouse(mouse_) {
if (!mouse)
return;
// clang-format off
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
mouse = nullptr;
listeners.destroy = mouse->events.destroy.registerListener([this](std::any d) {
mouse.reset();
events.destroy.emit();
}, this, "CMouse");
});
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) {
auto E = (wlr_pointer_motion_event*)data;
listeners.motion = mouse->events.move.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SMoveEvent>(d);
pointerEvents.motion.emit(SMotionEvent{
.timeMs = E->time_msec,
.delta = {E->delta_x, E->delta_y},
.unaccel = {E->unaccel_dx, E->unaccel_dy},
.timeMs = E.timeMs,
.delta = E.delta,
.unaccel = E.unaccel,
});
}, this, "CMouse");
});
hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) {
auto E = (wlr_pointer_motion_absolute_event*)data;
listeners.motionAbsolute = mouse->events.warp.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SWarpEvent>(d);
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec,
.absolute = {E->x, E->y},
.timeMs = E.timeMs,
.absolute = E.absolute,
.device = self.lock(),
});
}, this, "CMouse");
});
hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) {
auto E = (wlr_pointer_button_event*)data;
listeners.button = mouse->events.button.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SButtonEvent>(d);
pointerEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec,
.button = E->button,
.state = (wl_pointer_button_state)E->state,
.timeMs = E.timeMs,
.button = E.button,
.state = E.pressed ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED,
});
}, this, "CMouse");
});
hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) {
auto E = (wlr_pointer_axis_event*)data;
listeners.axis = mouse->events.axis.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SAxisEvent>(d);
pointerEvents.axis.emit(SAxisEvent{
.timeMs = E->time_msec,
.source = E->source,
.axis = E->orientation,
.relativeDirection = E->relative_direction,
.delta = E->delta,
.deltaDiscrete = E->delta_discrete,
.timeMs = E.timeMs,
.source = (wl_pointer_axis_source)E.source,
.axis = (wl_pointer_axis)E.axis,
.relativeDirection = (wl_pointer_axis_relative_direction)E.direction,
.delta = E.delta,
.deltaDiscrete = E.discrete,
});
}, this, "CMouse");
});
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) {
pointerEvents.frame.emit();
}, this, "CMouse");
listeners.frame = mouse->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_begin_event*)data;
listeners.swipeBegin = mouse->events.swipeBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeBeginEvent>(d);
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.timeMs = E.timeMs,
.fingers = E.fingers,
});
}, this, "CMouse");
});
hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_end_event*)data;
listeners.swipeEnd = mouse->events.swipeEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeEndEvent>(d);
pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
.timeMs = E.timeMs,
.cancelled = E.cancelled,
});
}, this, "CMouse");
});
hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_update_event*)data;
listeners.swipeUpdate = mouse->events.swipeUpdate.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SSwipeUpdateEvent>(d);
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
.timeMs = E.timeMs,
.fingers = E.fingers,
.delta = E.delta,
});
}, this, "CMouse");
});
hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_begin_event*)data;
listeners.pinchBegin = mouse->events.pinchBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchBeginEvent>(d);
pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.timeMs = E.timeMs,
.fingers = E.fingers,
});
}, this, "CMouse");
});
hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_end_event*)data;
listeners.pinchEnd = mouse->events.pinchEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchEndEvent>(d);
pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
.timeMs = E.timeMs,
.cancelled = E.cancelled,
});
}, this, "CMouse");
});
hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_update_event*)data;
listeners.pinchUpdate = mouse->events.pinchUpdate.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SPinchUpdateEvent>(d);
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
.scale = E->scale,
.rotation = E->rotation,
.timeMs = E.timeMs,
.fingers = E.fingers,
.delta = E.delta,
.scale = E.scale,
.rotation = E.rotation,
});
}, this, "CMouse");
});
hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_begin_event*)data;
listeners.holdBegin = mouse->events.holdBegin.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SHoldBeginEvent>(d);
pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.timeMs = E.timeMs,
.fingers = E.fingers,
});
}, this, "CMouse");
});
hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_end_event*)data;
listeners.holdEnd = mouse->events.holdEnd.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::IPointer::SHoldEndEvent>(d);
pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
.timeMs = E.timeMs,
.cancelled = E.cancelled,
});
}, this, "CMouse");
});
// clang-format on
deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN";
}
void CMouse::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_motion.removeCallback();
hyprListener_motionAbsolute.removeCallback();
hyprListener_button.removeCallback();
hyprListener_axis.removeCallback();
hyprListener_frame.removeCallback();
hyprListener_swipeBegin.removeCallback();
hyprListener_swipeEnd.removeCallback();
hyprListener_swipeUpdate.removeCallback();
hyprListener_pinchBegin.removeCallback();
hyprListener_pinchEnd.removeCallback();
hyprListener_pinchUpdate.removeCallback();
hyprListener_holdBegin.removeCallback();
hyprListener_holdEnd.removeCallback();
deviceName = mouse->getName();
}
bool CMouse::isVirtual() {
return false;
}
wlr_pointer* CMouse::wlr() {
return mouse;
SP<Aquamarine::IPointer> CMouse::aq() {
return mouse.lock();
}

View file

@ -4,33 +4,34 @@
class CMouse : public IPointer {
public:
static SP<CMouse> create(wlr_pointer* mouse);
static SP<CMouse> create(SP<Aquamarine::IPointer> mouse);
virtual bool isVirtual();
virtual wlr_pointer* wlr();
virtual bool isVirtual();
virtual SP<Aquamarine::IPointer> aq();
private:
CMouse(wlr_pointer* mouse);
CMouse(SP<Aquamarine::IPointer> mouse);
wlr_pointer* mouse = nullptr;
WP<Aquamarine::IPointer> mouse;
void disconnectCallbacks();
struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy);
DYNLISTENER(motion);
DYNLISTENER(motionAbsolute);
DYNLISTENER(button);
DYNLISTENER(axis);
DYNLISTENER(frame);
CHyprSignalListener motion;
CHyprSignalListener motionAbsolute;
CHyprSignalListener button;
CHyprSignalListener axis;
CHyprSignalListener frame;
DYNLISTENER(swipeBegin);
DYNLISTENER(swipeEnd);
DYNLISTENER(swipeUpdate);
CHyprSignalListener swipeBegin;
CHyprSignalListener swipeEnd;
CHyprSignalListener swipeUpdate;
DYNLISTENER(pinchBegin);
DYNLISTENER(pinchEnd);
DYNLISTENER(pinchUpdate);
CHyprSignalListener pinchBegin;
CHyprSignalListener pinchEnd;
CHyprSignalListener pinchUpdate;
DYNLISTENER(holdBegin);
DYNLISTENER(holdEnd);
CHyprSignalListener holdBegin;
CHyprSignalListener holdEnd;
} listeners;
};

View file

@ -1,7 +1,8 @@
#include "TouchDevice.hpp"
#include "../defines.hpp"
#include <aquamarine/input/Input.hpp>
SP<CTouchDevice> CTouchDevice::create(wlr_touch* touch) {
SP<CTouchDevice> CTouchDevice::create(SP<Aquamarine::ITouch> touch) {
SP<CTouchDevice> pTouch = SP<CTouchDevice>(new CTouchDevice(touch));
pTouch->self = pTouch;
@ -9,78 +10,63 @@ SP<CTouchDevice> CTouchDevice::create(wlr_touch* touch) {
return pTouch;
}
CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) {
CTouchDevice::CTouchDevice(SP<Aquamarine::ITouch> touch_) : touch(touch_) {
if (!touch)
return;
// clang-format off
hyprListener_destroy.initCallback(&touch->base.events.destroy, [this] (void* owner, void* data) {
listeners.destroy = touch->events.destroy.registerListener([this](std::any d) {
events.destroy.emit();
disconnectCallbacks();
touch = nullptr;
}, this, "CTouchDevice");
touch.reset();
});
hyprListener_down.initCallback(&touch->events.down, [this] (void* owner, void* data) {
auto E = (wlr_touch_down_event*)data;
listeners.down = touch->events.down.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SDownEvent>(d);
touchEvents.down.emit(SDownEvent{
.timeMs = E->time_msec,
.touchID = E->touch_id,
.pos = {E->x, E->y},
.timeMs = E.timeMs,
.touchID = E.touchID,
.pos = E.pos,
.device = self.lock(),
});
}, this, "CTouchDevice");
});
hyprListener_up.initCallback(&touch->events.up, [this] (void* owner, void* data) {
auto E = (wlr_touch_up_event*)data;
listeners.up = touch->events.up.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SUpEvent>(d);
touchEvents.up.emit(SUpEvent{
.timeMs = E->time_msec,
.touchID = E->touch_id
.timeMs = E.timeMs,
.touchID = E.touchID,
});
}, this, "CTouchDevice");
});
hyprListener_motion.initCallback(&touch->events.motion, [this] (void* owner, void* data) {
auto E = (wlr_touch_motion_event*)data;
listeners.motion = touch->events.move.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SMotionEvent>(d);
touchEvents.motion.emit(SMotionEvent{
.timeMs = E->time_msec,
.touchID = E->touch_id,
.pos = {E->x, E->y},
.timeMs = E.timeMs,
.touchID = E.touchID,
.pos = E.pos,
});
}, this, "CTouchDevice");
});
hyprListener_cancel.initCallback(&touch->events.cancel, [this] (void* owner, void* data) {
auto E = (wlr_touch_cancel_event*)data;
listeners.cancel = touch->events.cancel.registerListener([this](std::any d) {
auto E = std::any_cast<Aquamarine::ITouch::SCancelEvent>(d);
touchEvents.cancel.emit(SCancelEvent{
.timeMs = E->time_msec,
.touchID = E->touch_id
.timeMs = E.timeMs,
.touchID = E.touchID,
});
}, this, "CTouchDevice");
});
hyprListener_frame.initCallback(&touch->events.frame, [this] (void* owner, void* data) {
touchEvents.frame.emit();
}, this, "CTouchDevice");
listeners.frame = touch->events.frame.registerListener([this](std::any d) { touchEvents.frame.emit(); });
// clang-format on
deviceName = touch->base.name ? touch->base.name : "UNKNOWN";
deviceName = touch->getName();
}
bool CTouchDevice::isVirtual() {
return false;
}
wlr_touch* CTouchDevice::wlr() {
return touch;
}
void CTouchDevice::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_down.removeCallback();
hyprListener_up.removeCallback();
hyprListener_motion.removeCallback();
hyprListener_cancel.removeCallback();
hyprListener_frame.removeCallback();
SP<Aquamarine::ITouch> CTouchDevice::aq() {
return touch.lock();
}

View file

@ -4,22 +4,22 @@
class CTouchDevice : public ITouch {
public:
static SP<CTouchDevice> create(wlr_touch* touch);
static SP<CTouchDevice> create(SP<Aquamarine::ITouch> touch);
virtual bool isVirtual();
virtual wlr_touch* wlr();
virtual bool isVirtual();
virtual SP<Aquamarine::ITouch> aq();
private:
CTouchDevice(wlr_touch* touch);
CTouchDevice(SP<Aquamarine::ITouch> touch);
wlr_touch* touch = nullptr;
WP<Aquamarine::ITouch> touch;
void disconnectCallbacks();
DYNLISTENER(destroy);
DYNLISTENER(down);
DYNLISTENER(up);
DYNLISTENER(motion);
DYNLISTENER(cancel);
DYNLISTENER(frame);
struct {
CHyprSignalListener destroy;
CHyprSignalListener down;
CHyprSignalListener up;
CHyprSignalListener motion;
CHyprSignalListener cancel;
CHyprSignalListener frame;
} listeners;
};

View file

@ -14,58 +14,37 @@ CVirtualKeyboard::CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb_) : keybo
if (!keeb_)
return;
auto keeb = keeb_->wlr();
// clang-format off
hyprListener_destroy.initCallback(&keeb->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
listeners.destroy = keeb_->events.destroy.registerListener([this](std::any d) {
keyboard.reset();
events.destroy.emit();
}, this, "CVirtualKeyboard");
events.destroy.emit();
});
hyprListener_key.initCallback(&keeb->events.key, [this] (void* owner, void* data) {
auto E = (wlr_keyboard_key_event*)data;
keyboardEvents.key.emit(SKeyEvent{
.timeMs = E->time_msec,
.keycode = E->keycode,
.updateMods = E->update_state,
.state = E->state,
listeners.key = keeb_->events.key.registerListener([this](std::any d) { keyboardEvents.key.emit(d); });
listeners.modifiers = keeb_->events.modifiers.registerListener([this](std::any d) {
auto E = std::any_cast<SModifiersEvent>(d);
updateModifiers(E.depressed, E.latched, E.locked, E.group);
keyboardEvents.modifiers.emit(SModifiersEvent{
.depressed = modifiersState.depressed,
.latched = modifiersState.latched,
.locked = modifiersState.locked,
.group = modifiersState.group,
});
}, this, "CVirtualKeyboard");
});
listeners.keymap = keeb_->events.keymap.registerListener([this](std::any d) {
auto E = std::any_cast<SKeymapEvent>(d);
xkbKeymap = xkb_keymap_ref(E.keymap);
keyboardEvents.keymap.emit(d);
});
hyprListener_keymap.initCallback(&keeb->events.keymap, [this] (void* owner, void* data) {
keyboardEvents.keymap.emit();
}, this, "CVirtualKeyboard");
hyprListener_modifiers.initCallback(&keeb->events.modifiers, [this] (void* owner, void* data) {
keyboardEvents.modifiers.emit();
}, this, "CVirtualKeyboard");
hyprListener_repeatInfo.initCallback(&keeb->events.repeat_info, [this] (void* owner, void* data) {
keyboardEvents.repeatInfo.emit();
}, this, "CVirtualKeyboard");
// clang-format on
deviceName = keeb->base.name ? keeb->base.name : "UNKNOWN";
deviceName = keeb_->name;
}
bool CVirtualKeyboard::isVirtual() {
return true;
}
wlr_keyboard* CVirtualKeyboard::wlr() {
if (keyboard.expired())
return nullptr;
return keyboard->wlr();
}
void CVirtualKeyboard::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_key.removeCallback();
hyprListener_keymap.removeCallback();
hyprListener_repeatInfo.removeCallback();
hyprListener_modifiers.removeCallback();
SP<Aquamarine::IKeyboard> CVirtualKeyboard::aq() {
return nullptr;
}
wl_client* CVirtualKeyboard::getClient() {

View file

@ -6,23 +6,22 @@ class CVirtualKeyboardV1Resource;
class CVirtualKeyboard : public IKeyboard {
public:
static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb);
static SP<CVirtualKeyboard> create(SP<CVirtualKeyboardV1Resource> keeb);
virtual bool isVirtual();
virtual wlr_keyboard* wlr();
virtual bool isVirtual();
virtual SP<Aquamarine::IKeyboard> aq();
wl_client* getClient();
wl_client* getClient();
private:
CVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keeb);
WP<CVirtualKeyboardV1Resource> keyboard;
void disconnectCallbacks();
DYNLISTENER(destroy);
DYNLISTENER(key);
DYNLISTENER(modifiers);
DYNLISTENER(keymap);
DYNLISTENER(repeatInfo);
struct {
CHyprSignalListener destroy;
CHyprSignalListener key;
CHyprSignalListener modifiers;
CHyprSignalListener keymap;
} listeners;
};

View file

@ -1,5 +1,6 @@
#include "VirtualPointer.hpp"
#include "../protocols/VirtualPointer.hpp"
#include <aquamarine/input/Input.hpp>
SP<CVirtualPointer> CVirtualPointer::create(SP<CVirtualPointerV1Resource> resource) {
SP<CVirtualPointer> pPointer = SP<CVirtualPointer>(new CVirtualPointer(resource));
@ -13,165 +14,32 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
if (!resource->good())
return;
auto mouse = resource->wlr();
// clang-format off
hyprListener_destroy.initCallback(&mouse->base.events.destroy, [this] (void* owner, void* data) {
disconnectCallbacks();
listeners.destroy = pointer->events.destroy.registerListener([this](std::any d) {
pointer.reset();
events.destroy.emit();
}, this, "CVirtualPointer");
});
hyprListener_motion.initCallback(&mouse->events.motion, [this] (void* owner, void* data) {
auto E = (wlr_pointer_motion_event*)data;
listeners.motion = pointer->events.move.registerListener([this](std::any d) { pointerEvents.motion.emit(d); });
listeners.motionAbsolute = pointer->events.warp.registerListener([this](std::any d) { pointerEvents.motionAbsolute.emit(d); });
listeners.button = pointer->events.button.registerListener([this](std::any d) { pointerEvents.button.emit(d); });
listeners.axis = pointer->events.axis.registerListener([this](std::any d) { pointerEvents.axis.emit(d); });
listeners.frame = pointer->events.frame.registerListener([this](std::any d) { pointerEvents.frame.emit(); });
listeners.swipeBegin = pointer->events.swipeBegin.registerListener([this](std::any d) { pointerEvents.swipeBegin.emit(d); });
listeners.swipeEnd = pointer->events.swipeEnd.registerListener([this](std::any d) { pointerEvents.swipeEnd.emit(d); });
listeners.swipeUpdate = pointer->events.swipeUpdate.registerListener([this](std::any d) { pointerEvents.swipeUpdate.emit(d); });
listeners.pinchBegin = pointer->events.pinchBegin.registerListener([this](std::any d) { pointerEvents.pinchBegin.emit(d); });
listeners.pinchEnd = pointer->events.pinchEnd.registerListener([this](std::any d) { pointerEvents.pinchEnd.emit(d); });
listeners.pinchUpdate = pointer->events.pinchUpdate.registerListener([this](std::any d) { pointerEvents.pinchUpdate.emit(d); });
listeners.holdBegin = pointer->events.holdBegin.registerListener([this](std::any d) { pointerEvents.holdBegin.emit(d); });
listeners.holdEnd = pointer->events.holdEnd.registerListener([this](std::any d) { pointerEvents.holdEnd.emit(d); });
pointerEvents.motion.emit(SMotionEvent{
.timeMs = E->time_msec,
.delta = {E->delta_x, E->delta_y},
.unaccel = {E->unaccel_dx, E->unaccel_dy},
});
}, this, "CVirtualPointer");
hyprListener_motionAbsolute.initCallback(&mouse->events.motion_absolute, [this] (void* owner, void* data) {
auto E = (wlr_pointer_motion_absolute_event*)data;
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec,
.absolute = {E->x, E->y},
.device = self.lock(),
});
}, this, "CVirtualPointer");
hyprListener_button.initCallback(&mouse->events.button, [this] (void* owner, void* data) {
auto E = (wlr_pointer_button_event*)data;
pointerEvents.button.emit(SButtonEvent{
.timeMs = E->time_msec,
.button = E->button,
.state = (wl_pointer_button_state)E->state,
});
}, this, "CVirtualPointer");
hyprListener_axis.initCallback(&mouse->events.axis, [this] (void* owner, void* data) {
auto E = (wlr_pointer_axis_event*)data;
pointerEvents.axis.emit(SAxisEvent{
.timeMs = E->time_msec,
.source = E->source,
.axis = E->orientation,
.relativeDirection = E->relative_direction,
.delta = E->delta,
.deltaDiscrete = E->delta_discrete,
});
}, this, "CVirtualPointer");
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) {
pointerEvents.frame.emit();
}, this, "CVirtualPointer");
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_begin_event*)data;
pointerEvents.swipeBegin.emit(SSwipeBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_swipeEnd.initCallback(&mouse->events.swipe_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_end_event*)data;
pointerEvents.swipeEnd.emit(SSwipeEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
hyprListener_swipeUpdate.initCallback(&mouse->events.swipe_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_update_event*)data;
pointerEvents.swipeUpdate.emit(SSwipeUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
});
}, this, "CVirtualPointer");
hyprListener_pinchBegin.initCallback(&mouse->events.pinch_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_begin_event*)data;
pointerEvents.pinchBegin.emit(SPinchBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_pinchEnd.initCallback(&mouse->events.pinch_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_end_event*)data;
pointerEvents.pinchEnd.emit(SPinchEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
hyprListener_pinchUpdate.initCallback(&mouse->events.pinch_update, [this] (void* owner, void* data) {
auto E = (wlr_pointer_pinch_update_event*)data;
pointerEvents.pinchUpdate.emit(SPinchUpdateEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
.delta = {E->dx, E->dy},
.scale = E->scale,
.rotation = E->rotation,
});
}, this, "CVirtualPointer");
hyprListener_holdBegin.initCallback(&mouse->events.hold_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_begin_event*)data;
pointerEvents.holdBegin.emit(SHoldBeginEvent{
.timeMs = E->time_msec,
.fingers = E->fingers,
});
}, this, "CVirtualPointer");
hyprListener_holdEnd.initCallback(&mouse->events.hold_end, [this] (void* owner, void* data) {
auto E = (wlr_pointer_hold_end_event*)data;
pointerEvents.holdEnd.emit(SHoldEndEvent{
.timeMs = E->time_msec,
.cancelled = E->cancelled,
});
}, this, "CVirtualPointer");
// clang-format on
deviceName = mouse->base.name ? mouse->base.name : "UNKNOWN";
deviceName = pointer->name;
}
bool CVirtualPointer::isVirtual() {
return true;
}
void CVirtualPointer::disconnectCallbacks() {
hyprListener_destroy.removeCallback();
hyprListener_motion.removeCallback();
hyprListener_motionAbsolute.removeCallback();
hyprListener_button.removeCallback();
hyprListener_axis.removeCallback();
hyprListener_frame.removeCallback();
hyprListener_swipeBegin.removeCallback();
hyprListener_swipeEnd.removeCallback();
hyprListener_swipeUpdate.removeCallback();
hyprListener_pinchBegin.removeCallback();
hyprListener_pinchEnd.removeCallback();
hyprListener_pinchUpdate.removeCallback();
hyprListener_holdBegin.removeCallback();
hyprListener_holdEnd.removeCallback();
}
wlr_pointer* CVirtualPointer::wlr() {
if (pointer.expired())
return nullptr;
return pointer->wlr();
SP<Aquamarine::IPointer> CVirtualPointer::aq() {
return nullptr;
}

View file

@ -6,33 +6,34 @@ class CVirtualPointerV1Resource;
class CVirtualPointer : public IPointer {
public:
static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource);
static SP<CVirtualPointer> create(SP<CVirtualPointerV1Resource> resource);
virtual bool isVirtual();
virtual wlr_pointer* wlr();
virtual bool isVirtual();
virtual SP<Aquamarine::IPointer> aq();
private:
CVirtualPointer(SP<CVirtualPointerV1Resource>);
WP<CVirtualPointerV1Resource> pointer;
void disconnectCallbacks();
struct {
CHyprSignalListener destroy;
DYNLISTENER(destroy);
DYNLISTENER(motion);
DYNLISTENER(motionAbsolute);
DYNLISTENER(button);
DYNLISTENER(axis);
DYNLISTENER(frame);
CHyprSignalListener motion;
CHyprSignalListener motionAbsolute;
CHyprSignalListener button;
CHyprSignalListener axis;
CHyprSignalListener frame;
DYNLISTENER(swipeBegin);
DYNLISTENER(swipeEnd);
DYNLISTENER(swipeUpdate);
CHyprSignalListener swipeBegin;
CHyprSignalListener swipeEnd;
CHyprSignalListener swipeUpdate;
DYNLISTENER(pinchBegin);
DYNLISTENER(pinchEnd);
DYNLISTENER(pinchUpdate);
CHyprSignalListener pinchBegin;
CHyprSignalListener pinchEnd;
CHyprSignalListener pinchUpdate;
DYNLISTENER(holdBegin);
DYNLISTENER(holdEnd);
CHyprSignalListener holdBegin;
CHyprSignalListener holdEnd;
} listeners;
};

View file

@ -21,15 +21,15 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
switch (DEVICE->type) {
case WLR_INPUT_DEVICE_KEYBOARD:
Debug::log(LOG, "Attached a keyboard with name {}", DEVICE->name);
g_pInputManager->newKeyboard(DEVICE);
//g_pInputManager->newKeyboard(DEVICE);
break;
case WLR_INPUT_DEVICE_POINTER:
Debug::log(LOG, "Attached a mouse with name {}", DEVICE->name);
g_pInputManager->newMouse(DEVICE);
//g_pInputManager->newMouse(DEVICE);
break;
case WLR_INPUT_DEVICE_TOUCH:
Debug::log(LOG, "Attached a touch device with name {}", DEVICE->name);
g_pInputManager->newTouchDevice(DEVICE);
// g_pInputManager->newTouchDevice(DEVICE);
break;
case WLR_INPUT_DEVICE_TABLET:
Debug::log(LOG, "Attached a tablet with name {}", DEVICE->name);

View file

@ -16,88 +16,6 @@
// //
// --------------------------------------------------------- //
static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("cursor:default_monitor");
static auto firstMonitorAdded = std::chrono::steady_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::steady_clock::now() - firstMonitorAdded);
if (timePassedSec.count() > 10) {
cursorDefaultDone = true;
return;
}
if (*PCURSORMONITOR == monitorName) {
cursorDefaultDone = true;
g_pCompositor->warpCursorTo(POS, true);
g_pInputManager->refocus();
}
}
void Events::listener_newOutput(wl_listener* listener, void* data) {
// new monitor added, let's accommodate for that.
const auto OUTPUT = (wlr_output*)data;
if (!OUTPUT->name) {
Debug::log(ERR, "New monitor has no name?? Ignoring");
return;
}
// 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->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();
}
}
}
void Events::listener_monitorFrame(void* owner, void* data) {
if (g_pCompositor->m_bExitTriggered) {
// Only signal cleanup once
@ -108,18 +26,19 @@ void Events::listener_monitorFrame(void* owner, void* data) {
CMonitor* const PMONITOR = (CMonitor*)owner;
if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
Debug::log(WARN, "Attempted to render frame on inactive session!");
// FIXME:
// if ((g_pCompositor->m_sWLRSession && !g_pCompositor->m_sWLRSession->active) || !g_pCompositor->m_bSessionActive || g_pCompositor->m_bUnsafeState) {
// Debug::log(WARN, "Attempted to render frame on inactive session!");
if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
return m->output != g_pCompositor->m_pUnsafeOutput->output;
})) {
// restore from unsafe state
g_pCompositor->leaveUnsafeState();
}
// if (g_pCompositor->m_bUnsafeState && std::ranges::any_of(g_pCompositor->m_vMonitors.begin(), g_pCompositor->m_vMonitors.end(), [&](auto& m) {
// return m->output != g_pCompositor->m_pUnsafeOutput->output;
// })) {
// // restore from unsafe state
// g_pCompositor->leaveUnsafeState();
// }
return; // cannot draw on session inactive (different tty)
}
// return; // cannot draw on session inactive (different tty)
// }
if (!PMONITOR->m_bEnabled)
return;
@ -172,12 +91,10 @@ void Events::listener_monitorFrame(void* owner, void* data) {
}
void Events::listener_monitorDestroy(void* owner, void* data) {
const auto OUTPUT = (wlr_output*)data;
CMonitor* pMonitor = nullptr;
CMonitor* pMonitor = nullptr;
for (auto& m : g_pCompositor->m_vRealMonitors) {
if (m->output == OUTPUT) {
if (m->output == pMonitor->output) {
pMonitor = m.get();
break;
}
@ -188,9 +105,6 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
Debug::log(LOG, "Destroy called for monitor {}", pMonitor->output->name);
if (pMonitor->output->idle_frame)
wl_event_source_remove(pMonitor->output->idle_frame);
pMonitor->onDisconnect(true);
pMonitor->output = nullptr;
@ -202,20 +116,20 @@ void Events::listener_monitorDestroy(void* owner, void* data) {
}
void Events::listener_monitorStateRequest(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_request_state*)data;
// const auto PMONITOR = (CMonitor*)owner;
// const auto E = (wlr_output_event_request_state*)data;
if (!PMONITOR->createdByUser)
return;
// if (!PMONITOR->createdByUser)
// return;
const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height};
// const auto SIZE = E->state->mode ? Vector2D{E->state->mode->width, E->state->mode->height} : Vector2D{E->state->custom_mode.width, E->state->custom_mode.height};
PMONITOR->forceSize = SIZE;
// PMONITOR->forceSize = SIZE;
SMonitorRule rule = PMONITOR->activeMonitorRule;
rule.resolution = SIZE;
// SMonitorRule rule = PMONITOR->activeMonitorRule;
// rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule);
// g_pHyprRenderer->applyMonitorRule(PMONITOR, &rule);
}
void Events::listener_monitorDamage(void* owner, void* data) {
@ -234,11 +148,9 @@ void Events::listener_monitorNeedsFrame(void* owner, void* data) {
void Events::listener_monitorCommit(void* owner, void* data) {
const auto PMONITOR = (CMonitor*)owner;
const auto E = (wlr_output_event_commit*)data;
if (E->state->committed & WLR_OUTPUT_STATE_BUFFER) {
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR, E);
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR, E);
if (true) { // FIXME: E->state->committed & WLR_OUTPUT_STATE_BUFFER
g_pProtocolManager->m_pScreencopyProtocolManager->onOutputCommit(PMONITOR);
g_pProtocolManager->m_pToplevelExportProtocolManager->onOutputCommit(PMONITOR);
}
}

View file

@ -19,7 +19,7 @@ struct SPixelFormat {
};
struct SDRMFormat {
uint32_t format = 0;
DRMFormat format = 0; /* DRM_FORMAT_INVALID */
std::vector<uint64_t> mods;
};

View file

@ -6,6 +6,7 @@
#include "../devices/ITouch.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/PresentationTime.hpp"
#include "../protocols/core/Output.hpp"
#include "../managers/PointerManager.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
@ -21,14 +22,6 @@ CMonitor::CMonitor() : state(this) {
}
CMonitor::~CMonitor() {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorStateRequest.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
events.destroy.emit();
}
@ -40,43 +33,48 @@ static void onPresented(void* owner, void* data) {
}
void CMonitor::onConnect(bool noRule) {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorStateRequest.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
hyprListener_monitorPresented.removeCallback();
hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor");
hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor");
hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor");
hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor");
hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor");
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor");
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor");
hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor");
tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); });
listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); });
listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); });
listeners.needsFrame = output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this); });
listeners.state = output->events.state.registerListener([this](std::any d) {
if (!createdByUser)
return;
auto E = std::any_cast<Aquamarine::IOutput::SStateEvent>(d);
const auto SIZE = E.size;
forceSize = SIZE;
SMonitorRule rule = activeMonitorRule;
rule.resolution = SIZE;
g_pHyprRenderer->applyMonitorRule(this, &rule);
});
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
if (m_bEnabled) {
wlr_output_state_set_enabled(state.wlr(), true);
output->state->setEnabled(true);
state.commit();
return;
}
szName = output->name;
szDescription = output->description ? output->description : "";
szDescription = output->description;
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
std::erase(szDescription, ',');
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
szShortDescription = trim(std::format("{} {} {}", output->make, output->model, output->serial));
std::erase(szShortDescription, ',');
if (!wlr_backend_is_drm(output->backend))
createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
if (output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM)
createdByUser = true; // should be true. WL and Headless backends should be addable / removable
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
@ -84,56 +82,26 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
wlr_output_state_set_scale(state.wlr(), 1);
wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
auto PREFSTATE = wlr_output_preferred_mode(output);
if (!PREFSTATE) {
wlr_output_mode* mode;
wl_list_for_each(mode, &output->modes, link) {
wlr_output_state_set_mode(state.wlr(), mode);
if (!wlr_output_test_state(output, state.wlr()))
continue;
PREFSTATE = mode;
break;
}
}
if (PREFSTATE)
wlr_output_state_set_mode(state.wlr(), PREFSTATE);
else
Debug::log(WARN, "No mode found for disabled output {}", output->name);
wlr_output_state_set_enabled(state.wlr(), 0);
output->state->setEnabled(false);
if (!state.commit())
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false;
hyprListener_monitorFrame.removeCallback();
listeners.frame.reset();
return;
}
if (output->non_desktop) {
if (output->nonDesktop) {
Debug::log(LOG, "Not configuring non-desktop output");
if (g_pCompositor->m_sWRLDRMLeaseMgr) {
wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
}
// TODO:
// if (g_pCompositor->m_sWRLDRMLeaseMgr) {
// wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
// }
return;
}
if (!m_bRenderingInitPassed) {
output->allocator = nullptr;
output->renderer = nullptr;
wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
m_bRenderingInitPassed = true;
}
SP<CMonitor>* thisWrapper = nullptr;
// find the wrap
@ -151,7 +119,7 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true;
wlr_output_state_set_enabled(state.wlr(), 1);
output->state->setEnabled(true);
// set mode, also applies
if (!noRule)
@ -261,12 +229,10 @@ void CMonitor::onDisconnect(bool destroy) {
g_pConfigManager->m_bWantsMonitorReload = true;
}
hyprListener_monitorFrame.removeCallback();
hyprListener_monitorPresented.removeCallback();
hyprListener_monitorDamage.removeCallback();
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
listeners.frame.reset();
listeners.presented.reset();
listeners.needsFrame.reset();
listeners.commit.reset();
for (size_t i = 0; i < 4; ++i) {
for (auto& ls : m_aLayerSurfaceLayers[i]) {
@ -316,10 +282,10 @@ void CMonitor::onDisconnect(bool destroy) {
activeWorkspace->m_bVisible = false;
activeWorkspace.reset();
wlr_output_state_set_enabled(state.wlr(), false);
output->state->setEnabled(false);
if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor.get() == this)
g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput);
@ -369,8 +335,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
// skip scheduling extra frames for fullsreen apps with vrr
bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow &&
activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
bool shouldSkip =
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
// keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
@ -563,7 +529,7 @@ float CMonitor::getDefaultScale() {
static constexpr double MMPERINCH = 25.4;
const auto DIAGONALPX = sqrt(pow(vecPixelSize.x, 2) + pow(vecPixelSize.y, 2));
const auto DIAGONALIN = sqrt(pow(output->phys_width / MMPERINCH, 2) + pow(output->phys_height / MMPERINCH, 2));
const auto DIAGONALIN = sqrt(pow(output->physicalSize.x / MMPERINCH, 2) + pow(output->physicalSize.y / MMPERINCH, 2));
const auto PPI = DIAGONALPX / DIAGONALIN;
@ -787,31 +753,35 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize};
}
static void onDoneSource(void* data) {
auto pMonitor = (CMonitor*)data;
if (!PROTO::outputs.contains(pMonitor->szName))
return;
PROTO::outputs.at(pMonitor->szName)->sendDone();
}
void CMonitor::scheduleDone() {
if (doneSource)
return;
doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this);
}
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
wlr_output_state_init(&m_state);
}
CMonitorState::~CMonitorState() {
wlr_output_state_finish(&m_state);
}
wlr_output_state* CMonitorState::wlr() {
return &m_state;
}
void CMonitorState::clear() {
wlr_output_state_finish(&m_state);
m_state = {0};
wlr_output_state_init(&m_state);
;
}
bool CMonitorState::commit() {
bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
clear();
bool ret = m_pOwner->output->commit();
return ret;
}
bool CMonitorState::test() {
return wlr_output_test_state(m_pOwner->output, &m_state);
return m_pOwner->output->test();
}

View file

@ -12,6 +12,8 @@
#include <optional>
#include "signal/Signal.hpp"
#include "DamageRing.hpp"
#include <aquamarine/output/Output.hpp>
#include <aquamarine/allocator/Swapchain.hpp>
// Enum for the different types of auto directions, e.g. auto-left, auto-up.
enum eAutoDirs {
@ -45,15 +47,11 @@ class CMonitorState {
CMonitorState(CMonitor* owner);
~CMonitorState();
wlr_output_state* wlr();
void clear();
// commit() will also clear()
bool commit();
bool test();
private:
wlr_output_state m_state = {0};
CMonitor* m_pOwner;
CMonitor* m_pOwner;
};
class CMonitor {
@ -61,61 +59,62 @@ class CMonitor {
CMonitor();
~CMonitor();
Vector2D vecPosition = Vector2D(-1, -1); // means unset
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
Vector2D vecSize = Vector2D(0, 0);
Vector2D vecPixelSize = Vector2D(0, 0);
Vector2D vecTransformedSize = Vector2D(0, 0);
Vector2D vecPosition = Vector2D(-1, -1); // means unset
Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset
Vector2D vecSize = Vector2D(0, 0);
Vector2D vecPixelSize = Vector2D(0, 0);
Vector2D vecTransformedSize = Vector2D(0, 0);
bool primary = false;
bool primary = false;
uint64_t ID = -1;
PHLWORKSPACE activeWorkspace = nullptr;
PHLWORKSPACE activeSpecialWorkspace = nullptr;
float setScale = 1; // scale set by cfg
float scale = 1; // real scale
uint64_t ID = -1;
PHLWORKSPACE activeWorkspace = nullptr;
PHLWORKSPACE activeSpecialWorkspace = nullptr;
float setScale = 1; // scale set by cfg
float scale = 1; // real scale
std::string szName = "";
std::string szDescription = "";
std::string szShortDescription = "";
std::string szName = "";
std::string szDescription = "";
std::string szShortDescription = "";
Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0);
Vector2D vecReservedTopLeft = Vector2D(0, 0);
Vector2D vecReservedBottomRight = Vector2D(0, 0);
drmModeModeInfo customDrmMode = {};
drmModeModeInfo customDrmMode = {};
CMonitorState state;
CDamageRing damage;
CMonitorState state;
CDamageRing damage;
wlr_output* output = nullptr;
float refreshRate = 60;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
std::optional<Vector2D> forceSize;
wlr_output_mode* currentMode = nullptr;
SP<Aquamarine::IOutput> output;
float refreshRate = 60;
int framesToSkip = 0;
int forceFullFrames = 0;
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
std::optional<Vector2D> forceSize;
SP<Aquamarine::SOutputMode> currentMode;
SP<Aquamarine::CSwapchain> cursorSwapchain;
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false;
bool dpmsStatus = true;
bool vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
bool enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
bool createdByUser = false;
uint32_t drmFormat = DRM_FORMAT_INVALID;
bool isUnsafeFallback = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false;
CTimer lastPresentationTimer;
wl_event_source* renderTimer = nullptr; // for RAT
bool RATScheduled = false;
CTimer lastPresentationTimer;
SMonitorRule activeMonitorRule;
SMonitorRule activeMonitorRule;
WP<CMonitor> self;
WP<CMonitor> self;
// mirroring
CMonitor* pMirrorOf = nullptr;
@ -143,15 +142,6 @@ class CMonitor {
std::array<std::vector<PHLLSREF>, 4> m_aLayerSurfaceLayers;
DYNLISTENER(monitorFrame);
DYNLISTENER(monitorDestroy);
DYNLISTENER(monitorStateRequest);
DYNLISTENER(monitorDamage);
DYNLISTENER(monitorNeedsFrame);
DYNLISTENER(monitorCommit);
DYNLISTENER(monitorBind);
DYNLISTENER(monitorPresented);
// methods
void onConnect(bool noRule);
void onDisconnect(bool destroy = false);
@ -173,6 +163,7 @@ class CMonitor {
int64_t activeWorkspaceID();
int64_t activeSpecialWorkspaceID();
CBox logicalBox();
void scheduleDone();
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;
@ -184,6 +175,17 @@ class CMonitor {
}
private:
void setupDefaultWS(const SMonitorRule&);
int findAvailableDefaultWS();
void setupDefaultWS(const SMonitorRule&);
int findAvailableDefaultWS();
wl_event_source* doneSource = nullptr;
struct {
CHyprSignalListener frame;
CHyprSignalListener destroy;
CHyprSignalListener state;
CHyprSignalListener needsFrame;
CHyprSignalListener presented;
CHyprSignalListener commit;
} listeners;
};

View file

@ -105,3 +105,8 @@
class name; \
} \
}
#define AQUAMARINE_FORWARD(name) \
namespace Aquamarine { \
class name; \
}

View file

@ -67,54 +67,61 @@ void CCursorManager::dropBufferRef(CCursorManager::CCursorBuffer* ref) {
std::erase_if(m_vCursorBuffers, [ref](const auto& buf) { return buf.get() == ref; });
}
static void cursorBufferDestroy(struct wlr_buffer* wlr_buffer) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
g_pCursorManager->dropBufferRef(buffer->parent);
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
surface = surf;
size = size_;
stride = cairo_image_surface_get_stride(surf);
}
static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t flags, void** data, uint32_t* format, size_t* stride) {
CCursorManager::CCursorBuffer::SCursorWlrBuffer* buffer = wl_container_of(wlr_buffer, buffer, base);
if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE)
return false;
*data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface);
*stride = buffer->stride;
*format = DRM_FORMAT_ARGB8888;
return true;
}
static void cursorBufferEndDataPtr(struct wlr_buffer* wlr_buffer) {
;
}
//
static const wlr_buffer_impl bufferImpl = {
.destroy = cursorBufferDestroy,
.begin_data_ptr_access = cursorBufferBeginDataPtr,
.end_data_ptr_access = cursorBufferEndDataPtr,
};
CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
wlrBuffer.surface = surf;
wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
wlrBuffer.parent = this;
wlrBuffer.stride = cairo_image_surface_get_stride(surf);
}
CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData, const Vector2D& size_, const Vector2D& hot_) : size(size_), hotspot(hot_) {
wlrBuffer.pixelData = pixelData;
wlr_buffer_init(&wlrBuffer.base, &bufferImpl, size.x, size.y);
wlrBuffer.parent = this;
wlrBuffer.stride = 4 * size_.x;
CCursorManager::CCursorBuffer::CCursorBuffer(uint8_t* pixelData_, const Vector2D& size_, const Vector2D& hot_) : hotspot(hot_) {
pixelData = pixelData_;
size = size_;
stride = 4 * size_.x;
}
CCursorManager::CCursorBuffer::~CCursorBuffer() {
; // will be freed in .destroy
;
}
wlr_buffer* CCursorManager::getCursorBuffer() {
return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
Aquamarine::eBufferCapability CCursorManager::CCursorBuffer::caps() {
return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
Aquamarine::eBufferType CCursorManager::CCursorBuffer::type() {
return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
}
void CCursorManager::CCursorBuffer::update(const Hyprutils::Math::CRegion& damage) {
;
}
bool CCursorManager::CCursorBuffer::isSynchronous() {
return true;
}
bool CCursorManager::CCursorBuffer::good() {
return true;
}
Aquamarine::SSHMAttrs CCursorManager::CCursorBuffer::shm() {
Aquamarine::SSHMAttrs attrs;
attrs.success = true;
attrs.format = DRM_FORMAT_ARGB8888;
attrs.size = size;
attrs.stride = stride;
return attrs;
}
std::tuple<uint8_t*, uint32_t, size_t> CCursorManager::CCursorBuffer::beginDataPtr(uint32_t flags) {
return {pixelData ? pixelData : cairo_image_surface_get_data(surface), DRM_FORMAT_ARGB8888, stride};
}
void CCursorManager::CCursorBuffer::endDataPtr() {
;
}
SP<Aquamarine::IBuffer> CCursorManager::getCursorBuffer() {
return !m_vCursorBuffers.empty() ? m_vCursorBuffers.back() : nullptr;
}
void CCursorManager::setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot) {
@ -150,11 +157,11 @@ void CCursorManager::setXCursor(const std::string& name) {
auto image = xcursor->images[0];
m_vCursorBuffers.emplace_back(
std::make_unique<CCursorBuffer>(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y}));
makeShared<CCursorBuffer>(image->buffer, Vector2D{(int)image->width, (int)image->height}, Vector2D{(double)image->hotspot_x, (double)image->hotspot_y}));
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{(double)image->hotspot_x, (double)image->hotspot_y} / scale, scale);
if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
dropBufferRef(m_vCursorBuffers.at(0).get());
m_bOurBufferConnected = true;
}
@ -196,14 +203,14 @@ void CCursorManager::setCursorFromName(const std::string& name) {
}
}
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface,
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(m_sCurrentCursorShapeData.images[0].surface,
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY} / m_fCursorScale,
m_fCursorScale);
if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
dropBufferRef(m_vCursorBuffers.at(0).get());
m_bOurBufferConnected = true;
@ -225,7 +232,7 @@ void CCursorManager::tickAnimatedCursor() {
if ((size_t)m_iCurrentAnimationFrame >= m_sCurrentCursorShapeData.images.size())
m_iCurrentAnimationFrame = 0;
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(
m_vCursorBuffers.emplace_back(makeShared<CCursorBuffer>(
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].surface,
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].size},
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY}));

View file

@ -7,46 +7,49 @@
#include "../helpers/math/Math.hpp"
#include "../helpers/memory/Memory.hpp"
struct wlr_buffer;
struct wlr_xcursor_manager;
class CWLSurface;
AQUAMARINE_FORWARD(IBuffer);
class CCursorManager {
public:
CCursorManager();
~CCursorManager();
wlr_buffer* getCursorBuffer();
SP<Aquamarine::IBuffer> getCursorBuffer();
void setCursorFromName(const std::string& name);
void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot);
void setXCursor(const std::string& name);
void setCursorFromName(const std::string& name);
void setCursorSurface(SP<CWLSurface> surf, const Vector2D& hotspot);
void setXCursor(const std::string& name);
bool changeTheme(const std::string& name, const int size);
void updateTheme();
SCursorImageData dataFor(const std::string& name); // for xwayland
void setXWaylandCursor();
bool changeTheme(const std::string& name, const int size);
void updateTheme();
SCursorImageData dataFor(const std::string& name); // for xwayland
void setXWaylandCursor();
void tickAnimatedCursor();
void tickAnimatedCursor();
class CCursorBuffer {
class CCursorBuffer : public Aquamarine::IBuffer {
public:
CCursorBuffer(cairo_surface_t* surf, const Vector2D& size, const Vector2D& hotspot);
CCursorBuffer(uint8_t* pixelData, const Vector2D& size, const Vector2D& hotspot);
~CCursorBuffer();
struct SCursorWlrBuffer {
wlr_buffer base;
cairo_surface_t* surface = nullptr;
bool dropped = false;
CCursorBuffer* parent = nullptr;
uint8_t* pixelData = nullptr;
size_t stride = 0;
} wlrBuffer;
virtual Aquamarine::eBufferCapability caps();
virtual Aquamarine::eBufferType type();
virtual void update(const Hyprutils::Math::CRegion& damage);
virtual bool isSynchronous(); // whether the updates to this buffer are synchronous, aka happen over cpu
virtual bool good();
virtual Aquamarine::SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
private:
Vector2D size;
Vector2D hotspot;
Vector2D hotspot;
cairo_surface_t* surface = nullptr;
uint8_t* pixelData = nullptr;
size_t stride = 0;
friend class CCursorManager;
};
@ -56,7 +59,7 @@ class CCursorManager {
bool m_bOurBufferConnected = false;
private:
std::vector<std::unique_ptr<CCursorBuffer>> m_vCursorBuffers;
std::vector<SP<CCursorBuffer>> m_vCursorBuffers;
std::unique_ptr<Hyprcursor::CHyprcursorManager> m_pHyprcursor;

View file

@ -367,7 +367,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
const auto KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput
const xkb_keysym_t keysym = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbTranslationState : m_pXKBTranslationState, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->wlr()->xkb_state, KEYCODE);
const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbInternalTranslationState, KEYCODE);
if (handleInternalKeybinds(internalKeysym))
return true;
@ -554,7 +554,7 @@ int repeatKeyHandler(void* data) {
Debug::log(LOG, "Keybind repeat triggered, calling dispatcher.");
DISPATCHER->second((*ppActiveKeybind)->arg);
wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->wlr()->repeat_info.rate);
wl_event_source_timer_update(g_pKeybindManager->m_pActiveKeybindEventSource, 1000 / g_pSeatManager->keyboard->repeatRate);
return 0;
}
@ -786,7 +786,7 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
// beyond this point, return true to not handle anything else.
// we'll avoid printing shit to active windows.
if (g_pCompositor->m_sWLRSession) {
if (g_pCompositor->m_pAqBackend->hasSession()) {
const unsigned int TTY = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
// vtnr is bugged for some reason.
@ -810,7 +810,8 @@ bool CKeybindManager::handleVT(xkb_keysym_t keysym) {
Debug::log(LOG, "Switching from VT {} to VT {}", ttynum, TTY);
wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY);
// FIXME:
//wlr_session_change_vt(g_pCompositor->m_sWLRSession, TTY);
return true;
}
@ -2121,7 +2122,7 @@ void CKeybindManager::sendshortcut(std::string args) {
const auto KEYPAIRSTRING = std::format("{}{}", (uintptr_t)KB.get(), KEY);
if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) {
xkb_keymap* km = KB->wlr()->keymap;
xkb_keymap* km = KB->xkbKeymap;
xkb_state* ks = KB->xkbTranslationState;
xkb_keycode_t keycode_min, keycode_max;
@ -2259,7 +2260,7 @@ void CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port)
continue;
wlr_output_state_set_enabled(m->state.wlr(), enable);
m->output->state->setEnabled(enable);
m->dpmsStatus = enable;

View file

@ -10,128 +10,26 @@
#include <wlr/render/interface.h>
#include <wlr/render/wlr_renderer.h>
// TODO: make nicer
// this will come with the eventual rewrite of wlr_drm, etc...
static bool wlr_drm_format_intersect(wlr_drm_format* dst, const wlr_drm_format* a, const wlr_drm_format* b) {
ASSERT(a->format == b->format);
static Aquamarine::SDRMFormat pickCursorFormat(SP<Aquamarine::IOutput> output) {
size_t capacity = a->len < b->len ? a->len : b->len;
uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * capacity);
if (!modifiers)
return false;
const auto fmts = output->getBackend()->getCursorFormats();
struct wlr_drm_format fmt = {
.format = a->format,
.len = 0,
.capacity = capacity,
.modifiers = modifiers,
};
if (fmts.empty())
return {};
for (size_t i = 0; i < a->len; i++) {
for (size_t j = 0; j < b->len; j++) {
if (a->modifiers[i] == b->modifiers[j]) {
ASSERT(fmt.len < fmt.capacity);
fmt.modifiers[fmt.len++] = a->modifiers[i];
break;
}
// try to use common formats in their order
std::vector<uint32_t> PREFERRED_FORMATS = {DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888};
for (auto& pf : PREFERRED_FORMATS) {
for (auto& fmt : fmts) {
if (pf != fmt.drmFormat)
continue;
return fmt;
}
}
wlr_drm_format_finish(dst);
*dst = fmt;
return true;
}
static bool wlr_drm_format_copy(wlr_drm_format* dst, const wlr_drm_format* src) {
ASSERT(src->len <= src->capacity);
uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * src->len);
if (!modifiers)
return false;
memcpy(modifiers, src->modifiers, sizeof(*modifiers) * src->len);
wlr_drm_format_finish(dst);
dst->capacity = src->len;
dst->len = src->len;
dst->format = src->format;
dst->modifiers = modifiers;
return true;
}
static const wlr_drm_format_set* wlr_renderer_get_render_formats(wlr_renderer* r) {
if (!r->impl->get_render_formats)
return nullptr;
return r->impl->get_render_formats(r);
}
static bool output_pick_format(wlr_output* output, const wlr_drm_format_set* display_formats, wlr_drm_format* format, uint32_t fmt) {
const wlr_drm_format_set* render_formats = wlr_renderer_get_render_formats(g_pCompositor->m_sWLRRenderer);
if (render_formats == NULL) {
wlr_log(WLR_ERROR, "Failed to get render formats");
return false;
}
const wlr_drm_format* render_format = wlr_drm_format_set_get(render_formats, fmt);
if (render_format == NULL) {
wlr_log(WLR_DEBUG, "Renderer doesn't support format 0x%" PRIX32, fmt);
return false;
}
if (display_formats != NULL) {
const wlr_drm_format* display_format = wlr_drm_format_set_get(display_formats, fmt);
if (display_format == NULL) {
wlr_log(WLR_DEBUG, "Output doesn't support format 0x%" PRIX32, fmt);
return false;
}
if (!wlr_drm_format_intersect(format, display_format, render_format)) {
wlr_log(WLR_DEBUG,
"Failed to intersect display and render "
"modifiers for format 0x%" PRIX32 " on output %s",
fmt, output->name);
return false;
}
} else {
// The output can display any format
if (!wlr_drm_format_copy(format, render_format))
return false;
}
if (format->len == 0) {
wlr_drm_format_finish(format);
wlr_log(WLR_DEBUG, "Failed to pick output format");
return false;
}
return true;
}
static bool output_pick_cursor_format(struct wlr_output* output, struct wlr_drm_format* format) {
struct wlr_allocator* allocator = output->allocator;
ASSERT(allocator != NULL);
const struct wlr_drm_format_set* display_formats = NULL;
if (output->impl->get_cursor_formats) {
display_formats = output->impl->get_cursor_formats(output, allocator->buffer_caps);
if (display_formats == NULL) {
wlr_log(WLR_DEBUG, "Failed to get cursor display formats");
return false;
}
}
// Note: taken from https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4596/diffs#diff-content-e3ea164da86650995728d70bd118f6aa8c386797
// If this fails to find a shared modifier try to use a linear
// modifier. This avoids a scenario where the hardware cannot render to
// linear textures but only linear textures are supported for cursors,
// as is the case with Nvidia and VmWare GPUs
if (!output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888)) {
// Clear the format as output_pick_format doesn't zero it
memset(format, 0, sizeof(*format));
return output_pick_format(output, NULL, format, DRM_FORMAT_ARGB8888);
}
return true;
return fmts.at(0);
}
CPointerManager::CPointerManager() {
@ -201,6 +99,11 @@ void CPointerManager::unlockSoftwareForMonitor(SP<CMonitor> mon) {
updateCursorBackend();
}
bool CPointerManager::softwareLockedFor(SP<CMonitor> mon) {
auto state = stateFor(mon);
return state->softwareLocks > 0 || state->hardwareFailed;
}
Vector2D CPointerManager::position() {
return pointerPos;
}
@ -216,7 +119,7 @@ SP<CPointerManager::SMonitorPointerState> CPointerManager::stateFor(SP<CMonitor>
return *it;
}
void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) {
void CPointerManager::setCursorBuffer(SP<Aquamarine::IBuffer> buf, const Vector2D& hotspot, const float& scale) {
damageIfSoftware();
if (buf == currentCursorImage.pBuffer) {
if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) {
@ -232,10 +135,8 @@ void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot,
resetCursorImage(false);
if (buf) {
currentCursorImage.size = {buf->width, buf->height};
currentCursorImage.pBuffer = wlr_buffer_lock(buf);
currentCursorImage.hyprListener_destroyBuffer.initCallback(&buf->events.destroy, [this](void* owner, void* data) { resetCursorImage(); }, this, "CPointerManager");
currentCursorImage.size = buf->size;
currentCursorImage.pBuffer = buf;
}
currentCursorImage.hotspot = hotspot;
@ -317,8 +218,8 @@ void CPointerManager::recheckEnteredOutputs() {
// if we are using hw cursors, prevent
// the cursor from being stuck at the last point.
// if we are leaving it, move it to narnia.
if (!s->hardwareFailed && s->monitor->output->impl->move_cursor)
s->monitor->output->impl->move_cursor(s->monitor->output, -1337, -420);
if (!s->hardwareFailed && (s->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
s->monitor->output->moveCursor({-1337, -420});
if (!currentCursorImage.surface)
continue;
@ -339,16 +240,11 @@ void CPointerManager::resetCursorImage(bool apply) {
currentCursorImage.destroySurface.reset();
currentCursorImage.commitSurface.reset();
currentCursorImage.surface.reset();
} else if (currentCursorImage.pBuffer) {
wlr_buffer_unlock(currentCursorImage.pBuffer);
currentCursorImage.hyprListener_destroyBuffer.removeCallback();
} else if (currentCursorImage.pBuffer)
currentCursorImage.pBuffer = nullptr;
}
if (currentCursorImage.pBufferTexture) {
wlr_texture_destroy(currentCursorImage.pBufferTexture);
currentCursorImage.pBufferTexture = nullptr;
}
if (currentCursorImage.bufferTex)
currentCursorImage.bufferTex = nullptr;
currentCursorImage.scale = 1.F;
currentCursorImage.hotspot = {0, 0};
@ -370,9 +266,8 @@ void CPointerManager::resetCursorImage(bool apply) {
}
if (ms->cursorFrontBuffer) {
if (ms->monitor->output->impl->set_cursor)
ms->monitor->output->impl->set_cursor(ms->monitor->output, nullptr, 0, 0);
wlr_buffer_unlock(ms->cursorFrontBuffer);
if (ms->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER)
ms->monitor->output->setCursor(nullptr, {});
ms->cursorFrontBuffer = nullptr;
}
}
@ -418,18 +313,18 @@ void CPointerManager::onCursorMoved() {
continue;
const auto CURSORPOS = getCursorPosForMonitor(m);
m->output->impl->move_cursor(m->output, CURSORPOS.x, CURSORPOS.y);
m->output->moveCursor(CURSORPOS);
}
}
bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerState> state) {
auto output = state->monitor->output;
if (!output->impl->set_cursor)
if (!(output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
return false;
const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
state->monitor->output->impl->move_cursor(state->monitor->output, CURSORPOS.x, CURSORPOS.y);
state->monitor->output->moveCursor(CURSORPOS);
auto texture = getCurrentCursorTexture();
@ -459,64 +354,68 @@ bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerS
return success;
}
bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf) {
if (!state->monitor->output->impl->set_cursor)
bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf) {
if (!(state->monitor->output->getBackend()->capabilities() & Aquamarine::IBackendImplementation::eBackendCapabilities::AQ_BACKEND_CAPABILITY_POINTER))
return false;
const auto HOTSPOT = transformedHotspot(state->monitor.lock());
Debug::log(TRACE, "[pointer] hw transformed hotspot for {}: {}", state->monitor->szName, HOTSPOT);
if (!state->monitor->output->impl->set_cursor(state->monitor->output, buf, HOTSPOT.x, HOTSPOT.y))
if (!state->monitor->output->setCursor(buf, HOTSPOT))
return false;
wlr_buffer_unlock(state->cursorFrontBuffer);
state->cursorFrontBuffer = buf;
g_pCompositor->scheduleFrameForMonitor(state->monitor.get());
if (buf)
wlr_buffer_lock(buf);
return true;
}
wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
SP<Aquamarine::IBuffer> CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPointerState> state, SP<CTexture> texture) {
auto output = state->monitor->output;
int w = currentCursorImage.size.x, h = currentCursorImage.size.y;
if (output->impl->get_cursor_size) {
output->impl->get_cursor_size(output, &w, &h);
auto maxSize = output->maxCursorSize();
if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) {
Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h);
return nullptr;
}
}
auto cursorSize = currentCursorImage.size;
if (w <= 0 || h <= 0) {
Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, w, h);
if (cursorSize == Vector2D{})
return nullptr;
}
if (!output->cursor_swapchain || Vector2D{w, h} != Vector2D{output->cursor_swapchain->width, output->cursor_swapchain->height}) {
wlr_drm_format fmt = {0};
if (!output_pick_cursor_format(output, &fmt)) {
Debug::log(TRACE, "Failed to pick cursor format");
return nullptr;
}
// error
if (maxSize == Vector2D{})
return nullptr;
wlr_swapchain_destroy(output->cursor_swapchain);
output->cursor_swapchain = wlr_swapchain_create(output->allocator, w, h, &fmt);
wlr_drm_format_finish(&fmt);
if (!output->cursor_swapchain) {
Debug::log(TRACE, "Failed to create cursor swapchain");
if (maxSize != Vector2D{-1, -1}) {
if (cursorSize.x < maxSize.x || cursorSize.y < maxSize.y) {
Debug::log(TRACE, "hardware cursor too big! {} > {}", currentCursorImage.size, maxSize);
return nullptr;
}
}
wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr);
if (!state->monitor->cursorSwapchain || cursorSize != state->monitor->cursorSwapchain->currentOptions().size) {
auto format = pickCursorFormat(output);
if (format.drmFormat == DRM_FORMAT_INVALID) {
Debug::log(TRACE, "Failed to pick an output format for hw cursor");
return nullptr;
}
if (!state->monitor->cursorSwapchain)
state->monitor->cursorSwapchain = makeShared<Aquamarine::CSwapchain>(g_pCompositor->m_pAqBackend->allocator);
auto options = state->monitor->cursorSwapchain->currentOptions();
options.size = cursorSize;
options.length = 2;
options.format = format.drmFormat;
if (!state->monitor->cursorSwapchain->reconfigure(options)) {
Debug::log(TRACE, "Failed to reconfigure cursor swapchain");
return nullptr;
}
}
auto buf = state->monitor->cursorSwapchain->next(nullptr);
if (!buf) {
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
return nullptr;
@ -525,16 +424,16 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPo
CRegion damage = {0, 0, INT16_MAX, INT16_MAX};
g_pHyprRenderer->makeEGLCurrent();
g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get(); // has to be set cuz allocs
g_pHyprOpenGL->m_RenderData.pMonitor = state->monitor.get();
const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, DRM_FORMAT_ARGB8888);
const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, state->monitor->cursorSwapchain->currentOptions().format);
RBO->bind();
g_pHyprOpenGL->beginSimple(state->monitor.get(), damage, RBO);
g_pHyprOpenGL->clear(CColor{0.F, 0.F, 0.F, 0.F});
CBox xbox = {{}, Vector2D{currentCursorImage.size / currentCursorImage.scale * state->monitor->scale}.round()};
Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, Vector2D{w, h},
Debug::log(TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->szName, currentCursorImage.size, cursorSize,
currentCursorImage.scale, state->monitor->scale, xbox.size());
g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F);
@ -545,8 +444,6 @@ wlr_buffer* CPointerManager::renderHWCursorBuffer(SP<CPointerManager::SMonitorPo
g_pHyprRenderer->onRenderbufferDestroy(RBO);
wlr_buffer_unlock(buf);
return buf;
}
@ -593,11 +490,12 @@ Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) {
}
Vector2D CPointerManager::transformedHotspot(SP<CMonitor> pMonitor) {
if (!pMonitor->output->cursor_swapchain)
if (!pMonitor->cursorSwapchain)
return {}; // doesn't matter, we have no hw cursor, and this is only for hw cursors
return CBox{currentCursorImage.hotspot * pMonitor->scale, {0, 0}}
.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->transform)), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height)
.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->transform)), pMonitor->cursorSwapchain->currentOptions().size.x,
pMonitor->cursorSwapchain->currentOptions().size.y)
.pos();
}
@ -799,10 +697,8 @@ SP<CTexture> CPointerManager::getCurrentCursorTexture() {
return nullptr;
if (currentCursorImage.pBuffer) {
if (!currentCursorImage.pBufferTexture) {
currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer);
currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBufferTexture);
}
if (!currentCursorImage.bufferTex)
currentCursorImage.bufferTex = makeShared<CTexture>(currentCursorImage.pBuffer);
return currentCursorImage.bufferTex;
}

View file

@ -9,10 +9,11 @@
#include <tuple>
class CMonitor;
struct wlr_input_device;
class IHID;
class CTexture;
AQUAMARINE_FORWARD(IBuffer);
/*
The naming here is a bit confusing.
CPointerManager manages the _position_ and _displaying_ of the cursor,
@ -37,7 +38,7 @@ class CPointerManager {
void move(const Vector2D& deltaLogical);
void warpAbsolute(Vector2D abs, SP<IHID> dev);
void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale);
void setCursorBuffer(SP<Aquamarine::IBuffer> buf, const Vector2D& hotspot, const float& scale);
void setCursorSurface(SP<CWLSurface> buf, const Vector2D& hotspot);
void resetCursorImage(bool apply = true);
@ -47,6 +48,7 @@ class CPointerManager {
void unlockSoftwareForMonitor(CMonitor* pMonitor);
void lockSoftwareAll();
void unlockSoftwareAll();
bool softwareLockedFor(SP<CMonitor> pMonitor);
void renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */);
@ -135,45 +137,40 @@ class CPointerManager {
} currentMonitorLayout;
struct {
wlr_buffer* pBuffer = nullptr;
SP<CTexture> bufferTex;
WP<CWLSurface> surface;
wlr_texture* pBufferTexture = nullptr;
SP<Aquamarine::IBuffer> pBuffer;
SP<CTexture> bufferTex;
WP<CWLSurface> surface;
Vector2D hotspot;
Vector2D size;
float scale = 1.F;
Vector2D hotspot;
Vector2D size;
float scale = 1.F;
CHyprSignalListener destroySurface;
CHyprSignalListener commitSurface;
DYNLISTENER(destroyBuffer);
CHyprSignalListener destroySurface;
CHyprSignalListener commitSurface;
} currentCursorImage; // TODO: support various sizes per-output so we can have pixel-perfect cursors
Vector2D pointerPos = {0, 0};
struct SMonitorPointerState {
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
~SMonitorPointerState() {
if (cursorFrontBuffer)
wlr_buffer_unlock(cursorFrontBuffer);
}
~SMonitorPointerState() {}
WP<CMonitor> monitor;
WP<CMonitor> monitor;
int softwareLocks = 0;
bool hardwareFailed = false;
CBox box; // logical
bool entered = false;
bool hwApplied = false;
int softwareLocks = 0;
bool hardwareFailed = false;
CBox box; // logical
bool entered = false;
bool hwApplied = false;
wlr_buffer* cursorFrontBuffer = nullptr;
SP<Aquamarine::IBuffer> cursorFrontBuffer;
};
std::vector<SP<SMonitorPointerState>> monitorStates;
SP<SMonitorPointerState> stateFor(SP<CMonitor> mon);
bool attemptHardwareCursor(SP<SMonitorPointerState> state);
wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
bool setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf);
SP<Aquamarine::IBuffer> renderHWCursorBuffer(SP<SMonitorPointerState> state, SP<CTexture> texture);
bool setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquamarine::IBuffer> buf);
struct {
SP<HOOK_CALLBACK_FN> monitorAdded;

View file

@ -94,8 +94,8 @@ void CSeatManager::setKeyboard(SP<IKeyboard> KEEB) {
}
void CSeatManager::updateActiveKeyboardData() {
if (keyboard && keyboard->wlr())
PROTO::seat->updateRepeatInfo(keyboard->wlr()->repeat_info.rate, keyboard->wlr()->repeat_info.delay);
if (keyboard)
PROTO::seat->updateRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay);
PROTO::seat->updateKeymap();
}
@ -103,7 +103,7 @@ void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) {
if (state.keyboardFocus == surf)
return;
if (!keyboard || !keyboard->wlr()) {
if (!keyboard) {
Debug::log(ERR, "BUG THIS: setKeyboardFocus without a valid keyboard set");
return;
}
@ -144,7 +144,7 @@ void CSeatManager::setKeyboardFocus(SP<CWLSurfaceResource> surf) {
continue;
k->sendEnter(surf);
k->sendMods(keyboard->wlr()->modifiers.depressed, keyboard->wlr()->modifiers.latched, keyboard->wlr()->modifiers.locked, keyboard->wlr()->modifiers.group);
k->sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group);
}
}
@ -196,7 +196,7 @@ void CSeatManager::setPointerFocus(SP<CWLSurfaceResource> surf, const Vector2D&
return;
}
if (!mouse || !mouse->wlr()) {
if (!mouse) {
Debug::log(ERR, "BUG THIS: setPointerFocus without a valid mouse set");
return;
}

View file

@ -1,5 +1,6 @@
#include "EventLoopManager.hpp"
#include "../../debug/Log.hpp"
#include "../../Compositor.hpp"
#include <algorithm>
#include <limits>
@ -25,9 +26,19 @@ static int timerWrite(int fd, uint32_t mask, void* data) {
return 1;
}
static int aquamarineFDWrite(int fd, uint32_t mask, void* data) {
g_pCompositor->m_pAqBackend->dispatchEventsAsync();
return 1;
}
void CEventLoopManager::enterLoop() {
m_sWayland.eventSource = wl_event_loop_add_fd(m_sWayland.loop, m_sTimers.timerfd, WL_EVENT_READABLE, timerWrite, nullptr);
auto aqFDs = g_pCompositor->m_pAqBackend->getPollFDs();
for (auto& fd : aqFDs) {
m_sWayland.aqEventSources.emplace_back(wl_event_loop_add_fd(m_sWayland.loop, fd, WL_EVENT_READABLE, aquamarineFDWrite, nullptr));
}
wl_display_run(m_sWayland.display);
Debug::log(LOG, "Kicked off the event loop! :(");

View file

@ -33,9 +33,10 @@ class CEventLoopManager {
private:
struct {
wl_event_loop* loop = nullptr;
wl_display* display = nullptr;
wl_event_source* eventSource = nullptr;
wl_event_loop* loop = nullptr;
wl_display* display = nullptr;
wl_event_source* eventSource = nullptr;
std::vector<wl_event_source*> aqEventSources;
} m_sWayland;
struct {

View file

@ -28,6 +28,8 @@
#include "../../managers/PointerManager.hpp"
#include "../../managers/SeatManager.hpp"
#include <aquamarine/input/Input.hpp>
CInputManager::CInputManager() {
m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) {
if (!cursorImageUnlocked())
@ -189,7 +191,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
bool skipFrameSchedule = PMONITOR->shouldSkipScheduleFrameOnMouseEvent();
if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && PMONITOR->output->software_cursor_locks > 0 && !skipFrameSchedule)
if (!PMONITOR->solitaryClient.lock() && g_pHyprRenderer->shouldRenderCursor() && g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) && !skipFrameSchedule)
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
PHLWINDOW forcedFocus = m_pForcedFocus.lock();
@ -372,7 +374,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
foundSurface =
g_pCompositor->vectorToLayerSurface(mouseCoords, &PMONITOR->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], &surfaceCoords, &pFoundLayerSurface);
if (g_pCompositor->m_pLastMonitor->output->software_cursor_locks > 0 && !skipFrameSchedule)
if (g_pPointerManager->softwareLockedFor(PMONITOR->self.lock()) > 0 && !skipFrameSchedule)
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get());
// grabs
@ -843,8 +845,8 @@ Vector2D CInputManager::getMouseCoordsInternal() {
return g_pPointerManager->position();
}
void CInputManager::newKeyboard(wlr_input_device* keyboard) {
const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(wlr_keyboard_from_input_device(keyboard)));
void CInputManager::newKeyboard(SP<Aquamarine::IKeyboard> keyboard) {
const auto PNEWKEYBOARD = m_vKeyboards.emplace_back(CKeyboard::create(keyboard));
setupKeyboard(PNEWKEYBOARD);
@ -856,14 +858,14 @@ void CInputManager::newVirtualKeyboard(SP<CVirtualKeyboardV1Resource> keyboard)
setupKeyboard(PNEWKEYBOARD);
Debug::log(LOG, "New virtual keyboard created, pointers Hypr: {:x} and WLR: {:x}", (uintptr_t)PNEWKEYBOARD.get(), (uintptr_t)keyboard->wlr());
Debug::log(LOG, "New virtual keyboard created at {:x}", (uintptr_t)PNEWKEYBOARD.get());
}
void CInputManager::setupKeyboard(SP<IKeyboard> keeb) {
m_vHIDs.push_back(keeb);
try {
keeb->hlName = getNameForNewDevice(keeb->wlr()->base.name);
keeb->hlName = getNameForNewDevice(keeb->deviceName);
} catch (std::exception& e) {
Debug::log(ERR, "Keyboard had no name???"); // logic error
}
@ -962,83 +964,12 @@ void CInputManager::applyConfigToKeyboard(SP<IKeyboard> pKeyboard) {
// we can ignore those and just apply
}
wlr_keyboard_set_repeat_info(pKeyboard->wlr(), std::max(0, REPEATRATE), std::max(0, REPEATDELAY));
pKeyboard->repeatDelay = REPEATDELAY;
pKeyboard->repeatRate = REPEATRATE;
pKeyboard->repeatRate = std::max(0, REPEATRATE);
pKeyboard->repeatDelay = std::max(0, REPEATDELAY);
pKeyboard->numlockOn = NUMLOCKON;
pKeyboard->xkbFilePath = FILEPATH;
xkb_rule_names rules = {.rules = RULES.c_str(), .model = MODEL.c_str(), .layout = LAYOUT.c_str(), .variant = VARIANT.c_str(), .options = OPTIONS.c_str()};
pKeyboard->currentRules.rules = RULES;
pKeyboard->currentRules.model = MODEL;
pKeyboard->currentRules.variant = VARIANT;
pKeyboard->currentRules.options = OPTIONS;
pKeyboard->currentRules.layout = LAYOUT;
const auto CONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!CONTEXT) {
Debug::log(ERR, "applyConfigToKeyboard: CONTEXT null??");
return;
}
Debug::log(LOG, "Attempting to create a keymap for layout {} with variant {} (rules: {}, model: {}, options: {})", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
xkb_keymap* KEYMAP = NULL;
if (!FILEPATH.empty()) {
auto path = absolutePath(FILEPATH, g_pConfigManager->configCurrentPath);
if (FILE* const KEYMAPFILE = fopen(path.c_str(), "r"); !KEYMAPFILE)
Debug::log(ERR, "Cannot open input:kb_file= file for reading");
else {
KEYMAP = xkb_keymap_new_from_file(CONTEXT, KEYMAPFILE, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
fclose(KEYMAPFILE);
}
}
if (!KEYMAP)
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!KEYMAP) {
g_pConfigManager->addParseError("Invalid keyboard layout passed. ( rules: " + RULES + ", model: " + MODEL + ", variant: " + VARIANT + ", options: " + OPTIONS +
", layout: " + LAYOUT + " )");
Debug::log(ERR, "Keyboard layout {} with variant {} (rules: {}, model: {}, options: {}) couldn't have been loaded.", rules.layout, rules.variant, rules.rules, rules.model,
rules.options);
memset(&rules, 0, sizeof(rules));
pKeyboard->currentRules.rules = "";
pKeyboard->currentRules.model = "";
pKeyboard->currentRules.variant = "";
pKeyboard->currentRules.options = "";
pKeyboard->currentRules.layout = "us";
KEYMAP = xkb_keymap_new_from_names(CONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
}
wlr_keyboard_set_keymap(pKeyboard->wlr(), KEYMAP);
pKeyboard->updateXKBTranslationState();
wlr_keyboard_modifiers wlrMods = {0};
if (NUMLOCKON == 1) {
// lock numlock
const auto IDX = xkb_map_mod_get_index(KEYMAP, XKB_MOD_NAME_NUM);
if (IDX != XKB_MOD_INVALID)
wlrMods.locked |= (uint32_t)1 << IDX;
}
if (wlrMods.locked != 0)
wlr_keyboard_notify_modifiers(pKeyboard->wlr(), 0, 0, wlrMods.locked, 0);
xkb_keymap_unref(KEYMAP);
xkb_context_unref(CONTEXT);
pKeyboard->setKeymap(IKeyboard::SStringRuleNames{LAYOUT, MODEL, VARIANT, OPTIONS, RULES});
const auto LAYOUTSTR = pKeyboard->getActiveLayout();
@ -1053,11 +984,11 @@ void CInputManager::newVirtualMouse(SP<CVirtualPointerV1Resource> mouse) {
setupMouse(PMOUSE);
Debug::log(LOG, "New virtual mouse created, pointer WLR: {:x}", (uintptr_t)mouse->wlr());
Debug::log(LOG, "New virtual mouse created");
}
void CInputManager::newMouse(wlr_input_device* mouse) {
const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(wlr_pointer_from_input_device(mouse)));
void CInputManager::newMouse(SP<Aquamarine::IPointer> mouse) {
const auto PMOUSE = m_vPointers.emplace_back(CMouse::create(mouse));
setupMouse(PMOUSE);
@ -1068,13 +999,13 @@ void CInputManager::setupMouse(SP<IPointer> mauz) {
m_vHIDs.push_back(mauz);
try {
mauz->hlName = getNameForNewDevice(mauz->wlr()->base.name);
mauz->hlName = getNameForNewDevice(mauz->deviceName);
} catch (std::exception& e) {
Debug::log(ERR, "Mouse had no name???"); // logic error
}
if (wlr_input_device_is_libinput(&mauz->wlr()->base)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&mauz->wlr()->base);
if (mauz->aq() && mauz->aq()->getLibinputHandle()) {
const auto LIBINPUTDEV = mauz->aq()->getLibinputHandle();
Debug::log(LOG, "New mouse has libinput sens {:.2f} ({:.2f}) with accel profile {} ({})", libinput_device_config_accel_get_speed(LIBINPUTDEV),
libinput_device_config_accel_get_default_speed(LIBINPUTDEV), (int)libinput_device_config_accel_get_profile(LIBINPUTDEV),
@ -1120,8 +1051,8 @@ void CInputManager::setPointerConfigs() {
}
}
if (wlr_input_device_is_libinput(&m->wlr()->base)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&m->wlr()->base);
if (m->aq() && m->aq()->getLibinputHandle()) {
const auto LIBINPUTDEV = m->aq()->getLibinputHandle();
double touchw = 0, touchh = 0;
const auto ISTOUCHPAD = libinput_device_has_capability(LIBINPUTDEV, LIBINPUT_DEVICE_CAP_POINTER) &&
@ -1270,7 +1201,7 @@ void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
if (m_vKeyboards.size() > 0) {
bool found = false;
for (auto& k : m_vKeyboards | std::views::reverse) {
if (!k->wlr())
if (!k)
continue;
g_pSeatManager->setKeyboard(k);
@ -1330,23 +1261,19 @@ void CInputManager::destroyTabletPad(SP<CTabletPad> pad) {
}
void CInputManager::updateKeyboardsLeds(SP<IKeyboard> pKeyboard) {
if (!pKeyboard)
if (!pKeyboard || !pKeyboard->xkbTranslationState)
return;
auto keyboard = pKeyboard->wlr();
// FIXME:
// uint32_t leds = 0;
// for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
// if (xkb_state_led_index_is_active(pKeyboard->xkbTranslationState, keyboard->led_indexes[i]))
// leds |= (1 << i);
// }
if (!keyboard || keyboard->xkb_state == nullptr)
return;
uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
if (xkb_state_led_index_is_active(keyboard->xkb_state, keyboard->led_indexes[i]))
leds |= (1 << i);
}
for (auto& k : m_vKeyboards) {
k->updateLEDs(leds);
}
// for (auto& k : m_vKeyboards) {
// k->updateLEDs(leds);
// }
}
void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {
@ -1374,7 +1301,7 @@ void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {
const auto IME = m_sIMERelay.m_pIME.lock();
if (IME && IME->hasGrab() && !DISALLOWACTION) {
IME->setKeyboard(pKeyboard->wlr());
IME->setKeyboard(pKeyboard);
IME->sendKey(e.timeMs, e.keycode, e.state);
} else {
g_pSeatManager->setKeyboard(pKeyboard);
@ -1392,15 +1319,14 @@ void CInputManager::onKeyboardMod(SP<IKeyboard> pKeyboard) {
const bool DISALLOWACTION = pKeyboard->isVirtual() && shouldIgnoreVirtualKeyboard(pKeyboard);
const auto ALLMODS = accumulateModsFromAllKBs();
const auto PWLRKB = pKeyboard->wlr();
auto MODS = PWLRKB->modifiers;
auto MODS = pKeyboard->modifiersState;
MODS.depressed = ALLMODS;
const auto IME = m_sIMERelay.m_pIME.lock();
if (IME && IME->hasGrab() && !DISALLOWACTION) {
IME->setKeyboard(PWLRKB);
IME->setKeyboard(pKeyboard);
IME->sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group);
} else {
g_pSeatManager->setKeyboard(pKeyboard);
@ -1409,8 +1335,8 @@ void CInputManager::onKeyboardMod(SP<IKeyboard> pKeyboard) {
updateKeyboardsLeds(pKeyboard);
if (PWLRKB->modifiers.group != pKeyboard->activeLayout) {
pKeyboard->activeLayout = PWLRKB->modifiers.group;
if (pKeyboard->modifiersState.group != pKeyboard->activeLayout) {
pKeyboard->activeLayout = pKeyboard->modifiersState.group;
const auto LAYOUT = pKeyboard->getActiveLayout();
@ -1524,10 +1450,10 @@ uint32_t CInputManager::accumulateModsFromAllKBs() {
if (kb->isVirtual() && shouldIgnoreVirtualKeyboard(kb))
continue;
if (!kb->enabled || !kb->wlr())
if (!kb->enabled)
continue;
finalMask |= wlr_keyboard_get_modifiers(kb->wlr());
finalMask |= kb->getModifiers();
}
return finalMask;
@ -1543,12 +1469,12 @@ void CInputManager::disableAllKeyboards(bool virt) {
}
}
void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(wlr_touch_from_input_device(pDevice)));
void CInputManager::newTouchDevice(SP<Aquamarine::ITouch> pDevice) {
const auto PNEWDEV = m_vTouches.emplace_back(CTouchDevice::create(pDevice));
m_vHIDs.push_back(PNEWDEV);
try {
PNEWDEV->hlName = getNameForNewDevice(pDevice->name);
PNEWDEV->hlName = getNameForNewDevice(PNEWDEV->deviceName);
} catch (std::exception& e) {
Debug::log(ERR, "Touch Device had no name???"); // logic error
}
@ -1572,8 +1498,8 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
auto setConfig = [&](SP<ITouch> PTOUCHDEV) -> void {
if (wlr_input_device_is_libinput(&PTOUCHDEV->wlr()->base)) {
const auto LIBINPUTDEV = (libinput_device*)wlr_libinput_get_device_handle(&PTOUCHDEV->wlr()->base);
if (dev->aq() && dev->aq()->getLibinputHandle()) {
const auto LIBINPUTDEV = dev->aq()->getLibinputHandle();
const auto ENABLED = g_pConfigManager->getDeviceInt(PTOUCHDEV->hlName, "enabled", "input:touchdevice:enabled");
const auto mode = ENABLED ? LIBINPUT_CONFIG_SEND_EVENTS_ENABLED : LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
@ -1589,11 +1515,12 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
bool bound = !output.empty() && output != STRVAL_EMPTY;
const bool AUTODETECT = output == "[[Auto]]";
if (!bound && AUTODETECT) {
const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name;
if (DEFAULTOUTPUT) {
output = DEFAULTOUTPUT;
bound = true;
}
// FIXME:
// const auto DEFAULTOUTPUT = PTOUCHDEV->wlr()->output_name;
// if (DEFAULTOUTPUT) {
// output = DEFAULTOUTPUT;
// bound = true;
// }
}
PTOUCHDEV->boundOutput = bound ? output : "";
const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr;

View file

@ -18,6 +18,10 @@ class CVirtualKeyboardV1Resource;
class CVirtualPointerV1Resource;
class IKeyboard;
AQUAMARINE_FORWARD(IPointer);
AQUAMARINE_FORWARD(IKeyboard);
AQUAMARINE_FORWARD(ITouch);
enum eClickBehaviorMode {
CLICKMODE_DEFAULT = 0,
CLICKMODE_KILL
@ -82,11 +86,11 @@ class CInputManager {
void onKeyboardKey(std::any, SP<IKeyboard>);
void onKeyboardMod(SP<IKeyboard>);
void newKeyboard(wlr_input_device*);
void newKeyboard(SP<Aquamarine::IKeyboard>);
void newVirtualKeyboard(SP<CVirtualKeyboardV1Resource>);
void newMouse(wlr_input_device*);
void newMouse(SP<Aquamarine::IPointer>);
void newVirtualMouse(SP<CVirtualPointerV1Resource>);
void newTouchDevice(wlr_input_device*);
void newTouchDevice(SP<Aquamarine::ITouch>);
void newSwitch(wlr_input_device*);
void newTabletTool(wlr_tablet_tool*);
void newTabletPad(wlr_input_device*);

View file

@ -34,7 +34,7 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* out
}
}
gammaSize = wlr_output_get_gamma_size(pMonitor->output);
gammaSize = pMonitor->output->getGammaSize();
if (gammaSize <= 0) {
LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName);
@ -95,7 +95,7 @@ CGammaControl::~CGammaControl() {
return;
// reset the LUT if the client dies for whatever reason and doesn't unset the gamma
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
pMonitor->output->state->setGammaLut({});
}
bool CGammaControl::good() {
@ -109,19 +109,15 @@ void CGammaControl::applyToMonitor() {
LOGM(LOG, "setting to monitor {}", pMonitor->szName);
if (!gammaTableSet) {
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
pMonitor->output->state->setGammaLut({});
return;
}
uint16_t* red = &gammaTable.at(0);
uint16_t* green = &gammaTable.at(gammaSize);
uint16_t* blue = &gammaTable.at(gammaSize * 2);
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), gammaSize, red, green, blue);
pMonitor->output->state->setGammaLut(gammaTable);
if (!pMonitor->state.test()) {
LOGM(LOG, "setting to monitor {} failed", pMonitor->szName);
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
pMonitor->output->state->setGammaLut({});
}
g_pHyprRenderer->damageMonitor(pMonitor);

View file

@ -19,7 +19,7 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SP<CZwpInputMethodKeyboar
return;
}
sendKeyboardData(g_pSeatManager->keyboard->wlr());
sendKeyboardData(g_pSeatManager->keyboard.lock());
}
CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() {
@ -27,37 +27,36 @@ CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() {
std::erase_if(owner->grabs, [](const auto& g) { return g.expired(); });
}
void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) {
void CInputMethodKeyboardGrabV2::sendKeyboardData(SP<IKeyboard> keyboard) {
if (keyboard == pLastKeyboard)
return;
pLastKeyboard = keyboard;
int keymapFD = allocateSHMFile(keyboard->keymap_size);
int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1);
if (keymapFD < 0) {
LOGM(ERR, "Failed to create a keymap file for keyboard grab");
return;
}
void* data = mmap(nullptr, keyboard->keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0);
void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0);
if (data == MAP_FAILED) {
LOGM(ERR, "Failed to mmap a keymap file for keyboard grab");
close(keymapFD);
return;
}
memcpy(data, keyboard->keymap_string, keyboard->keymap_size);
munmap(data, keyboard->keymap_size);
memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length());
munmap(data, keyboard->xkbKeymapString.length() + 1);
resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->keymap_size);
resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1);
close(keymapFD);
const auto MODS = keyboard->modifiers;
sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group);
sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group);
resource->sendRepeatInfo(keyboard->repeat_info.rate, keyboard->repeat_info.delay);
resource->sendRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay);
}
void CInputMethodKeyboardGrabV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) {
@ -316,7 +315,7 @@ void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t loc
}
}
void CInputMethodV2::setKeyboard(wlr_keyboard* keyboard) {
void CInputMethodV2::setKeyboard(SP<IKeyboard> keyboard) {
for (auto& gw : grabs) {
auto g = gw.lock();

View file

@ -11,6 +11,7 @@
class CInputMethodKeyboardGrabV2;
class CInputMethodPopupV2;
class IKeyboard;
class CInputMethodV2 {
public:
@ -58,7 +59,7 @@ class CInputMethodV2 {
bool hasGrab();
void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state);
void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
void setKeyboard(wlr_keyboard* keyboard);
void setKeyboard(SP<IKeyboard> keyboard);
wl_client* client();
wl_client* grabClient();
@ -90,13 +91,13 @@ class CInputMethodKeyboardGrabV2 {
void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state);
void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
void sendKeyboardData(wlr_keyboard* keyboard);
void sendKeyboardData(SP<IKeyboard> keyboard);
private:
SP<CZwpInputMethodKeyboardGrabV2> resource;
WP<CInputMethodV2> owner;
wlr_keyboard* pLastKeyboard = nullptr; // READ-ONLY
WP<IKeyboard> pLastKeyboard;
};
class CInputMethodPopupV2 {

View file

@ -73,7 +73,7 @@ CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() {
close(tableFD);
}
CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) {
CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) {
buffer = makeShared<CDMABuffer>(id, client, attrs);
buffer->resource->buffer = buffer;
@ -103,7 +103,7 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParam
resource->setOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
attrs = makeShared<SDMABUFAttrs>();
attrs = makeShared<Aquamarine::SDMABUFAttrs>();
attrs->success = true;
@ -376,7 +376,7 @@ void CLinuxDMABUFResource::sendMods() {
CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) {
int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
int rendererFD = g_pCompositor->m_iDRMFD;
auto dev = devIDFromFD(rendererFD);
if (!dev.has_value()) {

View file

@ -7,15 +7,15 @@
#include "wayland.hpp"
#include "linux-dmabuf-v1.hpp"
#include "../helpers/signal/Signal.hpp"
#include <aquamarine/buffer/Buffer.hpp>
class CDMABuffer;
struct SDRMFormat;
struct SDMABUFAttrs;
class CWLSurfaceResource;
class CLinuxDMABuffer {
public:
CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs);
CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs);
~CLinuxDMABuffer();
bool good();
@ -66,12 +66,12 @@ class CLinuxDMABBUFParamsResource {
CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParamsV1> resource_);
~CLinuxDMABBUFParamsResource();
bool good();
void create(uint32_t id); // 0 means not immed
bool good();
void create(uint32_t id); // 0 means not immed
SP<SDMABUFAttrs> attrs;
WP<CLinuxDMABuffer> createdBuffer;
bool used = false;
SP<Aquamarine::SDMABUFAttrs> attrs;
WP<CLinuxDMABuffer> createdBuffer;
bool used = false;
private:
SP<CZwpLinuxBufferParamsV1> resource;

View file

@ -7,7 +7,7 @@
#define LOGM PROTO::mesaDRM->protoLog
CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) {
CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) {
LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes);
for (int i = 0; i < attrs_.planes; ++i) {
LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]);
@ -60,7 +60,7 @@ CMesaDRMResource::CMesaDRMResource(SP<CWlDrm> resource_) : resource(resource_) {
return;
}
SDMABUFAttrs attrs;
Aquamarine::SDMABUFAttrs attrs;
attrs.success = true;
attrs.size = {w, h};
attrs.modifier = DRM_FORMAT_MOD_INVALID;
@ -97,7 +97,7 @@ bool CMesaDRMResource::good() {
CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
drmDevice* dev = nullptr;
int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
int drmFD = g_pCompositor->m_iDRMFD;
if (drmGetDevice2(drmFD, 0, &dev) != 0) {
LOGM(ERR, "Failed to get device");
PROTO::mesaDRM.reset();

View file

@ -10,7 +10,7 @@
class CMesaDRMBufferResource {
public:
CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs);
CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs);
~CMesaDRMBufferResource();
bool good();

View file

@ -2,6 +2,8 @@
#include <algorithm>
#include "../Compositor.hpp"
using namespace Aquamarine;
#define LOGM PROTO::outputManagement->protoLog
COutputManager::COutputManager(SP<CZwlrOutputManagerV1> resource_) : resource(resource_) {
@ -123,8 +125,8 @@ void COutputHead::sendAllData() {
resource->sendName(pMonitor->szName.c_str());
resource->sendDescription(pMonitor->szDescription.c_str());
if (pMonitor->output->phys_width > 0 && pMonitor->output->phys_height > 0)
resource->sendPhysicalSize(pMonitor->output->phys_width, pMonitor->output->phys_height);
if (pMonitor->output->physicalSize.x > 0 && pMonitor->output->physicalSize.y > 0)
resource->sendPhysicalSize(pMonitor->output->physicalSize.x, pMonitor->output->physicalSize.y);
resource->sendEnabled(pMonitor->m_bEnabled);
if (pMonitor->m_bEnabled) {
@ -133,12 +135,12 @@ void COutputHead::sendAllData() {
resource->sendScale(wl_fixed_from_double(pMonitor->scale));
}
if (pMonitor->output->make && VERSION >= 2)
resource->sendMake(pMonitor->output->make);
if (pMonitor->output->model && VERSION >= 2)
resource->sendModel(pMonitor->output->model);
if (pMonitor->output->serial && VERSION >= 2)
resource->sendSerialNumber(pMonitor->output->serial);
if (!pMonitor->output->make.empty() && VERSION >= 2)
resource->sendMake(pMonitor->output->make.c_str());
if (!pMonitor->output->model.empty() && VERSION >= 2)
resource->sendModel(pMonitor->output->model.c_str());
if (!pMonitor->output->serial.empty() && VERSION >= 2)
resource->sendSerialNumber(pMonitor->output->serial.c_str());
if (VERSION >= 4)
resource->sendAdaptiveSync(pMonitor->vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED);
@ -146,12 +148,12 @@ void COutputHead::sendAllData() {
// send all available modes
if (modes.empty()) {
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
wl_list_for_each(mode, &pMonitor->output->modes, link) {
makeAndSendNewMode(mode);
if (!pMonitor->output->modes.empty()) {
for (auto& m : pMonitor->output->modes) {
makeAndSendNewMode(m);
}
} else if (pMonitor->output->state->state().customMode) {
makeAndSendNewMode(pMonitor->output->state->state().customMode);
} else
makeAndSendNewMode(nullptr);
}
@ -164,9 +166,9 @@ void COutputHead::sendAllData() {
if (!m)
continue;
if (m->mode == pMonitor->currentMode) {
if (m->mode == pMonitor->output->state->state().mode) {
if (m->mode)
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh);
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate);
else
LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName);
resource->sendCurrentMode(m->resource.get());
@ -197,7 +199,7 @@ void COutputHead::updateMode() {
if (m->mode == pMonitor->currentMode) {
if (m->mode)
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh);
LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate);
else
LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName);
resource->sendCurrentMode(m->resource.get());
@ -207,7 +209,7 @@ void COutputHead::updateMode() {
}
}
void COutputHead::makeAndSendNewMode(wlr_output_mode* mode) {
void COutputHead::makeAndSendNewMode(SP<Aquamarine::SOutputMode> mode) {
const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared<COutputMode>(makeShared<CZwlrOutputModeV1>(resource->client(), resource->version(), 0), mode));
if (!RESOURCE->good()) {
@ -225,7 +227,7 @@ CMonitor* COutputHead::monitor() {
return pMonitor;
}
COutputMode::COutputMode(SP<CZwlrOutputModeV1> resource_, wlr_output_mode* mode_) : resource(resource_), mode(mode_) {
COutputMode::COutputMode(SP<CZwlrOutputModeV1> resource_, SP<Aquamarine::SOutputMode> mode_) : resource(resource_), mode(mode_) {
if (!good())
return;
@ -237,11 +239,11 @@ void COutputMode::sendAllData() {
if (!mode)
return;
LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->width, mode->height, mode->refresh, mode->preferred);
LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate, mode->preferred);
resource->sendSize(mode->width, mode->height);
if (mode->refresh > 0)
resource->sendRefresh(mode->refresh);
resource->sendSize(mode->pixelSize.x, mode->pixelSize.y);
if (mode->refreshRate > 0)
resource->sendRefresh(mode->refreshRate);
if (mode->preferred)
resource->sendPreferred();
}
@ -250,8 +252,8 @@ bool COutputMode::good() {
return resource->resource();
}
wlr_output_mode* COutputMode::getMode() {
return mode;
SP<Aquamarine::SOutputMode> COutputMode::getMode() {
return mode.lock();
}
COutputConfiguration::COutputConfiguration(SP<CZwlrOutputConfigurationV1> resource_, SP<COutputManager> owner_) : resource(resource_), owner(owner_) {
@ -364,8 +366,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) {
newRule.disabled = false;
if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) {
newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height};
newRule.refreshRate = head->state.mode->getMode()->refresh / 1000.F;
newRule.resolution = head->state.mode->getMode()->pixelSize;
newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F;
} else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) {
newRule.resolution = head->state.customMode.size;
newRule.refreshRate = head->state.customMode.refresh / 1000.F;
@ -425,7 +427,7 @@ COutputConfigurationHead::COutputConfigurationHead(SP<CZwlrOutputConfigurationHe
committedProperties |= OUTPUT_HEAD_COMMITTED_MODE;
state.mode = MODE;
LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->width, MODE->getMode()->height, MODE->getMode()->refresh);
LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate);
});
resource->setSetCustomMode([this](CZwlrOutputConfigurationHeadV1* r, int32_t w, int32_t h, int32_t refresh) {

View file

@ -6,6 +6,7 @@
#include "WaylandProtocol.hpp"
#include "wlr-output-management-unstable-v1.hpp"
#include "../helpers/signal/Signal.hpp"
#include <aquamarine/output/Output.hpp>
class CMonitor;
@ -34,15 +35,15 @@ class COutputManager {
class COutputMode {
public:
COutputMode(SP<CZwlrOutputModeV1> resource_, wlr_output_mode* mode_);
COutputMode(SP<CZwlrOutputModeV1> resource_, SP<Aquamarine::SOutputMode> mode_);
bool good();
wlr_output_mode* getMode();
void sendAllData();
bool good();
SP<Aquamarine::SOutputMode> getMode();
void sendAllData();
private:
SP<CZwlrOutputModeV1> resource;
wlr_output_mode* mode = nullptr;
SP<CZwlrOutputModeV1> resource;
WP<Aquamarine::SOutputMode> mode;
friend class COutputHead;
friend class COutputManagementProtocol;
@ -61,7 +62,7 @@ class COutputHead {
SP<CZwlrOutputHeadV1> resource;
CMonitor* pMonitor = nullptr;
void makeAndSendNewMode(wlr_output_mode* mode);
void makeAndSendNewMode(SP<Aquamarine::SOutputMode> mode);
void sendCurrentMode();
std::vector<WP<COutputMode>> modes;

View file

@ -17,7 +17,7 @@ COutputPower::COutputPower(SP<CZwlrOutputPowerV1> resource_, CMonitor* pMonitor_
pMonitor->dpmsStatus = mode == ZWLR_OUTPUT_POWER_V1_MODE_ON;
wlr_output_state_set_enabled(pMonitor->state.wlr(), pMonitor->dpmsStatus);
pMonitor->output->state->setEnabled(mode == ZWLR_OUTPUT_POWER_V1_MODE_ON);
if (!pMonitor->state.commit())
LOGM(ERR, "Couldn't set dpms to {} for {}", pMonitor->dpmsStatus, pMonitor->szName);

View file

@ -3,6 +3,7 @@
#include "../helpers/Monitor.hpp"
#include "../managers/HookSystemManager.hpp"
#include "core/Compositor.hpp"
#include "core/Output.hpp"
#define LOGM PROTO::presentation->protoLog
@ -41,13 +42,11 @@ bool CPresentationFeedback::good() {
}
void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) {
auto client = resource->client();
wl_resource* res;
wl_resource_for_each(res, &data->pMonitor->output->resources) {
if (client == wl_resource_get_client(res)) {
resource->sendSyncOutput(res);
break;
}
auto client = resource->client();
if (PROTO::outputs.contains(data->pMonitor->szName)) {
if (auto outputResource = PROTO::outputs.at(data->pMonitor->szName)->outputResourceFrom(client); outputResource)
resource->sendSyncOutput(outputResource->getResource()->resource());
}
uint32_t flags = 0;

View file

@ -266,20 +266,17 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r
return;
}
if (PFRAME->pMonitor->output->allocator && (PFRAME->pMonitor->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
PFRAME->dmabufFormat = PFRAME->pMonitor->output->render_format;
} else {
PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
}
PFRAME->dmabufFormat = PFRAME->pMonitor->output->state->state().drmFormat;
if (box.width == 0 && box.height == 0)
PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x), (int)(PFRAME->pMonitor->vecSize.y)};
else {
PFRAME->box = box;
}
int ow, oh;
wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh);
PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), ow, oh).scale(PFRAME->pMonitor->scale).round();
PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), PFRAME->pMonitor->vecTransformedSize.x, PFRAME->pMonitor->vecTransformedSize.y)
.scale(PFRAME->pMonitor->scale)
.round();
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
@ -383,10 +380,10 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
g_pHyprRenderer->damageMonitor(PFRAME->pMonitor);
}
void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) {
m_pLastMonitorBackBuffer = e->state->buffer;
void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor) {
m_pLastMonitorBackBuffer = pMonitor->output->state->state().buffer;
shareAllFrames(pMonitor);
m_pLastMonitorBackBuffer = nullptr;
m_pLastMonitorBackBuffer.reset();
}
void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) {
@ -473,11 +470,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) {
}
bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer);
if (!sourceTex)
return false;
auto TEXTURE = makeShared<CTexture>(sourceTex);
auto TEXTURE = makeShared<CTexture>(m_pLastMonitorBackBuffer);
auto shm = frame->buffer->shm();
auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm
@ -489,10 +482,8 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
CFramebuffer fb;
fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat);
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) {
wlr_texture_destroy(sourceTex);
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true))
return false;
}
CBox monbox = CBox{0, 0, frame->pMonitor->vecTransformedSize.x, frame->pMonitor->vecTransformedSize.y}.translate({-frame->box.x, -frame->box.y});
g_pHyprOpenGL->setMonitorTransformEnabled(true);
@ -510,7 +501,6 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format);
if (!PFORMAT) {
g_pHyprRenderer->endRender();
wlr_texture_destroy(sourceTex);
return false;
}
@ -539,27 +529,20 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec*
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
wlr_texture_destroy(sourceTex);
return true;
}
bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer);
if (!sourceTex)
return false;
auto TEXTURE = makeShared<CTexture>(sourceTex);
auto TEXTURE = makeShared<CTexture>(m_pLastMonitorBackBuffer);
CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX};
if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true))
return false;
CBox monbox =
CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}
.translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
.transform(wlTransformToHyprutils(wlr_output_transform_invert(frame->pMonitor->output->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y}
.translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh.
.transform(wlTransformToHyprutils(wlr_output_transform_invert(frame->pMonitor->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y);
g_pHyprOpenGL->setMonitorTransformEnabled(true);
g_pHyprOpenGL->setRenderModifEnabled(false);
g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1);
@ -569,7 +552,5 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
g_pHyprRenderer->endRender();
wlr_texture_destroy(sourceTex);
return true;
}

View file

@ -10,7 +10,7 @@
#include "../managers/eventLoop/EventLoopTimer.hpp"
class CMonitor;
class IWLBuffer;
class IHLBuffer;
enum eClientOwners {
CLIENT_SCREENCOPY = 0,
@ -56,7 +56,7 @@ struct SScreencopyFrame {
bool bufferDMA = false;
WP<IWLBuffer> buffer;
WP<IHLBuffer> buffer;
CMonitor* pMonitor = nullptr;
PHLWINDOWREF pWindow;
@ -79,7 +79,7 @@ class CScreencopyProtocolManager {
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer);
void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e);
void onOutputCommit(CMonitor* pMonitor);
private:
wl_global* m_pGlobal = nullptr;
@ -93,7 +93,7 @@ class CScreencopyProtocolManager {
std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
wlr_buffer* m_pLastMonitorBackBuffer = nullptr;
SP<Aquamarine::IBuffer> m_pLastMonitorBackBuffer;
void shareAllFrames(CMonitor* pMonitor);
void shareFrame(SScreencopyFrame* frame);

View file

@ -193,16 +193,11 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou
return;
}
if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) {
PFRAME->dmabufFormat = PMONITOR->output->render_format;
} else {
PFRAME->dmabufFormat = DRM_FORMAT_INVALID;
}
PFRAME->dmabufFormat = PMONITOR->output->state->state().drmFormat;
PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)};
int ow, oh;
wlr_output_effective_resolution(PMONITOR->output, &ow, &oh);
PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), ow, oh).round();
PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round();
PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w);
@ -289,12 +284,10 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r
m_vFramesAwaitingWrite.emplace_back(PFRAME);
}
void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) {
void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor) {
if (m_vFramesAwaitingWrite.empty())
return; // nothing to share
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(e->output);
std::vector<SScreencopyFrame*> framesToRemove;
// share frame if correct output
@ -306,7 +299,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp
continue;
}
if (PMONITOR != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID))
continue;
CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y};

View file

@ -21,7 +21,7 @@ class CToplevelExportProtocolManager {
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
void displayDestroy();
void onWindowUnmap(PHLWINDOW pWindow);
void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e);
void onOutputCommit(CMonitor* pMonitor);
private:
wl_global* m_pGlobal = nullptr;

View file

@ -1,12 +1,9 @@
#include "VirtualKeyboard.hpp"
#include <sys/mman.h>
#include "../devices/IKeyboard.hpp"
#define LOGM PROTO::virtualKeyboard->protoLog
static const struct wlr_keyboard_impl virtualKeyboardImpl = {
.name = "virtual-keyboard",
};
CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1> resource_) : resource(resource_) {
if (!good())
return;
@ -28,13 +25,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
return;
}
wlr_keyboard_key_event event = {
.time_msec = timeMs,
.keycode = key,
.update_state = false,
.state = (wl_keyboard_key_state)state,
};
wlr_keyboard_notify_key(&keyboard, &event);
events.key.emit(IKeyboard::SKeyEvent{
.timeMs = timeMs,
.keycode = key,
.state = (wl_keyboard_key_state)state,
});
const bool CONTAINS = std::find(pressed.begin(), pressed.end(), key) != pressed.end();
if (state && !CONTAINS)
pressed.emplace_back(key);
else if (!state && CONTAINS)
std::erase(pressed, key);
});
resource->setModifiers([this](CZwpVirtualKeyboardV1* r, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
@ -43,7 +44,12 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
return;
}
wlr_keyboard_notify_modifiers(&keyboard, depressed, latched, locked, group);
events.modifiers.emit(IKeyboard::SModifiersEvent{
.depressed = depressed,
.latched = latched,
.locked = locked,
.group = group,
});
});
resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) {
@ -75,7 +81,9 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
return;
}
wlr_keyboard_set_keymap(&keyboard, xkbKeymap);
events.keymap.emit(IKeyboard::SKeymapEvent{
.keymap = xkbKeymap,
});
hasKeymap = true;
xkb_keymap_unref(xkbKeymap);
@ -83,22 +91,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
close(fd);
});
wlr_keyboard_init(&keyboard, &virtualKeyboardImpl, "CVirtualKeyboard");
name = "hl-virtual-keyboard";
}
CVirtualKeyboardV1Resource::~CVirtualKeyboardV1Resource() {
events.destroy.emit();
wlr_keyboard_finish(&keyboard);
}
bool CVirtualKeyboardV1Resource::good() {
return resource->resource();
}
wlr_keyboard* CVirtualKeyboardV1Resource::wlr() {
return &keyboard;
}
wl_client* CVirtualKeyboardV1Resource::client() {
return resource->resource() ? resource->client() : nullptr;
}
@ -106,17 +109,16 @@ wl_client* CVirtualKeyboardV1Resource::client() {
void CVirtualKeyboardV1Resource::releasePressed() {
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
size_t keycodesNum = keyboard.num_keycodes;
for (size_t i = 0; i < keycodesNum; ++i) {
struct wlr_keyboard_key_event event = {
.time_msec = (now.tv_sec * 1000 + now.tv_nsec / 1000000),
.keycode = keyboard.keycodes[keycodesNum - i - 1],
.update_state = false,
.state = WL_KEYBOARD_KEY_STATE_RELEASED,
};
wlr_keyboard_notify_key(&keyboard, &event); // updates num_keycodes
for (auto& p : pressed) {
events.key.emit(IKeyboard::SKeyEvent{
.timeMs = now.tv_sec * 1000 + now.tv_nsec / 1000000,
.keycode = p,
.state = WL_KEYBOARD_KEY_STATE_RELEASED,
});
}
pressed.clear();
}
CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {

View file

@ -14,19 +14,24 @@ class CVirtualKeyboardV1Resource {
struct {
CSignal destroy;
CSignal key;
CSignal modifiers;
CSignal keymap;
} events;
bool good();
wlr_keyboard* wlr();
wl_client* client();
bool good();
wl_client* client();
std::string name = "";
private:
SP<CZwpVirtualKeyboardV1> resource;
wlr_keyboard keyboard;
void releasePressed();
bool hasKeymap = false;
std::vector<uint32_t> pressed;
};
class CVirtualKeyboardProtocol : public IWaylandProtocol {

View file

@ -2,10 +2,6 @@
#define LOGM PROTO::virtualPointer->protoLog
static const wlr_pointer_impl pointerImpl = {
.name = "virtual-pointer-v1",
};
CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> resource_) : resource(resource_) {
if (!good())
return;
@ -19,41 +15,30 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
PROTO::virtualPointer->destroyResource(this);
});
wlr_pointer_init(&pointer, &pointerImpl, "CVirtualPointerV1Resource");
resource->setMotion([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, wl_fixed_t dx, wl_fixed_t dy) {
wlr_pointer_motion_event event = {
.pointer = &pointer,
.time_msec = timeMs,
.delta_x = wl_fixed_to_double(dx),
.delta_y = wl_fixed_to_double(dy),
.unaccel_dx = wl_fixed_to_double(dx),
.unaccel_dy = wl_fixed_to_double(dy),
};
wl_signal_emit_mutable(&pointer.events.motion, &event);
events.move.emit(IPointer::SMotionEvent{
.timeMs = timeMs,
.delta = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)},
.unaccel = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)},
});
});
resource->setMotionAbsolute([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t x, uint32_t y, uint32_t xExtent, uint32_t yExtent) {
if (!xExtent || !yExtent)
return;
wlr_pointer_motion_absolute_event event = {
.pointer = &pointer,
.time_msec = timeMs,
.x = (double)x / xExtent,
.y = (double)y / yExtent,
};
wl_signal_emit_mutable(&pointer.events.motion_absolute, &event);
events.warp.emit(IPointer::SMotionAbsoluteEvent{
.timeMs = timeMs,
.absolute = {(double)x / xExtent, (double)y / yExtent},
});
});
resource->setButton([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t button, uint32_t state) {
struct wlr_pointer_button_event event = {
.pointer = &pointer,
.time_msec = timeMs,
.button = button,
.state = (wl_pointer_button_state)state,
};
wl_signal_emit_mutable(&pointer.events.button, &event);
events.button.emit(IPointer::SButtonEvent{
.timeMs = timeMs,
.button = button,
.state = (wl_pointer_button_state)state,
});
});
resource->setAxis([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value) {
@ -63,18 +48,18 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
}
axis = axis_;
axisEvents[axis] = wlr_pointer_axis_event{.pointer = &pointer, .time_msec = timeMs, .orientation = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)};
axisEvents[axis] = IPointer::SAxisEvent{.timeMs = timeMs, .axis = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)};
});
resource->setFrame([this](CZwlrVirtualPointerV1* r) {
for (auto& e : axisEvents) {
if (!e.pointer)
if (!e.timeMs)
continue;
wl_signal_emit_mutable(&pointer.events.axis, &e);
e.pointer = nullptr;
events.axis.emit(e);
e.timeMs = 0;
}
wl_signal_emit_mutable(&pointer.events.frame, &pointer);
events.frame.emit();
});
resource->setAxisSource([this](CZwlrVirtualPointerV1* r, uint32_t source) { axisEvents[axis].source = (wl_pointer_axis_source)source; });
@ -85,12 +70,11 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
return;
}
axis = axis_;
axisEvents[axis].pointer = &pointer;
axisEvents[axis].time_msec = timeMs;
axisEvents[axis].orientation = (wl_pointer_axis)axis;
axisEvents[axis].delta = 0;
axisEvents[axis].delta_discrete = 0;
axis = axis_;
axisEvents[axis].timeMs = timeMs;
axisEvents[axis].axis = (wl_pointer_axis)axis;
axisEvents[axis].delta = 0;
axisEvents[axis].deltaDiscrete = 0;
});
resource->setAxisDiscrete([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value, int32_t discrete) {
@ -99,17 +83,15 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> r
return;
}
axis = axis_;
axisEvents[axis].pointer = &pointer;
axisEvents[axis].time_msec = timeMs;
axisEvents[axis].orientation = (wl_pointer_axis)axis;
axisEvents[axis].delta = wl_fixed_to_double(value);
axisEvents[axis].delta_discrete = discrete * 120;
axis = axis_;
axisEvents[axis].timeMs = timeMs;
axisEvents[axis].axis = (wl_pointer_axis)axis;
axisEvents[axis].delta = wl_fixed_to_double(value);
axisEvents[axis].deltaDiscrete = discrete * 120;
});
}
CVirtualPointerV1Resource::~CVirtualPointerV1Resource() {
wlr_pointer_finish(&pointer);
events.destroy.emit();
}
@ -117,10 +99,6 @@ bool CVirtualPointerV1Resource::good() {
return resource->resource();
}
wlr_pointer* CVirtualPointerV1Resource::wlr() {
return &pointer;
}
wl_client* CVirtualPointerV1Resource::client() {
return resource->client();
}

View file

@ -7,6 +7,7 @@
#include "WaylandProtocol.hpp"
#include "wlr-virtual-pointer-unstable-v1.hpp"
#include "../helpers/signal/Signal.hpp"
#include "../devices/IPointer.hpp"
class CVirtualPointerV1Resource {
public:
@ -15,19 +16,35 @@ class CVirtualPointerV1Resource {
struct {
CSignal destroy;
CSignal move;
CSignal warp;
CSignal button;
CSignal axis;
CSignal frame;
CSignal swipeBegin;
CSignal swipeUpdate;
CSignal swipeEnd;
CSignal pinchBegin;
CSignal pinchUpdate;
CSignal pinchEnd;
CSignal holdBegin;
CSignal holdEnd;
} events;
bool good();
wlr_pointer* wlr();
wl_client* client();
bool good();
wl_client* client();
std::string name;
private:
SP<CZwlrVirtualPointerV1> resource;
wlr_pointer pointer;
SP<CZwlrVirtualPointerV1> resource;
uint32_t axis = 0;
uint32_t axis = 0;
std::array<wlr_pointer_axis_event, 2> axisEvents;
std::array<IPointer::SAxisEvent, 2> axisEvents;
};
class CVirtualPointerProtocol : public IWaylandProtocol {

View file

@ -75,8 +75,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32
if (XDGVER >= OUTPUT_NAME_SINCE_VERSION)
pXDGOutput->resource->sendName(PMONITOR->szName.c_str());
if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && PMONITOR->output->description)
pXDGOutput->resource->sendDescription(PMONITOR->output->description);
if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && !PMONITOR->output->description.empty())
pXDGOutput->resource->sendDescription(PMONITOR->output->description.c_str());
pXDGOutput->sendDetails();
@ -93,7 +93,7 @@ void CXDGOutputProtocol::updateAllOutputs() {
o->sendDetails();
wlr_output_schedule_done(o->monitor->output);
o->monitor->scheduleDone();
}
}

View file

@ -85,7 +85,7 @@ class CWLSurfaceResource {
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
int scale = 1;
SP<IWLBuffer> buffer;
SP<IHLBuffer> buffer;
SP<CTexture> texture;
Vector2D offset;
Vector2D size;

View file

@ -21,8 +21,8 @@ CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> pMoni
PROTO::outputs.at(monitor->szName)->destroyResource(this);
});
resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null",
monitor->output->model ? monitor->output->model : "null", monitor->transform);
resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(),
monitor->output->model.c_str(), monitor->transform);
if (resource->version() >= 4) {
resource->sendName(monitor->szName.c_str());
resource->sendDescription(monitor->szDescription.c_str());
@ -115,3 +115,9 @@ void CWLOutputProtocol::remove() {
bool CWLOutputProtocol::isDefunct() {
return defunct;
}
void CWLOutputProtocol::sendDone() {
for (auto& r : m_vOutputs) {
r->resource->sendDone();
}
}

View file

@ -26,6 +26,8 @@ class CWLOutputResource {
private:
SP<CWlOutput> resource;
wl_client* pClient = nullptr;
friend class CWLOutputProtocol;
};
class CWLOutputProtocol : public IWaylandProtocol {
@ -35,6 +37,7 @@ class CWLOutputProtocol : public IWaylandProtocol {
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
SP<CWLOutputResource> outputResourceFrom(wl_client* client);
void sendDone();
WP<CMonitor> monitor;

View file

@ -254,8 +254,8 @@ void CWLKeyboardResource::sendKeymap(SP<IKeyboard> keyboard) {
int fd;
uint32_t size;
if (keyboard) {
fd = keyboard->wlr()->keymap_fd;
size = keyboard->wlr()->keymap_size;
fd = keyboard->xkbKeymapFD;
size = keyboard->xkbKeymapString.length() + 1;
} else {
fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
if (fd < 0) {

View file

@ -41,20 +41,20 @@ CWLSHMBuffer::~CWLSHMBuffer() {
;
}
eBufferCapability CWLSHMBuffer::caps() {
return BUFFER_CAPABILITY_DATAPTR;
Aquamarine::eBufferCapability CWLSHMBuffer::caps() {
return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
eBufferType CWLSHMBuffer::type() {
return BUFFER_TYPE_SHM;
Aquamarine::eBufferType CWLSHMBuffer::type() {
return Aquamarine::eBufferType::BUFFER_TYPE_SHM;
}
bool CWLSHMBuffer::isSynchronous() {
return true;
}
SSHMAttrs CWLSHMBuffer::shm() {
SSHMAttrs attrs;
Aquamarine::SSHMAttrs CWLSHMBuffer::shm() {
Aquamarine::SSHMAttrs attrs;
attrs.success = true;
attrs.fd = pool->fd;
attrs.format = FormatUtils::shmToDRM(fmt);
@ -188,12 +188,11 @@ CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const
void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
if (shmFormats.empty()) {
size_t len = 0;
const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len);
size_t len = 0;
// TODO: support 10 bit shm
for (size_t i = 0; i < len; ++i) {
shmFormats.push_back(FormatUtils::drmToShm(formats[i]));
}
shmFormats.push_back(WL_SHM_FORMAT_ARGB8888);
shmFormats.push_back(WL_SHM_FORMAT_XRGB8888);
}
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CWLSHMResource>(makeShared<CWlShm>(client, ver, id)));

View file

@ -29,16 +29,16 @@ class CSHMPool {
void resize(size_t size);
};
class CWLSHMBuffer : public IWLBuffer {
class CWLSHMBuffer : public IHLBuffer {
public:
CWLSHMBuffer(SP<CWLSHMPoolResource> pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt);
virtual ~CWLSHMBuffer();
virtual eBufferCapability caps();
virtual eBufferType type();
virtual Aquamarine::eBufferCapability caps();
virtual Aquamarine::eBufferType type();
virtual void update(const CRegion& damage);
virtual bool isSynchronous();
virtual SSHMAttrs shm();
virtual Aquamarine::SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();

View file

@ -1,41 +1,5 @@
#include "Buffer.hpp"
#include "WLBuffer.hpp"
SDMABUFAttrs IWLBuffer::dmabuf() {
return SDMABUFAttrs{};
}
SSHMAttrs IWLBuffer::shm() {
return SSHMAttrs{};
}
std::tuple<uint8_t*, uint32_t, size_t> IWLBuffer::beginDataPtr(uint32_t flags) {
return {nullptr, 0, 0};
}
void IWLBuffer::endDataPtr() {
; // empty
}
void IWLBuffer::sendRelease() {
if (!resource || !resource->resource)
return;
resource->resource->sendRelease();
}
void IWLBuffer::lock() {
locks++;
}
void IWLBuffer::unlock() {
locks--;
ASSERT(locks >= 0);
if (locks <= 0)
sendRelease();
}
bool IWLBuffer::locked() {
return locks;
void IHLBuffer::sendRelease() {
resource->sendRelease();
}

View file

@ -1,75 +1,24 @@
#pragma once
#include "../../defines.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../render/Texture.hpp"
#include "./WLBuffer.hpp"
#include <array>
#include <tuple>
#include <aquamarine/buffer/Buffer.hpp>
enum eBufferCapability {
BUFFER_CAPABILITY_DATAPTR = (1 << 0),
};
enum eBufferType {
BUFFER_TYPE_DMABUF = 0,
BUFFER_TYPE_SHM,
BUFFER_TYPE_MISC,
};
class CWLBufferResource;
struct SDMABUFAttrs {
bool success = false;
Vector2D size;
uint32_t format = 0; // fourcc
uint64_t modifier = 0;
int planes = 1;
std::array<uint32_t, 4> offsets = {0};
std::array<uint32_t, 4> strides = {0};
std::array<int, 4> fds = {-1, -1, -1, -1};
};
struct SSHMAttrs {
bool success = false;
int fd = 0;
uint32_t format = 0;
Vector2D size;
int stride = 0;
int64_t offset = 0;
};
class IWLBuffer {
class IHLBuffer : public Aquamarine::IBuffer {
public:
virtual ~IWLBuffer() {
virtual ~IHLBuffer() {
;
};
}
virtual Aquamarine::eBufferCapability caps() = 0;
virtual Aquamarine::eBufferType type() = 0;
virtual void update(const CRegion& damage) = 0;
virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu
virtual bool good() = 0;
virtual void sendRelease();
virtual eBufferCapability caps() = 0;
virtual eBufferType type() = 0;
virtual void update(const CRegion& damage) = 0;
virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu
virtual SDMABUFAttrs dmabuf();
virtual SSHMAttrs shm();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
virtual void sendRelease();
virtual void lock();
virtual void unlock();
virtual bool locked();
Vector2D size;
bool opaque = false;
SP<CWLBufferResource> resource;
SP<CTexture> texture;
struct {
CSignal destroy;
} events;
private:
int locks = 0;
SP<CTexture> texture;
bool opaque = false;
SP<CWLBufferResource> resource;
};

View file

@ -3,7 +3,7 @@
#include "../../render/Renderer.hpp"
#include "../../helpers/Format.hpp"
CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_) : attrs(attrs_) {
CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : attrs(attrs_) {
g_pHyprRenderer->makeEGLCurrent();
listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) {
@ -31,12 +31,12 @@ CDMABuffer::~CDMABuffer() {
closeFDs();
}
eBufferCapability CDMABuffer::caps() {
return BUFFER_CAPABILITY_DATAPTR;
Aquamarine::eBufferCapability CDMABuffer::caps() {
return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR;
}
eBufferType CDMABuffer::type() {
return BUFFER_TYPE_DMABUF;
Aquamarine::eBufferType CDMABuffer::type() {
return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF;
}
void CDMABuffer::update(const CRegion& damage) {
@ -47,7 +47,7 @@ bool CDMABuffer::isSynchronous() {
return false;
}
SDMABUFAttrs CDMABuffer::dmabuf() {
Aquamarine::SDMABUFAttrs CDMABuffer::dmabuf() {
return attrs;
}

View file

@ -2,16 +2,16 @@
#include "Buffer.hpp"
class CDMABuffer : public IWLBuffer {
class CDMABuffer : public IHLBuffer {
public:
CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_);
CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_);
virtual ~CDMABuffer();
virtual eBufferCapability caps();
virtual eBufferType type();
virtual Aquamarine::eBufferCapability caps();
virtual Aquamarine::eBufferType type();
virtual bool isSynchronous();
virtual void update(const CRegion& damage);
virtual SDMABUFAttrs dmabuf();
virtual Aquamarine::SDMABUFAttrs dmabuf();
virtual std::tuple<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();
bool good();
@ -21,7 +21,7 @@ class CDMABuffer : public IWLBuffer {
bool success = false;
private:
SDMABUFAttrs attrs;
Aquamarine::SDMABUFAttrs attrs;
struct {
CHyprSignalListener resourceDestroy;

View file

@ -7,7 +7,7 @@
#include "wayland.hpp"
#include "../../helpers/signal/Signal.hpp"
class IWLBuffer;
class IHLBuffer;
class CWLBufferResource {
public:
@ -18,7 +18,7 @@ class CWLBufferResource {
void sendRelease();
wl_resource* getResource();
WP<IWLBuffer> buffer;
WP<IHLBuffer> buffer;
WP<CWLBufferResource> self;
@ -27,5 +27,5 @@ class CWLBufferResource {
SP<CWlBuffer> resource;
friend class IWLBuffer;
friend class IHLBuffer;
};

View file

@ -9,6 +9,8 @@
#include "../protocols/LayerShell.hpp"
#include "../protocols/core/Compositor.hpp"
#include <xf86drm.h>
#include <fcntl.h>
#include <gbm.h>
inline void loadGLProc(void* pProc, const char* name) {
void* proc = (void*)eglGetProcAddress(name);
@ -19,17 +21,198 @@ inline void loadGLProc(void* pProc, const char* name) {
*(void**)pProc = proc;
}
static enum LogLevel eglLogToLevel(EGLint type) {
switch (type) {
case EGL_DEBUG_MSG_CRITICAL_KHR: return CRIT;
case EGL_DEBUG_MSG_ERROR_KHR: return ERR;
case EGL_DEBUG_MSG_WARN_KHR: return WARN;
case EGL_DEBUG_MSG_INFO_KHR: return LOG;
default: return LOG;
}
}
static const char* eglErrorToString(EGLint error) {
switch (error) {
case EGL_SUCCESS: return "EGL_SUCCESS";
case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
case EGL_BAD_DEVICE_EXT: return "EGL_BAD_DEVICE_EXT";
case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
}
return "Unknown";
}
static void eglLog(EGLenum error, const char* command, EGLint type, EGLLabelKHR thread, EGLLabelKHR obj, const char* msg) {
Debug::log(eglLogToLevel(type), "[EGL] Command {} errored out with {} (0x{}): {}", command, eglErrorToString(error), error, msg);
}
static int openRenderNode(int drmFd) {
char* renderName = drmGetRenderDeviceNameFromFd(drmFd);
if (renderName == NULL) {
// This can happen on split render/display platforms, fallback to
// primary node
renderName = drmGetPrimaryDeviceNameFromFd(drmFd);
if (renderName == NULL) {
wlr_log_errno(WLR_ERROR, "drmGetPrimaryDeviceNameFromFd failed");
return -1;
}
wlr_log(WLR_DEBUG,
"DRM device '%s' has no render node, "
"falling back to primary node",
renderName);
drmVersion* render_version = drmGetVersion(drmFd);
if (render_version != NULL && render_version->name != NULL) {
wlr_log(WLR_DEBUG, "DRM device version.name '%s'", render_version->name);
if (strcmp(render_version->name, "evdi") == 0) {
free(renderName);
renderName = (char*)malloc(sizeof(char) * 15);
strcpy(renderName, "/dev/dri/card0");
}
drmFreeVersion(render_version);
}
}
wlr_log(WLR_DEBUG, "open_render_node() DRM device '%s'", renderName);
int render_fd = open(renderName, O_RDWR | O_CLOEXEC);
if (render_fd < 0) {
wlr_log_errno(WLR_ERROR, "Failed to open DRM node '%s'", renderName);
}
free(renderName);
return render_fd;
}
void CHyprOpenGLImpl::initEGL(bool gbm) {
std::vector<EGLint> attrs;
if (m_sExts.KHR_display_reference) {
attrs.push_back(EGL_TRACK_REFERENCES_KHR);
attrs.push_back(EGL_TRUE);
}
attrs.push_back(EGL_NONE);
m_pEglDisplay = m_sProc.eglGetPlatformDisplayEXT(gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT, gbm ? m_pGbmDevice : nullptr, attrs.data());
if (m_pEglDisplay == EGL_NO_DISPLAY)
RASSERT(false, "EGL: failed to create a platform display");
attrs.clear();
EGLint major, minor;
if (eglInitialize(m_pEglDisplay, &major, &minor) == EGL_FALSE)
RASSERT(false, "EGL: failed to initialize a platform display");
const std::string EGLEXTENSIONS = (const char*)eglQueryString(m_pEglDisplay, EGL_EXTENSIONS);
m_sExts.IMG_context_priority = EGLEXTENSIONS.contains("IMG_context_priority");
m_sExts.EXT_create_context_robustness = EGLEXTENSIONS.contains("EXT_create_context_robustness");
m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import");
m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers");
if (m_sExts.IMG_context_priority) {
Debug::log(LOG, "EGL: IMG_context_priority supported, requesting high");
attrs.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
attrs.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
}
if (m_sExts.EXT_create_context_robustness) {
Debug::log(LOG, "EGL: EXT_create_context_robustness supported, requesting lose on reset");
attrs.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
attrs.push_back(EGL_LOSE_CONTEXT_ON_RESET_EXT);
}
attrs.push_back(EGL_CONTEXT_MAJOR_VERSION);
attrs.push_back(3);
attrs.push_back(EGL_CONTEXT_MINOR_VERSION);
attrs.push_back(2);
attrs.push_back(EGL_CONTEXT_OPENGL_DEBUG);
attrs.push_back(ISDEBUG ? EGL_TRUE : EGL_FALSE);
attrs.push_back(EGL_NONE);
m_pEglContext = eglCreateContext(m_pEglDisplay, EGL_NO_CONFIG_KHR, EGL_NO_CONTEXT, attrs.data());
if (m_pEglContext == EGL_NO_CONTEXT)
RASSERT(false, "EGL: failed to create a context");
if (m_sExts.IMG_context_priority) {
EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
eglQueryContext(m_pEglDisplay, m_pEglContext, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &priority);
if (priority != EGL_CONTEXT_PRIORITY_HIGH_IMG)
Debug::log(ERR, "EGL: Failed to obtain a high priority context");
else
Debug::log(LOG, "EGL: Got a high priority context");
}
eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, m_pEglContext);
}
CHyprOpenGLImpl::CHyprOpenGLImpl() {
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL)),
"Couldn't unset current EGL!");
const std::string EGLEXTENSIONS = (const char*)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
const std::string EGLEXTENSIONS = (const char*)eglQueryString(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_EXTENSIONS);
RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!");
Debug::log(LOG, "Supported EGL extensions: ({}) {}", std::count(EGLEXTENSIONS.begin(), EGLEXTENSIONS.end(), ' '), EGLEXTENSIONS);
m_iDRMFD = g_pCompositor->m_iDRMFD;
m_sExts.KHR_display_reference = EGLEXTENSIONS.contains("KHR_display_reference");
loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR");
loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR");
loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT");
loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT");
loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR");
loadGLProc(&m_sProc.eglGetPlatformDisplayEXT, "eglGetPlatformDisplayEXT");
if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_enumeration"))
loadGLProc(&m_sProc.eglQueryDevicesEXT, "eglQueryDevicesEXT");
if (EGLEXTENSIONS.contains("EGL_EXT_device_base") || EGLEXTENSIONS.contains("EGL_EXT_device_query")) {
loadGLProc(&m_sProc.eglQueryDeviceStringEXT, "eglQueryDeviceStringEXT");
loadGLProc(&m_sProc.eglQueryDisplayAttribEXT, "eglQueryDisplayAttribEXT");
}
if (EGLEXTENSIONS.contains("EGL_KHR_debug")) {
loadGLProc(&m_sProc.eglDebugMessageControlKHR, "eglDebugMessageControlKHR");
static const EGLAttrib debugAttrs[] = {
EGL_DEBUG_MSG_CRITICAL_KHR, EGL_TRUE, EGL_DEBUG_MSG_ERROR_KHR, EGL_TRUE, EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, EGL_DEBUG_MSG_INFO_KHR, EGL_TRUE, EGL_NONE,
};
m_sProc.eglDebugMessageControlKHR(::eglLog, debugAttrs);
}
RASSERT(eglBindAPI(EGL_OPENGL_ES_API) != EGL_FALSE, "Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a hyprland issue.");
// if (m_sProc.eglQueryDevicesEXT) {
// // TODO:
// }
if (EGLEXTENSIONS.contains("KHR_platform_gbm")) {
m_iGBMFD = openRenderNode(m_iDRMFD);
if (m_iGBMFD < 0)
RASSERT(false, "Couldn't open a gbm fd");
m_pGbmDevice = gbm_create_device(m_iGBMFD);
if (!m_pGbmDevice)
RASSERT(false, "Couldn't open a gbm device");
initEGL(true);
} else
RASSERT(false, "EGL does not support KHR_platform_gbm, this is an issue with your gpu driver.");
auto* const EXTENSIONS = (const char*)glGetString(GL_EXTENSIONS);
RASSERT(EXTENSIONS, "Couldn't retrieve openGL extensions!");
m_szExtensions = EXTENSIONS;
Debug::log(LOG, "Creating the Hypr OpenGL Renderer!");
@ -38,16 +221,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
Debug::log(LOG, "Renderer: {}", (char*)glGetString(GL_RENDERER));
Debug::log(LOG, "Supported extensions: ({}) {}", std::count(m_szExtensions.begin(), m_szExtensions.end(), ' '), m_szExtensions);
loadGLProc(&m_sProc.glEGLImageTargetRenderbufferStorageOES, "glEGLImageTargetRenderbufferStorageOES");
loadGLProc(&m_sProc.eglCreateImageKHR, "eglCreateImageKHR");
loadGLProc(&m_sProc.eglDestroyImageKHR, "eglDestroyImageKHR");
loadGLProc(&m_sProc.eglQueryDmaBufFormatsEXT, "eglQueryDmaBufFormatsEXT");
loadGLProc(&m_sProc.eglQueryDmaBufModifiersEXT, "eglQueryDmaBufModifiersEXT");
loadGLProc(&m_sProc.glEGLImageTargetTexture2DOES, "glEGLImageTargetTexture2DOES");
m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
m_sExts.EXT_image_dma_buf_import = EGLEXTENSIONS.contains("EXT_image_dma_buf_import");
m_sExts.EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS.contains("EXT_image_dma_buf_import_modifiers");
m_sExts.EXT_read_format_bgra = m_szExtensions.contains("GL_EXT_read_format_bgra");
RASSERT(m_szExtensions.contains("GL_EXT_texture_format_BGRA8888"), "GL_EXT_texture_format_BGRA8888 support by the GPU driver is required");
@ -74,7 +248,7 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
static auto P = g_pHookSystem->hookDynamic("preRender", [&](void* self, SCallbackInfo& info, std::any data) { preRender(std::any_cast<CMonitor*>(data)); });
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
RASSERT(eglMakeCurrent(m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
m_tGlobalTimer.reset();
}
@ -86,7 +260,7 @@ std::optional<std::vector<uint64_t>> CHyprOpenGLImpl::getModsForFormat(EGLint fo
return std::nullopt;
EGLint len = 0;
if (!m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, 0, nullptr, nullptr, &len)) {
if (!m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, 0, nullptr, nullptr, &len)) {
Debug::log(ERR, "EGL: Failed to query mods");
return std::nullopt;
}
@ -100,7 +274,7 @@ std::optional<std::vector<uint64_t>> CHyprOpenGLImpl::getModsForFormat(EGLint fo
mods.resize(len);
external.resize(len);
m_sProc.eglQueryDmaBufModifiersEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), format, len, mods.data(), external.data(), &len);
m_sProc.eglQueryDmaBufModifiersEXT(m_pEglDisplay, format, len, mods.data(), external.data(), &len);
std::vector<uint64_t> result;
bool linearIsExternal = false;
@ -139,9 +313,9 @@ void CHyprOpenGLImpl::initDRMFormats() {
Debug::log(WARN, "EGL: No mod support");
} else {
EGLint len = 0;
m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), 0, nullptr, &len);
m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, 0, nullptr, &len);
formats.resize(len);
m_sProc.eglQueryDmaBufFormatsEXT(wlr_egl_get_display(g_pCompositor->m_sWLREGL), len, formats.data(), &len);
m_sProc.eglQueryDmaBufFormatsEXT(m_pEglDisplay, len, formats.data(), &len);
}
if (formats.size() == 0) {
@ -209,7 +383,7 @@ void CHyprOpenGLImpl::initDRMFormats() {
drmFormats = dmaFormats;
}
EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) {
EGLImageKHR CHyprOpenGLImpl::createEGLImage(const Aquamarine::SDMABUFAttrs& attrs) {
std::vector<uint32_t> attribs;
attribs.push_back(EGL_WIDTH);
@ -251,7 +425,7 @@ EGLImageKHR CHyprOpenGLImpl::createEGLImage(const SDMABUFAttrs& attrs) {
attribs.push_back(EGL_NONE);
EGLImageKHR image = m_sProc.eglCreateImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data());
EGLImageKHR image = m_sProc.eglCreateImageKHR(m_pEglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, nullptr, (int*)attribs.data());
if (image == EGL_NO_IMAGE_KHR) {
Debug::log(ERR, "EGL: EGLCreateImageKHR failed: {}", eglGetError());
return EGL_NO_IMAGE_KHR;
@ -915,11 +1089,8 @@ void CHyprOpenGLImpl::scissor(const CBox* pBox, bool transform) {
CBox newBox = *pBox;
if (transform) {
int w, h;
wlr_output_transformed_resolution(m_RenderData.pMonitor->output, &w, &h);
const auto TR = wlTransformToHyprutils(wlr_output_transform_invert(m_RenderData.pMonitor->transform));
newBox.transform(TR, w, h);
newBox.transform(TR, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y);
}
glScissor(newBox.x, newBox.y, newBox.width, newBox.height);
@ -2474,6 +2645,9 @@ void CHyprOpenGLImpl::clearWithTex() {
void CHyprOpenGLImpl::destroyMonitorResources(CMonitor* pMonitor) {
g_pHyprRenderer->makeEGLCurrent();
if (!g_pHyprOpenGL)
return;
auto RESIT = g_pHyprOpenGL->m_mMonitorRenderResources.find(pMonitor);
if (RESIT != g_pHyprOpenGL->m_mMonitorRenderResources.end()) {
RESIT->second.mirrorFB.release();

View file

@ -19,9 +19,11 @@
#include "Renderbuffer.hpp"
#include <GLES2/gl2ext.h>
#include <aquamarine/buffer/Buffer.hpp>
#include "../debug/TracyDefines.hpp"
struct gbm_device;
class CHyprRenderer;
inline const float fullVerts[] = {
@ -182,12 +184,17 @@ class CHyprOpenGLImpl {
uint32_t getPreferredReadFormat(CMonitor* pMonitor);
std::vector<SDRMFormat> getDRMFormats();
EGLImageKHR createEGLImage(const SDMABUFAttrs& attrs);
EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
SCurrentRenderData m_RenderData;
GLint m_iCurrentOutputFb = 0;
int m_iGBMFD = -1;
gbm_device* m_pGbmDevice = nullptr;
EGLContext m_pEglContext = nullptr;
EGLDisplay m_pEglDisplay = nullptr;
bool m_bReloadScreenShader = true; // at launch it can be set
PHLWINDOWREF m_pCurrentWindow; // hack to get the current rendered window
@ -205,12 +212,20 @@ class CHyprOpenGLImpl {
PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
} m_sProc;
struct {
bool EXT_read_format_bgra = false;
bool EXT_image_dma_buf_import = false;
bool EXT_image_dma_buf_import_modifiers = false;
bool KHR_display_reference = false;
bool IMG_context_priority = false;
bool EXT_create_context_robustness = false;
} m_sExts;
private:
@ -220,7 +235,7 @@ class CHyprOpenGLImpl {
std::vector<SDRMFormat> drmFormats;
bool m_bHasModifiers = false;
int m_iDRMFD;
int m_iDRMFD = -1;
std::string m_szExtensions;
bool m_bFakeFrame = false;
@ -238,6 +253,7 @@ class CHyprOpenGLImpl {
void createBGTextureForMonitor(CMonitor*);
void initShaders();
void initDRMFormats();
void initEGL(bool gbm);
//
std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);

View file

@ -15,53 +15,10 @@ CRenderbuffer::~CRenderbuffer() {
m_sFramebuffer.release();
glDeleteRenderbuffers(1, &m_iRBO);
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage);
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_iImage);
}
CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer), m_uDrmFormat(format) {
// EVIL, but we can't include a hidden header because nixos is fucking special
static EGLImageKHR (*PWLREGLCREATEIMAGEFROMDMABUF)(wlr_egl*, wlr_dmabuf_attributes*, bool*);
static bool symbolFound = false;
if (!symbolFound) {
PWLREGLCREATEIMAGEFROMDMABUF = reinterpret_cast<EGLImageKHR (*)(wlr_egl*, wlr_dmabuf_attributes*, bool*)>(dlsym(RTLD_DEFAULT, "wlr_egl_create_image_from_dmabuf"));
symbolFound = true;
RASSERT(PWLREGLCREATEIMAGEFROMDMABUF, "wlr_egl_create_image_from_dmabuf was not found in wlroots!");
Debug::log(LOG, "CRenderbuffer: wlr_egl_create_image_from_dmabuf found at {:x}", (uintptr_t)PWLREGLCREATEIMAGEFROMDMABUF);
}
// end evil hack
struct wlr_dmabuf_attributes dmabuf = {0};
if (!wlr_buffer_get_dmabuf(buffer, &dmabuf))
throw std::runtime_error("wlr_buffer_get_dmabuf failed");
bool externalOnly;
m_iImage = PWLREGLCREATEIMAGEFROMDMABUF(g_pCompositor->m_sWLREGL, &dmabuf, &externalOnly);
if (m_iImage == EGL_NO_IMAGE_KHR)
throw std::runtime_error("wlr_egl_create_image_from_dmabuf failed");
glGenRenderbuffers(1, &m_iRBO);
glBindRenderbuffer(GL_RENDERBUFFER, m_iRBO);
g_pHyprOpenGL->m_sProc.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, (GLeglImageOES)m_iImage);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glGenFramebuffers(1, &m_sFramebuffer.m_iFb);
m_sFramebuffer.m_vSize = {buffer->width, buffer->height};
m_sFramebuffer.bind();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_iRBO);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
hyprListener_destroyBuffer.initCallback(&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer");
}
CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) {
CRenderbuffer::CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format) : m_pHLBuffer(buffer), m_uDrmFormat(format) {
auto dma = buffer->dmabuf();
m_iImage = g_pHyprOpenGL->createEGLImage(dma);
@ -82,6 +39,8 @@ CRenderbuffer::CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format) : m_pHLBuffe
throw std::runtime_error("rbo: glCheckFramebufferStatus failed");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
listeners.destroyBuffer = buffer->events.destroy.registerListener([this](std::any d) { g_pHyprRenderer->onRenderbufferDestroy(this); });
}
void CRenderbuffer::bind() {

View file

@ -1,30 +1,30 @@
#pragma once
#include "Framebuffer.hpp"
#include <aquamarine/buffer/Buffer.hpp>
class CMonitor;
class IWLBuffer;
class CRenderbuffer {
public:
CRenderbuffer(wlr_buffer* buffer, uint32_t format);
CRenderbuffer(SP<IWLBuffer> buffer, uint32_t format);
CRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
~CRenderbuffer();
void bind();
void bindFB();
void unbind();
CFramebuffer* getFB();
uint32_t getFormat();
void bind();
void bindFB();
void unbind();
CFramebuffer* getFB();
uint32_t getFormat();
wlr_buffer* m_pWlrBuffer = nullptr;
WP<IWLBuffer> m_pHLBuffer = {};
DYNLISTENER(destroyBuffer);
WP<Aquamarine::IBuffer> m_pHLBuffer;
private:
EGLImageKHR m_iImage = 0;
GLuint m_iRBO = 0;
CFramebuffer m_sFramebuffer;
uint32_t m_uDrmFormat = 0;
struct {
CHyprSignalListener destroyBuffer;
} listeners;
};

View file

@ -25,22 +25,23 @@ static int cursorTicker(void* data) {
}
CHyprRenderer::CHyprRenderer() {
if (g_pCompositor->m_sWLRSession) {
wlr_device* dev;
wl_list_for_each(dev, &g_pCompositor->m_sWLRSession->devices, link) {
const auto DRMV = drmGetVersion(dev->fd);
if (g_pCompositor->m_pAqBackend->hasSession()) {
// wlr_device* dev;
// FIXME:
// wl_list_for_each(dev, &g_pCompositor->m_sWLRSession->devices, link) {
// const auto DRMV = drmGetVersion(dev->fd);
std::string name = std::string{DRMV->name, DRMV->name_len};
std::transform(name.begin(), name.end(), name.begin(), tolower);
// std::string name = std::string{DRMV->name, DRMV->name_len};
// std::transform(name.begin(), name.end(), name.begin(), tolower);
if (name.contains("nvidia"))
m_bNvidia = true;
// if (name.contains("nvidia"))
// m_bNvidia = true;
Debug::log(LOG, "DRM driver information: {} v{}.{}.{} from {} description {}", name, DRMV->version_major, DRMV->version_minor, DRMV->version_patchlevel,
std::string{DRMV->date, DRMV->date_len}, std::string{DRMV->desc, DRMV->desc_len});
// Debug::log(LOG, "DRM driver information: {} v{}.{}.{} from {} description {}", name, DRMV->version_major, DRMV->version_minor, DRMV->version_patchlevel,
// std::string{DRMV->date, DRMV->date_len}, std::string{DRMV->desc, DRMV->desc_len});
drmFreeVersion(DRMV);
}
// drmFreeVersion(DRMV);
// }
} else {
Debug::log(LOG, "m_sWLRSession is null, omitting full DRM node checks");
@ -1249,7 +1250,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
clock_gettime(CLOCK_MONOTONIC, &now);
// check the damage
bool hasChanged = pMonitor->output->needs_frame || pMonitor->damage.hasChanged();
bool hasChanged = /*pMonitor->output->needs_frame ||*/ pMonitor->damage.hasChanged();
if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0)
return;
@ -1295,7 +1296,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
CRegion damage, finalDamage;
if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) {
Debug::log(ERR, "renderer: couldn't beginRender()!");
pMonitor->state.clear();
return;
}
@ -1398,7 +1398,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
if (!pMonitor->mirrors.empty()) {
CRegion frameDamage{};
const auto TRANSFORM = wlr_output_transform_invert(pMonitor->output->transform);
const auto TRANSFORM = wlr_output_transform_invert(pMonitor->transform);
wlr_region_transform(frameDamage.pixman(), finalDamage.pixman(), TRANSFORM, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
@ -1414,7 +1414,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
EMIT_HOOK_EVENT("render", RENDER_POST);
pMonitor->state.wlr()->tearing_page_flip = shouldTear;
pMonitor->output->state->setPresentationMode(shouldTear ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
if (!pMonitor->state.commit()) {
pMonitor->damage.damageEntire();
@ -1869,7 +1870,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// don't touch VR headsets
if (pMonitor->output->non_desktop)
if (pMonitor->output->nonDesktop)
return true;
if (!pMonitor->m_bEnabled) {
@ -1910,38 +1911,36 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->scale = DEFAULTSCALE;
}
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
pMonitor->setScale = pMonitor->scale;
wlr_output_state_set_transform(pMonitor->state.wlr(), RULE->transform);
pMonitor->setScale = pMonitor->scale;
pMonitor->transform = RULE->transform;
pMonitor->output->state->setFormat(DRM_FORMAT_XBGR8888);
const auto WLRREFRESHRATE = (wlr_backend_is_wl(pMonitor->output->backend) || wlr_backend_is_x11(pMonitor->output->backend)) ? 0 : RULE->refreshRate * 1000;
const auto WLRREFRESHRATE = pMonitor->output->getBackend()->type() == Aquamarine::eBackendType::AQ_BACKEND_DRM ? RULE->refreshRate * 1000 : 0;
// loop over modes and choose an appropriate one.
if (RULE->resolution != Vector2D() && RULE->resolution != Vector2D(-1, -1) && RULE->resolution != Vector2D(-1, -2)) {
if (!wl_list_empty(&pMonitor->output->modes) && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) {
wlr_output_mode* mode;
bool found = false;
if (!pMonitor->output->modes.empty() && RULE->drmMode.type != DRM_MODE_TYPE_USERDEF) {
bool found = false;
wl_list_for_each(mode, &pMonitor->output->modes, link) {
for (auto& mode : pMonitor->output->modes) {
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
if (DELTALESSTHAN(mode->width, RULE->resolution.x, 1) && DELTALESSTHAN(mode->height, RULE->resolution.y, 1) &&
DELTALESSTHAN(mode->refresh / 1000.f, RULE->refreshRate, 1)) {
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (DELTALESSTHAN(mode->pixelSize.x, RULE->resolution.x, 1) && DELTALESSTHAN(mode->pixelSize.y, RULE->resolution.y, 1) &&
DELTALESSTHAN(mode->refreshRate / 1000.f, RULE->refreshRate, 1)) {
pMonitor->output->state->setMode(mode);
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
if (!pMonitor->state.test()) {
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y,
mode->refreshRate / 1000.f);
continue;
}
Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution,
(float)RULE->refreshRate, mode->width, mode->height, mode->refresh);
(float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate);
found = true;
pMonitor->refreshRate = mode->refresh / 1000.f;
pMonitor->vecSize = Vector2D(mode->width, mode->height);
pMonitor->refreshRate = mode->refreshRate / 1000.f;
pMonitor->vecSize = mode->pixelSize;
pMonitor->currentMode = mode;
break;
@ -1949,14 +1948,14 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
if (!found) {
wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE);
pMonitor->output->state->setCustomMode(makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE}));
pMonitor->vecSize = RULE->resolution;
pMonitor->refreshRate = RULE->refreshRate;
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
if (!pMonitor->state.test()) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution,
@ -1965,13 +1964,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// Preferred is valid
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
pMonitor->output->state->setMode(PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
(float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
(float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
pMonitor->vecSize = PREFERREDMODE->pixelSize;
pMonitor->currentMode = PREFERREDMODE;
} else {
Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate);
@ -1982,30 +1981,30 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
bool fail = false;
if (RULE->drmMode.type == DRM_MODE_TYPE_USERDEF) {
if (!wlr_output_is_drm(pMonitor->output)) {
if (pMonitor->output->getBackend()->type() != Aquamarine::eBackendType::AQ_BACKEND_DRM) {
Debug::log(ERR, "Tried to set custom modeline on non-DRM output");
fail = true;
} else {
auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode);
if (mode) {
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
pMonitor->customDrmMode = RULE->drmMode;
} else {
Debug::log(ERR, "wlr_drm_connector_add_mode failed");
fail = true;
}
// FIXME:
// auto* mode = wlr_drm_connector_add_mode(pMonitor->output, &RULE->drmMode);
// if (mode) {
// wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
// pMonitor->customDrmMode = RULE->drmMode;
// } else {
// Debug::log(ERR, "wlr_drm_connector_add_mode failed");
// fail = true;
// }
}
} else {
wlr_output_state_set_custom_mode(pMonitor->state.wlr(), (int)RULE->resolution.x, (int)RULE->resolution.y, WLRREFRESHRATE);
}
} else
pMonitor->output->state->setCustomMode(makeShared<Aquamarine::SOutputMode>(Aquamarine::SOutputMode{.pixelSize = RULE->resolution, .refreshRate = WLRREFRESHRATE}));
pMonitor->vecSize = RULE->resolution;
pMonitor->refreshRate = RULE->refreshRate;
if (fail || !wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
if (fail || !pMonitor->state.test()) {
Debug::log(ERR, "Custom resolution FAILED, falling back to preferred");
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->output->name, RULE->resolution,
@ -2014,48 +2013,47 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// Preferred is valid
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
pMonitor->output->state->setMode(PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
(float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
(float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
pMonitor->vecSize = PREFERREDMODE->pixelSize;
pMonitor->customDrmMode = {};
} else {
} else
Debug::log(LOG, "Set a custom mode {:X0}@{:2f} (mode not found in monitor modes)", RULE->resolution, (float)RULE->refreshRate);
}
}
} else if (RULE->resolution != Vector2D()) {
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
float currentWidth = 0;
float currentHeight = 0;
float currentRefresh = 0;
bool success = false;
if (!pMonitor->output->modes.empty()) {
float currentWidth = 0;
float currentHeight = 0;
float currentRefresh = 0;
bool success = false;
//(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution
if (RULE->resolution == Vector2D(-1, -1)) {
wl_list_for_each(mode, &pMonitor->output->modes, link) {
if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) || mode->refresh > (currentRefresh + 3000.f)) {
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
currentWidth = mode->width;
currentHeight = mode->height;
currentRefresh = mode->refresh;
for (auto& mode : pMonitor->output->modes) {
if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) ||
mode->refreshRate > (currentRefresh + 3000.f)) {
pMonitor->output->state->setMode(mode);
if (pMonitor->state.test()) {
currentWidth = mode->pixelSize.x;
currentHeight = mode->pixelSize.y;
currentRefresh = mode->refreshRate;
success = true;
}
}
}
} else {
wl_list_for_each(mode, &pMonitor->output->modes, link) {
if ((mode->width >= currentWidth && mode->height >= currentHeight && mode->refresh >= (currentRefresh - 1000.f)) ||
(mode->width > currentWidth && mode->height > currentHeight)) {
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
currentWidth = mode->width;
currentHeight = mode->height;
currentRefresh = mode->refresh;
for (auto& mode : pMonitor->output->modes) {
if ((mode->pixelSize.x >= currentWidth && mode->pixelSize.y >= currentHeight && mode->refreshRate >= (currentRefresh - 1000.f)) ||
(mode->pixelSize.x > currentWidth && mode->pixelSize.y > currentHeight)) {
pMonitor->output->state->setMode(mode);
if (pMonitor->state.test()) {
currentWidth = mode->pixelSize.x;
currentHeight = mode->pixelSize.y;
currentRefresh = mode->refreshRate;
success = true;
}
}
@ -2063,10 +2061,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
if (!success) {
Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
(float)RULE->refreshRate, mode->width, mode->height, mode->refresh / 1000.f);
if (pMonitor->output->state->state().mode)
Debug::log(LOG, "Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
(float)RULE->refreshRate, pMonitor->output->state->state().mode->pixelSize.x, pMonitor->output->state->state().mode->pixelSize.y,
pMonitor->output->state->state().mode->refreshRate / 1000.f);
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f}", pMonitor->ID, RULE->resolution, (float)RULE->refreshRate);
@ -2074,13 +2074,13 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
// Preferred is valid
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
pMonitor->output->state->setMode(PREFERREDMODE);
Debug::log(ERR, "Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f}", pMonitor->output->name, RULE->resolution,
(float)RULE->refreshRate, PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f);
(float)RULE->refreshRate, PREFERREDMODE->pixelSize.x, PREFERREDMODE->pixelSize.y, PREFERREDMODE->refreshRate / 1000.f);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
pMonitor->vecSize = PREFERREDMODE->pixelSize;
pMonitor->currentMode = PREFERREDMODE;
} else {
@ -2091,27 +2091,26 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
}
} else {
const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output);
const auto PREFERREDMODE = pMonitor->output->preferredMode();
if (!PREFERREDMODE) {
Debug::log(ERR, "Monitor {} has NO PREFERRED MODE", pMonitor->output->name);
if (!wl_list_empty(&pMonitor->output->modes)) {
wlr_output_mode* mode;
if (!pMonitor->output->modes.empty()) {
for (auto& mode : pMonitor->output->modes) {
pMonitor->output->state->setMode(mode);
wl_list_for_each(mode, &pMonitor->output->modes, link) {
wlr_output_state_set_mode(pMonitor->state.wlr(), mode);
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->width, mode->height, mode->refresh / 1000.f);
if (!pMonitor->state.test()) {
Debug::log(LOG, "Monitor {}: REJECTED available mode: {}x{}@{:2f}!", pMonitor->output->name, mode->pixelSize.x, mode->pixelSize.y,
mode->refreshRate / 1000.f);
continue;
}
Debug::log(LOG, "Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying.", pMonitor->output->name, RULE->resolution,
(float)RULE->refreshRate, mode->width, mode->height, mode->refresh);
(float)RULE->refreshRate, mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate);
pMonitor->refreshRate = mode->refresh / 1000.f;
pMonitor->vecSize = Vector2D(mode->width, mode->height);
pMonitor->refreshRate = mode->refreshRate / 1000.f;
pMonitor->vecSize = mode->pixelSize;
pMonitor->currentMode = mode;
break;
@ -2119,18 +2118,18 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
}
} else {
// Preferred is valid
wlr_output_state_set_mode(pMonitor->state.wlr(), PREFERREDMODE);
pMonitor->output->state->setMode(PREFERREDMODE);
pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height);
pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f;
pMonitor->vecSize = PREFERREDMODE->pixelSize;
pMonitor->refreshRate = PREFERREDMODE->refreshRate / 1000.f;
pMonitor->currentMode = PREFERREDMODE;
Debug::log(LOG, "Setting preferred mode for {}", pMonitor->output->name);
}
}
pMonitor->vrrActive = pMonitor->state.wlr()->adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR()
|| pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
pMonitor->vrrActive = pMonitor->output->state->state().adaptiveSync // disabled here, will be tested in CConfigManager::ensureVRR()
|| pMonitor->createdByUser; // wayland backend doesn't allow for disabling adaptive_sync
pMonitor->vecPixelSize = pMonitor->vecSize;
@ -2145,10 +2144,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
double scaleZero = searchScale / 120.0;
Vector2D logicalZero = pMonitor->vecPixelSize / scaleZero;
if (logicalZero == logicalZero.round()) {
if (logicalZero == logicalZero.round())
pMonitor->scale = scaleZero;
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->scale);
} else {
else {
for (size_t i = 1; i < 90; ++i) {
double scaleUp = (searchScale + i) / 120.0;
double scaleDown = (searchScale - i) / 120.0;
@ -2185,12 +2183,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
} else
pMonitor->scale = searchScale;
}
// for wlroots, that likes flooring, we have to do this.
double logicalX = std::round(pMonitor->vecPixelSize.x / pMonitor->scale);
logicalX += 0.1;
wlr_output_state_set_scale(pMonitor->state.wlr(), pMonitor->vecPixelSize.x / logicalX);
}
}
@ -2209,9 +2201,9 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->drmFormat = DRM_FORMAT_INVALID;
for (auto& fmt : formats[(int)!RULE->enable10bit]) {
wlr_output_state_set_render_format(pMonitor->state.wlr(), fmt.second);
pMonitor->output->state->setFormat(fmt.second);
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
if (!pMonitor->state.test()) {
Debug::log(ERR, "output {} failed basic test on format {}", pMonitor->szName, fmt.first);
} else {
Debug::log(LOG, "output {} succeeded basic test on format {}", pMonitor->szName, fmt.first);
@ -2225,17 +2217,18 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->enabled10bit = set10bit;
pMonitor->output->scheduleFrame();
if (!pMonitor->state.commit())
Debug::log(ERR, "Couldn't commit output named {}", pMonitor->output->name);
int x, y;
wlr_output_transformed_resolution(pMonitor->output, &x, &y);
pMonitor->vecSize = (Vector2D(x, y) / pMonitor->scale).round();
pMonitor->vecTransformedSize = Vector2D(x, y);
Vector2D xfmd = pMonitor->transform % 2 == 1 ? Vector2D{pMonitor->vecPixelSize.y, pMonitor->vecPixelSize.x} : pMonitor->vecPixelSize;
pMonitor->vecSize = (xfmd / pMonitor->scale).round();
pMonitor->vecTransformedSize = xfmd;
if (pMonitor->createdByUser) {
CBox transformedBox = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y};
transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->output->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
transformedBox.transform(wlTransformToHyprutils(wlr_output_transform_invert(pMonitor->transform)), pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y);
pMonitor->vecPixelSize = Vector2D(transformedBox.width, transformedBox.height);
}
@ -2260,9 +2253,6 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
// updato us
arrangeLayersForMonitor(pMonitor->ID);
// frame skip
pMonitor->framesToSkip = 1;
// reload to fix mirrors
g_pConfigManager->m_bWantsMonitorReload = true;
@ -2329,7 +2319,7 @@ void CHyprRenderer::ensureCursorRenderingMode() {
Debug::log(LOG, "Hiding the cursor (hl-mandated)");
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->output->software_cursor_locks == 0)
if (!g_pPointerManager->softwareLockedFor(m))
continue;
g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area?
@ -2341,7 +2331,7 @@ void CHyprRenderer::ensureCursorRenderingMode() {
Debug::log(LOG, "Showing the cursor (hl-mandated)");
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->output->software_cursor_locks == 0)
if (!g_pPointerManager->softwareLockedFor(m))
continue;
g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area?
@ -2570,16 +2560,7 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) {
pMonitor->solitaryClient = PCANDIDATE;
}
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt) {
auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pWlrBuffer == buffer; });
if (it != m_vRenderbuffers.end())
return it->get();
return m_vRenderbuffers.emplace_back(std::make_unique<CRenderbuffer>(buffer, fmt)).get();
}
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt) {
CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
auto it = std::find_if(m_vRenderbuffers.begin(), m_vRenderbuffers.end(), [&](const auto& other) { return other->m_pHLBuffer == buffer; });
if (it != m_vRenderbuffers.end())
@ -2589,18 +2570,21 @@ CRenderbuffer* CHyprRenderer::getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint
}
void CHyprRenderer::makeEGLCurrent() {
if (!g_pCompositor)
if (!g_pCompositor || !g_pHyprOpenGL)
return;
if (eglGetCurrentContext() != wlr_egl_get_context(g_pCompositor->m_sWLREGL))
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, wlr_egl_get_context(g_pCompositor->m_sWLREGL));
if (eglGetCurrentContext() != g_pHyprOpenGL->m_pEglContext)
eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, g_pHyprOpenGL->m_pEglContext);
}
void CHyprRenderer::unsetEGL() {
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (!g_pHyprOpenGL)
return;
eglMakeCurrent(g_pHyprOpenGL->m_pEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IWLBuffer> buffer, CFramebuffer* fb, bool simple) {
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, SP<IHLBuffer> buffer, CFramebuffer* fb, bool simple) {
makeEGLCurrent();
@ -2621,27 +2605,18 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
int bufferAge = 0;
if (!buffer) {
if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain)) {
Debug::log(ERR, "Failed to configure primary swapchain for {}", pMonitor->szName);
return false;
}
m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &bufferAge);
if (!m_pCurrentWlrBuffer) {
m_pCurrentBuffer = pMonitor->output->swapchain->next(&bufferAge);
if (!m_pCurrentBuffer) {
Debug::log(ERR, "Failed to acquire swapchain buffer for {}", pMonitor->szName);
return false;
}
} else
m_pCurrentHLBuffer = buffer;
m_pCurrentBuffer = buffer;
try {
if (m_pCurrentWlrBuffer)
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentWlrBuffer, pMonitor->drmFormat);
else
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentHLBuffer.lock(), pMonitor->drmFormat);
m_pCurrentRenderbuffer = getOrCreateRenderbuffer(m_pCurrentBuffer, pMonitor->drmFormat);
} catch (std::exception& e) {
Debug::log(ERR, "getOrCreateRenderbuffer failed for {}", pMonitor->szName);
wlr_buffer_unlock(m_pCurrentWlrBuffer);
return false;
}
@ -2679,17 +2654,13 @@ void CHyprRenderer::endRender() {
else
glFlush();
if (m_eRenderMode == RENDER_MODE_NORMAL) {
wlr_output_state_set_buffer(PMONITOR->state.wlr(), m_pCurrentWlrBuffer);
unsetEGL(); // flush the context
}
wlr_buffer_unlock(m_pCurrentWlrBuffer);
if (m_eRenderMode == RENDER_MODE_NORMAL)
PMONITOR->output->state->setBuffer(m_pCurrentBuffer);
m_pCurrentRenderbuffer->unbind();
m_pCurrentRenderbuffer = nullptr;
m_pCurrentWlrBuffer = nullptr;
m_pCurrentBuffer = nullptr;
}
void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) {

View file

@ -12,7 +12,7 @@ struct SMonitorRule;
class CWorkspace;
class CWindow;
class CInputPopup;
class IWLBuffer;
class IHLBuffer;
// TODO: add fuller damage tracking for updating only parts of a window
enum DAMAGETRACKINGMODES {
@ -76,7 +76,7 @@ class CHyprRenderer {
// if RENDER_MODE_NORMAL, provided damage will be written to.
// otherwise, it will be the one used.
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IWLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, CFramebuffer* fb = nullptr, bool simple = false);
void endRender();
bool m_bBlockSurfaceFeedback = false;
@ -122,11 +122,10 @@ class CHyprRenderer {
bool m_bCursorHidden = false;
bool m_bCursorHasSurface = false;
CRenderbuffer* m_pCurrentRenderbuffer = nullptr;
wlr_buffer* m_pCurrentWlrBuffer = nullptr;
WP<IWLBuffer> m_pCurrentHLBuffer = {};
eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
SP<Aquamarine::IBuffer> m_pCurrentBuffer;
eRenderMode m_eRenderMode = RENDER_MODE_NORMAL;
bool m_bNvidia = false;
bool m_bNvidia = false;
struct {
bool hiddenOnTouch = false;
@ -134,8 +133,7 @@ class CHyprRenderer {
bool hiddenOnKeyboard = false;
} m_sCursorHiddenConditions;
CRenderbuffer* getOrCreateRenderbuffer(wlr_buffer* buffer, uint32_t fmt);
CRenderbuffer* getOrCreateRenderbuffer(SP<IWLBuffer> buffer, uint32_t fmt);
CRenderbuffer* getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt);
std::vector<std::unique_ptr<CRenderbuffer>> m_vRenderbuffers;
friend class CHyprOpenGLImpl;

View file

@ -17,6 +17,62 @@ CTexture::~CTexture() {
}
CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
createFromShm(drmFormat, pixels, stride, size_);
}
CTexture::CTexture(wlr_texture* tex) {
RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!");
wlr_gles2_texture_attribs attrs;
wlr_gles2_texture_get_attribs(tex, &attrs);
m_iTarget = attrs.target;
m_iTexID = attrs.tex;
m_bNonOwning = true;
if (m_iTarget == GL_TEXTURE_2D)
m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX;
else
m_iType = TEXTURE_EXTERNAL;
m_vSize = Vector2D((int)tex->width, (int)tex->height);
}
CTexture::CTexture(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
createFromDma(attrs, image);
}
CTexture::CTexture(const SP<Aquamarine::IBuffer> buffer) {
if (!buffer)
return;
auto attrs = buffer->dmabuf();
if (!attrs.success) {
// attempt shm
auto shm = buffer->shm();
if (!shm.success) {
Debug::log(ERR, "Cannot create a texture: buffer has no dmabuf or shm");
return;
}
auto [pixelData, fmt, bufLen] = buffer->beginDataPtr(0);
createFromShm(fmt, pixelData, bufLen, shm.size);
return;
}
auto image = g_pHyprOpenGL->createEGLImage(buffer->dmabuf());
if (!image) {
Debug::log(ERR, "Cannot create a texture: failed to create an EGLImage");
return;
}
createFromDma(attrs, image);
}
void CTexture::createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size_) {
g_pHyprRenderer->makeEGLCurrent();
const auto format = FormatUtils::getPixelFormatFromDRM(drmFormat);
@ -41,24 +97,7 @@ CTexture::CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const V
GLCALL(glBindTexture(GL_TEXTURE_2D, 0));
}
CTexture::CTexture(wlr_texture* tex) {
RASSERT(wlr_texture_is_gles2(tex), "wlr_texture provided to CTexture that isn't GLES2!");
wlr_gles2_texture_attribs attrs;
wlr_gles2_texture_get_attribs(tex, &attrs);
m_iTarget = attrs.target;
m_iTexID = attrs.tex;
m_bNonOwning = true;
if (m_iTarget == GL_TEXTURE_2D)
m_iType = attrs.has_alpha ? TEXTURE_RGBA : TEXTURE_RGBX;
else
m_iType = TEXTURE_EXTERNAL;
m_vSize = Vector2D((int)tex->width, (int)tex->height);
}
CTexture::CTexture(const SDMABUFAttrs& attrs, void* image) {
void CTexture::createFromDma(const Aquamarine::SDMABUFAttrs& attrs, void* image) {
if (!g_pHyprOpenGL->m_sProc.glEGLImageTargetTexture2DOES) {
Debug::log(ERR, "Cannot create a dmabuf texture: no glEGLImageTargetTexture2DOES");
return;
@ -119,7 +158,7 @@ void CTexture::destroyTexture() {
}
if (m_pEglImage)
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_pEglImage);
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(g_pHyprOpenGL->m_pEglDisplay, m_pEglImage);
m_pEglImage = nullptr;
}

View file

@ -1,9 +1,9 @@
#pragma once
#include "../defines.hpp"
#include <aquamarine/buffer/Buffer.hpp>
class IWLBuffer;
struct SDMABUFAttrs;
class IHLBuffer;
HYPRUTILS_FORWARD(Math, CRegion);
enum TEXTURETYPE {
@ -25,8 +25,9 @@ class CTexture {
CTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
CTexture(wlr_texture*);
CTexture(const SP<Aquamarine::IBuffer> buffer);
// this ctor takes ownership of the eglImage.
CTexture(const SDMABUFAttrs&, void* image);
CTexture(const Aquamarine::SDMABUFAttrs&, void* image);
~CTexture();
void destroyTexture();
@ -39,4 +40,8 @@ class CTexture {
Vector2D m_vSize;
void* m_pEglImage = nullptr;
bool m_bNonOwning = false; // wlr
private:
void createFromShm(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size);
void createFromDma(const Aquamarine::SDMABUFAttrs&, void* image);
};