00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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
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
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
00212 if (d->themeName.isEmpty()) {
00213 theme = ThemePrivate::defaultTheme;
00214 } else {
00215 return;
00216 }
00217 }
00218
00219
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
00234 QString colorsFile = KStandardDirs::locate("data", "desktoptheme/" + theme + "/colors");
00235
00236
00237
00238 KConfig metadata(KStandardDirs::locate("data", "desktoptheme/" + theme + "/metadata.desktop"));
00239 KConfigGroup cg;
00240 if (metadata.hasGroup("Wallpaper")) {
00241
00242
00243 cg = KConfigGroup(&metadata, "Wallpaper");
00244 } else {
00245
00246
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
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
00308
00309
00310
00311 image = image.arg(size.width()).arg(size.height());
00312 } else {
00313 image = defaultImage;
00314 }
00315
00316
00317
00318
00319 if (d->hasWallpapers) {
00320
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
00330
00331 fullPath = KStandardDirs::locate("wallpaper", image);
00332 }
00333
00334 if (fullPath.isEmpty()) {
00335
00336
00337
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
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>