hyprlock/src/core/LockSurface.cpp

146 lines
5 KiB
C++
Raw Normal View History

2024-02-18 23:08:03 +00:00
#include "LockSurface.hpp"
#include "hyprlock.hpp"
#include "Egl.hpp"
#include "../config/ConfigManager.hpp"
#include "../core/AnimationManager.hpp"
#include "../helpers/Log.hpp"
2024-02-18 23:08:03 +00:00
#include "../renderer/Renderer.hpp"
CSessionLockSurface::~CSessionLockSurface() {
if (eglWindow)
wl_egl_window_destroy(eglWindow);
2024-02-18 23:08:03 +00:00
}
CSessionLockSurface::CSessionLockSurface(const SP<COutput>& pOutput) : m_outputRef(pOutput), m_outputID(pOutput->m_ID) {
surface = makeShared<CCWlSurface>(g_pHyprlock->getCompositor()->sendCreateSurface());
RASSERT(surface, "Couldn't create wl_surface");
2024-02-18 23:08:03 +00:00
static const auto FRACTIONALSCALING = g_pConfigManager->getValue<Hyprlang::INT>("general:fractional_scaling");
const auto ENABLE_FSV1 = *FRACTIONALSCALING == 1 || /* auto enable */ (*FRACTIONALSCALING == 2);
const auto PFRACTIONALMGR = g_pHyprlock->getFractionalMgr();
const auto PVIEWPORTER = g_pHyprlock->getViewporter();
if (ENABLE_FSV1 && PFRACTIONALMGR && PVIEWPORTER) {
fractional = makeShared<CCWpFractionalScaleV1>(PFRACTIONALMGR->sendGetFractionalScale(surface->resource()));
fractional->setPreferredScale([this](CCWpFractionalScaleV1*, uint32_t scale) {
const bool SAMESCALE = fractionalScale == scale / 120.0;
fractionalScale = scale / 120.0;
Debug::log(LOG, "Got fractional scale: {:.1f}%", fractionalScale * 100.F);
if (!SAMESCALE && readyForFrame)
onScaleUpdate();
});
viewport = makeShared<CCWpViewport>(PVIEWPORTER->sendGetViewport(surface->resource()));
}
if (!PFRACTIONALMGR)
2024-02-18 23:08:03 +00:00
Debug::log(LOG, "No fractional-scale support! Oops, won't be able to scale!");
if (!PVIEWPORTER)
Debug::log(LOG, "No viewporter support! Oops, won't be able to scale!");
2024-02-18 23:08:03 +00:00
lockSurface = makeShared<CCExtSessionLockSurfaceV1>(g_pHyprlock->getSessionLock()->sendGetLockSurface(surface->resource(), pOutput->m_wlOutput->resource()));
RASSERT(lockSurface, "Couldn't create ext_session_lock_surface_v1");
2024-02-18 23:08:03 +00:00
lockSurface->setConfigure([this](CCExtSessionLockSurfaceV1* r, uint32_t serial, uint32_t width, uint32_t height) { configure({(double)width, (double)height}, serial); });
2024-02-18 23:08:03 +00:00
}
void CSessionLockSurface::configure(const Vector2D& size_, uint32_t serial_) {
2024-02-19 02:39:57 +00:00
Debug::log(LOG, "configure with serial {}", serial_);
2024-02-18 23:08:03 +00:00
const bool SAMESERIAL = serial == serial_;
const bool SAMESIZE = logicalSize == size_;
const bool SAMESCALE = appliedScale == fractionalScale;
const auto POUTPUT = m_outputRef.lock();
serial = serial_;
logicalSize = size_;
appliedScale = fractionalScale;
2024-02-20 16:16:40 +00:00
2024-07-07 11:55:59 -04:00
if (fractional) {
size = (size_ * fractionalScale).floor();
viewport->sendSetDestination(logicalSize.x, logicalSize.y);
surface->sendSetBufferScale(1);
2024-07-07 11:55:59 -04:00
} else {
size = size_ * POUTPUT->scale;
surface->sendSetBufferScale(POUTPUT->scale);
2024-07-07 11:55:59 -04:00
}
if (!SAMESERIAL)
lockSurface->sendAckConfigure(serial);
2024-02-18 23:08:03 +00:00
Debug::log(LOG, "Configuring surface for logical {} and pixel {}", logicalSize, size);
surface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF);
2024-02-18 23:08:03 +00:00
2024-07-07 11:55:59 -04:00
if (!eglWindow) {
eglWindow = wl_egl_window_create((wl_surface*)surface->resource(), size.x, size.y);
RASSERT(eglWindow, "Couldn't create eglWindow");
2024-07-07 11:55:59 -04:00
} else
2024-02-18 23:08:03 +00:00
wl_egl_window_resize(eglWindow, size.x, size.y, 0, 0);
if (!eglSurface) {
2024-07-07 11:55:59 -04:00
eglSurface = g_pEGL->eglCreatePlatformWindowSurfaceEXT(g_pEGL->eglDisplay, g_pEGL->eglConfig, eglWindow, nullptr);
RASSERT(eglSurface, "Couldn't create eglSurface");
2024-02-18 23:08:03 +00:00
}
if (readyForFrame && !(SAMESIZE && SAMESCALE)) {
Debug::log(LOG, "output {} changed, reloading widgets!", POUTPUT->stringPort);
g_pRenderer->reconfigureWidgetsFor(POUTPUT->m_ID);
}
2024-02-18 23:08:03 +00:00
readyForFrame = true;
render();
2024-02-18 23:08:03 +00:00
}
void CSessionLockSurface::onScaleUpdate() {
configure(logicalSize, serial);
}
2024-02-18 23:08:03 +00:00
void CSessionLockSurface::render() {
if (frameCallback || !readyForFrame) {
needsFrame = true;
return;
}
g_pAnimationManager->tick();
2024-02-18 23:08:03 +00:00
const auto FEEDBACK = g_pRenderer->renderLock(*this);
frameCallback = makeShared<CCWlCallback>(surface->sendFrame());
frameCallback->setDone([this](CCWlCallback* r, uint32_t frameTime) {
if (g_pHyprlock->m_bTerminate)
return;
if (Debug::verbose) {
const auto POUTPUT = m_outputRef.lock();
Debug::log(TRACE, "[{}] frame {}, Current fps: {:.2f}", POUTPUT->stringPort, m_frames, 1000.f / (frameTime - m_lastFrameTime));
}
m_lastFrameTime = frameTime;
m_frames++;
onCallback();
});
2024-02-18 23:08:03 +00:00
eglSwapBuffers(g_pEGL->eglDisplay, eglSurface);
2024-02-18 23:08:03 +00:00
needsFrame = FEEDBACK.needsFrame || g_pAnimationManager->shouldTickForNext();
2024-02-18 23:08:03 +00:00
}
void CSessionLockSurface::onCallback() {
frameCallback.reset();
2024-02-18 23:08:03 +00:00
2024-07-07 11:55:59 -04:00
if (needsFrame && !g_pHyprlock->m_bTerminate && g_pEGL) {
needsFrame = false;
2024-02-18 23:08:03 +00:00
render();
2024-07-07 11:55:59 -04:00
}
}
widgets: add onclick feature (#736) * widget: add click handling and point containment methods to IWidget interface * core: add onClick method to handle mouse click events - renderer: move getOrCreateWidgetsFor method declaration to public section * core: update mouse event handling to track mouse location and button clicks * widget: add onclick command handling and point containment to CLabel - config: add onclick special config value to label * assets: add label configuration for keyboard layout switching * config: add onclick configuration for label widgets - add CLICKABLE macro for onclick configuration - replace direct onclick assignment with CLICKABLE macro * core: fix cursor shape initialization and pointer handling - ensure pointer is available before setting cursor shape - initialize cursor shape device if not already done * core: add hover handling and cursor shape updates - implement onHover method to manage widget hover states - update cursor shape based on hover status - ensure all outputs are redrawn after state changes * widgets: add hover state management and bounding box calculations - add setHover and isHovered methods to manage hover state - implement containsPoint method for hit testing - override getBoundingBox in CLabel for accurate positioning - add onHover method in CLabel to change cursor shape * core: add hover handling in pointer motion - invoke onHover method with current mouse location * widgets: add hover handling and bounding box for password input field - add getBoundingBox method to calculate the widget's bounding box - implement onHover method to update cursor shape on hover * widgets: update hover behavior for label widget - modify cursor shape setting to only apply when onclickCommand is not empty * core: optimize hover handling and rendering for lock surfaces - Improve hover state tracking for widgets - reduce unnecessary redraw calls by tracking hover changes - remove redundant renderAllOutputs() call * widgets: add onclick and hover to shape and image * core: trigger hover and onclick only for the currently focused surface * core: handle fractionalScale in onclick and hover * core: don't trigger onclick or hover when hide_cursor is set * misc: remove braces * core: run onclick commands asnychronously --------- Co-authored-by: Memoraike <memoraike@gmail.com>
2025-05-05 17:11:24 +02:00
SP<CCWlSurface> CSessionLockSurface::getWlSurface() {
return surface;
}