Improved activation item

pull/7/head
cutefishd 5 years ago
parent d4ef3cdf21
commit 27e0cf1cd2

@ -26,6 +26,7 @@ set(SRCS
src/volume.cpp
src/processprovider.cpp
src/activity.cpp
src/capplications.cpp
src/systemtray/statusnotifieritemsource.cpp
src/systemtray/systemtraytypes.cpp

@ -49,9 +49,8 @@ Item {
StandardItem {
id: acticityItem
Layout.fillHeight: true
Layout.preferredWidth: acticityLayout.implicitWidth + FishUI.Units.largeSpacing
visible: acticity.title
Layout.preferredWidth: acticityLayout.implicitWidth ? acticityLayout.implicitWidth + FishUI.Units.largeSpacing
: 0
onClicked: acticityMenu.open()
RowLayout {
@ -61,18 +60,20 @@ Item {
anchors.rightMargin: FishUI.Units.smallSpacing
spacing: FishUI.Units.largeSpacing
Image {
id: acticityIcon
width: 16
height: 16
sourceSize: Qt.size(width, height)
source: acticity.icon ? "image://icontheme/" + acticity.icon : ""
visible: status === Image.Ready
}
// Image {
// id: acticityIcon
// width: 16
// height: 16
// sourceSize: Qt.size(width, height)
// source: acticity.icon ? "image://icontheme/" + acticity.icon : ""
// visible: status === Image.Ready
// asynchronous: true
// }
Label {
id: acticityLabel
text: acticity.title
visible: text
}
}
}

@ -31,6 +31,7 @@
Activity::Activity(QObject *parent)
: QObject(parent)
, m_cApps(CApplications::self())
{
onActiveWindowChanged();
@ -72,85 +73,24 @@ void Activity::onActiveWindowChanged()
m_pid = info.pid();
m_windowClass = info.windowClassClass().toLower();
if (!matchInfo()) {
QString title = info.visibleName();
if (title != m_title) {
m_title = title;
emit titleChanged();
m_icon.clear();
emit iconChanged();
}
}
}
CAppItem *item = m_cApps->matchItem(m_pid);
bool Activity::matchInfo()
{
QString command = commandFromPid(m_pid);
// TODO: optimization
QDirIterator it("/usr/share/applications", { "*.desktop" },
QDir::NoFilter, QDirIterator::Subdirectories);
while (it.hasNext()) {
const QString &filePath = it.next();
QSettings desktop(filePath, QSettings::IniFormat);
desktop.setIniCodec("UTF-8");
desktop.beginGroup("Desktop Entry");
if (item) {
m_title = item->localName;
emit titleChanged();
if (desktop.value("NoDisplay").toBool() ||
desktop.value("Hidden").toBool()) {
continue;
if (m_icon != item->icon) {
m_icon = item->icon;
emit iconChanged();
}
QString exec = desktop.value("Exec").toString();
exec.remove(QRegularExpression("%."));
exec.remove(QRegularExpression("^\""));
exec = exec.simplified();
if (command == exec) {
QString name = desktop.value(QString("Name[%1]").arg(QLocale::system().name())).toString();
if (name.isEmpty())
name = desktop.value("Name").toString();
m_title = name;
} else {
QString title = info.visibleName();
if (title != m_title) {
m_title = title;
emit titleChanged();
m_icon = desktop.value("Icon").toString();
m_icon.clear();
emit iconChanged();
return true;
}
}
return false;
}
QString Activity::commandFromPid(quint32 pid)
{
QFile file(QString("/proc/%1/cmdline").arg(pid));
if (file.open(QIODevice::ReadOnly)) {
QByteArray cmd = file.readAll();
// ref: https://github.com/KDE/kcoreaddons/blob/230c98aa7e01f9e36a9c2776f3633182e6778002/src/lib/util/kprocesslist_unix.cpp#L137
if (!cmd.isEmpty()) {
// extract non-truncated name from cmdline
int zeroIndex = cmd.indexOf('\0');
int processNameStart = cmd.lastIndexOf('/', zeroIndex);
if (processNameStart == -1) {
processNameStart = 0;
} else {
processNameStart++;
}
QString name = QString::fromLocal8Bit(cmd.mid(processNameStart, zeroIndex - processNameStart));
cmd.replace('\0', ' ');
QString command = QString::fromLocal8Bit(cmd).trimmed();
return name;
}
}
return QString();
}

@ -21,6 +21,7 @@
#define ACTIVITY_H
#include <QObject>
#include "capplications.h"
class Activity : public QObject
{
@ -38,15 +39,13 @@ public:
private slots:
void onActiveWindowChanged();
bool matchInfo();
QString commandFromPid(quint32 pid);
signals:
void titleChanged();
void iconChanged();
private:
CApplications *m_cApps;
QString m_title;
QString m_icon;
QString m_windowClass;

@ -0,0 +1,206 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: cutefishos <cutefishos@foxmail.com>
*
* 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 3 of the License, or
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "capplications.h"
#include <QRegularExpression>
#include <QSettings>
#include <QLocale>
#include <QDirIterator>
#include <QDir>
static CApplications *SELF = nullptr;
static QString s_systemAppFolder = "/usr/share/applications";
static QByteArray detectDesktopEnvironment()
{
const QByteArray desktop = qgetenv("XDG_CURRENT_DESKTOP");
if (!desktop.isEmpty())
return desktop.toUpper();
return QByteArray("UNKNOWN");
}
CApplications *CApplications::self()
{
if (!SELF)
SELF = new CApplications;
return SELF;
}
CApplications::CApplications(QObject *parent)
: QObject(parent)
, m_watcher(new QFileSystemWatcher(this))
{
m_watcher->addPath(s_systemAppFolder);
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &CApplications::refresh);
refresh();
}
CApplications::~CApplications()
{
while (!m_items.isEmpty())
delete m_items.takeFirst();
}
CAppItem *CApplications::find(const QString &fileName)
{
for (CAppItem *item : m_items)
if (item->path == fileName)
return item;
return nullptr;
}
CAppItem *CApplications::matchItem(quint32 pid)
{
QStringList commands = commandFromPid(pid);
QString command = commands.first();
QString commandName = commands.last();
if (command.isEmpty())
return nullptr;
for (CAppItem *item : m_items) {
if (item->fullExec == command ||
item->exec == command ||
item->fullExec == commandName ||
item->exec == commandName) {
return item;
}
}
return nullptr;
}
void CApplications::refresh()
{
QStringList addedEntries;
for (CAppItem *item : m_items)
addedEntries.append(item->path);
QStringList allEntries;
QDirIterator it(s_systemAppFolder, { "*.desktop" }, QDir::NoFilter, QDirIterator::Subdirectories);
while (it.hasNext()) {
const QString &filePath = it.next();
if (!QFile::exists(filePath))
continue;
allEntries.append(filePath);
}
for (const QString &filePath : allEntries) {
if (!addedEntries.contains(filePath)) {
addApplication(filePath);
}
}
for (CAppItem *item : m_items) {
if (!allEntries.contains(item->path)) {
removeApplication(item);
}
}
}
void CApplications::addApplication(const QString &filePath)
{
if (find(filePath))
return;
QSettings desktop(filePath, QSettings::IniFormat);
desktop.setIniCodec("UTF-8");
desktop.beginGroup("Desktop Entry");
// Skip...
if (desktop.contains("OnlyShowIn")) {
const QString &value = desktop.value("OnlyShowIn").toString();
if (!value.contains(detectDesktopEnvironment(), Qt::CaseInsensitive)) {
return;
}
}
if (desktop.value("NoDisplay").toBool() ||
desktop.value("Hidden").toBool()) {
return;
}
// Local Name
QString localName = desktop.value(QString("Name[%1]").arg(QLocale::system().name())).toString();
if (localName.isEmpty())
localName = desktop.value("Name").toString();
// Exec
QString simplifiedExec = desktop.value("Exec").toString();
simplifiedExec.remove(QRegularExpression("%."));
simplifiedExec.remove(QRegularExpression("^\""));
// appExec.remove(QRegularExpression(" *$"));
simplifiedExec = simplifiedExec.simplified();
// New data
CAppItem *item = new CAppItem;
item->path = filePath;
item->localName = localName;
item->name = desktop.value("Name").toString();;
item->comment = desktop.value("Comment").toString();
item->icon = desktop.value("Icon").toString();
item->fullExec = desktop.value("Exec").toString();
item->exec = simplifiedExec;
m_items.append(item);
}
void CApplications::removeApplication(CAppItem *item)
{
m_items.removeOne(item);
delete item;
}
QStringList CApplications::commandFromPid(quint32 pid)
{
QFile file(QString("/proc/%1/cmdline").arg(pid));
if (file.open(QIODevice::ReadOnly)) {
QByteArray cmd = file.readAll();
// ref: https://github.com/KDE/kcoreaddons/blob/230c98aa7e01f9e36a9c2776f3633182e6778002/src/lib/util/kprocesslist_unix.cpp#L137
if (!cmd.isEmpty()) {
// extract non-truncated name from cmdline
int zeroIndex = cmd.indexOf('\0');
int processNameStart = cmd.lastIndexOf('/', zeroIndex);
if (processNameStart == -1) {
processNameStart = 0;
} else {
processNameStart++;
}
QString name = QString::fromLocal8Bit(cmd.mid(processNameStart, zeroIndex - processNameStart));
cmd.replace('\0', ' ');
QString command = QString::fromLocal8Bit(cmd).trimmed();
return { command, name };
}
}
return QStringList();
}

@ -0,0 +1,62 @@
/*
* Copyright (C) 2021 CutefishOS Team.
*
* Author: cutefishos <cutefishos@foxmail.com>
*
* 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 3 of the License, or
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef CAPPLICATIONS_H
#define CAPPLICATIONS_H
#include <QObject>
#include <QFileSystemWatcher>
class CAppItem
{
public:
QString path;
QString localName;
QString name;
QString comment;
QString icon;
QString fullExec;
QString exec;
};
class CApplications : public QObject
{
Q_OBJECT
public:
static CApplications *self();
explicit CApplications(QObject *parent = nullptr);
~CApplications();
CAppItem *find(const QString &fileName);
CAppItem *matchItem(quint32 pid);
private:
void refresh();
void addApplication(const QString &filePath);
void removeApplication(CAppItem *item);
QStringList commandFromPid(quint32 pid);
private:
QFileSystemWatcher *m_watcher;
QList<CAppItem *> m_items;
};
#endif // CAPPLICATIONS_H
Loading…
Cancel
Save