Замена иконки Skype в Ubuntu

06/17/2014, автор dimaz, категории Ubuntu

Иконка скайпа всегда выделялась в панели индикаторов, что очень сильно раздражало. И вот, вроде бы, уже привык к этому, но нашлось отличное решение проблемы, а именно подправить sni-qt, который и отвечает за вывод иконок трея Qt приложений в панели индикаторов unity.
Конечно можно, используя skype wrapper, иконку засунуть в indicator-messages, но мне удобней, чтобы иконка была сразу на панели.

Скатываем исходники sni-qt:

apt-get source sni-qt && cd sni-qt*

Находим файл iconcache.cpp и заменяем один метод:

void IconCache::cacheIcon(const QString& key, const QIcon& icon) const {
    QList<QSize> sizes = icon.availableSizes();
    if (sizes.isEmpty()) {
        sizes << QSize(16,16) << QSize(22,22) << QSize(32,32) << QSize(48,48);
    }
    QDir dir(m_themePath);
    Q_FOREACH(const QSize& size, sizes) {
        QPixmap pix = icon.pixmap(size);
        QString dirName = QString("hicolor/%1x%1/apps").arg(size.width());
        if (!dir.exists(dirName)) {
            if (!dir.mkpath(dirName)) {
                qWarning("Could not create '%s' dir in '%s'",
                    qPrintable(m_themePath), qPrintable(dirName));
                continue;
            }
        }
        QString pixPath = QString("%1/%2/%3.png").arg(m_themePath).arg(dirName).arg(key);
        bool replaced = false;
        // Если skype выполняем
        if (QString::compare(QCoreApplication::applicationFilePath().section('/', -1), "skype") == 0) {
            QString iconFile;
            QString hash = QString(key);
            hash.remove(0, hash.lastIndexOf("_")+1);
            // Сопоставляем хэшу изображения необходимого файла иконки
            if (QString::compare("37e170fc54e7355d9d298917e74f9ea9", hash) == 0) { // в сети
                iconFile = "skype_online.svg";
            } else
            if (QString::compare("602c84fa0f4d61c64f770495a500279e", hash) == 0) { // нет на месте
                iconFile = "skype_away.svg";
            } else
            if (QString::compare("bd2e3972c2a97520bbabac7e275d7b9f", hash) == 0) { // не беспокоить
                iconFile = "skype_busy.svg";
            } else
            if (QString::compare("2d1ee5482260fd9cd180b32787792683", hash) == 0) { // не в сети
                iconFile = "skype_offline.svg";
            } else
            if (QString::compare("ad07f7e1479ab81315ec8c6c23e19170", hash) == 0) { // невидимый
                iconFile = "skype_invisible.svg";
            } else
            if (QString::compare("f2fc4a539a7b9553f5b35241d1154e84", hash) == 0) { // загрузка
                iconFile = "skype_load.svg";
            } else
            if (QString::compare("dad77418071bead905e2dbe605715dcd", hash) == 0) { // загрузка
                iconFile = "skype_load.svg";
            } else
            if (QString::compare("6cbeda8e2c9f56d3ac75ccdf8d282a69", hash) == 0) { // загрузка
                iconFile = "skype_load.svg";
            } else
            if (QString::compare("0972e5fde53a4a87346ebb91c4c2b159", hash) == 0) { // загрузка
                iconFile = "skype_load.svg";
            }
            else { // уведомления, пропущенные звонки, непрочитанные сообщения
                iconFile = "skype_message.svg";
            }
            // Загружает и сохраняет в временном каталоге подменяемую иконку
            iconFile = QString("/usr/share/icons/skype/%1").arg(iconFile);
            QIcon newIcon = QIcon(iconFile);
            if (!newIcon.isNull()) {
                QList<QSize> newSizes = newIcon.availableSizes();
                if (newSizes.isEmpty()) {
                    newSizes << QSize(22, 22);
                }
                Q_FOREACH(const QSize& newSize, newSizes) {
                    if (newSize.width() == 22) {
                        QPixmap newPix = newIcon.pixmap(newSize);
                        replaced = newPix.save(pixPath, "png");
                        break;
                    }
                }
            }
        }

        if (!replaced) {
            if (!pix.save(pixPath, "png")) {
                qWarning("Could not save icon as '%s'", qPrintable(pixPath));
            }
        }
    }
    m_cacheKeys << key;
    QFileInfo info(m_themePath);
    QDateTime mtime = info.lastModified();
    FsUtils::touch(m_themePath, mtime.addSecs(1));
}

Собираем и устанавливаем

sudo apt-get build-dep sni-qt
mkdir build && cmake --build=build .
make && sudo make install

Как видно иконки будут браться из директории:

/usr/share/icons/skype

Иконки должны быть векторными. Можно использовать системные от empathy, только нужно будет дать им правильные названия или изменить в коде на нужные.

Есть один небольшой минус, на иконке не будет отображатся количество чатов с непрочитанными сообщениями, но это можно пережить.

UPD: существует проблема в 64 битных версиях. По непонятной причине библиотека отказывается конвертить из svg в png. Поступим просто, будем использовать png, но при изменении размера панели, придется иконки перерисовывать. Такое случается не часто, так что это не критично.

IconCache::IconCache(const QString& baseDir, QObject* parent)
: QObject(parent)
, m_themePath(baseDir + "/icons")
{
    QDir dir(baseDir);
    bool ok = dir.mkdir("icons");
    if (!ok) {
        qCritical("Could not create '%s' dir for SNI icon cache", qPrintable(m_themePath));
        m_themePath = QString();
        return;
    }
}

QString IconCache::themePath() const
{
    return m_themePath;
}

