1 /*
2     KRDB - puts current KDE color scheme into preprocessor statements
3     cats specially written application default files and uses xrdb -merge to
4     write to RESOURCE_MANAGER. Thus it gives a  simple way to make non-KDE
5     applications fit in with the desktop
6 
7     SPDX-FileCopyrightText: 1998 Mark Donohoe
8     SPDX-FileCopyrightText: 2001 Waldo Bastian <bastian@kde.org>
9     SPDX-FileCopyrightText: 2002 Karol Szwed <gallium@kde.org>
10 
11     reworked for KDE 2.0:
12     SPDX-FileCopyrightText: 1999 Dirk A. Mueller
13 
14     add support for GTK applications:
15     SPDX-FileCopyrightText: 2001 Matthias Ettrich
16 
17     SPDX-License-Identifier: GPL-2.0-or-later
18 */
19 
20 #include <config-X11.h>
21 #include <config-workspace.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #undef Unsorted
28 #include <QApplication>
29 #include <QBuffer>
30 #include <QDir>
31 #include <QFontDatabase>
32 #include <QSettings>
33 #include <QTextCodec>
34 
35 #include <QByteArray>
36 #include <QDBusConnection>
37 #include <QDateTime>
38 #include <QDebug>
39 #include <QPixmap>
40 #include <QSaveFile>
41 #include <QTemporaryFile>
42 #include <QTextStream>
43 
44 #include <KColorScheme>
45 #include <KConfig>
46 #include <KConfigGroup>
47 #include <KLocalizedString>
48 #include <KProcess>
49 #include <KWindowSystem>
50 #include <Kdelibs4Migration>
51 
52 #include <updatelaunchenvjob.h>
53 
54 #include "krdb.h"
55 #if HAVE_X11
56 #include <QX11Info>
57 #include <X11/Xlib.h>
58 #endif
gtkEnvVar(int version)59 inline const char *gtkEnvVar(int version)
60 {
61     return 2 == version ? "GTK2_RC_FILES" : "GTK_RC_FILES";
62 }
63 
sysGtkrc(int version)64 inline const char *sysGtkrc(int version)
65 {
66     if (2 == version) {
67         if (access("/etc/opt/gnome/gtk-2.0", F_OK) == 0)
68             return "/etc/opt/gnome/gtk-2.0/gtkrc";
69         else
70             return "/etc/gtk-2.0/gtkrc";
71     } else {
72         if (access("/etc/opt/gnome/gtk", F_OK) == 0)
73             return "/etc/opt/gnome/gtk/gtkrc";
74         else
75             return "/etc/gtk/gtkrc";
76     }
77 }
78 
userGtkrc(int version)79 inline const char *userGtkrc(int version)
80 {
81     return 2 == version ? "/.gtkrc-2.0" : "/.gtkrc";
82 }
83 
84 // -----------------------------------------------------------------------------
writableGtkrc(int version)85 static QString writableGtkrc(int version)
86 {
87     QString gtkrc = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
88     QDir dir;
89     dir.mkpath(gtkrc);
90     gtkrc += 2 == version ? "/gtkrc-2.0" : "/gtkrc";
91     return gtkrc;
92 }
93 
94 // -----------------------------------------------------------------------------
applyGtkStyles(int version)95 static void applyGtkStyles(int version)
96 {
97     QString gtkkde = writableGtkrc(version);
98     QByteArray gtkrc = getenv(gtkEnvVar(version));
99     QStringList list = QFile::decodeName(gtkrc).split(QLatin1Char(':'));
100     QString userHomeGtkrc = QDir::homePath() + userGtkrc(version);
101     if (!list.contains(userHomeGtkrc))
102         list.prepend(userHomeGtkrc);
103     QLatin1String systemGtkrc = QLatin1String(sysGtkrc(version));
104     if (!list.contains(systemGtkrc))
105         list.prepend(systemGtkrc);
106     list.removeAll(QLatin1String(""));
107     list.removeAll(gtkkde);
108     list.append(gtkkde);
109 
110     // Pass env. var to kdeinit.
111     QString name = gtkEnvVar(version);
112     QString value = list.join(QLatin1Char(':'));
113     UpdateLaunchEnvJob(name, value);
114 }
115 
116 // -----------------------------------------------------------------------------
117 
applyQtColors(KSharedConfigPtr kglobalcfg,QSettings & settings,QPalette & newPal)118 static void applyQtColors(KSharedConfigPtr kglobalcfg, QSettings &settings, QPalette &newPal)
119 {
120     QStringList actcg, inactcg, discg;
121     /* export kde color settings */
122     int i;
123     for (i = 0; i < QPalette::NColorRoles; i++)
124         actcg << newPal.color(QPalette::Active, (QPalette::ColorRole)i).name();
125     for (i = 0; i < QPalette::NColorRoles; i++)
126         inactcg << newPal.color(QPalette::Inactive, (QPalette::ColorRole)i).name();
127     for (i = 0; i < QPalette::NColorRoles; i++)
128         discg << newPal.color(QPalette::Disabled, (QPalette::ColorRole)i).name();
129 
130     settings.setValue(QStringLiteral("/qt/Palette/active"), actcg);
131     settings.setValue(QStringLiteral("/qt/Palette/inactive"), inactcg);
132     settings.setValue(QStringLiteral("/qt/Palette/disabled"), discg);
133 
134     // export kwin's colors to qtrc for kstyle to use
135     KConfigGroup wmCfgGroup(kglobalcfg, "WM");
136 
137     // active colors
138     QColor clr = newPal.color(QPalette::Active, QPalette::Window);
139     clr = wmCfgGroup.readEntry("activeBackground", clr);
140     settings.setValue(QStringLiteral("/qt/KWinPalette/activeBackground"), clr.name());
141     if (QPixmap::defaultDepth() > 8)
142         clr = clr.darker(110);
143     clr = wmCfgGroup.readEntry("activeBlend", clr);
144     settings.setValue(QStringLiteral("/qt/KWinPalette/activeBlend"), clr.name());
145     clr = newPal.color(QPalette::Active, QPalette::HighlightedText);
146     clr = wmCfgGroup.readEntry("activeForeground", clr);
147     settings.setValue(QStringLiteral("/qt/KWinPalette/activeForeground"), clr.name());
148     clr = newPal.color(QPalette::Active, QPalette::Window);
149     clr = wmCfgGroup.readEntry("frame", clr);
150     settings.setValue(QStringLiteral("/qt/KWinPalette/frame"), clr.name());
151     clr = wmCfgGroup.readEntry("activeTitleBtnBg", clr);
152     settings.setValue(QStringLiteral("/qt/KWinPalette/activeTitleBtnBg"), clr.name());
153 
154     // inactive colors
155     clr = newPal.color(QPalette::Inactive, QPalette::Window);
156     clr = wmCfgGroup.readEntry("inactiveBackground", clr);
157     settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBackground"), clr.name());
158     if (QPixmap::defaultDepth() > 8)
159         clr = clr.darker(110);
160     clr = wmCfgGroup.readEntry("inactiveBlend", clr);
161     settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveBlend"), clr.name());
162     clr = newPal.color(QPalette::Inactive, QPalette::Window).darker();
163     clr = wmCfgGroup.readEntry("inactiveForeground", clr);
164     settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveForeground"), clr.name());
165     clr = newPal.color(QPalette::Inactive, QPalette::Window);
166     clr = wmCfgGroup.readEntry("inactiveFrame", clr);
167     settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveFrame"), clr.name());
168     clr = wmCfgGroup.readEntry("inactiveTitleBtnBg", clr);
169     settings.setValue(QStringLiteral("/qt/KWinPalette/inactiveTitleBtnBg"), clr.name());
170 
171     KConfigGroup kdeCfgGroup(kglobalcfg, "KDE");
172     settings.setValue(QStringLiteral("/qt/KDE/contrast"), kdeCfgGroup.readEntry("contrast", 7));
173 }
174 
175 // -----------------------------------------------------------------------------
176 
applyQtSettings(KSharedConfigPtr kglobalcfg,QSettings & settings)177 static void applyQtSettings(KSharedConfigPtr kglobalcfg, QSettings &settings)
178 {
179     /* export font settings */
180 
181     // NOTE keep this in sync with kfontsettingsdata in plasma-integration (cf. also Bug 378262)
182     QFont defaultFont(QStringLiteral("Noto Sans"), 10, -1);
183     defaultFont.setStyleHint(QFont::SansSerif);
184 
185     const KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("General"));
186     const QString fontInfo = configGroup.readEntry(QStringLiteral("font"), QString());
187     if (!fontInfo.isEmpty()) {
188         defaultFont.fromString(fontInfo);
189     }
190 
191     settings.setValue(QStringLiteral("/qt/font"), defaultFont.toString());
192 
193     /* export effects settings */
194     KConfigGroup kdeCfgGroup(kglobalcfg, "General");
195     bool effectsEnabled = kdeCfgGroup.readEntry("EffectsEnabled", false);
196     bool fadeMenus = kdeCfgGroup.readEntry("EffectFadeMenu", false);
197     bool fadeTooltips = kdeCfgGroup.readEntry("EffectFadeTooltip", false);
198     bool animateCombobox = kdeCfgGroup.readEntry("EffectAnimateCombo", false);
199 
200     QStringList guieffects;
201     if (effectsEnabled) {
202         guieffects << QStringLiteral("general");
203         if (fadeMenus)
204             guieffects << QStringLiteral("fademenu");
205         if (animateCombobox)
206             guieffects << QStringLiteral("animatecombo");
207         if (fadeTooltips)
208             guieffects << QStringLiteral("fadetooltip");
209     } else
210         guieffects << QStringLiteral("none");
211 
212     settings.setValue(QStringLiteral("/qt/GUIEffects"), guieffects);
213 }
214 
215 // -----------------------------------------------------------------------------
216 
addColorDef(QString & s,const char * n,const QColor & col)217 static void addColorDef(QString &s, const char *n, const QColor &col)
218 {
219     s += QStringLiteral("#define %1 ").arg(QString::fromUtf8(n));
220     s += col.name().toLower();
221     s += QLatin1Char('\n');
222 }
223 
224 // -----------------------------------------------------------------------------
225 
copyFile(QFile & tmp,QString const & filename,bool)226 static void copyFile(QFile &tmp, QString const &filename, bool)
227 {
228     QFile f(filename);
229     if (f.open(QIODevice::ReadOnly)) {
230         QByteArray buf(8192, ' ');
231         while (!f.atEnd()) {
232             int read = f.read(buf.data(), buf.size());
233             if (read > 0)
234                 tmp.write(buf.data(), read);
235         }
236     }
237 }
238 
239 // -----------------------------------------------------------------------------
240 
createGtkrc(const QPalette & cg,bool exportGtkTheme,const QString & gtkTheme,int version)241 static void createGtkrc(const QPalette &cg, bool exportGtkTheme, const QString &gtkTheme, int version)
242 {
243     Q_UNUSED(cg);
244     // lukas: why does it create in ~/.kde/share/config ???
245     // pfeiffer: so that we don't overwrite the user's gtkrc.
246     // it is found via the GTK_RC_FILES environment variable.
247     QSaveFile saveFile(writableGtkrc(version));
248     if (!saveFile.open(QIODevice::WriteOnly))
249         return;
250 
251     QTextStream t(&saveFile);
252     t.setCodec(QTextCodec::codecForLocale());
253 
254     t << i18n(
255         "# created by KDE Plasma, %1\n"
256         "#\n",
257         QDateTime::currentDateTime().toString());
258 
259     if (2 == version) { // we should maybe check for MacOS settings here
260         using Qt::endl;
261         t << endl;
262         t << "gtk-alternative-button-order = 1" << endl;
263         t << endl;
264     }
265 
266     if (exportGtkTheme) {
267         QString gtkStyle;
268         if (gtkTheme.toLower() == QLatin1String("oxygen"))
269             gtkStyle = QStringLiteral("oxygen-gtk");
270         else
271             gtkStyle = gtkTheme;
272 
273         bool exist_gtkrc = false;
274         QByteArray gtkrc = getenv(gtkEnvVar(version));
275         QStringList listGtkrc = QFile::decodeName(gtkrc).split(QLatin1Char(':'));
276         if (listGtkrc.contains(saveFile.fileName()))
277             listGtkrc.removeAll(saveFile.fileName());
278         listGtkrc.append(QDir::homePath() + userGtkrc(version));
279         listGtkrc.append(QDir::homePath() + "/.gtkrc-2.0-kde");
280         listGtkrc.append(QDir::homePath() + "/.gtkrc-2.0-kde4");
281         listGtkrc.removeAll(QLatin1String(""));
282         listGtkrc.removeDuplicates();
283         for (int i = 0; i < listGtkrc.size(); ++i) {
284             if ((exist_gtkrc = QFile::exists(listGtkrc.at(i))))
285                 break;
286         }
287 
288         if (!exist_gtkrc) {
289             QString gtk2ThemeFilename;
290             gtk2ThemeFilename = QStringLiteral("%1/.themes/%2/gtk-2.0/gtkrc").arg(QDir::homePath(), gtkStyle);
291             if (!QFile::exists(gtk2ThemeFilename)) {
292                 QStringList gtk2ThemePath;
293                 gtk2ThemeFilename.clear();
294                 QByteArray xdgDataDirs = getenv("XDG_DATA_DIRS");
295                 gtk2ThemePath.append(QDir::homePath() + "/.local");
296                 gtk2ThemePath.append(QFile::decodeName(xdgDataDirs).split(QLatin1Char(':')));
297                 gtk2ThemePath.removeDuplicates();
298                 for (int i = 0; i < gtk2ThemePath.size(); ++i) {
299                     gtk2ThemeFilename = QStringLiteral("%1/themes/%2/gtk-2.0/gtkrc").arg(gtk2ThemePath.at(i), gtkStyle);
300                     if (QFile::exists(gtk2ThemeFilename))
301                         break;
302                     else
303                         gtk2ThemeFilename.clear();
304                 }
305             }
306 
307             if (!gtk2ThemeFilename.isEmpty()) {
308                 t << "include \"" << gtk2ThemeFilename << "\"" << Qt::endl;
309                 t << Qt::endl;
310                 t << "gtk-theme-name=\"" << gtkStyle << "\"" << Qt::endl;
311                 t << Qt::endl;
312             }
313         }
314     }
315 
316     saveFile.commit();
317 }
318 
319 // -----------------------------------------------------------------------------
320 
runRdb(uint flags)321 void runRdb(uint flags)
322 {
323     // Obtain the application palette that is about to be set.
324     bool exportQtColors = flags & KRdbExportQtColors;
325     bool exportQtSettings = flags & KRdbExportQtSettings;
326     bool exportXftSettings = flags & KRdbExportXftSettings;
327     bool exportGtkTheme = flags & KRdbExportGtkTheme;
328 
329     KSharedConfigPtr kglobalcfg = KSharedConfig::openConfig(QStringLiteral("kdeglobals"));
330     KConfigGroup kglobals(kglobalcfg, "KDE");
331     QPalette newPal = KColorScheme::createApplicationPalette(kglobalcfg);
332 
333     QTemporaryFile tmpFile;
334     if (!tmpFile.open()) {
335         qDebug() << "Couldn't open temp file";
336         exit(0);
337     }
338 
339     KConfigGroup generalCfgGroup(kglobalcfg, "General");
340 
341     QString gtkTheme;
342     if (kglobals.hasKey("widgetStyle"))
343         gtkTheme = kglobals.readEntry("widgetStyle");
344     else
345         gtkTheme = QStringLiteral("oxygen");
346 
347     createGtkrc(newPal, exportGtkTheme, gtkTheme, 1);
348     createGtkrc(newPal, exportGtkTheme, gtkTheme, 2);
349 
350     // Merge ~/.Xresources or fallback to ~/.Xdefaults
351     QString homeDir = QDir::homePath();
352     QString xResources = homeDir + "/.Xresources";
353 
354     // very primitive support for ~/.Xresources by appending it
355     if (QFile::exists(xResources))
356         copyFile(tmpFile, xResources, true);
357     else
358         copyFile(tmpFile, homeDir + "/.Xdefaults", true);
359 
360     // Export the Xcursor theme & size settings
361     KConfigGroup mousecfg(KSharedConfig::openConfig(QStringLiteral("kcminputrc")), "Mouse");
362     QString theme = mousecfg.readEntry("cursorTheme", QStringLiteral("breeze_cursors"));
363     QString size = mousecfg.readEntry("cursorSize", QStringLiteral("24"));
364     QString contents;
365 
366     if (!theme.isNull())
367         contents = "Xcursor.theme: " + theme + '\n';
368 
369     if (!size.isNull())
370         contents += "Xcursor.size: " + size + '\n';
371 
372     if (exportXftSettings) {
373         contents += QLatin1String("Xft.antialias: ");
374         if (generalCfgGroup.readEntry("XftAntialias", true))
375             contents += QLatin1String("1\n");
376         else
377             contents += QLatin1String("0\n");
378 
379         QString hintStyle = generalCfgGroup.readEntry("XftHintStyle", "hintslight");
380         contents += QLatin1String("Xft.hinting: ");
381         if (hintStyle.isEmpty())
382             contents += QLatin1String("-1\n");
383         else {
384             if (hintStyle != QLatin1String("hintnone"))
385                 contents += QLatin1String("1\n");
386             else
387                 contents += QLatin1String("0\n");
388             contents += "Xft.hintstyle: " + hintStyle + '\n';
389         }
390 
391         QString subPixel = generalCfgGroup.readEntry("XftSubPixel", "rgb");
392         if (!subPixel.isEmpty())
393             contents += "Xft.rgba: " + subPixel + '\n';
394 
395         KConfig _cfgfonts(QStringLiteral("kcmfonts"));
396         KConfigGroup cfgfonts(&_cfgfonts, "General");
397 
398         int dpi;
399 
400         // even though this sets up the X rdb, we want to use the value the
401         // user has set to use when under wayland - as X apps will be scaled by the compositor
402         if (KWindowSystem::isPlatformWayland()) {
403             dpi = cfgfonts.readEntry("forceFontDPIWayland", 0);
404             if (dpi == 0) { // with wayland we want xwayland to run at 96 dpi (unless set otherwise) as we have wayland scaling on top
405                 dpi = 96;
406             }
407         } else {
408             dpi = cfgfonts.readEntry("forceFontDPI", 0);
409         }
410         if (dpi != 0)
411             contents += "Xft.dpi: " + QString::number(dpi) + '\n';
412         else {
413             KProcess queryProc;
414             queryProc << QStringLiteral("xrdb") << QStringLiteral("-query");
415             queryProc.setOutputChannelMode(KProcess::OnlyStdoutChannel);
416             queryProc.start();
417             if (queryProc.waitForFinished()) {
418                 QByteArray db = queryProc.readAllStandardOutput();
419                 int idx1 = 0;
420                 while (idx1 < db.size()) {
421                     int idx2 = db.indexOf('\n', idx1);
422                     if (idx2 == -1) {
423                         idx2 = db.size() - 1;
424                     }
425                     const auto entry = QByteArray::fromRawData(db.constData() + idx1, idx2 - idx1 + 1);
426                     if (entry.startsWith("Xft.dpi:")) {
427                         db.remove(idx1, entry.size());
428                     } else {
429                         idx1 = idx2 + 1;
430                     }
431                 }
432 
433                 KProcess loadProc;
434                 loadProc << QStringLiteral("xrdb") << QStringLiteral("-quiet") << QStringLiteral("-load") << QStringLiteral("-nocpp");
435                 loadProc.start();
436                 if (loadProc.waitForStarted()) {
437                     loadProc.write(db);
438                     loadProc.closeWriteChannel();
439                     loadProc.waitForFinished();
440                 }
441             }
442         }
443     }
444 
445     if (contents.length() > 0)
446         tmpFile.write(contents.toLatin1(), contents.length());
447 
448     tmpFile.flush();
449 
450     KProcess proc;
451 #ifndef NDEBUG
452     proc << QStringLiteral("xrdb") << QStringLiteral("-merge") << tmpFile.fileName();
453 #else
454     proc << "xrdb"
455          << "-quiet"
456          << "-merge" << tmpFile.fileName();
457 #endif
458     proc.execute();
459 
460     applyGtkStyles(1);
461     applyGtkStyles(2);
462 
463     /* Qt exports */
464     if (exportQtColors || exportQtSettings) {
465         QSettings *settings = new QSettings(QStringLiteral("Trolltech"));
466 
467         if (exportQtColors)
468             applyQtColors(kglobalcfg, *settings, newPal); // For kcmcolors
469 
470         if (exportQtSettings)
471             applyQtSettings(kglobalcfg, *settings); // For kcmstyle
472 
473         delete settings;
474         QCoreApplication::processEvents();
475 #if HAVE_X11
476         if (qApp->platformName() == QLatin1String("xcb")) {
477             // We let KIPC take care of ourselves, as we are in a KDE app with
478             // QApp::setDesktopSettingsAware(false);
479             // Instead of calling QApp::x11_apply_settings() directly, we instead
480             // modify the timestamp which propagates the settings changes onto
481             // Qt-only apps without adversely affecting ourselves.
482 
483             // Cheat and use the current timestamp, since we just saved to qtrc.
484             QDateTime settingsstamp = QDateTime::currentDateTime();
485 
486             static Atom qt_settings_timestamp = 0;
487             if (!qt_settings_timestamp) {
488                 QString atomname(QStringLiteral("_QT_SETTINGS_TIMESTAMP_"));
489                 atomname += XDisplayName(nullptr); // Use the $DISPLAY envvar.
490                 qt_settings_timestamp = XInternAtom(QX11Info::display(), atomname.toLatin1(), False);
491             }
492 
493             QBuffer stamp;
494             QDataStream s(&stamp.buffer(), QIODevice::WriteOnly);
495             s << settingsstamp;
496             XChangeProperty(QX11Info::display(),
497                             QX11Info::appRootWindow(),
498                             qt_settings_timestamp,
499                             qt_settings_timestamp,
500                             8,
501                             PropModeReplace,
502                             (unsigned char *)stamp.buffer().data(),
503                             stamp.buffer().size());
504             QApplication::flush();
505         }
506 #endif
507     }
508 
509     // Legacy support:
510     // Try to sync kde4 settings with ours
511 
512     Kdelibs4Migration migration;
513     // kf5 congig groups for general and icons
514     KConfigGroup generalGroup(kglobalcfg, "General");
515     KConfigGroup iconsGroup(kglobalcfg, "Icons");
516 
517     const QString colorSchemeName = generalGroup.readEntry("ColorScheme", QStringLiteral("BreezeLight"));
518 
519     QString colorSchemeSrcFile;
520     if (colorSchemeName != QLatin1String("Default")) {
521         // fix filename, copied from ColorsCM::saveScheme()
522         QString colorSchemeFilename = colorSchemeName;
523         colorSchemeFilename.remove('\''); // So Foo's does not become FooS
524         QRegExp fixer(QStringLiteral("[\\W,.-]+(.?)"));
525         int offset;
526         while ((offset = fixer.indexIn(colorSchemeFilename)) >= 0)
527             colorSchemeFilename.replace(offset, fixer.matchedLength(), fixer.cap(1).toUpper());
528         colorSchemeFilename.replace(0, 1, colorSchemeFilename.at(0).toUpper());
529 
530         // clone the color scheme
531         colorSchemeSrcFile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "color-schemes/" + colorSchemeFilename + ".colors");
532         const QString dest = migration.saveLocation("data", QStringLiteral("color-schemes")) + colorSchemeName + ".colors";
533         QFile::remove(dest);
534         QFile::copy(colorSchemeSrcFile, dest);
535     }
536 
537     // Apply the color scheme
538     QString configFilePath = migration.saveLocation("config") + "kdeglobals";
539 
540     if (configFilePath.isEmpty()) {
541         return;
542     }
543 
544     KConfig kde4config(configFilePath, KConfig::SimpleConfig);
545 
546     KConfigGroup kde4generalGroup(&kde4config, "General");
547     kde4generalGroup.writeEntry("ColorScheme", colorSchemeName);
548 
549     // fonts
550     QString font = generalGroup.readEntry("font", QString());
551     if (!font.isEmpty()) {
552         kde4generalGroup.writeEntry("font", font);
553     }
554     font = generalGroup.readEntry("desktopFont", QString());
555     if (!font.isEmpty()) {
556         kde4generalGroup.writeEntry("desktopFont", font);
557     }
558     font = generalGroup.readEntry("menuFont", QString());
559     if (!font.isEmpty()) {
560         kde4generalGroup.writeEntry("menuFont", font);
561     }
562     font = generalGroup.readEntry("smallestReadableFont", QString());
563     if (!font.isEmpty()) {
564         kde4generalGroup.writeEntry("smallestReadableFont", font);
565     }
566     font = generalGroup.readEntry("taskbarFont", QString());
567     if (!font.isEmpty()) {
568         kde4generalGroup.writeEntry("taskbarFont", font);
569     }
570     font = generalGroup.readEntry("toolBarFont", QString());
571     if (!font.isEmpty()) {
572         kde4generalGroup.writeEntry("toolBarFont", font);
573     }
574 
575     // TODO: does exist any way to check if a qt4 widget style is present from a qt5 app?
576     // kde4generalGroup.writeEntry("widgetStyle", "qtcurve");
577     kde4generalGroup.sync();
578 
579     KConfigGroup kde4IconGroup(&kde4config, "Icons");
580     QString iconTheme = iconsGroup.readEntry("Theme", QString());
581     if (!iconTheme.isEmpty()) {
582         kde4IconGroup.writeEntry("Theme", iconTheme);
583     }
584     kde4IconGroup.sync();
585 
586     if (!colorSchemeSrcFile.isEmpty()) {
587         // copy all the groups in the color scheme in kdeglobals
588         KSharedConfigPtr kde4ColorConfig = KSharedConfig::openConfig(colorSchemeSrcFile, KConfig::SimpleConfig);
589 
590         foreach (const QString &grp, kde4ColorConfig->groupList()) {
591             KConfigGroup cg(kde4ColorConfig, grp);
592             KConfigGroup cg2(&kde4config, grp);
593             cg.copyTo(&cg2);
594         }
595     }
596 
597     // widgets settings
598     KConfigGroup kglobals4(&kde4config, "KDE");
599     kglobals4.writeEntry("ShowIconsInMenuItems", kglobals.readEntry("ShowIconsInMenuItems", true));
600     kglobals4.writeEntry("ShowIconsOnPushButtons", kglobals.readEntry("ShowIconsOnPushButtons", true));
601     kglobals4.writeEntry("contrast", kglobals.readEntry("contrast", 4));
602     // FIXME: this should somehow check if the kde4 version of the style is installed
603     kde4generalGroup.writeEntry("widgetStyle", kglobals.readEntry("widgetStyle", "breeze"));
604 
605     // toolbar style
606     KConfigGroup toolbars4(&kde4config, "Toolbar style");
607     KConfigGroup toolbars5(kglobalcfg, "Toolbar style");
608     toolbars4.writeEntry("ToolButtonStyle", toolbars5.readEntry("ToolButtonStyle", "TextBesideIcon"));
609     toolbars4.writeEntry("ToolButtonStyleOtherToolbars", toolbars5.readEntry("ToolButtonStyleOtherToolbars", "TextBesideIcon"));
610 }
611