You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
pcmanfm-qt-packaging/libfm-qt/icontheme.cpp

144 lines
4.5 KiB

/*
<one line to give the library's name and an idea of what it does.>
Copyright (C) 2012 Hong Jen Yee (PCMan) <pcman.tw@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "icontheme.h"
#include <libfm/fm.h>
#include <QList>
#include <QIcon>
#include <QtGlobal>
#include <QApplication>
#include <QDesktopWidget>
using namespace Fm;
static IconTheme* theIconTheme = NULL; // the global single instance of IconTheme.
static const char* fallbackNames[] = {"unknown", "application-octet-stream", NULL};
static void fmIconDataDestroy(gpointer data) {
QIcon* picon = reinterpret_cast<QIcon*>(data);
delete picon;
}
IconTheme::IconTheme():
currentThemeName_(QIcon::themeName()) {
// NOTE: only one instance is allowed
Q_ASSERT(theIconTheme == NULL);
Q_ASSERT(qApp != NULL); // QApplication should exists before contructing IconTheme.
theIconTheme = this;
fm_icon_set_user_data_destroy(reinterpret_cast<GDestroyNotify>(fmIconDataDestroy));
fallbackIcon_ = iconFromNames(fallbackNames);
// We need to get notified when there is a QEvent::StyleChange event so
// we can check if the current icon theme name is changed.
// To do this, we can filter QApplication object itself to intercept
// signals of all widgets, but this may be too inefficient.
// So, we only filter the events on QDesktopWidget instead.
qApp->desktop()->installEventFilter(this);
}
IconTheme::~IconTheme() {
}
IconTheme* IconTheme::instance() {
return theIconTheme;
}
// check if the icon theme name is changed and emit "changed()" signal if any change is detected.
void IconTheme::checkChanged() {
if(QIcon::themeName() != theIconTheme->currentThemeName_) {
// if the icon theme is changed
theIconTheme->currentThemeName_ = QIcon::themeName();
// invalidate the cached data
fm_icon_reset_user_data_cache(fm_qdata_id);
theIconTheme->fallbackIcon_ = iconFromNames(fallbackNames);
Q_EMIT theIconTheme->changed();
}
}
QIcon IconTheme::iconFromNames(const char* const* names) {
const gchar* const* name;
// qDebug("names: %p", names);
for(name = names; *name; ++name) {
// qDebug("icon name=%s", *name);
QString qname = *name;
QIcon qicon = QIcon::fromTheme(qname);
if(!qicon.isNull()) {
return qicon;
}
}
return QIcon();
}
QIcon IconTheme::convertFromGIcon(GIcon* gicon) {
if(G_IS_THEMED_ICON(gicon)) {
const gchar * const * names = g_themed_icon_get_names(G_THEMED_ICON(gicon));
QIcon icon = iconFromNames(names);
if(!icon.isNull())
return icon;
}
else if(G_IS_FILE_ICON(gicon)) {
GFile* file = g_file_icon_get_file(G_FILE_ICON(gicon));
char* fpath = g_file_get_path(file);
QString path = fpath;
g_free(fpath);
return QIcon(path);
}
return theIconTheme->fallbackIcon_;
}
//static
QIcon IconTheme::icon(FmIcon* fmicon) {
// check if we have a cached version
QIcon* picon = reinterpret_cast<QIcon*>(fm_icon_get_user_data(fmicon));
if(!picon) { // we don't have a cache yet
picon = new QIcon(); // what a waste!
*picon = convertFromGIcon(G_ICON(fmicon));
fm_icon_set_user_data(fmicon, picon); // store it in FmIcon
}
return *picon;
}
//static
QIcon IconTheme::icon(GIcon* gicon) {
if(G_IS_THEMED_ICON(gicon)) {
FmIcon* fmicon = fm_icon_from_gicon(gicon);
QIcon qicon = icon(fmicon);
fm_icon_unref(fmicon);
return qicon;
}
else if(G_IS_FILE_ICON(gicon)) {
// we do not map GFileIcon to FmIcon deliberately.
return convertFromGIcon(gicon);
}
return theIconTheme->fallbackIcon_;
}
// this method is called whenever there is an event on the QDesktopWidget object.
bool IconTheme::eventFilter(QObject* obj, QEvent* event) {
// we're only interested in the StyleChange event.
if(event->type() == QEvent::StyleChange) {
checkChanged(); // check if the icon theme is changed
}
return QObject::eventFilter(obj, event);
}