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 #include "qgtkstyle_p.h"
34 
35 #include <private/qapplication_p.h>
36 #include <QtCore/QSettings>
37 #include <QtWidgets/QDialogButtonBox>
38 #include <QtWidgets/QStatusBar>
39 #include <QtWidgets/QLineEdit>
40 #include <QtWidgets/QWidget>
41 #include <QtWidgets/QListView>
42 #include <QtWidgets/QApplication>
43 #include <QtWidgets/QStyleOption>
44 #include <QtWidgets/QPushButton>
45 #include <QtGui/QPainter>
46 #include <QtWidgets/QMainWindow>
47 #include <QtWidgets/QToolBar>
48 #include <QtWidgets/QHeaderView>
49 #include <QtWidgets/QMenuBar>
50 #include <QtWidgets/QComboBox>
51 #include <QtWidgets/QSpinBox>
52 #include <QtWidgets/QScrollBar>
53 #include <QtWidgets/QAbstractButton>
54 #include <QtWidgets/QToolButton>
55 #include <QtWidgets/QGroupBox>
56 #include <QtWidgets/QRadioButton>
57 #include <QtWidgets/QCheckBox>
58 #include <QtWidgets/QTreeView>
59 #include <QtWidgets/QStyledItemDelegate>
60 #include <QtWidgets/QWizard>
61 
62 #include <qpixmapcache.h>
63 #include <private/qstyleanimation_p.h>
64 #undef signals // Collides with GTK stymbols
65 #include "qgtkpainter_p.h"
66 #include <private/qstylehelper_p.h>
67 #include "qgtkstyle_p_p.h"
68 
69 QT_BEGIN_NAMESPACE
70 
qt_gtk_state(const QStyleOption * option)71 static GtkStateType qt_gtk_state(const QStyleOption *option)
72 {
73     GtkStateType state = GTK_STATE_NORMAL;
74     if (!(option->state & QStyle::State_Enabled))
75         state = GTK_STATE_INSENSITIVE;
76     else if (option->state & QStyle::State_MouseOver)
77         state = GTK_STATE_PRELIGHT;
78 
79     return state;
80 }
81 
qt_gtk_get_icon(const char * iconName,GtkIconSize size=GTK_ICON_SIZE_BUTTON)82 static QPixmap qt_gtk_get_icon(const char* iconName, GtkIconSize size = GTK_ICON_SIZE_BUTTON)
83 {
84     GtkStyle *style = QGtkStylePrivate::gtkStyle();
85     GtkIconSet* iconSet  = gtk_icon_factory_lookup_default (iconName);
86     GdkPixbuf* icon = gtk_icon_set_render_icon(iconSet,
87                                                style,
88                                                GTK_TEXT_DIR_LTR,
89                                                GTK_STATE_NORMAL,
90                                                size,
91                                                NULL,
92                                                "button");
93     uchar* data = (uchar*)gdk_pixbuf_get_pixels(icon);
94     int width = gdk_pixbuf_get_width(icon);
95     int height = gdk_pixbuf_get_height(icon);
96     QImage converted(width, height, QImage::Format_ARGB32);
97     uchar* tdata = (uchar*)converted.bits();
98 
99     for ( int index = 0 ; index < height * width*4 ; index +=4 ) {
100         //int index = y * rowstride + x;
101         tdata[index + QT_RED] = data[index + GTK_RED];
102         tdata[index + QT_GREEN] = data[index + GTK_GREEN];
103         tdata[index + QT_BLUE] = data[index + GTK_BLUE];
104         tdata[index + QT_ALPHA] = data[index + GTK_ALPHA];
105     }
106 
107     g_object_unref(icon);
108 
109     // should we free iconset?
110     return QPixmap::fromImage(converted);
111 }
112 
qt_gtk_draw_mdibutton(QPainter * painter,const QStyleOptionTitleBar * option,const QRect & tmp,bool hover,bool sunken)113 static void qt_gtk_draw_mdibutton(QPainter *painter, const QStyleOptionTitleBar *option, const QRect &tmp, bool hover, bool sunken)
114 {
115     QColor dark;
116     dark.setHsv(option->palette.button().color().hue(),
117                 qMin(255, (int)(option->palette.button().color().saturation()*1.9)),
118                 qMin(255, (int)(option->palette.button().color().value()*0.7)));
119 
120     QColor highlight = option->palette.highlight().color();
121 
122     bool active = (option->titleBarState & QStyle::State_Active);
123     QColor titleBarHighlight(255, 255, 255, 60);
124 
125     if (sunken)
126         painter->fillRect(tmp.adjusted(1, 1, -1, -1), option->palette.highlight().color().darker(120));
127     else if (hover)
128         painter->fillRect(tmp.adjusted(1, 1, -1, -1), QColor(255, 255, 255, 20));
129 
130     QColor mdiButtonGradientStartColor;
131     QColor mdiButtonGradientStopColor;
132 
133     mdiButtonGradientStartColor = QColor(0, 0, 0, 40);
134     mdiButtonGradientStopColor = QColor(255, 255, 255, 60);
135 
136     if (sunken)
137         titleBarHighlight = highlight.darker(130);
138 
139     QLinearGradient gradient(tmp.center().x(), tmp.top(), tmp.center().x(), tmp.bottom());
140     gradient.setColorAt(0, mdiButtonGradientStartColor);
141     gradient.setColorAt(1, mdiButtonGradientStopColor);
142     QColor mdiButtonBorderColor(active ? option->palette.highlight().color().darker(180): dark.darker(110));
143 
144     painter->setPen(QPen(mdiButtonBorderColor, 1));
145     const QLine lines[4] = {
146         QLine(tmp.left() + 2, tmp.top(), tmp.right() - 2, tmp.top()),
147         QLine(tmp.left() + 2, tmp.bottom(), tmp.right() - 2, tmp.bottom()),
148         QLine(tmp.left(), tmp.top() + 2, tmp.left(), tmp.bottom() - 2),
149         QLine(tmp.right(), tmp.top() + 2, tmp.right(), tmp.bottom() - 2)
150     };
151     painter->drawLines(lines, 4);
152     const QPoint points[4] = {
153         QPoint(tmp.left() + 1, tmp.top() + 1),
154         QPoint(tmp.right() - 1, tmp.top() + 1),
155         QPoint(tmp.left() + 1, tmp.bottom() - 1),
156         QPoint(tmp.right() - 1, tmp.bottom() - 1)
157     };
158     painter->drawPoints(points, 4);
159 
160     painter->setPen(titleBarHighlight);
161     painter->drawLine(tmp.left() + 2, tmp.top() + 1, tmp.right() - 2, tmp.top() + 1);
162     painter->drawLine(tmp.left() + 1, tmp.top() + 2, tmp.left() + 1, tmp.bottom() - 2);
163 
164     painter->setPen(QPen(gradient, 1));
165     painter->drawLine(tmp.right() + 1, tmp.top() + 2, tmp.right() + 1, tmp.bottom() - 2);
166     painter->drawPoint(tmp.right() , tmp.top() + 1);
167 
168     painter->drawLine(tmp.left() + 2, tmp.bottom() + 1, tmp.right() - 2, tmp.bottom() + 1);
169     painter->drawPoint(tmp.left() + 1, tmp.bottom());
170     painter->drawPoint(tmp.right() - 1, tmp.bottom());
171     painter->drawPoint(tmp.right() , tmp.bottom() - 1);
172 }
173 
174 static const char * const dock_widget_close_xpm[] =
175     {
176         "11 13 5 1",
177         "  c None",
178         ". c #D5CFCB",
179         "+ c #6C6A67",
180         "@ c #6C6A67",
181         "$ c #B5B0AC",
182         "           ",
183         " @@@@@@@@@ ",
184         "@+       +@",
185         "@ +@   @+ @",
186         "@ @@@ @@@ @",
187         "@  @@@@@  @",
188         "@   @@@   @",
189         "@  @@@@@  @",
190         "@ @@@ @@@ @",
191         "@ +@   @+ @",
192         "@+       +@",
193         " @@@@@@@@@ ",
194         "           "
195     };
196 
197 static const char * const dock_widget_restore_xpm[] =
198     {
199         "11 13 5 1",
200         "  c None",
201         ". c #D5CFCB",
202         "+ c #6C6A67",
203         "@ c #6C6A67",
204         "# c #6C6A67",
205         "           ",
206         " @@@@@@@@@ ",
207         "@+       +@",
208         "@   #@@@# @",
209         "@   @   @ @",
210         "@ #@@@# @ @",
211         "@ @   @ @ @",
212         "@ @   @@@ @",
213         "@ @   @   @",
214         "@ #@@@@   @",
215         "@+       +@",
216         " @@@@@@@@@ ",
217         "           "
218     };
219 
220 static const char * const qt_titlebar_context_help[] = {
221     "10 10 3 1",
222     "  c None",
223     "# c #000000",
224     "+ c #444444",
225     "  +####+  ",
226     " ###  ### ",
227     " ##    ## ",
228     "     +##+ ",
229     "    +##   ",
230     "    ##    ",
231     "    ##    ",
232     "          ",
233     "    ##    ",
234     "    ##    "};
235 
236 static const char * const qt_scrollbar_button_arrow_up[] = {
237     "7 4 2 1",
238     "   c None",
239     "*  c #BFBFBF",
240     "   *   ",
241     "  ***  ",
242     " ***** ",
243     "*******"};
244 
245 static const char * const qt_scrollbar_button_arrow_down[] = {
246     "7 4 2 1",
247     "   c None",
248     "*  c #BFBFBF",
249     "*******",
250     " ***** ",
251     "  ***  ",
252     "   *   "};
253 
254 static const int groupBoxBottomMargin    =  2;  // space below the groupbox
255 static const int groupBoxTitleMargin     =  6;  // space between contents and title
256 static const int groupBoxTopMargin       =  2;
257 
mergedColors(const QColor & colorA,const QColor & colorB,int factor=50)258 static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50)
259 {
260     const int maxFactor = 100;
261     QColor tmp = colorA;
262     tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
263     tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
264     tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
265     return tmp;
266 }
267 
fromQColor(const QColor & color)268 static GdkColor fromQColor(const QColor &color)
269 {
270     GdkColor retval;
271     retval.pixel = 0;
272     retval.red = color.red() * 255;
273     retval.green = color.green() * 255;
274     retval.blue = color.blue() * 255;
275     return retval;
276 }
277 
278 /*!
279     \class QGtkStyle
280     \brief The QGtkStyle class provides a widget style rendered by GTK+
281     \since 4.5
282 
283     \internal
284     \inmodule QtWidgets
285 
286     The QGtkStyle style provides a look and feel that integrates well
287     into GTK-based desktop environments such as the XFCe and GNOME.
288 
289     It does this by making use of the GTK+ theme engine, ensuring
290     that Qt applications look and feel native on these platforms.
291 
292     Note: The style requires GTK+ version 2.18 or later.
293           The Qt3-based "Qt" GTK+ theme engine will not work with QGtkStyle.
294 
295     \sa QWindowsXPStyle, QMacStyle, QWindowsStyle, QFusionStyle
296 */
297 
298 /*!
299     Constructs a QGtkStyle object.
300 */
QGtkStyle()301 QGtkStyle::QGtkStyle()
302     : QCommonStyle(*new QGtkStylePrivate)
303 {
304     Q_D(QGtkStyle);
305     d->init();
306 }
307 
308 /*!
309     \internal
310 
311     Constructs a QGtkStyle object.
312 */
QGtkStyle(QGtkStylePrivate & dd)313 QGtkStyle::QGtkStyle(QGtkStylePrivate &dd)
314      : QCommonStyle(dd)
315 {
316     Q_D(QGtkStyle);
317     d->init();
318 }
319 
320 
321 /*!
322     Destroys the QGtkStyle object.
323 */
~QGtkStyle()324 QGtkStyle::~QGtkStyle()
325 {
326 }
327 
328 /*!
329     \reimp
330 */
standardPalette() const331 QPalette QGtkStyle::standardPalette() const
332 {
333     Q_D(const QGtkStyle);
334 
335     QPalette palette = QCommonStyle::standardPalette();
336     if (d->isThemeAvailable()) {
337         GtkStyle *style = d->gtkStyle();
338         GtkWidget *gtkButton = d->gtkWidget("GtkButton");
339         GtkWidget *gtkEntry = d->getTextColorWidget();
340         GdkColor gdkBg, gdkBase, gdkText, gdkForeground, gdkSbg, gdkSfg, gdkaSbg, gdkaSfg;
341         QColor bg, base, text, fg, highlight, highlightText, inactiveHighlight, inactiveHighlightedTExt;
342         gdkBg = style->bg[GTK_STATE_NORMAL];
343         gdkForeground = gtk_widget_get_style(gtkButton)->fg[GTK_STATE_NORMAL];
344 
345         // Our base and selected color is primarily used for text
346         // so we assume a gtkEntry will have the most correct value
347         GtkStyle *gtkEntryStyle = gtk_widget_get_style(gtkEntry);
348         gdkBase = gtkEntryStyle->base[GTK_STATE_NORMAL];
349         gdkText = gtkEntryStyle->text[GTK_STATE_NORMAL];
350         gdkSbg = gtkEntryStyle->base[GTK_STATE_SELECTED];
351         gdkSfg = gtkEntryStyle->text[GTK_STATE_SELECTED];
352 
353         // The ACTIVE base color is really used for inactive windows
354         gdkaSbg = gtkEntryStyle->base[GTK_STATE_ACTIVE];
355         gdkaSfg = gtkEntryStyle->text[GTK_STATE_ACTIVE];
356 
357         bg = QColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8);
358         text = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
359         fg = QColor(gdkForeground.red>>8, gdkForeground.green>>8, gdkForeground.blue>>8);
360         base = QColor(gdkBase.red>>8, gdkBase.green>>8, gdkBase.blue>>8);
361         highlight = QColor(gdkSbg.red>>8, gdkSbg.green>>8, gdkSbg.blue>>8);
362         highlightText = QColor(gdkSfg.red>>8, gdkSfg.green>>8, gdkSfg.blue>>8);
363         inactiveHighlight = QColor(gdkaSbg.red>>8, gdkaSbg.green>>8, gdkaSbg.blue>>8);
364         inactiveHighlightedTExt = QColor(gdkaSfg.red>>8, gdkaSfg.green>>8, gdkaSfg.blue>>8);
365 
366         palette.setColor(QPalette::HighlightedText, highlightText);
367 
368 
369         palette.setColor(QPalette::Light, bg.lighter(125));
370         palette.setColor(QPalette::Shadow, bg.darker(130));
371         palette.setColor(QPalette::Dark, bg.darker(120));
372         palette.setColor(QPalette::Text, text);
373         palette.setColor(QPalette::WindowText, fg);
374         palette.setColor(QPalette::ButtonText, fg);
375         palette.setColor(QPalette::Base, base);
376 
377         QColor alternateRowColor = palette.base().color().lighter(93); // ref gtkstyle.c draw_flat_box
378         GtkWidget *gtkTreeView = d->gtkWidget("GtkTreeView");
379         GdkColor *gtkAltBase = NULL;
380         gtk_widget_style_get(gtkTreeView, "odd-row-color", &gtkAltBase, NULL);
381         if (gtkAltBase) {
382             alternateRowColor = QColor(gtkAltBase->red>>8, gtkAltBase->green>>8, gtkAltBase->blue>>8);
383             gdk_color_free(gtkAltBase);
384         }
385         palette.setColor(QPalette::AlternateBase, alternateRowColor);
386 
387         palette.setColor(QPalette::Window, bg);
388         palette.setColor(QPalette::Button, bg);
389         palette.setColor(QPalette::Background, bg);
390         QColor disabled((fg.red()   + bg.red())  / 2,
391                         (fg.green() + bg.green())/ 2,
392                         (fg.blue()  + bg.blue()) / 2);
393         palette.setColor(QPalette::Disabled, QPalette::Text, disabled);
394         palette.setColor(QPalette::Disabled, QPalette::WindowText, disabled);
395         palette.setColor(QPalette::Disabled, QPalette::Foreground, disabled);
396         palette.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
397         palette.setColor(QPalette::Highlight, highlight);
398         // calculate disabled colors by removing saturation
399         highlight.setHsv(highlight.hue(), 0, highlight.value(), highlight.alpha());
400         highlightText.setHsv(highlightText.hue(), 0, highlightText.value(), highlightText.alpha());
401         palette.setColor(QPalette::Disabled, QPalette::Highlight, highlight);
402         palette.setColor(QPalette::Disabled, QPalette::HighlightedText, highlightText);
403 
404         palette.setColor(QPalette::Inactive, QPalette::HighlightedText, inactiveHighlightedTExt);
405         palette.setColor(QPalette::Inactive, QPalette::Highlight, inactiveHighlight);
406 
407         style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), "gtk-tooltips", "GtkWindow",
408                 gtk_window_get_type());
409         if (style) {
410             gdkText = style->fg[GTK_STATE_NORMAL];
411             text = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
412             palette.setColor(QPalette::ToolTipText, text);
413         }
414     }
415     return palette;
416 }
417 
418 /*!
419     \reimp
420 */
polish(QPalette & palette)421 void QGtkStyle::polish(QPalette &palette)
422 {
423     Q_D(QGtkStyle);
424 
425     if (!d->isThemeAvailable())
426         QCommonStyle::polish(palette);
427     else
428         palette = palette.resolve(standardPalette());
429 }
430 
431 /*!
432     \reimp
433 */
polish(QApplication * app)434 void QGtkStyle::polish(QApplication *app)
435 {
436     Q_D(QGtkStyle);
437 
438     QCommonStyle::polish(app);
439     // Custom fonts and palettes with QtConfig are intentionally
440     // not supported as these should be entirely determined by
441     // current Gtk settings
442     if (app->desktopSettingsAware() && d->isThemeAvailable()) {
443 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
444         QApplicationPrivate::setSystemPalette(standardPalette());
445 #else
446         QApplication::setPalette(standardPalette());
447 #endif
448         QApplicationPrivate::setSystemFont(d->getThemeFont());
449         d->applyCustomPaletteHash();
450         if (!d->isKDE4Session())
451             qApp->installEventFilter(&d->filter);
452     }
453 }
454 
455 /*!
456     \reimp
457 */
unpolish(QApplication * app)458 void QGtkStyle::unpolish(QApplication *app)
459 {
460     Q_D(QGtkStyle);
461 
462     QCommonStyle::unpolish(app);
463     QPixmapCache::clear();
464 
465     if (app->desktopSettingsAware() && d->isThemeAvailable() && !d->isKDE4Session())
466         qApp->removeEventFilter(&d->filter);
467 }
468 
469 /*!
470     \reimp
471 */
472 
polish(QWidget * widget)473 void QGtkStyle::polish(QWidget *widget)
474 {
475     Q_D(QGtkStyle);
476 
477     QCommonStyle::polish(widget);
478     if (!d->isThemeAvailable())
479         return;
480     if (qobject_cast<QAbstractButton*>(widget)
481             || qobject_cast<QToolButton*>(widget)
482             || qobject_cast<QComboBox*>(widget)
483             || qobject_cast<QGroupBox*>(widget)
484             || qobject_cast<QScrollBar*>(widget)
485             || qobject_cast<QSlider*>(widget)
486             || qobject_cast<QAbstractSpinBox*>(widget)
487             || qobject_cast<QSpinBox*>(widget)
488             || qobject_cast<QHeaderView*>(widget))
489         widget->setAttribute(Qt::WA_Hover);
490 #ifndef QT_NO_TREEVIEW
491     else if (QTreeView *tree = qobject_cast<QTreeView *> (widget))
492         tree->viewport()->setAttribute(Qt::WA_Hover);
493 #endif
494 }
495 
496 /*!
497     \reimp
498 */
unpolish(QWidget * widget)499 void QGtkStyle::unpolish(QWidget *widget)
500 {
501     QCommonStyle::unpolish(widget);
502 }
503 
504 /*!
505     \reimp
506 */
pixelMetric(PixelMetric metric,const QStyleOption * option,const QWidget * widget) const507 int QGtkStyle::pixelMetric(PixelMetric metric,
508                            const QStyleOption *option,
509                            const QWidget *widget) const
510 {
511     Q_D(const QGtkStyle);
512 
513     if (!d->isThemeAvailable())
514         return QCommonStyle::pixelMetric(metric, option, widget);
515 
516     switch (metric) {
517     case PM_DefaultFrameWidth:
518         if (qobject_cast<const QFrame*>(widget)) {
519             if (GtkStyle *style =
520                 gtk_rc_get_style_by_paths(gtk_settings_get_default(),
521                                                 "*.GtkScrolledWindow",
522                                                 "*.GtkScrolledWindow",
523                                                 gtk_window_get_type()))
524                 return qMax(style->xthickness, style->ythickness);
525         }
526         return 2;
527 
528     case PM_MenuButtonIndicator:
529         return 20;
530 
531     case PM_TabBarBaseOverlap:
532         return 1;
533 
534     case PM_ToolBarSeparatorExtent:
535         return 11;
536 
537     case PM_ToolBarFrameWidth:
538         return 1;
539 
540     case PM_ToolBarItemSpacing:
541         return 0;
542 
543     case PM_ButtonShiftHorizontal: {
544         GtkWidget *gtkButton = d->gtkWidget("GtkButton");
545         guint horizontal_shift;
546         gtk_widget_style_get(gtkButton, "child-displacement-x", &horizontal_shift, NULL);
547         return horizontal_shift;
548     }
549 
550     case PM_ButtonShiftVertical: {
551         GtkWidget *gtkButton = d->gtkWidget("GtkButton");
552         guint vertical_shift;
553         gtk_widget_style_get(gtkButton, "child-displacement-y", &vertical_shift, NULL);
554         return vertical_shift;
555     }
556 
557     case PM_MenuBarPanelWidth:
558         return 0;
559 
560     case PM_MenuPanelWidth: {
561         GtkWidget *gtkMenu = d->gtkWidget("GtkMenu");
562         guint horizontal_padding = 0;
563         // horizontal-padding is used by Maemo to get thicker borders
564         if (!gtk_check_version(2, 10, 0))
565             gtk_widget_style_get(gtkMenu, "horizontal-padding", &horizontal_padding, NULL);
566         int padding = qMax<int>(gtk_widget_get_style(gtkMenu)->xthickness, horizontal_padding);
567         return padding;
568     }
569 
570     case PM_ButtonIconSize: {
571         int retVal = 24;
572         GtkSettings *settings = gtk_settings_get_default();
573         gchararray icon_sizes;
574         g_object_get(settings, "gtk-icon-sizes", &icon_sizes, NULL);
575         QStringList values = QString(QLS(icon_sizes)).split(QLatin1Char(':'));
576         g_free(icon_sizes);
577         QChar splitChar(QLatin1Char(','));
578         foreach (const QString &value, values) {
579             if (value.startsWith(QLS("gtk-button="))) {
580                 QString iconSize = value.right(value.size() - 11);
581 
582                 if (iconSize.contains(splitChar))
583                     retVal = iconSize.split(splitChar)[0].toInt();
584                 break;
585             }
586         }
587         return retVal;
588     }
589 
590     case PM_MenuVMargin:
591 
592     case PM_MenuHMargin:
593         return 0;
594 
595     case PM_DockWidgetTitleMargin:
596         return 0;
597 
598     case PM_DockWidgetTitleBarButtonMargin:
599         return 5;
600 
601     case PM_TabBarTabVSpace:
602         return 12;
603 
604     case PM_TabBarTabHSpace:
605         return 14;
606 
607     case PM_TabBarTabShiftVertical:
608         return 2;
609 
610     case PM_ToolBarHandleExtent:
611         return 9;
612 
613     case PM_SplitterWidth:
614         return 6;
615 
616     case PM_SliderThickness:
617     case PM_SliderControlThickness: {
618         GtkWidget *gtkScale = d->gtkWidget("GtkHScale");
619         gint val;
620         gtk_widget_style_get(gtkScale, "slider-width", &val, NULL);
621         if (metric == PM_SliderControlThickness)
622             return val + 2*gtk_widget_get_style(gtkScale)->ythickness;
623         return val;
624     }
625 
626     case PM_ScrollBarExtent: {
627         gint sliderLength;
628         gint trough_border;
629         GtkWidget *hScrollbar = d->gtkWidget("GtkHScrollbar");
630         gtk_widget_style_get(hScrollbar,
631                              "trough-border",   &trough_border,
632                              "slider-width",    &sliderLength,
633                              NULL);
634         return sliderLength + trough_border*2;
635     }
636 
637     case PM_ScrollBarSliderMin:
638         return 34;
639 
640     case PM_SliderLength:
641         gint val;
642         gtk_widget_style_get(d->gtkWidget("GtkHScale"), "slider-length", &val, NULL);
643         return val;
644 
645     case PM_ExclusiveIndicatorWidth:
646     case PM_ExclusiveIndicatorHeight:
647     case PM_IndicatorWidth:
648     case PM_IndicatorHeight: {
649         GtkWidget *gtkCheckButton = d->gtkWidget("GtkCheckButton");
650         gint size, spacing;
651         gtk_widget_style_get(gtkCheckButton, "indicator-spacing", &spacing, "indicator-size", &size, NULL);
652         return size + 2 * spacing;
653     }
654 
655     case PM_MenuBarVMargin: {
656         GtkWidget *gtkMenubar = d->gtkWidget("GtkMenuBar");
657         return  qMax(0, gtk_widget_get_style(gtkMenubar)->ythickness);
658     }
659     case PM_ScrollView_ScrollBarSpacing:
660     {
661         gint spacing = 3;
662         GtkWidget *gtkScrollWindow = d->gtkWidget("GtkScrolledWindow");
663         Q_ASSERT(gtkScrollWindow);
664         gtk_widget_style_get(gtkScrollWindow, "scrollbar-spacing", &spacing, NULL);
665         return spacing;
666     }
667     case PM_SubMenuOverlap: {
668         gint offset = 0;
669         GtkWidget *gtkMenu = d->gtkWidget("GtkMenu");
670         gtk_widget_style_get(gtkMenu, "horizontal-offset", &offset, NULL);
671         return offset;
672     }
673     case PM_ToolTipLabelFrameWidth:
674         return 2;
675     case PM_ButtonDefaultIndicator:
676         return 0;
677     case PM_ListViewIconSize:
678         return 24;
679     case PM_DialogButtonsSeparator:
680         return 6;
681     case PM_TitleBarHeight:
682         return 24;
683     case PM_SpinBoxFrameWidth:
684         return 3;
685     case PM_MenuBarItemSpacing:
686         return 6;
687     case PM_MenuBarHMargin:
688         return 0;
689     case PM_ToolBarItemMargin:
690         return 1;
691     case PM_SmallIconSize:
692         return 16;
693     case PM_MaximumDragDistance:
694         return -1;
695     case PM_TabCloseIndicatorWidth:
696     case PM_TabCloseIndicatorHeight:
697         return 20;
698     default:
699         return QCommonStyle::pixelMetric(metric, option, widget);
700     }
701 }
702 
703 /*!
704     \reimp
705 */
styleHint(StyleHint hint,const QStyleOption * option,const QWidget * widget,QStyleHintReturn * returnData=0) const706 int QGtkStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
707 
708                          QStyleHintReturn *returnData = 0) const
709 {
710     Q_D(const QGtkStyle);
711 
712     if (!d->isThemeAvailable())
713         return QCommonStyle::styleHint(hint, option, widget, returnData);
714 
715     switch (hint) {
716     case SH_ItemView_ChangeHighlightOnFocus:
717         return true;
718     case SH_ScrollBar_MiddleClickAbsolutePosition:
719         return true;
720     case SH_Menu_AllowActiveAndDisabled:
721         return false;
722     case SH_MainWindow_SpaceBelowMenuBar:
723         return false;
724     case SH_MenuBar_MouseTracking:
725         return true;
726     case SH_Menu_MouseTracking:
727         return true;
728     case SH_TitleBar_AutoRaise:
729         return true;
730     case SH_TitleBar_NoBorder:
731         return true;
732     case SH_ItemView_ShowDecorationSelected:
733         return true;
734     case SH_Table_GridLineColor:
735         if (option)
736             return option->palette.background().color().darker(120).rgb();
737         break;
738     case SH_WindowFrame_Mask:
739         if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData)) {
740             //left rounded corner
741             mask->region = option->rect;
742             mask->region -= QRect(option->rect.left(), option->rect.top(), 5, 1);
743             mask->region -= QRect(option->rect.left(), option->rect.top() + 1, 3, 1);
744             mask->region -= QRect(option->rect.left(), option->rect.top() + 2, 2, 1);
745             mask->region -= QRect(option->rect.left(), option->rect.top() + 3, 1, 2);
746 
747             //right rounded corner
748             mask->region -= QRect(option->rect.right() - 4, option->rect.top(), 5, 1);
749             mask->region -= QRect(option->rect.right() - 2, option->rect.top() + 1, 3, 1);
750             mask->region -= QRect(option->rect.right() - 1, option->rect.top() + 2, 2, 1);
751             mask->region -= QRect(option->rect.right() , option->rect.top() + 3, 1, 2);
752         }
753         return QCommonStyle::styleHint(hint, option, widget, returnData);
754     case SH_MessageBox_TextInteractionFlags:
755         return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse;
756     case SH_MessageBox_CenterButtons:
757         return false;
758 #ifndef QT_NO_WIZARD
759     case SH_WizardStyle:
760         return  QWizard::ClassicStyle;
761 #endif
762     case SH_ItemView_ArrowKeysNavigateIntoChildren:
763         return false;
764     case SH_DialogButtonLayout: {
765         int ret = QDialogButtonBox::GnomeLayout;
766         gboolean alternateOrder = 0;
767         GtkSettings *settings = gtk_settings_get_default();
768         g_object_get(settings, "gtk-alternative-button-order", &alternateOrder, NULL);
769 
770         if (alternateOrder)
771             ret = QDialogButtonBox::WinLayout;
772 
773         return ret;
774     }
775     break;
776 
777     case SH_ToolButtonStyle:
778     {
779         if (d->isKDE4Session())
780             return QCommonStyle::styleHint(hint, option, widget, returnData);
781         GtkWidget *gtkToolbar = d->gtkWidget("GtkToolbar");
782         GtkToolbarStyle toolbar_style = GTK_TOOLBAR_ICONS;
783         g_object_get(gtkToolbar, "toolbar-style", &toolbar_style, NULL);
784         switch (toolbar_style) {
785         case GTK_TOOLBAR_TEXT:
786             return Qt::ToolButtonTextOnly;
787         case GTK_TOOLBAR_BOTH:
788             return Qt::ToolButtonTextUnderIcon;
789         case GTK_TOOLBAR_BOTH_HORIZ:
790             return Qt::ToolButtonTextBesideIcon;
791         case GTK_TOOLBAR_ICONS:
792         default:
793             return Qt::ToolButtonIconOnly;
794         }
795     }
796     break;
797     case SH_SpinControls_DisableOnBounds:
798         return int(true);
799 
800     case SH_DitherDisabledText:
801         return int(false);
802 
803     case SH_ComboBox_Popup: {
804         GtkWidget *gtkComboBox = d->gtkWidget("GtkComboBox");
805         gboolean appears_as_list;
806         gtk_widget_style_get((GtkWidget*)gtkComboBox, "appears-as-list", &appears_as_list, NULL);
807         return appears_as_list ? 0 : 1;
808     }
809 
810     case SH_MenuBar_AltKeyNavigation:
811         return int(false);
812 
813     case SH_EtchDisabledText:
814         return int(false);
815 
816     case SH_Menu_SubMenuPopupDelay: {
817         gint delay = 225;
818         GtkSettings *settings = gtk_settings_get_default();
819         g_object_get(settings, "gtk-menu-popup-delay", &delay, NULL);
820         return delay;
821     }
822 
823     case SH_ScrollView_FrameOnlyAroundContents: {
824         gboolean scrollbars_within_bevel = false;
825         if (widget && widget->isWindow())
826             scrollbars_within_bevel = true;
827         else if (!gtk_check_version(2, 12, 0)) {
828             GtkWidget *gtkScrollWindow = d->gtkWidget("GtkScrolledWindow");
829             gtk_widget_style_get(gtkScrollWindow, "scrollbars-within-bevel", &scrollbars_within_bevel, NULL);
830         }
831         return !scrollbars_within_bevel;
832     }
833 
834     case SH_DialogButtonBox_ButtonsHaveIcons: {
835         gboolean buttonsHaveIcons = true;
836         GtkSettings *settings = gtk_settings_get_default();
837         g_object_get(settings, "gtk-button-images", &buttonsHaveIcons, NULL);
838         return buttonsHaveIcons;
839     }
840 
841     case SH_UnderlineShortcut: {
842         gboolean underlineShortcut = true;
843         if (!gtk_check_version(2, 12, 0)) {
844             GtkSettings *settings = gtk_settings_get_default();
845             g_object_get(settings, "gtk-enable-mnemonics", &underlineShortcut, NULL);
846         }
847         return underlineShortcut;
848     }
849 
850     default:
851         break;
852     }
853     return QCommonStyle::styleHint(hint, option, widget, returnData);
854 }
855 
856 /*!
857     \reimp
858 */
drawPrimitive(PrimitiveElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const859 void QGtkStyle::drawPrimitive(PrimitiveElement element,
860                               const QStyleOption *option,
861                               QPainter *painter,
862                               const QWidget *widget) const
863 {
864     Q_D(const QGtkStyle);
865 
866     if (!d->isThemeAvailable()) {
867         QCommonStyle::drawPrimitive(element, option, painter, widget);
868         return;
869     }
870 
871     GtkStyle* style = d->gtkStyle();
872     QGtkPainter* gtkPainter = d->gtkPainter(painter);
873 
874     switch (element) {
875       case PE_Frame: {
876         if (widget && widget->inherits("QComboBoxPrivateContainer")){
877             QStyleOption copy = *option;
878             copy.state |= State_Raised;
879             proxy()->drawPrimitive(PE_PanelMenu, &copy, painter, widget);
880             break;
881         }
882         // Drawing the entire itemview frame is very expensive, especially on the native X11 engine
883         // Instead we cheat a bit and draw a border image without the center part, hence only scaling
884         // thin rectangular images
885         const int pmSize = 64;
886         const int border = proxy()->pixelMetric(PM_DefaultFrameWidth, option, widget);
887         const QString pmKey = QLatin1String("windowframe") % HexString<uint>(option->state);
888 
889         QPixmap pixmap;
890         QRect pmRect(QPoint(0,0), QSize(pmSize, pmSize));
891 
892         // Only draw through style once
893         if (!QPixmapCache::find(pmKey, pixmap)) {
894             pixmap = QPixmap(pmSize, pmSize);
895             pixmap.fill(Qt::transparent);
896             QPainter pmPainter(&pixmap);
897             gtkPainter->reset(&pmPainter);
898             gtkPainter->setUsePixmapCache(false); // Don't cache twice
899 
900             GtkShadowType shadow_type = GTK_SHADOW_NONE;
901             if (option->state & State_Sunken)
902                 shadow_type = GTK_SHADOW_IN;
903             else if (option->state & State_Raised)
904                 shadow_type = GTK_SHADOW_OUT;
905 
906             GtkStyle *style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
907                                      "*.GtkScrolledWindow", "*.GtkScrolledWindow", gtk_window_get_type());
908             if (style)
909                 gtkPainter->paintShadow(d->gtkWidget("GtkFrame"), "viewport", pmRect,
910                                         option->state & State_Enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE,
911                                         shadow_type, style);
912             QPixmapCache::insert(pmKey, pixmap);
913             gtkPainter->reset(painter);
914         }
915 
916         QRect rect = option->rect;
917         const int rw = rect.width() - border;
918         const int rh = rect.height() - border;
919         const int pw = pmRect.width() - border;
920         const int ph = pmRect.height() - border;
921 
922         // Sidelines
923         painter->drawPixmap(rect.adjusted(border, 0, -border, -rh), pixmap, pmRect.adjusted(border, 0, -border,-ph));
924         painter->drawPixmap(rect.adjusted(border, rh, -border, 0), pixmap, pmRect.adjusted(border, ph,-border,0));
925         painter->drawPixmap(rect.adjusted(0, border, -rw, -border), pixmap, pmRect.adjusted(0, border, -pw, -border));
926         painter->drawPixmap(rect.adjusted(rw, border, 0, -border), pixmap, pmRect.adjusted(pw, border, 0, -border));
927 
928         // Corners
929         painter->drawPixmap(rect.adjusted(0, 0, -rw, -rh), pixmap, pmRect.adjusted(0, 0, -pw,-ph));
930         painter->drawPixmap(rect.adjusted(rw, 0, 0, -rh), pixmap, pmRect.adjusted(pw, 0, 0,-ph));
931         painter->drawPixmap(rect.adjusted(0, rh, -rw, 0), pixmap, pmRect.adjusted(0, ph, -pw,0));
932         painter->drawPixmap(rect.adjusted(rw, rh, 0, 0), pixmap, pmRect.adjusted(pw, ph, 0,0));
933     }
934     break;
935     case PE_FrameWindow:
936         painter->save();
937         {
938             QRect rect= option->rect;
939             painter->setPen(QPen(option->palette.dark().color().darker(150), 0));
940             painter->drawRect(option->rect.adjusted(0, 0, -1, -1));
941             painter->setPen(QPen(option->palette.light(), 0));
942             painter->drawLine(QPoint(rect.left() + 1, rect.top() + 1),
943                               QPoint(rect.left() + 1, rect.bottom() - 1));
944             painter->setPen(QPen(option->palette.background().color().darker(120), 0));
945             painter->drawLine(QPoint(rect.left() + 1, rect.bottom() - 1),
946                               QPoint(rect.right() - 2, rect.bottom() - 1));
947             painter->drawLine(QPoint(rect.right() - 1, rect.top() + 1),
948                               QPoint(rect.right() - 1, rect.bottom() - 1));
949         }
950         painter->restore();
951         break;
952 
953     case PE_PanelTipLabel: {
954         GtkWidget *gtkWindow = d->gtkWidget("GtkWindow"); // The Murrine Engine currently assumes a widget is passed
955         style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), "gtk-tooltips", "GtkWindow",
956                 gtk_window_get_type());
957         gtkPainter->paintFlatBox(gtkWindow, "tooltip", option->rect, GTK_STATE_NORMAL, GTK_SHADOW_NONE, style);
958     }
959     break;
960 
961     case PE_PanelStatusBar: {
962         if (widget && widget->testAttribute(Qt::WA_SetPalette) &&
963             option->palette.resolve() & (1 << QPalette::Window)) {
964             // Respect custom palette
965             painter->fillRect(option->rect, option->palette.window());
966             break;
967         }
968         GtkShadowType shadow_type;
969         GtkWidget *gtkStatusbarFrame = d->gtkWidget("GtkStatusbar.GtkFrame");
970         gtk_widget_style_get(gtk_widget_get_parent(gtkStatusbarFrame), "shadow-type", &shadow_type, NULL);
971         gtkPainter->paintShadow(gtkStatusbarFrame, "frame", option->rect, GTK_STATE_NORMAL,
972                                 shadow_type, gtk_widget_get_style(gtkStatusbarFrame));
973     }
974     break;
975 
976     case PE_IndicatorHeaderArrow:
977         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
978             GtkWidget *gtkTreeHeader = d->gtkWidget("GtkTreeView.GtkButton");
979             GtkStateType state = qt_gtk_state(option);
980             style = gtk_widget_get_style(gtkTreeHeader);
981             GtkArrowType type = GTK_ARROW_UP;
982             // This sorting indicator inversion is intentional, and follows the GNOME HIG.
983             // See http://library.gnome.org/devel/hig-book/stable/controls-lists.html.en#controls-lists-sortable
984             if (header->sortIndicator & QStyleOptionHeader::SortUp)
985                 type = GTK_ARROW_UP;
986             else if (header->sortIndicator & QStyleOptionHeader::SortDown)
987                 type = GTK_ARROW_DOWN;
988 
989             gtkPainter->paintArrow(gtkTreeHeader, "button", option->rect.adjusted(1, 1, -1, -1), type, state,
990                                    GTK_SHADOW_NONE, false, style);
991         }
992         break;
993 
994     case PE_FrameDefaultButton: // fall through
995     case PE_FrameFocusRect: {
996             QRect frameRect = option->rect.adjusted(1, 1, -2, -2); // ### this mess should move to subcontrolrect
997             if (qobject_cast<const QAbstractItemView*>(widget)) {
998                 // Don't draw anything
999             } else if (qobject_cast<const QTabBar*>(widget)) {
1000                 GtkWidget *gtkNotebook = d->gtkWidget("GtkNotebook");
1001                 style = gtk_widget_get_style(gtkNotebook);
1002                 gtkPainter->paintFocus(gtkNotebook, "tab", frameRect.adjusted(-1, 1, 1, 1), GTK_STATE_ACTIVE, style);
1003             } else {
1004                 GtkWidget *gtkRadioButton = d->gtkWidget("GtkRadioButton");
1005                 gtkPainter->paintFocus(gtkRadioButton, "radiobutton", frameRect, GTK_STATE_ACTIVE, style);
1006             }
1007         }
1008         break;
1009 
1010     case PE_IndicatorBranch:
1011         if (option->state & State_Children) {
1012             QRect rect = option->rect;
1013             rect = QRect(0, 0, 12, 12);
1014             rect.moveCenter(option->rect.center());
1015             rect.translate(2, 0);
1016             GtkExpanderStyle openState = GTK_EXPANDER_EXPANDED;
1017             GtkExpanderStyle closedState = GTK_EXPANDER_COLLAPSED;
1018             GtkWidget *gtkTreeView = d->gtkWidget("GtkTreeView");
1019 
1020             GtkStateType state = GTK_STATE_NORMAL;
1021             if (!(option->state & State_Enabled))
1022                 state = GTK_STATE_INSENSITIVE;
1023             else if (option->state & State_MouseOver)
1024                 state = GTK_STATE_PRELIGHT;
1025 
1026             gtkPainter->paintExpander(gtkTreeView, "treeview", rect, state,
1027                                       option->state & State_Open ? openState : closedState , gtk_widget_get_style(gtkTreeView));
1028         }
1029         break;
1030 
1031     case PE_PanelItemViewRow:
1032         // This primitive is only used to draw selection behind selected expander arrows.
1033         // We try not to decorate the tree branch background unless you inherit from StyledItemDelegate
1034         // The reason for this is that a lot of code that relies on custom item delegates will look odd having
1035         // a gradient on the branch but a flat shaded color on the item itself.
1036         QCommonStyle::drawPrimitive(element, option, painter, widget);
1037         if (!(option->state & State_Selected)) {
1038             break;
1039         } else {
1040             if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView*>(widget)) {
1041                 if (!qobject_cast<QStyledItemDelegate*>(view->itemDelegate()))
1042                     break;
1043             }
1044         } // fall through
1045 
1046     case PE_PanelItemViewItem:
1047         if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
1048             uint resolve_mask = vopt->palette.resolve();
1049             if (vopt->backgroundBrush.style() != Qt::NoBrush
1050                     || (resolve_mask & (1 << QPalette::Base)))
1051             {
1052                 QPointF oldBO = painter->brushOrigin();
1053                 painter->setBrushOrigin(vopt->rect.topLeft());
1054                 painter->fillRect(vopt->rect, vopt->backgroundBrush);
1055                 painter->setBrushOrigin(oldBO);
1056                 if (!(option->state & State_Selected))
1057                     break;
1058             }
1059             if (GtkWidget *gtkTreeView = d->gtkWidget("GtkTreeView")) {
1060                 const char *detail = "cell_even_ruled";
1061                 if (vopt && vopt->features & QStyleOptionViewItem::Alternate)
1062                     detail = "cell_odd_ruled";
1063                 bool isActive = option->state & State_Active;
1064                 QString key;
1065                 if (isActive ) {
1066                     // Required for active/non-active window appearance
1067                     key = QLS("a");
1068                     QGtkStylePrivate::gtkWidgetSetFocus(gtkTreeView, true);
1069                 }
1070                 bool isEnabled = (widget ? widget->isEnabled() : (vopt->state & QStyle::State_Enabled));
1071                 gtkPainter->paintFlatBox(gtkTreeView, detail, option->rect,
1072                                          option->state & State_Selected ? GTK_STATE_SELECTED :
1073                                          isEnabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE,
1074                                          GTK_SHADOW_OUT, gtk_widget_get_style(gtkTreeView), key);
1075                 if (isActive )
1076                     QGtkStylePrivate::gtkWidgetSetFocus(gtkTreeView, false);
1077             }
1078         }
1079         break;
1080     case PE_IndicatorToolBarSeparator:
1081         {
1082             const int margin = 6;
1083             GtkWidget *gtkSeparator = d->gtkWidget("GtkToolbar.GtkSeparatorToolItem");
1084             if (option->state & State_Horizontal) {
1085                 const int offset = option->rect.width()/2;
1086                 QRect rect = option->rect.adjusted(offset, margin, 0, -margin);
1087                 painter->setPen(QPen(option->palette.background().color().darker(110)));
1088                 gtkPainter->paintVline(gtkSeparator, "vseparator",
1089                                        rect, GTK_STATE_NORMAL, gtk_widget_get_style(gtkSeparator),
1090                                        0, rect.height(), 0);
1091             } else { //Draw vertical separator
1092                 const int offset = option->rect.height()/2;
1093                 QRect rect = option->rect.adjusted(margin, offset, -margin, 0);
1094                 painter->setPen(QPen(option->palette.background().color().darker(110)));
1095                 gtkPainter->paintHline(gtkSeparator, "hseparator",
1096                                        rect, GTK_STATE_NORMAL, gtk_widget_get_style(gtkSeparator),
1097                                        0, rect.width(), 0);
1098             }
1099        }
1100        break;
1101 
1102     case PE_IndicatorToolBarHandle: {
1103         GtkWidget *gtkToolbar = d->gtkWidget("GtkToolbar");
1104         GtkShadowType shadow_type;
1105         gtk_widget_style_get(gtkToolbar, "shadow-type", &shadow_type, NULL);
1106         //Note when the toolbar is horizontal, the handle is vertical
1107         painter->setClipRect(option->rect);
1108         gtkPainter->paintHandle(gtkToolbar, "toolbar", option->rect.adjusted(-1, -1 ,0 ,1),
1109                                 GTK_STATE_NORMAL, shadow_type, !(option->state & State_Horizontal) ?
1110                                 GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL, gtk_widget_get_style(gtkToolbar));
1111     }
1112     break;
1113 
1114     case PE_IndicatorArrowUp:
1115     case PE_IndicatorArrowDown:
1116     case PE_IndicatorArrowLeft:
1117     case PE_IndicatorArrowRight: {
1118 
1119 
1120         GtkArrowType type = GTK_ARROW_UP;
1121 
1122         switch (element) {
1123 
1124         case PE_IndicatorArrowDown:
1125             type = GTK_ARROW_DOWN;
1126             break;
1127 
1128         case PE_IndicatorArrowLeft:
1129             type = GTK_ARROW_LEFT;
1130             break;
1131 
1132         case PE_IndicatorArrowRight:
1133             type = GTK_ARROW_RIGHT;
1134             break;
1135 
1136         default:
1137             break;
1138         }
1139         int size = qMin(option->rect.height(), option->rect.width());
1140         int border = (size > 9) ? (size/4) : 0; //Allow small arrows to have exact dimensions
1141         int bsx = 0, bsy = 0;
1142         if (option->state & State_Sunken) {
1143             bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal);
1144             bsy = proxy()->pixelMetric(PM_ButtonShiftVertical);
1145         }
1146         QRect arrowRect = option->rect.adjusted(border + bsx, border + bsy, -border + bsx, -border + bsy);
1147         GtkShadowType shadow = option->state & State_Sunken ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
1148         GtkStateType state = qt_gtk_state(option);
1149 
1150         QColor arrowColor = option->palette.buttonText().color();
1151         GtkWidget *gtkArrow = d->gtkWidget("GtkArrow");
1152         GdkColor color = fromQColor(arrowColor);
1153         gtk_widget_modify_fg (gtkArrow, state, &color);
1154         gtkPainter->paintArrow(gtkArrow, "button", arrowRect,
1155                                type, state, shadow, false, gtk_widget_get_style(gtkArrow),
1156                                QString::number(arrowColor.rgba(), 16));
1157         // Passing NULL will revert the color change
1158         gtk_widget_modify_fg (gtkArrow, state, NULL);
1159     }
1160     break;
1161 
1162     case PE_FrameGroupBox:
1163         // Do nothing here, the GNOME groupboxes are flat
1164         break;
1165 
1166     case PE_PanelMenu: {
1167             GtkWidget *gtkMenu = d->gtkWidget("GtkMenu");
1168             gtkPainter->setAlphaSupport(false); // Note, alpha disabled for performance reasons
1169             gtkPainter->paintBox(gtkMenu, "menu", option->rect, GTK_STATE_NORMAL, GTK_SHADOW_OUT, gtk_widget_get_style(gtkMenu), QString());
1170         }
1171         break;
1172 
1173     case PE_FrameMenu:
1174         //This is actually done by PE_Widget due to a clipping issue
1175         //Otherwise Menu items will not be able to span the entire menu width
1176 
1177         // This is only used by floating tool bars
1178         if (qobject_cast<const QToolBar *>(widget)) {
1179             GtkWidget *gtkMenubar = d->gtkWidget("GtkMenuBar");
1180             gtkPainter->paintBox(gtkMenubar, "toolbar", option->rect,
1181                                  GTK_STATE_NORMAL, GTK_SHADOW_OUT, style);
1182             gtkPainter->paintBox(gtkMenubar, "menu", option->rect,
1183                                  GTK_STATE_NORMAL, GTK_SHADOW_OUT, style);
1184         }
1185         break;
1186 
1187     case PE_FrameLineEdit: {
1188         GtkWidget *gtkEntry = d->gtkWidget("GtkEntry");
1189 
1190 
1191         gboolean interior_focus;
1192         gint focus_line_width;
1193         QRect rect = option->rect;
1194         gtk_widget_style_get(gtkEntry,
1195                              "interior-focus", &interior_focus,
1196                              "focus-line-width", &focus_line_width, NULL);
1197 
1198         // See https://bugzilla.mozilla.org/show_bug.cgi?id=405421 for info about this hack
1199         g_object_set_data(G_OBJECT(gtkEntry), "transparent-bg-hint", GINT_TO_POINTER(true));
1200 
1201         if (!interior_focus && option->state & State_HasFocus)
1202             rect.adjust(focus_line_width, focus_line_width, -focus_line_width, -focus_line_width);
1203 
1204         if (option->state & State_HasFocus)
1205             QGtkStylePrivate::gtkWidgetSetFocus(gtkEntry, true);
1206         gtkPainter->paintShadow(gtkEntry, "entry", rect, option->state & State_Enabled ?
1207                                 GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE,
1208                                 GTK_SHADOW_IN, gtk_widget_get_style(gtkEntry),
1209                                 option->state & State_HasFocus ? QLS("focus") : QString());
1210         if (!interior_focus && option->state & State_HasFocus)
1211             gtkPainter->paintShadow(gtkEntry, "entry", option->rect, option->state & State_Enabled ?
1212                                     GTK_STATE_ACTIVE : GTK_STATE_INSENSITIVE,
1213                                     GTK_SHADOW_IN, gtk_widget_get_style(gtkEntry), QLS("GtkEntryShadowIn"));
1214 
1215         if (option->state & State_HasFocus)
1216             QGtkStylePrivate::gtkWidgetSetFocus(gtkEntry, false);
1217     }
1218     break;
1219 
1220     case PE_PanelLineEdit:
1221         if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
1222             GtkWidget *gtkEntry = d->gtkWidget("GtkEntry");
1223             if (panel->lineWidth > 0)
1224                 proxy()->drawPrimitive(PE_FrameLineEdit, option, painter, widget);
1225             uint resolve_mask = option->palette.resolve();
1226             GtkStyle *gtkEntryStyle = gtk_widget_get_style(gtkEntry);
1227             QRect textRect = option->rect.adjusted(gtkEntryStyle->xthickness, gtkEntryStyle->ythickness,
1228                                                    -gtkEntryStyle->xthickness, -gtkEntryStyle->ythickness);
1229 
1230             if (widget && widget->testAttribute(Qt::WA_SetPalette) &&
1231                 resolve_mask & (1 << QPalette::Base)) // Palette overridden by user
1232                 painter->fillRect(textRect, option->palette.base());
1233             else
1234                 gtkPainter->paintFlatBox(gtkEntry, "entry_bg", textRect,
1235                                          option->state & State_Enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE, GTK_SHADOW_NONE, gtkEntryStyle);
1236         }
1237         break;
1238 
1239     case PE_FrameTabWidget:
1240         if (const QStyleOptionTabWidgetFrame *frame = qstyleoption_cast<const QStyleOptionTabWidgetFrame*>(option)) {
1241             GtkWidget *gtkNotebook = d->gtkWidget("GtkNotebook");
1242             style = gtk_widget_get_style(gtkNotebook);
1243             gtkPainter->setAlphaSupport(false);
1244             GtkShadowType shadow = GTK_SHADOW_OUT;
1245             GtkStateType state = GTK_STATE_NORMAL; // Only state supported by gtknotebook
1246             bool reverse = (option->direction == Qt::RightToLeft);
1247             gtk_widget_set_direction(gtkNotebook, reverse ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
1248 
1249             GtkPositionType frameType = GTK_POS_TOP;
1250             QTabBar::Shape shape = frame->shape;
1251             int gapStart = 0;
1252             int gapSize = 0;
1253             if (shape == QTabBar::RoundedNorth || shape == QTabBar::RoundedSouth) {
1254                 frameType = (shape == QTabBar::RoundedNorth) ? GTK_POS_TOP : GTK_POS_BOTTOM;
1255                 gapStart = frame->selectedTabRect.left();
1256                 gapSize = frame->selectedTabRect.width();
1257             } else {
1258                 frameType = (shape == QTabBar::RoundedWest) ? GTK_POS_LEFT : GTK_POS_RIGHT;
1259                 gapStart = frame->selectedTabRect.y();
1260                 gapSize = frame->selectedTabRect.height();
1261             }
1262             gtkPainter->paintBoxGap(gtkNotebook, "notebook", option->rect, state, shadow, frameType,
1263                                     gapStart, gapSize, style);
1264         }
1265         break;
1266 
1267     case PE_PanelButtonCommand:
1268     case PE_PanelButtonTool: {
1269         bool isDefault = false;
1270         bool isTool = (element == PE_PanelButtonTool);
1271         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton*>(option))
1272             isDefault = btn->features & QStyleOptionButton::DefaultButton;
1273 
1274         // don't draw a frame for tool buttons that have the autoRaise flag and are not enabled or on
1275         if (isTool && !(option->state & State_Enabled || option->state & State_On) && (option->state & State_AutoRaise))
1276             break;
1277         // don't draw a frame for dock widget buttons, unless we are hovering
1278         if (widget && widget->inherits("QDockWidgetTitleButton") && !(option->state & State_MouseOver))
1279             break;
1280 
1281         GtkStateType state = qt_gtk_state(option);
1282         if (option->state & State_On || option->state & State_Sunken)
1283             state = GTK_STATE_ACTIVE;
1284         GtkWidget *gtkButton = isTool ? d->gtkWidget("GtkToolButton.GtkButton") : d->gtkWidget("GtkButton");
1285         gint focusWidth, focusPad;
1286         gboolean interiorFocus = false;
1287         gtk_widget_style_get (gtkButton,
1288                               "focus-line-width", &focusWidth,
1289                               "focus-padding", &focusPad,
1290                               "interior-focus", &interiorFocus, NULL);
1291 
1292         style = gtk_widget_get_style(gtkButton);
1293 
1294         QRect buttonRect = option->rect;
1295 
1296         QString key;
1297         if (isDefault) {
1298             key += QLS("def");
1299             gtk_widget_set_can_default(gtkButton, true);
1300             gtk_window_set_default((GtkWindow*)gtk_widget_get_toplevel(gtkButton), gtkButton);
1301             gtkPainter->paintBox(gtkButton, "buttondefault", buttonRect, state, GTK_SHADOW_IN,
1302                                  style, isDefault ? QLS("d") : QString());
1303         }
1304 
1305         bool hasFocus = option->state & State_HasFocus;
1306 
1307         if (hasFocus) {
1308             key += QLS("def");
1309             QGtkStylePrivate::gtkWidgetSetFocus(gtkButton, true);
1310         }
1311 
1312         if (!interiorFocus)
1313             buttonRect = buttonRect.adjusted(focusWidth, focusWidth, -focusWidth, -focusWidth);
1314 
1315         GtkShadowType shadow = (option->state & State_Sunken || option->state & State_On ) ?
1316                                GTK_SHADOW_IN : GTK_SHADOW_OUT;
1317 
1318         gtkPainter->paintBox(gtkButton, "button", buttonRect, state, shadow,
1319                              style, key);
1320         if (isDefault)
1321             gtk_window_set_default((GtkWindow*)gtk_widget_get_toplevel(gtkButton), 0);
1322         if (hasFocus)
1323             QGtkStylePrivate::gtkWidgetSetFocus(gtkButton, false);
1324     }
1325     break;
1326 
1327     case PE_IndicatorRadioButton: {
1328         GtkShadowType shadow = GTK_SHADOW_OUT;
1329         GtkStateType state = qt_gtk_state(option);
1330 
1331         if (option->state & State_Sunken)
1332             state = GTK_STATE_ACTIVE;
1333 
1334         if (option->state & State_NoChange)
1335             shadow = GTK_SHADOW_ETCHED_IN;
1336         else if (option->state & State_On)
1337             shadow = GTK_SHADOW_IN;
1338         else
1339             shadow = GTK_SHADOW_OUT;
1340 
1341         GtkWidget *gtkRadioButton = d->gtkWidget("GtkRadioButton");
1342         gint spacing;
1343         gtk_widget_style_get(gtkRadioButton, "indicator-spacing", &spacing, NULL);
1344         QRect buttonRect = option->rect.adjusted(spacing, spacing, -spacing, -spacing);
1345         gtkPainter->setClipRect(option->rect);
1346         // ### Note: Ubuntulooks breaks when the proper widget is passed
1347         //           Murrine engine requires a widget not to get RGBA check - warnings
1348         GtkWidget *gtkCheckButton = d->gtkWidget("GtkCheckButton");
1349         QString key(QLS("radiobutton"));
1350         if (option->state & State_HasFocus) { // Themes such as Nodoka check this flag
1351             key += QLatin1Char('f');
1352             QGtkStylePrivate::gtkWidgetSetFocus(gtkCheckButton, true);
1353         }
1354         gtkPainter->paintOption(gtkCheckButton , buttonRect, state, shadow, gtk_widget_get_style(gtkRadioButton), key);
1355         if (option->state & State_HasFocus)
1356             QGtkStylePrivate::gtkWidgetSetFocus(gtkCheckButton, false);
1357     }
1358     break;
1359 
1360     case PE_IndicatorCheckBox: {
1361         GtkShadowType shadow = GTK_SHADOW_OUT;
1362         GtkStateType state = qt_gtk_state(option);
1363 
1364         if (option->state & State_Sunken)
1365             state = GTK_STATE_ACTIVE;
1366 
1367         if (option->state & State_NoChange)
1368             shadow = GTK_SHADOW_ETCHED_IN;
1369         else if (option->state & State_On)
1370             shadow = GTK_SHADOW_IN;
1371         else
1372             shadow = GTK_SHADOW_OUT;
1373 
1374         int spacing;
1375 
1376         GtkWidget *gtkCheckButton = d->gtkWidget("GtkCheckButton");
1377         QString key(QLS("checkbutton"));
1378         if (option->state & State_HasFocus) { // Themes such as Nodoka checks this flag
1379             key += QLatin1Char('f');
1380             QGtkStylePrivate::gtkWidgetSetFocus(gtkCheckButton, true);
1381         }
1382 
1383         // Some styles such as aero-clone assume they can paint in the spacing area
1384         gtkPainter->setClipRect(option->rect);
1385 
1386         gtk_widget_style_get(gtkCheckButton, "indicator-spacing", &spacing, NULL);
1387 
1388         QRect checkRect = option->rect.adjusted(spacing, spacing, -spacing, -spacing);
1389 
1390         gtkPainter->paintCheckbox(gtkCheckButton, checkRect, state, shadow, gtk_widget_get_style(gtkCheckButton),
1391                                   key);
1392         if (option->state & State_HasFocus)
1393             QGtkStylePrivate::gtkWidgetSetFocus(gtkCheckButton, false);
1394 
1395     }
1396     break;
1397 
1398 #ifndef QT_NO_TABBAR
1399 
1400     case PE_FrameTabBarBase:
1401         if (const QStyleOptionTabBarBase *tbb
1402                 = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
1403             QRect tabRect = tbb->rect;
1404             painter->save();
1405             painter->setPen(QPen(option->palette.dark().color().dark(110), 0));
1406             switch (tbb->shape) {
1407 
1408             case QTabBar::RoundedNorth:
1409                 painter->drawLine(tabRect.topLeft(), tabRect.topRight());
1410                 break;
1411 
1412             case QTabBar::RoundedWest:
1413                 painter->drawLine(tabRect.left(), tabRect.top(), tabRect.left(), tabRect.bottom());
1414                 break;
1415 
1416             case QTabBar::RoundedSouth:
1417                 painter->drawLine(tbb->rect.left(), tbb->rect.bottom(),
1418                                   tabRect.right(), tabRect.bottom());
1419                 break;
1420 
1421             case QTabBar::RoundedEast:
1422                 painter->drawLine(tabRect.topRight(), tabRect.bottomRight());
1423                 break;
1424 
1425             case QTabBar::TriangularNorth:
1426             case QTabBar::TriangularEast:
1427             case QTabBar::TriangularWest:
1428             case QTabBar::TriangularSouth:
1429                 painter->restore();
1430                 QCommonStyle::drawPrimitive(element, option, painter, widget);
1431                 return;
1432             }
1433 
1434             painter->restore();
1435         }
1436         return;
1437 
1438 #endif // QT_NO_TABBAR
1439 
1440     case PE_Widget:
1441         break;
1442 
1443     default:
1444         QCommonStyle::drawPrimitive(element, option, painter, widget);
1445     }
1446 }
1447 
1448 /*!
1449     \reimp
1450 */
drawComplexControl(ComplexControl control,const QStyleOptionComplex * option,QPainter * painter,const QWidget * widget) const1451 void QGtkStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
1452 
1453                                    QPainter *painter, const QWidget *widget) const
1454 {
1455     Q_D(const QGtkStyle);
1456 
1457     if (!d->isThemeAvailable()) {
1458         QCommonStyle::drawComplexControl(control, option, painter, widget);
1459         return;
1460     }
1461 
1462     GtkStyle* style = d->gtkStyle();
1463     QGtkPainter* gtkPainter = d->gtkPainter(painter);
1464     QColor button = option->palette.button().color();
1465     QColor dark;
1466     QColor grooveColor;
1467     QColor darkOutline;
1468     dark.setHsv(button.hue(),
1469                 qMin(255, (int)(button.saturation()*1.9)),
1470                 qMin(255, (int)(button.value()*0.7)));
1471     grooveColor.setHsv(button.hue(),
1472                        qMin(255, (int)(button.saturation()*2.6)),
1473                        qMin(255, (int)(button.value()*0.9)));
1474     darkOutline.setHsv(button.hue(),
1475                        qMin(255, (int)(button.saturation()*3.0)),
1476                        qMin(255, (int)(button.value()*0.6)));
1477 
1478     QColor alphaCornerColor;
1479 
1480     if (widget)
1481         alphaCornerColor = mergedColors(option->palette.color(widget->backgroundRole()), darkOutline);
1482     else
1483         alphaCornerColor = mergedColors(option->palette.background().color(), darkOutline);
1484 
1485     switch (control) {
1486 
1487     case CC_TitleBar:
1488         painter->save();
1489         if (const QStyleOptionTitleBar *titleBar = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
1490             // Since this is drawn by metacity and not Gtk we
1491             // have to do custom drawing
1492 
1493             GdkColor gdkBg = style->bg[GTK_STATE_SELECTED];
1494             QColor bgColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8);
1495 
1496             const int buttonMargin = 5;
1497             bool active = (titleBar->titleBarState & State_Active);
1498             QRect fullRect = titleBar->rect;
1499             QPalette palette = option->palette;
1500             QColor highlight = bgColor;
1501 
1502             QColor titleBarFrameBorder(active ? highlight.darker(180): dark.darker(110));
1503             QColor titleBarHighlight(active ? highlight.lighter(120): palette.background().color().lighter(120));
1504             QColor textColor(active ? 0xffffff : 0xff000000);
1505             QColor textAlphaColor(active ? 0xffffff : 0xff000000 );
1506 
1507             {
1508                 // Fill title bar gradient
1509                 QColor titlebarColor = QColor(active ? highlight: palette.background().color());
1510                 QLinearGradient gradient(option->rect.center().x(), option->rect.top(),
1511                                          option->rect.center().x(), option->rect.bottom());
1512 
1513                 gradient.setColorAt(0, titlebarColor.lighter(114));
1514                 gradient.setColorAt(0.5, titlebarColor.lighter(102));
1515                 gradient.setColorAt(0.51, titlebarColor.darker(104));
1516                 gradient.setColorAt(1, titlebarColor);
1517                 painter->fillRect(option->rect.adjusted(1, 1, -1, 0), gradient);
1518 
1519                 // Frame and rounded corners
1520                 painter->setPen(titleBarFrameBorder);
1521 
1522                 // top outline
1523                 painter->drawLine(fullRect.left() + 5, fullRect.top(), fullRect.right() - 5, fullRect.top());
1524                 painter->drawLine(fullRect.left(), fullRect.top() + 4, fullRect.left(), fullRect.bottom());
1525                 const QPoint points[5] = {
1526                     QPoint(fullRect.left() + 4, fullRect.top() + 1),
1527                     QPoint(fullRect.left() + 3, fullRect.top() + 1),
1528                     QPoint(fullRect.left() + 2, fullRect.top() + 2),
1529                     QPoint(fullRect.left() + 1, fullRect.top() + 3),
1530                     QPoint(fullRect.left() + 1, fullRect.top() + 4)
1531                 };
1532                 painter->drawPoints(points, 5);
1533 
1534                 painter->drawLine(fullRect.right(), fullRect.top() + 4, fullRect.right(), fullRect.bottom());
1535                 const QPoint points2[5] = {
1536                     QPoint(fullRect.right() - 3, fullRect.top() + 1),
1537                     QPoint(fullRect.right() - 4, fullRect.top() + 1),
1538                     QPoint(fullRect.right() - 2, fullRect.top() + 2),
1539                     QPoint(fullRect.right() - 1, fullRect.top() + 3),
1540                     QPoint(fullRect.right() - 1, fullRect.top() + 4)
1541                 };
1542                 painter->drawPoints(points2, 5);
1543 
1544                 // draw bottomline
1545                 painter->drawLine(fullRect.right(), fullRect.bottom(), fullRect.left(), fullRect.bottom());
1546 
1547                 // top highlight
1548                 painter->setPen(titleBarHighlight);
1549                 painter->drawLine(fullRect.left() + 6, fullRect.top() + 1, fullRect.right() - 6, fullRect.top() + 1);
1550             }
1551             // draw title
1552             QRect textRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarLabel, widget);
1553             QFont font = painter->font();
1554             font.setBold(true);
1555             painter->setFont(font);
1556             painter->setPen(active? (titleBar->palette.text().color().lighter(120)) :
1557                                      titleBar->palette.text().color() );
1558             // Note workspace also does elliding but it does not use the correct font
1559             QString title = QFontMetrics(font).elidedText(titleBar->text, Qt::ElideRight, textRect.width() - 14);
1560             painter->drawText(textRect.adjusted(1, 1, 1, 1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
1561             painter->setPen(Qt::white);
1562             if (active)
1563                 painter->drawText(textRect, title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter));
1564             // min button
1565             if ((titleBar->subControls & SC_TitleBarMinButton) && (titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
1566                 !(titleBar->titleBarState& Qt::WindowMinimized)) {
1567                 QRect minButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMinButton, widget);
1568                 if (minButtonRect.isValid()) {
1569                     bool hover = (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_MouseOver);
1570                     bool sunken = (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_Sunken);
1571                     qt_gtk_draw_mdibutton(painter, titleBar, minButtonRect, hover, sunken);
1572                     QRect minButtonIconRect = minButtonRect.adjusted(buttonMargin ,buttonMargin , -buttonMargin, -buttonMargin);
1573                     painter->setPen(textColor);
1574                     painter->drawLine(minButtonIconRect.center().x() - 2, minButtonIconRect.center().y() + 3,
1575                                     minButtonIconRect.center().x() + 3, minButtonIconRect.center().y() + 3);
1576                     painter->drawLine(minButtonIconRect.center().x() - 2, minButtonIconRect.center().y() + 4,
1577                                     minButtonIconRect.center().x() + 3, minButtonIconRect.center().y() + 4);
1578                     painter->setPen(textAlphaColor);
1579                     painter->drawLine(minButtonIconRect.center().x() - 3, minButtonIconRect.center().y() + 3,
1580                                     minButtonIconRect.center().x() - 3, minButtonIconRect.center().y() + 4);
1581                     painter->drawLine(minButtonIconRect.center().x() + 4, minButtonIconRect.center().y() + 3,
1582                                     minButtonIconRect.center().x() + 4, minButtonIconRect.center().y() + 4);
1583                 }
1584             }
1585             // max button
1586             if ((titleBar->subControls & SC_TitleBarMaxButton) && (titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
1587                 !(titleBar->titleBarState & Qt::WindowMaximized)) {
1588                 QRect maxButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMaxButton, widget);
1589                 if (maxButtonRect.isValid()) {
1590                     bool hover = (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_MouseOver);
1591                     bool sunken = (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_Sunken);
1592                     qt_gtk_draw_mdibutton(painter, titleBar, maxButtonRect, hover, sunken);
1593 
1594                     QRect maxButtonIconRect = maxButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin);
1595 
1596                     painter->setPen(textColor);
1597                     painter->drawRect(maxButtonIconRect.adjusted(0, 0, -1, -1));
1598                     painter->drawLine(maxButtonIconRect.left() + 1, maxButtonIconRect.top() + 1,
1599                                     maxButtonIconRect.right() - 1, maxButtonIconRect.top() + 1);
1600                     painter->setPen(textAlphaColor);
1601                     const QPoint points[4] = {
1602                         maxButtonIconRect.topLeft(),
1603                         maxButtonIconRect.topRight(),
1604                         maxButtonIconRect.bottomLeft(),
1605                         maxButtonIconRect.bottomRight()
1606                     };
1607                     painter->drawPoints(points, 4);
1608                 }
1609             }
1610 
1611             // close button
1612             if ((titleBar->subControls & SC_TitleBarCloseButton) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) {
1613                 QRect closeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarCloseButton, widget);
1614                 if (closeButtonRect.isValid()) {
1615                     bool hover = (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_MouseOver);
1616                     bool sunken = (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_Sunken);
1617                     qt_gtk_draw_mdibutton(painter, titleBar, closeButtonRect, hover, sunken);
1618                     QRect closeIconRect = closeButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin);
1619                     painter->setPen(textAlphaColor);
1620                     const QLine lines[4] = {
1621                         QLine(closeIconRect.left() + 1, closeIconRect.top(),
1622                               closeIconRect.right(), closeIconRect.bottom() - 1),
1623                         QLine(closeIconRect.left(), closeIconRect.top() + 1,
1624                               closeIconRect.right() - 1, closeIconRect.bottom()),
1625                         QLine(closeIconRect.right() - 1, closeIconRect.top(),
1626                               closeIconRect.left(), closeIconRect.bottom() - 1),
1627                         QLine(closeIconRect.right(), closeIconRect.top() + 1,
1628                               closeIconRect.left() + 1, closeIconRect.bottom())
1629                     };
1630                     painter->drawLines(lines, 4);
1631                     const QPoint points[4] = {
1632                         closeIconRect.topLeft(),
1633                         closeIconRect.topRight(),
1634                         closeIconRect.bottomLeft(),
1635                         closeIconRect.bottomRight()
1636                     };
1637                     painter->drawPoints(points, 4);
1638 
1639                     painter->setPen(textColor);
1640                     painter->drawLine(closeIconRect.left() + 1, closeIconRect.top() + 1,
1641                                     closeIconRect.right() - 1, closeIconRect.bottom() - 1);
1642                     painter->drawLine(closeIconRect.left() + 1, closeIconRect.bottom() - 1,
1643                                     closeIconRect.right() - 1, closeIconRect.top() + 1);
1644                 }
1645             }
1646 
1647             // normalize button
1648             if ((titleBar->subControls & SC_TitleBarNormalButton) &&
1649                (((titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) &&
1650                (titleBar->titleBarState & Qt::WindowMinimized)) ||
1651                ((titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) &&
1652                (titleBar->titleBarState & Qt::WindowMaximized)))) {
1653                 QRect normalButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarNormalButton, widget);
1654                 if (normalButtonRect.isValid()) {
1655 
1656                     bool hover = (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_MouseOver);
1657                     bool sunken = (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_Sunken);
1658                     QRect normalButtonIconRect = normalButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin);
1659                     qt_gtk_draw_mdibutton(painter, titleBar, normalButtonRect, hover, sunken);
1660 
1661                     QRect frontWindowRect = normalButtonIconRect.adjusted(0, 3, -3, 0);
1662                     painter->setPen(textColor);
1663                     painter->drawRect(frontWindowRect.adjusted(0, 0, -1, -1));
1664                     painter->drawLine(frontWindowRect.left() + 1, frontWindowRect.top() + 1,
1665                                     frontWindowRect.right() - 1, frontWindowRect.top() + 1);
1666                     painter->setPen(textAlphaColor);
1667                     const QPoint points[4] = {
1668                         frontWindowRect.topLeft(),
1669                         frontWindowRect.topRight(),
1670                         frontWindowRect.bottomLeft(),
1671                         frontWindowRect.bottomRight()
1672                     };
1673                     painter->drawPoints(points, 4);
1674 
1675                     QRect backWindowRect = normalButtonIconRect.adjusted(3, 0, 0, -3);
1676                     QRegion clipRegion = backWindowRect;
1677                     clipRegion -= frontWindowRect;
1678                     painter->save();
1679                     painter->setClipRegion(clipRegion);
1680                     painter->setPen(textColor);
1681                     painter->drawRect(backWindowRect.adjusted(0, 0, -1, -1));
1682                     painter->drawLine(backWindowRect.left() + 1, backWindowRect.top() + 1,
1683                                     backWindowRect.right() - 1, backWindowRect.top() + 1);
1684                     painter->setPen(textAlphaColor);
1685                     const QPoint points2[4] = {
1686                         backWindowRect.topLeft(),
1687                         backWindowRect.topRight(),
1688                         backWindowRect.bottomLeft(),
1689                         backWindowRect.bottomRight()
1690                     };
1691                     painter->drawPoints(points2, 4);
1692                     painter->restore();
1693                 }
1694             }
1695 
1696             // context help button
1697             if (titleBar->subControls & SC_TitleBarContextHelpButton
1698                 && (titleBar->titleBarFlags & Qt::WindowContextHelpButtonHint)) {
1699                 QRect contextHelpButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarContextHelpButton, widget);
1700                 if (contextHelpButtonRect.isValid()) {
1701                     bool hover = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_MouseOver);
1702                     bool sunken = (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_Sunken);
1703                     qt_gtk_draw_mdibutton(painter, titleBar, contextHelpButtonRect, hover, sunken);
1704 
1705                     QColor blend;
1706                     QImage image(qt_titlebar_context_help);
1707                     QColor alpha = textColor;
1708                     alpha.setAlpha(128);
1709                     image.setColor(1, textColor.rgba());
1710                     image.setColor(2, alpha.rgba());
1711                     painter->setRenderHint(QPainter::SmoothPixmapTransform);
1712                     painter->drawImage(contextHelpButtonRect.adjusted(4, 4, -4, -4), image);
1713                 }
1714             }
1715 
1716             // shade button
1717             if (titleBar->subControls & SC_TitleBarShadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) {
1718                 QRect shadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarShadeButton, widget);
1719                 if (shadeButtonRect.isValid()) {
1720                     bool hover = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_MouseOver);
1721                     bool sunken = (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_Sunken);
1722                     qt_gtk_draw_mdibutton(painter, titleBar, shadeButtonRect, hover, sunken);
1723                     QImage image(qt_scrollbar_button_arrow_up);
1724                     image.setColor(1, textColor.rgba());
1725                     painter->drawImage(shadeButtonRect.adjusted(5, 7, -5, -7), image);
1726                 }
1727             }
1728 
1729             // unshade button
1730             if (titleBar->subControls & SC_TitleBarUnshadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) {
1731                 QRect unshadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarUnshadeButton, widget);
1732                 if (unshadeButtonRect.isValid()) {
1733                     bool hover = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_MouseOver);
1734                     bool sunken = (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_Sunken);
1735                     qt_gtk_draw_mdibutton(painter, titleBar, unshadeButtonRect, hover, sunken);
1736                     QImage image(qt_scrollbar_button_arrow_down);
1737                     image.setColor(1, textColor.rgba());
1738                     painter->drawImage(unshadeButtonRect.adjusted(5, 7, -5, -7), image);
1739                 }
1740             }
1741 
1742             if ((titleBar->subControls & SC_TitleBarSysMenu) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) {
1743                 QRect iconRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarSysMenu, widget);
1744                 if (iconRect.isValid()) {
1745                     if (!titleBar->icon.isNull()) {
1746                         titleBar->icon.paint(painter, iconRect);
1747                     } else {
1748                         QStyleOption tool(0);
1749                         tool.palette = titleBar->palette;
1750                         QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget).pixmap(16, 16);
1751                         tool.rect = iconRect;
1752                         painter->save();
1753                         proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm);
1754                         painter->restore();
1755                     }
1756                 }
1757             }
1758         }
1759         painter->restore();
1760         break;
1761 
1762 #ifndef QT_NO_GROUPBOX
1763 
1764     case CC_GroupBox:
1765         painter->save();
1766 
1767         if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
1768             QRect textRect = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxLabel, widget);
1769             QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, groupBox, SC_GroupBoxCheckBox, widget);
1770             // Draw title
1771 
1772             if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) {
1773                 // Draw prelight background
1774                 GtkWidget *gtkCheckButton = d->gtkWidget("GtkCheckButton");
1775 
1776                 if (option->state & State_MouseOver) {
1777                     QRect bgRect = textRect | checkBoxRect;
1778                     gtkPainter->paintFlatBox(gtkCheckButton, "checkbutton", bgRect.adjusted(0, 0, 0, -2),
1779                                              GTK_STATE_PRELIGHT, GTK_SHADOW_ETCHED_OUT, gtk_widget_get_style(gtkCheckButton));
1780                 }
1781 
1782                 if (!groupBox->text.isEmpty()) {
1783                     int alignment = int(groupBox->textAlignment);
1784                     if (!proxy()->styleHint(QStyle::SH_UnderlineShortcut, option, widget))
1785                         alignment |= Qt::TextHideMnemonic;
1786                     QColor textColor = groupBox->textColor; // Note: custom textColor is currently ignored
1787                     int labelState = GTK_STATE_INSENSITIVE;
1788 
1789                     if (option->state & State_Enabled)
1790                         labelState = (option->state & State_MouseOver) ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
1791 
1792                     GdkColor gdkText = gtk_widget_get_style(gtkCheckButton)->fg[labelState];
1793                     textColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
1794                     painter->setPen(textColor);
1795                     QFont font = painter->font();
1796                     font.setBold(true);
1797                     painter->setFont(font);
1798                     painter->drawText(textRect, Qt::TextShowMnemonic | Qt::AlignLeft| alignment, groupBox->text);
1799 
1800                     if (option->state & State_HasFocus)
1801                         gtkPainter->paintFocus(gtkCheckButton, "checkbutton", textRect.adjusted(-4, -1, 0, -3), GTK_STATE_ACTIVE, style);
1802                 }
1803             }
1804 
1805             if (groupBox->subControls & SC_GroupBoxCheckBox) {
1806                 QStyleOptionButton box;
1807                 box.QStyleOption::operator=(*groupBox);
1808                 box.rect = checkBoxRect;
1809                 proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget);
1810             }
1811         }
1812 
1813         painter->restore();
1814         break;
1815 #endif // QT_NO_GROUPBOX
1816 
1817 #ifndef QT_NO_COMBOBOX
1818 
1819     case CC_ComboBox:
1820         // See: http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/GtkComboBox
1821         // and http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/GtkComboBoxEntry
1822         if (const QStyleOptionComboBox *comboBox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
1823             bool sunken = comboBox->state & State_On; // play dead, if combobox has no items
1824             BEGIN_STYLE_PIXMAPCACHE(QString::fromLatin1("cb-%0-%1").arg(sunken).arg(comboBox->editable));
1825             gtkPainter->reset(p);
1826             gtkPainter->setUsePixmapCache(false); // cached externally
1827 
1828             bool isEnabled = (comboBox->state & State_Enabled);
1829             bool focus = isEnabled && (comboBox->state & State_HasFocus);
1830             GtkStateType state = qt_gtk_state(option);
1831             int appears_as_list = !proxy()->styleHint(QStyle::SH_ComboBox_Popup, comboBox, widget);
1832             QStyleOptionComboBox comboBoxCopy = *comboBox;
1833             comboBoxCopy.rect = option->rect;
1834 
1835             bool reverse = (option->direction == Qt::RightToLeft);
1836             QRect rect = option->rect;
1837             QRect arrowButtonRect = proxy()->subControlRect(CC_ComboBox, &comboBoxCopy,
1838                                                    SC_ComboBoxArrow, widget);
1839 
1840             GtkShadowType shadow = (option->state & State_Sunken || option->state & State_On ) ?
1841                                    GTK_SHADOW_IN : GTK_SHADOW_OUT;
1842             const QHashableLatin1Literal comboBoxPath = comboBox->editable ? QHashableLatin1Literal("GtkComboBoxEntry") : QHashableLatin1Literal("GtkComboBox");
1843 
1844             // We use the gtk widget to position arrows and separators for us
1845             GtkWidget *gtkCombo = d->gtkWidget(comboBoxPath);
1846             GtkAllocation geometry = {0, 0, option->rect.width(), option->rect.height()};
1847             gtk_widget_set_direction(gtkCombo, reverse ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
1848             gtk_widget_size_allocate(gtkCombo, &geometry);
1849 
1850             QHashableLatin1Literal buttonPath = comboBox->editable ? QHashableLatin1Literal("GtkComboBoxEntry.GtkToggleButton")
1851                                 : QHashableLatin1Literal("GtkComboBox.GtkToggleButton");
1852             GtkWidget *gtkToggleButton = d->gtkWidget(buttonPath);
1853             gtk_widget_set_direction(gtkToggleButton, reverse ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
1854             if (gtkToggleButton && (appears_as_list || comboBox->editable)) {
1855                 if (focus)
1856                     QGtkStylePrivate::gtkWidgetSetFocus(gtkToggleButton, true);
1857                 // Draw the combo box as a line edit with a button next to it
1858                 if (comboBox->editable || appears_as_list) {
1859                     GtkStateType frameState = (state == GTK_STATE_PRELIGHT) ? GTK_STATE_NORMAL : state;
1860                     QHashableLatin1Literal entryPath = comboBox->editable ? QHashableLatin1Literal("GtkComboBoxEntry.GtkEntry") : QHashableLatin1Literal("GtkComboBox.GtkFrame");
1861                     GtkWidget *gtkEntry = d->gtkWidget(entryPath);
1862                     gtk_widget_set_direction(gtkEntry, reverse ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
1863                     QRect frameRect = option->rect;
1864 
1865                     if (reverse)
1866                         frameRect.setLeft(arrowButtonRect.right());
1867                     else
1868                         frameRect.setRight(arrowButtonRect.left());
1869 
1870                     // Fill the line edit background
1871                     // We could have used flat_box with "entry_bg" but that is probably not worth the overhead
1872                     uint resolve_mask = option->palette.resolve();
1873                     GtkStyle *gtkEntryStyle = gtk_widget_get_style(gtkEntry);
1874                     QRect contentRect = frameRect.adjusted(gtkEntryStyle->xthickness, gtkEntryStyle->ythickness,
1875                                                            -gtkEntryStyle->xthickness, -gtkEntryStyle->ythickness);
1876                     // Required for inner blue highlight with clearlooks
1877                     if (focus)
1878                         QGtkStylePrivate::gtkWidgetSetFocus(gtkEntry, true);
1879 
1880                     if (widget && widget->testAttribute(Qt::WA_SetPalette) &&
1881                         resolve_mask & (1 << QPalette::Base)) // Palette overridden by user
1882                         p->fillRect(contentRect, option->palette.base().color());
1883                     else {
1884                         gtkPainter->paintFlatBox(gtkEntry, "entry_bg", contentRect,
1885                                                  option->state & State_Enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE,
1886                                                  GTK_SHADOW_NONE, gtkEntryStyle, entryPath.toString() + QString::number(focus));
1887                     }
1888 
1889                     gtkPainter->paintShadow(gtkEntry, comboBox->editable ? "entry" : "frame", frameRect, frameState,
1890                                             GTK_SHADOW_IN, gtkEntryStyle, entryPath.toString() +
1891                                             QString::number(focus) + QString::number(comboBox->editable) +
1892                                             QString::number(option->direction));
1893                     if (focus)
1894                         QGtkStylePrivate::gtkWidgetSetFocus(gtkEntry, false);
1895                 }
1896 
1897                 GtkStateType buttonState = GTK_STATE_NORMAL;
1898 
1899                 if (!(option->state & State_Enabled))
1900                     buttonState = GTK_STATE_INSENSITIVE;
1901                 else if (option->state & State_Sunken || option->state & State_On)
1902                     buttonState = GTK_STATE_ACTIVE;
1903                 else if (option->state & State_MouseOver && comboBox->activeSubControls & SC_ComboBoxArrow)
1904                     buttonState = GTK_STATE_PRELIGHT;
1905 
1906                 Q_ASSERT(gtkToggleButton);
1907                 gtkPainter->paintBox(gtkToggleButton, "button", arrowButtonRect, buttonState,
1908                                      shadow, gtk_widget_get_style(gtkToggleButton), buttonPath.toString() +
1909                                      QString::number(focus) + QString::number(option->direction));
1910                 if (focus)
1911                     QGtkStylePrivate::gtkWidgetSetFocus(gtkToggleButton, false);
1912             } else {
1913                 // Draw combo box as a button
1914                 QRect buttonRect = option->rect;
1915                 GtkStyle *gtkToggleButtonStyle = gtk_widget_get_style(gtkToggleButton);
1916 
1917                 if (focus) // Clearlooks actually check the widget for the default state
1918                     QGtkStylePrivate::gtkWidgetSetFocus(gtkToggleButton, true);
1919                 gtkPainter->paintBox(gtkToggleButton, "button",
1920                                      buttonRect, state,
1921                                      shadow, gtkToggleButtonStyle,
1922                                      buttonPath.toString() + QString::number(focus));
1923                 if (focus)
1924                     QGtkStylePrivate::gtkWidgetSetFocus(gtkToggleButton, false);
1925 
1926 
1927                 // Draw the separator between label and arrows
1928                 QHashableLatin1Literal vSeparatorPath = comboBox->editable
1929                     ? QHashableLatin1Literal("GtkComboBoxEntry.GtkToggleButton.GtkHBox.GtkVSeparator")
1930                     : QHashableLatin1Literal("GtkComboBox.GtkToggleButton.GtkHBox.GtkVSeparator");
1931 
1932                 if (GtkWidget *gtkVSeparator = d->gtkWidget(vSeparatorPath)) {
1933                     GtkAllocation allocation;
1934                     gtk_widget_get_allocation(gtkVSeparator, &allocation);
1935                     QRect vLineRect(allocation.x, allocation.y, allocation.width, allocation.height);
1936 
1937                     gtkPainter->paintVline(gtkVSeparator, "vseparator",
1938                                            vLineRect, state, gtk_widget_get_style(gtkVSeparator),
1939                                            0, vLineRect.height(), 0, vSeparatorPath.toString());
1940 
1941 
1942                     gint interiorFocus = true;
1943                     gtk_widget_style_get(gtkToggleButton, "interior-focus", &interiorFocus, NULL);
1944                     int xt = interiorFocus ? gtkToggleButtonStyle->xthickness : 0;
1945                     int yt = interiorFocus ? gtkToggleButtonStyle->ythickness : 0;
1946                     if (focus && ((option->state & State_KeyboardFocusChange) || styleHint(SH_UnderlineShortcut, option, widget)))
1947                         gtkPainter->paintFocus(gtkToggleButton, "button",
1948                                                option->rect.adjusted(xt, yt, -xt, -yt),
1949                                                option->state & State_Sunken ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL,
1950                                                gtkToggleButtonStyle);
1951                 }
1952             }
1953 
1954             if (comboBox->subControls & SC_ComboBoxArrow) {
1955                 if (!isEnabled)
1956                     state = GTK_STATE_INSENSITIVE;
1957                 else if (sunken)
1958                     state = GTK_STATE_ACTIVE;
1959                 else if (option->state & State_MouseOver)
1960                     state = GTK_STATE_PRELIGHT;
1961                 else
1962                     state = GTK_STATE_NORMAL;
1963 
1964                 QHashableLatin1Literal arrowPath("");
1965                 if (comboBox->editable) {
1966                     if (appears_as_list)
1967                         arrowPath = QHashableLatin1Literal("GtkComboBoxEntry.GtkToggleButton.GtkArrow");
1968                     else
1969                         arrowPath = QHashableLatin1Literal("GtkComboBoxEntry.GtkToggleButton.GtkHBox.GtkArrow");
1970                 } else {
1971                     if (appears_as_list)
1972                         arrowPath = QHashableLatin1Literal("GtkComboBox.GtkToggleButton.GtkArrow");
1973                     else
1974                         arrowPath = QHashableLatin1Literal("GtkComboBox.GtkToggleButton.GtkHBox.GtkArrow");
1975                 }
1976 
1977                 GtkWidget *gtkArrow = d->gtkWidget(arrowPath);
1978                 gfloat scale = 0.7;
1979                 gint minSize = 15;
1980                 QRect arrowWidgetRect;
1981 
1982                 if (gtkArrow && !gtk_check_version(2, 12, 0)) {
1983                     gtk_widget_style_get(gtkArrow, "arrow-scaling", &scale, NULL);
1984                     gtk_widget_style_get(gtkCombo, "arrow-size", &minSize, NULL);
1985                 }
1986                 if (gtkArrow) {
1987                     GtkAllocation allocation;
1988                     gtk_widget_get_allocation(gtkArrow, &allocation);
1989                     arrowWidgetRect = QRect(allocation.x, allocation.y, allocation.width, allocation.height);
1990                     style = gtk_widget_get_style(gtkArrow);
1991                 }
1992 
1993                 // Note that for some reason the arrow-size is not properly respected with Hildon
1994                 // Hence we enforce the minimum "arrow-size" ourselves
1995                 int arrowSize = qMax(qMin(rect.height() - gtk_widget_get_style(gtkCombo)->ythickness * 2, minSize),
1996                                      qMin(arrowWidgetRect.width(), arrowWidgetRect.height()));
1997                 QRect arrowRect(0, 0, static_cast<int>(arrowSize * scale), static_cast<int>(arrowSize * scale));
1998 
1999                 arrowRect.moveCenter(arrowWidgetRect.center());
2000 
2001                 if (sunken) {
2002                     int xoff, yoff;
2003                     const QHashableLatin1Literal toggleButtonPath = comboBox->editable
2004                             ? QHashableLatin1Literal("GtkComboBoxEntry.GtkToggleButton")
2005                             : QHashableLatin1Literal("GtkComboBox.GtkToggleButton");
2006 
2007                     GtkWidget *gtkButton = d->gtkWidget(toggleButtonPath);
2008                     gtk_widget_style_get(gtkButton, "child-displacement-x", &xoff, NULL);
2009                     gtk_widget_style_get(gtkButton, "child-displacement-y", &yoff, NULL);
2010                     arrowRect = arrowRect.adjusted(xoff, yoff, xoff, yoff);
2011                 }
2012 
2013                 // Some styles such as Nimbus paint outside the arrowRect
2014                 // hence we have provide the whole widget as the cliprect
2015                 if (gtkArrow) {
2016                     gtkPainter->setClipRect(option->rect);
2017                     gtkPainter->paintArrow(gtkArrow, "arrow", arrowRect,
2018                                            GTK_ARROW_DOWN, state, GTK_SHADOW_NONE, true,
2019                                            style, arrowPath.toString() + QString::number(option->direction));
2020                 }
2021             }
2022             END_STYLE_PIXMAPCACHE;
2023         }
2024         break;
2025 #endif // QT_NO_COMBOBOX
2026 #ifndef QT_NO_TOOLBUTTON
2027 
2028     case CC_ToolButton:
2029         if (const QStyleOptionToolButton *toolbutton
2030                 = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
2031             QRect button, menuarea;
2032             button = proxy()->subControlRect(control, toolbutton, SC_ToolButton, widget);
2033             menuarea = proxy()->subControlRect(control, toolbutton, SC_ToolButtonMenu, widget);
2034             State bflags = toolbutton->state & ~(State_Sunken | State_MouseOver);
2035 
2036             if (bflags & State_AutoRaise)
2037                 if (!(bflags & State_MouseOver))
2038                     bflags &= ~State_Raised;
2039 
2040             State mflags = bflags;
2041 
2042             if (toolbutton->state & State_Sunken) {
2043                 if (toolbutton->activeSubControls & SC_ToolButton)
2044                     bflags |= State_Sunken;
2045                 if (toolbutton->activeSubControls & SC_ToolButtonMenu)
2046                     mflags |= State_Sunken;
2047             } else if (toolbutton->state & State_MouseOver) {
2048                 if (toolbutton->activeSubControls & SC_ToolButton)
2049                     bflags |= State_MouseOver;
2050                 if (toolbutton->activeSubControls & SC_ToolButtonMenu)
2051                     mflags |= State_MouseOver;
2052             }
2053 
2054             QStyleOption tool(0);
2055 
2056             tool.palette = toolbutton->palette;
2057 
2058             if (toolbutton->subControls & SC_ToolButton) {
2059                 if (bflags & (State_Sunken | State_On | State_Raised | State_MouseOver)) {
2060                     tool.rect = button;
2061                     tool.state = bflags;
2062                     proxy()->drawPrimitive(PE_PanelButtonTool, &tool, painter, widget);
2063                 }
2064             }
2065 
2066             bool drawMenuArrow = toolbutton->features & QStyleOptionToolButton::HasMenu &&
2067                                  !(toolbutton->features & QStyleOptionToolButton::MenuButtonPopup);
2068             int popupArrowSize = drawMenuArrow ? 7 : 0;
2069 
2070             if (toolbutton->state & State_HasFocus) {
2071                 QStyleOptionFocusRect fr;
2072                 fr.QStyleOption::operator=(*toolbutton);
2073                 fr.rect = proxy()->subControlRect(CC_ToolButton, toolbutton, SC_ToolButton, widget);
2074                 fr.rect.adjust(1, 1, -1, -1);
2075                 proxy()->drawPrimitive(PE_FrameFocusRect, &fr, painter, widget);
2076             }
2077 
2078             QStyleOptionToolButton label = *toolbutton;
2079             label.state = bflags;
2080             GtkWidget *gtkButton = d->gtkWidget("GtkToolButton.GtkButton");
2081             QPalette pal = toolbutton->palette;
2082             if (option->state & State_Enabled &&
2083                 option->state & State_MouseOver && !(widget && widget->testAttribute(Qt::WA_SetPalette))) {
2084                 GdkColor gdkText = gtk_widget_get_style(gtkButton)->fg[GTK_STATE_PRELIGHT];
2085                 QColor textColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
2086                 pal.setBrush(QPalette::All, QPalette::ButtonText, textColor);
2087                 label.palette = pal;
2088             }
2089             label.rect = button.adjusted(style->xthickness, style->ythickness,
2090                                         -style->xthickness - popupArrowSize, -style->ythickness);
2091             proxy()->drawControl(CE_ToolButtonLabel, &label, painter, widget);
2092 
2093             if (toolbutton->subControls & SC_ToolButtonMenu) {
2094                 tool.rect = menuarea;
2095                 tool.state = mflags;
2096                 if ((mflags & State_Enabled && (mflags & (State_Sunken | State_Raised | State_MouseOver))) || !(mflags & State_AutoRaise))
2097                     proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, painter, widget);
2098 
2099                 proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, painter, widget);
2100 
2101             } else if (drawMenuArrow) {
2102                 QRect ir = toolbutton->rect;
2103                 QStyleOptionToolButton newBtn = *toolbutton;
2104                 newBtn.rect = QRect(ir.right() - popupArrowSize - style->xthickness - 3, ir.height()/2 - 1, popupArrowSize, popupArrowSize);
2105                 proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
2106             }
2107         }
2108         break;
2109 
2110 #endif // QT_NO_TOOLBUTTON
2111 #ifndef QT_NO_SCROLLBAR
2112 
2113     case CC_ScrollBar:
2114         if (const QStyleOptionSlider *scrollBar = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
2115             GtkWidget *gtkHScrollBar = d->gtkWidget("GtkHScrollbar");
2116             GtkWidget *gtkVScrollBar = d->gtkWidget("GtkVScrollbar");
2117 
2118             // Fill background in case the scrollbar is partially transparent
2119             painter->fillRect(option->rect, option->palette.background());
2120 
2121             QRect rect = scrollBar->rect;
2122             QRect scrollBarSubLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSubLine, widget);
2123             QRect scrollBarAddLine = proxy()->subControlRect(control, scrollBar, SC_ScrollBarAddLine, widget);
2124             QRect scrollBarSlider = proxy()->subControlRect(control, scrollBar, SC_ScrollBarSlider, widget);
2125             QRect grooveRect = proxy()->subControlRect(control, scrollBar, SC_ScrollBarGroove, widget);
2126             bool horizontal = scrollBar->orientation == Qt::Horizontal;
2127             GtkWidget * scrollbarWidget = horizontal ? gtkHScrollBar : gtkVScrollBar;
2128             style = gtk_widget_get_style(scrollbarWidget);
2129             gboolean trough_under_steppers = true;
2130             gboolean trough_side_details = false;
2131             gboolean activate_slider = false;
2132             gboolean stepper_size = 14;
2133             gint trough_border = 1;
2134             if (!gtk_check_version(2, 10, 0)) {
2135                 gtk_widget_style_get((GtkWidget*)(scrollbarWidget),
2136                                      "trough-border",         &trough_border,
2137                                      "trough-side-details",   &trough_side_details,
2138                                      "trough-under-steppers", &trough_under_steppers,
2139                                      "activate-slider",       &activate_slider,
2140                                      "stepper-size",          &stepper_size, NULL);
2141             }
2142             if (trough_under_steppers) {
2143                 scrollBarAddLine.adjust(trough_border, trough_border, -trough_border, -trough_border);
2144                 scrollBarSubLine.adjust(trough_border, trough_border, -trough_border, -trough_border);
2145                 scrollBarSlider.adjust(horizontal ? -trough_border : 0, horizontal ? 0 : -trough_border,
2146                                        horizontal ? trough_border : 0, horizontal ? 0 : trough_border);
2147             }
2148 
2149             // Some styles check the position of scrollbars in order to determine
2150             // if lines should be painted when the scrollbar is in max or min positions.
2151             int maximum = 2;
2152             int fakePos = 0;
2153             bool reverse = (option->direction == Qt::RightToLeft);
2154             if (scrollBar->minimum == scrollBar->maximum)
2155                 maximum = 0;
2156             if (scrollBar->sliderPosition == scrollBar->maximum)
2157                 fakePos = maximum;
2158             else if (scrollBar->sliderPosition > scrollBar->minimum)
2159                 fakePos = maximum - 1;
2160 
2161 
2162             GtkRange *range = (GtkRange*)(horizontal ? gtkHScrollBar : gtkVScrollBar);
2163             GtkAdjustment *adjustment = 0;
2164 
2165             adjustment = gtk_range_get_adjustment(range);
2166             if (adjustment) {
2167                 gtk_adjustment_configure(adjustment, fakePos, 0, maximum, 0, 0, 0);
2168             } else {
2169                 adjustment = (GtkAdjustment*)gtk_adjustment_new(fakePos, 0, maximum, 0, 0, 0);
2170                 gtk_range_set_adjustment(range, adjustment);
2171             }
2172 
2173             if (scrollBar->subControls & SC_ScrollBarGroove) {
2174                 GtkStateType state = GTK_STATE_ACTIVE;
2175 
2176                 if (!(option->state & State_Enabled))
2177                     state = GTK_STATE_INSENSITIVE;
2178 
2179                 if (trough_under_steppers)
2180                     grooveRect = option->rect;
2181 
2182                 gtkPainter->paintBox(scrollbarWidget, "trough", grooveRect, state, GTK_SHADOW_IN, style);
2183             }
2184 
2185             //paint slider
2186             if (scrollBar->subControls & SC_ScrollBarSlider) {
2187                 GtkStateType state = GTK_STATE_NORMAL;
2188 
2189                 if (!(option->state & State_Enabled))
2190                     state = GTK_STATE_INSENSITIVE;
2191                 else if (activate_slider &&
2192                          option->state & State_Sunken && (scrollBar->activeSubControls & SC_ScrollBarSlider))
2193                     state = GTK_STATE_ACTIVE;
2194                 else if (option->state & State_MouseOver && (scrollBar->activeSubControls & SC_ScrollBarSlider))
2195                     state = GTK_STATE_PRELIGHT;
2196 
2197                 GtkShadowType shadow = GTK_SHADOW_OUT;
2198 
2199                 if (trough_under_steppers) {
2200                     if (!horizontal)
2201                         scrollBarSlider.adjust(trough_border, 0, -trough_border, 0);
2202                     else
2203                         scrollBarSlider.adjust(0, trough_border, 0, -trough_border);
2204                 }
2205 
2206                 gtkPainter->paintSlider(scrollbarWidget, "slider", scrollBarSlider, state, shadow, style,
2207                                         horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL, QString(QLS("%0%1")).arg(fakePos).arg(maximum));
2208             }
2209 
2210             if (scrollBar->subControls & SC_ScrollBarAddLine) {
2211                 GtkAllocation vAllocation;
2212                 vAllocation.y = scrollBarAddLine.top();
2213                 vAllocation.height = scrollBarAddLine.height() - rect.height() + 6;
2214                 gtk_widget_set_allocation(gtkVScrollBar, &vAllocation);
2215 
2216                 GtkAllocation hAllocation;
2217                 hAllocation.x = scrollBarAddLine.right();
2218                 hAllocation.width = scrollBarAddLine.width() - rect.width();
2219                 gtk_widget_set_allocation(gtkHScrollBar, &hAllocation);
2220 
2221                 GtkShadowType shadow = GTK_SHADOW_OUT;
2222                 GtkStateType state = GTK_STATE_NORMAL;
2223 
2224                 if (!(option->state & State_Enabled) || (fakePos == maximum))
2225                     state = GTK_STATE_INSENSITIVE;
2226                 else if (option->state & State_Sunken && (scrollBar->activeSubControls & SC_ScrollBarAddLine)) {
2227                     state = GTK_STATE_ACTIVE;
2228                     shadow = GTK_SHADOW_IN;
2229 
2230                 } else if (option->state & State_MouseOver && (scrollBar->activeSubControls & SC_ScrollBarAddLine))
2231                     state = GTK_STATE_PRELIGHT;
2232 
2233                 gtkPainter->paintBox(scrollbarWidget,
2234                                      horizontal ? "hscrollbar" : "vscrollbar", scrollBarAddLine,
2235                                      state, shadow, style, QLS("add"));
2236 
2237                 gtkPainter->paintArrow(scrollbarWidget, horizontal ? "hscrollbar" : "vscrollbar", scrollBarAddLine.adjusted(4, 4, -4, -4),
2238                                        horizontal ? (reverse ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT) :
2239                                        GTK_ARROW_DOWN, state, GTK_SHADOW_NONE, false, style);
2240             }
2241 
2242             if (scrollBar->subControls & SC_ScrollBarSubLine) {
2243                 GtkAllocation vAllocation;
2244                 vAllocation.y = 0;
2245                 vAllocation.height = scrollBarSubLine.height();
2246                 gtk_widget_set_allocation(gtkVScrollBar, &vAllocation);
2247 
2248                 GtkAllocation hAllocation;
2249                 hAllocation.x = 0;
2250                 hAllocation.width = scrollBarSubLine.width();
2251                 gtk_widget_set_allocation(gtkHScrollBar, &hAllocation);
2252 
2253                 GtkShadowType shadow = GTK_SHADOW_OUT;
2254                 GtkStateType state = GTK_STATE_NORMAL;
2255 
2256                 if (!(option->state & State_Enabled) || (fakePos == 0))
2257                     state = GTK_STATE_INSENSITIVE;
2258                 else if (option->state & State_Sunken && (scrollBar->activeSubControls & SC_ScrollBarSubLine)) {
2259                     shadow = GTK_SHADOW_IN;
2260                     state = GTK_STATE_ACTIVE;
2261 
2262                 } else if (option->state & State_MouseOver && (scrollBar->activeSubControls & SC_ScrollBarSubLine))
2263                     state = GTK_STATE_PRELIGHT;
2264 
2265                 gtkPainter->paintBox(scrollbarWidget, horizontal ? "hscrollbar" : "vscrollbar", scrollBarSubLine,
2266                                      state, shadow, style, QLS("sub"));
2267 
2268                 gtkPainter->paintArrow(scrollbarWidget, horizontal ? "hscrollbar" : "vscrollbar", scrollBarSubLine.adjusted(4, 4, -4, -4),
2269                                        horizontal ? (reverse ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT) :
2270                                        GTK_ARROW_UP, state, GTK_SHADOW_NONE, false, style);
2271             }
2272         }
2273         break;
2274 
2275 #endif //QT_NO_SCROLLBAR
2276 #ifndef QT_NO_SPINBOX
2277 
2278     case CC_SpinBox:
2279         if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
2280 
2281             GtkWidget *gtkSpinButton = spinBox->buttonSymbols == QAbstractSpinBox::NoButtons
2282                         ? d->gtkWidget("GtkEntry")
2283                         : d->gtkWidget("GtkSpinButton");
2284             bool isEnabled = (spinBox->state & State_Enabled);
2285             bool hover = isEnabled && (spinBox->state & State_MouseOver);
2286             bool sunken = (spinBox->state & State_Sunken);
2287             bool upIsActive = (spinBox->activeSubControls == SC_SpinBoxUp);
2288             bool downIsActive = (spinBox->activeSubControls == SC_SpinBoxDown);
2289             bool reverse = (spinBox->direction == Qt::RightToLeft);
2290 
2291             QRect editArea = option->rect;
2292             QRect editRect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxEditField, widget);
2293             QRect upRect, downRect, buttonRect;
2294             if (spinBox->buttonSymbols != QAbstractSpinBox::NoButtons) {
2295                 upRect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget);
2296                 downRect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
2297 
2298                 //### Move this to subControlRect
2299                 upRect.setTop(option->rect.top());
2300 
2301                 if (reverse)
2302                     upRect.setLeft(option->rect.left());
2303                 else
2304                     upRect.setRight(option->rect.right());
2305 
2306                 downRect.setBottom(option->rect.bottom());
2307 
2308                 if (reverse)
2309                     downRect.setLeft(option->rect.left());
2310                 else
2311                     downRect.setRight(option->rect.right());
2312 
2313                 buttonRect = upRect | downRect;
2314 
2315                 if (reverse)
2316                     editArea.setLeft(upRect.right());
2317                 else
2318                     editArea.setRight(upRect.left());
2319             }
2320             if (spinBox->frame) {
2321                 GtkStateType state = qt_gtk_state(option);
2322 
2323                 if (!(option->state & State_Enabled))
2324                     state = GTK_STATE_INSENSITIVE;
2325                 else if (option->state & State_HasFocus)
2326                     state = GTK_STATE_NORMAL;
2327                 else if (state == GTK_STATE_PRELIGHT)
2328                     state = GTK_STATE_NORMAL;
2329 
2330                 style = gtk_widget_get_style(gtkSpinButton);
2331 
2332 
2333                 QString key;
2334 
2335                 if (option->state & State_HasFocus) {
2336                     key += QLatin1Char('f');
2337                     QGtkStylePrivate::gtkWidgetSetFocus(gtkSpinButton, true);
2338                 }
2339 
2340                 uint resolve_mask = option->palette.resolve();
2341 
2342                 if (resolve_mask & (1 << QPalette::Base)) // Palette overridden by user
2343                     painter->fillRect(editRect, option->palette.base().color());
2344                 else
2345                     gtkPainter->paintFlatBox(gtkSpinButton, "entry_bg", editArea.adjusted(style->xthickness, style->ythickness,
2346                                              -style->xthickness, -style->ythickness),
2347                                              option->state & State_Enabled ?
2348                                              GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE, GTK_SHADOW_NONE, style, key);
2349 
2350                 gtkPainter->paintShadow(gtkSpinButton, "entry", editArea, state, GTK_SHADOW_IN, gtk_widget_get_style(gtkSpinButton), key);
2351                 if (spinBox->buttonSymbols != QAbstractSpinBox::NoButtons) {
2352                     gtkPainter->paintBox(gtkSpinButton, "spinbutton", buttonRect, state, GTK_SHADOW_IN, style, key);
2353 
2354                     upRect.setSize(downRect.size());
2355                     if (!(option->state & State_Enabled))
2356                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_up", upRect, GTK_STATE_INSENSITIVE, GTK_SHADOW_IN, style, key);
2357                     else if (upIsActive && sunken)
2358                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_up", upRect, GTK_STATE_ACTIVE, GTK_SHADOW_IN, style, key);
2359                     else if (upIsActive && hover)
2360                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_up", upRect, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, style, key);
2361                     else
2362                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_up", upRect, GTK_STATE_NORMAL, GTK_SHADOW_OUT, style, key);
2363 
2364                     if (!(option->state & State_Enabled))
2365                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_down", downRect, GTK_STATE_INSENSITIVE, GTK_SHADOW_IN, style, key);
2366                     else if (downIsActive && sunken)
2367                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_down", downRect, GTK_STATE_ACTIVE, GTK_SHADOW_IN, style, key);
2368                     else if (downIsActive && hover)
2369                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_down", downRect, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, style, key);
2370                     else
2371                         gtkPainter->paintBox(gtkSpinButton, "spinbutton_down", downRect, GTK_STATE_NORMAL, GTK_SHADOW_OUT, style, key);
2372 
2373                     if (option->state & State_HasFocus)
2374                         QGtkStylePrivate::gtkWidgetSetFocus(gtkSpinButton, false);
2375                 }
2376             }
2377 
2378             if (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) {
2379                 int centerX = upRect.center().x();
2380                 int centerY = upRect.center().y();
2381                 // plus/minus
2382 
2383                 if (spinBox->activeSubControls == SC_SpinBoxUp && sunken) {
2384                     painter->drawLine(1 + centerX - 2, 1 + centerY, 1 + centerX + 2, 1 + centerY);
2385                     painter->drawLine(1 + centerX, 1 + centerY - 2, 1 + centerX, 1 + centerY + 2);
2386 
2387                 } else {
2388                     painter->drawLine(centerX - 2, centerY, centerX + 2, centerY);
2389                     painter->drawLine(centerX, centerY - 2, centerX, centerY + 2);
2390                 }
2391                 centerX = downRect.center().x();
2392                 centerY = downRect.center().y();
2393 
2394                 if (spinBox->activeSubControls == SC_SpinBoxDown && sunken) {
2395                     painter->drawLine(1 + centerX - 2, 1 + centerY, 1 + centerX + 2, 1 + centerY);
2396                 } else {
2397                     painter->drawLine(centerX - 2, centerY, centerX + 2, centerY);
2398                 }
2399 
2400             } else if (spinBox->buttonSymbols == QAbstractSpinBox::UpDownArrows) {
2401                 int size = d->getSpinboxArrowSize();
2402                 int w = size / 2 - 1;
2403                 w -= w % 2 - 1; // force odd
2404                 int h = (w + 1)/2;
2405                 QRect arrowRect(0, 0, w, h);
2406                 arrowRect.moveCenter(upRect.center());
2407                 // arrows
2408                 GtkStateType state = GTK_STATE_NORMAL;
2409 
2410                 if (!(option->state & State_Enabled) || !(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled))
2411                     state = GTK_STATE_INSENSITIVE;
2412 
2413                 gtkPainter->paintArrow(gtkSpinButton, "spinbutton", arrowRect, GTK_ARROW_UP, state,
2414                                        GTK_SHADOW_NONE, false, style);
2415 
2416                 arrowRect.moveCenter(downRect.center());
2417 
2418                 state = GTK_STATE_NORMAL;
2419                 if (!(option->state & State_Enabled) || !(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled))
2420                     state = GTK_STATE_INSENSITIVE;
2421 
2422                 gtkPainter->paintArrow(gtkSpinButton, "spinbutton", arrowRect, GTK_ARROW_DOWN, state,
2423                                        GTK_SHADOW_NONE, false, style);
2424             }
2425         }
2426         break;
2427 
2428 #endif // QT_NO_SPINBOX
2429 
2430 #ifndef QT_NO_SLIDER
2431 
2432     case CC_Slider:
2433         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
2434             GtkWidget *hScaleWidget = d->gtkWidget("GtkHScale");
2435             GtkWidget *vScaleWidget = d->gtkWidget("GtkVScale");
2436 
2437             QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
2438             QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
2439 
2440             bool horizontal = slider->orientation == Qt::Horizontal;
2441             bool ticksAbove = slider->tickPosition & QSlider::TicksAbove;
2442             bool ticksBelow = slider->tickPosition & QSlider::TicksBelow;
2443 
2444             QBrush oldBrush = painter->brush();
2445             QPen oldPen = painter->pen();
2446 
2447             QColor shadowAlpha(Qt::black);
2448             shadowAlpha.setAlpha(10);
2449             QColor highlightAlpha(Qt::white);
2450             highlightAlpha.setAlpha(80);
2451 
2452             gtk_widget_set_direction(hScaleWidget, slider->upsideDown ?
2453                                                        GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
2454             GtkWidget *scaleWidget = horizontal ? hScaleWidget : vScaleWidget;
2455             style = gtk_widget_get_style(scaleWidget);
2456 
2457             if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
2458 
2459                 GtkRange *range = (GtkRange*)scaleWidget;
2460                 GtkAdjustment *adjustment = 0;
2461                 adjustment = gtk_range_get_adjustment(range);
2462                 if (adjustment) {
2463                     gtk_adjustment_configure(adjustment,
2464                                              slider->sliderPosition,
2465                                              slider->minimum,
2466                                              slider->maximum,
2467                                              slider->singleStep,
2468                                              slider->singleStep,
2469                                              slider->pageStep);
2470                 } else {
2471                     adjustment = (GtkAdjustment*)gtk_adjustment_new(slider->sliderPosition,
2472                                                                     slider->minimum,
2473                                                                     slider->maximum,
2474                                                                     slider->singleStep,
2475                                                                     slider->singleStep,
2476                                                                     slider->pageStep);
2477                     gtk_range_set_adjustment(range, adjustment);
2478                 }
2479 
2480                 int outerSize;
2481                 gtk_range_set_inverted(range, !horizontal);
2482                 gtk_widget_style_get(scaleWidget, "trough-border", &outerSize, NULL);
2483                 outerSize++;
2484 
2485                 GtkStateType state = qt_gtk_state(option);
2486                 int focusFrameMargin = 2;
2487                 QRect grooveRect = option->rect.adjusted(focusFrameMargin, outerSize + focusFrameMargin,
2488                                    -focusFrameMargin, -outerSize - focusFrameMargin);
2489 
2490                 gboolean trough_side_details = false; // Indicates if the upper or lower scale background differs
2491                 if (!gtk_check_version(2, 10, 0))
2492                     gtk_widget_style_get((GtkWidget*)(scaleWidget), "trough-side-details", &trough_side_details, NULL);
2493 
2494                 if (!trough_side_details) {
2495                     gtkPainter->paintBox(scaleWidget, "trough", grooveRect, state,
2496                                          GTK_SHADOW_IN, style, QString(QLS("p%0")).arg(slider->sliderPosition));
2497                 } else {
2498                     QRect upperGroove = grooveRect;
2499                     QRect lowerGroove = grooveRect;
2500 
2501                     if (horizontal) {
2502                         if (slider->upsideDown) {
2503                             lowerGroove.setLeft(handle.center().x());
2504                             upperGroove.setRight(handle.center().x());
2505                         } else {
2506                             upperGroove.setLeft(handle.center().x());
2507                             lowerGroove.setRight(handle.center().x());
2508                         }
2509                     } else {
2510                         if (!slider->upsideDown) {
2511                             lowerGroove.setBottom(handle.center().y());
2512                             upperGroove.setTop(handle.center().y());
2513                         } else {
2514                             upperGroove.setBottom(handle.center().y());
2515                             lowerGroove.setTop(handle.center().y());
2516                         }
2517                     }
2518 
2519                     gtkPainter->paintBox(scaleWidget, "trough-upper", upperGroove, state,
2520                                          GTK_SHADOW_IN, style, QString(QLS("p%0")).arg(slider->sliderPosition));
2521                     gtkPainter->paintBox(scaleWidget, "trough-lower", lowerGroove, state,
2522                                          GTK_SHADOW_IN, style, QString(QLS("p%0")).arg(slider->sliderPosition));
2523                 }
2524             }
2525 
2526             if (option->subControls & SC_SliderTickmarks) {
2527                 painter->setPen(darkOutline);
2528                 int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
2529                 int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
2530                 int interval = slider->tickInterval;
2531 
2532                 if (interval <= 0) {
2533                     interval = slider->singleStep;
2534 
2535                     if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
2536                                                         available)
2537                             - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
2538                                                               0, available) < 3)
2539                         interval = slider->pageStep;
2540                 }
2541 
2542                 if (interval <= 0)
2543                     interval = 1;
2544 
2545                 int v = slider->minimum;
2546                 int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
2547                 while (v <= slider->maximum + 1) {
2548                     if (v == slider->maximum + 1 && interval == 1)
2549                         break;
2550                     const int v_ = qMin(v, slider->maximum);
2551                     int pos = sliderPositionFromValue(slider->minimum, slider->maximum,
2552                                                       v_, (horizontal
2553                                                            ? slider->rect.width()
2554                                                            : slider->rect.height()) - len,
2555                                                       slider->upsideDown) + len / 2;
2556                     int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0);
2557                     if (horizontal) {
2558                         if (ticksAbove)
2559                             painter->drawLine(pos, slider->rect.top() + extra,
2560                                               pos, slider->rect.top() + tickSize);
2561                         if (ticksBelow)
2562                             painter->drawLine(pos, slider->rect.bottom() - extra,
2563                                               pos, slider->rect.bottom() - tickSize);
2564 
2565                     } else {
2566                         if (ticksAbove)
2567                             painter->drawLine(slider->rect.left() + extra, pos,
2568                                               slider->rect.left() + tickSize, pos);
2569                         if (ticksBelow)
2570                             painter->drawLine(slider->rect.right() - extra, pos,
2571                                               slider->rect.right() - tickSize, pos);
2572                     }
2573 
2574                     // In the case where maximum is max int
2575                     int nextInterval = v + interval;
2576                     if (nextInterval < v)
2577                         break;
2578                     v = nextInterval;
2579                 }
2580             }
2581 
2582             // Draw slider handle
2583             if (option->subControls & SC_SliderHandle) {
2584                 GtkShadowType shadow =  GTK_SHADOW_OUT;
2585                 GtkStateType state = GTK_STATE_NORMAL;
2586 
2587                 if (!(option->state & State_Enabled))
2588                     state = GTK_STATE_INSENSITIVE;
2589                 else if (option->state & State_MouseOver && option->activeSubControls & SC_SliderHandle)
2590                     state = GTK_STATE_PRELIGHT;
2591 
2592                 bool horizontal = option->state & State_Horizontal;
2593 
2594                 if (slider->state & State_HasFocus) {
2595                     QStyleOptionFocusRect fropt;
2596                     fropt.QStyleOption::operator=(*slider);
2597                     fropt.rect = slider->rect.adjusted(-1, -1 ,1, 1);
2598 
2599                     if (horizontal) {
2600                         fropt.rect.setTop(handle.top() - 3);
2601                         fropt.rect.setBottom(handle.bottom() + 4);
2602 
2603                     } else {
2604                         fropt.rect.setLeft(handle.left() - 3);
2605                         fropt.rect.setRight(handle.right() + 3);
2606                     }
2607                     proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
2608                 }
2609                 gtkPainter->paintSlider(scaleWidget, horizontal ? "hscale" : "vscale", handle, state, shadow, style,
2610                                         horizontal ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
2611             }
2612             painter->setBrush(oldBrush);
2613             painter->setPen(oldPen);
2614         }
2615         break;
2616     case CC_Dial:
2617         if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(option))
2618             QStyleHelper::drawDial(dial, painter);
2619         break;
2620 
2621 #endif // QT_NO_SLIDER
2622 
2623     default:
2624         QCommonStyle::drawComplexControl(control, option, painter, widget);
2625 
2626         break;
2627     }
2628 }
2629 
2630 
2631 /*!
2632     \reimp
2633 */
drawControl(ControlElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const2634 void QGtkStyle::drawControl(ControlElement element,
2635                             const QStyleOption *option,
2636                             QPainter *painter,
2637                             const QWidget *widget) const
2638 {
2639     Q_D(const QGtkStyle);
2640 
2641     if (!d->isThemeAvailable()) {
2642         QCommonStyle::drawControl(element, option, painter, widget);
2643         return;
2644     }
2645 
2646     GtkStyle* style = d->gtkStyle();
2647     QGtkPainter* gtkPainter = d->gtkPainter(painter);
2648 
2649     switch (element) {
2650     case CE_ProgressBarLabel:
2651         if (const QStyleOptionProgressBar *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
2652             GtkWidget *gtkProgressBar = d->gtkWidget("GtkProgressBar");
2653             if (!gtkProgressBar)
2654                 return;
2655 
2656             QRect leftRect;
2657             QRect rect = bar->rect;
2658             GtkStyle *gtkProgressBarStyle = gtk_widget_get_style(gtkProgressBar);
2659             GdkColor gdkText = gtkProgressBarStyle->fg[GTK_STATE_NORMAL];
2660             QColor textColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
2661             gdkText = gtkProgressBarStyle->fg[GTK_STATE_PRELIGHT];
2662             QColor alternateTextColor= QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
2663 
2664             painter->save();
2665             bool vertical = (bar->orientation == Qt::Vertical);
2666             bool inverted = bar->invertedAppearance;
2667             if (vertical)
2668                 rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // flip width and height
2669             const int progressIndicatorPos = (bar->progress - qreal(bar->minimum)) * rect.width() /
2670                                               qMax(qreal(1.0), qreal(bar->maximum) - bar->minimum);
2671             if (progressIndicatorPos >= 0 && progressIndicatorPos <= rect.width())
2672                 leftRect = QRect(rect.left(), rect.top(), progressIndicatorPos, rect.height());
2673             if (vertical)
2674                 leftRect.translate(rect.width() - progressIndicatorPos, 0);
2675 
2676             bool flip = (!vertical && (((bar->direction == Qt::RightToLeft) && !inverted) ||
2677                                        ((bar->direction == Qt::LeftToRight) && inverted)));
2678 
2679             QRegion rightRect = rect;
2680             rightRect = rightRect.subtracted(leftRect);
2681             painter->setClipRegion(rightRect);
2682             painter->setPen(flip ? alternateTextColor : textColor);
2683             painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
2684             if (!leftRect.isNull()) {
2685                 painter->setPen(flip ? textColor : alternateTextColor);
2686                 painter->setClipRect(leftRect);
2687                 painter->drawText(rect, bar->text, QTextOption(Qt::AlignAbsolute | Qt::AlignHCenter | Qt::AlignVCenter));
2688             }
2689             painter->restore();
2690         }
2691         break;
2692     case CE_PushButtonLabel:
2693         if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
2694             QRect ir = button->rect;
2695             uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic;
2696             QPoint buttonShift;
2697 
2698             if (option->state & State_Sunken)
2699                 buttonShift = QPoint(pixelMetric(PM_ButtonShiftHorizontal, option, widget),
2700                                      proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget));
2701 
2702             if (proxy()->styleHint(SH_UnderlineShortcut, button, widget))
2703                 tf |= Qt::TextShowMnemonic;
2704             else
2705                 tf |= Qt::TextHideMnemonic;
2706 
2707             if (!button->icon.isNull()) {
2708                 //Center both icon and text
2709                 QPoint point;
2710 
2711                 QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
2712                 if (mode == QIcon::Normal && button->state & State_HasFocus)
2713                     mode = QIcon::Active;
2714 
2715                 QIcon::State state = QIcon::Off;
2716 
2717                 if (button->state & State_On)
2718                     state = QIcon::On;
2719 
2720                 QPixmap pixmap = button->icon.pixmap(button->iconSize, mode, state);
2721                 int w = pixmap.width();
2722                 int h = pixmap.height();
2723 
2724                 if (!button->text.isEmpty())
2725                     w += button->fontMetrics.boundingRect(option->rect, tf, button->text).width() + 4;
2726 
2727                 point = QPoint(ir.x() + ir.width() / 2 - w / 2,
2728                                ir.y() + ir.height() / 2 - h / 2);
2729 
2730                 if (button->direction == Qt::RightToLeft)
2731                     point.rx() += pixmap.width();
2732 
2733                 painter->drawPixmap(visualPos(button->direction, button->rect, point + buttonShift), pixmap);
2734 
2735                 if (button->direction == Qt::RightToLeft)
2736                     ir.translate(-point.x() - 2, 0);
2737                 else
2738                     ir.translate(point.x() + pixmap.width() + 2, 0);
2739 
2740                 // left-align text if there is
2741                 if (!button->text.isEmpty())
2742                     tf |= Qt::AlignLeft;
2743 
2744             } else {
2745                 tf |= Qt::AlignHCenter;
2746             }
2747 
2748             ir.translate(buttonShift);
2749 
2750             if (button->features & QStyleOptionButton::HasMenu)
2751                 ir = ir.adjusted(0, 0, -pixelMetric(PM_MenuButtonIndicator, button, widget), 0);
2752 
2753             GtkWidget *gtkButton = d->gtkWidget("GtkButton");
2754             QPalette pal = button->palette;
2755             int labelState = GTK_STATE_INSENSITIVE;
2756             if (option->state & State_Enabled)
2757                 labelState = (option->state & State_MouseOver && !(option->state & State_Sunken)) ?
2758                              GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
2759 
2760             GdkColor gdkText = gtk_widget_get_style(gtkButton)->fg[labelState];
2761             QColor textColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
2762             pal.setBrush(QPalette::ButtonText, textColor);
2763             proxy()->drawItemText(painter, ir, tf, pal, (button->state & State_Enabled),
2764                          button->text, QPalette::ButtonText);
2765         }
2766         break;
2767 
2768     case CE_RadioButton: // Fall through
2769     case CE_CheckBox:
2770         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
2771             bool isRadio = (element == CE_RadioButton);
2772 
2773             // Draw prelight background
2774             GtkWidget *gtkRadioButton = d->gtkWidget("GtkRadioButton");
2775 
2776             if (option->state & State_MouseOver) {
2777                 gtkPainter->paintFlatBox(gtkRadioButton, "checkbutton", option->rect,
2778                                          GTK_STATE_PRELIGHT, GTK_SHADOW_ETCHED_OUT, gtk_widget_get_style(gtkRadioButton));
2779             }
2780 
2781             QStyleOptionButton subopt = *btn;
2782             subopt.rect = subElementRect(isRadio ? SE_RadioButtonIndicator
2783                                          : SE_CheckBoxIndicator, btn, widget);
2784             proxy()->drawPrimitive(isRadio ? PE_IndicatorRadioButton : PE_IndicatorCheckBox,
2785                           &subopt, painter, widget);
2786             subopt.rect = subElementRect(isRadio ? SE_RadioButtonContents
2787                                          : SE_CheckBoxContents, btn, widget);
2788             // Get label text color
2789             QPalette pal = subopt.palette;
2790             int labelState = GTK_STATE_INSENSITIVE;
2791             if (option->state & State_Enabled)
2792                 labelState = (option->state & State_MouseOver) ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
2793 
2794             GdkColor gdkText = gtk_widget_get_style(gtkRadioButton)->fg[labelState];
2795             QColor textColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
2796             pal.setBrush(QPalette::WindowText, textColor);
2797             subopt.palette = pal;
2798             proxy()->drawControl(isRadio ? CE_RadioButtonLabel : CE_CheckBoxLabel, &subopt, painter, widget);
2799 
2800             if (btn->state & State_HasFocus) {
2801                 QStyleOptionFocusRect fropt;
2802                 fropt.QStyleOption::operator=(*btn);
2803                 fropt.rect = subElementRect(isRadio ? SE_RadioButtonFocusRect
2804                                             : SE_CheckBoxFocusRect, btn, widget);
2805                 proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
2806             }
2807         }
2808         break;
2809 
2810 #ifndef QT_NO_COMBOBOX
2811 
2812     case CE_ComboBoxLabel:
2813         if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
2814             QRect editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget);
2815             bool appearsAsList = !proxy()->styleHint(QStyle::SH_ComboBox_Popup, cb, widget);
2816             painter->save();
2817             painter->setClipRect(editRect);
2818 
2819             if (!cb->currentIcon.isNull()) {
2820                 QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
2821                                    : QIcon::Disabled;
2822                 QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode);
2823                 QRect iconRect(editRect);
2824                 iconRect.setWidth(cb->iconSize.width() + 4);
2825 
2826                 iconRect = alignedRect(cb->direction,
2827                                        Qt::AlignLeft | Qt::AlignVCenter,
2828                                        iconRect.size(), editRect);
2829 
2830                 if (cb->editable)
2831                     painter->fillRect(iconRect, option->palette.brush(QPalette::Base));
2832 
2833                 proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap);
2834 
2835                 if (cb->direction == Qt::RightToLeft)
2836                     editRect.translate(-4 - cb->iconSize.width(), 0);
2837                 else
2838                     editRect.translate(cb->iconSize.width() + 4, 0);
2839             }
2840 
2841             if (!cb->currentText.isEmpty() && !cb->editable) {
2842                 GtkWidget *gtkCombo = d->gtkWidget("GtkComboBox");
2843                 QPalette pal = cb->palette;
2844                 int labelState = GTK_STATE_INSENSITIVE;
2845 
2846                 if (option->state & State_Enabled)
2847                     labelState = (option->state & State_MouseOver && !appearsAsList) ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
2848 
2849                 GdkColor gdkText = gtk_widget_get_style(gtkCombo)->fg[labelState];
2850 
2851                 QColor textColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
2852 
2853                 pal.setBrush(QPalette::ButtonText, textColor);
2854 
2855                 proxy()->drawItemText(painter, editRect.adjusted(1, 0, -1, 0),
2856                              visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter),
2857                              pal, cb->state & State_Enabled, cb->currentText, QPalette::ButtonText);
2858             }
2859 
2860             painter->restore();
2861         }
2862         break;
2863 
2864 #endif // QT_NO_COMBOBOX
2865 
2866     case CE_DockWidgetTitle:
2867         painter->save();
2868         if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
2869             bool verticalTitleBar = dwOpt->verticalTitleBar;
2870 
2871             QRect rect = dwOpt->rect;
2872             QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, option, widget).adjusted(-2, 0, -2, 0);
2873             QRect r = rect.adjusted(0, 0, -1, -1);
2874             if (verticalTitleBar)
2875                 r.adjust(0, 0, 0, -1);
2876 
2877             if (verticalTitleBar) {
2878                 QRect r = rect;
2879                 r.setSize(r.size().transposed());
2880 
2881                 titleRect = QRect(r.left() + rect.bottom()
2882                                     - titleRect.bottom(),
2883                                 r.top() + titleRect.left() - rect.left(),
2884                                 titleRect.height(), titleRect.width());
2885 
2886                 painter->translate(r.left(), r.top() + r.width());
2887                 painter->rotate(-90);
2888                 painter->translate(-r.left(), -r.top());
2889 
2890                 rect = r;
2891             }
2892 
2893             if (!dwOpt->title.isEmpty()) {
2894                 QString titleText
2895                     = painter->fontMetrics().elidedText(dwOpt->title,
2896                                             Qt::ElideRight, titleRect.width());
2897                 proxy()->drawItemText(painter,
2898                              titleRect,
2899                              Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, dwOpt->palette,
2900                              dwOpt->state & State_Enabled, titleText,
2901                              QPalette::WindowText);
2902                 }
2903         }
2904         painter->restore();
2905         break;
2906 
2907 
2908 
2909     case CE_HeaderSection:
2910         painter->save();
2911 
2912         // Draws the header in tables.
2913         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
2914             Q_UNUSED(header);
2915             GtkWidget *gtkTreeView = d->gtkWidget("GtkTreeView");
2916             // Get the middle column
2917             GtkTreeViewColumn *column = gtk_tree_view_get_column((GtkTreeView*)gtkTreeView, 1);
2918             Q_ASSERT(column);
2919 
2920             GtkWidget *gtkTreeHeader = column->button;
2921             GtkStateType state = qt_gtk_state(option);
2922             GtkShadowType shadow = GTK_SHADOW_OUT;
2923 
2924             if (option->state & State_Sunken)
2925                 shadow = GTK_SHADOW_IN;
2926 
2927             gtkPainter->paintBox(gtkTreeHeader, "button", option->rect.adjusted(-1, 0, 0, 0), state, shadow, gtk_widget_get_style(gtkTreeHeader));
2928         }
2929 
2930         painter->restore();
2931         break;
2932 
2933 #ifndef QT_NO_SIZEGRIP
2934 
2935     case CE_SizeGrip: {
2936         GtkWidget *gtkStatusbar = d->gtkWidget("GtkStatusbar.GtkFrame");
2937         GtkStyle *gtkStatusbarStyle = gtk_widget_get_style(gtkStatusbar);
2938         QRect gripRect = option->rect.adjusted(0, 0, -gtkStatusbarStyle->xthickness, -gtkStatusbarStyle->ythickness);
2939         gtkPainter->paintResizeGrip(gtkStatusbar, "statusbar", gripRect, GTK_STATE_NORMAL,
2940                                     GTK_SHADOW_OUT, option->direction == Qt::RightToLeft ?
2941                                     GDK_WINDOW_EDGE_SOUTH_WEST : GDK_WINDOW_EDGE_SOUTH_EAST,
2942                                     gtkStatusbarStyle);
2943     }
2944     break;
2945 
2946 #endif // QT_NO_SIZEGRIP
2947 
2948     case CE_MenuBarEmptyArea: {
2949         GtkWidget *gtkMenubar = d->gtkWidget("GtkMenuBar");
2950         GdkColor gdkBg = gtk_widget_get_style(gtkMenubar)->bg[GTK_STATE_NORMAL]; // Theme can depend on transparency
2951         painter->fillRect(option->rect, QColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8));
2952         if (widget) { // See CE_MenuBarItem
2953             QRect menuBarRect = widget->rect();
2954             QPixmap pixmap(menuBarRect.size());
2955             pixmap.fill(Qt::transparent);
2956             QPainter pmPainter(&pixmap);
2957             gtkPainter->reset(&pmPainter);
2958             GtkShadowType shadow_type;
2959             gtk_widget_style_get(gtkMenubar, "shadow-type", &shadow_type, NULL);
2960             gtkPainter->paintBox(gtkMenubar, "menubar", menuBarRect,
2961                                  GTK_STATE_NORMAL, shadow_type, gtk_widget_get_style(gtkMenubar));
2962             pmPainter.end();
2963             painter->drawPixmap(option->rect, pixmap, option->rect);
2964             gtkPainter->reset(painter);
2965         }
2966     }
2967     break;
2968 
2969     case CE_MenuBarItem:
2970         painter->save();
2971 
2972         if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
2973             GtkWidget *gtkMenubarItem = d->gtkWidget("GtkMenuBar.GtkMenuItem");
2974             GtkWidget *gtkMenubar = d->gtkWidget("GtkMenuBar");
2975 
2976             style = gtk_widget_get_style(gtkMenubarItem);
2977 
2978             if (widget) {
2979                 // Since Qt does not currently allow filling the entire background
2980                 // we use a hack for this by making a complete menubar each time and
2981                 // paint with the correct offset inside it. Pixmap caching should resolve
2982                 // most of the performance penalty.
2983                 QRect menuBarRect = widget->rect();
2984                 QPixmap pixmap(menuBarRect.size());
2985                 pixmap.fill(Qt::transparent);
2986                 QPainter pmPainter(&pixmap);
2987                 gtkPainter->reset(&pmPainter);
2988                 GtkShadowType shadow_type;
2989                 gtk_widget_style_get(gtkMenubar, "shadow-type", &shadow_type, NULL);
2990                 GdkColor gdkBg = gtk_widget_get_style(gtkMenubar)->bg[GTK_STATE_NORMAL]; // Theme can depend on transparency
2991                 painter->fillRect(option->rect, QColor(gdkBg.red>>8, gdkBg.green>>8, gdkBg.blue>>8));
2992                 gtkPainter->paintBox(gtkMenubar, "menubar", menuBarRect,
2993                                      GTK_STATE_NORMAL, shadow_type, gtk_widget_get_style(gtkMenubar));
2994                 pmPainter.end();
2995                 painter->drawPixmap(option->rect, pixmap, option->rect);
2996                 gtkPainter->reset(painter);
2997             }
2998 
2999             QStyleOptionMenuItem item = *mbi;
3000             bool act = mbi->state & State_Selected && mbi->state & State_Sunken;
3001             bool dis = !(mbi->state & State_Enabled);
3002             item.rect = mbi->rect;
3003             GdkColor gdkText = style->fg[dis ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL];
3004             GdkColor gdkHText = style->fg[GTK_STATE_PRELIGHT];
3005             QColor normalTextColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
3006             QColor highlightedTextColor = QColor(gdkHText.red>>8, gdkHText.green>>8, gdkHText.blue>>8);
3007             item.palette.setBrush(QPalette::HighlightedText, highlightedTextColor);
3008             item.palette.setBrush(QPalette::Text, normalTextColor);
3009             item.palette.setBrush(QPalette::ButtonText, normalTextColor);
3010             QCommonStyle::drawControl(element, &item, painter, widget);
3011 
3012             if (act) {
3013                 GtkShadowType shadowType = GTK_SHADOW_NONE;
3014                 gtk_widget_style_get (gtkMenubarItem, "selected-shadow-type", &shadowType, NULL);
3015                 gtkPainter->paintBox(gtkMenubarItem, "menuitem", option->rect.adjusted(0, 0, 0, 3),
3016                                      GTK_STATE_PRELIGHT, shadowType, style);
3017                 //draw text
3018                 QPalette::ColorRole textRole = dis ? QPalette::Text : QPalette::HighlightedText;
3019                 uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
3020 
3021                 if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
3022                     alignment |= Qt::TextHideMnemonic;
3023 
3024                 proxy()->drawItemText(painter, item.rect, alignment, item.palette, mbi->state & State_Enabled, mbi->text, textRole);
3025             }
3026         }
3027         painter->restore();
3028         break;
3029 
3030     case CE_Splitter: {
3031         GtkWidget *gtkWindow = d->gtkWidget("GtkWindow"); // The Murrine Engine currently assumes a widget is passed
3032         gtkPainter->paintHandle(gtkWindow, "splitter", option->rect, qt_gtk_state(option), GTK_SHADOW_NONE,
3033                                 !(option->state & State_Horizontal) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL,
3034                                 style);
3035     }
3036     break;
3037 
3038 #ifndef QT_NO_TOOLBAR
3039 
3040     case CE_ToolBar:
3041         if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) {
3042             // Reserve the beveled appearance only for mainwindow toolbars
3043             if (!(widget && qobject_cast<const QMainWindow*> (widget->parentWidget())))
3044                 break;
3045 
3046             QRect rect = option->rect;
3047             // There is a 1 pixel gap between toolbar lines in some styles (i.e Human)
3048             if (toolbar->positionWithinLine != QStyleOptionToolBar::End)
3049                 rect.adjust(0, 0, 1, 0);
3050 
3051             GtkWidget *gtkToolbar = d->gtkWidget("GtkToolbar");
3052             GtkShadowType shadow_type = GTK_SHADOW_NONE;
3053             gtk_widget_style_get(gtkToolbar, "shadow-type", &shadow_type, NULL);
3054             gtkPainter->paintBox(gtkToolbar, "toolbar", rect,
3055                                  GTK_STATE_NORMAL, shadow_type, gtk_widget_get_style(gtkToolbar));
3056         }
3057         break;
3058 
3059 #endif // QT_NO_TOOLBAR
3060 
3061     case CE_MenuItem:
3062         painter->save();
3063 
3064         // Draws one item in a popup menu.
3065         if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
3066             const int windowsItemHMargin      =  3; // menu item hor text margin
3067             const int windowsItemVMargin      = 26; // menu item ver text margin
3068             GtkWidget *gtkMenuItem = menuItem->checked ? d->gtkWidget("GtkMenu.GtkCheckMenuItem") :
3069                                      d->gtkWidget("GtkMenu.GtkMenuItem");
3070 
3071             style = gtk_widget_get_style(gtkMenuItem);
3072             QColor shadow = option->palette.dark().color();
3073 
3074             if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
3075                 GtkWidget *gtkMenuSeparator = d->gtkWidget("GtkMenu.GtkSeparatorMenuItem");
3076                 painter->setPen(shadow.lighter(106));
3077                 gboolean wide_separators = 0;
3078                 gint     separator_height = 0;
3079                 guint    horizontal_padding = 3;
3080                 QRect separatorRect = option->rect;
3081                 if (!gtk_check_version(2, 10, 0)) {
3082                     gtk_widget_style_get(gtkMenuSeparator,
3083                                          "wide-separators",    &wide_separators,
3084                                          "separator-height",   &separator_height,
3085                                          "horizontal-padding", &horizontal_padding,
3086                                          NULL);
3087                 }
3088                 GtkStyle *gtkMenuSeparatorStyle = gtk_widget_get_style(gtkMenuSeparator);
3089                 separatorRect.setHeight(option->rect.height() - 2 * gtkMenuSeparatorStyle->ythickness);
3090                 separatorRect.setWidth(option->rect.width() - 2 * (horizontal_padding + gtkMenuSeparatorStyle->xthickness));
3091                 separatorRect.moveCenter(option->rect.center());
3092                 if (wide_separators)
3093                    gtkPainter->paintBox(gtkMenuSeparator, "hseparator",
3094                                         separatorRect, GTK_STATE_NORMAL, GTK_SHADOW_NONE, gtkMenuSeparatorStyle);
3095                 else
3096                     gtkPainter->paintHline(gtkMenuSeparator, "hseparator",
3097                                            separatorRect, GTK_STATE_NORMAL, gtkMenuSeparatorStyle,
3098                                            0, option->rect.right() - 1, 1);
3099                 painter->restore();
3100                 break;
3101             }
3102 
3103             bool selected = menuItem->state & State_Selected && menuItem->state & State_Enabled;
3104 
3105             if (selected) {
3106                 QRect rect = option->rect;
3107 #ifndef QT_NO_COMBOBOX
3108                 if (qobject_cast<const QComboBox*>(widget))
3109                     rect = option->rect;
3110 #endif
3111                 gtkPainter->paintBox(gtkMenuItem, "menuitem", rect, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, style);
3112             }
3113 
3114             bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable;
3115             bool checked = menuItem->checked;
3116             bool enabled = menuItem->state & State_Enabled;
3117             bool ignoreCheckMark = false;
3118 
3119             gint checkSize;
3120             gtk_widget_style_get(d->gtkWidget("GtkMenu.GtkCheckMenuItem"), "indicator-size", &checkSize, NULL);
3121 
3122             int checkcol = qMax(menuItem->maxIconWidth, qMax(20, checkSize));
3123 
3124 #ifndef QT_NO_COMBOBOX
3125 
3126             if (qobject_cast<const QComboBox*>(widget) ||
3127                 (option->styleObject && option->styleObject->property("_q_isComboBoxPopupItem").toBool()))
3128                 ignoreCheckMark = true; // Ignore the checkmarks provided by the QComboMenuDelegate
3129 
3130 #endif
3131             if (!ignoreCheckMark) {
3132                 // Check
3133                 QRect checkRect(option->rect.left() + 7, option->rect.center().y() - checkSize/2 + 1, checkSize, checkSize);
3134                 checkRect = visualRect(menuItem->direction, menuItem->rect, checkRect);
3135 
3136                 if (checkable && menuItem->icon.isNull()) {
3137                     // Some themes such as aero-clone draw slightly outside the paint rect
3138                     int spacing = 1; // ### Consider using gtkCheckBox : "indicator-spacing" instead
3139 
3140                     if (menuItem->checkType & QStyleOptionMenuItem::Exclusive) {
3141                         // Radio button
3142                         GtkShadowType shadow = GTK_SHADOW_OUT;
3143                         GtkStateType state = qt_gtk_state(option);
3144 
3145                         if (selected)
3146                             state = GTK_STATE_PRELIGHT;
3147                         if (checked)
3148                             shadow = GTK_SHADOW_IN;
3149 
3150                         gtkPainter->setClipRect(checkRect.adjusted(-spacing, -spacing, spacing, spacing));
3151                         gtkPainter->paintOption(gtkMenuItem, checkRect.translated(-spacing, -spacing), state, shadow,
3152                                                 style, QLS("option"));
3153                         gtkPainter->setClipRect(QRect());
3154 
3155                     } else {
3156                         // Check box
3157                         if (menuItem->icon.isNull()) {
3158                             GtkShadowType shadow = GTK_SHADOW_OUT;
3159                             GtkStateType state = qt_gtk_state(option);
3160 
3161                             if (selected)
3162                                 state = GTK_STATE_PRELIGHT;
3163                             if (checked)
3164                                 shadow = GTK_SHADOW_IN;
3165 
3166                             gtkPainter->setClipRect(checkRect.adjusted(-spacing, -spacing, -spacing, -spacing));
3167                             gtkPainter->paintCheckbox(gtkMenuItem, checkRect.translated(-spacing, -spacing), state, shadow,
3168                                                       style, QLS("check"));
3169                             gtkPainter->setClipRect(QRect());
3170                         }
3171                     }
3172                 }
3173 
3174             } else {
3175                 // Ignore checkmark
3176                 if (menuItem->icon.isNull())
3177                     checkcol = 0;
3178                 else
3179                     checkcol = menuItem->maxIconWidth;
3180             }
3181 
3182             bool dis = !(menuItem->state & State_Enabled);
3183             bool act = menuItem->state & State_Selected;
3184             const QStyleOption *opt = option;
3185             const QStyleOptionMenuItem *menuitem = menuItem;
3186             QPainter *p = painter;
3187             QRect vCheckRect = visualRect(opt->direction, menuitem->rect,
3188                                           QRect(menuitem->rect.x() + 3, menuitem->rect.y(),
3189                                                 checkcol, menuitem->rect.height()));
3190 
3191             if (!menuItem->icon.isNull()) {
3192                 QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
3193 
3194                 if (act && !dis)
3195                     mode = QIcon::Active;
3196 
3197                 QPixmap pixmap;
3198                 int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize, option, widget);
3199                 QSize iconSize(smallIconSize, smallIconSize);
3200 
3201 #ifndef QT_NO_COMBOBOX
3202                 if (const QComboBox *combo = qobject_cast<const QComboBox*>(widget))
3203                     iconSize = combo->iconSize();
3204 
3205 #endif // QT_NO_COMBOBOX
3206                 if (checked)
3207                     pixmap = menuItem->icon.pixmap(iconSize, mode, QIcon::On);
3208                 else
3209                     pixmap = menuItem->icon.pixmap(iconSize, mode);
3210 
3211                 const int pixw = pixmap.width() / pixmap.devicePixelRatio();
3212                 const int pixh = pixmap.height() / pixmap.devicePixelRatio();
3213                 QRect pmr(0, 0, pixw, pixh);
3214                 pmr.moveCenter(vCheckRect.center() - QPoint(0, 1));
3215                 painter->setPen(menuItem->palette.text().color());
3216                 if (!ignoreCheckMark && checkable && checked) {
3217                     QStyleOption opt = *option;
3218 
3219                     if (act) {
3220                         QColor activeColor = mergedColors(option->palette.background().color(),
3221                                                           option->palette.highlight().color());
3222                         opt.palette.setBrush(QPalette::Button, activeColor);
3223                     }
3224                     opt.state |= State_Sunken;
3225                     opt.rect = vCheckRect;
3226                     proxy()->drawPrimitive(PE_PanelButtonCommand, &opt, painter, widget);
3227                 }
3228                 painter->drawPixmap(pmr.topLeft(), pixmap);
3229             }
3230 
3231             GdkColor gdkText = style->fg[GTK_STATE_NORMAL];
3232             GdkColor gdkDText = style->fg[GTK_STATE_INSENSITIVE];
3233             GdkColor gdkHText = style->fg[GTK_STATE_PRELIGHT];
3234             uint resolve_mask = option->palette.resolve();
3235             QColor textColor = QColor(gdkText.red>>8, gdkText.green>>8, gdkText.blue>>8);
3236             QColor disabledTextColor = QColor(gdkDText.red>>8, gdkDText.green>>8, gdkDText.blue>>8);
3237             if (resolve_mask & (1 << QPalette::ButtonText)) {
3238                 textColor = option->palette.buttonText().color();
3239                 disabledTextColor = option->palette.brush(QPalette::Disabled, QPalette::ButtonText).color();
3240             }
3241 
3242             QColor highlightedTextColor = QColor(gdkHText.red>>8, gdkHText.green>>8, gdkHText.blue>>8);
3243             if (resolve_mask & (1 << QPalette::HighlightedText)) {
3244                 highlightedTextColor = option->palette.highlightedText().color();
3245             }
3246 
3247             if (selected)
3248                 painter->setPen(highlightedTextColor);
3249             else
3250                 painter->setPen(textColor);
3251 
3252             int x, y, w, h;
3253             menuitem->rect.getRect(&x, &y, &w, &h);
3254             int tab = menuitem->tabWidth;
3255             int xm = QGtkStylePrivate::menuItemFrame + checkcol + windowsItemHMargin;
3256             int xpos = menuitem->rect.x() + xm + 1;
3257             QRect textRect(xpos, y + windowsItemVMargin, w - xm - QGtkStylePrivate::menuRightBorder - tab + 1, h - 2 * windowsItemVMargin);
3258             QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect);
3259             QString s = menuitem->text;
3260 
3261             if (!s.isEmpty()) { // Draw text
3262                 p->save();
3263                 int t = s.indexOf(QLatin1Char('\t'));
3264                 int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
3265 
3266                 if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
3267                     text_flags |= Qt::TextHideMnemonic;
3268 
3269                 // Draw shortcut right aligned
3270                 text_flags |= Qt::AlignRight;
3271 
3272                 if (t >= 0) {
3273                     int rightMargin = 12; // Hardcode for now
3274                     QRect vShortcutRect = visualRect(opt->direction, menuitem->rect,
3275                                                      QRect(textRect.topRight(), QPoint(menuitem->rect.right() - rightMargin, textRect.bottom())));
3276 
3277                     if (dis)
3278                         p->setPen(disabledTextColor);
3279                     p->drawText(vShortcutRect, text_flags , s.mid(t + 1));
3280                     s = s.left(t);
3281                 }
3282 
3283                 text_flags &= ~Qt::AlignRight;
3284                 text_flags |= Qt::AlignLeft;
3285                 QFont font = menuitem->font;
3286                 if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
3287                     font.setBold(true);
3288                 p->setFont(font);
3289 
3290                 if (dis)
3291                     p->setPen(disabledTextColor);
3292                 p->drawText(vTextRect, text_flags, s.left(t));
3293                 p->restore();
3294             }
3295 
3296             // Arrow
3297             if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
3298 
3299                 QFontMetrics fm(menuitem->font);
3300                 int arrow_size = fm.ascent() + fm.descent() - 2 * style->ythickness;
3301                 gfloat arrow_scaling = 0.8;
3302                 int extra = 0;
3303                 if (!gtk_check_version(2, 16, 0)) {
3304                     // "arrow-scaling" is actually hardcoded and fails on hardy (see gtk+-2.12/gtkmenuitem.c)
3305                     // though the current documentation states otherwise
3306                     gtk_widget_style_get(gtkMenuItem, "arrow-scaling", &arrow_scaling, NULL);
3307                     // in versions < 2.16 ythickness was previously subtracted from the arrow_size
3308                     extra = 2 * style->ythickness;
3309                 }
3310 
3311                 int horizontal_padding;
3312                 gtk_widget_style_get(gtkMenuItem, "horizontal-padding", &horizontal_padding, NULL);
3313 
3314                 const int dim = static_cast<int>(arrow_size * arrow_scaling) + extra;
3315                 int xpos = menuItem->rect.left() + menuItem->rect.width() - horizontal_padding - dim;
3316                 QRect  vSubMenuRect = visualRect(option->direction, menuItem->rect,
3317                                                  QRect(xpos, menuItem->rect.top() +
3318                                                        menuItem->rect.height() / 2 - dim / 2, dim, dim));
3319                 GtkStateType state = enabled ? (act ? GTK_STATE_PRELIGHT: GTK_STATE_NORMAL) : GTK_STATE_INSENSITIVE;
3320                 GtkShadowType shadowType = (state == GTK_STATE_PRELIGHT) ? GTK_SHADOW_OUT : GTK_SHADOW_IN;
3321                 gtkPainter->paintArrow(gtkMenuItem, "menuitem", vSubMenuRect, option->direction == Qt::RightToLeft ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT, state,
3322                                        shadowType, false, style);
3323             }
3324         }
3325         painter->restore();
3326         break;
3327 
3328     case CE_PushButton:
3329         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
3330             GtkWidget *gtkButton = d->gtkWidget("GtkButton");
3331             proxy()->drawControl(CE_PushButtonBevel, btn, painter, widget);
3332             QStyleOptionButton subopt = *btn;
3333             subopt.rect = subElementRect(SE_PushButtonContents, btn, widget);
3334             gint interiorFocus = true;
3335             gtk_widget_style_get(gtkButton, "interior-focus", &interiorFocus, NULL);
3336             GtkStyle *gtkButtonStyle = gtk_widget_get_style(gtkButton);
3337             int xt = interiorFocus ? gtkButtonStyle->xthickness : 0;
3338             int yt = interiorFocus ? gtkButtonStyle->ythickness : 0;
3339 
3340             if (btn->features & QStyleOptionButton::Flat && btn->state & State_HasFocus)
3341                 // The normal button focus rect does not work well for flat buttons in Clearlooks
3342                 proxy()->drawPrimitive(PE_FrameFocusRect, option, painter, widget);
3343             else if (btn->state & State_HasFocus)
3344                 gtkPainter->paintFocus(gtkButton, "button",
3345                                        option->rect.adjusted(xt, yt, -xt, -yt),
3346                                        btn->state & State_Sunken ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL,
3347                                        gtkButtonStyle);
3348 
3349             proxy()->drawControl(CE_PushButtonLabel, &subopt, painter, widget);
3350         }
3351         break;
3352 
3353 #ifndef QT_NO_TABBAR
3354 
3355     case CE_TabBarTabShape:
3356         if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
3357             GtkWidget *gtkNotebook = d->gtkWidget("GtkNotebook");
3358             style = gtk_widget_get_style(gtkNotebook);
3359 
3360             QRect rect = option->rect;
3361             GtkShadowType shadow = GTK_SHADOW_OUT;
3362             GtkStateType state = GTK_STATE_ACTIVE;
3363             if (tab->state & State_Selected)
3364                 state = GTK_STATE_NORMAL;
3365 
3366             bool selected = (tab->state & State_Selected);
3367             bool first = false, last = false;
3368             if (widget) {
3369                 // This is most accurate and avoids resizing tabs while moving
3370                 first = tab->rect.left() == widget->rect().left();
3371                 last = tab->rect.right() == widget->rect().right();
3372             } else if (option->direction == Qt::RightToLeft) {
3373                 bool tmp = first;
3374                 first = last;
3375                 last = tmp;
3376             }
3377             int topIndent = 3;
3378             int bottomIndent = 1;
3379             int tabOverlap = 1;
3380             painter->save();
3381 
3382             switch (tab->shape) {
3383             case QTabBar::RoundedNorth:
3384                 if (!selected)
3385                     rect.adjust(first ? 0 : -tabOverlap, topIndent, last ? 0 : tabOverlap, -bottomIndent);
3386                 gtkPainter->paintExtention(gtkNotebook, "tab", rect,
3387                                            state, shadow, GTK_POS_BOTTOM, style);
3388                 break;
3389 
3390             case QTabBar::RoundedSouth:
3391                 if (!selected)
3392                     rect.adjust(first ? 0 : -tabOverlap, 0, last ? 0 : tabOverlap, -topIndent);
3393                 gtkPainter->paintExtention(gtkNotebook, "tab", rect.adjusted(0, 1, 0, 0),
3394                                            state, shadow, GTK_POS_TOP, style);
3395                 break;
3396 
3397             case QTabBar::RoundedWest:
3398                 if (!selected)
3399                     rect.adjust(topIndent, 0, -bottomIndent, 0);
3400                 gtkPainter->paintExtention(gtkNotebook, "tab", rect, state, shadow, GTK_POS_RIGHT, style);
3401                 break;
3402 
3403             case QTabBar::RoundedEast:
3404                 if (!selected)
3405                     rect.adjust(bottomIndent, 0, -topIndent, 0);
3406                 gtkPainter->paintExtention(gtkNotebook, "tab", rect, state, shadow, GTK_POS_LEFT, style);
3407                 break;
3408 
3409             default:
3410                 QCommonStyle::drawControl(element, option, painter, widget);
3411                 break;
3412             }
3413 
3414             painter->restore();
3415         }
3416 
3417         break;
3418 
3419 #endif //QT_NO_TABBAR
3420 
3421     case CE_ProgressBarGroove:
3422         if (const QStyleOptionProgressBar *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
3423             Q_UNUSED(bar);
3424             GtkWidget *gtkProgressBar = d->gtkWidget("GtkProgressBar");
3425             GtkStateType state = qt_gtk_state(option);
3426             gtkPainter->paintBox(gtkProgressBar, "trough", option->rect, state, GTK_SHADOW_IN, gtk_widget_get_style(gtkProgressBar));
3427         }
3428 
3429         break;
3430 
3431     case CE_ProgressBarContents:
3432         if (const QStyleOptionProgressBar *bar = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
3433             GtkStateType state = option->state & State_Enabled ? GTK_STATE_NORMAL : GTK_STATE_INSENSITIVE;
3434             GtkWidget *gtkProgressBar = d->gtkWidget("GtkProgressBar");
3435             style = gtk_widget_get_style(gtkProgressBar);
3436             gtkPainter->paintBox(gtkProgressBar, "trough", option->rect, state, GTK_SHADOW_IN, style);
3437             int xt = style->xthickness;
3438             int yt = style->ythickness;
3439             QRect rect = bar->rect.adjusted(xt, yt, -xt, -yt);
3440             bool vertical = (bar->orientation == Qt::Vertical);
3441             bool inverted = bar->invertedAppearance;
3442             bool indeterminate = (bar->minimum == 0 && bar->maximum == 0);
3443 
3444             // If the orientation is vertical, we use a transform to rotate
3445             // the progress bar 90 degrees clockwise.  This way we can use the
3446             // same rendering code for both orientations.
3447             if (vertical) {
3448                 rect.translate(xt, -yt * 2);
3449                 rect = QRect(rect.left(), rect.top(), rect.height(), rect.width()); // Flip width and height
3450                 QTransform m = QTransform::fromTranslate(rect.height(), 0);
3451                 m.rotate(90.0);
3452                 painter->setTransform(m);
3453             }
3454 
3455             int maxWidth = rect.width();
3456             int minWidth = 4;
3457 
3458             qint64 progress = (qint64)qMax(bar->progress, bar->minimum); // Workaround for bug in QProgressBar
3459             double vc6_workaround = ((progress - qint64(bar->minimum)) / double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth;
3460             int progressBarWidth = (int(vc6_workaround) > minWidth ) ? int(vc6_workaround) : minWidth;
3461             int width = indeterminate ? maxWidth : progressBarWidth;
3462             bool reverse = (!vertical && (bar->direction == Qt::RightToLeft)) || vertical;
3463 
3464             if (inverted)
3465                 reverse = !reverse;
3466 
3467             int maximum = 2;
3468             int fakePos = 0;
3469             if (bar->minimum == bar->maximum)
3470                 maximum = 0;
3471             if (bar->progress == bar->maximum)
3472                 fakePos = maximum;
3473             else if (bar->progress > bar->minimum)
3474                 fakePos = maximum - 1;
3475 
3476             QRect progressBar;
3477 
3478             if (!indeterminate) {
3479                 if (!reverse)
3480                     progressBar.setRect(rect.left(), rect.top(), width, rect.height());
3481                 else
3482                     progressBar.setRect(rect.right() - width, rect.top(), width, rect.height());
3483 #ifndef QT_NO_ANIMATION
3484                 d->stopAnimation(option->styleObject);
3485 #endif
3486             } else {
3487                 int slideWidth = ((rect.width() - 4) * 2) / 3;
3488                 int step = 0;
3489 #ifndef QT_NO_ANIMATION
3490                 Q_D(const QGtkStyle);
3491                 if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(option->styleObject)))
3492                     step = animation->progressStep(slideWidth);
3493                 else
3494                     d->startAnimation(new QProgressStyleAnimation(d->animationFps, option->styleObject));
3495 #endif
3496                 progressBar.setRect(rect.left() + step, rect.top(), slideWidth / 2, rect.height());
3497             }
3498 
3499             QString key = QString(QLS("%0")).arg(fakePos);
3500             if (inverted) {
3501                 key += QLatin1String("inv");
3502                 gtkPainter->setFlipHorizontal(true);
3503             }
3504             gtkPainter->paintBox(gtkProgressBar, "bar", progressBar, GTK_STATE_SELECTED, GTK_SHADOW_OUT, style, key);
3505         }
3506 
3507         break;
3508 
3509     default:
3510         QCommonStyle::drawControl(element, option, painter, widget);
3511     }
3512 }
3513 
3514 /*!
3515   \reimp
3516 */
subControlRect(ComplexControl control,const QStyleOptionComplex * option,SubControl subControl,const QWidget * widget) const3517 QRect QGtkStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
3518                                 SubControl subControl, const QWidget *widget) const
3519 {
3520     Q_D(const QGtkStyle);
3521 
3522     QRect rect = QCommonStyle::subControlRect(control, option, subControl, widget);
3523     if (!d->isThemeAvailable())
3524         return QCommonStyle::subControlRect(control, option, subControl, widget);
3525 
3526     switch (control) {
3527     case CC_ScrollBar:
3528         break;
3529     case CC_Slider:
3530         if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
3531             int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
3532             switch (subControl) {
3533             case SC_SliderHandle: {
3534                 if (slider->orientation == Qt::Horizontal) {
3535                     rect.setHeight(proxy()->pixelMetric(PM_SliderThickness));
3536                     rect.setWidth(proxy()->pixelMetric(PM_SliderLength));
3537                     int centerY = slider->rect.center().y() - rect.height() / 2;
3538                     if (slider->tickPosition & QSlider::TicksAbove)
3539                         centerY += tickSize;
3540                     if (slider->tickPosition & QSlider::TicksBelow)
3541                         centerY -= tickSize;
3542                     rect.moveTop(centerY);
3543                 } else {
3544                     rect.setWidth(proxy()->pixelMetric(PM_SliderThickness));
3545                     rect.setHeight(proxy()->pixelMetric(PM_SliderLength));
3546                     int centerX = slider->rect.center().x() - rect.width() / 2;
3547                     if (slider->tickPosition & QSlider::TicksAbove)
3548                         centerX += tickSize;
3549                     if (slider->tickPosition & QSlider::TicksBelow)
3550                         centerX -= tickSize;
3551                     rect.moveLeft(centerX);
3552                 }
3553             }
3554                 break;
3555             case SC_SliderGroove: {
3556                 QPoint grooveCenter = slider->rect.center();
3557                 if (slider->orientation == Qt::Horizontal) {
3558                     rect.setHeight(7);
3559                     if (slider->tickPosition & QSlider::TicksAbove)
3560                         grooveCenter.ry() += tickSize;
3561                     if (slider->tickPosition & QSlider::TicksBelow)
3562                         grooveCenter.ry() -= tickSize;
3563                 } else {
3564                     rect.setWidth(7);
3565                     if (slider->tickPosition & QSlider::TicksAbove)
3566                         grooveCenter.rx() += tickSize;
3567                     if (slider->tickPosition & QSlider::TicksBelow)
3568                         grooveCenter.rx() -= tickSize;
3569                 }
3570                 rect.moveCenter(grooveCenter);
3571                 break;
3572             }
3573             default:
3574                 break;
3575             }
3576         }
3577         break;
3578 
3579 #ifndef QT_NO_GROUPBOX
3580 
3581     case CC_GroupBox:
3582         if (const QStyleOptionGroupBox * groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) {
3583             rect = option->rect.adjusted(0, groupBoxTopMargin, 0, -groupBoxBottomMargin);
3584             int topMargin = 0;
3585             int topHeight = 0;
3586             topHeight = 10;
3587             QRect frameRect = rect;
3588             frameRect.setTop(topMargin);
3589 
3590             if (subControl == SC_GroupBoxFrame)
3591                 return rect;
3592             else if (subControl == SC_GroupBoxContents) {
3593                 int margin = 0;
3594                 int leftMarginExtension = 8;
3595                 return frameRect.adjusted(leftMarginExtension + margin, margin + topHeight + groupBoxTitleMargin, -margin, -margin);
3596             }
3597 
3598             QFontMetrics fontMetrics = option->fontMetrics;
3599             if (qobject_cast<const QGroupBox *>(widget)) {
3600                 //Prepare metrics for a bold font
3601                 QFont font = widget->font();
3602                 font.setBold(true);
3603                 fontMetrics = QFontMetrics(font);
3604             } else if (QStyleHelper::isInstanceOf(groupBox->styleObject, QAccessible::Grouping)) {
3605                 QVariant var = groupBox->styleObject->property("font");
3606                 if (var.isValid() && var.canConvert<QFont>()) {
3607                     QFont font = var.value<QFont>();
3608                     font.setBold(true);
3609                     fontMetrics = QFontMetrics(font);
3610                 }
3611             }
3612 
3613             QSize textRect = fontMetrics.boundingRect(groupBox->text).size() + QSize(4, 4);
3614             int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget);
3615             int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget);
3616 
3617             if (subControl == SC_GroupBoxCheckBox) {
3618                 rect.setWidth(indicatorWidth);
3619                 rect.setHeight(indicatorHeight);
3620                 rect.moveTop((textRect.height() - indicatorHeight) / 2);
3621 
3622             } else if (subControl == SC_GroupBoxLabel) {
3623                 if (groupBox->subControls & SC_GroupBoxCheckBox)
3624                     rect.adjust(indicatorWidth + 4, 0, 0, 0);
3625                 rect.setSize(textRect);
3626             }
3627             rect = visualRect(option->direction, option->rect, rect);
3628         }
3629 
3630         return rect;
3631 
3632 #endif
3633 #ifndef QT_NO_SPINBOX
3634 
3635     case CC_SpinBox:
3636         if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
3637             GtkWidget *gtkSpinButton = d->gtkWidget("GtkSpinButton");
3638             int center = spinbox->rect.height() / 2;
3639             GtkStyle *gtkSpinButtonStyle = gtk_widget_get_style(gtkSpinButton);
3640             int xt = spinbox->frame ? gtkSpinButtonStyle->xthickness : 0;
3641             int yt = spinbox->frame ? gtkSpinButtonStyle->ythickness : 0;
3642             int y = yt;
3643 
3644             QSize bs;
3645             bs.setHeight(qMax(8, spinbox->rect.height()/2 - y));
3646             bs.setWidth(d->getSpinboxArrowSize());
3647             int x, lx, rx;
3648             x = spinbox->rect.width() - y - bs.width() + 2;
3649             lx = xt;
3650             rx = x - xt;
3651 
3652             switch (subControl) {
3653 
3654             case SC_SpinBoxUp:
3655                 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
3656                     return QRect();
3657                 rect = QRect(x, xt, bs.width(), center - yt);
3658                 break;
3659 
3660             case SC_SpinBoxDown:
3661                 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
3662                     return QRect();
3663                 rect = QRect(x, center, bs.width(), spinbox->rect.bottom() - center - yt + 1);
3664                 break;
3665 
3666             case SC_SpinBoxEditField:
3667                 if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons)
3668                     rect = QRect(lx, yt, spinbox->rect.width() - 2*xt, spinbox->rect.height() - 2*yt);
3669                 else
3670                     rect = QRect(lx, yt, rx - qMax(xt - 1, 0), spinbox->rect.height() - 2*yt);
3671                 break;
3672 
3673             case SC_SpinBoxFrame:
3674                 rect = spinbox->rect;
3675 
3676             default:
3677                 break;
3678             }
3679 
3680             rect = visualRect(spinbox->direction, spinbox->rect, rect);
3681         }
3682 
3683         break;
3684 
3685 #endif // Qt_NO_SPINBOX
3686 #ifndef QT_NO_COMBOBOX
3687 
3688     case CC_TitleBar:
3689     if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
3690         SubControl sc = subControl;
3691         QRect &ret = rect;
3692         const int indent = 3;
3693         const int controlTopMargin = 3;
3694         const int controlBottomMargin = 3;
3695         const int controlWidthMargin = 2;
3696         const int controlHeight = tb->rect.height() - controlTopMargin - controlBottomMargin ;
3697         const int delta = controlHeight + controlWidthMargin;
3698         int offset = 0;
3699 
3700         bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
3701         bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
3702 
3703         switch (sc) {
3704         case SC_TitleBarLabel:
3705             if (tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
3706                 ret = tb->rect;
3707                 if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
3708                     ret.adjust(delta, 0, -delta, 0);
3709                 if (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
3710                     ret.adjust(0, 0, -delta, 0);
3711                 if (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
3712                     ret.adjust(0, 0, -delta, 0);
3713                 if (tb->titleBarFlags & Qt::WindowShadeButtonHint)
3714                     ret.adjust(0, 0, -delta, 0);
3715                 if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
3716                     ret.adjust(0, 0, -delta, 0);
3717             }
3718             break;
3719         case SC_TitleBarContextHelpButton:
3720             if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
3721                 offset += delta;
3722         case SC_TitleBarMinButton:
3723             if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
3724                 offset += delta;
3725             else if (sc == SC_TitleBarMinButton)
3726                 break;
3727         case SC_TitleBarNormalButton:
3728             if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
3729                 offset += delta;
3730             else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
3731                 offset += delta;
3732             else if (sc == SC_TitleBarNormalButton)
3733                 break;
3734         case SC_TitleBarMaxButton:
3735             if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
3736                 offset += delta;
3737             else if (sc == SC_TitleBarMaxButton)
3738                 break;
3739         case SC_TitleBarShadeButton:
3740             if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
3741                 offset += delta;
3742             else if (sc == SC_TitleBarShadeButton)
3743                 break;
3744         case SC_TitleBarUnshadeButton:
3745             if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
3746                 offset += delta;
3747             else if (sc == SC_TitleBarUnshadeButton)
3748                 break;
3749         case SC_TitleBarCloseButton:
3750             if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
3751                 offset += delta;
3752             else if (sc == SC_TitleBarCloseButton)
3753                 break;
3754             ret.setRect(tb->rect.right() - indent - offset, tb->rect.top() + controlTopMargin,
3755                         controlHeight, controlHeight);
3756             break;
3757         case SC_TitleBarSysMenu:
3758             if (tb->titleBarFlags & Qt::WindowSystemMenuHint) {
3759                 ret.setRect(tb->rect.left() + controlWidthMargin + indent, tb->rect.top() + controlTopMargin,
3760                             controlHeight, controlHeight);
3761             }
3762             break;
3763         default:
3764             break;
3765         }
3766         ret = visualRect(tb->direction, tb->rect, ret);
3767     }
3768     break;
3769     case CC_ComboBox:
3770         if (const QStyleOptionComboBox *box = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
3771             // We employ the gtk widget to position arrows and separators for us
3772             GtkWidget *gtkCombo = box->editable ? d->gtkWidget("GtkComboBoxEntry")
3773                                                 : d->gtkWidget("GtkComboBox");
3774             gtk_widget_set_direction(gtkCombo, (option->direction == Qt::RightToLeft) ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
3775             GtkAllocation geometry = {0, 0, qMax(0, option->rect.width()), qMax(0, option->rect.height())};
3776             gtk_widget_size_allocate(gtkCombo, &geometry);
3777             int appears_as_list = !proxy()->styleHint(QStyle::SH_ComboBox_Popup, option, widget);
3778             QHashableLatin1Literal arrowPath("GtkComboBoxEntry.GtkToggleButton");
3779             if (!box->editable) {
3780                 if (appears_as_list)
3781                     arrowPath = "GtkComboBox.GtkToggleButton";
3782                 else
3783                     arrowPath = "GtkComboBox.GtkToggleButton.GtkHBox.GtkArrow";
3784             }
3785 
3786             GtkWidget *arrowWidget = d->gtkWidget(arrowPath);
3787             if (!arrowWidget)
3788                 return QCommonStyle::subControlRect(control, option, subControl, widget);
3789 
3790             GtkAllocation allocation;
3791             gtk_widget_get_allocation(arrowWidget, &allocation);
3792             QRect buttonRect(option->rect.left() + allocation.x,
3793                              option->rect.top() + allocation.y,
3794                              allocation.width, allocation.height);
3795 
3796             switch (subControl) {
3797 
3798             case SC_ComboBoxArrow: // Note: this indicates the arrowbutton for editable combos
3799                 rect = buttonRect;
3800                 break;
3801 
3802             case SC_ComboBoxEditField: {
3803                 rect = visualRect(option->direction, option->rect, rect);
3804                 int xMargin = box->editable ? 1 : 4, yMargin = 2;
3805                 GtkStyle *gtkComboStyle = gtk_widget_get_style(gtkCombo);
3806                 rect.setRect(option->rect.left() + gtkComboStyle->xthickness + xMargin,
3807                              option->rect.top()  + gtkComboStyle->ythickness + yMargin,
3808                              option->rect.width() - buttonRect.width() - 2*(gtkComboStyle->xthickness + xMargin),
3809                              option->rect.height() - 2*(gtkComboStyle->ythickness + yMargin));
3810                 rect = visualRect(option->direction, option->rect, rect);
3811                 break;
3812             }
3813 
3814             default:
3815                 break;
3816             }
3817         }
3818 
3819         break;
3820 #endif // QT_NO_COMBOBOX
3821 
3822     default:
3823         break;
3824     }
3825 
3826     return rect;
3827 }
3828 
3829 /*!
3830   \reimp
3831 */
sizeFromContents(ContentsType type,const QStyleOption * option,const QSize & size,const QWidget * widget) const3832 QSize QGtkStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
3833                                   const QSize &size, const QWidget *widget) const
3834 {
3835     Q_D(const QGtkStyle);
3836 
3837     QSize newSize = QCommonStyle::sizeFromContents(type, option, size, widget);
3838     if (!d->isThemeAvailable())
3839         return newSize;
3840 
3841     switch (type) {
3842     case CT_GroupBox:
3843         // Since we use a bold font we have to recalculate base width
3844         if (const QGroupBox *gb = qobject_cast<const QGroupBox*>(widget)) {
3845             QFont font = gb->font();
3846             font.setBold(true);
3847             QFontMetrics metrics(font);
3848             int baseWidth = metrics.width(gb->title()) + metrics.width(QLatin1Char(' '));
3849             if (gb->isCheckable()) {
3850                 baseWidth += proxy()->pixelMetric(QStyle::PM_IndicatorWidth, option, widget);
3851                 baseWidth += proxy()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, option, widget);
3852             }
3853             newSize.setWidth(qMax(baseWidth, newSize.width()));
3854         }
3855         newSize += QSize(4, 1 + groupBoxBottomMargin + groupBoxTopMargin + groupBoxTitleMargin); // Add some space below the groupbox
3856         break;
3857     case CT_ToolButton:
3858         if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
3859             GtkWidget *gtkButton = d->gtkWidget("GtkToolButton.GtkButton");
3860             GtkStyle *gtkButtonStyle = gtk_widget_get_style(gtkButton);
3861             newSize = size + QSize(2 * gtkButtonStyle->xthickness, 2 + 2 * gtkButtonStyle->ythickness);
3862             if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
3863                 QSize minSize(0, 25);
3864                 if (toolbutton->toolButtonStyle != Qt::ToolButtonTextOnly)
3865                     minSize = toolbutton->iconSize + QSize(12, 12);
3866                 newSize = newSize.expandedTo(minSize);
3867             }
3868 
3869             if (toolbutton->features & QStyleOptionToolButton::HasMenu)
3870                 newSize += QSize(6, 0);
3871         }
3872         break;
3873     case CT_SpinBox:
3874         // QSpinBox does some nasty things that depends on CT_LineEdit
3875         newSize = newSize + QSize(0, -gtk_widget_get_style(d->gtkWidget("GtkSpinButton"))->ythickness * 2);
3876         break;
3877     case CT_RadioButton:
3878     case CT_CheckBox:
3879         newSize += QSize(0, 1);
3880         break;
3881     case CT_PushButton:
3882         if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
3883             if (!btn->icon.isNull() && btn->iconSize.height() > 16)
3884                 newSize -= QSize(0, 2); // From cleanlooksstyle
3885             newSize += QSize(0, 1);
3886             GtkWidget *gtkButton = d->gtkWidget("GtkButton");
3887             gint focusPadding, focusWidth;
3888             gtk_widget_style_get(gtkButton, "focus-padding", &focusPadding, NULL);
3889             gtk_widget_style_get(gtkButton, "focus-line-width", &focusWidth, NULL);
3890             newSize = size;
3891             GtkStyle *gtkButtonStyle = gtk_widget_get_style(gtkButton);
3892             newSize += QSize(2*gtkButtonStyle->xthickness + 4, 2*gtkButtonStyle->ythickness);
3893             newSize += QSize(2*(focusWidth + focusPadding + 2), 2*(focusWidth + focusPadding));
3894 
3895             GtkWidget *gtkButtonBox = d->gtkWidget("GtkHButtonBox");
3896             gint minWidth = 85, minHeight = 0;
3897             gtk_widget_style_get(gtkButtonBox, "child-min-width", &minWidth,
3898                                    "child-min-height", &minHeight, NULL);
3899             if (!btn->text.isEmpty() && newSize.width() < minWidth)
3900                 newSize.setWidth(minWidth);
3901             if (newSize.height() < minHeight)
3902                 newSize.setHeight(minHeight);
3903         }
3904         break;
3905     case CT_Slider: {
3906         GtkWidget *gtkSlider = d->gtkWidget("GtkHScale");
3907         GtkStyle *gtkSliderStyle = gtk_widget_get_style(gtkSlider);
3908         newSize = size + QSize(2*gtkSliderStyle->xthickness, 2*gtkSliderStyle->ythickness); }
3909         break;
3910     case CT_LineEdit: {
3911         GtkWidget *gtkEntry = d->gtkWidget("GtkEntry");
3912         GtkStyle *gtkEntryStyle = gtk_widget_get_style(gtkEntry);
3913         newSize = size + QSize(2*gtkEntryStyle->xthickness, 2 + 2*gtkEntryStyle->ythickness); }
3914         break;
3915     case CT_ItemViewItem:
3916         newSize += QSize(0, 2);
3917         break;
3918     case CT_ComboBox:
3919         if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
3920             GtkWidget *gtkCombo = d->gtkWidget("GtkComboBox");
3921             QRect arrowButtonRect = proxy()->subControlRect(CC_ComboBox, combo, SC_ComboBoxArrow, widget);
3922             GtkStyle *gtkComboStyle = gtk_widget_get_style(gtkCombo);
3923             newSize = size + QSize(12 + arrowButtonRect.width() + 2*gtkComboStyle->xthickness, 4 + 2*gtkComboStyle->ythickness);
3924 
3925             if (!(widget && qobject_cast<QToolBar *>(widget->parentWidget())))
3926                 newSize += QSize(0, 2);
3927         }
3928         break;
3929     case CT_TabBarTab:
3930         if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
3931             if (!tab->icon.isNull())
3932                 newSize += QSize(6, 0);
3933         }
3934         newSize += QSize(1, 1);
3935         break;
3936     case CT_MenuBarItem:
3937         newSize += QSize(QGtkStylePrivate::menuItemHMargin * 4, QGtkStylePrivate::menuItemVMargin * 2 + 2);
3938         break;
3939     case CT_SizeGrip:
3940         newSize += QSize(4, 4);
3941         break;
3942     case CT_MdiControls:
3943         if (const QStyleOptionComplex *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(option)) {
3944             int width = 0;
3945             if (styleOpt->subControls & SC_MdiMinButton)
3946                 width += 19 + 1;
3947             if (styleOpt->subControls & SC_MdiNormalButton)
3948                 width += 19 + 1;
3949             if (styleOpt->subControls & SC_MdiCloseButton)
3950                 width += 19 + 1;
3951             newSize = QSize(width, 19);
3952         } else {
3953             newSize = QSize(60, 19);
3954         }
3955     break;
3956     case CT_MenuItem:
3957         if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
3958             int w = newSize.width();
3959             int maxpmw = menuItem->maxIconWidth;
3960             int tabSpacing = 20;
3961             if (menuItem->text.contains(QLatin1Char('\t')))
3962                 w += tabSpacing;
3963             else if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu)
3964                 w += 2 * QGtkStylePrivate::menuArrowHMargin;
3965             else if (menuItem->menuItemType == QStyleOptionMenuItem::DefaultItem) {
3966                 // adjust the font and add the difference in size.
3967                 // it would be better if the font could be adjusted in the initStyleOption qmenu func!!
3968                 QFontMetrics fm(menuItem->font);
3969                 QFont fontBold = menuItem->font;
3970                 fontBold.setBold(true);
3971                 QFontMetrics fmBold(fontBold);
3972                 w += fmBold.width(menuItem->text) - fm.width(menuItem->text);
3973             }
3974 
3975             int checkcol = qMax<int>(maxpmw, QGtkStylePrivate::menuCheckMarkWidth); // Windows always shows a check column
3976             w += checkcol;
3977             w += int(QGtkStylePrivate::menuRightBorder) + 10;
3978 
3979             newSize.setWidth(w);
3980 
3981             int textMargin = 8;
3982             if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) {
3983                 GtkWidget *gtkMenuSeparator = d->gtkWidget("GtkMenu.GtkSeparatorMenuItem");
3984                 GtkRequisition sizeReq = {0, 0};
3985                 gtk_widget_size_request(gtkMenuSeparator, &sizeReq);
3986                 newSize = QSize(newSize.width(), sizeReq.height);
3987                 break;
3988             }
3989 
3990             GtkWidget *gtkMenuItem = d->gtkWidget("GtkMenu.GtkCheckMenuItem");
3991             GtkStyle* style = gtk_widget_get_style(gtkMenuItem);
3992 
3993             // Note we get the perfect height for the default font since we
3994             // set a fake text label on the gtkMenuItem
3995             // But if custom fonts are used on the widget we need a minimum size
3996             GtkRequisition sizeReq = {0, 0};
3997             gtk_widget_size_request(gtkMenuItem, &sizeReq);
3998             newSize.setHeight(qMax(newSize.height() - 4, sizeReq.height));
3999             newSize += QSize(textMargin + style->xthickness - 1, 0);
4000 
4001             gint checkSize;
4002             gtk_widget_style_get(gtkMenuItem, "indicator-size", &checkSize, NULL);
4003             newSize.setWidth(newSize.width() + qMax(0, checkSize - 20));
4004         }
4005         break;
4006     default:
4007         break;
4008     }
4009 
4010     return newSize;
4011 }
4012 
4013 
4014 /*! \reimp */
standardPixmap(StandardPixmap sp,const QStyleOption * option,const QWidget * widget) const4015 QPixmap QGtkStyle::standardPixmap(StandardPixmap sp, const QStyleOption *option,
4016                                   const QWidget *widget) const
4017 {
4018     Q_D(const QGtkStyle);
4019 
4020     if (!d->isThemeAvailable())
4021         return QCommonStyle::standardPixmap(sp, option, widget);
4022 
4023     QPixmap pixmap;
4024     switch (sp) {
4025 
4026     case SP_TitleBarNormalButton: {
4027         QImage restoreButton(dock_widget_restore_xpm);
4028         QColor alphaCorner = restoreButton.color(2);
4029         alphaCorner.setAlpha(80);
4030         restoreButton.setColor(2, alphaCorner.rgba());
4031         alphaCorner.setAlpha(180);
4032         restoreButton.setColor(4, alphaCorner.rgba());
4033         return QPixmap::fromImage(restoreButton);
4034     }
4035     break;
4036 
4037     case SP_TitleBarCloseButton: // Fall through
4038     case SP_DockWidgetCloseButton: {
4039 
4040         QImage closeButton(dock_widget_close_xpm);
4041         QColor alphaCorner = closeButton.color(2);
4042         alphaCorner.setAlpha(80);
4043         closeButton.setColor(2, alphaCorner.rgba());
4044         return QPixmap::fromImage(closeButton);
4045     }
4046     break;
4047 
4048     case SP_DialogDiscardButton:
4049         return qt_gtk_get_icon(GTK_STOCK_DELETE);
4050     case SP_DialogOkButton:
4051         return qt_gtk_get_icon(GTK_STOCK_OK);
4052     case SP_DialogCancelButton:
4053         return qt_gtk_get_icon(GTK_STOCK_CANCEL);
4054     case SP_DialogYesButton:
4055         return qt_gtk_get_icon(GTK_STOCK_YES);
4056     case SP_DialogNoButton:
4057         return qt_gtk_get_icon(GTK_STOCK_NO);
4058     case SP_DialogOpenButton:
4059         return qt_gtk_get_icon(GTK_STOCK_OPEN);
4060     case SP_DialogCloseButton:
4061         return qt_gtk_get_icon(GTK_STOCK_CLOSE);
4062     case SP_DialogApplyButton:
4063         return qt_gtk_get_icon(GTK_STOCK_APPLY);
4064     case SP_DialogSaveButton:
4065         return qt_gtk_get_icon(GTK_STOCK_SAVE);
4066     case SP_MessageBoxWarning:
4067         return qt_gtk_get_icon(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
4068     case SP_MessageBoxQuestion:
4069         return qt_gtk_get_icon(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
4070     case SP_MessageBoxInformation:
4071         return qt_gtk_get_icon(GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
4072     case SP_MessageBoxCritical:
4073         return qt_gtk_get_icon(GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG);
4074     default:
4075         return QCommonStyle::standardPixmap(sp, option, widget);
4076     }
4077     return pixmap;
4078 }
4079 
4080 /*!
4081     \reimp
4082 */
standardIcon(StandardPixmap standardIcon,const QStyleOption * option,const QWidget * widget) const4083 QIcon QGtkStyle::standardIcon(StandardPixmap standardIcon,
4084                               const QStyleOption *option,
4085                               const QWidget *widget) const
4086 {
4087     Q_D(const QGtkStyle);
4088 
4089     if (!d->isThemeAvailable())
4090         return QCommonStyle::standardIcon(standardIcon, option, widget);
4091     switch (standardIcon) {
4092     case SP_DialogDiscardButton:
4093         return qt_gtk_get_icon(GTK_STOCK_DELETE);
4094     case SP_DialogOkButton:
4095         return qt_gtk_get_icon(GTK_STOCK_OK);
4096     case SP_DialogCancelButton:
4097         return qt_gtk_get_icon(GTK_STOCK_CANCEL);
4098     case SP_DialogYesButton:
4099         return qt_gtk_get_icon(GTK_STOCK_YES);
4100     case SP_DialogNoButton:
4101         return qt_gtk_get_icon(GTK_STOCK_NO);
4102     case SP_DialogOpenButton:
4103         return qt_gtk_get_icon(GTK_STOCK_OPEN);
4104     case SP_DialogCloseButton:
4105         return qt_gtk_get_icon(GTK_STOCK_CLOSE);
4106     case SP_DialogApplyButton:
4107         return qt_gtk_get_icon(GTK_STOCK_APPLY);
4108     case SP_DialogSaveButton:
4109         return qt_gtk_get_icon(GTK_STOCK_SAVE);
4110     case SP_MessageBoxWarning:
4111         return qt_gtk_get_icon(GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG);
4112     case SP_MessageBoxQuestion:
4113         return qt_gtk_get_icon(GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
4114     case SP_MessageBoxInformation:
4115         return qt_gtk_get_icon(GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
4116     case SP_MessageBoxCritical:
4117         return qt_gtk_get_icon(GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG);
4118     default:
4119         return QCommonStyle::standardIcon(standardIcon, option, widget);
4120     }
4121 }
4122 
4123 
4124 /*! \reimp */
subElementRect(SubElement element,const QStyleOption * option,const QWidget * widget) const4125 QRect QGtkStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
4126 {
4127     Q_D(const QGtkStyle);
4128 
4129     QRect r = QCommonStyle::subElementRect(element, option, widget);
4130     if (!d->isThemeAvailable())
4131         return r;
4132 
4133     switch (element) {
4134     case SE_PushButtonFocusRect:
4135         r.adjust(0, 1, 0, -1);
4136         break;
4137     case SE_DockWidgetTitleBarText: {
4138         const QStyleOptionDockWidget *dwOpt
4139             = qstyleoption_cast<const QStyleOptionDockWidget*>(option);
4140         bool verticalTitleBar = dwOpt && dwOpt->verticalTitleBar;
4141         if (verticalTitleBar) {
4142             r.adjust(0, 0, 0, -4);
4143         } else {
4144             if (option->direction == Qt::LeftToRight)
4145                 r.adjust(4, 0, 0, 0);
4146             else
4147                 r.adjust(0, 0, -4, 0);
4148         }
4149 
4150         break;
4151     }
4152     case SE_ProgressBarLabel:
4153     case SE_ProgressBarContents:
4154     case SE_ProgressBarGroove:
4155         return option->rect;
4156     case SE_PushButtonContents:
4157         if (!gtk_check_version(2, 10, 0)) {
4158             GtkWidget *gtkButton = d->gtkWidget("GtkButton");
4159             GtkBorder *border = 0;
4160             gtk_widget_style_get(gtkButton, "inner-border", &border, NULL);
4161             if (border) {
4162                 r = option->rect.adjusted(border->left, border->top, -border->right, -border->bottom);
4163                 gtk_border_free(border);
4164             } else {
4165                 r = option->rect.adjusted(1, 1, -1, -1);
4166             }
4167             r = visualRect(option->direction, option->rect, r);
4168         }
4169         break;
4170     default:
4171         break;
4172     }
4173 
4174     return r;
4175 }
4176 
4177 /*!
4178   \reimp
4179 */
itemPixmapRect(const QRect & r,int flags,const QPixmap & pixmap) const4180 QRect QGtkStyle::itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const
4181 {
4182     return QCommonStyle::itemPixmapRect(r, flags, pixmap);
4183 }
4184 
4185 /*!
4186   \reimp
4187 */
drawItemPixmap(QPainter * painter,const QRect & rect,int alignment,const QPixmap & pixmap) const4188 void QGtkStyle::drawItemPixmap(QPainter *painter, const QRect &rect,
4189                             int alignment, const QPixmap &pixmap) const
4190 {
4191     QCommonStyle::drawItemPixmap(painter, rect, alignment, pixmap);
4192 }
4193 
4194 /*!
4195   \reimp
4196 */
hitTestComplexControl(ComplexControl cc,const QStyleOptionComplex * opt,const QPoint & pt,const QWidget * w) const4197 QStyle::SubControl QGtkStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
4198                               const QPoint &pt, const QWidget *w) const
4199 {
4200     return QCommonStyle::hitTestComplexControl(cc, opt, pt, w);
4201 }
4202 
4203 /*!
4204   \reimp
4205 */
generatedIconPixmap(QIcon::Mode iconMode,const QPixmap & pixmap,const QStyleOption * opt) const4206 QPixmap QGtkStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
4207                                         const QStyleOption *opt) const
4208 {
4209     return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
4210 }
4211 
4212 /*!
4213   \reimp
4214 */
drawItemText(QPainter * painter,const QRect & rect,int alignment,const QPalette & pal,bool enabled,const QString & text,QPalette::ColorRole textRole) const4215 void QGtkStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal,
4216                                     bool enabled, const QString& text, QPalette::ColorRole textRole) const
4217 {
4218     return QCommonStyle::drawItemText(painter, rect, alignment, pal, enabled, text, textRole);
4219 }
4220 
4221 QT_END_NAMESPACE
4222