1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33
34 #include "qgtkstyle_p_p.h"
35
36 // This file is responsible for resolving all GTK functions we use
37 // dynamically. This is done to avoid link-time dependency on GTK
38 // as well as crashes occurring due to usage of the GTK_QT engines
39 //
40 // Additionally we create a map of common GTK widgets that we can pass
41 // to the GTK theme engine as many engines resort to querying the
42 // actual widget pointers for details that are not covered by the
43 // state flags
44
45 #include <QtCore/qglobal.h>
46
47 #include <QtCore/QEvent>
48 #include <QtCore/QFile>
49 #include <QtCore/QStringList>
50 #include <QtCore/QTextStream>
51 #include <QtCore/QHash>
52 #include <QtCore/QUrl>
53 #include <QtCore/QDebug>
54
55 #include "qgtk2painter_p.h"
56 #include <private/qapplication_p.h>
57 #include <private/qiconloader_p.h>
58 #include <qpa/qplatformfontdatabase.h>
59
60 #include <QtWidgets/QMenu>
61 #include <QtWidgets/QStyle>
62 #include <QtWidgets/QApplication>
63 #include <QtGui/QPixmapCache>
64 #include <QtWidgets/QStatusBar>
65 #include <QtWidgets/QMenuBar>
66 #include <QtWidgets/QToolBar>
67 #include <QtWidgets/QToolButton>
68
69 // X11 Includes:
70
71 // the following is necessary to work around breakage in many versions
72 // of XFree86's Xlib.h still in use
73 // ### which versions?
74 #if defined(_XLIB_H_) // crude hack, but...
75 #error "cannot include <X11/Xlib.h> before this file"
76 #endif
77 #define XRegisterIMInstantiateCallback qt_XRegisterIMInstantiateCallback
78 #define XUnregisterIMInstantiateCallback qt_XUnregisterIMInstantiateCallback
79 #define XSetIMValues qt_XSetIMValues
80 #include <X11/Xlib.h>
81 #undef XRegisterIMInstantiateCallback
82 #undef XUnregisterIMInstantiateCallback
83 #undef XSetIMValues
84
85 QT_BEGIN_NAMESPACE
86
87 Q_GLOBAL_STATIC(QGtkStyleUpdateScheduler, styleScheduler)
88
89 Ptr_ubuntu_gtk_set_use_overlay_scrollbar QGtkStylePrivate::ubuntu_gtk_set_use_overlay_scrollbar = 0;
90
91 typedef int (*x11ErrorHandler)(Display*, XErrorEvent*);
92
93 QT_END_NAMESPACE
94
95 Q_DECLARE_METATYPE(QGtkStylePrivate*);
96
97 QT_BEGIN_NAMESPACE
98
gtkStyleSetCallback(GtkWidget *)99 static void gtkStyleSetCallback(GtkWidget*)
100 {
101 qRegisterMetaType<QGtkStylePrivate *>();
102
103 // We have to let this function return and complete the event
104 // loop to ensure that all gtk widgets have been styled before
105 // updating
106 QMetaObject::invokeMethod(styleScheduler(), "updateTheme", Qt::QueuedConnection);
107 }
108
update_toolbar_style(GtkWidget * gtkToolBar,GParamSpec *,gpointer)109 static void update_toolbar_style(GtkWidget *gtkToolBar, GParamSpec *, gpointer)
110 {
111 GtkToolbarStyle toolbar_style = GTK_TOOLBAR_ICONS;
112 g_object_get(gtkToolBar, "toolbar-style", &toolbar_style, NULL);
113 QWidgetList widgets = QApplication::allWidgets();
114 for (int i = 0; i < widgets.size(); ++i) {
115 QWidget *widget = widgets.at(i);
116 if (qobject_cast<QToolButton*>(widget)) {
117 QEvent event(QEvent::StyleChange);
118 QApplication::sendEvent(widget, &event);
119 }
120 }
121 }
122
classPath(GtkWidget * widget)123 static QHashableLatin1Literal classPath(GtkWidget *widget)
124 {
125 char *class_path;
126 gtk_widget_path (widget, NULL, &class_path, NULL);
127
128 char *copy = class_path;
129 if (strncmp(copy, "GtkWindow.", 10) == 0)
130 copy += 10;
131 if (strncmp(copy, "GtkFixed.", 9) == 0)
132 copy += 9;
133
134 copy = strdup(copy);
135
136 g_free(class_path);
137
138 return QHashableLatin1Literal::fromData(copy);
139 }
140
141
142
eventFilter(QObject * obj,QEvent * e)143 bool QGtkStyleFilter::eventFilter(QObject *obj, QEvent *e)
144 {
145 if (e->type() == QEvent::ApplicationPaletteChange) {
146 // Only do this the first time since this will also
147 // generate applicationPaletteChange events
148 //if (!qt_app_palettes_hash() || qt_app_palettes_hash()->isEmpty()) {
149 // stylePrivate->applyCustomPaletteHash();
150 //}
151 }
152 return QObject::eventFilter(obj, e);
153 }
154
155 QList<QGtkStylePrivate *> QGtkStylePrivate::instances;
156 QGtkStylePrivate::WidgetMap *QGtkStylePrivate::widgetMap = 0;
157
QGtkStylePrivate()158 QGtkStylePrivate::QGtkStylePrivate()
159 : QCommonStylePrivate()
160 , filter(this)
161 {
162 instances.append(this);
163 animationFps = 60;
164 }
165
~QGtkStylePrivate()166 QGtkStylePrivate::~QGtkStylePrivate()
167 {
168 instances.removeOne(this);
169 }
170
init()171 void QGtkStylePrivate::init()
172 {
173 initGtkWidgets();
174 }
175
gtkPainter(QPainter * painter)176 QGtkPainter* QGtkStylePrivate::gtkPainter(QPainter *painter)
177 {
178 // TODO: choose between gtk2 and gtk3
179 static QGtk2Painter instance;
180 instance.reset(painter);
181 return &instance;
182 }
183
gtkWidget(const QHashableLatin1Literal & path)184 GtkWidget* QGtkStylePrivate::gtkWidget(const QHashableLatin1Literal &path)
185 {
186 GtkWidget *widget = gtkWidgetMap()->value(path);
187 if (!widget) {
188 // Theme might have rearranged widget internals
189 widget = gtkWidgetMap()->value(path);
190 }
191 return widget;
192 }
193
gtkStyle(const QHashableLatin1Literal & path)194 GtkStyle* QGtkStylePrivate::gtkStyle(const QHashableLatin1Literal &path)
195 {
196 if (GtkWidget *w = gtkWidgetMap()->value(path))
197 return gtk_widget_get_style(w);
198 return 0;
199 }
200
gtkWidgetSetFocus(GtkWidget * widget,bool focus)201 void QGtkStylePrivate::gtkWidgetSetFocus(GtkWidget *widget, bool focus)
202 {
203 GdkEvent *event = gdk_event_new(GDK_FOCUS_CHANGE);
204 event->focus_change.type = GDK_FOCUS_CHANGE;
205 event->focus_change.in = focus;
206 gtk_widget_send_focus_change(widget, event);
207 gdk_event_free(event);
208 }
209
210 /* \internal
211 * Initializes a number of gtk menu widgets.
212 * The widgets are cached.
213 */
initGtkMenu() const214 void QGtkStylePrivate::initGtkMenu() const
215 {
216 // Create menubar
217 GtkWidget *gtkMenuBar = gtk_menu_bar_new();
218 setupGtkWidget(gtkMenuBar);
219
220 GtkWidget *gtkMenuBarItem = gtk_menu_item_new_with_label("X");
221 gtk_menu_shell_append((GtkMenuShell*)(gtkMenuBar), gtkMenuBarItem);
222 gtk_widget_realize(gtkMenuBarItem);
223
224 // Create menu
225 GtkWidget *gtkMenu = gtk_menu_new();
226 gtk_menu_item_set_submenu((GtkMenuItem*)(gtkMenuBarItem), gtkMenu);
227 gtk_widget_realize(gtkMenu);
228
229 GtkWidget *gtkMenuItem = gtk_menu_item_new_with_label("X");
230 gtk_menu_shell_append((GtkMenuShell*)gtkMenu, gtkMenuItem);
231 gtk_widget_realize(gtkMenuItem);
232
233 GtkWidget *gtkCheckMenuItem = gtk_check_menu_item_new_with_label("X");
234 gtk_menu_shell_append((GtkMenuShell*)gtkMenu, gtkCheckMenuItem);
235 gtk_widget_realize(gtkCheckMenuItem);
236
237 GtkWidget *gtkMenuSeparator = gtk_separator_menu_item_new();
238 gtk_menu_shell_append((GtkMenuShell*)gtkMenu, gtkMenuSeparator);
239
240 addAllSubWidgets(gtkMenuBar);
241 addAllSubWidgets(gtkMenu);
242 }
243
244
initGtkTreeview() const245 void QGtkStylePrivate::initGtkTreeview() const
246 {
247 GtkWidget *gtkTreeView = gtk_tree_view_new();
248 gtk_tree_view_append_column((GtkTreeView*)gtkTreeView, gtk_tree_view_column_new());
249 gtk_tree_view_append_column((GtkTreeView*)gtkTreeView, gtk_tree_view_column_new());
250 gtk_tree_view_append_column((GtkTreeView*)gtkTreeView, gtk_tree_view_column_new());
251 addWidget(gtkTreeView);
252 }
253
254
255 /* \internal
256 * Initializes a number of gtk widgets that we can later on use to determine some of our styles.
257 * The widgets are cached.
258 */
initGtkWidgets() const259 void QGtkStylePrivate::initGtkWidgets() const
260 {
261 // From gtkmain.c
262 uid_t ruid = getuid ();
263 uid_t rgid = getgid ();
264 uid_t euid = geteuid ();
265 uid_t egid = getegid ();
266 if (ruid != euid || rgid != egid) {
267 qWarning("\nThis process is currently running setuid or setgid.\nGTK+ does not allow this "
268 "therefore Qt cannot use the GTK+ integration.\nTry launching your app using \'gksudo\', "
269 "\'kdesudo\' or a similar tool.\n\n"
270 "See http://www.gtk.org/setuid.html for more information.\n");
271 return;
272 }
273
274 // Gtk will set the Qt error handler so we have to reset it afterwards
275 x11ErrorHandler qt_x_errhandler = XSetErrorHandler(0);
276 gtk_init (NULL, NULL);
277 XSetErrorHandler(qt_x_errhandler);
278
279 ubuntu_gtk_set_use_overlay_scrollbar = (Ptr_ubuntu_gtk_set_use_overlay_scrollbar)QLibrary::resolve(QLS("gtk-x11-2.0"), "ubuntu_gtk_set_use_overlay_scrollbar");
280 if (ubuntu_gtk_set_use_overlay_scrollbar)
281 ubuntu_gtk_set_use_overlay_scrollbar(false);
282
283 // make a window
284 GtkWidget* gtkWindow = gtk_window_new(GTK_WINDOW_POPUP);
285 gtk_widget_realize(gtkWindow);
286 QHashableLatin1Literal widgetPath = QHashableLatin1Literal::fromData(strdup("GtkWindow"));
287 removeWidgetFromMap(widgetPath);
288 gtkWidgetMap()->insert(widgetPath, gtkWindow);
289
290
291 // Make all other widgets. respect the text direction
292 if (qApp->layoutDirection() == Qt::RightToLeft)
293 gtk_widget_set_default_direction(GTK_TEXT_DIR_RTL);
294
295 if (!gtkWidgetMap()->contains("GtkButton")) {
296 GtkWidget *gtkButton = gtk_button_new();
297 addWidget(gtkButton);
298 g_signal_connect(gtkButton, "style-set", G_CALLBACK(gtkStyleSetCallback), 0);
299 addWidget(GTK_WIDGET(gtk_tool_button_new(NULL, "Qt")));
300 addWidget(GTK_WIDGET(gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE)));
301 addWidget(GTK_WIDGET(gtk_hbutton_box_new()));
302 addWidget(GTK_WIDGET(gtk_check_button_new()));
303 addWidget(GTK_WIDGET(gtk_radio_button_new(NULL)));
304 addWidget(GTK_WIDGET(gtk_combo_box_new()));
305 addWidget(GTK_WIDGET(gtk_combo_box_entry_new()));
306 GtkWidget *entry = gtk_entry_new();
307 // gtk-im-context-none is supported in gtk+ since 2.19.5
308 // and also exists in gtk3
309 // http://git.gnome.org/browse/gtk+/tree/gtk/gtkimmulticontext.c?id=2.19.5#n33
310 // reason that we don't use gtk-im-context-simple here is,
311 // gtk-im-context-none has less overhead, and 2.19.5 is
312 // relatively old. and even for older gtk+, it will fallback
313 // to gtk-im-context-simple if gtk-im-context-none doesn't
314 // exists.
315 g_object_set(entry, "im-module", "gtk-im-context-none", NULL);
316 addWidget(entry);
317 addWidget(gtk_frame_new(NULL));
318 addWidget(gtk_expander_new(""));
319 addWidget(gtk_statusbar_new());
320 addWidget(gtk_hscale_new(GTK_ADJUSTMENT(gtk_adjustment_new(1, 0, 1, 0, 0, 0))));
321 addWidget(gtk_hscrollbar_new(NULL));
322 addWidget(gtk_scrolled_window_new(NULL, NULL));
323
324 initGtkMenu();
325 addWidget(gtk_notebook_new());
326 addWidget(gtk_progress_bar_new());
327 addWidget(gtk_spin_button_new(GTK_ADJUSTMENT(gtk_adjustment_new(1, 0, 1, 0, 0, 0)), 0.1, 3));
328 GtkWidget *toolbar = gtk_toolbar_new();
329 g_signal_connect (toolbar, "notify::toolbar-style", G_CALLBACK (update_toolbar_style), toolbar);
330 gtk_toolbar_insert((GtkToolbar*)toolbar, gtk_separator_tool_item_new(), -1);
331 addWidget(toolbar);
332 initGtkTreeview();
333 addWidget(gtk_vscale_new(GTK_ADJUSTMENT(gtk_adjustment_new(1, 0, 1, 0, 0, 0))));
334 addWidget(gtk_vscrollbar_new(NULL));
335 }
336 else // Rebuild map
337 {
338 // When styles change subwidgets can get rearranged
339 // as with the combo box. We need to update the widget map
340 // to reflect this;
341 QHash<QHashableLatin1Literal, GtkWidget*> oldMap = *gtkWidgetMap();
342 gtkWidgetMap()->clear();
343 QHashIterator<QHashableLatin1Literal, GtkWidget*> it(oldMap);
344 while (it.hasNext()) {
345 it.next();
346 if (!strchr(it.key().data(), '.')) {
347 addAllSubWidgets(it.value());
348 }
349 free(const_cast<char *>(it.key().data()));
350 }
351 }
352 }
353
354 /*! \internal
355 * destroys all previously buffered widgets.
356 */
cleanupGtkWidgets()357 void QGtkStylePrivate::cleanupGtkWidgets()
358 {
359 if (!widgetMap)
360 return;
361 if (widgetMap->contains("GtkWindow")) // Gtk will destroy all children
362 gtk_widget_destroy(widgetMap->value("GtkWindow"));
363 for (QHash<QHashableLatin1Literal, GtkWidget *>::const_iterator it = widgetMap->constBegin();
364 it != widgetMap->constEnd(); ++it)
365 free(const_cast<char *>(it.key().data()));
366 }
367
getThemeName()368 QString QGtkStylePrivate::getThemeName()
369 {
370 QString themeName;
371 // Read the theme name from GtkSettings
372 GtkSettings *settings = gtk_settings_get_default();
373 gchararray value;
374 g_object_get(settings, "gtk-theme-name", &value, NULL);
375 themeName = QString::fromUtf8(value);
376 g_free(value);
377 return themeName;
378 }
379
380 // Get size of the arrow controls in a GtkSpinButton
getSpinboxArrowSize() const381 int QGtkStylePrivate::getSpinboxArrowSize() const
382 {
383 const int MIN_ARROW_WIDTH = 6;
384 GtkWidget *spinButton = gtkWidget("GtkSpinButton");
385 GtkStyle *style = gtk_widget_get_style(spinButton);
386 gint size = pango_font_description_get_size (style->font_desc);
387 gint arrow_size;
388 arrow_size = qMax(PANGO_PIXELS (size), MIN_ARROW_WIDTH) + style->xthickness;
389 arrow_size += arrow_size%2 + 1;
390 return arrow_size;
391 }
392
393
isKDE4Session()394 bool QGtkStylePrivate::isKDE4Session()
395 {
396 static int version = -1;
397 if (version == -1)
398 version = qgetenv("KDE_SESSION_VERSION").toInt();
399 return (version == 4);
400 }
401
applyCustomPaletteHash()402 void QGtkStylePrivate::applyCustomPaletteHash()
403 {
404 QPalette menuPal = gtkWidgetPalette("GtkMenu");
405 GdkColor gdkBg = gtk_widget_get_style(gtkWidget("GtkMenu"))->bg[GTK_STATE_NORMAL];
406 QColor bgColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8);
407 menuPal.setBrush(QPalette::Base, bgColor);
408 menuPal.setBrush(QPalette::Window, bgColor);
409 qApp->setPalette(menuPal, "QMenu");
410
411 QPalette toolbarPal = gtkWidgetPalette("GtkToolbar");
412 qApp->setPalette(toolbarPal, "QToolBar");
413
414 QPalette menuBarPal = gtkWidgetPalette("GtkMenuBar");
415 qApp->setPalette(menuBarPal, "QMenuBar");
416 }
417
418 /*! \internal
419 * Returns the gtk Widget that should be used to determine text foreground and background colors.
420 */
getTextColorWidget() const421 GtkWidget* QGtkStylePrivate::getTextColorWidget() const
422 {
423 return gtkWidget("GtkEntry");
424 }
425
setupGtkWidget(GtkWidget * widget)426 void QGtkStylePrivate::setupGtkWidget(GtkWidget* widget)
427 {
428 if (GTK_IS_WIDGET(widget)) {
429 GtkWidget *protoLayout = gtkWidgetMap()->value("GtkContainer");
430 if (!protoLayout) {
431 protoLayout = gtk_fixed_new();
432 gtk_container_add((GtkContainer*)(gtkWidgetMap()->value("GtkWindow")), protoLayout);
433 QHashableLatin1Literal widgetPath = QHashableLatin1Literal::fromData(strdup("GtkContainer"));
434 gtkWidgetMap()->insert(widgetPath, protoLayout);
435 }
436 Q_ASSERT(protoLayout);
437
438 if (!gtk_widget_get_parent(widget) && !gtk_widget_is_toplevel(widget))
439 gtk_container_add((GtkContainer*)(protoLayout), widget);
440 gtk_widget_realize(widget);
441 }
442 }
443
removeWidgetFromMap(const QHashableLatin1Literal & path)444 void QGtkStylePrivate::removeWidgetFromMap(const QHashableLatin1Literal &path)
445 {
446 WidgetMap *map = gtkWidgetMap();
447 WidgetMap::iterator it = map->find(path);
448 if (it != map->end()) {
449 char* keyData = const_cast<char *>(it.key().data());
450 map->erase(it);
451 free(keyData);
452 }
453 }
454
addWidgetToMap(GtkWidget * widget)455 void QGtkStylePrivate::addWidgetToMap(GtkWidget *widget)
456 {
457 if (GTK_IS_WIDGET(widget)) {
458 gtk_widget_realize(widget);
459 QHashableLatin1Literal widgetPath = classPath(widget);
460
461 removeWidgetFromMap(widgetPath);
462 gtkWidgetMap()->insert(widgetPath, widget);
463 #ifdef DUMP_GTK_WIDGET_TREE
464 qWarning("Inserted Gtk Widget: %s", widgetPath.data());
465 #endif
466 }
467 }
468
addAllSubWidgets(GtkWidget * widget,gpointer v)469 void QGtkStylePrivate::addAllSubWidgets(GtkWidget *widget, gpointer v)
470 {
471 Q_UNUSED(v);
472 addWidgetToMap(widget);
473 if (G_TYPE_CHECK_INSTANCE_TYPE ((widget), gtk_container_get_type()))
474 gtk_container_forall((GtkContainer*)widget, addAllSubWidgets, NULL);
475 }
476
477 // Updates window/windowtext palette based on the indicated gtk widget
gtkWidgetPalette(const QHashableLatin1Literal & gtkWidgetName) const478 QPalette QGtkStylePrivate::gtkWidgetPalette(const QHashableLatin1Literal >kWidgetName) const
479 {
480 GtkWidget *gtkWidget = QGtkStylePrivate::gtkWidget(gtkWidgetName);
481 Q_ASSERT(gtkWidget);
482 QPalette pal = QApplication::palette();
483 GdkColor gdkBg = gtk_widget_get_style(gtkWidget)->bg[GTK_STATE_NORMAL];
484 GdkColor gdkText = gtk_widget_get_style(gtkWidget)->fg[GTK_STATE_NORMAL];
485 GdkColor gdkDisabledText = gtk_widget_get_style(gtkWidget)->fg[GTK_STATE_INSENSITIVE];
486 QColor bgColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8);
487 QColor textColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
488 QColor disabledTextColor(gdkDisabledText.red>>8, gdkDisabledText.green>>8, gdkDisabledText.blue>>8);
489 pal.setBrush(QPalette::Window, bgColor);
490 pal.setBrush(QPalette::Button, bgColor);
491 pal.setBrush(QPalette::All, QPalette::WindowText, textColor);
492 pal.setBrush(QPalette::Disabled, QPalette::WindowText, disabledTextColor);
493 pal.setBrush(QPalette::All, QPalette::ButtonText, textColor);
494 pal.setBrush(QPalette::Disabled, QPalette::ButtonText, disabledTextColor);
495 return pal;
496 }
497
498
updateTheme()499 void QGtkStyleUpdateScheduler::updateTheme()
500 {
501 static QString oldTheme(QLS("qt_not_set"));
502 QPixmapCache::clear();
503
504 QFont font = QGtkStylePrivate::getThemeFont();
505 if (QApplication::font() != font)
506 qApp->setFont(font);
507
508 if (oldTheme != QGtkStylePrivate::getThemeName()) {
509 oldTheme = QGtkStylePrivate::getThemeName();
510 QPalette newPalette = qApp->style()->standardPalette();
511 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
512 QApplicationPrivate::setSystemPalette(newPalette);
513 #endif
514 QApplication::setPalette(newPalette);
515 if (!QGtkStylePrivate::instances.isEmpty()) {
516 QGtkStylePrivate::instances.last()->initGtkWidgets();
517 QGtkStylePrivate::instances.last()->applyCustomPaletteHash();
518 }
519 QList<QWidget*> widgets = QApplication::allWidgets();
520 // Notify all widgets that size metrics might have changed
521 foreach (QWidget *widget, widgets) {
522 QEvent e(QEvent::StyleChange);
523 QApplication::sendEvent(widget, &e);
524 }
525 }
526 QIconLoader::instance()->updateSystemTheme();
527 }
528
addWidget(GtkWidget * widget)529 void QGtkStylePrivate::addWidget(GtkWidget *widget)
530 {
531 if (widget) {
532 setupGtkWidget(widget);
533 addAllSubWidgets(widget);
534 }
535 }
536
537
538 // Fetch the application font from the pango font description
539 // contained in the theme.
getThemeFont()540 QFont QGtkStylePrivate::getThemeFont()
541 {
542 QFont font;
543 GtkStyle *style = gtkStyle();
544 if (style && qApp->desktopSettingsAware())
545 {
546 PangoFontDescription *gtk_font = style->font_desc;
547 font.setPointSizeF((float)(pango_font_description_get_size(gtk_font))/PANGO_SCALE);
548
549 QString family = QString::fromLatin1(pango_font_description_get_family(gtk_font));
550 if (!family.isEmpty())
551 font.setFamily(family);
552
553 #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
554 const int weight = pango_font_description_get_weight(gtk_font);
555 font.setWeight(QPlatformFontDatabase::weightFromInteger(weight));
556 #else
557 int weight = pango_font_description_get_weight(gtk_font);
558 if (weight >= PANGO_WEIGHT_HEAVY)
559 font.setWeight(QFont::Black);
560 else if (weight >= PANGO_WEIGHT_BOLD)
561 font.setWeight(QFont::Bold);
562 else if (weight >= PANGO_WEIGHT_SEMIBOLD)
563 font.setWeight(QFont::DemiBold);
564 else if (weight >= PANGO_WEIGHT_NORMAL)
565 font.setWeight(QFont::Normal);
566 else
567 font.setWeight(QFont::Light);
568 #endif
569
570 PangoStyle fontstyle = pango_font_description_get_style(gtk_font);
571 if (fontstyle == PANGO_STYLE_ITALIC)
572 font.setStyle(QFont::StyleItalic);
573 else if (fontstyle == PANGO_STYLE_OBLIQUE)
574 font.setStyle(QFont::StyleOblique);
575 else
576 font.setStyle(QFont::StyleNormal);
577 }
578 return font;
579 }
580
operator ==(const QHashableLatin1Literal & l1,const QHashableLatin1Literal & l2)581 bool operator==(const QHashableLatin1Literal &l1, const QHashableLatin1Literal &l2)
582 {
583 return l1.size() == l2.size() || qstrcmp(l1.data(), l2.data()) == 0;
584 }
585
586 // copied from qHash.cpp
qHash(const QHashableLatin1Literal & key)587 uint qHash(const QHashableLatin1Literal &key)
588 {
589 int n = key.size();
590 const uchar *p = reinterpret_cast<const uchar *>(key.data());
591 uint h = 0;
592 uint g;
593
594 while (n--) {
595 h = (h << 4) + *p++;
596 if ((g = (h & 0xf0000000)) != 0)
597 h ^= g >> 23;
598 h &= ~g;
599 }
600 return h;
601 }
602
603 QT_END_NAMESPACE
604