• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libplasma

theme.cpp

Go to the documentation of this file.
00001 /*
00002  *   Copyright 2006-2007 Aaron Seigo <aseigo@kde.org>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU Library General Public License as
00006  *   published by the Free Software Foundation; either version 2, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details
00013  *
00014  *   You should have received a copy of the GNU Library General Public
00015  *   License along with this program; if not, write to the
00016  *   Free Software Foundation, Inc.,
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00018  */
00019 
00020 #include "theme.h"
00021 
00022 #include <QApplication>
00023 #include <QFile>
00024 #ifdef Q_WS_X11
00025 #include <QX11Info>
00026 #endif
00027 
00028 #include <KWindowSystem>
00029 #include <KColorScheme>
00030 #include <KConfigGroup>
00031 #include <KDebug>
00032 #include <KGlobal>
00033 #include <KSelectionWatcher>
00034 #include <KSharedConfig>
00035 #include <KStandardDirs>
00036 #include <KGlobalSettings>
00037 
00038 #include "plasma/packages_p.h"
00039 
00040 namespace Plasma
00041 {
00042 
00043 #define DEFAULT_WALLPAPER_THEME "Blue_Curl"
00044 #define DEFAULT_WALLPAPER_SUFFIX ".jpg"
00045 static const int DEFAULT_WALLPAPER_WIDTH = 1920;
00046 static const int DEFAULT_WALLPAPER_HEIGHT = 1200;
00047 
00048 class ThemePrivate
00049 {
00050 public:
00051     ThemePrivate(Theme *theme)
00052         : q(theme),
00053           defaultWallpaperTheme(DEFAULT_WALLPAPER_THEME),
00054           defaultWallpaperSuffix(DEFAULT_WALLPAPER_SUFFIX),
00055           defaultWallpaperWidth(DEFAULT_WALLPAPER_WIDTH),
00056           defaultWallpaperHeight(DEFAULT_WALLPAPER_HEIGHT),
00057           locolor(false),
00058           compositingActive(KWindowSystem::compositingActive()),
00059           isDefault(false),
00060           useGlobal(true),
00061           hasWallpapers(false)
00062     {
00063         generalFont = QApplication::font();
00064     }
00065 
00066     KConfigGroup& config()
00067     {
00068         if (!cfg.isValid()) {
00069             QString groupName = "Theme";
00070 
00071             if (!useGlobal) {
00072                 QString app = KGlobal::mainComponent().componentName();
00073 
00074                 if (!app.isEmpty() && app != "plasma") {
00075                     kDebug() << "using theme for app" << app;
00076                     groupName.append("-").append(app);
00077                 }
00078             }
00079 
00080             cfg = KConfigGroup(KSharedConfig::openConfig("plasmarc"), groupName);
00081         }
00082 
00083         return cfg;
00084     }
00085 
00086     QString findInTheme(const QString &image, const QString &theme) const;
00087     void compositingChanged();
00088 
00089     static const char *defaultTheme;
00090     static PackageStructure::Ptr packageStructure;
00091 
00092     Theme *q;
00093     QString themeName;
00094     KSharedConfigPtr colors;
00095     KConfigGroup cfg;
00096     QFont generalFont;
00097     QString defaultWallpaperTheme;
00098     QString defaultWallpaperSuffix;
00099     int defaultWallpaperWidth;
00100     int defaultWallpaperHeight;
00101 
00102 #ifdef Q_WS_X11
00103     KSelectionWatcher *compositeWatch;
00104 #endif
00105     bool locolor : 1;
00106     bool compositingActive : 1;
00107     bool isDefault : 1;
00108     bool useGlobal : 1;
00109     bool hasWallpapers : 1;
00110 };
00111 
00112 PackageStructure::Ptr ThemePrivate::packageStructure(0);
00113 const char *ThemePrivate::defaultTheme = "default";
00114 
00115 QString ThemePrivate::findInTheme(const QString &image, const QString &theme) const
00116 {
00117     //TODO: this should be using Package
00118     QString search;
00119 
00120     if (locolor) {
00121         search = "desktoptheme/" + theme + "/locolor/" + image;
00122         search =  KStandardDirs::locate("data", search);
00123     } else if (!compositingActive) {
00124         search = "desktoptheme/" + theme + "/opaque/" + image;
00125         search =  KStandardDirs::locate("data", search);
00126     }
00127 
00128     //not found or compositing enabled
00129     if (search.isEmpty()) {
00130         search = "desktoptheme/" + theme + '/' + image;
00131         search =  KStandardDirs::locate("data", search);
00132     }
00133 
00134     return search;
00135 }
00136 
00137 void ThemePrivate::compositingChanged()
00138 {
00139 #ifdef Q_WS_X11
00140     bool nowCompositingActive = compositeWatch->owner() != None;
00141 
00142     if (compositingActive != nowCompositingActive) {
00143         compositingActive = nowCompositingActive;
00144         emit q->themeChanged();
00145     }
00146 #endif
00147 }
00148 
00149 class ThemeSingleton
00150 {
00151 public:
00152     ThemeSingleton()
00153     {
00154         self.d->isDefault = true;
00155     }
00156 
00157    Theme self;
00158 };
00159 
00160 K_GLOBAL_STATIC( ThemeSingleton, privateThemeSelf )
00161 
00162 Theme* Theme::defaultTheme()
00163 {
00164     return &privateThemeSelf->self;
00165 }
00166 
00167 Theme::Theme(QObject* parent)
00168     : QObject(parent),
00169       d(new ThemePrivate(this))
00170 {
00171     settingsChanged();
00172 
00173 #ifdef Q_WS_X11
00174     Display *dpy = QX11Info::display();
00175     int screen = DefaultScreen(dpy);
00176     d->locolor = DefaultDepth(dpy, screen) < 16;
00177 
00178     if (!d->locolor) {
00179         char net_wm_cm_name[100];
00180         sprintf(net_wm_cm_name, "_NET_WM_CM_S%d", screen);
00181         d->compositeWatch = new KSelectionWatcher(net_wm_cm_name, -1, this);
00182         connect(d->compositeWatch, SIGNAL(newOwner(Window)), this, SLOT(compositingChanged()));
00183         connect(d->compositeWatch, SIGNAL(lostOwner()), this, SLOT(compositingChanged()));
00184     }
00185 #endif
00186 }
00187 
00188 Theme::~Theme()
00189 {
00190     delete d;
00191 }
00192 
00193 PackageStructure::Ptr Theme::packageStructure()
00194 {
00195     if (!ThemePrivate::packageStructure) {
00196         ThemePrivate::packageStructure = new ThemePackage();
00197     }
00198 
00199     return ThemePrivate::packageStructure;
00200 }
00201 
00202 void Theme::settingsChanged()
00203 {
00204     setThemeName(d->config().readEntry("name", ThemePrivate::defaultTheme));
00205 }
00206 
00207 void Theme::setThemeName(const QString &themeName)
00208 {
00209     QString theme = themeName;
00210     if (theme.isEmpty() || theme == d->themeName) {
00211         // let's try and get the default theme at least
00212         if (d->themeName.isEmpty()) {
00213             theme = ThemePrivate::defaultTheme;
00214         } else {
00215             return;
00216         }
00217     }
00218 
00219     //TODO: should we care about names with relative paths in them?
00220     QString themePath = KStandardDirs::locate("data", "desktoptheme/" + theme + '/');
00221     if (themePath.isEmpty() && d->themeName.isEmpty()) {
00222         themePath = KStandardDirs::locate("data", "desktoptheme/default/");
00223 
00224         if (themePath.isEmpty()) {
00225             return;
00226         }
00227 
00228         theme = ThemePrivate::defaultTheme;
00229     }
00230 
00231     d->themeName = theme;
00232 
00233     // load the color scheme config
00234     QString colorsFile = KStandardDirs::locate("data", "desktoptheme/" + theme + "/colors");
00235     //kDebug() << "we're going for..." << colorsFile << "*******************";
00236 
00237     // load the wallpaper settings, if any
00238     KConfig metadata(KStandardDirs::locate("data", "desktoptheme/" + theme + "/metadata.desktop"));
00239     KConfigGroup cg;
00240     if (metadata.hasGroup("Wallpaper")) {
00241         // we have a theme color config, so let's also check to see if
00242         // there is a wallpaper defined in there.
00243         cg = KConfigGroup(&metadata, "Wallpaper");
00244     } else {
00245         // since we didn't find an entry in the theme, let's look in the main
00246         // theme config
00247         cg = d->config();
00248     }
00249 
00250     d->defaultWallpaperTheme = cg.readEntry("defaultWallpaperTheme", DEFAULT_WALLPAPER_THEME);
00251     d->defaultWallpaperSuffix = cg.readEntry("defaultFileSuffix", DEFAULT_WALLPAPER_SUFFIX);
00252     d->defaultWallpaperWidth = cg.readEntry("defaultWidth", DEFAULT_WALLPAPER_WIDTH);
00253     d->defaultWallpaperHeight = cg.readEntry("defaultHeight", DEFAULT_WALLPAPER_HEIGHT);
00254 
00255     disconnect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), this, SIGNAL(themeChanged()));
00256     if (colorsFile.isEmpty()) {
00257         d->colors = 0;
00258         connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), this, SIGNAL(themeChanged()));
00259     } else {
00260         d->colors = KSharedConfig::openConfig(colorsFile);
00261     }
00262 
00263     d->hasWallpapers = !KStandardDirs::locate("data", "desktoptheme/" + theme + "/wallpapers").isEmpty();
00264 
00265     if (d->isDefault) {
00266         // we're the default theme, let's save our state
00267         KConfigGroup &cg = d->config();
00268         if (ThemePrivate::defaultTheme == d->themeName) {
00269             cg.deleteEntry("name");
00270         } else {
00271             cg.writeEntry("name", d->themeName);
00272         }
00273     }
00274 
00275     emit themeChanged();
00276 }
00277 
00278 QString Theme::themeName() const
00279 {
00280     return d->themeName;
00281 }
00282 
00283 QString Theme::imagePath(const QString& name)  const
00284 {
00285     QString path = d->findInTheme(name + ".svg", d->themeName);
00286 
00287     if (path.isEmpty() && d->themeName != ThemePrivate::defaultTheme) {
00288         path = d->findInTheme(name + ".svg", ThemePrivate::defaultTheme);
00289     }
00290 
00291     if (path.isEmpty()) {
00292         kDebug() << "Theme says: bad image path " << name;
00293     }
00294 
00295     return path;
00296 }
00297 
00298 QString Theme::wallpaperPath(const QSize &size) const
00299 {
00300     QString fullPath;
00301     QString image = d->defaultWallpaperTheme;
00302 
00303     image.append("/contents/images/%1x%2").append(d->defaultWallpaperSuffix);
00304     QString defaultImage = image.arg(d->defaultWallpaperWidth).arg(d->defaultWallpaperHeight);
00305 
00306     if (size.isValid()) {
00307         // try to customize the paper to the size requested
00308         //TODO: this should do better than just fallback to the default size.
00309         //      a "best fit" matching would be far better, so we don't end
00310         //      up returning a 1920x1200 wallpaper for a 640x480 request ;)
00311         image = image.arg(size.width()).arg(size.height());
00312     } else {
00313         image = defaultImage;
00314     }
00315 
00316     //TODO: the theme's wallpaper overrides regularly installed wallpapers.
00317     //      should it be possible for user installed (e.g. locateLocal) wallpapers
00318     //      to override the theme?
00319     if (d->hasWallpapers) {
00320         // check in the theme first
00321         fullPath = d->findInTheme("wallpaper/" + image, d->themeName);
00322 
00323         if (fullPath.isEmpty()) {
00324             fullPath = d->findInTheme("wallpaper/" + defaultImage, d->themeName);
00325         }
00326     }
00327 
00328     if (fullPath.isEmpty()) {
00329         // we failed to find it in the theme, so look in the standard directories
00330         //kDebug() << "looking for" << image;
00331         fullPath = KStandardDirs::locate("wallpaper", image);
00332     }
00333 
00334     if (fullPath.isEmpty()) {
00335         // we still failed to find it in the theme, so look for the default in
00336         // the standard directories
00337         //kDebug() << "looking for" << defaultImage;
00338         fullPath = KStandardDirs::locate("wallpaper", defaultImage);
00339 
00340         if (fullPath.isEmpty()) {
00341             kDebug() << "exhausted every effort to find a wallpaper.";
00342         }
00343     }
00344 
00345     return fullPath;
00346 }
00347 
00348 bool Theme::currentThemeHasImage(const QString& name)  const
00349 {
00350     return (!d->findInTheme(name + ".svg", d->themeName).isEmpty());
00351 }
00352 
00353 KSharedConfigPtr Theme::colorScheme() const
00354 {
00355     return d->colors;
00356 }
00357 
00358 QColor Theme::color(ColorRole role) const
00359 {
00360     KColorScheme colorScheme(QPalette::Active, KColorScheme::Window, Theme::defaultTheme()->colorScheme());
00361 
00362     switch (role) {
00363         case TextColor:
00364             return colorScheme.foreground(KColorScheme::NormalText).color();
00365             break;
00366 
00367         case HighlightColor:
00368             return colorScheme.background(KColorScheme::ActiveBackground).color();
00369             break;
00370 
00371         case BackgroundColor:
00372             return colorScheme.background().color();
00373             break;
00374     }
00375 
00376     return QColor();
00377 }
00378 
00379 void Theme::setFont(const QFont &font, FontRole role)
00380 {
00381     Q_UNUSED(role)
00382     d->generalFont = font;
00383 }
00384 
00385 QFont Theme::font(FontRole role) const
00386 {
00387     Q_UNUSED(role)
00388     return d->generalFont;
00389 }
00390 
00391 QFontMetrics Theme::fontMetrics() const
00392 {
00393     //TODO: allow this to be overridden with a plasma specific font?
00394     return QFontMetrics(d->generalFont);
00395 }
00396 
00397 bool Theme::windowTranslucencyEnabled() const
00398 {
00399     return d->compositingActive;
00400 }
00401 
00402 void Theme::setUseGlobalSettings(bool useGlobal)
00403 {
00404     if (d->useGlobal == useGlobal) {
00405         return;
00406     }
00407 
00408     d->useGlobal = useGlobal;
00409     d->cfg = KConfigGroup();
00410     d->themeName = QString();
00411     settingsChanged();
00412 }
00413 
00414 bool Theme::useGlobalSettings() const
00415 {
00416     return d->useGlobal;
00417 }
00418 
00419 }
00420 
00421 #include <theme.moc>

libplasma

Skip menu "libplasma"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal