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"