Commit cb4dd3b1 authored by David Redondo's avatar David Redondo 🏎
Browse files

osd: Make the osd service a standalone program

Having the OSD in the daemon is problematic currently as it requires
manual positioning of the window. Because KDED is running arbitrary
other plugins this prevents already porting it to layer shell
in Plasma 5 as only one shell plugin can be used per process currently.
Furthermore in the future positioning will not work because of the Qt6
change to report window positions always in the
corner of the screen. This cannot be opted out globally for the same
reasons.
See also the plasma-workspace commit e87d29c2a31b147d243ce6b9b8d1df7da36f1550
parent 08c90e7e
......@@ -19,6 +19,8 @@ set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMConfiguredInstall)
include(ECMGenerateDBusServiceFile)
include(ECMInstallIcons)
include(ECMMarkAsTest)
include(ECMQtDeclareLoggingCategory)
......@@ -65,6 +67,7 @@ configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h)
add_subdirectory(kcm)
add_subdirectory(kded)
add_subdirectory(osd)
add_subdirectory(plasmoid)
add_subdirectory(tests)
add_subdirectory(console)
......
......@@ -6,9 +6,7 @@ set(kscreen_daemon_SRCS
output.cpp
generator.cpp
device.cpp
osd.cpp
osdmanager.cpp
osdaction.cpp
${CMAKE_SOURCE_DIR}/common/osdaction.cpp
${CMAKE_SOURCE_DIR}/common/globals.cpp
${CMAKE_SOURCE_DIR}/common/control.cpp
${CMAKE_SOURCE_DIR}/common/orientation_sensor.cpp
......@@ -20,6 +18,9 @@ ecm_qt_declare_logging_category(kscreen_daemon_SRCS HEADER kscreen_daemon_debug.
qt_add_dbus_interface(kscreen_daemon_SRCS
org.freedesktop.DBus.Properties.xml
freedesktop_interface)
qt_add_dbus_interface(kscreen_daemon_SRCS
../osd/org.kde.kscreen.osdService.xml
osdservice_interface)
qt_add_dbus_adaptor(kscreen_daemon_SRCS
org.kde.KScreen.xml
daemon.h
......@@ -57,9 +58,3 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kscreen.desktop.cmake
kcoreaddons_desktop_to_json(kscreen ${CMAKE_CURRENT_BINARY_DIR}/kscreen.desktop)
install(TARGETS kscreen DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/kded)
set(QML_FILES
qml/OsdSelector.qml
)
install(FILES ${QML_FILES} DESTINATION ${KDE_INSTALL_DATADIR}/kded_kscreen/qml)
......@@ -15,7 +15,7 @@
#include "generator.h"
#include "kscreen_daemon_debug.h"
#include "kscreenadaptor.h"
#include "osdmanager.h"
#include "osdservice_interface.h"
#include <kscreen/configmonitor.h>
#include <kscreen/getconfigoperation.h>
......@@ -80,6 +80,7 @@ KScreenDaemon::KScreenDaemon(QObject *parent, const QList<QVariant> &)
connect(m_orientationSensor, &OrientationSensor::valueChanged, this, &KScreenDaemon::updateOrientation);
KScreen::Log::instance();
qMetaTypeId<KScreen::OsdAction>();
QMetaObject::invokeMethod(this, "getInitialConfig", Qt::QueuedConnection);
}
......@@ -116,9 +117,12 @@ void KScreenDaemon::init()
connect(action, &QAction::triggered, this, &KScreenDaemon::displayButton);
new KScreenAdaptor(this);
// Initialize OSD manager to register its dbus interface
m_osdManager = new KScreen::OsdManager(this);
connect(m_osdManager, &KScreen::OsdManager::selected, this, &KScreenDaemon::applyOsdAction);
const QString osdService = QStringLiteral("org.kde.kscreen.osdService");
const QString osdPath = QStringLiteral("/org/kde/kscreen/osdService");
m_osdServiceInterface = new OrgKdeKscreenOsdServiceInterface(osdService, osdPath, QDBusConnection::sessionBus(), this);
// Set a longer timeout to not assume timeout while the osd is still shown
m_osdServiceInterface->setTimeout(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds(60)).count());
m_changeCompressor->setInterval(10);
m_changeCompressor->setSingleShot(true);
......@@ -282,6 +286,20 @@ void KScreenDaemon::setAutoRotate(bool value)
m_orientationSensor->setEnabled(value);
}
void KScreenDaemon::showOSD()
{
auto call = m_osdServiceInterface->showActionSelector();
auto watcher = new QDBusPendingCallWatcher(call);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher] {
watcher->deleteLater();
QDBusReply<int> reply = *watcher;
if (!reply.isValid()) {
return;
}
applyOsdAction(static_cast<KScreen::OsdAction::Action>(reply.value()));
});
}
void KScreenDaemon::applyOsdAction(KScreen::OsdAction::Action action)
{
switch (action) {
......@@ -320,9 +338,9 @@ void KScreenDaemon::applyIdealConfig()
if (showOsd) {
qCDebug(KSCREEN_KDED) << "Getting ideal config from user via OSD...";
m_osdManager->showActionSelector();
showOSD();
} else {
m_osdManager->hideOsd();
m_osdServiceInterface->hideOsd();
}
}
......@@ -537,8 +555,7 @@ void KScreenDaemon::saveCurrentConfig()
void KScreenDaemon::displayButton()
{
qCDebug(KSCREEN_KDED) << "displayBtn triggered";
m_osdManager->showActionSelector();
showOSD();
}
void KScreenDaemon::lidClosedChanged(bool lidIsClosed)
......
......@@ -8,8 +8,8 @@
#define KSCREEN_DAEMON_H
#include "../common/globals.h"
#include "../common/osdaction.h"
#include "config-X11.h"
#include "osdaction.h"
#include <kscreen/config.h>
......@@ -21,6 +21,7 @@
class Config;
class OrientationSensor;
class OrgKdeKscreenOsdServiceInterface;
namespace KScreen
{
......@@ -67,6 +68,7 @@ private:
void setMonitorForChanges(bool enabled);
void outputConnectedChanged();
void showOSD();
void applyOsdAction(KScreen::OsdAction::Action action);
void doApplyConfig(const KScreen::ConfigPtr &config);
......@@ -84,8 +86,9 @@ private:
QTimer *m_changeCompressor;
QTimer *m_saveTimer;
QTimer *m_lidClosedTimer;
KScreen::OsdManager *m_osdManager;
OrgKdeKscreenOsdServiceInterface *m_osdServiceInterface;
OrientationSensor *m_orientationSensor;
bool m_startingUp = true;
};
......
add_executable(kscreen_osd_service main.cpp osdmanager.cpp osd.cpp ../common/osdaction.cpp)
qt_add_dbus_adaptor(DBUS_SRC org.kde.kscreen.osdService.xml osdmanager.h KScreen::OsdManager)
target_sources(kscreen_osd_service PRIVATE ${DBUS_SRC})
target_link_libraries(kscreen_osd_service PRIVATE Qt::DBus KF5::Declarative KF5::I18n KF5::Screen)
set(QML_FILES
qml/OsdSelector.qml
)
install(FILES ${QML_FILES} DESTINATION ${KDE_INSTALL_DATADIR}/kded_kscreen/qml)
install(TARGETS kscreen_osd_service DESTINATION ${KDE_INSTALL_LIBEXECDIR})
ecm_generate_dbus_service_file(
NAME org.kde.kscreen.osdService
EXECUTABLE ${KDE_INSTALL_FULL_LIBEXECDIR}
DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}
)
ecm_install_configured_files(INPUT plasma-kscreen-osd.service @ONLY
DESTINATION ${KDE_INSTALL_SYSTEMDUSERUNITDIR}
)
/*
SPDX-FileCopyrightText: 2022 David Redondo <kde@david-redondo.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <QGuiApplication>
#include "osdmanager.h"
int main(int argc, char **argv)
{
KScreen::OsdManager osdManager;
return QGuiApplication(argc, argv).exec();
}
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.kde.kscreen.osdService">
<method name="hideOsd">
</method>
<method name="showActionSelector">
<arg type="i" direction="out"/>
</method>
</interface>
</node>
......@@ -7,8 +7,6 @@
#include "osd.h"
#include "kscreen_daemon_debug.h"
#include "../common/utils.h"
#include <KScreen/Mode>
......@@ -41,14 +39,14 @@ void Osd::showActionSelector()
if (!m_osdActionSelector) {
const QString osdPath = QStandardPaths::locate(QStandardPaths::QStandardPaths::GenericDataLocation, QStringLiteral("kded_kscreen/qml/OsdSelector.qml"));
if (osdPath.isEmpty()) {
qCWarning(KSCREEN_KDED) << "Failed to find action selector OSD QML file" << osdPath;
qWarning() << "Failed to find action selector OSD QML file" << osdPath;
return;
}
m_osdActionSelector = new KDeclarative::QmlObjectSharedEngine(this);
m_osdActionSelector->setSource(QUrl::fromLocalFile(osdPath));
if (m_osdActionSelector->status() != QQmlComponent::Ready) {
qCWarning(KSCREEN_KDED) << "Failed to load OSD QML file" << osdPath;
qWarning() << "Failed to load OSD QML file" << osdPath;
delete m_osdActionSelector;
m_osdActionSelector = nullptr;
return;
......@@ -65,7 +63,7 @@ void Osd::showActionSelector()
rootObject->setProperty("visible", true);
rootObject->setProperty("actions", QVariant::fromValue(OsdAction::availableActions()));
} else {
qCWarning(KSCREEN_KDED) << "Could not get root object for action selector.";
qWarning() << "Could not get root object for action selector.";
}
}
......
......@@ -6,8 +6,8 @@
*/
#include "osdmanager.h"
#include "kscreen_daemon_debug.h"
#include "osd.h"
#include "osdserviceadaptor.h"
#include <KScreen/Config>
#include <KScreen/EDID>
......@@ -21,13 +21,12 @@
namespace KScreen
{
OsdManager::OsdManager(QObject *parent)
: QObject(parent)
, m_cleanupTimer(new QTimer(this))
{
qmlRegisterUncreatableType<KScreen::OsdAction>("org.kde.KScreen", 1, 0, "OsdAction", QStringLiteral("Can't create OsdAction"));
new OsdServiceAdaptor(this);
// free up memory when the osd hasn't been used for more than 1 minute
m_cleanupTimer->setInterval(60000);
......@@ -35,29 +34,30 @@ OsdManager::OsdManager(QObject *parent)
connect(m_cleanupTimer, &QTimer::timeout, this, [this]() {
hideOsd();
});
QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/kscreen/osdService"), this, QDBusConnection::ExportAdaptors);
QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.kscreen.osdService"));
if (!QDBusConnection::sessionBus().registerObject(QStringLiteral("/org/kde/kscreen/osdService"), this, QDBusConnection::ExportAllSlots)) {
qCWarning(KSCREEN_KDED) << "Failed to registerObject";
}
}
void OsdManager::hideOsd()
{
qDeleteAll(m_osds);
m_osds.clear();
qApp->quit();
}
OsdManager::~OsdManager()
{
}
void OsdManager::showActionSelector()
OsdAction::Action OsdManager::showActionSelector()
{
setDelayedReply(true);
hideOsd();
connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this](const KScreen::ConfigOperation *op) {
connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished, this, [this, message = message()](const KScreen::ConfigOperation *op) {
if (op->hasError()) {
qCWarning(KSCREEN_KDED) << op->errorString();
qWarning() << op->errorString();
auto error = message.createErrorReply(QDBusError::Failed, QStringLiteral("Failed to get current output configuration"));
QDBusConnection::sessionBus().send(error);
return;
}
......@@ -92,7 +92,8 @@ void OsdManager::showActionSelector()
}
if (!osdOutput) {
// huh!?
auto error = message.createErrorReply(QDBusError::Failed, QStringLiteral("No enabled output"));
QDBusConnection::sessionBus().send(error);
return;
}
......@@ -102,17 +103,24 @@ void OsdManager::showActionSelector()
} else {
osd = new KScreen::Osd(osdOutput, this);
m_osds.insert(osdOutput->name(), osd);
connect(osd, &Osd::osdActionSelected, this, [this](OsdAction::Action action) {
connect(osd, &Osd::osdActionSelected, this, [this, message](OsdAction::Action action) {
for (auto osd : qAsConst(m_osds)) {
osd->hideOsd();
}
Q_EMIT selected(action);
auto reply = message.createReply(action);
QDBusConnection::sessionBus().send(reply);
hideOsd();
});
}
osd->showActionSelector();
connect(m_cleanupTimer, &QTimer::timeout, this, [this, message] {
auto reply = message.createReply(OsdAction::NoAction);
QDBusConnection::sessionBus().send(reply);
});
m_cleanupTimer->start();
});
return OsdAction::NoAction;
}
}
......@@ -7,12 +7,13 @@
#ifndef OSDM_H
#define OSDM_H
#include <QDBusContext>
#include <QMap>
#include <QObject>
#include <QString>
#include <QTimer>
#include "osdaction.h"
#include "../common/osdaction.h"
namespace KScreen
{
......@@ -20,10 +21,9 @@ class ConfigOperation;
class Osd;
class Output;
class OsdManager : public QObject
class OsdManager : public QObject, public QDBusContext
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kscreen.osdService")
public:
OsdManager(QObject *parent = nullptr);
......@@ -31,9 +31,7 @@ public:
public Q_SLOTS:
void hideOsd();
void showActionSelector();
Q_SIGNALS:
void selected(OsdAction::Action action);
OsdAction::Action showActionSelector();
private:
void slotIdentifyOutputs(KScreen::ConfigOperation *op);
......
[Unit]
Description=KScreen OSD service
PartOf=graphical-session.target
[Service]
ExecStart=@KDE_INSTALL_FULL_LIBEXECDIR@/kscreen_osd_service
Type=dbus
BusName=org.kde.kscreen.osdService
TimeoutSec=5sec
Slice=background.slice
# Disable restart as we're dbus activated anyway
Restart=no
......@@ -2,7 +2,7 @@ add_definitions(-DTRANSLATION_DOMAIN=\"plasma_applet_org.kde.kscreen\")
set(kscreenapplet_SRCS
kscreenapplet.cpp
../kded/osdaction.cpp
../common/osdaction.cpp
)
add_library(plasma_applet_kscreen MODULE ${kscreenapplet_SRCS})
......
......@@ -11,7 +11,7 @@
#include <KScreen/Types>
#include "../kded/osdaction.h"
#include "../common/osdaction.h"
class KScreenApplet : public Plasma::Applet
{
......
......@@ -2,21 +2,16 @@ include_directories(
${CMAKE_BINARY_DIR}/kded
)
qt_add_dbus_interface(OsdInterface ../../osd/org.kde.kscreen.osdService.xml osdservice_interface)
add_executable(osdtest main.cpp
osdtest.cpp
../../kded/osd.cpp
../../kded/osdmanager.cpp
../../kded/osdaction.cpp
../../common/utils.cpp
../../common/osdaction.cpp
${OsdInterface}
)
target_link_libraries(osdtest Qt::Core
Qt::DBus
Qt::Quick
Qt::Qml
KF5::Screen
KF5::I18n
KF5::Declarative
)
add_test(NAME kscreen-kded-osdtest COMMAND osdtest)
......
/*
SPDX-FileCopyrightText: 2014-2016 Sebastian Kügler <sebas@kde.org>
SPDX-FileCopyrightText: 2022 David Redondo <kde@david-redondo.de>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "osdtest.h"
#include "../../common/osdaction.h"
#include "osdservice_interface.h"
#include <QCommandLineParser>
#include <QGuiApplication>
#include <QCoreApplication>
#include <QDBusConnection>
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QCoreApplication app(argc, argv);
QCommandLineOption dbus = QCommandLineOption(QStringList() << QStringLiteral("d") << QStringLiteral("dbus"), QStringLiteral("Call over dbus"));
KScreen::OsdTest osdtest;
QCommandLineParser parser;
parser.addHelpOption();
parser.addOption(dbus);
parser.process(app);
const QString name = QStringLiteral("org.kde.kscreen.osdService");
const QString path = QStringLiteral("/org/kde/kscreen/osdService");
auto osdService = new OrgKdeKscreenOsdServiceInterface(name, path, QDBusConnection::sessionBus());
if (parser.isSet(dbus)) {
osdtest.setUseDBus(true);
}
QDBusReply<int> reply = osdService->showActionSelector();
osdtest.showActionSelector();
if (!reply.isValid()) {
qDebug() << "Error calling osdService:";
qDebug() << reply.error();
return 1;
}
return app.exec();
auto actionEnum = QMetaEnum::fromType<KScreen::OsdAction::Action>();
const char *value = actionEnum.valueToKey(reply.value());
if (!value) {
qDebug() << "Got invalid action" << reply.value();
return 1;
}
qDebug() << "Selected Action" << value;
return 0;
}
/*
SPDX-FileCopyrightText: 2016 Sebastian Kügler <sebas@kde.org>
SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "osdtest.h"
#include "../../kded/osdmanager.h"
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingCall>
#include <QLoggingCategory>
Q_LOGGING_CATEGORY(KSCREEN_KDED, "kscreen.kded")
namespace KScreen
{
OsdTest::OsdTest(QObject *parent)
: QObject(parent)
{
}
OsdTest::~OsdTest()
{
}
OsdManager *OsdTest::getOsdManager()
{
if (m_osdManager) {
return m_osdManager;
}
m_osdManager = new OsdManager(this);
return m_osdManager;
}
void OsdTest::setUseDBus(bool yesno)
{
m_useDBus = yesno;
}
void OsdTest::showActionSelector()
{
if (!m_useDBus) {
getOsdManager()->showActionSelector();
connect(getOsdManager(), &KScreen::OsdManager::selected, [](KScreen::OsdAction::Action action) {
qCDebug(KSCREEN_KDED) << "Selected action:" << action;
qApp->quit();
});
} else {
QDBusMessage msg = QDBusMessage::createMethodCall(QLatin1String("org.kde.kscreen.osdService"),
QLatin1String("/org/kde/kscreen/osdService"),
QLatin1String("org.kde.kscreen.osdService"),
QLatin1String("showActionSelector"));
QDBusConnection::sessionBus().asyncCall(msg);
qCWarning(KSCREEN_KDED) << "Sent dbus message.";
QTimer::singleShot(500, qApp, &QCoreApplication::quit);
}
}
} // ns
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment