src/gui/kernel/qapplication_mac.mm
changeset 30 5dc02b23752f
parent 18 2f34d5167611
child 37 758a864f9613
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
   182 extern bool qt_tab_all_widgets;         // from qapplication.cpp
   182 extern bool qt_tab_all_widgets;         // from qapplication.cpp
   183 bool qt_mac_app_fullscreen = false;
   183 bool qt_mac_app_fullscreen = false;
   184 bool qt_scrollbar_jump_to_pos = false;
   184 bool qt_scrollbar_jump_to_pos = false;
   185 static bool qt_mac_collapse_on_dblclick = true;
   185 static bool qt_mac_collapse_on_dblclick = true;
   186 extern int qt_antialiasing_threshold; // from qapplication.cpp
   186 extern int qt_antialiasing_threshold; // from qapplication.cpp
   187 QPointer<QWidget> qt_button_down;                // widget got last button-down
   187 QWidget * qt_button_down;                // widget got last button-down
       
   188 QPointer<QWidget> qt_last_mouse_receiver;
   188 #ifndef QT_MAC_USE_COCOA
   189 #ifndef QT_MAC_USE_COCOA
   189 static bool qt_button_down_in_content; // whether the button_down was in the content area.
   190 static bool qt_button_down_in_content; // whether the button_down was in the content area.
   190 static bool qt_mac_previous_press_in_popup_mode = false;
   191 static bool qt_mac_previous_press_in_popup_mode = false;
   191 static bool qt_mac_no_click_through_mode = false;
   192 static bool qt_mac_no_click_through_mode = false;
   192 static int tablet_button_state = 0;
   193 static int tablet_button_state = 0;
  1218             app_proc_handlerUPP = NewEventHandlerUPP(QApplicationPrivate::globalEventProcessor);
  1219             app_proc_handlerUPP = NewEventHandlerUPP(QApplicationPrivate::globalEventProcessor);
  1219             qt_init_app_proc_handler();
  1220             qt_init_app_proc_handler();
  1220         }
  1221         }
  1221 
  1222 
  1222 #endif
  1223 #endif
  1223         if (!app_proc_ae_handlerUPP) {
  1224         if (!app_proc_ae_handlerUPP && !QApplication::testAttribute(Qt::AA_MacPluginApplication)) {
  1224             app_proc_ae_handlerUPP = AEEventHandlerUPP(QApplicationPrivate::globalAppleEventProcessor);
  1225             app_proc_ae_handlerUPP = AEEventHandlerUPP(QApplicationPrivate::globalAppleEventProcessor);
  1225             for(uint i = 0; i < sizeof(app_apple_events) / sizeof(QMacAppleEventTypeSpec); ++i)
  1226             for(uint i = 0; i < sizeof(app_apple_events) / sizeof(QMacAppleEventTypeSpec); ++i) {
  1226                 AEInstallEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id,
  1227                 // Install apple event handler, but avoid overwriting an already
  1227                         app_proc_ae_handlerUPP, SRefCon(qApp), false);
  1228                 // existing handler (it means a 3rd party application has installed one):
       
  1229                 SRefCon refCon = 0;
       
  1230                 AEEventHandlerUPP current_handler = NULL;
       
  1231                 AEGetEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id, &current_handler, &refCon, false);
       
  1232                 if (!current_handler)
       
  1233                     AEInstallEventHandler(app_apple_events[i].mac_class, app_apple_events[i].mac_id,
       
  1234                             app_proc_ae_handlerUPP, SRefCon(qApp), false);
       
  1235             }
  1228         }
  1236         }
  1229 
  1237 
  1230         if (QApplicationPrivate::app_style) {
  1238         if (QApplicationPrivate::app_style) {
  1231             QEvent ev(QEvent::Style);
  1239             QEvent ev(QEvent::Style);
  1232             qt_sendSpontaneousEvent(QApplicationPrivate::app_style, &ev);
  1240             qt_sendSpontaneousEvent(QApplicationPrivate::app_style, &ev);
  1235     if (QApplication::desktopSettingsAware())
  1243     if (QApplication::desktopSettingsAware())
  1236         QApplicationPrivate::qt_mac_apply_settings();
  1244         QApplicationPrivate::qt_mac_apply_settings();
  1237 
  1245 
  1238     // Cocoa application delegate
  1246     // Cocoa application delegate
  1239 #ifdef QT_MAC_USE_COCOA
  1247 #ifdef QT_MAC_USE_COCOA
  1240     NSApplication *cocoaApp = [NSApplication sharedApplication];
  1248     NSApplication *cocoaApp = [QNSApplication sharedApplication];
  1241     QMacCocoaAutoReleasePool pool;
  1249     QMacCocoaAutoReleasePool pool;
  1242     NSObject *oldDelegate = [cocoaApp delegate];
  1250     NSObject *oldDelegate = [cocoaApp delegate];
  1243     QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
  1251     QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
  1244     Q_ASSERT(newDelegate);
  1252     Q_ASSERT(newDelegate);
  1245     [newDelegate setQtPrivate:priv];
  1253     [newDelegate setQtPrivate:priv];
  1256         }
  1264         }
  1257 
  1265 
  1258         [cocoaApp setMenu:[qtMenuLoader menu]];
  1266         [cocoaApp setMenu:[qtMenuLoader menu]];
  1259         [newDelegate setMenuLoader:qtMenuLoader];
  1267         [newDelegate setMenuLoader:qtMenuLoader];
  1260         [qtMenuLoader release];
  1268         [qtMenuLoader release];
  1261 
       
  1262         NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
       
  1263         [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:)
       
  1264           forEventClass:kInternetEventClass andEventID:kAEGetURL];
       
  1265     }
  1269     }
  1266 #endif
  1270 #endif
  1267     // Register for Carbon tablet proximity events on the event monitor target.
  1271     // Register for Carbon tablet proximity events on the event monitor target.
  1268     // This means that we should receive proximity events even when we aren't the active application.
  1272     // This means that we should receive proximity events even when we aren't the active application.
  1269     if (!tablet_proximity_handler) {
  1273     if (!tablet_proximity_handler) {
  1359 #ifndef QT_NO_CURSOR
  1363 #ifndef QT_NO_CURSOR
  1360 
  1364 
  1361 /*****************************************************************************
  1365 /*****************************************************************************
  1362   QApplication cursor stack
  1366   QApplication cursor stack
  1363  *****************************************************************************/
  1367  *****************************************************************************/
       
  1368 #ifdef QT_MAC_USE_COCOA
       
  1369 void QApplicationPrivate::disableUsageOfCursorRects(bool disable)
       
  1370 {
       
  1371     // In Cocoa there are two competing ways of setting the cursor; either
       
  1372     // by using cursor rects (see qcocoaview_mac.mm), or by pushing/popping
       
  1373     // the cursor manually. When we use override cursors, it makes most sense
       
  1374     // to use the latter. But then we need to tell cocoa to stop using the
       
  1375     // first approach so it doesn't change the cursor back when hovering over
       
  1376     // a cursor rect:
       
  1377     QWidgetList topLevels = qApp->topLevelWidgets();
       
  1378     for (int i=0; i<topLevels.size(); ++i) {
       
  1379         if (NSWindow *window = qt_mac_window_for(topLevels.at(i)))
       
  1380             disable ? [window disableCursorRects] : [window enableCursorRects];
       
  1381     }
       
  1382 }
       
  1383 
       
  1384 void QApplicationPrivate::updateOverrideCursor()
       
  1385 {
       
  1386     // Sometimes Cocoa forgets that we have set a Cursor
       
  1387     // manually. In those cases, remind it again:
       
  1388     if (QCursor *override = qApp->overrideCursor())
       
  1389         [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*override)) set];
       
  1390 }
       
  1391 #endif
       
  1392 
  1364 void QApplication::setOverrideCursor(const QCursor &cursor)
  1393 void QApplication::setOverrideCursor(const QCursor &cursor)
  1365 {
  1394 {
  1366     qApp->d_func()->cursor_list.prepend(cursor);
  1395     qApp->d_func()->cursor_list.prepend(cursor);
  1367 
  1396 
  1368 #ifdef QT_MAC_USE_COCOA
  1397 #ifdef QT_MAC_USE_COCOA
  1369     QMacCocoaAutoReleasePool pool;
  1398     QMacCocoaAutoReleasePool pool;
       
  1399     if (qApp->d_func()->cursor_list.size() == 1)
       
  1400         qApp->d_func()->disableUsageOfCursorRects(true);
  1370     [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
  1401     [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
  1371 #else
  1402 #else
  1372     if (qApp && qApp->activeWindow())
  1403     if (qApp && qApp->activeWindow())
  1373         qt_mac_set_cursor(&qApp->d_func()->cursor_list.first(), QCursor::pos());
  1404         qt_mac_set_cursor(&qApp->d_func()->cursor_list.first(), QCursor::pos());
  1374 #endif
  1405 #endif
  1381     qApp->d_func()->cursor_list.removeFirst();
  1412     qApp->d_func()->cursor_list.removeFirst();
  1382 
  1413 
  1383 #ifdef QT_MAC_USE_COCOA
  1414 #ifdef QT_MAC_USE_COCOA
  1384     QMacCocoaAutoReleasePool pool;
  1415     QMacCocoaAutoReleasePool pool;
  1385     [NSCursor pop];
  1416     [NSCursor pop];
       
  1417     if (qApp->d_func()->cursor_list.isEmpty())
       
  1418         qApp->d_func()->disableUsageOfCursorRects(false);
  1386 #else
  1419 #else
  1387     if (qApp && qApp->activeWindow()) {
  1420     if (qApp && qApp->activeWindow()) {
  1388         const QCursor def(Qt::ArrowCursor);
  1421         const QCursor def(Qt::ArrowCursor);
  1389         qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first(), QCursor::pos());
  1422         qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first(), QCursor::pos());
  1390     }
  1423     }
  1724             // compatibility with older applications, carbon will also send us
  1757             // compatibility with older applications, carbon will also send us
  1725             // kEventMouseWheelMoved events if we dont eat this event
  1758             // kEventMouseWheelMoved events if we dont eat this event
  1726             // (actually two events; one for horizontal and one for vertical).
  1759             // (actually two events; one for horizontal and one for vertical).
  1727             // As a results of this, and to make sure we dont't receive duplicate events,
  1760             // As a results of this, and to make sure we dont't receive duplicate events,
  1728             // we try to detect when this happend by checking the 'compatibilityEvent'.
  1761             // we try to detect when this happend by checking the 'compatibilityEvent'.
       
  1762             // Since delta is delivered as pixels rather than degrees, we need to
       
  1763             // convert from pixels to degrees in a sensible manner.
       
  1764             // It looks like 1/4 degrees per pixel behaves most native.
       
  1765             // (NB: Qt expects the unit for delta to be 8 per degree):
       
  1766             const int pixelsToDegrees = 2;
  1729             SInt32 mdelt = 0;
  1767             SInt32 mdelt = 0;
  1730             GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0,
  1768             GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0,
  1731                               sizeof(mdelt), 0, &mdelt);
  1769                               sizeof(mdelt), 0, &mdelt);
  1732             wheel_deltaX = mdelt;
  1770             wheel_deltaX = mdelt * pixelsToDegrees;
  1733             mdelt = 0;
  1771             mdelt = 0;
  1734             GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0,
  1772             GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0,
  1735                               sizeof(mdelt), 0, &mdelt);
  1773                               sizeof(mdelt), 0, &mdelt);
  1736             wheel_deltaY = mdelt;
  1774             wheel_deltaY = mdelt * pixelsToDegrees;
  1737             GetEventParameter(event, kEventParamEventRef, typeEventRef, 0,
  1775             GetEventParameter(event, kEventParamEventRef, typeEventRef, 0,
  1738                               sizeof(compatibilityEvent), 0, &compatibilityEvent);
  1776                               sizeof(compatibilityEvent), 0, &compatibilityEvent);
  1739         } else if (ekind == kEventMouseWheelMoved) {
  1777         } else if (ekind == kEventMouseWheelMoved) {
  1740             if (event != compatibilityEvent) {
  1778             if (event != compatibilityEvent) {
  1741                 compatibilityEvent = 0;
  1779                 compatibilityEvent = 0;
  2406                 if(SendEventToMenu(copy, copy_cmd.menu.menuRef) == noErr)
  2444                 if(SendEventToMenu(copy, copy_cmd.menu.menuRef) == noErr)
  2407                     handled_event = true;
  2445                     handled_event = true;
  2408             }
  2446             }
  2409             if(!handled_event) {
  2447             if(!handled_event) {
  2410                 if(cmd.commandID == kHICommandQuit) {
  2448                 if(cmd.commandID == kHICommandQuit) {
  2411                     handled_event = true;
  2449                     // Quitting the application is not Qt's responsibility if
  2412                     HiliteMenu(0);
  2450                     // used in a plugin or just embedded into a native application.
  2413                     bool handle_quit = true;
  2451                     // In that case, let the event pass down to the native apps event handler.
  2414                     if(QApplicationPrivate::modalState()) {
  2452                     if (!QApplication::testAttribute(Qt::AA_MacPluginApplication)) {
  2415                         int visible = 0;
  2453                         handled_event = true;
  2416                         const QWidgetList tlws = QApplication::topLevelWidgets();
  2454                         HiliteMenu(0);
  2417                         for(int i = 0; i < tlws.size(); ++i) {
  2455                         bool handle_quit = true;
  2418                             if(tlws.at(i)->isVisible())
  2456                         if(QApplicationPrivate::modalState()) {
  2419                                 ++visible;
  2457                             int visible = 0;
       
  2458                             const QWidgetList tlws = QApplication::topLevelWidgets();
       
  2459                             for(int i = 0; i < tlws.size(); ++i) {
       
  2460                                 if(tlws.at(i)->isVisible())
       
  2461                                     ++visible;
       
  2462                             }
       
  2463                             handle_quit = (visible <= 1);
  2420                         }
  2464                         }
  2421                         handle_quit = (visible <= 1);
  2465                         if(handle_quit) {
  2422                     }
  2466                             QCloseEvent ev;
  2423                     if(handle_quit) {
  2467                             QApplication::sendSpontaneousEvent(app, &ev);
  2424                         QCloseEvent ev;
  2468                             if(ev.isAccepted())
  2425                         QApplication::sendSpontaneousEvent(app, &ev);
  2469                                 app->quit();
  2426                         if(ev.isAccepted())
  2470                         } else {
  2427                             app->quit();
  2471                             QApplication::beep();
  2428                     } else {
  2472                         }
  2429                         QApplication::beep();
       
  2430                     }
  2473                     }
  2431                 } else if(cmd.commandID == kHICommandSelectWindow) {
  2474                 } else if(cmd.commandID == kHICommandSelectWindow) {
  2432                     if((GetCurrentKeyModifiers() & cmdKey))
  2475                     if((GetCurrentKeyModifiers() & cmdKey))
  2433                         handled_event = true;
  2476                         handled_event = true;
  2434                 } else if(cmd.commandID == kHICommandAbout) {
  2477                 } else if(cmd.commandID == kHICommandAbout) {
  2454     Q_UNUSED(event);
  2497     Q_UNUSED(event);
  2455     Q_UNUSED(data);
  2498     Q_UNUSED(data);
  2456     return eventNotHandledErr;
  2499     return eventNotHandledErr;
  2457 #endif
  2500 #endif
  2458 }
  2501 }
       
  2502 
       
  2503 #ifdef QT_MAC_USE_COCOA
       
  2504 void QApplicationPrivate::qt_initAfterNSAppStarted()
       
  2505 {
       
  2506     setupAppleEvents();
       
  2507     updateOverrideCursor();
       
  2508 }
       
  2509 
       
  2510 void QApplicationPrivate::setupAppleEvents()
       
  2511 {
       
  2512     // This function is called from the event dispatcher when NSApplication has
       
  2513     // finished initialization, which appears to be just after [NSApplication run] has
       
  2514     // started to execute. By setting up our apple events handlers this late, we override
       
  2515     // the ones set up by NSApplication.
       
  2516 
       
  2517     // If Qt is used as a plugin, we let the 3rd party application handle events
       
  2518     // like quit and open file events. Otherwise, if we install our own handlers, we
       
  2519     // easily end up breaking functionallity the 3rd party application depend on:
       
  2520     if (QApplication::testAttribute(Qt::AA_MacPluginApplication))
       
  2521         return;
       
  2522 
       
  2523     QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
       
  2524     NSAppleEventManager *eventManager = [NSAppleEventManager sharedAppleEventManager];
       
  2525     [eventManager setEventHandler:newDelegate andSelector:@selector(appleEventQuit:withReplyEvent:)
       
  2526      forEventClass:kCoreEventClass andEventID:kAEQuitApplication];
       
  2527     [eventManager setEventHandler:newDelegate andSelector:@selector(getUrl:withReplyEvent:)
       
  2528       forEventClass:kInternetEventClass andEventID:kAEGetURL];
       
  2529 }
       
  2530 #endif
  2459 
  2531 
  2460 // In Carbon this is your one stop for apple events.
  2532 // In Carbon this is your one stop for apple events.
  2461 // In Cocoa, it ISN'T. This is the catch-all Apple Event handler that exists
  2533 // In Cocoa, it ISN'T. This is the catch-all Apple Event handler that exists
  2462 // for the time between instantiating the NSApplication, but before the
  2534 // for the time between instantiating the NSApplication, but before the
  2463 // NSApplication has installed it's OWN Apple Event handler. When Cocoa has
  2535 // NSApplication has installed it's OWN Apple Event handler. When Cocoa has
  3006         if (QApplicationPrivate::active_window == widget)
  3078         if (QApplicationPrivate::active_window == widget)
  3007             qApp->setActiveWindow(0);
  3079             qApp->setActiveWindow(0);
  3008     }
  3080     }
  3009 
  3081 
  3010     QMenuBar::macUpdateMenuBar();
  3082     QMenuBar::macUpdateMenuBar();
  3011 
  3083     QApplicationPrivate::updateOverrideCursor();
  3012 #else
  3084 #else
  3013     Q_UNUSED(widget);
  3085     Q_UNUSED(widget);
  3014     Q_UNUSED(activated);
  3086     Q_UNUSED(activated);
  3015 #endif
  3087 #endif
  3016 }
  3088 }