QMacStyle: Fix QTabBar appearance on Yosemite
[qt:qtbase.git] / src / widgets / styles / qmacstyle_mac.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 /*
43   Note: The qdoc comments for QMacStyle are contained in
44   .../doc/src/qstyles.qdoc.
45 */
46
47 #include <Cocoa/Cocoa.h>
48
49 #include "qmacstyle_mac_p.h"
50 #include "qmacstyle_mac_p_p.h"
51
52 #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
53 //#define DEBUG_SIZE_CONSTRAINT
54
55 #include <private/qcore_mac_p.h>
56 #include <private/qcombobox_p.h>
57 #include <private/qpainter_p.h>
58 #include <qapplication.h>
59 #include <qbitmap.h>
60 #include <qcheckbox.h>
61 #include <qcombobox.h>
62 #include <qdialogbuttonbox.h>
63 #include <qdockwidget.h>
64 #include <qevent.h>
65 #include <qfocusframe.h>
66 #include <qformlayout.h>
67 #include <qgroupbox.h>
68 #include <qhash.h>
69 #include <qheaderview.h>
70 #include <qlineedit.h>
71 #include <qmainwindow.h>
72 #include <qmdisubwindow.h>
73 #include <qmenubar.h>
74 #include <qpaintdevice.h>
75 #include <qpainter.h>
76 #include <qpixmapcache.h>
77 #include <qpointer.h>
78 #include <qprogressbar.h>
79 #include <qpushbutton.h>
80 #include <qradiobutton.h>
81 #include <qrubberband.h>
82 #include <qscrollbar.h>
83 #include <qsizegrip.h>
84 #include <qstyleoption.h>
85 #include <qtoolbar.h>
86 #include <qtoolbutton.h>
87 #include <qtreeview.h>
88 #include <qtableview.h>
89 #include <qwizard.h>
90 #include <qdebug.h>
91 #include <qlibrary.h>
92 #include <qdatetimeedit.h>
93 #include <qmath.h>
94 #include <QtWidgets/qgraphicsproxywidget.h>
95 #include <QtWidgets/qgraphicsview.h>
96 #include <private/qstylehelper_p.h>
97 #include <private/qstyleanimation_p.h>
98 #include <qpa/qplatformfontdatabase.h>
99 #include <qpa/qplatformtheme.h>
100
101 QT_USE_NAMESPACE
102
103 @interface QT_MANGLE_NAMESPACE(NotificationReceiver) : NSObject {
104 QMacStylePrivate *mPrivate;
105 }
106 - (id)initWithPrivate:(QMacStylePrivate *)priv;
107 - (void)scrollBarStyleDidChange:(NSNotification *)notification;
108 @end
109
110 QT_NAMESPACE_ALIAS_OBJC_CLASS(NotificationReceiver);
111
112 @implementation NotificationReceiver
113 - (id)initWithPrivate:(QMacStylePrivate *)priv
114 {
115     self = [super init];
116     mPrivate = priv;
117     return self;
118 }
119
120 - (void)scrollBarStyleDidChange:(NSNotification *)notification
121 {
122     Q_UNUSED(notification);
123     QEvent event(QEvent::StyleChange);
124     QMutableSetIterator<QPointer<QObject> > it(QMacStylePrivate::scrollBars);
125     while (it.hasNext()) {
126         if (!it.next())
127             it.remove();
128         else
129             QCoreApplication::sendEvent(it.value(), &event);
130     }
131 }
132 @end
133
134 QT_BEGIN_NAMESPACE
135
136 // The following constants are used for adjusting the size
137 // of push buttons so that they are drawn inside their bounds.
138 const int QMacStylePrivate::PushButtonLeftOffset = 6;
139 const int QMacStylePrivate::PushButtonTopOffset = 4;
140 const int QMacStylePrivate::PushButtonRightOffset = 12;
141 const int QMacStylePrivate::PushButtonBottomOffset = 12;
142 const int QMacStylePrivate::MiniButtonH = 26;
143 const int QMacStylePrivate::SmallButtonH = 30;
144 const int QMacStylePrivate::BevelButtonW = 50;
145 const int QMacStylePrivate::BevelButtonH = 22;
146 const int QMacStylePrivate::PushButtonContentPadding = 6;
147
148 QSet<QPointer<QObject> > QMacStylePrivate::scrollBars;
149
150 static uint qHash(const QPointer<QObject> &ptr)
151 {
152     return qHash(ptr.data());
153 }
154
155 // These colors specify the titlebar gradient colors on
156 // Leopard. Ideally we should get them from the system.
157 static const QColor titlebarGradientActiveBegin(220, 220, 220);
158 static const QColor titlebarGradientActiveEnd(151, 151, 151);
159 static const QColor titlebarSeparatorLineActive(111, 111, 111);
160 static const QColor titlebarGradientInactiveBegin(241, 241, 241);
161 static const QColor titlebarGradientInactiveEnd(207, 207, 207);
162 static const QColor titlebarSeparatorLineInactive(131, 131, 131);
163
164 // Gradient colors used for the dock widget title bar and
165 // non-unifed tool bar bacground.
166 static const QColor mainWindowGradientBegin(240, 240, 240);
167 static const QColor mainWindowGradientEnd(200, 200, 200);
168
169 static const int DisclosureOffset = 4;
170
171 // Resolve these at run-time, since the functions was moved in Leopard.
172 typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *);
173 static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0;
174
175 static int closeButtonSize = 12;
176 static bool isVerticalTabs(const QTabBar::Shape shape) {
177     return (shape == QTabBar::RoundedEast
178                 || shape == QTabBar::TriangularEast
179                 || shape == QTabBar::RoundedWest
180                 || shape == QTabBar::TriangularWest);
181 }
182
183 static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY)
184 {
185     QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
186     QPlatformNativeInterface::NativeResourceForIntegrationFunction function =
187         nativeInterface->nativeResourceFunctionForIntegration("testContentBorderPosition");
188     if (!function)
189         return false; // Not Cocoa platform plugin.
190
191     typedef bool (*TestContentBorderPositionFunction)(QWindow *, int);
192     return (reinterpret_cast<TestContentBorderPositionFunction>(function))(window, windowY);
193 }
194
195
196 void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
197 {
198     // draw background circle
199     p->setRenderHints(QPainter::Antialiasing);
200     QRect rect(0, 0, closeButtonSize, closeButtonSize);
201     QColor background;
202     if (hover) {
203         background = QColor(124, 124, 124);
204     } else {
205         if (active) {
206             if (selected)
207                 background = QColor(104, 104, 104);
208             else
209                 background = QColor(83, 83, 83);
210         } else {
211             if (selected)
212                 background = QColor(144, 144, 144);
213             else
214                 background = QColor(114, 114, 114);
215         }
216     }
217     p->setPen(Qt::transparent);
218     p->setBrush(background);
219     p->drawEllipse(rect);
220
221     // draw cross
222     int min = 3;
223     int max = 9;
224     QPen crossPen;
225     crossPen.setColor(QColor(194, 194, 194));
226     crossPen.setWidthF(1.3);
227     crossPen.setCapStyle(Qt::FlatCap);
228     p->setPen(crossPen);
229     p->drawLine(min, min, max, max);
230     p->drawLine(min, max, max, min);
231 }
232
233 QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect)
234 {
235     if (isVerticalTabs(shape)) {
236         int newX, newY, newRot;
237         if (shape == QTabBar::RoundedEast
238             || shape == QTabBar::TriangularEast) {
239             newX = tabRect.width();
240             newY = tabRect.y();
241             newRot = 90;
242         } else {
243             newX = 0;
244             newY = tabRect.y() + tabRect.height();
245             newRot = -90;
246         }
247         tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
248         QMatrix m;
249         m.translate(newX, newY);
250         m.rotate(newRot);
251         p->setMatrix(m, true);
252     }
253     return tabRect;
254 }
255
256 void drawTabShape(QPainter *p, const QStyleOptionTabV3 *tabOpt, bool isUnified)
257 {
258     QRect r = tabOpt->rect;
259     p->translate(tabOpt->rect.x(), tabOpt->rect.y());
260     r.moveLeft(0);
261     r.moveTop(0);
262     QRect tabRect = rotateTabPainter(p, tabOpt->shape, r);
263
264     int width = tabRect.width();
265     int height = 20;
266     bool active = (tabOpt->state & QStyle::State_Active);
267     bool selected = (tabOpt->state & QStyle::State_Selected);
268
269     if (selected) {
270         QRect rect(1, 0, width - 2, height);
271
272         // fill body
273         if (tabOpt->documentMode && isUnified) {
274             p->save();
275             p->setCompositionMode(QPainter::CompositionMode_Source);
276             p->fillRect(rect, QColor(Qt::transparent));
277             p->restore();
278         } else if (active) {
279             int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 16 : 0;
280             p->fillRect(rect, QColor(151 + d, 151 + d, 151 + d));
281         } else {
282             int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 9 : 0;
283             QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
284             gradient.setColorAt(0, QColor(207 + d, 207 + d, 207 + d));
285             gradient.setColorAt(0.5, QColor(206 + d, 206 + d, 206 + d));
286             gradient.setColorAt(1, QColor(201 + d, 201 + d, 201 + d));
287             p->fillRect(rect, gradient);
288         }
289
290         // draw border
291         QColor borderSides;
292         QColor borderBottom;
293         if (active) {
294             borderSides = QColor(88, 88, 88);
295             borderBottom = QColor(88, 88, 88);
296         } else {
297             borderSides = QColor(121, 121, 121);
298             borderBottom = QColor(116, 116, 116);
299         }
300
301         p->setPen(borderSides);
302
303         int bottom = height;
304         // left line
305         p->drawLine(0, 1, 0, bottom-2);
306         // right line
307         p->drawLine(width-1, 1, width-1, bottom-2);
308
309         // bottom line
310         if (active) {
311             p->setPen(QColor(168, 168, 168));
312             p->drawLine(3, bottom-1, width-3, bottom-1);
313         }
314         p->setPen(borderBottom);
315         p->drawLine(2, bottom, width-2, bottom);
316
317         int w = 3;
318         QRectF rectangleLeft(1, height - w, w, w);
319         QRectF rectangleRight(width - 2, height - 1, w, w);
320         int startAngle = 180 * 16;
321         int spanAngle = 90 * 16;
322         p->setRenderHint(QPainter::Antialiasing);
323         p->drawArc(rectangleLeft, startAngle, spanAngle);
324         p->drawArc(rectangleRight, startAngle, -spanAngle);
325     } else {
326         // when the mouse is over non selected tabs they get a new color
327         bool hover = (tabOpt->state & QStyle::State_MouseOver);
328         if (hover) {
329             QRect rect(1, 2, width - 1, height - 1);
330             p->fillRect(rect, QColor(110, 110, 110));
331         }
332
333         // seperator lines between tabs
334         bool west = (tabOpt->shape == QTabBar::RoundedWest || tabOpt->shape == QTabBar::TriangularWest);
335         bool drawOnRight = !west;
336         if ((!drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)
337             || (drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)) {
338             QColor borderColor;
339             QColor borderHighlightColor;
340             if (active) {
341                 borderColor = QColor(64, 64, 64);
342                 borderHighlightColor = QColor(140, 140, 140);
343             } else {
344                 borderColor = QColor(135, 135, 135);
345                 borderHighlightColor = QColor(178, 178, 178);
346             }
347
348             int x = drawOnRight ? width : 0;
349
350             // tab seperator line
351             p->setPen(borderColor);
352             p->drawLine(x, 2, x, height + 1);
353
354             // tab seperator highlight
355             p->setPen(borderHighlightColor);
356             p->drawLine(x-1, 2, x-1, height + 1);
357             p->drawLine(x+1, 2, x+1, height + 1);
358         }
359     }
360 }
361
362 void drawTabBase(QPainter *p, const QStyleOptionTabBarBaseV2 *tbb, const QWidget *w)
363 {
364     QRect r = tbb->rect;
365     if (isVerticalTabs(tbb->shape)) {
366         r.setWidth(w->width());
367     } else {
368         r.setHeight(w->height());
369     }
370     QRect tabRect = rotateTabPainter(p, tbb->shape, r);
371     int width = tabRect.width();
372     int height = tabRect.height();
373     bool active = (tbb->state & QStyle::State_Active);
374
375     // top border lines
376     QColor borderHighlightTop;
377     QColor borderTop;
378     if (active) {
379         borderTop = QColor(64, 64, 64);
380         borderHighlightTop = QColor(174, 174, 174);
381     } else {
382         borderTop = QColor(135, 135, 135);
383         borderHighlightTop = QColor(207, 207, 207);
384     }
385     p->setPen(borderHighlightTop);
386     p->drawLine(tabRect.x(), 0, width, 0);
387     p->setPen(borderTop);
388     p->drawLine(tabRect.x(), 1, width, 1);
389
390     // center block
391     QRect centralRect(tabRect.x(), 2, width, height - 2);
392     if (active) {
393         QColor mainColor = QColor(120, 120, 120);
394         p->fillRect(centralRect, mainColor);
395     } else {
396         QLinearGradient gradient(centralRect.topLeft(), centralRect.bottomLeft());
397         gradient.setColorAt(0, QColor(165, 165, 165));
398         gradient.setColorAt(0.5, QColor(164, 164, 164));
399         gradient.setColorAt(1, QColor(158, 158, 158));
400         p->fillRect(centralRect, gradient);
401     }
402
403     // bottom border lines
404     QColor borderHighlightBottom;
405     QColor borderBottom;
406     if (active) {
407         borderHighlightBottom = QColor(153, 153, 153);
408         borderBottom = QColor(64, 64, 64);
409     } else {
410         borderHighlightBottom = QColor(177, 177, 177);
411         borderBottom = QColor(127, 127, 127);
412     }
413     p->setPen(borderHighlightBottom);
414     p->drawLine(tabRect.x(), height - 2, width, height - 2);
415     p->setPen(borderBottom);
416     p->drawLine(tabRect.x(), height - 1, width, height - 1);
417 }
418
419 static int getControlSize(const QStyleOption *option, const QWidget *widget)
420 {
421     switch (QMacStyle::widgetSizePolicy(widget, option)) {
422     case QMacStyle::SizeSmall:
423         return QAquaSizeSmall;
424     case QMacStyle::SizeMini:
425         return QAquaSizeMini;
426     default:
427         break;
428     }
429     return QAquaSizeLarge;
430 }
431
432
433 static inline bool isTreeView(const QWidget *widget)
434 {
435     return (widget && widget->parentWidget() &&
436             (qobject_cast<const QTreeView *>(widget->parentWidget())
437              ));
438 }
439
440 static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
441 {
442     ThemeTabDirection ttd;
443     switch (shape) {
444     case QTabBar::RoundedSouth:
445     case QTabBar::TriangularSouth:
446         ttd = kThemeTabSouth;
447         break;
448     default:  // Added to remove the warning, since all values are taken care of, really!
449     case QTabBar::RoundedNorth:
450     case QTabBar::TriangularNorth:
451         ttd = kThemeTabNorth;
452         break;
453     case QTabBar::RoundedWest:
454     case QTabBar::TriangularWest:
455         ttd = kThemeTabWest;
456         break;
457     case QTabBar::RoundedEast:
458     case QTabBar::TriangularEast:
459         ttd = kThemeTabEast;
460         break;
461     }
462     return ttd;
463 }
464
465 static QString qt_mac_removeMnemonics(const QString &original)
466 {
467     QString returnText(original.size(), 0);
468     int finalDest = 0;
469     int currPos = 0;
470     int l = original.length();
471     while (l) {
472         if (original.at(currPos) == QLatin1Char('&')
473             && (l == 1 || original.at(currPos + 1) != QLatin1Char('&'))) {
474             ++currPos;
475             --l;
476             if (l == 0)
477                 break;
478         }
479         returnText[finalDest] = original.at(currPos);
480         ++currPos;
481         ++finalDest;
482         --l;
483     }
484     returnText.truncate(finalDest);
485     return returnText;
486 }
487
488 static CGContextRef qt_mac_cg_context(const QPaintDevice *pdev);
489
490 namespace {
491 class QMacCGContext
492 {
493     CGContextRef context;
494 public:
495     QMacCGContext(QPainter *p);
496     inline QMacCGContext() { context = 0; }
497     inline QMacCGContext(const QPaintDevice *pdev) {
498         context = qt_mac_cg_context(pdev);
499     }
500     inline QMacCGContext(CGContextRef cg, bool takeOwnership=false) {
501         context = cg;
502         if (!takeOwnership)
503             CGContextRetain(context);
504     }
505     inline QMacCGContext(const QMacCGContext &copy) : context(0) { *this = copy; }
506     inline ~QMacCGContext() {
507         if (context)
508             CGContextRelease(context);
509     }
510     inline bool isNull() const { return context; }
511     inline operator CGContextRef() { return context; }
512     inline QMacCGContext &operator=(const QMacCGContext &copy) {
513         if (context)
514             CGContextRelease(context);
515         context = copy.context;
516         CGContextRetain(context);
517         return *this;
518     }
519     inline QMacCGContext &operator=(CGContextRef cg) {
520         if (context)
521             CGContextRelease(context);
522         context = cg;
523         CGContextRetain(context); //we do not take ownership
524         return *this;
525     }
526 };
527 } // anonymous namespace
528
529 static QColor qcolorFromCGColor(CGColorRef cgcolor)
530 {
531     QColor pc;
532     CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(cgcolor));
533     const CGFloat *components = CGColorGetComponents(cgcolor);
534     if (model == kCGColorSpaceModelRGB) {
535         pc.setRgbF(components[0], components[1], components[2], components[3]);
536     } else if (model == kCGColorSpaceModelCMYK) {
537         pc.setCmykF(components[0], components[1], components[2], components[3]);
538     } else if (model == kCGColorSpaceModelMonochrome) {
539         pc.setRgbF(components[0], components[0], components[0], components[1]);
540     } else {
541         // Colorspace we can't deal with.
542         qWarning("Qt: qcolorFromCGColor: cannot convert from colorspace model: %d", model);
543         Q_ASSERT(false);
544     }
545     return pc;
546 }
547
548 OSStatus qt_mac_shape2QRegionHelper(int inMessage, HIShapeRef, const CGRect *inRect, void *inRefcon)
549 {
550     QRegion *region = static_cast<QRegion *>(inRefcon);
551     if (!region)
552         return paramErr;
553
554     switch (inMessage) {
555     case kHIShapeEnumerateRect:
556         *region += QRect(inRect->origin.x, inRect->origin.y,
557                          inRect->size.width, inRect->size.height);
558         break;
559     case kHIShapeEnumerateInit:
560         // Assume the region is already setup correctly
561     case kHIShapeEnumerateTerminate:
562     default:
563         break;
564     }
565     return noErr;
566 }
567
568
569 /*!
570     \internal
571      Create's a mutable shape, it's the caller's responsibility to release.
572      WARNING: this function clamps the coordinates to SHRT_MIN/MAX on 10.4 and below.
573 */
574 HIMutableShapeRef qt_mac_toHIMutableShape(const QRegion &region)
575 {
576     HIMutableShapeRef shape = HIShapeCreateMutable();
577     if (region.rectCount() < 2 ) {
578         QRect qtRect = region.boundingRect();
579         CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
580         HIShapeUnionWithRect(shape, &cgRect);
581     } else {
582         foreach (const QRect &qtRect, region.rects()) {
583             CGRect cgRect = CGRectMake(qtRect.x(), qtRect.y(), qtRect.width(), qtRect.height());
584             HIShapeUnionWithRect(shape, &cgRect);
585         }
586     }
587     return shape;
588 }
589
590 QRegion qt_mac_fromHIShapeRef(HIShapeRef shape)
591 {
592     QRegion returnRegion;
593     //returnRegion.detach();
594     HIShapeEnumerate(shape, kHIShapeParseFromTopLeft, qt_mac_shape2QRegionHelper, &returnRegion);
595     return returnRegion;
596 }
597
598 CGColorSpaceRef m_genericColorSpace = 0;
599 static QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash;
600 bool m_postRoutineRegistered = false;
601
602 static CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget);
603 static CGColorSpaceRef qt_mac_genericColorSpace()
604 {
605 #if 0
606     if (!m_genericColorSpace) {
607         if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
608             m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
609         } else
610         {
611             m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
612         }
613         if (!m_postRoutineRegistered) {
614             m_postRoutineRegistered = true;
615             qAddPostRoutine(QCoreGraphicsPaintEngine::cleanUpMacColorSpaces);
616         }
617     }
618     return m_genericColorSpace;
619 #else
620     // Just return the main display colorspace for the moment.
621     return qt_mac_displayColorSpace(0);
622 #endif
623 }
624
625 static void qt_mac_cleanUpMacColorSpaces()
626 {
627     if (m_genericColorSpace) {
628         CFRelease(m_genericColorSpace);
629         m_genericColorSpace = 0;
630     }
631     QHash<CGDirectDisplayID, CGColorSpaceRef>::const_iterator it = m_displayColorSpaceHash.constBegin();
632     while (it != m_displayColorSpaceHash.constEnd()) {
633         if (it.value())
634             CFRelease(it.value());
635         ++it;
636     }
637     m_displayColorSpaceHash.clear();
638 }
639
640 /*
641     Ideally, we should pass the widget in here, and use CGGetDisplaysWithRect() etc.
642     to support multiple displays correctly.
643 */
644 static CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget)
645 {
646     CGColorSpaceRef colorSpace;
647
648     CGDirectDisplayID displayID;
649     if (widget == 0) {
650         displayID = CGMainDisplayID();
651     } else {
652         displayID = CGMainDisplayID();
653         /*
654         ### get correct display
655         const QRect &qrect = widget->window()->geometry();
656         CGRect rect = CGRectMake(qrect.x(), qrect.y(), qrect.width(), qrect.height());
657         CGDisplayCount throwAway;
658         CGDisplayErr dErr = CGGetDisplaysWithRect(rect, 1, &displayID, &throwAway);
659         if (dErr != kCGErrorSuccess)
660             return macDisplayColorSpace(0); // fall back on main display
661         */
662     }
663     if ((colorSpace = m_displayColorSpaceHash.value(displayID)))
664         return colorSpace;
665
666     colorSpace = CGDisplayCopyColorSpace(displayID);
667     if (colorSpace == 0)
668         colorSpace = CGColorSpaceCreateDeviceRGB();
669
670     m_displayColorSpaceHash.insert(displayID, colorSpace);
671     if (!m_postRoutineRegistered) {
672         m_postRoutineRegistered = true;
673         qAddPostRoutine(qt_mac_cleanUpMacColorSpaces);
674     }
675     return colorSpace;
676 }
677
678 bool qt_macWindowIsTextured(const QWidget *window)
679 {
680     if (QWindow *w = window->windowHandle())
681         if (w->handle())
682             if (NSWindow *nswindow = static_cast<NSWindow*>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("NSWindow"), w)))
683                 return ([nswindow styleMask] & NSTexturedBackgroundWindowMask) ? true : false;
684     return false;
685 }
686
687 static bool qt_macWindowMainWindow(const QWidget *window)
688 {
689     if (QWindow *w = window->windowHandle()) {
690         if (w->handle()) {
691             if (NSWindow *nswindow = static_cast<NSWindow*>(QGuiApplication::platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("nswindow"), w))) {
692                 return [nswindow isMainWindow];
693             }
694         }
695     }
696     return false;
697 }
698
699 /*****************************************************************************
700   QMacCGStyle globals
701  *****************************************************************************/
702 const int qt_mac_hitheme_version = 0; //the HITheme version we speak
703 const int macItemFrame         = 2;    // menu item frame width
704 const int macItemHMargin       = 3;    // menu item hor text margin
705 const int macItemVMargin       = 2;    // menu item ver text margin
706 const int macRightBorder       = 12;   // right border on mac
707 const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar.
708 QPixmap *qt_mac_backgroundPattern = 0; // stores the standard widget background.
709
710 /*****************************************************************************
711   QMacCGStyle utility functions
712  *****************************************************************************/
713 static inline int qt_mac_hitheme_tab_version()
714 {
715     return 1;
716 }
717
718 static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect())
719 {
720     return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(),
721                       convertRect.width() - rect.width(), convertRect.height() - rect.height());
722 }
723
724 static inline const QRect qt_qrectForHIRect(const HIRect &hirect)
725 {
726     return QRect(QPoint(int(hirect.origin.x), int(hirect.origin.y)),
727                  QSize(int(hirect.size.width), int(hirect.size.height)));
728 }
729
730 inline bool qt_mac_is_metal(const QWidget *w)
731 {
732     for (; w; w = w->parentWidget()) {
733         if (w->testAttribute(Qt::WA_MacBrushedMetal))
734             return true;
735         if (w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) {  // If not created will fall through to the opaque check and be fine anyway.
736             return qt_macWindowIsTextured(w);
737         }
738         if (w->d_func()->isOpaque)
739             break;
740     }
741     return false;
742 }
743
744 static int qt_mac_aqua_get_metric(ThemeMetric met)
745 {
746     SInt32 ret;
747     GetThemeMetric(met, &ret);
748     return ret;
749 }
750
751 static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint,
752                                     QAquaWidgetSize sz)
753 {
754     QSize ret(-1, -1);
755     if (sz != QAquaSizeSmall && sz != QAquaSizeLarge && sz != QAquaSizeMini) {
756         qDebug("Not sure how to return this...");
757         return ret;
758     }
759     if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
760         // If you're using a custom font and it's bigger than the default font,
761         // then no constraints for you. If you are smaller, we can try to help you out
762         QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont());
763         if (widg->font().pointSize() > font.pointSize())
764             return ret;
765     }
766
767     if (ct == QStyle::CT_CustomBase && widg) {
768         if (qobject_cast<const QPushButton *>(widg))
769             ct = QStyle::CT_PushButton;
770         else if (qobject_cast<const QRadioButton *>(widg))
771             ct = QStyle::CT_RadioButton;
772         else if (qobject_cast<const QCheckBox *>(widg))
773             ct = QStyle::CT_CheckBox;
774         else if (qobject_cast<const QComboBox *>(widg))
775             ct = QStyle::CT_ComboBox;
776         else if (qobject_cast<const QToolButton *>(widg))
777             ct = QStyle::CT_ToolButton;
778         else if (qobject_cast<const QSlider *>(widg))
779             ct = QStyle::CT_Slider;
780         else if (qobject_cast<const QProgressBar *>(widg))
781             ct = QStyle::CT_ProgressBar;
782         else if (qobject_cast<const QLineEdit *>(widg))
783             ct = QStyle::CT_LineEdit;
784         else if (qobject_cast<const QHeaderView *>(widg))
785             ct = QStyle::CT_HeaderSection;
786         else if (qobject_cast<const QMenuBar *>(widg))
787             ct = QStyle::CT_MenuBar;
788         else if (qobject_cast<const QSizeGrip *>(widg))
789             ct = QStyle::CT_SizeGrip;
790         else
791             return ret;
792     }
793
794     switch (ct) {
795     case QStyle::CT_PushButton: {
796         const QPushButton *psh = qobject_cast<const QPushButton *>(widg);
797         // If this comparison is false, then the widget was not a push button.
798         // This is bad and there's very little we can do since we were requested to find a
799         // sensible size for a widget that pretends to be a QPushButton but is not.
800         if(psh) {
801             QString buttonText = qt_mac_removeMnemonics(psh->text());
802             if (buttonText.contains(QLatin1Char('\n')))
803                 ret = QSize(-1, -1);
804             else if (sz == QAquaSizeLarge)
805                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
806             else if (sz == QAquaSizeSmall)
807                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
808             else if (sz == QAquaSizeMini)
809                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
810
811             if (!psh->icon().isNull()){
812                 // If the button got an icon, and the icon is larger than the
813                 // button, we can't decide on a default size
814                 ret.setWidth(-1);
815                 if (ret.height() < psh->iconSize().height())
816                     ret.setHeight(-1);
817             }
818             else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
819                 // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
820                 // However, this doesn't work for German, therefore only do it for English,
821                 // I suppose it would be better to do some sort of lookups for languages
822                 // that like to have really long words.
823                 ret.setWidth(77 - 8);
824             }
825         } else {
826             // The only sensible thing to do is to return whatever the style suggests...
827             if (sz == QAquaSizeLarge)
828                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
829             else if (sz == QAquaSizeSmall)
830                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
831             else if (sz == QAquaSizeMini)
832                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
833             else
834                 // Since there's no default size we return the large size...
835                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
836          }
837 #if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
838     } else if (ct == QStyle::CT_RadioButton) {
839         QRadioButton *rdo = static_cast<QRadioButton *>(widg);
840         // Exception for case where multiline radio button text requires no size constrainment
841         if (rdo->text().find('\n') != -1)
842             return ret;
843         if (sz == QAquaSizeLarge)
844             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricRadioButtonHeight));
845         else if (sz == QAquaSizeSmall)
846             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallRadioButtonHeight));
847         else if (sz == QAquaSizeMini)
848             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniRadioButtonHeight));
849     } else if (ct == QStyle::CT_CheckBox) {
850         if (sz == QAquaSizeLarge)
851             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricCheckBoxHeight));
852         else if (sz == QAquaSizeSmall)
853             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallCheckBoxHeight));
854         else if (sz == QAquaSizeMini)
855             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniCheckBoxHeight));
856 #endif
857         break;
858     }
859     case QStyle::CT_SizeGrip:
860         if (sz == QAquaSizeLarge || sz == QAquaSizeSmall) {
861             HIRect r;
862             HIPoint p = { 0, 0 };
863             HIThemeGrowBoxDrawInfo gbi;
864             gbi.version = 0;
865             gbi.state = kThemeStateActive;
866             gbi.kind = kHIThemeGrowBoxKindNormal;
867             gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown
868                                                           : kThemeGrowRight | kThemeGrowDown;
869             gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal;
870             if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr) {
871                 int width = 0;
872                 // Snow Leopard and older get a size grip, as well as QMdiSubWindows.
873                 if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_6
874 #ifndef QT_NO_MDIAREA
875                     || (widg && widg->parentWidget() && qobject_cast<QMdiSubWindow *>(widg->parentWidget()))
876 #endif
877                    )
878                     width = r.size.width;
879                 ret = QSize(width, r.size.height);
880             }
881         }
882         break;
883     case QStyle::CT_ComboBox:
884         switch (sz) {
885         case QAquaSizeLarge:
886             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPopupButtonHeight));
887             break;
888         case QAquaSizeSmall:
889             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPopupButtonHeight));
890             break;
891         case QAquaSizeMini:
892             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPopupButtonHeight));
893             break;
894         default:
895             break;
896         }
897         break;
898     case QStyle::CT_ToolButton:
899         if (sz == QAquaSizeSmall) {
900             int width = 0, height = 0;
901             if (szHint == QSize(-1, -1)) { //just 'guess'..
902                 const QToolButton *bt = qobject_cast<const QToolButton *>(widg);
903                 // If this conversion fails then the widget was not what it claimed to be.
904                 if(bt) {
905                     if (!bt->icon().isNull()) {
906                         QSize iconSize = bt->iconSize();
907                         QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal);
908                         width = qMax(width, qMax(iconSize.width(), pmSize.width()));
909                         height = qMax(height, qMax(iconSize.height(), pmSize.height()));
910                     }
911                     if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) {
912                         int text_width = bt->fontMetrics().width(bt->text()),
913                            text_height = bt->fontMetrics().height();
914                         if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) {
915                             width = qMax(width, text_width);
916                             height += text_height;
917                         } else {
918                             width += text_width;
919                             width = qMax(height, text_height);
920                         }
921                     }
922                 } else {
923                     // Let's return the size hint...
924                     width = szHint.width();
925                     height = szHint.height();
926                 }
927             } else {
928                 width = szHint.width();
929                 height = szHint.height();
930             }
931             width =  qMax(20, width +  5); //border
932             height = qMax(20, height + 5); //border
933             ret = QSize(width, height);
934         }
935         break;
936     case QStyle::CT_Slider: {
937         int w = -1;
938         const QSlider *sld = qobject_cast<const QSlider *>(widg);
939         // If this conversion fails then the widget was not what it claimed to be.
940         if(sld) {
941             if (sz == QAquaSizeLarge) {
942                 if (sld->orientation() == Qt::Horizontal) {
943                     w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
944                     if (sld->tickPosition() != QSlider::NoTicks)
945                         w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
946                 } else {
947                     w = qt_mac_aqua_get_metric(kThemeMetricVSliderWidth);
948                     if (sld->tickPosition() != QSlider::NoTicks)
949                         w += qt_mac_aqua_get_metric(kThemeMetricVSliderTickWidth);
950                 }
951             } else if (sz == QAquaSizeSmall) {
952                 if (sld->orientation() == Qt::Horizontal) {
953                     w = qt_mac_aqua_get_metric(kThemeMetricSmallHSliderHeight);
954                     if (sld->tickPosition() != QSlider::NoTicks)
955                         w += qt_mac_aqua_get_metric(kThemeMetricSmallHSliderTickHeight);
956                 } else {
957                     w = qt_mac_aqua_get_metric(kThemeMetricSmallVSliderWidth);
958                     if (sld->tickPosition() != QSlider::NoTicks)
959                         w += qt_mac_aqua_get_metric(kThemeMetricSmallVSliderTickWidth);
960                 }
961             } else if (sz == QAquaSizeMini) {
962                 if (sld->orientation() == Qt::Horizontal) {
963                     w = qt_mac_aqua_get_metric(kThemeMetricMiniHSliderHeight);
964                     if (sld->tickPosition() != QSlider::NoTicks)
965                         w += qt_mac_aqua_get_metric(kThemeMetricMiniHSliderTickHeight);
966                 } else {
967                     w = qt_mac_aqua_get_metric(kThemeMetricMiniVSliderWidth);
968                     if (sld->tickPosition() != QSlider::NoTicks)
969                         w += qt_mac_aqua_get_metric(kThemeMetricMiniVSliderTickWidth);
970                 }
971             }
972         } else {
973             // This is tricky, we were requested to find a size for a slider which is not
974             // a slider. We don't know if this is vertical or horizontal or if we need to
975             // have tick marks or not.
976             // For this case we will return an horizontal slider without tick marks.
977             w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
978             w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
979         }
980         if (sld->orientation() == Qt::Horizontal)
981             ret.setHeight(w);
982         else
983             ret.setWidth(w);
984         break;
985     }
986     case QStyle::CT_ProgressBar: {
987         int finalValue = -1;
988         Qt::Orientation orient = Qt::Horizontal;
989         if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
990             orient = pb->orientation();
991
992         if (sz == QAquaSizeLarge)
993             finalValue = qt_mac_aqua_get_metric(kThemeMetricLargeProgressBarThickness)
994                             + qt_mac_aqua_get_metric(kThemeMetricProgressBarShadowOutset);
995         else
996             finalValue = qt_mac_aqua_get_metric(kThemeMetricNormalProgressBarThickness)
997                             + qt_mac_aqua_get_metric(kThemeMetricSmallProgressBarShadowOutset);
998         if (orient == Qt::Horizontal)
999             ret.setHeight(finalValue);
1000         else
1001             ret.setWidth(finalValue);
1002         break;
1003     }
1004     case QStyle::CT_LineEdit:
1005         if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
1006             //should I take into account the font dimentions of the lineedit? -Sam
1007             if (sz == QAquaSizeLarge)
1008                 ret = QSize(-1, 21);
1009             else
1010                 ret = QSize(-1, 19);
1011         }
1012         break;
1013     case QStyle::CT_HeaderSection:
1014         if (isTreeView(widg))
1015            ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight));
1016         break;
1017     case QStyle::CT_MenuBar:
1018         if (sz == QAquaSizeLarge) {
1019             ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
1020             // In the qt_mac_set_native_menubar(false) case,
1021             // we come it here with a zero-height main menu,
1022             // preventing the in-window menu from displaying.
1023             // Use 22 pixels for the height, by observation.
1024             if (ret.height() <= 0)
1025                 ret.setHeight(22);
1026         }
1027         break;
1028     default:
1029         break;
1030     }
1031     return ret;
1032 }
1033
1034
1035 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
1036 static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini)
1037 {
1038     if (large == QSize(-1, -1)) {
1039         if (small != QSize(-1, -1))
1040             return QAquaSizeSmall;
1041         if (mini != QSize(-1, -1))
1042             return QAquaSizeMini;
1043         return QAquaSizeUnknown;
1044     } else if (small == QSize(-1, -1)) {
1045         if (mini != QSize(-1, -1))
1046             return QAquaSizeMini;
1047         return QAquaSizeLarge;
1048     } else if (mini == QSize(-1, -1)) {
1049         return QAquaSizeLarge;
1050     }
1051
1052 #ifndef QT_NO_MAINWINDOW
1053     if (qobject_cast<QDockWidget *>(widg->window()) || qEnvironmentVariableIsSet("QWIDGET_ALL_SMALL")) {
1054         //if (small.width() != -1 || small.height() != -1)
1055         return QAquaSizeSmall;
1056     } else if (qEnvironmentVariableIsSet("QWIDGET_ALL_MINI")) {
1057         return QAquaSizeMini;
1058     }
1059 #endif
1060
1061 #if 0
1062     /* Figure out which size we're closer to, I just hacked this in, I haven't
1063        tested it as it would probably look pretty strange to have some widgets
1064        big and some widgets small in the same window?? -Sam */
1065     int large_delta=0;
1066     if (large.width() != -1) {
1067         int delta = large.width() - widg->width();
1068         large_delta += delta * delta;
1069     }
1070     if (large.height() != -1) {
1071         int delta = large.height() - widg->height();
1072         large_delta += delta * delta;
1073     }
1074     int small_delta=0;
1075     if (small.width() != -1) {
1076         int delta = small.width() - widg->width();
1077         small_delta += delta * delta;
1078     }
1079     if (small.height() != -1) {
1080         int delta = small.height() - widg->height();
1081         small_delta += delta * delta;
1082     }
1083     int mini_delta=0;
1084     if (mini.width() != -1) {
1085         int delta = mini.width() - widg->width();
1086         mini_delta += delta * delta;
1087     }
1088     if (mini.height() != -1) {
1089         int delta = mini.height() - widg->height();
1090         mini_delta += delta * delta;
1091     }
1092     if (mini_delta < small_delta && mini_delta < large_delta)
1093         return QAquaSizeMini;
1094     else if (small_delta < large_delta)
1095         return QAquaSizeSmall;
1096 #endif
1097     return QAquaSizeLarge;
1098 }
1099 #endif
1100
1101 QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
1102                                        QStyle::ContentsType ct, QSize szHint, QSize *insz) const
1103 {
1104 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
1105     if (option) {
1106         if (option->state & QStyle::State_Small)
1107             return QAquaSizeSmall;
1108         if (option->state & QStyle::State_Mini)
1109             return QAquaSizeMini;
1110     }
1111
1112     if (!widg) {
1113         if (insz)
1114             *insz = QSize();
1115         if (qEnvironmentVariableIsSet("QWIDGET_ALL_SMALL"))
1116             return QAquaSizeSmall;
1117         if (qEnvironmentVariableIsSet("QWIDGET_ALL_MINI"))
1118             return QAquaSizeMini;
1119         return QAquaSizeUnknown;
1120     }
1121
1122     Q_Q(const QMacStyle);
1123     QSize large = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeLarge),
1124           small = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeSmall),
1125           mini  = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeMini);
1126     bool guess_size = false;
1127     QAquaWidgetSize ret = QAquaSizeUnknown;
1128     QMacStyle::WidgetSizePolicy wsp = q->widgetSizePolicy(widg);
1129     if (wsp == QMacStyle::SizeDefault)
1130         guess_size = true;
1131     else if (wsp == QMacStyle::SizeMini)
1132         ret = QAquaSizeMini;
1133     else if (wsp == QMacStyle::SizeSmall)
1134         ret = QAquaSizeSmall;
1135     else if (wsp == QMacStyle::SizeLarge)
1136         ret = QAquaSizeLarge;
1137     if (guess_size)
1138         ret = qt_aqua_guess_size(widg, large, small, mini);
1139
1140     QSize *sz = 0;
1141     if (ret == QAquaSizeSmall)
1142         sz = &small;
1143     else if (ret == QAquaSizeLarge)
1144         sz = &large;
1145     else if (ret == QAquaSizeMini)
1146         sz = &mini;
1147     if (insz)
1148         *insz = sz ? *sz : QSize(-1, -1);
1149 #ifdef DEBUG_SIZE_CONSTRAINT
1150     if (sz) {
1151         const char *size_desc = "Unknown";
1152         if (sz == &small)
1153             size_desc = "Small";
1154         else if (sz == &large)
1155             size_desc = "Large";
1156         else if (sz == &mini)
1157             size_desc = "Mini";
1158         qDebug("%s - %s: %s taken (%d, %d) [%d, %d]",
1159                widg ? widg->objectName().toLatin1().constData() : "*Unknown*",
1160                widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(),
1161                sz->width(), sz->height());
1162     }
1163 #endif
1164     return ret;
1165 #else
1166     if (insz)
1167         *insz = QSize();
1168     Q_UNUSED(widg);
1169     Q_UNUSED(ct);
1170     Q_UNUSED(szHint);
1171     return QAquaSizeUnknown;
1172 #endif
1173 }
1174
1175 /**
1176     Returns the free space awailable for contents inside the
1177     button (and not the size of the contents itself)
1178 */
1179 HIRect QMacStylePrivate::pushButtonContentBounds(const QStyleOptionButton *btn,
1180                                                  const HIThemeButtonDrawInfo *bdi) const
1181 {
1182     HIRect outerBounds = qt_hirectForQRect(btn->rect);
1183     // Adjust the bounds to correct for
1184     // carbon not calculating the content bounds fully correct
1185     if (bdi->kind == kThemePushButton || bdi->kind == kThemePushButtonSmall){
1186         outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
1187         outerBounds.size.height -= QMacStylePrivate::PushButtonBottomOffset;
1188     } else if (bdi->kind == kThemePushButtonMini) {
1189         outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
1190     }
1191
1192     HIRect contentBounds;
1193     HIThemeGetButtonContentBounds(&outerBounds, bdi, &contentBounds);
1194     return contentBounds;
1195 }
1196
1197 /**
1198     Calculates the size of the button contents.
1199     This includes both the text and the icon.
1200 */
1201 QSize QMacStylePrivate::pushButtonSizeFromContents(const QStyleOptionButton *btn) const
1202 {
1203     Q_Q(const QMacStyle);
1204     QSize csz(0, 0);
1205     QSize iconSize = btn->icon.isNull() ? QSize(0, 0)
1206                 : (btn->iconSize + QSize(QMacStylePrivate::PushButtonContentPadding, 0));
1207     QRect textRect = btn->text.isEmpty() ? QRect(0, 0, 1, 1)
1208                 : btn->fontMetrics.boundingRect(QRect(), Qt::AlignCenter, btn->text);
1209     csz.setWidth(iconSize.width() + textRect.width()
1210              + ((btn->features & QStyleOptionButton::HasMenu)
1211                             ? q->proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, 0) : 0));
1212     csz.setHeight(qMax(iconSize.height(), textRect.height()));
1213     return csz;
1214 }
1215
1216 /**
1217     Checks if the actual contents of btn fits inside the free content bounds of
1218     'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton'
1219     for determining which button kind to use for drawing.
1220 */
1221 bool QMacStylePrivate::contentFitsInPushButton(const QStyleOptionButton *btn,
1222                                                HIThemeButtonDrawInfo *bdi,
1223                                                ThemeButtonKind buttonKindToCheck) const
1224 {
1225     ThemeButtonKind tmp = bdi->kind;
1226     bdi->kind = buttonKindToCheck;
1227     QSize contentSize = pushButtonSizeFromContents(btn);
1228     QRect freeContentRect = qt_qrectForHIRect(pushButtonContentBounds(btn, bdi));
1229     bdi->kind = tmp;
1230     return freeContentRect.contains(QRect(freeContentRect.x(), freeContentRect.y(),
1231                                     contentSize.width(), contentSize.height()));
1232 }
1233
1234 /**
1235     Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1236     kind and other details to use for drawing the given push button. Which
1237     button kind depends on the size of the button, the size of the contents,
1238     explicit user style settings, etc.
1239 */
1240 void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
1241                                              const QWidget *widget,
1242                                              const ThemeDrawState tds,
1243                                              HIThemeButtonDrawInfo *bdi) const
1244 {
1245     ThemeDrawState tdsModified = tds;
1246     if (btn->state & QStyle::State_On)
1247         tdsModified = kThemeStatePressed;
1248     bdi->version = qt_mac_hitheme_version;
1249     bdi->state = tdsModified;
1250     bdi->value = kThemeButtonOff;
1251
1252     if (tds == kThemeStateInactive)
1253         bdi->state = kThemeStateActive;
1254     if (btn->state & QStyle::State_HasFocus)
1255         bdi->adornment = kThemeAdornmentFocus;
1256     else
1257         bdi->adornment = kThemeAdornmentNone;
1258
1259
1260     if (btn->features & (QStyleOptionButton::Flat)) {
1261         bdi->kind = kThemeBevelButton;
1262     } else {
1263         switch (aquaSizeConstrain(btn, widget)) {
1264         case QAquaSizeSmall:
1265             bdi->kind = kThemePushButtonSmall;
1266             break;
1267         case QAquaSizeMini:
1268             bdi->kind = kThemePushButtonMini;
1269             break;
1270         case QAquaSizeLarge:
1271             // ... We should honor if the user is explicit about using the
1272             // large button. But right now Qt will specify the large button
1273             // as default rather than QAquaSizeUnknown.
1274             // So we treat it like QAquaSizeUnknown
1275             // to get the dynamic choosing of button kind.
1276         case QAquaSizeUnknown:
1277             // Choose the button kind that closest match the button rect, but at the
1278             // same time displays the button contents without clipping.
1279             bdi->kind = kThemeBevelButton;
1280             if (btn->rect.width() >= QMacStylePrivate::BevelButtonW && btn->rect.height() >= QMacStylePrivate::BevelButtonH){
1281                 if (widget && widget->testAttribute(Qt::WA_MacVariableSize)) {
1282                     if (btn->rect.height() <= QMacStylePrivate::MiniButtonH){
1283                         if (contentFitsInPushButton(btn, bdi, kThemePushButtonMini))
1284                             bdi->kind = kThemePushButtonMini;
1285                     } else if (btn->rect.height() <= QMacStylePrivate::SmallButtonH){
1286                         if (contentFitsInPushButton(btn, bdi, kThemePushButtonSmall))
1287                             bdi->kind = kThemePushButtonSmall;
1288                     } else if (contentFitsInPushButton(btn, bdi, kThemePushButton)) {
1289                         bdi->kind = kThemePushButton;
1290                     }
1291                 } else {
1292                     bdi->kind = kThemePushButton;
1293                 }
1294             }
1295         }
1296     }
1297 }
1298
1299 bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option)
1300 {
1301     QMacStyle *macStyle = qobject_cast<QMacStyle *>(pushButton->style());
1302     if (!macStyle)
1303         return false;
1304     HIThemeButtonDrawInfo bdi;
1305     macStyle->d_func()->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi);
1306     return bdi.kind == kThemeBevelButton;
1307 }
1308
1309 /**
1310     Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1311     kind and other details to use for drawing the given combobox. Which button
1312     kind depends on the size of the combo, wether or not it is editable,
1313     explicit user style settings, etc.
1314 */
1315 void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
1316                                     const QWidget *widget, const ThemeDrawState &tds) const
1317 {
1318     bdi->version = qt_mac_hitheme_version;
1319     bdi->adornment = kThemeAdornmentArrowLeftArrow;
1320     bdi->value = kThemeButtonOff;
1321     if (combo->state & QStyle::State_HasFocus)
1322         bdi->adornment = kThemeAdornmentFocus;
1323     if (combo->activeSubControls & QStyle::SC_ComboBoxArrow)
1324         bdi->state = kThemeStatePressed;
1325     else if (tds == kThemeStateInactive)
1326         bdi->state = kThemeStateActive;
1327     else
1328         bdi->state = tds;
1329
1330     QAquaWidgetSize aSize = aquaSizeConstrain(combo, widget);
1331     switch (aSize) {
1332     case QAquaSizeMini:
1333         bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
1334             : ThemeButtonKind(kThemePopupButtonMini);
1335         break;
1336     case QAquaSizeSmall:
1337         bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxSmall)
1338             : ThemeButtonKind(kThemePopupButtonSmall);
1339         break;
1340     case QAquaSizeUnknown:
1341     case QAquaSizeLarge:
1342         // Unless the user explicitly specified large buttons, determine the
1343         // kind by looking at the combox size.
1344         // ... specifying small and mini-buttons it not a current feature of
1345         // Qt (e.g. QWidget::getAttribute(WA_ButtonSize)). But when it is, add
1346         // an extra check here before using the mini and small buttons.
1347         int h = combo->rect.size().height();
1348         if (combo->editable){
1349             if (qobject_cast<const QDateTimeEdit *>(widget)) {
1350                 // Except when, you know, we get a QDateTimeEdit with calendarPopup
1351                 // enabled. And then things get weird, basically because it's a
1352                 // transvestite spinbox with editable combobox tendencies. Meaning
1353                 // that it wants to look a combobox, except that it isn't one, so it
1354                 // doesn't get all those extra free margins around. (Don't know whose
1355                 // idea those margins were, but now it looks like we're stuck with
1356                 // them forever). So anyway, the height threshold should be smaller
1357                 // in this case, or the style gets confused when it needs to render
1358                 // or return any subcontrol size of the poor thing.
1359                 if (h < 9)
1360                     bdi->kind = kThemeComboBoxMini;
1361                 else if (h < 22)
1362                     bdi->kind = kThemeComboBoxSmall;
1363                 else
1364                     bdi->kind = kThemeComboBox;
1365             } else {
1366                 if (h < 21)
1367                     bdi->kind = kThemeComboBoxMini;
1368                 else if (h < 26)
1369                     bdi->kind = kThemeComboBoxSmall;
1370                 else
1371                     bdi->kind = kThemeComboBox;
1372             }
1373         } else {
1374             // Even if we specify that we want the kThemePopupButton, Carbon
1375             // will use the kThemePopupButtonSmall if the size matches. So we
1376             // do the same size check explicit to have the size of the inner
1377             // text field be correct. Therefore, do this even if the user specifies
1378             // the use of LargeButtons explicit.
1379             if (h < 21)
1380                 bdi->kind = kThemePopupButtonMini;
1381             else if (h < 26)
1382                 bdi->kind = kThemePopupButtonSmall;
1383             else
1384                 bdi->kind = kThemePopupButton;
1385         }
1386         break;
1387     }
1388 }
1389
1390 /**
1391     Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
1392     the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
1393 */
1394 HIRect QMacStylePrivate::comboboxInnerBounds(const HIRect &outerBounds, int buttonKind)
1395 {
1396     HIRect innerBounds = outerBounds;
1397     // Carbon draw parts of the view outside the rect.
1398     // So make the rect a bit smaller to compensate
1399     // (I wish HIThemeGetButtonBackgroundBounds worked)
1400     switch (buttonKind){
1401     case kThemePopupButton:
1402         innerBounds.origin.x += 2;
1403         innerBounds.origin.y += 2;
1404         innerBounds.size.width -= 5;
1405         innerBounds.size.height -= 6;
1406         break;
1407     case kThemePopupButtonSmall:
1408         innerBounds.origin.x += 3;
1409         innerBounds.origin.y += 3;
1410         innerBounds.size.width -= 6;
1411         innerBounds.size.height -= 7;
1412         break;
1413     case kThemePopupButtonMini:
1414         innerBounds.origin.x += 2;
1415         innerBounds.origin.y += 2;
1416         innerBounds.size.width -= 5;
1417         innerBounds.size.height -= 6;
1418         break;
1419     case kThemeComboBox:
1420         innerBounds.origin.x += 3;
1421         innerBounds.origin.y += 2;
1422         innerBounds.size.width -= 6;
1423         innerBounds.size.height -= 8;
1424         break;
1425     case kThemeComboBoxSmall:
1426         innerBounds.origin.x += 3;
1427         innerBounds.origin.y += 3;
1428         innerBounds.size.width -= 7;
1429         innerBounds.size.height -= 8;
1430         break;
1431     case kThemeComboBoxMini:
1432         innerBounds.origin.x += 3;
1433         innerBounds.origin.y += 3;
1434         innerBounds.size.width -= 4;
1435         innerBounds.size.height -= 8;
1436         break;
1437     default:
1438         break;
1439     }
1440     return innerBounds;
1441 }
1442
1443 /**
1444     Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind
1445     of combobox we choose to draw. This function calculates and returns this size.
1446 */
1447 QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi)
1448 {
1449     QRect ret = outerBounds;
1450     switch (bdi.kind){
1451     case kThemeComboBox:
1452         ret.adjust(5, 5, -22, -5);
1453         break;
1454     case kThemeComboBoxSmall:
1455         ret.adjust(4, 5, -18, 0);
1456         ret.setHeight(16);
1457         break;
1458     case kThemeComboBoxMini:
1459         ret.adjust(4, 5, -16, 0);
1460         ret.setHeight(13);
1461         break;
1462     case kThemePopupButton:
1463         ret.adjust(10, 2, -23, -4);
1464         break;
1465     case kThemePopupButtonSmall:
1466         ret.adjust(9, 3, -20, -3);
1467         break;
1468     case kThemePopupButtonMini:
1469         ret.adjust(8, 3, -19, 0);
1470         ret.setHeight(13);
1471         break;
1472     }
1473     return ret;
1474 }
1475
1476 /**
1477     Carbon comboboxes don't scale (sight). If the size of the combo suggest a scaled version,
1478     create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
1479     it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
1480 */
1481 void QMacStylePrivate::drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1482 {
1483     if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
1484         // We have an unscaled combobox, or popup-button; use Carbon directly.
1485         HIRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
1486         HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
1487     } else {
1488         QPixmap buffer;
1489         QString key = QString(QLatin1String("$qt_cbox%1-%2")).arg(int(bdi.state)).arg(int(bdi.adornment));
1490         if (!QPixmapCache::find(key, buffer)) {
1491             HIRect innerBoundsSmallCombo = {{3, 3}, {29, 25}};
1492             buffer = QPixmap(35, 28);
1493             buffer.fill(Qt::transparent);
1494             QPainter buffPainter(&buffer);
1495             HIThemeDrawButton(&innerBoundsSmallCombo, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1496             buffPainter.end();
1497             QPixmapCache::insert(key, buffer);
1498         }
1499
1500         const int bwidth = 20;
1501         const int fwidth = 10;
1502         const int fheight = 10;
1503         int w = qRound(outerBounds.size.width);
1504         int h = qRound(outerBounds.size.height);
1505         int bstart = w - bwidth;
1506         int blower = fheight + 1;
1507         int flower = h - fheight;
1508         int sheight = flower - fheight;
1509         int center = qRound(outerBounds.size.height + outerBounds.origin.y) / 2;
1510
1511         // Draw upper and lower gap
1512         p->drawPixmap(fwidth, 0, bstart - fwidth, fheight, buffer, fwidth, 0, 1, fheight);
1513         p->drawPixmap(fwidth, flower, bstart - fwidth, fheight, buffer, fwidth, buffer.height() - fheight, 1, fheight);
1514         // Draw left and right gap. Right gap is drawn top and bottom separatly
1515         p->drawPixmap(0, fheight, fwidth, sheight, buffer, 0, fheight, fwidth, 1);
1516         p->drawPixmap(bstart, fheight, bwidth, center - fheight, buffer, buffer.width() - bwidth, fheight - 1, bwidth, 1);
1517         p->drawPixmap(bstart, center, bwidth, sheight / 2, buffer, buffer.width() - bwidth, fheight + 6, bwidth, 1);
1518         // Draw arrow
1519         p->drawPixmap(bstart, center - 4, bwidth - 3, 6, buffer, buffer.width() - bwidth, fheight, bwidth - 3, 6);
1520         // Draw corners
1521         p->drawPixmap(0, 0, fwidth, fheight, buffer, 0, 0, fwidth, fheight);
1522         p->drawPixmap(bstart, 0, bwidth, fheight, buffer, buffer.width() - bwidth, 0, bwidth, fheight);
1523         p->drawPixmap(0, flower, fwidth, fheight, buffer, 0, buffer.height() - fheight, fwidth, fheight);
1524         p->drawPixmap(bstart, h - blower, bwidth, blower, buffer, buffer.width() - bwidth, buffer.height() - blower, bwidth, blower);
1525     }
1526 }
1527
1528 /**
1529     Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
1530     onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
1531 */
1532 void QMacStylePrivate::drawTableHeader(const HIRect &outerBounds,
1533     bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1534 {
1535     static SInt32 headerHeight = 0;
1536     static OSStatus err = GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
1537     Q_UNUSED(err);
1538
1539     QPixmap buffer;
1540     QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
1541     if (!QPixmapCache::find(key, buffer)) {
1542         HIRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
1543         buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
1544         buffer.fill(Qt::transparent);
1545         QPainter buffPainter(&buffer);
1546         HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1547         buffPainter.end();
1548         QPixmapCache::insert(key, buffer);
1549     }
1550     const int buttonw = qRound(outerBounds.size.width);
1551     const int buttonh = qRound(outerBounds.size.height);
1552     const int framew = 1;
1553     const int frameh_n = 4;
1554     const int frameh_s = 3;
1555     const int transh = buffer.height() - frameh_n - frameh_s;
1556     int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
1557
1558     int skipTopBorder = 0;
1559     if (!drawTopBorder)
1560         skipTopBorder = 1;
1561
1562     p->translate(outerBounds.origin.x, outerBounds.origin.y);
1563
1564     p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
1565     p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
1566     // Draw upper and lower center blocks
1567     p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
1568     p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
1569     // Draw right center block borders
1570     p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
1571     p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
1572     // Draw right corners
1573     p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
1574     p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
1575     // Draw center transition block
1576     p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), buttonw - framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(framew, frameh_n + 1, 1, transh));
1577     // Draw right center transition block border
1578     p->drawPixmap(QRect(buttonw - framew, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(buffer.width() - framew, frameh_n + 1, framew, transh));
1579     if (drawLeftBorder){
1580         // Draw left center block borders
1581         p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
1582         p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
1583         // Draw left corners
1584         p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
1585         p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
1586         // Draw left center transition block border
1587         p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
1588     }
1589
1590     p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
1591 }
1592
1593 /*
1594     Returns cutoff sizes for scroll bars.
1595     thumbIndicatorCutoff is the smallest size where the thumb indicator is drawn.
1596     scrollButtonsCutoff is the smallest size where the up/down buttons is drawn.
1597 */
1598 enum ScrollBarCutoffType { thumbIndicatorCutoff = 0, scrollButtonsCutoff = 1 };
1599 static int scrollButtonsCutoffSize(ScrollBarCutoffType cutoffType, QMacStyle::WidgetSizePolicy widgetSize)
1600 {
1601     // Mini scroll bars do not exist as of version 10.4.
1602     if (widgetSize ==  QMacStyle::SizeMini)
1603         return 0;
1604
1605     const int sizeIndex = (widgetSize == QMacStyle::SizeSmall) ? 1 : 0;
1606     static const int sizeTable[2][2] = { { 61, 56 }, { 49, 44 } };
1607     return sizeTable[sizeIndex][cutoffType];
1608 }
1609
1610 void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
1611                           HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe) const
1612 {
1613     memset(tdi, 0, sizeof(HIThemeTrackDrawInfo)); // We don't get it all for some reason or another...
1614     tdi->version = qt_mac_hitheme_version;
1615     tdi->reserved = 0;
1616     tdi->filler1 = 0;
1617     bool isScrollbar = (cc == QStyle::CC_ScrollBar);
1618     switch (aquaSizeConstrain(slider, needToRemoveMe)) {
1619     case QAquaSizeUnknown:
1620     case QAquaSizeLarge:
1621         if (isScrollbar)
1622             tdi->kind = kThemeMediumScrollBar;
1623         else
1624             tdi->kind = kThemeMediumSlider;
1625         break;
1626     case QAquaSizeMini:
1627         if (isScrollbar)
1628             tdi->kind = kThemeSmallScrollBar; // should be kThemeMiniScrollBar, but not implemented
1629         else
1630             tdi->kind = kThemeMiniSlider;
1631         break;
1632     case QAquaSizeSmall:
1633         if (isScrollbar)
1634             tdi->kind = kThemeSmallScrollBar;
1635         else
1636             tdi->kind = kThemeSmallSlider;
1637         break;
1638     }
1639     tdi->bounds = qt_hirectForQRect(slider->rect);
1640     tdi->min = slider->minimum;
1641     tdi->max = slider->maximum;
1642     tdi->value = slider->sliderPosition;
1643     tdi->attributes = kThemeTrackShowThumb;
1644     if (slider->upsideDown)
1645         tdi->attributes |= kThemeTrackRightToLeft;
1646     if (slider->orientation == Qt::Horizontal) {
1647         tdi->attributes |= kThemeTrackHorizontal;
1648         if (isScrollbar && slider->direction == Qt::RightToLeft) {
1649             if (!slider->upsideDown)
1650                 tdi->attributes |= kThemeTrackRightToLeft;
1651             else
1652                 tdi->attributes &= ~kThemeTrackRightToLeft;
1653         }
1654     }
1655
1656     // Tiger broke reverse scroll bars so put them back and "fake it"
1657     if (isScrollbar && (tdi->attributes & kThemeTrackRightToLeft)) {
1658         tdi->attributes &= ~kThemeTrackRightToLeft;
1659         tdi->value = tdi->max - slider->sliderPosition;
1660     }
1661
1662     tdi->enableState = (slider->state & QStyle::State_Enabled) ? kThemeTrackActive
1663                                                              : kThemeTrackDisabled;
1664     if (!isScrollbar) {
1665         if (slider->state & QStyle::QStyle::State_HasFocus)
1666             tdi->attributes |= kThemeTrackHasFocus;
1667         if (slider->tickPosition == QSlider::NoTicks || slider->tickPosition == QSlider::TicksBothSides)
1668             tdi->trackInfo.slider.thumbDir = kThemeThumbPlain;
1669         else if (slider->tickPosition == QSlider::TicksAbove)
1670             tdi->trackInfo.slider.thumbDir = kThemeThumbUpward;
1671         else
1672             tdi->trackInfo.slider.thumbDir = kThemeThumbDownward;
1673     } else {
1674         tdi->trackInfo.scrollbar.viewsize = slider->pageStep;
1675     }
1676 }
1677
1678 void QMacStylePrivate::setAutoDefaultButton(QObject *button) const
1679 {
1680     if (autoDefaultButton != button) {
1681         if (QStyleAnimation *anim = animation(autoDefaultButton)) {
1682             anim->updateTarget();
1683             stopAnimation(autoDefaultButton);
1684         }
1685         autoDefaultButton = button;
1686     }
1687     if (autoDefaultButton && !animation(autoDefaultButton))
1688         startAnimation(new QStyleAnimation(autoDefaultButton));
1689 }
1690
1691 QMacStylePrivate::QMacStylePrivate()
1692     : mouseDown(false)
1693 {
1694     defaultButtonStart = CFAbsoluteTimeGetCurrent();
1695     memset(&buttonState, 0, sizeof(ButtonState));
1696
1697     if (ptrHIShapeGetBounds == 0) {
1698         QLibrary library(QLatin1String("/System/Library/Frameworks/Carbon.framework/Carbon"));
1699         library.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1700         ptrHIShapeGetBounds = reinterpret_cast<PtrHIShapeGetBounds>(library.resolve("HIShapeGetBounds"));
1701     }
1702
1703 }
1704
1705 ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
1706 {
1707     ThemeDrawState tds = kThemeStateActive;
1708     if (flags & QStyle::State_Sunken) {
1709         tds = kThemeStatePressed;
1710     } else if (flags & QStyle::State_Active) {
1711         if (!(flags & QStyle::State_Enabled))
1712             tds = kThemeStateUnavailable;
1713     } else {
1714         if (flags & QStyle::State_Enabled)
1715             tds = kThemeStateInactive;
1716         else
1717             tds = kThemeStateUnavailableInactive;
1718     }
1719     return tds;
1720 }
1721
1722 void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
1723                                            QPainter *p, const QStyleOption *opt) const
1724 {
1725     int xoff = 0,
1726         yoff = 0,
1727         extraWidth = 0,
1728         extraHeight = 0,
1729         finalyoff = 0;
1730
1731     const bool combo = opt->type == QStyleOption::SO_ComboBox;
1732     const bool button = opt->type == QStyleOption::SO_Button;
1733     const bool pressed = bdi->state == kThemeStatePressed;
1734
1735     if (button && pressed) {
1736         if (bdi->kind == kThemePushButton) {
1737             extraHeight = 2;
1738         } else if (bdi->kind == kThemePushButtonSmall) {
1739             xoff = 1;
1740             extraWidth = 2;
1741             extraHeight = 5;
1742         }
1743     }
1744
1745     int devicePixelRatio = p->device()->devicePixelRatio();
1746     int width = devicePixelRatio * (int(macRect.size.width) + extraWidth);
1747     int height = devicePixelRatio * (int(macRect.size.height) + extraHeight);
1748
1749     if (width <= 0 || height <= 0)
1750         return;   // nothing to draw
1751
1752     QString key = QLatin1String("$qt_mac_style_ctb_") + QString::number(bdi->kind) + QLatin1Char('_')
1753                   + QString::number(bdi->value) + QLatin1Char('_')
1754                   + (button ? QString::number(bdi->state) + QLatin1Char('_') : QString())
1755                   + QLatin1Char('_') + QString::number(width) + QLatin1Char('_') + QString::number(height);
1756     QPixmap pm;
1757     if (!QPixmapCache::find(key, pm)) {
1758         QPixmap activePixmap(width, height);
1759         activePixmap.setDevicePixelRatio(devicePixelRatio);
1760         activePixmap.fill(Qt::transparent);
1761         {
1762             if (combo){
1763                 // Carbon combos don't scale. Therefore we draw it
1764                 // ourselves, if a scaled version is needed.
1765                 QPainter tmpPainter(&activePixmap);
1766                 QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
1767             } else {
1768                 QMacCGContext cg(&activePixmap);
1769                 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1770                 if (button && pressed)
1771                     bdi->state = kThemeStateActive;
1772                 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1773             }
1774         }
1775
1776         if (!combo && !button && bdi->value == kThemeButtonOff) {
1777             pm = activePixmap;
1778         } else if (combo || button) {
1779             QImage image = activePixmap.toImage();
1780
1781             for (int y = 0; y < height; ++y) {
1782                 QRgb *scanLine = reinterpret_cast<QRgb *>(image.scanLine(y));
1783
1784                 for (int x = 0; x < width; ++x) {
1785                     QRgb &pixel = scanLine[x];
1786
1787                     int darkest = qRed(pixel);
1788                     int mid = qGreen(pixel);
1789                     int lightest = qBlue(pixel);
1790
1791                     if (darkest > mid)
1792                         qSwap(darkest, mid);
1793                     if (mid > lightest)
1794                         qSwap(mid, lightest);
1795                     if (darkest > mid)
1796                         qSwap(darkest, mid);
1797
1798                     int gray = (mid + 2 * lightest) / 3;
1799                     if (pressed)
1800                         gray *= 0.88;
1801                     pixel = qRgba(gray, gray, gray, qAlpha(pixel));
1802                 }
1803             }
1804             pm = QPixmap::fromImage(image);
1805         } else {
1806             QImage activeImage = activePixmap.toImage();
1807             QImage colorlessImage;
1808             {
1809                 QPixmap colorlessPixmap(width, height);
1810                 colorlessPixmap.setDevicePixelRatio(devicePixelRatio);
1811                 colorlessPixmap.fill(Qt::transparent);
1812
1813                 QMacCGContext cg(&colorlessPixmap);
1814                 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1815                 int oldValue = bdi->value;
1816                 bdi->value = kThemeButtonOff;
1817                 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1818                 bdi->value = oldValue;
1819                 colorlessImage = colorlessPixmap.toImage();
1820             }
1821
1822             for (int y = 0; y < height; ++y) {
1823                 QRgb *colorlessScanLine = reinterpret_cast<QRgb *>(colorlessImage.scanLine(y));
1824                 const QRgb *activeScanLine = reinterpret_cast<const QRgb *>(activeImage.scanLine(y));
1825
1826                 for (int x = 0; x < width; ++x) {
1827                     QRgb &colorlessPixel = colorlessScanLine[x];
1828                     QRgb activePixel = activeScanLine[x];
1829
1830                     if (activePixel != colorlessPixel) {
1831                         int max = qMax(qMax(qRed(activePixel), qGreen(activePixel)),
1832                                        qBlue(activePixel));
1833                         QRgb newPixel = qRgba(max, max, max, qAlpha(activePixel));
1834                         if (qGray(newPixel) < qGray(colorlessPixel)
1835                                 || qAlpha(newPixel) > qAlpha(colorlessPixel))
1836                             colorlessPixel = newPixel;
1837                     }
1838                 }
1839             }
1840             pm = QPixmap::fromImage(colorlessImage);
1841         }
1842         QPixmapCache::insert(key, pm);
1843     }
1844     p->drawPixmap(int(macRect.origin.x) - xoff, int(macRect.origin.y) + finalyoff, width / devicePixelRatio, height / devicePixelRatio , pm);
1845 }
1846
1847 QMacStyle::QMacStyle()
1848     : QCommonStyle(*new QMacStylePrivate)
1849 {
1850     Q_D(QMacStyle);
1851 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
1852     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
1853         d->receiver = [[NotificationReceiver alloc] initWithPrivate:d];
1854         NotificationReceiver *receiver = static_cast<NotificationReceiver *>(d->receiver);
1855
1856         [[NSNotificationCenter defaultCenter] addObserver:receiver
1857             selector:@selector(scrollBarStyleDidChange:)
1858             name:NSPreferredScrollerStyleDidChangeNotification
1859             object:nil];
1860
1861         d->nsscroller = [[NSScroller alloc] init];
1862     }
1863 #endif
1864     d->indicatorBranchButtonCell = nil;
1865 }
1866
1867 QMacStyle::~QMacStyle()
1868 {
1869 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
1870     Q_D(QMacStyle);
1871     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
1872         [reinterpret_cast<NSScroller*>(d->nsscroller) release];
1873
1874         NotificationReceiver *receiver = static_cast<NotificationReceiver *>(d->receiver);
1875         [[NSNotificationCenter defaultCenter] removeObserver:receiver];
1876         [receiver release];
1877     }
1878 #endif
1879
1880     delete qt_mac_backgroundPattern;
1881     qt_mac_backgroundPattern = 0;
1882 }
1883
1884 /*! \internal
1885     Generates the standard widget background pattern.
1886 */
1887 QPixmap QMacStylePrivate::generateBackgroundPattern() const
1888 {
1889     QPixmap px(4, 4);
1890     QMacCGContext cg(&px);
1891     HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationNormal);
1892     const CGRect cgRect = CGRectMake(0, 0, px.width(), px.height());
1893     CGContextFillRect(cg, cgRect);
1894     return px;
1895 }
1896
1897 /*! \internal
1898     Fills the given \a rect with the pattern stored in \a brush. As an optimization,
1899     HIThemeSetFill us used directly if we are filling with the standard background.
1900 */
1901 void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush)
1902 {
1903 #if 0
1904     QPoint dummy;
1905     const QPaintDevice *target = painter->device();
1906     const QPaintDevice *redirected = QPainter::redirected(target, &dummy);
1907     //const bool usePainter = redirected && redirected != target;
1908
1909     if (!usePainter && qt_mac_backgroundPattern
1910         && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) {
1911
1912         painter->setClipRegion(rgn);
1913
1914         QCFType<CGContextRef> cg = qt_mac_cg_context(target);
1915         CGContextSaveGState(cg);
1916         HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted);
1917
1918         const QVector<QRect> &rects = rgn.rects();
1919         for (int i = 0; i < rects.size(); ++i) {
1920             const QRect rect(rects.at(i));
1921             // Anchor the pattern to the top so it stays put when the window is resized.
1922             CGContextSetPatternPhase(cg, CGSizeMake(rect.width(), rect.height()));
1923             CGRect mac_rect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
1924             CGContextFillRect(cg, mac_rect);
1925         }
1926
1927         CGContextRestoreGState(cg);
1928     } else {
1929 #endif
1930         const QRect rect(rgn.boundingRect());
1931         painter->setClipRegion(rgn);
1932         painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
1933 //    }
1934 }
1935
1936 void QMacStyle::polish(QPalette &pal)
1937 {
1938     Q_D(QMacStyle);
1939     if (!qt_mac_backgroundPattern) {
1940         if (!qApp)
1941             return;
1942         qt_mac_backgroundPattern = new QPixmap(d->generateBackgroundPattern());
1943     }
1944
1945
1946     QCFString theme;
1947     const OSErr err = CopyThemeIdentifier(&theme);
1948     if (err == noErr && CFStringCompare(theme, kThemeAppearanceAquaGraphite, 0) == kCFCompareEqualTo) {
1949         pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(240, 240, 240));
1950     } else {
1951         pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(237, 243, 254));
1952     }
1953 }
1954
1955 void QMacStyle::polish(QApplication *)
1956 {
1957 }
1958
1959 void QMacStyle::unpolish(QApplication *)
1960 {
1961 }
1962
1963 void QMacStyle::polish(QWidget* w)
1964 {
1965     if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) {
1966         // Set a clear brush so that the metal shines through.
1967         QPalette pal = w->palette();
1968         QBrush background(Qt::transparent);
1969         pal.setBrush(QPalette::All, QPalette::Window, background);
1970         pal.setBrush(QPalette::All, QPalette::Button, background);
1971         w->setPalette(pal);
1972         w->setAttribute(Qt::WA_SetPalette, false);
1973     }
1974
1975     if (qobject_cast<QMenu*>(w) || qobject_cast<QComboBoxPrivateContainer *>(w)) {
1976         w->setWindowOpacity(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 ? 0.985 : 0.94);
1977         if (!w->testAttribute(Qt::WA_SetPalette)) {
1978             QPixmap px(64, 64);
1979             px.fill(Qt::white);
1980             HIThemeMenuDrawInfo mtinfo;
1981             mtinfo.version = qt_mac_hitheme_version;
1982             mtinfo.menuType = kThemeMenuTypePopUp;
1983             // HIRect rect = CGRectMake(0, 0, px.width(), px.height());
1984             // ###
1985             //HIThemeDrawMenuBackground(&rect, &mtinfo, QCFType<CGContextRef>(qt_mac_cg_context(&px)),
1986             //                          kHIThemeOrientationNormal);
1987             QPalette pal = w->palette();
1988             QBrush background(px);
1989             pal.setBrush(QPalette::All, QPalette::Window, background);
1990             pal.setBrush(QPalette::All, QPalette::Button, background);
1991             w->setPalette(pal);
1992             w->setAttribute(Qt::WA_SetPalette, false);
1993         }
1994     }
1995
1996     if (QTabBar *tb = qobject_cast<QTabBar*>(w)) {
1997         if (tb->documentMode()) {
1998             w->setAttribute(Qt::WA_Hover);
1999             w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont()));
2000             QPalette p = w->palette();
2001             p.setColor(QPalette::WindowText, QColor(17, 17, 17));
2002             w->setPalette(p);
2003         }
2004     }
2005
2006     QCommonStyle::polish(w);
2007
2008     if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2009         rubber->setWindowOpacity(0.25);
2010         rubber->setAttribute(Qt::WA_PaintOnScreen, false);
2011         rubber->setAttribute(Qt::WA_NoSystemBackground, false);
2012     }
2013
2014     if (qobject_cast<QScrollBar*>(w)) {
2015         w->setAttribute(Qt::WA_OpaquePaintEvent, false);
2016         w->setAttribute(Qt::WA_Hover, true);
2017         w->setMouseTracking(true);
2018     }
2019 }
2020
2021 void QMacStyle::unpolish(QWidget* w)
2022 {
2023     if ((qobject_cast<QMenu*>(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) {
2024         QPalette pal = qApp->palette(w);
2025         w->setPalette(pal);
2026         w->setAttribute(Qt::WA_SetPalette, false);
2027         w->setWindowOpacity(1.0);
2028     }
2029
2030     if (QComboBox *combo = qobject_cast<QComboBox *>(w)) {
2031         if (!combo->isEditable()) {
2032             if (QWidget *widget = combo->findChild<QComboBoxPrivateContainer *>())
2033                 widget->setWindowOpacity(1.0);
2034         }
2035     }
2036
2037     if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
2038         rubber->setWindowOpacity(1.0);
2039         rubber->setAttribute(Qt::WA_PaintOnScreen, true);
2040         rubber->setAttribute(Qt::WA_NoSystemBackground, true);
2041     }
2042
2043     if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w))
2044         frame->setAttribute(Qt::WA_NoSystemBackground, true);
2045
2046     QCommonStyle::unpolish(w);
2047
2048     if (qobject_cast<QScrollBar*>(w)) {
2049         w->setAttribute(Qt::WA_OpaquePaintEvent, true);
2050         w->setAttribute(Qt::WA_Hover, false);
2051         w->setMouseTracking(false);
2052     }
2053 }
2054
2055 int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const
2056 {
2057     Q_D(const QMacStyle);
2058     int controlSize = getControlSize(opt, widget);
2059     SInt32 ret = 0;
2060
2061     switch (metric) {
2062     case PM_TabCloseIndicatorWidth:
2063     case PM_TabCloseIndicatorHeight:
2064         ret = closeButtonSize;
2065         break;
2066     case PM_ToolBarIconSize:
2067         ret = proxy()->pixelMetric(PM_LargeIconSize);
2068         break;
2069     case PM_FocusFrameVMargin:
2070     case PM_FocusFrameHMargin:
2071         GetThemeMetric(kThemeMetricFocusRectOutset, &ret);
2072         break;
2073     case PM_DialogButtonsSeparator:
2074         ret = -5;
2075         break;
2076     case PM_DialogButtonsButtonHeight: {
2077         QSize sz;
2078         ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2079         if (sz == QSize(-1, -1))
2080             ret = 32;
2081         else
2082             ret = sz.height();
2083         break; }
2084     case PM_DialogButtonsButtonWidth: {
2085         QSize sz;
2086         ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2087         if (sz == QSize(-1, -1))
2088             ret = 70;
2089         else
2090             ret = sz.width();
2091         break; }
2092
2093     case PM_MenuBarHMargin:
2094         ret = 8;
2095         break;
2096
2097     case PM_MenuBarVMargin:
2098         ret = 0;
2099         break;
2100
2101     case PM_MenuBarPanelWidth:
2102         ret = 0;
2103         break;
2104
2105     case QStyle::PM_MenuDesktopFrameWidth:
2106         ret = 5;
2107         break;
2108
2109     case PM_CheckBoxLabelSpacing:
2110     case PM_RadioButtonLabelSpacing:
2111         ret = 2;
2112         break;
2113     case PM_MenuScrollerHeight:
2114 #if 0
2115         SInt16 ash, asw;
2116         GetThemeMenuItemExtra(kThemeMenuItemScrollUpArrow, &ash, &asw);
2117         ret = ash;
2118 #else
2119         ret = 15; // I hate having magic numbers in here...
2120 #endif
2121         break;
2122     case PM_DefaultFrameWidth:
2123 #ifndef QT_NO_MAINWINDOW
2124         if (widget && (widget->isWindow() || !widget->parentWidget()
2125                 || (qobject_cast<const QMainWindow*>(widget->parentWidget())
2126                    && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
2127                 && qobject_cast<const QAbstractScrollArea *>(widget))
2128             ret = 0;
2129         else
2130 #endif
2131         // The combo box popup has no frame.
2132         if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
2133             ret = 0;
2134         else
2135             ret = 1;
2136         break;
2137     case PM_MaximumDragDistance:
2138         ret = -1;
2139         break;
2140     case PM_ScrollBarSliderMin:
2141         ret = 24;
2142         break;
2143     case PM_SpinBoxFrameWidth:
2144         GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret);
2145         switch (d->aquaSizeConstrain(opt, widget)) {
2146         default:
2147             ret += 2;
2148             break;
2149         case QAquaSizeMini:
2150             ret += 1;
2151             break;
2152         }
2153         break;
2154     case PM_ButtonShiftHorizontal:
2155     case PM_ButtonShiftVertical:
2156         ret = 0;
2157         break;
2158     case PM_SliderLength:
2159         ret = 17;
2160         break;
2161         // Returns the number of pixels to use for the business part of the
2162         // slider (i.e., the non-tickmark portion). The remaining space is shared
2163         // equally between the tickmark regions.
2164     case PM_SliderControlThickness:
2165         if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
2166             int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
2167             int ticks = sl->tickPosition;
2168             int n = 0;
2169             if (ticks & QSlider::TicksAbove)
2170                 ++n;
2171             if (ticks & QSlider::TicksBelow)
2172                 ++n;
2173             if (!n) {
2174                 ret = space;
2175                 break;
2176             }
2177
2178             int thick = 6;        // Magic constant to get 5 + 16 + 5
2179             if (ticks != QSlider::TicksBothSides && ticks != QSlider::NoTicks)
2180                 thick += proxy()->pixelMetric(PM_SliderLength, sl, widget) / 4;
2181
2182             space -= thick;
2183             if (space > 0)
2184                 thick += (space * 2) / (n + 2);
2185             ret = thick;
2186         } else {
2187             ret = 0;
2188         }
2189         break;
2190     case PM_SmallIconSize:
2191         ret = int(QStyleHelper::dpiScaled(16.));
2192         break;
2193
2194     case PM_LargeIconSize:
2195         ret = int(QStyleHelper::dpiScaled(32.));
2196         break;
2197
2198     case PM_IconViewIconSize:
2199         ret = proxy()->pixelMetric(PM_LargeIconSize, opt, widget);
2200         break;
2201
2202     case PM_ButtonDefaultIndicator:
2203         ret = 0;
2204         break;
2205     case PM_TitleBarHeight:
2206         if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
2207             HIThemeWindowDrawInfo wdi;
2208             wdi.version = qt_mac_hitheme_version;
2209             wdi.state = kThemeStateActive;
2210             wdi.windowType = QtWinType;
2211             if (tb->titleBarState)
2212                 wdi.attributes = kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
2213                                   | kThemeWindowHasCollapseBox;
2214             else if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
2215                 wdi.attributes = kThemeWindowHasCloseBox;
2216             else
2217                 wdi.attributes = 0;
2218             wdi.titleHeight = tb->rect.height();
2219             wdi.titleWidth = tb->rect.width();
2220             QCFType<HIShapeRef> region;
2221             HIRect hirect = qt_hirectForQRect(tb->rect);
2222             if (hirect.size.width <= 0)
2223                 hirect.size.width = 100;
2224             if (hirect.size.height <= 0)
2225                 hirect.size.height = 30;
2226
2227             HIThemeGetWindowShape(&hirect, &wdi, kWindowTitleBarRgn, &region);
2228             HIRect rect;
2229             ptrHIShapeGetBounds(region, &rect);
2230             ret = int(rect.size.height);
2231         }
2232         break;
2233     case PM_TabBarTabVSpace:
2234         ret = 4;
2235         break;
2236     case PM_TabBarTabShiftHorizontal:
2237     case PM_TabBarTabShiftVertical:
2238         ret = 0;
2239         break;
2240     case PM_TabBarBaseHeight:
2241         ret = 0;
2242         break;
2243     case PM_TabBarTabOverlap:
2244         ret = 0;
2245         break;
2246     case PM_TabBarBaseOverlap:
2247         switch (d->aquaSizeConstrain(opt, widget)) {
2248         case QAquaSizeUnknown:
2249         case QAquaSizeLarge:
2250             ret = 11;
2251             break;
2252         case QAquaSizeSmall:
2253             ret = 8;
2254             break;
2255         case QAquaSizeMini:
2256             ret = 7;
2257             break;
2258         }
2259         break;
2260     case PM_ScrollBarExtent: {
2261 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
2262         if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 &&
2263            [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay) {
2264             switch (d->aquaSizeConstrain(opt, widget)) {
2265             case QAquaSizeUnknown:
2266             case QAquaSizeLarge:
2267                 ret = QSysInfo::macVersion() >= QSysInfo::MV_10_8 ? 16 : 9;
2268                 break;
2269             case QAquaSizeMini:
2270             case QAquaSizeSmall:
2271                 ret =  QSysInfo::macVersion() >= QSysInfo::MV_10_8 ? 14 : 7;
2272                 break;
2273             }
2274             break;
2275         }
2276 #endif
2277         switch (d->aquaSizeConstrain(opt, widget)) {
2278         case QAquaSizeUnknown:
2279         case QAquaSizeLarge:
2280             GetThemeMetric(kThemeMetricScrollBarWidth, &ret);
2281             break;
2282         case QAquaSizeMini:
2283         case QAquaSizeSmall:
2284             GetThemeMetric(kThemeMetricSmallScrollBarWidth, &ret);
2285             break;
2286         }
2287         break; }
2288     case PM_IndicatorHeight: {
2289         switch (d->aquaSizeConstrain(opt, widget)) {
2290         case QAquaSizeUnknown:
2291         case QAquaSizeLarge:
2292             GetThemeMetric(kThemeMetricCheckBoxHeight, &ret);
2293             break;
2294         case QAquaSizeMini:
2295             GetThemeMetric(kThemeMetricMiniCheckBoxHeight, &ret);
2296             break;
2297         case QAquaSizeSmall:
2298             GetThemeMetric(kThemeMetricSmallCheckBoxHeight, &ret);
2299             break;
2300         }
2301         break; }
2302     case PM_IndicatorWidth: {
2303         switch (d->aquaSizeConstrain(opt, widget)) {
2304         case QAquaSizeUnknown:
2305         case QAquaSizeLarge:
2306             GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2307             break;
2308         case QAquaSizeMini:
2309             GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2310             break;
2311         case QAquaSizeSmall:
2312             GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2313             break;
2314         }
2315         ++ret;
2316         break; }
2317     case PM_ExclusiveIndicatorHeight: {
2318         switch (d->aquaSizeConstrain(opt, widget)) {
2319         case QAquaSizeUnknown:
2320         case QAquaSizeLarge:
2321             GetThemeMetric(kThemeMetricRadioButtonHeight, &ret);
2322             break;
2323         case QAquaSizeMini:
2324             GetThemeMetric(kThemeMetricMiniRadioButtonHeight, &ret);
2325             break;
2326         case QAquaSizeSmall:
2327             GetThemeMetric(kThemeMetricSmallRadioButtonHeight, &ret);
2328             break;
2329         }
2330         break; }
2331     case PM_ExclusiveIndicatorWidth: {
2332         switch (d->aquaSizeConstrain(opt, widget)) {
2333         case QAquaSizeUnknown:
2334         case QAquaSizeLarge:
2335             GetThemeMetric(kThemeMetricRadioButtonWidth, &ret);
2336             break;
2337         case QAquaSizeMini:
2338             GetThemeMetric(kThemeMetricMiniRadioButtonWidth, &ret);
2339             break;
2340         case QAquaSizeSmall:
2341             GetThemeMetric(kThemeMetricSmallRadioButtonWidth, &ret);
2342             break;
2343         }
2344         ++ret;
2345         break; }
2346     case PM_MenuVMargin:
2347         ret = 4;
2348         break;
2349     case PM_MenuPanelWidth:
2350         ret = 0;
2351         break;
2352     case PM_ToolTipLabelFrameWidth:
2353         ret = 0;
2354         break;
2355     case PM_SizeGripSize: {
2356         QAquaWidgetSize aSize;
2357         if (widget && widget->window()->windowType() == Qt::Tool)
2358             aSize = QAquaSizeSmall;
2359         else
2360             aSize = QAquaSizeLarge;
2361         const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize);
2362         ret = size.width();
2363         break; }
2364     case PM_MdiSubWindowFrameWidth:
2365         ret = 1;
2366         break;
2367     case PM_DockWidgetFrameWidth:
2368         ret = 0;
2369         break;
2370     case PM_DockWidgetTitleMargin:
2371         ret = 0;
2372         break;
2373     case PM_DockWidgetSeparatorExtent:
2374         ret = 1;
2375         break;
2376     case PM_ToolBarHandleExtent:
2377         ret = 11;
2378         break;
2379     case PM_ToolBarItemMargin:
2380         ret = 0;
2381         break;
2382     case PM_ToolBarItemSpacing:
2383         ret = 4;
2384         break;
2385     case PM_SplitterWidth:
2386         ret = qMax(7, QApplication::globalStrut().width());
2387         break;
2388     case PM_LayoutLeftMargin:
2389     case PM_LayoutTopMargin:
2390     case PM_LayoutRightMargin:
2391     case PM_LayoutBottomMargin:
2392         {
2393             bool isWindow = false;
2394             if (opt) {
2395                 isWindow = (opt->state & State_Window);
2396             } else if (widget) {
2397                 isWindow = widget->isWindow();
2398             }
2399
2400             if (isWindow) {
2401                 bool isMetal = widget && widget->testAttribute(Qt::WA_MacBrushedMetal);
2402                 if (isMetal) {
2403                     if (metric == PM_LayoutTopMargin) {
2404                         return_SIZE(9 /* AHIG */, 6 /* guess */, 6 /* guess */);
2405                     } else if (metric == PM_LayoutBottomMargin) {
2406                         return_SIZE(18 /* AHIG */, 15 /* guess */, 13 /* guess */);
2407                     } else {
2408                         return_SIZE(14 /* AHIG */, 11 /* guess */, 9 /* guess */);
2409                     }
2410                 } else {
2411                     /*
2412                         AHIG would have (20, 8, 10) here but that makes
2413                         no sense. It would also have 14 for the top margin
2414                         but this contradicts both Builder and most
2415                         applications.
2416                     */
2417                     return_SIZE(20, 10, 10);    // AHIG
2418                 }
2419             } else {
2420                 // hack to detect QTabWidget
2421                 if (widget && widget->parentWidget()
2422                         && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
2423                     if (metric == PM_LayoutTopMargin) {
2424                         /*
2425                             Builder would have 14 (= 20 - 6) instead of 12,
2426                             but that makes the tab look disproportionate.
2427                         */
2428                         return_SIZE(12, 6, 6);  // guess
2429                     } else {
2430                         return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
2431                     }
2432                 } else {
2433                     /*
2434                         Child margins are highly inconsistent in AHIG and Builder.
2435                     */
2436                     return_SIZE(12, 8, 6);    // guess
2437                 }
2438             }
2439         }
2440     case PM_LayoutHorizontalSpacing:
2441     case PM_LayoutVerticalSpacing:
2442         return -1;
2443     case QStyle::PM_TabBarTabHSpace:
2444         switch (d->aquaSizeConstrain(opt, widget)) {
2445         case QAquaSizeLarge:
2446         case QAquaSizeUnknown:
2447             ret = QCommonStyle::pixelMetric(metric, opt, widget);
2448             break;
2449         case QAquaSizeSmall:
2450             ret = 20;
2451             break;
2452         case QAquaSizeMini:
2453             ret = 16;
2454             break;
2455         }
2456         break;
2457     case PM_MenuHMargin:
2458         ret = 0;
2459         break;
2460     case PM_ToolBarExtensionExtent:
2461         ret = 21;
2462         break;
2463     case PM_ToolBarFrameWidth:
2464         ret = 1;
2465         break;
2466     case PM_ScrollView_ScrollBarOverlap:
2467 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
2468         ret = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7 &&
2469                [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay) ?
2470                pixelMetric(PM_ScrollBarExtent, opt, widget) : 0;
2471 #else
2472         ret = 0;
2473 #endif
2474         break;
2475     default:
2476         ret = QCommonStyle::pixelMetric(metric, opt, widget);
2477         break;
2478     }
2479     return ret;
2480 }
2481
2482 QPalette QMacStyle::standardPalette() const
2483 {
2484     QPalette pal = QCommonStyle::standardPalette();
2485     pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
2486     pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
2487     pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
2488     return pal;
2489 }
2490
2491 int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
2492                          QStyleHintReturn *hret) const
2493 {
2494     SInt32 ret = 0;
2495     switch (sh) {
2496     case SH_Slider_SnapToValue:
2497     case SH_PrintDialog_RightAlignButtons:
2498     case SH_FontDialog_SelectAssociatedText:
2499     case SH_MenuBar_MouseTracking:
2500     case SH_Menu_MouseTracking:
2501     case SH_ComboBox_ListMouseTracking:
2502     case SH_MainWindow_SpaceBelowMenuBar:
2503     case SH_ItemView_ChangeHighlightOnFocus:
2504         ret = 1;
2505         break;
2506     case SH_ToolBox_SelectedPageTitleBold:
2507         ret = 0;
2508         break;
2509     case SH_DialogButtonBox_ButtonsHaveIcons:
2510         ret = 0;
2511         break;
2512     case SH_Menu_SelectionWrap:
2513         ret = false;
2514         break;
2515     case SH_Menu_KeyboardSearch:
2516         ret = true;
2517         break;
2518     case SH_Menu_SpaceActivatesItem:
2519         ret = true;
2520         break;
2521     case SH_Slider_AbsoluteSetButtons:
2522         ret = Qt::LeftButton|Qt::MidButton;
2523         break;
2524     case SH_Slider_PageSetButtons:
2525         ret = 0;
2526         break;
2527     case SH_ScrollBar_ContextMenu:
2528         ret = false;
2529         break;
2530     case SH_TitleBar_AutoRaise:
2531         ret = true;
2532         break;
2533     case SH_Menu_AllowActiveAndDisabled:
2534         ret = false;
2535         break;
2536     case SH_Menu_SubMenuPopupDelay:
2537         ret = 100;
2538         break;
2539     case SH_ScrollBar_LeftClickAbsolutePosition: {
2540         NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
2541         bool result = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
2542         if(QApplication::keyboardModifiers() & Qt::AltModifier)
2543             ret = !result;
2544         else
2545             ret = result;
2546         break; }
2547     case SH_TabBar_PreferNoArrows:
2548         ret = true;
2549         break;
2550         /*
2551     case SH_DialogButtons_DefaultButton:
2552         ret = QDialogButtons::Reject;
2553         break;
2554         */
2555     case SH_GroupBox_TextLabelVerticalAlignment:
2556         ret = Qt::AlignTop;
2557         break;
2558     case SH_ScrollView_FrameOnlyAroundContents:
2559         ret = QCommonStyle::styleHint(sh, opt, w, hret);
2560         break;
2561     case SH_Menu_FillScreenWithScroll:
2562         ret = false;
2563         break;
2564     case SH_Menu_Scrollable:
2565         ret = true;
2566         break;
2567     case SH_RichText_FullWidthSelection:
2568         ret = true;
2569         break;
2570     case SH_BlinkCursorWhenTextSelected:
2571         ret = false;
2572         break;
2573     case SH_ScrollBar_StopMouseOverSlider:
2574         ret = true;
2575         break;
2576     case SH_ListViewExpand_SelectMouseType:
2577         ret = QEvent::MouseButtonRelease;
2578         break;
2579     case SH_TabBar_SelectMouseType:
2580         if (const QStyleOptionTabBarBaseV2 *opt2 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2581             ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2582         } else {
2583             ret = QEvent::MouseButtonRelease;
2584         }
2585         break;
2586     case SH_ComboBox_Popup:
2587         if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2588             ret = !cmb->editable;
2589         else
2590             ret = 0;
2591         break;
2592     case SH_Workspace_FillSpaceOnMaximize:
2593         ret = true;
2594         break;
2595     case SH_Widget_ShareActivation:
2596         ret = true;
2597         break;
2598     case SH_Header_ArrowAlignment:
2599         ret = Qt::AlignRight;
2600         break;
2601     case SH_TabBar_Alignment: {
2602         if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2603             if (tab->documentMode()) {
2604                 ret = Qt::AlignLeft;
2605                 break;
2606             }
2607         }
2608         if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2609             if (tab->documentMode()) {
2610                 ret = Qt::AlignLeft;
2611                 break;
2612             }
2613         }
2614         ret = Qt::AlignCenter;
2615         } break;
2616     case SH_UnderlineShortcut:
2617         ret = false;
2618         break;
2619     case SH_ToolTipLabel_Opacity:
2620         ret = 242; // About 95%
2621         break;
2622     case SH_Button_FocusPolicy:
2623         ret = Qt::TabFocus;
2624         break;
2625     case SH_EtchDisabledText:
2626         ret = false;
2627         break;
2628     case SH_FocusFrame_Mask: {
2629         ret = true;
2630         if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2631             const uchar fillR = 192, fillG = 191, fillB = 190;
2632             QImage img;
2633
2634             QSize pixmapSize = opt->rect.size();
2635             if (pixmapSize.isValid()) {
2636                 QPixmap pix(pixmapSize);
2637                 pix.fill(QColor(fillR, fillG, fillB));
2638                 QPainter pix_paint(&pix);
2639                 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint, w);
2640                 pix_paint.end();
2641                 img = pix.toImage();
2642             }
2643
2644             const QRgb *sptr = (QRgb*)img.bits(), *srow;
2645             const int sbpl = img.bytesPerLine();
2646             const int w = sbpl/4, h = img.height();
2647
2648             QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2649             QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2650             const int dbpl = img_mask.bytesPerLine();
2651
2652             for (int y = 0; y < h; ++y) {
2653                 srow = sptr+((y*sbpl)/4);
2654                 drow = dptr+((y*dbpl)/4);
2655                 for (int x = 0; x < w; ++x) {
2656                     const int redDiff = qRed(*srow) - fillR;
2657                     const int greenDiff = qGreen(*srow) - fillG;
2658                     const int blueDiff = qBlue(*srow) - fillB;
2659                     const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
2660                     (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
2661                     ++srow;
2662                 }
2663             }
2664             QBitmap qmask = QBitmap::fromImage(img_mask);
2665             mask->region = QRegion(qmask);
2666         }
2667         break; }
2668     case SH_TitleBar_NoBorder:
2669         ret = 1;
2670         break;
2671     case SH_RubberBand_Mask:
2672         ret = 0;
2673         break;
2674     case SH_ComboBox_LayoutDirection:
2675         ret = Qt::LeftToRight;
2676         break;
2677     case SH_ItemView_EllipsisLocation:
2678         ret = Qt::AlignHCenter;
2679         break;
2680     case SH_ItemView_ShowDecorationSelected:
2681         ret = true;
2682         break;
2683     case SH_TitleBar_ModifyNotification:
2684         ret = false;
2685         break;
2686     case SH_ScrollBar_RollBetweenButtons:
2687         ret = true;
2688         break;
2689     case SH_WindowFrame_Mask:
2690         ret = 1;
2691         if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hret)) {
2692             mask->region = opt->rect;
2693             mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1);
2694             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1);
2695             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1);
2696             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2);
2697
2698             mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1);
2699             mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1);
2700             mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1);
2701             mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2);
2702         }
2703         break;
2704     case SH_TabBar_ElideMode:
2705         ret = Qt::ElideRight;
2706         break;
2707     case SH_DialogButtonLayout:
2708         ret = QDialogButtonBox::MacLayout;
2709         break;
2710     case SH_FormLayoutWrapPolicy:
2711         ret = QFormLayout::DontWrapRows;
2712         break;
2713     case SH_FormLayoutFieldGrowthPolicy:
2714         ret = QFormLayout::FieldsStayAtSizeHint;
2715         break;
2716     case SH_FormLayoutFormAlignment:
2717         ret = Qt::AlignHCenter | Qt::AlignTop;
2718         break;
2719     case SH_FormLayoutLabelAlignment:
2720         ret = Qt::AlignRight;
2721         break;
2722     case SH_ComboBox_PopupFrameStyle:
2723         ret = QFrame::NoFrame | QFrame::Plain;
2724         break;
2725     case SH_MessageBox_TextInteractionFlags:
2726         ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2727         break;
2728     case SH_SpellCheckUnderlineStyle:
2729         ret = QTextCharFormat::DashUnderline;
2730         break;
2731     case SH_MessageBox_CenterButtons:
2732         ret = false;
2733         break;
2734     case SH_MenuBar_AltKeyNavigation:
2735         ret = false;
2736         break;
2737     case SH_ItemView_MovementWithoutUpdatingSelection:
2738         ret = false;
2739         break;
2740     case SH_FocusFrame_AboveWidget:
2741         ret = true;
2742         break;
2743     case SH_WizardStyle:
2744         ret = QWizard::MacStyle;
2745         break;
2746     case SH_ItemView_ArrowKeysNavigateIntoChildren:
2747         ret = false;
2748         break;
2749     case SH_Menu_FlashTriggeredItem:
2750         ret = true;
2751         break;
2752     case SH_Menu_FadeOutOnHide:
2753         ret = true;
2754         break;
2755     case SH_Menu_Mask:
2756         if (opt) {
2757             if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2758                 ret = true;
2759                 HIRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4,
2760                                              opt->rect.width(), opt->rect.height() - 8);
2761                 HIThemeMenuDrawInfo mdi;
2762                 mdi.version = 0;
2763                 if (w && qobject_cast<QMenu *>(w->parentWidget()))
2764                     mdi.menuType = kThemeMenuTypeHierarchical;
2765                 else
2766                     mdi.menuType = kThemeMenuTypePopUp;
2767                 QCFType<HIShapeRef> shape;
2768                 HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape);
2769
2770                 mask->region = qt_mac_fromHIShapeRef(shape);
2771             }
2772         }
2773         break;
2774     case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2775         ret = true;
2776         break;
2777     case SH_TabBar_CloseButtonPosition:
2778         ret = QTabBar::LeftSide;
2779         break;
2780     case SH_DockWidget_ButtonsHaveFrame:
2781         ret = false;
2782         break;
2783     case SH_ScrollBar_Transient:
2784         if ((qobject_cast<const QScrollBar *>(w) && w->parent() &&
2785                 qobject_cast<QAbstractScrollArea*>(w->parent()->parent())) ||
2786                 (opt && QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ScrollBar))) {
2787             ret = QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7;
2788 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
2789             if (ret)
2790                 ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay;
2791 #endif
2792         }
2793         break;
2794     default:
2795         ret = QCommonStyle::styleHint(sh, opt, w, hret);
2796         break;
2797     }
2798     return ret;
2799 }
2800
2801 QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
2802                                        const QStyleOption *opt) const
2803 {
2804     switch (iconMode) {
2805     case QIcon::Disabled: {
2806         QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2807         int imgh = img.height();
2808         int imgw = img.width();
2809         QRgb pixel;
2810         for (int y = 0; y < imgh; ++y) {
2811             for (int x = 0; x < imgw; ++x) {
2812                 pixel = img.pixel(x, y);
2813                 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2814                                          qAlpha(pixel) / 2));
2815             }
2816         }
2817         return QPixmap::fromImage(img);
2818     }
2819     default:
2820         ;
2821     }
2822     return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
2823 }
2824
2825
2826 QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
2827                                   const QWidget *widget) const
2828 {
2829     // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2830     // I don't want infinite recursion so if we do get in that situation, just return the Window's
2831     // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2832     // someone changes how Windows standard
2833     // pixmap works.
2834     static bool recursionGuard = false;
2835
2836     if (recursionGuard)