cursor: move to a hyprland impl

This moves wlr_cursor to a completely new impl mostly under
CPointerManager

Also adds beginSimple to OpenGL for simple render passes (e.g. cursor)
This commit is contained in:
Vaxry 2024-05-05 22:18:10 +01:00
parent 22a86fd7a2
commit 232ad43ee8
52 changed files with 1551 additions and 497 deletions

View file

@ -109,7 +109,7 @@ pkg_check_modules(deps REQUIRED IMPORTED_TARGET
wayland-server wayland-client wayland-cursor wayland-protocols
cairo pango pangocairo pixman-1
libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
hyprwayland-scanner>=0.3.4 hyprlang>=0.3.2 hyprcursor>=0.1.7
hyprwayland-scanner>=0.3.5 hyprlang>=0.3.2 hyprcursor>=0.1.7
)
file(GLOB_RECURSE SRCFILES "src/*.cpp")

View file

@ -3,6 +3,7 @@
#include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp"
#include "managers/TokenManager.hpp"
#include "managers/PointerManager.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include <random>
#include <unordered_set>
@ -227,13 +228,8 @@ void CCompositor::initServer() {
wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
wlr_viewporter_create(m_sWLDisplay);
m_sWLROutputLayout = wlr_output_layout_create(m_sWLDisplay);
m_sWLRXDGShell = wlr_xdg_shell_create(m_sWLDisplay, 6);
m_sWLRCursor = wlr_cursor_create();
wlr_cursor_attach_output_layout(m_sWLRCursor, m_sWLROutputLayout);
m_sSeat.seat = wlr_seat_create(m_sWLDisplay, "seat0");
m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend);
@ -246,7 +242,7 @@ void CCompositor::initServer() {
Debug::log(INFO, "VR will not be available");
}
m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay);
// m_sWLRTabletManager = wlr_tablet_v2_create(m_sWLDisplay);
m_sWLRForeignRegistry = wlr_xdg_foreign_registry_create(m_sWLDisplay);
@ -270,23 +266,6 @@ void CCompositor::initServer() {
void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRBackend->events.new_output, &Events::listen_newOutput, m_sWLRBackend, "Backend");
addWLSignal(&m_sWLRXDGShell->events.new_toplevel, &Events::listen_newXDGToplevel, m_sWLRXDGShell, "XDG Shell");
addWLSignal(&m_sWLRCursor->events.motion, &Events::listen_mouseMove, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.motion_absolute, &Events::listen_mouseMoveAbsolute, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.button, &Events::listen_mouseButton, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.axis, &Events::listen_mouseAxis, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.frame, &Events::listen_mouseFrame, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.swipe_begin, &Events::listen_swipeBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.swipe_update, &Events::listen_swipeUpdate, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.swipe_end, &Events::listen_swipeEnd, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.pinch_begin, &Events::listen_pinchBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.pinch_update, &Events::listen_pinchUpdate, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.pinch_end, &Events::listen_pinchEnd, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.touch_down, &Events::listen_touchBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.touch_up, &Events::listen_touchEnd, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.touch_motion, &Events::listen_touchUpdate, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.touch_frame, &Events::listen_touchFrame, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.hold_begin, &Events::listen_holdBegin, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRCursor->events.hold_end, &Events::listen_holdEnd, m_sWLRCursor, "WLRCursor");
addWLSignal(&m_sWLRBackend->events.new_input, &Events::listen_newInput, m_sWLRBackend, "Backend");
addWLSignal(&m_sSeat.seat->events.request_set_cursor, &Events::listen_requestMouse, &m_sSeat, "Seat");
addWLSignal(&m_sSeat.seat->events.request_set_selection, &Events::listen_requestSetSel, &m_sSeat, "Seat");
@ -307,23 +286,6 @@ void CCompositor::initAllSignals() {
void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_newOutput);
removeWLSignal(&Events::listen_newXDGToplevel);
removeWLSignal(&Events::listen_mouseMove);
removeWLSignal(&Events::listen_mouseMoveAbsolute);
removeWLSignal(&Events::listen_mouseButton);
removeWLSignal(&Events::listen_mouseAxis);
removeWLSignal(&Events::listen_mouseFrame);
removeWLSignal(&Events::listen_swipeBegin);
removeWLSignal(&Events::listen_swipeUpdate);
removeWLSignal(&Events::listen_swipeEnd);
removeWLSignal(&Events::listen_pinchBegin);
removeWLSignal(&Events::listen_pinchUpdate);
removeWLSignal(&Events::listen_pinchEnd);
removeWLSignal(&Events::listen_touchBegin);
removeWLSignal(&Events::listen_touchEnd);
removeWLSignal(&Events::listen_touchUpdate);
removeWLSignal(&Events::listen_touchFrame);
removeWLSignal(&Events::listen_holdBegin);
removeWLSignal(&Events::listen_holdEnd);
removeWLSignal(&Events::listen_newInput);
removeWLSignal(&Events::listen_requestMouse);
removeWLSignal(&Events::listen_requestSetSel);
@ -410,9 +372,6 @@ void CCompositor::cleanup() {
g_pWatchdog.reset();
g_pXWaylandManager.reset();
if (m_sWLRCursor)
wlr_cursor_destroy(m_sWLRCursor);
if (m_sSeat.seat)
wlr_seat_destroy(m_sSeat.seat);
@ -461,6 +420,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
g_pConfigManager->init();
g_pWatchdog = std::make_unique<CWatchdog>(); // requires config
Debug::log(LOG, "Creating the PointerManager!");
g_pPointerManager = std::make_unique<CPointerManager>();
} break;
case STAGE_LATE: {
Debug::log(LOG, "Creating the ThreadManager!");
@ -644,24 +606,28 @@ CMonitor* CCompositor::getMonitorFromDesc(const std::string& desc) {
}
CMonitor* CCompositor::getMonitorFromCursor() {
const auto COORDS = Vector2D(m_sWLRCursor->x, m_sWLRCursor->y);
return getMonitorFromVector(COORDS);
return getMonitorFromVector(g_pPointerManager->position());
}
CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
const auto OUTPUT = wlr_output_layout_output_at(m_sWLROutputLayout, point.x, point.y);
SP<CMonitor> mon;
for (auto& m : m_vMonitors) {
if (CBox{m->vecPosition, m->vecSize}.containsPoint(point)) {
mon = m;
break;
}
}
if (!OUTPUT) {
float bestDistance = 0.f;
CMonitor* pBestMon = nullptr;
if (!mon) {
float bestDistance = 0.f;
SP<CMonitor> pBestMon;
for (auto& m : m_vMonitors) {
float dist = vecToRectDistanceSquared(point, m->vecPosition, m->vecPosition + m->vecSize);
if (dist < bestDistance || !pBestMon) {
bestDistance = dist;
pBestMon = m.get();
pBestMon = m;
}
}
@ -670,10 +636,10 @@ CMonitor* CCompositor::getMonitorFromVector(const Vector2D& point) {
return m_vMonitors.front().get();
}
return pBestMon;
return pBestMon.get();
}
return getMonitorFromOutput(OUTPUT);
return mon.get();
}
void CCompositor::removeWindowFromVectorSafe(PHLWINDOW pWindow) {
@ -708,7 +674,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
const auto BB = w->getWindowBoxUnified(properties);
CBox box = {BB.x - BORDER_GRAB_AREA, BB.y - BORDER_GRAB_AREA, BB.width + 2 * BORDER_GRAB_AREA, BB.height + 2 * BORDER_GRAB_AREA};
if (w->m_bIsFloating && w->m_bIsMapped && !w->isHidden() && !w->m_bX11ShouldntFocus && w->m_bPinned && !w->m_sAdditionalConfigData.noFocus && w != pIgnoreWindow) {
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y}))
if (box.containsPoint(g_pPointerManager->position()))
return w;
if (!w->m_bIsX11) {
@ -742,7 +708,7 @@ PHLWINDOW CCompositor::vectorToWindowUnified(const Vector2D& pos, uint8_t proper
if (w->m_bX11ShouldntFocus && w->m_iX11Type != 2)
continue;
if (box.containsPoint({m_sWLRCursor->x, m_sWLRCursor->y})) {
if (box.containsPoint(g_pPointerManager->position())) {
if (w->m_bIsX11 && w->m_iX11Type == 2 && !wlr_xwayland_or_surface_wants_focus(w->m_uSurface.xwayland)) {
// Override Redirect
@ -1695,7 +1661,7 @@ void checkFocusSurfaceIter(wlr_surface* pSurface, int x, int y, void* data) {
}
CMonitor* CCompositor::getMonitorInDirection(const char& dir) {
return this->getMonitorInDirection(m_pLastMonitor, dir);
return this->getMonitorInDirection(m_pLastMonitor.get(), dir);
}
CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const char& dir) {
@ -1709,7 +1675,7 @@ CMonitor* CCompositor::getMonitorInDirection(CMonitor* pSourceMonitor, const cha
CMonitor* longestIntersectMonitor = nullptr;
for (auto& m : m_vMonitors) {
if (m.get() == m_pLastMonitor)
if (m == m_pLastMonitor)
continue;
const auto POSB = m->vecPosition;
@ -1987,7 +1953,7 @@ void CCompositor::swapActiveWorkspaces(CMonitor* pMonitorA, CMonitor* pMonitorB)
CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
if (name == "current")
return g_pCompositor->m_pLastMonitor;
return g_pCompositor->m_pLastMonitor.get();
else if (isDirection(name))
return getMonitorInDirection(name[0]);
else if (name[0] == '+' || name[0] == '-') {
@ -2008,7 +1974,7 @@ CMonitor* CCompositor::getMonitorFromString(const std::string& name) {
int currentPlace = 0;
for (int i = 0; i < (int)m_vMonitors.size(); i++) {
if (m_vMonitors[i].get() == m_pLastMonitor) {
if (m_vMonitors[i] == m_pLastMonitor) {
currentPlace = i;
break;
}
@ -2134,7 +2100,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
}
}
if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor) { // if it was active, preserve its' status. If it wasn't, don't.
if (SWITCHINGISACTIVE && POLDMON == g_pCompositor->m_pLastMonitor.get()) { // if it was active, preserve its' status. If it wasn't, don't.
Debug::log(LOG, "moveWorkspaceToMonitor: SWITCHINGISACTIVE, active {} -> {}", pMonitor->activeWorkspaceID(), pWorkspace->m_iID);
if (valid(pMonitor->activeWorkspace)) {
@ -2150,7 +2116,7 @@ void CCompositor::moveWorkspaceToMonitor(PHLWORKSPACE pWorkspace, CMonitor* pMon
pWorkspace->m_bVisible = true;
if (!noWarpCursor)
wlr_cursor_warp(m_sWLRCursor, nullptr, pMonitor->vecPosition.x + pMonitor->vecTransformedSize.x / 2, pMonitor->vecPosition.y + pMonitor->vecTransformedSize.y / 2);
g_pPointerManager->warpTo(pMonitor->vecPosition + pMonitor->vecTransformedSize / 2.F);
g_pInputManager->sendMotionEventsToFocused();
}
@ -2415,10 +2381,10 @@ void CCompositor::warpCursorTo(const Vector2D& pos, bool force) {
if (*PNOWARPS && !force)
return;
wlr_cursor_warp(m_sWLRCursor, nullptr, pos.x, pos.y);
g_pPointerManager->warpTo(pos);
const auto PMONITORNEW = getMonitorFromVector(pos);
if (PMONITORNEW != m_pLastMonitor)
if (PMONITORNEW != m_pLastMonitor.get())
setActiveMonitor(PMONITORNEW);
}
@ -2563,11 +2529,11 @@ void CCompositor::renameWorkspace(const int& id, const std::string& name) {
}
void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
if (m_pLastMonitor == pMonitor)
if (m_pLastMonitor.get() == pMonitor)
return;
if (!pMonitor) {
m_pLastMonitor = nullptr;
m_pLastMonitor.reset();
return;
}
@ -2575,7 +2541,7 @@ void CCompositor::setActiveMonitor(CMonitor* pMonitor) {
g_pEventManager->postEvent(SHyprIPCEvent{"focusedmon", pMonitor->szName + "," + (PWORKSPACE ? PWORKSPACE->m_szName : "?")});
EMIT_HOOK_EVENT("focusedMon", pMonitor);
m_pLastMonitor = pMonitor;
m_pLastMonitor = pMonitor->self;
}
bool CCompositor::isWorkspaceSpecial(const int& id) {

View file

@ -51,10 +51,8 @@ class CCompositor {
wlr_data_device_manager* m_sWLRDataDevMgr;
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_output_layout* m_sWLROutputLayout;
wlr_layer_shell_v1* m_sWLRLayerShell;
wlr_xdg_shell* m_sWLRXDGShell;
wlr_cursor* m_sWLRCursor;
wlr_presentation* m_sWLRPresentation;
wlr_egl* m_sWLREGL;
int m_iDRMFD;
@ -88,7 +86,7 @@ class CCompositor {
wlr_surface* m_pLastFocus = nullptr;
PHLWINDOWREF m_pLastWindow;
CMonitor* m_pLastMonitor = nullptr;
WP<CMonitor> m_pLastMonitor;
std::vector<PHLWINDOWREF> m_vWindowFocusHistory; // first element is the most recently focused.

View file

@ -516,6 +516,9 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("opengl:nvidia_anti_flicker", Hyprlang::INT{1});
m_pConfig->addConfigValue("opengl:force_introspection", Hyprlang::INT{2});
m_pConfig->addConfigValue("cursor:no_hardware_cursors", Hyprlang::INT{0});
m_pConfig->addConfigValue("cursor:hotspot_padding", Hyprlang::INT{1});
m_pConfig->addConfigValue("autogenerated", Hyprlang::INT{0});
m_pConfig->addConfigValue("general:col.active_border", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0xffffffff"});

View file

@ -115,7 +115,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
(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.get() == g_pCompositor->m_pLastMonitor ? "true" : "false"),
(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));
}
@ -137,7 +137,7 @@ std::string monitorsRequest(eHyprCtlOutputFormat format, std::string request) {
(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.get() == g_pCompositor->m_pLastMonitor ? "yes" : "no"), (int)m->dpmsStatus, (int)(m->output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED),
(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));
}
}

View file

@ -33,7 +33,7 @@ void CHyprMonitorDebugOverlay::frameData(CMonitor* pMonitor) {
m_pMonitor = pMonitor;
// anim data too
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor;
const auto PMONITORFORTICKS = g_pHyprRenderer->m_pMostHzMonitor ? g_pHyprRenderer->m_pMostHzMonitor : g_pCompositor->m_pLastMonitor.get();
if (PMONITORFORTICKS) {
if (m_dLastAnimationTicks.size() > (long unsigned int)PMONITORFORTICKS->refreshRate)
m_dLastAnimationTicks.pop_front();

View file

@ -122,7 +122,7 @@ void CWLSurface::destroy() {
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager && g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
if (g_pHyprRenderer && g_pHyprRenderer->m_sLastCursorData.surf == this)
g_pHyprRenderer->m_sLastCursorData.surf.reset();
m_pWLRSurface = nullptr;

View file

@ -1169,7 +1169,7 @@ void CWindow::setSuspended(bool suspend) {
bool CWindow::visibleOnMonitor(CMonitor* pMonitor) {
CBox wbox = {m_vRealPosition.value(), m_vRealSize.value()};
return wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, wbox.pWlr());
return !wbox.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty();
}
void CWindow::setAnimationsToMove() {

5
src/devices/IHID.cpp Normal file
View file

@ -0,0 +1,5 @@
#include "IHID.hpp"
eHIDType IHID::getType() {
return HID_TYPE_UNKNOWN;
}

View file

@ -10,13 +10,24 @@ enum eHIDCapabilityType : uint32_t {
HID_INPUT_CAPABILITY_TOUCH = (1 << 2),
};
enum eHIDType {
HID_TYPE_UNKNOWN = 0,
HID_TYPE_POINTER,
HID_TYPE_KEYBOARD,
HID_TYPE_TOUCH,
HID_TYPE_TABLET,
};
/*
Base class for a HID device.
This could be a keyboard, a mouse, or a touchscreen.
*/
class IHID {
public:
virtual ~IHID() {}
virtual uint32_t getCapabilities() = 0;
virtual eHIDType getType();
struct {
CSignal destroy;

View file

@ -7,6 +7,10 @@ uint32_t IKeyboard::getCapabilities() {
return HID_INPUT_CAPABILITY_KEYBOARD;
}
eHIDType IKeyboard::getType() {
return HID_TYPE_KEYBOARD;
}
IKeyboard::~IKeyboard() {
events.destroy.emit();

View file

@ -13,6 +13,7 @@ class IKeyboard : public IHID {
public:
virtual ~IKeyboard();
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual wlr_keyboard* wlr() = 0;

View file

@ -3,3 +3,7 @@
uint32_t IPointer::getCapabilities() {
return HID_INPUT_CAPABILITY_POINTER;
}
eHIDType IPointer::getType() {
return HID_TYPE_POINTER;
}

View file

@ -13,6 +13,7 @@ struct wlr_pointer;
class IPointer : public IHID {
public:
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual wlr_pointer* wlr() = 0;
@ -24,6 +25,7 @@ class IPointer : public IHID {
struct SMotionAbsoluteEvent {
uint32_t timeMs = 0;
Vector2D absolute; // 0.0 - 1.0
SP<IHID> device;
};
struct SButtonEvent {

View file

@ -2,4 +2,8 @@
uint32_t ITouch::getCapabilities() {
return HID_INPUT_CAPABILITY_TOUCH;
}
}
eHIDType ITouch::getType() {
return HID_TYPE_TOUCH;
}

View file

@ -10,13 +10,15 @@ struct wlr_touch;
class ITouch : public IHID {
public:
virtual uint32_t getCapabilities();
virtual eHIDType getType();
virtual bool isVirtual() = 0;
virtual wlr_touch* wlr() = 0;
struct SDownEvent {
uint32_t timeMs = 0;
int32_t touchID = 0;
Vector2D pos;
uint32_t timeMs = 0;
int32_t touchID = 0;
Vector2D pos;
SP<ITouch> device;
};
struct SUpEvent {

View file

@ -36,6 +36,7 @@ CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) {
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec,
.absolute = {E->x, E->y},
.device = self.lock(),
});
}, this, "CMouse");
@ -62,6 +63,10 @@ CMouse::CMouse(wlr_pointer* mouse_) : mouse(mouse_) {
});
}, this, "CMouse");
hyprListener_frame.initCallback(&mouse->events.frame, [this] (void* owner, void* data) {
pointerEvents.frame.emit();
}, this, "CMouse");
hyprListener_swipeBegin.initCallback(&mouse->events.swipe_begin, [this] (void* owner, void* data) {
auto E = (wlr_pointer_swipe_begin_event*)data;

View file

@ -27,6 +27,7 @@ CTouchDevice::CTouchDevice(wlr_touch* touch_) : touch(touch_) {
.timeMs = E->time_msec,
.touchID = E->touch_id,
.pos = {E->x, E->y},
.device = self.lock(),
});
}, this, "CTouchDevice");

View file

@ -37,6 +37,7 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
pointerEvents.motionAbsolute.emit(SMotionAbsoluteEvent{
.timeMs = E->time_msec,
.absolute = {E->x, E->y},
.device = self.lock(),
});
}, this, "CVirtualPointer");
@ -63,6 +64,10 @@ CVirtualPointer::CVirtualPointer(SP<CVirtualPointerV1Resource> resource) : point
});
}, 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;

View file

@ -4,7 +4,6 @@
#include "../helpers/WLClasses.hpp"
#include "../managers/input/InputManager.hpp"
#include "../render/Renderer.hpp"
#include "../protocols/PointerGestures.hpp"
// ---------------------------------------------------- //
// _____ ________ _______ _____ ______ _____ //
@ -16,26 +15,6 @@
// //
// ---------------------------------------------------- //
void Events::listener_mouseFrame(wl_listener* listener, void* data) {
wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat);
}
void Events::listener_mouseMove(wl_listener* listener, void* data) {
g_pInputManager->onMouseMoved((wlr_pointer_motion_event*)data);
}
void Events::listener_mouseMoveAbsolute(wl_listener* listener, void* data) {
g_pInputManager->onMouseWarp((wlr_pointer_motion_absolute_event*)data);
}
void Events::listener_mouseButton(wl_listener* listener, void* data) {
g_pInputManager->onMouseButton((wlr_pointer_button_event*)data);
}
void Events::listener_mouseAxis(wl_listener* listener, void* data) {
g_pInputManager->onMouseWheel((wlr_pointer_axis_event*)data);
}
void Events::listener_requestMouse(wl_listener* listener, void* data) {
const auto EVENT = (wlr_seat_pointer_request_set_cursor_event*)data;
@ -75,62 +54,3 @@ void Events::listener_newInput(wl_listener* listener, void* data) {
g_pInputManager->updateCapabilities();
}
void Events::listener_swipeBegin(wl_listener* listener, void* data) {
const auto EVENT = (wlr_pointer_swipe_begin_event*)data;
g_pInputManager->onSwipeBegin(EVENT);
}
void Events::listener_swipeUpdate(wl_listener* listener, void* data) {
const auto EVENT = (wlr_pointer_swipe_update_event*)data;
g_pInputManager->onSwipeUpdate(EVENT);
}
void Events::listener_swipeEnd(wl_listener* listener, void* data) {
const auto EVENT = (wlr_pointer_swipe_end_event*)data;
g_pInputManager->onSwipeEnd(EVENT);
}
void Events::listener_pinchBegin(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_begin_event*)data;
PROTO::pointerGestures->pinchBegin(EV->time_msec, EV->fingers);
}
void Events::listener_pinchUpdate(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_update_event*)data;
PROTO::pointerGestures->pinchUpdate(EV->time_msec, {EV->dx, EV->dy}, EV->scale, EV->rotation);
}
void Events::listener_pinchEnd(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_pinch_end_event*)data;
PROTO::pointerGestures->pinchEnd(EV->time_msec, EV->cancelled);
}
void Events::listener_touchBegin(wl_listener* listener, void* data) {
g_pInputManager->onTouchDown((wlr_touch_down_event*)data);
}
void Events::listener_touchEnd(wl_listener* listener, void* data) {
g_pInputManager->onTouchUp((wlr_touch_up_event*)data);
}
void Events::listener_touchUpdate(wl_listener* listener, void* data) {
g_pInputManager->onTouchMove((wlr_touch_motion_event*)data);
}
void Events::listener_touchFrame(wl_listener* listener, void* data) {
wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat);
}
void Events::listener_holdBegin(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_hold_begin_event*)data;
PROTO::pointerGestures->holdBegin(EV->time_msec, EV->fingers);
}
void Events::listener_holdEnd(wl_listener* listener, void* data) {
const auto EV = (wlr_pointer_hold_end_event*)data;
PROTO::pointerGestures->holdEnd(EV->time_msec, EV->cancelled);
}

View file

@ -40,16 +40,6 @@ namespace Events {
DYNLISTENFUNC(dissociateX11);
DYNLISTENFUNC(ackConfigure);
// Window subsurfaces
// LISTENER(newSubsurfaceWindow);
// Input events
LISTENER(mouseMove);
LISTENER(mouseMoveAbsolute);
LISTENER(mouseButton);
LISTENER(mouseAxis);
LISTENER(mouseFrame);
LISTENER(newInput);
// Virt Ptr
@ -89,23 +79,6 @@ namespace Events {
// session
LISTENER(sessionActive);
// Touchpad shit
LISTENER(swipeBegin);
LISTENER(swipeEnd);
LISTENER(swipeUpdate);
LISTENER(pinchBegin);
LISTENER(pinchUpdate);
LISTENER(pinchEnd);
// Touch
LISTENER(touchBegin);
LISTENER(touchEnd);
LISTENER(touchUpdate);
LISTENER(touchFrame);
LISTENER(holdBegin);
LISTENER(holdEnd);
// Session Lock
LISTENER(newSessionLock);
};

View file

@ -16,8 +16,7 @@
// //
// --------------------------------------------------------- //
static void checkDefaultCursorWarp(SP<CMonitor>* PNEWMONITORWRAP, std::string monitorName) {
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
static void checkDefaultCursorWarp(SP<CMonitor> PNEWMONITOR, std::string monitorName) {
static auto PCURSORMONITOR = CConfigValue<std::string>("general:default_cursor_monitor");
static auto firstMonitorAdded = std::chrono::system_clock::now();
@ -61,18 +60,18 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
}
// add it to real
SP<CMonitor>* PNEWMONITORWRAP = nullptr;
PNEWMONITORWRAP = &g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>());
auto PNEWMONITOR = g_pCompositor->m_vRealMonitors.emplace_back(makeShared<CMonitor>());
if (std::string("HEADLESS-1") == OUTPUT->name)
g_pCompositor->m_pUnsafeOutput = PNEWMONITORWRAP->get();
g_pCompositor->m_pUnsafeOutput = PNEWMONITOR.get();
(*PNEWMONITORWRAP)->output = OUTPUT;
PNEWMONITOR->output = OUTPUT;
PNEWMONITOR->self = PNEWMONITOR;
const bool FALLBACK = g_pCompositor->m_pUnsafeOutput ? OUTPUT == g_pCompositor->m_pUnsafeOutput->output : false;
(*PNEWMONITORWRAP)->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
const auto PNEWMONITOR = PNEWMONITORWRAP->get();
PNEWMONITOR->ID = FALLBACK ? -1 : g_pCompositor->getNextAvailableMonitorID(OUTPUT->name);
PNEWMONITOR->isUnsafeFallback = FALLBACK;
EMIT_HOOK_EVENT("newMonitor", PNEWMONITOR);
if (!FALLBACK)
PNEWMONITOR->onConnect(false);
@ -82,14 +81,14 @@ void Events::listener_newOutput(wl_listener* listener, void* data) {
// 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;
g_pHyprRenderer->m_pMostHzMonitor = PNEWMONITOR.get();
g_pCompositor->m_bReadyToProcess = true;
g_pConfigManager->m_bWantsMonitorReload = true;
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR);
g_pCompositor->scheduleFrameForMonitor(PNEWMONITOR.get());
checkDefaultCursorWarp(PNEWMONITORWRAP, OUTPUT->name);
checkDefaultCursorWarp(PNEWMONITOR, OUTPUT->name);
for (auto& w : g_pCompositor->m_vWindows) {
if (w->m_iMonitorID == PNEWMONITOR->ID) {

View file

@ -54,10 +54,10 @@ void Events::listener_mapWindow(void* owner, void* data) {
static auto PNEWTAKESOVERFS = CConfigValue<Hyprlang::INT>("misc:new_window_takes_over_fullscreen");
static auto PINITIALWSTRACKING = CConfigValue<Hyprlang::INT>("misc:initial_workspace_tracking");
auto PMONITOR = g_pCompositor->m_pLastMonitor;
auto PMONITOR = g_pCompositor->m_pLastMonitor.get();
if (!g_pCompositor->m_pLastMonitor) {
g_pCompositor->setActiveMonitor(g_pCompositor->getMonitorFromVector({}));
PMONITOR = g_pCompositor->m_pLastMonitor;
PMONITOR = g_pCompositor->m_pLastMonitor.get();
}
auto PWORKSPACE = PMONITOR->activeSpecialWorkspace ? PMONITOR->activeSpecialWorkspace : PMONITOR->activeWorkspace;
PWINDOW->m_iMonitorID = PMONITOR->ID;
@ -330,7 +330,7 @@ void Events::listener_mapWindow(void* owner, void* data) {
else if (PMONITOR->activeWorkspaceID() != REQUESTEDWORKSPACEID)
g_pKeybindManager->m_mDispatchers["workspace"](requestedWorkspaceName);
PMONITOR = g_pCompositor->m_pLastMonitor;
PMONITOR = g_pCompositor->m_pLastMonitor.get();
}
} else
workspaceSilent = false;

View file

@ -121,7 +121,7 @@ CBox& CBox::noNegativeSize() {
return *this;
}
CBox CBox::intersection(const CBox other) const {
CBox CBox::intersection(const CBox& other) const {
const float newX = std::max(x, other.x);
const float newY = std::max(y, other.y);
const float newBottom = std::min(y + h, other.y + other.h);
@ -137,6 +137,14 @@ CBox CBox::intersection(const CBox other) const {
return {newX, newY, newW, newH};
}
bool CBox::overlaps(const CBox& other) const {
return (other.x + other.w >= x) && (x + w >= other.x) && (other.y + other.h >= y) && (y + h >= other.y);
}
bool CBox::inside(const CBox& bound) const {
return bound.x < x && bound.y < y && x + w < bound.x + bound.w && y + h < bound.y + bound.h;
}
CBox CBox::roundInternal() {
float newW = x + w - std::floor(x);
float newH = y + h - std::floor(y);
@ -156,6 +164,16 @@ Vector2D CBox::size() const {
return {w, h};
}
Vector2D CBox::closestPoint(const Vector2D& vec) const {
if (containsPoint(vec))
return vec;
Vector2D nv = vec;
nv.x = std::clamp(nv.x, x, x + w);
nv.y = std::clamp(nv.y, y, y + h);
return nv;
}
SWindowDecorationExtents CBox::extentsFrom(const CBox& small) {
return {{small.x - x, small.y - y}, {w - small.w - (small.x - x), h - small.h - (small.y - y)}};
}

View file

@ -54,13 +54,16 @@ class CBox {
CBox& noNegativeSize();
CBox copy() const;
CBox intersection(const CBox other) const;
CBox intersection(const CBox& other) const;
bool overlaps(const CBox& other) const;
bool inside(const CBox& bound) const;
SWindowDecorationExtents extentsFrom(const CBox&); // this is the big box
Vector2D middle() const;
Vector2D pos() const;
Vector2D size() const;
Vector2D closestPoint(const Vector2D& vec) const;
bool containsPoint(const Vector2D& vec) const;
bool empty() const;

View file

@ -149,14 +149,14 @@ void CMonitor::onConnect(bool noRule) {
for (const auto& PTOUCHDEV : g_pInputManager->m_vTouches) {
if (matchesStaticSelector(PTOUCHDEV->boundOutput)) {
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output);
// wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, output);
}
}
for (const auto& PTABLET : g_pInputManager->m_lTablets) {
if (matchesStaticSelector(PTABLET.boundOutput)) {
Debug::log(LOG, "Binding tablet {} to output {}", PTABLET.name, szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
// wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, PTABLET.wlrDevice, output);
}
}
@ -203,7 +203,7 @@ void CMonitor::onConnect(bool noRule) {
// verify last mon valid
bool found = false;
for (auto& m : g_pCompositor->m_vMonitors) {
if (m.get() == g_pCompositor->m_pLastMonitor) {
if (m == g_pCompositor->m_pLastMonitor) {
found = true;
break;
}
@ -219,6 +219,7 @@ void CMonitor::onConnect(bool noRule) {
PROTO::gamma->applyGammaToState(this);
events.connect.emit();
updateGlobal();
}
void CMonitor::onDisconnect(bool destroy) {
@ -285,10 +286,11 @@ void CMonitor::onDisconnect(bool destroy) {
m_bEnabled = false;
m_bRenderingInitPassed = false;
updateGlobal();
if (BACKUPMON) {
// snap cursor
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, BACKUPMON->vecPosition.x + BACKUPMON->vecTransformedSize.x / 2.f,
BACKUPMON->vecPosition.y + BACKUPMON->vecTransformedSize.y / 2.f);
g_pCompositor->warpCursorTo(BACKUPMON->vecPosition + BACKUPMON->vecTransformedSize / 2.F, true);
// move workspaces
std::deque<PHLWORKSPACE> wspToMove;
@ -306,22 +308,19 @@ void CMonitor::onDisconnect(bool destroy) {
} else {
g_pCompositor->m_pLastFocus = nullptr;
g_pCompositor->m_pLastWindow.reset();
g_pCompositor->m_pLastMonitor = nullptr;
g_pCompositor->m_pLastMonitor.reset();
}
if (activeWorkspace)
activeWorkspace->m_bVisible = false;
activeWorkspace.reset();
if (!destroy)
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
wlr_output_state_set_enabled(state.wlr(), false);
if (!state.commit())
Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor == this)
if (g_pCompositor->m_pLastMonitor.get() == this)
g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput);
if (g_pHyprRenderer->m_pMostHzMonitor == this) {
@ -508,8 +507,6 @@ void CMonitor::setMirror(const std::string& mirrorOf) {
activeWorkspace.reset();
wlr_output_layout_remove(g_pCompositor->m_sWLROutputLayout, output);
vecPosition = PMIRRORMON->vecPosition;
pMirrorOf = PMIRRORMON;
@ -728,9 +725,6 @@ void CMonitor::setSpecialWorkspace(const int& id) {
void CMonitor::moveTo(const Vector2D& pos) {
vecPosition = pos;
if (!isMirror())
wlr_output_layout_add(g_pCompositor->m_sWLROutputLayout, output, (int)vecPosition.x, (int)vecPosition.y);
}
Vector2D CMonitor::middle() {
@ -749,10 +743,22 @@ void CMonitor::updateMatrix() {
int64_t CMonitor::activeWorkspaceID() {
return activeWorkspace ? activeWorkspace->m_iID : 0;
}
int64_t CMonitor::activeSpecialWorkspaceID() {
return activeSpecialWorkspace ? activeSpecialWorkspace->m_iID : 0;
}
CBox CMonitor::logicalBox() {
return {vecPosition, vecSize};
}
void CMonitor::updateGlobal() {
if (output->width > 0 && output->height > 0 && m_bEnabled)
wlr_output_create_global(output, g_pCompositor->m_sWLDisplay);
else
wlr_output_destroy_global(output);
}
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
wlr_output_state_init(&m_state);

View file

@ -114,6 +114,8 @@ class CMonitor {
SMonitorRule activeMonitorRule;
WP<CMonitor> self;
// mirroring
CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors;
@ -167,6 +169,8 @@ class CMonitor {
void updateMatrix();
int64_t activeWorkspaceID();
int64_t activeSpecialWorkspaceID();
CBox logicalBox();
void updateGlobal();
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;

View file

@ -142,6 +142,9 @@ bool CRegion::empty() const {
}
Vector2D CRegion::closestPoint(const Vector2D& vec) const {
if (containsPoint(vec))
return vec;
double bestDist = __FLT_MAX__;
Vector2D leader = vec;
@ -162,7 +165,7 @@ Vector2D CRegion::closestPoint(const Vector2D& vec) const {
else
y = vec.y;
double distance = sqrt(pow(x, 2) + pow(y, 2));
double distance = pow(x, 2) + pow(y, 2);
if (distance < bestDist) {
bestDist = distance;
leader = {x, y};

View file

@ -42,9 +42,11 @@ Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const {
}
double Vector2D::distance(const Vector2D& other) const {
double dx = x - other.x;
double dy = y - other.y;
return std::sqrt(dx * dx + dy * dy);
return std::sqrt(distanceSq(other));
}
double Vector2D::distanceSq(const Vector2D& other) const {
return (x - other.x) * (x - other.x) + (y - other.y) * (y - other.y);
}
double Vector2D::size() const {

View file

@ -89,6 +89,7 @@ class Vector2D {
}
double distance(const Vector2D& other) const;
double distanceSq(const Vector2D& other) const;
double size() const;
Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D{-1, -1}) const;

View file

@ -10,7 +10,7 @@ CHyprError::CHyprError() {
if (!m_bIsCreated)
return;
g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor);
g_pHyprRenderer->damageMonitor(g_pCompositor->m_pLastMonitor.get());
m_bMonitorChanged = true;
});

View file

@ -39,7 +39,6 @@ extern "C" {
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_drm_lease_v1.h>
@ -52,7 +51,6 @@ extern "C" {
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_matrix.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_presentation_time.h>

View file

@ -1,6 +1,7 @@
#include "CursorManager.hpp"
#include "Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "PointerManager.hpp"
extern "C" {
#include <wlr/interfaces/wlr_buffer.h>
@ -73,8 +74,8 @@ static bool cursorBufferBeginDataPtr(struct wlr_buffer* wlr_buffer, uint32_t fla
if (flags & WLR_BUFFER_DATA_PTR_ACCESS_WRITE)
return false;
*data = cairo_image_surface_get_data(buffer->surface);
*stride = cairo_image_surface_get_stride(buffer->surface);
*data = buffer->pixelData ? buffer->pixelData : cairo_image_surface_get_data(buffer->surface);
*stride = buffer->stride;
*format = DRM_FORMAT_ARGB8888;
return true;
}
@ -94,6 +95,14 @@ CCursorManager::CCursorBuffer::CCursorBuffer(cairo_surface_t* surf, const Vector
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() {
@ -104,18 +113,53 @@ wlr_buffer* CCursorManager::getCursorBuffer() {
return !m_vCursorBuffers.empty() ? &m_vCursorBuffers.back()->wlrBuffer.base : nullptr;
}
void CCursorManager::setCursorSurface(wlr_surface* surf, const Vector2D& hotspot) {
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspot.x, hotspot.y);
void CCursorManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) {
if (!surf || !surf->wlr())
g_pPointerManager->resetCursorImage();
else
g_pPointerManager->setCursorSurface(surf, hotspot);
m_bOurBufferConnected = false;
}
void CCursorManager::setXCursor(const std::string& name) {
if (!m_pWLRXCursorMgr) {
g_pPointerManager->resetCursorImage();
return;
}
float scale = std::ceil(m_fCursorScale);
wlr_xcursor_manager_load(m_pWLRXCursorMgr, scale);
auto xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, name.c_str(), scale);
if (!xcursor) {
Debug::log(ERR, "XCursor has no shape {}, retrying with left-ptr", name);
xcursor = wlr_xcursor_manager_get_xcursor(m_pWLRXCursorMgr, "left-ptr", scale);
}
if (!xcursor || !xcursor->images[0]) {
Debug::log(ERR, "XCursor is broken. F this garbage.");
g_pPointerManager->resetCursorImage();
return;
}
auto image = xcursor->images[0];
m_vCursorBuffers.emplace_back(std::make_unique<CCursorBuffer>(image->buffer, Vector2D{image->width, image->height}, Vector2D{image->hotspot_x, image->hotspot_y}));
g_pPointerManager->setCursorBuffer(getCursorBuffer(), Vector2D{image->hotspot_x, image->hotspot_y} / scale, scale);
if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
m_bOurBufferConnected = true;
}
void CCursorManager::setCursorFromName(const std::string& name) {
static auto PUSEHYPRCURSOR = CConfigValue<Hyprlang::INT>("misc:enable_hyprcursor");
if (!m_pHyprcursor->valid() || !*PUSEHYPRCURSOR) {
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str());
setXCursor(name);
return;
}
@ -142,7 +186,7 @@ void CCursorManager::setCursorFromName(const std::string& name) {
if (m_sCurrentCursorShapeData.images.size() < 1) {
Debug::log(ERR, "BUG THIS: No fallback found for a cursor in setCursorFromName");
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, m_pWLRXCursorMgr, name.c_str());
setXCursor(name);
return;
}
}
@ -151,12 +195,10 @@ void CCursorManager::setCursorFromName(const std::string& name) {
Vector2D{m_sCurrentCursorShapeData.images[0].size, m_sCurrentCursorShapeData.images[0].size},
Vector2D{m_sCurrentCursorShapeData.images[0].hotspotX, m_sCurrentCursorShapeData.images[0].hotspotY}));
if (g_pCompositor->m_sWLRCursor) {
wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[0].hotspotX / m_fCursorScale,
m_sCurrentCursorShapeData.images[0].hotspotY / m_fCursorScale, m_fCursorScale);
if (m_vCursorBuffers.size() > 1)
wlr_buffer_drop(&m_vCursorBuffers.front()->wlrBuffer.base);
}
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);
m_bOurBufferConnected = true;
@ -183,9 +225,10 @@ void CCursorManager::tickAnimatedCursor() {
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}));
if (g_pCompositor->m_sWLRCursor)
wlr_cursor_set_buffer(g_pCompositor->m_sWLRCursor, getCursorBuffer(), m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX / m_fCursorScale,
m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY / m_fCursorScale, m_fCursorScale);
g_pPointerManager->setCursorBuffer(
getCursorBuffer(),
Vector2D{m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotX, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].hotspotY} / m_fCursorScale,
m_fCursorScale);
wl_event_source_timer_update(m_pAnimationTimer, m_sCurrentCursorShapeData.images[m_iCurrentAnimationFrame].delay);
}
@ -223,8 +266,6 @@ void CCursorManager::updateTheme() {
highestScale = m->scale;
}
highestScale = std::ceil(highestScale);
if (std::round(highestScale * m_iSize) == m_sCurrentStyleInfo.size)
return;

View file

@ -9,6 +9,7 @@
struct wlr_buffer;
struct wlr_xcursor_manager;
struct wlr_xwayland;
class CWLSurface;
class CCursorManager {
public:
@ -18,7 +19,8 @@ class CCursorManager {
wlr_buffer* getCursorBuffer();
void setCursorFromName(const std::string& name);
void setCursorSurface(wlr_surface* surf, const Vector2D& hotspot);
void setCursorSurface(CWLSurface* surf, const Vector2D& hotspot);
void setXCursor(const std::string& name);
void changeTheme(const std::string& name, const int size);
void updateTheme();
@ -30,13 +32,16 @@ class CCursorManager {
class CCursorBuffer {
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;
cairo_surface_t* surface = nullptr;
bool dropped = false;
CCursorBuffer* parent = nullptr;
uint8_t* pixelData = nullptr;
size_t stride = 0;
} wlrBuffer;
private:

View file

@ -256,7 +256,7 @@ bool CKeybindManager::tryMoveFocusToMonitor(CMonitor* monitor) {
if (!monitor)
return false;
const auto LASTMONITOR = g_pCompositor->m_pLastMonitor;
const auto LASTMONITOR = g_pCompositor->m_pLastMonitor.get();
if (LASTMONITOR == monitor) {
Debug::log(LOG, "Tried to move to active monitor");
return false;
@ -407,7 +407,7 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
return !suppressEvent && !mouseBindWasActive;
}
bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
bool CKeybindManager::onAxisEvent(const IPointer::SAxisEvent& e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
static auto PDELAY = CConfigValue<Hyprlang::INT>("binds:scroll_event_delay");
@ -426,13 +426,13 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
}
bool found = false;
if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_VERTICAL_SCROLL) {
if (e->delta < 0)
if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
if (e.delta < 0)
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_down"}, true);
else
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_up"}, true);
} else if (e->source == WL_POINTER_AXIS_SOURCE_WHEEL && e->orientation == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
if (e->delta < 0)
} else if (e.source == WL_POINTER_AXIS_SOURCE_WHEEL && e.axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
if (e.delta < 0)
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_left"}, true);
else
found = handleKeybinds(MODS, SPressedKeyWithMods{.keyName = "mouse_right"}, true);
@ -444,18 +444,18 @@ bool CKeybindManager::onAxisEvent(wlr_pointer_axis_event* e) {
return !found;
}
bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
bool CKeybindManager::onMouseEvent(const IPointer::SButtonEvent& e) {
const auto MODS = g_pInputManager->accumulateModsFromAllKBs();
bool suppressEvent = false;
m_uLastMouseCode = e->button;
m_uLastMouseCode = e.button;
m_uLastCode = 0;
m_uTimeLastMs = e->time_msec;
m_uTimeLastMs = e.timeMs;
bool mouseBindWasActive = ensureMouseBindState();
const auto KEY_NAME = "mouse:" + std::to_string(e->button);
const auto KEY_NAME = "mouse:" + std::to_string(e.button);
const auto KEY = SPressedKeyWithMods{
.keyName = KEY_NAME,
@ -468,7 +468,7 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
m_pActiveKeybind = nullptr;
}
if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) {
if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) {
m_dPressedKeys.push_back(KEY);
suppressEvent = handleKeybinds(MODS, KEY, true);
@ -501,12 +501,11 @@ bool CKeybindManager::onMouseEvent(wlr_pointer_button_event* e) {
return !suppressEvent && !mouseBindWasActive;
}
void CKeybindManager::resizeWithBorder(wlr_pointer_button_event* e) {
if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) {
void CKeybindManager::resizeWithBorder(const IPointer::SButtonEvent& e) {
if (e.state == WL_POINTER_BUTTON_STATE_PRESSED)
mouse("1resizewindow");
} else {
else
mouse("0resizewindow");
}
}
void CKeybindManager::onSwitchEvent(const std::string& switchName) {
@ -965,7 +964,7 @@ void CKeybindManager::changeworkspace(std::string args) {
static auto PALLOWWORKSPACECYCLES = CConfigValue<Hyprlang::INT>("binds:allow_workspace_cycles");
static auto PWORKSPACECENTERON = CConfigValue<Hyprlang::INT>("binds:workspace_center_on");
const auto PMONITOR = g_pCompositor->m_pLastMonitor;
const auto PMONITOR = g_pCompositor->m_pLastMonitor.get();
if (!PMONITOR)
return;
@ -1445,20 +1444,20 @@ void CKeybindManager::moveCursorToCorner(std::string arg) {
switch (CORNER) {
case 0:
// bottom left
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y);
g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y}, true);
break;
case 1:
// bottom right
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x,
PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y);
g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y + PWINDOW->m_vRealSize.value().y},
true);
break;
case 2:
// top right
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y);
g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x + PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealPosition.value().y}, true);
break;
case 3:
// top left
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y);
g_pCompositor->warpCursorTo({PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y}, true);
break;
}
}
@ -1488,7 +1487,7 @@ void CKeybindManager::moveCursor(std::string args) {
x = std::stoi(x_str);
y = std::stoi(y_str);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, x, y);
g_pCompositor->warpCursorTo({x, y}, true);
}
void CKeybindManager::workspaceOpt(std::string args) {
@ -1624,7 +1623,7 @@ void CKeybindManager::focusWorkspaceOnCurrentMonitor(std::string args) {
return;
}
const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor;
const auto PCURRMONITOR = g_pCompositor->m_pLastMonitor.get();
if (!PCURRMONITOR) {
Debug::log(ERR, "focusWorkspaceOnCurrentMonitor monitor doesn't exist!");

View file

@ -5,6 +5,7 @@
#include "../Compositor.hpp"
#include <unordered_map>
#include <functional>
#include "../devices/IPointer.hpp"
class CInputManager;
class CConfigManager;
@ -62,9 +63,9 @@ class CKeybindManager {
~CKeybindManager();
bool onKeyEvent(std::any, SP<IKeyboard>);
bool onAxisEvent(wlr_pointer_axis_event*);
bool onMouseEvent(wlr_pointer_button_event*);
void resizeWithBorder(wlr_pointer_button_event*);
bool onAxisEvent(const IPointer::SAxisEvent&);
bool onMouseEvent(const IPointer::SButtonEvent&);
void resizeWithBorder(const IPointer::SButtonEvent&);
void onSwitchEvent(const std::string&);
void onSwitchOnEvent(const std::string&);
void onSwitchOffEvent(const std::string&);

View file

@ -0,0 +1,864 @@
#include "PointerManager.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/PointerGestures.hpp"
#include "../protocols/FractionalScale.hpp"
#include <wlr/interfaces/wlr_output.h>
#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);
size_t capacity = a->len < b->len ? a->len : b->len;
uint64_t* modifiers = (uint64_t*)malloc(sizeof(*modifiers) * capacity);
if (!modifiers)
return false;
struct wlr_drm_format fmt = {
.format = a->format,
.len = 0,
.capacity = capacity,
.modifiers = modifiers,
};
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;
}
}
}
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;
}
}
return output_pick_format(output, display_formats, format, DRM_FORMAT_ARGB8888);
}
CPointerManager::CPointerManager() {
hooks.monitorAdded = g_pHookSystem->hookDynamic("newMonitor", [this](void* self, SCallbackInfo& info, std::any data) {
auto PMONITOR = std::any_cast<SP<CMonitor>>(data);
onMonitorLayoutChange();
PMONITOR->events.modeChanged.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr);
PMONITOR->events.disconnect.registerStaticListener([this](void* owner, std::any data) { onMonitorLayoutChange(); }, nullptr);
PMONITOR->events.destroy.registerStaticListener(
[this](void* owner, std::any data) { std::erase_if(monitorStates, [](const auto& other) { return other->monitor.expired(); }); }, nullptr);
});
}
void CPointerManager::lockSoftwareForMonitor(SP<CMonitor> mon) {
auto state = stateFor(mon);
state->softwareLocks++;
if (state->softwareLocks == 1)
updateCursorBackend();
}
void CPointerManager::unlockSoftwareForMonitor(SP<CMonitor> mon) {
auto state = stateFor(mon);
state->softwareLocks--;
if (state->softwareLocks < 0)
state->softwareLocks = 0;
if (state->softwareLocks == 0)
updateCursorBackend();
}
Vector2D CPointerManager::position() {
return pointerPos;
}
bool CPointerManager::hasCursor() {
return currentCursorImage.pBuffer || currentCursorImage.surface;
}
SP<CPointerManager::SMonitorPointerState> CPointerManager::stateFor(SP<CMonitor> mon) {
auto it = std::find_if(monitorStates.begin(), monitorStates.end(), [mon](const auto& other) { return other->monitor == mon; });
if (it == monitorStates.end())
return monitorStates.emplace_back(makeShared<CPointerManager::SMonitorPointerState>(mon));
return *it;
}
void CPointerManager::setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale) {
if (buf == currentCursorImage.pBuffer) {
if (hotspot != currentCursorImage.hotspot || scale != currentCursorImage.scale) {
currentCursorImage.hotspot = hotspot;
currentCursorImage.scale = scale;
updateCursorBackend();
}
return;
}
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.hotspot = hotspot;
currentCursorImage.scale = scale;
updateCursorBackend();
}
void CPointerManager::setCursorSurface(CWLSurface* surf, const Vector2D& hotspot) {
if (surf == currentCursorImage.surface) {
if (hotspot != currentCursorImage.hotspot || (surf && surf->wlr() ? surf->wlr()->current.scale : 1.F) != currentCursorImage.scale) {
currentCursorImage.hotspot = hotspot;
currentCursorImage.scale = surf && surf->wlr() ? surf->wlr()->current.scale : 1.F;
updateCursorBackend();
}
return;
}
resetCursorImage(false);
if (surf) {
currentCursorImage.size = {surf->wlr()->current.buffer_width, surf->wlr()->current.buffer_height};
currentCursorImage.surface = surf;
currentCursorImage.scale = surf->wlr()->current.scale;
currentCursorImage.destroySurface = surf->events.destroy.registerListener([this](std::any data) { resetCursorImage(); });
currentCursorImage.hyprListener_commitSurface.initCallback(
&surf->wlr()->events.commit,
[this](void* owner, void* data) {
currentCursorImage.size = {currentCursorImage.surface->wlr()->current.buffer_width, currentCursorImage.surface->wlr()->current.buffer_height};
currentCursorImage.scale = currentCursorImage.surface && currentCursorImage.surface->wlr() ? currentCursorImage.surface->wlr()->current.scale : 1.F;
recheckEnteredOutputs();
updateCursorBackend();
},
nullptr, "CPointerManager");
if (surf->wlr()->current.buffer) {
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
wlr_surface_send_frame_done(surf->wlr(), &now);
}
}
currentCursorImage.hotspot = hotspot;
recheckEnteredOutputs();
updateCursorBackend();
}
void CPointerManager::recheckEnteredOutputs() {
if (!hasCursor())
return;
auto box = getCursorBoxGlobal();
for (auto& s : monitorStates) {
if (s->monitor.expired() || s->monitor->isMirror() || !s->monitor->m_bEnabled)
continue;
const bool overlaps = box.overlaps(s->monitor->logicalBox());
if (!s->entered && overlaps) {
s->entered = true;
if (!currentCursorImage.surface)
continue;
wlr_surface_send_enter(currentCursorImage.surface->wlr(), s->monitor->output);
PROTO::fractional->sendScale(currentCursorImage.surface->wlr(), s->monitor->scale);
g_pCompositor->setPreferredScaleForSurface(currentCursorImage.surface->wlr(), s->monitor->scale);
} else if (s->entered && !overlaps) {
s->entered = false;
// 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 (!currentCursorImage.surface)
continue;
wlr_surface_send_leave(currentCursorImage.surface->wlr(), s->monitor->output);
}
}
}
void CPointerManager::resetCursorImage(bool apply) {
if (currentCursorImage.surface) {
for (auto& m : g_pCompositor->m_vMonitors) {
wlr_surface_send_leave(currentCursorImage.surface->wlr(), m->output);
}
currentCursorImage.destroySurface.reset();
currentCursorImage.hyprListener_commitSurface.removeCallback();
currentCursorImage.surface = nullptr;
} else if (currentCursorImage.pBuffer) {
wlr_buffer_unlock(currentCursorImage.pBuffer);
currentCursorImage.hyprListener_destroyBuffer.removeCallback();
currentCursorImage.pBuffer = nullptr;
}
if (currentCursorImage.pBufferTexture) {
wlr_texture_destroy(currentCursorImage.pBufferTexture);
currentCursorImage.pBufferTexture = nullptr;
}
currentCursorImage.scale = 1.F;
currentCursorImage.hotspot = {0, 0};
if (!apply)
return;
for (auto& ms : monitorStates) {
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);
ms->cursorFrontBuffer = nullptr;
}
}
}
void CPointerManager::updateCursorBackend() {
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
for (auto& m : g_pCompositor->m_vMonitors) {
auto state = stateFor(m);
if (state->softwareLocks > 0 || *PNOHW || !attemptHardwareCursor(state)) {
Debug::log(TRACE, "Output {} rejected hardware cursors, falling back to sw", m->szName);
state->box = getCursorBoxLogicalForMonitor(state->monitor.lock());
state->hardwareFailed = true;
if (state->hwApplied)
setHWCursorBuffer(state, nullptr);
state->hwApplied = false;
continue;
}
state->hardwareFailed = false;
}
}
void CPointerManager::onCursorMoved() {
if (!hasCursor())
return;
for (auto& m : g_pCompositor->m_vMonitors) {
auto state = stateFor(m);
state->box = getCursorBoxLogicalForMonitor(state->monitor.lock());
if (state->hardwareFailed || !state->entered)
continue;
const auto CURSORPOS = getCursorPosForMonitor(m);
m->output->impl->move_cursor(m->output, CURSORPOS.x, CURSORPOS.y);
}
}
bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerState> state) {
auto output = state->monitor->output;
if (!output->impl->set_cursor)
return false;
const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
state->monitor->output->impl->move_cursor(state->monitor->output, CURSORPOS.x, CURSORPOS.y);
auto texture = getCurrentCursorTexture();
if (!texture) {
Debug::log(TRACE, "[pointer] no texture for hw cursor -> hiding");
setHWCursorBuffer(state, nullptr);
return true;
}
auto buffer = renderHWCursorBuffer(state, texture);
if (!buffer) {
Debug::log(TRACE, "[pointer] hw cursor failed rendering");
setHWCursorBuffer(state, nullptr);
return false;
}
bool success = setHWCursorBuffer(state, buffer);
if (!success) {
Debug::log(TRACE, "[pointer] hw cursor failed applying, hiding");
setHWCursorBuffer(state, nullptr);
return false;
} else
state->hwApplied = true;
return success;
}
bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf) {
if (!state->monitor->output->impl->set_cursor)
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))
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, wlr_texture* 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);
if (w < currentCursorImage.size.x || h < currentCursorImage.size.y) {
Debug::log(TRACE, "hardware cursor too big! {} > {}x{}", currentCursorImage.size, w, h);
return nullptr;
}
}
if (w <= 0 || h <= 0) {
Debug::log(TRACE, "hw cursor for output {} failed the size checks ({}x{} is invalid)", state->monitor->szName, w, h);
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;
}
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");
return nullptr;
}
}
wlr_buffer* buf = wlr_swapchain_acquire(output->cursor_swapchain, nullptr);
if (!buf) {
Debug::log(TRACE, "Failed to acquire a buffer from the cursor swapchain");
return nullptr;
}
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
const auto RBO = g_pHyprRenderer->getOrCreateRenderbuffer(buf, DRM_FORMAT_ARGB8888);
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},
currentCursorImage.scale, state->monitor->scale, xbox.size());
g_pHyprOpenGL->renderTexture(texture, &xbox, 1.F);
g_pHyprOpenGL->end();
glFlush();
g_pHyprOpenGL->m_RenderData.pMonitor = nullptr;
g_pHyprRenderer->onRenderbufferDestroy(RBO);
wlr_buffer_unlock(buf);
return buf;
}
void CPointerManager::renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage, std::optional<Vector2D> overridePos) {
if (!hasCursor())
return;
auto state = stateFor(pMonitor);
if ((!state->hardwareFailed && state->softwareLocks == 0)) {
if (currentCursorImage.surface)
wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now);
return;
}
auto box = state->box.copy();
if (overridePos.has_value()) {
box.x = overridePos->x;
box.y = overridePos->y;
}
if (box.intersection(CBox{{}, {pMonitor->vecSize}}).empty())
return;
auto texture = getCurrentCursorTexture();
if (!texture)
return;
box.scale(pMonitor->scale);
g_pHyprOpenGL->renderTextureWithDamage(texture, &box, &damage, 1.F);
if (currentCursorImage.surface)
wlr_surface_send_frame_done(currentCursorImage.surface->wlr(), now);
}
Vector2D CPointerManager::getCursorPosForMonitor(SP<CMonitor> pMonitor) {
return CBox{pointerPos - pMonitor->vecPosition, {0, 0}}
//.transform(pMonitor->transform, pMonitor->vecTransformedSize.x / pMonitor->scale, pMonitor->vecTransformedSize.y / pMonitor->scale)
.pos() *
pMonitor->scale;
}
Vector2D CPointerManager::transformedHotspot(SP<CMonitor> pMonitor) {
return CBox{currentCursorImage.hotspot, {0, 0}}
.transform(wlr_output_transform_invert(pMonitor->transform), pMonitor->output->cursor_swapchain->width, pMonitor->output->cursor_swapchain->height)
.pos();
}
CBox CPointerManager::getCursorBoxLogicalForMonitor(SP<CMonitor> pMonitor) {
return getCursorBoxGlobal().translate(-pMonitor->vecPosition);
}
CBox CPointerManager::getCursorBoxGlobal() {
return CBox{pointerPos, currentCursorImage.size / currentCursorImage.scale}.translate(-currentCursorImage.hotspot / currentCursorImage.scale);
}
Vector2D CPointerManager::closestValid(const Vector2D& pos) {
static auto PADDING = CConfigValue<Hyprlang::INT>("cursor:hotspot_padding");
auto CURSOR_PADDING = std::clamp((int)*PADDING, 1, 100); // 1px
CBox hotBox = {{pos.x - CURSOR_PADDING, pos.y - CURSOR_PADDING}, {2 * CURSOR_PADDING, 2 * CURSOR_PADDING}};
//
static auto INSIDE_LAYOUT = [this](const CBox& box) -> bool {
for (auto& b : currentMonitorLayout.monitorBoxes) {
if (box.inside(b))
return true;
}
return false;
};
static auto INSIDE_LAYOUT_COORD = [this](const Vector2D& vec) -> bool {
for (auto& b : currentMonitorLayout.monitorBoxes) {
if (b.containsPoint(vec))
return true;
}
return false;
};
static auto NEAREST_LAYOUT = [this](const Vector2D& vec) -> Vector2D {
Vector2D leader;
float distanceSq = __FLT_MAX__;
for (auto& b : currentMonitorLayout.monitorBoxes) {
auto p = b.closestPoint(vec);
auto distSq = p.distanceSq(vec);
if (distSq < distanceSq) {
leader = p;
distanceSq = distSq;
}
}
if (distanceSq > 1337.69420e+20F)
return {0, 0}; // ???
return leader;
};
if (INSIDE_LAYOUT(hotBox))
return pos;
Vector2D leader = NEAREST_LAYOUT(pos);
hotBox.x = leader.x - CURSOR_PADDING;
hotBox.y = leader.y - CURSOR_PADDING;
// push the hotbox around so that it fits in the layout
if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING})) {
auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() + Vector2D{CURSOR_PADDING, CURSOR_PADDING});
hotBox.translate(delta);
}
if (!INSIDE_LAYOUT_COORD(hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING})) {
auto delta = NEAREST_LAYOUT(hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() - Vector2D{CURSOR_PADDING, CURSOR_PADDING});
hotBox.translate(delta);
}
if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING})) {
auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING}) - (hotBox.middle() + Vector2D{CURSOR_PADDING, -CURSOR_PADDING});
hotBox.translate(delta);
}
if (!INSIDE_LAYOUT_COORD(hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING})) {
auto delta = NEAREST_LAYOUT(hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING}) - (hotBox.middle() + Vector2D{-CURSOR_PADDING, CURSOR_PADDING});
hotBox.translate(delta);
}
return hotBox.middle();
}
void CPointerManager::damageIfSoftware() {
auto b = getCursorBoxGlobal();
static auto PNOHW = CConfigValue<Hyprlang::INT>("cursor:no_hardware_cursors");
for (auto& mw : monitorStates) {
if (mw->monitor.expired())
continue;
if ((mw->softwareLocks > 0 || mw->hardwareFailed || *PNOHW) && b.overlaps({mw->monitor->vecPosition, mw->monitor->vecSize})) {
g_pHyprRenderer->damageBox(&b);
break;
}
}
}
void CPointerManager::warpTo(const Vector2D& logical) {
damageIfSoftware();
pointerPos = closestValid(logical);
recheckEnteredOutputs();
onCursorMoved();
damageIfSoftware();
}
void CPointerManager::move(const Vector2D& deltaLogical) {
const auto oldPos = pointerPos;
auto newPos = oldPos + deltaLogical;
warpTo(newPos);
}
void CPointerManager::warpAbsolute(const Vector2D& abs, SP<IHID> dev) {
SP<CMonitor> currentMonitor = g_pCompositor->m_pLastMonitor.lock();
switch (dev->getType()) {
case HID_TYPE_TABLET:
//TODO:
break;
case HID_TYPE_TOUCH: {
auto TOUCH = SP<ITouch>(dev);
if (!TOUCH->boundOutput.empty()) {
const auto PMONITOR = g_pCompositor->getMonitorFromString(TOUCH->boundOutput);
if (PMONITOR)
currentMonitor = PMONITOR->self.lock();
}
break;
}
default: break;
}
if (!currentMonitor)
return;
damageIfSoftware();
pointerPos = currentMonitor->vecPosition + currentMonitor->vecSize * abs;
onCursorMoved();
recheckEnteredOutputs();
damageIfSoftware();
}
void CPointerManager::onMonitorLayoutChange() {
currentMonitorLayout.monitorBoxes.clear();
for (auto& m : g_pCompositor->m_vMonitors) {
if (m->isMirror() || !m->m_bEnabled)
continue;
currentMonitorLayout.monitorBoxes.emplace_back(CBox{m->vecPosition, m->vecSize});
}
damageIfSoftware();
pointerPos = closestValid(pointerPos);
updateCursorBackend();
recheckEnteredOutputs();
damageIfSoftware();
}
wlr_texture* CPointerManager::getCurrentCursorTexture() {
if (!currentCursorImage.pBuffer && (!currentCursorImage.surface || !wlr_surface_get_texture(currentCursorImage.surface->wlr())))
return nullptr;
if (currentCursorImage.pBuffer) {
if (!currentCursorImage.pBufferTexture)
currentCursorImage.pBufferTexture = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, currentCursorImage.pBuffer);
return currentCursorImage.pBufferTexture;
}
return wlr_surface_get_texture(currentCursorImage.surface->wlr());
}
void CPointerManager::attachPointer(SP<IPointer> pointer) {
if (!pointer)
return;
auto listener = pointerListeners.emplace_back(makeShared<SPointerListener>());
listener->pointer = pointer;
// clang-format off
listener->destroy = pointer->events.destroy.registerListener([this] (std::any d) {
detachPointer(nullptr);
});
listener->motion = pointer->pointerEvents.motion.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SMotionEvent>(e);
g_pInputManager->onMouseMoved(E);
});
listener->motionAbsolute = pointer->pointerEvents.motionAbsolute.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SMotionAbsoluteEvent>(e);
g_pInputManager->onMouseWarp(E);
});
listener->button = pointer->pointerEvents.button.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SButtonEvent>(e);
g_pInputManager->onMouseButton(E);
});
listener->axis = pointer->pointerEvents.axis.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SAxisEvent>(e);
g_pInputManager->onMouseWheel(E);
});
listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) {
wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat);
});
listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SSwipeBeginEvent>(e);
g_pInputManager->onSwipeBegin(E);
});
listener->swipeEnd = pointer->pointerEvents.swipeEnd.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SSwipeEndEvent>(e);
g_pInputManager->onSwipeEnd(E);
});
listener->swipeUpdate = pointer->pointerEvents.swipeUpdate.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SSwipeUpdateEvent>(e);
g_pInputManager->onSwipeUpdate(E);
});
listener->pinchBegin = pointer->pointerEvents.pinchBegin.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SPinchBeginEvent>(e);
PROTO::pointerGestures->pinchBegin(E.timeMs, E.fingers);
});
listener->pinchEnd = pointer->pointerEvents.pinchEnd.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SPinchEndEvent>(e);
PROTO::pointerGestures->pinchEnd(E.timeMs, E.cancelled);
});
listener->pinchUpdate = pointer->pointerEvents.pinchUpdate.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SPinchUpdateEvent>(e);
PROTO::pointerGestures->pinchUpdate(E.timeMs, E.delta, E.scale, E.rotation);
});
listener->holdBegin = pointer->pointerEvents.holdBegin.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SHoldBeginEvent>(e);
PROTO::pointerGestures->holdBegin(E.timeMs, E.fingers);
});
listener->holdEnd = pointer->pointerEvents.holdEnd.registerListener([this] (std::any e) {
auto E = std::any_cast<IPointer::SHoldEndEvent>(e);
PROTO::pointerGestures->holdEnd(E.timeMs, E.cancelled);
});
// clang-format on
Debug::log(LOG, "Attached pointer {} to global", pointer->hlName);
}
void CPointerManager::attachTouch(SP<ITouch> touch) {
if (!touch)
return;
auto listener = touchListeners.emplace_back(makeShared<STouchListener>());
listener->touch = touch;
// clang-format off
listener->destroy = touch->events.destroy.registerListener([this] (std::any d) {
detachTouch(nullptr);
});
listener->down = touch->touchEvents.down.registerListener([this] (std::any e) {
auto E = std::any_cast<ITouch::SDownEvent>(e);
g_pInputManager->onTouchDown(E);
});
listener->up = touch->touchEvents.up.registerListener([this] (std::any e) {
auto E = std::any_cast<ITouch::SUpEvent>(e);
g_pInputManager->onTouchUp(E);
});
listener->motion = touch->touchEvents.motion.registerListener([this] (std::any e) {
auto E = std::any_cast<ITouch::SMotionEvent>(e);
g_pInputManager->onTouchMove(E);
});
listener->cancel = touch->touchEvents.cancel.registerListener([this] (std::any e) {
//
});
listener->frame = touch->touchEvents.frame.registerListener([this] (std::any e) {
wlr_seat_touch_notify_frame(g_pCompositor->m_sSeat.seat);
});
// clang-format on
Debug::log(LOG, "Attached touch {} to global", touch->hlName);
}
void CPointerManager::detachPointer(SP<IPointer> pointer) {
std::erase_if(pointerListeners, [pointer](const auto& e) { return e->pointer.expired() || e->pointer == pointer; });
}
void CPointerManager::detachTouch(SP<ITouch> touch) {
std::erase_if(touchListeners, [touch](const auto& e) { return e->touch.expired() || e->touch == touch; });
}
void CPointerManager::damageCursor(SP<CMonitor> pMonitor) {
for (auto& mw : monitorStates) {
if (mw->monitor != pMonitor)
continue;
auto b = getCursorBoxGlobal().intersection(pMonitor->logicalBox());
if (b.empty())
return;
g_pHyprRenderer->damageBox(&b);
return;
}
}

