diff --git a/containments/panel/CMakeLists.txt b/containments/panel/CMakeLists.txt
index 49cb9c9..13e6417 100644
--- a/containments/panel/CMakeLists.txt
+++ b/containments/panel/CMakeLists.txt
@@ -1,25 +1,26 @@
-qt5_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KWin.Screenshot.xml)
+qt5_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KWin.Screenshot.xml
+ dbus/org.kde.KScreen.xml)
set(phonepanel_SRCS
phonepanel.cpp
${DBUS_SRCS}
)
add_library(plasma_applet_phonepanel MODULE ${phonepanel_SRCS})
kcoreaddons_desktop_to_json(plasma_applet_phonepanel package/metadata.desktop)
target_link_libraries(plasma_applet_phonepanel
Qt5::Gui
Qt5::DBus
KF5::Plasma
KF5::I18n
${GSTREAMER_LIBRARIES} GLIB2::GLIB2 ${GOBJECT_LIBRARIES})
target_include_directories(plasma_applet_phonepanel PRIVATE "${GSTREAMER_INCLUDE_DIR}")
install(TARGETS plasma_applet_phonepanel DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/applets)
#install(FILES plasma-phonepanel-default.desktop DESTINATION ${SERVICES_INSTALL_DIR})
plasma_install_package(package org.kde.phone.panel)
diff --git a/containments/panel/dbus/org.kde.KScreen.xml b/containments/panel/dbus/org.kde.KScreen.xml
new file mode 100644
index 0000000..5c6f3a8
--- /dev/null
+++ b/containments/panel/dbus/org.kde.KScreen.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/containments/panel/package/contents/ui/quicksettings/QuickSettings.qml b/containments/panel/package/contents/ui/quicksettings/QuickSettings.qml
index c0fdccf..1e0d79a 100644
--- a/containments/panel/package/contents/ui/quicksettings/QuickSettings.qml
+++ b/containments/panel/package/contents/ui/quicksettings/QuickSettings.qml
@@ -1,261 +1,275 @@
/*
* Copyright 2015 Marco Martin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, 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 Library General Public License for more details
*
* You should have received a copy of the GNU Library 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.
*/
import QtQuick 2.1
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
Item {
id: root
implicitWidth: flow.implicitWidth + units.smallSpacing * 6
implicitHeight: flow.implicitHeight + units.smallSpacing * 6
signal closeRequested
signal closed
property bool screenshotRequested: false
PlasmaNM.Handler {
id: nmHandler
}
PlasmaNM.EnabledConnections {
id: enabledConnections
}
function toggleAirplane() {
print("toggle airplane mode")
}
function toggleTorch() {
plasmoid.nativeInterface.toggleTorch()
}
function toggleWifi() {
nmHandler.enableWireless(!enabledConnections.wirelessEnabled)
settingsModel.get(1).enabled = !enabledConnections.wirelessEnabled
}
function toggleWwan() {
nmHandler.enableWwan(!enabledConnections.wwanEnabled)
settingsModel.get(2).enabled = !enabledConnections.wwanEnabled
}
+ function toggleRotation() {
+ const enable = !plasmoid.nativeInterface.autoRotateEnabled
+ plasmoid.nativeInterface.autoRotateEnabled = enable
+ settingsModel.get(8).enabled = enable
+ }
+
function requestShutdown() {
print("Shutdown requested, depends on ksmserver running");
var service = pmSource.serviceForSource("PowerDevil");
//note the strange camelCasing is intentional
var operation = service.operationDescription("requestShutDown");
return service.startOperationCall(operation);
}
function addPlasmoid(applet) {
settingsModel.append({"icon": applet.icon,
"text": applet.title,
"enabled": false,
"applet": applet,
"settingsCommand": "",
"toggleFunction": ""});
}
signal plasmoidTriggered(var applet, var id)
Layout.minimumHeight: flow.implicitHeight + units.largeSpacing*2
property int screenBrightness
property bool disableBrightnessUpdate: true
readonly property int maximumScreenBrightness: pmSource.data["PowerDevil"] ? pmSource.data["PowerDevil"]["Maximum Screen Brightness"] || 0 : 0
onScreenBrightnessChanged: {
if(!disableBrightnessUpdate) {
var service = pmSource.serviceForSource("PowerDevil");
var operation = service.operationDescription("setBrightness");
operation.brightness = screenBrightness;
operation.silent = true
service.startOperationCall(operation);
}
}
function requestScreenshot() {
screenshotRequested = true;
root.closeRequested();
}
onClosed: {
if (screenshotRequested) {
plasmoid.nativeInterface.takeScreenshot();
screenshotRequested = false;
}
}
PlasmaCore.DataSource {
id: pmSource
engine: "powermanagement"
connectedSources: ["PowerDevil"]
onSourceAdded: {
if (source === "PowerDevil") {
disconnectSource(source);
connectSource(source);
}
}
onDataChanged: {
disableBrightnessUpdate = true;
root.screenBrightness = pmSource.data["PowerDevil"]["Screen Brightness"];
disableBrightnessUpdate = false;
}
}
//HACK: make the list know about the applet delegate which is a qtobject
QtObject {
id: nullApplet
}
Component.onCompleted: {
//NOTE: add all in javascript as the static decl of listelements can't have scripts
settingsModel.append({
"text": i18n("Settings"),
"icon": "configure",
"enabled": false,
"settingsCommand": "plasma-settings",
"toggleFunction": "",
"delegate": "",
"enabled": false,
"applet": null
});
settingsModel.append({
"text": i18n("Wifi"),
"icon": "network-wireless-signal",
"settingsCommand": "",
"toggleFunction": "toggleWifi",
"delegate": "",
"enabled": enabledConnections.wirelessEnabled,
"applet": null
});
settingsModel.append({
"text": i18n("Mobile Data"),
"icon": "network-modem",
"settingsCommand": "",
"toggleFunction": "toggleWwan",
"delegate": "",
"enabled": enabledConnections.wwanEnabled,
"applet": null
});
settingsModel.append({
"text": i18n("Battery"),
"icon": "battery-full",
"enabled": false,
"settingsCommand": "plasma-settings -m kcm_mobile_power",
"toggleFunction": "",
"delegate": "",
"enabled": false,
"applet": null
});
settingsModel.append({
"text": i18n("Sound"),
"icon": "audio-speakers-symbolic",
"enabled": false,
"settingsCommand": "plasma-settings -m kcm_pulseaudio",
"toggleFunction": "",
"delegate": "",
"enabled": false,
"applet": null
});
settingsModel.append({
"text": i18n("Flashlight"),
"icon": "flashlight-on",
"enabled": false,
"settingsCommand": "",
"toggleFunction": "toggleTorch",
"applet": null
});
settingsModel.append({
"text": i18n("Location"),
"icon": "find-location-symbolic",
"enabled": false,
"settingsCommand": "",
"applet": null
});
settingsModel.append({
"text": i18n("Screenshot"),
"icon": "spectacle",
"enabled": false,
"settingsCommand": "",
"toggleFunction": "requestScreenshot",
"applet": null
});
+ settingsModel.append({
+ "text": i18n("Auto-rotate"),
+ "icon": "rotation-allowed",
+ "enabled": plasmoid.nativeInterface.autoRotateEnabled,
+ "settingsCommand": "",
+ "toggleFunction": "toggleRotation",
+ "applet": null
+ });
brightnessSlider.moved.connect(function() {
root.screenBrightness = brightnessSlider.value;
});
disableBrightnessUpdate = false;
}
ListModel {
id: settingsModel
}
Flow {
id: flow
anchors {
fill: parent
margins: units.smallSpacing
}
readonly property real cellSizeHint: units.iconSizes.large + units.smallSpacing * 6
readonly property real columnWidth: Math.floor(width / Math.floor(width / cellSizeHint))
spacing: 0
Repeater {
model: settingsModel
delegate: Loader {
id: loader
//FIXME: why this is needed?
width: flow.columnWidth
height: item ? item.implicitHeight : 0
source: Qt.resolvedUrl((model.delegate ? model.delegate : "Delegate") + ".qml")
Connections {
target: loader.item
onCloseRequested: root.closeRequested();
}
Connections {
target: root
onClosed: loader.item.panelClosed();
}
}
}
move: Transition {
NumberAnimation {
duration: units.shortDuration
easing.type: Easing.InOutQuad
properties: "x,y"
}
}
BrightnessItem {
id: brightnessSlider
width: flow.width
icon: "video-display-brightness"
label: i18n("Display Brightness")
value: root.screenBrightness
maximumValue: root.maximumScreenBrightness
Connections {
target: root
onScreenBrightnessChanged: brightnessSlider.value = root.screenBrightness
}
}
}
}
diff --git a/containments/panel/phonepanel.cpp b/containments/panel/phonepanel.cpp
index f3cd43d..7c8843f 100644
--- a/containments/panel/phonepanel.cpp
+++ b/containments/panel/phonepanel.cpp
@@ -1,134 +1,158 @@
/***************************************************************************
* Copyright (C) 2015 Marco Martin *
* Copyright (C) 2018 Bhushan Shah *
* *
* 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 "phonepanel.h"
#include
#include
#include
#include
#include
#include
#include
#include
constexpr int SCREENSHOT_DELAY = 200;
PhonePanel::PhonePanel(QObject *parent, const QVariantList &args)
: Plasma::Containment(parent, args)
{
//setHasConfigurationInterface(true);
+ m_kscreenInterface = new org::kde::KScreen(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/kscreen"), QDBusConnection::sessionBus(), this);
m_screenshotInterface = new org::kde::kwin::Screenshot(QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"), QDBusConnection::sessionBus(), this);
}
PhonePanel::~PhonePanel() = default;
void PhonePanel::executeCommand(const QString &command)
{
qWarning() << "Executing" << command;
QProcess::startDetached(command);
}
void PhonePanel::toggleTorch()
{
if (!m_running) {
gst_init(nullptr, nullptr);
// create elements
m_source = gst_element_factory_make("droidcamsrc", "source");
m_sink = gst_element_factory_make("fakesink", "sink");
m_pipeline = gst_pipeline_new("torch-pipeline");
if (!m_pipeline || !m_source || !m_sink) {
qDebug() << "Failed to turn on torch: failed to create elements";
return;
}
gst_bin_add_many(GST_BIN(m_pipeline), m_source, m_sink, NULL);
if (gst_element_link(m_source, m_sink) != TRUE) {
qDebug() << "Failed to turn on torch: failed to link source and sink";
g_object_unref(m_pipeline);
return;
}
g_object_set(m_source, "mode", 2, NULL);
g_object_set(m_source, "video-torch", TRUE, NULL);
if (gst_element_set_state(m_pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
qDebug() << "Failed to turn on torch: failed to start pipeline";
g_object_unref(m_pipeline);
return;
}
m_running = true;
} else {
gst_element_set_state(m_pipeline, GST_STATE_NULL);
gst_object_unref(m_pipeline);
m_running = false;
}
}
+bool PhonePanel::autoRotate()
+{
+ QDBusPendingReply reply = m_kscreenInterface->getAutoRotate();
+ reply.waitForFinished();
+ if (reply.isError()) {
+ qWarning() << "Getting auto rotate failed:" << reply.error().name() << reply.error().message();
+ return false;
+ } else {
+ return reply.value();
+ }
+}
+
+void PhonePanel::setAutoRotate(bool value)
+{
+ QDBusPendingReply<> reply = m_kscreenInterface->setAutoRotate(value);
+ reply.waitForFinished();
+ if (reply.isError()) {
+ qWarning() << "Setting auto rotate failed:" << reply.error().name() << reply.error().message();
+ } else {
+ emit autoRotateChanged(value);
+ }
+}
+
void PhonePanel::takeScreenshot()
{
// wait ~200 ms to wait for rest of animations
QTimer::singleShot(SCREENSHOT_DELAY, [=]() {
// screenshot fullscreen currently doesn't work on all devices -> we need to use screenshot area
// this won't work with multiple screens
QSize screenSize = QGuiApplication::primaryScreen()->size();
QDBusPendingReply reply = m_screenshotInterface->screenshotArea(0, 0, screenSize.width(), screenSize.height());
auto *watcher = new QDBusPendingCallWatcher(reply, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [=](QDBusPendingCallWatcher *watcher) {
QDBusPendingReply reply = *watcher;
if (reply.isError()) {
qWarning() << "Creating the screenshot failed:" << reply.error().name() << reply.error().message();
} else {
QString filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
if (filePath.isEmpty()) {
qWarning() << "Couldn't find a writable location for the screenshot! The screenshot is in /tmp.";
return;
}
QDir picturesDir(filePath);
if (!picturesDir.mkpath(QStringLiteral("Screenshots"))) {
qWarning() << "Couldn't create folder at"
<< picturesDir.path() + QStringLiteral("/Screenshots")
<< "to take screenshot.";
return;
}
filePath += QStringLiteral("/Screenshots/Screenshot_%1.png")
.arg(QDateTime::currentDateTime().toString(QStringLiteral("yyyyMMdd_hhmmss")));
const QString currentPath = reply.argumentAt<0>();
QtConcurrent::run(QThreadPool::globalInstance(), [=]() {
QFile screenshotFile(currentPath);
if (!screenshotFile.rename(filePath)) {
qWarning() << "Couldn't move screenshot into Pictures folder:"
<< screenshotFile.errorString();
}
qDebug() << "Successfully saved screenshot at" << filePath;
});
}
watcher->deleteLater();
});
});
}
K_EXPORT_PLASMA_APPLET_WITH_JSON(quicksettings, PhonePanel, "metadata.json")
#include "phonepanel.moc"
diff --git a/containments/panel/phonepanel.h b/containments/panel/phonepanel.h
index 4e0bc67..4403fff 100644
--- a/containments/panel/phonepanel.h
+++ b/containments/panel/phonepanel.h
@@ -1,53 +1,62 @@
/***************************************************************************
* Copyright (C) 2015 Marco Martin *
*
* *
* 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 PHONEPANEL_H
#define PHONEPANEL_H
#include
#include
+#include "kscreeninterface.h"
#include "screenshotinterface.h"
class PhonePanel : public Plasma::Containment
{
Q_OBJECT
+ Q_PROPERTY(bool autoRotateEnabled READ autoRotate WRITE setAutoRotate NOTIFY autoRotateChanged);
public:
PhonePanel( QObject *parent, const QVariantList &args );
~PhonePanel() override;
public Q_SLOTS:
void executeCommand(const QString &command);
void toggleTorch();
void takeScreenshot();
+ bool autoRotate();
+ void setAutoRotate(bool value);
+
+signals:
+ void autoRotateChanged(bool value);
+
private:
GstElement* m_pipeline;
GstElement* m_sink;
GstElement* m_source;
bool m_running = false;
+ org::kde::KScreen *m_kscreenInterface;
org::kde::kwin::Screenshot *m_screenshotInterface;
};
#endif