13#include "zoomconfig.h"
19#include <KConfigGroup>
20#include <KGlobalAccel>
21#include <KLocalizedString>
25#include <kstandardaction.h>
41 , mouseTracking(MouseTrackingProportional)
42 , mousePointer(MousePointerScale)
44 , isMouseHidden(false)
48 , lastPresentTime(std::chrono::milliseconds::zero())
52 a = KStandardAction::zoomIn(
this, SLOT(zoomIn()),
this);
53 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_Plus) << (Qt::META | Qt::Key_Equal));
54 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_Plus) << (Qt::META | Qt::Key_Equal));
57 a = KStandardAction::zoomOut(
this, SLOT(zoomOut()),
this);
58 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_Minus));
59 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_Minus));
62 a = KStandardAction::actualSize(
this, SLOT(actualSize()),
this);
63 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_0));
64 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_0));
66 a =
new QAction(
this);
67 a->setObjectName(QStringLiteral(
"MoveZoomLeft"));
68 a->setText(i18n(
"Move Zoomed Area to Left"));
69 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>());
70 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>());
71 connect(a, &QAction::triggered,
this, &ZoomEffect::moveZoomLeft);
73 a =
new QAction(
this);
74 a->setObjectName(QStringLiteral(
"MoveZoomRight"));
75 a->setText(i18n(
"Move Zoomed Area to Right"));
76 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>());
77 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>());
78 connect(a, &QAction::triggered,
this, &ZoomEffect::moveZoomRight);
80 a =
new QAction(
this);
81 a->setObjectName(QStringLiteral(
"MoveZoomUp"));
82 a->setText(i18n(
"Move Zoomed Area Upwards"));
83 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>());
84 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>());
85 connect(a, &QAction::triggered,
this, &ZoomEffect::moveZoomUp);
87 a =
new QAction(
this);
88 a->setObjectName(QStringLiteral(
"MoveZoomDown"));
89 a->setText(i18n(
"Move Zoomed Area Downwards"));
90 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>());
91 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>());
92 connect(a, &QAction::triggered,
this, &ZoomEffect::moveZoomDown);
95 a =
new QAction(
this);
96 a->setObjectName(QStringLiteral(
"MoveMouseToFocus"));
97 a->setText(i18n(
"Move Mouse to Focus"));
98 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_F5));
99 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_F5));
100 connect(a, &QAction::triggered,
this, &ZoomEffect::moveMouseToFocus);
102 a =
new QAction(
this);
103 a->setObjectName(QStringLiteral(
"MoveMouseToCenter"));
104 a->setText(i18n(
"Move Mouse to Center"));
105 KGlobalAccel::self()->setDefaultShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_F6));
106 KGlobalAccel::self()->setShortcut(a, QList<QKeySequence>() << (Qt::META | Qt::Key_F6));
107 connect(a, &QAction::triggered,
this, &ZoomEffect::moveMouseToCenter);
109 timeline.setDuration(350);
110 timeline.setFrameRange(0, 100);
111 connect(&timeline, &QTimeLine::frameChanged,
this, &ZoomEffect::timelineFrameChanged);
116#if HAVE_ACCESSIBILITY
138 ZoomConfig::setInitialZoom(target_zoom);
139 ZoomConfig::self()->save();
144#if HAVE_ACCESSIBILITY
145 return m_accessibilityIntegration && m_accessibilityIntegration->isFocusTrackingEnabled();
153#if HAVE_ACCESSIBILITY
154 return m_accessibilityIntegration && m_accessibilityIntegration->isTextCaretTrackingEnabled();
160GLTexture *ZoomEffect::ensureCursorTexture()
162 if (!m_cursorTexture || m_cursorTextureDirty) {
163 m_cursorTexture.reset();
164 m_cursorTextureDirty =
false;
166 if (!cursor.image().isNull()) {
168 if (!m_cursorTexture) {
171 m_cursorTexture->setWrapMode(GL_CLAMP_TO_EDGE);
174 return m_cursorTexture.get();
177void ZoomEffect::markCursorTextureDirty()
179 m_cursorTextureDirty =
true;
182void ZoomEffect::showCursor()
188 m_cursorTexture.reset();
189 isMouseHidden =
false;
193void ZoomEffect::hideCursor()
198 if (!isMouseHidden) {
200 GLTexture *texture =
nullptr;
202 texture = ensureCursorTexture();
207 isMouseHidden =
true;
214 ZoomConfig::self()->read();
216 zoomFactor = std::max(0.1, ZoomConfig::zoomFactor());
218 mousePointer = MousePointerType(ZoomConfig::mousePointer());
220 mouseTracking = MouseTrackingType(ZoomConfig::mouseTracking());
221#if HAVE_ACCESSIBILITY
222 if (m_accessibilityIntegration) {
224 m_accessibilityIntegration->setFocusTrackingEnabled(ZoomConfig::enableFocusTracking());
226 m_accessibilityIntegration->setTextCaretTrackingEnabled(ZoomConfig::enableTextCaretTracking());
230 focusDelay = std::max(uint(0), ZoomConfig::focusDelay());
232 moveFactor = std::max(0.1, ZoomConfig::moveFactor());
233 if (source_zoom < 0) {
236 target_zoom = ZoomConfig::initialZoom();
237 if (target_zoom > 1.0) {
247 if (zoom != target_zoom) {
249 if (lastPresentTime.count()) {
250 time = (presentTime - lastPresentTime).count();
252 lastPresentTime = presentTime;
254 const float zoomDist = std::abs(target_zoom - source_zoom);
255 if (target_zoom > zoom) {
273 const QRect rect = viewport.
renderRect().toRect();
274 const qreal devicePixelRatio = viewport.
scale();
275 const QSize nativeSize = (viewport.
renderRect().size() * devicePixelRatio).toSize();
278 data.viewport = rect;
281 if (!data.texture || data.texture->size() != nativeSize || data.texture->internalFormat() != textureFormat) {
286 data.texture->setFilter(GL_LINEAR);
287 data.texture->setWrapMode(GL_CLAMP_TO_EDGE);
288 data.framebuffer = std::make_unique<GLFramebuffer>(data.texture.get());
296 OffscreenData *offscreenData = ensureOffscreenData(renderTarget, viewport, screen);
297 if (!offscreenData) {
309 const auto scale = viewport.
scale();
312 qreal xTranslation = 0;
313 qreal yTranslation = 0;
315 case MouseTrackingProportional:
316 xTranslation = -int(cursorPoint.x() * (zoom - 1.0));
317 yTranslation = -int(cursorPoint.y() * (zoom - 1.0));
318 prevPoint = cursorPoint;
320 case MouseTrackingCentred:
321 prevPoint = cursorPoint;
323 case MouseTrackingDisabled:
324 xTranslation = std::min(0, std::max(
int(screenSize.width() - screenSize.width() * zoom),
int(screenSize.width() / 2 - prevPoint.x() * zoom)));
325 yTranslation = std::min(0, std::max(
int(screenSize.height() - screenSize.height() * zoom),
int(screenSize.height() / 2 - prevPoint.y() * zoom)));
327 case MouseTrackingPush: {
329 int x = cursorPoint.x() * zoom - prevPoint.x() * (zoom - 1.0);
330 int y = cursorPoint.y() * zoom - prevPoint.y() * (zoom - 1.0);
334 xMove = (x - threshold) / zoom;
335 }
else if (x + threshold > screenSize.width()) {
336 xMove = (x + threshold - screenSize.width()) / zoom;
339 yMove = (y - threshold) / zoom;
340 }
else if (y + threshold > screenSize.height()) {
341 yMove = (y + threshold - screenSize.height()) / zoom;
344 prevPoint.setX(std::max(0, std::min(screenSize.width(), prevPoint.x() + xMove)));
347 prevPoint.setY(std::max(0, std::min(screenSize.height(), prevPoint.y() + yMove)));
349 xTranslation = -int(prevPoint.x() * (zoom - 1.0));
350 yTranslation = -int(prevPoint.y() * (zoom - 1.0));
357 bool acceptFocus =
true;
361 const int msecs = lastMouseEvent.msecsTo(lastFocusEvent);
365 xTranslation = -int(focusPoint.x() * (zoom - 1.0));
366 yTranslation = -int(focusPoint.y() * (zoom - 1.0));
367 prevPoint = focusPoint;
372 glClearColor(0.0, 0.0, 0.0, 0.0);
373 glClear(GL_COLOR_BUFFER_BIT);
376 for (
auto &[screen, offscreen] : m_offscreenData) {
378 matrix.translate(xTranslation * scale, yTranslation * scale);
379 matrix.scale(zoom, zoom);
380 matrix.translate(offscreen.viewport.x() * scale, offscreen.viewport.y() * scale);
384 offscreen.texture->render(offscreen.viewport.size() * scale);
393 GLTexture *cursorTexture = ensureCursorTexture();
396 QSizeF cursorSize = QSizeF(cursor.image().size()) / cursor.
image().devicePixelRatio();
401 const QPointF p = (
effects->
cursorPos() - cursor.hotSpot()) * zoom + QPoint(xTranslation, yTranslation);
404 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
408 mvp.translate(p.x() * scale, p.y() * scale);
410 cursorTexture->
render(cursorSize * scale);
419 if (zoom == target_zoom) {
420 lastPresentTime = std::chrono::milliseconds::zero();
423 if (zoom == 1.0 || zoom != target_zoom) {
431void ZoomEffect::zoomIn(
double to)
445 prevPoint = cursorPoint;
450void ZoomEffect::zoomOut()
454 if ((
zoomFactor > 1 && target_zoom < 1.01) || (zoomFactor < 1 && target_zoom > 0.99)) {
467void ZoomEffect::actualSize()
478void ZoomEffect::timelineFrameChanged(
int )
481 prevPoint.setX(std::max(0, std::min(screenSize.width(), prevPoint.x() + xMove)));
482 prevPoint.setY(std::max(0, std::min(screenSize.height(), prevPoint.y() + yMove)));
483 cursorPoint = prevPoint;
487void ZoomEffect::moveZoom(
int x,
int y)
489 if (timeline.state() == QTimeLine::Running) {
495 xMove = -std::max(1.0, screenSize.width() / zoom /
moveFactor);
497 xMove = std::max(1.0, screenSize.width() / zoom /
moveFactor);
503 yMove = -std::max(1.0, screenSize.height() / zoom /
moveFactor);
505 yMove = std::max(1.0, screenSize.height() / zoom /
moveFactor);
513void ZoomEffect::moveZoomLeft()
518void ZoomEffect::moveZoomRight()
523void ZoomEffect::moveZoomUp()
528void ZoomEffect::moveZoomDown()
533void ZoomEffect::moveMouseToFocus()
535 QCursor::setPos(focusPoint.x(), focusPoint.y());
538void ZoomEffect::moveMouseToCenter()
541 QCursor::setPos(r.x() + r.width() / 2, r.y() + r.height() / 2);
544void ZoomEffect::slotMouseChanged(
const QPointF &pos,
const QPointF &old, Qt::MouseButtons,
545 Qt::MouseButtons, Qt::KeyboardModifiers, Qt::KeyboardModifiers)
550 cursorPoint = pos.toPoint();
552 lastMouseEvent = QTime::currentTime();
557void ZoomEffect::slotWindowAdded(EffectWindow *w)
562void ZoomEffect::slotWindowDamaged()
569void ZoomEffect::slotScreenRemoved(Output *screen)
571 if (
auto it = m_offscreenData.find(screen); it != m_offscreenData.end()) {
573 m_offscreenData.erase(it);
577void ZoomEffect::moveFocus(
const QPoint &point)
583 lastFocusEvent = QTime::currentTime();
589 return zoom != 1.0 || zoom != target_zoom;
629#include "moc_zoom.cpp"
static const ColorDescription sRGB
Base class for all KWin effects.
Representation of a window used by/for Effect classes.
void windowDamaged(KWin::EffectWindow *w)
Display * waylandDisplay() const
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen)
void screenRemoved(KWin::Output *screen)
QList< EffectWindow * > stackingOrder
bool makeOpenGLContextCurrent()
Makes the OpenGL compositing context current.
void registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action)
Registers a global axis shortcut with the provided action.
QRect virtualScreenGeometry
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
bool isOpenGLCompositing() const
Whether the Compositor is OpenGL based (either GL 1 or 2).
void cursorShapeChanged()
void mouseChanged(const QPointF &pos, const QPointF &oldpos, Qt::MouseButtons buttons, Qt::MouseButtons oldbuttons, Qt::KeyboardModifiers modifiers, Qt::KeyboardModifiers oldmodifiers)
PlatformCursorImage cursorImage() const
KSharedConfigPtr config() const
void windowAdded(KWin::EffectWindow *w)
Q_SCRIPTABLE void addRepaintFull()
static GLFramebuffer * popFramebuffer()
static void pushFramebuffer(GLFramebuffer *fbo)
bool setColorspaceUniformsFromSRGB(const ColorDescription &dst)
@ ModelViewProjectionMatrix
bool setUniform(const char *name, float value)
static std::unique_ptr< GLTexture > allocate(GLenum internalFormat, const QSize &size, int levels=1)
static std::unique_ptr< GLTexture > upload(const QImage &image)
void render(const QSizeF &size)
const ColorDescription & colorDescription() const
QMatrix4x4 projectionMatrix() const
QRectF renderRect() const
static ShaderManager * instance()
GLShader * pushShader(ShaderTraits traits)
void focusPointChanged(const QPoint &point)
qreal configuredMoveFactor() const
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion ®ion, Output *screen) override
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override
void reconfigure(ReconfigureFlags flags) override
int configuredFocusDelay() const
int configuredMousePointer() const
int configuredMouseTracking() const
int requestedEffectChainPosition() const override
bool isActive() const override
void postPaintScreen() override
bool isFocusTrackingEnabled() const
bool isTextCaretTrackingEnabled() const
qreal configuredZoomFactor() const
static double animationTime(const KConfigGroup &cfg, const QString &key, int defaultTime)