OSDN Git Service

721e762137d5da240434c523f1d6b40adcf5785d
[kde/kde-workspace.git] / kcontrol / krdb / krdb.cpp
1 /****************************************************************************
2 **
3 **
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
8 **
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.
15 **
16 *****************************************************************************/
17
18 #include <config-workspace.h>
19 #include <limits.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23
24 #undef Unsorted
25 #include <QBuffer>
26 #include <QDir>
27 #include <QtCore/QSettings>
28 #include <QtCore/QTextCodec>
29 #include <QToolTip>
30 #include <QPixmap>
31 #include <QByteArray>
32 #include <QTextStream>
33 #include <QDateTime>
34 #include <QProcess>
35
36 #include <ktoolinvocation.h>
37 #include <klauncher_iface.h>
38 #include <kapplication.h>
39 #include <kconfig.h>
40 #include <kconfiggroup.h>
41 #include <kdebug.h>
42 #include <kglobalsettings.h>
43 #include <kstandarddirs.h>
44 #include <ksavefile.h>
45 #include <ktemporaryfile.h>
46 #include <klocale.h>
47 #include <kstyle.h>
48
49 #include "krdb.h"
50 #ifdef Q_WS_X11
51 #include <X11/Xlib.h>
52 #include <QtGui/qx11info_x11.h>
53 #endif
54 inline const char * gtkEnvVar(int version)
55 {
56     return 2==version ? "GTK2_RC_FILES" : "GTK_RC_FILES";
57 }
58
59 inline const char * sysGtkrc(int version)
60 {
61     if(2==version)
62     {
63         if(access("/etc/opt/gnome/gtk-2.0", F_OK) == 0)
64             return "/etc/opt/gnome/gtk-2.0/gtkrc";
65         else
66             return "/etc/gtk-2.0/gtkrc";
67     }
68     else
69     {
70         if(access("/etc/opt/gnome/gtk", F_OK) == 0)
71             return "/etc/opt/gnome/gtk/gtkrc";
72         else
73             return "/etc/gtk/gtkrc";
74     }
75 }
76
77 inline const char * userGtkrc(int version)
78 {
79     return 2==version  ? "/.gtkrc-2.0" : "/.gtkrc";
80 }
81
82 // -----------------------------------------------------------------------------
83 static void applyGtkStyles(bool active, int version)
84 {
85    QString gtkkde = KStandardDirs::locateLocal("config", 2==version?"gtkrc-2.0":"gtkrc");
86    QByteArray gtkrc = getenv(gtkEnvVar(version));
87    QStringList list = QFile::decodeName(gtkrc).split( ':');
88    QString userHomeGtkrc = QDir::homePath()+userGtkrc(version);
89    if (!list.contains(userHomeGtkrc))
90       list.prepend(userHomeGtkrc);
91    QLatin1String systemGtkrc = QLatin1String(sysGtkrc(version));
92    if (!list.contains(systemGtkrc))
93       list.prepend(systemGtkrc);
94    list.removeAll("");
95    list.removeAll(gtkkde);
96    list.append(gtkkde);
97
98    // Pass env. var to kdeinit.
99    QString name = gtkEnvVar(version);
100    QString value = list.join(":");
101    KToolInvocation::klauncher()->setLaunchEnv(name, value);
102 }
103
104 // -----------------------------------------------------------------------------
105
106 static void applyQtColors( QSettings& settings, QPalette& newPal )
107 {
108   QStringList actcg, inactcg, discg;
109   /* export kde color settings */
110   int i;
111   for (i = 0; i < QPalette::NColorRoles; i++)
112      actcg   << newPal.color(QPalette::Active,
113                 (QPalette::ColorRole) i).name();
114   for (i = 0; i < QPalette::NColorRoles; i++)
115      inactcg << newPal.color(QPalette::Inactive,
116                 (QPalette::ColorRole) i).name();
117   for (i = 0; i < QPalette::NColorRoles; i++)
118      discg   << newPal.color(QPalette::Disabled,
119                 (QPalette::ColorRole) i).name();
120
121   settings.setValue("Qt/Palette/active", actcg);
122   settings.setValue("Qt/Palette/inactive", inactcg);
123   settings.setValue("Qt/Palette/disabled", discg);
124 }
125
126 // -----------------------------------------------------------------------------
127
128 static void applyQtSettings( KSharedConfigPtr kglobalcfg, QSettings& settings )
129 {
130 #warning FIXME: KGlobalSettings race, settings may not be reloaded yet
131   /* export font settings */
132   settings.setValue("Qt/font", KGlobalSettings::generalFont().toString());
133
134   /* export effects settings */
135   KConfigGroup kglobalgrp( kglobalcfg, "KDE-Global GUI Settings" );
136   int graphicEffects = kglobalgrp.readEntry("GraphicEffectsLevel", int(KGlobalSettings::graphicEffectsLevelDefault()));
137   KGlobalSettings::GraphicEffects graphicEffectsFlags = KGlobalSettings::GraphicEffects(graphicEffects);
138   bool effectsEnabled = (graphicEffectsFlags != KGlobalSettings::NoEffects);
139   bool fadeMenus = (graphicEffectsFlags & KGlobalSettings::ComplexAnimationEffects);
140   bool fadeTooltips = (graphicEffectsFlags & KGlobalSettings::ComplexAnimationEffects);
141   bool animateCombobox = (graphicEffectsFlags & KGlobalSettings::SimpleAnimationEffects);
142   // qDebug() << Q_FUNC_INFO << effectsEnabled << fadeMenus << fadeTooltips << animateCombobox;
143
144   QStringList guieffects;
145   if (effectsEnabled) {
146     guieffects << QString("general");
147     if (fadeMenus)
148       guieffects << QString("fademenu");
149     if (animateCombobox)
150       guieffects << QString("animatecombo");
151     if (fadeTooltips)
152       guieffects << QString("fadetooltip");
153   } else {
154     guieffects << QString("none");
155   }
156
157   settings.setValue("Qt/GUIEffects", guieffects);
158 }
159
160 // -----------------------------------------------------------------------------
161
162 static void addColorDef(QString& s, const char* n, const QColor& col)
163 {
164   QString tmp;
165
166   tmp.sprintf("#define %s #%02x%02x%02x\n",
167               n, col.red(), col.green(), col.blue());
168
169   s += tmp;
170 }
171
172
173 // -----------------------------------------------------------------------------
174
175 static void copyFile(QFile& tmp, QString const& filename, bool )
176 {
177   QFile f( filename );
178   if ( f.open(QIODevice::ReadOnly) ) {
179       QByteArray buf( 8192, ' ' );
180       while ( !f.atEnd() ) {
181           int read = f.read( buf.data(), buf.size() );
182           if ( read > 0 )
183               tmp.write( buf.data(), read );
184       }
185   }
186 }
187
188
189 // -----------------------------------------------------------------------------
190
191 static QString item( int i ) {
192     return QString::number( i / 255.0, 'f', 3 );
193 }
194
195 static QString color( const QColor& col )
196 {
197     return QString( "{ %1, %2, %3 }" ).arg( item( col.red() ) ).arg( item( col.green() ) ).arg( item( col.blue() ) );
198 }
199
200 static void createGtkrc( bool exportColors, const QPalette& cg, int version )
201 {
202     // lukas: why does it create in ~/.kde/share/config ???
203     // pfeiffer: so that we don't overwrite the user's gtkrc.
204     // it is found via the GTK_RC_FILES environment variable.
205     KSaveFile saveFile( KStandardDirs::locateLocal( "config", 2==version?"gtkrc-2.0":"gtkrc" ) );
206     if ( !saveFile.open() ) {
207         return;
208     }
209
210     QTextStream t ( &saveFile );
211     t.setCodec( QTextCodec::codecForLocale () );
212
213     t << i18n(
214             "# created by KDE, %1\n"
215             "#\n"
216             "# If you do not want KDE to override your GTK settings, select\n"
217             "# Appearance -> Colors in the System Settings and disable the checkbox\n"
218             "# \"Apply colors to non-KDE4 applications\"\n"
219             "#\n"
220             "#\n", QDateTime::currentDateTime().toString());
221
222     if ( 2==version ) {  // we should maybe check for MacOS settings here
223         t << endl;
224         t << "gtk-alternative-button-order = 1" << endl;
225         t << endl;
226     }
227
228     if (exportColors)
229     {
230         t << "style \"default\"" << endl;
231         t << "{" << endl;
232         t << "  bg[NORMAL] = " << color( cg.color( QPalette::Active, QPalette::Background ) ) << endl;
233         t << "  bg[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl;
234         t << "  bg[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Background ) ) << endl;
235         t << "  bg[ACTIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl;
236         t << "  bg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::Background ) ) << endl;
237         t << endl;
238         t << "  base[NORMAL] = " << color( cg.color( QPalette::Active, QPalette::Base ) ) << endl;
239         t << "  base[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl;
240         t << "  base[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Background ) ) << endl;
241         t << "  base[ACTIVE] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl;
242         t << "  base[PRELIGHT] = " << color( cg.color(QPalette::Active, QPalette::Highlight) ) << endl;
243         t << endl;
244         t << "  text[NORMAL] = " << color( cg.color(QPalette::Active, QPalette::Text) ) << endl;
245         t << "  text[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl;
246         t << "  text[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl;
247         t << "  text[ACTIVE] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl;
248         t << "  text[PRELIGHT] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl;
249         t << endl;
250         t << "  fg[NORMAL] = " << color ( cg.color( QPalette::Active, QPalette::Foreground ) ) << endl;
251         t << "  fg[SELECTED] = " << color( cg.color(QPalette::Active, QPalette::HighlightedText) ) << endl;
252         t << "  fg[INSENSITIVE] = " << color( cg.color( QPalette::Active, QPalette::Mid ) ) << endl;
253         t << "  fg[ACTIVE] = " << color( cg.color( QPalette::Active, QPalette::Foreground ) ) << endl;
254         t << "  fg[PRELIGHT] = " << color( cg.color( QPalette::Active, QPalette::Foreground ) ) << endl;
255         t << "}" << endl;
256         t << endl;
257         t << "class \"*\" style \"default\"" << endl;
258         t << endl;
259
260         // tooltips don't have the standard background color
261         t << "style \"ToolTip\"" << endl;
262         t << "{" << endl;
263         QPalette group = QToolTip::palette();
264         t << "  bg[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Background ) ) << endl;
265         t << "  base[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Base ) ) << endl;
266         t << "  text[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Text ) ) << endl;
267         t << "  fg[NORMAL] = " << color( group.color( QPalette::Active, QPalette::Foreground ) ) << endl;
268         t << "}" << endl;
269         t << endl;
270         t << "widget \"gtk-tooltip\" style \"ToolTip\"" << endl;
271         t << "widget \"gtk-tooltips\" style \"ToolTip\"" << endl;
272         t << endl;
273
274
275         // highlight the current (mouse-hovered) menu-item
276         // not every button, checkbox, etc.
277         t << "style \"MenuItem\"" << endl;
278         t << "{" << endl;
279         t << "  bg[PRELIGHT] = " << color( cg.color(QPalette::Highlight) ) << endl;
280         t << "  fg[PRELIGHT] = " << color( cg.color(QPalette::HighlightedText) ) << endl;
281         t << "}" << endl;
282         t << endl;
283         t << "class \"*MenuItem\" style \"MenuItem\"" << endl;
284         t << endl;
285     }
286
287 }
288
289 // -----------------------------------------------------------------------------
290
291 void runRdb( uint flags )
292 {
293   // Obtain the application palette that is about to be set.
294   bool exportColors      = flags & KRdbExportColors;
295   bool exportQtColors    = flags & KRdbExportQtColors;
296   bool exportQtSettings  = flags & KRdbExportQtSettings;
297   bool exportXftSettings = flags & KRdbExportXftSettings;
298
299   KSharedConfigPtr kglobalcfg = KSharedConfig::openConfig( "kdeglobals" );
300   KConfigGroup kglobals(kglobalcfg, "KDE");
301   QPalette newPal = KGlobalSettings::createApplicationPalette(kglobalcfg);
302
303   KTemporaryFile tmpFile;
304   if (!tmpFile.open())
305   {
306     kDebug() << "Couldn't open temp file";
307     exit(0);
308   }
309
310   KConfigGroup generalCfgGroup(kglobalcfg, "General");
311
312   createGtkrc( exportColors, newPal, 1 );
313   createGtkrc( exportColors, newPal, 2 );
314
315   // Export colors to non-(KDE/Qt) apps (e.g. Motif, GTK+ apps)
316   if (exportColors)
317   {
318     KGlobal::dirs()->addResourceType("appdefaults", "data", "kdisplay/app-defaults/");
319     KGlobal::locale()->insertCatalog("krdb");
320
321     QString preproc;
322     QColor backCol = newPal.color( QPalette::Active, QPalette::Background );
323     addColorDef(preproc, "FOREGROUND"         , newPal.color( QPalette::Active, QPalette::Foreground ) );
324     addColorDef(preproc, "BACKGROUND"         , backCol);
325     addColorDef(preproc, "HIGHLIGHT"          , backCol.light(100+(2*KGlobalSettings::contrast()+4)*16/1));
326     addColorDef(preproc, "LOWLIGHT"           , backCol.dark(100+(2*KGlobalSettings::contrast()+4)*10));
327     addColorDef(preproc, "SELECT_BACKGROUND"  , newPal.color( QPalette::Active, QPalette::Highlight));
328     addColorDef(preproc, "SELECT_FOREGROUND"  , newPal.color( QPalette::Active, QPalette::HighlightedText));
329     addColorDef(preproc, "WINDOW_BACKGROUND"  , newPal.color( QPalette::Active, QPalette::Base ) );
330     addColorDef(preproc, "WINDOW_FOREGROUND"  , newPal.color( QPalette::Active, QPalette::Text ) );
331     addColorDef(preproc, "INACTIVE_BACKGROUND", KGlobalSettings::inactiveTitleColor());
332     addColorDef(preproc, "INACTIVE_FOREGROUND", KGlobalSettings::inactiveTitleColor());
333     addColorDef(preproc, "ACTIVE_BACKGROUND"  , KGlobalSettings::activeTitleColor());
334     addColorDef(preproc, "ACTIVE_FOREGROUND"  , KGlobalSettings::activeTitleColor());
335     //---------------------------------------------------------------
336
337     tmpFile.write( preproc.toLatin1(), preproc.length() );
338
339     QStringList list;
340
341     const QStringList adPaths = KGlobal::dirs()->findDirs("appdefaults", "");
342     for (QStringList::ConstIterator it = adPaths.constBegin(); it != adPaths.constEnd(); ++it) {
343       QDir dSys( *it );
344
345       if ( dSys.exists() ) {
346         dSys.setFilter( QDir::Files );
347         dSys.setSorting( QDir::Name );
348         dSys.setNameFilters(QStringList("*.ad"));
349         list += dSys.entryList();
350       }
351     }
352
353     for (QStringList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it)
354       copyFile(tmpFile, KStandardDirs::locate("appdefaults", *it ), true);
355   }
356
357   // Merge ~/.Xresources or fallback to ~/.Xdefaults
358   QString homeDir = QDir::homePath();
359   QString xResources = homeDir + "/.Xresources";
360
361   // very primitive support for ~/.Xresources by appending it
362   if ( QFile::exists( xResources ) )
363     copyFile(tmpFile, xResources, true);
364   else
365     copyFile(tmpFile, homeDir + "/.Xdefaults", true);
366
367   // Export the Xcursor theme & size settings
368   KConfigGroup mousecfg(KSharedConfig::openConfig( "kcminputrc" ), "Mouse" );
369   QString theme = mousecfg.readEntry("cursorTheme", QString());
370   QString size  = mousecfg.readEntry("cursorSize", QString());
371   QString contents;
372
373   if (!theme.isNull())
374     contents = "Xcursor.theme: " + theme + '\n';
375
376   if (!size.isNull())
377     contents += "Xcursor.size: " + size + '\n';
378
379   if (exportXftSettings)
380   {
381     if (generalCfgGroup.hasKey("XftAntialias"))
382     {
383       contents += "Xft.antialias: ";
384       if(generalCfgGroup.readEntry("XftAntialias", true))
385         contents += "1\n";
386       else
387         contents += "0\n";
388     }
389
390     if (generalCfgGroup.hasKey("XftHintStyle"))
391     {
392       QString hintStyle = generalCfgGroup.readEntry("XftHintStyle", "hintmedium");
393       contents += "Xft.hinting: ";
394       if(hintStyle.isEmpty())
395         contents += "-1\n";
396       else
397       {
398         if(hintStyle!="hintnone")
399           contents += "1\n";
400         else
401           contents += "0\n";
402         contents += "Xft.hintstyle: " + hintStyle + '\n';
403       }
404     }
405
406     if (generalCfgGroup.hasKey("XftSubPixel"))
407     {
408       QString subPixel = generalCfgGroup.readEntry("XftSubPixel");
409       if(!subPixel.isEmpty())
410         contents += "Xft.rgba: " + subPixel + '\n';
411     }
412
413     KConfig _cfgfonts( "kcmfonts" );
414     KConfigGroup cfgfonts(&_cfgfonts, "General");
415
416     if( cfgfonts.readEntry( "forceFontDPI", 0 ) != 0 )
417       contents += "Xft.dpi: " + cfgfonts.readEntry( "forceFontDPI" ) + '\n';
418     else
419     {
420       QProcess proc;
421       proc.start("xrdb", QStringList() << "-quiet" << "-remove" << "-nocpp");
422       if (proc.waitForStarted())
423       {
424         proc.write( QByteArray( "Xft.dpi\n" ) );
425         proc.closeWriteChannel();
426         proc.waitForFinished();
427       }
428     }
429   }
430
431   if (contents.length() > 0)
432     tmpFile.write( contents.toLatin1(), contents.length() );
433
434   tmpFile.flush();
435
436   QStringList procargs;
437 #ifndef NDEBUG
438   procargs << "-merge" << tmpFile.fileName();
439 #else
440   procargs << "-quiet" << "-merge" << tmpFile.fileName();
441 #endif
442   QProcess::execute("xrdb", procargs);
443
444   applyGtkStyles(exportColors, 1);
445   applyGtkStyles(exportColors, 2);
446
447   /* Katie exports */
448   if ( exportQtColors || exportQtSettings )
449   {
450     {
451       QSettings settings(QLatin1String("Katie"), QSettings::NativeFormat);
452
453       if ( exportQtColors )
454         applyQtColors( settings, newPal );    // For kcmcolors
455
456       if ( exportQtSettings )
457         applyQtSettings( kglobalcfg, settings );          // For kcmstyle
458     }
459
460     QApplication::flush();
461 #ifdef Q_WS_X11
462     // We let KIPC take care of ourselves, as we are in a KDE app with
463     // QApp::setDesktopSettingsAware(false);
464     // Instead of calling QApp::x11_apply_settings() directly, we instead
465     // modify the timestamp which propagates the settings changes onto
466     // Katie-only apps without adversely affecting ourselves.
467
468     // Cheat and use the current timestamp, since we just saved to qtrc.
469     QDateTime settingsstamp = QDateTime::currentDateTime();
470
471     static const QByteArray atomname("_QT_SETTINGS_TIMESTAMP");
472     static Atom qt_settings_timestamp = XInternAtom( QX11Info::display(), atomname.constData(), False);
473
474     QBuffer stamp;
475     QDataStream s(&stamp.buffer(), QIODevice::WriteOnly);
476     s << settingsstamp;
477     XChangeProperty( QX11Info::display(), QX11Info::appRootWindow(), qt_settings_timestamp,
478                      qt_settings_timestamp, 8, PropModeReplace,
479                      (unsigned char*) stamp.buffer().data(),
480                      stamp.buffer().size() );
481     QApplication::flush();
482 #endif
483   }
484 }
485