diff --git a/kded/osd.cpp b/kded/osd.cpp index 3d19e56..9d738ae 100644 --- a/kded/osd.cpp +++ b/kded/osd.cpp @@ -1,208 +1,218 @@ /* * Copyright 2014 Martin Klapetek * Copyright 2016 Sebastian Kügler * * 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_daemon_debug.h" #include #include #include #include -#include +#include using namespace KScreen; Osd::Osd(const KScreen::OutputPtr &output, QObject *parent) : QObject(parent) , m_output(output) { connect(output.data(), &KScreen::Output::isConnectedChanged, this, &Osd::onOutputAvailabilityChanged); connect(output.data(), &KScreen::Output::isEnabledChanged, this, &Osd::onOutputAvailabilityChanged); connect(output.data(), &KScreen::Output::currentModeIdChanged, this, &Osd::updatePosition); connect(output.data(), &KScreen::Output::destroyed, this, &Osd::hideOsd); } Osd::~Osd() { } bool Osd::initOsd() { if (m_osdObject) { return true; } const QString osdPath = QStandardPaths::locate(QStandardPaths::QStandardPaths::GenericDataLocation, QStringLiteral("kded_kscreen/qml/Osd.qml")); if (osdPath.isEmpty()) { qCWarning(KSCREEN_KDED) << "Failed to find OSD QML file" << osdPath; return false; } - m_osdObject = new KDeclarative::QmlObject(this); + m_osdObject = new KDeclarative::QmlObjectSharedEngine(this); m_osdObject->setSource(QUrl::fromLocalFile(osdPath)); if (m_osdObject->status() != QQmlComponent::Ready) { qCWarning(KSCREEN_KDED) << "Failed to load OSD QML file" << osdPath; delete m_osdObject; m_osdObject = nullptr; return false; } m_timeout = m_osdObject->rootObject()->property("timeout").toInt(); m_osdTimer = new QTimer(this); m_osdTimer->setSingleShot(true); connect(m_osdTimer, &QTimer::timeout, this, &Osd::hideOsd); return true; } void Osd::showGenericOsd(const QString &icon, const QString &text) { if (!initOsd()) { return; } m_outputGeometry = m_output->geometry(); auto *rootObject = m_osdObject->rootObject(); rootObject->setProperty("itemSource", QStringLiteral("OsdItem.qml")); rootObject->setProperty("infoText", text); rootObject->setProperty("icon", icon); showOsd(); } void Osd::showOutputIdentifier(const KScreen::OutputPtr &output) { if (!initOsd()) { return; } m_outputGeometry = output->geometry(); auto *rootObject = m_osdObject->rootObject(); auto mode = output->currentMode(); QSize realSize = mode->size(); if (!output->isHorizontal()) { realSize.transpose(); } rootObject->setProperty("itemSource", QStringLiteral("OutputIdentifier.qml")); rootObject->setProperty("modeName", Utils::sizeToString(realSize)); rootObject->setProperty("outputName", Utils::outputName(output)); showOsd(); } void Osd::showActionSelector() { - if (!initOsd()) { - return; - } - - m_outputGeometry = m_output->geometry(); - auto *rootObject = m_osdObject->rootObject(); - rootObject->setProperty("itemSource", QStringLiteral("OsdSelector.qml")); - rootObject->setProperty("timeout", 0); - rootObject->setProperty("outputOnly", false); - auto osdItem = rootObject->property("osdItem").value(); - connect(osdItem, SIGNAL(clicked(int)), - this, SLOT(onOsdActionSelected(int))); - m_timeout = 0; // no timeout for this one + 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; + 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; + delete m_osdActionSelector; + m_osdActionSelector = nullptr; + return; + } - showOsd(); + auto *rootObject = m_osdActionSelector->rootObject(); + connect(rootObject, SIGNAL(clicked(int)), + this, SLOT(onOsdActionSelected(int))); + } + if (auto *rootObject = m_osdActionSelector->rootObject()) { + rootObject->setProperty("visible", true); + } else { + qCWarning(KSCREEN_KDED) << "Could not get root object for action selector."; + } } void Osd::onOsdActionSelected(int action) { Q_EMIT osdActionSelected(static_cast(action)); hideOsd(); } void Osd::onOutputAvailabilityChanged() { if (!m_output || !m_output->isConnected() || !m_output->isEnabled() || !m_output->currentMode()) { hideOsd(); } } void Osd::updatePosition() { if (!initOsd()) { return; } const auto geometry = m_output->geometry(); if (!geometry.isValid()) { hideOsd(); } auto *rootObject = m_osdObject->rootObject(); const int dialogWidth = rootObject->property("width").toInt(); const int dialogHeight = rootObject->property("height").toInt(); const int relx = geometry.x(); const int rely = geometry.y(); const int pos_x = relx + (geometry.width() - dialogWidth) / 2; const int pos_y = rely + (geometry.height() - dialogHeight) / 2; rootObject->setProperty("x", pos_x); rootObject->setProperty("y", pos_y); } void Osd::showOsd() { m_osdTimer->stop(); auto *rootObject = m_osdObject->rootObject(); // only animate on X11, wayland plugin doesn't support this and // pukes loads of warnings into our logs if (qGuiApp->platformName() == QLatin1String("xcb")) { if (rootObject->property("timeout").toInt() > 0) { rootObject->setProperty("animateOpacity", false); rootObject->setProperty("opacity", 1); rootObject->setProperty("animateOpacity", true); rootObject->setProperty("opacity", 0); } } rootObject->setProperty("visible", true); QTimer::singleShot(0, this, &Osd::updatePosition); if (m_timeout > 0) { m_osdTimer->start(m_timeout); } } void Osd::hideOsd() { - if (!initOsd()) { - return; + if (m_osdActionSelector) { + if (auto *rootObject = m_osdActionSelector->rootObject()) { + rootObject->setProperty("visible", false); + } } - - auto *rootObject = m_osdObject->rootObject(); - if (!rootObject) { - return; + if (m_osdObject) { + if (auto *rootObject = m_osdObject->rootObject()) { + rootObject->setProperty("visible", false); + } } - rootObject->setProperty("visible", false); } - diff --git a/kded/osd.h b/kded/osd.h index d810209..73c0b36 100644 --- a/kded/osd.h +++ b/kded/osd.h @@ -1,74 +1,74 @@ /* * Copyright 2014 Martin Klapetek * Copyright 2016 Sebastian Kügler * * 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 KSCREEN_OSD_H #define KSCREEN_OSD_H #include #include #include #include #include "osdmanager.h" namespace KDeclarative { class QmlObject; } class QTimer; namespace KScreen { class Osd : public QObject { Q_OBJECT public: explicit Osd(const OutputPtr &output, QObject *parent = nullptr); ~Osd() override; void showGenericOsd(const QString &icon, const QString &text); void showOutputIdentifier(const KScreen::OutputPtr &output); void showActionSelector(); void hideOsd(); Q_SIGNALS: void osdActionSelected(OsdAction::Action action); private Q_SLOTS: void onOsdActionSelected(int action); void onOutputAvailabilityChanged(); private: bool initOsd(); void showOsd(); void updatePosition(); KScreen::OutputPtr m_output; QRect m_outputGeometry; KDeclarative::QmlObject *m_osdObject = nullptr; + KDeclarative::QmlObject *m_osdActionSelector = nullptr; QTimer *m_osdTimer = nullptr; int m_timeout = 0; - }; } // ns #endif // KSCREEN_OSD_H diff --git a/kded/qml/OsdSelector.qml b/kded/qml/OsdSelector.qml index b1c7437..eb26f51 100644 --- a/kded/qml/OsdSelector.qml +++ b/kded/qml/OsdSelector.qml @@ -1,117 +1,119 @@ /* * Copyright 2017 Daniel Vrátil * * 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 . */ import QtQuick 2.5 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 PlasmaExtras import org.kde.KScreen 1.0 -Item { +PlasmaCore.Dialog { id: root - property QtObject rootItem + location: PlasmaCore.Types.Floating + type: PlasmaCore.Dialog.Normal + property string infoText signal clicked(int actionId) - height: Math.min(units.gridUnit * 15, Screen.desktopAvailableHeight / 5) - width: buttonRow.width - - PlasmaComponents.ButtonRow { - id: buttonRow - - exclusive: false - - height: parent.height - label.height - ((units.smallSpacing/2) * 3) - width: (actionRepeater.count * height) + ((actionRepeater.count - 1) * buttonRow.spacing); - - Repeater { - id: actionRepeater - model: [ - { - iconSource: "osd-shutd-laptop", - label: i18n("Switch to external screen"), - action: OsdAction.SwitchToExternal - }, - { - iconSource: "osd-shutd-screen", - label: i18n("Switch to laptop screen"), - action: OsdAction.SwitchToInternal - }, - { - iconSource: "osd-duplicate", - label: i18n("Unify outputs"), - action: OsdAction.Clone - }, - { - iconSource: "osd-sbs-left", - label: i18n("Extend to left"), - action: OsdAction.ExtendLeft - }, - { - iconSource: "osd-sbs-sright", - label: i18n("Extend to right"), - action: OsdAction.ExtendRight - }, - { - iconSource: "dialog-cancel", - label: i18n("Leave unchanged"), - action: OsdAction.NoAction + mainItem: Item { + height: Math.min(units.gridUnit * 15, Screen.desktopAvailableHeight / 5) + width: buttonRow.width + + PlasmaComponents.ButtonRow { + id: buttonRow + exclusive: false + + height: parent.height - label.height - ((units.smallSpacing/2) * 3) + width: (actionRepeater.count * height) + ((actionRepeater.count - 1) * buttonRow.spacing); + + Repeater { + id: actionRepeater + model: [ + { + iconSource: "osd-shutd-laptop", + label: i18n("Switch to external screen"), + action: OsdAction.SwitchToExternal + }, + { + iconSource: "osd-shutd-screen", + label: i18n("Switch to laptop screen"), + action: OsdAction.SwitchToInternal + }, + { + iconSource: "osd-duplicate", + label: i18n("Unify outputs"), + action: OsdAction.Clone + }, + { + iconSource: "osd-sbs-left", + label: i18n("Extend to left"), + action: OsdAction.ExtendLeft + }, + { + iconSource: "osd-sbs-sright", + label: i18n("Extend to right"), + action: OsdAction.ExtendRight + }, + { + iconSource: "dialog-cancel", + label: i18n("Leave unchanged"), + action: OsdAction.NoAction + } + ] + delegate: PlasmaComponents.Button { + Accessible.name: modelData.label + PlasmaCore.IconItem { + source: modelData.iconSource + height: buttonRow.height - ((units.smallSpacing / 2) * 3) + width: height + anchors.centerIn: parent } - ] - delegate: PlasmaComponents.Button { - Accessible.name: modelData.label - PlasmaCore.IconItem { - source: modelData.iconSource - height: buttonRow.height - ((units.smallSpacing / 2) * 3) + height: parent.height width: height - anchors.centerIn: parent - } - height: parent.height - width: height - onHoveredChanged: rootItem.infoText = (hovered ? modelData.label : "") + onHoveredChanged: root.infoText = (hovered ? modelData.label : "") - onClicked: root.clicked(modelData.action) + onClicked: root.clicked(modelData.action) + } } } - } - // TODO: keep? remove? - PlasmaExtras.Heading { - id: label - anchors { - bottom: parent.bottom - left: parent.left - right: parent.right - margins: Math.floor(units.smallSpacing / 2) + PlasmaExtras.Heading { + id: label + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + margins: Math.floor(units.smallSpacing / 2) + } + + text: root.infoText + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + maximumLineCount: 2 + elide: Text.ElideLeft + minimumPointSize: theme.defaultFont.pointSize + fontSizeMode: Text.HorizontalFit } - text: rootItem.infoText - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap - maximumLineCount: 2 - elide: Text.ElideLeft - minimumPointSize: theme.defaultFont.pointSize - fontSizeMode: Text.HorizontalFit + Component.onCompleted: print("OsdSelector loaded..."); } - - Component.onCompleted: print("OsdSelector loaded..."); }