View file

@ -0,0 +1,158 @@
#pragma once
#include "../devices/IPointer.hpp"
#include "../devices/ITouch.hpp"
#include "../helpers/Box.hpp"
#include "../helpers/Region.hpp"
#include "../desktop/WLSurface.hpp"
#include <tuple>
class CMonitor;
struct wlr_input_device;
class IHID;
/*
The naming here is a bit confusing.
CPointerManager manages the _position_ and _displaying_ of the cursor,
but the CCursorManager _only_ manages the actual image (texture) and size
of the cursor.
*/
class CPointerManager {
public:
CPointerManager();
// pointers will move the cursor on their respective events
void attachPointer(SP<IPointer> pointer);
// touch inputs won't move the cursor, it needs to be done manually
void attachTouch(SP<ITouch> touch);
void detachPointer(SP<IPointer> pointer);
void detachTouch(SP<ITouch> touch);
// only clamps to the layout.
void warpTo(const Vector2D& logical);
void move(const Vector2D& deltaLogical);
void warpAbsolute(const Vector2D& abs, SP<IHID> dev);
void setCursorBuffer(wlr_buffer* buf, const Vector2D& hotspot, const float& scale);
void setCursorSurface(CWLSurface* buf, const Vector2D& hotspot);
void resetCursorImage(bool apply = true);
void lockSoftwareForMonitor(SP<CMonitor> pMonitor);
void unlockSoftwareForMonitor(SP<CMonitor> pMonitor);
void renderSoftwareCursorsFor(SP<CMonitor> pMonitor, timespec* now, CRegion& damage /* logical */, std::optional<Vector2D> overridePos = {} /* monitor-local */);
// this is needed e.g. during screensharing where
// the software cursors aren't locked during the cursor move, but they
// are rendered later.
void damageCursor(SP<CMonitor> pMonitor);
//
Vector2D position();
private:
void recheckPointerPosition();
void onMonitorLayoutChange();
void onMonitorDisconnect();
void updateCursorBackend();
void onCursorMoved();
bool hasCursor();
void damageIfSoftware();
void recheckEnteredOutputs();
// closest valid point to a given one
Vector2D closestValid(const Vector2D& pos);
// returns the thing in device coordinates. Is NOT offset by the hotspot, relies on set_cursor with hotspot.
Vector2D getCursorPosForMonitor(SP<CMonitor> pMonitor);
// returns the thing in logical coordinates of the monitor
CBox getCursorBoxLogicalForMonitor(SP<CMonitor> pMonitor);
// returns the thing in global coords
CBox getCursorBoxGlobal();
Vector2D transformedHotspot(SP<CMonitor> pMonitor);
wlr_texture* getCurrentCursorTexture();
struct SPointerListener {
CHyprSignalListener destroy;
CHyprSignalListener motion;
CHyprSignalListener motionAbsolute;
CHyprSignalListener button;
CHyprSignalListener axis;
CHyprSignalListener frame;
CHyprSignalListener swipeBegin;
CHyprSignalListener swipeEnd;
CHyprSignalListener swipeUpdate;
CHyprSignalListener pinchBegin;
CHyprSignalListener pinchEnd;
CHyprSignalListener pinchUpdate;
CHyprSignalListener holdBegin;
CHyprSignalListener holdEnd;
WP<IPointer> pointer;
};
std::vector<SP<SPointerListener>> pointerListeners;
struct STouchListener {
CHyprSignalListener destroy;
CHyprSignalListener down;
CHyprSignalListener up;
CHyprSignalListener motion;
CHyprSignalListener cancel;
CHyprSignalListener frame;
WP<ITouch> touch;
};
std::vector<SP<STouchListener>> touchListeners;
struct {
std::vector<CBox> monitorBoxes;
} currentMonitorLayout;
struct {
wlr_buffer* pBuffer = nullptr;
CWLSurface* surface = nullptr;
wlr_texture* pBufferTexture = nullptr;
Vector2D hotspot;
Vector2D size;
float scale = 1.F;
CHyprSignalListener destroySurface;
DYNLISTENER(commitSurface);
DYNLISTENER(destroyBuffer);
} 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) {}
WP<CMonitor> monitor;
int softwareLocks = 0;
bool hardwareFailed = false;
CBox box; // logical
bool entered = false;
bool hwApplied = false;
wlr_buffer* cursorFrontBuffer = nullptr;
};
std::vector<SP<SMonitorPointerState>> monitorStates;
SP<SMonitorPointerState> stateFor(SP<CMonitor> mon);
bool attemptHardwareCursor(SP<SMonitorPointerState> state);
wlr_buffer* renderHWCursorBuffer(SP<SMonitorPointerState> state, wlr_texture* texture);
bool setHWCursorBuffer(SP<SMonitorPointerState> state, wlr_buffer* buf);
struct {
SP<HOOK_CALLBACK_FN> monitorAdded;
} hooks;
};
inline UP<CPointerManager> g_pPointerManager;

