1 /* This file is part of the KDE libraries
2    Copyright (C) 2000, 2006 David Faure <faure@kde.org>
3    Copyright 2008 Friedrich W. H. Kossebau <kossebau@kde.org>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License version 2 as published by the Free Software Foundation.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public License
15    along with this library; see the file COPYING.LIB.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17    Boston, MA 02110-1301, USA.
18 */
19 
20 #include "kglobalsettings.h"
21 
22 #include <ktoolbar.h>
23 #include <kconfig.h>
24 #include <kcolorscheme.h>
25 
26 //#include <kstyle.h>
27 
28 #include <QColor>
29 #include <QCursor>
30 #include <QDesktopWidget>
31 #include <QDir>
32 #include <QFont>
33 #include <QFontDatabase>
34 #include <QFontInfo>
35 #include <QKeySequence>
36 #include <QPixmap>
37 #include <QPixmapCache>
38 #include <QApplication>
39 #include <QDBusConnection>
40 #include <QStyleFactory>
41 #include <QDebug>
42 #include <qstandardpaths.h>
43 
44 // next two needed so we can set their palettes
45 #include <QDBusMessage>
46 #include <QToolTip>
47 #include <QUrl>
48 #include <QWhatsThis>
49 
50 #ifdef Q_OS_WIN
51 #include <windows.h>
52 
qt_colorref2qrgb(COLORREF col)53 static QRgb qt_colorref2qrgb(COLORREF col)
54 {
55     return qRgb(GetRValue(col), GetGValue(col), GetBValue(col));
56 }
57 #endif
58 #include <config-kdelibs4support.h>
59 #if HAVE_X11
60 #include <X11/Xlib.h>
61 #ifdef HAVE_XCURSOR // TODO NOT DEFINED ANYMORE. Can we drop X cursor themes?
62 #include <X11/Xcursor/Xcursor.h>
63 #endif
64 //#include "fixx11h.h"
65 #include <QX11Info>
66 #endif
67 
68 #include <stdlib.h>
69 #include <kconfiggroup.h>
70 #include <kiconloader.h>
71 
72 //static QColor *_buttonBackground = 0;
73 static KGlobalSettings::GraphicEffects _graphicEffects = KGlobalSettings::NoEffects;
74 
75 class Q_DECL_HIDDEN KGlobalSettings::Private
76 {
77 public:
Private(KGlobalSettings * q)78     Private(KGlobalSettings *q)
79     : q(q), activated(false), paletteCreated(false), mMouseSettings(nullptr), mLargeFont(nullptr)
80 #if HAVE_X11
81         , isX11(QX11Info::isPlatformX11())
82 #endif
83     {
84         kdeFullSession = !qgetenv("KDE_FULL_SESSION").isEmpty();
85     }
86 
87     QPalette createApplicationPalette(const KSharedConfigPtr &config);
88     QPalette createNewApplicationPalette(const KSharedConfigPtr &config);
89     void _k_slotNotifyChange(int, int);
90     void _k_slotIconChange(int);
91 
92     void propagateQtSettings();
93     void kdisplaySetPalette();
94     void kdisplaySetStyle();
95     void kdisplaySetFont();
96     void applyGUIStyle();
97     void dropMouseSettingsCache();
98     KGlobalSettings::KMouseSettings &mouseSettings();
99 
100     /**
101      * @internal
102      *
103      * Ensures that cursors are loaded from the theme KDE is configured
104      * to use. Note that calling this function doesn't cause existing
105      * cursors to be reloaded. Reloading already created cursors is
106      * handled by the KCM when a cursor theme is applied.
107      *
108      * It is not necessary to call this function when KGlobalSettings
109      * is initialized.
110      */
111     void applyCursorTheme();
112 
113     static void reloadStyleSettings();
114 
115     QFont largeFont(const QString &text);
116 
117     KGlobalSettings *q;
118     bool activated;
119     bool paletteCreated;
120     bool kdeFullSession;
121     QPalette applicationPalette;
122     KGlobalSettings::KMouseSettings *mMouseSettings;
123     QFont *mLargeFont;
124 #if HAVE_X11
125     bool isX11;
126 #endif
127 };
128 
129 // class for access to KGlobalSettings constructor
130 class KGlobalSettingsSingleton
131 {
132 public:
133     KGlobalSettings object;
134 };
135 
Q_GLOBAL_STATIC(KGlobalSettingsSingleton,s_self)136 Q_GLOBAL_STATIC(KGlobalSettingsSingleton, s_self)
137 
138 KGlobalSettings *KGlobalSettings::self()
139 {
140     return &s_self()->object;
141 }
142 
KGlobalSettings()143 KGlobalSettings::KGlobalSettings()
144     : QObject(nullptr), d(new Private(this))
145 {
146     connect(this, SIGNAL(kdisplayFontChanged()), SIGNAL(appearanceChanged()));
147 }
148 
~KGlobalSettings()149 KGlobalSettings::~KGlobalSettings()
150 {
151     delete d;
152 }
153 
activate()154 void KGlobalSettings::activate()
155 {
156     activate(ApplySettings | ListenForChanges);
157 }
158 
activate(ActivateOptions options)159 void KGlobalSettings::activate(ActivateOptions options)
160 {
161     if (!d->activated) {
162         d->activated = true;
163 
164         if (options & ListenForChanges) {
165             QDBusConnection::sessionBus().connect(QString(), "/KGlobalSettings", "org.kde.KGlobalSettings",
166                                                   "notifyChange", this, SLOT(_k_slotNotifyChange(int,int)));
167             QDBusConnection::sessionBus().connect(QString(), "/KIconLoader", "org.kde.KIconLoader",
168                                                   "iconChanged", this, SLOT(_k_slotIconChange(int)));
169             QDBusConnection::sessionBus().connect(QString(), "/KDEPlatformTheme", "org.kde.KDEPlatformTheme",
170                                                   "refreshFonts", this, SLOT(kdisplayFontChanged()));
171         }
172 
173         if (options & ApplySettings) {
174             d->kdisplaySetStyle(); // implies palette setup
175             d->propagateQtSettings();
176         }
177     }
178 }
179 
180 // Qt5 TODO: implement QPlatformIntegration::styleHint so that it reads a Qt or KDE setting,
181 // so that apps can just use QApplication::startDragDistance().
dndEventDelay()182 int KGlobalSettings::dndEventDelay()
183 {
184     KConfigGroup g(KSharedConfig::openConfig(), "General");
185     return g.readEntry("StartDragDist", QApplication::startDragDistance());
186 }
187 
singleClick()188 bool KGlobalSettings::singleClick()
189 {
190     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
191     return g.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK);
192 }
193 
changeCursorOverIcon()194 bool KGlobalSettings::changeCursorOverIcon()
195 {
196     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
197     return g.readEntry("ChangeCursor", KDE_DEFAULT_CHANGECURSOR);
198 }
199 
autoSelectDelay()200 int KGlobalSettings::autoSelectDelay()
201 {
202     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
203     return g.readEntry("AutoSelectDelay", KDE_DEFAULT_AUTOSELECTDELAY);
204 }
205 
completionMode()206 KGlobalSettings::Completion KGlobalSettings::completionMode()
207 {
208     int completion;
209     KConfigGroup g(KSharedConfig::openConfig(), "General");
210     completion = g.readEntry("completionMode", -1);
211     if ((completion < (int) CompletionNone) ||
212             (completion > (int) CompletionPopupAuto)) {
213         completion = (int) CompletionPopup; // Default
214     }
215     return (Completion) completion;
216 }
217 
showContextMenusOnPress()218 bool KGlobalSettings::showContextMenusOnPress()
219 {
220     KConfigGroup g(KSharedConfig::openConfig(), "ContextMenus");
221     return g.readEntry("ShowOnPress", true);
222 }
223 
224 // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp
inactiveTitleColor()225 QColor KGlobalSettings::inactiveTitleColor()
226 {
227 #ifdef Q_OS_WIN
228     return qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION));
229 #else
230     KConfigGroup g(KSharedConfig::openConfig(), "WM");
231     return g.readEntry("inactiveBackground", QColor(224, 223, 222));
232 #endif
233 }
234 
235 // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp
inactiveTextColor()236 QColor KGlobalSettings::inactiveTextColor()
237 {
238 #ifdef Q_OS_WIN
239     return qt_colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT));
240 #else
241     KConfigGroup g(KSharedConfig::openConfig(), "WM");
242     return g.readEntry("inactiveForeground", QColor(75, 71, 67));
243 #endif
244 }
245 
246 // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp
activeTitleColor()247 QColor KGlobalSettings::activeTitleColor()
248 {
249 #ifdef Q_OS_WIN
250     return qt_colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION));
251 #else
252     KConfigGroup g(KSharedConfig::openConfig(), "WM");
253     return g.readEntry("activeBackground", QColor(48, 174, 232));
254 #endif
255 }
256 
257 // NOTE: keep this in sync with kdebase/workspace/kcontrol/colors/colorscm.cpp
activeTextColor()258 QColor KGlobalSettings::activeTextColor()
259 {
260 #ifdef Q_OS_WIN
261     return qt_colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT));
262 #else
263     KConfigGroup g(KSharedConfig::openConfig(), "WM");
264     return g.readEntry("activeForeground", QColor(255, 255, 255));
265 #endif
266 }
267 
contrast()268 int KGlobalSettings::contrast()
269 {
270     return KColorScheme::contrast();
271 }
272 
contrastF(const KSharedConfigPtr & config)273 qreal KGlobalSettings::contrastF(const KSharedConfigPtr &config)
274 {
275     return KColorScheme::contrastF(config);
276 }
277 
shadeSortColumn()278 bool KGlobalSettings::shadeSortColumn()
279 {
280     KConfigGroup g(KSharedConfig::openConfig(), "General");
281     return g.readEntry("shadeSortColumn", KDE_DEFAULT_SHADE_SORT_COLUMN);
282 }
283 
allowDefaultBackgroundImages()284 bool KGlobalSettings::allowDefaultBackgroundImages()
285 {
286     KConfigGroup g(KSharedConfig::openConfig(), "General");
287     return g.readEntry("allowDefaultBackgroundImages", KDE_DEFAULT_ALLOW_DEFAULT_BACKGROUND_IMAGES);
288 }
289 
290 //inspired in old KGlobalSettingsData code
constructFontFromConfig(const char * groupKey,const char * configKey)291 QFont constructFontFromConfig(const char *groupKey, const char *configKey)
292 {
293     const KConfigGroup configGroup(KSharedConfig::openConfig(), groupKey);
294     QFont ret;
295     ret.setStyleHint(QFont::SansSerif);
296     ret = configGroup.readEntry(configKey, ret);
297     return ret;
298 }
299 
generalFont()300 QFont KGlobalSettings::generalFont()
301 {
302     return QFontDatabase::systemFont(QFontDatabase::GeneralFont);
303 }
fixedFont()304 QFont KGlobalSettings::fixedFont()
305 {
306     return QFontDatabase::systemFont(QFontDatabase::FixedFont);
307 }
windowTitleFont()308 QFont KGlobalSettings::windowTitleFont()
309 {
310     return QFontDatabase::systemFont(QFontDatabase::TitleFont);
311 }
smallestReadableFont()312 QFont KGlobalSettings::smallestReadableFont()
313 {
314     return QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont);
315 }
toolBarFont()316 QFont KGlobalSettings::toolBarFont()
317 {
318     return constructFontFromConfig("General", "toolBarFont");
319 }
menuFont()320 QFont KGlobalSettings::menuFont()
321 {
322     return constructFontFromConfig("General", "menuFont");
323 }
taskbarFont()324 QFont KGlobalSettings::taskbarFont()
325 {
326     return constructFontFromConfig("General", "taskbarFont");
327 }
328 
largeFont(const QString & text)329 QFont KGlobalSettings::Private::largeFont(const QString &text)
330 {
331     QFontDatabase db;
332     QStringList fam = db.families();
333 
334     // Move a bunch of preferred fonts to the front.
335     // most preferred last
336     static const char *const PreferredFontNames[] = {
337         "Arial",
338         "Sans Serif",
339         "Verdana",
340         "Tahoma",
341         "Lucida Sans",
342         "Lucidux Sans",
343         "Nimbus Sans",
344         "Gothic I"
345     };
346     static const unsigned int PreferredFontNamesCount = sizeof(PreferredFontNames) / sizeof(const char *);
347     for (unsigned int i = 0; i < PreferredFontNamesCount; ++i) {
348         const QString fontName(PreferredFontNames[i]);
349         if (fam.removeAll(fontName) > 0) {
350             fam.prepend(fontName);
351         }
352     }
353 
354     if (mLargeFont) {
355         fam.prepend(mLargeFont->family());
356         delete mLargeFont;
357     }
358 
359     for (QStringList::ConstIterator it = fam.constBegin();
360             it != fam.constEnd(); ++it) {
361         if (db.isSmoothlyScalable(*it) && !db.isFixedPitch(*it)) {
362             QFont font(*it);
363             font.setPixelSize(75);
364             QFontMetrics metrics(font);
365             int h = metrics.height();
366             if ((h < 60) || (h > 90)) {
367                 continue;
368             }
369 
370             bool ok = true;
371             for (int i = 0; i < text.length(); i++) {
372                 if (!metrics.inFont(text[i])) {
373                     ok = false;
374                     break;
375                 }
376             }
377             if (!ok) {
378                 continue;
379             }
380 
381             font.setPointSize(48);
382             mLargeFont = new QFont(font);
383             return *mLargeFont;
384         }
385     }
386     mLargeFont = new QFont(q->generalFont());
387     mLargeFont->setPointSize(48);
388     return *mLargeFont;
389 }
390 
largeFont(const QString & text)391 QFont KGlobalSettings::largeFont(const QString &text)
392 {
393     return self()->d->largeFont(text);
394 }
395 
mouseSettings()396 KGlobalSettings::KMouseSettings &KGlobalSettings::Private::mouseSettings()
397 {
398     if (!mMouseSettings) {
399         mMouseSettings = new KGlobalSettings::KMouseSettings;
400         KGlobalSettings::KMouseSettings &s = *mMouseSettings; // for convenience
401 
402 #ifndef Q_OS_WIN
403         KConfigGroup g(KSharedConfig::openConfig(), "Mouse");
404         QString setting = g.readEntry("MouseButtonMapping");
405         if (setting == "RightHanded") {
406             s.handed = KGlobalSettings::KMouseSettings::RightHanded;
407         } else if (setting == "LeftHanded") {
408             s.handed = KGlobalSettings::KMouseSettings::LeftHanded;
409         } else {
410 #if HAVE_X11
411         if (isX11) {
412             // get settings from X server
413             // This is a simplified version of the code in input/mouse.cpp
414             // Keep in sync !
415             s.handed = KGlobalSettings::KMouseSettings::RightHanded;
416             unsigned char map[20];
417             int num_buttons = XGetPointerMapping(QX11Info::display(), map, 20);
418             if (num_buttons == 2) {
419                 if ((int)map[0] == 1 && (int)map[1] == 2) {
420                     s.handed = KGlobalSettings::KMouseSettings::RightHanded;
421                 } else if ((int)map[0] == 2 && (int)map[1] == 1) {
422                     s.handed = KGlobalSettings::KMouseSettings::LeftHanded;
423                 }
424             } else if (num_buttons >= 3) {
425                 if ((int)map[0] == 1 && (int)map[2] == 3) {
426                     s.handed = KGlobalSettings::KMouseSettings::RightHanded;
427                 } else if ((int)map[0] == 3 && (int)map[2] == 1) {
428                     s.handed = KGlobalSettings::KMouseSettings::LeftHanded;
429                 }
430             }
431         }
432 #else
433             // FIXME: Implement on other platforms
434 #endif
435         }
436 #endif //Q_OS_WIN
437     }
438 #ifdef Q_OS_WIN
439     //not cached
440 #ifndef _WIN32_WCE
441     mMouseSettings->handed = (GetSystemMetrics(SM_SWAPBUTTON) ?
442                               KGlobalSettings::KMouseSettings::LeftHanded :
443                               KGlobalSettings::KMouseSettings::RightHanded);
444 #else
445 // There is no mice under wince
446     mMouseSettings->handed = KGlobalSettings::KMouseSettings::RightHanded;
447 #endif
448 #endif
449     return *mMouseSettings;
450 }
451 // KDE5: make this a const return?
mouseSettings()452 KGlobalSettings::KMouseSettings &KGlobalSettings::mouseSettings()
453 {
454     return self()->d->mouseSettings();
455 }
456 
desktopPath()457 QString KGlobalSettings::desktopPath()
458 {
459     QString path = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
460     return path.isEmpty() ? QDir::homePath() : path;
461 }
462 
463 // This was the KDE-specific autostart folder in KDEHOME.
464 // KDE 5 : re-evaluate this, I'd say the xdg autostart spec supersedes this, and is sufficient
465 // (since there's a GUI for creating the necessary desktop files)
466 #if 0
467 QString KGlobalSettings::autostartPath()
468 {
469     QString s_autostartPath;
470     KConfigGroup g(KSharedConfig::openConfig(), "Paths");
471     s_autostartPath = KGlobal::dirs()->localkdedir() + "Autostart/";
472     s_autostartPath = g.readPathEntry("Autostart", s_autostartPath);
473     s_autostartPath = QDir::cleanPath(s_autostartPath);
474     if (!s_autostartPath.endsWith('/')) {
475         s_autostartPath.append(QLatin1Char('/'));
476     }
477     return s_autostartPath;
478 }
479 #endif
480 
documentPath()481 QString KGlobalSettings::documentPath()
482 {
483     QString path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
484     return path.isEmpty() ? QDir::homePath() : path;
485 }
486 
downloadPath()487 QString KGlobalSettings::downloadPath()
488 {
489     QString path = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
490     return path.isEmpty() ? QDir::homePath() : path;
491 }
492 
videosPath()493 QString KGlobalSettings::videosPath()
494 {
495     QString path = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation);
496     return path.isEmpty() ? QDir::homePath() : path;
497 }
498 
picturesPath()499 QString KGlobalSettings::picturesPath()
500 {
501     QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
502     return path.isEmpty() ? QDir::homePath() : path;
503 }
504 
musicPath()505 QString KGlobalSettings::musicPath()
506 {
507     QString path = QStandardPaths::writableLocation(QStandardPaths::MusicLocation);
508     return path.isEmpty() ? QDir::homePath() : path;
509 }
510 
isMultiHead()511 bool KGlobalSettings::isMultiHead()
512 {
513 #ifdef Q_OS_WIN
514     return GetSystemMetrics(SM_CMONITORS) > 1;
515 #else
516     QByteArray multiHead = qgetenv("KDE_MULTIHEAD");
517     if (!multiHead.isEmpty()) {
518         return (multiHead.toLower() == "true");
519     }
520     return false;
521 #endif
522 }
523 
wheelMouseZooms()524 bool KGlobalSettings::wheelMouseZooms()
525 {
526     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
527     return g.readEntry("WheelMouseZooms", KDE_DEFAULT_WHEEL_ZOOM);
528 }
529 
splashScreenDesktopGeometry()530 QRect KGlobalSettings::splashScreenDesktopGeometry()
531 {
532     return QApplication::desktop()->screenGeometry(QCursor::pos());
533 }
534 
desktopGeometry(const QPoint & point)535 QRect KGlobalSettings::desktopGeometry(const QPoint &point)
536 {
537     return QApplication::desktop()->screenGeometry(point);
538 }
539 
desktopGeometry(const QWidget * w)540 QRect KGlobalSettings::desktopGeometry(const QWidget *w)
541 {
542     return QApplication::desktop()->screenGeometry(w);
543 }
544 
showIconsOnPushButtons()545 bool KGlobalSettings::showIconsOnPushButtons()
546 {
547     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
548     return g.readEntry("ShowIconsOnPushButtons",
549                        KDE_DEFAULT_ICON_ON_PUSHBUTTON);
550 }
551 
naturalSorting()552 bool KGlobalSettings::naturalSorting()
553 {
554     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
555     return g.readEntry("NaturalSorting",
556                        KDE_DEFAULT_NATURAL_SORTING);
557 }
558 
graphicEffectsLevel()559 KGlobalSettings::GraphicEffects KGlobalSettings::graphicEffectsLevel()
560 {
561     // This variable stores whether _graphicEffects has the default value because it has not been
562     // loaded yet, or if it has been loaded from the user settings or defaults and contains a valid
563     // value.
564     static bool _graphicEffectsInitialized = false;
565 
566     if (!_graphicEffectsInitialized) {
567         _graphicEffectsInitialized = true;
568         Private::reloadStyleSettings();
569     }
570 
571     return _graphicEffects;
572 }
573 
graphicEffectsLevelDefault()574 KGlobalSettings::GraphicEffects KGlobalSettings::graphicEffectsLevelDefault()
575 {
576     // For now, let always enable animations by default. The plan is to make
577     // this code a bit smarter. (ereslibre)
578 
579     return ComplexAnimationEffects;
580 }
581 
582 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
showFilePreview(const QUrl & url)583 bool KGlobalSettings::showFilePreview(const QUrl &url)
584 {
585     KConfigGroup g(KSharedConfig::openConfig(), "PreviewSettings");
586     bool defaultSetting = url.isLocalFile(); // ## incorrect, use KProtocolInfo::showFilePreview instead
587     return g.readEntry(url.scheme(), defaultSetting);
588 }
589 #endif
590 
opaqueResize()591 bool KGlobalSettings::opaqueResize()
592 {
593     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
594     return g.readEntry("OpaqueResize", KDE_DEFAULT_OPAQUE_RESIZE);
595 }
596 
buttonLayout()597 int KGlobalSettings::buttonLayout()
598 {
599     KConfigGroup g(KSharedConfig::openConfig(), "KDE");
600     return g.readEntry("ButtonLayout", KDE_DEFAULT_BUTTON_LAYOUT);
601 }
602 
603 #if 0 // HAVE_X11 && QT_VERSION >= QT_VERSION_CHECK(5,0,0)
604 // Taken from Qt-4.x qt_x11_apply_settings_in_all_apps since Qt5 doesn't have it anymore.
605 // TODO: evaluate if this is still needed
606 // TODO: if yes, this code should be an invokable method of the qxcb platform plugin?
607 // TODO: it looks like the handling code for this in QPA is missing, too...
608 static void x11_apply_settings_in_all_apps()
609 {
610     QByteArray stamp;
611     QDataStream s(&stamp, QIODevice::WriteOnly);
612     s << QDateTime::currentDateTime();
613 
614     QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_");
615     settings_atom_name += XDisplayString(QX11Info::display());
616 
617     xcb_connection_t *xcb_conn = QX11Info::connection();
618     xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_conn, false, settings_atom_name.size(), settings_atom_name.constData());
619     xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_conn, cookie, 0);
620     xcb_atom_t atom = reply->atom;
621     free(reply);
622 
623     xcb_change_property(xcb_conn, XCB_PROP_MODE_REPLACE, QX11Info::appRootWindow(), atom, XCB_ATOM_ATOM,
624                         8, stamp.size(), (const void *)stamp.constData());
625 
626     //XChangeProperty(QX11Info::display(), QX11Info::appRootWindow(0),
627     //ATOM(_QT_SETTINGS_TIMESTAMP), ATOM(_QT_SETTINGS_TIMESTAMP), 8,
628     //PropModeReplace, (unsigned char *)stamp.data(), stamp.size());
629 }
630 #endif
631 
emitChange(ChangeType changeType,int arg)632 void KGlobalSettings::emitChange(ChangeType changeType, int arg)
633 {
634     switch (changeType) {
635     case IconChanged:
636         KIconLoader::emitChange(KIconLoader::Group(arg));
637         break;
638     case ToolbarStyleChanged:
639         KToolBar::emitToolbarStyleChanged();
640         break;
641     case FontChanged:
642         self()->d->kdisplaySetFont();
643         break;
644     default: {
645         QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange");
646         QList<QVariant> args;
647         args.append(static_cast<int>(changeType));
648         args.append(arg);
649         message.setArguments(args);
650         QDBusConnection::sessionBus().send(message);
651     }   break;
652 
653     }
654 }
655 
_k_slotIconChange(int arg)656 void KGlobalSettings::Private::_k_slotIconChange(int arg)
657 {
658     _k_slotNotifyChange(IconChanged, arg);
659 }
660 
_k_slotNotifyChange(int changeType,int arg)661 void KGlobalSettings::Private::_k_slotNotifyChange(int changeType, int arg)
662 {
663     switch (changeType) {
664     case StyleChanged:
665         if (activated) {
666             KSharedConfig::openConfig()->reparseConfiguration();
667             kdisplaySetStyle();
668         }
669         break;
670 
671     case ToolbarStyleChanged:
672         KSharedConfig::openConfig()->reparseConfiguration();
673         emit q->toolbarAppearanceChanged(arg);
674         break;
675 
676     case PaletteChanged:
677         if (activated) {
678             KSharedConfig::openConfig()->reparseConfiguration();
679             paletteCreated = false;
680             kdisplaySetPalette();
681         }
682         break;
683 
684     case FontChanged:
685         Q_ASSERT(false && "shouldn't get here now...");
686         break;
687 
688     case SettingsChanged: {
689         KSharedConfig::openConfig()->reparseConfiguration();
690         SettingsCategory category = static_cast<SettingsCategory>(arg);
691         if (category == SETTINGS_QT) {
692             if (activated) {
693                 propagateQtSettings();
694             }
695         } else {
696             switch (category) {
697             case SETTINGS_STYLE:
698                 reloadStyleSettings();
699                 break;
700             case SETTINGS_MOUSE:
701                 self()->d->dropMouseSettingsCache();
702                 break;
703             case SETTINGS_LOCALE:
704                 // QT5 TODO REPLACEMENT ? KLocale::global()->reparseConfiguration();
705                 break;
706             default:
707                 break;
708             }
709             emit q->settingsChanged(category);
710         }
711         break;
712     }
713     case IconChanged:
714         QPixmapCache::clear();
715         KSharedConfig::openConfig()->reparseConfiguration();
716         emit q->iconChanged(arg);
717         break;
718 
719     case CursorChanged:
720         applyCursorTheme();
721         break;
722 
723     case BlockShortcuts:
724         // FIXME KAccel port
725         //KGlobalAccel::blockShortcuts(arg);
726         emit q->blockShortcuts(arg); // see kwin
727         break;
728 
729     case NaturalSortingChanged:
730         emit q->naturalSortingChanged();
731         break;
732 
733     default:
734         qWarning() << "Unknown type of change in KGlobalSettings::slotNotifyChange: " << changeType;
735     }
736 }
737 
738 // Set by KApplication
739 QString kde_overrideStyle;
740 
applyGUIStyle()741 void KGlobalSettings::Private::applyGUIStyle()
742 {
743 #if 0 // Disabled for KF5. TODO Qt5: check that the KDE style is correctly applied.
744     //Platform plugin only loaded on X11 systems
745 #if HAVE_X11
746     if (!kde_overrideStyle.isEmpty()) {
747         const QLatin1String currentStyleName(qApp->style()->metaObject()->className());
748         if (0 != kde_overrideStyle.compare(currentStyleName, Qt::CaseInsensitive) &&
749                 0 != (QString(kde_overrideStyle + QLatin1String("Style"))).compare(currentStyleName, Qt::CaseInsensitive)) {
750             qApp->setStyle(kde_overrideStyle);
751         }
752     } else {
753         emit q->kdisplayStyleChanged();
754     }
755 #else
756     const QLatin1String currentStyleName(qApp->style()->metaObject()->className());
757 
758     if (kde_overrideStyle.isEmpty()) {
759         const QString &defaultStyle = KStyle::defaultStyle();
760         const KConfigGroup pConfig(KSharedConfig::openConfig(), "General");
761         const QString &styleStr = pConfig.readEntry("widgetStyle", defaultStyle);
762 
763         if (styleStr.isEmpty() ||
764                 // check whether we already use the correct style to return then
765                 // (workaround for Qt misbehavior to avoid double style initialization)
766                 0 == (QString(styleStr + QLatin1String("Style"))).compare(currentStyleName, Qt::CaseInsensitive) ||
767                 0 == styleStr.compare(currentStyleName, Qt::CaseInsensitive)) {
768             return;
769         }
770 
771         QStyle *sp = QStyleFactory::create(styleStr);
772         if (sp && currentStyleName == sp->metaObject()->className()) {
773             delete sp;
774             return;
775         }
776 
777         // If there is no default style available, try falling back any available style
778         if (!sp && styleStr != defaultStyle) {
779             sp = QStyleFactory::create(defaultStyle);
780         }
781         if (!sp) {
782             sp = QStyleFactory::create(QStyleFactory::keys().first());
783         }
784         qApp->setStyle(sp);
785     } else if (0 != kde_overrideStyle.compare(currentStyleName, Qt::CaseInsensitive) &&
786                0 != (QString(kde_overrideStyle + QLatin1String("Style"))).compare(currentStyleName, Qt::CaseInsensitive)) {
787         qApp->setStyle(kde_overrideStyle);
788     }
789     emit q->kdisplayStyleChanged();
790 #endif //HAVE_X11
791 #endif
792 }
793 
createApplicationPalette(const KSharedConfigPtr & config)794 QPalette KGlobalSettings::createApplicationPalette(const KSharedConfigPtr &config)
795 {
796     return self()->d->createApplicationPalette(config);
797 }
798 
createNewApplicationPalette(const KSharedConfigPtr & config)799 QPalette KGlobalSettings::createNewApplicationPalette(const KSharedConfigPtr &config)
800 {
801     return self()->d->createNewApplicationPalette(config);
802 }
803 
createApplicationPalette(const KSharedConfigPtr & config)804 QPalette KGlobalSettings::Private::createApplicationPalette(const KSharedConfigPtr &config)
805 {
806     // This method is typically called once by KQGuiPlatformPlugin::palette and once again
807     // by kdisplaySetPalette(), so we cache the palette to save time.
808     if (config == KSharedConfig::openConfig() && paletteCreated) {
809         return applicationPalette;
810     }
811     return createNewApplicationPalette(config);
812 }
813 
createNewApplicationPalette(const KSharedConfigPtr & config)814 QPalette KGlobalSettings::Private::createNewApplicationPalette(const KSharedConfigPtr &config)
815 {
816     QPalette palette = KColorScheme::createApplicationPalette(config);
817 
818     if (config == KSharedConfig::openConfig()) {
819         paletteCreated = true;
820         applicationPalette = palette;
821     }
822 
823     return palette;
824 }
825 
kdisplaySetPalette()826 void KGlobalSettings::Private::kdisplaySetPalette()
827 {
828 #if !defined(Q_OS_WINCE)
829     if (!kdeFullSession) {
830         return;
831     }
832 
833     QApplication::setPalette(q->createApplicationPalette());
834     emit q->kdisplayPaletteChanged();
835     emit q->appearanceChanged();
836 #endif
837 }
838 
kdisplaySetFont()839 void KGlobalSettings::Private::kdisplaySetFont()
840 {
841 #if !defined(Q_OS_WINCE)
842     if (!kdeFullSession) {
843         return;
844     }
845 
846     QDBusMessage message = QDBusMessage::createSignal("/KDEPlatformTheme", "org.kde.KDEPlatformTheme", "refreshFonts");
847     QDBusConnection::sessionBus().send(message);
848     emit q->kdisplayFontChanged();
849 #endif
850 }
851 
kdisplaySetStyle()852 void KGlobalSettings::Private::kdisplaySetStyle()
853 {
854     applyGUIStyle();
855 
856     // Reread palette from config file.
857     kdisplaySetPalette();
858 }
859 
reloadStyleSettings()860 void KGlobalSettings::Private::reloadStyleSettings()
861 {
862     KConfigGroup g(KSharedConfig::openConfig(), "KDE-Global GUI Settings");
863 
864     // Asking for hasKey we do not ask for graphicEffectsLevelDefault() that can
865     // contain some very slow code. If we can save that time, do it. (ereslibre)
866 
867     if (g.hasKey("GraphicEffectsLevel")) {
868         _graphicEffects = ((GraphicEffects) g.readEntry("GraphicEffectsLevel", QVariant((int) NoEffects)).toInt());
869 
870         return;
871     }
872 
873     _graphicEffects = KGlobalSettings::graphicEffectsLevelDefault();
874 }
875 
applyCursorTheme()876 void KGlobalSettings::Private::applyCursorTheme()
877 {
878 #if HAVE_X11 && defined(HAVE_XCURSOR)
879     if (!isX11) {
880         return;
881     }
882     KConfig config("kcminputrc");
883     KConfigGroup g(&config, "Mouse");
884 
885     QString theme = g.readEntry("cursorTheme", QString());
886     int size      = g.readEntry("cursorSize", -1);
887 
888     // Default cursor size is 16 points
889     if (size == -1) {
890         QApplication *app = static_cast<QApplication *>(QApplication::instance());
891         size = app->desktop()->screen(0)->logicalDpiY() * 16 / 72;
892     }
893 
894     // Note that in X11R7.1 and earlier, calling XcursorSetTheme()
895     // with a NULL theme would cause Xcursor to use "default", but
896     // in 7.2 and later it will cause it to revert to the theme that
897     // was configured when the application was started.
898     XcursorSetTheme(QX11Info::display(), theme.isNull() ?
899                     "default" : QFile::encodeName(theme));
900     XcursorSetDefaultSize(QX11Info::display(), size);
901 
902     emit q->cursorChanged();
903 #endif
904 }
905 
propagateQtSettings()906 void KGlobalSettings::Private::propagateQtSettings()
907 {
908     KConfigGroup cg(KSharedConfig::openConfig(), "KDE");
909 
910 #ifndef Q_OS_WIN
911     int num = cg.readEntry("CursorBlinkRate", QApplication::cursorFlashTime());
912     if ((num != 0) && (num < 200)) {
913         num = 200;
914     }
915     if (num > 2000) {
916         num = 2000;
917     }
918     QApplication::setCursorFlashTime(num);
919 #else
920     int num;
921 #endif
922     num = cg.readEntry("DoubleClickInterval", QApplication::doubleClickInterval());
923     QApplication::setDoubleClickInterval(num);
924     num = cg.readEntry("StartDragTime", QApplication::startDragTime());
925     QApplication::setStartDragTime(num);
926     num = cg.readEntry("StartDragDist", QApplication::startDragDistance());
927     QApplication::setStartDragDistance(num);
928     num = cg.readEntry("WheelScrollLines", QApplication::wheelScrollLines());
929     QApplication::setWheelScrollLines(num);
930     bool showIcons = cg.readEntry("ShowIconsInMenuItems", !QApplication::testAttribute(Qt::AA_DontShowIconsInMenus));
931     QApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !showIcons);
932 
933     // KDE5: this seems fairly pointless
934     emit q->settingsChanged(SETTINGS_QT);
935 }
936 
dropMouseSettingsCache()937 void KGlobalSettings::Private::dropMouseSettingsCache()
938 {
939 #ifndef Q_OS_WIN
940     delete self()->d->mMouseSettings;
941     self()->d->mMouseSettings = nullptr;
942 #endif
943 }
944 
945 #include "moc_kglobalsettings.cpp"
946