input: better cursor image infrastructure

Improves handling of cursor images/surfaces
Fixes an issue with decos and cursors
Fixes #3471
This commit is contained in:
Vaxry 2023-10-29 18:09:05 +00:00
parent af9440152e
commit 7a5234a0cc
7 changed files with 100 additions and 21 deletions

View file

@ -171,6 +171,10 @@ wlr_box CWindow::getWindowInputBox() {
return finalBox;
}
wlr_box CWindow::getWindowMainSurfaceBox() {
return {m_vRealPosition.vec().x, m_vRealPosition.vec().y, m_vRealSize.vec().x, m_vRealSize.vec().y};
}
SWindowDecorationExtents CWindow::getFullWindowReservedArea() {
SWindowDecorationExtents extents;

View file

@ -339,6 +339,7 @@ class CWindow {
wlr_box getFullWindowBoundingBox();
SWindowDecorationExtents getFullWindowExtents();
wlr_box getWindowInputBox();
wlr_box getWindowMainSurfaceBox();
wlr_box getWindowIdealBoundingBoxIgnoreReserved();
void updateWindowDecos();
pid_t getPID();

View file

@ -64,6 +64,8 @@ void CWLSurface::destroy() {
g_pCompositor->m_pLastFocus = nullptr;
if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
g_pInputManager->m_pLastMouseSurface = nullptr;
if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
g_pInputManager->setCursorImageOverride("left_ptr");
m_pWLRSurface = nullptr;

View file

@ -301,9 +301,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (g_pHyprRenderer->m_bHasARenderedCursor) {
// TODO: maybe wrap?
if (m_ecbClickBehavior == CLICKMODE_KILL)
g_pHyprRenderer->setCursorFromName("crosshair");
setCursorImageOverride("crosshair");
else
g_pHyprRenderer->setCursorFromName("left_ptr");
setCursorImageOverride("left_ptr");
}
m_bEmptyFocusCursorSet = true;
@ -355,6 +355,14 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
return;
}
if (pFoundWindow && foundSurface == pFoundWindow->m_pWLSurface.wlr() && !m_bCursorImageOverridden) {
const auto BOX = pFoundWindow->getWindowMainSurfaceBox();
if (!VECINRECT(mouseCoords, BOX.x, BOX.y, BOX.x + BOX.width, BOX.y + BOX.height))
setCursorImageOverride("left_ptr");
else
restoreCursorIconToApp();
}
if (pFoundWindow) {
// change cursor icon if hovering over border
if (*PRESIZEONBORDER && *PRESIZECURSORICON) {
@ -460,25 +468,65 @@ void CInputManager::processMouseRequest(wlr_seat_pointer_request_set_cursor_even
if (!cursorImageUnlocked() || !g_pHyprRenderer->m_bHasARenderedCursor)
return;
// cursorSurfaceInfo.pSurface = e->surface;
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
m_sCursorSurfaceInfo.wlSurface.unassign();
// if (e->surface) {
// hyprListener_CursorSurfaceDestroy.removeCallback();
// hyprListener_CursorSurfaceDestroy.initCallback(
// &e->surface->events.destroy, [&](void* owner, void* data) { cursorSurfaceInfo.pSurface = nullptr; }, this, "InputManager");
// cursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y};
// }
if (e->surface) {
m_sCursorSurfaceInfo.wlSurface.assign(e->surface);
m_sCursorSurfaceInfo.vHotspot = {e->hotspot_x, e->hotspot_y};
m_sCursorSurfaceInfo.hidden = false;
} else {
m_sCursorSurfaceInfo.vHotspot = {};
m_sCursorSurfaceInfo.hidden = true;
}
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client)
m_sCursorSurfaceInfo.name = "";
m_sCursorSurfaceInfo.inUse = true;
g_pHyprRenderer->setCursorSurface(e->surface, e->hotspot_x, e->hotspot_y);
}
}
void CInputManager::processMouseRequest(wlr_cursor_shape_manager_v1_request_set_shape_event* e) {
if (!g_pHyprRenderer->m_bHasARenderedCursor || !cursorImageUnlocked())
return;
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client)
g_pHyprRenderer->setCursorFromName(wlr_cursor_shape_v1_name(e->shape));
if (e->seat_client == g_pCompositor->m_sSeat.seat->pointer_state.focused_client) {
m_sCursorSurfaceInfo.wlSurface.unassign();
m_sCursorSurfaceInfo.vHotspot = {};
m_sCursorSurfaceInfo.name = wlr_cursor_shape_v1_name(e->shape);
m_sCursorSurfaceInfo.hidden = false;
m_sCursorSurfaceInfo.inUse = true;
g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name);
}
}
void CInputManager::restoreCursorIconToApp() {
if (m_sCursorSurfaceInfo.inUse)
return;
if (m_sCursorSurfaceInfo.hidden) {
g_pHyprRenderer->setCursorSurface(nullptr, 0, 0);
return;
}
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);
} else {
g_pHyprRenderer->setCursorFromName(m_sCursorSurfaceInfo.name);
}
m_sCursorSurfaceInfo.inUse = true;
}
void CInputManager::setCursorImageOverride(const std::string& name) {
if (m_bCursorImageOverridden)
return;
m_sCursorSurfaceInfo.inUse = false;
g_pHyprRenderer->setCursorFromName(name);
}
bool CInputManager::cursorImageUnlocked() {
@ -1488,6 +1536,7 @@ void CInputManager::destroySwitch(SSwitchDevice* pDevice) {
void CInputManager::setCursorImageUntilUnset(std::string name) {
g_pHyprRenderer->setCursorFromName(name.c_str());
m_bCursorImageOverridden = true;
m_sCursorSurfaceInfo.inUse = false;
}
void CInputManager::unsetCursorImage() {
@ -1495,8 +1544,7 @@ void CInputManager::unsetCursorImage() {
return;
m_bCursorImageOverridden = false;
if (!g_pHyprRenderer->m_bWindowRequestedCursorHide)
g_pHyprRenderer->setCursorFromName("left_ptr");
restoreCursorIconToApp();
}
std::string CInputManager::deviceNameToInternalString(std::string in) {

View file

@ -229,15 +229,22 @@ class CInputManager {
void setBorderCursorIcon(eBorderIconDirection);
void setCursorIconOnBorder(CWindow* w);
// temporary. Obeys setUntilUnset.
void setCursorImageOverride(const std::string& name);
// cursor surface
// struct cursorSI {
// wlr_surface* pSurface = nullptr;
// Vector2D vHotspot;
// bool bUsed = false;
// } cursorSurfaceInfo;
// DYNLISTENER(CursorSurfaceDestroy);
struct cursorSI {
bool hidden = false; // null surface = hidden
CWLSurface wlSurface;
Vector2D vHotspot;
std::string name; // if not empty, means set by name.
bool inUse = false;
} m_sCursorSurfaceInfo;
void restoreCursorIconToApp(); // no-op if restored
friend class CKeybindManager;
friend class CWLSurface;
};
inline std::unique_ptr<CInputManager> g_pInputManager;

View file

@ -1940,11 +1940,23 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR
void CHyprRenderer::setCursorSurface(wlr_surface* surf, int hotspotX, int hotspotY) {
m_bCursorHasSurface = surf;
if (surf == m_sLastCursorData.surf)
return;
m_sLastCursorData.name = "";
m_sLastCursorData.surf = surf;
wlr_cursor_set_surface(g_pCompositor->m_sWLRCursor, surf, hotspotX, hotspotY);
}
void CHyprRenderer::setCursorFromName(const std::string& name) {
m_bCursorHasSurface = true;
if (name == m_sLastCursorData.name)
return;
m_sLastCursorData.name = name;
m_sLastCursorData.surf = nullptr;
wlr_cursor_set_xcursor(g_pCompositor->m_sWLRCursor, g_pCompositor->m_sWLRXCursorMgr, name.c_str());
}

View file

@ -83,6 +83,11 @@ class CHyprRenderer {
CTimer m_tRenderTimer;
struct {
wlr_surface* surf = nullptr;
std::string name;
} m_sLastCursorData;
private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
void renderWorkspaceWindowsFullscreen(CMonitor*, CWorkspace*, timespec*); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)