View file

@ -20,6 +20,8 @@
#include "../../devices/VirtualKeyboard.hpp"
#include "../../devices/TouchDevice.hpp"
#include "../../managers/PointerManager.hpp"
CInputManager::CInputManager() {
m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) {
if (!cursorImageUnlocked())
@ -63,31 +65,31 @@ CInputManager::~CInputManager() {
m_lSwitches.clear();
}
void CInputManager::onMouseMoved(wlr_pointer_motion_event* e) {
void CInputManager::onMouseMoved(IPointer::SMotionEvent e) {
static auto PSENS = CConfigValue<Hyprlang::FLOAT>("general:sensitivity");
static auto PNOACCEL = CConfigValue<Hyprlang::INT>("input:force_no_accel");
static auto PSENSTORAW = CConfigValue<Hyprlang::INT>("general:apply_sens_to_raw");
const auto DELTA = *PNOACCEL == 1 ? Vector2D(e->unaccel_dx, e->unaccel_dy) : Vector2D(e->delta_x, e->delta_y);
const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta;
if (*PSENSTORAW == 1)
PROTO::relativePointer->sendRelativeMotion((uint64_t)e->time_msec * 1000, DELTA * *PSENS, Vector2D{e->unaccel_dx, e->unaccel_dy} * *PSENS);
PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA * *PSENS, e.unaccel * *PSENS);
else
PROTO::relativePointer->sendRelativeMotion((uint64_t)e->time_msec * 1000, DELTA, Vector2D{e->unaccel_dx, e->unaccel_dy});
PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel);
wlr_cursor_move(g_pCompositor->m_sWLRCursor, &e->pointer->base, DELTA.x * *PSENS, DELTA.y * *PSENS);
g_pPointerManager->move(DELTA * *PSENS);
mouseMoveUnified(e->time_msec);
mouseMoveUnified(e.timeMs);
m_tmrLastCursorMovement.reset();
m_bLastInputTouch = false;
}
void CInputManager::onMouseWarp(wlr_pointer_motion_absolute_event* e) {
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, &e->pointer->base, e->x, e->y);
void CInputManager::onMouseWarp(IPointer::SMotionAbsoluteEvent e) {
g_pPointerManager->warpAbsolute(e.absolute, e.device);
mouseMoveUnified(e->time_msec);
mouseMoveUnified(e.timeMs);
m_tmrLastCursorMovement.reset();
@ -194,14 +196,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (SURF && CONSTRAINT) {
if (CONSTRAINT->isLocked()) {
const auto HINT = CONSTRAINT->logicPositionHint();
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, HINT.x, HINT.y);
g_pCompositor->warpCursorTo(HINT, true);
} else {
const auto RG = CONSTRAINT->logicConstraintRegion();
const auto CLOSEST = RG.closestPoint(mouseCoords);
const auto BOX = SURF->getSurfaceBoxGlobal();
const auto CLOSESTLOCAL = (CLOSEST - (BOX.has_value() ? BOX->pos() : Vector2D{})) * (SURF->getWindow() ? SURF->getWindow()->m_fX11SurfaceScaledBy : 1.0);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, CLOSEST.x, CLOSEST.y);
g_pCompositor->warpCursorTo(CLOSEST, true);
wlr_seat_pointer_send_motion(g_pCompositor->m_sSeat.seat, time, CLOSESTLOCAL.x, CLOSESTLOCAL.y);
PROTO::relativePointer->sendRelativeMotion((uint64_t)time * 1000, {}, {});
}
@ -241,7 +243,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
g_pLayoutManager->getCurrentLayout()->onMouseMove(getMouseCoordsInternal());
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired())
if (PMONITOR && PMONITOR != g_pCompositor->m_pLastMonitor.get() && (*PMOUSEFOCUSMON || refocus) && m_pForcedFocus.expired())
g_pCompositor->setActiveMonitor(PMONITOR);
if (g_pSessionLockManager->isSessionLocked()) {
@ -350,7 +352,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
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)
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor);
g_pCompositor->scheduleFrameForMonitor(g_pCompositor->m_pLastMonitor.get());
if (!foundSurface) {
if (!m_bEmptyFocusCursorSet) {
@ -491,19 +493,19 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, time, surfaceLocal.x, surfaceLocal.y);
}
void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
void CInputManager::onMouseButton(IPointer::SButtonEvent e) {
EMIT_HOOK_EVENT_CANCELLABLE("mouseButton", e);
PROTO::idle->onActivity();
m_tmrLastCursorMovement.reset();
if (e->state == WL_POINTER_BUTTON_STATE_PRESSED) {
m_lCurrentlyHeldButtons.push_back(e->button);
if (e.state == WL_POINTER_BUTTON_STATE_PRESSED) {
m_lCurrentlyHeldButtons.push_back(e.button);
} else {
if (std::find_if(m_lCurrentlyHeldButtons.begin(), m_lCurrentlyHeldButtons.end(), [&](const auto& other) { return other == e->button; }) == m_lCurrentlyHeldButtons.end())
if (std::find_if(m_lCurrentlyHeldButtons.begin(), m_lCurrentlyHeldButtons.end(), [&](const auto& other) { return other == e.button; }) == m_lCurrentlyHeldButtons.end())
return;
std::erase_if(m_lCurrentlyHeldButtons, [&](const auto& other) { return other == e->button; });
std::erase_if(m_lCurrentlyHeldButtons, [&](const auto& other) { return other == e.button; });
}
switch (m_ecbClickBehavior) {
@ -512,7 +514,7 @@ void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
default: break;
}
if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e->state == WL_POINTER_BUTTON_STATE_RELEASED) {
if (m_bFocusHeldByButtons && m_lCurrentlyHeldButtons.empty() && e.state == WL_POINTER_BUTTON_STATE_RELEASED) {
if (m_bRefocusHeldByButtons)
refocus();
else
@ -549,7 +551,7 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
m_sCursorSurfaceInfo.name = "";
m_sCursorSurfaceInfo.inUse = true;
g_pHyprRenderer->setCursorSurface(e->surface, e->hotspot_x, e->hotspot_y);
g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, e->hotspot_x, e->hotspot_y);
}
}
@ -564,7 +566,7 @@ void CInputManager::restoreCursorIconToApp() {
if (m_sCursorSurfaceInfo.name.empty()) {
if (m_sCursorSurfaceInfo.wlSurface.exists())
g_pHyprRenderer->setCursorSurface(m_sCursorSurfaceInfo.wlSurface.wlr(), m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y);
g_pHyprRenderer->setCursorSurface(&m_sCursorSurfaceInfo.wlSurface, m_sCursorSurfaceInfo.vHotspot.x, m_sCursorSurfaceInfo.vHotspot.y);
} else {
g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name);
}
@ -617,7 +619,7 @@ void CInputManager::setClickMode(eClickBehaviorMode mode) {
}
}
void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
void CInputManager::processMouseDownNormal(const IPointer::SButtonEvent& e) {
// notify the keybind manager
static auto PPASSMOUSE = CConfigValue<Hyprlang::INT>("binds:pass_mouse_when_bound");
@ -639,7 +641,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
// clicking on border triggers resize
// TODO detect click on LS properly
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e->state == WL_POINTER_BUTTON_STATE_PRESSED) {
if (*PRESIZEONBORDER && !m_bLastFocusOnLS && e.state == WL_POINTER_BUTTON_STATE_PRESSED) {
if (w && !w->m_bIsFullscreen) {
const CBox real = {w->m_vRealPosition.value().x, w->m_vRealPosition.value().y, w->m_vRealSize.value().x, w->m_vRealSize.value().y};
const CBox grab = {real.x - BORDER_GRAB_AREA, real.y - BORDER_GRAB_AREA, real.width + 2 * BORDER_GRAB_AREA, real.height + 2 * BORDER_GRAB_AREA};
@ -651,7 +653,7 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
}
}
switch (e->state) {
switch (e.state) {
case WL_POINTER_BUTTON_STATE_PRESSED:
if (*PFOLLOWMOUSE == 3) // don't refocus on full loose
break;
@ -679,14 +681,14 @@ void CInputManager::processMouseDownNormal(wlr_pointer_button_event* e) {
// notify app if we didnt handle it
if (g_pCompositor->doesSeatAcceptInput(g_pCompositor->m_pLastFocus))
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e->time_msec, e->button, e->state);
wlr_seat_pointer_notify_button(g_pCompositor->m_sSeat.seat, e.timeMs, e.button, e.state);
if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor && PMON)
if (const auto PMON = g_pCompositor->getMonitorFromVector(mouseCoords); PMON != g_pCompositor->m_pLastMonitor.get() && PMON)
g_pCompositor->setActiveMonitor(PMON);
}
void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
switch (e->state) {
void CInputManager::processMouseDownKill(const IPointer::SButtonEvent& e) {
switch (e.state) {
case WL_POINTER_BUTTON_STATE_PRESSED: {
const auto PWINDOW = g_pCompositor->vectorToWindowUnified(getMouseCoordsInternal(), RESERVED_EXTENTS | INPUT_EXTENTS | ALLOW_FLOATING);
@ -707,12 +709,12 @@ void CInputManager::processMouseDownKill(wlr_pointer_button_event* e) {
m_ecbClickBehavior = CLICKMODE_DEFAULT;
}
void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
void CInputManager::onMouseWheel(IPointer::SAxisEvent e) {
static auto POFFWINDOWAXIS = CConfigValue<Hyprlang::INT>("input:off_window_axis_events");
static auto PINPUTSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:scroll_factor");
static auto PTOUCHPADSCROLLFACTOR = CConfigValue<Hyprlang::FLOAT>("input:touchpad:scroll_factor");
auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e->source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR);
auto factor = (*PTOUCHPADSCROLLFACTOR <= 0.f || e.source == WL_POINTER_AXIS_SOURCE_FINGER ? *PTOUCHPADSCROLLFACTOR : *PINPUTSCROLLFACTOR);
const auto EMAP = std::unordered_map<std::string, std::any>{{"event", e}};
EMIT_HOOK_EVENT_CANCELLABLE("mouseAxis", EMAP);
@ -742,20 +744,20 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
const auto TEMPCURY = std::clamp(MOUSECOORDS.y, BOX.y, BOX.y + BOX.h - 1);
if (*POFFWINDOWAXIS == 3)
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, TEMPCURX, TEMPCURY);
g_pCompositor->warpCursorTo({TEMPCURX, TEMPCURY}, true);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, TEMPCURX - BOX.x, TEMPCURY - BOX.y);
wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, TEMPCURX - BOX.x, TEMPCURY - BOX.y);
wlr_seat_pointer_notify_frame(g_pCompositor->m_sSeat.seat);
}
}
}
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e->time_msec, e->orientation, factor * e->delta, std::round(factor * e->delta_discrete), e->source,
wlr_seat_pointer_notify_axis(g_pCompositor->m_sSeat.seat, e.timeMs, e.axis, factor * e.delta, std::round(factor * e.deltaDiscrete), e.source,
WL_POINTER_AXIS_RELATIVE_DIRECTION_IDENTICAL);
}
Vector2D CInputManager::getMouseCoordsInternal() {
return Vector2D(g_pCompositor->m_sWLRCursor->x, g_pCompositor->m_sWLRCursor->y);
return g_pPointerManager->position();
}
void CInputManager::newKeyboard(wlr_input_device* keyboard) {
@ -989,7 +991,7 @@ void CInputManager::setupMouse(SP<IPointer> mauz) {
(int)libinput_device_config_accel_get_default_profile(LIBINPUTDEV));
}
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, &mauz->wlr()->base);
g_pPointerManager->attachPointer(mauz);
mauz->connected = true;
@ -1020,10 +1022,10 @@ void CInputManager::setPointerConfigs() {
if (HASCONFIG) {
const auto ENABLED = g_pConfigManager->getDeviceInt(devname, "enabled");
if (ENABLED && !m->connected) {
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, &m->wlr()->base);
g_pPointerManager->attachPointer(m);
m->connected = true;
} else if (!ENABLED && m->connected) {
wlr_cursor_detach_input_device(g_pCompositor->m_sWLRCursor, &m->wlr()->base);
g_pPointerManager->detachPointer(m);
m->connected = false;
}
}
@ -1386,7 +1388,7 @@ void CInputManager::newTouchDevice(wlr_input_device* pDevice) {
}
setTouchDeviceConfigs(PNEWDEV);
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice);
g_pPointerManager->attachTouch(PNEWDEV);
PNEWDEV->events.destroy.registerStaticListener(
[this](void* owner, std::any data) {
@ -1431,7 +1433,7 @@ void CInputManager::setTouchDeviceConfigs(SP<ITouch> dev) {
const auto PMONITOR = bound ? g_pCompositor->getMonitorFromName(output) : nullptr;
if (PMONITOR) {
Debug::log(LOG, "Binding touch device {} to output {}", PTOUCHDEV->hlName, PMONITOR->szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, PMONITOR->output);
// wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, &PTOUCHDEV->wlr()->base, PMONITOR->output);
} else if (bound)
Debug::log(ERR, "Failed to bind touch device {} to output '{}': monitor not found", PTOUCHDEV->hlName, output);
}
@ -1468,17 +1470,17 @@ void CInputManager::setTabletConfigs() {
const auto PMONITOR = g_pCompositor->getMonitorFromString(OUTPUT);
if (!OUTPUT.empty() && OUTPUT != STRVAL_EMPTY && PMONITOR) {
Debug::log(LOG, "Binding tablet {} to output {}", t.name, PMONITOR->szName);
wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output);
wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr);
// wlr_cursor_map_input_to_output(g_pCompositor->m_sWLRCursor, t.wlrDevice, PMONITOR->output);
// wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, nullptr);
t.boundOutput = OUTPUT;
} else if (!PMONITOR)
Debug::log(ERR, "Failed to bind tablet {} to output '{}': monitor not found", t.name, OUTPUT);
const auto REGION_POS = g_pConfigManager->getDeviceVec(t.name, "region_position", "input:tablet:region_position");
const auto REGION_SIZE = g_pConfigManager->getDeviceVec(t.name, "region_size", "input:tablet:region_size");
auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y};
if (!regionBox.empty())
wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr());
//auto regionBox = CBox{REGION_POS.x, REGION_POS.y, REGION_SIZE.x, REGION_SIZE.y};
// if (!regionBox.empty())
// wlr_cursor_map_input_to_region(g_pCompositor->m_sWLRCursor, t.wlrDevice, regionBox.pWlr());
const auto ACTIVE_AREA_SIZE = g_pConfigManager->getDeviceVec(t.name, "active_area_size", "input:tablet:active_area_size");
const auto ACTIVE_AREA_POS = g_pConfigManager->getDeviceVec(t.name, "active_area_position", "input:tablet:active_area_position");

