diff --git a/configure b/configure index cb8d78fd3c..cadb3f0a88 100755 --- a/configure +++ b/configure @@ -511,7 +511,8 @@ if [ "$BUILD_ON_MAC" = "yes" ]; then exit 2 fi - if ! /usr/bin/xcrun -find xcrun >/dev/null 2>&1; then + # Patch: Fix Qt for working with Xcode 8. + if ! /usr/bin/xcrun -find xcodebuild >/dev/null 2>&1; then echo >&2 echo " Xcode not set up properly. You may need to confirm the license" >&2 echo " agreement by running /usr/bin/xcodebuild without arguments." >&2 diff --git a/mkspecs/common/g++-macx.conf b/mkspecs/common/g++-macx.conf index 086510dd96..078a5ed1dd 100644 --- a/mkspecs/common/g++-macx.conf +++ b/mkspecs/common/g++-macx.conf @@ -14,7 +14,13 @@ QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2 QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO += -gdwarf-2 QMAKE_LFLAGS_RELEASE_WITH_DEBUGINFO += -g -gdwarf-2 -QMAKE_LFLAGS_STATIC_LIB += -all_load +# Patch: Don't remember :( +#QMAKE_LFLAGS_STATIC_LIB += -all_load + +# Patch: Use C++14 with custom libc++ build. +QMAKE_CXXFLAGS_CXX11 = -std=c++1y +QMAKE_CXXFLAGS += -nostdinc++ -I/usr/local/macold/include/c++/v1 +QMAKE_LFLAGS += /usr/local/macold/lib/libc++.a /usr/local/macold/lib/libc++abi.a -isysroot / QMAKE_XCODE_GCC_VERSION = com.apple.compilers.llvmgcc42 diff --git a/mkspecs/features/mac/default_pre.prf b/mkspecs/features/mac/default_pre.prf index 0cc8cd6dfd..ca9725b779 100644 --- a/mkspecs/features/mac/default_pre.prf +++ b/mkspecs/features/mac/default_pre.prf @@ -12,7 +12,9 @@ isEmpty(QMAKE_XCODE_DEVELOPER_PATH) { error("Xcode is not installed in $${QMAKE_XCODE_DEVELOPER_PATH}. Please use xcode-select to choose Xcode installation path.") # Make sure Xcode is set up properly - isEmpty($$list($$system("/usr/bin/xcrun -find xcrun 2>/dev/null"))): \ + + # Patch: Fix Qt for working with Xcode 8. + isEmpty($$list($$system("/usr/bin/xcrun -find xcodebuild 2>/dev/null"))): \ error("Xcode not set up properly. You may need to confirm the license agreement by running /usr/bin/xcodebuild.") } diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index bb79a139b3..5d595bc3b3 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -220,6 +220,10 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int int blue_scale = 0; int alpha_scale = 0; + // Patch: Backport a fix for bmp reader. + if (!d->isSequential()) + d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) return false; @@ -307,8 +311,9 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int image.setDotsPerMeterX(bi.biXPelsPerMeter); image.setDotsPerMeterY(bi.biYPelsPerMeter); - if (!d->isSequential()) - d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + // Patch: Backport a fix for bmp reader. + //if (!d->isSequential()) + // d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap if (ncols > 0) { // read color table uchar rgb[4]; diff --git a/src/gui/painting/qpaintengine_p.h b/src/gui/painting/qpaintengine_p.h index ebff9509ab..4300ca4c0f 100644 --- a/src/gui/painting/qpaintengine_p.h +++ b/src/gui/painting/qpaintengine_p.h @@ -87,8 +87,18 @@ public: if (hasSystemTransform) { if (systemTransform.type() <= QTransform::TxTranslate) systemClip.translate(qRound(systemTransform.dx()), qRound(systemTransform.dy())); - else + // Patch: Transform the system clip region back from device pixels to device-independent pixels before + // applying systemTransform, which already has transform from device-independent pixels to device pixels. + else { +#ifdef Q_OS_MAC + QTransform scaleTransform; + const qreal invDevicePixelRatio = 1. / pdev->devicePixelRatio(); + scaleTransform.scale(invDevicePixelRatio, invDevicePixelRatio); + systemClip = systemTransform.map(scaleTransform.map(systemClip)); +#else systemClip = systemTransform.map(systemClip); +#endif + } } // Make sure we're inside the viewport. diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 4879ae51d7..56cdcbaf01 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -654,6 +654,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const while (oldPos < len && !attributes[oldPos].graphemeBoundary) oldPos++; } else { + // Patch: Skip to the end of the current word, not to the start of the next one. + while (oldPos < len && attributes[oldPos].whiteSpace) + oldPos++; if (oldPos < len && d->atWordSeparator(oldPos)) { oldPos++; while (oldPos < len && d->atWordSeparator(oldPos)) @@ -662,8 +665,9 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const while (oldPos < len && !d->atSpace(oldPos) && !d->atWordSeparator(oldPos)) oldPos++; } - while (oldPos < len && d->atSpace(oldPos)) - oldPos++; + // Patch: Skip to the end of the current word, not to the start of the next one. + //while (oldPos < len && d->atSpace(oldPos)) + // oldPos++; } return oldPos; @@ -1602,6 +1606,9 @@ namespace { int currentPosition; glyph_t previousGlyph; + // Patch: Backport a crash fix. + QFontEngine *previousGlyphFontEngine; + QFixed minw; QFixed softHyphenWidth; QFixed rightBearing; @@ -1634,13 +1641,19 @@ namespace { if (currentPosition > 0 && logClusters[currentPosition - 1] < glyphs.numGlyphs) { previousGlyph = currentGlyph(); // needed to calculate right bearing later + + // Patch: Backport a crash fix. + previousGlyphFontEngine = fontEngine; } } - inline void adjustRightBearing(glyph_t glyph) + // Patch: Backport a crash fix. + inline void adjustRightBearing(QFontEngine *engine, glyph_t glyph) { qreal rb; - fontEngine->getGlyphBearings(glyph, 0, &rb); + + // Patch: Backport a crash fix. + engine->getGlyphBearings(glyph, 0, &rb); rightBearing = qMin(QFixed(), QFixed::fromReal(rb)); } @@ -1648,13 +1661,16 @@ namespace { { if (currentPosition <= 0) return; - adjustRightBearing(currentGlyph()); + + // Patch: Backport a crash fix. + adjustRightBearing(fontEngine, currentGlyph()); } inline void adjustPreviousRightBearing() { if (previousGlyph > 0) - adjustRightBearing(previousGlyph); + // Patch: Backport a crash fix. + adjustRightBearing(previousGlyphFontEngine, previousGlyph); } inline void resetRightBearing() diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h index cbe42c3844..b273db7e78 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -194,6 +194,9 @@ private: QRectF *brect, int tabstops, int* tabarray, int tabarraylen, QPainter *painter); QTextEngine *d; + + // Patch: Give access to the internal api. + friend class TextBlock; }; diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index 360f9722c7..f28f289ef6 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -118,6 +118,8 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() { for (int i = 0; i < channelCount; ++i) { if (channels[i].socket) { + // Patch: backport critical bugfix from '4f959b6b30' commit. + QObject::disconnect(channels[i].socket, Q_NULLPTR, &channels[i], Q_NULLPTR); channels[i].socket->close(); delete channels[i].socket; } diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index ca7afb7d1b..25ae50008d 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -256,6 +256,13 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) fd->foundryName = QStringLiteral("CoreText"); fd->familyName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontFamilyNameAttribute); + + // Patch: Fix open sans semibold loading. + QCFString _displayName = (CFStringRef) CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute); + if (_displayName == QStringLiteral("Open Sans Semibold")) { + fd->familyName = _displayName; + } + fd->styleName = (CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontStyleNameAttribute); fd->weight = QFont::Normal; fd->style = QFont::StyleNormal; diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 6e2c8a2a9a..3cace8abcb 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -717,7 +717,8 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metric QFixed QCoreTextFontEngine::emSquareSize() const { - return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); + // Patch: Fix build for Xcode 9.3.1. + return QFixed(int(CTFontGetUnitsPerEm(ctfont))); } QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 92358ecc74..694fee7350 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -213,7 +213,8 @@ static void cleanupCocoaApplicationDelegate() if (reflectionDelegate) { if ([reflectionDelegate respondsToSelector:@selector(applicationShouldTerminate:)]) return [reflectionDelegate applicationShouldTerminate:sender]; - return NSTerminateNow; + // Patch: Don't terminate if reflectionDelegate does not respond to that selector, just use the default. + //return NSTerminateNow; } if ([self canQuit]) { @@ -289,6 +290,11 @@ static void cleanupCocoaApplicationDelegate() - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Patch: We need to receive this notification in the delegate as well. + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationDidFinishLaunching:)]) + [reflectionDelegate applicationDidFinishLaunching:aNotification]; + Q_UNUSED(aNotification); inLaunch = false; // qt_release_apple_event_handler(); @@ -411,7 +417,9 @@ static void cleanupCocoaApplicationDelegate() { Q_UNUSED(replyEvent); NSString *urlString = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; - QWindowSystemInterface::handleFileOpenEvent(QUrl(QCFString::toQString(urlString))); + + // Patch: Fix opening of an external url by a protocol handler. + QWindowSystemInterface::handleFileOpenEvent(QUrl::fromNSURL([NSURL URLWithString:urlString])); } - (void)appleEventQuit:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm index b81b9a0b1c..4e59e833b1 100644 --- a/src/plugins/platforms/cocoa/qcocoacursor.mm +++ b/src/plugins/platforms/cocoa/qcocoacursor.mm @@ -81,7 +81,7 @@ void QCocoaCursor::setPos(const QPoint &position) pos.x = position.x(); pos.y = position.y(); - CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, 0); + CGEventRef e = CGEventCreateMouseEvent(0, kCGEventMouseMoved, pos, kCGMouseButtonLeft); CGEventPost(kCGHIDEventTap, e); CFRelease(e); } diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 9850f83dea..b2e1d3dfda 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -649,9 +649,10 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm // Verbatim copy if HIViewDrawCGImage (as shown on Carbon-Dev) OSStatus err = noErr; - require_action(inContext != NULL, InvalidContext, err = paramErr); - require_action(inBounds != NULL, InvalidBounds, err = paramErr); - require_action(inImage != NULL, InvalidImage, err = paramErr); + // Patch: Fix build on latest Xcode. + //require_action(inContext != NULL, InvalidContext, err = paramErr); + //require_action(inBounds != NULL, InvalidBounds, err = paramErr); + //require_action(inImage != NULL, InvalidImage, err = paramErr); CGContextSaveGState( inContext ); CGContextTranslateCTM (inContext, 0, inBounds->origin.y + CGRectGetMaxY(*inBounds)); @@ -660,9 +661,11 @@ OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGIm CGContextDrawImage(inContext, *inBounds, inImage); CGContextRestoreGState(inContext); -InvalidImage: -InvalidBounds: -InvalidContext: + +// Patch: Fix build on latest Xcode. +//InvalidImage: +//InvalidBounds: +//InvalidContext: return err; } diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 9fd05a65ee..dea60720e7 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -402,14 +402,24 @@ void QCocoaIntegration::updateScreens() } siblings << screen; } + + // Patch: Backport crash fix from Qt 5.6.1. + // 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); delete screen; } + + // Patch: Backport crash fix from Qt 5.6.1. // All screens in mScreens are siblings, because we ignored the mirrors. - foreach (QCocoaScreen* screen, mScreens) - screen->setVirtualSiblings(siblings); + //foreach (QCocoaScreen* screen, mScreens) + // screen->setVirtualSiblings(siblings); } QCocoaScreen *QCocoaIntegration::screenAtIndex(int index) diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm index e46eaff6be..c62db534a2 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm +++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm @@ -382,6 +382,12 @@ bool QCocoaKeyMapper::updateKeyboard() keyboardInputLocale = QLocale::c(); keyboardInputDirection = Qt::LeftToRight; } + + // Patch: Backport a fix for layout-independent keyboard shortcuts. + const auto newMode = keyboard_mode; + deleteLayouts(); + keyboard_mode = newMode; + return true; } @@ -464,7 +470,8 @@ QList QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const Qt::KeyboardModifiers neededMods = ModsTbl[i]; int key = kbItem->qtKey[i]; if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) { - ret << int(key + (keyMods & ~neededMods)); + // Patch: Backport a fix for layout-independent keyboard shortcuts. + ret << int(key + neededMods); } } return ret; diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 83c960d931..03ae9696af 100755 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -102,7 +102,10 @@ QT_USE_NAMESPACE QCocoaSystemTrayIcon *systray; NSStatusItem *item; QCocoaMenu *menu; - bool menuVisible; + + // Patch: Nice macOS tray icon support. + bool menuVisible, iconSelected; + QIcon icon; QT_MANGLE_NAMESPACE(QNSImageView) *imageCell; } @@ -124,6 +127,10 @@ QT_USE_NAMESPACE QT_MANGLE_NAMESPACE(QNSStatusItem) *parent; } -(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent; + +// Patch: Nice macOS tray icon support. +-(void)updateIconSelection; + -(void)menuTrackingDone:(NSNotification*)notification; -(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton; @end @@ -187,6 +194,19 @@ void QCocoaSystemTrayIcon::cleanup() m_sys = 0; } +// Patch: Nice macOS tray icon support. +namespace { + +qreal getDevicePixelRatio() { + qreal result = 1.0; + foreach (QScreen *screen, QGuiApplication::screens()) { + result = qMax(result, screen->devicePixelRatio()); + } + return result; +} + +} // namespace + void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) { if (!m_sys) @@ -194,13 +214,18 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) m_sys->item->icon = icon; - const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible; + // Patch: Nice macOS tray icon support. + //const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible; - CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - const short scale = hgt - 4; + const int padding = 0; + const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; + const int maxImageHeight = menuHeight - padding; + + const short scale = maxImageHeight * getDevicePixelRatio(); QPixmap pm = m_sys->item->icon.pixmap(QSize(scale, scale), - menuVisible ? QIcon::Selected : QIcon::Normal); + // Patch: Nice macOS tray icon support. + m_sys->item->iconSelected ? QIcon::Selected : QIcon::Normal); if (pm.isNull()) { pm = QPixmap(scale, scale); pm.fill(Qt::transparent); @@ -322,15 +347,16 @@ QT_END_NAMESPACE return self; } --(void)menuTrackingDone:(NSNotification*)notification +// Patch: Nice macOS tray icon support. +-(void)updateIconSelection { - Q_UNUSED(notification); - down = NO; + const int padding = 0; + const int menuHeight = [[NSStatusBar systemStatusBar] thickness]; + const int maxImageHeight = menuHeight - padding; - CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - const short scale = hgt - 4; - - QPixmap pm = parent->icon.pixmap(QSize(scale, scale), QIcon::Normal); + const short scale = maxImageHeight * getDevicePixelRatio(); + QPixmap pm = parent->icon.pixmap(QSize(scale, scale), + parent->iconSelected ? QIcon::Selected : QIcon::Normal); if (pm.isNull()) { pm = QPixmap(scale, scale); pm.fill(Qt::transparent); @@ -338,9 +364,19 @@ QT_END_NAMESPACE NSImage *nsaltimage = static_cast(qt_mac_create_nsimage(pm)); [self setImage: nsaltimage]; [nsaltimage release]; +} + +-(void)menuTrackingDone:(NSNotification*)notification +{ + Q_UNUSED(notification); + down = NO; parent->menuVisible = false; + // Patch: Nice macOS tray icon support. + parent->iconSelected = false; + [self updateIconSelection]; + [self setNeedsDisplay:YES]; } @@ -350,18 +386,9 @@ QT_END_NAMESPACE int clickCount = [mouseEvent clickCount]; [self setNeedsDisplay:YES]; - CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - const short scale = hgt - 4; - - QPixmap pm = parent->icon.pixmap(QSize(scale, scale), - parent->menuVisible ? QIcon::Selected : QIcon::Normal); - if (pm.isNull()) { - pm = QPixmap(scale, scale); - pm.fill(Qt::transparent); - } - NSImage *nsaltimage = static_cast(qt_mac_create_nsimage(pm)); - [self setImage: nsaltimage]; - [nsaltimage release]; + // Patch: Nice macOS tray icon support. + parent->iconSelected = (clickCount != 2) && parent->menu; + [self updateIconSelection]; if (clickCount == 2) { [self menuTrackingDone:nil]; @@ -380,6 +407,10 @@ QT_END_NAMESPACE { Q_UNUSED(mouseEvent); [self menuTrackingDone:nil]; + + // Patch: Nice macOS tray icon support. + parent->iconSelected = false; + [self updateIconSelection]; } - (void)rightMouseDown:(NSEvent *)mouseEvent @@ -391,6 +422,10 @@ QT_END_NAMESPACE { Q_UNUSED(mouseEvent); [self menuTrackingDone:nil]; + + // Patch: Nice macOS tray icon support. + parent->iconSelected = false; + [self updateIconSelection]; } - (void)otherMouseDown:(NSEvent *)mouseEvent @@ -405,7 +440,8 @@ QT_END_NAMESPACE } -(void)drawRect:(NSRect)rect { - [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down]; + // Patch: Nice macOS tray icon support. + [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:parent->menu ? down : NO]; [super drawRect:rect]; } @end diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 4d0458a4aa..3357a5ef81 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -167,7 +167,8 @@ static bool isMouseEvent(NSEvent *ev) if (!self.window.delegate) return; // Already detached, pending NSAppKitDefined event - if (pw && pw->frameStrutEventsEnabled() && isMouseEvent(theEvent)) { + // Patch: Fix events loss if the window was minimized or hidden. + if (pw && pw->frameStrutEventsEnabled() && pw->m_synchedWindowState != Qt::WindowMinimized && pw->m_isExposed && isMouseEvent(theEvent)) { NSPoint loc = [theEvent locationInWindow]; NSRect windowFrame = [self.window legacyConvertRectFromScreen:[self.window frame]]; NSRect contentFrame = [[self.window contentView] frame]; @@ -795,6 +796,16 @@ NSUInteger QCocoaWindow::windowStyleMask(Qt::WindowFlags flags) { Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); NSInteger styleMask = NSBorderlessWindowMask; + + // Patch: allow creating panels floating on all spaces in macOS. + // If you call "setCollectionBehavior:NSWindowCollectionBehaviorFullScreenAuxiliary" before + // setting the "NSNonactivatingPanelMask" bit in the style mask it won't work after that. + // So we need a way to set that bit before Qt sets collection behavior the way it does. + QVariant nonactivatingPanelMask = window()->property("_td_macNonactivatingPanelMask"); + if (nonactivatingPanelMask.isValid() && nonactivatingPanelMask.toBool()) { + styleMask |= NSNonactivatingPanelMask; + } + if (flags & Qt::FramelessWindowHint) return styleMask; if ((type & Qt::Popup) == Qt::Popup) { @@ -914,6 +925,19 @@ void QCocoaWindow::setWindowFilePath(const QString &filePath) [m_nsWindow setRepresentedFilename: fi.exists() ? QCFString::toNSString(filePath) : @""]; } +// Patch: Nice macOS window icon. +namespace { + +qreal getDevicePixelRatio() { + qreal result = 1.0; + foreach (QScreen *screen, QGuiApplication::screens()) { + result = qMax(result, screen->devicePixelRatio()); + } + return result; +} + +} // namespace + void QCocoaWindow::setWindowIcon(const QIcon &icon) { QCocoaAutoReleasePool pool; @@ -929,7 +953,10 @@ void QCocoaWindow::setWindowIcon(const QIcon &icon) if (icon.isNull()) { [iconButton setImage:nil]; } else { - QPixmap pixmap = icon.pixmap(QSize(22, 22)); + // Patch: Nice macOS window icon. + CGFloat hgt = 16. * getDevicePixelRatio(); + QPixmap pixmap = icon.pixmap(QSize(hgt, hgt)); + NSImage *image = static_cast(qt_mac_create_nsimage(pixmap)); [iconButton setImage:image]; [image release]; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index a18ee7ff71..1f91feb0ae 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -393,7 +393,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; [self notifyWindowStateChanged:newState]; // NSWindowDidOrderOnScreenAndFinishAnimatingNotification is private API, and not // emitted in 10.6, so we bring back the old behavior for that case alone. - if (newState == Qt::WindowNoState && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6) + + // Patch: Fix macOS window show after window was hidden. + if (newState == Qt::WindowNoState/* && QSysInfo::QSysInfo::MacintoshVersion == QSysInfo::MV_10_6*/) m_platformWindow->exposeWindow(); } else if ([notificationName isEqualToString: @"NSWindowDidOrderOffScreenNotification"]) { m_platformWindow->obscureWindow(); @@ -1300,7 +1302,9 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) { // On 10.8 and above, MayBegin is likely to happen. We treat it the same as an actual begin. - if (phase == NSEventPhaseMayBegin) + + // Patch: Actual begin should be treated as begin as well. + if (phase == NSEventPhaseMayBegin || phase == NSEventPhaseBegan) ph = Qt::ScrollBegin; } else #endif @@ -1366,14 +1370,22 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) quint32 nativeVirtualKey = [nsevent keyCode]; QChar ch = QChar::ReplacementCharacter; - int keyCode = Qt::Key_unknown; - if ([characters length] != 0) { - if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) - ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); - else - ch = QChar([characters characterAtIndex:0]); - keyCode = [self convertKeyCode:ch]; - } + + // Patch: Backport a fix for layout-independent shortcuts. + if ([characters length] != 0) // https://bugreports.qt.io/browse/QTBUG-42584 + ch = QChar([characters characterAtIndex:0]); + else if ([charactersIgnoringModifiers length] != 0 && ((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier))) + ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); + + int keyCode = [self convertKeyCode:ch]; + //int keyCode = Qt::Key_unknown; + //if ([characters length] != 0) { + // if (((modifiers & Qt::MetaModifier) || (modifiers & Qt::AltModifier)) && ([charactersIgnoringModifiers length] != 0)) + // ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); + // else + // ch = QChar([characters characterAtIndex:0]); + // keyCode = [self convertKeyCode:ch]; + //} // we will send a key event unless the input method sets m_sendKeyEvent to false m_sendKeyEvent = true; @@ -1437,6 +1449,11 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) && qtKey == Qt::Key_Period) { [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; return YES; + + // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app. + } else if ([nsevent modifierFlags] & NSControlKeyMask && (qtKey == Qt::Key_Tab || qtKey == Qt::Key_Backtab)) { + [self handleKeyEvent:nsevent eventType:int(QEvent::KeyPress)]; + return YES; } } return [super performKeyEquivalent:nsevent]; diff --git a/src/tools/qlalr/lalr.cpp b/src/tools/qlalr/lalr.cpp index c68076477f..e2a7aafa58 100644 --- a/src/tools/qlalr/lalr.cpp +++ b/src/tools/qlalr/lalr.cpp @@ -246,11 +246,13 @@ void Grammar::buildExtendedGrammar () non_terminals.insert (accept_symbol); } -struct _Nullable: public std::unary_function +// Patch: Fix building with the new SDK. +struct __Nullable: public std::unary_function { Automaton *_M_automaton; - _Nullable (Automaton *aut): + // Patch: Fix building with the new SDK. + __Nullable (Automaton *aut): _M_automaton (aut) {} bool operator () (Name name) const @@ -308,7 +310,8 @@ void Automaton::buildNullables () for (RulePointer rule = _M_grammar->rules.begin (); rule != _M_grammar->rules.end (); ++rule) { - NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (_Nullable (this))); + // Patch: Fix building with the new SDK. + NameList::iterator nn = std::find_if (rule->rhs.begin (), rule->rhs.end (), std::not1 (__Nullable (this))); if (nn == rule->rhs.end ()) changed |= nullables.insert (rule->lhs).second; @@ -643,7 +646,8 @@ void Automaton::buildIncludesDigraph () if (! _M_grammar->isNonTerminal (*A)) continue; - NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (_Nullable (this))); + // Patch: Fix building with the new SDK. + NameList::iterator first_not_nullable = std::find_if (dot, rule->rhs.end (), std::not1 (__Nullable (this))); if (first_not_nullable != rule->rhs.end ()) continue; diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 7396808442..7178aecf80 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -4722,6 +4722,17 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, return; // Fully transparent. Q_D(QWidget); + + // Patch: save and restore dirtyOpaqueChildren field. + // + // Just like in QWidget::grab() this field should be restored + // after the d->render() call, because it will be set to 1 and + // opaqueChildren field will be filled with empty region in + // case the widget is hidden (because all the opaque children + // will be skipped in isVisible() check). + // + const bool oldDirtyOpaqueChildren = d->dirtyOpaqueChildren; + const bool inRenderWithPainter = d->extra && d->extra->inRenderWithPainter; const QRegion toBePainted = !inRenderWithPainter ? d->prepareToRender(sourceRegion, renderFlags) : sourceRegion; @@ -4743,6 +4754,10 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) { d->render_helper(painter, targetOffset, toBePainted, renderFlags); d->extra->inRenderWithPainter = inRenderWithPainter; + + // Patch: save and restore dirtyOpaqueChildren field. + d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; + return; } @@ -4774,6 +4789,9 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, d->setSharedPainter(oldPainter); d->extra->inRenderWithPainter = inRenderWithPainter; + + // Patch: save and restore dirtyOpaqueChildren field. + d->dirtyOpaqueChildren = oldDirtyOpaqueChildren; } static void sendResizeEvents(QWidget *target) @@ -7983,7 +8001,8 @@ bool QWidget::event(QEvent *event) case QEvent::KeyPress: { QKeyEvent *k = (QKeyEvent *)event; bool res = false; - if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier? + // Patch: Allow us to handle Ctrl+Tab and Ctrl+Backtab in the app. + if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier))) { //### Add MetaModifier? if (k->key() == Qt::Key_Backtab || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) res = focusNextPrevChild(false); diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index 0845a5eb02..5735cb6b39 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -3667,9 +3667,11 @@ void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter NSBezierPath *pushButtonFocusRingPath; if (bdi.kind == kThemeBevelButton) - pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:focusRect]; + // Patch: Fix building with the new SDK. + pushButtonFocusRingPath = [NSBezierPath bezierPathWithRect:NSRectFromCGRect(focusRect)]; else - pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:focusRect xRadius:4 yRadius:4]; + // Patch: Fix building with the new SDK. + pushButtonFocusRingPath = [NSBezierPath bezierPathWithRoundedRect:NSRectFromCGRect(focusRect) xRadius:4 yRadius:4]; qt_drawFocusRingOnPath(cg, pushButtonFocusRingPath); } diff --git a/src/widgets/util/qsystemtrayicon_qpa.cpp b/src/widgets/util/qsystemtrayicon_qpa.cpp index f98aeaf678..00c0734129 100644 --- a/src/widgets/util/qsystemtrayicon_qpa.cpp +++ b/src/widgets/util/qsystemtrayicon_qpa.cpp @@ -99,13 +99,18 @@ void QSystemTrayIconPrivate::updateIcon_sys() void QSystemTrayIconPrivate::updateMenu_sys() { - if (qpa_sys && menu) { - if (!menu->platformMenu()) { - QPlatformMenu *platformMenu = qpa_sys->createMenu(); - if (platformMenu) - menu->setPlatformMenu(platformMenu); + // Patch: Nice macOS tray icon support. + if (qpa_sys) { + if (menu) { + if (!menu->platformMenu()) { + QPlatformMenu *platformMenu = qpa_sys->createMenu(); + if (platformMenu) + menu->setPlatformMenu(platformMenu); + } + qpa_sys->updateMenu(menu->platformMenu()); + } else { + qpa_sys->updateMenu(0); } - qpa_sys->updateMenu(menu->platformMenu()); } } diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 75f30599be..980f2be1e9 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -1867,7 +1867,8 @@ void QWidgetLineControl::processKeyEvent(QKeyEvent* event) if (unknown && !isReadOnly()) { QString t = event->text(); - if (!t.isEmpty() && t.at(0).isPrint()) { + // Patch: Enable ZWJ and ZWNJ characters to be in text input. + if (!t.isEmpty() && (t.at(0).isPrint() || t.at(0).unicode() == 0x200C || t.at(0).unicode() == 0x200D)) { insert(t); #ifndef QT_NO_COMPLETER complete(event->key()); diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index 96438a0bdf..b0b7206405 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -1342,7 +1342,8 @@ void QWidgetTextControlPrivate::keyPressEvent(QKeyEvent *e) process: { QString text = e->text(); - if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) { + // Patch: Enable ZWJ and ZWNJ characters to be in text input. + if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t') || text.at(0).unicode() == 0x200C || text.at(0).unicode() == 0x200D)) { if (overwriteMode // no need to call deleteChar() if we have a selection, insertText // does it already