Commit 52b41d15 authored by Kai Uwe Broulik's avatar Kai Uwe Broulik 🍇

Use libTaskManager for identifying the browser

Leverages its heuristic for finding desktop files and lets us support
pretty much any browser without the need to hardcode a mapping.

The browser still sends us its environment as a fallback. It is also
used so we at least have a baseline of "this is a Firefox derivate" or
"a Chromium browser" since some parts of the host react differently
based on the environment.
parent 1c8b5ea3
......@@ -36,6 +36,8 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
FileMetaData
)
find_package(LibTaskManager ${PROJECT_VERSION} CONFIG REQUIRED)
add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
#add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000)
......
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.kde.plasma.browser_integration.Settings">
<property name="Environment" type="s" access="read" />
</interface>
</node>
......@@ -17,8 +17,6 @@ set(HOST_SOURCES main.cpp
purposeplugin.cpp
)
qt5_add_dbus_adaptor(HOST_SOURCES ../dbus/org.kde.plasma.browser_integration.Settings.xml settings.h Settings)
qt5_add_dbus_adaptor(HOST_SOURCES ../dbus/org.mpris.MediaPlayer2.xml mprisplugin.h MPrisPlugin mprisroot MPrisRoot)
qt5_add_dbus_adaptor(HOST_SOURCES ../dbus/org.mpris.MediaPlayer2.Player.xml mprisplugin.h MPrisPlugin mprisplayer MPrisPlayer)
......@@ -38,6 +36,7 @@ target_link_libraries(
KF5::PurposeWidgets
KF5::Runner
KF5::FileMetaData
PW::LibTaskManager
)
install(TARGETS plasma-browser-integration-host ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
......
......@@ -25,14 +25,19 @@
#include <unistd.h> // getppid
#include <QGuiApplication>
#include <QDBusConnection>
#include <QGuiApplication>
#include <QIcon>
#include <QProcess>
#include <KDesktopFile>
#include <KProcessList>
#include <KService>
#include <taskmanager/abstracttasksmodel.h>
#include <taskmanager/windowtasksmodel.h>
#include "pluginmanager.h"
#include "settingsadaptor.h"
#include <config-host.h>
......@@ -99,10 +104,48 @@ const QMap<Settings::Environment, EnvironmentDescription> Settings::environmentD
Settings::Settings()
: AbstractBrowserPlugin(QStringLiteral("settings"), 1, nullptr)
, m_tasksModel(new TaskManager::WindowTasksModel(this))
{
new SettingsAdaptor(this);
QDBusConnection::sessionBus().registerObject(QStringLiteral("/Settings"), this);
for (int i = 0; i < m_tasksModel->rowCount(); ++i) {
if (setEnvironmentFromTasksModelIndex(m_tasksModel->index(i, 0))) {
break;
}
}
// If we didn't find the browser window yet, monitor the model for changes
if (qApp->desktopFileName().isEmpty()) {
connect(m_tasksModel, &TaskManager::WindowTasksModel::rowsInserted, this, [this](const QModelIndex &parent, int first, int last) {
if (parent.isValid()) {
return;
}
for (int i = first; i <= last; ++i) {
if (setEnvironmentFromTasksModelIndex(m_tasksModel->index(i, 0))) {
break;
}
}
});
connect(m_tasksModel, &TaskManager::WindowTasksModel::dataChanged, this, [this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) {
// TODO should we bother checking this, even?
if (topLeft.parent().isValid() || bottomRight.parent().isValid()
|| topLeft.column() != 0 || bottomRight.column() != 0) {
return;
}
if (!roles.isEmpty()
&& !roles.contains(TaskManager::AbstractTasksModel::LauncherUrlWithoutIcon)
&& !roles.contains(TaskManager::AbstractTasksModel::AppId)) {
return;
}
for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
if (setEnvironmentFromTasksModelIndex(m_tasksModel->index(i, 0))) {
break;
}
}
});
}
}
Settings &Settings::self()
......@@ -144,25 +187,76 @@ void Settings::handleData(const QString &event, const QJsonObject &data)
} else if (event == QLatin1String("openKRunnerSettings")) {
QProcess::startDetached(QStringLiteral("kcmshell5"), {QStringLiteral("kcm_plasmasearch")});
} else if (event == QLatin1String("setEnvironment")) {
QString name = data[QStringLiteral("browserName")].toString();
// Most chromium-based browsers just impersonate Chromium nowadays to keep websites from locking them out
// so we'll need to make an educated guess from our parent process
if (name == QLatin1String("chromium") || name == QLatin1String("chrome")) {
const auto processInfo = KProcessList::processInfo(getppid());
if (processInfo.name().contains(QLatin1String("vivaldi"))) {
name = QStringLiteral("vivaldi");
} else if (processInfo.name().contains(QLatin1String("brave"))) {
name = QStringLiteral("brave");
}
setEnvironmentFromExtensionMessage(data);
}
}
bool Settings::setEnvironmentFromTasksModelIndex(const QModelIndex &idx)
{
bool ok = false;
const auto pid = idx.data(TaskManager::AbstractTasksModel::AppPid).toLongLong(&ok);
if (!ok || pid != getppid()) {
return false;
}
const QUrl launcherUrl = idx.data(TaskManager::AbstractTasksModel::LauncherUrlWithoutIcon).toUrl();
if (!launcherUrl.isValid()) {
return false;
}
KService::Ptr service;
if (launcherUrl.scheme() == QLatin1String("applications")) {
service = KService::serviceByMenuId(launcherUrl.path());
} else if (launcherUrl.isLocalFile()) {
const QString launcherPath = launcherUrl.toLocalFile();
if (KDesktopFile::isDesktopFile(launcherPath)) {
service = KService::serviceByDesktopPath(launcherUrl.toLocalFile());
}
} else {
qWarning() << "Got unrecognized launcher URL" << launcherUrl;
return false;
}
m_environment = Settings::environmentNames.key(name, Settings::Environment::Unknown);
m_currentEnvironment = Settings::environmentDescriptions.value(m_environment);
if (!service) {
qWarning() << "Failed to get service from launcher URL" << launcherUrl;
return false;
}
qApp->setApplicationName(service->menuId());
qApp->setApplicationDisplayName(service->name());
qApp->setDesktopFileName(service->desktopEntryName());
qApp->setWindowIcon(QIcon::fromTheme(service->icon()));
disconnect(m_tasksModel, nullptr, this, nullptr);
return true;
}
void Settings::setEnvironmentFromExtensionMessage(const QJsonObject &data)
{
QString name = data.value(QStringLiteral("browserName")).toString();
// Most chromium-based browsers just impersonate Chromium nowadays to keep websites from locking them out
// so we'll need to make an educated guess from our parent process
if (name == QLatin1String("chromium") || name == QLatin1String("chrome")) {
const auto processInfo = KProcessList::processInfo(getppid());
if (processInfo.name().contains(QLatin1String("vivaldi"))) {
name = QStringLiteral("vivaldi");
} else if (processInfo.name().contains(QLatin1String("brave"))) {
name = QStringLiteral("brave");
}
}
m_environment = Settings::environmentNames.key(name, Settings::Environment::Unknown);
m_currentEnvironment = Settings::environmentDescriptions.value(m_environment);
if (qApp->desktopFileName().isEmpty()) {
qApp->setApplicationName(m_currentEnvironment.applicationName);
qApp->setApplicationDisplayName(m_currentEnvironment.applicationDisplayName);
qApp->setDesktopFileName(m_currentEnvironment.desktopFileName);
qApp->setWindowIcon(QIcon::fromTheme(m_currentEnvironment.iconName));
// TODO remove?
qApp->setOrganizationDomain(m_currentEnvironment.organizationDomain);
qApp->setOrganizationName(m_currentEnvironment.organizationName);
}
......@@ -198,11 +292,6 @@ Settings::Environment Settings::environment() const
return m_environment;
}
QString Settings::environmentString() const
{
return Settings::environmentNames.value(m_environment);
}
EnvironmentDescription Settings::environmentDescription() const
{
return m_currentEnvironment;
......
......@@ -36,6 +36,11 @@ struct EnvironmentDescription {
QString iconName;
};
namespace TaskManager
{
class WindowTasksModel;
}
/*
* This class manages the extension's settings (so that settings in the browser
* propagate to our extension) and also detects the environment the host is run
......@@ -45,8 +50,6 @@ class Settings : public AbstractBrowserPlugin
{
Q_OBJECT
Q_PROPERTY(QString Environment READ environmentString)
public:
static Settings &self();
......@@ -65,7 +68,7 @@ public:
QJsonObject handleData(int serial, const QString &event, const QJsonObject &data) override;
Environment environment() const;
QString environmentString() const; // dbus
// TODO remove and migrate runners to use qApp->windowIcon().name()
EnvironmentDescription environmentDescription() const;
bool pluginEnabled(const QString &subsystem) const;
......@@ -78,6 +81,9 @@ private:
Settings();
~Settings() override = default;
bool setEnvironmentFromTasksModelIndex(const QModelIndex &idx);
void setEnvironmentFromExtensionMessage(const QJsonObject &data);
static const QMap<Environment, QString> environmentNames;
static const QMap<Environment, EnvironmentDescription> environmentDescriptions;
......@@ -86,4 +92,6 @@ private:
QJsonObject m_settings;
TaskManager::WindowTasksModel *m_tasksModel;
};
Markdown is supported
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