View file

@ -7,15 +7,15 @@
#include "../../helpers/Timer.hpp"
#include "InputMethodRelay.hpp"
#include "../../helpers/signal/Listener.hpp"
#include "../../devices/IPointer.hpp"
#include "../../devices/ITouch.hpp"
class CPointerConstraint;
class CWindow;
class CIdleInhibitor;
class CVirtualKeyboardV1Resource;
class CVirtualPointerV1Resource;
class IPointer;
class IKeyboard;
class ITouch;
enum eClickBehaviorMode {
CLICKMODE_DEFAULT = 0,
@ -74,10 +74,10 @@ class CInputManager {
CInputManager();
~CInputManager();
void onMouseMoved(wlr_pointer_motion_event*);
void onMouseWarp(wlr_pointer_motion_absolute_event*);
void onMouseButton(wlr_pointer_button_event*);
void onMouseWheel(wlr_pointer_axis_event*);
void onMouseMoved(IPointer::SMotionEvent);
void onMouseWarp(IPointer::SMotionAbsoluteEvent);
void onMouseButton(IPointer::SButtonEvent);
void onMouseWheel(IPointer::SAxisEvent);
void onKeyboardKey(std::any, SP<IKeyboard>);
void onKeyboardMod(SP<IKeyboard>);
@ -112,9 +112,9 @@ class CInputManager {
eClickBehaviorMode getClickMode();
void processMouseRequest(wlr_seat_pointer_request_set_cursor_event* e);
void onTouchDown(wlr_touch_down_event*);
void onTouchUp(wlr_touch_up_event*);
void onTouchMove(wlr_touch_motion_event*);
void onTouchDown(ITouch::SDownEvent);
void onTouchUp(ITouch::SUpEvent);
void onTouchMove(ITouch::SMotionEvent);
STouchData m_sTouchData;
@ -153,9 +153,9 @@ class CInputManager {
void newIdleInhibitor(std::any);
void recheckIdleInhibitorStatus();
void onSwipeBegin(wlr_pointer_swipe_begin_event*);
void onSwipeEnd(wlr_pointer_swipe_end_event*);
void onSwipeUpdate(wlr_pointer_swipe_update_event*);
void onSwipeBegin(IPointer::SSwipeBeginEvent);
void onSwipeEnd(IPointer::SSwipeEndEvent);
void onSwipeUpdate(IPointer::SSwipeUpdateEvent);
SSwipeGesture m_sActiveSwipe;
@ -212,8 +212,8 @@ class CInputManager {
void setupKeyboard(SP<IKeyboard> keeb);
void setupMouse(SP<IPointer> mauz);
void processMouseDownNormal(wlr_pointer_button_event* e);
void processMouseDownKill(wlr_pointer_button_event* e);
void processMouseDownNormal(const IPointer::SButtonEvent& e);
void processMouseDownKill(const IPointer::SButtonEvent& e);
bool cursorImageUnlocked();

View file

@ -2,14 +2,14 @@
#include "../../Compositor.hpp"
#include "../../config/ConfigValue.hpp"
void CInputManager::onSwipeBegin(wlr_pointer_swipe_begin_event* e) {
void CInputManager::onSwipeBegin(IPointer::SSwipeBeginEvent e) {
static auto PSWIPE = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe");
static auto PSWIPEFINGERS = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_fingers");
static auto PSWIPENEW = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_create_new");
EMIT_HOOK_EVENT_CANCELLABLE("swipeBegin", e);
if (e->fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked())
if (e.fingers != *PSWIPEFINGERS || *PSWIPE == 0 || g_pSessionLockManager->isSessionLocked())
return;
int onMonitor = 0;
@ -32,7 +32,7 @@ void CInputManager::beginWorkspaceSwipe() {
m_sActiveSwipe.pWorkspaceBegin = PWORKSPACE;
m_sActiveSwipe.delta = 0;
m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor;
m_sActiveSwipe.pMonitor = g_pCompositor->m_pLastMonitor.get();
m_sActiveSwipe.avgSpeed = 0;
m_sActiveSwipe.speedPoints = 0;
@ -43,7 +43,7 @@ void CInputManager::beginWorkspaceSwipe() {
}
}
void CInputManager::onSwipeEnd(wlr_pointer_swipe_end_event* e) {
void CInputManager::onSwipeEnd(IPointer::SSwipeEndEvent e) {
EMIT_HOOK_EVENT_CANCELLABLE("swipeEnd", e);
if (!m_sActiveSwipe.pWorkspaceBegin)
@ -198,7 +198,7 @@ void CInputManager::endWorkspaceSwipe() {
}
}
void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
void CInputManager::onSwipeUpdate(IPointer::SSwipeUpdateEvent e) {
EMIT_HOOK_EVENT_CANCELLABLE("swipeUpdate", e);
if (!m_sActiveSwipe.pWorkspaceBegin)
@ -207,7 +207,7 @@ void CInputManager::onSwipeUpdate(wlr_pointer_swipe_update_event* e) {
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e->dy : e->dy) : (*PSWIPEINVR ? -e->dx : e->dx));
const double delta = m_sActiveSwipe.delta + (VERTANIMS ? (*PSWIPEINVR ? -e.delta.y : e.delta.y) : (*PSWIPEINVR ? -e.delta.x : e.delta.x));
updateWorkspaceSwipe(delta);
}
@ -348,7 +348,7 @@ void CInputManager::updateWorkspaceSwipe(double delta) {
if (*PSWIPEFOREVER) {
if (abs(m_sActiveSwipe.delta) >= SWIPEDISTANCE) {
onSwipeEnd(nullptr);
onSwipeEnd({});
beginWorkspaceSwipe();
}
}

View file

@ -18,7 +18,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
Debug::log(LOG, "Attaching tablet to cursor!");
wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice);
// wlr_cursor_attach_input_device(g_pCompositor->m_sWLRCursor, pDevice);
PNEWTABLET->hyprListener_Destroy.initCallback(
&pDevice->events.destroy,
@ -39,7 +39,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
switch (EVENT->tool->type) {
case WLR_TABLET_TOOL_TYPE_MOUSE:
wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy);
// wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, EVENT->dx, EVENT->dy);
g_pInputManager->simulateMouseMovement();
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);
g_pInputManager->m_tmrLastCursorMovement.reset();
@ -50,16 +50,16 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
double y = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->y : NAN;
double dy = (EVENT->updated_axes & WLR_TABLET_TOOL_AXIS_Y) ? EVENT->dy : NAN;
if (PTAB->relativeInput)
wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy);
else {
// Calculate transformations if active area is set
if (!PTAB->activeArea.empty()) {
x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x);
y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y);
}
wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
}
// if (PTAB->relativeInput)
// wlr_cursor_move(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, dx, dy);
// else {
// Calculate transformations if active area is set
// if (!PTAB->activeArea.empty()) {
// x = (x - PTAB->activeArea.x) / (PTAB->activeArea.w - PTAB->activeArea.x);
// y = (y - PTAB->activeArea.y) / (PTAB->activeArea.h - PTAB->activeArea.y);
// }
// wlr_cursor_warp_absolute(g_pCompositor->m_sWLRCursor, PTAB->wlrDevice, x, y);
// }
g_pInputManager->simulateMouseMovement();
g_pInputManager->focusTablet(PTAB, EVENT->tool, true);

View file

@ -4,7 +4,7 @@
#include "../../protocols/IdleNotify.hpp"
#include "../../devices/ITouch.hpp"
void CInputManager::onTouchDown(wlr_touch_down_event* e) {
void CInputManager::onTouchDown(ITouch::SDownEvent e) {
static auto PSWIPETOUCH = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_touch");
static auto PGAPSOUTDATA = CConfigValue<Hyprlang::CUSTOMTYPE>("general:gaps_out");
auto* const PGAPSOUT = (CCssGapData*)(PGAPSOUTDATA.ptr())->getData();
@ -14,23 +14,18 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
static auto PSWIPEINVR = CConfigValue<Hyprlang::INT>("gestures:workspace_swipe_invert");
EMIT_HOOK_EVENT_CANCELLABLE("touchDown", e);
auto PMONITOR = g_pCompositor->getMonitorFromName(e->touch->output_name ? e->touch->output_name : "");
auto PMONITOR = g_pCompositor->getMonitorFromName(!e.device->boundOutput.empty() ? e.device->boundOutput : "");
const auto PDEVIT = std::find_if(m_vTouches.begin(), m_vTouches.end(), [&](const auto& other) { return other->wlr() == e->touch; });
PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor.get();
if (PDEVIT != m_vTouches.end() && !(*PDEVIT)->boundOutput.empty())
PMONITOR = g_pCompositor->getMonitorFromName((*PDEVIT)->boundOutput);
PMONITOR = PMONITOR ? PMONITOR : g_pCompositor->m_pLastMonitor;
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true);
refocus();
if (m_ecbClickBehavior == CLICKMODE_KILL) {
wlr_pointer_button_event e;
IPointer::SButtonEvent e;
e.state = WL_POINTER_BUTTON_STATE_PRESSED;
g_pInputManager->processMouseDownKill(&e);
g_pInputManager->processMouseDownKill(e);
return;
}
@ -45,10 +40,10 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
// TODO: support no_gaps_when_only?
const double TARGETLEFT = ((VERTANIMS ? gapsOut.top : gapsOut.left) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x);
const double TARGETRIGHT = 1 - (((VERTANIMS ? gapsOut.bottom : gapsOut.right) + *PBORDERSIZE) / (VERTANIMS ? PMONITOR->vecSize.y : PMONITOR->vecSize.x));
const double POSITION = (VERTANIMS ? e->y : e->x);
const double POSITION = (VERTANIMS ? e.pos.y : e.pos.x);
if (POSITION < TARGETLEFT || POSITION > TARGETRIGHT) {
beginWorkspaceSwipe();
m_sActiveSwipe.touch_id = e->touch_id;
m_sActiveSwipe.touch_id = e.touchID;
// Set the initial direction based on which edge you started from
if (POSITION > 0.5)
m_sActiveSwipe.initialDirection = *PSWIPEINVR ? -1 : 1;
@ -78,34 +73,33 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchFocusLS->geometry.pos();
m_sTouchData.touchSurfaceOrigin = g_pInputManager->getMouseCoordsInternal() - local;
} else {
} else
return; // oops, nothing found.
}
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e->time_msec, e->touch_id, local.x, local.y);
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e.timeMs, e.touchID, local.x, local.y);
PROTO::idle->onActivity();
}
void CInputManager::onTouchUp(wlr_touch_up_event* e) {
void CInputManager::onTouchUp(ITouch::SUpEvent e) {
EMIT_HOOK_EVENT_CANCELLABLE("touchUp", e);
if (m_sActiveSwipe.pWorkspaceBegin) {
// If there was a swipe from this finger, end it.
if (e->touch_id == m_sActiveSwipe.touch_id)
if (e.touchID == m_sActiveSwipe.touch_id)
endWorkspaceSwipe();
return;
}
if (m_sTouchData.touchFocusSurface) {
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id);
wlr_seat_touch_notify_up(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID);
}
}
void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
void CInputManager::onTouchMove(ITouch::SMotionEvent e) {
EMIT_HOOK_EVENT_CANCELLABLE("touchMove", e);
if (m_sActiveSwipe.pWorkspaceBegin) {
// Do nothing if this is using a different finger.
if (e->touch_id != m_sActiveSwipe.touch_id)
if (e.touchID != m_sActiveSwipe.touch_id)
return;
const bool VERTANIMS = m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle == "slidevert" ||
m_sActiveSwipe.pWorkspaceBegin->m_vRenderOffset.getConfig()->pValues->internalStyle.starts_with("slidefadevert");
@ -116,37 +110,37 @@ void CInputManager::onTouchMove(wlr_touch_motion_event* e) {
if (m_sActiveSwipe.initialDirection == -1) {
if (*PSWIPEINVR)
// go from 0 to -SWIPEDISTANCE
updateWorkspaceSwipe(SWIPEDISTANCE * ((VERTANIMS ? e->y : e->x) - 1));
updateWorkspaceSwipe(SWIPEDISTANCE * ((VERTANIMS ? e.pos.y : e.pos.x) - 1));
else
// go from 0 to -SWIPEDISTANCE
updateWorkspaceSwipe(SWIPEDISTANCE * (-1 * (VERTANIMS ? e->y : e->x)));
updateWorkspaceSwipe(SWIPEDISTANCE * (-1 * (VERTANIMS ? e.pos.y : e.pos.x)));
} else if (*PSWIPEINVR)
// go from 0 to SWIPEDISTANCE
updateWorkspaceSwipe(SWIPEDISTANCE * (VERTANIMS ? e->y : e->x));
updateWorkspaceSwipe(SWIPEDISTANCE * (VERTANIMS ? e.pos.y : e.pos.x));
else
// go from 0 to SWIPEDISTANCE
updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e->y : e->x)));
updateWorkspaceSwipe(SWIPEDISTANCE * (1 - (VERTANIMS ? e.pos.y : e.pos.x)));
return;
}
if (validMapped(m_sTouchData.touchFocusWindow)) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusWindow->m_iMonitorID);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true);
auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
if (m_sTouchData.touchFocusWindow->m_bIsX11)
local = local * m_sTouchData.touchFocusWindow->m_fX11SurfaceScaledBy;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y);
// wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
} else if (!m_sTouchData.touchFocusLS.expired()) {
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_sTouchData.touchFocusLS->monitorID);
wlr_cursor_warp(g_pCompositor->m_sWLRCursor, nullptr, PMONITOR->vecPosition.x + e->x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e->y * PMONITOR->vecSize.y);
g_pCompositor->warpCursorTo({PMONITOR->vecPosition.x + e.pos.x * PMONITOR->vecSize.x, PMONITOR->vecPosition.y + e.pos.y * PMONITOR->vecSize.y}, true);
const auto local = g_pInputManager->getMouseCoordsInternal() - m_sTouchData.touchSurfaceOrigin;
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, e->touch_id, local.x, local.y);
wlr_seat_touch_notify_motion(g_pCompositor->m_sSeat.seat, e.timeMs, e.touchID, local.x, local.y);
// wlr_seat_pointer_notify_motion(g_pCompositor->m_sSeat.seat, e->time_msec, local.x, local.y);
}
}

