Skip to content

Commit

Permalink
Use libTaskManager for identifying the browser
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kbroulik committed Jan 12, 2021
1 parent 1c8b5ea commit 52b41d1
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 33 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
6 changes: 0 additions & 6 deletions dbus/org.kde.plasma.browser_integration.Settings.xml

This file was deleted.

3 changes: 1 addition & 2 deletions host/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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})
Expand Down
133 changes: 111 additions & 22 deletions host/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 11 additions & 3 deletions host/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -45,8 +50,6 @@ class Settings : public AbstractBrowserPlugin
{
Q_OBJECT

Q_PROPERTY(QString Environment READ environmentString)

public:
static Settings &self();

Expand All @@ -65,7 +68,7 @@ class Settings : public AbstractBrowserPlugin
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;
Expand All @@ -78,6 +81,9 @@ class Settings : public AbstractBrowserPlugin
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;

Expand All @@ -86,4 +92,6 @@ class Settings : public AbstractBrowserPlugin

QJsonObject m_settings;

TaskManager::WindowTasksModel *m_tasksModel;

};

0 comments on commit 52b41d1

Please sign in to comment.