File: utils.cpp

package info (click to toggle)
plasma-workspace 4%3A5.27.5-2%2Bdeb12u2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 102,040 kB
  • sloc: cpp: 121,800; xml: 3,238; python: 645; perl: 586; sh: 254; javascript: 113; ruby: 62; makefile: 15; ansic: 13
file content (127 lines) | stat: -rw-r--r-- 4,134 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
    SPDX-FileCopyrightText: 2019 Kai Uwe Broulik <kde@privat.broulik.de>

    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/

#include "utils_p.h"

#include "notifications.h"

#include <QAbstractItemModel>
#include <QAbstractProxyModel>
#include <QConcatenateTablesProxyModel>
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QFile>
#include <QFileInfo>
#include <QMetaEnum>
#include <QSettings>
#include <QTextStream>

#include <KProcessList>

using namespace NotificationManager;

QHash<int, QByteArray> Utils::roleNames()
{
    static QHash<int, QByteArray> s_roles;

    if (s_roles.isEmpty()) {
        // This generates role names from the Roles enum in the form of: FooRole -> foo
        const QMetaEnum e = QMetaEnum::fromType<Notifications::Roles>();

        // Qt built-in roles we use
        s_roles.insert(Qt::DisplayRole, QByteArrayLiteral("display"));
        s_roles.insert(Qt::DecorationRole, QByteArrayLiteral("decoration"));
        s_roles.insert(Qt::AccessibleDescriptionRole, QByteArrayLiteral("accessibleDescription"));

        for (int i = 0; i < e.keyCount(); ++i) {
            const int value = e.value(i);

            QByteArray key(e.key(i));
            key[0] = key[0] + 32; // lower case first letter
            key.chop(4); // strip "Role" suffix

            s_roles.insert(value, key);
        }

        s_roles.insert(Notifications::IdRole, QByteArrayLiteral("notificationId")); // id is QML-reserved
    }

    return s_roles;
}

QString Utils::processNameFromPid(uint pid)
{
    auto processInfo = KProcessList::processInfo(pid);

    if (!processInfo.isValid()) {
        return QString();
    }

    return processInfo.name();
}

QString Utils::desktopEntryFromPid(uint pid)
{
    const QString flatpakInfoPath = QStringLiteral("/proc/%1/root/.flatpak-info").arg(QString::number(pid));
    if (QFileInfo::exists(flatpakInfoPath)) {
        QSettings flatpakInfo(flatpakInfoPath, QSettings::IniFormat);

        const QString name = flatpakInfo.value("Application/name").toString();
        if (!name.isEmpty()) {
            return name;
        }

        // If it's a flatpak, can't be a snap, bail out.
        return QString();
    }

    QFile environFile(QStringLiteral("/proc/%1/environ").arg(QString::number(pid)));
    if (environFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        const QByteArray bamfDesktopFileHint = QByteArrayLiteral("BAMF_DESKTOP_FILE_HINT");

        const auto lines = environFile.readAll().split('\0');
        for (const QByteArray &line : lines) {
            const int equalsIdx = line.indexOf('=');
            if (equalsIdx <= 0) {
                continue;
            }

            const QByteArray key = line.left(equalsIdx);
            if (key == bamfDesktopFileHint) {
                const QByteArray value = line.mid(equalsIdx + 1);
                return value;
            }
        }
    }

    return QString();
}

QModelIndex Utils::mapToModel(const QModelIndex &idx, const QAbstractItemModel *sourceModel)
{
    // KModelIndexProxyMapper can only map different indices to a single source
    // but we have the other way round, a single index that splits into different source models
    QModelIndex resolvedIdx = idx;
    while (resolvedIdx.isValid() && resolvedIdx.model() != sourceModel) {
        if (auto *proxyModel = qobject_cast<const QAbstractProxyModel *>(resolvedIdx.model())) {
            resolvedIdx = proxyModel->mapToSource(resolvedIdx);
            // QConcatenateTablesProxyModel isn't a "real" proxy model, so we need to special case for it :(
        } else if (auto *concatenateModel = qobject_cast<const QConcatenateTablesProxyModel *>(resolvedIdx.model())) {
            resolvedIdx = concatenateModel->mapToSource(resolvedIdx);
        } else {
            if (resolvedIdx.model() != sourceModel) {
                resolvedIdx = QModelIndex(); // give up
            }
        }
    }
    return resolvedIdx;
}

bool Utils::isDBusMaster()
{
    return qApp->property("_plasma_dbus_master").toBool();
}