Cocoa: Add basic support for Qt::SubWindow.

This allows embedding a QWindow in a foreign NSView
hierarchy.

Don't create a NSWindow. Add code paths for handling
the embedded window case. Avoid changing the other
window cases. There is potential for merging some of
these cases but that can be done at a later point in
time.

Change-Id: I54c7b4eb82fad268f90ea6b716fc650ae31bd3af
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@digia.com>
bb10
Morten Johan Sørvig 2013-01-04 12:50:40 +01:00 committed by The Qt Project
parent bfce04fe5b
commit 3dc634be36
3 changed files with 55 additions and 2 deletions

View File

@ -162,6 +162,8 @@ public: // for QNSView
QNSView *m_contentView;
NSWindow *m_nsWindow;
bool m_contentViewIsEmbedded; // true if the m_contentView is embedded in a "foregin" NSView hiearchy
QNSWindowDelegate *m_nsWindowDelegate;
Qt::WindowFlags m_windowFlags;
Qt::WindowState m_synchedWindowState;

View File

@ -186,6 +186,7 @@ static bool isMouseEvent(NSEvent *ev)
QCocoaWindow::QCocoaWindow(QWindow *tlw)
: QPlatformWindow(tlw)
, m_nsWindow(0)
, m_contentViewIsEmbedded(false)
, m_nsWindowDelegate(0)
, m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal)
@ -237,6 +238,10 @@ void QCocoaWindow::setGeometry(const QRect &rect)
void QCocoaWindow::setCocoaGeometry(const QRect &rect)
{
QCocoaAutoReleasePool pool;
if (m_contentViewIsEmbedded)
return;
if (m_nsWindow) {
NSRect bounds = qt_mac_flipRect(rect, window());
[m_nsWindow setContentSize : bounds.size];
@ -634,7 +639,9 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
m_nsWindowDelegate = 0;
}
if (!parentWindow) {
if (window()->type() == Qt::SubWindow) {
// Subwindows don't have a NSWindow.
} else if (!parentWindow) {
// Create a new NSWindow if this is a top-level window.
m_nsWindow = createNSWindow();
setNSWindow(m_nsWindow);

View File

@ -173,6 +173,36 @@ static QTouchDevice *touchDevice = 0;
QWindowSystemInterface::handleExposeEvent(m_window, m_window->geometry());
}
- (void)viewDidMoveToSuperview
{
if (!(m_window->type() & Qt::SubWindow))
return;
if ([self superview]) {
m_platformWindow->m_contentViewIsEmbedded = true;
QWindowSystemInterface::handleGeometryChange(m_window, m_platformWindow->geometry());
QWindowSystemInterface::handleExposeEvent(m_window, m_platformWindow->geometry());
QWindowSystemInterface::flushWindowSystemEvents();
} else {
m_platformWindow->m_contentViewIsEmbedded = false;
}
}
- (void)viewWillMoveToWindow:(NSWindow *)newWindow
{
// ### Merge "normal" window code path with this one for 5.1.
if (!(m_window->type() & Qt::SubWindow))
return;
if (newWindow) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(windowNotification:)
name:nil // Get all notifications
object:newWindow];
} else {
[[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:[self window]];
}
}
- (void)updateGeometry
{
QRect geometry;
@ -181,6 +211,9 @@ static QTouchDevice *touchDevice = 0;
NSRect rect = [self frame];
NSRect windowRect = [[self window] frame];
geometry = QRect(windowRect.origin.x, qt_mac_flipYCoordinate(windowRect.origin.y + rect.size.height), rect.size.width, rect.size.height);
} else if (m_window->type() & Qt::SubWindow) {
// embedded child window, use the frame rect ### merge with case below
geometry = qt_mac_toQRect([self bounds]);
} else {
// child window, use the frame rect
geometry = qt_mac_toQRect([self frame]);
@ -198,6 +231,12 @@ static QTouchDevice *touchDevice = 0;
// an infinite loop when this notification is triggered again.)
m_platformWindow->QPlatformWindow::setGeometry(geometry);
// Don't send the geometry change if the QWindow is designated to be
// embedded in a foregin view hiearchy but has not actually been
// embedded yet - it's too early.
if ((m_window->type() & Qt::SubWindow) && !m_platformWindow->m_contentViewIsEmbedded)
return;
// Send a geometry change event to Qt, if it's ready to handle events
if (!m_platformWindow->m_inConstructor) {
QWindowSystemInterface::handleGeometryChange(m_window, geometry);
@ -317,7 +356,12 @@ static QTouchDevice *touchDevice = 0;
);
CGImageRef bsCGImage = m_backingStore->getBackingStoreCGImage();
CGImageRef cleanImg = CGImageCreateWithImageInRect(bsCGImage, backingStoreRect);
CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
// Optimization: Copy frame buffer content instead of blending for
// top-level windows where Qt fills the entire window content area.
if (m_platformWindow->m_nsWindow)
CGContextSetBlendMode(cgContext, kCGBlendModeCopy);
CGContextDrawImage(cgContext, dirtyWindowRect, cleanImg);
// Clean-up: