Add buttons to create virtual displays

This commit is contained in:
wheaney 2025-09-03 16:40:43 -07:00
parent 259d2f97f6
commit 2a0baaf1e2
7 changed files with 173 additions and 62 deletions

View File

@ -119,14 +119,11 @@ then
pkgkwin_rc=$? pkgkwin_rc=$?
set -e set -e
if [ "$pkgkwin_rc" -ne 0 ]; then if [ "$pkgkwin_rc" -ne 0 ]; then
if echo "$pkgkwin_stderr" | grep -qi "could not find"; then if echo "$pkgkwin_stderr" | grep -qi "could not find" && [ -z "${PRINT_FULL_STDERR+x}" ]; then
if [ -z "${PRINT_FULL_STDERR+x}" ]; then print_missing_dependencies "$0"
print_missing_dependencies "$0" else
else echo "$pkgkwin_stderr"
echo "$pkgkwin_stderr"
fi
fi fi
echo ""
echo "Error: Breezy Desktop build failed with exit code $pkgkwin_rc" echo "Error: Breezy Desktop build failed with exit code $pkgkwin_rc"
exit $pkgkwin_rc exit $pkgkwin_rc
fi fi

View File

@ -52,6 +52,7 @@ target_link_libraries(breezy_desktop
Qt6::Core Qt6::Core
Qt6::Gui Qt6::Gui
Qt6::Quick Qt6::Quick
Qt6::DBus
KF6::ConfigCore KF6::ConfigCore
KF6::ConfigGui KF6::ConfigGui

View File

@ -20,12 +20,36 @@
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QQuickItem> #include <QQuickItem>
#include <QTimer> #include <QTimer>
#include <QDBusConnection>
#include <KGlobalAccel> #include <KGlobalAccel>
#include <KLocalizedString> #include <KLocalizedString>
Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr") Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr")
// A small DBus adaptor to expose effect controls to the KCM.
// Service is provided by KWin (org.kde.KWin). We only register an object path.
// Interface: com.xronlinux.BreezyDesktop, Path: /com/xronlinux/BreezyDesktop
namespace {
class BreezyDesktopDBusAdaptor : public QObject {
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.xronlinux.BreezyDesktop")
public:
explicit BreezyDesktopDBusAdaptor(KWin::BreezyDesktopEffect *effect)
: QObject(effect), m_effect(effect) {}
public Q_SLOTS:
void AddVirtualDisplay(int width, int height) {
QMetaObject::invokeMethod(m_effect, [this, width, height]() {
m_effect->addVirtualDisplay(QSize(width, height));
}, Qt::QueuedConnection);
}
private:
KWin::BreezyDesktopEffect *m_effect;
};
} // namespace
namespace DataView namespace DataView
{ {
const QString SHM_DIR = QStringLiteral("/dev/shm"); const QString SHM_DIR = QStringLiteral("/dev/shm");
@ -129,6 +153,16 @@ BreezyDesktopEffect::BreezyDesktopEffect()
m_cursorUpdateTimer->start(); m_cursorUpdateTimer->start();
enableDriver(); enableDriver();
// Register DBus object under KWin's session bus name
auto *adaptor = new BreezyDesktopDBusAdaptor(this);
const bool dbusOk = QDBusConnection::sessionBus().registerObject(
QStringLiteral("/com/xronlinux/BreezyDesktop"),
adaptor,
QDBusConnection::ExportAllSlots);
if (!dbusOk) {
qCWarning(KWIN_XR) << "Failed to register DBus object /com/xronlinux/BreezyDesktop";
}
} }
void BreezyDesktopEffect::setupGlobalShortcut(const BreezyShortcuts::Shortcut &shortcut, std::function<void()> triggeredFunc) { void BreezyDesktopEffect::setupGlobalShortcut(const BreezyShortcuts::Shortcut &shortcut, std::function<void()> triggeredFunc) {
@ -550,4 +584,4 @@ void BreezyDesktopEffect::updateCursorPos()
} }
} }
#include "moc_breezydesktopeffect.cpp" #include "breezydesktopeffect.moc"

