From aef7cf397f8ad5490d13dd322a2f9861e4fa875a Mon Sep 17 00:00:00 2001 From: Vaxry Date: Sun, 29 Sep 2024 18:12:50 +0100 Subject: [PATCH] core: implement fractional scaling support Additionally, adds --quiet, --verbose. --- src/debug/Log.cpp | 6 ++++ src/debug/Log.hpp | 6 ++-- src/helpers/LayerSurface.cpp | 22 ++++++++++-- src/helpers/LayerSurface.hpp | 34 ++++++++++--------- src/hyprpicker.cpp | 66 ++++++++++++++++++++++-------------- src/hyprpicker.hpp | 3 ++ src/main.cpp | 13 +++++-- 7 files changed, 103 insertions(+), 47 deletions(-) diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp index 264dd79..a283591 100644 --- a/src/debug/Log.cpp +++ b/src/debug/Log.cpp @@ -8,6 +8,12 @@ void Debug::log(LogLevel level, const char* fmt, ...) { std::string levelstr = ""; + if (quiet && (level != ERR && level != CRIT)) + return; + + if (!verbose && level == TRACE) + return; + switch (level) { case LOG: levelstr = "[LOG] "; break; case WARN: levelstr = "[WARN] "; break; diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp index bdf9380..446d69d 100644 --- a/src/debug/Log.hpp +++ b/src/debug/Log.hpp @@ -9,9 +9,11 @@ enum LogLevel { WARN, ERR, CRIT, - INFO + INFO, + TRACE, }; namespace Debug { - void log(LogLevel level, const char* fmt, ...); + inline bool quiet = false, verbose = false; + void log(LogLevel level, const char* fmt, ...); }; \ No newline at end of file diff --git a/src/helpers/LayerSurface.cpp b/src/helpers/LayerSurface.cpp index 9b5c600..03cb3e4 100644 --- a/src/helpers/LayerSurface.cpp +++ b/src/helpers/LayerSurface.cpp @@ -13,6 +13,17 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { return; } + if (!g_pHyprpicker->m_bNoFractional) { + pViewport = makeShared(g_pHyprpicker->m_pViewporter->sendGetViewport(pSurface->resource())); + + // this will not actually be used, as we assume we'll be fullscreen and we can get the real dimensions from screencopy, but we'll have + // this for if we need it in the future + pFractionalScale = makeShared(g_pHyprpicker->m_pFractionalMgr->sendGetFractionalScale(pSurface->resource())); + pFractionalScale->setPreferredScale([this](CCWpFractionalScaleV1* r, uint32_t scale120) { // + Debug::log(TRACE, "Received a preferredScale for %s: %.2f", m_pMonitor->name.c_str(), scale120 / 120.F); + }); + } + pLayerSurface = makeShared( g_pHyprpicker->m_pLayerShell->sendGetLayerSurface(pSurface->resource(), pMonitor->output->resource(), ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "hyprpicker")); @@ -62,8 +73,15 @@ void CLayerSurface::sendFrame() { frameCallback = makeShared(pSurface->sendFrame()); frameCallback->setDone([this](CCWlCallback* r, uint32_t when) { onCallbackDone(this, when); }); - pSurface->sendAttach(lastBuffer == 0 ? buffers[0]->buffer.get() : buffers[1]->buffer.get(), 0, 0); - pSurface->sendSetBufferScale(m_pMonitor->scale); + const auto& PBUFFER = lastBuffer == 0 ? buffers[0] : buffers[1]; + + pSurface->sendAttach(PBUFFER->buffer.get(), 0, 0); + if (!g_pHyprpicker->m_bNoFractional) { + pSurface->sendSetBufferScale(1); + pViewport->sendSetDestination(m_pMonitor->size.x, m_pMonitor->size.y); + } else + pSurface->sendSetBufferScale(m_pMonitor->scale); + pSurface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF); pSurface->sendCommit(); diff --git a/src/helpers/LayerSurface.hpp b/src/helpers/LayerSurface.hpp index c6b7c2d..29aa10b 100644 --- a/src/helpers/LayerSurface.hpp +++ b/src/helpers/LayerSurface.hpp @@ -10,28 +10,30 @@ class CLayerSurface { CLayerSurface(SMonitor*); ~CLayerSurface(); - void sendFrame(); - void markDirty(); + void sendFrame(); + void markDirty(); - SMonitor* m_pMonitor = nullptr; + SMonitor* m_pMonitor = nullptr; - SP pLayerSurface = nullptr; - SP pSurface = nullptr; + SP pLayerSurface = nullptr; + SP pSurface = nullptr; + SP pViewport = nullptr; + SP pFractionalScale = nullptr; - bool wantsACK = false; - uint32_t ACKSerial = 0; - bool working = false; + bool wantsACK = false; + uint32_t ACKSerial = 0; + bool working = false; - int lastBuffer = 0; - SP buffers[2]; + int lastBuffer = 0; + SP buffers[2]; - SP screenBuffer; - uint32_t scflags = 0; - uint32_t screenBufferFormat = 0; + SP screenBuffer; + uint32_t scflags = 0; + uint32_t screenBufferFormat = 0; - bool dirty = true; + bool dirty = true; - bool rendered = false; + bool rendered = false; - SP frameCallback = nullptr; + SP frameCallback = nullptr; }; \ No newline at end of file diff --git a/src/hyprpicker.cpp b/src/hyprpicker.cpp index 8543cd3..9101585 100644 --- a/src/hyprpicker.cpp +++ b/src/hyprpicker.cpp @@ -11,7 +11,7 @@ void CHyprpicker::init() { if (!m_pXKBContext) Debug::log(ERR, "Failed to create xkb context"); - m_pWLDisplay = wl_display_connect(nullptr); + m_pWLDisplay = wl_display_connect("wayland-2"); if (!m_pWLDisplay) { Debug::log(CRIT, "No wayland compositor running!"); @@ -70,6 +70,11 @@ void CHyprpicker::init() { } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { m_pCursorShapeMgr = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_cursor_shape_manager_v1_interface, 1)); + } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { + m_pFractionalMgr = + makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_fractional_scale_manager_v1_interface, 1)); + } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { + m_pViewporter = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_viewporter_interface, 1)); } }); @@ -83,6 +88,15 @@ void CHyprpicker::init() { exit(1); } + if (!m_pFractionalMgr) { + Debug::log(WARN, "wp_fractional_scale_v1 not supported, fractional scaling won't work"); + m_bNoFractional = true; + } + if (!m_pViewporter) { + Debug::log(WARN, "wp_viewporter not supported, fractional scaling won't work"); + m_bNoFractional = true; + } + for (auto& m : m_vMonitors) { m_vLayerSurfaces.emplace_back(std::make_unique(m.get())); @@ -121,6 +135,8 @@ void CHyprpicker::finish(int code) { m_pSeat.reset(); m_pKeyboard.reset(); m_pPointer.reset(); + m_pViewporter.reset(); + m_pFractionalMgr.reset(); wl_display_disconnect(m_pWLDisplay); m_pWLDisplay = nullptr; @@ -135,9 +151,11 @@ void CHyprpicker::recheckACK() { ls->wantsACK = false; ls->pLayerSurface->sendAckConfigure(ls->ACKSerial); - if (!ls->buffers[0] || ls->buffers[0]->pixelSize != ls->m_pMonitor->size * ls->m_pMonitor->scale) { - ls->buffers[0] = makeShared(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4); - ls->buffers[1] = makeShared(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4); + const auto MONITORSIZE = ls->screenBuffer && !g_pHyprpicker->m_bNoFractional ? ls->screenBuffer->pixelSize : ls->m_pMonitor->size * ls->m_pMonitor->scale; + + if (!ls->buffers[0] || ls->buffers[0]->pixelSize != MONITORSIZE) { + ls->buffers[0] = makeShared(MONITORSIZE, WL_SHM_FORMAT_ARGB8888, MONITORSIZE.x * 4); + ls->buffers[1] = makeShared(MONITORSIZE, WL_SHM_FORMAT_ARGB8888, MONITORSIZE.x * 4); } } } @@ -323,8 +341,8 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { return; } - PBUFFER->surface = cairo_image_surface_create_for_data((unsigned char*)PBUFFER->data, CAIRO_FORMAT_ARGB32, pSurface->m_pMonitor->size.x * pSurface->m_pMonitor->scale, - pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale, PBUFFER->pixelSize.x * 4); + PBUFFER->surface = + cairo_image_surface_create_for_data((unsigned char*)PBUFFER->data, CAIRO_FORMAT_ARGB32, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y, PBUFFER->pixelSize.x * 4); PBUFFER->cairo = cairo_create(PBUFFER->surface); @@ -334,15 +352,13 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0); - cairo_rectangle(PCAIRO, 0, 0, pSurface->m_pMonitor->size.x * pSurface->m_pMonitor->scale, pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale); + cairo_rectangle(PCAIRO, 0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y); cairo_fill(PCAIRO); - if (pSurface == g_pHyprpicker->m_pLastSurface && !forceInactive) { - const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; - const auto SCALECURSOR = Vector2D{ - g_pHyprpicker->m_pLastSurface->screenBuffer->pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0]->pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale), - g_pHyprpicker->m_pLastSurface->screenBuffer->pixelSize.y / (g_pHyprpicker->m_pLastSurface->buffers[0]->pixelSize.y / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale)}; - const auto CLICKPOS = Vector2D{g_pHyprpicker->m_vLastCoords.floor().x * SCALECURSOR.x, g_pHyprpicker->m_vLastCoords.floor().y * SCALECURSOR.y}; + if (pSurface == m_pLastSurface && !forceInactive) { + const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; + const auto MOUSECOORDSABS = m_vLastCoords.floor() / pSurface->m_pMonitor->size; + const auto CLICKPOS = MOUSECOORDSABS * PBUFFER->pixelSize; const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer->surface); cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); @@ -368,15 +384,17 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { // cairo_restore(PCAIRO); - if (!g_pHyprpicker->m_bNoZoom) { + if (!m_bNoZoom) { cairo_save(PCAIRO); - const auto PIXCOLOR = getColorFromPixel(pSurface, CLICKPOS); + const auto CLICKPOSBUF = CLICKPOS / PBUFFER->pixelSize * pSurface->screenBuffer->pixelSize; + + const auto PIXCOLOR = getColorFromPixel(pSurface, CLICKPOSBUF); cairo_set_source_rgba(PCAIRO, PIXCOLOR.r / 255.f, PIXCOLOR.g / 255.f, PIXCOLOR.b / 255.f, PIXCOLOR.a / 255.f); cairo_scale(PCAIRO, 1, 1); - cairo_arc(PCAIRO, m_vLastCoords.x * pSurface->m_pMonitor->scale, m_vLastCoords.y * pSurface->m_pMonitor->scale, 105 / SCALEBUFS.x, 0, 2 * M_PI); + cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, 105 / SCALEBUFS.x, 0, 2 * M_PI); cairo_clip(PCAIRO); cairo_fill(PCAIRO); @@ -391,12 +409,12 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_pattern_set_filter(PATTERN, CAIRO_FILTER_NEAREST); cairo_matrix_t matrix; cairo_matrix_init_identity(&matrix); - cairo_matrix_translate(&matrix, CLICKPOS.x + 0.5f, CLICKPOS.y + 0.5f); + cairo_matrix_translate(&matrix, CLICKPOSBUF.x + 0.5f, CLICKPOSBUF.y + 0.5f); cairo_matrix_scale(&matrix, 0.1f, 0.1f); - cairo_matrix_translate(&matrix, -CLICKPOS.x / SCALEBUFS.x - 0.5f, -CLICKPOS.y / SCALEBUFS.y - 0.5f); + cairo_matrix_translate(&matrix, -CLICKPOSBUF.x / SCALEBUFS.x - 0.5f, -CLICKPOSBUF.y / SCALEBUFS.y - 0.5f); cairo_pattern_set_matrix(PATTERN, &matrix); cairo_set_source(PCAIRO, PATTERN); - cairo_arc(PCAIRO, m_vLastCoords.x * pSurface->m_pMonitor->scale, m_vLastCoords.y * pSurface->m_pMonitor->scale, 100 / SCALEBUFS.x, 0, 2 * M_PI); + cairo_arc(PCAIRO, CLICKPOS.x, CLICKPOS.y, 100 / SCALEBUFS.x, 0, 2 * M_PI); cairo_clip(PCAIRO); cairo_paint(PCAIRO); @@ -406,10 +424,10 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) { cairo_pattern_destroy(PATTERN); } - } else if (!g_pHyprpicker->m_bRenderInactive) { + } else if (!m_bRenderInactive) { cairo_set_operator(PCAIRO, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0); - cairo_rectangle(PCAIRO, 0, 0, pSurface->m_pMonitor->size.x * pSurface->m_pMonitor->scale, pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale); + cairo_rectangle(PCAIRO, 0, 0, PBUFFER->pixelSize.x, PBUFFER->pixelSize.y); cairo_fill(PCAIRO); } else { const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; @@ -537,10 +555,8 @@ void CHyprpicker::initMouse() { const auto FLUMI = [](const float& c) -> float { return c <= 0.03928 ? c / 12.92 : powf((c + 0.055) / 1.055, 2.4); }; // get the px and print it - const auto SCALE = Vector2D{m_pLastSurface->screenBuffer->pixelSize.x / (m_pLastSurface->buffers[0]->pixelSize.x / m_pLastSurface->m_pMonitor->scale), - m_pLastSurface->screenBuffer->pixelSize.y / (m_pLastSurface->buffers[0]->pixelSize.y / m_pLastSurface->m_pMonitor->scale)}; - - const auto CLICKPOS = m_vLastCoords.floor() * SCALE; + const auto MOUSECOORDSABS = m_vLastCoords.floor() / m_pLastSurface->m_pMonitor->size; + const auto CLICKPOS = MOUSECOORDSABS * m_pLastSurface->screenBuffer->pixelSize; const auto COL = getColorFromPixel(m_pLastSurface, CLICKPOS); diff --git a/src/hyprpicker.hpp b/src/hyprpicker.hpp index 01e51e5..c449daf 100644 --- a/src/hyprpicker.hpp +++ b/src/hyprpicker.hpp @@ -28,6 +28,8 @@ class CHyprpicker { SP m_pSeat; SP m_pKeyboard; SP m_pPointer; + SP m_pFractionalMgr; + SP m_pViewporter; wl_display* m_pWLDisplay = nullptr; xkb_context* m_pXKBContext = nullptr; @@ -41,6 +43,7 @@ class CHyprpicker { bool m_bAutoCopy = false; bool m_bRenderInactive = false; bool m_bNoZoom = false; + bool m_bNoFractional = false; bool m_bRunning = true; diff --git a/src/main.cpp b/src/main.cpp index 788cbbe..6b91e58 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,7 +11,10 @@ static void help(void) { << " -n | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" << " -h | --help | Show this help message\n" << " -r | --render-inactive | Render (freeze) inactive displays\n" - << " -z | --no-zoom | Disable the zoom lens\n"; + << " -z | --no-zoom | Disable the zoom lens\n" + << " -q | --quiet | Disable most logs (leaves errors)\n" + << " -v | --verbose | Enable more logs\n" + << " -t | --no-fractional | Disable fractional scaling support\n"; } int main(int argc, char** argv, char** envp) { @@ -25,9 +28,12 @@ int main(int argc, char** argv, char** envp) { {"no-fancy", no_argument, NULL, 'n'}, {"render-inactive", no_argument, NULL, 'r'}, {"no-zoom", no_argument, NULL, 'z'}, + {"no-fractional", no_argument, NULL, 't'}, + {"quiet", no_argument, NULL, 'q'}, + {"verbose", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0}}; - int c = getopt_long(argc, argv, ":f:hnarz", long_options, &option_index); + int c = getopt_long(argc, argv, ":f:hnarzqvt", long_options, &option_index); if (c == -1) break; @@ -53,6 +59,9 @@ int main(int argc, char** argv, char** envp) { case 'a': g_pHyprpicker->m_bAutoCopy = true; break; case 'r': g_pHyprpicker->m_bRenderInactive = true; break; case 'z': g_pHyprpicker->m_bNoZoom = true; break; + case 't': g_pHyprpicker->m_bNoFractional = true; break; + case 'q': Debug::quiet = true; break; + case 'v': Debug::verbose = true; break; default: help(); exit(1); }