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/cocoa.pro12
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm78
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.h6
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm115
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h3
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm17
-rw-r--r--src/plugins/platforms/cocoa/qcocoasystemsettings.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm77
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h9
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm260
-rw-r--r--src/plugins/platforms/cocoa/qt_mac_p.h1
20 files changed, 383 insertions, 249 deletions
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index fec1da334f..02d8b16110 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -1,10 +1,5 @@
TARGET = qcocoa
-PLUGIN_TYPE = platforms
-PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
-!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
-load(qt_plugin)
-
OBJECTIVE_SOURCES += main.mm \
qcocoaintegration.mm \
qcocoatheme.mm \
@@ -110,5 +105,8 @@ OTHER_FILES += cocoa.json
# DEFINES += QT_COCOA_ENABLE_ACCESSIBILITY_INSPECTOR
# include ($$PWD/../../../../util/accessibilityinspector/accessibilityinspector.pri)
-# Window debug support
-#DEFINES += QT_COCOA_ENABLE_WINDOW_DEBUG
+
+PLUGIN_TYPE = platforms
+PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin
+!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = -
+load(qt_plugin)
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index bc4cb227a8..1faa806480 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -63,7 +63,7 @@ void QCocoaAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
return;
QMacAccessibilityElement *element = [QMacAccessibilityElement elementWithId: event->uniqueId()];
if (!element) {
- qWarning() << "QCocoaAccessibility::notifyAccessibilityUpdate: invalid element";
+ qWarning("QCocoaAccessibility::notifyAccessibilityUpdate: invalid element");
return;
}
@@ -277,7 +277,7 @@ NSArray *unignoredChildren(QAccessibleInterface *interface)
if (element)
[kids addObject: element];
else
- qWarning() << "QCocoaAccessibility: invalid child";
+ qWarning("QCocoaAccessibility: invalid child");
}
return NSAccessibilityUnignoredChildren(kids);
}
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index 0f8081715b..7128fb72c3 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -555,7 +555,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
- (id)accessibilityHitTest:(NSPoint)point {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface || !iface->isValid()) {
-// qDebug() << "Hit test: INVALID";
+// qDebug("Hit test: INVALID");
return NSAccessibilityUnignoredAncestor(self);
}
@@ -585,7 +585,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int *line, int *of
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface || !iface->isValid()) {
- qWarning() << "FocusedUIElement for INVALID";
+ qWarning("FocusedUIElement for INVALID");
return nil;
}
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h
index 18673a3667..fa05626d18 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.h
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h
@@ -57,7 +57,11 @@ public:
QPaintDevice *paintDevice() Q_DECL_OVERRIDE;
void flush(QWindow *widget, const QRegion &region, const QPoint &offset) Q_DECL_OVERRIDE;
+#ifndef QT_NO_OPENGL
QImage toImage() const Q_DECL_OVERRIDE;
+#else
+ QImage toImage() const; // No QPlatformBackingStore::toImage() for NO_OPENGL builds.
+#endif
void resize (const QSize &size, const QRegion &) Q_DECL_OVERRIDE;
bool scroll(const QRegion &area, int dx, int dy) Q_DECL_OVERRIDE;
void beginPaint(const QRegion &region) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h
index cca541e0e3..5bee708b76 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.h
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h
@@ -63,7 +63,7 @@ public:
bool makeCurrent(QPlatformSurface *surface) Q_DECL_OVERRIDE;
void doneCurrent() Q_DECL_OVERRIDE;
- void (*getProcAddress(const QByteArray &procName)) () Q_DECL_OVERRIDE;
+ QFunctionPointer getProcAddress(const char *procName) Q_DECL_OVERRIDE;
void update();
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index e4712d88bc..7a12969972 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -44,6 +44,7 @@
#include <QtCore/private/qcore_mac_p.h>
#include <QtPlatformSupport/private/cglconvenience_p.h>
#include <QtPlatformHeaders/qcocoanativecontext.h>
+#include <dlfcn.h>
#import <AppKit/AppKit.h>
@@ -335,9 +336,9 @@ void QCocoaGLContext::doneCurrent()
[NSOpenGLContext clearCurrentContext];
}
-void (*QCocoaGLContext::getProcAddress(const QByteArray &procName))()
+QFunctionPointer QCocoaGLContext::getProcAddress(const char *procName)
{
- return qcgl_getProcAddress(procName);
+ return (QFunctionPointer)dlsym(RTLD_DEFAULT, procName);
}
void QCocoaGLContext::update()
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 766561a264..ec2f7f8cf1 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -57,6 +57,8 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaCocoaWindow)
+
class QPixmap;
class QString;
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index b6b1862d80..c91c67fe79 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -77,6 +77,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaCocoaWindow, "qt.qpa.cocoa.window");
+
//
// Conversion Functions
//
@@ -766,11 +768,11 @@ CGContextRef qt_mac_cg_context(QPaintDevice *pdev)
if (data && data->classId() == QPlatformPixmap::RasterClass) {
image = data->buffer();
} else {
- qDebug() << "qt_mac_cg_context: Unsupported pixmap class";
+ qDebug("qt_mac_cg_context: Unsupported pixmap class");
}
} else if (pdev->devType() == QInternal::Widget) {
// TODO test: image = static_cast<QImage *>(static_cast<const QWidget *>(pdev)->backingStore()->paintDevice());
- qDebug() << "qt_mac_cg_context: not implemented: Widget class";
+ qDebug("qt_mac_cg_context: not implemented: Widget class");
}
if (!image)
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index f98ddbb14f..c021a551a7 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -428,14 +428,18 @@ void QCocoaIntegration::updateScreens()
}
siblings << screen;
}
+
+ // Set virtual siblings list. All screens in mScreens are siblings, because we ignored the
+ // mirrors. Note that some of the screens we update the siblings list for here may be deleted
+ // below, but update anyway to keep the to-be-deleted screens out of the siblings list.
+ foreach (QCocoaScreen* screen, mScreens)
+ screen->setVirtualSiblings(siblings);
+
// Now the leftovers in remainingScreens are no longer current, so we can delete them.
foreach (QCocoaScreen* screen, remainingScreens) {
mScreens.removeOne(screen);
destroyScreen(screen);
}
- // All screens in mScreens are siblings, because we ignored the mirrors.
- foreach (QCocoaScreen* screen, mScreens)
- screen->setVirtualSiblings(siblings);
}
QCocoaScreen *QCocoaIntegration::screenAtIndex(int index)
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 64299c6cd2..64eeabcc2d 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -81,8 +81,6 @@ public:
inline NSMenu *nsMenu() const
{ return m_nativeMenu; }
- inline NSMenuItem *nsMenuItem() const
- { return m_nativeItem; }
inline bool isVisible() const { return m_visible; }
@@ -91,11 +89,9 @@ public:
QList<QCocoaMenuItem *> items() const;
QList<QCocoaMenuItem *> merged() const;
- void setMenuBar(QCocoaMenuBar *menuBar);
- QCocoaMenuBar *menuBar() const;
- void setContainingMenuItem(QCocoaMenuItem *menuItem);
- QCocoaMenuItem *containingMenuItem() const;
+ void setAttachedItem(NSMenuItem *item);
+ NSMenuItem *attachedItem() const;
private:
QCocoaMenuItem *itemOrNull(int index) const;
@@ -103,13 +99,10 @@ private:
QList<QCocoaMenuItem *> m_menuItems;
NSMenu *m_nativeMenu;
- NSMenuItem *m_nativeItem;
- NSObject *m_delegate;
+ NSMenuItem *m_attachedItem;
bool m_enabled;
bool m_visible;
quintptr m_tag;
- QCocoaMenuBar *m_menuBar;
- QCocoaMenuItem *m_containingMenuItem;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 8c576c7cbe..3fc98c071f 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -102,6 +102,28 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
return self;
}
+- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
+{
+ Q_ASSERT(m_menu->nsMenu() == menu);
+ return m_menu->items().count();
+}
+
+- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
+{
+ Q_UNUSED(index);
+ Q_ASSERT(m_menu->nsMenu() == menu);
+ if (shouldCancel) {
+ // TODO detach all submenus
+ return NO;
+ }
+
+ QCocoaMenuItem *menuItem = reinterpret_cast<QCocoaMenuItem *>(item.tag);
+ if (m_menu->items().contains(menuItem)) {
+ if (QCocoaMenu *itemSubmenu = menuItem->menu())
+ itemSubmenu->setAttachedItem(item);
+ }
+ return YES;
+}
- (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item
{
@@ -234,20 +256,16 @@ QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate);
QT_BEGIN_NAMESPACE
QCocoaMenu::QCocoaMenu() :
+ m_attachedItem(0),
m_enabled(true),
m_visible(true),
- m_tag(0),
- m_menuBar(0),
- m_containingMenuItem(0)
+ m_tag(0)
{
QMacAutoReleasePool pool;
- m_delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this];
- m_nativeItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
m_nativeMenu = [[NSMenu alloc] initWithTitle:@"Untitled"];
[m_nativeMenu setAutoenablesItems:YES];
- m_nativeMenu.delegate = (QCocoaMenuDelegate *) m_delegate;
- [m_nativeItem setSubmenu:m_nativeMenu];
+ m_nativeMenu.delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this];
}
QCocoaMenu::~QCocoaMenu()
@@ -257,14 +275,11 @@ QCocoaMenu::~QCocoaMenu()
SET_COCOA_MENU_ANCESTOR(item, 0);
}
- if (m_containingMenuItem)
- m_containingMenuItem->clearMenu(this);
-
QMacAutoReleasePool pool;
- [m_nativeItem setSubmenu:nil];
+ NSObject *delegate = m_nativeMenu.delegate;
+ m_nativeMenu.delegate = nil;
+ [delegate release];
[m_nativeMenu release];
- [m_delegate release];
- [m_nativeItem release];
}
void QCocoaMenu::setText(const QString &text)
@@ -272,7 +287,6 @@ void QCocoaMenu::setText(const QString &text)
QMacAutoReleasePool pool;
QString stripped = qt_mac_removeAmpersandEscapes(text);
[m_nativeMenu setTitle:QCFString::toNSString(stripped)];
- [m_nativeItem setTitle:QCFString::toNSString(stripped)];
}
void QCocoaMenu::setMinimumWidth(int width)
@@ -313,17 +327,13 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *
void QCocoaMenu::insertNative(QCocoaMenuItem *item, QCocoaMenuItem *beforeItem)
{
- [item->nsItem() setTarget:m_delegate];
+ item->nsItem().target = m_nativeMenu.delegate;
if (!item->menu())
[item->nsItem() setAction:@selector(itemFired:)];
if (item->isMerged())
return;
- if ([item->nsItem() menu]) {
- qWarning("Menu item is already in a menu, remove it from the other menu first before inserting");
- return;
- }
// if the item we're inserting before is merged, skip along until
// we find a non-merged real item to insert ahead of.
while (beforeItem && beforeItem->isMerged()) {
@@ -451,12 +461,11 @@ void QCocoaMenu::setEnabled(bool enabled)
bool QCocoaMenu::isEnabled() const
{
- return [m_nativeItem isEnabled];
+ return m_attachedItem ? [m_attachedItem isEnabled] : m_enabled;
}
void QCocoaMenu::setVisible(bool visible)
{
- [m_nativeItem setSubmenu:(visible ? m_nativeMenu : nil)];
m_visible = visible;
}
@@ -593,8 +602,6 @@ void QCocoaMenu::syncModalState(bool modal)
if (!m_enabled)
modal = true;
- [m_nativeItem setEnabled:!modal];
-
foreach (QCocoaMenuItem *item, m_menuItems) {
if (item->menu()) { // recurse into submenus
item->menu()->syncModalState(modal);
@@ -605,25 +612,24 @@ void QCocoaMenu::syncModalState(bool modal)
}
}
-void QCocoaMenu::setMenuBar(QCocoaMenuBar *menuBar)
+void QCocoaMenu::setAttachedItem(NSMenuItem *item)
{
- m_menuBar = menuBar;
- SET_COCOA_MENU_ANCESTOR(this, menuBar);
-}
+ if (item == m_attachedItem)
+ return;
-QCocoaMenuBar *QCocoaMenu::menuBar() const
-{
- return m_menuBar;
-}
+ if (m_attachedItem)
+ m_attachedItem.submenu = nil;
+
+ m_attachedItem = item;
+
+ if (m_attachedItem)
+ m_attachedItem.submenu = m_nativeMenu;
-void QCocoaMenu::setContainingMenuItem(QCocoaMenuItem *menuItem)
-{
- m_containingMenuItem = menuItem;
}
-QCocoaMenuItem *QCocoaMenu::containingMenuItem() const
+NSMenuItem *QCocoaMenu::attachedItem() const
{
- return m_containingMenuItem;
+ return m_attachedItem;
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.h b/src/plugins/platforms/cocoa/qcocoamenubar.h
index 0521bcd430..7ce2059450 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.h
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.h
@@ -77,10 +77,10 @@ private:
static QCocoaMenuBar *findGlobalMenubar();
bool shouldDisable(QCocoaWindow *active) const;
- void insertNativeMenu(QCocoaMenu *menu, QCocoaMenu *beforeMenu);
- void removeNativeMenu(QCocoaMenu *menu);
- QList<QCocoaMenu*> m_menus;
+ NSMenuItem *nativeItemForMenu(QCocoaMenu *menu) const;
+
+ QList<QPointer<QCocoaMenu> > m_menus;
NSMenu *m_nativeMenu;
QCocoaWindow *m_window;
};
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index c9a42e9d8e..e8b3823012 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -57,7 +57,6 @@ static inline QCocoaMenuLoader *getMenuLoader()
return [NSApp QT_MANGLE_NAMESPACE(qt_qcocoamenuLoader)];
}
-
QCocoaMenuBar::QCocoaMenuBar() :
m_window(0)
{
@@ -74,11 +73,20 @@ QCocoaMenuBar::~QCocoaMenuBar()
#ifdef QT_COCOA_ENABLE_MENU_DEBUG
qDebug() << "~QCocoaMenuBar" << this;
#endif
+ foreach (QCocoaMenu *menu, m_menus) {
+ if (!menu)
+ continue;
+ NSMenuItem *item = nativeItemForMenu(menu);
+ if (menu->attachedItem() == item)
+ menu->setAttachedItem(nil);
+ }
+
[m_nativeMenu release];
static_menubars.removeOne(this);
if (m_window && m_window->menubar() == this) {
m_window->setMenubar(0);
+
// Delete the children first so they do not cause
// the native menu items to be hidden after
// the menu bar was updated
@@ -87,24 +95,6 @@ QCocoaMenuBar::~QCocoaMenuBar()
}
}
-void QCocoaMenuBar::insertNativeMenu(QCocoaMenu *menu, QCocoaMenu *beforeMenu)
-{
- QMacAutoReleasePool pool;
-
- if (beforeMenu) {
- NSUInteger nativeIndex = [m_nativeMenu indexOfItem:beforeMenu->nsMenuItem()];
- [m_nativeMenu insertItem: menu->nsMenuItem() atIndex: nativeIndex];
- } else {
- [m_nativeMenu addItem: menu->nsMenuItem()];
- }
-
- menu->setMenuBar(this);
- syncMenu(static_cast<QPlatformMenu *>(menu));
- if (menu->isVisible()) {
- [m_nativeMenu setSubmenu: menu->nsMenu() forItem: menu->nsMenuItem()];
- }
-}
-
void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *before)
{
QCocoaMenu *menu = static_cast<QCocoaMenu *>(platformMenu);
@@ -113,31 +103,40 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor
qDebug() << "QCocoaMenuBar" << this << "insertMenu" << menu << "before" << before;
#endif
- if (m_menus.contains(menu)) {
+ if (m_menus.contains(QPointer<QCocoaMenu>(menu))) {
qWarning("This menu already belongs to the menubar, remove it first");
return;
}
- if (beforeMenu && !m_menus.contains(beforeMenu)) {
+ if (beforeMenu && !m_menus.contains(QPointer<QCocoaMenu>(beforeMenu))) {
qWarning("The before menu does not belong to the menubar");
return;
}
- m_menus.insert(beforeMenu ? m_menus.indexOf(beforeMenu) : m_menus.size(), menu);
- if (!menu->menuBar())
- insertNativeMenu(menu, beforeMenu);
- if (m_window && m_window->window()->isActive())
- updateMenuBarImmediately();
-}
+ int insertionIndex = beforeMenu ? m_menus.indexOf(beforeMenu) : m_menus.size();
+ m_menus.insert(insertionIndex, menu);
+
+ {
+ QMacAutoReleasePool pool;
+ NSMenuItem *item = [[[NSMenuItem alloc] init] autorelease];
+ item.tag = reinterpret_cast<NSInteger>(menu);
+
+ if (beforeMenu) {
+ // QMenuBar::toNSMenu() exposes the native menubar and
+ // the user could have inserted its own items in there.
+ // Same remark applies to removeMenu().
+ NSMenuItem *beforeItem = nativeItemForMenu(beforeMenu);
+ NSInteger nativeIndex = [m_nativeMenu indexOfItem:beforeItem];
+ [m_nativeMenu insertItem:item atIndex:nativeIndex];
+ } else {
+ [m_nativeMenu addItem:item];
+ }
+ }
-void QCocoaMenuBar::removeNativeMenu(QCocoaMenu *menu)
-{
- QMacAutoReleasePool pool;
+ syncMenu(menu);
- if (menu->menuBar() == this)
- menu->setMenuBar(0);
- NSUInteger realIndex = [m_nativeMenu indexOfItem:menu->nsMenuItem()];
- [m_nativeMenu removeItemAtIndex: realIndex];
+ if (m_window && m_window->window()->isActive())
+ updateMenuBarImmediately();
}
void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu)
@@ -147,8 +146,17 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu)
qWarning("Trying to remove a menu that does not belong to the menubar");
return;
}
+
+ NSMenuItem *item = nativeItemForMenu(menu);
+ if (menu->attachedItem() == item)
+ menu->setAttachedItem(nil);
m_menus.removeOne(menu);
- removeNativeMenu(menu);
+
+ QMacAutoReleasePool pool;
+
+ // See remark in insertMenu().
+ NSInteger nativeIndex = [m_nativeMenu indexOfItem:item];
+ [m_nativeMenu removeItemAtIndex:nativeIndex];
}
void QCocoaMenuBar::syncMenu(QPlatformMenu *menu)
@@ -170,7 +178,16 @@ void QCocoaMenuBar::syncMenu(QPlatformMenu *menu)
break;
}
}
- [cocoaMenu->nsMenuItem() setHidden:shouldHide];
+
+ nativeItemForMenu(cocoaMenu).hidden = shouldHide;
+}
+
+NSMenuItem *QCocoaMenuBar::nativeItemForMenu(QCocoaMenu *menu) const
+{
+ if (!menu)
+ return nil;
+
+ return [m_nativeMenu itemWithTag:reinterpret_cast<NSInteger>(menu)];
}
void QCocoaMenuBar::handleReparent(QWindow *newParentWindow)
@@ -297,24 +314,16 @@ void QCocoaMenuBar::updateMenuBarImmediately()
qDebug() << "QCocoaMenuBar" << "updateMenuBarImmediately" << cw;
#endif
bool disableForModal = mb->shouldDisable(cw);
- // force a sync?
- foreach (QCocoaMenu *m, mb->m_menus) {
- mb->syncMenu(m);
- m->syncModalState(disableForModal);
- }
- // reparent shared menu items if necessary.
- // We browse the list in reverse order to be sure that the next items are redrawn before the current ones,
- // in this way we are sure that "beforeMenu" (see below) is part of the native menu before "m" is redraw
- for (int i = mb->m_menus.size() - 1; i >= 0; i--) {
- QCocoaMenu *m = mb->m_menus.at(i);
- QCocoaMenuBar *menuBar = m->menuBar();
- if (menuBar != mb) {
- QCocoaMenu *beforeMenu = i < (mb->m_menus.size() - 1) ? mb->m_menus.at(i + 1) : 0;
- if (menuBar)
- menuBar->removeNativeMenu(m);
- mb->insertNativeMenu(m, beforeMenu);
- }
+ foreach (QCocoaMenu *menu, mb->m_menus) {
+ if (!menu)
+ continue;
+ NSMenuItem *item = mb->nativeItemForMenu(menu);
+ menu->setAttachedItem(item);
+ SET_COCOA_MENU_ANCESTOR(menu, mb);
+ // force a sync?
+ mb->syncMenu(menu);
+ menu->syncModalState(disableForModal);
}
QCocoaMenuLoader *loader = getMenuLoader();
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index 0d6f67959b..bba9ce3963 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -93,7 +93,6 @@ public:
inline bool isSeparator() const { return m_isSeparator; }
QCocoaMenu *menu() const { return m_menu; }
- void clearMenu(QCocoaMenu *menu);
MenuRole effectiveRole() const;
private:
@@ -105,7 +104,7 @@ private:
QString m_text;
bool m_textSynced;
QIcon m_icon;
- QCocoaMenu *m_menu;
+ QPointer<QCocoaMenu> m_menu;
bool m_isVisible;
bool m_enabled;
bool m_isSeparator;
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index 9e4f0b9ad1..de0271ce4d 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -142,15 +142,12 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
if (m_menu) {
if (COCOA_MENU_ANCESTOR(m_menu) == this)
SET_COCOA_MENU_ANCESTOR(m_menu, 0);
- if (m_menu->containingMenuItem() == this)
- m_menu->setContainingMenuItem(0);
}
QMacAutoReleasePool pool;
m_menu = static_cast<QCocoaMenu *>(menu);
if (m_menu) {
SET_COCOA_MENU_ANCESTOR(m_menu, this);
- m_menu->setContainingMenuItem(this);
} else {
// we previously had a menu, but no longer
// clear out our item so the nexy sync() call builds a new one
@@ -159,12 +156,6 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
}
}
-void QCocoaMenuItem::clearMenu(QCocoaMenu *menu)
-{
- if (menu == m_menu)
- m_menu = 0;
-}
-
void QCocoaMenuItem::setVisible(bool isVisible)
{
m_isVisible = isVisible;
@@ -226,14 +217,6 @@ NSMenuItem *QCocoaMenuItem::sync()
m_native = nil;
}
- if (m_menu) {
- if (m_native != m_menu->nsMenuItem()) {
- [m_native release];
- m_native = [m_menu->nsMenuItem() retain];
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
- }
- }
-
if ((m_role != NoRole && !m_textSynced) || m_merged) {
NSMenuItem *mergeItem = nil;
QCocoaMenuLoader *loader = getMenuLoader();
diff --git a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
index 7fd5537215..be5fa61b8b 100644
--- a/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemsettings.mm
@@ -153,6 +153,7 @@ static QMacPaletteMap mac_widget_colors[] = {
QMacPaletteMap(QPlatformTheme::LabelPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
QMacPaletteMap(QPlatformTheme::GroupBoxPalette, kThemeTextColorPlacardActive, kThemeTextColorPlacardInactive),
QMacPaletteMap(QPlatformTheme::MenuPalette, kThemeTextColorMenuItemActive, kThemeTextColorMenuItemDisabled),
+ QMacPaletteMap(QPlatformTheme::MenuBarPalette, kThemeTextColorMenuItemActive, kThemeTextColorMenuItemDisabled),
//### TODO: The zeros below gives white-on-black text.
QMacPaletteMap(QPlatformTheme::TextEditPalette, 0, 0),
QMacPaletteMap(QPlatformTheme::TextLineEditPalette, 0, 0),
@@ -177,7 +178,8 @@ QHash<QPlatformTheme::Palette, QPalette*> qt_mac_createRolePalettes()
pal.setColor(QPalette::Disabled, QPalette::WindowText, qc);
pal.setColor(QPalette::Disabled, QPalette::HighlightedText, qc);
}
- if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette) {
+ if (mac_widget_colors[i].paletteRole == QPlatformTheme::MenuPalette
+ || mac_widget_colors[i].paletteRole == QPlatformTheme::MenuBarPalette) {
pal.setBrush(QPalette::Background, qt_mac_brushForTheme(kThemeBrushMenuBackground));
qc = qt_mac_colorForThemeTextColor(kThemeTextColorMenuItemActive);
pal.setBrush(QPalette::ButtonText, qc);
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 9572b5ac4c..01e72303be 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -376,9 +376,8 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_bottomContentBorderThickness(0)
, m_normalGeometry(QRect(0,0,-1,-1))
{
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug() << "QCocoaWindow::QCocoaWindow" << this;
-#endif
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::QCocoaWindow" << window();
+
QMacAutoReleasePool pool;
if (tlw->type() == Qt::ForeignWindow) {
@@ -411,11 +410,10 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
QCocoaWindow::~QCocoaWindow()
{
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug() << "QCocoaWindow::~QCocoaWindow" << this;
-#endif
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::~QCocoaWindow" << window();
QMacAutoReleasePool pool;
+ [m_nsWindow makeFirstResponder:nil];
[m_nsWindow setContentView:nil];
[m_nsWindow.helper detachFromPlatformWindow];
if (m_isNSWindowChild) {
@@ -470,6 +468,8 @@ QSurfaceFormat QCocoaWindow::format() const
void QCocoaWindow::setGeometry(const QRect &rectIn)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setGeometry" << window() << rectIn;
+
QBoolBlocker inSetGeometry(m_inSetGeometry, true);
QRect rect = rectIn;
@@ -482,9 +482,7 @@ void QCocoaWindow::setGeometry(const QRect &rectIn)
}
if (geometry() == rect)
return;
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug() << "QCocoaWindow::setGeometry" << this << rect;
-#endif
+
setCocoaGeometry(rect);
}
@@ -507,6 +505,7 @@ QRect QCocoaWindow::geometry() const
void QCocoaWindow::setCocoaGeometry(const QRect &rect)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setCocoaGeometry" << window() << rect;
QMacAutoReleasePool pool;
if (m_contentViewIsEmbedded) {
@@ -630,6 +629,8 @@ void QCocoaWindow::show(bool becauseOfAncestor)
void QCocoaWindow::setVisible(bool visible)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setVisible" << window() << visible;
+
if (m_isNSWindowChild && m_hiddenByClipping)
return;
@@ -639,9 +640,7 @@ void QCocoaWindow::setVisible(bool visible)
QCocoaWindow *parentCocoaWindow = 0;
if (window()->transientParent())
parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle());
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug() << "QCocoaWindow::setVisible" << window() << visible;
-#endif
+
if (visible) {
// We need to recreate if the modality has changed as the style mask will need updating
if (m_windowModality != window()->modality())
@@ -862,9 +861,6 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags)
if (m_drawContentBorderGradient)
styleMask |= NSTexturedBackgroundWindowMask;
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug("windowStyleMask of '%s': flags %X -> styleMask %lX", qPrintable(window()->title()), (int)flags, styleMask);
-#endif
return styleMask;
}
@@ -986,7 +982,8 @@ bool QCocoaWindow::isAlertState() const
void QCocoaWindow::raise()
{
- //qDebug() << "raise" << this;
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::raise" << window();
+
// ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
if (!m_nsWindow)
return;
@@ -1006,7 +1003,15 @@ void QCocoaWindow::raise()
[parentNSWindow removeChildWindow:m_nsWindow];
[parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove];
} else {
- [m_nsWindow orderFront: m_nsWindow];
+ {
+ // Clean up autoreleased temp objects from orderFront immediately.
+ // Failure to do so has been observed to cause leaks also beyond any outer
+ // autorelease pool (for example around a complete QWindow
+ // construct-show-raise-hide-delete cyle), counter to expected autoreleasepool
+ // behavior.
+ QMacAutoReleasePool pool;
+ [m_nsWindow orderFront: m_nsWindow];
+ }
static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS");
if (raiseProcess) {
ProcessSerialNumber psn;
@@ -1019,6 +1024,7 @@ void QCocoaWindow::raise()
void QCocoaWindow::lower()
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::lower" << window();
if (!m_nsWindow)
return;
if (m_isNSWindowChild) {
@@ -1071,13 +1077,11 @@ void QCocoaWindow::propagateSizeHints()
if (!m_nsWindow)
return;
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug() << "QCocoaWindow::propagateSizeHints" << this;
- qDebug() << " min/max" << windowMinimumSize() << windowMaximumSize();
- qDebug() << "size increment" << windowSizeIncrement();
- qDebug() << " basesize" << windowBaseSize();
- qDebug() << " geometry" << windowGeometry();
-#endif
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::propagateSizeHints" << window() << "\n"
+ << " min/max" << windowMinimumSize() << windowMaximumSize()
+ << "size increment" << windowSizeIncrement()
+ << " basesize" << windowBaseSize()
+ << " geometry" << windowGeometry();
// Set the minimum content size.
const QSize minimumSize = windowMinimumSize();
@@ -1109,6 +1113,7 @@ void QCocoaWindow::propagateSizeHints()
void QCocoaWindow::setOpacity(qreal level)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setOpacity" << level;
if (m_nsWindow) {
[m_nsWindow setAlphaValue:level];
[m_nsWindow setOpaque: isOpaque()];
@@ -1117,6 +1122,7 @@ void QCocoaWindow::setOpacity(qreal level)
void QCocoaWindow::setMask(const QRegion &region)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMask" << window() << region;
if (m_nsWindow)
[m_nsWindow setBackgroundColor:[NSColor clearColor]];
@@ -1126,6 +1132,7 @@ void QCocoaWindow::setMask(const QRegion &region)
bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setKeyboardGrabEnabled" << window() << grab;
if (!m_nsWindow)
return false;
@@ -1138,6 +1145,7 @@ bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
bool QCocoaWindow::setMouseGrabEnabled(bool grab)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setMouseGrabEnabled" << window() << grab;
if (!m_nsWindow)
return false;
@@ -1155,6 +1163,8 @@ WId QCocoaWindow::winId() const
void QCocoaWindow::setParent(const QPlatformWindow *parentWindow)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::setParent" << window() << (parentWindow ? parentWindow->window() : 0);
+
// recreate the window for compatibility
bool unhideAfterRecreate = parentWindow && !m_contentViewIsToBeEmbedded && ![m_contentView isHidden];
recreateWindow(parentWindow);
@@ -1238,6 +1248,7 @@ void QCocoaWindow::windowDidEndLiveResize()
bool QCocoaWindow::windowShouldClose()
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::windowShouldClose" << window();
// This callback should technically only determine if the window
// should (be allowed to) close, but since our QPA API to determine
// that also involves actually closing the window we do both at the
@@ -1278,6 +1289,9 @@ QCocoaGLContext *QCocoaWindow::currentContext() const
void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
{
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::recreateWindow" << window()
+ << "parent" << (parentWindow ? parentWindow->window() : 0);
+
bool wasNSWindowChild = m_isNSWindowChild;
BOOL requestNSWindowChild = qt_mac_resolveOption(NO, window(), "_q_platform_MacUseNSWindow",
"QT_MAC_USE_NSWINDOW");
@@ -1614,10 +1628,6 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState)
}
}
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug() << "QCocoaWindow::syncWindowState" << newState << "actual" << predictedState << "was" << m_synchedWindowState << "effectively maximized" << m_effectivelyMaximized;
-#endif
-
// New state is now the current synched state
m_synchedWindowState = predictedState;
}
@@ -1810,7 +1820,9 @@ void QCocoaWindow::exposeWindow()
m_isExposed = true;
m_exposedGeometry = geometry();
m_exposedDevicePixelRatio = devicePixelRatio();
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), m_exposedGeometry.size()));
+ QRect geometry(QPoint(0, 0), m_exposedGeometry.size());
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow: exposeWindow" << window() << geometry;
+ QWindowSystemInterface::handleExposeEvent(window(), geometry);
}
}
@@ -1820,6 +1832,8 @@ void QCocoaWindow::obscureWindow()
if (m_isExposed) {
m_geometryUpdateExposeAllowed = false;
m_isExposed = false;
+
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::obscureWindow" << window();
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
}
}
@@ -1846,7 +1860,10 @@ void QCocoaWindow::updateExposedGeometry()
m_isExposed = true;
m_exposedGeometry = geometry();
m_exposedDevicePixelRatio = devicePixelRatio();
- QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), m_exposedGeometry.size()));
+
+ QRect geometry(QPoint(0, 0), m_exposedGeometry.size());
+ qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::updateExposedGeometry" << window() << geometry;
+ QWindowSystemInterface::handleExposeEvent(window(), geometry);
}
QWindow *QCocoaWindow::childWindowAt(QPoint windowPoint)
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index cbd92df9cf..b5738abf4c 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -43,6 +43,7 @@
#include <AppKit/AppKit.h>
#include <QtCore/QPointer>
+#include <QtCore/QSet>
#include <QtGui/QImage>
#include <QtGui/QAccessible>
@@ -59,6 +60,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
@interface QT_MANGLE_NAMESPACE(QNSView) : NSView <NSTextInputClient> {
QCocoaBackingStore* m_backingStore;
QPoint m_backingStoreOffset;
+ QRegion m_maskRegion;
CGImageRef m_maskImage;
uchar *m_maskData;
bool m_shouldInvalidateWindowShadow;
@@ -66,6 +68,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
QCocoaWindow *m_platformWindow;
NSTrackingArea *m_trackingArea;
Qt::MouseButtons m_buttons;
+ Qt::MouseButtons m_acceptedMouseDowns;
Qt::MouseButtons m_frameStrutButtons;
QString m_composingText;
bool m_sendKeyEvent;
@@ -85,6 +88,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
bool m_exposedOnMoveToWindow;
NSEvent *m_currentlyInterpretedKeyEvent;
bool m_isMenuView;
+ QSet<quint32> m_acceptedKeyDowns;
}
- (id)init;
@@ -118,6 +122,9 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (void)resetMouseButtons;
- (void)handleMouseEvent:(NSEvent *)theEvent;
+- (bool)handleMouseDownEvent:(NSEvent *)theEvent;
+- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent;
+- (bool)handleMouseUpEvent:(NSEvent *)theEvent;
- (void)mouseDown:(NSEvent *)theEvent;
- (void)mouseDragged:(NSEvent *)theEvent;
- (void)mouseUp:(NSEvent *)theEvent;
@@ -139,7 +146,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper));
- (int) convertKeyCode : (QChar)keyCode;
+ (Qt::KeyboardModifiers) convertKeyModifiers : (ulong)modifierFlags;
-- (void)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType;
+- (bool)handleKeyEvent:(NSEvent *)theEvent eventType:(int)eventType;
- (void)keyDown:(NSEvent *)theEvent;
- (void)keyUp:(NSEvent *)theEvent;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 360ad3baf7..bb12c30fa3 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -145,6 +145,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
m_shouldInvalidateWindowShadow = false;
m_window = 0;
m_buttons = Qt::NoButton;
+ m_acceptedMouseDowns = Qt::NoButton;
m_frameStrutButtons = Qt::NoButton;
m_sendKeyEvent = false;
m_subscribesForGlobalFrameNotifications = false;
@@ -361,15 +362,16 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry())
return;
+ const bool isResize = geometry.size() != m_platformWindow->geometry().size();
+
// It can happen that self.window is nil (if we are changing
// styleMask from/to borderless and content view is being re-parented)
// - this results in an invalid coordinates.
if (m_platformWindow->m_inSetStyleMask && !self.window)
return;
-#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
- qDebug() << "QNSView::udpateGeometry" << m_platformWindow << geometry;
-#endif
+ qCDebug(lcQpaCocoaWindow) << "[QNSView udpateGeometry:]" << m_window
+ << "current" << m_platformWindow->geometry() << "new" << geometry;
// Call setGeometry on QPlatformWindow. (not on QCocoaWindow,
// doing that will initiate a geometry change it and possibly create
@@ -390,7 +392,7 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
// calles, which Qt and Qt applications do not excpect.
if (!m_platformWindow->m_inSetGeometry)
QWindowSystemInterface::flushWindowSystemEvents();
- else
+ else if (isResize)
m_backingStore = 0;
}
}
@@ -512,6 +514,8 @@ QT_WARNING_POP
- (void) flushBackingStore:(QCocoaBackingStore *)backingStore region:(const QRegion &)region offset:(QPoint)offset
{
+ qCDebug(lcQpaCocoaWindow) << "[QNSView flushBackingStore:]" << m_window << region.rectCount() << region.boundingRect() << offset;
+
m_backingStore = backingStore;
m_backingStoreOffset = offset * m_backingStore->getBackingStoreDevicePixelRatio();
for (const QRect &rect : region)
@@ -526,7 +530,7 @@ QT_WARNING_POP
- (BOOL) hasMask
{
- return m_maskImage != 0;
+ return !m_maskRegion.isEmpty();
}
- (BOOL) isOpaque
@@ -539,6 +543,7 @@ QT_WARNING_POP
- (void) setMaskRegion:(const QRegion *)region
{
m_shouldInvalidateWindowShadow = true;
+ m_maskRegion = *region;
if (m_maskImage)
CGImageRelease(m_maskImage);
if (region->isEmpty()) {
@@ -574,6 +579,8 @@ QT_WARNING_POP
- (void) drawRect:(NSRect)dirtyRect
{
+ qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:]" << m_window << qt_mac_toQRect(dirtyRect);
+
#ifndef QT_NO_OPENGL
if (m_glContext && m_shouldSetGLContextinDrawRect) {
[m_glContext->nsOpenGLContext() setView:self];
@@ -813,6 +820,82 @@ QT_WARNING_POP
QWindowSystemInterface::handleFrameStrutMouseEvent(m_window, timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
}
+- (bool)handleMouseDownEvent:(NSEvent *)theEvent
+{
+ if (m_window && (m_window->flags() & Qt::WindowTransparentForInput))
+ return false;
+
+ Qt::MouseButton button = cocoaButton2QtButton([theEvent buttonNumber]);
+
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ Q_UNUSED(qtScreenPoint);
+
+ // Maintain masked state for the button for use by MouseDragged and MouseUp.
+ const bool masked = m_maskRegion.contains(qtWindowPoint.toPoint());
+ if (masked)
+ m_acceptedMouseDowns &= ~button;
+ else
+ m_acceptedMouseDowns |= button;
+
+ // Forward masked out events to the next responder
+ if (masked)
+ return false;
+
+ if (button == Qt::RightButton)
+ m_sendUpAsRightButton = true;
+
+ m_buttons |= button;
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
+- (bool)handleMouseDraggedEvent:(NSEvent *)theEvent
+{
+ if (m_window && (m_window->flags() & Qt::WindowTransparentForInput))
+ return false;
+
+ Qt::MouseButton button = cocoaButton2QtButton([theEvent buttonNumber]);
+
+ // Forward the event to the next responder if Qt did not accept the
+ // corresponding mouse down for this button
+ if (!(m_acceptedMouseDowns & button) == button)
+ return false;
+
+ if (!(m_buttons & (m_sendUpAsRightButton ? Qt::RightButton : Qt::LeftButton))) {
+ qCWarning(lcQpaCocoaWindow) << "QNSView mouseDragged: Internal mouse button tracking"
+ << "invalid (missing Qt::LeftButton)";
+ }
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
+- (bool)handleMouseUpEvent:(NSEvent *)theEvent
+{
+ if (m_window && (m_window->flags() & Qt::WindowTransparentForInput))
+ return false;
+
+ Qt::MouseButton button = cocoaButton2QtButton([theEvent buttonNumber]);
+
+ // Forward the event to the next responder if Qt did not accept the
+ // corresponding mouse down for this button
+ if (!(m_acceptedMouseDowns & button) == button)
+ return false;
+
+ if (m_sendUpAsRightButton && button == Qt::LeftButton)
+ button = Qt::RightButton;
+ if (button == Qt::RightButton)
+ m_sendUpAsRightButton = false;
+
+ m_buttons &= ~button;
+
+ [self handleMouseEvent:theEvent];
+ return true;
+}
+
- (void)mouseDown:(NSEvent *)theEvent
{
if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
@@ -851,6 +934,25 @@ QT_WARNING_POP
}
}
+ QPointF qtWindowPoint;
+ QPointF qtScreenPoint;
+ [self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
+ Q_UNUSED(qtScreenPoint);
+
+ bool masked = m_maskRegion.contains(qtWindowPoint.toPoint());
+
+ // Maintain masked state for the button for use by MouseDragged and Up.
+ if (masked)
+ m_acceptedMouseDowns &= ~Qt::LeftButton;
+ else
+ m_acceptedMouseDowns |= Qt::LeftButton;
+
+ // Forward masked out events to the next responder
+ if (masked) {
+ [super mouseDown:theEvent];
+ return;
+ }
+
if ([self hasMarkedText]) {
[[NSTextInputContext currentInputContext] handleEvent:theEvent];
} else {
@@ -866,24 +968,58 @@ QT_WARNING_POP
- (void)mouseDragged:(NSEvent *)theEvent
{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super mouseDragged:theEvent];
- if (!(m_buttons & (m_sendUpAsRightButton ? Qt::RightButton : Qt::LeftButton)))
- qWarning("QNSView mouseDragged: Internal mouse button tracking invalid (missing Qt::LeftButton)");
- [self handleMouseEvent:theEvent];
+ const bool accepted = [self handleMouseDraggedEvent:theEvent];
+ if (!accepted)
+ [super mouseDragged:theEvent];
}
- (void)mouseUp:(NSEvent *)theEvent
{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super mouseUp:theEvent];
- if (m_sendUpAsRightButton) {
- m_buttons &= ~Qt::RightButton;
- m_sendUpAsRightButton = false;
- } else {
- m_buttons &= ~Qt::LeftButton;
- }
- [self handleMouseEvent:theEvent];
+ const bool accepted = [self handleMouseUpEvent:theEvent];
+ if (!accepted)
+ [super mouseUp:theEvent];
+}
+
+- (void)rightMouseDown:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDownEvent:theEvent];
+ if (!accepted)
+ [super rightMouseDown:theEvent];
+}
+
+- (void)rightMouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent];
+ if (!accepted)
+ [super rightMouseDragged:theEvent];
+}
+
+- (void)rightMouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent];
+ if (!accepted)
+ [super rightMouseUp:theEvent];
+}
+
+- (void)otherMouseDown:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDownEvent:theEvent];
+ if (!accepted)
+ [super otherMouseDown:theEvent];
+}
+
+- (void)otherMouseDragged:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseDraggedEvent:theEvent];
+ if (!accepted)
+ [super otherMouseDragged:theEvent];
+}
+
+- (void)otherMouseUp:(NSEvent *)theEvent
+{
+ const bool accepted = [self handleMouseUpEvent:theEvent];
+ if (!accepted)
+ [super otherMouseUp:theEvent];
}
- (void)updateTrackingAreas
@@ -994,58 +1130,6 @@ QT_WARNING_POP
m_platformWindow->m_enterLeaveTargetWindow = 0;
}
-- (void)rightMouseDown:(NSEvent *)theEvent
-{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super rightMouseDown:theEvent];
- m_buttons |= Qt::RightButton;
- m_sendUpAsRightButton = true;
- [self handleMouseEvent:theEvent];
-}
-
-- (void)rightMouseDragged:(NSEvent *)theEvent
-{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super rightMouseDragged:theEvent];
- if (!(m_buttons & Qt::RightButton))
- qWarning("QNSView rightMouseDragged: Internal mouse button tracking invalid (missing Qt::RightButton)");
- [self handleMouseEvent:theEvent];
-}
-
-- (void)rightMouseUp:(NSEvent *)theEvent
-{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super rightMouseUp:theEvent];
- m_buttons &= ~Qt::RightButton;
- m_sendUpAsRightButton = false;
- [self handleMouseEvent:theEvent];
-}
-
-- (void)otherMouseDown:(NSEvent *)theEvent
-{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super otherMouseDown:theEvent];
- m_buttons |= cocoaButton2QtButton([theEvent buttonNumber]);
- [self handleMouseEvent:theEvent];
-}
-
-- (void)otherMouseDragged:(NSEvent *)theEvent
-{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super otherMouseDragged:theEvent];
- if (!(m_buttons & ~(Qt::LeftButton | Qt::RightButton)))
- qWarning("QNSView otherMouseDragged: Internal mouse button tracking invalid (missing Qt::MiddleButton or Qt::ExtraButton*)");
- [self handleMouseEvent:theEvent];
-}
-
-- (void)otherMouseUp:(NSEvent *)theEvent
-{
- if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
- return [super otherMouseUp:theEvent];
- m_buttons &= ~cocoaButton2QtButton([theEvent buttonNumber]);
- [self handleMouseEvent:theEvent];
-}
-
struct QCocoaTabletDeviceData
{
QTabletEvent::TabletDevice device;
@@ -1413,8 +1497,10 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
} else if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
ph = Qt::NoScrollPhase;
}
+ // "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective.
+ bool isInverted = [theEvent isDirectionInvertedFromDevice];
- QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph, source);
+ QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph, source, isInverted);
}
#endif //QT_NO_WHEELEVENT
@@ -1439,7 +1525,7 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
return qtMods;
}
-- (void)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
+- (bool)handleKeyEvent:(NSEvent *)nsevent eventType:(int)eventType
{
ulong timestamp = [nsevent timestamp] * 1000;
ulong nativeModifiers = [nsevent modifierFlags];
@@ -1509,26 +1595,46 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent)
m_sendKeyEvent = true;
}
- if (m_sendKeyEvent && m_composingText.isEmpty())
+ bool accepted = true;
+ if (m_sendKeyEvent && m_composingText.isEmpty()) {
QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, QEvent::Type(eventType), keyCode, modifiers,
nativeScanCode, nativeVirtualKey, nativeModifiers, text, [nsevent isARepeat], 1, false);
-
+ accepted = QWindowSystemInterface::flushWindowSystemEvents();
+ }
m_sendKeyEvent = false;
m_resendKeyEvent = false;
+ return accepted;
}
- (void)keyDown:(NSEvent *)nsevent
{
if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
return [super keyDown:nsevent];
- [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
+
+ const bool accepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)];
+
+ // Track keyDown acceptance state for later acceptance of the keyUp.
+ if (accepted)
+ m_acceptedKeyDowns.insert([nsevent keyCode]);
+
+ // Propagate the keyDown to the next responder if Qt did not accept it.
+ if (!accepted)
+ [super keyDown:nsevent];
}
- (void)keyUp:(NSEvent *)nsevent
{
if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) )
return [super keyUp:nsevent];
- [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
+
+ const bool keyUpAccepted = [self handleKeyEvent:nsevent eventType:int(QEvent::KeyRelease)];
+
+ // Propagate the keyUp if neither Qt accepted it nor the corresponding KeyDown was
+ // accepted. Qt text controls wil often not use and ignore keyUp events, but we
+ // want to avoid propagating unmatched keyUps.
+ const bool keyDownAccepted = m_acceptedKeyDowns.remove([nsevent keyCode]);
+ if (!keyUpAccepted && !keyDownAccepted)
+ [super keyUp:nsevent];
}
- (void)cancelOperation:(id)sender
diff --git a/src/plugins/platforms/cocoa/qt_mac_p.h b/src/plugins/platforms/cocoa/qt_mac_p.h
index 18a3d1b3e5..03eae1b2e7 100644
--- a/src/plugins/platforms/cocoa/qt_mac_p.h
+++ b/src/plugins/platforms/cocoa/qt_mac_p.h
@@ -64,6 +64,7 @@
#include "QtCore/qvariant.h"
#include "QtCore/qmimedata.h"
#include "QtCore/qpointer.h"
+#include "QtCore/qloggingcategory.h"
#include "private/qcore_mac_p.h"