summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2015-10-14 15:45:35 +0200
committerLiang Qi <liang.qi@theqtcompany.com>2015-10-14 15:45:35 +0200
commit4456984da780b14572e1ec0f079a4d349ab299bd (patch)
treef586a281a81c57c91c49e83a5d3ec6c7eece0578 /src/plugins/platforms/cocoa
parente824abd987d77efaa085fe1f9fb514d270798d55 (diff)
parent281121697340084f7d385eab530f41916789b94d (diff)
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts: tests/auto/corelib/io/qfile/tst_qfile.cpp tests/auto/corelib/io/qprocess/tst_qprocess.cpp tests/auto/corelib/tools/qversionnumber/qversionnumber.pro Change-Id: Ia93ce500349d96a2fbf0b4a37b73f088cc505c6e
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm41
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm18
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h2
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm60
7 files changed, 76 insertions, 50 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index 2098f0dc8c..8e38181c29 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -303,7 +303,7 @@ NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoin
NSImage *nsimage;
if (pixmap.devicePixelRatio() > 1.0) {
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();
- QPixmap scaledPixmap = pixmap.scaled(layoutSize);
+ QPixmap scaledPixmap = pixmap.scaled(layoutSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(scaledPixmap));
CGImageRef cgImage = qt_mac_toCGImage(pixmap.toImage());
NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage];
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index bb493ef2be..8ad80333f8 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -622,7 +622,7 @@ QString qt_mac_applicationName()
if (appName.isEmpty()) {
QString arg0 = QGuiApplicationPrivate::instance()->appName();
if (arg0.contains("/")) {
- QStringList parts = arg0.split("/");
+ QStringList parts = arg0.split(QLatin1Char('/'));
appName = parts.at(parts.count() - 1);
} else {
appName = arg0;
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 57739f3a58..aa7a09805a 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -463,6 +463,13 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
NSView *view = cocoaWindow ? cocoaWindow->contentView() : nil;
NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
+ QScreen *screen = 0;
+ if (parentWindow)
+ screen = parentWindow->screen();
+ if (!screen && !QGuiApplication::screens().isEmpty())
+ screen = QGuiApplication::screens().at(0);
+ Q_ASSERT(screen);
+
// Ideally, we would call -popUpMenuPositioningItem:atLocation:inView:.
// However, this showed not to work with modal windows where the menu items
// would appear disabled. So, we resort to a more artisanal solution. Note
@@ -479,6 +486,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
[popupCell setTransparent:YES];
[popupCell setMenu:m_nativeMenu];
[popupCell selectItem:nsItem];
+
+ int availableHeight = screen->availableSize().height();
+ const QPoint &globalPos = parentWindow->mapToGlobal(pos);
+ int menuHeight = m_nativeMenu.size.height;
+ if (globalPos.y() + menuHeight > availableHeight) {
+ // Maybe we need to fix the vertical popup position but we don't know the
+ // exact popup height at the moment (and Cocoa is just guessing) nor its
+ // position. So, instead of translating by the popup's full height, we need
+ // to estimate where the menu will show up and translate by the remaining height.
+ float idx = ([m_nativeMenu indexOfItem:nsItem] + 1.0f) / m_nativeMenu.numberOfItems;
+ float heightBelowPos = (1.0 - idx) * menuHeight;
+ if (globalPos.y() + heightBelowPos > availableHeight)
+ pos.setY(pos.y() - globalPos.y() + availableHeight - heightBelowPos);
+ }
+
NSRect cellFrame = NSMakeRect(pos.x(), pos.y(), m_nativeMenu.minimumWidth, 10);
[popupCell performClickWithFrame:cellFrame inView:view];
} else {
@@ -487,22 +509,21 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect,
if (view) {
// convert coordinates from view to the view's window
nsPos = [view convertPoint:nsPos toView:nil];
- } else if (!QGuiApplication::screens().isEmpty()) {
- QScreen *screen = QGuiApplication::screens().at(0);
+ } else {
nsPos.y = screen->availableVirtualSize().height() - nsPos.y;
}
if (view) {
// Finally, we need to synthesize an event.
NSEvent *menuEvent = [NSEvent mouseEventWithType:NSRightMouseDown
- location:nsPos
- modifierFlags:0
- timestamp:0
- windowNumber:view ? view.window.windowNumber : 0
- context:nil
- eventNumber:0
- clickCount:1
- pressure:1.0];
+ location:nsPos
+ modifierFlags:0
+ timestamp:0
+ windowNumber:view ? view.window.windowNumber : 0
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
[NSMenu popUpContextMenu:m_nativeMenu withEvent:menuEvent forView:view];
} else {
[m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:0];
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index f78a27614e..e830be212a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -270,7 +270,6 @@ public: // for QNSView
QPointer<QWindow> m_enterLeaveTargetWindow;
bool m_windowUnderMouse;
- bool m_ignoreWindowShouldClose;
bool m_inConstructor;
bool m_inSetVisible;
bool m_inSetGeometry;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index f790259f0e..adfef81117 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -345,7 +345,6 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
- , m_ignoreWindowShouldClose(false)
, m_inConstructor(true)
, m_inSetVisible(false)
, m_inSetGeometry(false)
@@ -809,13 +808,10 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
return styleMask;
if ((type & Qt::Popup) == Qt::Popup) {
if (!windowIsPopupType(type)) {
- styleMask = NSUtilityWindowMask;
+ styleMask = NSUtilityWindowMask | NSResizableWindowMask;
if (!(flags & Qt::CustomizeWindowHint)) {
- styleMask |= NSResizableWindowMask | NSClosableWindowMask |
- NSMiniaturizableWindowMask | NSTitledWindowMask;
+ styleMask |= NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask;
} else {
- if (flags & Qt::WindowMaximizeButtonHint)
- styleMask |= NSResizableWindowMask;
if (flags & Qt::WindowTitleHint)
styleMask |= NSTitledWindowMask;
if (flags & Qt::WindowCloseButtonHint)
@@ -1228,9 +1224,10 @@ void QCocoaWindow::windowDidEndLiveResize()
bool QCocoaWindow::windowShouldClose()
{
- // might have been set from qnsview.mm
- if (m_ignoreWindowShouldClose)
- return false;
+ // This callback should technically only determine if the window
+ // should (be allowed to) close, but since our QPA API to determine
+ // that also involves actually closing the window we do both at the
+ // same time, instead of doing the latter in windowWillClose.
bool accepted = false;
QWindowSystemInterface::handleCloseEvent(window(), &accepted);
QWindowSystemInterface::flushWindowSystemEvents();
@@ -1364,6 +1361,9 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
[m_contentView setHidden: YES];
}
+ m_nsWindow.ignoresMouseEvents =
+ (window()->flags() & Qt::WindowTransparentForInput) == Qt::WindowTransparentForInput;
+
const qreal opacity = qt_window_private(window())->opacity;
if (!qFuzzyCompare(opacity, qreal(1.0)))
setOpacity(opacity);
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index a49a42378d..d7b9c3831b 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -76,6 +76,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
bool m_resendKeyEvent;
bool m_scrolling;
bool m_exposedOnMoveToWindow;
+ NSEvent *m_currentlyInterpretedKeyEvent;
}
- (id)init;
@@ -131,7 +132,6 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType;
- (void)keyDown:(NSEvent *)theEvent;
- (void)keyUp:(NSEvent *)theEvent;
-- (BOOL)performKeyEquivalent:(NSEvent *)theEvent;
- (void)registerDragTypes;
- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 4db55c1b73..8c22e51fe2 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -152,6 +152,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
m_resendKeyEvent = false;
m_scrolling = false;
+ m_currentlyInterpretedKeyEvent = 0;
if (!touchDevice) {
touchDevice = new QTouchDevice;
@@ -709,8 +710,12 @@ QT_WARNING_POP
// Popups implicitly grap mouse events; forward to the active popup if there is one
if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow()) {
- if (QNSView *popupView = popup->qtView())
- targetView = popupView;
+ // Tooltips must be transparent for mouse events
+ // The bug reference is QTBUG-46379
+ if (!popup->m_windowFlags.testFlag(Qt::ToolTip)) {
+ if (QNSView *popupView = popup->qtView())
+ targetView = popupView;
+ }
}
[targetView convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
@@ -1436,41 +1441,40 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
if (!(modifiers & (Qt::ControlModifier | Qt::MetaModifier)) && (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff))
text = QCFString::toQString(characters);
- QWindow *focusWindow = [self topLevelWindow];
+ QWindow *window = [self topLevelWindow];
+
+ // Popups implicitly grab key events; forward to the active popup if there is one.
+ // This allows popups to e.g. intercept shortcuts and close the popup in response.
+ if (QCocoaWindow *popup = QCocoaIntegration::instance()->activePopupWindow())
+ window = popup->window();
if (eventType == QEvent::KeyPress) {
if (m_composingText.isEmpty()) {
- QKeyEvent override(QEvent::ShortcutOverride, keyCode, modifiers,
- nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
- override.setTimestamp(timestamp);
- m_sendKeyEvent = !QWindowSystemInterface::tryHandleShortcutOverrideEvent(focusWindow, &override);
+ m_sendKeyEvent = !QWindowSystemInterface::handleShortcutEvent(window, timestamp, keyCode,
+ modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1);
}
QObject *fo = QGuiApplication::focusObject();
if (m_sendKeyEvent && fo) {
- // if escape is pressed we don't want interpretKeyEvents to close a dialog. This will be done via QWindowSystemInterface
- if (keyCode == Qt::Key_Escape)
- m_platformWindow->m_ignoreWindowShouldClose = true;
-
QInputMethodQueryEvent queryEvent(Qt::ImEnabled | Qt::ImHints);
if (QCoreApplication::sendEvent(fo, &queryEvent)) {
bool imEnabled = queryEvent.value(Qt::ImEnabled).toBool();
Qt::InputMethodHints hints = static_cast<Qt::InputMethodHints>(queryEvent.value(Qt::ImHints).toUInt());
if (imEnabled && !(hints & Qt::ImhDigitsOnly || hints & Qt::ImhFormattedNumbersOnly || hints & Qt::ImhHiddenText)) {
// pass the key event to the input method. note that m_sendKeyEvent may be set to false during this call
+ m_currentlyInterpretedKeyEvent = nsevent;
[self interpretKeyEvents:[NSArray arrayWithObject:nsevent]];
+ m_currentlyInterpretedKeyEvent = 0;
}
}
-
- m_platformWindow->m_ignoreWindowShouldClose = false;;
}
if (m_resendKeyEvent)
m_sendKeyEvent = true;
}
if (m_sendKeyEvent && m_composingText.isEmpty())
- QWindowSystemInterface::handleExtendedKeyEvent(focusWindow, timestamp, QEvent::Type(eventType), keyCode, modifiers,
+ QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers,
nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false);
m_sendKeyEvent = false;
@@ -1491,21 +1495,23 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
[self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
}
-- (BOOL)performKeyEquivalent:(NSEvent *)nsevent
+- (void)cancelOperation:(id)sender
{
- NSString *chars = [nsevent charactersIgnoringModifiers];
+ Q_UNUSED(sender);
- if ([nsevent type] == NSKeyDown && [chars length] > 0) {
- QChar ch = [chars characterAtIndex:0];
- Qt::Key qtKey = qt_mac_cocoaKey2QtKey(ch);
- // check for Command + Key_Period
- if ([nsevent modifierFlags] & NSCommandKeyMask
- && qtKey == Qt::Key_Period) {
- [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
- return YES;
- }
- }
- return [super performKeyEquivalent:nsevent];
+ NSEvent *currentEvent = [NSApp currentEvent];
+ if (!currentEvent || currentEvent.type != NSKeyDown)
+ return;
+
+ // Handling the key event may recurse back here through interpretKeyEvents
+ // (when IM is enabled), so we need to guard against that.
+ if (currentEvent == m_currentlyInterpretedKeyEvent)
+ return;
+
+ // Send Command+Key_Period and Escape as normal keypresses so that
+ // the key sequence is delivered through Qt. That way clients can
+ // intercept the shortcut and override its effect.
+ [self handleKeyEvent:currentEvent eventType:int(QEvent::KeyPress)];
}
- (void)flagsChanged:(NSEvent *)nsevent