diff --git a/src/plugins/zoom/CMakeLists.txt b/src/plugins/zoom/CMakeLists.txt index c27bdbbb2d..b5fb343e17 100644 --- a/src/plugins/zoom/CMakeLists.txt +++ b/src/plugins/zoom/CMakeLists.txt @@ -4,6 +4,7 @@ set(zoom_SOURCES main.cpp zoom.cpp + zoom.qrc ) if (HAVE_ACCESSIBILITY) diff --git a/src/plugins/zoom/shaders/pixelgrid.frag b/src/plugins/zoom/shaders/pixelgrid.frag new file mode 100644 index 0000000000..1e9ee9431f --- /dev/null +++ b/src/plugins/zoom/shaders/pixelgrid.frag @@ -0,0 +1,25 @@ +#include "colormanagement.glsl" + +uniform sampler2D sampler; +uniform int textureWidth; +uniform int textureHeight; + +varying vec2 texcoord0; + +void main() +{ + vec2 texSize = vec2(textureWidth, textureHeight); + vec2 samplePosition = texcoord0 * texSize; + vec2 pixelCenter = floor(samplePosition) + vec2(0.5); + vec2 pixelCenterDistance = abs(samplePosition - pixelCenter); + + vec4 tex; + if (pixelCenterDistance.x > 0.4 || pixelCenterDistance.y > 0.4) { + tex = vec4(0, 0, 0, 1); + } else { + tex = texture2D(sampler, pixelCenter / texSize); + } + + tex = sourceEncodingToNitsInDestinationColorspace(tex); + gl_FragColor = nitsToDestinationEncoding(tex); +} diff --git a/src/plugins/zoom/shaders/pixelgrid_core.frag b/src/plugins/zoom/shaders/pixelgrid_core.frag new file mode 100644 index 0000000000..a1cc7f27f2 --- /dev/null +++ b/src/plugins/zoom/shaders/pixelgrid_core.frag @@ -0,0 +1,24 @@ +#version 140 + +#include "colormanagement.glsl" + +uniform sampler2D sampler; +uniform int textureWidth; +uniform int textureHeight; + +in vec2 texcoord0; + +out vec4 fragColor; + +void main() +{ + vec2 texSize = vec2(textureWidth, textureHeight); + vec2 samplePosition = texcoord0 * texSize; + vec2 pixelCenter = floor(samplePosition) + vec2(0.5); + vec2 pixelCenterDistance = abs(samplePosition - pixelCenter); + + float t = smoothstep(0.4, 0.5, max(pixelCenterDistance.x, pixelCenterDistance.y)); + vec4 tex = mix(texture(sampler, pixelCenter / texSize), vec4(0, 0, 0, 1), t); + tex = sourceEncodingToNitsInDestinationColorspace(tex); + fragColor = nitsToDestinationEncoding(tex); +} diff --git a/src/plugins/zoom/ui_zoom_config.h b/src/plugins/zoom/ui_zoom_config.h new file mode 100644 index 0000000000..7e5944a902 --- /dev/null +++ b/src/plugins/zoom/ui_zoom_config.h @@ -0,0 +1,195 @@ +/******************************************************************************** +** Form generated from reading UI file 'zoom_config.ui' +** +** Created by: Qt User Interface Compiler version 6.8.1 +** +** WARNING! All changes made in this file will be lost when recompiling UI file! +********************************************************************************/ + +#ifndef UI_ZOOM_CONFIG_H +#define UI_ZOOM_CONFIG_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kshortcutseditor.h" + +namespace KWin { + +class Ui_ZoomEffectConfigForm +{ +public: + QVBoxLayout *verticalLayout_2; + QGroupBox *groupSize; + QHBoxLayout *horizontalLayout; + QGridLayout *gridLayout; + QLabel *label; + QDoubleSpinBox *kcfg_ZoomFactor; + QCheckBox *kcfg_EnableFocusTracking; + QCheckBox *kcfg_EnableTextCaretTracking; + QLabel *label_2; + QComboBox *kcfg_MousePointer; + QComboBox *kcfg_MouseTracking; + QLabel *label_3; + KShortcutsEditor *editor; + + void setupUi(QWidget *KWin__ZoomEffectConfigForm) + { + if (KWin__ZoomEffectConfigForm->objectName().isEmpty()) + KWin__ZoomEffectConfigForm->setObjectName("KWin__ZoomEffectConfigForm"); + KWin__ZoomEffectConfigForm->resize(304, 288); + verticalLayout_2 = new QVBoxLayout(KWin__ZoomEffectConfigForm); + verticalLayout_2->setObjectName("verticalLayout_2"); + groupSize = new QGroupBox(KWin__ZoomEffectConfigForm); + groupSize->setObjectName("groupSize"); + horizontalLayout = new QHBoxLayout(groupSize); + horizontalLayout->setObjectName("horizontalLayout"); + gridLayout = new QGridLayout(); + gridLayout->setObjectName("gridLayout"); + label = new QLabel(groupSize); + label->setObjectName("label"); + label->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + + gridLayout->addWidget(label, 0, 0, 1, 1); + + kcfg_ZoomFactor = new QDoubleSpinBox(groupSize); + kcfg_ZoomFactor->setObjectName("kcfg_ZoomFactor"); + kcfg_ZoomFactor->setDecimals(2); + kcfg_ZoomFactor->setMaximum(9999.000000000000000); + kcfg_ZoomFactor->setSingleStep(0.050000000000000); + kcfg_ZoomFactor->setValue(1.250000000000000); + + gridLayout->addWidget(kcfg_ZoomFactor, 0, 1, 1, 1); + + kcfg_EnableFocusTracking = new QCheckBox(groupSize); + kcfg_EnableFocusTracking->setObjectName("kcfg_EnableFocusTracking"); + + gridLayout->addWidget(kcfg_EnableFocusTracking, 4, 0, 1, 2); + + kcfg_EnableTextCaretTracking = new QCheckBox(groupSize); + kcfg_EnableTextCaretTracking->setObjectName("kcfg_EnableTextCaretTracking"); + + gridLayout->addWidget(kcfg_EnableTextCaretTracking, 5, 0, 1, 2); + + label_2 = new QLabel(groupSize); + label_2->setObjectName("label_2"); + label_2->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + + gridLayout->addWidget(label_2, 2, 0, 1, 1); + + kcfg_MousePointer = new QComboBox(groupSize); + kcfg_MousePointer->addItem(QString()); + kcfg_MousePointer->addItem(QString()); + kcfg_MousePointer->addItem(QString()); + kcfg_MousePointer->setObjectName("kcfg_MousePointer"); + + gridLayout->addWidget(kcfg_MousePointer, 2, 1, 1, 1); + + kcfg_MouseTracking = new QComboBox(groupSize); + kcfg_MouseTracking->addItem(QString()); + kcfg_MouseTracking->addItem(QString()); + kcfg_MouseTracking->addItem(QString()); + kcfg_MouseTracking->addItem(QString()); + kcfg_MouseTracking->setObjectName("kcfg_MouseTracking"); + + gridLayout->addWidget(kcfg_MouseTracking, 3, 1, 1, 1); + + label_3 = new QLabel(groupSize); + label_3->setObjectName("label_3"); + label_3->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter); + + gridLayout->addWidget(label_3, 3, 0, 1, 1); + + + horizontalLayout->addLayout(gridLayout); + + + verticalLayout_2->addWidget(groupSize); + + editor = new KShortcutsEditor(KWin__ZoomEffectConfigForm); + editor->setObjectName("editor"); + QSizePolicy sizePolicy(QSizePolicy::Policy::Preferred, QSizePolicy::Policy::Expanding); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(editor->sizePolicy().hasHeightForWidth()); + editor->setSizePolicy(sizePolicy); + editor->setActionTypes(KShortcutsEditor::GlobalAction); + + verticalLayout_2->addWidget(editor); + +#if QT_CONFIG(shortcut) + label->setBuddy(kcfg_ZoomFactor); + label_2->setBuddy(kcfg_MousePointer); + label_3->setBuddy(kcfg_MouseTracking); +#endif // QT_CONFIG(shortcut) + QWidget::setTabOrder(kcfg_ZoomFactor, kcfg_MousePointer); + QWidget::setTabOrder(kcfg_MousePointer, kcfg_MouseTracking); + QWidget::setTabOrder(kcfg_MouseTracking, kcfg_EnableFocusTracking); + QWidget::setTabOrder(kcfg_EnableFocusTracking, kcfg_EnableTextCaretTracking); + + retranslateUi(KWin__ZoomEffectConfigForm); + + QMetaObject::connectSlotsByName(KWin__ZoomEffectConfigForm); + } // setupUi + + void retranslateUi(QWidget *KWin__ZoomEffectConfigForm) + { + groupSize->setTitle(QString()); +#if QT_CONFIG(whatsthis) + label->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "On zoom-in and zoom-out change the zoom by the defined zoom-factor.", nullptr)); +#endif // QT_CONFIG(whatsthis) + label->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Zoom Factor:", nullptr)); +#if QT_CONFIG(whatsthis) + kcfg_ZoomFactor->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "On zoom-in and zoom-out change the zoom by the defined zoom-factor.", nullptr)); +#endif // QT_CONFIG(whatsthis) + kcfg_ZoomFactor->setSuffix(QString()); +#if QT_CONFIG(tooltip) + kcfg_EnableFocusTracking->setToolTip(QString()); +#endif // QT_CONFIG(tooltip) +#if QT_CONFIG(whatsthis) + kcfg_EnableFocusTracking->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable tracking of the focused location. This needs QAccessible to be enabled per application (\"export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1\").", nullptr)); +#endif // QT_CONFIG(whatsthis) + kcfg_EnableFocusTracking->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable Focus Tracking", nullptr)); +#if QT_CONFIG(whatsthis) + kcfg_EnableTextCaretTracking->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable tracking of the text cursor. This needs QAccessible to be enabled per application (\"export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1\").", nullptr)); +#endif // QT_CONFIG(whatsthis) + kcfg_EnableTextCaretTracking->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Enable Text Cursor Tracking", nullptr)); + label_2->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Mouse Pointer:", nullptr)); + kcfg_MousePointer->setItemText(0, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Scale", nullptr)); + kcfg_MousePointer->setItemText(1, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Keep", nullptr)); + kcfg_MousePointer->setItemText(2, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Hide", nullptr)); + +#if QT_CONFIG(whatsthis) + kcfg_MousePointer->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Visibility of the mouse-pointer.", nullptr)); +#endif // QT_CONFIG(whatsthis) + kcfg_MouseTracking->setItemText(0, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Proportional", nullptr)); + kcfg_MouseTracking->setItemText(1, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Centered", nullptr)); + kcfg_MouseTracking->setItemText(2, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Push", nullptr)); + kcfg_MouseTracking->setItemText(3, QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Disabled", nullptr)); + +#if QT_CONFIG(whatsthis) + kcfg_MouseTracking->setWhatsThis(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Track moving of the mouse.", nullptr)); +#endif // QT_CONFIG(whatsthis) + label_3->setText(QCoreApplication::translate("KWin::ZoomEffectConfigForm", "Mouse Tracking:", nullptr)); + (void)KWin__ZoomEffectConfigForm; + } // retranslateUi + +}; + +} // namespace KWin + +namespace KWin { +namespace Ui { + class ZoomEffectConfigForm: public Ui_ZoomEffectConfigForm {}; +} // namespace Ui +} // namespace KWin + +#endif // UI_ZOOM_CONFIG_H diff --git a/src/plugins/zoom/zoom.cpp b/src/plugins/zoom/zoom.cpp index a6eb528767..950583c15b 100644 --- a/src/plugins/zoom/zoom.cpp +++ b/src/plugins/zoom/zoom.cpp @@ -31,6 +31,12 @@ using namespace std::chrono_literals; +static void ensureResources() +{ + // Must initialize resources manually because the effect is a static lib. + Q_INIT_RESOURCE(zoom); +} + namespace KWin { @@ -48,6 +54,8 @@ ZoomEffect::ZoomEffect() , moveFactor(20.0) , lastPresentTime(std::chrono::milliseconds::zero()) { + ensureResources(); + ZoomConfig::instance(effects->config()); QAction *a = nullptr; a = KStandardAction::zoomIn(this, SLOT(zoomIn()), this); @@ -214,6 +222,7 @@ void ZoomEffect::reconfigure(ReconfigureFlags) ZoomConfig::self()->read(); // On zoom-in and zoom-out change the zoom by the defined zoom-factor. zoomFactor = std::max(0.1, ZoomConfig::zoomFactor()); + m_pixelGridZoom = ZoomConfig::pixelGridZoom(); // Visibility of the mouse-pointer. mousePointer = MousePointerType(ZoomConfig::mousePointer()); // Track moving of the mouse. @@ -271,12 +280,10 @@ void ZoomEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseco ZoomEffect::OffscreenData *ZoomEffect::ensureOffscreenData(const RenderTarget &renderTarget, const RenderViewport &viewport, Output *screen) { - const QRect rect = viewport.renderRect().toRect(); - const qreal devicePixelRatio = viewport.scale(); - const QSize nativeSize = (viewport.renderRect().size() * devicePixelRatio).toSize(); + const QSize nativeSize = renderTarget.size(); OffscreenData &data = m_offscreenData[effects->waylandDisplay() ? screen : nullptr]; - data.viewport = rect; + data.viewport = viewport.renderRect(); data.color = renderTarget.colorDescription(); const GLenum textureFormat = renderTarget.colorDescription() == ColorDescription::sRGB ? GL_RGBA8 : GL_RGBA16F; @@ -290,9 +297,22 @@ ZoomEffect::OffscreenData *ZoomEffect::ensureOffscreenData(const RenderTarget &r data.framebuffer = std::make_unique(data.texture.get()); } + data.texture->setContentTransform(renderTarget.transform()); return &data; } +GLShader *ZoomEffect::shaderForZoom(double zoom) +{ + if (zoom < m_pixelGridZoom) { + return ShaderManager::instance()->shader(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace); + } else { + if (!m_pixelGridShader) { + m_pixelGridShader = ShaderManager::instance()->generateShaderFromFile(ShaderTrait::MapTexture, QString(), QStringLiteral(":/effects/zoom/shaders/pixelgrid.frag")); + } + return m_pixelGridShader.get(); + } +} + void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen) { OffscreenData *offscreenData = ensureOffscreenData(renderTarget, viewport, screen); @@ -391,7 +411,8 @@ void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewp glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); - auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture | ShaderTrait::TransformColorspace); + GLShader *shader = shaderForZoom(zoom); + ShaderManager::instance()->pushShader(shader); for (auto &[screen, offscreen] : m_offscreenData) { QMatrix4x4 matrix; matrix.translate(xTranslation * scale, yTranslation * scale); @@ -399,6 +420,8 @@ void ZoomEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewp matrix.translate(offscreen.viewport.x() * scale, offscreen.viewport.y() * scale); shader->setUniform(GLShader::Mat4Uniform::ModelViewProjectionMatrix, viewport.projectionMatrix() * matrix); + shader->setUniform(GLShader::IntUniform::TextureWidth, offscreen.texture->width()); + shader->setUniform(GLShader::IntUniform::TextureHeight, offscreen.texture->height()); shader->setColorspaceUniforms(offscreen.color, renderTarget.colorDescription(), RenderingIntent::Perceptual); offscreen.texture->render(offscreen.viewport.size() * scale); diff --git a/src/plugins/zoom/zoom.h b/src/plugins/zoom/zoom.h index 2a44395d74..1c9abb4b4e 100644 --- a/src/plugins/zoom/zoom.h +++ b/src/plugins/zoom/zoom.h @@ -26,6 +26,7 @@ class ZoomAccessibilityIntegration; class GLFramebuffer; class GLTexture; class GLVertexBuffer; +class GLShader; class ZoomEffect : public Effect @@ -94,7 +95,7 @@ private: { std::unique_ptr texture; std::unique_ptr framebuffer; - QRect viewport; + QRectF viewport; ColorDescription color = ColorDescription::sRGB; }; @@ -102,6 +103,8 @@ private: OffscreenData *ensureOffscreenData(const RenderTarget &renderTarget, const RenderViewport &viewport, Output *screen); void markCursorTextureDirty(); + GLShader *shaderForZoom(double zoom); + #if HAVE_ACCESSIBILITY ZoomAccessibilityIntegration *m_accessibilityIntegration = nullptr; #endif @@ -136,6 +139,8 @@ private: double moveFactor; std::chrono::milliseconds lastPresentTime; std::map m_offscreenData; + std::unique_ptr m_pixelGridShader; + double m_pixelGridZoom; }; } // namespace diff --git a/src/plugins/zoom/zoom.kcfg b/src/plugins/zoom/zoom.kcfg index 63887e32aa..ed43e225c8 100644 --- a/src/plugins/zoom/zoom.kcfg +++ b/src/plugins/zoom/zoom.kcfg @@ -29,5 +29,8 @@ 1.0 + + 15.0 + diff --git a/src/plugins/zoom/zoom.qrc b/src/plugins/zoom/zoom.qrc new file mode 100644 index 0000000000..56e7369003 --- /dev/null +++ b/src/plugins/zoom/zoom.qrc @@ -0,0 +1,6 @@ + + + shaders/pixelgrid.frag + shaders/pixelgrid_core.frag + + diff --git a/src/plugins/zoom/zoom_config.ui b/src/plugins/zoom/zoom_config.ui index 454f9f9161..4b8a5c000e 100644 --- a/src/plugins/zoom/zoom_config.ui +++ b/src/plugins/zoom/zoom_config.ui @@ -6,159 +6,157 @@ 0 0 - 304 - 288 + 595 + 551 - - - + + + Qt::AlignHCenter|Qt::AlignTop - - - - - - - On zoom-in and zoom-out change the zoom by the defined zoom-factor. - - - Zoom Factor: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_ZoomFactor - - - - - - - On zoom-in and zoom-out change the zoom by the defined zoom-factor. - - - - - - 2 - - - 9999.000000000000000 - - - 0.050000000000000 - - - 1.250000000000000 - - - - - - - - - - Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1"). - - - Enable Focus Tracking - - - - - - - Enable tracking of the text cursor. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1"). - - - Enable Text Cursor Tracking - - - - - - - Mouse Pointer: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_MousePointer - - - - - - - Visibility of the mouse-pointer. - - - - Scale - - - - - Keep - - - - - Hide - - - - - - - - Track moving of the mouse. - - - - Proportional - - - - - Centered - - - - - Push - - - - - Disabled - - - - - - - - Mouse Tracking: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - kcfg_MouseTracking - - - - - - - + + + + On zoom-in and zoom-out change the zoom by the defined zoom-factor. + + + Zoom factor: + + + kcfg_ZoomFactor + + + + + + + On zoom-in and zoom-out change the zoom by the defined zoom-factor. + + + + + + 2 + + + 9999.000000000000000 + + + 0.050000000000000 + + + 1.250000000000000 + + + + + + + Show pixel grid at zoom level: + + + kcfg_PixelGridZoom + + + + + + + + + + Mouse pointer: + + + kcfg_MousePointer + + + + + + + Visibility of the mouse-pointer. + + + + Scale + + + + + Keep + + + + + Hide + + + + + + + + Mouse tracking: + + + kcfg_MouseTracking + + + + + + + Track moving of the mouse. + + + + Proportional + + + + + Centered + + + + + Push + + + + + Disabled + + + + + + + + + + + Enable tracking of the focused location. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1"). + + + Enable focus tracking + + + + + + + Enable tracking of the text cursor. This needs QAccessible to be enabled per application ("export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1"). + + + Enable text cursor tracking + + + + @@ -183,13 +181,6 @@ 1 - - kcfg_ZoomFactor - kcfg_MousePointer - kcfg_MouseTracking - kcfg_EnableFocusTracking - kcfg_EnableTextCaretTracking -