View file

@ -1,5 +1,6 @@
#include "Screencopy.hpp"
#include "../Compositor.hpp"
#include "../managers/PointerManager.hpp"
#include <algorithm>
@ -183,6 +184,11 @@ void CScreencopyProtocolManager::removeFrame(SScreencopyFrame* frame, bool force
if (!frame)
return;
if (frame->lockedSWCursors) {
g_pPointerManager->unlockSoftwareForMonitor(frame->pMonitor->self.lock());
g_pPointerManager->damageCursor(frame->pMonitor->self.lock());
}
std::erase_if(m_vFramesAwaitingWrite, [&](const auto& other) { return other == frame; });
wl_resource_set_user_data(frame->resource, nullptr);
@ -352,8 +358,11 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou
m_vFramesAwaitingWrite.emplace_back(PFRAME);
g_pHyprRenderer->m_bDirectScanoutBlocked = true;
if (PFRAME->overlayCursor)
g_pHyprRenderer->m_bSoftwareCursorsLocked = true;
if (PFRAME->overlayCursor && !PFRAME->lockedSWCursors) {
PFRAME->lockedSWCursors = true;
g_pPointerManager->lockSoftwareForMonitor(PFRAME->pMonitor->self.lock());
g_pPointerManager->damageCursor(PFRAME->pMonitor->self.lock());
}
if (!PFRAME->withDamage)
g_pHyprRenderer->damageMonitor(PFRAME->pMonitor);
@ -393,17 +402,8 @@ void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) {
removeFrame(f);
}
g_pHyprRenderer->m_bSoftwareCursorsLocked = false;
if (m_vFramesAwaitingWrite.empty()) {
g_pHyprRenderer->m_bDirectScanoutBlocked = false;
} else {
for (auto& f : m_vFramesAwaitingWrite) {
if (f->overlayCursor) {
g_pHyprRenderer->m_bSoftwareCursorsLocked = true;
break;
}
}
}
}

