src/gui/kernel/qt_cocoa_helpers_mac.mm
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /****************************************************************************
       
    43 **
       
    44 ** Copyright (c) 2007-2008, Apple, Inc.
       
    45 **
       
    46 ** All rights reserved.
       
    47 **
       
    48 ** Redistribution and use in source and binary forms, with or without
       
    49 ** modification, are permitted provided that the following conditions are met:
       
    50 **
       
    51 **   * Redistributions of source code must retain the above copyright notice,
       
    52 **     this list of conditions and the following disclaimer.
       
    53 **
       
    54 **   * Redistributions in binary form must reproduce the above copyright notice,
       
    55 **     this list of conditions and the following disclaimer in the documentation
       
    56 **     and/or other materials provided with the distribution.
       
    57 **
       
    58 **   * Neither the name of Apple, Inc. nor the names of its contributors
       
    59 **     may be used to endorse or promote products derived from this software
       
    60 **     without specific prior written permission.
       
    61 **
       
    62 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
       
    63 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
       
    64 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
       
    65 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    66 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    67 ** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    68 ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    69 ** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    70 ** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    71 ** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    72 ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    73 **
       
    74 ****************************************************************************/
       
    75 
       
    76 #include <private/qcore_mac_p.h>
       
    77 #include <qaction.h>
       
    78 #include <qwidget.h>
       
    79 #include <qdesktopwidget.h>
       
    80 #include <qevent.h>
       
    81 #include <qpixmapcache.h>
       
    82 #include <private/qevent_p.h>
       
    83 #include <private/qt_cocoa_helpers_mac_p.h>
       
    84 #include <private/qt_mac_p.h>
       
    85 #include <private/qapplication_p.h>
       
    86 #include <private/qcocoawindow_mac_p.h>
       
    87 #include <private/qcocoaview_mac_p.h>
       
    88 #include <private/qkeymapper_p.h>
       
    89 #include <private/qwidget_p.h>
       
    90 
       
    91 QT_BEGIN_NAMESPACE
       
    92 
       
    93 Q_GLOBAL_STATIC(QMacWindowFader, macwindowFader);
       
    94 
       
    95 QMacWindowFader::QMacWindowFader()
       
    96     : m_duration(0.250)
       
    97 {
       
    98 }
       
    99 
       
   100 QMacWindowFader *QMacWindowFader::currentFader()
       
   101 {
       
   102     return macwindowFader();
       
   103 }
       
   104 
       
   105 void QMacWindowFader::registerWindowToFade(QWidget *window)
       
   106 {
       
   107     m_windowsToFade.append(window);
       
   108 }
       
   109 
       
   110 void QMacWindowFader::performFade()
       
   111 {
       
   112     const QWidgetList myWidgetsToFade = m_windowsToFade;
       
   113     const int widgetCount = myWidgetsToFade.count();
       
   114 #if QT_MAC_USE_COCOA
       
   115     QMacCocoaAutoReleasePool pool;
       
   116     [NSAnimationContext beginGrouping];
       
   117     [[NSAnimationContext currentContext] setDuration:NSTimeInterval(m_duration)];
       
   118 #endif
       
   119 
       
   120     for (int i = 0; i < widgetCount; ++i) {
       
   121         QWidget *widget = m_windowsToFade.at(i);
       
   122         OSWindowRef window = qt_mac_window_for(widget);
       
   123 #if QT_MAC_USE_COCOA
       
   124         [[window animator] setAlphaValue:0.0];
       
   125         QTimer::singleShot(qRound(m_duration * 1000), widget, SLOT(hide()));
       
   126 #else
       
   127         TransitionWindowOptions options = {0, m_duration, 0, 0};
       
   128         TransitionWindowWithOptions(window, kWindowFadeTransitionEffect, kWindowHideTransitionAction,
       
   129                                     0, 1, &options);
       
   130 #endif
       
   131     }
       
   132 #if QT_MAC_USE_COCOA
       
   133     [NSAnimationContext endGrouping];
       
   134 #endif
       
   135     m_duration = 0.250;
       
   136     m_windowsToFade.clear();
       
   137 }
       
   138 
       
   139 extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); // qapplication.cpp;
       
   140 extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm
       
   141 extern QWidget * mac_mouse_grabber;
       
   142 
       
   143 void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds)
       
   144 {
       
   145     OSWindowRef wnd = static_cast<OSWindowRef>(window);
       
   146     if (wnd) {
       
   147         QWidget *widget;
       
   148 #if QT_MAC_USE_COCOA
       
   149         widget = [wnd QT_MANGLE_NAMESPACE(qt_qwidget)];
       
   150 #else
       
   151     const UInt32 kWidgetCreatorQt = kEventClassQt;
       
   152     enum {
       
   153         kWidgetPropertyQWidget = 'QWId' //QWidget *
       
   154     };
       
   155         if (GetWindowProperty(static_cast<WindowRef>(window), kWidgetCreatorQt, kWidgetPropertyQWidget, sizeof(widget), 0, &widget) != noErr)
       
   156             widget = 0;
       
   157 #endif
       
   158         if (widget) {
       
   159             QMacWindowFader::currentFader()->setFadeDuration(durationSeconds);
       
   160             QMacWindowFader::currentFader()->registerWindowToFade(widget);
       
   161             QMacWindowFader::currentFader()->performFade();
       
   162         }
       
   163     }
       
   164 }
       
   165 
       
   166 bool macWindowIsTextured( void * /*OSWindowRef*/ window )
       
   167 {
       
   168     OSWindowRef wnd = static_cast<OSWindowRef>(window);
       
   169 #if QT_MAC_USE_COCOA
       
   170 	return ( [wnd styleMask] & NSTexturedBackgroundWindowMask ) ? true : false;
       
   171 #else
       
   172 	WindowAttributes currentAttributes;
       
   173 	GetWindowAttributes(wnd, &currentAttributes);
       
   174 	return (currentAttributes & kWindowMetalAttribute) ? true : false;
       
   175 #endif
       
   176 }
       
   177 
       
   178 void macWindowToolbarShow(const QWidget *widget, bool show )
       
   179 {
       
   180     OSWindowRef wnd = qt_mac_window_for(widget);
       
   181 #if QT_MAC_USE_COCOA
       
   182     if (NSToolbar *toolbar = [wnd toolbar]) {
       
   183         QMacCocoaAutoReleasePool pool;
       
   184         if (show != [toolbar isVisible]) {
       
   185            [toolbar setVisible:show];
       
   186         } else {
       
   187             // The toolbar may be in sync, but we are not, update our framestrut.
       
   188             qt_widget_private(const_cast<QWidget *>(widget))->updateFrameStrut();
       
   189         }
       
   190     }
       
   191 #else
       
   192     ShowHideWindowToolbar(wnd, show, false);
       
   193 #endif
       
   194 }
       
   195 
       
   196 
       
   197 void macWindowToolbarSet( void * /*OSWindowRef*/ window, void *toolbarRef  )
       
   198 {
       
   199     OSWindowRef wnd = static_cast<OSWindowRef>(window);
       
   200 #if QT_MAC_USE_COCOA
       
   201     [wnd setToolbar:static_cast<NSToolbar *>(toolbarRef)];
       
   202 #else
       
   203     SetWindowToolbar(wnd, static_cast<HIToolbarRef>(toolbarRef));
       
   204 #endif
       
   205 }
       
   206 
       
   207 bool macWindowToolbarIsVisible( void * /*OSWindowRef*/ window )
       
   208 {
       
   209     OSWindowRef wnd = static_cast<OSWindowRef>(window);
       
   210 #if QT_MAC_USE_COCOA
       
   211     if (NSToolbar *toolbar = [wnd toolbar])
       
   212         return [toolbar isVisible];
       
   213     return false;
       
   214 #else
       
   215     return IsWindowToolbarVisible(wnd);
       
   216 #endif
       
   217 }
       
   218 
       
   219 void macWindowSetHasShadow( void * /*OSWindowRef*/ window, bool hasShadow  )
       
   220 {
       
   221     OSWindowRef wnd = static_cast<OSWindowRef>(window);
       
   222 #if QT_MAC_USE_COCOA
       
   223     [wnd setHasShadow:BOOL(hasShadow)];
       
   224 #else
       
   225     if (hasShadow)
       
   226         ChangeWindowAttributes(wnd, 0, kWindowNoShadowAttribute);
       
   227     else
       
   228         ChangeWindowAttributes(wnd, kWindowNoShadowAttribute, 0);
       
   229 #endif
       
   230 }
       
   231 
       
   232 void macWindowFlush(void * /*OSWindowRef*/ window)
       
   233 {
       
   234     OSWindowRef wnd = static_cast<OSWindowRef>(window);
       
   235 #if QT_MAC_USE_COCOA
       
   236     [wnd flushWindowIfNeeded];
       
   237 #else
       
   238     HIWindowFlush(wnd);
       
   239 #endif
       
   240 }
       
   241 
       
   242 void * /*NSImage */qt_mac_create_nsimage(const QPixmap &pm)
       
   243 {
       
   244     QMacCocoaAutoReleasePool pool;
       
   245     if(QCFType<CGImageRef> image = pm.toMacCGImageRef()) {
       
   246         NSImage *newImage = 0;
       
   247         NSRect imageRect = NSMakeRect(0.0, 0.0, CGImageGetWidth(image), CGImageGetHeight(image));
       
   248         newImage = [[NSImage alloc] initWithSize:imageRect.size];
       
   249         [newImage lockFocus];
       
   250         {
       
   251             CGContextRef imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
       
   252             CGContextDrawImage(imageContext, *(CGRect*)&imageRect, image);
       
   253         }
       
   254         [newImage unlockFocus];
       
   255         return newImage;
       
   256     }
       
   257     return 0;
       
   258 }
       
   259 
       
   260 void qt_mac_update_mouseTracking(QWidget *widget)
       
   261 {
       
   262 #ifdef QT_MAC_USE_COCOA
       
   263     [qt_mac_nativeview_for(widget) updateTrackingAreas];
       
   264 #else
       
   265     Q_UNUSED(widget);
       
   266 #endif
       
   267 }
       
   268 
       
   269 OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage)
       
   270 {
       
   271     // Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev)
       
   272     OSStatus err = noErr;
       
   273 
       
   274     require_action(inContext != NULL, InvalidContext, err = paramErr);
       
   275     require_action(inBounds != NULL, InvalidBounds, err = paramErr);
       
   276     require_action(inImage != NULL, InvalidImage, err = paramErr);
       
   277 
       
   278     CGContextSaveGState( inContext );
       
   279     CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds));
       
   280     CGContextScaleCTM(inContext, 1, -1);
       
   281 
       
   282     CGContextDrawImage(inContext, *inBounds, inImage);
       
   283 
       
   284     CGContextRestoreGState(inContext);
       
   285 InvalidImage:
       
   286 InvalidBounds:
       
   287 InvalidContext:
       
   288 	return err;
       
   289 }
       
   290 
       
   291 bool qt_mac_checkForNativeSizeGrip(const QWidget *widget)
       
   292 {
       
   293 #ifndef QT_MAC_USE_COCOA
       
   294     OSViewRef nativeSizeGrip = 0;
       
   295     HIViewFindByID(HIViewGetRoot(HIViewGetWindow(HIViewRef(widget->winId()))), kHIViewWindowGrowBoxID, &nativeSizeGrip);
       
   296     return (nativeSizeGrip != 0);
       
   297 #else
       
   298     return [[reinterpret_cast<NSView *>(widget->winId()) window] showsResizeIndicator];
       
   299 #endif
       
   300 }
       
   301 struct qt_mac_enum_mapper
       
   302 {
       
   303     int mac_code;
       
   304     int qt_code;
       
   305 #if defined(DEBUG_MOUSE_MAPS)
       
   306 #   define QT_MAC_MAP_ENUM(x) x, #x
       
   307     const char *desc;
       
   308 #else
       
   309 #   define QT_MAC_MAP_ENUM(x) x
       
   310 #endif
       
   311 };
       
   312 
       
   313 //mouse buttons
       
   314 static qt_mac_enum_mapper qt_mac_mouse_symbols[] = {
       
   315 { kEventMouseButtonPrimary, QT_MAC_MAP_ENUM(Qt::LeftButton) },
       
   316 { kEventMouseButtonSecondary, QT_MAC_MAP_ENUM(Qt::RightButton) },
       
   317 { kEventMouseButtonTertiary, QT_MAC_MAP_ENUM(Qt::MidButton) },
       
   318 { 4, QT_MAC_MAP_ENUM(Qt::XButton1) },
       
   319 { 5, QT_MAC_MAP_ENUM(Qt::XButton2) },
       
   320 { 0, QT_MAC_MAP_ENUM(0) }
       
   321 };
       
   322 Qt::MouseButtons qt_mac_get_buttons(int buttons)
       
   323 {
       
   324 #ifdef DEBUG_MOUSE_MAPS
       
   325     qDebug("Qt: internal: **Mapping buttons: %d (0x%04x)", buttons, buttons);
       
   326 #endif
       
   327     Qt::MouseButtons ret = Qt::NoButton;
       
   328     for(int i = 0; qt_mac_mouse_symbols[i].qt_code; i++) {
       
   329         if (buttons & (0x01<<(qt_mac_mouse_symbols[i].mac_code-1))) {
       
   330 #ifdef DEBUG_MOUSE_MAPS
       
   331             qDebug("Qt: internal: got button: %s", qt_mac_mouse_symbols[i].desc);
       
   332 #endif
       
   333             ret |= Qt::MouseButtons(qt_mac_mouse_symbols[i].qt_code);
       
   334         }
       
   335     }
       
   336     return ret;
       
   337 }
       
   338 Qt::MouseButton qt_mac_get_button(EventMouseButton button)
       
   339 {
       
   340 #ifdef DEBUG_MOUSE_MAPS
       
   341     qDebug("Qt: internal: **Mapping button: %d (0x%04x)", button, button);
       
   342 #endif
       
   343     Qt::MouseButtons ret = 0;
       
   344     for(int i = 0; qt_mac_mouse_symbols[i].qt_code; i++) {
       
   345         if (button == qt_mac_mouse_symbols[i].mac_code) {
       
   346 #ifdef DEBUG_MOUSE_MAPS
       
   347             qDebug("Qt: internal: got button: %s", qt_mac_mouse_symbols[i].desc);
       
   348 #endif
       
   349             return Qt::MouseButton(qt_mac_mouse_symbols[i].qt_code);
       
   350         }
       
   351     }
       
   352     return Qt::NoButton;
       
   353 }
       
   354 
       
   355 void macSendToolbarChangeEvent(QWidget *widget)
       
   356 {
       
   357     QToolBarChangeEvent ev(!(GetCurrentKeyModifiers() & cmdKey));
       
   358     qt_sendSpontaneousEvent(widget, &ev);
       
   359 }
       
   360 
       
   361 Q_GLOBAL_STATIC(QMacTabletHash, tablet_hash)
       
   362 QMacTabletHash *qt_mac_tablet_hash()
       
   363 {
       
   364     return tablet_hash();
       
   365 }
       
   366 
       
   367 #ifdef QT_MAC_USE_COCOA
       
   368 void qt_dispatchTabletProximityEvent(void * /*NSEvent * */ tabletEvent)
       
   369 {
       
   370     NSEvent *proximityEvent = static_cast<NSEvent *>(tabletEvent);
       
   371     // simply construct a Carbon proximity record and handle it all in one spot.
       
   372     TabletProximityRec carbonProximityRec = { [proximityEvent vendorID],
       
   373                                               [proximityEvent tabletID],
       
   374                                               [proximityEvent pointingDeviceID],
       
   375                                               [proximityEvent deviceID],
       
   376                                               [proximityEvent systemTabletID],
       
   377                                               [proximityEvent vendorPointingDeviceType],
       
   378                                               [proximityEvent pointingDeviceSerialNumber],
       
   379                                               [proximityEvent uniqueID],
       
   380                                               [proximityEvent capabilityMask],
       
   381                                               [proximityEvent pointingDeviceType],
       
   382                                               [proximityEvent isEnteringProximity] };
       
   383     qt_dispatchTabletProximityEvent(carbonProximityRec);
       
   384 }
       
   385 #endif // QT_MAC_USE_COCOA
       
   386 
       
   387 void qt_dispatchTabletProximityEvent(const ::TabletProximityRec &proxRec)
       
   388 {
       
   389     QTabletDeviceData proximityDevice;
       
   390     proximityDevice.tabletUniqueID = proxRec.uniqueID;
       
   391     proximityDevice.capabilityMask = proxRec.capabilityMask;
       
   392 
       
   393     switch (proxRec.pointerType) {
       
   394         case NSUnknownPointingDevice:
       
   395         default:
       
   396             proximityDevice.tabletPointerType = QTabletEvent::UnknownPointer;
       
   397             break;
       
   398         case NSPenPointingDevice:
       
   399             proximityDevice.tabletPointerType = QTabletEvent::Pen;
       
   400             break;
       
   401         case NSCursorPointingDevice:
       
   402             proximityDevice.tabletPointerType = QTabletEvent::Cursor;
       
   403             break;
       
   404         case NSEraserPointingDevice:
       
   405             proximityDevice.tabletPointerType = QTabletEvent::Eraser;
       
   406             break;
       
   407     }
       
   408     uint bits = proxRec.vendorPointerType;
       
   409     if (bits == 0 && proximityDevice.tabletUniqueID != 0) {
       
   410         // Fallback. It seems that the driver doesn't always include all the information.
       
   411         // High-End Wacom devices store their "type" in the uper bits of the Unique ID.
       
   412         // I'm not sure how to handle it for consumer devices, but I'll test that in a bit.
       
   413         bits = proximityDevice.tabletUniqueID >> 32;
       
   414     }
       
   415     // Defined in the "EN0056-NxtGenImpGuideX"
       
   416     // on Wacom's Developer Website (www.wacomeng.com)
       
   417     if (((bits & 0x0006) == 0x0002) && ((bits & 0x0F06) != 0x0902)) {
       
   418         proximityDevice.tabletDeviceType = QTabletEvent::Stylus;
       
   419     } else {
       
   420         switch (bits & 0x0F06) {
       
   421             case 0x0802:
       
   422                 proximityDevice.tabletDeviceType = QTabletEvent::Stylus;
       
   423                 break;
       
   424             case 0x0902:
       
   425                 proximityDevice.tabletDeviceType = QTabletEvent::Airbrush;
       
   426                 break;
       
   427             case 0x0004:
       
   428                 proximityDevice.tabletDeviceType = QTabletEvent::FourDMouse;
       
   429                 break;
       
   430             case 0x0006:
       
   431                 proximityDevice.tabletDeviceType = QTabletEvent::Puck;
       
   432                 break;
       
   433             case 0x0804:
       
   434                 proximityDevice.tabletDeviceType = QTabletEvent::RotationStylus;
       
   435                 break;
       
   436             default:
       
   437                 proximityDevice.tabletDeviceType = QTabletEvent::NoDevice;
       
   438         }
       
   439     }
       
   440     // The deviceID is "unique" while in the proximity, it's a key that we can use for
       
   441     // linking up TabletDeviceData to an event (especially if there are two devices in action).
       
   442     bool entering = proxRec.enterProximity;
       
   443     if (entering) {
       
   444         qt_mac_tablet_hash()->insert(proxRec.deviceID, proximityDevice);
       
   445     } else {
       
   446         qt_mac_tablet_hash()->remove(proxRec.deviceID);
       
   447     }
       
   448 
       
   449     QTabletEvent qtabletProximity(entering ? QEvent::TabletEnterProximity
       
   450                                   : QEvent::TabletLeaveProximity,
       
   451                                   QPoint(), QPoint(), QPointF(), proximityDevice.tabletDeviceType,
       
   452                                   proximityDevice.tabletPointerType, 0., 0, 0, 0., 0., 0, 0,
       
   453                                   proximityDevice.tabletUniqueID);
       
   454 
       
   455     qt_sendSpontaneousEvent(qApp, &qtabletProximity);
       
   456 }
       
   457 
       
   458 #ifdef QT_MAC_USE_COCOA
       
   459 // Use this method to keep all the information in the TextSegment. As long as it is ordered
       
   460 // we are in OK shape, and we can influence that ourselves.
       
   461 struct KeyPair
       
   462 {
       
   463     QChar cocoaKey;
       
   464     Qt::Key qtKey;
       
   465 };
       
   466 
       
   467 bool operator==(const KeyPair &entry, QChar qchar)
       
   468 {
       
   469     return entry.cocoaKey == qchar;
       
   470 }
       
   471 
       
   472 bool operator<(const KeyPair &entry, QChar qchar)
       
   473 {
       
   474     return entry.cocoaKey < qchar;
       
   475 }
       
   476 
       
   477 bool operator<(QChar qchar, const KeyPair &entry)
       
   478 {
       
   479     return qchar < entry.cocoaKey;
       
   480 }
       
   481 
       
   482 static Qt::Key cocoaKey2QtKey(QChar keyCode)
       
   483 {
       
   484     static const int NumEntries = 57;
       
   485     static const KeyPair entries[NumEntries] = {
       
   486         { NSEnterCharacter, Qt::Key_Enter },
       
   487         { NSTabCharacter, Qt::Key_Tab },
       
   488         { NSCarriageReturnCharacter, Qt::Key_Return },
       
   489         { NSBackTabCharacter, Qt::Key_Backtab },
       
   490         { kEscapeCharCode, Qt::Key_Escape },
       
   491         { NSDeleteCharacter, Qt::Key_Backspace },
       
   492         { NSUpArrowFunctionKey, Qt::Key_Up },
       
   493         { NSDownArrowFunctionKey, Qt::Key_Down },
       
   494         { NSLeftArrowFunctionKey, Qt::Key_Left },
       
   495         { NSRightArrowFunctionKey, Qt::Key_Right },
       
   496         { NSF1FunctionKey, Qt::Key_F1 },
       
   497         { NSF2FunctionKey, Qt::Key_F2 },
       
   498         { NSF3FunctionKey, Qt::Key_F3 },
       
   499         { NSF4FunctionKey, Qt::Key_F4 },
       
   500         { NSF5FunctionKey, Qt::Key_F5 },
       
   501         { NSF6FunctionKey, Qt::Key_F6 },
       
   502         { NSF7FunctionKey, Qt::Key_F7 },
       
   503         { NSF8FunctionKey, Qt::Key_F8 },
       
   504         { NSF9FunctionKey, Qt::Key_F8 },
       
   505         { NSF10FunctionKey, Qt::Key_F10 },
       
   506         { NSF11FunctionKey, Qt::Key_F11 },
       
   507         { NSF12FunctionKey, Qt::Key_F12 },
       
   508         { NSF13FunctionKey, Qt::Key_F13 },
       
   509         { NSF14FunctionKey, Qt::Key_F14 },
       
   510         { NSF15FunctionKey, Qt::Key_F15 },
       
   511         { NSF16FunctionKey, Qt::Key_F16 },
       
   512         { NSF17FunctionKey, Qt::Key_F17 },
       
   513         { NSF18FunctionKey, Qt::Key_F18 },
       
   514         { NSF19FunctionKey, Qt::Key_F19 },
       
   515         { NSF20FunctionKey, Qt::Key_F20 },
       
   516         { NSF21FunctionKey, Qt::Key_F21 },
       
   517         { NSF22FunctionKey, Qt::Key_F22 },
       
   518         { NSF23FunctionKey, Qt::Key_F23 },
       
   519         { NSF24FunctionKey, Qt::Key_F24 },
       
   520         { NSF25FunctionKey, Qt::Key_F25 },
       
   521         { NSF26FunctionKey, Qt::Key_F26 },
       
   522         { NSF27FunctionKey, Qt::Key_F27 },
       
   523         { NSF28FunctionKey, Qt::Key_F28 },
       
   524         { NSF29FunctionKey, Qt::Key_F29 },
       
   525         { NSF30FunctionKey, Qt::Key_F30 },
       
   526         { NSF31FunctionKey, Qt::Key_F31 },
       
   527         { NSF32FunctionKey, Qt::Key_F32 },
       
   528         { NSF33FunctionKey, Qt::Key_F33 },
       
   529         { NSF34FunctionKey, Qt::Key_F34 },
       
   530         { NSF35FunctionKey, Qt::Key_F35 },
       
   531         { NSInsertFunctionKey, Qt::Key_Insert },
       
   532         { NSDeleteFunctionKey, Qt::Key_Delete },
       
   533         { NSHomeFunctionKey, Qt::Key_Home },
       
   534         { NSEndFunctionKey, Qt::Key_End },
       
   535         { NSPageUpFunctionKey, Qt::Key_PageUp },
       
   536         { NSPageDownFunctionKey, Qt::Key_PageDown },
       
   537         { NSPrintScreenFunctionKey, Qt::Key_Print },
       
   538         { NSScrollLockFunctionKey, Qt::Key_ScrollLock },
       
   539         { NSPauseFunctionKey, Qt::Key_Pause },
       
   540         { NSSysReqFunctionKey, Qt::Key_SysReq },
       
   541         { NSMenuFunctionKey, Qt::Key_Menu },
       
   542         { NSHelpFunctionKey, Qt::Key_Help },
       
   543     };
       
   544     static const KeyPair * const end = entries + NumEntries;
       
   545     const KeyPair *i = qBinaryFind(entries, end, keyCode);
       
   546     if (i == end)
       
   547         return Qt::Key(keyCode.unicode());
       
   548     return i->qtKey;
       
   549 }
       
   550 
       
   551 Qt::KeyboardModifiers qt_cocoaModifiers2QtModifiers(ulong modifierFlags)
       
   552 {
       
   553     Qt::KeyboardModifiers qtMods =Qt::NoModifier;
       
   554     if (modifierFlags &  NSShiftKeyMask)
       
   555         qtMods |= Qt::ShiftModifier;
       
   556     if (modifierFlags & NSControlKeyMask)
       
   557         qtMods |= Qt::MetaModifier;
       
   558     if (modifierFlags & NSAlternateKeyMask)
       
   559         qtMods |= Qt::AltModifier;
       
   560     if (modifierFlags & NSCommandKeyMask)
       
   561         qtMods |= Qt::ControlModifier;
       
   562     if (modifierFlags & NSNumericPadKeyMask)
       
   563         qtMods |= Qt::KeypadModifier;
       
   564     return qtMods;
       
   565 }
       
   566 
       
   567 Qt::KeyboardModifiers qt_cocoaDragOperation2QtModifiers(uint dragOperations)
       
   568 {
       
   569     Qt::KeyboardModifiers qtMods =Qt::NoModifier;
       
   570     if (dragOperations &  NSDragOperationLink)
       
   571         qtMods |= Qt::MetaModifier;
       
   572     if (dragOperations & NSDragOperationGeneric)
       
   573         qtMods |= Qt::ControlModifier;
       
   574     if (dragOperations & NSDragOperationCopy)
       
   575         qtMods |= Qt::AltModifier;
       
   576     return qtMods;
       
   577 }
       
   578 
       
   579 static inline QEvent::Type cocoaEvent2QtEvent(NSUInteger eventType)
       
   580 {
       
   581     // Handle the trivial cases that can be determined from the type.
       
   582     switch (eventType) {
       
   583     case NSKeyDown:
       
   584         return QEvent::KeyPress;
       
   585     case NSKeyUp:
       
   586         return QEvent::KeyRelease;
       
   587     case NSLeftMouseDown:
       
   588     case NSRightMouseDown:
       
   589     case NSOtherMouseDown:
       
   590         return QEvent::MouseButtonPress;
       
   591     case NSLeftMouseUp:
       
   592     case NSRightMouseUp:
       
   593     case NSOtherMouseUp:
       
   594         return QEvent::MouseButtonRelease;
       
   595     case NSMouseMoved:
       
   596     case NSLeftMouseDragged:
       
   597     case NSRightMouseDragged:
       
   598     case NSOtherMouseDragged:
       
   599         return QEvent::MouseMove;
       
   600     case NSScrollWheel:
       
   601         return QEvent::Wheel;
       
   602     }
       
   603     return QEvent::None;
       
   604 }
       
   605 
       
   606 static bool mustUseCocoaKeyEvent()
       
   607 {
       
   608     QCFType<TISInputSourceRef> source = TISCopyCurrentKeyboardInputSource();
       
   609     return TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData) == 0;
       
   610 }
       
   611 
       
   612 bool qt_dispatchKeyEventWithCocoa(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent)
       
   613 {
       
   614     NSEvent *event = static_cast<NSEvent *>(keyEvent);
       
   615     NSString *keyChars = [event charactersIgnoringModifiers];
       
   616     int keyLength = [keyChars length];
       
   617     if (keyLength == 0)
       
   618         return false; // Dead Key, nothing to do!
       
   619     bool ignoreText = false;
       
   620     Qt::Key qtKey = Qt::Key_unknown;
       
   621     if (keyLength == 1) {
       
   622         QChar ch([keyChars characterAtIndex:0]);
       
   623         if (ch.isLower())
       
   624             ch = ch.toUpper();
       
   625         qtKey = cocoaKey2QtKey(ch);
       
   626         // Do not set the text for Function-Key Unicodes characters (0xF700–0xF8FF).
       
   627         ignoreText = (ch.unicode() >= 0xF700 && ch.unicode() <= 0xF8FF);
       
   628     }
       
   629     Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]);
       
   630     QString text;
       
   631 
       
   632     // To quote from the Carbon port: This is actually wrong--but it is the best that
       
   633     // can be done for now because of the Control/Meta mapping issues
       
   634     // (we always get text on the Mac)
       
   635     if (!ignoreText && !(keyMods & (Qt::ControlModifier | Qt::MetaModifier)))
       
   636         text = QCFString::toQString(reinterpret_cast<CFStringRef>(keyChars));
       
   637 
       
   638     UInt32 macScanCode = 1;
       
   639     QKeyEventEx ke(cocoaEvent2QtEvent([event type]), qtKey, keyMods, text, [event isARepeat], qMax(1, keyLength),
       
   640                    macScanCode, [event keyCode], [event modifierFlags]);
       
   641     qt_sendSpontaneousEvent(widgetToGetEvent, &ke);
       
   642     return ke.isAccepted();
       
   643 }
       
   644 #endif
       
   645 
       
   646 // Helper to share code between QCocoaWindow and QCocoaView
       
   647 bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent)
       
   648 {
       
   649 #ifndef QT_MAC_USE_COCOA
       
   650     Q_UNUSED(keyEvent);
       
   651     Q_UNUSED(widgetToGetEvent);
       
   652     return false;
       
   653 #else
       
   654     NSEvent *event = static_cast<NSEvent *>(keyEvent);
       
   655     EventRef key_event = static_cast<EventRef>(const_cast<void *>([event eventRef]));
       
   656     Q_ASSERT(key_event);
       
   657     if ([event type] == NSKeyDown) {
       
   658         qt_keymapper_private()->updateKeyMap(0, key_event, 0);
       
   659     }
       
   660     if (widgetToGetEvent == 0)
       
   661         return false;
       
   662 
       
   663     if (qt_mac_sendMacEventToWidget(widgetToGetEvent, key_event))
       
   664         return true;
       
   665 
       
   666     if (mustUseCocoaKeyEvent())
       
   667         return qt_dispatchKeyEventWithCocoa(keyEvent, widgetToGetEvent);
       
   668     bool isAccepted;
       
   669     qt_keymapper_private()->translateKeyEvent(widgetToGetEvent, 0, key_event, &isAccepted, true);
       
   670     return isAccepted;
       
   671 #endif
       
   672 }
       
   673 
       
   674 void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget *widgetToGetEvent)
       
   675 {
       
   676 #ifndef QT_MAC_USE_COCOA
       
   677     Q_UNUSED(flagsChangedEvent);
       
   678     Q_UNUSED(widgetToGetEvent);
       
   679 #else
       
   680     UInt32 modifiers = 0;
       
   681     // Sync modifiers with Qt
       
   682     NSEvent *event = static_cast<NSEvent *>(flagsChangedEvent);
       
   683     EventRef key_event = static_cast<EventRef>(const_cast<void *>([event eventRef]));
       
   684     Q_ASSERT(key_event);
       
   685     GetEventParameter(key_event, kEventParamKeyModifiers, typeUInt32, 0,
       
   686                       sizeof(modifiers), 0, &modifiers);
       
   687     extern void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object);
       
   688     qt_mac_send_modifiers_changed(modifiers, widgetToGetEvent);
       
   689 #endif
       
   690 }
       
   691 
       
   692 
       
   693 QPointF flipPoint(const NSPoint &p)
       
   694 {
       
   695     return QPointF(p.x, flipYCoordinate(p.y));
       
   696 }
       
   697 
       
   698 NSPoint flipPoint(const QPoint &p)
       
   699 {
       
   700     return NSMakePoint(p.x(), flipYCoordinate(p.y()));
       
   701 }
       
   702 
       
   703 NSPoint flipPoint(const QPointF &p)
       
   704 {
       
   705     return NSMakePoint(p.x(), flipYCoordinate(p.y()));
       
   706 }
       
   707 
       
   708 void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /* NSEvent* */mouseEvent,
       
   709                                    QWidget *widgetToGetEvent, bool &leftButtonIsRightButton)
       
   710 {
       
   711 #ifndef QT_MAC_USE_COCOA
       
   712     Q_UNUSED(eventWindow);
       
   713     Q_UNUSED(mouseEvent);
       
   714     Q_UNUSED(widgetToGetEvent);
       
   715     Q_UNUSED(leftButtonIsRightButton);
       
   716 #else
       
   717     if (widgetToGetEvent == 0)
       
   718         return;
       
   719     NSWindow *window = static_cast<NSWindow *>(eventWindow);
       
   720     NSEvent *event = static_cast<NSEvent *>(mouseEvent);
       
   721     NSEventType evtType = [event type];
       
   722 
       
   723     QPoint qlocalPoint;
       
   724     QPoint qglobalPoint;
       
   725     bool processThisEvent = false;
       
   726     bool fakeNCEvents = false;
       
   727     bool fakeMouseEvents = false;
       
   728 
       
   729     // Check if this is a mouse event.
       
   730     if (evtType == NSLeftMouseDown || evtType == NSLeftMouseUp
       
   731         || evtType == NSRightMouseDown || evtType == NSRightMouseUp
       
   732         || evtType == NSOtherMouseDown || evtType == NSOtherMouseUp
       
   733         || evtType == NSMouseMoved     || evtType == NSLeftMouseDragged
       
   734         || evtType == NSRightMouseDragged || evtType == NSOtherMouseDragged) {
       
   735         // Check if we want to pass this message to another window
       
   736         if (mac_mouse_grabber  && mac_mouse_grabber != widgetToGetEvent) {
       
   737             NSWindow *grabWindow = static_cast<NSWindow *>(qt_mac_window_for(mac_mouse_grabber));
       
   738             if (window != grabWindow) {
       
   739                 window = grabWindow;
       
   740                 widgetToGetEvent = mac_mouse_grabber;
       
   741                 fakeNCEvents = true;
       
   742             }
       
   743         }
       
   744         // Dont generate normal NC mouse events for Left Button dragged
       
   745         if(evtType != NSLeftMouseDragged || fakeNCEvents) {
       
   746             NSPoint windowPoint = [event locationInWindow];
       
   747             NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
       
   748             NSRect frameRect = [window frame];
       
   749             if (fakeNCEvents || NSMouseInRect(globalPoint, frameRect, NO)) {
       
   750                 NSRect contentRect = [window contentRectForFrameRect:frameRect];
       
   751                 if (fakeNCEvents || !NSMouseInRect(globalPoint, contentRect, NO)) {
       
   752                     qglobalPoint = QPoint(flipPoint(globalPoint).toPoint());
       
   753                     qlocalPoint = widgetToGetEvent->mapFromGlobal(qglobalPoint);
       
   754                     processThisEvent = true;
       
   755                 }
       
   756             }
       
   757         }
       
   758     }
       
   759     // This is not an NC area mouse message.
       
   760     if (!processThisEvent)
       
   761         return;
       
   762     // If the window is frame less, generate fake mouse events instead. (floating QToolBar)
       
   763     if (fakeNCEvents && (widgetToGetEvent->window()->windowFlags() & Qt::FramelessWindowHint))
       
   764         fakeMouseEvents = true;
       
   765 
       
   766     Qt::MouseButton button;
       
   767     QEvent::Type eventType;
       
   768     // Convert to Qt::Event type
       
   769     switch (evtType) {
       
   770         case NSLeftMouseDown:
       
   771             button = Qt::LeftButton;
       
   772             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonPress
       
   773                                            : QEvent::MouseButtonPress;
       
   774             break;
       
   775         case NSLeftMouseUp:
       
   776             button = Qt::LeftButton;
       
   777             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonRelease
       
   778                                            : QEvent::MouseButtonRelease;
       
   779             break;
       
   780         case NSRightMouseDown:
       
   781             button = Qt::RightButton;
       
   782             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonPress
       
   783                                            : QEvent::MouseButtonPress;
       
   784             break;
       
   785         case NSRightMouseUp:
       
   786             button = Qt::RightButton;
       
   787             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonRelease
       
   788                                            : QEvent::MouseButtonRelease;
       
   789             break;
       
   790         case NSOtherMouseDown:
       
   791             button = cocoaButton2QtButton([event buttonNumber]);
       
   792             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonPress
       
   793                                            : QEvent::MouseButtonPress;
       
   794             break;
       
   795         case NSOtherMouseUp:
       
   796             button = cocoaButton2QtButton([event buttonNumber]);
       
   797             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonRelease
       
   798                                            : QEvent::MouseButtonRelease;
       
   799             break;
       
   800         case NSMouseMoved:
       
   801             button = Qt::NoButton;
       
   802             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
       
   803                                            : QEvent::MouseMove;
       
   804             break;
       
   805         case NSLeftMouseDragged:
       
   806             button = Qt::LeftButton;
       
   807             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
       
   808                                            : QEvent::MouseMove;
       
   809             break;
       
   810         case NSRightMouseDragged:
       
   811             button = Qt::RightButton;
       
   812             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
       
   813                                            : QEvent::MouseMove;
       
   814             break;
       
   815         case NSOtherMouseDragged:
       
   816             button = cocoaButton2QtButton([event buttonNumber]);
       
   817             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseMove
       
   818                                            : QEvent::MouseMove;
       
   819             break;
       
   820         default:
       
   821             qWarning("not handled! Non client area mouse message");
       
   822             return;
       
   823     }
       
   824 
       
   825     Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]);
       
   826     if (eventType == QEvent::NonClientAreaMouseButtonPress || eventType == QEvent::MouseButtonPress) {
       
   827         NSInteger clickCount = [event clickCount];
       
   828         if (clickCount % 2 == 0)
       
   829             eventType = (!fakeMouseEvents) ? QEvent::NonClientAreaMouseButtonDblClick
       
   830                                            : QEvent::MouseButtonDblClick;
       
   831         if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) {
       
   832             button = Qt::RightButton;
       
   833             leftButtonIsRightButton = true;
       
   834         }
       
   835     } else if (eventType == QEvent::NonClientAreaMouseButtonRelease || eventType == QEvent::MouseButtonRelease) {
       
   836         if (button == Qt::LeftButton && leftButtonIsRightButton) {
       
   837             button = Qt::RightButton;
       
   838             leftButtonIsRightButton = false;
       
   839         }
       
   840     }
       
   841     QMouseEvent qme(eventType, qlocalPoint, qglobalPoint, button, button, keyMods);
       
   842     qt_sendSpontaneousEvent(widgetToGetEvent, &qme);
       
   843 #endif
       
   844 }
       
   845 
       
   846 bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */event, QEvent::Type eventType, Qt::MouseButton button)
       
   847 {
       
   848 #ifndef QT_MAC_USE_COCOA
       
   849     Q_UNUSED(view);
       
   850     Q_UNUSED(event);
       
   851     Q_UNUSED(eventType);
       
   852     Q_UNUSED(button);
       
   853     return false;
       
   854 #else
       
   855     QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
       
   856     NSEvent *theEvent = static_cast<NSEvent *>(event);
       
   857 
       
   858     // Give the Input Manager a chance to process the mouse events.
       
   859    NSInputManager *currentIManager = [NSInputManager currentInputManager];
       
   860    if (currentIManager && [currentIManager wantsToHandleMouseEvents]) {
       
   861         [currentIManager handleMouseEvent:theEvent];
       
   862    }
       
   863 
       
   864     // Handle tablet events (if any) first.
       
   865     if (qt_mac_handleTabletEvent(theView, theEvent)) {
       
   866         // Tablet event was handled. In Qt we aren't supposed to send the mouse event.
       
   867         return true;
       
   868     }
       
   869 
       
   870     NSPoint windowPoint = [theEvent locationInWindow];
       
   871     NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint];
       
   872 
       
   873     // Find the widget that *should* get the event (e.g., maybe it was a pop-up,
       
   874     // they always get the mouse event).
       
   875     QWidget *qwidget = [theView qt_qwidget];
       
   876     QWidget *widgetToGetMouse = qwidget;
       
   877     QWidget *popup = qAppInstance()->activePopupWidget();
       
   878     NSView *tmpView = theView;
       
   879     if (mac_mouse_grabber  && mac_mouse_grabber != widgetToGetMouse) {
       
   880         widgetToGetMouse = mac_mouse_grabber;
       
   881         tmpView = qt_mac_nativeview_for(widgetToGetMouse);
       
   882     }
       
   883 
       
   884     if (popup && popup != qwidget->window()) {
       
   885         widgetToGetMouse = popup;
       
   886         tmpView = qt_mac_nativeview_for(popup);
       
   887         windowPoint = [[tmpView window] convertScreenToBase:globalPoint];
       
   888 
       
   889         QPoint qWindowPoint(windowPoint.x, windowPoint.y);
       
   890         if (widgetToGetMouse->rect().contains(qWindowPoint)) {
       
   891             // Keeping the mouse pressed on a combobox button will make
       
   892             // the popup pop in front of the mouse. But all mouse events
       
   893             // will be sendt to the button. Since we want mouse events
       
   894             // to be sendt to widgets inside the popup, we search for the
       
   895             // widget in front of the mouse:
       
   896             tmpView = [tmpView hitTest:windowPoint];
       
   897             if (!tmpView)
       
   898                 return false;
       
   899             widgetToGetMouse =
       
   900                 [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(tmpView) qt_qwidget];
       
   901         }
       
   902     }
       
   903 
       
   904     NSPoint localPoint = [tmpView convertPoint:windowPoint fromView:nil];
       
   905     QPoint qlocalPoint(localPoint.x, localPoint.y);
       
   906 
       
   907     EventRef carbonEvent = static_cast<EventRef>(const_cast<void *>([theEvent eventRef]));
       
   908     if (qt_mac_sendMacEventToWidget(widgetToGetMouse, carbonEvent))
       
   909         return true;
       
   910 
       
   911     // Yay! All the special cases are handled, it really is just a normal mouse event.
       
   912     Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]);
       
   913     NSInteger clickCount = [theEvent clickCount];
       
   914     Qt::MouseButtons buttons = 0;
       
   915     {
       
   916         UInt32 mac_buttons;
       
   917         if (GetEventParameter(carbonEvent, kEventParamMouseChord, typeUInt32, 0,
       
   918                               sizeof(mac_buttons), 0, &mac_buttons) == noErr)
       
   919             buttons = qt_mac_get_buttons(mac_buttons);
       
   920     }
       
   921     switch (eventType) {
       
   922     default:
       
   923         qWarning("not handled! %d", eventType);
       
   924         break;
       
   925     case QEvent::MouseMove:
       
   926         break;
       
   927     case QEvent::MouseButtonPress:
       
   928         [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->view = theView;
       
   929         [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->theEvent = theEvent;
       
   930 #ifndef QT_NAMESPACE
       
   931         Q_ASSERT(clickCount > 0);
       
   932 #endif
       
   933         if (clickCount % 2 == 0)
       
   934             eventType = QEvent::MouseButtonDblClick;
       
   935         if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) {
       
   936             button = Qt::RightButton;
       
   937             [theView qt_setLeftButtonIsRightButton: true];
       
   938         }
       
   939         break;
       
   940     case QEvent::MouseButtonRelease:
       
   941         if (button == Qt::LeftButton && [theView qt_leftButtonIsRightButton]) {
       
   942             button = Qt::RightButton;
       
   943             [theView qt_setLeftButtonIsRightButton: false];
       
   944         }
       
   945         break;
       
   946     }
       
   947     [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->localPoint = localPoint;
       
   948     QPoint qglobalPoint(flipPoint(globalPoint).toPoint());
       
   949     QMouseEvent qme(eventType, qlocalPoint, qglobalPoint, button, buttons, keyMods);
       
   950     qt_sendSpontaneousEvent(widgetToGetMouse, &qme);
       
   951     if (eventType == QEvent::MouseButtonPress && button == Qt::RightButton) {
       
   952         QContextMenuEvent qcme(QContextMenuEvent::Mouse, qlocalPoint, qglobalPoint, keyMods);
       
   953         qt_sendSpontaneousEvent(widgetToGetMouse, &qcme);
       
   954     }
       
   955     return qme.isAccepted();
       
   956 #endif
       
   957 }
       
   958 
       
   959 bool qt_mac_handleTabletEvent(void * /*QCocoaView * */view, void * /*NSEvent * */tabletEvent)
       
   960 {
       
   961 #ifndef QT_MAC_USE_COCOA
       
   962     Q_UNUSED(view);
       
   963     Q_UNUSED(tabletEvent);
       
   964     return false;
       
   965 #else
       
   966     QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
       
   967     NSView *theNSView = static_cast<NSView *>(view);
       
   968     NSEvent *theTabletEvent = static_cast<NSEvent *>(tabletEvent);
       
   969 
       
   970     NSEventType eventType = [theTabletEvent type];
       
   971     if (eventType != NSTabletPoint && [theTabletEvent subtype] != NSTabletPointEventSubtype)
       
   972         return false; // Not a tablet event.
       
   973 
       
   974     NSPoint windowPoint = [theTabletEvent locationInWindow];
       
   975     NSPoint globalPoint = [[theTabletEvent window] convertBaseToScreen:windowPoint];
       
   976 
       
   977     QWidget *qwidget = [theView qt_qwidget];
       
   978     QWidget *widgetToGetMouse = qwidget;
       
   979     QWidget *popup = qAppInstance()->activePopupWidget();
       
   980     if (popup && popup != qwidget->window())
       
   981         widgetToGetMouse = popup;
       
   982 
       
   983     if (qt_mac_sendMacEventToWidget(widgetToGetMouse,
       
   984                                 static_cast<EventRef>(const_cast<void *>([theTabletEvent eventRef]))))
       
   985         return true;
       
   986     if (widgetToGetMouse != qwidget) {
       
   987         theNSView = qt_mac_nativeview_for(widgetToGetMouse);
       
   988         windowPoint = [[theNSView window] convertScreenToBase:globalPoint];
       
   989     }
       
   990     NSPoint localPoint = [theNSView convertPoint:windowPoint fromView:nil];
       
   991     // Tablet events do not handle WA_TransparentForMouseEvents ATM
       
   992     // In theory, people who set the WA_TransparentForMouseEvents attribute won't handle
       
   993     // tablet events either in which case they will fall into the mouse event case and get
       
   994     // them passed on. This will NOT handle the raw events, but that might not be a big problem.
       
   995 
       
   996     const QMacTabletHash *tabletHash = qt_mac_tablet_hash();
       
   997     if (!tabletHash->contains([theTabletEvent deviceID])) {
       
   998         qWarning("QCocoaView handleTabletEvent: This tablet device is unknown"
       
   999                  " (received no proximity event for it). Discarding event.");
       
  1000         return false;
       
  1001     }
       
  1002     const QTabletDeviceData &deviceData = tabletHash->value([theTabletEvent deviceID]);
       
  1003 
       
  1004 
       
  1005     QEvent::Type qType;
       
  1006     switch (eventType) {
       
  1007     case NSLeftMouseDown:
       
  1008     case NSRightMouseDown:
       
  1009         qType = QEvent::TabletPress;
       
  1010         break;
       
  1011     case NSLeftMouseUp:
       
  1012     case NSRightMouseUp:
       
  1013         qType = QEvent::TabletRelease;
       
  1014         break;
       
  1015     case NSMouseMoved:
       
  1016     case NSTabletPoint:
       
  1017     case NSLeftMouseDragged:
       
  1018     case NSRightMouseDragged:
       
  1019     default:
       
  1020         qType = QEvent::TabletMove;
       
  1021         break;
       
  1022     }
       
  1023 
       
  1024     qreal pressure;
       
  1025     if (eventType != NSMouseMoved) {
       
  1026         pressure = [theTabletEvent pressure];
       
  1027     } else {
       
  1028         pressure = 0.0;
       
  1029     }
       
  1030 
       
  1031     NSPoint tilt = [theTabletEvent tilt];
       
  1032     int xTilt = qRound(tilt.x * 60.0);
       
  1033     int yTilt = qRound(tilt.y * -60.0);
       
  1034     qreal tangentialPressure = 0;
       
  1035     qreal rotation = 0;
       
  1036     int z = 0;
       
  1037     if (deviceData.capabilityMask & 0x0200)
       
  1038         z = [theTabletEvent absoluteZ];
       
  1039 
       
  1040     if (deviceData.capabilityMask & 0x0800)
       
  1041         tangentialPressure = [theTabletEvent tangentialPressure];
       
  1042 
       
  1043     rotation = [theTabletEvent rotation];
       
  1044     QPointF hiRes = flipPoint(globalPoint);
       
  1045     QTabletEvent qtabletEvent(qType, QPoint(localPoint.x, localPoint.y),
       
  1046                               hiRes.toPoint(), hiRes,
       
  1047                               deviceData.tabletDeviceType, deviceData.tabletPointerType,
       
  1048                               pressure, xTilt, yTilt, tangentialPressure, rotation, z,
       
  1049                               qt_cocoaModifiers2QtModifiers([theTabletEvent modifierFlags]),
       
  1050                               deviceData.tabletUniqueID);
       
  1051 
       
  1052     qt_sendSpontaneousEvent(widgetToGetMouse, &qtabletEvent);
       
  1053     return qtabletEvent.isAccepted();
       
  1054 #endif
       
  1055 }
       
  1056 
       
  1057 void qt_mac_updateContentBorderMetricts(void * /*OSWindowRef */window, const ::HIContentBorderMetrics &metrics)
       
  1058 {
       
  1059     OSWindowRef theWindow = static_cast<OSWindowRef>(window);
       
  1060 #if !defined(QT_MAC_USE_COCOA)
       
  1061 #  if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
       
  1062     if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
       
  1063         ::HIWindowSetContentBorderThickness(theWindow, &metrics);
       
  1064     }
       
  1065 #  else
       
  1066     Q_UNUSED(window);
       
  1067     Q_UNUSED(metrics);
       
  1068 #  endif
       
  1069 #else
       
  1070     if ([theWindow styleMask] & NSTexturedBackgroundWindowMask)
       
  1071         [theWindow setContentBorderThickness:metrics.top forEdge:NSMaxYEdge];
       
  1072     [theWindow setContentBorderThickness:metrics.bottom forEdge:NSMinYEdge];
       
  1073 #endif
       
  1074 }
       
  1075 
       
  1076 void qt_mac_showBaseLineSeparator(void * /*OSWindowRef */window, bool show)
       
  1077 {
       
  1078 #if QT_MAC_USE_COCOA
       
  1079     QMacCocoaAutoReleasePool pool;
       
  1080     OSWindowRef theWindow = static_cast<OSWindowRef>(window);
       
  1081     NSToolbar *macToolbar = [theWindow toolbar];
       
  1082     if (macToolbar)
       
  1083         [macToolbar setShowsBaselineSeparator: show];
       
  1084 #endif
       
  1085 }
       
  1086 
       
  1087 QStringList qt_mac_NSArrayToQStringList(void *nsarray)
       
  1088 {
       
  1089     QStringList result;
       
  1090     NSArray *array = static_cast<NSArray *>(nsarray);
       
  1091     for (NSUInteger i=0; i<[array count]; ++i)
       
  1092         result << qt_mac_NSStringToQString([array objectAtIndex:i]);
       
  1093     return result;
       
  1094 }
       
  1095 
       
  1096 void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list)
       
  1097 {
       
  1098     NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()];
       
  1099     for (int i=0; i<list.size(); ++i){
       
  1100         [result addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(list[i]))];
       
  1101     }
       
  1102     return result;
       
  1103 }
       
  1104 
       
  1105 void qt_syncCocoaTitleBarButtons(OSWindowRef window, QWidget *widgetForWindow)
       
  1106 {
       
  1107     if (!widgetForWindow)
       
  1108         return;
       
  1109 
       
  1110     Qt::WindowFlags flags = widgetForWindow->windowFlags();
       
  1111     bool customize = flags & Qt::CustomizeWindowHint;
       
  1112 
       
  1113     NSButton *btn = [window standardWindowButton:NSWindowZoomButton];
       
  1114     // BOOL is not an int, so the bitwise AND doesn't work.
       
  1115     bool go = uint(customize && !(flags & Qt::WindowMaximizeButtonHint)) == 0;
       
  1116     [btn setEnabled:go];
       
  1117 
       
  1118     btn = [window standardWindowButton:NSWindowMiniaturizeButton];
       
  1119     go = uint(customize && !(flags & Qt::WindowMinimizeButtonHint)) == 0;
       
  1120     [btn setEnabled:go];
       
  1121 
       
  1122     btn = [window standardWindowButton:NSWindowCloseButton];
       
  1123     go = uint(customize && !(flags & Qt::WindowSystemMenuHint
       
  1124                              || flags & Qt::WindowCloseButtonHint)) == 0;
       
  1125     [btn setEnabled:go];
       
  1126 
       
  1127     [window setShowsToolbarButton:uint(flags & Qt::MacWindowToolBarButtonHint) != 0];
       
  1128 }
       
  1129 
       
  1130 // Carbon: Make sure you call QDEndContext on the context when done with it.
       
  1131 CGContextRef qt_mac_graphicsContextFor(QWidget *widget)
       
  1132 {
       
  1133     if (!widget)
       
  1134         return 0;
       
  1135 
       
  1136 #ifndef QT_MAC_USE_COCOA
       
  1137     CGContextRef context;
       
  1138     CGrafPtr port = GetWindowPort(qt_mac_window_for(widget));
       
  1139     QDBeginCGContext(port, &context);
       
  1140 #else
       
  1141     CGContextRef context = (CGContextRef)[[NSGraphicsContext graphicsContextWithWindow:qt_mac_window_for(widget)] graphicsPort];
       
  1142 #endif
       
  1143     return context;
       
  1144 }
       
  1145 
       
  1146 CGFloat qt_mac_get_scalefactor()
       
  1147 {
       
  1148 #ifndef QT_MAC_USE_COCOA
       
  1149     return HIGetScaleFactor();
       
  1150 #else
       
  1151     return [[NSScreen mainScreen] userSpaceScaleFactor];
       
  1152 #endif
       
  1153 }
       
  1154 
       
  1155 QString qt_mac_get_pasteboardString()
       
  1156 {
       
  1157     QMacCocoaAutoReleasePool pool;
       
  1158     NSPasteboard *pb = [NSPasteboard generalPasteboard];
       
  1159     NSString *text = [pb stringForType:NSStringPboardType];
       
  1160     if (text) {
       
  1161         return qt_mac_NSStringToQString(text);
       
  1162     } else {
       
  1163         return QString();
       
  1164     }
       
  1165 }
       
  1166 
       
  1167 QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height)
       
  1168 {
       
  1169     QPixmap ret(width, height);
       
  1170     ret.fill(QColor(0, 0, 0, 0));
       
  1171 
       
  1172     CGRect rect = CGRectMake(0, 0, width, height);
       
  1173 
       
  1174     CGContextRef ctx = qt_mac_cg_context(&ret);
       
  1175     CGAffineTransform old_xform = CGContextGetCTM(ctx);
       
  1176     CGContextConcatCTM(ctx, CGAffineTransformInvert(old_xform));
       
  1177     CGContextConcatCTM(ctx, CGAffineTransformIdentity);
       
  1178 
       
  1179     ::RGBColor b;
       
  1180     b.blue = b.green = b.red = 255*255;
       
  1181     PlotIconRefInContext(ctx, &rect, kAlignNone, kTransformNone, &b, kPlotIconRefNormalFlags, icon);
       
  1182     CGContextRelease(ctx);
       
  1183     return ret;
       
  1184 }
       
  1185 
       
  1186 void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon, QStyle::StandardPixmap standardIcon)
       
  1187 {
       
  1188     int size = 16;
       
  1189     while (size <= 128) {
       
  1190 
       
  1191         const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size);
       
  1192         QPixmap mainIcon;
       
  1193         if (standardIcon >= QStyle::SP_CustomBase) {
       
  1194             mainIcon = qt_mac_convert_iconref(icon, size, size);
       
  1195         } else if (QPixmapCache::find(cacheKey, mainIcon) == false) {
       
  1196             mainIcon = qt_mac_convert_iconref(icon, size, size);
       
  1197             QPixmapCache::insert(cacheKey, mainIcon);
       
  1198         }
       
  1199 
       
  1200         if (overlayIcon) {
       
  1201             int littleSize = size / 2;
       
  1202             QPixmap overlayPix = qt_mac_convert_iconref(overlayIcon, littleSize, littleSize);
       
  1203             QPainter painter(&mainIcon);
       
  1204             painter.drawPixmap(size - littleSize, size - littleSize, overlayPix);
       
  1205         }
       
  1206 
       
  1207         retIcon->addPixmap(mainIcon);
       
  1208         size += size;  // 16 -> 32 -> 64 -> 128
       
  1209     }
       
  1210 }
       
  1211 
       
  1212 void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse)
       
  1213 {
       
  1214     OSMenuRef menu = static_cast<OSMenuRef>(theMenu);
       
  1215     if (collapse) {
       
  1216         bool previousIsSeparator = true; // setting to true kills all the separators placed at the top.
       
  1217         NSMenuItem *previousItem = nil;
       
  1218             
       
  1219         NSArray *itemArray = [menu itemArray];
       
  1220         for (unsigned int i = 0; i < [itemArray count]; ++i) {
       
  1221             NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
       
  1222             if ([item isSeparatorItem]) {
       
  1223                 [item setHidden:previousIsSeparator];
       
  1224             }
       
  1225 
       
  1226             if (![item isHidden]) {
       
  1227                 previousItem = item;
       
  1228                 previousIsSeparator = ([previousItem isSeparatorItem]);
       
  1229             }
       
  1230         }
       
  1231 
       
  1232         // We now need to check the final item since we don't want any separators at the end of the list.
       
  1233         if (previousItem && previousIsSeparator)
       
  1234             [previousItem setHidden:YES];
       
  1235     } else {
       
  1236         NSArray *itemArray = [menu itemArray];
       
  1237         for (unsigned int i = 0; i < [itemArray count]; ++i) {
       
  1238             NSMenuItem *item = reinterpret_cast<NSMenuItem *>([itemArray objectAtIndex:i]);
       
  1239             if (QAction *action = reinterpret_cast<QAction *>([item tag]))
       
  1240                 [item setHidden:!action->isVisible()];
       
  1241         }
       
  1242     }
       
  1243 }
       
  1244 
       
  1245 #ifdef QT_MAC_USE_COCOA
       
  1246 void qt_cocoaChangeOverrideCursor(const QCursor &cursor)
       
  1247 {
       
  1248     QMacCocoaAutoReleasePool pool;
       
  1249     [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) set];
       
  1250 }
       
  1251 #endif
       
  1252 
       
  1253 QT_END_NAMESPACE