Commit 3a3e60e2 authored by Sebastian Kügler's avatar Sebastian Kügler Committed by Daniel Vrátil
Browse files

add Osd classes

Osd represents a single osd dialog.
OsdManager handles showing them per output.

The content can be loaded from a QML file. It should be reachable via
DBus, but I haven't tried.

This should also make the osd wayland compatible.
parent ad2aaa68
add_definitions(-DTRANSLATION_DOMAIN=\"kscreen\")
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/../ ${CMAKE_SOURCE_DIR}/kcm/src)
set(kscreen_daemon_SRCS
daemon.cpp
serializer.cpp
generator.cpp
device.cpp
osd.cpp
osdmanager.cpp
${CMAKE_SOURCE_DIR}/kcm/src/utils.cpp
)
ecm_qt_declare_logging_category(kscreen_daemon_SRCS HEADER kscreen_daemon_debug.h IDENTIFIER KSCREEN_KDED CATEGORY_NAME kscreen.kded)
......@@ -22,7 +25,15 @@ qt5_add_dbus_adaptor(kscreen_daemon_SRCS
add_library(kscreen MODULE ${kscreen_daemon_SRCS})
target_link_libraries(kscreen Qt5::Widgets Qt5::DBus KF5::Screen KF5::DBusAddons KF5::I18n KF5::XmlGui KF5::GlobalAccel)
target_link_libraries(kscreen Qt5::Widgets
Qt5::DBus
Qt5::Quick
KF5::Declarative
KF5::Screen
KF5::DBusAddons
KF5::I18n
KF5::XmlGui
KF5::GlobalAccel)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kscreen.desktop.cmake
${CMAKE_CURRENT_BINARY_DIR}/kscreen.desktop
......@@ -31,3 +42,12 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kscreen.desktop.cmake
kcoreaddons_desktop_to_json(kscreen ${CMAKE_CURRENT_BINARY_DIR}/kscreen.desktop)
install(TARGETS kscreen DESTINATION ${PLUGIN_INSTALL_DIR}/kf5/kded)
set(QML_FILES
qml/Osd.qml
qml/OsdItem.qml
qml/OutputIdentifier.qml
qml/ConfigPicker.qml
)
install(FILES ${QML_FILES} DESTINATION ${DATA_INSTALL_DIR}/kded_kscreen/qml)
......@@ -23,6 +23,7 @@
#include "device.h"
#include "kscreenadaptor.h"
#include "kscreen_daemon_debug.h"
#include "osdmanager.h"
#include <QTimer>
#include <QAction>
......@@ -243,8 +244,18 @@ void KScreenDaemon::showOsd(const QString &icon, const QString &text)
QDBusConnection::sessionBus().asyncCall(msg);
}
void KScreenDaemon::showOutputIdentifier()
{
auto osd = new KScreen::OsdManager(this);
osd->showOutputIdentifiers();
}
void KScreenDaemon::displayButton()
{
showOutputIdentifier();
return;
qCDebug(KSCREEN_KDED) << "displayBtn triggered";
QString message = i18nc("OSD text after XF86Display button press", "No External Display");
......@@ -433,5 +444,4 @@ KScreen::OutputPtr KScreenDaemon::findEmbeddedOutput(const KScreen::ConfigPtr &c
}
#include "daemon.moc"
......@@ -60,6 +60,7 @@ class Q_DECL_EXPORT KScreenDaemon : public KDEDModule
void lidClosedTimeout();
void setMonitorForChanges(bool enabled);
void outputConnectedChanged();
void showOutputIdentifier();
Q_SIGNALS:
void outputConnected(const QString &outputName);
......
/*
* Copyright 2014 (c) Martin Klapetek <mklapetek@kde.org>
* Copyright 2016 Sebastian Kügler <sebas@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "osd.h"
#include "utils.h"
#include <KScreen/Mode>
#include <QDBusConnection>
#include <QLoggingCategory>
#include <QTimer>
#include <QWindow>
#include <QStandardPaths>
#include <QDebug>
#include <QUrl>
#include <QQuickItem>
#include <KDeclarative/QmlObject>
namespace KScreen {
Osd::Osd(QObject *parent)
: QObject(parent)
, m_osdPath(QStandardPaths::locate(QStandardPaths::QStandardPaths::GenericDataLocation, QStringLiteral("kded_kscreen/qml/Osd.qml")))
{
init();
}
Osd::~Osd()
{
}
bool Osd::setRootProperty(const char* name, const QVariant& value)
{
return m_osdObject->rootObject()->setProperty(name, value);
}
void Osd::showOutputIdentifier(const KScreen::OutputPtr output)
{
m_output = output;
if (!init()) {
return;
}
auto *rootObject = m_osdObject->rootObject();
auto mode = output->currentMode();
QSize realSize;
if (output->isHorizontal()) {
realSize = mode->size();
} else {
realSize = QSize(mode->size().height(), mode->size().width());
}
rootObject->setProperty("itemSource", QStringLiteral("OutputIdentifier.qml"));
rootObject->setProperty("modeName", Utils::sizeToString(realSize));
rootObject->setProperty("showingProgress", false);
rootObject->setProperty("outputName", Utils::outputName(output));
rootObject->setProperty("osdValue", Utils::outputName(output));
rootObject->setProperty("icon", QStringLiteral("preferences-desktop-display-randr"));
showOsd();
}
void Osd::updatePosition()
{
if (m_output == nullptr) {
return;
}
auto *rootObject = m_osdObject->rootObject();
const int dialogWidth = rootObject->property("width").toInt();
const int dialogHeight = rootObject->property("height").toInt();
const int relx = m_output->pos().x();
const int rely = m_output->pos().y();
const int pos_x = relx + (m_output->geometry().width() - dialogWidth) / 2;
const int pos_y = rely + (m_output->geometry().height() - dialogHeight) / 2;
rootObject->setProperty("x", pos_x);
rootObject->setProperty("y", pos_y);
}
bool Osd::init()
{
if (m_osdObject && m_osdObject->rootObject()) {
return true;
}
if (m_osdPath.isEmpty()) {
return false;
}
if (!m_osdObject) {
m_osdObject = new KDeclarative::QmlObject(this);
}
m_osdObject->setSource(QUrl::fromLocalFile(m_osdPath));
if (m_osdObject->status() != QQmlComponent::Ready) {
qWarning() << "Failed to load OSD QML file" << m_osdPath;
return false;
}
m_timeout = m_osdObject->rootObject()->property("timeout").toInt();
if (!m_osdTimer) {
m_osdTimer = new QTimer(this);
m_osdTimer->setSingleShot(true);
connect(m_osdTimer, &QTimer::timeout, this, &Osd::hideOsd);
}
return true;
}
void Osd::showProgress(const QString &icon, const int percent, const QString &additionalText)
{
if (!init()) {
return;
}
auto *rootObject = m_osdObject->rootObject();
int value = qBound(0, percent, 100);
rootObject->setProperty("osdValue", value);
rootObject->setProperty("osdAdditionalText", additionalText);
rootObject->setProperty("showingProgress", true);
rootObject->setProperty("icon", icon);
emit osdProgress(icon, value, additionalText);
showOsd();
}
void Osd::showText(const QString &icon, const QString &text)
{
if (!init()) {
return;
}
auto *rootObject = m_osdObject->rootObject();
rootObject->setProperty("showingProgress", false);
rootObject->setProperty("osdValue", text);
rootObject->setProperty("icon", icon);
emit osdText(icon, text);
showOsd();
}
void Osd::showOsd()
{
m_osdTimer->stop();
auto *rootObject = m_osdObject->rootObject();
// if our OSD understands animating the opacity, do it;
// otherwise just show it to not break existing lnf packages
if (rootObject->property("animateOpacity").isValid()) {
rootObject->setProperty("animateOpacity", false);
rootObject->setProperty("opacity", 1);
rootObject->setProperty("visible", true);
rootObject->setProperty("animateOpacity", true);
rootObject->setProperty("opacity", 0);
} else {
rootObject->setProperty("visible", true);
}
updatePosition();
m_osdTimer->start(m_timeout);
}
void Osd::hideOsd()
{
auto *rootObject = m_osdObject->rootObject();
if (!rootObject) {
return;
}
rootObject->setProperty("visible", false);
// this is needed to prevent fading from "old" values when the OSD shows up
rootObject->setProperty("osdValue", 0);
}
} // ns
/*
* Copyright 2014 (c) Martin Klapetek <mklapetek@kde.org>
* Copyright 2016 Sebastian Kügler <sebas@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef OSD_H
#define OSD_H
#include <QObject>
#include <QString>
#include <KScreen/Output>
class QmlObject;
namespace KDeclarative {
class QmlObject;
}
namespace Plasma {
}
class QTimer;
namespace KScreen {
class Osd : public QObject {
Q_OBJECT
public:
Osd(QObject *parent = nullptr);
~Osd() override;
bool setRootProperty(const char *name, const QVariant &value);
void showOutputIdentifier(const KScreen::OutputPtr output);
public Q_SLOTS:
void showText(const QString &icon, const QString &text);
Q_SIGNALS:
void osdProgress(const QString &icon, const int percent, const QString &additionalText);
void osdText(const QString &icon, const QString &text);
private Q_SLOTS:
void hideOsd();
private:
bool init();
void showProgress(const QString &icon, const int percent, const QString &additionalText = QString());
void showOsd();
void updatePosition();
QString m_osdPath;
KDeclarative::QmlObject *m_osdObject = nullptr;
QTimer *m_osdTimer = nullptr;
int m_timeout = 0;
KScreen::OutputPtr m_output;
};
} // ns
#endif // OSD_H
/*
* Copyright 2016 Sebastian Kügler <sebas@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "osdmanager.h"
#include "osd.h"
#include <KScreen/Config>
#include <KScreen/GetConfigOperation>
#include <KScreen/Output>
#include <QDBusConnection>
#include <QLoggingCategory>
#include <QDebug>
namespace KScreen {
OsdManager::OsdManager(QObject *parent)
: QObject(parent)
{
}
OsdManager::~OsdManager()
{
}
void OsdManager::showOutputIdentifiers()
{
connect(new KScreen::GetConfigOperation(), &KScreen::GetConfigOperation::finished,
this, &OsdManager::slotIdentifyOutputs);
}
void OsdManager::slotIdentifyOutputs(KScreen::ConfigOperation *op)
{
if (op->hasError()) {
return;
}
const KScreen::ConfigPtr config = qobject_cast<KScreen::GetConfigOperation*>(op)->config();
Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) {
connect(output.data(), &KScreen::Output::isConnectedChanged,
this, [this](){
KScreen::Output *output = qobject_cast<KScreen::Output*>(sender());
qDebug() << "outputConnectedChanged():" << output->name();
if (!output->isConnected()) {
KScreen::Osd* osd = nullptr;
if (m_osds.keys().contains(output)) {
osd->deleteLater();
m_osds.remove(output);
}
}
},
Qt::UniqueConnection);
if (!output->isConnected() || !output->currentMode()) {
continue;
}
const KScreen::ModePtr mode = output->currentMode();
KScreen::Osd* osd = nullptr;
if (m_osds.keys().contains(output.data())) {
osd = m_osds.value(output.data());
} else {
osd = new KScreen::Osd(output.data());
}
osd->showOutputIdentifier(output);
}
}
}
/*
* Copyright 2016 Sebastian Kügler <sebas@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef OSDM_H
#define OSDM_H
#include <QObject>
#include <QString>
#include <QMap>
class QmlObject;
namespace KScreen {
class ConfigOperation;
class Osd;
class Output;
class OsdManager : public QObject {
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "org.kde.kscreen.osdService")
public:
OsdManager(QObject *parent = nullptr);
~OsdManager() override;
public Q_SLOTS:
void showOutputIdentifiers();
private:
void slotIdentifyOutputs(KScreen::ConfigOperation *op);
QMap<KScreen::Output*, KScreen::Osd*> m_osds;
};
} // ns
#endif // OSDM_H
/*
* Copyright 2014 Martin Klapetek <mklapetek@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtra
import QtQuick.Window 2.2
Item {
property QtObject rootItem
height: Math.min(units.gridUnit * 15, Screen.desktopAvailableHeight / 5)
width: height
// height: rootItem.outputHeight + units.gridUnit
// width: rootItem.outputWidth + units.gridUnit
// objectName: "dialog"
// /--------------------\
// | spacing |
// | /----------------\ |
// | | | |
// | | icon | |
// | | | |
// | | | |
// | \----------------/ |
// | spacing |
// | [progressbar/text] |
// | spacing |
// \--------------------/
PlasmaCore.IconItem {
id: icon
height: parent.height - Math.max(progressBar.height, label.height)
- ((units.smallSpacing/2) * 3) //it's an svg
width: parent.width
source: rootItem.icon
}
PlasmaComponents.ProgressBar {
id: progressBar
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
margins: Math.floor(units.smallSpacing / 2)
}
visible: rootItem.showingProgress
minimumValue: 0
maximumValue: 100
value: Number(rootItem.osdValue)
}
PlasmaExtra.Heading {
id: label
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
margins: Math.floor(units.smallSpacing / 2)
}
visible: !rootItem.showingProgress
text: rootItem.showingProgress ? "" : (rootItem.osdValue ? rootItem.osdValue : "")
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
maximumLineCount: 2
elide: Text.ElideLeft
minimumPointSize: theme.defaultFont.pointSize
fontSizeMode: Text.HorizontalFit
}
Component.onCompleted: {
}
}
/*
* Copyright 2014 Martin Klapetek <mklapetek@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.0
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtra
PlasmaCore.Dialog {
id: root
location: PlasmaCore.Types.Floating
type: PlasmaCore.Dialog.OnScreenDisplay
outputOnly: true
// OSD Timeout in msecs - how long it will stay on the screen
property int timeout: 5000
property int outputHeight: 0
property int outputWidth: 0
// This is either a text or a number, if showingProgress is set to true,
// the number will be used as a value for the progress bar
property var osdValue
// Icon name to display