View file

@ -48,8 +48,9 @@ struct SScreencopyFrame {
CBox box = {};
int shmStride = 0;
bool overlayCursor = false;
bool withDamage = false;
bool overlayCursor = false;
bool withDamage = false;
bool lockedSWCursors = false;
wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM;

View file

@ -1,6 +1,7 @@
#include "ToplevelExport.hpp"
#include "../Compositor.hpp"
#include "ForeignToplevelWlr.hpp"
#include "../managers/PointerManager.hpp"
#include <algorithm>
@ -313,7 +314,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp
CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y};
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr()))
if (geometry.intersection({pMonitor->vecPosition, pMonitor->vecSize}).empty())
continue;
shareFrame(f);
@ -382,8 +383,10 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
return false;
}
if (frame->overlayCursor)
wlr_output_lock_software_cursors(PMONITOR->output, true);
if (frame->overlayCursor) {
g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock());
g_pPointerManager->damageCursor(PMONITOR->self.lock());
}
g_pHyprOpenGL->clear(CColor(0, 0, 0, 1.0));
@ -393,7 +396,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
if (frame->overlayCursor)
g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value());
g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value());
const auto PFORMAT = g_pHyprOpenGL->getPixelFormatFromDRM(format);
if (!PFORMAT) {
@ -419,8 +422,10 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times
wlr_buffer_end_data_ptr_access(frame->buffer);
if (frame->overlayCursor)
wlr_output_lock_software_cursors(PMONITOR->output, false);
if (frame->overlayCursor) {
g_pPointerManager->unlockSoftwareForMonitor(PMONITOR->self.lock());
g_pPointerManager->damageCursor(PMONITOR->self.lock());
}
return true;
}
@ -440,7 +445,7 @@ bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame, ti
g_pHyprRenderer->m_bBlockSurfaceFeedback = false;
if (frame->overlayCursor)
g_pHyprRenderer->renderSoftwareCursors(PMONITOR, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value());
g_pPointerManager->renderSoftwareCursorsFor(PMONITOR->self.lock(), now, fakeDamage, g_pInputManager->getMouseCoordsInternal() - frame->pWindow->m_vRealPosition.value());
g_pHyprOpenGL->m_RenderData.blockScreenShader = true;
g_pHyprRenderer->endRender();