View File

@ -5,6 +5,7 @@ qt_add_dbus_interface(breezy_desktop_config_SOURCES ${KWIN_EFFECTS_INTERFACE} kw
kcoreaddons_add_plugin(breezy_desktop_config INSTALL_NAMESPACE "kwin/effects/configs" SOURCES ${breezy_desktop_config_SOURCES}) kcoreaddons_add_plugin(breezy_desktop_config INSTALL_NAMESPACE "kwin/effects/configs" SOURCES ${breezy_desktop_config_SOURCES})
kconfig_add_kcfg_files(breezy_desktop_config ../breezydesktopconfig.kcfgc) kconfig_add_kcfg_files(breezy_desktop_config ../breezydesktopconfig.kcfgc)
target_link_libraries(breezy_desktop_config target_link_libraries(breezy_desktop_config
Qt6::DBus
KF6::ConfigCore KF6::ConfigCore
KF6::ConfigGui KF6::ConfigGui
KF6::ConfigWidgets KF6::ConfigWidgets

View File

@ -14,6 +14,7 @@
#include <KPluginFactory> #include <KPluginFactory>
#include <QAction> #include <QAction>
#include <QGuiApplication>
#include <QKeyEvent> #include <QKeyEvent>
#include <QLineEdit> #include <QLineEdit>
#include <QLabel> #include <QLabel>
@ -21,6 +22,8 @@
#include <QJsonArray> #include <QJsonArray>
#include <QPushButton> #include <QPushButton>
#include <QComboBox> #include <QComboBox>
#include <QDBusInterface>
#include <QDBusConnection>
Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr") Q_LOGGING_CATEGORY(KWIN_XR, "kwin.xr")
@ -43,6 +46,20 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
ui.setupUi(widget()); ui.setupUi(widget());
addConfig(BreezyDesktopConfig::self(), widget()); addConfig(BreezyDesktopConfig::self(), widget());
// Show/enable Virtual Display controls only when we're on Wayland
const bool isWaylandSession = QGuiApplication::platformName().contains(QStringLiteral("wayland"), Qt::CaseInsensitive)
|| qEnvironmentVariable("XDG_SESSION_TYPE").compare(QStringLiteral("wayland"), Qt::CaseInsensitive) == 0;
if (isWaylandSession) {
if (auto lbl = widget()->findChild<QLabel*>(QStringLiteral("labelVirtualDisplays"))) {
lbl->setVisible(true);
lbl->setEnabled(true);
}
if (auto row = widget()->findChild<QWidget*>(QStringLiteral("widgetVirtualDisplayButtons"))) {
row->setVisible(true);
row->setEnabled(true);
}
}
m_statePollTimer.setInterval(2000); m_statePollTimer.setInterval(2000);
m_statePollTimer.setTimerType(Qt::CoarseTimer); m_statePollTimer.setTimerType(Qt::CoarseTimer);
connect(&m_statePollTimer, &QTimer::timeout, this, &BreezyDesktopEffectConfig::pollDriverState); connect(&m_statePollTimer, &QTimer::timeout, this, &BreezyDesktopEffectConfig::pollDriverState);
@ -118,6 +135,28 @@ BreezyDesktopEffectConfig::BreezyDesktopEffectConfig(QObject *parent, const KPlu
tokenEdit->installEventFilter(this); tokenEdit->installEventFilter(this);
} }
} }
// Wire Add Virtual Display buttons via DBus to the effect
auto callAddVirtualDisplay = [](int w, int h) {
QDBusInterface iface(
QStringLiteral("org.kde.KWin"),
QStringLiteral("/com/xronlinux/BreezyDesktop"),
QStringLiteral("com.xronlinux.BreezyDesktop"),
QDBusConnection::sessionBus());
if (iface.isValid()) {
iface.call(QDBus::NoBlock, QStringLiteral("AddVirtualDisplay"), w, h);
}
};
if (auto btn1080p = widget()->findChild<QPushButton*>("buttonAdd1080p")) {
connect(btn1080p, &QPushButton::clicked, this, [callAddVirtualDisplay]() {
callAddVirtualDisplay(1920, 1080);
});
}
if (auto btn1440p = widget()->findChild<QPushButton*>("buttonAdd1440p")) {
connect(btn1440p, &QPushButton::clicked, this, [callAddVirtualDisplay]() {
callAddVirtualDisplay(2560, 1440);
});
}
} }
BreezyDesktopEffectConfig::~BreezyDesktopEffectConfig() BreezyDesktopEffectConfig::~BreezyDesktopEffectConfig()

