summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r--src/plugins/platforms/cocoa/messages.cpp5
-rw-r--r--src/plugins/platforms/cocoa/messages.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplication.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h30
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm28
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h65
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm555
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm51
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm4
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm126
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac_p.h1
18 files changed, 652 insertions, 238 deletions
diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp
index 3db1618a50..1fe80b28b1 100644
--- a/src/plugins/platforms/cocoa/messages.cpp
+++ b/src/plugins/platforms/cocoa/messages.cpp
@@ -93,4 +93,9 @@ QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption)
return QPlatformMenuItem::NoRole;
}
+QString msgDialogButtonDiscard()
+{
+ return QCoreApplication::translate("QCocoaTheme", "Don't Save");
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/messages.h b/src/plugins/platforms/cocoa/messages.h
index 09705c1e21..97f3ea7009 100644
--- a/src/plugins/platforms/cocoa/messages.h
+++ b/src/plugins/platforms/cocoa/messages.h
@@ -53,6 +53,8 @@ QString qt_mac_applicationmenu_string(int type);
QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption);
+QString msgDialogButtonDiscard();
+
QT_END_NAMESPACE
#endif // MESSAGES_H
diff --git a/src/plugins/platforms/cocoa/qcocoaapplication.h b/src/plugins/platforms/cocoa/qcocoaapplication.h
index ffb12ea846..bb218bcabe 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplication.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplication.h
@@ -86,7 +86,7 @@
//
/*
- Cocoa Application Categories
+ Cocoa Application Categories
*/
#include "qglobal.h"
#include "private/qcore_mac_p.h"
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index f9767ce716..327ca00ad6 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -114,7 +114,7 @@ static void cleanupCocoaApplicationDelegate()
- (void)updateScreens:(NSNotification *)notification
{
Q_UNUSED(notification);
- if (QCocoaIntegration *ci = dynamic_cast<QCocoaIntegration *>(QGuiApplicationPrivate::platformIntegration()))
+ if (QCocoaIntegration *ci = QCocoaIntegration::instance())
ci->updateScreens();
}
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index 8f74a71b1e..4b637a707d 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -143,7 +143,7 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo
[pixelFormat release];
- const GLint interval = 1;
+ const GLint interval = format.swapInterval() >= 0 ? format.swapInterval() : 1;
[m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
if (format.alphaBufferSize() > 0) {
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 3e402673f3..64e1640a69 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -116,6 +116,7 @@ inline NSPoint qt_mac_flipPoint(const QPoint &p)
inline NSPoint qt_mac_flipPoint(const QPointF &p)
{ return NSMakePoint(p.x(), qt_mac_flipYCoordinate(p.y())); }
+NSRect qt_mac_flipRect(const QRect &rect);
NSRect qt_mac_flipRect(const QRect &rect, QWindow *window);
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 4a5696b35e..d27c134fa3 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -585,6 +585,12 @@ QString qt_mac_applicationName()
return appName;
}
+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
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 111329aaee..8babfcf8ae 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -46,6 +46,10 @@
#include "qcocoaautoreleasepool.h"
#include "qcocoacursor.h"
+#include "qcocoawindow.h"
+#include "qcocoanativeinterface.h"
+#include "qcocoainputcontext.h"
+#include "qcocoaaccessibility.h"
#include "qcocoaclipboard.h"
#include "qcocoadrag.h"
#include "qcocoaservices.h"
@@ -53,6 +57,7 @@
#include <QtCore/QScopedPointer>
#include <qpa/qplatformintegration.h>
+#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
QT_BEGIN_NAMESPACE
@@ -103,23 +108,25 @@ public:
QCocoaIntegration();
~QCocoaIntegration();
+ static QCocoaIntegration *instance();
+
bool hasCapability(QPlatformIntegration::Capability cap) const;
QPlatformWindow *createPlatformWindow(QWindow *window) const;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
QPlatformBackingStore *createPlatformBackingStore(QWindow *widget) const;
QAbstractEventDispatcher *createEventDispatcher() const;
- QPlatformFontDatabase *fontDatabase() const;
- QPlatformNativeInterface *nativeInterface() const;
- QPlatformInputContext *inputContext() const;
- QPlatformAccessibility *accessibility() const;
- QPlatformClipboard *clipboard() const;
- QPlatformDrag *drag() const;
+ QCoreTextFontDatabase *fontDatabase() const;
+ QCocoaNativeInterface *nativeInterface() const;
+ QCocoaInputContext *inputContext() const;
+ QCocoaAccessibility *accessibility() const;
+ QCocoaClipboard *clipboard() const;
+ QCocoaDrag *drag() const;
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
- QPlatformServices *services() const;
+ QCocoaServices *services() const;
QVariant styleHint(StyleHint hint) const;
QList<int> possibleKeys(const QKeyEvent *event) const;
@@ -128,18 +135,19 @@ public:
QCocoaScreen *screenAtIndex(int index);
private:
+ static QCocoaIntegration *mInstance;
- QScopedPointer<QPlatformFontDatabase> mFontDb;
+ QScopedPointer<QCoreTextFontDatabase> mFontDb;
- QScopedPointer<QPlatformInputContext> mInputContext;
+ QScopedPointer<QCocoaInputContext> mInputContext;
#ifndef QT_NO_ACCESSIBILITY
- QScopedPointer<QPlatformAccessibility> mAccessibility;
+ QScopedPointer<QCocoaAccessibility> mAccessibility;
#endif
QScopedPointer<QPlatformTheme> mPlatformTheme;
QList<QCocoaScreen *> mScreens;
QCocoaClipboard *mCocoaClipboard;
QScopedPointer<QCocoaDrag> mCocoaDrag;
- QScopedPointer<QPlatformNativeInterface> mNativeInterface;
+ QScopedPointer<QCocoaNativeInterface> mNativeInterface;
QScopedPointer<QCocoaServices> mServices;
QScopedPointer<QCocoaKeyMapper> mKeyboardMapper;
};
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 5f01274d98..e8cf5ca69b 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -58,7 +58,6 @@
#include <qpa/qplatformaccessibility.h>
#include <QtCore/qcoreapplication.h>
-#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
#include <IOKit/graphics/IOGraphicsLib.h>
static void initResources()
@@ -214,6 +213,8 @@ QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height
return windowPixmap;
}
+QCocoaIntegration *QCocoaIntegration::mInstance = 0;
+
QCocoaIntegration::QCocoaIntegration()
: mFontDb(new QCoreTextFontDatabase())
, mInputContext(new QCocoaInputContext)
@@ -226,6 +227,10 @@ QCocoaIntegration::QCocoaIntegration()
, mServices(new QCocoaServices)
, mKeyboardMapper(new QCocoaKeyMapper)
{
+ if (mInstance != 0)
+ qWarning("Creating multiple Cocoa platform integrations is not supported");
+ mInstance = this;
+
initResources();
QCocoaAutoReleasePool pool;
@@ -273,6 +278,8 @@ QCocoaIntegration::QCocoaIntegration()
QCocoaIntegration::~QCocoaIntegration()
{
+ mInstance = 0;
+
qt_resetNSApplicationSendEvent();
QCocoaAutoReleasePool pool;
@@ -296,6 +303,11 @@ QCocoaIntegration::~QCocoaIntegration()
}
}
+QCocoaIntegration *QCocoaIntegration::instance()
+{
+ return mInstance;
+}
+
/*!
\brief Synchronizes the screen list, adds new screens, removes deleted ones
*/
@@ -388,22 +400,22 @@ QAbstractEventDispatcher *QCocoaIntegration::createEventDispatcher() const
return new QCocoaEventDispatcher;
}
-QPlatformFontDatabase *QCocoaIntegration::fontDatabase() const
+QCoreTextFontDatabase *QCocoaIntegration::fontDatabase() const
{
return mFontDb.data();
}
-QPlatformNativeInterface *QCocoaIntegration::nativeInterface() const
+QCocoaNativeInterface *QCocoaIntegration::nativeInterface() const
{
return mNativeInterface.data();
}
-QPlatformInputContext *QCocoaIntegration::inputContext() const
+QCocoaInputContext *QCocoaIntegration::inputContext() const
{
return mInputContext.data();
}
-QPlatformAccessibility *QCocoaIntegration::accessibility() const
+QCocoaAccessibility *QCocoaIntegration::accessibility() const
{
#ifndef QT_NO_ACCESSIBILITY
return mAccessibility.data();
@@ -412,12 +424,12 @@ QPlatformAccessibility *QCocoaIntegration::accessibility() const
#endif
}
-QPlatformClipboard *QCocoaIntegration::clipboard() const
+QCocoaClipboard *QCocoaIntegration::clipboard() const
{
return mCocoaClipboard;
}
-QPlatformDrag *QCocoaIntegration::drag() const
+QCocoaDrag *QCocoaIntegration::drag() const
{
return mCocoaDrag.data();
}
@@ -434,7 +446,7 @@ QPlatformTheme *QCocoaIntegration::createPlatformTheme(const QString &name) cons
return QPlatformIntegration::createPlatformTheme(name);
}
-QPlatformServices *QCocoaIntegration::services() const
+QCocoaServices *QCocoaIntegration::services() const
{
return mServices.data();
}
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
index 5c59c73847..4bcb348acb 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
@@ -137,6 +137,7 @@ private:
static void setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness);
};
+QT_END_NAMESPACE
+
#endif // QCOCOANATIVEINTERFACE_H
-QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index e4237c9b3e..d60cdf10d1 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -73,6 +73,7 @@ public:
QPlatformTheme::IconOptions options = 0) const;
QVariant themeHint(ThemeHint hint) const;
+ QString standardButtonText(int button) const Q_DECL_OVERRIDE;
static const char *name;
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index d863861288..109649f24e 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -42,6 +42,7 @@
#import <Cocoa/Cocoa.h>
#include "qcocoatheme.h"
+#include "messages.h"
#include <QtCore/QVariant>
@@ -300,6 +301,11 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
return QPlatformTheme::themeHint(hint);
}
+QString QCocoaTheme::standardButtonText(int button) const
+{
+ return button == QMessageDialogOptions::Discard ? msgDialogButtonDiscard() : QPlatformTheme::standardButtonText(button);
+}
+
QPlatformMenuItem *QCocoaTheme::createPlatformMenuItem() const
{
return new QCocoaMenuItem();
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 452be90108..7b9768fcd9 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -52,34 +52,32 @@
QT_FORWARD_DECLARE_CLASS(QCocoaWindow)
-@interface QNSWindow : NSWindow {
- @public QCocoaWindow *m_cocoaPlatformWindow;
-}
-
-- (void)clearPlatformWindow;
-- (BOOL)canBecomeKeyWindow;
-@end
+@class QNSWindowDelegate;
-@interface QNSPanel : NSPanel {
- @public QCocoaWindow *m_cocoaPlatformWindow;
+@interface QNSWindow : NSPanel {
+@public
+ QCocoaWindow *m_cocoaPlatformWindow;
}
+
- (void)clearPlatformWindow;
-- (BOOL)canBecomeKeyWindow;
@end
-@class QNSWindowDelegate;
-
QT_BEGIN_NAMESPACE
+
// QCocoaWindow
//
-// QCocoaWindow is an NSView (not an NSWindow!) in the sense
-// that it relies on a NSView for all event handling and
-// graphics output and does not require a NSWindow, except for
-// for the window-related functions like setWindowTitle.
+// A QCocoaWindow is backed by a NSView and optionally a NSWindow.
+//
+// The NSView is used for most event handling and graphics output.
//
-// As a consequence of this it is possible to embed the QCocoaWindow
-// in an NSView hierarchy by getting a pointer to the "backing"
-// NSView and not calling QCocoaWindow::show():
+// Top-level QWindows are always backed by a NSWindow in addition to
+// the NSView. Child QWindows can also be backed by NSWindows, which
+// enables proper stacking of GL Widgets and threaded GL rendering
+// to multiple contexts.
+//
+// It is possible to embed the QCocoaWindow in an NSView hierarchy
+// by getting a pointer to the backing NSView and not calling
+// QCocoaWindow::show():
//
// QWindow *qtWindow = new MyWindow();
// qtWindow->create();
@@ -100,6 +98,10 @@ public:
void setGeometry(const QRect &rect);
void setCocoaGeometry(const QRect &rect);
+ void clipChildWindows();
+ void clipWindow(const NSRect &clipRect);
+ void show(bool becauseOfAncestor = false);
+ void hide(bool becauseOfAncestor = false);
void setVisible(bool visible);
void setWindowFlags(Qt::WindowFlags flags);
void setWindowState(Qt::WindowState state);
@@ -135,6 +137,7 @@ public:
void windowDidResize();
bool windowShouldClose();
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
+ bool windowShouldBehaveAsPanel() const;
void setSynchedWindowStateFromWindow();
@@ -167,16 +170,16 @@ public:
void updateExposedGeometry();
QWindow *childWindowAt(QPoint windowPoint);
protected:
- // NSWindow handling. The QCocoaWindow/QNSView can either be displayed
- // in an existing NSWindow or in one created by Qt.
void recreateWindow(const QPlatformWindow *parentWindow);
- NSWindow *createNSWindow();
- void setNSWindow(NSWindow *window);
- void clearNSWindow(NSWindow *window);
+ QNSWindow *createNSWindow();
+ void setNSWindow(QNSWindow *window);
+ void clearNSWindow(QNSWindow *window);
QRect windowGeometry() const;
QCocoaWindow *parentCocoaWindow() const;
void syncWindowState(Qt::WindowState newState);
+ void reinsertChildWindow(QCocoaWindow *child);
+ void removeChildWindow(QCocoaWindow *child);
// private:
public: // for QNSView
@@ -185,12 +188,17 @@ public: // for QNSView
NSView *m_contentView;
QNSView *m_qtView;
- NSWindow *m_nsWindow;
+ QNSWindow *m_nsWindow;
+ QCocoaWindow *m_forwardWindow;
// TODO merge to one variable if possible
bool m_contentViewIsEmbedded; // true if the m_contentView is actually embedded in a "foreign" NSView hiearchy
bool m_contentViewIsToBeEmbedded; // true if the m_contentView is intended to be embedded in a "foreign" NSView hiearchy
+ QCocoaWindow *m_parentCocoaWindow;
+ bool m_isNSWindowChild; // this window is a non-top level QWindow with a NSWindow.
+ QList<QCocoaWindow *> m_childWindows;
+
QNSWindowDelegate *m_nsWindowDelegate;
Qt::WindowFlags m_windowFlags;
Qt::WindowState m_synchedWindowState;
@@ -211,6 +219,8 @@ public: // for QNSView
QRect m_exposedGeometry;
int m_registerTouchCount;
bool m_resizableTransientParent;
+ bool m_hiddenByClipping;
+ bool m_hiddenByAncestor;
static const int NoAlertRequest;
NSInteger m_alertRequest;
@@ -219,6 +229,11 @@ public: // for QNSView
bool m_drawContentBorderGradient;
int m_topContentBorderThickness;
int m_bottomContentBorderThickness;
+
+ // used by showFullScreen in fake mode
+ QRect m_normalGeometry;
+ Qt::WindowFlags m_oldWindowFlags;
+ NSApplicationPresentationOptions m_presentationOptions;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 211ecd60ab..70a08bbea5 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -80,15 +80,10 @@ static bool isMouseEvent(NSEvent *ev)
}
@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
@@ -104,11 +99,40 @@ static bool isMouseEvent(NSEvent *ev)
@implementation QNSWindow
+- (id)initWithContentRect:(NSRect)contentRect
+ styleMask:(NSUInteger)windowStyle
+ qPlatformWindow:(QCocoaWindow *)qpw
+{
+ self = [super initWithContentRect:contentRect
+ styleMask:windowStyle
+ backing:NSBackingStoreBuffered
+ defer:NO]; // Deferring window creation breaks OpenGL (the GL context is
+ // set up before the window is shown and needs a proper window)
+
+ if (self) {
+ m_cocoaPlatformWindow = qpw;
+ }
+ return self;
+}
+
- (BOOL)canBecomeKeyWindow
{
- // The default implementation returns NO for title-bar less windows,
- // override and return yes here to make sure popup windows such as
- // the combobox popup can become the key window.
+ // Prevent child NSWindows from becoming the key window in
+ // order keep the active apperance of the top-level window.
+ if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->m_isNSWindowChild)
+ return NO;
+
+ // Only tool or dialog windows should become key:
+ if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->windowShouldBehaveAsPanel()) {
+ Qt::WindowType type = m_cocoaPlatformWindow->window()->type();
+ if (type == Qt::Tool || type == Qt::Dialog)
+ return YES;
+ return NO;
+ }
+
+ // All other windows can become the key window. This includes
+ // popup windows such as the combobox popup, which is a title-bar
+ // less window that by default can't become key.
return YES;
}
@@ -118,7 +142,11 @@ static bool isMouseEvent(NSEvent *ev)
// Windows with a transient parent (such as combobox popup windows)
// cannot become the main window:
- if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->window()->transientParent())
+ if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->m_isNSWindowChild
+ || m_cocoaPlatformWindow->window()->transientParent())
+ canBecomeMain = NO;
+
+ if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->windowShouldBehaveAsPanel())
canBecomeMain = NO;
return canBecomeMain;
@@ -126,47 +154,24 @@ static bool isMouseEvent(NSEvent *ev)
- (void) sendEvent: (NSEvent*) theEvent
{
- [super sendEvent: theEvent];
+ if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->m_forwardWindow) {
+ if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) {
+ QNSView *forwardView = m_cocoaPlatformWindow->m_qtView;
+ if (theEvent.type == NSLeftMouseUp) {
+ [forwardView mouseUp:theEvent];
+ m_cocoaPlatformWindow->m_forwardWindow = 0;
+ } else {
+ [forwardView mouseDragged:theEvent];
+ }
- if (!m_cocoaPlatformWindow)
- return;
+ 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];
+ if (theEvent.type == NSLeftMouseDown) {
+ m_cocoaPlatformWindow->m_forwardWindow = 0;
}
}
-}
-
-- (void)clearPlatformWindow
-{
- m_cocoaPlatformWindow = 0;
-}
-
-@end
-
-@implementation QNSPanel
-
-- (BOOL)canBecomeKeyWindow
-{
- if (!m_cocoaPlatformWindow)
- return NO;
- // Only tool or dialog windows should become key:
- if (m_cocoaPlatformWindow
- && (m_cocoaPlatformWindow->window()->type() == Qt::Tool || m_cocoaPlatformWindow->window()->type() == Qt::Dialog))
- return YES;
- return NO;
-}
-
-- (void) sendEvent: (NSEvent*) theEvent
-{
[super sendEvent: theEvent];
if (!m_cocoaPlatformWindow)
@@ -199,8 +204,11 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_contentView(nil)
, m_qtView(nil)
, m_nsWindow(0)
+ , m_forwardWindow(0)
, m_contentViewIsEmbedded(false)
, m_contentViewIsToBeEmbedded(false)
+ , m_parentCocoaWindow(0)
+ , m_isNSWindowChild(false)
, m_nsWindowDelegate(0)
, m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal)
@@ -215,11 +223,14 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_isExposed(false)
, m_registerTouchCount(0)
, m_resizableTransientParent(false)
+ , m_hiddenByClipping(false)
+ , m_hiddenByAncestor(false)
, m_alertRequest(NoAlertRequest)
, monitor(nil)
, m_drawContentBorderGradient(false)
, m_topContentBorderThickness(0)
, m_bottomContentBorderThickness(0)
+ , m_normalGeometry(QRect(0,0,-1,-1))
{
#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
qDebug() << "QCocoaWindow::QCocoaWindow" << this;
@@ -259,8 +270,21 @@ QCocoaWindow::~QCocoaWindow()
QCocoaAutoReleasePool pool;
clearNSWindow(m_nsWindow);
- if (parent())
+ if (m_isNSWindowChild) {
+ if (m_parentCocoaWindow)
+ m_parentCocoaWindow->removeChildWindow(this);
+ } else if (parent()) {
[m_contentView removeFromSuperview];
+ } else if (m_qtView) {
+ [[NSNotificationCenter defaultCenter] removeObserver:m_qtView
+ name:nil object:m_nsWindow];
+ }
+
+ foreach (QCocoaWindow *child, m_childWindows) {
+ [m_nsWindow removeChildWindow:child->m_nsWindow];
+ child->m_parentCocoaWindow = 0;
+ }
+
[m_contentView release];
[m_nsWindow release];
[m_nsWindowDelegate release];
@@ -272,8 +296,16 @@ QSurfaceFormat QCocoaWindow::format() const
return window()->requestedFormat();
}
-void QCocoaWindow::setGeometry(const QRect &rect)
+void QCocoaWindow::setGeometry(const QRect &rectIn)
{
+ QRect rect = rectIn;
+ // This means it is a call from QWindow::setFramePosition() and
+ // the coordinates include the frame (size is still the contents rectangle).
+ if (qt_window_private(const_cast<QWindow *>(window()))->positionPolicy
+ == QWindowPrivate::WindowFrameInclusive) {
+ const QMargins margins = frameMargins();
+ rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
+ }
if (geometry() == rect)
return;
#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
@@ -291,7 +323,16 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
return;
}
- if (m_nsWindow) {
+ if (m_isNSWindowChild) {
+ QPlatformWindow::setGeometry(rect);
+ NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow;
+ NSRect parentWindowFrame = [parentNSWindow contentRectForFrameRect:parentNSWindow.frame];
+ clipWindow(parentWindowFrame);
+
+ // call this here: updateGeometry in qnsview.mm is a no-op for this case
+ QWindowSystemInterface::handleGeometryChange(window(), rect);
+ QWindowSystemInterface::handleExposeEvent(window(), rect);
+ } else if (m_nsWindow) {
NSRect bounds = qt_mac_flipRect(rect, window());
[m_nsWindow setFrame:[m_nsWindow frameRectForContentRect:bounds] display:YES animate:NO];
} else {
@@ -301,8 +342,99 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect)
// will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm)
}
+void QCocoaWindow::clipChildWindows()
+{
+ foreach (QCocoaWindow *childWindow, m_childWindows) {
+ childWindow->clipWindow(m_nsWindow.frame);
+ }
+}
+
+void QCocoaWindow::clipWindow(const NSRect &clipRect)
+{
+ if (!m_isNSWindowChild)
+ return;
+
+ NSRect clippedWindowRect = NSZeroRect;
+ if (!NSIsEmptyRect(clipRect)) {
+ NSRect windowFrame = qt_mac_flipRect(QRect(window()->mapToGlobal(QPoint(0, 0)), geometry().size()), window());
+ clippedWindowRect = NSIntersectionRect(windowFrame, clipRect);
+ // Clipping top/left offsets the content. Move it back.
+ NSPoint contentViewOffset = NSMakePoint(qMax(CGFloat(0), NSMinX(clippedWindowRect) - NSMinX(windowFrame)),
+ qMax(CGFloat(0), NSMaxY(windowFrame) - NSMaxY(clippedWindowRect)));
+ [m_contentView setBoundsOrigin:contentViewOffset];
+ }
+
+ if (NSIsEmptyRect(clippedWindowRect)) {
+ if (!m_hiddenByClipping) {
+ // We dont call hide() here as we will recurse further down
+ [m_nsWindow orderOut:nil];
+ m_hiddenByClipping = true;
+ }
+ } else {
+ [m_nsWindow setFrame:clippedWindowRect display:YES animate:NO];
+ if (m_hiddenByClipping) {
+ m_hiddenByClipping = false;
+ if (!m_hiddenByAncestor) {
+ [m_nsWindow orderFront:nil];
+ m_parentCocoaWindow->reinsertChildWindow(this);
+ }
+ }
+ }
+
+ // recurse
+ foreach (QCocoaWindow *childWindow, m_childWindows) {
+ childWindow->clipWindow(clippedWindowRect);
+ }
+}
+
+void QCocoaWindow::hide(bool becauseOfAncestor)
+{
+ bool visible = [m_nsWindow isVisible];
+
+ if (!m_hiddenByAncestor && !visible) // Already explicitly hidden
+ return;
+ if (m_hiddenByAncestor && becauseOfAncestor) // Trying to hide some child again
+ return;
+
+ m_hiddenByAncestor = becauseOfAncestor;
+
+ if (!visible) // Could have been clipped before
+ return;
+
+ foreach (QCocoaWindow *childWindow, m_childWindows)
+ childWindow->hide(true);
+
+ [m_nsWindow orderOut:nil];
+}
+
+void QCocoaWindow::show(bool becauseOfAncestor)
+{
+ if ([m_nsWindow isVisible])
+ return;
+
+ if (m_parentCocoaWindow && ![m_parentCocoaWindow->m_nsWindow isVisible]) {
+ m_hiddenByAncestor = true; // Parent still hidden, don't show now
+ } else if ((becauseOfAncestor == m_hiddenByAncestor) // Was NEITHER explicitly hidden
+ && !m_hiddenByClipping) { // ... NOR clipped
+ if (m_isNSWindowChild) {
+ m_hiddenByAncestor = false;
+ setCocoaGeometry(window()->geometry());
+ }
+ if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status
+ [m_nsWindow orderFront:nil];
+ if (m_isNSWindowChild)
+ m_parentCocoaWindow->reinsertChildWindow(this);
+ foreach (QCocoaWindow *childWindow, m_childWindows)
+ childWindow->show(true);
+ }
+ }
+}
+
void QCocoaWindow::setVisible(bool visible)
{
+ if (m_isNSWindowChild && m_hiddenByClipping)
+ return;
+
QCocoaAutoReleasePool pool;
QCocoaWindow *parentCocoaWindow = 0;
if (window()->transientParent())
@@ -367,8 +499,10 @@ void QCocoaWindow::setVisible(bool visible)
m_hasModalSession = true;
} else if ([m_nsWindow canBecomeKeyWindow]) {
[m_nsWindow makeKeyAndOrderFront:nil];
+ foreach (QCocoaWindow *childWindow, m_childWindows)
+ childWindow->show(true);
} else {
- [m_nsWindow orderFront: nil];
+ show();
}
// We want the events to properly reach the popup, dialog, and tool
@@ -392,28 +526,27 @@ void QCocoaWindow::setVisible(bool visible)
// qDebug() << "close" << this;
if (m_glContext)
m_glContext->windowWasHidden();
+ QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
+ Q_ASSERT(cocoaEventDispatcher != 0);
+ QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
if (m_nsWindow) {
if (m_hasModalSession) {
- QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher());
- Q_ASSERT(cocoaEventDispatcher != 0);
- QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher));
cocoaEventDispatcherPrivate->endModalSession(window());
m_hasModalSession = false;
-
- [m_nsWindow orderOut:m_nsWindow];
- if (m_nsWindow == [NSApp keyWindow] && !cocoaEventDispatcherPrivate->currentModalSession()) {
- // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher
- // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that
- // the current NSWindow is still key after being ordered out. Then, after checking we
- // don't have any other modal session left, it's safe to make the main window key again.
- NSWindow *mainWindow = [NSApp mainWindow];
- if (mainWindow && [mainWindow canBecomeKeyWindow])
- [mainWindow makeKeyWindow];
- }
} else {
if ([m_nsWindow isSheet])
[NSApp endSheet:m_nsWindow];
- [m_nsWindow orderOut:m_nsWindow];
+ }
+
+ hide();
+ if (m_nsWindow == [NSApp keyWindow] && !cocoaEventDispatcherPrivate->currentModalSession()) {
+ // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher
+ // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that
+ // the current NSWindow is still key after being ordered out. Then, after checking we
+ // don't have any other modal session left, it's safe to make the main window key again.
+ NSWindow *mainWindow = [NSApp mainWindow];
+ if (mainWindow && [mainWindow canBecomeKeyWindow])
+ [mainWindow makeKeyWindow];
}
} else {
[m_contentView setHidden:YES];
@@ -520,7 +653,7 @@ void QCocoaWindow::setWindowShadow(Qt::WindowFlags flags)
void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
{
- if (m_nsWindow) {
+ if (m_nsWindow && !m_isNSWindowChild) {
NSUInteger styleMask = windowStyleMask(flags);
NSInteger level = this->windowLevel(flags);
[m_nsWindow setStyleMask:styleMask];
@@ -532,15 +665,21 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
- Qt::WindowType type = window()->type();
- if ((type & Qt::Popup) != Qt::Popup && (type & Qt::Dialog) != Qt::Dialog) {
- NSWindowCollectionBehavior behavior = [m_nsWindow collectionBehavior];
+ NSWindowCollectionBehavior behavior = [m_nsWindow collectionBehavior];
+ if (windowShouldBehaveAsPanel()) {
+ behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
+ behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
+ } else {
if (flags & Qt::WindowFullscreenButtonHint)
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
else
behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
- [m_nsWindow setCollectionBehavior:behavior];
}
+ [m_nsWindow setCollectionBehavior:behavior];
+
+ [m_nsWindow setAnimationBehavior:(flags & Qt::Popup) == Qt::Popup
+ ? NSWindowAnimationBehaviorUtilityWindow
+ : NSWindowAnimationBehaviorDefault];
}
#endif
}
@@ -618,16 +757,55 @@ void QCocoaWindow::raise()
// ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
if (!m_nsWindow)
return;
- if ([m_nsWindow isVisible])
- [m_nsWindow orderFront: m_nsWindow];
+ if (m_isNSWindowChild) {
+ QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows;
+ siblings.removeOne(this);
+ siblings.append(this);
+ if (m_hiddenByClipping)
+ return;
+ }
+ if ([m_nsWindow isVisible]) {
+ if (m_isNSWindowChild) {
+ // -[NSWindow orderFront:] doesn't work with attached windows.
+ // The only solution is to remove and add the child window.
+ // This will place it on top of all the other NSWindows.
+ NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow;
+ [parentNSWindow removeChildWindow:m_nsWindow];
+ [parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
+ } else {
+ [m_nsWindow orderFront: m_nsWindow];
+ }
+ }
}
void QCocoaWindow::lower()
{
if (!m_nsWindow)
return;
- if ([m_nsWindow isVisible])
- [m_nsWindow orderBack: m_nsWindow];
+ if (m_isNSWindowChild) {
+ QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows;
+ siblings.removeOne(this);
+ siblings.prepend(this);
+ if (m_hiddenByClipping)
+ return;
+ }
+ if ([m_nsWindow isVisible]) {
+ if (m_isNSWindowChild) {
+ // -[NSWindow orderBack:] doesn't work with attached windows.
+ // The only solution is to remove and add all the child windows except this one.
+ // This will keep the current window at the bottom while adding the others on top of it,
+ // hopefully in the same order (this is not documented anywhere in the Cocoa documentation).
+ NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow;
+ NSArray *children = [parentNSWindow.childWindows copy];
+ for (NSWindow *child in children)
+ if (m_nsWindow != child) {
+ [parentNSWindow removeChildWindow:child];
+ [parentNSWindow addChildWindow:child ordered:NSWindowAbove];
+ }
+ } else {
+ [m_nsWindow orderBack: m_nsWindow];
+ }
+ }
}
bool QCocoaWindow::isExposed() const
@@ -773,6 +951,9 @@ void QCocoaWindow::windowWillMove()
void QCocoaWindow::windowDidMove()
{
+ if (m_isNSWindowChild)
+ return;
+
[m_qtView updateGeometry];
}
@@ -781,6 +962,10 @@ void QCocoaWindow::windowDidResize()
if (!m_nsWindow)
return;
+ if (m_isNSWindowChild)
+ return;
+
+ clipChildWindows();
[m_qtView updateGeometry];
}
@@ -808,6 +993,14 @@ bool QCocoaWindow::windowIsPopupType(Qt::WindowType type) const
return ((type & Qt::Popup) == Qt::Popup);
}
+bool QCocoaWindow::windowShouldBehaveAsPanel() const
+{
+ // Before merging QNSPanel and QNSWindow, we used NSPanel for popup-type
+ // windows (Popup, Tool, ToolTip, SplashScreen) and dialogs
+ Qt::WindowType type = window()->type();
+ return (type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog;
+}
+
void QCocoaWindow::setCurrentContext(QCocoaGLContext *context)
{
m_glContext = context;
@@ -820,8 +1013,18 @@ QCocoaGLContext *QCocoaWindow::currentContext() const
void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
{
+ bool wasNSWindowChild = m_isNSWindowChild;
+ bool needsNSWindow = m_isNSWindowChild || !parentWindow;
+
+ QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow;
+ m_parentCocoaWindow = const_cast<QCocoaWindow *>(static_cast<const QCocoaWindow *>(parentWindow));
+
+ // No child QNSWindow should notify its QNSView
+ if (m_nsWindow && m_qtView && m_parentCocoaWindow && !oldParentCocoaWindow)
+ [[NSNotificationCenter defaultCenter] removeObserver:m_qtView
+ name:nil object:m_nsWindow];
// Remove current window (if any)
- if (m_nsWindow) {
+ if (m_nsWindow && !needsNSWindow) {
clearNSWindow(m_nsWindow);
[m_nsWindow close];
[m_nsWindow release];
@@ -830,22 +1033,64 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
m_nsWindowDelegate = 0;
}
+ if (needsNSWindow) {
+ bool noPreviousWindow = m_nsWindow == 0;
+ if (noPreviousWindow)
+ m_nsWindow = createNSWindow();
+
+ // Only non-child QNSWindows should notify their QNSViews
+ // (but don't register more than once).
+ if (m_qtView && (noPreviousWindow || (wasNSWindowChild && !m_isNSWindowChild)))
+ [[NSNotificationCenter defaultCenter] addObserver:m_qtView
+ selector:@selector(windowNotification:)
+ name:nil // Get all notifications
+ object:m_nsWindow];
+
+ if (oldParentCocoaWindow) {
+ if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow)
+ oldParentCocoaWindow->removeChildWindow(this);
+ m_forwardWindow = oldParentCocoaWindow;
+ }
+
+ setNSWindow(m_nsWindow);
+ }
+
+
if (m_contentViewIsToBeEmbedded) {
// An embedded window doesn't have its own NSWindow.
} else if (!parentWindow) {
- // Create a new NSWindow if this is a top-level window.
- m_nsWindow = createNSWindow();
- setNSWindow(m_nsWindow);
-
// QPlatformWindow subclasses must sync up with QWindow on creation:
propagateSizeHints();
setWindowFlags(window()->flags());
setWindowTitle(window()->title());
setWindowState(window()->windowState());
+ } else if (m_isNSWindowChild) {
+ m_nsWindow.styleMask = NSBorderlessWindowMask;
+ m_nsWindow.hasShadow = NO;
+ m_nsWindow.level = NSNormalWindowLevel;
+ NSWindowCollectionBehavior collectionBehavior =
+ NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+ if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
+ collectionBehavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
+ m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone;
+ }
+#endif
+ m_nsWindow.collectionBehavior = collectionBehavior;
+ setCocoaGeometry(window()->geometry());
+
+ QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows;
+ if (siblings.contains(this)) {
+ if (!m_hiddenByClipping)
+ m_parentCocoaWindow->reinsertChildWindow(this);
+ } else {
+ if (!m_hiddenByClipping)
+ [m_parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
+ siblings.append(this);
+ }
} else {
// Child windows have no NSWindow, link the NSViews instead.
- const QCocoaWindow *parentCococaWindow = static_cast<const QCocoaWindow *>(parentWindow);
- [parentCococaWindow->m_contentView addSubview : m_contentView];
+ [m_parentCocoaWindow->m_contentView addSubview : m_contentView];
QRect rect = window()->geometry();
NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
[m_contentView setFrame:frame];
@@ -857,6 +1102,19 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
setOpacity(opacity);
}
+void QCocoaWindow::reinsertChildWindow(QCocoaWindow *child)
+{
+ int childIndex = m_childWindows.indexOf(child);
+ Q_ASSERT(childIndex != -1);
+
+ for (int i = childIndex; i < m_childWindows.size(); i++) {
+ NSWindow *nsChild = m_childWindows[i]->m_nsWindow;
+ if (i != childIndex)
+ [m_nsWindow removeChildWindow:nsChild];
+ [m_nsWindow addChildWindow:nsChild ordered:NSWindowAbove];
+ }
+}
+
void QCocoaWindow::requestActivateWindow()
{
NSWindow *window = [m_contentView window];
@@ -864,63 +1122,33 @@ void QCocoaWindow::requestActivateWindow()
[ window makeKeyWindow ];
}
-NSWindow * QCocoaWindow::createNSWindow()
+QNSWindow * QCocoaWindow::createNSWindow()
{
QCocoaAutoReleasePool pool;
QRect rect = initialGeometry(window(), window()->geometry(), defaultWindowWidth, defaultWindowHeight);
NSRect frame = qt_mac_flipRect(rect, window());
- Qt::WindowType type = window()->type();
Qt::WindowFlags flags = window()->flags();
- NSUInteger styleMask = windowStyleMask(flags);
- NSWindow *createdWindow = 0;
-
- // Use NSPanel for popup-type windows. (Popup, Tool, ToolTip, SplashScreen)
- // and dialogs
- if ((type & Qt::Popup) == Qt::Popup || (type & Qt::Dialog) == Qt::Dialog) {
- QNSPanel *window;
- window = [[QNSPanel alloc] initWithContentRect:frame
- styleMask: styleMask
- backing:NSBackingStoreBuffered
- defer:NO]; // Deferring window creation breaks OpenGL (the GL context is set up
- // before the window is shown and needs a proper window.).
- if ((type & Qt::Popup) == Qt::Popup)
- [window setHasShadow:YES];
- [window setHidesOnDeactivate: NO];
-
-#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];
-
- if ((type & Qt::Popup) == Qt::Popup)
- [window setAnimationBehavior:NSWindowAnimationBehaviorUtilityWindow];
- }
-#endif
- window->m_cocoaPlatformWindow = this;
- createdWindow = window;
+ NSUInteger styleMask;
+ if (m_isNSWindowChild) {
+ styleMask = NSBorderlessWindowMask;
} else {
- QNSWindow *window;
- window = [[QNSWindow alloc] initWithContentRect:frame
- styleMask: styleMask
- backing:NSBackingStoreBuffered
- 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;
-
- createdWindow = window;
+ styleMask = windowStyleMask(flags);
}
+ QNSWindow *createdWindow = [[QNSWindow alloc] initWithContentRect:frame styleMask:styleMask qPlatformWindow:this];
+
+ Qt::WindowFlags type = window()->type();
+ createdWindow.hidesOnDeactivate = type == Qt::Tool || type == Qt::ToolTip;
+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
- if ([createdWindow respondsToSelector:@selector(setRestorable:)])
+ if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
[createdWindow setRestorable: NO];
+ }
#endif
- NSInteger level = windowLevel(flags);
- [createdWindow setLevel:level];
-
if (window()->format().alphaBufferSize() > 0) {
[createdWindow setBackgroundColor:[NSColor clearColor]];
[createdWindow setOpaque:NO];
@@ -933,10 +1161,12 @@ NSWindow * QCocoaWindow::createNSWindow()
return createdWindow;
}
-void QCocoaWindow::setNSWindow(NSWindow *window)
+void QCocoaWindow::setNSWindow(QNSWindow *window)
{
- m_nsWindowDelegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this];
- [window setDelegate:m_nsWindowDelegate];
+ if (!m_nsWindowDelegate) {
+ m_nsWindowDelegate = [[QNSWindowDelegate alloc] initWithQCocoaWindow:this];
+ [window setDelegate:m_nsWindowDelegate];
+ }
// Prevent Cocoa from releasing the window on close. Qt
// handles the close event asynchronously and we want to
@@ -944,31 +1174,33 @@ void QCocoaWindow::setNSWindow(NSWindow *window)
// QCocoaWindow is deleted by Qt.
[window setReleasedWhenClosed : NO];
-
- if (m_qtView)
- [[NSNotificationCenter defaultCenter] addObserver:m_qtView
- selector:@selector(windowNotification:)
- name:nil // Get all notifications
- object:m_nsWindow];
-
- [m_contentView setPostsFrameChangedNotifications: NO];
- [window setContentView:m_contentView];
- [m_contentView setPostsFrameChangedNotifications: YES];
+ if (window.contentView != m_contentView) {
+ [m_contentView setPostsFrameChangedNotifications: NO];
+ [window setContentView:m_contentView];
+ [m_contentView setPostsFrameChangedNotifications: YES];
+ }
}
-void QCocoaWindow::clearNSWindow(NSWindow *window)
+void QCocoaWindow::clearNSWindow(QNSWindow *window)
{
[window setContentView:nil];
[window setDelegate:nil];
[window clearPlatformWindow];
- [[NSNotificationCenter defaultCenter] removeObserver:m_contentView
- name:nil object:window];
+ if (m_isNSWindowChild) {
+ m_parentCocoaWindow->removeChildWindow(this);
+ }
+}
+
+void QCocoaWindow::removeChildWindow(QCocoaWindow *child)
+{
+ m_childWindows.removeOne(child);
+ [m_nsWindow removeChildWindow:child->m_nsWindow];
}
// Returns the current global screen geometry for the nswindow associated with this window.
QRect QCocoaWindow::windowGeometry() const
{
- if (!m_nsWindow)
+ if (!m_nsWindow || m_isNSWindowChild)
return geometry();
NSRect rect = [m_nsWindow frame];
@@ -1015,13 +1247,35 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState)
}
if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) {
+ bool fakeFullScreen = true;
#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 {
- // TODO: "normal" fullscreen
+ if (window()->flags() & Qt::WindowFullscreenButtonHint) {
+ fakeFullScreen = false;
+ [m_nsWindow toggleFullScreen : m_nsWindow];
+ }
}
#endif
+ if (fakeFullScreen) {
+ if (newState & Qt::WindowFullScreen) {
+ QScreen *screen = window()->screen();
+ if (screen) {
+ if (m_normalGeometry.width() < 0) {
+ m_oldWindowFlags = m_windowFlags;
+ window()->setFlags(window()->flags() | Qt::FramelessWindowHint);
+ m_normalGeometry = windowGeometry();
+ setGeometry(screen->geometry());
+ m_presentationOptions = [NSApp presentationOptions];
+ [NSApp setPresentationOptions : m_presentationOptions | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
+ }
+ }
+ } else {
+ window()->setFlags(m_oldWindowFlags);
+ setGeometry(m_normalGeometry);
+ m_normalGeometry.setRect(0, 0, -1, -1);
+ [NSApp setPresentationOptions : m_presentationOptions];
+ }
+ }
}
// New state is now the current synched state
@@ -1054,16 +1308,21 @@ void QCocoaWindow::setWindowCursor(NSCursor *cursor)
// for a popup window.) Qt expects the set cursor to "stick":
// it should be accociated with the window until a different
// cursor is set.
-
- // Cocoa has different abstractions. We can set the cursor *now*:
- if (m_windowUnderMouse)
- [cursor set];
- // or we can set the cursor on mouse enter/leave using tracking
- // areas. This is done in QNSView, save the cursor:
if (m_windowCursor != cursor) {
[m_windowCursor release];
m_windowCursor = [cursor retain];
}
+
+ // Use the built in cursor rect API if the QCocoaWindow has a NSWindow.
+ // Othervise, set the cursor if this window is under the mouse. In
+ // this case QNSView::cursorUpdate will set the cursor as the pointer
+ // moves.
+ if (m_nsWindow && m_qtView) {
+ [m_nsWindow invalidateCursorRectsForView : m_qtView];
+ } else {
+ if (m_windowUnderMouse)
+ [cursor set];
+ }
}
void QCocoaWindow::registerTouch(bool enable)
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index ed9aad1654..58c732de98 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -229,7 +229,21 @@ static QTouchDevice *touchDevice = 0;
- (void)updateGeometry
{
QRect geometry;
- if (m_platformWindow->m_nsWindow) {
+
+ if (m_platformWindow->m_isNSWindowChild) {
+ return;
+#if 0
+ //geometry = qt_mac_toQRect([self frame]);
+ qDebug() << "nsview updateGeometry" << m_platformWindow->window();
+ QRect screenRect = qt_mac_toQRect([m_platformWindow->m_nsWindow convertRectToScreen:[self frame]]);
+ qDebug() << "screenRect" << screenRect;
+
+ screenRect.moveTop(qt_mac_flipYCoordinate(screenRect.y() + screenRect.height()));
+ geometry = QRect(m_platformWindow->window()->parent()->mapFromGlobal(screenRect.topLeft()), screenRect.size());
+ qDebug() << "geometry" << geometry;
+#endif
+ //geometry = QRect(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y + screenRect.size.height), screenRect.size.width, screenRect.size.height);
+ } else if (m_platformWindow->m_nsWindow) {
// top level window, get window rect and flip y.
NSRect rect = [self frame];
NSRect windowRect = [[self window] frame];
@@ -310,10 +324,9 @@ static QTouchDevice *touchDevice = 0;
m_platformWindow->exposeWindow();
} else if (notificationName == NSWindowDidChangeScreenNotification) {
if (m_window) {
- QCocoaIntegration *ci = static_cast<QCocoaIntegration *>(QGuiApplicationPrivate::platformIntegration());
NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen];
if (screenIndex != NSNotFound) {
- QCocoaScreen *cocoaScreen = ci->screenAtIndex(screenIndex);
+ QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex);
QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen());
}
}
@@ -551,14 +564,20 @@ static QTouchDevice *touchDevice = 0;
QPointF qtWindowPoint;
QPointF qtScreenPoint;
- [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ QNSView *targetView = self;
+ if (m_platformWindow && m_platformWindow->m_forwardWindow
+ && (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)) {
+ targetView = m_platformWindow->m_forwardWindow->m_qtView;
+ }
+
+ [targetView convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
ulong timestamp = [theEvent timestamp] * 1000;
- QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
nativeDrag->setLastMouseEvent(theEvent, self);
Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]];
- QWindowSystemInterface::handleMouseEvent(m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers);
+ QWindowSystemInterface::handleMouseEvent(targetView->m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers);
}
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent
@@ -689,8 +708,18 @@ static QTouchDevice *touchDevice = 0;
-(void)cursorUpdate:(NSEvent *)theEvent
{
Q_UNUSED(theEvent)
- if (m_platformWindow->m_windowCursor)
+ // Set the cursor manually if there is no NSWindow.
+ if (!m_platformWindow->m_nsWindow && m_platformWindow->m_windowCursor)
[m_platformWindow->m_windowCursor set];
+ else
+ [super cursorUpdate:theEvent];
+}
+
+-(void)resetCursorRects
+{
+ // Use the cursor rect API if there is a NSWindow
+ if (m_platformWindow->m_nsWindow && m_platformWindow->m_windowCursor)
+ [self addCursorRect:[self visibleRect] cursor:m_platformWindow->m_windowCursor];
}
- (void)mouseMoved:(NSEvent *)theEvent
@@ -1619,7 +1648,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (NSDragOperation) draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
Q_UNUSED(isLocal);
- QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
}
@@ -1650,7 +1679,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
if ([sender draggingSource] != nil) {
- QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
response = QWindowSystemInterface::handleDrag(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed);
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
@@ -1678,14 +1707,14 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPlatformDropQtResponse response(false, Qt::IgnoreAction);
if ([sender draggingSource] != nil) {
- QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
response = QWindowSystemInterface::handleDrop(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed);
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
response = QWindowSystemInterface::handleDrop(m_window, &mimeData, qt_windowPoint, qtAllowed);
}
if (response.isAccepted()) {
- QCocoaDrag* nativeDrag = static_cast<QCocoaDrag *>(QGuiApplicationPrivate::platformIntegration()->drag());
+ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
nativeDrag->setAcceptedAction(response.acceptedAction());
}
return response.isAccepted();
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index e8f26aa8c4..a438950a55 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -45,7 +45,7 @@
#include "qcocoahelpers.h"
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
-#include <qpa/qplatformintegration.h>
+#include "qcocoaintegration.h"
#include <QtGui/qaccessible.h>
#include <QtCore/QDebug>
@@ -63,7 +63,7 @@
- (id)accessibilityAttributeValue:(NSString *)attribute {
// activate accessibility updates
- QGuiApplicationPrivate::platformIntegration()->accessibility()->setActive(true);
+ QCocoaIntegration::instance()->accessibility()->setActive(true);
if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
if (m_window->accessibleRoot())
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
index f363b1772f..3e92a45a62 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm
@@ -591,20 +591,43 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
return;
switch (key) {
- case PPK_CollateCopies:
+
+ // The following keys are properties or derived values and so cannot be set
+ case PPK_PageRect:
+ break;
+ case PPK_PaperRect:
+ break;
+ case PPK_PaperSources:
+ break;
+ case PPK_SupportsMultipleCopies:
+ break;
+ case PPK_SupportedResolutions:
break;
+
+ // The following keys are settings that are unsupported by the Mac PrintEngine
case PPK_ColorMode:
break;
- case PPK_Creator:
+ case PPK_CustomBase:
break;
- case PPK_DocumentName:
+ case PPK_Duplex:
+ // TODO Add support using PMSetDuplex / PMGetDuplex
+ break;
+ case PPK_FontEmbedding:
break;
case PPK_PageOrder:
+ // TODO Check if can be supported via Cups Options
break;
case PPK_PaperSource:
+ // TODO Check if can be supported via Cups Options
+ break;
+ case PPK_PrinterProgram:
break;
case PPK_SelectionOption:
break;
+ case PPK_WindowsPageSize:
+ break;
+
+ // The following keys are properties and settings that are supported by the Mac PrintEngine
case PPK_Resolution: {
PMPrinter printer;
UInt32 count;
@@ -633,7 +656,15 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean);
break;
}
-
+ case PPK_CollateCopies:
+ PMSetCollate(d->settings(), value.toBool());
+ break;
+ case PPK_Creator:
+ d->m_creator = value.toString();
+ break;
+ case PPK_DocumentName:
+ PMPrintSettingsSetJobName(d->settings(), QCFString(value.toString()));
+ break;
case PPK_FullPage:
d->fullPage = value.toBool();
break;
@@ -642,18 +673,15 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
PMSetCopies(d->settings(), value.toInt(), false);
break;
case PPK_Orientation: {
- if (d->state == QPrinter::Active) {
- qWarning("QMacPrintEngine::setOrientation: Orientation cannot be changed during a print job, ignoring change");
- } else {
- QPrinter::Orientation newOrientation = QPrinter::Orientation(value.toInt());
- if (d->hasCustomPaperSize && (d->orient != newOrientation))
- d->customSize = QSizeF(d->customSize.height(), d->customSize.width());
- d->orient = newOrientation;
- PMOrientation o = d->orient == QPrinter::Portrait ? kPMPortrait : kPMLandscape;
- PMSetOrientation(d->format(), o, false);
- PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean);
- }
- break; }
+ QPrinter::Orientation newOrientation = QPrinter::Orientation(value.toInt());
+ if (d->hasCustomPaperSize && (d->orient != newOrientation))
+ d->customSize = QSizeF(d->customSize.height(), d->customSize.width());
+ d->orient = newOrientation;
+ PMOrientation o = d->orient == QPrinter::Portrait ? kPMPortrait : kPMLandscape;
+ PMSetOrientation(d->format(), o, false);
+ PMSessionValidatePageFormat(d->session(), d->format(), kPMDontWantBoolean);
+ break;
+ }
case PPK_OutputFileName:
d->outputFilename = value.toString();
break;
@@ -709,9 +737,7 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
d->hasCustomPageMargins = true;
break;
}
-
- default:
- break;
+ // No default so that compiler will complain if new keys added and not handled in this engine
}
}
@@ -724,16 +750,63 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
return *d->valueCache.find(key);
switch (key) {
- case PPK_CollateCopies:
- ret = false;
- break;
+
+ // The following keys are settings that are unsupported by the Mac PrintEngine
+ // Return sensible default values to ensure consistent behavior across platforms
case PPK_ColorMode:
ret = QPrinter::Color;
break;
+ case PPK_CustomBase:
+ // Special case, leave null
+ break;
+ case PPK_Duplex:
+ // TODO Add support using PMSetDuplex / PMGetDuplex
+ ret = QPrinter::DuplexNone;
+ break;
+ case PPK_FontEmbedding:
+ ret = false;
+ break;
+ case PPK_PageOrder:
+ // TODO Check if can be supported via Cups Options
+ ret = QPrinter::FirstPageFirst;
+ break;
+ case PPK_PaperSource:
+ // TODO Check if can be supported via Cups Options
+ ret = QPrinter::Auto;
+ break;
+ case PPK_PaperSources: {
+ // TODO Check if can be supported via Cups Options
+ QList<QVariant> out;
+ out << int(QPrinter::Auto);
+ ret = out;
+ break;
+ }
+ case PPK_PrinterProgram:
+ ret = QString();
+ break;
+ case PPK_SelectionOption:
+ ret = QString();
+ break;
+ case PPK_WindowsPageSize:
+ // Special case, leave null
+ break;
+
+ // The following keys are properties and settings that are supported by the Mac PrintEngine
+ case PPK_CollateCopies: {
+ Boolean status;
+ PMGetCollate(d->settings(), &status);
+ ret = bool(status);
+ break;
+ }
case PPK_Creator:
+ ret = d->m_creator;
break;
- case PPK_DocumentName:
+ case PPK_DocumentName: {
+ CFStringRef name;
+ PMPrintSettingsGetJobName(d->settings(), &name);
+ ret = QCFString::toQString(name);
break;
+ }
case PPK_FullPage:
ret = d->fullPage;
break;
@@ -757,10 +830,6 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
case PPK_OutputFileName:
ret = d->outputFilename;
break;
- case PPK_PageOrder:
- break;
- case PPK_PaperSource:
- break;
case PPK_PageRect: {
// PageRect is returned in device pixels
QRect r;
@@ -855,8 +924,7 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
ret = margins;
break;
}
- default:
- break;
+ // No default so that compiler will complain if new keys added and not handled in this engine
}
return ret;
}
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
index 644a07184f..e3a8520811 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
@@ -125,6 +125,7 @@ public:
NSPrintInfo *printInfo;
PMResolution resolution;
QString outputFilename;
+ QString m_creator;
bool fullPage;
QPaintEngine *paintEngine;
bool hasCustomPaperSize;