File indexing completed on 2024-04-21 15:08:51

0001 /***************************************************************************
0002  *   Copyright (C) 2012-2016 by Daniel Nicoletti <dantti12@gmail.com>      *
0003  *                                                                         *
0004  *   This program is free software; you can redistribute it and/or modify  *
0005  *   it under the terms of the GNU General Public License as published by  *
0006  *   the Free Software Foundation; either version 2 of the License, or     *
0007  *   (at your option) any later version.                                   *
0008  *                                                                         *
0009  *   This program is distributed in the hope that it will be useful,       *
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0012  *   GNU General Public License for more details.                          *
0013  *                                                                         *
0014  *   You should have received a copy of the GNU General Public License     *
0015  *   along with this program; see the file COPYING. If not, write to       *
0016  *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,  *
0017  *   Boston, MA 02110-1301, USA.                                           *
0018  ***************************************************************************/
0019 
0020 #include "ProfilesWatcher.h"
0021 #include "CdInterface.h"
0022 #include "Edid.h"
0023 #include "ProfileUtils.h"
0024 
0025 #include <QDBusObjectPath>
0026 #include <QDBusReply>
0027 #include <QDBusUnixFileDescriptor>
0028 #include <QDirIterator>
0029 #include <QLoggingCategory>
0030 #include <QMimeDatabase>
0031 #include <QMimeType>
0032 
0033 Q_DECLARE_LOGGING_CATEGORY(COLORD)
0034 
0035 ProfilesWatcher::ProfilesWatcher(QObject *parent)
0036     : QThread(parent)
0037 {
0038 }
0039 
0040 QString ProfilesWatcher::profilesPath() const
0041 {
0042     // ~/.local/share/icc/
0043     return QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) % QLatin1String("/icc/");
0044 }
0045 
0046 void ProfilesWatcher::scanHomeDirectory()
0047 {
0048     // Get a list of files in ~/.local/share/icc/
0049     QDir profilesDir(profilesPath());
0050     profilesDir.setFilter(QDir::Files);
0051     if (!profilesDir.exists()) {
0052         qCWarning(COLORD) << "Icc path" << profilesDir.path() << "does not exist";
0053         if (!profilesDir.mkpath(profilesPath())) {
0054             qCWarning(COLORD) << "Failed to create icc path '~/.local/share/icc'";
0055         }
0056     }
0057 
0058     // check if any changes to the file occour
0059     // this also prevents from reading when a checkUpdate happens
0060     if (!m_dirWatch) {
0061         m_dirWatch = new KDirWatch(this);
0062         m_dirWatch->addDir(profilesDir.path(), KDirWatch::WatchFiles);
0063         connect(m_dirWatch, &KDirWatch::created, this, &ProfilesWatcher::addProfile);
0064         connect(m_dirWatch, &KDirWatch::deleted, this, &ProfilesWatcher::removeProfile);
0065         m_dirWatch->startScan();
0066     }
0067 
0068     // Call AddProfile() for each file
0069     QDirIterator it(profilesDir, QDirIterator::NoIteratorFlags);
0070     while (it.hasNext()) {
0071         addProfile(it.next());
0072     }
0073 
0074     emit scanFinished();
0075 }
0076 
0077 void ProfilesWatcher::createIccProfile(bool isLaptop, const Edid &edid)
0078 {
0079     // EDID profile Creation
0080     // Creates a path for EDID generated profile
0081     QString autogenPath = profilesPath();
0082     QDir profilesDir(autogenPath);
0083     if (!profilesDir.exists()) {
0084         qCWarning(COLORD) << "Icc path" << profilesDir.path() << "does not exist";
0085         if (!profilesDir.mkpath(autogenPath)) {
0086             qCWarning(COLORD) << "Failed to create icc path '~/.local/share/icc'";
0087         }
0088     }
0089     autogenPath.append(QLatin1String("edid-") % edid.hash() % QLatin1String(".icc"));
0090     ProfileUtils::createIccProfile(isLaptop, edid, autogenPath);
0091 }
0092 
0093 void ProfilesWatcher::addProfile(const QString &filePath)
0094 {
0095     // if the changed file is an ICC profile
0096     QMimeDatabase db;
0097     const QMimeType mimeType = db.mimeTypeForFile(filePath);
0098 
0099     if (!mimeType.inherits(QStringLiteral("application/vnd.iccprofile"))) {
0100         // not a profile file
0101         qCWarning(COLORD) << filePath << "is not an ICC profile";
0102         return;
0103     }
0104 
0105     // open filename
0106     QFile profile(filePath);
0107     if (!profile.open(QIODevice::ReadOnly)) {
0108         qCWarning(COLORD) << "Failed to open profile file:" << filePath;
0109         return;
0110     }
0111 
0112     // get the MD5 hash of the contents
0113     QString hash;
0114     hash = ProfileUtils::profileHash(profile);
0115     // seek(0) so that if we pass the FD to colord it is not at end
0116     profile.seek(0);
0117 
0118     QString profileId = QLatin1String("icc-") % hash;
0119     const CdStringMap properties = {{QStringLiteral("Filename"), filePath}, {QStringLiteral("FILE_checksum"), hash}};
0120 
0121     CdInterface cdInterface(QStringLiteral("org.freedesktop.ColorManager"), QStringLiteral("/org/freedesktop/ColorManager"), QDBusConnection::systemBus());
0122 
0123     QDBusReply<QDBusObjectPath> reply;
0124     // TODO async
0125     if (QDBusConnection::systemBus().connectionCapabilities() & QDBusConnection::UnixFileDescriptorPassing) {
0126         reply = cdInterface.CreateProfileWithFd(profileId, QStringLiteral("temp"), QDBusUnixFileDescriptor(profile.handle()), properties);
0127     } else {
0128         reply = cdInterface.CreateProfile(profileId, QStringLiteral("temp"), properties);
0129     }
0130 
0131     qCDebug(COLORD) << "created profile" << profileId << reply.value().path();
0132 }
0133 
0134 void ProfilesWatcher::removeProfile(const QString &filename)
0135 {
0136     CdInterface cdInterface(QStringLiteral("org.freedesktop.ColorManager"), QStringLiteral("/org/freedesktop/ColorManager"), QDBusConnection::systemBus());
0137 
0138     // TODO async
0139     QDBusReply<QDBusObjectPath> reply = cdInterface.FindProfileByFilename(filename);
0140     if (!reply.isValid()) {
0141         qCWarning(COLORD) << "Could not find the DBus object path for the given file name" << filename;
0142         return;
0143     }
0144 
0145     cdInterface.DeleteProfile(reply);
0146 }
0147 
0148 #include "moc_ProfilesWatcher.cpp"