summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qapplication_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qapplication_mac.mm')
-rw-r--r--src/gui/kernel/qapplication_mac.mm164
1 files changed, 81 insertions, 83 deletions
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 890d527..1f75f09 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -165,6 +165,7 @@ QT_BEGIN_NAMESPACE
//for qt_mac.h
QPaintDevice *qt_mac_safe_pdev = 0;
QList<QMacWindowChangeEvent*> *QMacWindowChangeEvent::change_events = 0;
+QPointer<QWidget> topLevelAt_cache = 0;
/*****************************************************************************
Internal variables and functions
@@ -192,7 +193,6 @@ static bool qt_mac_previous_press_in_popup_mode = false;
static bool qt_mac_no_click_through_mode = false;
static int tablet_button_state = 0;
#endif
-QPointer<QWidget> qt_mouseover;
#if defined(QT_DEBUG)
static bool appNoGrab = false; // mouse/keyboard grabbing
#endif
@@ -216,11 +216,11 @@ extern bool qt_mac_can_clickThrough(const QWidget *); //qwidget_mac.cpp
extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
extern OSWindowRef qt_mac_window_for(const QWidget*); //qwidget_mac.cpp
extern QWidget *qt_mac_find_window(OSWindowRef); //qwidget_mac.cpp
-extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.cpp
+extern void qt_mac_set_cursor(const QCursor *); //qcursor_mac.cpp
extern bool qt_mac_is_macsheet(const QWidget *); //qwidget_mac.cpp
-extern QString qt_mac_from_pascal_string(const Str255); //qglobal.cpp
extern void qt_mac_command_set_enabled(MenuRef, UInt32, bool); //qmenu_mac.cpp
extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); // qapplication.cpp
+extern void qt_mac_update_cursor(); // qcursor_mac.mm
// Forward Decls
void onApplicationWindowChangedActivation( QWidget*widget, bool activated );
@@ -549,7 +549,7 @@ void qt_mac_update_os_settings()
FontMap("QTipLabel", kThemeSmallSystemFont),
FontMap("QLabel", kThemeSystemFont),
FontMap("QToolButton", kThemeSmallSystemFont),
- FontMap("QMenuItem", kThemeMenuItemCmdKeyFont), // It doesn't exist, but its unique.
+ FontMap("QMenuItem", kThemeMenuItemFont), // It doesn't exist, but its unique.
FontMap("QComboLineEdit", kThemeViewsFont), // It doesn't exist, but its unique.
FontMap("QSmallFont", kThemeSmallSystemFont), // It doesn't exist, but its unique.
FontMap("QMiniFont", kThemeMiniSystemFont), // It doesn't exist, but its unique.
@@ -714,6 +714,7 @@ void qt_event_request_showsheet(QWidget *w)
{
Q_ASSERT(qt_mac_is_macsheet(w));
#ifdef QT_MAC_USE_COCOA
+ w->repaint();
[NSApp beginSheet:qt_mac_window_for(w) modalForWindow:qt_mac_window_for(w->parentWidget())
modalDelegate:nil didEndSelector:nil contextInfo:0];
#else
@@ -1243,8 +1244,10 @@ void qt_init(QApplicationPrivate *priv, int)
// Cocoa application delegate
#ifdef QT_MAC_USE_COCOA
NSApplication *cocoaApp = [QNSApplication sharedApplication];
+ qt_redirectNSApplicationSendEvent();
+
QMacCocoaAutoReleasePool pool;
- NSObject *oldDelegate = [cocoaApp delegate];
+ id oldDelegate = [cocoaApp delegate];
QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) *newDelegate = [QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate];
Q_ASSERT(newDelegate);
[newDelegate setQtPrivate:priv];
@@ -1362,43 +1365,16 @@ void QApplication::setMainWidget(QWidget *mainWidget)
/*****************************************************************************
QApplication cursor stack
*****************************************************************************/
-#ifdef QT_MAC_USE_COCOA
-void QApplicationPrivate::disableUsageOfCursorRects(bool disable)
-{
- // In Cocoa there are two competing ways of setting the cursor; either
- // by using cursor rects (see qcocoaview_mac.mm), or by pushing/popping
- // the cursor manually. When we use override cursors, it makes most sense
- // to use the latter. But then we need to tell cocoa to stop using the
- // first approach so it doesn't change the cursor back when hovering over
- // a cursor rect:
- QWidgetList topLevels = qApp->topLevelWidgets();
- for (int i=0; i<topLevels.size(); ++i) {
- if (NSWindow *window = qt_mac_window_for(topLevels.at(i)))
- disable ? [window disableCursorRects] : [window enableCursorRects];
- }
-}
-
-void QApplicationPrivate::updateOverrideCursor()
-{
- // Sometimes Cocoa forgets that we have set a Cursor
- // manually. In those cases, remind it again:
- if (QCursor *override = qApp->overrideCursor())
- [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*override)) set];
-}
-#endif
void QApplication::setOverrideCursor(const QCursor &cursor)
{
qApp->d_func()->cursor_list.prepend(cursor);
#ifdef QT_MAC_USE_COCOA
- QMacCocoaAutoReleasePool pool;
- if (qApp->d_func()->cursor_list.size() == 1)
- qApp->d_func()->disableUsageOfCursorRects(true);
- [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
+ qt_mac_update_cursor();
#else
if (qApp && qApp->activeWindow())
- qt_mac_set_cursor(&qApp->d_func()->cursor_list.first(), QCursor::pos());
+ qt_mac_set_cursor(&qApp->d_func()->cursor_list.first());
#endif
}
@@ -1409,19 +1385,21 @@ void QApplication::restoreOverrideCursor()
qApp->d_func()->cursor_list.removeFirst();
#ifdef QT_MAC_USE_COCOA
- QMacCocoaAutoReleasePool pool;
- [NSCursor pop];
- if (qApp->d_func()->cursor_list.isEmpty())
- qApp->d_func()->disableUsageOfCursorRects(false);
+ qt_mac_update_cursor();
#else
if (qApp && qApp->activeWindow()) {
const QCursor def(Qt::ArrowCursor);
- qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first(), QCursor::pos());
+ qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first());
}
#endif
}
#endif // QT_NO_CURSOR
+Qt::KeyboardModifiers QApplication::queryKeyboardModifiers()
+{
+ return qt_mac_get_modifiers(GetCurrentEventKeyModifiers());
+}
+
QWidget *QApplication::topLevelAt(const QPoint &p)
{
#ifndef QT_MAC_USE_COCOA
@@ -1429,30 +1407,54 @@ QWidget *QApplication::topLevelAt(const QPoint &p)
qt_mac_window_at(p.x(), p.y(), &widget);
return widget;
#else
+ // Use a cache to avoid iterate through the whole list of windows for all
+ // calls to to topLevelAt. We e.g. do this for each and every mouse
+ // move since we need to find the widget under mouse:
+ if (topLevelAt_cache && topLevelAt_cache->frameGeometry().contains(p))
+ return topLevelAt_cache;
+
+ // INVARIANT: Cache miss. Go through the list if windows instead:
+ QMacCocoaAutoReleasePool pool;
+ NSPoint cocoaPoint = flipPoint(p);
NSInteger windowCount;
NSCountWindows(&windowCount);
if (windowCount <= 0)
return 0; // There's no window to find!
- QMacCocoaAutoReleasePool pool;
- NSPoint cocoaPoint = flipPoint(p);
+
QVarLengthArray<NSInteger> windowList(windowCount);
NSWindowList(windowCount, windowList.data());
+ int firstQtWindowFound = -1;
for (int i = 0; i < windowCount; ++i) {
NSWindow *window = [NSApp windowWithWindowNumber:windowList[i]];
- if (window && NSPointInRect(cocoaPoint, [window frame])) {
+ if (window) {
QWidget *candidateWindow = [window QT_MANGLE_NAMESPACE(qt_qwidget)];
- // Check to see if there's a hole in the window where the mask is.
- // If there is, we should just continue to see if there is a window below.
- if (candidateWindow && !candidateWindow->mask().isEmpty()) {
- QPoint localPoint = candidateWindow->mapFromGlobal(p);
- if (!candidateWindow->mask().contains(localPoint)) {
- continue;
+ if (candidateWindow && firstQtWindowFound == -1)
+ firstQtWindowFound = i;
+
+ if (NSPointInRect(cocoaPoint, [window frame])) {
+ // Check to see if there's a hole in the window where the mask is.
+ // If there is, we should just continue to see if there is a window below.
+ if (candidateWindow && !candidateWindow->mask().isEmpty()) {
+ QPoint localPoint = candidateWindow->mapFromGlobal(p);
+ if (!candidateWindow->mask().contains(localPoint))
+ continue;
+ else
+ return candidateWindow;
+ } else {
+ if (i == firstQtWindowFound) {
+ // The cache will only work when the window under mouse is
+ // top most (that is, not partially obscured by other windows.
+ // And we only set it if no mask is present to optimize for the common case:
+ topLevelAt_cache = candidateWindow;
+ }
+ return candidateWindow;
}
}
- return candidateWindow;
}
}
- return 0; // Couldn't find a window at this point
+
+ topLevelAt_cache = 0;
+ return 0;
#endif
}
@@ -1478,8 +1480,8 @@ void QApplicationPrivate::enterModal_sys(QWidget *widget)
if (!qt_modal_stack)
qt_modal_stack = new QWidgetList;
- dispatchEnterLeave(0, qt_mouseover);
- qt_mouseover = 0;
+ dispatchEnterLeave(0, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = 0;
qt_modal_stack->insert(0, widget);
if (!app_do_modal)
@@ -1510,8 +1512,8 @@ void QApplicationPrivate::leaveModal_sys(QWidget *widget)
w = grabber;
else
w = QApplication::widgetAt(p.x(), p.y());
- dispatchEnterLeave(w, qt_mouseover); // send synthetic enter event
- qt_mouseover = w;
+ dispatchEnterLeave(w, qt_last_mouse_receiver); // send synthetic enter event
+ qt_last_mouse_receiver = w;
}
#ifdef QT_MAC_USE_COCOA
if (!qt_mac_is_macsheet(widget))
@@ -1936,7 +1938,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
}
}
}
- qt_mac_set_cursor(&cursor, QPoint(where.h, where.v));
+ qt_mac_set_cursor(&cursor);
}
//This mouse button state stuff looks like this on purpose
@@ -2130,20 +2132,20 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
QWidget * const enterLeaveWidget = (inPopupMode || ekind == kEventMouseUp) ?
QApplication::widgetAt(where.h, where.v) : static_cast<QWidget*>(widget);
- if ((QWidget *) qt_mouseover != enterLeaveWidget || inNonClientArea) {
+ if ((QWidget *) qt_last_mouse_receiver != enterLeaveWidget || inNonClientArea) {
#ifdef DEBUG_MOUSE_MAPS
qDebug("Entering: %p - %s (%s), Leaving %s (%s)", (QWidget*)enterLeaveWidget,
enterLeaveWidget ? enterLeaveWidget->metaObject()->className() : "none",
enterLeaveWidget ? enterLeaveWidget->objectName().toLocal8Bit().constData() : "",
- qt_mouseover ? qt_mouseover->metaObject()->className() : "none",
- qt_mouseover ? qt_mouseover->objectName().toLocal8Bit().constData() : "");
+ qt_last_mouse_receiver ? qt_last_mouse_receiver->metaObject()->className() : "none",
+ qt_last_mouse_receiver ? qt_last_mouse_receiver->objectName().toLocal8Bit().constData() : "");
#endif
QWidget * const mouseGrabber = QWidget::mouseGrabber();
if (inPopupMode) {
QWidget *enter = enterLeaveWidget;
- QWidget *leave = qt_mouseover;
+ QWidget *leave = qt_last_mouse_receiver;
if (mouseGrabber) {
QWidget * const popupWidget = qApp->activePopupWidget();
if (leave == popupWidget)
@@ -2153,15 +2155,15 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
if ((enter == mouseGrabber && leave == popupWidget)
|| (leave == mouseGrabber && enter == popupWidget)) {
QApplicationPrivate::dispatchEnterLeave(enter, leave);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
}
} else {
QApplicationPrivate::dispatchEnterLeave(enter, leave);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
}
- } else if ((!qt_button_down || !qt_mouseover) && !mouseGrabber && !leaveAfterRelease) {
- QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_mouseover);
- qt_mouseover = enterLeaveWidget;
+ } else if ((!qt_button_down || !qt_last_mouse_receiver) && !mouseGrabber && !leaveAfterRelease) {
+ QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = enterLeaveWidget;
}
}
break; }
@@ -2238,7 +2240,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
if (leaveAfterRelease) {
QWidget *enter = QApplication::widgetAt(where.h, where.v);
QApplicationPrivate::dispatchEnterLeave(enter, leaveAfterRelease);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
leaveAfterRelease = 0;
}
@@ -2501,7 +2503,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
void QApplicationPrivate::qt_initAfterNSAppStarted()
{
setupAppleEvents();
- updateOverrideCursor();
+ qt_mac_update_cursor();
}
void QApplicationPrivate::setupAppleEvents()
@@ -2608,25 +2610,24 @@ OSStatus QApplicationPrivate::globalAppleEventProcessor(const AppleEvent *ae, Ap
/*!
\fn bool QApplication::macEventFilter(EventHandlerCallRef caller, EventRef event)
- \warning This virtual function is only implemented under Mac OS X when against Carbon.
+ \warning This virtual function is only used under Mac OS X, and behaves different
+ depending on if Qt is based on Carbon or Cocoa.
- If you create an application that inherits QApplication and reimplement
+ For the Carbon port, If you create an application that inherits QApplication and reimplement
this function, you get direct access to all Carbon Events that Qt registers
for from Mac OS X with this function being called with the \a caller and
the \a event.
+ For the Cocoa port, If you create an application that inherits QApplication and reimplement
+ this function, you get direct access to all Cocoa Events that Qt receives
+ from Mac OS X with this function being called with the \a caller being 0 and
+ the \a event being an NSEvent pointer:
+
+ NSEvent *e = reinterpret_cast<NSEvent *>(event);
+
Return true if you want to stop the event from being processed.
Return false for normal event dispatching. The default
implementation returns false.
-
- Cocoa uses a different event system which means this function is NOT CALLED
- when building Qt against Cocoa. If you want similar functionality subclass
- NSApplication and reimplement the sendEvent: message to handle all the
- NSEvents. You also will need to to instantiate your custom NSApplication
- before creating a QApplication. See \l
- {http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/Reference/Reference.html}{Apple's
- NSApplication Reference} for more information.
-
*/
bool QApplication::macEventFilter(EventHandlerCallRef, EventRef)
{
@@ -3077,7 +3078,7 @@ void onApplicationWindowChangedActivation(QWidget *widget, bool activated)
}
QMenuBar::macUpdateMenuBar();
- QApplicationPrivate::updateOverrideCursor();
+ qt_mac_update_cursor();
#else
Q_UNUSED(widget);
Q_UNUSED(activated);
@@ -3107,15 +3108,12 @@ void onApplicationChangedActivation( bool activated )
}
if (!app->activeWindow()) {
-#if QT_MAC_USE_COCOA
- OSWindowRef wp = [NSApp keyWindow];
-#else
- OSWindowRef wp = ActiveNonFloatingWindow();
-#endif
+ OSWindowRef wp = [NSApp keyWindow];
if (QWidget *tmp_w = qt_mac_find_window(wp))
app->setActiveWindow(tmp_w);
}
QMenuBar::macUpdateMenuBar();
+ qt_mac_update_cursor();
} else { // de-activated
QApplicationPrivate *priv = [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] qAppPrivate];
while (priv->inPopupMode())