QMenu: Enable sloppy submenu mouse navigation
[qt:qt.git] / src / gui / 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 QtGui 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 "qmacstyle_mac.h"
48
49 #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC)
50 #define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
51 //#define DEBUG_SIZE_CONSTRAINT
52
53 #include <private/qapplication_p.h>
54 #include <private/qcombobox_p.h>
55 #include <private/qmacstylepixmaps_mac_p.h>
56 #include <private/qpaintengine_mac_p.h>
57 #include <private/qpainter_p.h>
58 #include <private/qprintengine_mac_p.h>
59 #include <qapplication.h>
60 #include <qbitmap.h>
61 #include <qcheckbox.h>
62 #include <qcombobox.h>
63 #include <qdialogbuttonbox.h>
64 #include <qdockwidget.h>
65 #include <qevent.h>
66 #include <qfocusframe.h>
67 #include <qformlayout.h>
68 #include <qgroupbox.h>
69 #include <qhash.h>
70 #include <qheaderview.h>
71 #include <qlayout.h>
72 #include <qlineedit.h>
73 #include <qlistview.h>
74 #include <qmainwindow.h>
75 #include <qmap.h>
76 #include <qmenubar.h>
77 #include <qpaintdevice.h>
78 #include <qpainter.h>
79 #include <qpixmapcache.h>
80 #include <qpointer.h>
81 #include <qprogressbar.h>
82 #include <qpushbutton.h>
83 #include <qradiobutton.h>
84 #include <qrubberband.h>
85 #include <qsizegrip.h>
86 #include <qspinbox.h>
87 #include <qsplitter.h>
88 #include <qstyleoption.h>
89 #include <qtextedit.h>
90 #include <qtextstream.h>
91 #include <qtoolbar.h>
92 #include <qtoolbutton.h>
93 #include <qtreeview.h>
94 #include <qtableview.h>
95 #include <qwizard.h>
96 #include <qdebug.h>
97 #include <qlibrary.h>
98 #include <qdatetimeedit.h>
99 #include <qmath.h>
100 #include <QtGui/qgraphicsproxywidget.h>
101 #include <QtGui/qgraphicsview.h>
102 #include <private/qt_cocoa_helpers_mac_p.h>
103 #include "qmacstyle_mac_p.h"
104 #include <private/qstylehelper_p.h>
105
106 QT_BEGIN_NAMESPACE
107
108 // The following constants are used for adjusting the size
109 // of push buttons so that they are drawn inside their bounds.
110 const int QMacStylePrivate::PushButtonLeftOffset = 6;
111 const int QMacStylePrivate::PushButtonTopOffset = 4;
112 const int QMacStylePrivate::PushButtonRightOffset = 12;
113 const int QMacStylePrivate::PushButtonBottomOffset = 12;
114 const int QMacStylePrivate::MiniButtonH = 26;
115 const int QMacStylePrivate::SmallButtonH = 30;
116 const int QMacStylePrivate::BevelButtonW = 50;
117 const int QMacStylePrivate::BevelButtonH = 22;
118 const int QMacStylePrivate::PushButtonContentPadding = 6;
119
120 // These colors specify the titlebar gradient colors on
121 // Leopard. Ideally we should get them from the system.
122 static const QColor titlebarGradientActiveBegin(220, 220, 220);
123 static const QColor titlebarGradientActiveEnd(151, 151, 151);
124 static const QColor titlebarSeparatorLineActive(111, 111, 111);
125 static const QColor titlebarGradientInactiveBegin(241, 241, 241);
126 static const QColor titlebarGradientInactiveEnd(207, 207, 207);
127 static const QColor titlebarSeparatorLineInactive(131, 131, 131);
128
129 // Gradient colors used for the dock widget title bar and
130 // non-unifed tool bar bacground.
131 static const QColor mainWindowGradientBegin(240, 240, 240);
132 static const QColor mainWindowGradientEnd(200, 200, 200);
133
134 static const int DisclosureOffset = 4;
135
136 // Resolve these at run-time, since the functions was moved in Leopard.
137 typedef HIRect * (*PtrHIShapeGetBounds)(HIShapeRef, HIRect *);
138 static PtrHIShapeGetBounds ptrHIShapeGetBounds = 0;
139
140 static int closeButtonSize = 12;
141
142 extern QRegion qt_mac_convert_mac_region(RgnHandle); //qregion_mac.cpp
143
144 static bool isVerticalTabs(const QTabBar::Shape shape) {
145     return (shape == QTabBar::RoundedEast
146                 || shape == QTabBar::TriangularEast
147                 || shape == QTabBar::RoundedWest
148                 || shape == QTabBar::TriangularWest);
149 }
150
151 void drawTabCloseButton(QPainter *p, bool hover, bool active, bool selected)
152 {
153     // draw background circle
154     p->setRenderHints(QPainter::Antialiasing);
155     QRect rect(0, 0, closeButtonSize, closeButtonSize);
156     QColor background;
157     if (hover) {
158         background = QColor(124, 124, 124);
159     } else {
160         if (active) {
161             if (selected)
162                 background = QColor(104, 104, 104);
163             else
164                 background = QColor(83, 83, 83);
165         } else {
166             if (selected)
167                 background = QColor(144, 144, 144);
168             else
169                 background = QColor(114, 114, 114);
170         }
171     }
172     p->setPen(Qt::transparent);
173     p->setBrush(background);
174     p->drawEllipse(rect);
175
176     // draw cross
177     int min = 3;
178     int max = 9;
179     QPen crossPen;
180     crossPen.setColor(QColor(194, 194, 194));
181     crossPen.setWidthF(1.3);
182     crossPen.setCapStyle(Qt::FlatCap);
183     p->setPen(crossPen);
184     p->drawLine(min, min, max, max);
185     p->drawLine(min, max, max, min);
186 }
187
188 QRect rotateTabPainter(QPainter *p, QTabBar::Shape shape, QRect tabRect)
189 {
190     if (isVerticalTabs(shape)) {
191         int newX, newY, newRot;
192         if (shape == QTabBar::RoundedEast
193             || shape == QTabBar::TriangularEast) {
194             newX = tabRect.width();
195             newY = tabRect.y();
196             newRot = 90;
197         } else {
198             newX = 0;
199             newY = tabRect.y() + tabRect.height();
200             newRot = -90;
201         }
202         tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
203         QMatrix m;
204         m.translate(newX, newY);
205         m.rotate(newRot);
206         p->setMatrix(m, true);
207     }
208     return tabRect;
209 }
210
211 void drawTabShape(QPainter *p, const QStyleOptionTabV3 *tabOpt)
212 {
213     QRect r = tabOpt->rect;
214     p->translate(tabOpt->rect.x(), tabOpt->rect.y());
215     r.moveLeft(0);
216     r.moveTop(0);
217     QRect tabRect = rotateTabPainter(p, tabOpt->shape, r);
218
219     int width = tabRect.width();
220     int height = 20;
221     bool active = (tabOpt->state & QStyle::State_Active);
222     bool selected = (tabOpt->state & QStyle::State_Selected);
223
224     if (selected) {
225         QRect rect(1, 0, width - 2, height);
226
227         // fill body
228         if (active) {
229             int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 16 : 0;
230             p->fillRect(rect, QColor(151 + d, 151 + d, 151 + d));
231         } else {
232             int d = (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) ? 9 : 0;
233             QLinearGradient gradient(rect.topLeft(), rect.bottomLeft());
234             gradient.setColorAt(0, QColor(207 + d, 207 + d, 207 + d));
235             gradient.setColorAt(0.5, QColor(206 + d, 206 + d, 206 + d));
236             gradient.setColorAt(1, QColor(201 + d, 201 + d, 201 + d));
237             p->fillRect(rect, gradient);
238         }
239
240         // draw border
241         QColor borderSides;
242         QColor borderBottom;
243         if (active) {
244             borderSides = QColor(88, 88, 88);
245             borderBottom = QColor(88, 88, 88);
246         } else {
247             borderSides = QColor(121, 121, 121);
248             borderBottom = QColor(116, 116, 116);
249         }
250
251         p->setPen(borderSides);
252
253         int bottom = height;
254         // left line
255         p->drawLine(0, 1, 0, bottom-2);
256         // right line
257         p->drawLine(width-1, 1, width-1, bottom-2);
258
259         // bottom line
260         if (active) {
261             p->setPen(QColor(168, 168, 168));
262             p->drawLine(3, bottom-1, width-3, bottom-1);
263         }
264         p->setPen(borderBottom);
265         p->drawLine(2, bottom, width-2, bottom);
266
267         int w = 3;
268         QRectF rectangleLeft(1, height - w, w, w);
269         QRectF rectangleRight(width - 2, height - 1, w, w);
270         int startAngle = 180 * 16;
271         int spanAngle = 90 * 16;
272         p->setRenderHint(QPainter::Antialiasing);
273         p->drawArc(rectangleLeft, startAngle, spanAngle);
274         p->drawArc(rectangleRight, startAngle, -spanAngle);
275     } else {
276         // when the mouse is over non selected tabs they get a new color
277         bool hover = (tabOpt->state & QStyle::State_MouseOver);
278         if (hover) {
279             QRect rect(1, 2, width - 1, height - 1);
280             p->fillRect(rect, QColor(110, 110, 110));
281         }
282
283         // seperator lines between tabs
284         bool west = (tabOpt->shape == QTabBar::RoundedWest || tabOpt->shape == QTabBar::TriangularWest);
285         bool drawOnRight = !west;
286         if ((!drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)
287             || (drawOnRight && tabOpt->selectedPosition != QStyleOptionTab::NextIsSelected)) {
288             QColor borderColor;
289             QColor borderHighlightColor;
290             if (active) {
291                 borderColor = QColor(64, 64, 64);
292                 borderHighlightColor = QColor(140, 140, 140);
293             } else {
294                 borderColor = QColor(135, 135, 135);
295                 borderHighlightColor = QColor(178, 178, 178);
296             }
297
298             int x = drawOnRight ? width : 0;
299
300             // tab seperator line
301             p->setPen(borderColor);
302             p->drawLine(x, 2, x, height + 1);
303
304             // tab seperator highlight
305             p->setPen(borderHighlightColor);
306             p->drawLine(x-1, 2, x-1, height + 1);
307             p->drawLine(x+1, 2, x+1, height + 1);
308         }
309     }
310 }
311
312 void drawTabBase(QPainter *p, const QStyleOptionTabBarBaseV2 *tbb, const QWidget *w)
313 {
314     QRect r = tbb->rect;
315     if (isVerticalTabs(tbb->shape)) {
316         r.setWidth(w->width());
317     } else {
318         r.setHeight(w->height());
319     }
320     QRect tabRect = rotateTabPainter(p, tbb->shape, r);
321     int width = tabRect.width();
322     int height = tabRect.height();
323     bool active = (tbb->state & QStyle::State_Active);
324
325     // top border lines
326     QColor borderHighlightTop;
327     QColor borderTop;
328     if (active) {
329         borderTop = QColor(64, 64, 64);
330         borderHighlightTop = QColor(174, 174, 174);
331     } else {
332         borderTop = QColor(135, 135, 135);
333         borderHighlightTop = QColor(207, 207, 207);
334     }
335     p->setPen(borderHighlightTop);
336     p->drawLine(tabRect.x(), 0, width, 0);
337     p->setPen(borderTop);
338     p->drawLine(tabRect.x(), 1, width, 1);
339
340     // center block
341     QRect centralRect(tabRect.x(), 2, width, height - 2);
342     if (active) {
343         QColor mainColor = QColor(120, 120, 120);
344         p->fillRect(centralRect, mainColor);
345     } else {
346         QLinearGradient gradient(centralRect.topLeft(), centralRect.bottomLeft());
347         gradient.setColorAt(0, QColor(165, 165, 165));
348         gradient.setColorAt(0.5, QColor(164, 164, 164));
349         gradient.setColorAt(1, QColor(158, 158, 158));
350         p->fillRect(centralRect, gradient);
351     }
352
353     // bottom border lines
354     QColor borderHighlightBottom;
355     QColor borderBottom;
356     if (active) {
357         borderHighlightBottom = QColor(153, 153, 153);
358         borderBottom = QColor(64, 64, 64);
359     } else {
360         borderHighlightBottom = QColor(177, 177, 177);
361         borderBottom = QColor(127, 127, 127);
362     }
363     p->setPen(borderHighlightBottom);
364     p->drawLine(tabRect.x(), height - 2, width, height - 2);
365     p->setPen(borderBottom);
366     p->drawLine(tabRect.x(), height - 1, width, height - 1);
367 }
368
369 static int getControlSize(const QStyleOption *option, const QWidget *widget)
370 {
371     if (option) {
372         if (option->state & (QStyle::State_Small | QStyle::State_Mini))
373             return (option->state & QStyle::State_Mini) ? QAquaSizeMini : QAquaSizeSmall;
374     } else if (widget) {
375         switch (QMacStyle::widgetSizePolicy(widget)) {
376         case QMacStyle::SizeSmall:
377             return QAquaSizeSmall;
378         case QMacStyle::SizeMini:
379             return QAquaSizeMini;
380         default:
381             break;
382         }
383     }
384     return QAquaSizeLarge;
385 }
386
387
388 static inline bool isTreeView(const QWidget *widget)
389 {
390     return (widget && widget->parentWidget() &&
391             (qobject_cast<const QTreeView *>(widget->parentWidget())
392 #ifdef QT3_SUPPORT
393              || widget->parentWidget()->inherits("Q3ListView")
394 #endif
395              ));
396 }
397
398 QString qt_mac_removeMnemonics(const QString &original)
399 {
400     QString returnText(original.size(), 0);
401     int finalDest = 0;
402     int currPos = 0;
403     int l = original.length();
404     while (l) {
405         if (original.at(currPos) == QLatin1Char('&')
406             && (l == 1 || original.at(currPos + 1) != QLatin1Char('&'))) {
407             ++currPos;
408             --l;
409             if (l == 0)
410                 break;
411         }
412         returnText[finalDest] = original.at(currPos);
413         ++currPos;
414         ++finalDest;
415         --l;
416     }
417     returnText.truncate(finalDest);
418     return returnText;
419 }
420
421 static inline ThemeTabDirection getTabDirection(QTabBar::Shape shape)
422 {
423     ThemeTabDirection ttd;
424     switch (shape) {
425     case QTabBar::RoundedSouth:
426     case QTabBar::TriangularSouth:
427         ttd = kThemeTabSouth;
428         break;
429     default:  // Added to remove the warning, since all values are taken care of, really!
430     case QTabBar::RoundedNorth:
431     case QTabBar::TriangularNorth:
432         ttd = kThemeTabNorth;
433         break;
434     case QTabBar::RoundedWest:
435     case QTabBar::TriangularWest:
436         ttd = kThemeTabWest;
437         break;
438     case QTabBar::RoundedEast:
439     case QTabBar::TriangularEast:
440         ttd = kThemeTabEast;
441         break;
442     }
443     return ttd;
444 }
445
446 QT_BEGIN_INCLUDE_NAMESPACE
447 #include "moc_qmacstyle_mac.cpp"
448 #include "moc_qmacstyle_mac_p.cpp"
449 QT_END_INCLUDE_NAMESPACE
450
451 /*****************************************************************************
452   External functions
453  *****************************************************************************/
454 extern CGContextRef qt_mac_cg_context(const QPaintDevice *); //qpaintdevice_mac.cpp
455 extern QRegion qt_mac_convert_mac_region(HIShapeRef); //qregion_mac.cpp
456 void qt_mac_dispose_rgn(RgnHandle r); //qregion_mac.cpp
457 extern QPaintDevice *qt_mac_safe_pdev; //qapplication_mac.cpp
458
459 /*****************************************************************************
460   QMacCGStyle globals
461  *****************************************************************************/
462 const int qt_mac_hitheme_version = 0; //the HITheme version we speak
463 const int macItemFrame         = 2;    // menu item frame width
464 const int macItemHMargin       = 3;    // menu item hor text margin
465 const int macItemVMargin       = 2;    // menu item ver text margin
466 const int macRightBorder       = 12;   // right border on mac
467 const ThemeWindowType QtWinType = kThemeDocumentWindow; // Window type we use for QTitleBar.
468 QPixmap *qt_mac_backgroundPattern = 0; // stores the standard widget background.
469
470 /*****************************************************************************
471   QMacCGStyle utility functions
472  *****************************************************************************/
473 static inline int qt_mac_hitheme_tab_version()
474 {
475     return 1;
476 }
477
478 static inline HIRect qt_hirectForQRect(const QRect &convertRect, const QRect &rect = QRect())
479 {
480     return CGRectMake(convertRect.x() + rect.x(), convertRect.y() + rect.y(),
481                       convertRect.width() - rect.width(), convertRect.height() - rect.height());
482 }
483
484 static inline const QRect qt_qrectForHIRect(const HIRect &hirect)
485 {
486     return QRect(QPoint(int(hirect.origin.x), int(hirect.origin.y)),
487                  QSize(int(hirect.size.width), int(hirect.size.height)));
488 }
489
490 inline bool qt_mac_is_metal(const QWidget *w)
491 {
492     for (; w; w = w->parentWidget()) {
493         if (w->testAttribute(Qt::WA_MacBrushedMetal))
494             return true;
495         if (w->isWindow() && w->testAttribute(Qt::WA_WState_Created)) {  // If not created will fall through to the opaque check and be fine anyway.
496                         return macWindowIsTextured(qt_mac_window_for(w));
497         }
498         if (w->d_func()->isOpaque)
499             break;
500     }
501     return false;
502 }
503
504 static int qt_mac_aqua_get_metric(ThemeMetric met)
505 {
506     SInt32 ret;
507     GetThemeMetric(met, &ret);
508     return ret;
509 }
510
511 static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QWidget *widg, QSize szHint,
512                                     QAquaWidgetSize sz)
513 {
514     QSize ret(-1, -1);
515     if (sz != QAquaSizeSmall && sz != QAquaSizeLarge && sz != QAquaSizeMini) {
516         qDebug("Not sure how to return this...");
517         return ret;
518     }
519     if ((widg && widg->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
520         // If you're using a custom font and it's bigger than the default font,
521         // then no constraints for you. If you are smaller, we can try to help you out
522         QFont font = qt_app_fonts_hash()->value(widg->metaObject()->className(), QFont());
523         if (widg->font().pointSize() > font.pointSize())
524             return ret;
525     }
526
527     if (ct == QStyle::CT_CustomBase && widg) {
528         if (qobject_cast<const QPushButton *>(widg))
529             ct = QStyle::CT_PushButton;
530         else if (qobject_cast<const QRadioButton *>(widg))
531             ct = QStyle::CT_RadioButton;
532         else if (qobject_cast<const QCheckBox *>(widg))
533             ct = QStyle::CT_CheckBox;
534         else if (qobject_cast<const QComboBox *>(widg))
535             ct = QStyle::CT_ComboBox;
536         else if (qobject_cast<const QToolButton *>(widg))
537             ct = QStyle::CT_ToolButton;
538         else if (qobject_cast<const QSlider *>(widg))
539             ct = QStyle::CT_Slider;
540         else if (qobject_cast<const QProgressBar *>(widg))
541             ct = QStyle::CT_ProgressBar;
542         else if (qobject_cast<const QLineEdit *>(widg))
543             ct = QStyle::CT_LineEdit;
544         else if (qobject_cast<const QHeaderView *>(widg)
545 #ifdef QT3_SUPPORT
546                  || widg->inherits("Q3Header")
547 #endif
548                 )
549             ct = QStyle::CT_HeaderSection;
550         else if (qobject_cast<const QMenuBar *>(widg)
551 #ifdef QT3_SUPPORT
552                 || widg->inherits("Q3MenuBar")
553 #endif
554                )
555             ct = QStyle::CT_MenuBar;
556         else if (qobject_cast<const QSizeGrip *>(widg))
557             ct = QStyle::CT_SizeGrip;
558         else
559             return ret;
560     }
561
562     switch (ct) {
563     case QStyle::CT_PushButton: {
564         const QPushButton *psh = qobject_cast<const QPushButton *>(widg);
565         // If this comparison is false, then the widget was not a push button.
566         // This is bad and there's very little we can do since we were requested to find a
567         // sensible size for a widget that pretends to be a QPushButton but is not.
568         if(psh) {
569             QString buttonText = qt_mac_removeMnemonics(psh->text());
570             if (buttonText.contains(QLatin1Char('\n')))
571                 ret = QSize(-1, -1);
572             else if (sz == QAquaSizeLarge)
573                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
574             else if (sz == QAquaSizeSmall)
575                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
576             else if (sz == QAquaSizeMini)
577                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
578
579             if (!psh->icon().isNull()){
580                 // If the button got an icon, and the icon is larger than the
581                 // button, we can't decide on a default size
582                 ret.setWidth(-1);
583                 if (ret.height() < psh->iconSize().height())
584                     ret.setHeight(-1);
585             }
586             else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
587                 // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
588                 // However, this doesn't work for German, therefore only do it for English,
589                 // I suppose it would be better to do some sort of lookups for languages
590                 // that like to have really long words.
591                 ret.setWidth(77 - 8);
592             }
593         } else {
594             // The only sensible thing to do is to return whatever the style suggests...
595             if (sz == QAquaSizeLarge)
596                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
597             else if (sz == QAquaSizeSmall)
598                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPushButtonHeight));
599             else if (sz == QAquaSizeMini)
600                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPushButtonHeight));
601             else
602                 // Since there's no default size we return the large size...
603                 ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPushButtonHeight));
604          }
605 #if 0 //Not sure we are applying the rules correctly for RadioButtons/CheckBoxes --Sam
606     } else if (ct == QStyle::CT_RadioButton) {
607         QRadioButton *rdo = static_cast<QRadioButton *>(widg);
608         // Exception for case where multiline radio button text requires no size constrainment
609         if (rdo->text().find('\n') != -1)
610             return ret;
611         if (sz == QAquaSizeLarge)
612             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricRadioButtonHeight));
613         else if (sz == QAquaSizeSmall)
614             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallRadioButtonHeight));
615         else if (sz == QAquaSizeMini)
616             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniRadioButtonHeight));
617     } else if (ct == QStyle::CT_CheckBox) {
618         if (sz == QAquaSizeLarge)
619             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricCheckBoxHeight));
620         else if (sz == QAquaSizeSmall)
621             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallCheckBoxHeight));
622         else if (sz == QAquaSizeMini)
623             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniCheckBoxHeight));
624 #endif
625         break;
626     }
627     case QStyle::CT_SizeGrip:
628         if (sz == QAquaSizeLarge || sz == QAquaSizeSmall) {
629             HIRect r;
630             HIPoint p = { 0, 0 };
631             HIThemeGrowBoxDrawInfo gbi;
632             gbi.version = 0;
633             gbi.state = kThemeStateActive;
634             gbi.kind = kHIThemeGrowBoxKindNormal;
635             gbi.direction = QApplication::isRightToLeft() ? kThemeGrowLeft | kThemeGrowDown
636                                                           : kThemeGrowRight | kThemeGrowDown;
637             gbi.size = sz == QAquaSizeSmall ? kHIThemeGrowBoxSizeSmall : kHIThemeGrowBoxSizeNormal;
638             if (HIThemeGetGrowBoxBounds(&p, &gbi, &r) == noErr)
639                 ret = QSize(r.size.width, r.size.height);
640         }
641         break;
642     case QStyle::CT_ComboBox:
643         switch (sz) {
644         case QAquaSizeLarge:
645             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricPopupButtonHeight));
646             break;
647         case QAquaSizeSmall:
648             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricSmallPopupButtonHeight));
649             break;
650         case QAquaSizeMini:
651             ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricMiniPopupButtonHeight));
652             break;
653         default:
654             break;
655         }
656         break;
657     case QStyle::CT_ToolButton:
658         if (sz == QAquaSizeSmall) {
659             int width = 0, height = 0;
660             if (szHint == QSize(-1, -1)) { //just 'guess'..
661                 const QToolButton *bt = qobject_cast<const QToolButton *>(widg);
662                 // If this conversion fails then the widget was not what it claimed to be.
663                 if(bt) {
664                     if (!bt->icon().isNull()) {
665                         QSize iconSize = bt->iconSize();
666                         QSize pmSize = bt->icon().actualSize(QSize(32, 32), QIcon::Normal);
667                         width = qMax(width, qMax(iconSize.width(), pmSize.width()));
668                         height = qMax(height, qMax(iconSize.height(), pmSize.height()));
669                     }
670                     if (!bt->text().isNull() && bt->toolButtonStyle() != Qt::ToolButtonIconOnly) {
671                         int text_width = bt->fontMetrics().width(bt->text()),
672                            text_height = bt->fontMetrics().height();
673                         if (bt->toolButtonStyle() == Qt::ToolButtonTextUnderIcon) {
674                             width = qMax(width, text_width);
675                             height += text_height;
676                         } else {
677                             width += text_width;
678                             width = qMax(height, text_height);
679                         }
680                     }
681                 } else {
682                     // Let's return the size hint...
683                     width = szHint.width();
684                     height = szHint.height();
685                 }
686             } else {
687                 width = szHint.width();
688                 height = szHint.height();
689             }
690             width =  qMax(20, width +  5); //border
691             height = qMax(20, height + 5); //border
692             ret = QSize(width, height);
693         }
694         break;
695     case QStyle::CT_Slider: {
696         int w = -1;
697         const QSlider *sld = qobject_cast<const QSlider *>(widg);
698         // If this conversion fails then the widget was not what it claimed to be.
699         if(sld) {
700             if (sz == QAquaSizeLarge) {
701                 if (sld->orientation() == Qt::Horizontal) {
702                     w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
703                     if (sld->tickPosition() != QSlider::NoTicks)
704                         w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
705                 } else {
706                     w = qt_mac_aqua_get_metric(kThemeMetricVSliderWidth);
707                     if (sld->tickPosition() != QSlider::NoTicks)
708                         w += qt_mac_aqua_get_metric(kThemeMetricVSliderTickWidth);
709                 }
710             } else if (sz == QAquaSizeSmall) {
711                 if (sld->orientation() == Qt::Horizontal) {
712                     w = qt_mac_aqua_get_metric(kThemeMetricSmallHSliderHeight);
713                     if (sld->tickPosition() != QSlider::NoTicks)
714                         w += qt_mac_aqua_get_metric(kThemeMetricSmallHSliderTickHeight);
715                 } else {
716                     w = qt_mac_aqua_get_metric(kThemeMetricSmallVSliderWidth);
717                     if (sld->tickPosition() != QSlider::NoTicks)
718                         w += qt_mac_aqua_get_metric(kThemeMetricSmallVSliderTickWidth);
719                 }
720             } else if (sz == QAquaSizeMini) {
721                 if (sld->orientation() == Qt::Horizontal) {
722                     w = qt_mac_aqua_get_metric(kThemeMetricMiniHSliderHeight);
723                     if (sld->tickPosition() != QSlider::NoTicks)
724                         w += qt_mac_aqua_get_metric(kThemeMetricMiniHSliderTickHeight);
725                 } else {
726                     w = qt_mac_aqua_get_metric(kThemeMetricMiniVSliderWidth);
727                     if (sld->tickPosition() != QSlider::NoTicks)
728                         w += qt_mac_aqua_get_metric(kThemeMetricMiniVSliderTickWidth);
729                 }
730             }
731         } else {
732             // This is tricky, we were requested to find a size for a slider which is not
733             // a slider. We don't know if this is vertical or horizontal or if we need to
734             // have tick marks or not.
735             // For this case we will return an horizontal slider without tick marks.
736             w = qt_mac_aqua_get_metric(kThemeMetricHSliderHeight);
737             w += qt_mac_aqua_get_metric(kThemeMetricHSliderTickHeight);
738         }
739         if (sld->orientation() == Qt::Horizontal)
740             ret.setHeight(w);
741         else
742             ret.setWidth(w);
743         break;
744     }
745     case QStyle::CT_ProgressBar: {
746         int finalValue = -1;
747         Qt::Orientation orient = Qt::Horizontal;
748         if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
749             orient = pb->orientation();
750
751         if (sz == QAquaSizeLarge)
752             finalValue = qt_mac_aqua_get_metric(kThemeMetricLargeProgressBarThickness)
753                             + qt_mac_aqua_get_metric(kThemeMetricProgressBarShadowOutset);
754         else
755             finalValue = qt_mac_aqua_get_metric(kThemeMetricNormalProgressBarThickness)
756                             + qt_mac_aqua_get_metric(kThemeMetricSmallProgressBarShadowOutset);
757         if (orient == Qt::Horizontal)
758             ret.setHeight(finalValue);
759         else
760             ret.setWidth(finalValue);
761         break;
762     }
763     case QStyle::CT_LineEdit:
764         if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
765             //should I take into account the font dimentions of the lineedit? -Sam
766             if (sz == QAquaSizeLarge)
767                 ret = QSize(-1, 21);
768             else
769                 ret = QSize(-1, 19);
770         }
771         break;
772     case QStyle::CT_HeaderSection:
773         if (isTreeView(widg))
774            ret = QSize(-1, qt_mac_aqua_get_metric(kThemeMetricListHeaderHeight));
775         break;
776     case QStyle::CT_MenuBar:
777         if (sz == QAquaSizeLarge) {
778 #ifndef QT_MAC_USE_COCOA
779             SInt16 size;
780             if (!GetThemeMenuBarHeight(&size))
781                 ret = QSize(-1, size);
782 #else
783             ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
784             // In the qt_mac_set_native_menubar(false) case,
785             // we come it here with a zero-height main menu,
786             // preventing the in-window menu from displaying.
787             // Use 22 pixels for the height, by observation.
788             if (ret.height() <= 0)
789                 ret.setHeight(22);
790 #endif
791         }
792         break;
793     default:
794         break;
795     }
796     return ret;
797 }
798
799
800 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
801 static QAquaWidgetSize qt_aqua_guess_size(const QWidget *widg, QSize large, QSize small, QSize mini)
802 {
803     if (large == QSize(-1, -1)) {
804         if (small != QSize(-1, -1))
805             return QAquaSizeSmall;
806         if (mini != QSize(-1, -1))
807             return QAquaSizeMini;
808         return QAquaSizeUnknown;
809     } else if (small == QSize(-1, -1)) {
810         if (mini != QSize(-1, -1))
811             return QAquaSizeMini;
812         return QAquaSizeLarge;
813     } else if (mini == QSize(-1, -1)) {
814         return QAquaSizeLarge;
815     }
816
817 #ifndef QT_NO_MAINWINDOW
818     if (qobject_cast<QDockWidget *>(widg->window()) || !qgetenv("QWIDGET_ALL_SMALL").isNull()) {
819         //if (small.width() != -1 || small.height() != -1)
820         return QAquaSizeSmall;
821     } else if (!qgetenv("QWIDGET_ALL_MINI").isNull()) {
822         return QAquaSizeMini;
823     }
824 #endif
825
826 #if 0
827     /* Figure out which size we're closer to, I just hacked this in, I haven't
828        tested it as it would probably look pretty strange to have some widgets
829        big and some widgets small in the same window?? -Sam */
830     int large_delta=0;
831     if (large.width() != -1) {
832         int delta = large.width() - widg->width();
833         large_delta += delta * delta;
834     }
835     if (large.height() != -1) {
836         int delta = large.height() - widg->height();
837         large_delta += delta * delta;
838     }
839     int small_delta=0;
840     if (small.width() != -1) {
841         int delta = small.width() - widg->width();
842         small_delta += delta * delta;
843     }
844     if (small.height() != -1) {
845         int delta = small.height() - widg->height();
846         small_delta += delta * delta;
847     }
848     int mini_delta=0;
849     if (mini.width() != -1) {
850         int delta = mini.width() - widg->width();
851         mini_delta += delta * delta;
852     }
853     if (mini.height() != -1) {
854         int delta = mini.height() - widg->height();
855         mini_delta += delta * delta;
856     }
857     if (mini_delta < small_delta && mini_delta < large_delta)
858         return QAquaSizeMini;
859     else if (small_delta < large_delta)
860         return QAquaSizeSmall;
861 #endif
862     return QAquaSizeLarge;
863 }
864 #endif
865
866 QAquaWidgetSize QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option, const QWidget *widg,
867                                        QStyle::ContentsType ct, QSize szHint, QSize *insz) const
868 {
869 #if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
870     if (option) {
871         if (option->state & QStyle::State_Small)
872             return QAquaSizeSmall;
873         if (option->state & QStyle::State_Mini)
874             return QAquaSizeMini;
875     }
876
877     if (!widg) {
878         if (insz)
879             *insz = QSize();
880         if (!qgetenv("QWIDGET_ALL_SMALL").isNull())
881             return QAquaSizeSmall;
882         if (!qgetenv("QWIDGET_ALL_MINI").isNull())
883             return QAquaSizeMini;
884         return QAquaSizeUnknown;
885     }
886     QSize large = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeLarge),
887           small = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeSmall),
888           mini  = qt_aqua_get_known_size(ct, widg, szHint, QAquaSizeMini);
889     bool guess_size = false;
890     QAquaWidgetSize ret = QAquaSizeUnknown;
891     QMacStyle::WidgetSizePolicy wsp = q->widgetSizePolicy(widg);
892     if (wsp == QMacStyle::SizeDefault)
893         guess_size = true;
894     else if (wsp == QMacStyle::SizeMini)
895         ret = QAquaSizeMini;
896     else if (wsp == QMacStyle::SizeSmall)
897         ret = QAquaSizeSmall;
898     else if (wsp == QMacStyle::SizeLarge)
899         ret = QAquaSizeLarge;
900     if (guess_size)
901         ret = qt_aqua_guess_size(widg, large, small, mini);
902
903     QSize *sz = 0;
904     if (ret == QAquaSizeSmall)
905         sz = &small;
906     else if (ret == QAquaSizeLarge)
907         sz = &large;
908     else if (ret == QAquaSizeMini)
909         sz = &mini;
910     if (insz)
911         *insz = sz ? *sz : QSize(-1, -1);
912 #ifdef DEBUG_SIZE_CONSTRAINT
913     if (sz) {
914         const char *size_desc = "Unknown";
915         if (sz == &small)
916             size_desc = "Small";
917         else if (sz == &large)
918             size_desc = "Large";
919         else if (sz == &mini)
920             size_desc = "Mini";
921         qDebug("%s - %s: %s taken (%d, %d) [%d, %d]",
922                widg ? widg->objectName().toLatin1().constData() : "*Unknown*",
923                widg ? widg->metaObject()->className() : "*Unknown*", size_desc, widg->width(), widg->height(),
924                sz->width(), sz->height());
925     }
926 #endif
927     return ret;
928 #else
929     if (insz)
930         *insz = QSize();
931     Q_UNUSED(widg);
932     Q_UNUSED(ct);
933     Q_UNUSED(szHint);
934     return QAquaSizeUnknown;
935 #endif
936 }
937
938 /**
939     Returns the free space awailable for contents inside the
940     button (and not the size of the contents itself)
941 */
942 HIRect QMacStylePrivate::pushButtonContentBounds(const QStyleOptionButton *btn,
943                                                  const HIThemeButtonDrawInfo *bdi) const
944 {
945     HIRect outerBounds = qt_hirectForQRect(btn->rect);
946     // Adjust the bounds to correct for
947     // carbon not calculating the content bounds fully correct
948     if (bdi->kind == kThemePushButton || bdi->kind == kThemePushButtonSmall){
949         outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
950         outerBounds.size.height -= QMacStylePrivate::PushButtonBottomOffset;
951     } else if (bdi->kind == kThemePushButtonMini) {
952         outerBounds.origin.y += QMacStylePrivate::PushButtonTopOffset;
953     }
954
955     HIRect contentBounds;
956     HIThemeGetButtonContentBounds(&outerBounds, bdi, &contentBounds);
957     return contentBounds;
958 }
959
960 /**
961     Calculates the size of the button contents.
962     This includes both the text and the icon.
963 */
964 QSize QMacStylePrivate::pushButtonSizeFromContents(const QStyleOptionButton *btn) const
965 {
966     QSize csz(0, 0);
967     QSize iconSize = btn->icon.isNull() ? QSize(0, 0)
968                 : (btn->iconSize + QSize(QMacStylePrivate::PushButtonContentPadding, 0));
969     QRect textRect = btn->text.isEmpty() ? QRect(0, 0, 1, 1)
970                 : btn->fontMetrics.boundingRect(QRect(), Qt::AlignCenter, btn->text);
971     csz.setWidth(iconSize.width() + textRect.width()
972              + ((btn->features & QStyleOptionButton::HasMenu)
973                             ? q->proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn, 0) : 0));
974     csz.setHeight(qMax(iconSize.height(), textRect.height()));
975     return csz;
976 }
977
978 /**
979     Checks if the actual contents of btn fits inside the free content bounds of
980     'buttonKindToCheck'. Meant as a helper function for 'initHIThemePushButton'
981     for determining which button kind to use for drawing.
982 */
983 bool QMacStylePrivate::contentFitsInPushButton(const QStyleOptionButton *btn,
984                                                HIThemeButtonDrawInfo *bdi,
985                                                ThemeButtonKind buttonKindToCheck) const
986 {
987     ThemeButtonKind tmp = bdi->kind;
988     bdi->kind = buttonKindToCheck;
989     QSize contentSize = pushButtonSizeFromContents(btn);
990     QRect freeContentRect = qt_qrectForHIRect(pushButtonContentBounds(btn, bdi));
991     bdi->kind = tmp;
992     return freeContentRect.contains(QRect(freeContentRect.x(), freeContentRect.y(),
993                                     contentSize.width(), contentSize.height()));
994 }
995
996 /**
997     Creates a HIThemeButtonDrawInfo structure that specifies the correct button
998     kind and other details to use for drawing the given push button. Which
999     button kind depends on the size of the button, the size of the contents,
1000     explicit user style settings, etc.
1001 */
1002 void QMacStylePrivate::initHIThemePushButton(const QStyleOptionButton *btn,
1003                                              const QWidget *widget,
1004                                              const ThemeDrawState tds,
1005                                              HIThemeButtonDrawInfo *bdi) const
1006 {
1007     bool drawColorless = btn->palette.currentColorGroup() == QPalette::Active;
1008     ThemeDrawState tdsModified = tds;
1009     if (btn->state & QStyle::State_On)
1010         tdsModified = kThemeStatePressed;
1011     bdi->version = qt_mac_hitheme_version;
1012     bdi->state = tdsModified;
1013     bdi->value = kThemeButtonOff;
1014
1015     if (drawColorless && tdsModified == kThemeStateInactive)
1016         bdi->state = kThemeStateActive;
1017     if (btn->state & QStyle::State_HasFocus)
1018         bdi->adornment = kThemeAdornmentFocus;
1019     else
1020         bdi->adornment = kThemeAdornmentNone;
1021
1022
1023     if (btn->features & (QStyleOptionButton::Flat)) {
1024         bdi->kind = kThemeBevelButton;
1025     } else {
1026         switch (aquaSizeConstrain(btn, widget)) {
1027         case QAquaSizeSmall:
1028             bdi->kind = kThemePushButtonSmall;
1029             break;
1030         case QAquaSizeMini:
1031             bdi->kind = kThemePushButtonMini;
1032             break;
1033         case QAquaSizeLarge:
1034             // ... We should honor if the user is explicit about using the
1035             // large button. But right now Qt will specify the large button
1036             // as default rather than QAquaSizeUnknown.
1037             // So we treat it like QAquaSizeUnknown
1038             // to get the dynamic choosing of button kind.
1039         case QAquaSizeUnknown:
1040             // Choose the button kind that closest match the button rect, but at the
1041             // same time displays the button contents without clipping.
1042             bdi->kind = kThemeBevelButton;
1043             if (btn->rect.width() >= QMacStylePrivate::BevelButtonW && btn->rect.height() >= QMacStylePrivate::BevelButtonH){
1044                 if (widget && widget->testAttribute(Qt::WA_MacVariableSize)) {
1045                     if (btn->rect.height() <= QMacStylePrivate::MiniButtonH){
1046                         if (contentFitsInPushButton(btn, bdi, kThemePushButtonMini))
1047                             bdi->kind = kThemePushButtonMini;
1048                     } else if (btn->rect.height() <= QMacStylePrivate::SmallButtonH){
1049                         if (contentFitsInPushButton(btn, bdi, kThemePushButtonSmall))
1050                             bdi->kind = kThemePushButtonSmall;
1051                     } else if (contentFitsInPushButton(btn, bdi, kThemePushButton)) {
1052                         bdi->kind = kThemePushButton;
1053                     }
1054                 } else {
1055                     bdi->kind = kThemePushButton;
1056                 }
1057             }
1058         }
1059     }
1060 }
1061
1062 bool qt_mac_buttonIsRenderedFlat(const QPushButton *pushButton, const QStyleOptionButton *option)
1063 {
1064     QMacStyle *macStyle = qobject_cast<QMacStyle *>(pushButton->style());
1065     if (!macStyle)
1066         return true;    // revert to 'flat' behavior if not Mac style
1067     HIThemeButtonDrawInfo bdi;
1068     macStyle->d->initHIThemePushButton(option, pushButton, kThemeStateActive, &bdi);
1069     return bdi.kind == kThemeBevelButton;
1070 }
1071
1072 /**
1073     Creates a HIThemeButtonDrawInfo structure that specifies the correct button
1074     kind and other details to use for drawing the given combobox. Which button
1075     kind depends on the size of the combo, wether or not it is editable,
1076     explicit user style settings, etc.
1077 */
1078 void QMacStylePrivate::initComboboxBdi(const QStyleOptionComboBox *combo, HIThemeButtonDrawInfo *bdi,
1079                                     const QWidget *widget, const ThemeDrawState &tds)
1080 {
1081     bdi->version = qt_mac_hitheme_version;
1082     bdi->adornment = kThemeAdornmentArrowLeftArrow;
1083     bdi->value = kThemeButtonOff;
1084     if (combo->state & QStyle::State_HasFocus)
1085         bdi->adornment = kThemeAdornmentFocus;
1086     bool drawColorless = combo->palette.currentColorGroup() == QPalette::Active && tds == kThemeStateInactive;
1087     if (combo->activeSubControls & QStyle::SC_ComboBoxArrow)
1088         bdi->state = kThemeStatePressed;
1089     else if (drawColorless)
1090         bdi->state = kThemeStateActive;
1091     else
1092         bdi->state = tds;
1093
1094     QAquaWidgetSize aSize = aquaSizeConstrain(combo, widget);
1095     switch (aSize) {
1096     case QAquaSizeMini:
1097         bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxMini)
1098             : ThemeButtonKind(kThemePopupButtonMini);
1099         break;
1100     case QAquaSizeSmall:
1101         bdi->kind = combo->editable ? ThemeButtonKind(kThemeComboBoxSmall)
1102             : ThemeButtonKind(kThemePopupButtonSmall);
1103         break;
1104     case QAquaSizeUnknown:
1105     case QAquaSizeLarge:
1106         // Unless the user explicitly specified large buttons, determine the
1107         // kind by looking at the combox size.
1108         // ... specifying small and mini-buttons it not a current feature of
1109         // Qt (e.g. QWidget::getAttribute(WA_ButtonSize)). But when it is, add
1110         // an extra check here before using the mini and small buttons.
1111         int h = combo->rect.size().height();
1112         if (combo->editable){
1113             if (h < 21)
1114                 bdi->kind = kThemeComboBoxMini;
1115             else if (h < 26)
1116                 bdi->kind = kThemeComboBoxSmall;
1117             else
1118                 bdi->kind = kThemeComboBox;
1119         } else {
1120             // Even if we specify that we want the kThemePopupButton, Carbon
1121             // will use the kThemePopupButtonSmall if the size matches. So we
1122             // do the same size check explicit to have the size of the inner
1123             // text field be correct. Therefore, do this even if the user specifies
1124             // the use of LargeButtons explicit.
1125             if (h < 21)
1126                 bdi->kind = kThemePopupButtonMini;
1127             else if (h < 26)
1128                 bdi->kind = kThemePopupButtonSmall;
1129             else
1130                 bdi->kind = kThemePopupButton;
1131         }
1132         break;
1133     }
1134 }
1135
1136 /**
1137     Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
1138     the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
1139 */
1140 HIRect QMacStylePrivate::comboboxInnerBounds(const HIRect &outerBounds, int buttonKind)
1141 {
1142     HIRect innerBounds = outerBounds;
1143     // Carbon draw parts of the view outside the rect.
1144     // So make the rect a bit smaller to compensate
1145     // (I wish HIThemeGetButtonBackgroundBounds worked)
1146     switch (buttonKind){
1147     case kThemePopupButton:
1148         innerBounds.origin.x += 2;
1149         innerBounds.origin.y += 2;
1150         innerBounds.size.width -= 5;
1151         innerBounds.size.height -= 6;
1152         break;
1153     case kThemePopupButtonSmall:
1154         innerBounds.origin.x += 3;
1155         innerBounds.origin.y += 3;
1156         innerBounds.size.width -= 6;
1157         innerBounds.size.height -= 7;
1158         break;
1159     case kThemePopupButtonMini:
1160         innerBounds.origin.x += 2;
1161         innerBounds.origin.y += 2;
1162         innerBounds.size.width -= 5;
1163         innerBounds.size.height -= 6;
1164         break;
1165     case kThemeComboBox:
1166         innerBounds.origin.x += 3;
1167         innerBounds.origin.y += 2;
1168         innerBounds.size.width -= 6;
1169         innerBounds.size.height -= 8;
1170         break;
1171     case kThemeComboBoxSmall:
1172         innerBounds.origin.x += 3;
1173         innerBounds.origin.y += 3;
1174         innerBounds.size.width -= 7;
1175         innerBounds.size.height -= 8;
1176         break;
1177     case kThemeComboBoxMini:
1178         innerBounds.origin.x += 3;
1179         innerBounds.origin.y += 3;
1180         innerBounds.size.width -= 4;
1181         innerBounds.size.height -= 8;
1182         break;
1183     default:
1184         break;
1185     }
1186     return innerBounds;
1187 }
1188
1189 /**
1190     Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind
1191     of combobox we choose to draw. This function calculates and returns this size.
1192 */
1193 QRect QMacStylePrivate::comboboxEditBounds(const QRect &outerBounds, const HIThemeButtonDrawInfo &bdi)
1194 {
1195     QRect ret = outerBounds;
1196     switch (bdi.kind){
1197     case kThemeComboBox:
1198         ret.adjust(5, 5, -22, -5);
1199         break;
1200     case kThemeComboBoxSmall:
1201         ret.adjust(4, 6, -20, 0);
1202         ret.setHeight(14);
1203         break;
1204     case kThemeComboBoxMini:
1205         ret.adjust(4, 5, -18, -1);
1206         ret.setHeight(12);
1207         break;
1208     case kThemePopupButton:
1209         ret.adjust(10, 2, -23, -4);
1210         break;
1211     case kThemePopupButtonSmall:
1212         ret.adjust(9, 3, -20, -3);
1213         break;
1214     case kThemePopupButtonMini:
1215         ret.adjust(8, 3, -19, 0);
1216         ret.setHeight(13);
1217         break;
1218     }
1219     return ret;
1220 }
1221
1222 /**
1223     Carbon comboboxes don't scale (sight). If the size of the combo suggest a scaled version,
1224     create it manually by drawing a small Carbon combo onto a pixmap (use pixmap cache), chop
1225     it up, and copy it back onto the widget. Othervise, draw the combobox supplied by Carbon directly.
1226 */
1227 void QMacStylePrivate::drawCombobox(const HIRect &outerBounds, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1228 {
1229     if (!(bdi.kind == kThemeComboBox && outerBounds.size.height > 28)){
1230         // We have an unscaled combobox, or popup-button; use Carbon directly.
1231         HIRect innerBounds = QMacStylePrivate::comboboxInnerBounds(outerBounds, bdi.kind);
1232         HIThemeDrawButton(&innerBounds, &bdi, QMacCGContext(p), kHIThemeOrientationNormal, 0);
1233     } else {
1234         QPixmap buffer;
1235         QString key = QString(QLatin1String("$qt_cbox%1-%2")).arg(int(bdi.state)).arg(int(bdi.adornment));
1236         if (!QPixmapCache::find(key, buffer)) {
1237             HIRect innerBoundsSmallCombo = {{3, 3}, {29, 25}};
1238             buffer = QPixmap(35, 28);
1239             buffer.fill(Qt::transparent);
1240             QPainter buffPainter(&buffer);
1241             HIThemeDrawButton(&innerBoundsSmallCombo, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1242             buffPainter.end();
1243             QPixmapCache::insert(key, buffer);
1244         }
1245
1246         const int bwidth = 20;
1247         const int fwidth = 10;
1248         const int fheight = 10;
1249         int w = qRound(outerBounds.size.width);
1250         int h = qRound(outerBounds.size.height);
1251         int bstart = w - bwidth;
1252         int blower = fheight + 1;
1253         int flower = h - fheight;
1254         int sheight = flower - fheight;
1255         int center = qRound(outerBounds.size.height + outerBounds.origin.y) / 2;
1256
1257         // Draw upper and lower gap
1258         p->drawPixmap(fwidth, 0, bstart - fwidth, fheight, buffer, fwidth, 0, 1, fheight);
1259         p->drawPixmap(fwidth, flower, bstart - fwidth, fheight, buffer, fwidth, buffer.height() - fheight, 1, fheight);
1260         // Draw left and right gap. Right gap is drawn top and bottom separatly
1261         p->drawPixmap(0, fheight, fwidth, sheight, buffer, 0, fheight, fwidth, 1);
1262         p->drawPixmap(bstart, fheight, bwidth, center - fheight, buffer, buffer.width() - bwidth, fheight - 1, bwidth, 1);
1263         p->drawPixmap(bstart, center, bwidth, sheight / 2, buffer, buffer.width() - bwidth, fheight + 6, bwidth, 1);
1264         // Draw arrow
1265         p->drawPixmap(bstart, center - 4, bwidth - 3, 6, buffer, buffer.width() - bwidth, fheight, bwidth - 3, 6);
1266         // Draw corners
1267         p->drawPixmap(0, 0, fwidth, fheight, buffer, 0, 0, fwidth, fheight);
1268         p->drawPixmap(bstart, 0, bwidth, fheight, buffer, buffer.width() - bwidth, 0, bwidth, fheight);
1269         p->drawPixmap(0, flower, fwidth, fheight, buffer, 0, buffer.height() - fheight, fwidth, fheight);
1270         p->drawPixmap(bstart, h - blower, bwidth, blower, buffer, buffer.width() - bwidth, buffer.height() - blower, bwidth, blower);
1271     }
1272 }
1273
1274 /**
1275     Carbon tableheaders don't scale (sight). So create it manually by drawing a small Carbon header
1276     onto a pixmap (use pixmap cache), chop it up, and copy it back onto the widget.
1277 */
1278 void QMacStylePrivate::drawTableHeader(const HIRect &outerBounds,
1279     bool drawTopBorder, bool drawLeftBorder, const HIThemeButtonDrawInfo &bdi, QPainter *p)
1280 {
1281     static SInt32 headerHeight = 0;
1282     static OSStatus err = GetThemeMetric(kThemeMetricListHeaderHeight, &headerHeight);
1283     Q_UNUSED(err);
1284
1285     QPixmap buffer;
1286     QString key = QString(QLatin1String("$qt_tableh%1-%2-%3")).arg(int(bdi.state)).arg(int(bdi.adornment)).arg(int(bdi.value));
1287     if (!QPixmapCache::find(key, buffer)) {
1288         HIRect headerNormalRect = {{0., 0.}, {16., CGFloat(headerHeight)}};
1289         buffer = QPixmap(headerNormalRect.size.width, headerNormalRect.size.height);
1290         buffer.fill(Qt::transparent);
1291         QPainter buffPainter(&buffer);
1292         HIThemeDrawButton(&headerNormalRect, &bdi, QMacCGContext(&buffPainter), kHIThemeOrientationNormal, 0);
1293         buffPainter.end();
1294         QPixmapCache::insert(key, buffer);
1295     }
1296     const int buttonw = qRound(outerBounds.size.width);
1297     const int buttonh = qRound(outerBounds.size.height);
1298     const int framew = 1;
1299     const int frameh_n = 4;
1300     const int frameh_s = 3;
1301     const int transh = buffer.height() - frameh_n - frameh_s;
1302     int center = buttonh - frameh_s - int(transh / 2.0f) + 1; // Align bottom;
1303
1304     int skipTopBorder = 0;
1305     if (!drawTopBorder)
1306         skipTopBorder = 1;
1307
1308     p->translate(outerBounds.origin.x, outerBounds.origin.y);
1309
1310     p->drawPixmap(QRect(QRect(0, -skipTopBorder, buttonw - framew , frameh_n)), buffer, QRect(framew, 0, 1, frameh_n));
1311     p->drawPixmap(QRect(0, buttonh - frameh_s, buttonw - framew, frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, frameh_s));
1312     // Draw upper and lower center blocks
1313     p->drawPixmap(QRect(0, frameh_n - skipTopBorder, buttonw - framew, center - frameh_n + skipTopBorder), buffer, QRect(framew, frameh_n, 1, 1));
1314     p->drawPixmap(QRect(0, center, buttonw - framew, buttonh - center - frameh_s), buffer, QRect(framew, buffer.height() - frameh_s, 1, 1));
1315     // Draw right center block borders
1316     p->drawPixmap(QRect(buttonw - framew, frameh_n - skipTopBorder, framew, center - frameh_n), buffer, QRect(buffer.width() - framew, frameh_n, framew, 1));
1317     p->drawPixmap(QRect(buttonw - framew, center, framew, buttonh - center - 1), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, 1));
1318     // Draw right corners
1319     p->drawPixmap(QRect(buttonw - framew, -skipTopBorder, framew, frameh_n), buffer, QRect(buffer.width() - framew, 0, framew, frameh_n));
1320     p->drawPixmap(QRect(buttonw - framew, buttonh - frameh_s, framew, frameh_s), buffer, QRect(buffer.width() - framew, buffer.height() - frameh_s, framew, frameh_s));
1321     // Draw center transition block
1322     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));
1323     // Draw right center transition block border
1324     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));
1325     if (drawLeftBorder){
1326         // Draw left center block borders
1327         p->drawPixmap(QRect(0, frameh_n - skipTopBorder, framew, center - frameh_n + skipTopBorder), buffer, QRect(0, frameh_n, framew, 1));
1328         p->drawPixmap(QRect(0, center, framew, buttonh - center - 1), buffer, QRect(0, buffer.height() - frameh_s, framew, 1));
1329         // Draw left corners
1330         p->drawPixmap(QRect(0, -skipTopBorder, framew, frameh_n), buffer, QRect(0, 0, framew, frameh_n));
1331         p->drawPixmap(QRect(0, buttonh - frameh_s, framew, frameh_s), buffer, QRect(0, buffer.height() - frameh_s, framew, frameh_s));
1332         // Draw left center transition block border
1333         p->drawPixmap(QRect(0, center - qRound(transh / 2.0f), framew, buffer.height() - frameh_n - frameh_s), buffer, QRect(0, frameh_n + 1, framew, transh));
1334     }
1335
1336     p->translate(-outerBounds.origin.x, -outerBounds.origin.y);
1337 }
1338
1339 /*
1340     Returns cutoff sizes for scroll bars.
1341     thumbIndicatorCutoff is the smallest size where the thumb indicator is drawn.
1342     scrollButtonsCutoff is the smallest size where the up/down buttons is drawn.
1343 */
1344 enum ScrollBarCutoffType { thumbIndicatorCutoff = 0, scrollButtonsCutoff = 1 };
1345 static int scrollButtonsCutoffSize(ScrollBarCutoffType cutoffType, QMacStyle::WidgetSizePolicy widgetSize)
1346 {
1347     // Mini scroll bars do not exist as of version 10.4.
1348     if (widgetSize ==  QMacStyle::SizeMini)
1349         return 0;
1350
1351     const int sizeIndex = (widgetSize == QMacStyle::SizeSmall) ? 1 : 0;
1352     static const int sizeTable[2][2] = { { 61, 56 }, { 49, 44 } };
1353     return sizeTable[sizeIndex][cutoffType];
1354 }
1355
1356 void QMacStylePrivate::getSliderInfo(QStyle::ComplexControl cc, const QStyleOptionSlider *slider,
1357                           HIThemeTrackDrawInfo *tdi, const QWidget *needToRemoveMe)
1358 {
1359     memset(tdi, 0, sizeof(HIThemeTrackDrawInfo)); // We don't get it all for some reason or another...
1360     tdi->version = qt_mac_hitheme_version;
1361     tdi->reserved = 0;
1362     tdi->filler1 = 0;
1363     bool isScrollbar = (cc == QStyle::CC_ScrollBar);
1364     switch (aquaSizeConstrain(0, needToRemoveMe)) {
1365     case QAquaSizeUnknown:
1366     case QAquaSizeLarge:
1367         if (isScrollbar)
1368             tdi->kind = kThemeMediumScrollBar;
1369         else
1370             tdi->kind = kThemeMediumSlider;
1371         break;
1372     case QAquaSizeMini:
1373         if (isScrollbar)
1374             tdi->kind = kThemeSmallScrollBar; // should be kThemeMiniScrollBar, but not implemented
1375         else
1376             tdi->kind = kThemeMiniSlider;
1377         break;
1378     case QAquaSizeSmall:
1379         if (isScrollbar)
1380             tdi->kind = kThemeSmallScrollBar;
1381         else
1382             tdi->kind = kThemeSmallSlider;
1383         break;
1384     }
1385     tdi->bounds = qt_hirectForQRect(slider->rect);
1386     tdi->min = slider->minimum;
1387     tdi->max = slider->maximum;
1388     tdi->value = slider->sliderPosition;
1389     tdi->attributes = kThemeTrackShowThumb;
1390     if (slider->upsideDown)
1391         tdi->attributes |= kThemeTrackRightToLeft;
1392     if (slider->orientation == Qt::Horizontal) {
1393         tdi->attributes |= kThemeTrackHorizontal;
1394         if (isScrollbar && slider->direction == Qt::RightToLeft) {
1395             if (!slider->upsideDown)
1396                 tdi->attributes |= kThemeTrackRightToLeft;
1397             else
1398                 tdi->attributes &= ~kThemeTrackRightToLeft;
1399         }
1400     }
1401
1402     // Tiger broke reverse scroll bars so put them back and "fake it"
1403     if (isScrollbar && (tdi->attributes & kThemeTrackRightToLeft)) {
1404         tdi->attributes &= ~kThemeTrackRightToLeft;
1405         tdi->value = tdi->max - slider->sliderPosition;
1406     }
1407
1408     tdi->enableState = (slider->state & QStyle::State_Enabled) ? kThemeTrackActive
1409                                                              : kThemeTrackDisabled;
1410     if (!(slider->state & QStyle::State_Active))
1411         tdi->enableState = kThemeTrackInactive;
1412     if (!isScrollbar) {
1413         if (slider->state & QStyle::QStyle::State_HasFocus)
1414             tdi->attributes |= kThemeTrackHasFocus;
1415         if (slider->tickPosition == QSlider::NoTicks || slider->tickPosition == QSlider::TicksBothSides)
1416             tdi->trackInfo.slider.thumbDir = kThemeThumbPlain;
1417         else if (slider->tickPosition == QSlider::TicksAbove)
1418             tdi->trackInfo.slider.thumbDir = kThemeThumbUpward;
1419         else
1420             tdi->trackInfo.slider.thumbDir = kThemeThumbDownward;
1421     } else {
1422         tdi->trackInfo.scrollbar.viewsize = slider->pageStep;
1423     }
1424 }
1425 #endif
1426
1427 QMacStylePrivate::QMacStylePrivate(QMacStyle *style)
1428     : timerID(-1), progressFrame(0), q(style), mouseDown(false)
1429 {
1430     defaultButtonStart = CFAbsoluteTimeGetCurrent();
1431     memset(&buttonState, 0, sizeof(ButtonState));
1432
1433     if (ptrHIShapeGetBounds == 0) {
1434         QLibrary library(QLatin1String("/System/Library/Frameworks/Carbon.framework/Carbon"));
1435         library.setLoadHints(QLibrary::ExportExternalSymbolsHint);
1436                 ptrHIShapeGetBounds = reinterpret_cast<PtrHIShapeGetBounds>(library.resolve("HIShapeGetBounds"));
1437     }
1438
1439 }
1440
1441 bool QMacStylePrivate::animatable(QMacStylePrivate::Animates as, const QWidget *w) const
1442 {
1443     if (!w)
1444         return false;
1445
1446     if (as == AquaPushButton) {
1447         QPushButton *pb = const_cast<QPushButton *>(static_cast<const QPushButton *>(w));
1448         if (w->window()->isActiveWindow() && pb && !mouseDown) {
1449             if (static_cast<const QPushButton *>(w) != defaultButton) {
1450                 // Changed on its own, update the value.
1451                 const_cast<QMacStylePrivate *>(this)->stopAnimate(as, defaultButton);
1452                 const_cast<QMacStylePrivate *>(this)->startAnimate(as, pb);
1453             }
1454             return true;
1455         }
1456     } else if (as == AquaProgressBar) {
1457         if (progressBars.contains((const_cast<QWidget *>(w))))
1458             return true;
1459     }
1460     return false;
1461 }
1462
1463 void QMacStylePrivate::stopAnimate(QMacStylePrivate::Animates as, QWidget *w)
1464 {
1465     if (as == AquaPushButton && defaultButton) {
1466         QPushButton *tmp = defaultButton;
1467         defaultButton = 0;
1468         tmp->update();
1469     } else if (as == AquaProgressBar) {
1470         progressBars.removeAll(w);
1471     }
1472 }
1473
1474 void QMacStylePrivate::startAnimate(QMacStylePrivate::Animates as, QWidget *w)
1475 {
1476     if (as == AquaPushButton)
1477         defaultButton = static_cast<QPushButton *>(w);
1478     else if (as == AquaProgressBar)
1479         progressBars.append(w);
1480     startAnimationTimer();
1481 }
1482
1483 void QMacStylePrivate::startAnimationTimer()
1484 {
1485     if ((defaultButton || !progressBars.isEmpty()) && timerID <= -1)
1486         timerID = startTimer(animateSpeed(AquaListViewItemOpen));
1487 }
1488
1489 bool QMacStylePrivate::addWidget(QWidget *w)
1490 {
1491     //already knew of it
1492     if (static_cast<QPushButton*>(w) == defaultButton
1493             || progressBars.contains(static_cast<QProgressBar*>(w)))
1494         return false;
1495
1496     if (QPushButton *btn = qobject_cast<QPushButton *>(w)) {
1497         btn->installEventFilter(this);
1498         if (btn->isDefault() || (btn->autoDefault() && btn->hasFocus()))
1499             startAnimate(AquaPushButton, btn);
1500         return true;
1501     } else {
1502         bool isProgressBar = (qobject_cast<QProgressBar *>(w)
1503 #ifdef QT3_SUPPORT
1504                 || w->inherits("Q3ProgressBar")
1505 #endif
1506             );
1507         if (isProgressBar) {
1508             w->installEventFilter(this);
1509             startAnimate(AquaProgressBar, w);
1510             return true;
1511         }
1512     }
1513     if (w->isWindow()) {
1514         w->installEventFilter(this);
1515         return true;
1516     }
1517     return false;
1518 }
1519
1520 void QMacStylePrivate::removeWidget(QWidget *w)
1521 {
1522     QPushButton *btn = qobject_cast<QPushButton *>(w);
1523     if (btn && btn == defaultButton) {
1524         stopAnimate(AquaPushButton, btn);
1525     } else if (qobject_cast<QProgressBar *>(w)
1526 #ifdef QT3_SUPPORT
1527             || w->inherits("Q3ProgressBar")
1528 #endif
1529             ) {
1530         stopAnimate(AquaProgressBar, w);
1531     }
1532 }
1533
1534 ThemeDrawState QMacStylePrivate::getDrawState(QStyle::State flags)
1535 {
1536     ThemeDrawState tds = kThemeStateActive;
1537     if (flags & QStyle::State_Sunken) {
1538         tds = kThemeStatePressed;
1539     } else if (flags & QStyle::State_Active) {
1540         if (!(flags & QStyle::State_Enabled))
1541             tds = kThemeStateUnavailable;
1542     } else {
1543         if (flags & QStyle::State_Enabled)
1544             tds = kThemeStateInactive;
1545         else
1546             tds = kThemeStateUnavailableInactive;
1547     }
1548     return tds;
1549 }
1550
1551 void QMacStylePrivate::timerEvent(QTimerEvent *)
1552 {
1553     int animated = 0;
1554     if (defaultButton && defaultButton->isEnabled() && defaultButton->window()->isActiveWindow()
1555         && defaultButton->isVisibleTo(0) && (defaultButton->isDefault()
1556         || (defaultButton->autoDefault() && defaultButton->hasFocus()))
1557         && doAnimate(AquaPushButton)) {
1558         ++animated;
1559         defaultButton->update();
1560     }
1561     if (!progressBars.isEmpty()) {
1562         int i = 0;
1563         while (i < progressBars.size()) {
1564             QWidget *maybeProgress = progressBars.at(i);
1565             if (!maybeProgress) {
1566                 progressBars.removeAt(i);
1567             } else {
1568                 if (QProgressBar *pb = qobject_cast<QProgressBar *>(maybeProgress)) {
1569                     if (pb->maximum() == 0 || (pb->value() > 0 && pb->value() < pb->maximum())) {
1570                         if (doAnimate(AquaProgressBar))
1571                             pb->update();
1572                     }
1573                 }
1574 #ifdef QT3_SUPPORT
1575                 else {
1576                     // Watch me now...
1577                     QVariant progress = maybeProgress->property("progress");
1578                     QVariant totalSteps = maybeProgress->property("totalSteps");
1579                     if (progress.isValid() && totalSteps.isValid()) {
1580                         int intProgress = progress.toInt();
1581                         int intTotalSteps = totalSteps.toInt();
1582                         if (intTotalSteps == 0 || intProgress > 0 && intProgress < intTotalSteps) {
1583                             if (doAnimate(AquaProgressBar))
1584                                 maybeProgress->update();
1585                         }
1586                     }
1587                 }
1588 #endif
1589                 ++i;
1590             }
1591         }
1592         if (i > 0) {
1593             ++progressFrame;
1594             animated += i;
1595         }
1596     }
1597     if (animated <= 0) {
1598         killTimer(timerID);
1599         timerID = -1;
1600     }
1601 }
1602
1603 bool QMacStylePrivate::eventFilter(QObject *o, QEvent *e)
1604 {
1605     //animate
1606     if (QProgressBar *pb = qobject_cast<QProgressBar *>(o)) {
1607         switch (e->type()) {
1608         default:
1609             break;
1610         case QEvent::Show:
1611             if (!progressBars.contains(pb))
1612                 startAnimate(AquaProgressBar, pb);
1613             break;
1614         case QEvent::Destroy:
1615         case QEvent::Hide:
1616             progressBars.removeAll(pb);
1617         }
1618     } else if (QPushButton *btn = qobject_cast<QPushButton *>(o)) {
1619         switch (e->type()) {
1620         default:
1621             break;
1622         case QEvent::FocusIn:
1623             if (btn->autoDefault())
1624                 startAnimate(AquaPushButton, btn);
1625             break;
1626         case QEvent::Destroy:
1627         case QEvent::Hide:
1628             if (btn == defaultButton)
1629                 stopAnimate(AquaPushButton, btn);
1630             break;
1631         case QEvent::MouseButtonPress:
1632             // It is very confusing to keep the button pulsing, so just stop the animation.
1633             if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1634                 mouseDown = true;
1635             stopAnimate(AquaPushButton, btn);
1636             break;
1637         case QEvent::MouseButtonRelease:
1638             if (static_cast<QMouseEvent *>(e)->button() == Qt::LeftButton)
1639                 mouseDown = false;
1640             // fall through
1641         case QEvent::FocusOut:
1642         case QEvent::Show:
1643         case QEvent::WindowActivate: {
1644             QList<QPushButton *> list = btn->window()->findChildren<QPushButton *>();
1645             for (int i = 0; i < list.size(); ++i) {
1646                 QPushButton *pBtn = list.at(i);
1647                 if ((e->type() == QEvent::FocusOut
1648                      && (pBtn->isDefault() || (pBtn->autoDefault() && pBtn->hasFocus()))
1649                      && pBtn != btn)
1650                     || ((e->type() == QEvent::Show || e->type() == QEvent::MouseButtonRelease
1651                          || e->type() == QEvent::WindowActivate)
1652                         && pBtn->isDefault())) {
1653                     if (pBtn->window()->isActiveWindow()) {
1654                         startAnimate(AquaPushButton, pBtn);
1655                     }
1656                     break;
1657                 }
1658             }
1659             break; }
1660         }
1661     }
1662     return false;
1663 }
1664
1665 bool QMacStylePrivate::doAnimate(QMacStylePrivate::Animates as)
1666 {
1667     if (as == AquaPushButton) {
1668     } else if (as == AquaProgressBar) {
1669         // something for later...
1670     } else if (as == AquaListViewItemOpen) {
1671         // To be revived later...
1672     }
1673     return true;
1674 }
1675
1676 void QMacStylePrivate::drawColorlessButton(const HIRect &macRect, HIThemeButtonDrawInfo *bdi,
1677                                            QPainter *p, const QStyleOption *opt) const
1678 {
1679     int xoff = 0,
1680         yoff = 0,
1681         extraWidth = 0,
1682         extraHeight = 0,
1683         finalyoff = 0;
1684
1685     const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
1686     int width = int(macRect.size.width) + extraWidth;
1687     int height = int(macRect.size.height) + extraHeight;
1688
1689     if (width <= 0 || height <= 0)
1690         return;   // nothing to draw
1691
1692     QString key = QLatin1String("$qt_mac_style_ctb_") + QString::number(bdi->kind) + QLatin1Char('_')
1693                   + QString::number(bdi->value) + QLatin1Char('_') + QString::number(width)
1694                   + QLatin1Char('_') + QString::number(height);
1695     QPixmap pm;
1696     if (!QPixmapCache::find(key, pm)) {
1697         QPixmap activePixmap(width, height);
1698         activePixmap.fill(Qt::transparent);
1699         {
1700             if (combo){
1701                 // Carbon combos don't scale. Therefore we draw it
1702                 // ourselves, if a scaled version is needed.
1703                 QPainter tmpPainter(&activePixmap);
1704                 QMacStylePrivate::drawCombobox(macRect, *bdi, &tmpPainter);
1705             }
1706             else {
1707                 QMacCGContext cg(&activePixmap);
1708                 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1709                 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1710             }
1711         }
1712
1713         if (!combo && bdi->value == kThemeButtonOff) {
1714             pm = activePixmap;
1715         } else if (combo) {
1716             QImage image = activePixmap.toImage();
1717
1718             for (int y = 0; y < height; ++y) {
1719                 QRgb *scanLine = reinterpret_cast<QRgb *>(image.scanLine(y));
1720
1721                 for (int x = 0; x < width; ++x) {
1722                     QRgb &pixel = scanLine[x];
1723
1724                     int darkest = qRed(pixel);
1725                     int mid = qGreen(pixel);
1726                     int lightest = qBlue(pixel);
1727
1728                     if (darkest > mid)
1729                         qSwap(darkest, mid);
1730                     if (mid > lightest)
1731                         qSwap(mid, lightest);
1732                     if (darkest > mid)
1733                         qSwap(darkest, mid);
1734
1735                     int gray = (mid + 2 * lightest) / 3;
1736                     pixel = qRgba(gray, gray, gray, qAlpha(pixel));
1737                 }
1738             }
1739             pm = QPixmap::fromImage(image);
1740         } else {
1741             QImage activeImage = activePixmap.toImage();
1742             QImage colorlessImage;
1743             {
1744                 QPixmap colorlessPixmap(width, height);
1745                 colorlessPixmap.fill(Qt::transparent);
1746
1747                 QMacCGContext cg(&colorlessPixmap);
1748                 HIRect newRect = CGRectMake(xoff, yoff, macRect.size.width, macRect.size.height);
1749                 int oldValue = bdi->value;
1750                 bdi->value = kThemeButtonOff;
1751                 HIThemeDrawButton(&newRect, bdi, cg, kHIThemeOrientationNormal, 0);
1752                 bdi->value = oldValue;
1753                 colorlessImage = colorlessPixmap.toImage();
1754             }
1755
1756             for (int y = 0; y < height; ++y) {
1757                 QRgb *colorlessScanLine = reinterpret_cast<QRgb *>(colorlessImage.scanLine(y));
1758                 const QRgb *activeScanLine = reinterpret_cast<const QRgb *>(activeImage.scanLine(y));
1759
1760                 for (int x = 0; x < width; ++x) {
1761                     QRgb &colorlessPixel = colorlessScanLine[x];
1762                     QRgb activePixel = activeScanLine[x];
1763
1764                     if (activePixel != colorlessPixel) {
1765                         int max = qMax(qMax(qRed(activePixel), qGreen(activePixel)),
1766                                        qBlue(activePixel));
1767                         QRgb newPixel = qRgba(max, max, max, qAlpha(activePixel));
1768                         if (qGray(newPixel) < qGray(colorlessPixel)
1769                                 || qAlpha(newPixel) > qAlpha(colorlessPixel))
1770                             colorlessPixel = newPixel;
1771                     }
1772                 }
1773             }
1774             pm = QPixmap::fromImage(colorlessImage);
1775         }
1776         QPixmapCache::insert(key, pm);
1777     }
1778     p->drawPixmap(int(macRect.origin.x), int(macRect.origin.y) + finalyoff, width, height, pm);
1779 }
1780
1781 QMacStyle::QMacStyle()
1782     : QWindowsStyle()
1783 {
1784     d = new QMacStylePrivate(this);
1785 }
1786
1787 QMacStyle::~QMacStyle()
1788 {
1789     delete qt_mac_backgroundPattern;
1790     qt_mac_backgroundPattern = 0;
1791     delete d;
1792 }
1793
1794 /*! \internal
1795     Generates the standard widget background pattern.
1796 */
1797 QPixmap QMacStylePrivate::generateBackgroundPattern() const
1798 {
1799     QPixmap px(4, 4);
1800     QMacCGContext cg(&px);
1801     HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationNormal);
1802     const CGRect cgRect = CGRectMake(0, 0, px.width(), px.height());
1803     CGContextFillRect(cg, cgRect);
1804     return px;
1805 }
1806
1807 /*! \internal
1808     Fills the given \a rect with the pattern stored in \a brush. As an optimization,
1809     HIThemeSetFill us used directly if we are filling with the standard background.
1810 */
1811 void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush)
1812 {
1813     QPoint dummy;
1814     const QPaintDevice *target = painter->device();
1815     const QPaintDevice *redirected = QPainter::redirected(target, &dummy);
1816     const bool usePainter = redirected && redirected != target;
1817
1818     if (!usePainter && qt_mac_backgroundPattern
1819         && qt_mac_backgroundPattern->cacheKey() == brush.texture().cacheKey()) {
1820
1821         painter->setClipRegion(rgn);
1822
1823         QCFType<CGContextRef> cg = qt_mac_cg_context(target);
1824         CGContextSaveGState(cg);
1825         HIThemeSetFill(kThemeBrushDialogBackgroundActive, 0, cg, kHIThemeOrientationInverted);
1826
1827         const QVector<QRect> &rects = rgn.rects();
1828         for (int i = 0; i < rects.size(); ++i) {
1829             const QRect rect(rects.at(i));
1830             // Anchor the pattern to the top so it stays put when the window is resized.
1831             CGContextSetPatternPhase(cg, CGSizeMake(rect.width(), rect.height()));
1832             CGRect mac_rect = CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
1833             CGContextFillRect(cg, mac_rect);
1834         }
1835
1836         CGContextRestoreGState(cg);
1837     } else {
1838         const QRect rect(rgn.boundingRect());
1839         painter->setClipRegion(rgn);
1840         painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft());
1841     }
1842 }
1843
1844 void QMacStyle::polish(QPalette &pal)
1845 {
1846     if (!qt_mac_backgroundPattern) {
1847         if (!qApp)
1848             return;
1849         qt_mac_backgroundPattern = new QPixmap(d->generateBackgroundPattern());
1850     }
1851
1852     QColor pc(Qt::black);
1853     pc = qcolorForTheme(kThemeBrushDialogBackgroundActive);
1854     QBrush background(pc, *qt_mac_backgroundPattern);
1855     pal.setBrush(QPalette::All, QPalette::Window, background);
1856     pal.setBrush(QPalette::All, QPalette::Button, background);
1857
1858     QCFString theme;
1859     const OSErr err = CopyThemeIdentifier(&theme);
1860     if (err == noErr && CFStringCompare(theme, kThemeAppearanceAquaGraphite, 0) == kCFCompareEqualTo) {
1861         pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(240, 240, 240));
1862     } else {
1863         pal.setBrush(QPalette::All, QPalette::AlternateBase, QColor(237, 243, 254));
1864     }
1865 }
1866
1867 void QMacStyle::polish(QApplication *)
1868 {
1869 }
1870
1871 void QMacStyle::unpolish(QApplication *)
1872 {
1873 }
1874
1875 void QMacStyle::polish(QWidget* w)
1876 {
1877     d->addWidget(w);
1878     if (qt_mac_is_metal(w) && !w->testAttribute(Qt::WA_SetPalette)) {
1879         // Set a clear brush so that the metal shines through.
1880         QPalette pal = w->palette();
1881         QBrush background(Qt::transparent);
1882         pal.setBrush(QPalette::All, QPalette::Window, background);
1883         pal.setBrush(QPalette::All, QPalette::Button, background);
1884         w->setPalette(pal);
1885         w->setAttribute(Qt::WA_SetPalette, false);
1886     }
1887
1888     if (qobject_cast<QMenu*>(w) || qobject_cast<QComboBoxPrivateContainer *>(w)) {
1889         w->setWindowOpacity(QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5 ? 0.985 : 0.94);
1890         if (!w->testAttribute(Qt::WA_SetPalette)) {
1891             QPixmap px(64, 64);
1892             px.fill(Qt::white);
1893             HIThemeMenuDrawInfo mtinfo;
1894             mtinfo.version = qt_mac_hitheme_version;
1895             mtinfo.menuType = kThemeMenuTypePopUp;
1896             HIRect rect = CGRectMake(0, 0, px.width(), px.height());
1897             HIThemeDrawMenuBackground(&rect, &mtinfo, QCFType<CGContextRef>(qt_mac_cg_context(&px)),
1898                                       kHIThemeOrientationNormal);
1899             QPalette pal = w->palette();
1900             QBrush background(px);
1901             pal.setBrush(QPalette::All, QPalette::Window, background);
1902             pal.setBrush(QPalette::All, QPalette::Button, background);
1903             w->setPalette(pal);
1904             w->setAttribute(Qt::WA_SetPalette, false);
1905         }
1906     }
1907
1908     if (QTabBar *tb = qobject_cast<QTabBar*>(w)) {
1909         if (tb->documentMode()) {
1910             w->setAttribute(Qt::WA_Hover);
1911             w->setFont(qt_app_fonts_hash()->value("QSmallFont", QFont()));
1912             QPalette p = w->palette();
1913             p.setColor(QPalette::WindowText, QColor(17, 17, 17));
1914             w->setPalette(p);
1915         }
1916     }
1917
1918     QWindowsStyle::polish(w);
1919
1920     if (QRubberBand *rubber = qobject_cast<QRubberBand*>(w)) {
1921         rubber->setWindowOpacity(0.25);
1922         rubber->setAttribute(Qt::WA_PaintOnScreen, false);
1923         rubber->setAttribute(Qt::WA_NoSystemBackground, false);
1924     }
1925 }
1926
1927 void QMacStyle::unpolish(QWidget* w)
1928 {
1929     d->removeWidget(w);
1930     if ((qobject_cast<QMenu*>(w) || qt_mac_is_metal(w)) && !w->testAttribute(Qt::WA_SetPalette)) {
1931         QPalette pal = qApp->palette(w);
1932         w->setPalette(pal);
1933         w->setAttribute(Qt::WA_SetPalette, false);
1934         w->setWindowOpacity(1.0);
1935     }
1936
1937     if (QComboBox *combo = qobject_cast<QComboBox *>(w)) {
1938         if (!combo->isEditable()) {
1939             if (QWidget *widget = combo->findChild<QComboBoxPrivateContainer *>())
1940                 widget->setWindowOpacity(1.0);
1941         }
1942     }
1943
1944     if (QRubberBand *rubber = ::qobject_cast<QRubberBand*>(w)) {
1945         rubber->setWindowOpacity(1.0);
1946         rubber->setAttribute(Qt::WA_PaintOnScreen, true);
1947         rubber->setAttribute(Qt::WA_NoSystemBackground, true);
1948     }
1949
1950     if (QFocusFrame *frame = qobject_cast<QFocusFrame *>(w))
1951         frame->setAttribute(Qt::WA_NoSystemBackground, true);
1952
1953     QWindowsStyle::unpolish(w);
1954 }
1955
1956 int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWidget *widget) const
1957 {
1958     int controlSize = getControlSize(opt, widget);
1959     SInt32 ret = 0;
1960
1961     switch (metric) {
1962     case PM_TabCloseIndicatorWidth:
1963     case PM_TabCloseIndicatorHeight:
1964         ret = closeButtonSize;
1965         break;
1966     case PM_ToolBarIconSize:
1967         ret = proxy()->pixelMetric(PM_LargeIconSize);
1968         break;
1969     case PM_FocusFrameVMargin:
1970     case PM_FocusFrameHMargin:
1971         GetThemeMetric(kThemeMetricFocusRectOutset, &ret);
1972         break;
1973     case PM_DialogButtonsSeparator:
1974         ret = -5;
1975         break;
1976     case PM_DialogButtonsButtonHeight: {
1977         QSize sz;
1978         ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
1979         if (sz == QSize(-1, -1))
1980             ret = 32;
1981         else
1982             ret = sz.height();
1983         break; }
1984     case PM_CheckListButtonSize: {
1985         switch (d->aquaSizeConstrain(opt, widget)) {
1986         case QAquaSizeUnknown:
1987         case QAquaSizeLarge:
1988             GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
1989             break;
1990         case QAquaSizeMini:
1991             GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
1992             break;
1993         case QAquaSizeSmall:
1994             GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
1995             break;
1996         }
1997         break; }
1998     case PM_DialogButtonsButtonWidth: {
1999         QSize sz;
2000         ret = d->aquaSizeConstrain(opt, 0, QStyle::CT_PushButton, QSize(-1, -1), &sz);
2001         if (sz == QSize(-1, -1))
2002             ret = 70;
2003         else
2004             ret = sz.width();
2005         break; }
2006
2007     case PM_MenuBarHMargin:
2008         ret = 8;
2009         break;
2010
2011     case PM_MenuBarVMargin:
2012         ret = 0;
2013         break;
2014
2015     case QStyle::PM_MenuDesktopFrameWidth:
2016         ret = 5;
2017         break;
2018
2019     case PM_CheckBoxLabelSpacing:
2020     case PM_RadioButtonLabelSpacing:
2021         ret = 2;
2022         break;
2023     case PM_MenuScrollerHeight:
2024 #if 0
2025         SInt16 ash, asw;
2026         GetThemeMenuItemExtra(kThemeMenuItemScrollUpArrow, &ash, &asw);
2027         ret = ash;
2028 #else
2029         ret = 15; // I hate having magic numbers in here...
2030 #endif
2031         break;
2032     case PM_DefaultFrameWidth:
2033 #ifndef QT_NO_MAINWINDOW
2034         if (widget && (widget->isWindow() || !widget->parentWidget()
2035                 || (qobject_cast<const QMainWindow*>(widget->parentWidget())
2036                    && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
2037                 && (qobject_cast<const QAbstractScrollArea *>(widget)
2038 #ifdef QT3_SUPPORT
2039                     || widget->inherits("QScrollView")
2040 #endif
2041                     || widget->inherits("QWorkspaceChild")))
2042             ret = 0;
2043         else
2044 #endif
2045         // The combo box popup has no frame.
2046         if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
2047             ret = 0;
2048         // Frame of mac style line edits is two pixels on top and one on the bottom
2049         else if (qobject_cast<const QLineEdit *>(widget) != 0)
2050             ret = 2;
2051         else
2052             ret = 1;
2053         break;
2054     case PM_MaximumDragDistance:
2055         ret = -1;
2056         break;
2057     case PM_ScrollBarSliderMin:
2058         ret = 24;
2059         break;
2060     case PM_SpinBoxFrameWidth:
2061         GetThemeMetric(kThemeMetricEditTextFrameOutset, &ret);
2062         switch (d->aquaSizeConstrain(opt, widget)) {
2063         default:
2064             ret += 2;
2065             break;
2066         case QAquaSizeMini:
2067             ret += 1;
2068             break;
2069         }
2070         break;
2071     case PM_ButtonShiftHorizontal:
2072     case PM_ButtonShiftVertical:
2073         ret = 0;
2074         break;
2075     case PM_SliderLength:
2076         ret = 17;
2077         break;
2078     case PM_ButtonDefaultIndicator:
2079         ret = 0;
2080         break;
2081     case PM_TitleBarHeight:
2082         if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
2083             HIThemeWindowDrawInfo wdi;
2084             wdi.version = qt_mac_hitheme_version;
2085             wdi.state = kThemeStateActive;
2086             wdi.windowType = QtWinType;
2087             if (tb->titleBarState)
2088                 wdi.attributes = kThemeWindowHasFullZoom | kThemeWindowHasCloseBox
2089                                   | kThemeWindowHasCollapseBox;
2090             else if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
2091                 wdi.attributes = kThemeWindowHasCloseBox;
2092             else
2093                 wdi.attributes = 0;
2094             wdi.titleHeight = tb->rect.height();
2095             wdi.titleWidth = tb->rect.width();
2096             QCFType<HIShapeRef> region;
2097             HIRect hirect = qt_hirectForQRect(tb->rect);
2098             if (hirect.size.width <= 0)
2099                 hirect.size.width = 100;
2100             if (hirect.size.height <= 0)
2101                 hirect.size.height = 30;
2102
2103             HIThemeGetWindowShape(&hirect, &wdi, kWindowTitleBarRgn, &region);
2104             HIRect rect;
2105             ptrHIShapeGetBounds(region, &rect);
2106             ret = int(rect.size.height);
2107             ret += 4;
2108         }
2109         break;
2110     case PM_TabBarTabVSpace:
2111         ret = 4;
2112         break;
2113     case PM_TabBarTabShiftHorizontal:
2114     case PM_TabBarTabShiftVertical:
2115         ret = 0;
2116         break;
2117     case PM_TabBarBaseHeight:
2118         ret = 0;
2119         break;
2120     case PM_TabBarTabOverlap:
2121         ret = 0;
2122         break;
2123     case PM_TabBarBaseOverlap:
2124         switch (d->aquaSizeConstrain(opt, widget)) {
2125         case QAquaSizeUnknown:
2126         case QAquaSizeLarge:
2127             ret = 11;
2128             break;
2129         case QAquaSizeSmall:
2130             ret = 8;
2131             break;
2132         case QAquaSizeMini:
2133             ret = 7;
2134             break;
2135         }
2136         break;
2137     case PM_ScrollBarExtent: {
2138         switch (d->aquaSizeConstrain(opt, widget)) {
2139         case QAquaSizeUnknown:
2140         case QAquaSizeLarge:
2141             GetThemeMetric(kThemeMetricScrollBarWidth, &ret);
2142             break;
2143         case QAquaSizeMini:
2144         case QAquaSizeSmall:
2145             GetThemeMetric(kThemeMetricSmallScrollBarWidth, &ret);
2146             break;
2147         }
2148         break; }
2149     case PM_IndicatorHeight: {
2150         switch (d->aquaSizeConstrain(opt, widget)) {
2151         case QAquaSizeUnknown:
2152         case QAquaSizeLarge:
2153             GetThemeMetric(kThemeMetricCheckBoxHeight, &ret);
2154             break;
2155         case QAquaSizeMini:
2156             GetThemeMetric(kThemeMetricMiniCheckBoxHeight, &ret);
2157             break;
2158         case QAquaSizeSmall:
2159             GetThemeMetric(kThemeMetricSmallCheckBoxHeight, &ret);
2160             break;
2161         }
2162         break; }
2163     case PM_IndicatorWidth: {
2164         switch (d->aquaSizeConstrain(opt, widget)) {
2165         case QAquaSizeUnknown:
2166         case QAquaSizeLarge:
2167             GetThemeMetric(kThemeMetricCheckBoxWidth, &ret);
2168             break;
2169         case QAquaSizeMini:
2170             GetThemeMetric(kThemeMetricMiniCheckBoxWidth, &ret);
2171             break;
2172         case QAquaSizeSmall:
2173             GetThemeMetric(kThemeMetricSmallCheckBoxWidth, &ret);
2174             break;
2175         }
2176         ++ret;
2177         break; }
2178     case PM_ExclusiveIndicatorHeight: {
2179         switch (d->aquaSizeConstrain(opt, widget)) {
2180         case QAquaSizeUnknown:
2181         case QAquaSizeLarge:
2182             GetThemeMetric(kThemeMetricRadioButtonHeight, &ret);
2183             break;
2184         case QAquaSizeMini:
2185             GetThemeMetric(kThemeMetricMiniRadioButtonHeight, &ret);
2186             break;
2187         case QAquaSizeSmall:
2188             GetThemeMetric(kThemeMetricSmallRadioButtonHeight, &ret);
2189             break;
2190         }
2191         break; }
2192     case PM_ExclusiveIndicatorWidth: {
2193         switch (d->aquaSizeConstrain(opt, widget)) {
2194         case QAquaSizeUnknown:
2195         case QAquaSizeLarge:
2196             GetThemeMetric(kThemeMetricRadioButtonWidth, &ret);
2197             break;
2198         case QAquaSizeMini:
2199             GetThemeMetric(kThemeMetricMiniRadioButtonWidth, &ret);
2200             break;
2201         case QAquaSizeSmall:
2202             GetThemeMetric(kThemeMetricSmallRadioButtonWidth, &ret);
2203             break;
2204         }
2205         ++ret;
2206         break; }
2207     case PM_MenuVMargin:
2208         ret = 4;
2209         break;
2210     case PM_MenuPanelWidth:
2211         ret = 0;
2212         break;
2213     case PM_ToolTipLabelFrameWidth:
2214         ret = 0;
2215         break;
2216     case PM_SizeGripSize: {
2217         QAquaWidgetSize aSize;
2218         if (widget && widget->window()->windowType() == Qt::Tool)
2219             aSize = QAquaSizeSmall;
2220         else
2221             aSize = QAquaSizeLarge;
2222         const QSize size = qt_aqua_get_known_size(CT_SizeGrip, widget, QSize(), aSize);
2223         ret = size.width();
2224         break; }
2225     case PM_MdiSubWindowFrameWidth:
2226         ret = 1;
2227         break;
2228     case PM_DockWidgetFrameWidth:
2229         ret = 2;
2230         break;
2231     case PM_DockWidgetTitleMargin:
2232         ret = 0;
2233         break;
2234     case PM_DockWidgetSeparatorExtent:
2235         ret = 1;
2236         break;
2237     case PM_ToolBarHandleExtent:
2238         ret = 11;
2239         break;
2240     case PM_ToolBarItemMargin:
2241         ret = 0;
2242         break;
2243     case PM_ToolBarItemSpacing:
2244         ret = 4;
2245         break;
2246     case PM_SplitterWidth:
2247         ret = qMax(7, QApplication::globalStrut().width());
2248         break;
2249     case PM_LayoutLeftMargin:
2250     case PM_LayoutTopMargin:
2251     case PM_LayoutRightMargin:
2252     case PM_LayoutBottomMargin:
2253         {
2254             bool isWindow = false;
2255             if (opt) {
2256                 isWindow = (opt->state & State_Window);
2257             } else if (widget) {
2258                 isWindow = widget->isWindow();
2259             }
2260
2261             if (isWindow) {
2262                 bool isMetal = widget && widget->testAttribute(Qt::WA_MacBrushedMetal);
2263                 if (isMetal) {
2264                     if (metric == PM_LayoutTopMargin) {
2265                         return_SIZE(9 /* AHIG */, 6 /* guess */, 6 /* guess */);
2266                     } else if (metric == PM_LayoutBottomMargin) {
2267                         return_SIZE(18 /* AHIG */, 15 /* guess */, 13 /* guess */);
2268                     } else {
2269                         return_SIZE(14 /* AHIG */, 11 /* guess */, 9 /* guess */);
2270                     }
2271                 } else {
2272                     /*
2273                         AHIG would have (20, 8, 10) here but that makes
2274                         no sense. It would also have 14 for the top margin
2275                         but this contradicts both Builder and most
2276                         applications.
2277                     */
2278                     return_SIZE(20, 10, 10);    // AHIG
2279                 }
2280             } else {
2281                 // hack to detect QTabWidget
2282                 if (widget && widget->parentWidget()
2283                         && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
2284                     if (metric == PM_LayoutTopMargin) {
2285                         /*
2286                             Builder would have 14 (= 20 - 6) instead of 12,
2287                             but that makes the tab look disproportionate.
2288                         */
2289                         return_SIZE(12, 6, 6);  // guess
2290                     } else {
2291                         return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
2292                     }
2293                 } else {
2294                     /*
2295                         Child margins are highly inconsistent in AHIG and Builder.
2296                     */
2297                     return_SIZE(12, 8, 6);    // guess
2298                 }
2299             }
2300         }
2301     case PM_LayoutHorizontalSpacing:
2302     case PM_LayoutVerticalSpacing:
2303         return -1;
2304     case QStyle::PM_TabBarTabHSpace:
2305         switch (d->aquaSizeConstrain(opt, widget)) {
2306         case QAquaSizeLarge:
2307         case QAquaSizeUnknown:
2308             ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2309             break;
2310         case QAquaSizeSmall:
2311             ret = 20;
2312             break;
2313         case QAquaSizeMini:
2314             ret = 16;
2315             break;
2316         }
2317         break;
2318     case PM_MenuHMargin:
2319         ret = 0;
2320         break;
2321     case PM_ToolBarFrameWidth:
2322         ret = 1;
2323         if (widget) {
2324             if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(widget->parent()))
2325                 if (mainWindow->unifiedTitleAndToolBarOnMac())
2326                     ret = 0;
2327         }
2328         break;
2329     default:
2330         ret = QWindowsStyle::pixelMetric(metric, opt, widget);
2331         break;
2332     }
2333     return ret;
2334 }
2335
2336 QPalette QMacStyle::standardPalette() const
2337 {
2338     QPalette pal = QWindowsStyle::standardPalette();
2339     pal.setColor(QPalette::Disabled, QPalette::Dark, QColor(191, 191, 191));
2340     pal.setColor(QPalette::Active, QPalette::Dark, QColor(191, 191, 191));
2341     pal.setColor(QPalette::Inactive, QPalette::Dark, QColor(191, 191, 191));
2342     return pal;
2343 }
2344
2345 int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *w,
2346                          QStyleHintReturn *hret) const
2347 {
2348     SInt32 ret = 0;
2349     switch (sh) {
2350     case SH_Menu_SelectionWrap:
2351         ret = false;
2352         break;
2353     case SH_Menu_KeyboardSearch:
2354         ret = true;
2355         break;
2356     case SH_Menu_SpaceActivatesItem:
2357         ret = true;
2358         break;
2359     case SH_Slider_AbsoluteSetButtons:
2360         ret = Qt::LeftButton|Qt::MidButton;
2361         break;
2362     case SH_Slider_PageSetButtons:
2363         ret = 0;
2364         break;
2365     case SH_ScrollBar_ContextMenu:
2366         ret = false;
2367         break;
2368     case SH_TitleBar_AutoRaise:
2369         ret = true;
2370         break;
2371     case SH_Menu_AllowActiveAndDisabled:
2372         ret = false;
2373         break;
2374     case SH_Menu_SubMenuPopupDelay:
2375         ret = 100;
2376         break;
2377     case SH_ScrollBar_LeftClickAbsolutePosition: {
2378         extern bool qt_scrollbar_jump_to_pos; //qapplication_mac.cpp
2379         if(QApplication::keyboardModifiers() & Qt::AltModifier)
2380             ret = !qt_scrollbar_jump_to_pos;
2381         else
2382             ret = qt_scrollbar_jump_to_pos;
2383         break; }
2384     case SH_TabBar_PreferNoArrows:
2385         ret = true;
2386         break;
2387     case SH_LineEdit_PasswordCharacter:
2388         ret = kBulletUnicode;
2389         break;
2390         /*
2391     case SH_DialogButtons_DefaultButton:
2392         ret = QDialogButtons::Reject;
2393         break;
2394         */
2395     case SH_GroupBox_TextLabelVerticalAlignment:
2396         ret = Qt::AlignTop;
2397         break;
2398     case SH_ScrollView_FrameOnlyAroundContents:
2399         if (w && (w->isWindow() || !w->parentWidget() || w->parentWidget()->isWindow())
2400                 && (w->inherits("QWorkspaceChild")
2401 #ifdef QT3_SUPPORT
2402                 || w->inherits("QScrollView")
2403 #endif
2404                 ))
2405             ret = true;
2406         else
2407             ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2408         break;
2409     case SH_Menu_FillScreenWithScroll:
2410         ret = false;
2411         break;
2412     case SH_Menu_Scrollable:
2413         ret = true;
2414         break;
2415     case SH_RichText_FullWidthSelection:
2416         ret = true;
2417         break;
2418     case SH_BlinkCursorWhenTextSelected:
2419         ret = false;
2420         break;
2421     case SH_ScrollBar_StopMouseOverSlider:
2422         ret = true;
2423         break;
2424     case SH_Q3ListViewExpand_SelectMouseType:
2425         ret = QEvent::MouseButtonRelease;
2426         break;
2427     case SH_TabBar_SelectMouseType:
2428         if (const QStyleOptionTabBarBaseV2 *opt2 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2429             ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
2430         } else {
2431             ret = QEvent::MouseButtonRelease;
2432         }
2433         break;
2434     case SH_ComboBox_Popup:
2435         if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
2436             ret = !cmb->editable;
2437         else
2438             ret = 0;
2439         break;
2440     case SH_Workspace_FillSpaceOnMaximize:
2441         ret = true;
2442         break;
2443     case SH_Widget_ShareActivation:
2444         ret = true;
2445         break;
2446     case SH_Header_ArrowAlignment:
2447         ret = Qt::AlignRight;
2448         break;
2449     case SH_TabBar_Alignment: {
2450         if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
2451             if (tab->documentMode()) {
2452                 ret = Qt::AlignLeft;
2453                 break;
2454             }
2455         }
2456         if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
2457             if (tab->documentMode()) {
2458                 ret = Qt::AlignLeft;
2459                 break;
2460             }
2461         }
2462         ret = Qt::AlignCenter;
2463         } break;
2464     case SH_UnderlineShortcut:
2465         ret = false;
2466         break;
2467     case SH_ToolTipLabel_Opacity:
2468         ret = 242; // About 95%
2469         break;
2470     case SH_Button_FocusPolicy:
2471         ret = Qt::TabFocus;
2472         break;
2473     case SH_EtchDisabledText:
2474         ret = false;
2475         break;
2476     case SH_FocusFrame_Mask: {
2477         ret = true;
2478         if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2479             const uchar fillR = 192, fillG = 191, fillB = 190;
2480             QImage img;
2481
2482             QSize pixmapSize = opt->rect.size();
2483             if (pixmapSize.isValid()) {
2484                 QPixmap pix(pixmapSize);
2485                 pix.fill(QColor(fillR, fillG, fillB));
2486                 QPainter pix_paint(&pix);
2487                 proxy()->drawControl(CE_FocusFrame, opt, &pix_paint, w);
2488                 pix_paint.end();
2489                 img = pix.toImage();
2490             }
2491
2492             const QRgb *sptr = (QRgb*)img.bits(), *srow;
2493             const int sbpl = img.bytesPerLine();
2494             const int w = sbpl/4, h = img.height();
2495
2496             QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
2497             QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
2498             const int dbpl = img_mask.bytesPerLine();
2499
2500             for (int y = 0; y < h; ++y) {
2501                 srow = sptr+((y*sbpl)/4);
2502                 drow = dptr+((y*dbpl)/4);
2503                 for (int x = 0; x < w; ++x) {
2504                     const int diff = (((qRed(*srow)-fillR)*(qRed(*srow)-fillR)) +
2505                                       ((qGreen(*srow)-fillG)*((qGreen(*srow)-fillG))) +
2506                                       ((qBlue(*srow)-fillB)*((qBlue(*srow)-fillB))));
2507                     (*drow++) = (diff < 100) ? 0xffffffff : 0xff000000;
2508                     ++srow;
2509                 }
2510             }
2511             QBitmap qmask = QBitmap::fromImage(img_mask);
2512             mask->region = QRegion(qmask);
2513         }
2514         break; }
2515     case SH_TitleBar_NoBorder:
2516         ret = 1;
2517         break;
2518     case SH_RubberBand_Mask:
2519         ret = 0;
2520         break;
2521     case SH_ComboBox_LayoutDirection:
2522         ret = Qt::LeftToRight;
2523         break;
2524     case SH_ItemView_EllipsisLocation:
2525         ret = Qt::AlignHCenter;
2526         break;
2527     case SH_ItemView_ShowDecorationSelected:
2528         ret = true;
2529         break;
2530     case SH_TitleBar_ModifyNotification:
2531         ret = false;
2532         break;
2533     case SH_ScrollBar_RollBetweenButtons:
2534         ret = true;
2535         break;
2536     case SH_WindowFrame_Mask:
2537         ret = 1;
2538         if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(hret)) {
2539             mask->region = opt->rect;
2540             mask->region -= QRect(opt->rect.left(), opt->rect.top(), 5, 1);
2541             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 1, 3, 1);
2542             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 2, 2, 1);
2543             mask->region -= QRect(opt->rect.left(), opt->rect.top() + 3, 1, 2);
2544
2545             mask->region -= QRect(opt->rect.right() - 4, opt->rect.top(), 5, 1);
2546             mask->region -= QRect(opt->rect.right() - 2, opt->rect.top() + 1, 3, 1);
2547             mask->region -= QRect(opt->rect.right() - 1, opt->rect.top() + 2, 2, 1);
2548             mask->region -= QRect(opt->rect.right() , opt->rect.top() + 3, 1, 2);
2549         }
2550         break;
2551     case SH_TabBar_ElideMode:
2552         ret = Qt::ElideRight;
2553         break;
2554     case SH_DialogButtonLayout:
2555         ret = QDialogButtonBox::MacLayout;
2556         break;
2557     case SH_FormLayoutWrapPolicy:
2558         ret = QFormLayout::DontWrapRows;
2559         break;
2560     case SH_FormLayoutFieldGrowthPolicy:
2561         ret = QFormLayout::FieldsStayAtSizeHint;
2562         break;
2563     case SH_FormLayoutFormAlignment:
2564         ret = Qt::AlignHCenter | Qt::AlignTop;
2565         break;
2566     case SH_FormLayoutLabelAlignment:
2567         ret = Qt::AlignRight;
2568         break;
2569     case SH_ComboBox_PopupFrameStyle:
2570         ret = QFrame::NoFrame | QFrame::Plain;
2571         break;
2572     case SH_MessageBox_TextInteractionFlags:
2573         ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
2574         break;
2575     case SH_SpellCheckUnderlineStyle:
2576         ret = QTextCharFormat::DashUnderline;
2577         break;
2578     case SH_MessageBox_CenterButtons:
2579         ret = false;
2580         break;
2581     case SH_MenuBar_AltKeyNavigation:
2582         ret = false;
2583         break;
2584     case SH_ItemView_MovementWithoutUpdatingSelection:
2585         ret = false;
2586         break;
2587     case SH_FocusFrame_AboveWidget:
2588         ret = true;
2589         break;
2590     case SH_WizardStyle:
2591         ret = QWizard::MacStyle;
2592         break;
2593     case SH_ItemView_ArrowKeysNavigateIntoChildren:
2594         ret = false;
2595         break;
2596     case SH_Menu_FlashTriggeredItem:
2597         ret = true;
2598         break;
2599     case SH_Menu_FadeOutOnHide:
2600         ret = true;
2601         break;
2602     case SH_Menu_Mask:
2603         if (opt) {
2604             if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
2605                 ret = true;
2606                 HIRect menuRect = CGRectMake(opt->rect.x(), opt->rect.y() + 4,
2607                                              opt->rect.width(), opt->rect.height() - 8);
2608                 HIThemeMenuDrawInfo mdi;
2609                 mdi.version = 0;
2610                 if (w && qobject_cast<QMenu *>(w->parentWidget()))
2611                     mdi.menuType = kThemeMenuTypeHierarchical;
2612                 else
2613                     mdi.menuType = kThemeMenuTypePopUp;
2614                 QCFType<HIShapeRef> shape;
2615                 HIThemeGetMenuBackgroundShape(&menuRect, &mdi, &shape);
2616                 mask->region = QRegion::fromHIShapeRef(shape);
2617             }
2618         }
2619         break;
2620     case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
2621         ret = true;
2622         break;
2623     case SH_TabBar_CloseButtonPosition:
2624         ret = QTabBar::LeftSide;
2625         break;
2626     case SH_DockWidget_ButtonsHaveFrame:
2627         ret = false;
2628         break;
2629     default:
2630         ret = QWindowsStyle::styleHint(sh, opt, w, hret);
2631         break;
2632     }
2633     return ret;
2634 }
2635
2636 QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
2637                                        const QStyleOption *opt) const
2638 {
2639     switch (iconMode) {
2640     case QIcon::Disabled: {
2641         QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
2642         int imgh = img.height();
2643         int imgw = img.width();
2644         QRgb pixel;
2645         for (int y = 0; y < imgh; ++y) {
2646             for (int x = 0; x < imgw; ++x) {
2647                 pixel = img.pixel(x, y);
2648                 img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
2649                                          qAlpha(pixel) / 2));
2650             }
2651         }
2652         return QPixmap::fromImage(img);
2653     }
2654     default:
2655         ;
2656     }
2657     return QWindowsStyle::generatedIconPixmap(iconMode, pixmap, opt);
2658 }
2659
2660
2661 QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
2662                                   const QWidget *widget) const
2663 {
2664     // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
2665     // I don't want infinite recursion so if we do get in that situation, just return the Window's
2666     // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
2667     // someone changes how Windows standard
2668     // pixmap works.
2669     static bool recursionGuard = false;
2670
2671     if (recursionGuard)
2672         return QWindowsStyle::standardPixmap(standardPixmap, opt, widget);
2673
2674     recursionGuard = true;
2675     QIcon icon = standardIconImplementation(standardPixmap, opt, widget);
2676     recursionGuard = false;
2677     int size;
2678     switch (standardPixmap) {
2679         default:
2680             size = 32;
2681             break;
2682         case SP_MessageBoxCritical:
2683         case SP_MessageBoxQuestion:
2684         case SP_MessageBoxInformation:
2685         case SP_MessageBoxWarning:
2686             size = 64;
2687             break;
2688     }
2689     return icon.pixmap(size, size);
2690 }
2691
2692 void QMacStyle::setFocusRectPolicy(QWidget *w, FocusRectPolicy policy)
2693 {
2694     switch (policy) {
2695     case FocusDefault:
2696         break;
2697     case FocusEnabled:
2698     case FocusDisabled:
2699         w->setAttribute(Qt::WA_MacShowFocusRect, policy == FocusEnabled);
2700         break;
2701     }
2702 }
2703
2704 QMacStyle::FocusRectPolicy QMacStyle::focusRectPolicy(const QWidget *w)
2705 {
2706     return w->testAttribute(Qt::WA_MacShowFocusRect) ? FocusEnabled : FocusDisabled;
2707 }
2708
2709 void QMacStyle::setWidgetSizePolicy(const QWidget *widget, WidgetSizePolicy policy)
2710 {
2711     QWidget *wadget = const_cast<QWidget *>(widget);
2712     wadget->setAttribute(Qt::WA_MacNormalSize, policy == SizeLarge);
2713     wadget->setAttribute(Qt::WA_MacSmallSize, policy == SizeSmall);
2714     wadget->setAttribute(Qt::WA_MacMiniSize, policy == SizeMini);
2715 }
2716
2717 QMacStyle::WidgetSizePolicy QMacStyle::widgetSizePolicy(const QWidget *widget)
2718 {
2719     while (widget) {
2720         if (widget->testAttribute(Qt::WA_MacMiniSize)) {
2721             return SizeMini;
2722         } else if (widget->testAttribute(Qt::WA_MacSmallSize)) {
2723             return SizeSmall;
2724         } else if (widget->testAttribute(Qt::WA_MacNormalSize)) {
2725             return SizeLarge;
2726         }
2727         widget = widget->parentWidget();
2728     }
2729     return SizeDefault;
2730 }
2731
2732 void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p,
2733                               const QWidget *w) const
2734 {
2735     ThemeDrawState tds = d->getDrawState(opt->state);
2736     QMacCGContext cg(p);
2737     switch (pe) {
2738     case PE_IndicatorArrowUp:
2739     case PE_IndicatorArrowDown:
2740     case PE_IndicatorArrowRight:
2741     case PE_IndicatorArrowLeft: {
2742         p->save();
2743         p->setRenderHint(QPainter::Antialiasing);
2744         int xOffset = opt->direction == Qt::LeftToRight ? 2 : -1;
2745         QMatrix matrix;
2746         matrix.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
2747         QPainterPath path;
2748         switch(pe) {
2749         default:
2750         case PE_IndicatorArrowDown:
2751             break;
2752         case PE_IndicatorArrowUp:
2753             matrix.rotate(180);
2754             break;
2755         case PE_IndicatorArrowLeft:
2756             matrix.rotate(90);
2757             break;
2758         case PE_IndicatorArrowRight:
2759             matrix.rotate(-90);
2760             break;
2761         }
2762         path.moveTo(0, 5);
2763         path.lineTo(-4, -3);
2764         path.lineTo(4, -3);
2765         p->setMatrix(matrix);
2766         p->setPen(Qt::NoPen);
2767         p->setBrush(QColor(0, 0, 0, 135));
2768         p->drawPath(path);
2769         p->restore();
2770         break; }
2771     case PE_FrameTabBarBase:
2772         if (const QStyleOptionTabBarBaseV2 *tbb
2773                 = qstyleoption_cast<const QStyleOptionTabBarBaseV2 *>(opt)) {
2774             if (tbb->documentMode) {
2775                 p->save();
2776                 drawTabBase(p, tbb, w);
2777                 p->restore();
2778                 return;
2779             }
2780
2781             QRegion region(tbb->rect);
2782             region -= tbb->tabBarRect;
2783             p->save();
2784             p->setClipRegion(region);
2785             QStyleOptionTabWidgetFrame twf;
2786             twf.QStyleOption::operator=(*tbb);
2787             twf.shape  = tbb->shape;
2788             switch (getTabDirection(twf.shape)) {
2789             case kThemeTabNorth:
2790                 twf.rect = twf.rect.adjusted(0, 0, 0, 10);
2791                 break;
2792             case kThemeTabSouth:
2793                 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2794                 break;
2795             case kThemeTabWest:
2796                 twf.rect = twf.rect.adjusted(0, 0, 10, 0);
2797                 break;
2798             case kThemeTabEast:
2799                 twf.rect = twf.rect.adjusted(0, -10, 0, 0);
2800                 break;
2801             }
2802             proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p, w);
2803             p->restore();
2804         }
2805         break;
2806     case PE_PanelTipLabel:
2807         p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
2808         break;
2809     case PE_FrameGroupBox:
2810         if (const QStyleOptionFrame *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
2811             const QStyleOptionFrameV2 *frame2 = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt);
2812             if (frame2 && frame2->features & QStyleOptionFrameV2::Flat) {
2813                 QWindowsStyle::drawPrimitive(pe, groupBox, p, w);
2814             } else {
2815                 HIThemeGroupBoxDrawInfo gdi;
2816                 gdi.version = qt_mac_hitheme_version;
2817                 gdi.state = tds;
2818                 if (w && qobject_cast<QGroupBox *>(w->parentWidget()))
2819                     gdi.kind = kHIThemeGroupBoxKindSecondary;
2820                 else
2821                     gdi.kind = kHIThemeGroupBoxKindPrimary;
2822                 HIRect hirect = qt_hirectForQRect(opt->rect);
2823                 HIThemeDrawGroupBox(&hirect, &gdi, cg, kHIThemeOrientationNormal);
2824             }
2825         }
2826         break;
2827     case PE_IndicatorToolBarSeparator: {
2828             QPainterPath path;
2829             if (opt->state & State_Horizontal) {
2830                 int xpoint = opt->rect.center().x();
2831                 path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
2832                 path.lineTo(xpoint + 0.5, opt->rect.bottom());
2833             } else {
2834                 int ypoint = opt->rect.center().y();
2835                 path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
2836                 path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
2837             }
2838             QPainterPathStroker theStroker;
2839             theStroker.setCapStyle(Qt::FlatCap);
2840             theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
2841             path = theStroker.createStroke(path);
2842             p->fillPath(path, QColor(0, 0, 0, 119));
2843         }
2844         break;
2845     case PE_FrameWindow:
2846         break;
2847     case PE_IndicatorDockWidgetResizeHandle: {
2848             // The docwidget resize handle is drawn as a one-pixel wide line.
2849             p->save();
2850             if (opt->state & State_Horizontal) {
2851                 p->setPen(QColor(160, 160, 160));
2852                 p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
2853             } else {
2854                 p->setPen(QColor(145, 145, 145));
2855                 p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
2856             }
2857             p->restore();
2858         } break;
2859     case PE_IndicatorToolBarHandle: {
2860             p->save();
2861             QPainterPath path;
2862             int x = opt->rect.x() + 6;
2863             int y = opt->rect.y() + 5;
2864             static const int RectHeight = 2;
2865             if (opt->state & State_Horizontal) {
2866                 while (y < opt->rect.height() - RectHeight - 6) {
2867                     path.moveTo(x, y);
2868                     path.addRect(x, y, RectHeight, RectHeight);
2869                     y += 6;
2870                 }
2871             } else {
2872                 while (x < opt->rect.width() - RectHeight - 6) {
2873                     path.moveTo(x, y);
2874                     path.addRect(x, y, RectHeight, RectHeight);
2875                     x += 6;
2876                 }
2877             }
2878             p->setPen(Qt::NoPen);
2879             QColor dark = opt->palette.dark().color();
2880             dark.setAlphaF(0.75);
2881             QColor light = opt->palette.light().color();
2882             light.setAlphaF(0.6);
2883             p->fillPath(path, light);
2884             p->save();
2885             p->translate(1, 1);
2886             p->fillPath(path, dark);
2887             p->restore();
2888             p->translate(3, 3);
2889             p->fillPath(path, light);
2890             p->translate(1, 1);
2891             p->fillPath(path, dark);
2892             p->restore();
2893
2894             break;
2895         }
2896     case PE_IndicatorHeaderArrow:
2897         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
2898             // In HITheme, up is down, down is up and hamburgers eat people.
2899             if (header->sortIndicator != QStyleOptionHeader::None)
2900                 proxy()->drawPrimitive(
2901                     (header->sortIndicator == QStyleOptionHeader::SortDown) ?
2902                     PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p, w);
2903         }
2904         break;
2905     case PE_IndicatorMenuCheckMark: {
2906         const int checkw = 8;
2907         const int checkh = 8;
2908         const int xoff = qMax(0, (opt->rect.width() - checkw) / 2);
2909         const int yoff = qMax(0, (opt->rect.width() - checkh) / 2);
2910         const int x1 = xoff + opt->rect.x();
2911         const int y1 = yoff + opt->rect.y() + checkw/2;
2912         const int x2 = xoff + opt->rect.x() + checkw/4;
2913         const int y2 = yoff + opt->rect.y() + checkh;
2914         const int x3 = xoff + opt->rect.x() + checkw;
2915         const int y3 = yoff + opt->rect.y();
2916
2917         QVector<QLineF> a(2);
2918         a << QLineF(x1, y1, x2, y2);
2919         a << QLineF(x2, y2, x3, y3);
2920         if (opt->palette.currentColorGroup() == QPalette::Active) {
2921             if (opt->state & State_On)
2922                 p->setPen(QPen(opt->palette.highlightedText().color(), 3));
2923             else
2924                 p->setPen(QPen(opt->palette.text().color(), 3));
2925         } else {
2926             p->setPen(QPen(QColor(100, 100, 100), 3));
2927         }
2928         p->save();
2929         p->setRenderHint(QPainter::Antialiasing);
2930         p->drawLines(a);
2931         p->restore();
2932         break; }
2933     case PE_IndicatorViewItemCheck:
2934     case PE_Q3CheckListExclusiveIndicator:
2935     case PE_Q3CheckListIndicator:
2936     case PE_IndicatorRadioButton:
2937     case PE_IndicatorCheckBox: {
2938         bool drawColorless = (!(opt->state & State_Active))
2939                               && opt->palette.currentColorGroup() == QPalette::Active;
2940         HIThemeButtonDrawInfo bdi;
2941         bdi.version = qt_mac_hitheme_version;
2942         bdi.state = tds;
2943         if (drawColorless && tds == kThemeStateInactive)
2944             bdi.state = kThemeStateActive;
2945         bdi.adornment = kThemeDrawIndicatorOnly;
2946         if (opt->state & State_HasFocus)
2947             bdi.adornment |= kThemeAdornmentFocus;
2948         bool isRadioButton = (pe == PE_Q3CheckListExclusiveIndicator
2949                               || pe == PE_IndicatorRadioButton);
2950         switch (d->aquaSizeConstrain(opt, w)) {
2951         case QAquaSizeUnknown:
2952         case QAquaSizeLarge:
2953             if (isRadioButton)
2954                 bdi.kind = kThemeRadioButton;
2955             else
2956                 bdi.kind = kThemeCheckBox;
2957             break;
2958         case QAquaSizeMini:
2959             if (isRadioButton)
2960                 bdi.kind = kThemeMiniRadioButton;
2961             else
2962                 bdi.kind = kThemeMiniCheckBox;
2963             break;
2964         case QAquaSizeSmall:
2965             if (isRadioButton)
2966                 bdi.kind = kThemeSmallRadioButton;
2967             else
2968                 bdi.kind = kThemeSmallCheckBox;
2969             break;
2970         }
2971         if (opt->state & State_NoChange)
2972             bdi.value = kThemeButtonMixed;
2973         else if (opt->state & State_On)
2974             bdi.value = kThemeButtonOn;
2975         else
2976             bdi.value = kThemeButtonOff;
2977         HIRect macRect;
2978         if (pe == PE_Q3CheckListExclusiveIndicator || pe == PE_Q3CheckListIndicator)
2979             macRect = qt_hirectForQRect(opt->rect);
2980         else
2981             macRect = qt_hirectForQRect(opt->rect);
2982         if (!drawColorless)
2983             HIThemeDrawButton(&macRect, &bdi, cg, kHIThemeOrientationNormal, 0);
2984         else
2985             d->drawColorlessButton(macRect, &bdi, p, opt);
2986         break; }
2987     case PE_FrameFocusRect:
2988         // Use the our own focus widget stuff.
2989         break;
2990     case PE_IndicatorBranch: {
2991         if (!(opt->state & State_Children))
2992             break;
2993         HIThemeButtonDrawInfo bi;
2994         bi.version = qt_mac_hitheme_version;
2995         bi.state = tds;
2996         if (tds == kThemeStateInactive && opt->palette.currentColorGroup() == QPalette::Active)
2997             bi.state = kThemeStateActive;
2998         if (opt->state & State_Sunken)
2999             bi.state |= kThemeStatePressed;
3000         bi.kind = kThemeDisclosureButton;
3001         if (opt->state & State_Open)
3002             bi.value = kThemeDisclosureDown;
3003         else
3004             bi.value = opt->direction == Qt::LeftToRight ? kThemeDisclosureRight : kThemeDisclosureLeft;
3005         bi.adornment = kThemeAdornmentNone;
3006         HIRect hirect = qt_hirectForQRect(opt->rect.adjusted(DisclosureOffset,0,-DisclosureOffset,0));
3007         HIThemeDrawButton(&hirect, &bi, cg, kHIThemeOrientationNormal, 0);
3008         break; }
3009
3010     case PE_Frame: {
3011         QPen oldPen = p->pen();
3012         p->setPen(opt->palette.base().color().darker(140));
3013         p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
3014         p->setPen(opt->palette.base().color().darker(180));
3015         p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3016         p->setPen(oldPen);
3017         break; }
3018
3019     case PE_FrameLineEdit:
3020         if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3021             if (frame->state & State_Sunken) {
3022                 QColor baseColor(frame->palette.background().color());
3023                 HIThemeFrameDrawInfo fdi;
3024                 fdi.version = qt_mac_hitheme_version;
3025                 fdi.state = tds;
3026                 SInt32 frame_size;
3027                 if (pe == PE_FrameLineEdit) {
3028                     fdi.kind = kHIThemeFrameTextFieldSquare;
3029                     GetThemeMetric(kThemeMetricEditTextFrameOutset, &frame_size);
3030                     if ((frame->state & State_ReadOnly) || !(frame->state & State_Enabled))
3031                         fdi.state = kThemeStateInactive;
3032                 } else {
3033                     baseColor = QColor(150, 150, 150); //hardcoded since no query function --Sam
3034                     fdi.kind = kHIThemeFrameListBox;
3035                     GetThemeMetric(kThemeMetricListBoxFrameOutset, &frame_size);
3036                 }
3037                 fdi.isFocused = (frame->state & State_HasFocus);
3038                 int lw = frame->lineWidth;
3039                 if (lw <= 0)
3040                     lw = proxy()->pixelMetric(PM_DefaultFrameWidth, frame, w);
3041                 { //clear to base color
3042                     p->save();
3043                     p->setPen(QPen(baseColor, lw));
3044                     p->setBrush(Qt::NoBrush);
3045                     p->drawRect(frame->rect);
3046                     p->restore();
3047                 }
3048                 HIRect hirect = qt_hirectForQRect(frame->rect,
3049                                                   QRect(frame_size, frame_size,
3050                                                         frame_size * 2, frame_size * 2));
3051
3052                 HIThemeDrawFrame(&hirect, &fdi, cg, kHIThemeOrientationNormal);
3053             } else {
3054                 QWindowsStyle::drawPrimitive(pe, opt, p, w);
3055             }
3056         }
3057         break;
3058     case PE_PanelLineEdit:
3059         QWindowsStyle::drawPrimitive(pe, opt, p, w);
3060         // Draw the focus frame for widgets other than QLineEdit (e.g. for line edits in Webkit).
3061         // Focus frame is drawn outside the rectangle passed in the option-rect.
3062         if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
3063             if ((opt->state & State_HasFocus) && !qobject_cast<const QLineEdit*>(w)) {
3064                 int vmargin = pixelMetric(QStyle::PM_FocusFrameVMargin);
3065                 int hmargin = pixelMetric(QStyle::PM_FocusFrameHMargin);
3066                 QStyleOptionFrame focusFrame = *panel;
3067                 focusFrame.rect = panel->rect.adjusted(-hmargin, -vmargin, hmargin, vmargin);
3068                 drawControl(CE_FocusFrame, &focusFrame, p, w);
3069             }
3070         }
3071
3072         break;
3073     case PE_FrameTabWidget:
3074         if (const QStyleOptionTabWidgetFrame *twf
3075                 = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
3076             HIRect hirect = qt_hirectForQRect(twf->rect);
3077             HIThemeTabPaneDrawInfo tpdi;
3078             tpdi.version = qt_mac_hitheme_tab_version();
3079             tpdi.state = tds;
3080             tpdi.direction = getTabDirection(twf->shape);
3081             tpdi.size = kHIThemeTabSizeNormal;
3082             tpdi.kind = kHIThemeTabKindNormal;
3083             tpdi.adornment = kHIThemeTabPaneAdornmentNormal;
3084             HIThemeDrawTabPane(&hirect, &tpdi, cg, kHIThemeOrientationNormal);
3085         }
3086         break;
3087     case PE_PanelScrollAreaCorner: {
3088         const QBrush brush(opt->palette.brush(QPalette::Base));
3089         p->fillRect(opt->rect, brush);
3090         p->setPen(QPen(QColor(217, 217, 217)));
3091         p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
3092         p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
3093         } break;
3094     case PE_FrameStatusBarItem:
3095         break;
3096     case PE_IndicatorTabClose: {
3097         bool hover = (opt->state & State_MouseOver);
3098         bool selected = (opt->state & State_Selected);
3099         bool active = (opt->state & State_Active);
3100         drawTabCloseButton(p, hover, active, selected);
3101         } break;
3102     case PE_PanelStatusBar: {
3103         if (QSysInfo::MacintoshVersion <= QSysInfo::MV_10_4) {
3104             QWindowsStyle::drawPrimitive(pe, opt, p, w);
3105             break;
3106         }
3107         // Use the Leopard style only if the status bar is the status bar for a
3108         // QMainWindow with a unifed toolbar.
3109         if (w == 0 || w->parent() == 0 || qobject_cast<QMainWindow *>(w->parent()) == 0 ||
3110             qobject_cast<QMainWindow *>(w->parent())->unifiedTitleAndToolBarOnMac() == false ) {
3111             QWindowsStyle::drawPrimitive(pe, opt, p, w);
3112             break;
3113         }
3114
3115         // Fill the status bar with the titlebar gradient.
3116         QLinearGradient linearGrad(0, opt->rect.top(), 0, opt->rect.bottom());
3117         if (opt->state & QStyle::State_Active) {
3118             linearGrad.setColorAt(0, titlebarGradientActiveBegin);
3119             linearGrad.setColorAt(1, titlebarGradientActiveEnd);
3120         } else {
3121             linearGrad.setColorAt(0, titlebarGradientInactiveBegin);
3122             linearGrad.setColorAt(1, titlebarGradientInactiveEnd);
3123         }
3124         p->fillRect(opt->rect, linearGrad);
3125
3126         // Draw the black separator line at the top of the status bar.
3127         if (opt->state & QStyle::State_Active)
3128             p->setPen(titlebarSeparatorLineActive);
3129         else
3130             p->setPen(titlebarSeparatorLineInactive);
3131         p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
3132
3133         break;
3134     }
3135
3136     default:
3137         QWindowsStyle::drawPrimitive(pe, opt, p, w);
3138         break;
3139     }
3140 }
3141
3142 static inline QPixmap darkenPixmap(const QPixmap &pixmap)
3143 {
3144     QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
3145     int imgh = img.height();
3146     int imgw = img.width();
3147     int h, s, v, a;
3148     QRgb pixel;
3149     for (int y = 0; y < imgh; ++y) {
3150         for (int x = 0; x < imgw; ++x) {
3151             pixel = img.pixel(x, y);
3152             a = qAlpha(pixel);
3153             QColor hsvColor(pixel);
3154             hsvColor.getHsv(&h, &s, &v);
3155             s = qMin(100, s * 2);
3156             v = v / 2;
3157             hsvColor.setHsv(h, s, v);
3158             pixel = hsvColor.rgb();
3159             img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
3160         }
3161     }
3162     return QPixmap::fromImage(img);
3163 }
3164
3165
3166
3167 void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p,
3168                             const QWidget *w) const
3169 {
3170     ThemeDrawState tds = d->getDrawState(opt->state);
3171     QMacCGContext cg(p);
3172     switch (ce) {
3173     case CE_HeaderSection:
3174         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3175             HIThemeButtonDrawInfo bdi;
3176             bdi.version = qt_mac_hitheme_version;
3177             State flags = header->state;
3178             QRect ir = header->rect;
3179             bdi.kind = kThemeListHeaderButton;
3180             bdi.adornment = kThemeAdornmentNone;
3181             bdi.state = kThemeStateActive;
3182
3183             if (flags & State_On)
3184                 bdi.value = kThemeButtonOn;
3185             else
3186                 bdi.value = kThemeButtonOff;
3187
3188             if (header->orientation == Qt::Horizontal){
3189                 switch (header->position) {
3190                 case QStyleOptionHeader::Beginning:
3191                     ir.adjust(-1, -1, 0, 0);
3192                     break;
3193                 case QStyleOptionHeader::Middle:
3194                     ir.adjust(-1, -1, 0, 0);
3195                     break;
3196                 case QStyleOptionHeader::OnlyOneSection:
3197                 case QStyleOptionHeader::End:
3198                     ir.adjust(-1, -1, 1, 0);
3199                     break;
3200                 default:
3201                     break;
3202                 }
3203
3204                 if (header->position != QStyleOptionHeader::Beginning
3205                     && header->position != QStyleOptionHeader::OnlyOneSection) {
3206                     bdi.adornment = header->direction == Qt::LeftToRight
3207                         ? kThemeAdornmentHeaderButtonLeftNeighborSelected
3208                         : kThemeAdornmentHeaderButtonRightNeighborSelected;
3209                 }
3210             }
3211
3212             if (flags & State_Active) {
3213                 if (!(flags & State_Enabled))
3214                     bdi.state = kThemeStateUnavailable;
3215                 else if (flags & State_Sunken)
3216                     bdi.state = kThemeStatePressed;
3217             } else {
3218                 if (flags & State_Enabled)
3219                     bdi.state = kThemeStateInactive;
3220                 else
3221                     bdi.state = kThemeStateUnavailableInactive;
3222             }
3223
3224             if (header->sortIndicator != QStyleOptionHeader::None) {
3225                 bdi.value = kThemeButtonOn;
3226                 if (header->sortIndicator == QStyleOptionHeader::SortDown)
3227                     bdi.adornment = kThemeAdornmentHeaderButtonSortUp;
3228             }
3229             if (flags & State_HasFocus)
3230                 bdi.adornment = kThemeAdornmentFocus;
3231
3232             ir = visualRect(header->direction, header->rect, ir);
3233             HIRect bounds = qt_hirectForQRect(ir);
3234
3235             bool noVerticalHeader = true;
3236             if (w)
3237                 if (const QTableView *table = qobject_cast<const QTableView *>(w->parentWidget()))
3238                     noVerticalHeader = !table->verticalHeader()->isVisible();
3239
3240             bool drawTopBorder = header->orientation == Qt::Horizontal;
3241             bool drawLeftBorder = header->orientation == Qt::Vertical
3242                 || header->position == QStyleOptionHeader::OnlyOneSection
3243                 || (header->position == QStyleOptionHeader::Beginning && noVerticalHeader);
3244             d->drawTableHeader(bounds, drawTopBorder, drawLeftBorder, bdi, p);
3245         }
3246         break;
3247     case CE_HeaderLabel:
3248         if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
3249             QRect textr = header->rect;
3250             if (!header->icon.isNull()) {
3251                 QIcon::Mode mode = QIcon::Disabled;
3252                 if (opt->state & State_Enabled)
3253                     mode = QIcon::Normal;
3254                 QPixmap pixmap = header->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize), mode);
3255
3256                 QRect pixr = header->rect;
3257                 pixr.setY(header->rect.center().y() - (pixmap.height() - 1) / 2);
3258                 proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
3259                 textr.translate(pixmap.width() + 2, 0);
3260             }
3261
3262             proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
3263                                        header->state & State_Enabled, header->text, QPalette::ButtonText);
3264         }
3265         break;
3266     case CE_ToolButtonLabel:
3267         if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
3268             QStyleOptionToolButton myTb = *tb;
3269             myTb.state &= ~State_AutoRaise;
3270             if (w && qobject_cast<QToolBar *>(w->parentWidget())) {
3271                 QRect cr = tb->rect;
3272                 int shiftX = 0;
3273                 int shiftY = 0;
3274                 bool needText = false;
3275                 int alignment = 0;
3276                 bool down = tb->state & (State_Sunken | State_On);
3277                 if (down) {
3278                     shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb, w);
3279                     shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb, w);
3280                 }
3281                 // The down state is special for QToolButtons in a toolbar on the Mac
3282                 // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
3283                 // This doesn't really fit into any particular case in QIcon, so we
3284                 // do the majority of the work ourselves.
3285                 if (!(tb->features & QStyleOptionToolButton::Arrow)) {
3286                     Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
3287                     if (tb->icon.isNull() && !tb->text.isEmpty())
3288                         tbstyle = Qt::ToolButtonTextOnly;
3289
3290                     switch (tbstyle) {
3291                     case Qt::ToolButtonTextOnly: {
3292                         needText = true;
3293                         alignment = Qt::AlignCenter;
3294                         break; }
3295                     case Qt::ToolButtonIconOnly:
3296                     case Qt::ToolButtonTextBesideIcon:
3297                     case Qt::ToolButtonTextUnderIcon: {
3298                         QRect pr = cr;
3299                         QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
3300                                                                             : QIcon::Disabled;
3301                         QIcon::State iconState = (tb->state & State_On) ? QIcon::On
3302                                                                          : QIcon::Off;
3303                         QPixmap pixmap = tb->icon.pixmap(tb->rect.size().boundedTo(tb->iconSize), iconMode, iconState);
3304
3305                         // Draw the text if it's needed.
3306                         if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
3307                             needText = true;
3308                             if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
3309                                 QMainWindow *mw = qobject_cast<QMainWindow *>(w->window());
3310                                 if (mw && mw->unifiedTitleAndToolBarOnMac()) {
3311                                     pr.setHeight(pixmap.size().height());
3312                                     cr.adjust(0, pr.bottom() + 1, 0, 1);
3313                                 } else {
3314                                     pr.setHeight(pixmap.size().height() + 6);
3315                                     cr.adjust(0, pr.bottom(), 0, -3);
3316                                 }       
3317                                 alignment |= Qt::AlignCenter;
3318                             } else {
3319                                 pr.setWidth(pixmap.width() + 8);
3320                                 cr.adjust(pr.right(), 0, 0, 0);
3321                                 alignment |= Qt::AlignLeft | Qt::AlignVCenter;
3322                             }
3323                         }
3324                         if (opt->state & State_Sunken) {