Add Zoom on Focus shortcut support

This commit is contained in:
wheaney 2025-08-20 17:05:50 -07:00
parent 7200ac95f5
commit 1f5e3b1d3f
9 changed files with 174 additions and 89 deletions

View File

@ -17,5 +17,10 @@
<max>250</max>
<label>All Displays Distance</label>
</entry>
<entry name="ZoomOnFocusEnabled" type="Bool">
<default>false</default>
<label>Zoom on Focus Enabled</label>
<description>Enable zooming in on the focused display.</description>
</entry>
</group>
</kcfg>

View File

@ -2,3 +2,4 @@ File=breezydesktopconfig.kcfg
ClassName=BreezyDesktopConfig
Singleton=true
Mutators=true
Notifiers=true

View File

@ -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<QKeySequence> 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;
}

View File

@ -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<QQuaternion> 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<QQuaternion> 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<QQuaternion> m_imuRotations;
quint32 m_imuTimeElapsedMs;

View File

@ -7,12 +7,18 @@
#include <KActionCollection>
#include <KGlobalAccel>
#include <KLocalizedString>
#include <KConfigWatcher>
#include <KSharedConfig>
#include <KPluginFactory>
#include <QAction>
#include <QFileDialog>
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"

View File

@ -7,9 +7,14 @@
#pragma once
#include <KCModule>
#include <KConfigWatcher>
#include <memory>
#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;
};

View File

@ -21,76 +21,86 @@
<height>250</height>
</size>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelFocusedDisplayDistance">
<property name="text">
<string>Focused Display Distance:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSlider" name="kcfg_FocusedDisplayDistance">
<property name="minimum">
<double>20</double>
</property>
<property name="maximum">
<double>250</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>20</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelAllDisplaysDistance">
<property name="text">
<string>All Displays Distance:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="kcfg_AllDisplaysDistance">
<property name="minimum">
<double>20</double>
</property>
<property name="maximum">
<double>250</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>20</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="KShortcutsEditor" name="shortcutsEditor" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="kcfg_ZoomOnFocusEnabled">
<property name="text">
<string>Zoom on Focus</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelFocusedDisplayDistance">
<property name="text">
<string>Focused Display Distance:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="kcfg_FocusedDisplayDistance">
<property name="minimum">
<double>20</double>
</property>
<property name="maximum">
<double>250</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>20</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelAllDisplaysDistance">
<property name="text">
<string>All Displays Distance:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSlider" name="kcfg_AllDisplaysDistance">
<property name="minimum">
<double>20</double>
</property>
<property name="maximum">
<double>250</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>20</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="KShortcutsEditor" name="shortcutsEditor" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>

View File

@ -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")
};
}

View File

@ -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;