Commit 1dd63227 authored by Devin Lin's avatar Devin Lin 🎨
Browse files

quicksettings/screenshot: Move C++ out of ShellUtil into package

parent 24c5b4a6
Pipeline #151161 failed with stages
in 37 seconds
......@@ -7,8 +7,7 @@ if (BUILD_TESTING)
add_subdirectory(autotests)
endif()
qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KWin.ScreenShot2.xml
dbus/org.kde.KScreen.xml
qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KScreen.xml
${KWIN_VIRTUALKEYBOARD_INTERFACE})
set(mobileshell_LIB_SRCS
......
......@@ -31,8 +31,6 @@
using namespace MobileShell;
constexpr int SCREENSHOT_DELAY = 200;
/* -- Static Helpers --------------------------------------------------------------------------- */
static QImage allocateImage(const QVariantMap &metadata)
......@@ -81,10 +79,6 @@ ShellUtil::ShellUtil(QObject *parent)
{
// setHasConfigurationInterface(true);
m_kscreenInterface = new org::kde::KScreen(QStringLiteral("org.kde.kded5"), QStringLiteral("/modules/kscreen"), QDBusConnection::sessionBus(), this);
m_screenshotInterface = new OrgKdeKWinScreenShot2Interface(QStringLiteral("org.kde.KWin.ScreenShot2"),
QStringLiteral("/org/kde/KWin/ScreenShot2"),
QDBusConnection::sessionBus(),
this);
m_localeConfig = KSharedConfig::openConfig(QStringLiteral("kdeglobals"), KConfig::SimpleConfig);
m_localeConfigWatcher = KConfigWatcher::create(m_localeConfig);
......@@ -130,10 +124,12 @@ void ShellUtil::toggleTorch()
m_running = !m_running;
Q_EMIT torchChanged(m_running);
}
bool ShellUtil::torchEnabled() const
{
return m_running;
}
bool ShellUtil::autoRotate()
{
QDBusPendingReply<bool> reply = m_kscreenInterface->getAutoRotate();
......@@ -157,76 +153,6 @@ void ShellUtil::setAutoRotate(bool value)
}
}
void ShellUtil::handleMetaDataReceived(const QVariantMap &metadata, int fd)
{
const QString type = metadata.value(QStringLiteral("type")).toString();
if (type != QLatin1String("raw")) {
qWarning() << "Unsupported metadata type:" << type;
return;
}
auto watcher = new QFutureWatcher<QImage>(this);
connect(watcher, &QFutureWatcher<QImage>::finished, this, [watcher]() {
watcher->deleteLater();
QString filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
if (filePath.isEmpty()) {
qWarning() << "Couldn't find a writable location for the screenshot!";
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 auto m_result = watcher->result();
if (m_result.isNull() || !m_result.save(filePath)) {
qWarning() << "Screenshot failed";
} else {
KNotification *notif = new KNotification("captured");
notif->setComponentName(QStringLiteral("plasma_phone_components"));
notif->setTitle(i18n("New Screenshot"));
notif->setUrls({QUrl::fromLocalFile(filePath)});
notif->setText(i18n("New screenshot saved to %1", filePath));
notif->sendEvent();
}
});
watcher->setFuture(QtConcurrent::run(readImage, fd, metadata));
}
void ShellUtil::takeScreenshot()
{
// wait ~200 ms to wait for rest of animations
QTimer::singleShot(SCREENSHOT_DELAY, [=]() {
int lPipeFds[2];
if (pipe2(lPipeFds, O_CLOEXEC) != 0) {
qWarning() << "Could not take screenshot";
return;
}
// We don't have access to the ScreenPool so we'll just take the first screen
QVariantMap options;
options.insert(QStringLiteral("native-resolution"), true);
auto pendingCall = m_screenshotInterface->CaptureScreen(qGuiApp->screens().constFirst()->name(), options, QDBusUnixFileDescriptor(lPipeFds[1]));
close(lPipeFds[1]);
auto pipeFileDescriptor = lPipeFds[0];
auto watcher = new QDBusPendingCallWatcher(pendingCall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher, pipeFileDescriptor]() {
watcher->deleteLater();
const QDBusPendingReply<QVariantMap> reply = *watcher;
if (reply.isError()) {
qWarning() << "Screenshot request failed:" << reply.error().message();
} else {
handleMetaDataReceived(reply, pipeFileDescriptor);
}
});
});
}
bool ShellUtil::isSystem24HourFormat()
{
KConfigGroup localeSettings = KConfigGroup(m_localeConfig, "Locale");
......
......@@ -36,7 +36,6 @@ public Q_SLOTS:
void executeCommand(const QString &command);
void launchApp(const QString &app);
void toggleTorch();
void takeScreenshot();
bool autoRotate();
void setAutoRotate(bool value);
......@@ -51,14 +50,12 @@ Q_SIGNALS:
void isSystem24HourFormatChanged();
private:
void handleMetaDataReceived(const QVariantMap &metadata, int fd);
bool m_running = false;
KConfigWatcher::Ptr m_localeConfigWatcher;
KSharedConfig::Ptr m_localeConfig;
org::kde::KScreen *m_kscreenInterface;
OrgKdeKWinScreenShot2Interface *m_screenshotInterface;
};
} // namespace MobileShell
......@@ -11,8 +11,8 @@ plasma_install_package(keyboardtoggle org.kde.plasma.keyboardtoggle quicksetting
plasma_install_package(location org.kde.plasma.location quicksettings)
plasma_install_package(mobiledata org.kde.plasma.mobiledata quicksettings)
plasma_install_package(screenrotation org.kde.plasma.screenrotation quicksettings)
plasma_install_package(screenshot org.kde.plasma.screenshot quicksettings)
plasma_install_package(settingsapp org.kde.plasma.settingsapp quicksettings)
plasma_install_package(wifi org.kde.plasma.wifi quicksettings)
add_subdirectory(nightcolor)
add_subdirectory(powermenu)
add_subdirectory(screenshot)
# SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
# SPDX-License-Identifier: GPL-2.0-or-later
qt_add_dbus_interfaces(DBUS_SRCS dbus/org.kde.KWin.ScreenShot2.xml)
set(screenshotplugin_SRCS
screenshotplugin.cpp
screenshotutil.cpp
${DBUS_SRCS}
)
add_library(screenshotplugin ${screenshotplugin_SRCS})
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
Declarative
)
target_link_libraries(screenshotplugin
PUBLIC
Qt::Core
PRIVATE
Qt::DBus
KF5::CoreAddons
KF5::QuickAddons
KF5::ConfigCore
KF5::ConfigGui
KF5::I18n
KF5::Notifications
)
set_property(TARGET screenshotplugin PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/plasma/quicksetting/screenshot)
file(COPY qmldir DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/org/kde/plasma/quicksetting/screenshot)
install(TARGETS screenshotplugin DESTINATION ${QML_INSTALL_DIR}/org/kde/plasma/quicksetting/screenshot)
install(FILES qmldir ${qml_SRC} DESTINATION ${QML_INSTALL_DIR}/org/kde/plasma/quicksetting/screenshot)
plasma_install_package(package org.kde.plasma.screenshot quicksettings)
......@@ -4,6 +4,7 @@
import QtQuick 2.15
import org.kde.plasma.private.mobileshell 1.0 as MobileShell
import org.kde.plasma.quicksetting.screenshot 1.0
MobileShell.QuickSetting {
text: i18n("Screenshot")
......@@ -32,6 +33,6 @@ MobileShell.QuickSetting {
Timer {
id: timer
interval: 500
onTriggered: MobileShell.ShellUtil.takeScreenshot()
onTriggered: ScreenShotUtil.takeScreenShot()
}
}
# SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
# SPDX-License-Identifier: GPL-2.0-or-later
module org.kde.plasma.quicksetting.screenshot
plugin screenshotplugin
classname ScreenShotPlugin
/*
* SPDX-FileCopyrightText: 2022 by Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "screenshotplugin.h"
#include <QQmlContext>
#include <QQuickItem>
#include "screenshotutil.h"
void ScreenShotPlugin::registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.plasma.quicksetting.screenshot"));
qmlRegisterSingletonType<ScreenShotUtil>(uri, 1, 0, "ScreenShotUtil", [](QQmlEngine *, QJSEngine *) {
return new ScreenShotUtil;
});
}
//#include "moc_nightcolorplugin.cpp"
/*
* SPDX-FileCopyrightText: 2022 by Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QUrl>
#include <QQmlEngine>
#include <QQmlExtensionPlugin>
class ScreenShotPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
void registerTypes(const char *uri) override;
};
/*
* SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
* SPDX-FileCopyrightText: 2018 Bhushan Shah <bshah@kde.org>
* SPDX-FileCopyrightText: 2022 by Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "screenshotutil.h"
#include <fcntl.h>
#include <qplatformdefs.h>
#include <unistd.h>
#include <KLocalizedString>
#include <KNotification>
#include <QGuiApplication>
#include <QImage>
#include <QScreen>
#include <QTimer>
#include <QtConcurrent/QtConcurrent>
constexpr int SCREENSHOT_DELAY = 200;
/* -- Static Helpers --------------------------------------------------------------------------- */
static QImage allocateImage(const QVariantMap &metadata)
{
bool ok;
const uint width = metadata.value(QStringLiteral("width")).toUInt(&ok);
if (!ok) {
return QImage();
}
const uint height = metadata.value(QStringLiteral("height")).toUInt(&ok);
if (!ok) {
return QImage();
}
const uint format = metadata.value(QStringLiteral("format")).toUInt(&ok);
if (!ok) {
return QImage();
}
return QImage(width, height, QImage::Format(format));
}
static QImage readImage(int fileDescriptor, const QVariantMap &metadata)
{
QFile file;
if (!file.open(fileDescriptor, QFileDevice::ReadOnly, QFileDevice::AutoCloseHandle)) {
close(fileDescriptor);
return QImage();
}
QImage result = allocateImage(metadata);
if (result.isNull()) {
return QImage();
}
QDataStream stream(&file);
stream.readRawData(reinterpret_cast<char *>(result.bits()), result.sizeInBytes());
return result;
}
ScreenShotUtil::ScreenShotUtil(QObject *parent)
: QObject{parent}
{
m_screenshotInterface = new OrgKdeKWinScreenShot2Interface(QStringLiteral("org.kde.KWin.ScreenShot2"),
QStringLiteral("/org/kde/KWin/ScreenShot2"),
QDBusConnection::sessionBus(),
this);
}
void ScreenShotUtil::takeScreenShot()
{
// wait ~200 ms to wait for rest of animations
QTimer::singleShot(SCREENSHOT_DELAY, [=]() {
int lPipeFds[2];
if (pipe2(lPipeFds, O_CLOEXEC) != 0) {
qWarning() << "Could not take screenshot";
return;
}
// We don't have access to the ScreenPool so we'll just take the first screen
QVariantMap options;
options.insert(QStringLiteral("native-resolution"), true);
auto pendingCall = m_screenshotInterface->CaptureScreen(qGuiApp->screens().constFirst()->name(), options, QDBusUnixFileDescriptor(lPipeFds[1]));
close(lPipeFds[1]);
auto pipeFileDescriptor = lPipeFds[0];
auto watcher = new QDBusPendingCallWatcher(pendingCall, this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [this, watcher, pipeFileDescriptor]() {
watcher->deleteLater();
const QDBusPendingReply<QVariantMap> reply = *watcher;
if (reply.isError()) {
qWarning() << "Screenshot request failed:" << reply.error().message();
} else {
handleMetaDataReceived(reply, pipeFileDescriptor);
}
});
});
}
void ScreenShotUtil::handleMetaDataReceived(const QVariantMap &metadata, int fd)
{
const QString type = metadata.value(QStringLiteral("type")).toString();
if (type != QLatin1String("raw")) {
qWarning() << "Unsupported metadata type:" << type;
return;
}
auto watcher = new QFutureWatcher<QImage>(this);
connect(watcher, &QFutureWatcher<QImage>::finished, this, [watcher]() {
watcher->deleteLater();
QString filePath = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
if (filePath.isEmpty()) {
qWarning() << "Couldn't find a writable location for the screenshot!";
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 auto m_result = watcher->result();
if (m_result.isNull() || !m_result.save(filePath)) {
qWarning() << "Screenshot failed";
} else {
KNotification *notif = new KNotification("captured");
notif->setComponentName(QStringLiteral("plasma_phone_components"));
notif->setTitle(i18n("New Screenshot"));
notif->setUrls({QUrl::fromLocalFile(filePath)});
notif->setText(i18n("New screenshot saved to %1", filePath));
notif->sendEvent();
}
});
watcher->setFuture(QtConcurrent::run(readImage, fd, metadata));
}
/*
* SPDX-FileCopyrightText: 2022 by Devin Lin <devin@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <QObject>
#include <QVariantMap>
#include "screenshot2interface.h"
class ScreenShotUtil : public QObject
{
Q_OBJECT
public:
ScreenShotUtil(QObject *parent = nullptr);
Q_INVOKABLE void takeScreenShot();
void handleMetaDataReceived(const QVariantMap &metadata, int fd);
private:
OrgKdeKWinScreenShot2Interface *m_screenshotInterface;
};
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