From 1f5e3b1d3f9339612ba1bc3d77dba4d091f34dd3 Mon Sep 17 00:00:00 2001
From: wheaney <42350981+wheaney@users.noreply.github.com>
Date: Wed, 20 Aug 2025 17:05:50 -0700
Subject: [PATCH] Add Zoom on Focus shortcut support
---
kwin/src/breezydesktopconfig.kcfg | 5 +
kwin/src/breezydesktopconfig.kcfgc | 1 +
kwin/src/breezydesktopeffect.cpp | 30 +++--
kwin/src/breezydesktopeffect.h | 6 +
kwin/src/kcm/breezydesktopeffectkcm.cpp | 31 ++++-
kwin/src/kcm/breezydesktopeffectkcm.h | 8 ++
kwin/src/kcm/breezydesktopeffectkcm.ui | 150 +++++++++++++-----------
kwin/src/kcm/shortcuts.h | 6 +
kwin/src/qml/BreezyDesktop.qml | 26 ++--
9 files changed, 174 insertions(+), 89 deletions(-)
diff --git a/kwin/src/breezydesktopconfig.kcfg b/kwin/src/breezydesktopconfig.kcfg
index 5164008..f986f19 100644
--- a/kwin/src/breezydesktopconfig.kcfg
+++ b/kwin/src/breezydesktopconfig.kcfg
@@ -17,5 +17,10 @@
250
+
+ false
+
+ Enable zooming in on the focused display.
+
diff --git a/kwin/src/breezydesktopconfig.kcfgc b/kwin/src/breezydesktopconfig.kcfgc
index 4f16263..f1666fe 100644
--- a/kwin/src/breezydesktopconfig.kcfgc
+++ b/kwin/src/breezydesktopconfig.kcfgc
@@ -2,3 +2,4 @@ File=breezydesktopconfig.kcfg
ClassName=BreezyDesktopConfig
Singleton=true
Mutators=true
+Notifiers=true
\ No newline at end of file
diff --git a/kwin/src/breezydesktopeffect.cpp b/kwin/src/breezydesktopeffect.cpp
index dede417..54607f6 100644
--- a/kwin/src/breezydesktopeffect.cpp
+++ b/kwin/src/breezydesktopeffect.cpp
@@ -82,6 +82,10 @@ BreezyDesktopEffect::BreezyDesktopEffect()
BreezyShortcuts::RECENTER,
[this]() { this->recenter(); }
);
+ setupGlobalShortcut(
+ BreezyShortcuts::TOGGLE_ZOOM_ON_FOCUS,
+ [this]() { this->toggleZoomOnFocus(); }
+ );
connect(effects, &EffectsHandler::cursorShapeChanged, this, &BreezyDesktopEffect::updateCursorImage);
updateCursorImage();
@@ -127,14 +131,7 @@ void BreezyDesktopEffect::setupGlobalShortcut(const BreezyShortcuts::Shortcut &s
action->setText(shortcut.actionText);
KGlobalAccel::self()->setDefaultShortcut(action, {shortcut.shortcut});
KGlobalAccel::self()->setShortcut(action, {shortcut.shortcut});
- QList shortcutKeys = KGlobalAccel::self()->shortcut(action);
connect(action, &QAction::triggered, this, triggeredFunc);
- connect(KGlobalAccel::self(), &KGlobalAccel::globalShortcutChanged, this, [this, shortcut, &shortcutKeys](QAction *action, const QKeySequence &seq) {
- if (action->objectName() == shortcut.actionName) {
- shortcutKeys.clear();
- shortcutKeys.append(seq);
- }
- });
}
void BreezyDesktopEffect::reconfigure(ReconfigureFlags)
@@ -142,6 +139,7 @@ void BreezyDesktopEffect::reconfigure(ReconfigureFlags)
BreezyDesktopConfig::self()->read();
setFocusedDisplayDistance(BreezyDesktopConfig::focusedDisplayDistance() / 100.0f);
setAllDisplaysDistance(BreezyDesktopConfig::allDisplaysDistance() / 100.0f);
+ setZoomOnFocusEnabled(BreezyDesktopConfig::zoomOnFocusEnabled());
}
QVariantMap BreezyDesktopEffect::initialProperties(Output *screen)
@@ -222,6 +220,11 @@ void BreezyDesktopEffect::recenter()
}
}
+void BreezyDesktopEffect::toggleZoomOnFocus()
+{
+ setZoomOnFocusEnabled(!m_zoomOnFocusEnabled);
+}
+
void BreezyDesktopEffect::addVirtualDisplay(QSize size)
{
// QSize size(2560, 1440);
@@ -241,6 +244,19 @@ bool BreezyDesktopEffect::isEnabled() const {
return m_enabled;
}
+bool BreezyDesktopEffect::isZoomOnFocusEnabled() const {
+ return m_zoomOnFocusEnabled;
+}
+
+void BreezyDesktopEffect::setZoomOnFocusEnabled(bool enabled) {
+ if (m_zoomOnFocusEnabled != enabled) {
+ m_zoomOnFocusEnabled = enabled;
+ BreezyDesktopConfig::setZoomOnFocusEnabled(enabled);
+ BreezyDesktopConfig::self()->save();
+ Q_EMIT zoomOnFocusChanged();
+ }
+}
+
bool BreezyDesktopEffect::imuResetState() const {
return m_imuResetState;
}
diff --git a/kwin/src/breezydesktopeffect.h b/kwin/src/breezydesktopeffect.h
index f68316b..08c2e54 100644
--- a/kwin/src/breezydesktopeffect.h
+++ b/kwin/src/breezydesktopeffect.h
@@ -15,6 +15,7 @@ namespace KWin
{
Q_OBJECT
Q_PROPERTY(bool isEnabled READ isEnabled NOTIFY enabledStateChanged)
+ Q_PROPERTY(bool zoomOnFocusEnabled READ isZoomOnFocusEnabled WRITE setZoomOnFocusEnabled NOTIFY zoomOnFocusChanged)
Q_PROPERTY(bool imuResetState READ imuResetState NOTIFY imuRotationsChanged)
Q_PROPERTY(QList imuRotations READ imuRotations NOTIFY imuRotationsChanged)
Q_PROPERTY(quint32 imuTimeElapsedMs READ imuTimeElapsedMs NOTIFY imuRotationsChanged)
@@ -42,6 +43,8 @@ namespace KWin
QPointF cursorPos() const;
bool isEnabled() const;
+ bool isZoomOnFocusEnabled() const;
+ void setZoomOnFocusEnabled(bool enabled);
QList imuRotations() const;
quint32 imuTimeElapsedMs() const;
quint64 imuTimestamp() const;
@@ -65,6 +68,7 @@ namespace KWin
void deactivate();
void toggle();
void recenter();
+ void toggleZoomOnFocus();
void addVirtualDisplay(QSize size);
void updateImuRotation();
void updateCursorImage();
@@ -73,6 +77,7 @@ namespace KWin
Q_SIGNALS:
void displayDistanceChanged();
void enabledStateChanged();
+ void zoomOnFocusChanged();
void imuRotationsChanged();
void cursorImageChanged();
void cursorPosChanged();
@@ -91,6 +96,7 @@ namespace KWin
QString m_cursorImageSource;
bool m_enabled = false;
+ bool m_zoomOnFocusEnabled = false;
bool m_imuResetState;
QList m_imuRotations;
quint32 m_imuTimeElapsedMs;
diff --git a/kwin/src/kcm/breezydesktopeffectkcm.cpp b/kwin/src/kcm/breezydesktopeffectkcm.cpp
index 9013c4a..8df3273 100644
--- a/kwin/src/kcm/breezydesktopeffectkcm.cpp
+++ b/kwin/src/kcm/breezydesktopeffectkcm.cpp
@@ -7,12 +7,18 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
+Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr")
+
+static const char EFFECT_GROUP[] = "Effect-breezy_desktop_effect";
+
void addShortcutAction(KActionCollection *collection, const BreezyShortcuts::Shortcut &shortcut)
{
QAction *action = collection->addAction(shortcut.actionName);
@@ -29,6 +35,22 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
{
ui.setupUi(widget());
addConfig(BreezyDesktopConfig::self(), widget());
+
+ m_configWatcher = KConfigWatcher::create(BreezyDesktopConfig::self()->sharedConfig());
+ if (m_configWatcher) {
+ connect(m_configWatcher.data(), &KConfigWatcher::configChanged, this,
+ [this](const KConfigGroup &group, const QByteArrayList &names) {
+ if (m_updatingFromConfig) {
+ return;
+ }
+ if (group.name() != QLatin1String(EFFECT_GROUP)) {
+ return;
+ }
+ BreezyDesktopConfig::self()->read();
+ updateUiFromConfig();
+ updateUnmanagedState();
+ });
+ }
auto actionCollection = new KActionCollection(this, QStringLiteral("kwin"));
actionCollection->setComponentDisplayName(i18n("KWin"));
@@ -37,6 +59,7 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
addShortcutAction(actionCollection, BreezyShortcuts::TOGGLE);
addShortcutAction(actionCollection, BreezyShortcuts::RECENTER);
+ addShortcutAction(actionCollection, BreezyShortcuts::TOGGLE_ZOOM_ON_FOCUS);
ui.shortcutsEditor->addCollection(actionCollection);
connect(ui.shortcutsEditor, &KShortcutsEditor::keyChange, this, &BreezyDesktopEffectConfig::markAsChanged);
connect(ui.kcfg_FocusedDisplayDistance, &QSlider::valueChanged, this, &BreezyDesktopEffectConfig::save);
@@ -56,9 +79,12 @@ void BreezyDesktopEffectConfig::load()
void BreezyDesktopEffectConfig::save()
{
+ // Prevent reacting to the file change we ourselves are about to write.
+ m_updatingFromConfig = true;
updateConfigFromUi();
BreezyDesktopConfig::self()->save();
KCModule::save();
+ m_updatingFromConfig = false;
updateUnmanagedState();
OrgKdeKwinEffectsInterface interface(QStringLiteral("org.kde.KWin"), QStringLiteral("/Effects"), QDBusConnection::sessionBus());
@@ -79,6 +105,9 @@ void BreezyDesktopEffectConfig::updateConfigFromUi()
void BreezyDesktopEffectConfig::updateUiFromConfig()
{
+ ui.kcfg_FocusedDisplayDistance->setValue(BreezyDesktopConfig::self()->focusedDisplayDistance());
+ ui.kcfg_AllDisplaysDistance->setValue(BreezyDesktopConfig::self()->allDisplaysDistance());
+ ui.kcfg_ZoomOnFocusEnabled->setChecked(BreezyDesktopConfig::self()->zoomOnFocusEnabled());
}
void BreezyDesktopEffectConfig::updateUiFromDefaultConfig()
@@ -90,4 +119,4 @@ void BreezyDesktopEffectConfig::updateUnmanagedState()
{
}
-#include "breezydesktopeffectkcm.moc"
+#include "breezydesktopeffectkcm.moc"
\ No newline at end of file
diff --git a/kwin/src/kcm/breezydesktopeffectkcm.h b/kwin/src/kcm/breezydesktopeffectkcm.h
index fa3b5e6..f795942 100644
--- a/kwin/src/kcm/breezydesktopeffectkcm.h
+++ b/kwin/src/kcm/breezydesktopeffectkcm.h
@@ -7,9 +7,14 @@
#pragma once
#include
+#include
+#include
#include "ui_breezydesktopeffectkcm.h"
+class KConfigWatcher;
+class KConfigGroup;
+
class BreezyDesktopEffectConfig : public KCModule
{
Q_OBJECT
@@ -30,4 +35,7 @@ private:
void updateUnmanagedState();
::Ui::BreezyDesktopEffectConfig ui;
+
+ KConfigWatcher::Ptr m_configWatcher;
+ bool m_updatingFromConfig = false;
};
diff --git a/kwin/src/kcm/breezydesktopeffectkcm.ui b/kwin/src/kcm/breezydesktopeffectkcm.ui
index 50048e9..f9ad626 100644
--- a/kwin/src/kcm/breezydesktopeffectkcm.ui
+++ b/kwin/src/kcm/breezydesktopeffectkcm.ui
@@ -21,76 +21,86 @@
250
-
- -
-
-
- Focused Display Distance:
-
-
-
- -
-
-
- 20
-
-
- 250
-
-
- QSlider::TicksBelow
-
-
- 20
-
-
- Qt::Horizontal
-
-
- true
-
-
-
- -
-
-
- All Displays Distance:
-
-
-
- -
-
-
- 20
-
-
- 250
-
-
- QSlider::TicksBelow
-
-
- 20
-
-
- Qt::Horizontal
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
+
+ -
+
+
+ Zoom on Focus
+
+
+ false
+
+
+
+ -
+
+
+ Focused Display Distance:
+
+
+
+ -
+
+
+ 20
+
+
+ 250
+
+
+ QSlider::TicksBelow
+
+
+ 20
+
+
+ Qt::Horizontal
+
+
+ true
+
+
+
+ -
+
+
+ All Displays Distance:
+
+
+
+ -
+
+
+ 20
+
+
+ 250
+
+
+ QSlider::TicksBelow
+
+
+ 20
+
+
+ Qt::Horizontal
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
diff --git a/kwin/src/kcm/shortcuts.h b/kwin/src/kcm/shortcuts.h
index 1eb8c75..f5792a6 100644
--- a/kwin/src/kcm/shortcuts.h
+++ b/kwin/src/kcm/shortcuts.h
@@ -22,4 +22,10 @@ namespace BreezyShortcuts {
QStringLiteral("Recenter"),
QStringLiteral("Recenter")
};
+
+ const Shortcut TOGGLE_ZOOM_ON_FOCUS = {
+ Qt::CTRL | Qt::META | Qt::Key_0,
+ QStringLiteral("Toggle Zoom on Focus"),
+ QStringLiteral("Toggle Zoom on Focus")
+ };
}
diff --git a/kwin/src/qml/BreezyDesktop.qml b/kwin/src/qml/BreezyDesktop.qml
index 56ef738..7fb0b32 100644
--- a/kwin/src/qml/BreezyDesktop.qml
+++ b/kwin/src/qml/BreezyDesktop.qml
@@ -94,20 +94,24 @@ Node {
running: true
onTriggered: {
if (breezyDesktop.imuRotations && breezyDesktop.imuRotations.length > 0) {
- const focusedIndex = displays.findFocusedMonitor(
- displays.eusToNwuQuat(breezyDesktop.imuRotations[0]),
- breezyDesktop.monitorPlacements.map(monitorVectors => monitorVectors.centerLook),
- breezyDesktop.focusedMonitorIndex,
- false, // TODO smooth follow
- breezyDesktop.fovDetails,
- breezyDesktop.screens.map(screen => screen.geometry)
- );
+ let focusedIndex = -1;
+
+ if (effect.zoomOnFocusEnabled) {
+ focusedIndex = displays.findFocusedMonitor(
+ displays.eusToNwuQuat(breezyDesktop.imuRotations[0]),
+ breezyDesktop.monitorPlacements.map(monitorVectors => monitorVectors.centerLook),
+ breezyDesktop.focusedMonitorIndex,
+ false, // TODO smooth follow
+ breezyDesktop.fovDetails,
+ breezyDesktop.screens.map(screen => screen.geometry)
+ );
+ }
const focusedDisplay = focusedIndex !== -1 ? breezyDesktop.displayAtIndex(focusedIndex) : null;
if (focusedIndex !== breezyDesktop.focusedMonitorIndex) {
- zoomOutAnimation.stop();
- zoomInAnimation.stop();
- zoomOnFocusSequence.stop();
+ // zoomOutAnimation.stop();
+ // zoomInAnimation.stop();
+ // zoomOnFocusSequence.stop();
if (focusedDisplay === null) {
zoomOutAnimation.target = breezyDesktop.displayAtIndex(breezyDesktop.focusedMonitorIndex);
zoomOutAnimation.target.targetDistance = zoomOutAnimation.to;