core: implement fractional scaling support

Additionally, adds --quiet, --verbose.
This commit is contained in:
Vaxry 2024-09-29 18:12:50 +01:00
parent c9238d39f6
commit ed3f644af7
7 changed files with 102 additions and 46 deletions

View file

@ -8,6 +8,12 @@
void Debug::log(LogLevel level, const char* fmt, ...) { void Debug::log(LogLevel level, const char* fmt, ...) {
std::string levelstr = ""; std::string levelstr = "";
if (quiet && (level != ERR && level != CRIT))
return;
if (!verbose && level == TRACE)
return;
switch (level) { switch (level) {
case LOG: levelstr = "[LOG] "; break; case LOG: levelstr = "[LOG] "; break;
case WARN: levelstr = "[WARN] "; break; case WARN: levelstr = "[WARN] "; break;

View file

@ -9,9 +9,11 @@ enum LogLevel {
WARN, WARN,
ERR, ERR,
CRIT, CRIT,
INFO INFO,
TRACE,
}; };
namespace Debug { namespace Debug {
inline bool quiet = false, verbose = false;
void log(LogLevel level, const char* fmt, ...); void log(LogLevel level, const char* fmt, ...);
}; };

View file

@ -13,6 +13,17 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) {
return; return;
} }
if (!g_pHyprpicker->m_bNoFractional) {
pViewport = makeShared<CCWpViewport>(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<CCWpFractionalScaleV1>(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<CCZwlrLayerSurfaceV1>( pLayerSurface = makeShared<CCZwlrLayerSurfaceV1>(
g_pHyprpicker->m_pLayerShell->sendGetLayerSurface(pSurface->resource(), pMonitor->output->resource(), ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "hyprpicker")); 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<CCWlCallback>(pSurface->sendFrame()); frameCallback = makeShared<CCWlCallback>(pSurface->sendFrame());
frameCallback->setDone([this](CCWlCallback* r, uint32_t when) { onCallbackDone(this, when); }); 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); 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->sendSetBufferScale(m_pMonitor->scale);
pSurface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF); pSurface->sendDamageBuffer(0, 0, 0xFFFF, 0xFFFF);
pSurface->sendCommit(); pSurface->sendCommit();

View file

@ -17,6 +17,8 @@ class CLayerSurface {
SP<CCZwlrLayerSurfaceV1> pLayerSurface = nullptr; SP<CCZwlrLayerSurfaceV1> pLayerSurface = nullptr;
SP<CCWlSurface> pSurface = nullptr; SP<CCWlSurface> pSurface = nullptr;
SP<CCWpViewport> pViewport = nullptr;
SP<CCWpFractionalScaleV1> pFractionalScale = nullptr;
bool wantsACK = false; bool wantsACK = false;
uint32_t ACKSerial = 0; uint32_t ACKSerial = 0;

View file

@ -70,6 +70,11 @@ void CHyprpicker::init() {
} else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
m_pCursorShapeMgr = m_pCursorShapeMgr =
makeShared<CCWpCursorShapeManagerV1>((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_cursor_shape_manager_v1_interface, 1)); makeShared<CCWpCursorShapeManagerV1>((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<CCWpFractionalScaleManagerV1>((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<CCWpViewporter>((wl_proxy*)wl_registry_bind((wl_registry*)m_pRegistry->resource(), name, &wp_viewporter_interface, 1));
} }
}); });
@ -83,6 +88,15 @@ void CHyprpicker::init() {
exit(1); 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) { for (auto& m : m_vMonitors) {
m_vLayerSurfaces.emplace_back(std::make_unique<CLayerSurface>(m.get())); m_vLayerSurfaces.emplace_back(std::make_unique<CLayerSurface>(m.get()));
@ -121,6 +135,8 @@ void CHyprpicker::finish(int code) {
m_pSeat.reset(); m_pSeat.reset();
m_pKeyboard.reset(); m_pKeyboard.reset();
m_pPointer.reset(); m_pPointer.reset();
m_pViewporter.reset();
m_pFractionalMgr.reset();
wl_display_disconnect(m_pWLDisplay); wl_display_disconnect(m_pWLDisplay);
m_pWLDisplay = nullptr; m_pWLDisplay = nullptr;
@ -135,9 +151,11 @@ void CHyprpicker::recheckACK() {
ls->wantsACK = false; ls->wantsACK = false;
ls->pLayerSurface->sendAckConfigure(ls->ACKSerial); ls->pLayerSurface->sendAckConfigure(ls->ACKSerial);
if (!ls->buffers[0] || ls->buffers[0]->pixelSize != ls->m_pMonitor->size * ls->m_pMonitor->scale) { const auto MONITORSIZE = ls->screenBuffer && !g_pHyprpicker->m_bNoFractional ? ls->screenBuffer->pixelSize : ls->m_pMonitor->size * ls->m_pMonitor->scale;
ls->buffers[0] = makeShared<SPoolBuffer>(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<SPoolBuffer>(ls->m_pMonitor->size * ls->m_pMonitor->scale, WL_SHM_FORMAT_ARGB8888, ls->m_pMonitor->size.x * ls->m_pMonitor->scale * 4); if (!ls->buffers[0] || ls->buffers[0]->pixelSize != MONITORSIZE) {
ls->buffers[0] = makeShared<SPoolBuffer>(MONITORSIZE, WL_SHM_FORMAT_ARGB8888, MONITORSIZE.x * 4);
ls->buffers[1] = makeShared<SPoolBuffer>(MONITORSIZE, WL_SHM_FORMAT_ARGB8888, MONITORSIZE.x * 4);
} }
} }
} }
@ -323,8 +341,8 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
return; 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, PBUFFER->surface =
pSurface->m_pMonitor->size.y * pSurface->m_pMonitor->scale, PBUFFER->pixelSize.x * 4); 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); 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_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); cairo_fill(PCAIRO);
if (pSurface == g_pHyprpicker->m_pLastSurface && !forceInactive) { if (pSurface == m_pLastSurface && !forceInactive) {
const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize;
const auto SCALECURSOR = Vector2D{ const auto MOUSECOORDSABS = m_vLastCoords.floor() / pSurface->m_pMonitor->size;
g_pHyprpicker->m_pLastSurface->screenBuffer->pixelSize.x / (g_pHyprpicker->m_pLastSurface->buffers[0]->pixelSize.x / g_pHyprpicker->m_pLastSurface->m_pMonitor->scale), const auto CLICKPOS = MOUSECOORDSABS * PBUFFER->pixelSize;
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};
const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer->surface); const auto PATTERNPRE = cairo_pattern_create_for_surface(pSurface->screenBuffer->surface);
cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR); cairo_pattern_set_filter(PATTERNPRE, CAIRO_FILTER_BILINEAR);
@ -368,15 +384,17 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
// //
cairo_restore(PCAIRO); cairo_restore(PCAIRO);
if (!g_pHyprpicker->m_bNoZoom) { if (!m_bNoZoom) {
cairo_save(PCAIRO); 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_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_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_clip(PCAIRO);
cairo_fill(PCAIRO); cairo_fill(PCAIRO);
@ -391,12 +409,12 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
cairo_pattern_set_filter(PATTERN, CAIRO_FILTER_NEAREST); cairo_pattern_set_filter(PATTERN, CAIRO_FILTER_NEAREST);
cairo_matrix_t matrix; cairo_matrix_t matrix;
cairo_matrix_init_identity(&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_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_pattern_set_matrix(PATTERN, &matrix);
cairo_set_source(PCAIRO, PATTERN); 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_clip(PCAIRO);
cairo_paint(PCAIRO); cairo_paint(PCAIRO);
@ -406,10 +424,10 @@ void CHyprpicker::renderSurface(CLayerSurface* pSurface, bool forceInactive) {
cairo_pattern_destroy(PATTERN); cairo_pattern_destroy(PATTERN);
} }
} else if (!g_pHyprpicker->m_bRenderInactive) { } else if (!m_bRenderInactive) {
cairo_set_operator(PCAIRO, CAIRO_OPERATOR_SOURCE); cairo_set_operator(PCAIRO, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(PCAIRO, 0, 0, 0, 0); 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); cairo_fill(PCAIRO);
} else { } else {
const auto SCALEBUFS = pSurface->screenBuffer->pixelSize / PBUFFER->pixelSize; 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); }; 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 // 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), const auto MOUSECOORDSABS = m_vLastCoords.floor() / m_pLastSurface->m_pMonitor->size;
m_pLastSurface->screenBuffer->pixelSize.y / (m_pLastSurface->buffers[0]->pixelSize.y / m_pLastSurface->m_pMonitor->scale)}; const auto CLICKPOS = MOUSECOORDSABS * m_pLastSurface->screenBuffer->pixelSize;
const auto CLICKPOS = m_vLastCoords.floor() * SCALE;
const auto COL = getColorFromPixel(m_pLastSurface, CLICKPOS); const auto COL = getColorFromPixel(m_pLastSurface, CLICKPOS);