View file

@ -246,13 +246,10 @@ bool CHyprOpenGLImpl::passRequiresIntrospection(CMonitor* pMonitor) {
return false;
}
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional<CRegion> finalDamage) {
void CHyprOpenGLImpl::beginSimple(CMonitor* pMonitor, const CRegion& damage, CRenderbuffer* rb, CFramebuffer* fb) {
m_RenderData.pMonitor = pMonitor;
static auto PFORCEINTROSPECTION = CConfigValue<Hyprlang::INT>("opengl:force_introspection");
#ifndef GLES2
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
if (RESETSTATUS != GL_NO_ERROR) {
std::string errStr = "";
@ -265,7 +262,62 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr);
return;
}
#endif
TRACY_GPU_ZONE("RenderBeginSimple");
const auto FBO = rb ? rb->getFB() : fb;
glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y);
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
wlr_matrix_identity(m_RenderData.monitorProjection.data());
if (pMonitor->transform != WL_OUTPUT_TRANSFORM_NORMAL) {
const Vector2D tfmd = pMonitor->transform % 2 == 1 ? Vector2D{FBO->m_vSize.y, FBO->m_vSize.x} : FBO->m_vSize;
wlr_matrix_translate(m_RenderData.monitorProjection.data(), FBO->m_vSize.x / 2.0, FBO->m_vSize.y / 2.0);
wlr_matrix_transform(m_RenderData.monitorProjection.data(), pMonitor->transform);
wlr_matrix_translate(m_RenderData.monitorProjection.data(), -tfmd.x / 2.0, -tfmd.y / 2.0);
}
m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor];
if (!m_RenderData.pCurrentMonData->m_bShadersInitialized)
initShaders();
m_RenderData.damage.set(damage);
m_RenderData.finalDamage.set(damage);
m_bFakeFrame = true;
m_RenderData.currentFB = FBO;
FBO->bind();
m_bOffloadedFramebuffer = false;
m_RenderData.mainFB = m_RenderData.currentFB;
m_RenderData.outFB = FBO;
m_RenderData.simplePass = true;
}
void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebuffer* fb, std::optional<CRegion> finalDamage) {
m_RenderData.pMonitor = pMonitor;
static auto PFORCEINTROSPECTION = CConfigValue<Hyprlang::INT>("opengl:force_introspection");
#ifndef GLES2
const GLenum RESETSTATUS = glGetGraphicsResetStatus();
if (RESETSTATUS != GL_NO_ERROR) {
std::string errStr = "";
switch (RESETSTATUS) {
case GL_GUILTY_CONTEXT_RESET: errStr = "GL_GUILTY_CONTEXT_RESET"; break;
case GL_INNOCENT_CONTEXT_RESET: errStr = "GL_INNOCENT_CONTEXT_RESET"; break;
case GL_UNKNOWN_CONTEXT_RESET: errStr = "GL_UNKNOWN_CONTEXT_RESET"; break;
default: errStr = "UNKNOWN??"; break;
}
RASSERT(false, "Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented.", errStr);
return;
}
#endif
TRACY_GPU_ZONE("RenderBegin");
@ -274,6 +326,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, const CRegion& damage_, CFramebu
matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL);
m_RenderData.monitorProjection = pMonitor->projMatrix;
if (m_mMonitorRenderResources.contains(pMonitor) && m_mMonitorRenderResources.at(pMonitor).offloadFB.m_vSize != pMonitor->vecPixelSize)
destroyMonitorResources(pMonitor);
@ -753,7 +807,7 @@ void CHyprOpenGLImpl::renderRectWithDamage(CBox* box, const CColor& col, CRegion
float matrix[9];
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot,
m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@ -814,6 +868,12 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, CBox* pBox, float alpha, i
renderTexture(CTexture(tex), pBox, alpha, round, false, allowCustomUV);
}
void CHyprOpenGLImpl::renderTextureWithDamage(wlr_texture* tex, CBox* pBox, CRegion* damage, float alpha, int round, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTextureWithDamage(CTexture(tex), pBox, damage, alpha, round, false, allowCustomUV);
}
void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha, int round, bool discardActive, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
@ -822,6 +882,14 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, CBox* pBox, float alpha
scissor((CBox*)nullptr);
}
void CHyprOpenGLImpl::renderTextureWithDamage(const CTexture& tex, CBox* pBox, CRegion* damage, float alpha, int round, bool discardActive, bool allowCustomUV) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
renderTextureInternalWithDamage(tex, pBox, alpha, damage, round, discardActive, false, allowCustomUV, true);
scissor((CBox*)nullptr);
}
void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox* pBox, float alpha, CRegion* damage, int round, bool discardActive, bool noAA, bool allowCustomUV,
bool allowDim) {
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
@ -843,7 +911,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, CBox*
// get transform
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
float matrix[9];
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data());
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@ -1006,7 +1074,7 @@ void CHyprOpenGLImpl::renderTexturePrimitive(const CTexture& tex, CBox* pBox) {
// get transform
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
float matrix[9];
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data());
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@ -1060,7 +1128,7 @@ void CHyprOpenGLImpl::renderTextureMatte(const CTexture& tex, CBox* pBox, CFrame
// get transform
const auto TRANSFORM = wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform);
float matrix[9];
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.pMonitor->projMatrix.data());
wlr_matrix_project_box(matrix, newBox.pWlr(), TRANSFORM, newBox.rot, m_RenderData.monitorProjection.data());
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@ -1119,7 +1187,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, CRegion* o
const auto TRANSFORM = wlr_output_transform_invert(m_RenderData.pMonitor->transform);
float matrix[9];
CBox MONITORBOX = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y};
wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.pMonitor->projMatrix.data());
wlr_matrix_project_box(matrix, MONITORBOX.pWlr(), TRANSFORM, 0, m_RenderData.monitorProjection.data());
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@ -1615,7 +1683,7 @@ void CHyprOpenGLImpl::renderBorder(CBox* box, const CGradientValueData& grad, in
float matrix[9];
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot,
m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);
@ -1921,7 +1989,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(CBox* box, int round, int range, const
float matrix[9];
wlr_matrix_project_box(matrix, box->pWlr(), wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), newBox.rot,
m_RenderData.pMonitor->projMatrix.data()); // TODO: write own, don't use WLR here
m_RenderData.monitorProjection.data()); // TODO: write own, don't use WLR here
float glMatrix[9];
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix);

