diff --git a/src/background.cpp b/src/background.cpp
index 6a4918b..c43bdd0 100644
--- a/src/background.cpp
+++ b/src/background.cpp
@@ -1,230 +1,237 @@
/*
* Copyright © 2020 Red Hat, Inc
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see .
*
* Authors:
* Jan Grulich
*/
#include "background.h"
#include "utils.h"
#include "waylandintegration.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
Q_LOGGING_CATEGORY(XdgDesktopPortalKdeBackground, "xdp-kde-background")
BackgroundPortal::BackgroundPortal(QObject *parent)
: QDBusAbstractAdaptor(parent)
{
connect(WaylandIntegration::waylandIntegration(), &WaylandIntegration::WaylandIntegration::plasmaWindowManagementInitialized, this, [=] () {
connect(WaylandIntegration::plasmaWindowManagement(), &KWayland::Client::PlasmaWindowManagement::windowCreated, this, [this] (KWayland::Client::PlasmaWindow *window) {
addWindow(window);
});
m_windows = WaylandIntegration::plasmaWindowManagement()->windows();
for (KWayland::Client::PlasmaWindow *window : m_windows) {
addWindow(window);
}
});
}
BackgroundPortal::~BackgroundPortal()
{
}
QVariantMap BackgroundPortal::GetAppState()
{
qCDebug(XdgDesktopPortalKdeBackground) << "GetAppState called: no parameters";
return m_appStates;
}
uint BackgroundPortal::NotifyBackground(const QDBusObjectPath &handle,
const QString &app_id,
const QString &name,
QVariantMap &results)
{
Q_UNUSED(results);
qCDebug(XdgDesktopPortalKdeBackground) << "NotifyBackground called with parameters:";
qCDebug(XdgDesktopPortalKdeBackground) << " handle: " << handle.path();
qCDebug(XdgDesktopPortalKdeBackground) << " app_id: " << app_id;
qCDebug(XdgDesktopPortalKdeBackground) << " name: " << name;
+ // If KWayland::Client::PlasmaWindowManagement hasn't been created, we would be notified about every
+ // application, which is not what we want. This will be mostly happening on X11 session.
+ if (!WaylandIntegration::plasmaWindowManagement()) {
+ results.insert(QStringLiteral("result"), static_cast(BackgroundPortal::Ignore));
+ return 0;
+ }
+
KNotification *notify = new KNotification(QStringLiteral("notification"), KNotification::Persistent | KNotification::DefaultEvent, this);
notify->setTitle(i18n("Background activity"));
notify->setText(i18n("%1 is running in the background.", app_id));
notify->setActions({i18n("Find out more")});
notify->setProperty("activated", false);
QObject *obj = QObject::parent();
if (!obj) {
qCWarning(XdgDesktopPortalKdeBackground) << "Failed to get dbus context";
return 2;
}
void *ptr = obj->qt_metacast("QDBusContext");
QDBusContext *q_ptr = reinterpret_cast(ptr);
if (!q_ptr) {
qCWarning(XdgDesktopPortalKdeBackground) << "Failed to get dbus context";
return 2;
}
QDBusMessage reply;
QDBusMessage message = q_ptr->message();
message.setDelayedReply(true);
connect(notify, QOverload::of(&KNotification::activated), this, [=] (uint action) {
if (action != 1) {
return;
}
notify->setProperty("activated", true);
const QString title = i18n("%1 is running in the background", app_id);
const QString text = i18n("This might be for a legitimate reason, but the application has not provided one."
"\n\nNote that forcing an application to quit might cause data loss.");
QMessageBox messageBox(QMessageBox::Question, title, text);
QPushButton *quitButton = messageBox.addButton(i18n("Force quit"), QMessageBox::RejectRole);
QPushButton *allowButton = messageBox.addButton(i18n("Allow"), QMessageBox::AcceptRole);
messageBox.exec();
BackgroundPortal::NotifyResult result = BackgroundPortal::Ignore;
if (messageBox.clickedButton() == quitButton) {
result = BackgroundPortal::Forbid;
} else if (messageBox.clickedButton() == allowButton) {
result = BackgroundPortal::Allow;
}
const QVariantMap map = { {QStringLiteral("result"), static_cast(result)} };
QDBusMessage reply = message.createReply({static_cast(0), map});
if (!QDBusConnection::sessionBus().send(reply)) {
qCWarning(XdgDesktopPortalKdeBackground) << "Failed to send response";
}
});
connect(notify, &KNotification::closed, this, [=] () {
if (notify->property("activated").toBool()) {
return;
}
QVariantMap map;
map.insert(QStringLiteral("result"), static_cast(BackgroundPortal::Ignore));
QDBusMessage reply = message.createReply({static_cast(0), map});
if (!QDBusConnection::sessionBus().send(reply)) {
qCWarning(XdgDesktopPortalKdeBackground) << "Failed to send response";
}
});
notify->sendEvent();
return 0;
}
bool BackgroundPortal::EnableAutostart(const QString &app_id,
bool enable,
const QStringList &commandline,
uint flags)
{
qCDebug(XdgDesktopPortalKdeBackground) << "EnableAutostart called with parameters:";
qCDebug(XdgDesktopPortalKdeBackground) << " app_id: " << app_id;
qCDebug(XdgDesktopPortalKdeBackground) << " enable: " << enable;
qCDebug(XdgDesktopPortalKdeBackground) << " commandline: " << commandline;
qCDebug(XdgDesktopPortalKdeBackground) << " flags: " << flags;
const QString fileName = app_id + QStringLiteral(".desktop");
const QString directory = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + QStringLiteral("/autostart/");
const QString fullPath = directory + fileName;
const AutostartFlags autostartFlags = static_cast(flags);
if (!enable) {
QFile file(fullPath);
if (!file.remove()) {
qCDebug(XdgDesktopPortalKdeBackground) << "Failed to remove " << fileName << " to disable autostart.";
}
return false;
}
QDir dir(directory);
if (!dir.mkpath(dir.absolutePath())) {
qCDebug(XdgDesktopPortalKdeBackground) << "Failed to create autostart directory.";
return false;
}
KDesktopFile desktopFile(fullPath);
KConfigGroup desktopEntryConfigGroup = desktopFile.desktopGroup();
desktopEntryConfigGroup.writeEntry(QStringLiteral("Type"), QStringLiteral("Application"));
desktopEntryConfigGroup.writeEntry(QStringLiteral("Name"), app_id);
desktopEntryConfigGroup.writeEntry(QStringLiteral("Exec"), KShell::joinArgs(commandline));
if (autostartFlags.testFlag(AutostartFlag::Activatable)) {
desktopEntryConfigGroup.writeEntry(QStringLiteral("DBusActivatable"), true);
}
desktopEntryConfigGroup.writeEntry(QStringLiteral("X-Flatpak"), app_id);
return true;
}
void BackgroundPortal::addWindow(KWayland::Client::PlasmaWindow *window)
{
const QString appId = window->appId();
const bool isActive = window->isActive();
m_appStates[appId] = QVariant::fromValue(isActive ? Active : Running);
connect(window, &KWayland::Client::PlasmaWindow::activeChanged, this, [this, window] () {
setActiveWindow(window->appId(), window->isActive());
});
connect(window, &KWayland::Client::PlasmaWindow::unmapped, this, [this, window] () {
uint windows = 0;
const QString appId = window->appId();
for (KWayland::Client::PlasmaWindow *otherWindow : WaylandIntegration::plasmaWindowManagement()->windows()) {
if (otherWindow->appId() == appId && otherWindow->internalId() != window->internalId()) {
windows++;
}
}
if (!windows) {
m_appStates.remove(appId);
Q_EMIT RunningApplicationsChanged();
}
});
Q_EMIT RunningApplicationsChanged();
}
void BackgroundPortal::setActiveWindow(const QString &appId, bool active)
{
m_appStates[appId] = QVariant::fromValue(active ? Active : Running);
Q_EMIT RunningApplicationsChanged();
}