View File

@ -112,59 +112,46 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="labelDisplayHorizontalOffset"> <widget class="QLabel" name="labelVirtualDisplays">
<property name="text"> <property name="text">
<string>Display Horizontal Offset:</string> <string>Add Virtual Display:</string>
</property> </property>
</widget> <property name="visible">
</item> <bool>false</bool>
<item row="4" column="1"> </property>
<widget class="LabeledSlider" name="kcfg_DisplayHorizontalOffset"> <property name="enabled">
<property name="decimalShift"> <bool>false</bool>
<double>2</double> </property>
</property> </widget>
<property name="tickPosition"> </item>
<enum>QSlider::TicksBelow</enum> <item row="4" column="1">
</property> <widget class="QWidget" name="widgetVirtualDisplayButtons">
<property name="tickInterval"> <property name="visible">
<double>50</double> <bool>false</bool>
</property> </property>
<property name="orientation"> <property name="enabled">
<enum>Qt::Horizontal</enum> <bool>false</bool>
</property> </property>
<property name="tracking"> <layout class="QHBoxLayout" name="layoutVirtualDisplayButtons">
<bool>true</bool> <item>
</property> <widget class="QPushButton" name="buttonAdd1080p">
</widget> <property name="text">
</item> <string>+ 1080p</string>
<item row="5" column="0"> </property>
<widget class="QLabel" name="labelDisplayVerticalOffset"> </widget>
<property name="text"> </item>
<string>Display Vertical Offset:</string> <item>
</property> <widget class="QPushButton" name="buttonAdd1440p">
</widget> <property name="text">
</item> <string>+ 1440p</string>
<item row="5" column="1"> </property>
<widget class="LabeledSlider" name="kcfg_DisplayVerticalOffset"> </widget>
<property name="decimalShift"> </item>
<double>2</double> </layout>
</property> </widget>
<property name="tickPosition"> </item>
<enum>QSlider::TicksBelow</enum> <item row="5" column="0" colspan="2">
</property>
<property name="tickInterval">
<double>50</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
<item row="6" column="0" colspan="2">
<widget class="KShortcutsEditor" name="shortcutsEditor" native="true"> <widget class="KShortcutsEditor" name="shortcutsEditor" native="true">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@ -212,6 +199,58 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="labelDisplayHorizontalOffset">
<property name="text">
<string>Display Horizontal Offset:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="LabeledSlider" name="kcfg_DisplayHorizontalOffset">
<property name="decimalShift">
<double>2</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>50</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="labelDisplayVerticalOffset">
<property name="text">
<string>Display Vertical Offset:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="LabeledSlider" name="kcfg_DisplayVerticalOffset">
<property name="decimalShift">
<double>2</double>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<double>50</double>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tracking">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tabLicenseDetails"> <widget class="QWidget" name="tabLicenseDetails">

View File

@ -120,7 +120,7 @@ Node {
duration: 150 duration: 150
running: false running: false
onFinished: { onFinished: {
const unfocusedDisplay = zoomInAnimation.target; const unfocusedDisplay = zoomOutAnimation.target;
if (unfocusedDisplay) { if (unfocusedDisplay) {
unfocusedDisplay.monitorDistance = Qt.binding(function() { return effect.allDisplaysDistance; }); unfocusedDisplay.monitorDistance = Qt.binding(function() { return effect.allDisplaysDistance; });
} }