View file

@ -28,6 +28,8 @@ class CHyprpicker {
SP<CCWlSeat> m_pSeat; SP<CCWlSeat> m_pSeat;
SP<CCWlKeyboard> m_pKeyboard; SP<CCWlKeyboard> m_pKeyboard;
SP<CCWlPointer> m_pPointer; SP<CCWlPointer> m_pPointer;
SP<CCWpFractionalScaleManagerV1> m_pFractionalMgr;
SP<CCWpViewporter> m_pViewporter;
wl_display* m_pWLDisplay = nullptr; wl_display* m_pWLDisplay = nullptr;
xkb_context* m_pXKBContext = nullptr; xkb_context* m_pXKBContext = nullptr;
@ -41,6 +43,7 @@ class CHyprpicker {
bool m_bAutoCopy = false; bool m_bAutoCopy = false;
bool m_bRenderInactive = false; bool m_bRenderInactive = false;
bool m_bNoZoom = false; bool m_bNoZoom = false;
bool m_bNoFractional = false;
bool m_bRunning = true; bool m_bRunning = true;

View file

@ -11,7 +11,10 @@ static void help(void) {
<< " -n | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n" << " -n | --no-fancy | Disables the \"fancy\" (aka. colored) outputting\n"
<< " -h | --help | Show this help message\n" << " -h | --help | Show this help message\n"
<< " -r | --render-inactive | Render (freeze) inactive displays\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) { 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'}, {"no-fancy", no_argument, NULL, 'n'},
{"render-inactive", no_argument, NULL, 'r'}, {"render-inactive", no_argument, NULL, 'r'},
{"no-zoom", no_argument, NULL, 'z'}, {"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}}; {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) if (c == -1)
break; break;
@ -53,6 +59,9 @@ int main(int argc, char** argv, char** envp) {
case 'a': g_pHyprpicker->m_bAutoCopy = true; break; case 'a': g_pHyprpicker->m_bAutoCopy = true; break;
case 'r': g_pHyprpicker->m_bRenderInactive = true; break; case 'r': g_pHyprpicker->m_bRenderInactive = true; break;
case 'z': g_pHyprpicker->m_bNoZoom = 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); default: help(); exit(1);
} }