X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fplugins%2Fplatforms%2Fcocoa%2Fqcocoawindow.mm;h=c1c5f49d3ffffac44e3b426387aca2a88ca9fcd0;hb=cd34da54269e6cd7fa5c18242d982736f022a14a;hp=32c87e752a19955b034e7d7bc25ac4484cf4f200;hpb=d9875f7bff6d52a52a1d0bf4002044a5304cf6bf;p=profile%2Fivi%2Fqtbase.git diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 32c87e7..c1c5f49 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1,38 +1,38 @@ /**************************************************************************** ** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal ** ** This file is part of the plugins of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** ** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ @@ -45,16 +45,56 @@ #include "qcocoaglcontext.h" #include "qcocoahelpers.h" #include "qnsview.h" +#include #include #include -#include -#include +#include +#include #include #include #include +static bool isMouseEvent(NSEvent *ev) +{ + switch ([ev type]) { + case NSLeftMouseDown: + case NSLeftMouseUp: + case NSRightMouseDown: + case NSRightMouseUp: + case NSMouseMoved: + case NSLeftMouseDragged: + case NSRightMouseDragged: + return true; + default: + return false; + } +} + +@interface NSWindow (CocoaWindowCategory) +- (void) clearPlatformWindow; +- (NSRect) legacyConvertRectFromScreen:(NSRect) rect; +@end + +@implementation NSWindow (CocoaWindowCategory) +- (void) clearPlatformWindow +{ +} + +- (NSRect) legacyConvertRectFromScreen:(NSRect) rect +{ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { + return [self convertRectFromScreen: rect]; + } +#endif + NSRect r = rect; + r.origin = [self convertScreenToBase:rect.origin]; + return r; +} +@end + @implementation QNSWindow - (BOOL)canBecomeKeyWindow @@ -77,6 +117,30 @@ return canBecomeMain; } +- (void) sendEvent: (NSEvent*) theEvent +{ + [super sendEvent: theEvent]; + + if (!m_cocoaPlatformWindow) + return; + + if (m_cocoaPlatformWindow->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { + NSPoint loc = [theEvent locationInWindow]; + NSRect windowFrame = [self legacyConvertRectFromScreen:[self frame]]; + NSRect contentFrame = [[self contentView] frame]; + if (NSMouseInRect(loc, windowFrame, NO) && + !NSMouseInRect(loc, contentFrame, NO)) + { + QNSView *contentView = (QNSView *) m_cocoaPlatformWindow->contentView(); + [contentView handleFrameStrutMouseEvent: theEvent]; + } + } +} + +- (void)clearPlatformWindow +{ + m_cocoaPlatformWindow = 0; +} @end @@ -85,22 +149,55 @@ - (BOOL)canBecomeKeyWindow { // Most panels can be come the key window. Exceptions are: - if (m_cocoaPlatformWindow->window()->windowType() == Qt::ToolTip) + if (m_cocoaPlatformWindow->window()->type() == Qt::ToolTip) return NO; - if (m_cocoaPlatformWindow->window()->windowType() == Qt::SplashScreen) + if (m_cocoaPlatformWindow->window()->type() == Qt::SplashScreen) return NO; return YES; } +- (void) sendEvent: (NSEvent*) theEvent +{ + [super sendEvent: theEvent]; + + if (!m_cocoaPlatformWindow) + return; + + if (m_cocoaPlatformWindow->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { + NSPoint loc = [theEvent locationInWindow]; + NSRect windowFrame = [self legacyConvertRectFromScreen:[self frame]]; + NSRect contentFrame = [[self contentView] frame]; + if (NSMouseInRect(loc, windowFrame, NO) && + !NSMouseInRect(loc, contentFrame, NO)) + { + QNSView *contentView = (QNSView *) m_cocoaPlatformWindow->contentView(); + [contentView handleFrameStrutMouseEvent: theEvent]; + } + } +} + +- (void)clearPlatformWindow +{ + m_cocoaPlatformWindow = 0; +} + @end QCocoaWindow::QCocoaWindow(QWindow *tlw) : QPlatformWindow(tlw) , m_nsWindow(0) + , m_nsWindowDelegate(0) + , m_synchedWindowState(Qt::WindowActive) + , m_windowModality(Qt::NonModal) , m_inConstructor(true) , m_glContext(0) + , m_menubar(0) , m_hasModalSession(false) + , m_frameStrutEventsEnabled(false) { +#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG + qDebug() << "QCocoaWindow::QCocoaWindow" << this; +#endif QCocoaAutoReleasePool pool; m_contentView = [[QNSView alloc] initWithQWindow:tlw platformWindow:this]; @@ -113,9 +210,15 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) QCocoaWindow::~QCocoaWindow() { +#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG + qDebug() << "QCocoaWindow::~QCocoaWindow" << this; +#endif + + QCocoaAutoReleasePool pool; clearNSWindow(m_nsWindow); [m_contentView release]; [m_nsWindow release]; + [m_nsWindowDelegate release]; } void QCocoaWindow::setGeometry(const QRect &rect) @@ -131,6 +234,7 @@ void QCocoaWindow::setGeometry(const QRect &rect) void QCocoaWindow::setCocoaGeometry(const QRect &rect) { + QCocoaAutoReleasePool pool; if (m_nsWindow) { NSRect bounds = qt_mac_flipRect(rect, window()); [m_nsWindow setContentSize : bounds.size]; @@ -147,6 +251,9 @@ void QCocoaWindow::setVisible(bool visible) qDebug() << "QCocoaWindow::setVisible" << window() << visible; #endif if (visible) { + // We need to recreate if the modality has changed as the style mask will need updating + if (m_windowModality != window()->modality()) + recreateWindow(parent()); QCocoaWindow *parentCocoaWindow = 0; if (window()->transientParent()) { parentCocoaWindow = static_cast(window()->transientParent()->handle()); @@ -157,15 +264,16 @@ void QCocoaWindow::setVisible(bool visible) // Register popup windows so that the parent window can // close them when needed. - if (window()->windowType() == Qt::Popup) { - // qDebug() << "transientParent and popup" << window()->windowType() << Qt::Popup << (window()->windowType() & Qt::Popup); + if (window()->type() == Qt::Popup) { + // qDebug() << "transientParent and popup" << window()->type() << Qt::Popup << (window()->type() & Qt::Popup); parentCocoaWindow->m_activePopupWindow = window(); } } // Make sure the QWindow has a frame ready before we show the NSWindow. - QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size())); + QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size())); + QWindowSystemInterface::flushWindowSystemEvents(); if (m_nsWindow) { // setWindowState might have been called while the window was hidden and @@ -173,12 +281,12 @@ void QCocoaWindow::setVisible(bool visible) syncWindowState(window()->windowState()); if (window()->windowState() != Qt::WindowMinimized) { - if ((window()->windowModality() == Qt::WindowModal - || window()->windowType() == Qt::Sheet) + if ((window()->modality() == Qt::WindowModal + || window()->type() == Qt::Sheet) && parentCocoaWindow) { // show the window as a sheet [NSApp beginSheet:m_nsWindow modalForWindow:parentCocoaWindow->m_nsWindow modalDelegate:nil didEndSelector:nil contextInfo:nil]; - } else if (window()->windowModality() != Qt::NonModal) { + } else if (window()->modality() != Qt::NonModal) { // show the window as application modal QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast(QGuiApplication::instance()->eventDispatcher()); Q_ASSERT(cocoaEventDispatcher != 0); @@ -190,6 +298,10 @@ void QCocoaWindow::setVisible(bool visible) } else { [m_nsWindow orderFront: nil]; } + + // We want the events to properly reach the popup + if (window()->type() == Qt::Popup) + [(NSPanel *)m_nsWindow setWorksWhenModal:YES]; } } } else { @@ -212,18 +324,88 @@ void QCocoaWindow::setVisible(bool visible) } } -Qt::WindowFlags QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) +NSInteger QCocoaWindow::windowLevel(Qt::WindowFlags flags) +{ + Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); + + NSInteger windowLevel = NSNormalWindowLevel; + + if (type == Qt::Tool) + windowLevel = NSFloatingWindowLevel; + else if ((type & Qt::Popup) == Qt::Popup) + windowLevel = NSPopUpMenuWindowLevel; + + // StayOnTop window should appear above Tool windows. + if (flags & Qt::WindowStaysOnTopHint) + windowLevel = NSPopUpMenuWindowLevel; + // Tooltips should appear above StayOnTop windows. + if (type == Qt::ToolTip) + windowLevel = NSScreenSaverWindowLevel; + + // A window should be in at least the same level as its parent. + const QWindow * const transientParent = window()->transientParent(); + const QCocoaWindow * const transientParentWindow = transientParent ? static_cast(transientParent->handle()) : 0; + if (transientParentWindow) + windowLevel = qMax([transientParentWindow->m_nsWindow level], windowLevel); + + return windowLevel; +} + +NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) +{ + Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); + NSInteger styleMask = NSBorderlessWindowMask; + + if ((type & Qt::Popup) == Qt::Popup) { + if (!windowIsPopupType(type)) + styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSTitledWindowMask); + } else { + // Filter flags for supported properties + flags &= Qt::WindowType_Mask | Qt::FramelessWindowHint | Qt::WindowTitleHint | + Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; + if (flags == Qt::Window) { + styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); + } else if ((flags & Qt::Dialog) && (window()->modality() != Qt::NonModal)) { + styleMask = NSTitledWindowMask; + } else if (!(flags & Qt::FramelessWindowHint)) { + if (flags & Qt::WindowMaximizeButtonHint) + styleMask |= NSResizableWindowMask; + if (flags & Qt::WindowTitleHint) + styleMask |= NSTitledWindowMask; + if (flags & Qt::WindowCloseButtonHint) + styleMask |= NSClosableWindowMask; + if (flags & Qt::WindowMinimizeButtonHint) + styleMask |= NSMiniaturizableWindowMask; + } + } + + return styleMask; +} + +void QCocoaWindow::setWindowShadow(Qt::WindowFlags flags) +{ + bool keepShadow = !(flags & Qt::NoDropShadowWindowHint); + [m_nsWindow setHasShadow:(keepShadow ? YES : NO)]; +} + +void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) { + if (m_nsWindow) { + NSUInteger styleMask = windowStyleMask(flags); + NSInteger level = this->windowLevel(flags); + [m_nsWindow setStyleMask:styleMask]; + [m_nsWindow setLevel:level]; + setWindowShadow(flags); + } + m_windowFlags = flags; - return m_windowFlags; } -Qt::WindowState QCocoaWindow::setWindowState(Qt::WindowState state) +void QCocoaWindow::setWindowState(Qt::WindowState state) { if ([m_nsWindow isVisible]) syncWindowState(state); // Window state set for hidden windows take effect when show() is called. - - return state; } void QCocoaWindow::setWindowTitle(const QString &title) @@ -237,6 +419,36 @@ void QCocoaWindow::setWindowTitle(const QString &title) CFRelease(windowTitle); } +void QCocoaWindow::setWindowFilePath(const QString &filePath) +{ + QCocoaAutoReleasePool pool; + if (!m_nsWindow) + return; + + QFileInfo fi(filePath); + [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""]; +} + +void QCocoaWindow::setWindowIcon(const QIcon &icon) +{ + QCocoaAutoReleasePool pool; + + NSButton *iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton]; + if (iconButton == nil) { + NSString *title = QCFString::toNSString(window()->title()); + [m_nsWindow setRepresentedURL:[NSURL fileURLWithPath:title]]; + iconButton = [m_nsWindow standardWindowButton:NSWindowDocumentIconButton]; + } + if (icon.isNull()) { + [iconButton setImage:nil]; + } else { + QPixmap pixmap = icon.pixmap(QSize(22, 22)); + NSImage *image = static_cast(qt_mac_create_nsimage(pixmap)); + [iconButton setImage:image]; + [image release]; + } +} + void QCocoaWindow::raise() { //qDebug() << "raise" << this; @@ -261,18 +473,30 @@ void QCocoaWindow::propagateSizeHints() if (!m_nsWindow) return; - [m_nsWindow setMinSize : qt_mac_toNSSize(window()->minimumSize())]; - [m_nsWindow setMaxSize : qt_mac_toNSSize(window()->maximumSize())]; - #ifdef QT_COCOA_ENABLE_WINDOW_DEBUG qDebug() << "QCocoaWindow::propagateSizeHints" << this; qDebug() << " min/max " << window()->minimumSize() << window()->maximumSize(); + qDebug() << "size increment" << window()->sizeIncrement(); qDebug() << " basesize" << window()->baseSize(); qDebug() << " geometry" << geometry(); #endif - if (!window()->sizeIncrement().isNull()) + // Set the minimum content size. + const QSize minimumSize = window()->minimumSize(); + if (!minimumSize.isValid()) // minimumSize is (-1, -1) when not set. Make that (0, 0) for Cocoa. + [m_nsWindow setContentMinSize : NSMakeSize(0.0, 0.0)]; + [m_nsWindow setContentMinSize : NSMakeSize(minimumSize.width(), minimumSize.height())]; + + // Set the maximum content size. + const QSize maximumSize = window()->maximumSize(); + [m_nsWindow setContentMaxSize : NSMakeSize(maximumSize.width(), maximumSize.height())]; + + // sizeIncrement is observed to take values of (-1, -1) and (0, 0) for windows that should be + // resizable and that have no specific size increment set. Cocoa expects (1.0, 1.0) in this case. + if (!window()->sizeIncrement().isEmpty()) [m_nsWindow setResizeIncrements : qt_mac_toNSSize(window()->sizeIncrement())]; + else + [m_nsWindow setResizeIncrements : NSMakeSize(1.0, 1.0)]; QRect rect = geometry(); QSize baseSize = window()->baseSize(); @@ -287,6 +511,16 @@ void QCocoaWindow::setOpacity(qreal level) [m_nsWindow setAlphaValue:level]; } +void QCocoaWindow::setMask(const QRegion ®ion) +{ + if (m_nsWindow) { + [m_nsWindow setOpaque:NO]; + [m_nsWindow setBackgroundColor:[NSColor clearColor]]; + } + + [m_contentView setMaskRegion:®ion]; +} + bool QCocoaWindow::setKeyboardGrabEnabled(bool grab) { if (!m_nsWindow) @@ -332,7 +566,8 @@ void QCocoaWindow::windowWillMove() { // Close any open popups on window move if (m_activePopupWindow) { - QWindowSystemInterface::handleSynchronousCloseEvent(m_activePopupWindow); + QWindowSystemInterface::handleCloseEvent(m_activePopupWindow); + QWindowSystemInterface::flushWindowSystemEvents(); m_activePopupWindow = 0; } } @@ -354,12 +589,14 @@ void QCocoaWindow::windowDidResize() void QCocoaWindow::windowWillClose() { - QWindowSystemInterface::handleSynchronousCloseEvent(window()); + QWindowSystemInterface::handleCloseEvent(window()); + QWindowSystemInterface::flushWindowSystemEvents(); } -bool QCocoaWindow::windowIsPopupType() const +bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const { - Qt::WindowType type = window()->windowType(); + if (type == Qt::Widget) + type = window()->type(); if (type == Qt::Tool) return false; // Qt::Tool has the Popup bit set but isn't, at least on Mac. @@ -384,6 +621,8 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) [m_nsWindow close]; [m_nsWindow release]; m_nsWindow = 0; + [m_nsWindowDelegate release]; + m_nsWindowDelegate = 0; } if (!parentWindow) { @@ -391,11 +630,11 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) m_nsWindow = createNSWindow(); setNSWindow(m_nsWindow); - if (window()->transientParent()) { - // keep this window on the same level as its transient parent (which may be a modal dialog, for example) - QCocoaWindow *parentCocoaWindow = static_cast(window()->transientParent()->handle()); - [m_nsWindow setLevel:[parentCocoaWindow->m_nsWindow level]]; - } + // QPlatformWindow subclasses must sync up with QWindow on creation: + propagateSizeHints(); + setWindowFlags(window()->flags()); + setWindowTitle(window()->title()); + setWindowState(window()->windowState()); } else { // Child windows have no NSWindow, link the NSViews instead. const QCocoaWindow *parentCococaWindow = static_cast(parentWindow); @@ -409,45 +648,14 @@ NSWindow * QCocoaWindow::createNSWindow() NSRect frame = qt_mac_flipRect(window()->geometry(), window()); - Qt::WindowType type = window()->windowType(); - Qt::WindowFlags flags = window()->windowFlags(); + Qt::WindowType type = window()->type(); + Qt::WindowFlags flags = window()->flags(); - NSUInteger styleMask; + NSUInteger styleMask = windowStyleMask(flags); NSWindow *createdWindow = 0; - NSInteger windowLevel = -1; - - if (type == Qt::Tool) { - windowLevel = NSFloatingWindowLevel; - } else if ((type & Qt::Popup) == Qt::Popup) { - // styleMask = NSBorderlessWindowMask; - windowLevel = NSPopUpMenuWindowLevel; - - // Popup should be in at least the same level as its parent. - const QWindow * const transientParent = window()->transientParent(); - const QCocoaWindow * const transientParentWindow = transientParent ? static_cast(transientParent->handle()) : 0; - if (transientParentWindow) - windowLevel = qMax([transientParentWindow->m_nsWindow level], windowLevel); - } - - // StayOnTop window should appear above Tool windows. - if (flags & Qt::WindowStaysOnTopHint) - windowLevel = NSPopUpMenuWindowLevel; - // Tooltips should appear above StayOnTop windows. - if (type == Qt::ToolTip) - windowLevel = NSScreenSaverWindowLevel; - // All other types are Normal level. - if (windowLevel == -1) - windowLevel = NSNormalWindowLevel; // Use NSPanel for popup-type windows. (Popup, Tool, ToolTip, SplashScreen) if ((type & Qt::Popup) == Qt::Popup) { - if (windowIsPopupType()) { - styleMask = NSBorderlessWindowMask; - } else { - styleMask = (NSUtilityWindowMask | NSResizableWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSTitledWindowMask); - } - QNSPanel *window; window = [[QNSPanel alloc] initWithContentRect:frame styleMask: styleMask @@ -455,10 +663,16 @@ NSWindow * QCocoaWindow::createNSWindow() defer:NO]; // Deferring window creation breaks OpenGL (the GL context is set up // before the window is shown and needs a proper window.). [window setHasShadow:YES]; + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { + // Make popup winows show on the same desktop as the parent full-screen window. + [window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary]; + } +#endif window->m_cocoaPlatformWindow = this; createdWindow = window; } else { - styleMask = (NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask); QNSWindow *window; window = [[QNSWindow alloc] initWithContentRect:frame styleMask: styleMask @@ -466,6 +680,7 @@ NSWindow * QCocoaWindow::createNSWindow() defer:NO]; // Deferring window creation breaks OpenGL (the GL context is set up // before the window is shown and needs a proper window.). window->m_cocoaPlatformWindow = this; + setWindowShadow(flags); #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { @@ -478,15 +693,16 @@ NSWindow * QCocoaWindow::createNSWindow() createdWindow = window; } - [createdWindow setLevel:windowLevel]; - + NSInteger level = windowLevel(flags); + [createdWindow setLevel:level]; + m_windowModality = window()->modality(); return createdWindow; } void QCocoaWindow::setNSWindow(NSWindow *window) { - QNSWindowDelegate *delegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; - [window setDelegate:delegate]; + m_nsWindowDelegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this]; + [window setDelegate:m_nsWindowDelegate]; [window setAcceptsMouseMovedEvents:YES]; // Prevent Cocoa from releasing the window on close. Qt @@ -501,17 +717,14 @@ void QCocoaWindow::setNSWindow(NSWindow *window) name:nil // Get all notifications object:m_nsWindow]; - // ### Accept touch events by default. - // Beware that enabling touch events has a negative impact on the overall performance. - // We probably need a QWindowSystemInterface API to enable/disable touch events. - [m_contentView setAcceptsTouchEvents:YES]; - [window setContentView:m_contentView]; } void QCocoaWindow::clearNSWindow(NSWindow *window) { + [window setContentView:nil]; [window setDelegate:nil]; + [window clearPlatformWindow]; [[NSNotificationCenter defaultCenter] removeObserver:m_contentView]; } @@ -543,41 +756,39 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) if (!m_nsWindow) return; - switch (newState) { - case Qt::WindowMinimized: - [m_nsWindow performMiniaturize : m_nsWindow]; - break; - case Qt::WindowMaximized: - [m_nsWindow performZoom : m_nsWindow]; - break; - case Qt::WindowFullScreen: -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - [m_nsWindow toggleFullScreen : m_nsWindow]; - } else { - qWarning("Not implemented: setWindowState WindowFullScreen"); - } -#endif - break; + // if content view width or height is 0 then the window animations will crash so + // do nothing except set the new state + NSRect contentRect = [contentView() frame]; + if (contentRect.size.width <= 0 || contentRect.size.height <= 0) { + qWarning() << Q_FUNC_INFO << "invalid window content view size, check your window geometry"; + m_synchedWindowState = newState; + return; + } - default: - // Undo current states - if ([m_nsWindow isMiniaturized]) - [m_nsWindow deminiaturize : m_nsWindow]; + if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) { + [m_nsWindow performZoom : m_nsWindow]; // toggles + } - if ([m_nsWindow isZoomed]) - [m_nsWindow performZoom : m_nsWindow]; // toggles + if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) { + if (newState & Qt::WindowMinimized) { + [m_nsWindow performMiniaturize : m_nsWindow]; + } else { + [m_nsWindow deminiaturize : m_nsWindow]; + } + } + if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { - if (window()->windowState() & Qt::WindowFullScreen) - [m_nsWindow toggleFullScreen : m_nsWindow]; - } else { - qWarning("Not implemented: setWindowState WindowFullScreen"); - } + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { + [m_nsWindow toggleFullScreen : m_nsWindow]; + } else { + // TODO: "normal" fullscreen + } #endif - break; } + + // New state is now the current synched state + m_synchedWindowState = newState; } bool QCocoaWindow::setWindowModified(bool modified) @@ -587,3 +798,29 @@ bool QCocoaWindow::setWindowModified(bool modified) [m_nsWindow setDocumentEdited:(modified?YES:NO)]; return true; } + +void QCocoaWindow::setMenubar(QCocoaMenuBar *mb) +{ + m_menubar = mb; +} + +QCocoaMenuBar *QCocoaWindow::menubar() const +{ + return m_menubar; +} + +QMargins QCocoaWindow::frameMargins() const +{ + NSRect frameW = [m_nsWindow frame]; + NSRect frameC = [m_nsWindow contentRectForFrameRect:frameW]; + + return QMargins(frameW.origin.x - frameC.origin.x, + (frameW.origin.y + frameW.size.height) - (frameC.origin.y + frameC.size.height), + (frameW.origin.x + frameW.size.width) - (frameC.origin.x + frameC.size.width), + frameC.origin.y - frameW.origin.y); +} + +void QCocoaWindow::setFrameStrutEventsEnabled(bool enabled) +{ + m_frameStrutEventsEnabled = enabled; +}