diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 15fbcda0..edfeb495 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -90,6 +90,8 @@ void CConfigManager::setDefaultVars() { configValues["misc:suppress_portal_warnings"].intValue = 0; configValues["misc:render_ahead_of_time"].intValue = 0; configValues["misc:render_ahead_safezone"].intValue = 1; + configValues["misc:cursor_zoom_factor"].floatValue = 1.f; + configValues["misc:cursor_zoom_rigid"].intValue = 0; configValues["debug:int"].intValue = 0; configValues["debug:log_damage"].intValue = 0; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index c271e066..44d566cb 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -299,11 +299,23 @@ void CMonitor::onDisconnect() { } void CMonitor::addDamage(const pixman_region32_t* rg) { + static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; + if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { + wlr_damage_ring_add_whole(&damage); + g_pCompositor->scheduleFrameForMonitor(this); + } + if (wlr_damage_ring_add(&damage, rg)) g_pCompositor->scheduleFrameForMonitor(this); } void CMonitor::addDamage(const wlr_box* box) { + static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; + if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { + wlr_damage_ring_add_whole(&damage); + g_pCompositor->scheduleFrameForMonitor(this); + } + if (wlr_damage_ring_add_box(&damage, box)) g_pCompositor->scheduleFrameForMonitor(this); } diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 118f21c7..9eebc93a 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -56,6 +56,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { static auto* const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; static auto* const PBORDERGRABEXTEND = &g_pConfigManager->getConfigValuePtr("general:extend_border_grab_area")->intValue; static auto* const PRESIZECURSORICON = &g_pConfigManager->getConfigValuePtr("general:hover_icon_on_border")->intValue; + static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; const auto BORDER_GRAB_AREA = *PRESIZEONBORDER ? *PBORDERSIZE + *PBORDERGRABEXTEND : 0; const auto FOLLOWMOUSE = *PFOLLOWONDND && m_sDrag.drag ? 1 : *PFOLLOWMOUSE; @@ -89,6 +90,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { const auto PMONITOR = g_pCompositor->getMonitorFromCursor(); + if (*PZOOMFACTOR != 1.f) + g_pHyprRenderer->damageMonitor(PMONITOR); + // constraints // All constraints TODO: multiple mice? if (g_pCompositor->m_sSeat.mouse && g_pCompositor->m_sSeat.mouse->currentConstraint && !g_pCompositor->m_sSeat.exclusiveClient && !g_pSessionLockManager->isSessionLocked()) { diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index 93bb774a..c1cd0a7d 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -145,6 +145,8 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool } void CHyprOpenGLImpl::end() { + static auto* const PZOOMRIGID = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_rigid")->intValue; + // end the render, copy the data to the WLR framebuffer if (!m_bFakeFrame) { pixman_region32_copy(m_RenderData.pDamage, &m_rOriginalDamageRegion); @@ -155,20 +157,41 @@ void CHyprOpenGLImpl::end() { glBindFramebuffer(GL_FRAMEBUFFER, m_iWLROutputFb); wlr_box monbox = {0, 0, m_RenderData.pMonitor->vecTransformedSize.x, m_RenderData.pMonitor->vecTransformedSize.y}; + if (m_RenderData.mouseZoomFactor != 1.f) { + const auto MOUSEPOS = g_pInputManager->getMouseCoordsInternal() - m_RenderData.pMonitor->vecPosition; + monbox.x -= MOUSEPOS.x; + monbox.y -= MOUSEPOS.y; + scaleBox(&monbox, m_RenderData.mouseZoomFactor); + monbox.x += *PZOOMRIGID ? m_RenderData.pMonitor->vecTransformedSize.x / 2 : MOUSEPOS.x; + monbox.y += *PZOOMRIGID ? m_RenderData.pMonitor->vecTransformedSize.y / 2 : MOUSEPOS.y; + + if (monbox.x > 0) + monbox.x = 0; + if (monbox.y > 0) + monbox.y = 0; + if (monbox.x + monbox.width < m_RenderData.pMonitor->vecTransformedSize.x) + monbox.x = m_RenderData.pMonitor->vecTransformedSize.x - monbox.width; + if (monbox.y + monbox.height < m_RenderData.pMonitor->vecTransformedSize.y) + monbox.y = m_RenderData.pMonitor->vecTransformedSize.y - monbox.height; + } + clear(CColor(11.0 / 255.0, 11.0 / 255.0, 11.0 / 255.0, 1.0)); - m_bEndFrame = true; - m_bApplyFinalShader = true; + m_bEndFrame = true; + m_bApplyFinalShader = true; + m_RenderData.useNearestNeighbor = true; renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 1.f, 0); - m_bApplyFinalShader = false; - m_bEndFrame = false; + m_RenderData.useNearestNeighbor = false; + m_bApplyFinalShader = false; + m_bEndFrame = false; } // reset our data - m_RenderData.pMonitor = nullptr; - m_iWLROutputFb = 0; + m_RenderData.pMonitor = nullptr; + m_iWLROutputFb = 0; + m_RenderData.mouseZoomFactor = 1.f; } void CHyprOpenGLImpl::initShaders() { @@ -554,7 +577,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b glActiveTexture(GL_TEXTURE0); glBindTexture(tex.m_iTarget, tex.m_iTexID); - glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if (m_RenderData.useNearestNeighbor) { + glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } else { + glTexParameteri(tex.m_iTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } glUseProgram(shader->program); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 6f54ea35..624878ff 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -74,6 +74,8 @@ struct SCurrentRenderData { pixman_region32_t* pDamage = nullptr; SRenderModifData renderModif; + float mouseZoomFactor = 1.f; + bool useNearestNeighbor = false; Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 7244666d..5d1968e2 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -767,6 +767,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static auto* const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue; static auto* const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue; static auto* const PVFR = &g_pConfigManager->getConfigValuePtr("misc:vfr")->intValue; + static auto* const PZOOMFACTOR = &g_pConfigManager->getConfigValuePtr("misc:cursor_zoom_factor")->floatValue; static int damageBlinkCleanup = 0; // because double-buffered @@ -907,7 +908,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { g_pHyprOpenGL->clear(CColor(17.0 / 255.0, 17.0 / 255.0, 17.0 / 255.0, 1.0)); g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper" - renderWorkspace(pMonitor, g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace), &now, {0, 0, (int)pMonitor->vecPixelSize.x, (int)pMonitor->vecPixelSize.y}); + wlr_box renderBox = {0, 0, (int)pMonitor->vecPixelSize.x, (int)pMonitor->vecPixelSize.y}; + renderWorkspace(pMonitor, g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace), &now, renderBox); renderLockscreen(pMonitor, &now); @@ -934,11 +936,20 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y)) { - wlr_output_render_software_cursors(pMonitor->output, NULL); + if (pMonitor == g_pCompositor->getMonitorFromCursor() && *PZOOMFACTOR != 1.f) { + wlr_output_lock_software_cursors(pMonitor->output, true); + wlr_output_render_software_cursors(pMonitor->output, NULL); + wlr_output_lock_software_cursors(pMonitor->output, false); + } else + wlr_output_render_software_cursors(pMonitor->output, NULL); wlr_renderer_end(g_pCompositor->m_sWLRRenderer); } } + if (pMonitor == g_pCompositor->getMonitorFromCursor()) + g_pHyprOpenGL->m_RenderData.mouseZoomFactor = std::clamp(*PZOOMFACTOR, 1.f, INFINITY); + else + g_pHyprOpenGL->m_RenderData.mouseZoomFactor = 1.f; g_pHyprOpenGL->end(); // calc frame damage diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 4495b9d0..c882a478 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -58,15 +58,16 @@ class CHyprRenderer { bool m_bDirectScanoutBlocked = false; bool m_bSoftwareCursorsLocked = false; - DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&); + DAMAGETRACKINGMODES + damageTrackingModeFromStr(const std::string&); - bool attemptDirectScanout(CMonitor*); - void setWindowScanoutMode(CWindow*); - void initiateManualCrash(); + bool attemptDirectScanout(CMonitor*); + void setWindowScanoutMode(CWindow*); + void initiateManualCrash(); - bool m_bCrashingInProgress = false; - float m_fCrashingDistort = 0.5f; - wl_event_source* m_pCrashingLoop = nullptr; + bool m_bCrashingInProgress = false; + float m_fCrashingDistort = 0.5f; + wl_event_source* m_pCrashingLoop = nullptr; private: void arrangeLayerArray(CMonitor*, const std::vector>&, bool, wlr_box*);