QString IconCache::nameForIcon(const QIcon& icon) const
{
    if (icon.isNull()) {
        return QString();
    }

    QString key = computeKeyForIcon(icon);
    QStringList::iterator it = qFind(m_cacheKeys.begin(), m_cacheKeys.end(), key);
    if (it == m_cacheKeys.end()) {
        cacheIcon(key, icon);
        trimCache();
    } else {
        // Place key at the end of list as it is the most recently accessed
        m_cacheKeys.erase(it);
        m_cacheKeys.append(key);
    }

    return key;
}

void IconCache::trimCache() const
{
    QDir dir(m_themePath + "/hicolor");
    dir.setFilter(QDir::Dirs);

    while (m_cacheKeys.count() > MaxIconCount) {
        QString cacheKey = m_cacheKeys.takeFirst();

        Q_FOREACH(const QString& sizeDir, dir.entryList()) {
            QString iconSubPath = QString("%1/apps/%2.png").arg(sizeDir).arg(cacheKey);
            if (dir.exists(iconSubPath)) {
                dir.remove(iconSubPath);
            }
        }
    }
}

void IconCache::cacheIcon(const QString& key, const QIcon& icon) const {
    QList<QSize> sizes = icon.availableSizes();
    if (sizes.isEmpty()) {
        sizes << QSize(16,16) << QSize(22,22) << QSize(32,32) << QSize(48,48);
    }
    QDir dir(m_themePath);
    Q_FOREACH(const QSize& size, sizes) {
        QPixmap pix = icon.pixmap(size);
        QString dirName = QString("hicolor/%1x%1/apps").arg(size.width());
        if (!dir.exists(dirName)) {
            if (!dir.mkpath(dirName)) {
                qWarning("Could not create '%s' dir in '%s'",
                    qPrintable(m_themePath), qPrintable(dirName));
                continue;
            }
        }
        QString pixPath = QString("%1/%2/%3.png").arg(m_themePath).arg(dirName).arg(key);
        bool replaced = false;
        // Если skype выполняем
        if (QString::compare(QCoreApplication::applicationFilePath().section('/', -1), "skype") == 0) {
            QString iconFile;
            QString hash = QString(key);
            hash.remove(0, hash.lastIndexOf("_")+1);

            // Сопоставляем хэшу изображения необходимого файла иконки
            if (QString::compare("37e170fc54e7355d9d298917e74f9ea9", hash) == 0) { // в сети
                iconFile = "skype_online.png";
            } else
            if (QString::compare("602c84fa0f4d61c64f770495a500279e", hash) == 0) { // нет на месте
                iconFile = "skype_away.png";
            } else
            if (QString::compare("bd2e3972c2a97520bbabac7e275d7b9f", hash) == 0) { // не беспокоить
                iconFile = "skype_busy.png";
            } else
            if (QString::compare("2d1ee5482260fd9cd180b32787792683", hash) == 0) { // не в сети
                iconFile = "skype_offline.png";
            } else
            if (QString::compare("ad07f7e1479ab81315ec8c6c23e19170", hash) == 0) { // невидимый
                iconFile = "skype_invisible.png";
            } else
            if (QString::compare("f2fc4a539a7b9553f5b35241d1154e84", hash) == 0) { // загрузка
                iconFile = "skype_load.png";
            } else
            if (QString::compare("dad77418071bead905e2dbe605715dcd", hash) == 0) { // загрузка
                iconFile = "skype_load.png";
            } else
            if (QString::compare("6cbeda8e2c9f56d3ac75ccdf8d282a69", hash) == 0) { // загрузка
                iconFile = "skype_load.png";
            } else
            if (QString::compare("0972e5fde53a4a87346ebb91c4c2b159", hash) == 0) { // загрузка
                iconFile = "skype_load.png";
            }
            else { // уведомления, пропущенные звонки, непрочитанные сообщения
                iconFile = "skype_message.png";
            }
            // Загружает и сохраняет в временном каталоге подменяемую иконку
            iconFile = QString("/usr/share/pixmaps/skype/%1").arg(iconFile);

            QFile file(iconFile);
						if (QFile::exists(pixPath)) {
							replaced = true;
						} else if (file.exists()) {
							QFile::copy(iconFile, pixPath);
              replaced = true;
						}

        }

        if (!replaced) {
            if (!pix.save(pixPath, "png")) {
              qWarning("Could not save icon as '%s'", qPrintable(pixPath));
            }
        }
    }
    m_cacheKeys << key;
    QFileInfo info(m_themePath);
    QDateTime mtime = info.lastModified();
    FsUtils::touch(m_themePath, mtime.addSecs(1));
}

Один хороший человек подсказал, что правильней будет хранить изображения в

/usr/share/pixmaps/skype/

Результат:

Прикрепляю свои файлы иконок:
svg
png

Навеяно

Читать похожие статьи:

Теги:  

6 комментариев “Замена иконки Skype в Ubuntu”

  1. Это надо столько сексом заниматься чтобы иконку сменить? А можно скрин как была иконка до ?

  2. AlexGluck:

    Огромнейшее спасибо, вот бы ещё добавить деб пакет было бы совсем супер. Я искал такую статью 3 дня!

  3. AlexGluck:

    Ну и конечно как на 64х разрядной системе компилировать 32х битный деб пакет было бы полезной информацией.

  4. Apuox:

    Все сделал, были ошибки с деб пакетом (коммент выше), но всё скомпилировал и разместил иконки. Но почему-то они не подтягиваются, как проверить узнать, что не так ?

  5. Пробовал – на первом же этапе в терминале написали что нет такого пакета. Ubuntu 16.04 mate . Подскажите что не так то

  6. Yuri:

    Попробовал оба варианта, и для svg, и для png. Всё как по мануалу, никаких ошибок при компиляции. Но и результат тоже нулевой.