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 if (list
.count() == 0)
92 list
.append(QLatin1String(sysGtkrc(version
)));
93 list
.append(QDir::homePath()+userGtkrc(version
));
95 list
.removeAll(gtkkde
);
98 ::unlink(QFile::encodeName(gtkkde
));
100 // Pass env. var to kdeinit.
101 QString name
= gtkEnvVar(version
);
102 QString value
= QFile::encodeName(list
.join(":"));
103 KToolInvocation::klauncher()->setLaunchEnv(name
, value
);
106 // -----------------------------------------------------------------------------
108 static void applyQtColors( KConfigGroup kglobals
, QSettings
& settings
, QPalette
& newPal
)
110 QStringList actcg
, inactcg
, discg
;
111 /* export kde color settings */
113 for (i
= 0; i
< QPalette::NColorRoles
; i
++)
114 actcg
<< newPal
.color(QPalette::Active
,
115 (QPalette::ColorRole
) i
).name();
116 for (i
= 0; i
< QPalette::NColorRoles
; i
++)
117 inactcg
<< newPal
.color(QPalette::Inactive
,
118 (QPalette::ColorRole
) i
).name();
119 for (i
= 0; i
< QPalette::NColorRoles
; i
++)
120 discg
<< newPal
.color(QPalette::Disabled
,
121 (QPalette::ColorRole
) i
).name();
123 settings
.setValue("/qt/Palette/active", actcg
);
124 settings
.setValue("/qt/Palette/inactive", inactcg
);
125 settings
.setValue("/qt/Palette/disabled", discg
);
127 // export kwin's colors to qtrc for kstyle to use
128 kglobals
.changeGroup("WM");
131 QColor clr
= newPal
.color( QPalette::Active
, QPalette::Background
);
132 clr
= kglobals
.readEntry("activeBackground", clr
);
133 settings
.setValue("/qt/KWinPalette/activeBackground", clr
.name());
134 if (QPixmap::defaultDepth() > 8)
136 clr
= kglobals
.readEntry("activeBlend", clr
);
137 settings
.setValue("/qt/KWinPalette/activeBlend", clr
.name());
138 clr
= newPal
.color( QPalette::Active
, QPalette::HighlightedText
);
139 clr
= kglobals
.readEntry("activeForeground", clr
);
140 settings
.setValue("/qt/KWinPalette/activeForeground", clr
.name());
141 clr
= newPal
.color( QPalette::Active
,QPalette::Background
);
142 clr
= kglobals
.readEntry("frame", clr
);
143 settings
.setValue("/qt/KWinPalette/frame", clr
.name());
144 clr
= kglobals
.readEntry("activeTitleBtnBg", clr
);
145 settings
.setValue("/qt/KWinPalette/activeTitleBtnBg", clr
.name());
148 clr
= newPal
.color(QPalette::Inactive
, QPalette::Background
);
149 clr
= kglobals
.readEntry("inactiveBackground", clr
);
150 settings
.setValue("/qt/KWinPalette/inactiveBackground", clr
.name());
151 if (QPixmap::defaultDepth() > 8)
153 clr
= kglobals
.readEntry("inactiveBlend", clr
);
154 settings
.setValue("/qt/KWinPalette/inactiveBlend", clr
.name());
155 clr
= newPal
.color(QPalette::Inactive
, QPalette::Background
).dark();
156 clr
= kglobals
.readEntry("inactiveForeground", clr
);
157 settings
.setValue("/qt/KWinPalette/inactiveForeground", clr
.name());
158 clr
= newPal
.color(QPalette::Inactive
, QPalette::Background
);
159 clr
= kglobals
.readEntry("inactiveFrame", clr
);
160 settings
.setValue("/qt/KWinPalette/inactiveFrame", clr
.name());
161 clr
= kglobals
.readEntry("inactiveTitleBtnBg", clr
);
162 settings
.setValue("/qt/KWinPalette/inactiveTitleBtnBg", clr
.name());
164 kglobals
.changeGroup("KDE");
165 settings
.setValue("/qt/KDE/contrast", kglobals
.readEntry("contrast", 7));
168 // -----------------------------------------------------------------------------
170 static void applyQtSettings( KConfigGroup kglobals
, QSettings
& settings
)
172 /* export kde's plugin library path to qtrc */
174 QMap
<QString
, bool> pathDb
;
175 // OK, this isn't fun at all.
176 // KApp adds paths ending with /, QApp those without slash, and if
177 // one gives it something that is other way around, it will complain and scare
178 // users. So we need to know whether a path being added is from KApp, and in this case
179 // end it with.. So keep a QMap to bool, specifying whether the path is KDE-specified..
181 QString qversion
= qVersion();
182 if ( qversion
.count( '.' ) > 1 )
183 qversion
.truncate( qversion
.lastIndexOf( '.' ) );
184 if ( qversion
.contains( '-' ) )
185 qversion
.truncate( qversion
.lastIndexOf( '-' ) );
187 QStringList kdeAdded
=
188 settings
.value("/qt/KDE/kdeAddedLibraryPaths").toStringList();
190 QString("/qt/%1/libraryPath").arg( qversion
);
192 //Read qt library path..
193 QStringList plugins
= settings
.value(libPathKey
, ':').toStringList();
194 for (QStringList::ConstIterator it
= plugins
.begin(); it
!= plugins
.end(); ++it
)
197 if (path
.endsWith('/'))
198 path
.truncate(path
.length()-1);
203 //Get rid of old KDE-added ones...
204 for (QStringList::ConstIterator it
= kdeAdded
.begin(); it
!= kdeAdded
.end(); ++it
)
208 if (path
.endsWith('/'))
209 path
.truncate(path
.length()-1);
217 //Merge in KDE ones..
218 plugins
= KGlobal::dirs()->resourceDirs( "qtplugins" );
220 for (QStringList::ConstIterator it
= plugins
.begin(); it
!= plugins
.end(); ++it
)
223 if (path
.endsWith('/'))
224 path
.truncate(path
.length()-1);
228 if(path
.contains("/lib64/"))
229 path
.replace("/lib64/","/lib/");
234 for (QMap
<QString
, bool>::ConstIterator it
= pathDb
.begin();
235 it
!= pathDb
.end(); ++it
)
237 QString path
= it
.key();
238 bool fromKDE
= it
.value();
240 char new_path
[PATH_MAX
+1];
241 if (realpath(QFile::encodeName(path
), new_path
))
242 path
= QFile::decodeName(new_path
);
246 if (!path
.endsWith('/'))
248 kdeAdded
.push_back(path
); //Add for the new list -- do it here to have it in the right form..
254 //Write the list out..
255 settings
.setValue("/qt/KDE/kdeAddedLibraryPaths", kdeAdded
);
256 settings
.setValue(libPathKey
, paths
.join(QString(':')));
258 /* export widget style */
259 kglobals
.changeGroup("General");
260 QString style
= kglobals
.readEntry("widgetStyle", KStyle::defaultStyle());
261 if (!style
.isEmpty())
262 settings
.setValue("/qt/style", style
);
264 /* export font settings */
265 settings
.setValue("/qt/font", KGlobalSettings::generalFont().toString());
267 /* ##### looks like kcmfonts skips this, so we don't do this here */
268 /*bool usexft = kglobals.readEntry("AntiAliasing", false);
269 kconfig.setGroup("General");
270 settings.writeEntry("/qt/enableXft", usexft);
271 settings.writeEntry("/qt/useXft", usexft); */
273 /* export effects settings */
274 kglobals
.changeGroup("KDE");
275 bool effectsEnabled
= kglobals
.readEntry("EffectsEnabled", false);
276 bool fadeMenus
= kglobals
.readEntry("EffectFadeMenu", false);
277 bool fadeTooltips
= kglobals
.readEntry("EffectFadeTooltip", false);
278 bool animateCombobox
= kglobals
.readEntry("EffectAnimateCombo", false);
280 QStringList guieffects
;
281 if (effectsEnabled
) {
282 guieffects
<< QString("general");
284 guieffects
<< QString("fademenu");
286 guieffects
<< QString("animatecombo");
288 guieffects
<< QString("fadetooltip");
291 guieffects
<< QString("none");
293 settings
.setValue("/qt/GUIEffects", guieffects
);
296 // -----------------------------------------------------------------------------
298 static void addColorDef(QString
& s
, const char* n
, const QColor
& col
)
302 tmp
.sprintf("#define %s #%02x%02x%02x\n",
303 n
, col
.red(), col
.green(), col
.blue());
309 // -----------------------------------------------------------------------------
311 static void copyFile(QFile
& tmp
, QString
const& filename
, bool )
314 if ( f
.open(QIODevice::ReadOnly
) ) {
315 QByteArray
buf( 8192, ' ' );
316 while ( !f
.atEnd() ) {
317 int read
= f
.read( buf
.data(), buf
.size() );
319 tmp
.write( buf
.data(), read
);
325 // -----------------------------------------------------------------------------
327 static QString
item( int i
) {
328 return QString::number( i
/ 255.0, 'f', 3 );
331 static QString
color( const QColor
& col
)
333 return QString( "{ %1, %2, %3 }" ).arg( item( col
.red() ) ).arg( item( col
.green() ) ).arg( item( col
.blue() ) );
336 static void createGtkrc( bool exportColors
, const QPalette
& cg
, int version
)
338 // lukas: why does it create in ~/.kde/share/config ???
339 // pfeiffer: so that we don't overwrite the user's gtkrc.
340 // it is found via the GTK_RC_FILES environment variable.
341 KSaveFile
saveFile( KStandardDirs::locateLocal( "config", 2==version
?"gtkrc-2.0":"gtkrc" ) );
342 if ( !saveFile
.open() )
345 QTextStream
t ( &saveFile
);
346 t
.setCodec( QTextCodec::codecForLocale () );
349 "# created by KDE, %1\n"
351 "# If you do not want KDE to override your GTK settings, select\n"
352 "# Appearance & Themes -> Colors in the Control Center and disable the checkbox\n"
353 "# \"Apply colors to non-KDE applications\"\n"
355 "#\n", QDateTime::currentDateTime().toString());
357 t
<< "style \"default\"" << endl
;
361 t
<< " bg[NORMAL] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
362 t
<< " bg[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
363 t
<< " bg[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
364 t
<< " bg[ACTIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Mid
) ) << endl
;
365 t
<< " bg[PRELIGHT] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
367 t
<< " base[NORMAL] = " << color( cg
.color( QPalette::Active
, QPalette::Base
) ) << endl
;
368 t
<< " base[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
369 t
<< " base[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
370 t
<< " base[ACTIVE] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
371 t
<< " base[PRELIGHT] = " << color( cg
.color(QPalette::Active
, QPalette::Highlight
) ) << endl
;
373 t
<< " text[NORMAL] = " << color( cg
.color(QPalette::Active
, QPalette::Text
) ) << endl
;
374 t
<< " text[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
375 t
<< " text[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Mid
) ) << endl
;
376 t
<< " text[ACTIVE] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
377 t
<< " text[PRELIGHT] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
379 t
<< " fg[NORMAL] = " << color ( cg
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
380 t
<< " fg[SELECTED] = " << color( cg
.color(QPalette::Active
, QPalette::HighlightedText
) ) << endl
;
381 t
<< " fg[INSENSITIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Mid
) ) << endl
;
382 t
<< " fg[ACTIVE] = " << color( cg
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
383 t
<< " fg[PRELIGHT] = " << color( cg
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
388 t
<< "class \"*\" style \"default\"" << endl
;
390 if ( 2==version
) { // we should maybe check for MacOS settings here
391 t
<< "gtk-alternative-button-order = 1" << endl
;
397 // tooltips don't have the standard background color
398 t
<< "style \"ToolTip\"" << endl
;
400 QPalette group
= QToolTip::palette();
401 t
<< " bg[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Background
) ) << endl
;
402 t
<< " base[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Base
) ) << endl
;
403 t
<< " text[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Text
) ) << endl
;
404 t
<< " fg[NORMAL] = " << color( group
.color( QPalette::Active
, QPalette::Foreground
) ) << endl
;
407 t
<< "widget \"gtk-tooltip\" style \"ToolTip\"" << endl
;
408 t
<< "widget \"gtk-tooltips\" style \"ToolTip\"" << endl
;
412 // highlight the current (mouse-hovered) menu-item
413 // not every button, checkbox, etc.
414 t
<< "style \"MenuItem\"" << endl
;
416 t
<< " bg[PRELIGHT] = " << color( cg
.color(QPalette::Highlight
) ) << endl
;
419 t
<< "class \"*MenuItem\" style \"MenuItem\"" << endl
;
424 // -----------------------------------------------------------------------------
426 void runRdb( uint flags
)
428 // Obtain the application palette that is about to be set.
429 QPalette newPal
= KGlobalSettings::createApplicationPalette();
430 bool exportColors
= flags
& KRdbExportColors
;
431 bool exportQtColors
= flags
& KRdbExportQtColors
;
432 bool exportQtSettings
= flags
& KRdbExportQtSettings
;
433 bool exportXftSettings
= flags
& KRdbExportXftSettings
;
435 KConfig
_kglobals( "kdeglobals", KConfig::NoGlobals
);
436 KConfigGroup
kglobals(KSharedConfig::openConfig( "kdeglobals" ), "KDE");
438 KTemporaryFile tmpFile
;
441 kDebug() << "Couldn't open temp file";
445 // Export colors to non-(KDE/Qt) apps (e.g. Motif, GTK+ apps)
448 KGlobal::dirs()->addResourceType("appdefaults", "data", "kdisplay/app-defaults/");
449 KGlobal::locale()->insertCatalog("krdb");
450 createGtkrc( true, newPal
, 1 );
451 createGtkrc( true, newPal
, 2 );
454 QColor backCol
= newPal
.color( QPalette::Active
, QPalette::Background
);
455 addColorDef(preproc
, "FOREGROUND" , newPal
.color( QPalette::Active
, QPalette::Foreground
) );
456 addColorDef(preproc
, "BACKGROUND" , backCol
);
457 addColorDef(preproc
, "HIGHLIGHT" , backCol
.light(100+(2*KGlobalSettings::contrast()+4)*16/1));
458 addColorDef(preproc
, "LOWLIGHT" , backCol
.dark(100+(2*KGlobalSettings::contrast()+4)*10));
459 addColorDef(preproc
, "SELECT_BACKGROUND" , newPal
.color( QPalette::Active
, QPalette::Highlight
));
460 addColorDef(preproc
, "SELECT_FOREGROUND" , newPal
.color( QPalette::Active
, QPalette::HighlightedText
));
461 addColorDef(preproc
, "WINDOW_BACKGROUND" , newPal
.color( QPalette::Active
, QPalette::Base
) );
462 addColorDef(preproc
, "WINDOW_FOREGROUND" , newPal
.color( QPalette::Active
, QPalette::Foreground
) );
463 addColorDef(preproc
, "INACTIVE_BACKGROUND", KGlobalSettings::inactiveTitleColor());
464 addColorDef(preproc
, "INACTIVE_FOREGROUND", KGlobalSettings::inactiveTitleColor());
465 addColorDef(preproc
, "ACTIVE_BACKGROUND" , KGlobalSettings::activeTitleColor());
466 addColorDef(preproc
, "ACTIVE_FOREGROUND" , KGlobalSettings::activeTitleColor());
467 //---------------------------------------------------------------
469 tmpFile
.write( preproc
.toLatin1(), preproc
.length() );
473 QStringList adPaths
= KGlobal::dirs()->findDirs("appdefaults", "");
474 for (QStringList::ConstIterator it
= adPaths
.begin(); it
!= adPaths
.end(); ++it
) {
477 if ( dSys
.exists() ) {
478 dSys
.setFilter( QDir::Files
);
479 dSys
.setSorting( QDir::Name
);
480 dSys
.setNameFilters(QStringList("*.ad"));
481 list
+= dSys
.entryList();
485 for (QStringList::ConstIterator it
= list
.begin(); it
!= list
.end(); ++it
)
486 copyFile(tmpFile
, KStandardDirs::locate("appdefaults", *it
), true);
489 // Merge ~/.Xresources or fallback to ~/.Xdefaults
490 QString homeDir
= QDir::homePath();
491 QString xResources
= homeDir
+ "/.Xresources";
493 // very primitive support for ~/.Xresources by appending it
494 if ( QFile::exists( xResources
) )
495 copyFile(tmpFile
, xResources
, true);
497 copyFile(tmpFile
, homeDir
+ "/.Xdefaults", true);
499 // Export the Xcursor theme & size settings
500 KConfigGroup
mousecfg(KSharedConfig::openConfig( "kcminputrc" ), "Mouse" );
501 QString theme
= mousecfg
.readEntry("cursorTheme", QString());
502 QString size
= mousecfg
.readEntry("cursorSize", QString());
506 contents
= "Xcursor.theme: " + theme
+ '\n';
509 contents
+= "Xcursor.size: " + size
+ '\n';
511 if (exportXftSettings
)
513 kglobals
.changeGroup("General");
515 if (kglobals
.hasKey("XftAntialias"))
517 contents
+= "Xft.antialias: ";
518 if(kglobals
.readEntry("XftAntialias", true))
524 if (kglobals
.hasKey("XftHintStyle"))
526 QString hintStyle
= kglobals
.readEntry("XftHintStyle", "hintmedium");
527 contents
+= "Xft.hinting: ";
528 if(hintStyle
.isEmpty())
532 if(hintStyle
!="hintnone")
536 contents
+= "Xft.hintstyle: " + hintStyle
+ '\n';
540 if (kglobals
.hasKey("XftSubPixel"))
542 QString subPixel
= kglobals
.readEntry("XftSubPixel");
543 if(!subPixel
.isEmpty())
544 contents
+= "Xft.rgba: " + subPixel
+ '\n';
547 KConfig
_cfgfonts( "kcmfonts" );
548 KConfigGroup
cfgfonts(&_cfgfonts
, "General");
550 if( cfgfonts
.readEntry( "forceFontDPI", 0 ) != 0 )
551 contents
+= "Xft.dpi: " + cfgfonts
.readEntry( "forceFontDPI" ) + '\n';
555 proc
<< "xrdb" << "-quiet" << "-remove" << "-nocpp";
557 if (proc
.waitForStarted())
559 proc
.write( QByteArray( "Xft.dpi\n" ) );
560 proc
.closeWriteChannel();
561 proc
.waitForFinished();
566 if (contents
.length() > 0)
567 tmpFile
.write( contents
.toLatin1(), contents
.length() );
573 proc
<< "xrdb" << "-merge" << tmpFile
.fileName();
575 proc
<< "xrdb" << "-quiet" << "-merge" << tmpFile
.fileName();
579 applyGtkStyles(exportColors
, 1);
580 applyGtkStyles(exportColors
, 2);
583 if ( exportQtColors
|| exportQtSettings
)
585 QSettings
* settings
= new QSettings(QLatin1String("Trolltech"));
587 if ( exportQtColors
)
588 applyQtColors( kglobals
, *settings
, newPal
); // For kcmcolors
590 if ( exportQtSettings
)
591 applyQtSettings( kglobals
, *settings
); // For kcmstyle
594 QApplication::flush();
596 // We let KIPC take care of ourselves, as we are in a KDE app with
597 // QApp::setDesktopSettingsAware(false);
598 // Instead of calling QApp::x11_apply_settings() directly, we instead
599 // modify the timestamp which propagates the settings changes onto
600 // Qt-only apps without adversely affecting ourselves.
602 // Cheat and use the current timestamp, since we just saved to qtrc.
603 QDateTime settingsstamp
= QDateTime::currentDateTime();
605 static Atom qt_settings_timestamp
= 0;
606 if (!qt_settings_timestamp
) {
607 QString
atomname("_QT_SETTINGS_TIMESTAMP_");
608 atomname
+= XDisplayName( 0 ); // Use the $DISPLAY envvar.
609 qt_settings_timestamp
= XInternAtom( QX11Info::display(), atomname
.toLatin1(), False
);
613 QDataStream
s(&stamp
.buffer(), QIODevice::WriteOnly
);
615 XChangeProperty( QX11Info::display(), QX11Info::appRootWindow(), qt_settings_timestamp
,
616 qt_settings_timestamp
, 8, PropModeReplace
,
617 (unsigned char*) stamp
.buffer().data(),
618 stamp
.buffer().size() );
619 QApplication::flush();