1 /****************************************************************************
4 ** KRDB - puts current KDE color scheme into preprocessor statements
5 ** cats specially written application default files and uses xrdb -merge to
6 ** write to RESOURCE_MANAGER. Thus it gives a simple way to make non-KDE
7 ** applications fit in with the desktop
9 ** Copyright (C) 1998 by Mark Donohoe
10 ** Copyright (C) 1999 by Dirk A. Mueller (reworked for KDE 2.0)
11 ** Copyright (C) 2001 by Matthias Ettrich (add support for GTK applications )
12 ** Copyright (C) 2001 by Waldo Bastian <bastian@kde.org>
13 ** Copyright (C) 2002 by Karol Szwed <gallium@kde.org>
14 ** This application is freely distributable under the GNU Public License.
16 *****************************************************************************/
18 #include <config-workspace.h>
27 #include <QtCore/QSettings>
28 #include <QtCore/QTextCodec>
33 #include <QTextStream>
35 #include <QtDBus/QtDBus>
36 #include <ktoolinvocation.h>
37 #include <klauncher_iface.h>
39 #include <kapplication.h>
41 #include <kconfiggroup.h>
43 #include <kglobalsettings.h>
44 #include <kstandarddirs.h>
46 #include <ksavefile.h>
47 #include <ktemporaryfile.h>
56 inline const char * gtkEnvVar(int version
)
58 return 2==version
? "GTK2_RC_FILES" : "GTK_RC_FILES";
61 inline const char * sysGtkrc(int version
)
65 if(access("/etc/opt/gnome/gtk-2.0", F_OK
) == 0)
66 return "/etc/opt/gnome/gtk-2.0/gtkrc";
68 return "/etc/gtk-2.0/gtkrc";
72 if(access("/etc/opt/gnome/gtk", F_OK
) == 0)
73 return "/etc/opt/gnome/gtk/gtkrc";
75 return "/etc/gtk/gtkrc";
79 inline const char * userGtkrc(int version
)
81 return 2==version
? "/.gtkrc-2.0" : "/.gtkrc";
84 // -----------------------------------------------------------------------------
85 static void applyGtkStyles(bool active
, int version
)
87 QString gtkkde
= KStandardDirs::locateLocal("config", 2==version
?"gtkrc-2.0":"gtkrc");
88 QByteArray gtkrc
= getenv(gtkEnvVar(version
));
89 QStringList list
= QFile::decodeName(gtkrc
).split( ':');
90 QString userHomeGtkrc
= QDir::homePath()+userGtkrc(version
);
91 if (!list
.contains(userHomeGtkrc
))
92 list
.prepend(userHomeGtkrc
);
93 QLatin1String systemGtkrc
= QLatin1String(sysGtkrc(version
));
94 if (!list
.contains(systemGtkrc
))
95 list
.prepend(systemGtkrc
);
96 list
.removeAll(gtkkde
);
99 ::unlink(QFile::encodeName(gtkkde
));
101 // Pass env. var to kdeinit.
102 QString name
= gtkEnvVar(version
);
103 QString value
= QFile::encodeName(list
.join(":"));
104 KToolInvocation::klauncher()->setLaunchEnv(name
, value
);
107 // -----------------------------------------------------------------------------
109 static void applyQtColors( KConfigGroup kglobals
, QSettings
& settings
, QPalette
& newPal
)
111 QStringList actcg
, inactcg
, discg
;
112 /* export kde color settings */
114 for (i
= 0; i
< QPalette::NColorRoles
; i
++)
115 actcg
<< newPal
.color(QPalette::Active
,
116 (QPalette::ColorRole
) i
).name();
117 for (i
= 0; i
< QPalette::NColorRoles
; i
++)
118 inactcg
<< newPal
.color(QPalette::Inactive
,
119 (QPalette::ColorRole
) i
).name();
120 for (i
= 0; i
< QPalette::NColorRoles
; i
++)
121 discg
<< newPal
.color(QPalette::Disabled
,
122 (QPalette::ColorRole
) i
).name();
124 settings
.setValue("/qt/Palette/active", actcg
);
125 settings
.setValue("/qt/Palette/inactive", inactcg
);
126 settings
.setValue("/qt/Palette/disabled", discg
);
128 // export kwin's colors to qtrc for kstyle to use
129 kglobals
.changeGroup("WM");
132 QColor clr
= newPal
.color( QPalette::Active
, QPalette::Background
);
133 clr
= kglobals
.readEntry("activeBackground", clr
);
134 settings
.setValue("/qt/KWinPalette/activeBackground", clr
.name());
135 if (QPixmap::defaultDepth() > 8)
137 clr
= kglobals
.readEntry("activeBlend", clr
);
138 settings
.setValue("/qt/KWinPalette/activeBlend", clr
.name());
139 clr
= newPal
.color( QPalette::Active
, QPalette::HighlightedText
);
140 clr
= kglobals
.readEntry("activeForeground", clr
);
141 settings
.setValue("/qt/KWinPalette/activeForeground", clr
.name());
142 clr
= newPal
.color( QPalette::Active
,QPalette::Background
);
143 clr
= kglobals
.readEntry("frame", clr
);
144 settings
.setValue("/qt/KWinPalette/frame", clr
.name());
145 clr
= kglobals
.readEntry("activeTitleBtnBg", clr
);
146 settings
.setValue("/qt/KWinPalette/activeTitleBtnBg", clr
.name());
149 clr
= newPal
.color(QPalette::Inactive
, QPalette::Background
);
150 clr
= kglobals
.readEntry("inactiveBackground", clr
);
151 settings
.setValue("/qt/KWinPalette/inactiveBackground", clr
.name());
152 if (QPixmap::defaultDepth() > 8)
154 clr
= kglobals
.readEntry("inactiveBlend", clr
);
155 settings
.setValue("/qt/KWinPalette/inactiveBlend", clr
.name());
156 clr
= newPal
.color(QPalette::Inactive
, QPalette::Background
).dark();
157 clr
= kglobals
.readEntry("inactiveForeground", clr
);
158 settings
.setValue("/qt/KWinPalette/inactiveForeground", clr
.name());
159 clr
= newPal
.color(QPalette::Inactive
, QPalette::Background
);
160 clr
= kglobals
.readEntry("inactiveFrame", clr
);
161 settings
.setValue("/qt/KWinPalette/inactiveFrame", clr
.name());
162 clr
= kglobals
.readEntry("inactiveTitleBtnBg", clr
);
163 settings
.setValue("/qt/KWinPalette/inactiveTitleBtnBg", clr
.name());
165 kglobals
.changeGroup("KDE");
166 settings
.setValue("/qt/KDE/contrast", kglobals
.readEntry("contrast", 7));
169 // -----------------------------------------------------------------------------
171 static void applyQtSettings( KConfigGroup kglobals
, QSettings
& settings
)
173 // export KDE's plugin library path to Trolltech.conf
174 // This is only needed for Qt applications that run outside of a KDE session but still should
175 // use a KDE style. In order to load the style (or any KDE code in that regard) Qt needs to
176 // know the plugin path of KDE.
178 QString qversion
= qVersion();
179 if ( qversion
.count( '.' ) > 1 )
180 qversion
.truncate( qversion
.lastIndexOf( '.' ) );
181 if ( qversion
.contains( '-' ) )
182 qversion
.truncate( qversion
.lastIndexOf( '-' ) );
184 // paths that KDE added
185 QStringList kdeAdded
= settings
.value("/qt/KDE/kdeAddedLibraryPaths").toStringList();
187 const QString
&libPathKey
= QString("/qt/%1/libraryPath").arg(qversion
);
188 // paths that Qt currently adds. Don't use toStringList! That's a different storage format
189 QStringList libraryPath
= settings
.value(libPathKey
, QString()).toString().split(QLatin1Char(':'), QString::SkipEmptyParts
);
191 // only keep entries that are not from KDE
192 foreach (const QString
&path
, const_cast<const QStringList
&>(kdeAdded
)) {
193 libraryPath
.removeAll(path
);
198 // paths that need to be in the list
199 const QStringList
&plugins
= KGlobal::dirs()->resourceDirs("qtplugins");
200 foreach (const QString
&_path
, plugins
) {
201 QString path
= QDir(_path
).canonicalPath();
202 if (path
.isEmpty() || kdeAdded
.contains(path
)) {
205 kdeAdded
.prepend(path
);
206 if (path
.contains("/lib64/")) {
207 path
.replace("/lib64/", "/lib/");
208 if (!kdeAdded
.contains(path
)) {
209 kdeAdded
.prepend(path
);
213 foreach (const QString
&path
, const_cast<const QStringList
&>(kdeAdded
)) {
214 libraryPath
.append(path
);
217 // Write the list out..
218 settings
.setValue("/qt/KDE/kdeAddedLibraryPaths", kdeAdded
);
219 settings
.setValue(libPathKey
, libraryPath
.join(QLatin1String(":")));
221 #if (QT_VERSION < QT_VERSION_CHECK(4, 5, 0)) //Qt 4.5 will read kde config files if running on kde
222 /* export widget style */
223 kglobals
.changeGroup("General");
224 QString style
= kglobals
.readEntry("widgetStyle", KStyle::defaultStyle());
225 if (!style
.isEmpty())
226 settings
.setValue("/qt/style", style
);
229 /* export font settings */
230 settings
.setValue("/qt/font", KGlobalSettings::generalFont().toString());
232 /* ##### looks like kcmfonts skips this, so we don't do this here */
233 /*bool usexft = kglobals.readEntry("AntiAliasing", false);
234 kconfig.setGroup("General");
235 settings.writeEntry("/qt/enableXft", usexft);
236 settings.writeEntry("/qt/useXft", usexft); */
238 /* export effects settings */
239 kglobals
.changeGroup("KDE");
240 bool effectsEnabled
= kglobals
.readEntry("EffectsEnabled", false);
241 bool fadeMenus
= kglobals
.readEntry("EffectFadeMenu", false);
242 bool fadeTooltips
= kglobals
.readEntry("EffectFadeTooltip", false);
243 bool animateCombobox
= kglobals
.readEntry("EffectAnimateCombo", false);
245 QStringList guieffects
;
246 if (effectsEnabled
) {
247 guieffects
<< QString("general");
249 guieffects
<< QString("fademenu");
251 guieffects
<< QString("animatecombo");
253 guieffects
<< QString("fadetooltip");
256 guieffects
<< QString("none");
258 settings
.setValue("/qt/GUIEffects", guieffects
);
261 // -----------------------------------------------------------------------------
263 static void addColorDef(QString
& s
, const char* n
, const QColor
& col
)
267 tmp
.sprintf("#define %s #%02x%02x%02x\n",
268 n
, col
.red(), col
.green(), col
.blue());
274 // -----------------------------------------------------------------------------
276 static void copyFile(QFile
& tmp
, QString
const& filename
, bool )
279 if ( f
.open(QIODevice::ReadOnly
) ) {
280 QByteArray
buf( 8192, ' ' );
281 while ( !f
.atEnd() ) {
282 int read
= f
.read( buf
.data(), buf
.size() );
284 tmp
.write( buf
.data(), read
);
290 // -----------------------------------------------------------------------------
292 static QString
item( int i
) {
293 return QString::number( i
/ 255.0, 'f', 3 );
296 static QString
color( const QColor
& col
)
298 return QString( "{ %1, %2, %3 }" ).arg( item( col
.red() ) ).arg( item( col
.green() ) ).arg( item( col
.blue() ) );
301 static void createGtkrc( bool exportColors
, const QPalette
& cg
, int version
)
303 // lukas: why does it create in ~/.kde/share/config ???
304 // pfeiffer: so that we don't overwrite the user's gtkrc.
305 // it is found via the GTK_RC_FILES environment variable.
306 KSaveFile
saveFile( KStandardDirs::locateLocal( "config", 2==version
?"gtkrc-2.0":"gtkrc" ) );
307 if ( !saveFile
.open() )
310 QTextStream
t ( &saveFile
);
311 t
.setCodec( QTextCodec::codecForLocale () );
314 "# created by KDE, %1\n"
316 "# If you do not want KDE to override your GTK settings, select\n"
317 "# Appearance -> Colors in the Control Center and disable the checkbox\n"
318 "# \"Apply colors to non-KDE4 applications\"\n"
320 "#\n", QDateTime::currentDateTime().toString());
322 t
<< "style \"default\"" << endl
;
326 t
<< " bg[NORMAL] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
327 t
<< " bg[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
328 t
<< " bg[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
329 t
<< " bg[ACTIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Mid
) ) << endl
;
330 t
<< " bg[PRELIGHT] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
332 t
<< " base[NORMAL] = " << color( cg
.color( QPalette::Active
, QPalette::Base
) ) << endl
;
333 t
<< " base[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
334 t
<< " base[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
335 t
<< " base[ACTIVE] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
336 t
<< " base[PRELIGHT] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
338 t
<< " text[NORMAL] = " << color( cg
.color(QPalette::Active
, QPalette::Text
) ) << endl
;
339 t
<< " text[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
340 t
<< " text[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Mid
) ) << endl
;
341 t
<< " text[ACTIVE] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
342 t
<< " text[PRELIGHT] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
344 t
<< " fg[NORMAL] = " << color ( cg
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
345 t
<< " fg[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
346 t
<< " fg[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Mid
) ) << endl
;
347 t
<< " fg[ACTIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
348 t
<< " fg[PRELIGHT] = " << color( cg
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
353 t
<< "class \"*\" style \"default\"" << endl
;
355 if ( 2==version
) { // we should maybe check for MacOS settings here
356 t
<< "gtk-alternative-button-order = 1" << endl
;
362 // tooltips don't have the standard background color
363 t
<< "style \"ToolTip\"" << endl
;
365 QPalette group
= QToolTip::palette();
366 t
<< " bg[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
367 t
<< " base[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Base
) ) << endl
;
368 t
<< " text[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Text
) ) << endl
;
369 t
<< " fg[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
372 t
<< "widget \"gtk-tooltip\" style \"ToolTip\"" << endl
;
373 t
<< "widget \"gtk-tooltips\" style \"ToolTip\"" << endl
;
377 // highlight the current (mouse-hovered) menu-item
378 // not every button, checkbox, etc.
379 t
<< "style \"MenuItem\"" << endl
;
381 t
<< " bg[PRELIGHT] = " << color( cg
.color(QPalette::Highlight
) ) << endl
;
384 t
<< "class \"*MenuItem\" style \"MenuItem\"" << endl
;
389 // -----------------------------------------------------------------------------
391 void runRdb( uint flags
)
393 // Obtain the application palette that is about to be set.
394 bool exportColors
= flags
& KRdbExportColors
;
395 bool exportQtColors
= flags
& KRdbExportQtColors
;
396 bool exportQtSettings
= flags
& KRdbExportQtSettings
;
397 bool exportXftSettings
= flags
& KRdbExportXftSettings
;
399 KSharedConfigPtr kglobalcfg
= KSharedConfig::openConfig( "kdeglobals" );
400 KConfigGroup
kglobals(kglobalcfg
, "KDE");
401 QPalette newPal
= KGlobalSettings::createApplicationPalette(kglobalcfg
);
403 KTemporaryFile tmpFile
;
406 kDebug() << "Couldn't open temp file";
410 // Export colors to non-(KDE/Qt) apps (e.g. Motif, GTK+ apps)
413 KGlobal::dirs()->addResourceType("appdefaults", "data", "kdisplay/app-defaults/");
414 KGlobal::locale()->insertCatalog("krdb");
415 createGtkrc( true, newPal
, 1 );
416 createGtkrc( true, newPal
, 2 );
419 QColor backCol
= newPal
.color( QPalette::Active
, QPalette::Background
);
420 addColorDef(preproc
, "FOREGROUND" , newPal
.color( QPalette::Active
, QPalette::Foreground
) );
421 addColorDef(preproc
, "BACKGROUND" , backCol
);
422 addColorDef(preproc
, "HIGHLIGHT" , backCol
.light(100+(2*KGlobalSettings::contrast()+4)*16/1));
423 addColorDef(preproc
, "LOWLIGHT" , backCol
.dark(100+(2*KGlobalSettings::contrast()+4)*10));
424 addColorDef(preproc
, "SELECT_BACKGROUND" , newPal
.color( QPalette::Active
, QPalette::Highlight
));
425 addColorDef(preproc
, "SELECT_FOREGROUND" , newPal
.color( QPalette::Active
, QPalette::HighlightedText
));
426 addColorDef(preproc
, "WINDOW_BACKGROUND" , newPal
.color( QPalette::Active
, QPalette::Base
) );
427 addColorDef(preproc
, "WINDOW_FOREGROUND" , newPal
.color( QPalette::Active
, QPalette::Foreground
) );
428 addColorDef(preproc
, "INACTIVE_BACKGROUND", KGlobalSettings::inactiveTitleColor());
429 addColorDef(preproc
, "INACTIVE_FOREGROUND", KGlobalSettings::inactiveTitleColor());
430 addColorDef(preproc
, "ACTIVE_BACKGROUND" , KGlobalSettings::activeTitleColor());
431 addColorDef(preproc
, "ACTIVE_FOREGROUND" , KGlobalSettings::activeTitleColor());
432 //---------------------------------------------------------------
434 tmpFile
.write( preproc
.toLatin1(), preproc
.length() );
438 const QStringList adPaths
= KGlobal::dirs()->findDirs("appdefaults", "");
439 for (QStringList::ConstIterator it
= adPaths
.constBegin(); it
!= adPaths
.constEnd(); ++it
) {
442 if ( dSys
.exists() ) {
443 dSys
.setFilter( QDir::Files
);
444 dSys
.setSorting( QDir::Name
);
445 dSys
.setNameFilters(QStringList("*.ad"));
446 list
+= dSys
.entryList();
450 for (QStringList::ConstIterator it
= list
.constBegin(); it
!= list
.constEnd(); ++it
)
451 copyFile(tmpFile
, KStandardDirs::locate("appdefaults", *it
), true);
454 // Merge ~/.Xresources or fallback to ~/.Xdefaults
455 QString homeDir
= QDir::homePath();
456 QString xResources
= homeDir
+ "/.Xresources";
458 // very primitive support for ~/.Xresources by appending it
459 if ( QFile::exists( xResources
) )
460 copyFile(tmpFile
, xResources
, true);
462 copyFile(tmpFile
, homeDir
+ "/.Xdefaults", true);
464 // Export the Xcursor theme & size settings
465 KConfigGroup
mousecfg(KSharedConfig::openConfig( "kcminputrc" ), "Mouse" );
466 QString theme
= mousecfg
.readEntry("cursorTheme", QString());
467 QString size
= mousecfg
.readEntry("cursorSize", QString());
471 contents
= "Xcursor.theme: " + theme
+ '\n';
474 contents
+= "Xcursor.size: " + size
+ '\n';
476 if (exportXftSettings
)
478 kglobals
.changeGroup("General");
480 if (kglobals
.hasKey("XftAntialias"))
482 contents
+= "Xft.antialias: ";
483 if(kglobals
.readEntry("XftAntialias", true))
489 if (kglobals
.hasKey("XftHintStyle"))
491 QString hintStyle
= kglobals
.readEntry("XftHintStyle", "hintmedium");
492 contents
+= "Xft.hinting: ";
493 if(hintStyle
.isEmpty())
497 if(hintStyle
!="hintnone")
501 contents
+= "Xft.hintstyle: " + hintStyle
+ '\n';
505 if (kglobals
.hasKey("XftSubPixel"))
507 QString subPixel
= kglobals
.readEntry("XftSubPixel");
508 if(!subPixel
.isEmpty())
509 contents
+= "Xft.rgba: " + subPixel
+ '\n';
512 KConfig
_cfgfonts( "kcmfonts" );
513 KConfigGroup
cfgfonts(&_cfgfonts
, "General");
515 if( cfgfonts
.readEntry( "forceFontDPI", 0 ) != 0 )
516 contents
+= "Xft.dpi: " + cfgfonts
.readEntry( "forceFontDPI" ) + '\n';
520 proc
<< "xrdb" << "-quiet" << "-remove" << "-nocpp";
522 if (proc
.waitForStarted())
524 proc
.write( QByteArray( "Xft.dpi\n" ) );
525 proc
.closeWriteChannel();
526 proc
.waitForFinished();
531 if (contents
.length() > 0)
532 tmpFile
.write( contents
.toLatin1(), contents
.length() );
538 proc
<< "xrdb" << "-merge" << tmpFile
.fileName();
540 proc
<< "xrdb" << "-quiet" << "-merge" << tmpFile
.fileName();
544 applyGtkStyles(exportColors
, 1);
545 applyGtkStyles(exportColors
, 2);
548 if ( exportQtColors
|| exportQtSettings
)
550 QSettings
* settings
= new QSettings(QLatin1String("Trolltech"));
552 if ( exportQtColors
)
553 applyQtColors( kglobals
, *settings
, newPal
); // For kcmcolors
555 if ( exportQtSettings
)
556 applyQtSettings( kglobals
, *settings
); // For kcmstyle
559 QApplication::flush();
561 // We let KIPC take care of ourselves, as we are in a KDE app with
562 // QApp::setDesktopSettingsAware(false);
563 // Instead of calling QApp::x11_apply_settings() directly, we instead
564 // modify the timestamp which propagates the settings changes onto
565 // Qt-only apps without adversely affecting ourselves.
567 // Cheat and use the current timestamp, since we just saved to qtrc.
568 QDateTime settingsstamp
= QDateTime::currentDateTime();
570 static Atom qt_settings_timestamp
= 0;
571 if (!qt_settings_timestamp
) {
572 QString
atomname("_QT_SETTINGS_TIMESTAMP_");
573 atomname
+= XDisplayName( 0 ); // Use the $DISPLAY envvar.
574 qt_settings_timestamp
= XInternAtom( QX11Info::display(), atomname
.toLatin1(), False
);
578 QDataStream
s(&stamp
.buffer(), QIODevice::WriteOnly
);
580 XChangeProperty( QX11Info::display(), QX11Info::appRootWindow(), qt_settings_timestamp
,
581 qt_settings_timestamp
, 8, PropModeReplace
,
582 (unsigned char*) stamp
.buffer().data(),
583 stamp
.buffer().size() );
584 QApplication::flush();