Cocoa: Fix popup window positioning.

Popup window positions where offset on retina MacBooks
with an connected external monitor.

Fix this by cleaning up the coordinate conversion 
functions:
    
Remove the qt_mac_flipRect overload which tries
to position the window according screen size. This
functionality does not belong inside a coordinate/
type conversion function. Also, it was using the windows's
screen instead of the main screen which is incorrect.

"Y flipping": Use the height of the first screen in
[NSScreen screens], which is documented to always
be the screen that contains the coordinate system
origin. Remove the usages of QApplication::primaryScreen()
("Don't use Qt to implement Qt").

Task-number: QTBUG-36672
Change-Id: I2354d31361f5a4c2c80035cf4c7def939218406f
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
bb10
Morten Johan Sørvig 2014-02-18 14:32:33 +01:00 committed by The Qt Project
parent 66e5f8e9dc
commit 9d2d4ad483
3 changed files with 41 additions and 53 deletions

View File

@ -103,23 +103,13 @@ CGColorSpaceRef qt_mac_displayColorSpace(const QWidget *widget);
CGColorSpaceRef qt_mac_colorSpaceForDeviceType(const QPaintDevice *paintDevice);
QString qt_mac_applicationName();
inline int qt_mac_flipYCoordinate(int y)
{ return QGuiApplication::primaryScreen()->geometry().height() - y; }
inline qreal qt_mac_flipYCoordinate(qreal y)
{ return QGuiApplication::primaryScreen()->geometry().height() - y; }
inline QPointF qt_mac_flipPoint(const NSPoint &p)
{ return QPointF(p.x, qt_mac_flipYCoordinate(p.y)); }
inline NSPoint qt_mac_flipPoint(const QPoint &p)
{ return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y())); }
inline NSPoint qt_mac_flipPoint(const QPointF &p)
{ return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y())); }
int qt_mac_flipYCoordinate(int y);
qreal qt_mac_flipYCoordinate(qreal y);
QPointF qt_mac_flipPoint(const NSPoint &p);
NSPoint qt_mac_flipPoint(const QPoint &p);
NSPoint qt_mac_flipPoint(const QPointF &p);
NSRect qt_mac_flipRect(const QRect &rect);
NSRect qt_mac_flipRect(const QRect &rect, QWindow *window);
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);

View File

@ -595,47 +595,45 @@ QString qt_mac_applicationName()
return appName;
}
int qt_mac_mainScreenHeight()
{
// The first screen in the screens array is documented
// to have the (0,0) origin.
NSRect screenFrame = [[[NSScreen screens] firstObject] frame];
return screenFrame.size.height;
}
int qt_mac_flipYCoordinate(int y)
{
return qt_mac_mainScreenHeight() - y;
}
qreal qt_mac_flipYCoordinate(qreal y)
{
return qt_mac_mainScreenHeight() - y;
}
QPointF qt_mac_flipPoint(const NSPoint &p)
{
return QPointF(p.x, qt_mac_flipYCoordinate(p.y));
}
NSPoint qt_mac_flipPoint(const QPoint &p)
{
return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y()));
}
NSPoint qt_mac_flipPoint(const QPointF &p)
{
return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y()));
}
NSRect qt_mac_flipRect(const QRect &rect)
{
int flippedY = qt_mac_flipYCoordinate(rect.y() + rect.height());
return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height());
}
/*
Mac window coordinates are in the first quadrant: 0, 0 is at the lower-left
corner of the primary screen. This function converts the given rect to an
NSRect for the window geometry, flipping from 4th quadrant to 1st quadrant
and simultaneously ensuring that as much of the window as possible will be
onscreen. If the rect is too tall for the screen, the OS will reduce the
window's height anyway; but by moving the window upwards we can have more
of it onscreen. But the application can still control the y coordinate
in case it really wants the window to be positioned partially offscreen.
*/
NSRect qt_mac_flipRect(const QRect &rect, QWindow *window)
{
QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window);
int flippedY = onScreen->geometry().height() - (rect.y() + rect.height());
QList<QScreen *> screens = QGuiApplication::screens();
if (screens.size() > 1) {
int height = 0;
foreach (QScreen *scr, screens)
height = qMax(height, scr->size().height());
int difference = height - onScreen->geometry().height();
if (difference > 0)
flippedY += difference;
else
flippedY -= difference;
}
// In case of automatic positioning, try to put as much of the window onscreen as possible.
if (window->isTopLevel() && qt_window_private(const_cast<QWindow*>(window))->positionAutomatic && flippedY < 0)
flippedY = onScreen->geometry().height() - onScreen->availableGeometry().height() - onScreen->availableGeometry().y();
#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
qDebug() << Q_FUNC_INFO << rect << "flippedY" << flippedY <<
"screen" << onScreen->geometry() << "available" << onScreen->availableGeometry();
#endif
return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height());
}
OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage)
{
// Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev)

View File

@ -392,7 +392,7 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
QWindowSystemInterface::handleGeometryChange(window(), rect);
QWindowSystemInterface::handleExposeEvent(window(), rect);
} else if (m_nsWindow) {
NSRect bounds = qt_mac_flipRect(rect, window());
NSRect bounds = qt_mac_flipRect(rect);
[m_nsWindow setFrame:[m_nsWindow frameRectForContentRect:bounds] display:YES animate:NO];
} else {
[m_contentView setFrame : NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
@ -418,7 +418,7 @@ void QCocoaWindow::clipWindow(const NSRect &clipRect)
NSRect clippedWindowRect = NSZeroRect;
if (!NSIsEmptyRect(clipRect)) {
NSRect windowFrame = qt_mac_flipRect(QRect(window()->mapToGlobal(QPoint(0, 0)), geometry().size()), window());
NSRect windowFrame = qt_mac_flipRect(QRect(window()->mapToGlobal(QPoint(0, 0)), geometry().size()));
clippedWindowRect = NSIntersectionRect(windowFrame, clipRect);
// Clipping top/left offsets the content. Move it back.
NSPoint contentViewOffset = NSMakePoint(qMax(CGFloat(0), NSMinX(clippedWindowRect) - NSMinX(windowFrame)),
@ -1208,7 +1208,7 @@ NSWindow * QCocoaWindow::createNSWindow()
QCocoaAutoReleasePool pool;
QRect rect = initialGeometry(window(), window()->geometry(), defaultWindowWidth, defaultWindowHeight);
NSRect frame = qt_mac_flipRect(rect, window());
NSRect frame = qt_mac_flipRect(rect);
Qt::WindowType type = window()->type();
Qt::WindowFlags flags = window()->flags();