View file

@ -95,33 +95,35 @@ struct SMonitorRenderData {
};
struct SCurrentRenderData {
CMonitor* pMonitor = nullptr;
PHLWORKSPACE pWorkspace = nullptr;
float projection[9];
float savedProjection[9];
CMonitor* pMonitor = nullptr;
PHLWORKSPACE pWorkspace = nullptr;
float projection[9];
float savedProjection[9];
std::array<float, 9> monitorProjection;
SMonitorRenderData* pCurrentMonData = nullptr;
CFramebuffer* currentFB = nullptr; // current rendering to
CFramebuffer* mainFB = nullptr; // main to render to
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
SMonitorRenderData* pCurrentMonData = nullptr;
CFramebuffer* currentFB = nullptr; // current rendering to
CFramebuffer* mainFB = nullptr; // main to render to
CFramebuffer* outFB = nullptr; // out to render to (if offloaded, etc)
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
CRegion damage;
CRegion finalDamage; // damage used for funal off -> main
SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool forceIntrospection = false; // cleaned in ::end()
bool blockScreenShader = false;
SRenderModifData renderModif;
float mouseZoomFactor = 1.f;
bool mouseZoomUseMouse = true; // true by default
bool useNearestNeighbor = false;
bool forceIntrospection = false; // cleaned in ::end()
bool blockScreenShader = false;
bool simplePass = false;
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
CBox clipBox = {}; // scaled coordinates
CBox clipBox = {}; // scaled coordinates
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
uint32_t discardMode = DISCARD_OPAQUE;
float discardOpacity = 0.f;
};
class CGradientValueData;
@ -131,13 +133,16 @@ class CHyprOpenGLImpl {
CHyprOpenGLImpl();
void begin(CMonitor*, const CRegion& damage, CFramebuffer* fb = nullptr, std::optional<CRegion> finalDamage = {});
void beginSimple(CMonitor*, const CRegion& damage, CRenderbuffer* rb = nullptr, CFramebuffer* fb = nullptr);
void end();
void renderRect(CBox*, const CColor&, int round = 0);
void renderRectWithBlur(CBox*, const CColor&, int round = 0, float blurA = 1.f, bool xray = false);
void renderRectWithDamage(CBox*, const CColor&, CRegion* damage, int round = 0);
void renderTexture(wlr_texture*, CBox*, float a, int round = 0, bool allowCustomUV = false);
void renderTextureWithDamage(wlr_texture*, CBox*, CRegion* damage, float a, int round = 0, bool allowCustomUV = false);
void renderTexture(const CTexture&, CBox*, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithDamage(const CTexture&, CBox*, CRegion* damage, float a, int round = 0, bool discardActive = false, bool allowCustomUV = false);
void renderTextureWithBlur(const CTexture&, CBox*, float a, wlr_surface* pSurface, int round = 0, bool blockBlurOptimization = false, float blurA = 1.f);
void renderRoundedShadow(CBox*, int round, int range, const CColor& color, float a = 1.0);
void renderBorder(CBox*, const CGradientValueData&, int round, int borderSize, float a = 1.0, int outerRound = -1 /* use round */);

View file

@ -8,16 +8,16 @@ CRenderbuffer::~CRenderbuffer() {
if (!g_pCompositor)
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));
g_pHyprRenderer->makeEGLCurrent();
unbind();
m_sFramebuffer.release();
glDeleteRenderbuffers(1, &m_iRBO);
g_pHyprOpenGL->m_sProc.eglDestroyImageKHR(wlr_egl_get_display(g_pCompositor->m_sWLREGL), m_iImage);
}
CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer(buffer) {
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*);
@ -58,7 +58,7 @@ CRenderbuffer::CRenderbuffer(wlr_buffer* buffer, uint32_t format) : m_pWlrBuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
hyprListener_destroyBuffer.initCallback(
&buffer->events.destroy, [](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy((CRenderbuffer*)owner); }, this, "CRenderbuffer");
&buffer->events.destroy, [this](void* owner, void* data) { g_pHyprRenderer->onRenderbufferDestroy(this); }, this, "CRenderbuffer");
}
void CRenderbuffer::bind() {

View file

@ -13,6 +13,7 @@ class CRenderbuffer {
void bindFB();
void unbind();
CFramebuffer* getFB();
uint32_t getFormat();
wlr_buffer* m_pWlrBuffer = nullptr;
@ -22,4 +23,5 @@ class CRenderbuffer {
EGLImageKHR m_iImage = 0;
GLuint m_iRBO = 0;
CFramebuffer m_sFramebuffer;
uint32_t m_uDrmFormat = 0;
};

View file

@ -5,6 +5,7 @@
#include <algorithm>
#include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp"
#include "../managers/PointerManager.hpp"
#include "../desktop/Window.hpp"
#include "../desktop/LayerSurface.hpp"
#include "../protocols/SessionLock.hpp"
@ -95,8 +96,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
TRACY_GPU_ZONE("RenderSurface");
double outputX = 0, outputY = 0;
wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, RDATA->pMonitor->output, &outputX, &outputY);
double outputX = -RDATA->pMonitor->vecPosition.x, outputY = -RDATA->pMonitor->vecPosition.y;
auto* const PSURFACE = CWLSurface::surfaceFromWlr(surface);
@ -217,9 +217,7 @@ static void renderSurface(struct wlr_surface* surface, int x, int y, void* data)
}
bool CHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, CMonitor* pMonitor) {
CBox geometry = pWindow->getFullWindowBoundingBox();
if (!wlr_output_layout_intersects(g_pCompositor->m_sWLROutputLayout, pMonitor->output, geometry.pWlr()))
if (!pWindow->visibleOnMonitor(pMonitor))
return false;
if (!pWindow->m_pWorkspace && !pWindow->m_bFadingOut)
@ -1209,10 +1207,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
EMIT_HOOK_EVENT("render", RENDER_PRE);
const bool UNLOCK_SC = g_pHyprRenderer->m_bSoftwareCursorsLocked;
if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, true);
pMonitor->renderingActive = true;
// we need to cleanup fading out when rendering the appropriate context
@ -1238,12 +1232,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
CRegion damage, finalDamage;
if (!beginRender(pMonitor, damage, RENDER_MODE_NORMAL)) {
Debug::log(ERR, "renderer: couldn't beginRender()!");
if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false);
pMonitor->state.clear();
return;
}
@ -1300,7 +1289,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
renderLockscreen(pMonitor, &now, renderBox);
if (pMonitor == g_pCompositor->m_pLastMonitor) {
if (pMonitor == g_pCompositor->m_pLastMonitor.get()) {
g_pHyprNotificationOverlay->draw(pMonitor);
g_pHyprError->draw();
}
@ -1338,11 +1327,11 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
bool lockSoftware = pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f;
if (lockSoftware) {
wlr_output_lock_software_cursors(pMonitor->output, true);
g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage);
wlr_output_lock_software_cursors(pMonitor->output, false);
g_pPointerManager->lockSoftwareForMonitor(pMonitor->self.lock());
g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage);
g_pPointerManager->unlockSoftwareForMonitor(pMonitor->self.lock());
} else
g_pHyprRenderer->renderSoftwareCursors(pMonitor, g_pHyprOpenGL->m_RenderData.damage);
g_pPointerManager->renderSoftwareCursorsFor(pMonitor->self.lock(), &now, g_pHyprOpenGL->m_RenderData.damage);
}
EMIT_HOOK_EVENT("render", RENDER_LAST_MOMENT);
@ -1373,21 +1362,13 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
pMonitor->state.wlr()->tearing_page_flip = shouldTear;
if (!pMonitor->state.commit()) {
if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false);
wlr_damage_ring_add_whole(&pMonitor->damage);
return;
}
if (shouldTear)
pMonitor->tearingState.busy = true;
if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false);
if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame)
g_pCompositor->scheduleFrameForMonitor(pMonitor);
@ -1843,6 +1824,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
pMonitor->onDisconnect();
pMonitor->events.modeChanged.emit();
pMonitor->updateGlobal();
return true;
}
@ -2248,11 +2230,12 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
EMIT_HOOK_EVENT("monitorLayoutChanged", nullptr);
pMonitor->events.modeChanged.emit();
pMonitor->updateGlobal();
return true;
}
void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force) {
void CHyprRenderer::setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force) {
m_bCursorHasSurface = surf;
if (surf == m_sLastCursorData.surf && hotspotX == m_sLastCursorData.hotspotX && hotspotY == m_sLastCursorData.hotspotY && !force)
@ -2266,7 +2249,7 @@ void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspo
if (m_bCursorHidden && !force)
return;
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspotX, hotspotY);
g_pCursorManager->setCursorSurface(surf, {hotspotX, hotspotY});
}
void CHyprRenderer::setCursorFromName(const std::string& name, bool force) {
@ -2338,7 +2321,7 @@ void CHyprRenderer::setCursorHidden(bool hide) {
m_bCursorHidden = hide;
if (hide) {
wlr_cursor_unset_image(g_pCompositor->m_sWLRCursor);
g_pPointerManager->resetCursorImage();
return;
}
@ -2544,23 +2527,6 @@ void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) {
pMonitor->solitaryClient = PCANDIDATE;
}
void CHyprRenderer::renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional<Vector2D> overridePos) {
const auto CURSORPOS = overridePos.value_or(g_pInputManager->getMouseCoordsInternal() - pMonitor->vecPosition) * pMonitor->scale;
wlr_output_cursor* cursor;
wl_list_for_each(cursor, &pMonitor->output->cursors, link) {
if (!cursor->enabled || !cursor->visible || pMonitor->output->hardware_cursor == cursor)
continue;
if (!cursor->texture)
continue;
CBox cursorBox = CBox{CURSORPOS.x, CURSORPOS.y, cursor->width, cursor->height}.translate({-cursor->hotspot_x, -cursor->hotspot_y});
// TODO: NVIDIA doesn't like if we use renderTexturePrimitive here. Why?
g_pHyprOpenGL->renderTexture(cursor->texture, &cursorBox, 1.0);
}
}
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; });
@ -2582,7 +2548,7 @@ void CHyprRenderer::unsetEGL() {
eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb) {
bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode, wlr_buffer* buffer, CFramebuffer* fb, bool simple) {
makeEGLCurrent();
@ -2593,7 +2559,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
if (mode == RENDER_MODE_FULL_FAKE) {
RASSERT(fb, "Cannot render FULL_FAKE without a provided fb!");
fb->bind();
g_pHyprOpenGL->begin(pMonitor, damage, fb);
if (simple)
g_pHyprOpenGL->beginSimple(pMonitor, damage, nullptr, fb);
else
g_pHyprOpenGL->begin(pMonitor, damage, fb);
return true;
}
@ -2623,7 +2592,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode
wlr_damage_ring_rotate_buffer(&pMonitor->damage, m_pCurrentWlrBuffer, damage.pixman());
m_pCurrentRenderbuffer->bind();
g_pHyprOpenGL->begin(pMonitor, damage);
if (simple)
g_pHyprOpenGL->beginSimple(pMonitor, damage, m_pCurrentRenderbuffer);
else
g_pHyprOpenGL->begin(pMonitor, damage);
return true;
}

View file

@ -64,9 +64,8 @@ class CHyprRenderer {
void setOccludedForMainWorkspace(CRegion& region, PHLWORKSPACE pWorkspace); // TODO: merge occlusion methods
bool canSkipBackBufferClear(CMonitor* pMonitor);
void recheckSolitaryForMonitor(CMonitor* pMonitor);
void setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY, bool force = false);
void setCursorSurface(CWLSurface* surf, int hotspotX, int hotspotY, bool force = false);
void setCursorFromName(const std::string& name, bool force = false);
void renderSoftwareCursors(CMonitor* pMonitor, const CRegion& damage, std::optional<Vector2D> overridePos = {});
void onRenderbufferDestroy(CRenderbuffer* rb);
CRenderbuffer* getCurrentRBO();
bool isNvidia();
@ -75,15 +74,14 @@ 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, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr);
void endRender();
bool beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, wlr_buffer* buffer = nullptr, CFramebuffer* fb = nullptr, bool simple = false);
void endRender();
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
PHLWINDOWREF m_pLastScanout;
CMonitor* m_pMostHzMonitor = nullptr;
bool m_bDirectScanoutBlocked = false;
bool m_bSoftwareCursorsLocked = false;
CMonitor* m_pMostHzMonitor = nullptr;
bool m_bDirectScanoutBlocked = false;
DAMAGETRACKINGMODES
damageTrackingModeFromStr(const std::string&);
@ -100,10 +98,10 @@ class CHyprRenderer {
CTimer m_tRenderTimer;
struct {
int hotspotX;
int hotspotY;
std::optional<wlr_surface*> surf = nullptr;
std::string name;
int hotspotX;
int hotspotY;
std::optional<CWLSurface*> surf = nullptr;
std::string name;
} m_sLastCursorData;
private:
@ -139,6 +137,7 @@ class CHyprRenderer {
friend class CHyprOpenGLImpl;
friend class CToplevelExportProtocolManager;
friend class CInputManager;
friend class CPointerManager;
};
inline std::unique_ptr<CHyprRenderer> g_pHyprRenderer;