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.cpp8
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm43
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm101
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm37
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm63
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm15
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuloader.mm3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamimetypes.mm67
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.h17
-rw-r--r--src/plugins/platforms/cocoa/qcocoanativeinterface.mm33
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintdevice.mm18
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h9
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm93
-rw-r--r--src/plugins/platforms/cocoa/qmacclipboard.mm5
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm40
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm3
25 files changed, 473 insertions, 113 deletions
diff --git a/src/plugins/platforms/cocoa/messages.cpp b/src/plugins/platforms/cocoa/messages.cpp
index 1fe80b28b1..8fc8b312f5 100644
--- a/src/plugins/platforms/cocoa/messages.cpp
+++ b/src/plugins/platforms/cocoa/messages.cpp
@@ -90,6 +90,14 @@ QPlatformMenuItem::MenuRole detectMenuRole(const QString &caption)
|| caption.startsWith(QCoreApplication::translate("QCocoaMenuItem", "Exit"), Qt::CaseInsensitive)) {
return QPlatformMenuItem::QuitRole;
}
+ if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Cut"), Qt::CaseInsensitive))
+ return QPlatformMenuItem::CutRole;
+ if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Copy"), Qt::CaseInsensitive))
+ return QPlatformMenuItem::CopyRole;
+ if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Paste"), Qt::CaseInsensitive))
+ return QPlatformMenuItem::PasteRole;
+ if (!caption.compare(QCoreApplication::translate("QCocoaMenuItem", "Select All"), Qt::CaseInsensitive))
+ return QPlatformMenuItem::SelectAllRole;
return QPlatformMenuItem::NoRole;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
index 86bb5323a7..a78901bfb1 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
@@ -79,7 +79,7 @@ namespace QCocoaAccessible {
NSString *macRole(QAccessibleInterface *interface);
bool shouldBeIgnored(QAccessibleInterface *interface);
-NSArray *unignoredChildren(id parentObject, QAccessibleInterface *interface);
+NSArray *unignoredChildren(QAccessibleInterface *interface);
NSString *getTranslatedAction(const QString &qtAction);
NSMutableArray *createTranslatedActionsList(const QStringList &qtActions);
QString translateAction(NSString *nsAction);
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 990acd5301..72045a1bbb 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -55,19 +55,31 @@ QCocoaAccessibility::~QCocoaAccessibility()
void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
{
- QAccessible::Id interfaceId = event->uniqueId();
- if (!interfaceId)
+ QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: event->uniqueId()];
+ if (!element) {
+ qWarning() << "QCocoaAccessibility::notifyAccessibilityUpdate: invalid element";
return;
+ }
switch (event->type()) {
- case QAccessible::ValueChanged:
- case QAccessible::TextInserted :
- case QAccessible::TextRemoved :
- case QAccessible::TextUpdated : {
- QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId : interfaceId parent : nil];
- [element autorelease];
- NSAccessibilityPostNotification(element, NSAccessibilityValueChangedNotification);
- break; }
+ case QAccessible::Focus: {
+ NSAccessibilityPostNotification(element, NSAccessibilityFocusedUIElementChangedNotification);
+ break;
+ }
+ case QAccessible::StateChanged:
+ case QAccessible::ValueChanged:
+ case QAccessible::TextInserted:
+ case QAccessible::TextRemoved:
+ case QAccessible::TextUpdated:
+ NSAccessibilityPostNotification(element, NSAccessibilityValueChangedNotification);
+ break;
+ case QAccessible::TextCaretMoved:
+ case QAccessible::TextSelectionChanged:
+ NSAccessibilityPostNotification(element, NSAccessibilitySelectedTextChangedNotification);
+ break;
+ case QAccessible::NameChanged:
+ NSAccessibilityPostNotification(element, NSAccessibilityTitleChangedNotification);
+ break;
default:
break;
}
@@ -218,7 +230,7 @@ bool shouldBeIgnored(QAccessibleInterface *interface)
return false;
}
-NSArray *unignoredChildren(id parentObject, QAccessibleInterface *interface)
+NSArray *unignoredChildren(QAccessibleInterface *interface)
{
int numKids = interface->childCount();
// qDebug() << "Children for: " << axid << iface << " are: " << numKids;
@@ -231,9 +243,12 @@ NSArray *unignoredChildren(id parentObject, QAccessibleInterface *interface)
QAccessible::Id childId = QAccessible::uniqueId(child);
//qDebug() << " kid: " << childId << child;
- QCocoaAccessibleElement *element = [QCocoaAccessibleElement createElementWithId:childId parent:parentObject];
- [kids addObject: element];
- [element release];
+
+ QCocoaAccessibleElement *element = [QCocoaAccessibleElement elementWithId: childId];
+ if (element)
+ [kids addObject: element];
+ else
+ qWarning() << "QCocoaAccessibility: invalid child";
}
return NSAccessibilityUnignoredChildren(kids);
}
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index c207cbee2d..babaab5ae2 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -52,12 +52,11 @@
@interface QCocoaAccessibleElement : NSObject {
NSString *role;
- NSObject *parent;
QAccessible::Id axid;
}
-- (id)initWithId:(QAccessible::Id)anId parent:(id)aParent;
-+ (QCocoaAccessibleElement *)createElementWithId:(QAccessible::Id)anId parent:(id)aParent;
+- (id)initWithId:(QAccessible::Id)anId;
++ (QCocoaAccessibleElement *)elementWithId:(QAccessible::Id)anId;
@end
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 0b674b8d2f..1df4230385 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -41,6 +41,8 @@
#include "qcocoaaccessibilityelement.h"
#include "qcocoaaccessibility.h"
#include "qcocoahelpers.h"
+#include "qcocoawindow.h"
+#include "private/qaccessiblecache_p.h"
#include <QtGui/qaccessible.h>
@@ -48,7 +50,7 @@
@implementation QCocoaAccessibleElement
-- (id)initWithId:(QAccessible::Id)anId parent:(id)aParent
+- (id)initWithId:(QAccessible::Id)anId
{
Q_ASSERT((int)anId < 0);
self = [super init];
@@ -57,15 +59,35 @@
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
Q_ASSERT(iface);
role = QCocoaAccessible::macRole(iface);
- parent = aParent;
}
return self;
}
-+ (QCocoaAccessibleElement *)createElementWithId:(QAccessible::Id)anId parent:(id)aParent
++ (id)elementWithId:(QAccessible::Id)anId
{
- return [[self alloc] initWithId:anId parent:aParent];
+ Q_ASSERT(anId);
+ if (!anId)
+ return nil;
+
+ QAccessibleCache *cache = QAccessibleCache::instance();
+
+ QCocoaAccessibleElement *element = cache->elementForId(anId);
+ if (!element) {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(anId);
+ Q_ASSERT(iface);
+ if (!iface)
+ return nil;
+ element = [[self alloc] initWithId:anId];
+ cache->insertElement(anId, element);
+ }
+ return element;
+}
+
+- (void)invalidate {
+ axid = 0;
+ NSAccessibilityPostNotification(self, NSAccessibilityUIElementDestroyedNotification);
+ [self release];
}
- (void)dealloc {
@@ -98,6 +120,10 @@
return [NSNumber numberWithInt: newlines];
}
+- (BOOL) accessibilityNotifiesWhenDestroyed {
+ return YES;
+}
+
- (NSArray *)accessibilityAttributeNames {
static NSArray *defaultAttributes = nil;
@@ -116,6 +142,7 @@
NSAccessibilityTopLevelUIElementAttribute,
NSAccessibilityPositionAttribute,
NSAccessibilitySizeAttribute,
+ NSAccessibilityTitleAttribute,
NSAccessibilityDescriptionAttribute,
NSAccessibilityEnabledAttribute,
nil];
@@ -144,6 +171,26 @@
return [attributes autorelease];
}
+- (id)parentElement {
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+ if (!iface)
+ return nil;
+
+ if (QWindow *window = iface->window()) {
+ QCocoaWindow *win = static_cast<QCocoaWindow*>(window->handle());
+ return win->qtView();
+ }
+
+ QAccessibleInterface *parent = iface->parent();
+ if (!parent) {
+ qWarning() << "INVALID PARENT FOR INTERFACE: " << iface;
+ return nil;
+ }
+
+ QAccessible::Id parentId = QAccessible::uniqueId(parent);
+ return [QCocoaAccessibleElement elementWithId: parentId];
+}
+
- (id)accessibilityAttributeValue:(NSString *)attribute {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface) {
@@ -156,19 +203,19 @@
} else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
return NSAccessibilityRoleDescription(role, nil);
} else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
- return QCocoaAccessible::unignoredChildren(self, iface);
+ return QCocoaAccessible::unignoredChildren(iface);
} else if ([attribute isEqualToString:NSAccessibilityFocusedAttribute]) {
// Just check if the app thinks we're focused.
id focusedElement = [NSApp accessibilityAttributeValue:NSAccessibilityFocusedUIElementAttribute];
return [NSNumber numberWithBool:[focusedElement isEqual:self]];
} else if ([attribute isEqualToString:NSAccessibilityParentAttribute]) {
- return NSAccessibilityUnignoredAncestor(parent);
+ return NSAccessibilityUnignoredAncestor([self parentElement]);
} else if ([attribute isEqualToString:NSAccessibilityWindowAttribute]) {
// We're in the same window as our parent.
- return [parent accessibilityAttributeValue:NSAccessibilityWindowAttribute];
+ return [[self parentElement] accessibilityAttributeValue:NSAccessibilityWindowAttribute];
} else if ([attribute isEqualToString:NSAccessibilityTopLevelUIElementAttribute]) {
// We're in the same top level element as our parent.
- return [parent accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
+ return [[self parentElement] accessibilityAttributeValue:NSAccessibilityTopLevelUIElementAttribute];
} else if ([attribute isEqualToString:NSAccessibilityPositionAttribute]) {
QPoint qtPosition = iface->rect().topLeft();
QSize qtSize = iface->rect().size();
@@ -176,8 +223,10 @@
} else if ([attribute isEqualToString:NSAccessibilitySizeAttribute]) {
QSize qtSize = iface->rect().size();
return [NSValue valueWithSize: NSMakeSize(qtSize.width(), qtSize.height())];
- } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
+ } else if ([attribute isEqualToString:NSAccessibilityTitleAttribute]) {
return QCFString::toNSString(iface->text(QAccessible::Name));
+ } else if ([attribute isEqualToString:NSAccessibilityDescriptionAttribute]) {
+ return QCFString::toNSString(iface->text(QAccessible::Description));
} else if ([attribute isEqualToString:NSAccessibilityEnabledAttribute]) {
return [NSNumber numberWithBool:!iface->state().disabled];
} else if ([attribute isEqualToString:NSAccessibilityValueAttribute]) {
@@ -400,20 +449,26 @@
return NSAccessibilityUnignoredAncestor(self);
}
- QAccessibleInterface *childInterface = iface->childAt(point.x, qt_mac_flipYCoordinate(point.y));
-
+ int y = qt_mac_flipYCoordinate(point.y);
+ QAccessibleInterface *childInterface = iface->childAt(point.x, y);
// No child found, meaning we hit this element.
- if (!childInterface) {
-// qDebug() << "Hit test returns: " << id << iface;
+ if (!childInterface)
return NSAccessibilityUnignoredAncestor(self);
- }
+
+ // find the deepest child at the point
+ QAccessibleInterface *childOfChildInterface = 0;
+ do {
+ childOfChildInterface = childInterface->childAt(point.x, y);
+ if (childOfChildInterface)
+ childInterface = childOfChildInterface;
+ } while (childOfChildInterface);
QAccessible::Id childId = QAccessible::uniqueId(childInterface);
// hit a child, forward to child accessible interface.
- QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childId parent:self];
- [accessibleElement autorelease];
-
- return [accessibleElement accessibilityHitTest:point];
+ QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childId];
+ if (accessibleElement)
+ return NSAccessibilityUnignoredAncestor(accessibleElement);
+ return NSAccessibilityUnignoredAncestor(self);
}
- (id)accessibilityFocusedUIElement {
@@ -423,17 +478,15 @@
qWarning() << "FocusedUIElement for INVALID";
return nil;
}
+
QAccessibleInterface *childInterface = iface->focusChild();
if (childInterface) {
QAccessible::Id childAxid = QAccessible::uniqueId(childInterface);
- // FIXME: parent could be wrong
- QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self];
- [accessibleElement autorelease];
- return accessibleElement;
+ QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement elementWithId:childAxid];
+ return NSAccessibilityUnignoredAncestor(accessibleElement);
}
- // no focus found
- return nil;
+ return NSAccessibilityUnignoredAncestor(self);
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index 592bfc8e50..b81b9a0b1c 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -308,8 +308,7 @@ NSCursor *QCocoaCursor::createCursorFromBitmap(const QBitmap *bitmap, const QBit
NSCursor *QCocoaCursor::createCursorFromPixmap(const QPixmap pixmap, const QPoint hotspot)
{
- NSPoint hotSpot = NSMakePoint(hotspot.x() / pixmap.devicePixelRatio(),
- hotspot.y() / pixmap.devicePixelRatio());
+ NSPoint hotSpot = NSMakePoint(hotspot.x(), hotspot.y());
NSImage *nsimage;
if (pixmap.devicePixelRatio() > 1.0) {
QSize layoutSize = pixmap.size() / pixmap.devicePixelRatio();
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 8728ab8764..2b7b8109ad 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -52,6 +52,7 @@
#include <private/qguiapplication_p.h>
#include "qt_mac_p.h"
#include "qcocoahelpers.h"
+#include "qcocoamenubar.h"
#include <qregexp.h>
#include <qbuffer.h>
#include <qdebug.h>
@@ -225,6 +226,7 @@ static QString strippedText(QString s)
|| [self panel:nil shouldShowFilename:filepath];
[self updateProperties];
+ QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
[mOpenPanel setAllowedFileTypes:nil];
[mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : @""];
@@ -250,7 +252,9 @@ static QString strippedText(QString s)
// cleanup of modal sessions. Do this before showing the native dialog, otherwise it will
// close down during the cleanup.
qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
+ QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
mReturnCode = [mSavePanel runModal];
+ QCocoaMenuBar::resetKnownMenuItemsToQt();
QAbstractEventDispatcher::instance()->interrupt();
return (mReturnCode == NSOKButton);
@@ -269,6 +273,7 @@ static QString strippedText(QString s)
|| [self panel:nil shouldShowFilename:filepath];
[self updateProperties];
+ QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder();
[mSavePanel setDirectoryURL: [NSURL fileURLWithPath:mCurrentDir]];
[mSavePanel setNameFieldStringValue:selectable ? QCFString::toNSString(info.fileName()) : @""];
@@ -583,6 +588,7 @@ void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_selectionChanged(const QSt
void QCocoaFileDialogHelper::QNSOpenSavePanelDelegate_panelClosed(bool accepted)
{
+ QCocoaMenuBar::resetKnownMenuItemsToQt();
if (accepted) {
emit accept();
} else {
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index a73944c07c..9850f83dea 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -74,7 +74,7 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list)
{
NSMutableArray *result = [NSMutableArray arrayWithCapacity:list.size()];
for (int i=0; i<list.size(); ++i){
- [result addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(list[i]))];
+ [result addObject:list[i].toNSString()];
}
return result;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h
index 24adc7a95b..9c4f86d893 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.h
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.h
@@ -80,6 +80,7 @@ public:
qreal refreshRate() const { return m_refreshRate; }
QString name() const { return m_name; }
QPlatformCursor *cursor() const { return m_cursor; }
+ QWindow *topLevelAt(const QPoint &point) const;
QList<QPlatformScreen *> virtualSiblings() const { return m_siblings; }
// ----------------------------------------------------
@@ -138,6 +139,8 @@ public:
void setToolbar(QWindow *window, NSToolbar *toolbar);
NSToolbar *toolbar(QWindow *window) const;
void clearToolbars();
+ void setWindow(NSWindow* nsWindow, QCocoaWindow *window);
+ QCocoaWindow *window(NSWindow *window);
private:
static QCocoaIntegration *mInstance;
@@ -156,6 +159,7 @@ private:
QScopedPointer<QCocoaKeyMapper> mKeyboardMapper;
QHash<QWindow *, NSToolbar *> mToolbars;
+ QHash<NSWindow *, QCocoaWindow*> mWindows;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 412818ae47..c4398622e8 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -81,12 +81,16 @@ QCocoaScreen::~QCocoaScreen()
NSScreen *QCocoaScreen::osScreen() const
{
- return [[NSScreen screens] objectAtIndex:m_screenIndex];
+ NSArray *screens = [NSScreen screens];
+ return ((NSUInteger)m_screenIndex < [screens count]) ? [screens objectAtIndex:m_screenIndex] : nil;
}
void QCocoaScreen::updateGeometry()
{
NSScreen *nsScreen = osScreen();
+ if (!nsScreen)
+ return;
+
NSRect frameRect = [nsScreen frame];
if (m_screenIndex == 0) {
@@ -143,7 +147,8 @@ qreal QCocoaScreen::devicePixelRatio() const
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
- return qreal([osScreen() backingScaleFactor]);
+ NSScreen * screen = osScreen();
+ return qreal(screen ? [screen backingScaleFactor] : 1.0);
} else
#endif
{
@@ -151,6 +156,24 @@ qreal QCocoaScreen::devicePixelRatio() const
}
}
+QWindow *QCocoaScreen::topLevelAt(const QPoint &point) const
+{
+ // Get a z-ordered list of windows. Iterate through it until
+ // we find a window which contains the point.
+ for (NSWindow *nsWindow in [NSApp orderedWindows]) {
+ QCocoaWindow *cocoaWindow = QCocoaIntegration::instance()->window(nsWindow);
+ if (!cocoaWindow)
+ continue;
+ QWindow *window = cocoaWindow->window();
+ if (!window->isTopLevel())
+ continue;
+ if (window->geometry().contains(point))
+ return window;
+ }
+
+ return QPlatformScreen::topLevelAt(point);
+}
+
extern CGContextRef qt_mac_cg_context(const QPaintDevice *pdev);
QPixmap QCocoaScreen::grabWindow(WId window, int x, int y, int width, int height) const
@@ -495,6 +518,16 @@ NSToolbar *QCocoaIntegration::toolbar(QWindow *window) const
return mToolbars.value(window);
}
+void QCocoaIntegration::setWindow(NSWindow* nsWindow, QCocoaWindow *window)
+{
+ mWindows.insert(nsWindow, window);
+}
+
+QCocoaWindow *QCocoaIntegration::window(NSWindow *window)
+{
+ return mWindows.value(window);
+}
+
void QCocoaIntegration::clearToolbars()
{
QHash<QWindow *, NSToolbar *>::const_iterator it = mToolbars.constBegin();
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 35e8fdebb4..6acc062eb9 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -269,7 +269,6 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *
QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem);
QCocoaMenuItem *beforeItem = static_cast<QCocoaMenuItem *>(before);
- SET_COCOA_MENU_ANCESTOR(menuItem, this);
cocoaItem->sync();
if (beforeItem) {
int index = m_menuItems.indexOf(beforeItem);
@@ -315,6 +314,7 @@ void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem)
} else {
[m_nativeMenu addItem: item->nsItem()];
}
+ SET_COCOA_MENU_ANCESTOR(item, this);
}
void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index 7a1bda74a4..fa02a7870b 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -67,9 +67,13 @@ public:
inline NSMenu *nsMenu() const
{ return m_nativeMenu; }
+ static void redirectKnownMenuItemsToFirstResponder();
+ static void resetKnownMenuItemsToQt();
static void updateMenuBarImmediately();
QList<QCocoaMenuItem*> merged() const;
+ NSMenuItem *itemForRole(QPlatformMenuItem::MenuRole r);
+
private:
static QCocoaWindow *findWindowForMenubar();
static QCocoaMenuBar *findGlobalMenubar();
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 7335deb800..ffc0fabdce 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -205,6 +205,59 @@ QCocoaMenuBar *QCocoaMenuBar::findGlobalMenubar()
return NULL;
}
+void QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder()
+{
+ // QTBUG-17291: http://forums.macrumors.com/showthread.php?t=1249452
+ // When a dialog is opened, shortcuts for actions inside the dialog (cut, paste, ...)
+ // continue to go through the same menu items which claimed those shortcuts.
+ // They are not keystrokes which we can intercept in any other way; the OS intercepts them.
+ // The menu items had to be created by the application. That's why we need roles
+ // to identify those "special" menu items which can be useful even when non-Qt
+ // native widgets are in focus. When the native widget is focused it will be the
+ // first responder, so the menu item needs to have its target be the first responder;
+ // this is done by setting it to nil.
+
+ // This function will find all menu items on all menus which have
+ // "special" roles, set the target and also set the standard actions which
+ // apply to those roles. But afterwards it is necessary to call
+ // resetKnownMenuItemsToQt() to put back the target and action so that
+ // those menu items will go back to invoking their associated QActions.
+ foreach (QCocoaMenuBar *mb, static_menubars)
+ foreach (QCocoaMenu *m, mb->m_menus)
+ foreach (QCocoaMenuItem *i, m->items()) {
+ bool known = true;
+ switch (i->effectiveRole()) {
+ case QPlatformMenuItem::CutRole:
+ [i->nsItem() setAction:@selector(cut:)];
+ break;
+ case QPlatformMenuItem::CopyRole:
+ [i->nsItem() setAction:@selector(copy:)];
+ break;
+ case QPlatformMenuItem::PasteRole:
+ [i->nsItem() setAction:@selector(paste:)];
+ break;
+ case QPlatformMenuItem::SelectAllRole:
+ [i->nsItem() setAction:@selector(selectAll:)];
+ break;
+ // We may discover later that there are other roles/actions which
+ // are meaningful to standard native widgets; they can be added.
+ default:
+ known = false;
+ break;
+ }
+ if (known)
+ [i->nsItem() setTarget:nil];
+ }
+}
+
+void QCocoaMenuBar::resetKnownMenuItemsToQt()
+{
+ // Undo the effect of redirectKnownMenuItemsToFirstResponder():
+ // set the menu items' actions to itemFired and their targets to
+ // the QCocoaMenuDelegate.
+ updateMenuBarImmediately();
+}
+
void QCocoaMenuBar::updateMenuBarImmediately()
{
QCocoaAutoReleasePool pool;
@@ -321,3 +374,13 @@ QPlatformMenu *QCocoaMenuBar::menuForTag(quintptr tag) const
return 0;
}
+
+NSMenuItem *QCocoaMenuBar::itemForRole(QPlatformMenuItem::MenuRole r)
+{
+ foreach (QCocoaMenu *m, m_menus)
+ foreach (QCocoaMenuItem *i, m->items())
+ if (i->effectiveRole() == r)
+ return i->nsItem();
+ return Q_NULLPTR;
+}
+
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index b0169b9746..61706c19bc 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -98,6 +98,8 @@ public:
inline bool isSeparator() const { return m_isSeparator; }
QCocoaMenu *menu() const { return m_menu; }
+ MenuRole effectiveRole() const;
+
private:
QString mergeText();
QKeySequence mergeAccel();
@@ -112,6 +114,7 @@ private:
bool m_isSeparator;
QFont m_font;
MenuRole m_role;
+ MenuRole m_detectedRole;
QKeySequence m_shortcut;
bool m_checked;
bool m_merged;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index 2246d2ce46..58fe07bc62 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -227,7 +227,8 @@ NSMenuItem *QCocoaMenuItem::sync()
if (depth == 3 || !menubar)
break; // Menu item too deep in the hierarchy, or not connected to any menubar
- switch (detectMenuRole(m_text)) {
+ m_detectedRole = detectMenuRole(m_text);
+ switch (m_detectedRole) {
case QPlatformMenuItem::AboutRole:
if (m_text.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1)
mergeItem = [loader aboutMenuItem];
@@ -241,6 +242,8 @@ NSMenuItem *QCocoaMenuItem::sync()
mergeItem = [loader quitMenuItem];
break;
default:
+ if (m_detectedRole >= CutRole && m_detectedRole < RoleCount && menubar)
+ mergeItem = menubar->itemForRole(m_detectedRole);
if (!m_text.isEmpty())
m_textSynced = true;
break;
@@ -249,7 +252,7 @@ NSMenuItem *QCocoaMenuItem::sync()
}
default:
- qWarning() << Q_FUNC_INFO << "unsupported role" << (int) m_role;
+ qWarning() << Q_FUNC_INFO << "menu item" << m_text << "has unsupported role" << (int)m_role;
}
if (mergeItem) {
@@ -374,3 +377,11 @@ void QCocoaMenuItem::syncModalState(bool modal)
else
[m_native setEnabled:m_enabled];
}
+
+QPlatformMenuItem::MenuRole QCocoaMenuItem::effectiveRole() const
+{
+ if (m_role > TextHeuristicRole)
+ return m_role;
+ else
+ return m_detectedRole;
+}
diff --git a/src/plugins/platforms/cocoa/qcocoamenuloader.mm b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
index 29fc0fb674..60bc3b5a55 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuloader.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuloader.mm
@@ -115,14 +115,13 @@ QT_END_NAMESPACE
showAllItem = [[appMenu itemWithTitle:@"Show All"] retain];
// Get the names in the nib to match the app name set by Qt.
- const NSString *appName = reinterpret_cast<const NSString*>(QCFString::toCFStringRef(qt_mac_applicationName()));
+ const NSString *appName = qt_mac_applicationName().toNSString();
[quitItem setTitle:[[quitItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
withString:const_cast<NSString *>(appName)]];
[hideItem setTitle:[[hideItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
withString:const_cast<NSString *>(appName)]];
[aboutItem setTitle:[[aboutItem title] stringByReplacingOccurrencesOfString:@"NewApplication"
withString:const_cast<NSString *>(appName)]];
- [appName release];
// Disable the items that don't do anything. If someone associates a QAction with them
// They should get synced back in.
[preferencesItem setEnabled:NO];
diff --git a/src/plugins/platforms/cocoa/qcocoamimetypes.mm b/src/plugins/platforms/cocoa/qcocoamimetypes.mm
index 05d4c19112..8151d31449 100644
--- a/src/plugins/platforms/cocoa/qcocoamimetypes.mm
+++ b/src/plugins/platforms/cocoa/qcocoamimetypes.mm
@@ -136,9 +136,76 @@ QList<QByteArray> QMacPasteboardMimeTiff::convertFromMime(const QString &mime, Q
return ret;
}
+// This handler is special: It supports converting public.rtf top text/html,
+// but not the other way around.
+class QMacPasteboardMimeRtfText : public QMacInternalPasteboardMime {
+public:
+ QMacPasteboardMimeRtfText() : QMacInternalPasteboardMime(MIME_ALL) { }
+ QString convertorName();
+
+ QString flavorFor(const QString &mime);
+ QString mimeFor(QString flav);
+ bool canConvert(const QString &mime, QString flav);
+ QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav);
+ QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav);
+};
+
+QString QMacPasteboardMimeRtfText::convertorName()
+{
+ return QLatin1String("Rtf");
+}
+
+QString QMacPasteboardMimeRtfText::flavorFor(const QString &mime)
+{
+ if (mime == QLatin1String("text/html"))
+ return QLatin1String("public.rtf");
+ return QString();
+}
+
+QString QMacPasteboardMimeRtfText::mimeFor(QString flav)
+{
+ if (flav == QLatin1String("public.rtf"))
+ return QLatin1String("text/html");
+ return QString();
+}
+
+bool QMacPasteboardMimeRtfText::canConvert(const QString &mime, QString flav)
+{
+ return flavorFor(mime) == flav;
+}
+
+QVariant QMacPasteboardMimeRtfText::convertToMime(const QString &mimeType, QList<QByteArray> data, QString flavor)
+{
+ if (!canConvert(mimeType, flavor))
+ return QVariant();
+ if (data.count() > 1)
+ qWarning("QMacPasteboardMimeHTMLText: Cannot handle multiple member data");
+
+ // Convert Rtf to Html.
+ NSAttributedString *string = [[NSAttributedString alloc] initWithRTF:data.at(0).toNSData() documentAttributes:NULL];
+ NSError *error;
+ NSRange range = NSMakeRange(0,[string length]);
+ NSDictionary *dict = [NSDictionary dictionaryWithObject:NSHTMLTextDocumentType forKey:NSDocumentTypeDocumentAttribute];
+ NSData *htmldata = [string dataFromRange:range documentAttributes:dict error:&error];
+ [string release];
+ return QByteArray::fromNSData(htmldata);
+}
+
+QList<QByteArray> QMacPasteboardMimeRtfText::convertFromMime(const QString &mime, QVariant data, QString flavor)
+{
+ Q_UNUSED(mime);
+ Q_UNUSED(data);
+ Q_UNUSED(flavor);
+
+ qWarning("QMacPasteboardMimeRtfText: Conversion from Html to Rtf is not supported");
+ QList<QByteArray> ret;
+ return ret;
+}
+
void QCocoaMimeTypes::initializeMimeTypes()
{
new QMacPasteboardMimeTiff;
+ new QMacPasteboardMimeRtfText;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.h b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
index efdd433d8f..54e45a1d99 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.h
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.h
@@ -133,16 +133,23 @@ private:
// deregisters.
static void registerTouchWindow(QWindow *window, bool enable);
- // Request a unified title and toolbar look for the window.
+ // Enable the unified title and toolbar area for a window.
+ static void setContentBorderEnabled(QWindow *window, bool enable);
+
+ // Set the size of the unified title and toolbar area.
static void setContentBorderThickness(QWindow *window, int topThickness, int bottomThickness);
- // Request a unified title and toolbar look for the window by registering
- // an area. Multiple callers can register areas and the platform plugin
+ // Set the size for a unified toolbar content border area.
+ // Multiple callers can register areas and the platform plugin
// will extend the "unified" area to cover them.
static void registerContentBorderArea(QWindow *window, quintptr identifer, int upper, int lower);
- // Enable the unified title and toolbar area.
- static void enableContentBorderArea(QWindow *window, bool enable);
+ // Enables or disiables a content border area.
+ static void setContentBorderAreaEnabled(QWindow *window, quintptr identifier, bool enable);
+
+ // Returns true if the given coordinate is inside the current
+ // content border.
+ static bool testContentBorderPosition(QWindow *window, int position);
// Sets a NSToolbar instance for the given QWindow. The
// toolbar will be attached to the native NSWindow when
diff --git a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
index d6a5be8d52..e09c31231d 100644
--- a/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
+++ b/src/plugins/platforms/cocoa/qcocoanativeinterface.mm
@@ -127,10 +127,14 @@ QPlatformNativeInterface::NativeResourceForIntegrationFunction QCocoaNativeInter
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderThickness);
if (resource.toLower() == "registercontentborderarea")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::registerContentBorderArea);
- if (resource.toLower() == "enablecontentborderarea")
- return NativeResourceForIntegrationFunction(QCocoaNativeInterface::enableContentBorderArea);
+ if (resource.toLower() == "setcontentborderareaenabled")
+ return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderAreaEnabled);
+ if (resource.toLower() == "setcontentborderenabled")
+ return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setContentBorderEnabled);
if (resource.toLower() == "setnstoolbar")
return NativeResourceForIntegrationFunction(QCocoaNativeInterface::setNSToolbar);
+ if (resource.toLower() == "testcontentborderposition")
+ return NativeResourceForIntegrationFunction(QCocoaNativeInterface::testContentBorderPosition);
return 0;
}
@@ -301,14 +305,24 @@ void QCocoaNativeInterface::registerContentBorderArea(QWindow *window, quintptr
cocoaWindow->registerContentBorderArea(identifier, upper, lower);
}
-void QCocoaNativeInterface::enableContentBorderArea(QWindow *window, bool enable)
+void QCocoaNativeInterface::setContentBorderAreaEnabled(QWindow *window, quintptr identifier, bool enable)
{
if (!window)
return;
QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
if (cocoaWindow)
- cocoaWindow->enableContentBorderArea(enable);
+ cocoaWindow->setContentBorderAreaEnabled(identifier, enable);
+}
+
+void QCocoaNativeInterface::setContentBorderEnabled(QWindow *window, bool enable)
+{
+ if (!window)
+ return;
+
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
+ if (cocoaWindow)
+ cocoaWindow->setContentBorderEnabled(enable);
}
void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar)
@@ -320,4 +334,15 @@ void QCocoaNativeInterface::setNSToolbar(QWindow *window, void *nsToolbar)
cocoaWindow->updateNSToolbar();
}
+bool QCocoaNativeInterface::testContentBorderPosition(QWindow *window, int position)
+{
+ if (!window)
+ return false;
+
+ QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window->handle());
+ if (cocoaWindow)
+ return cocoaWindow->testContentBorderAreaPosition(position);
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
index 3061e84470..57d5c800e0 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
+++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm
@@ -171,15 +171,18 @@ QPrint::DeviceState QCocoaPrintDevice::state() const
QPageSize QCocoaPrintDevice::createPageSize(const PMPaper &paper) const
{
- QCFString key;
+ CFStringRef key;
double width;
double height;
- QCFString localizedName;
+ CFStringRef localizedName;
if (PMPaperGetPPDPaperName(paper, &key) == noErr
&& PMPaperGetWidth(paper, &width) == noErr
&& PMPaperGetHeight(paper, &height) == noErr
&& PMPaperCreateLocalizedName(paper, m_printer, &localizedName) == noErr) {
- return(QPlatformPrintDevice::createPageSize(key, QSize(width, height), localizedName));
+ QPageSize pageSize = QPlatformPrintDevice::createPageSize(QString::fromCFString(key),QSize(width, height),
+ QString::fromCFString(localizedName));
+ CFRelease(localizedName);
+ return pageSize;
}
return QPageSize();
}
@@ -216,10 +219,11 @@ QPageSize QCocoaPrintDevice::defaultPageSize() const
QPageSize pageSize;
PMPageFormat pageFormat;
PMPaper paper;
- if (PMCreatePageFormat(&pageFormat) == noErr
- && PMSessionDefaultPageFormat(m_session, pageFormat) == noErr
- && PMGetPageFormatPaper(pageFormat, &paper) == noErr) {
- pageSize = createPageSize(paper);
+ if (PMCreatePageFormat(&pageFormat) == noErr) {
+ if (PMSessionDefaultPageFormat(m_session, pageFormat) == noErr
+ && PMGetPageFormatPaper(pageFormat, &paper) == noErr) {
+ pageSize = createPageSize(paper);
+ }
PMRelease(pageFormat);
}
return pageSize;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index b7a6a14d4a..bb5c0c1974 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -211,7 +211,9 @@ public:
void registerTouch(bool enable);
void setContentBorderThickness(int topThickness, int bottomThickness);
void registerContentBorderArea(quintptr identifier, int upper, int lower);
- void enableContentBorderArea(bool enable);
+ void setContentBorderAreaEnabled(quintptr identifier, bool enable);
+ void setContentBorderEnabled(bool enable);
+ bool testContentBorderAreaPosition(int position) const;
void applyContentBorderThickness(NSWindow *window);
void updateNSToolbar();
@@ -270,6 +272,7 @@ public: // for QNSView
bool m_geometryUpdateExposeAllowed;
bool m_isExposed;
QRect m_exposedGeometry;
+ qreal m_exposedDevicePixelRatio;
int m_registerTouchCount;
bool m_resizableTransientParent;
bool m_hiddenByClipping;
@@ -289,7 +292,8 @@ public: // for QNSView
NSApplicationPresentationOptions m_presentationOptions;
struct BorderRange {
- BorderRange(int u, int l) : upper(u), lower(l) { }
+ BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { }
+ quintptr identifier;
int upper;
int lower;
bool operator<(BorderRange const& right) const {
@@ -297,6 +301,7 @@ public: // for QNSView
}
};
QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
+ QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index b27e1b03db..5def64ee0a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -261,6 +261,8 @@ static bool isMouseEvent(NSEvent *ev)
{
[self close];
+ QCocoaIntegration::instance()->setWindow(self, 0);
+
if (self.helper.grabbingMouse) {
self.helper.releaseOnMouseUp = YES;
} else {
@@ -327,6 +329,7 @@ static bool isMouseEvent(NSEvent *ev)
{
[self.helper detachFromPlatformWindow];
[self close];
+ QCocoaIntegration::instance()->setWindow(self, 0);
[self release];
}
@@ -619,11 +622,13 @@ void QCocoaWindow::setVisible(bool visible)
// update the window geometry if there is a parent.
setGeometry(window()->geometry());
- // Register popup windows so that the parent window can
- // close them when needed.
- if (window()->type() == Qt::Popup) {
+ // Register popup windows so that the parent window can close them when needed.
+ if (window()->type() == Qt::Popup || window()->type() == Qt::ToolTip) {
// qDebug() << "transientParent and popup" << window()->type() << Qt::Popup << (window()->type() & Qt::Popup);
parentCocoaWindow->m_activePopupWindow = window();
+ }
+
+ if (window()->type() == Qt::Popup) {
// QTBUG-30266: a window should not be resizable while a transient popup is open
// Since this isn't a native popup, the window manager doesn't close the popup when you click outside
NSUInteger parentStyleMask = [parentCocoaWindow->m_nsWindow styleMask];
@@ -1210,11 +1215,18 @@ QCocoaGLContext *QCocoaWindow::currentContext() const
void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
{
bool wasNSWindowChild = m_isNSWindowChild;
- // TODO Set value for m_isNSWindowChild here
+ m_isNSWindowChild = parentWindow && (window()->property("_q_platform_MacUseNSWindow").toBool());
bool needsNSWindow = m_isNSWindowChild || !parentWindow;
QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow;
m_parentCocoaWindow = const_cast<QCocoaWindow *>(static_cast<const QCocoaWindow *>(parentWindow));
+ if (m_parentCocoaWindow && m_isNSWindowChild) {
+ QWindow *parentQWindow = m_parentCocoaWindow->window();
+ if (!parentQWindow->property("_q_platform_MacUseNSWindow").toBool()) {
+ parentQWindow->setProperty("_q_platform_MacUseNSWindow", QVariant(true));
+ m_parentCocoaWindow->recreateWindow(m_parentCocoaWindow->m_parentCocoaWindow);
+ }
+ }
bool usesNSPanel = [m_nsWindow isKindOfClass:[QNSPanel class]];
@@ -1400,6 +1412,8 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow()
applyContentBorderThickness(createdWindow);
+ QCocoaIntegration::instance()->setWindow(createdWindow, this);
+
return createdWindow;
}
@@ -1466,7 +1480,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState)
if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) {
if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) {
- [m_nsWindow performZoom : m_nsWindow]; // toggles
+ [m_nsWindow zoom : m_nsWindow]; // toggles
m_effectivelyMaximized = !m_effectivelyMaximized;
} else if (!(newState & Qt::WindowMaximized)) {
// it would be nice to change the target geometry that toggleFullScreen will animate toward
@@ -1582,28 +1596,17 @@ void QCocoaWindow::setContentBorderThickness(int topThickness, int bottomThickne
void QCocoaWindow::registerContentBorderArea(quintptr identifier, int upper, int lower)
{
- m_contentBorderAreas.insert(identifier, BorderRange(upper, lower));
-
- // Find consecutive registered border areas, starting from the top.
- QList<BorderRange> ranges = m_contentBorderAreas.values();
- std::sort(ranges.begin(), ranges.end());
- m_topContentBorderThickness = 0;
- foreach (BorderRange range, ranges) {
- // Is this sub-range adjacent to or overlaping the
- // existing total border area range? If so merge
- // it into the total range,
- if (range.upper <= (m_topContentBorderThickness + 1))
- m_topContentBorderThickness = qMax(m_topContentBorderThickness, range.lower);
- else
- break;
- }
+ m_contentBorderAreas.insert(identifier, BorderRange(identifier, upper, lower));
+ applyContentBorderThickness(m_nsWindow);
+}
- m_bottomContentBorderThickness = 0; // (not supported)
- if (m_drawContentBorderGradient)
- applyContentBorderThickness(m_nsWindow);
+void QCocoaWindow::setContentBorderAreaEnabled(quintptr identifier, bool enable)
+{
+ m_enabledContentBorderAreas.insert(identifier, enable);
+ applyContentBorderThickness(m_nsWindow);
}
-void QCocoaWindow::enableContentBorderArea(bool enable)
+void QCocoaWindow::setContentBorderEnabled(bool enable)
{
m_drawContentBorderGradient = enable;
applyContentBorderThickness(m_nsWindow);
@@ -1619,17 +1622,33 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
return;
}
- [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask];
+ // Find consecutive registered border areas, starting from the top.
+ QList<BorderRange> ranges = m_contentBorderAreas.values();
+ std::sort(ranges.begin(), ranges.end());
+ int effectiveTopContentBorderThickness = m_topContentBorderThickness;
+ foreach (BorderRange range, ranges) {
+ // Skip disiabled ranges (typically hidden tool bars)
+ if (!m_enabledContentBorderAreas.value(range.identifier, false))
+ continue;
- if (m_topContentBorderThickness > 0) {
- [window setContentBorderThickness:m_topContentBorderThickness forEdge:NSMaxYEdge];
- [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
+ // Is this sub-range adjacent to or overlaping the
+ // existing total border area range? If so merge
+ // it into the total range,
+ if (range.upper <= (effectiveTopContentBorderThickness + 1))
+ effectiveTopContentBorderThickness = qMax(effectiveTopContentBorderThickness, range.lower);
+ else
+ break;
}
- if (m_bottomContentBorderThickness > 0) {
- [window setContentBorderThickness:m_topContentBorderThickness forEdge:NSMinYEdge];
- [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge];
- }
+ int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness;
+
+ [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask];
+
+ [window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge];
+ [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
+
+ [window setContentBorderThickness:effectiveBottomContentBorderThickness forEdge:NSMinYEdge];
+ [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge];
}
void QCocoaWindow::updateNSToolbar()
@@ -1646,6 +1665,12 @@ void QCocoaWindow::updateNSToolbar()
[m_nsWindow setShowsToolbarButton:YES];
}
+bool QCocoaWindow::testContentBorderAreaPosition(int position) const
+{
+ return m_nsWindow && m_drawContentBorderGradient &&
+ 0 <= position && position < [m_nsWindow contentBorderThicknessForEdge: NSMaxYEdge];
+}
+
qreal QCocoaWindow::devicePixelRatio() const
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
@@ -1685,6 +1710,7 @@ void QCocoaWindow::exposeWindow()
if (!m_isExposed) {
m_isExposed = true;
m_exposedGeometry = geometry();
+ m_exposedDevicePixelRatio = devicePixelRatio();
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry()));
}
}
@@ -1710,11 +1736,12 @@ void QCocoaWindow::updateExposedGeometry()
if (!isWindowExposable())
return;
- if (m_exposedGeometry == geometry())
+ if (m_exposedGeometry == geometry() && m_exposedDevicePixelRatio == devicePixelRatio())
return;
m_isExposed = true;
m_exposedGeometry = geometry();
+ m_exposedDevicePixelRatio = devicePixelRatio();
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry()));
}
diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm
index 9368b65866..6549f127b6 100644
--- a/src/plugins/platforms/cocoa/qmacclipboard.mm
+++ b/src/plugins/platforms/cocoa/qmacclipboard.mm
@@ -305,6 +305,11 @@ QMacPasteboard::setMimeData(QMimeData *mime_src)
QString mimeType = formats.at(f);
for (QList<QMacInternalPasteboardMime *>::Iterator it = availableConverters.begin(); it != availableConverters.end(); ++it) {
QMacInternalPasteboardMime *c = (*it);
+ // Hack: The Rtf handler converts incoming Rtf to Html. We do
+ // not want to convert outgoing Html to Rtf but instead keep
+ // posting it as Html. Skip the Rtf handler here.
+ if (c->convertorName() == QStringLiteral("Rtf"))
+ continue;
QString flavor(c->flavorFor(mimeType));
if (!flavor.isEmpty()) {
QVariant mimeData = static_cast<QMacMimeData*>(mime_src)->variantData(mimeType);
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 1197aa9148..0b9683a3ef 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -329,6 +329,7 @@ static QTouchDevice *touchDevice = 0;
if (m_window) {
NSUInteger screenIndex = [[NSScreen screens] indexOfObject:self.window.screen];
if (screenIndex != NSNotFound) {
+ m_platformWindow->updateExposedGeometry();
QCocoaScreen *cocoaScreen = QCocoaIntegration::instance()->screenAtIndex(screenIndex);
QWindowSystemInterface::handleWindowScreenChanged(m_window, cocoaScreen->screen());
}
@@ -371,8 +372,9 @@ static QTouchDevice *touchDevice = 0;
{
m_backingStore = backingStore;
m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
- QRect br = region.boundingRect();
- [self setNeedsDisplayInRect:NSMakeRect(br.x(), br.y(), br.width(), br.height())];
+ foreach (QRect rect, region.rects()) {
+ [self setNeedsDisplayInRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
+ }
}
- (BOOL) hasMask
@@ -1647,6 +1649,21 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
}
}
+static QWindow *findEventTargetWindow(QWindow *candidate)
+{
+ while (candidate) {
+ if (!(candidate->flags() & Qt::WindowTransparentForInput))
+ return candidate;
+ candidate = candidate->parent();
+ }
+ return candidate;
+}
+
+static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint point)
+{
+ return target->mapFromGlobal(source->mapToGlobal(point));
+}
+
- (NSDragOperation) draggingSourceOperationMaskForLocal:(BOOL)isLocal
{
Q_UNUSED(isLocal);
@@ -1676,16 +1693,18 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
+ QWindow *target = findEventTargetWindow(m_window);
+
// update these so selecting move/copy/link works
QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers: [[NSApp currentEvent] modifierFlags]];
QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
if ([sender draggingSource] != nil) {
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- response = QWindowSystemInterface::handleDrag(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed);
+ response = QWindowSystemInterface::handleDrag(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
- response = QWindowSystemInterface::handleDrag(m_window, &mimeData, qt_windowPoint, qtAllowed);
+ response = QWindowSystemInterface::handleDrag(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
}
return qt_mac_mapDropAction(response.acceptedAction());
@@ -1693,16 +1712,20 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
- (void)draggingExited:(id <NSDraggingInfo>)sender
{
+ QWindow *target = findEventTargetWindow(m_window);
+
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
// Send 0 mime data to indicate drag exit
- QWindowSystemInterface::handleDrag(m_window, 0 ,qt_windowPoint, Qt::IgnoreAction);
+ QWindowSystemInterface::handleDrag(target, 0, mapWindowCoordinates(m_window, target, qt_windowPoint), Qt::IgnoreAction);
}
// called on drop, send the drop to Qt and return if it was accepted.
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
+ QWindow *target = findEventTargetWindow(m_window);
+
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
@@ -1710,10 +1733,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
QPlatformDropQtResponse response(false, Qt::IgnoreAction);
if ([sender draggingSource] != nil) {
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
- response = QWindowSystemInterface::handleDrop(m_window, nativeDrag->platformDropData(), qt_windowPoint, qtAllowed);
+ response = QWindowSystemInterface::handleDrop(target, nativeDrag->platformDropData(), mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
} else {
QCocoaDropData mimeData([sender draggingPasteboard]);
- response = QWindowSystemInterface::handleDrop(m_window, &mimeData, qt_windowPoint, qtAllowed);
+ response = QWindowSystemInterface::handleDrop(target, &mimeData, mapWindowCoordinates(m_window, target, qt_windowPoint), qtAllowed);
}
if (response.isAccepted()) {
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
@@ -1726,6 +1749,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
{
Q_UNUSED(img);
Q_UNUSED(operation);
+ QWindow *target = findEventTargetWindow(m_window);
// keep our state, and QGuiApplication state (buttons member) in-sync,
// or future mouse events will be processed incorrectly
@@ -1738,7 +1762,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
NSPoint screenPoint = [window convertBaseToScreen :point];
QPoint qtScreenPoint = QPoint(screenPoint.x, qt_mac_flipYCoordinate(screenPoint.y));
- QWindowSystemInterface::handleMouseEvent(m_window, qtWindowPoint, qtScreenPoint, m_buttons);
+ QWindowSystemInterface::handleMouseEvent(target, mapWindowCoordinates(m_window, target, qtWindowPoint), qtScreenPoint, m_buttons);
}
@end
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index 31e3e343b9..d18a01b11c 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -59,8 +59,7 @@
return nil;
QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot());
- QCocoaAccessibleElement *child = [QCocoaAccessibleElement createElementWithId: childId parent: self];
- return [child autorelease];
+ return [QCocoaAccessibleElement elementWithId: childId];
}
// The QNSView is a container that the user does not interact directly with: