diff options
Diffstat (limited to 'src/plugins/platforms')
18 files changed, 286 insertions, 76 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h index 96dbd23695..3d1c95a0b4 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h @@ -70,6 +70,7 @@ namespace QCocoaAccessible { */ NSString *macRole(QAccessibleInterface *interface); +NSString *macSubrole(QAccessibleInterface *interface); bool shouldBeIgnored(QAccessibleInterface *interface); NSArray *unignoredChildren(QAccessibleInterface *interface); NSString *getTranslatedAction(const QString &qtAction); diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm index 1ade985b79..00baeddb39 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm @@ -162,7 +162,7 @@ static void populateRoleMap() } /* - Returns a Mac accessibility role for the given interface, or + Returns a Cocoa accessibility role for the given interface, or NSAccessibilityUnknownRole if no role mapping is found. */ NSString *macRole(QAccessibleInterface *interface) @@ -190,13 +190,24 @@ NSString *macRole(QAccessibleInterface *interface) } /* - Mac accessibility supports ignoring elements, which means that + Returns a Cocoa sub role for the given interface. +*/ +NSString *macSubrole(QAccessibleInterface *interface) +{ + QAccessible::State s = interface->state(); + if (s.searchEdit) + return NSAccessibilitySearchFieldSubrole; + return nil; +} + +/* + Cocoa accessibility supports ignoring elements, which means that the elements are still present in the accessibility tree but is not used by the screen reader. */ bool shouldBeIgnored(QAccessibleInterface *interface) { - // Mac accessibility does not have an attribute that corresponds to the Invisible/Offscreen + // Cocoa accessibility does not have an attribute that corresponds to the Invisible/Offscreen // state. Ignore interfaces with those flags set. const QAccessible::State state = interface->state(); if (state.invisible || diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index 9f803e411d..dd76852b62 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -135,6 +135,7 @@ defaultAttributes = [[NSArray alloc] initWithObjects: NSAccessibilityRoleAttribute, NSAccessibilityRoleDescriptionAttribute, + NSAccessibilitySubroleAttribute, NSAccessibilityChildrenAttribute, NSAccessibilityFocusedAttribute, NSAccessibilityParentAttribute, @@ -221,6 +222,8 @@ if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { return role; + } else if ([attribute isEqualToString:NSAccessibilitySubroleAttribute]) { + return QCocoaAccessible::macSubrole(iface); } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { return NSAccessibilityRoleDescription(role, nil); } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 326628a261..9f7609f24c 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -396,7 +396,7 @@ static void cleanupCocoaApplicationDelegate() */ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive, true /*forcePropagate*/); - return NO; + return YES; } - (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index 2c8d391d2b..47b52c9fdd 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -132,7 +132,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o) QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacInternalPasteboardMime::MIME_DND); m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy")); - dragBoard.setMimeData(m_drag->mimeData()); + dragBoard.setMimeData(m_drag->mimeData(), QMacPasteboard::LazyRequest); NSPoint event_location = [m_lastEvent locationInWindow]; NSPoint local_point = [m_lastView convertPoint:event_location fromView:nil]; diff --git a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm index 7322025df6..2101b68769 100644 --- a/src/plugins/platforms/cocoa/qcocoaprintdevice.mm +++ b/src/plugins/platforms/cocoa/qcocoaprintdevice.mm @@ -391,6 +391,9 @@ void QCocoaPrintDevice::loadDuplexModes() const // If still no result, or not added in PPD, then add None if (m_duplexModes.size() == 0 || !m_duplexModes.contains(QPrint::DuplexNone)) m_duplexModes.append(QPrint::DuplexNone); + // If have both modes, then can support DuplexAuto + if (m_duplexModes.contains(QPrint::DuplexLongSide) && m_duplexModes.contains(QPrint::DuplexShortSide)) + m_duplexModes.append(QPrint::DuplexAuto); m_haveDuplexModes = true; } diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index 83c960d931..e449fd37d6 100755 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -187,6 +187,14 @@ void QCocoaSystemTrayIcon::cleanup() m_sys = 0; } +static bool heightCompareFunction (QSize a, QSize b) { return (a.height() < b.height()); } +static QList<QSize> sortByHeight(const QList<QSize> sizes) +{ + QList<QSize> sorted = sizes; + std::sort(sorted.begin(), sorted.end(), heightCompareFunction); + return sorted; +} + void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) { if (!m_sys) @@ -196,16 +204,62 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon) const bool menuVisible = m_sys->item->menu && m_sys->item->menuVisible; - CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - const short scale = hgt - 4; + // The reccomended maximum title bar icon height is 18 points + // (device independent pixels). The menu height on past and + // current OS X versions is 22 points. Provide some future-proofing + // by deriving the icon height from the menu height. + const int padding = 4; + const int menuHeight = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; + const int maxImageHeight = menuHeight - padding; + + // Select pixmap based on the device pixel height. Ideally we would use + // the devicePixelRatio of the target screen, but that value is not + // known until draw time. Use qApp->devicePixelRatio, which returns the + // devicePixelRatio for the "best" screen on the system. + qreal devicePixelRatio = qApp->devicePixelRatio(); + const int maxPixmapHeight = maxImageHeight * devicePixelRatio; + const QIcon::Mode mode = menuVisible ? QIcon::Selected : QIcon::Normal; + QSize selectedSize; + Q_FOREACH (const QSize& size, sortByHeight(icon.availableSizes(mode))) { + // Select a pixmap based on the height. We want the largest pixmap + // with a height smaller or equal to maxPixmapHeight. The pixmap + // may rectangular; assume it has a reasonable size. If there is + // not suitable pixmap use the smallest one the icon can provide. + if (size.height() <= maxPixmapHeight) { + selectedSize = size; + } else { + if (!selectedSize.isValid()) + selectedSize = size; + break; + } + } - QPixmap pm = m_sys->item->icon.pixmap(QSize(scale, scale), - menuVisible ? QIcon::Selected : QIcon::Normal); - if (pm.isNull()) { - pm = QPixmap(scale, scale); - pm.fill(Qt::transparent); + QPixmap pixmap = icon.pixmap(selectedSize, mode); + + // Draw a low-resolution icon if there is not enough pixels for a retina + // icon. This prevents showing a small icon on retina displays. + if (devicePixelRatio > 1.0 && selectedSize.height() < maxPixmapHeight / 2) + devicePixelRatio = 1.0; + + // Scale large pixmaps to fit the available menu bar area. + if (pixmap.height() > maxPixmapHeight) + pixmap = pixmap.scaledToHeight(maxPixmapHeight, Qt::SmoothTransformation); + + // The icon will be stretched over the full height of the menu bar + // therefore we create a second pixmap which has the full height + QSize fullHeightSize(!pixmap.isNull() ? pixmap.width(): + menuHeight * devicePixelRatio, + menuHeight * devicePixelRatio); + QPixmap fullHeightPixmap(fullHeightSize); + fullHeightPixmap.fill(Qt::transparent); + if (!pixmap.isNull()) { + QPainter p(&fullHeightPixmap); + QRect r = pixmap.rect(); + r.moveCenter(fullHeightPixmap.rect().center()); + p.drawPixmap(r, pixmap); } - NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(pm)); + + NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(fullHeightPixmap)); [(NSImageView*)[[m_sys->item item] view] setImage: nsimage]; [nsimage release]; } @@ -327,18 +381,7 @@ QT_END_NAMESPACE Q_UNUSED(notification); down = NO; - CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight]; - const short scale = hgt - 4; - - QPixmap pm = parent->icon.pixmap(QSize(scale, scale), QIcon::Normal); - if (pm.isNull()) { - pm = QPixmap(scale, scale); - pm.fill(Qt::transparent); - } - NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage(pm)); - [self setImage: nsaltimage]; - [nsaltimage release]; - + parent->systray->updateIcon(parent->icon); parent->menuVisible = false; [self setNeedsDisplay:YES]; @@ -350,18 +393,7 @@ 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<NSImage *>(qt_mac_create_nsimage(pm)); - [self setImage: nsaltimage]; - [nsaltimage release]; + parent->systray->updateIcon(parent->icon); if (clickCount == 2) { [self menuTrackingDone:nil]; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 9259c2c772..3366e5bc3c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -699,7 +699,7 @@ void QCocoaWindow::setVisible(bool visible) exposeWindow(); if (m_nsWindow) { - QWindowSystemInterface::flushWindowSystemEvents(); + QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // setWindowState might have been called while the window was hidden and // will not change the NSWindow state in that case. Sync up here: @@ -1009,9 +1009,12 @@ void QCocoaWindow::raise() [parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; } else { [m_nsWindow orderFront: m_nsWindow]; - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly); + static bool raiseProcess = qt_mac_resolveOption(true, "QT_MAC_SET_RAISE_PROCESS"); + if (raiseProcess) { + ProcessSerialNumber psn; + GetCurrentProcess(&psn); + SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly); + } } } } diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h index ba7a2e1aac..c5b6224545 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.h +++ b/src/plugins/platforms/cocoa/qmacclipboard.h @@ -43,15 +43,25 @@ QT_BEGIN_NAMESPACE +class QMacMimeData; class QMacPasteboard { +public: + enum DataRequestType { EagerRequest, LazyRequest }; +private: struct Promise { Promise() : itemId(0), convertor(0) { } - Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QVariant d, int o=0) : itemId(itemId), offset(o), convertor(c), mime(m), data(d) { } + + static Promise eagerPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0); + static Promise lazyPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0); + Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *md, int o, DataRequestType drt); + int itemId, offset; QMacInternalPasteboardMime *convertor; QString mime; - QVariant data; + QPointer<QMacMimeData> mimeData; + QVariant variantData; + DataRequestType dataRequestType; }; QList<Promise> promises; @@ -72,7 +82,8 @@ public: PasteboardRef pasteBoard() const; QMimeData *mimeData() const; - void setMimeData(QMimeData *mime); + + void setMimeData(QMimeData *mime, DataRequestType dataRequestType = EagerRequest); QStringList formats() const; bool hasFormat(const QString &format) const; diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index 65665ef790..b235625921 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -64,6 +64,26 @@ QT_BEGIN_NAMESPACE QMacPasteboard code *****************************************************************************/ +class QMacMimeData : public QMimeData +{ +public: + QVariant variantData(const QString &mime) { return retrieveData(mime, QVariant::Invalid); } +private: + QMacMimeData(); +}; + +QMacPasteboard::Promise::Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *md, int o, DataRequestType drt) + : itemId(itemId), offset(o), convertor(c), mime(m), dataRequestType(drt) +{ + // Request the data from the application immediately for eager requests. + if (dataRequestType == QMacPasteboard::EagerRequest) { + variantData = md->variantData(m); + mimeData = 0; + } else { + mimeData = md; + } +} + QMacPasteboard::QMacPasteboard(PasteboardRef p, uchar mt) { mac_mime_source = false; @@ -103,6 +123,11 @@ QMacPasteboard::~QMacPasteboard() // commit all promises for paste after exit close for (int i = 0; i < promises.count(); ++i) { const Promise &promise = promises.at(i); + // At this point app teardown has started and control is somewhere in the Q[Core]Application + // destructor. Skip "lazy" promises where the application has not provided data; + // the application will generally not be in a state to provide it. + if (promise.dataRequestType == LazyRequest) + continue; QCFString flavor = QCFString(promise.convertor->flavorFor(promise.mime)); NSInteger pbItemId = promise.itemId; promiseKeeper(paste, reinterpret_cast<PasteboardItemID>(pbItemId), flavor, this); @@ -155,7 +180,17 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id, qPrintable(flavorAsQString), qPrintable(promise.convertor->convertorName()), promise.offset); #endif - QList<QByteArray> md = promise.convertor->convertFromMime(promise.mime, promise.data, flavorAsQString); + // Get the promise data. If this is a "lazy" promise call variantData() + // to request the data from the application. + QVariant promiseData; + if (promise.dataRequestType == LazyRequest) { + if (!promise.mimeData.isNull()) + promiseData = promise.mimeData->variantData(promise.mime); + } else { + promiseData = promise.variantData; + } + + QList<QByteArray> md = promise.convertor->convertFromMime(promise.mime, promiseData, flavorAsQString); if (md.size() <= promise.offset) return cantGetFlavorErr; const QByteArray &ba = md[promise.offset]; @@ -266,16 +301,8 @@ QMimeData return mime; } -class QMacMimeData : public QMimeData -{ -public: - QVariant variantData(const QString &mime) { return retrieveData(mime, QVariant::Invalid); } -private: - QMacMimeData(); -}; - void -QMacPasteboard::setMimeData(QMimeData *mime_src) +QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType) { if (!paste) return; @@ -312,12 +339,17 @@ QMacPasteboard::setMimeData(QMimeData *mime_src) continue; QString flavor(c->flavorFor(mimeType)); if (!flavor.isEmpty()) { - QVariant mimeData = static_cast<QMacMimeData*>(mime_src)->variantData(mimeType); + QMacMimeData *mimeData = static_cast<QMacMimeData*>(mime_src); int numItems = c->count(mime_src); for (int item = 0; item < numItems; ++item) { const NSInteger itemID = item+1; //id starts at 1 - promises.append(QMacPasteboard::Promise(itemID, c, mimeType, mimeData, item)); + //QMacPasteboard::Promise promise = (dataRequestType == QMacPasteboard::EagerRequest) ? + // QMacPasteboard::Promise::eagerPromise(itemID, c, mimeType, mimeData, item) : + // QMacPasteboard::Promise::lazyPromise(itemID, c, mimeType, mimeData, item); + + QMacPasteboard::Promise promise(itemID, c, mimeType, mimeData, item, dataRequestType); + promises.append(promise); PasteboardPutItemFlavor(paste, reinterpret_cast<PasteboardItemID>(itemID), QCFString(flavor), 0, kPasteboardFlavorNoFlags); #ifdef DEBUG_PASTEBOARD qDebug(" - adding %d %s [%s] <%s> [%d]", diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 06680228bc..ca98f6cec3 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -361,8 +361,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; // Send a geometry change event to Qt, if it's ready to handle events if (!m_platformWindow->m_inConstructor) { QWindowSystemInterface::handleGeometryChange(m_window, geometry); - m_platformWindow->updateExposedGeometry(); - QWindowSystemInterface::flushWindowSystemEvents(); + // Do not send incorrect exposes in case the window is not even visible yet. + // We might get here as a result of a resize() from QWidget's show(), for instance. + if (m_platformWindow->window()->isVisible()) { + m_platformWindow->updateExposedGeometry(); + QWindowSystemInterface::flushWindowSystemEvents(); + } } } @@ -420,10 +424,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; #pragma clang diagnostic ignored "-Wobjc-method-access" enum { NSWindowOcclusionStateVisible = 1UL << 1 }; #endif + // Older versions managed in -[QNSView viewDidMoveToWindow]. + // Support QWidgetAction in NSMenu. Mavericks only sends this notification. + // Ideally we should support this in Qt as well, in order to disable animations + // when the window is occluded. if ((NSUInteger)[self.window occlusionState] & NSWindowOcclusionStateVisible) m_platformWindow->exposeWindow(); - else - m_platformWindow->obscureWindow(); #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 #pragma clang diagnostic pop #endif @@ -686,7 +692,23 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; m_platformWindow->m_forwardWindow = 0; } - [targetView convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; + NSPoint globalPos = [NSEvent mouseLocation]; + + if ([self.window parentWindow] + && (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)) { + // QToolBar can be implemented as a child window on top of its main window + // (with a borderless NSWindow). If an option "unified toolbar" set on the main window, + // it's possible to drag such a window using this toolbar. + // While handling mouse drag events, QToolBar moves the window (QWidget::move). + // In such a combination [NSEvent mouseLocation] is very different from the + // real event location and as a result a window will move chaotically. + NSPoint winPoint = [theEvent locationInWindow]; + NSRect tmpRect = NSMakeRect(winPoint.x, winPoint.y, 1., 1.); + tmpRect = [[theEvent window] convertRectToScreen:tmpRect]; + globalPos = tmpRect.origin; + } + + [targetView convertFromScreen:globalPos toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); @@ -699,6 +721,10 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent { // get m_buttons in sync + // Don't send frme strut events if we are in the middle of a mouse drag. + if (m_buttons != Qt::NoButton) + return; + NSEventType ty = [theEvent type]; switch (ty) { case NSLeftMouseDown: @@ -710,6 +736,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; case NSRightMouseDown: m_frameStrutButtons |= Qt::RightButton; break; + case NSLeftMouseDragged: + m_frameStrutButtons |= Qt::LeftButton; + break; + case NSRightMouseDragged: + m_frameStrutButtons |= Qt::RightButton; + break; case NSRightMouseUp: m_frameStrutButtons &= ~Qt::RightButton; break; @@ -1337,10 +1369,6 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) } QWindowSystemInterface::handleWheelEvent(m_window, qt_timestamp, qt_windowPoint, qt_screenPoint, pixelDelta, angleDelta, currentWheelModifiers, ph); - - if (momentumPhase == NSEventPhaseEnded || momentumPhase == NSEventPhaseCancelled || momentumPhase == NSEventPhaseNone) { - currentWheelModifiers = Qt::NoModifier; - } } else #endif { @@ -1806,6 +1834,19 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin return NO; } +- (BOOL)wantsPeriodicDraggingUpdates +{ + // From the documentation: + // + // "If the destination returns NO, these messages are sent only when the mouse moves + // or a modifier flag changes. Otherwise the destination gets the default behavior, + // where it receives periodic dragging-updated messages even if nothing changes." + // + // We do not want these constant drag update events while mouse is stationary, + // since we do all animations (autoscroll) with timers. + return NO; +} + - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { return [self handleDrag : sender]; diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm index fb968f31e9..f684fef233 100644 --- a/src/plugins/platforms/cocoa/qprintengine_mac.mm +++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm @@ -457,9 +457,6 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va break; case PPK_CustomBase: break; - case PPK_Duplex: - // TODO Add support using PMSetDuplex / PMGetDuplex - break; case PPK_FontEmbedding: break; case PPK_PageOrder: @@ -503,6 +500,29 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va case PPK_DocumentName: PMPrintSettingsSetJobName(d->settings(), QCFString(value.toString())); break; + case PPK_Duplex: { + QPrint::DuplexMode mode = QPrint::DuplexMode(value.toInt()); + if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice->supportedDuplexModes().contains(mode)) + break; + switch (mode) { + case QPrinter::DuplexNone: + PMSetDuplex(d->settings(), kPMDuplexNone); + break; + case QPrinter::DuplexAuto: + PMSetDuplex(d->settings(), d->m_pageLayout.orientation() == QPageLayout::Landscape ? kPMDuplexTumble : kPMDuplexNoTumble); + break; + case QPrinter::DuplexLongSide: + PMSetDuplex(d->settings(), kPMDuplexNoTumble); + break; + case QPrinter::DuplexShortSide: + PMSetDuplex(d->settings(), kPMDuplexTumble); + break; + default: + // Don't change + break; + } + break; + } case PPK_FullPage: if (value.toBool()) d->m_pageLayout.setMode(QPageLayout::FullPageMode); @@ -602,10 +622,6 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const case PPK_CustomBase: // Special case, leave null break; - case PPK_Duplex: - // TODO Add support using PMSetDuplex / PMGetDuplex - ret = QPrinter::DuplexNone; - break; case PPK_FontEmbedding: ret = false; break; @@ -647,6 +663,23 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const ret = QCFString::toQString(name); break; } + case PPK_Duplex: { + PMDuplexMode mode = kPMDuplexNone; + PMGetDuplex(d->settings(), &mode); + switch (mode) { + case kPMDuplexNoTumble: + ret = QPrinter::DuplexLongSide; + break; + case kPMDuplexTumble: + ret = QPrinter::DuplexShortSide; + break; + case kPMDuplexNone: + default: + ret = QPrinter::DuplexNone; + break; + } + break; + } case PPK_FullPage: ret = d->m_pageLayout.mode() == QPageLayout::FullPageMode; break; diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm index 821599d113..ce7dfe2606 100644 --- a/src/plugins/platforms/ios/qioseventdispatcher.mm +++ b/src/plugins/platforms/ios/qioseventdispatcher.mm @@ -259,10 +259,16 @@ static void __attribute__((noinline, noreturn)) user_main_trampoline() NSArray *arguments = [[NSProcessInfo processInfo] arguments]; int argc = arguments.count; char **argv = new char*[argc]; + for (int i = 0; i < argc; ++i) { NSString *arg = [arguments objectAtIndex:i]; - argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]])); - strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]); + + NSStringEncoding cStringEncoding = [NSString defaultCStringEncoding]; + unsigned int bufferSize = [arg lengthOfBytesUsingEncoding:cStringEncoding] + 1; + argv[i] = reinterpret_cast<char *>(malloc(bufferSize)); + + if (![arg getCString:argv[i] maxLength:bufferSize encoding:cStringEncoding]) + qFatal("Could not convert argv[%d] to C string", i); } int exitCode = qtmn(argc, argv); diff --git a/src/plugins/platforms/ios/quiaccessibilityelement.mm b/src/plugins/platforms/ios/quiaccessibilityelement.mm index 331c38460c..63b6827ad3 100644 --- a/src/plugins/platforms/ios/quiaccessibilityelement.mm +++ b/src/plugins/platforms/ios/quiaccessibilityelement.mm @@ -152,6 +152,9 @@ if (state.disabled) traits |= UIAccessibilityTraitNotEnabled; + if (state.searchEdit) + traits |= UIAccessibilityTraitSearchField; + if (iface->role() == QAccessible::Button) traits |= UIAccessibilityTraitButton; diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index d2460e0640..f5d6c140bf 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -48,6 +48,13 @@ #include <QtCore/QDebug> #include <QtCore/QScopedArrayPointer> +static void initResources() +{ +#if !defined (Q_OS_WINCE) && !defined (QT_NO_IMAGEFORMAT_PNG) + Q_INIT_RESOURCE(cursors); +#endif +} + QT_BEGIN_NAMESPACE Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0); @@ -568,6 +575,11 @@ QWindowsWindowCursor QWindowsCursor::pixmapWindowCursor(const QCursor &c) return it.value(); } +QWindowsCursor::QWindowsCursor() +{ + initResources(); +} + /*! \brief Set a cursor on a window. diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h index c8e1df3f4d..a024646553 100644 --- a/src/plugins/platforms/windows/qwindowscursor.h +++ b/src/plugins/platforms/windows/qwindowscursor.h @@ -91,7 +91,7 @@ public: CursorSuppressed // Cursor suppressed by touch interaction (Windows 8). }; - QWindowsCursor() {} + QWindowsCursor(); void changeCursor(QCursor * widgetCursor, QWindow * widget) Q_DECL_OVERRIDE; QPoint pos() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index dd9b9de0b6..8a80729354 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1149,6 +1149,13 @@ void QWindowsWindow::updateTransientParent() const #endif // !Q_OS_WINCE } +static inline bool testShowWithoutActivating(const QWindow *window) +{ + // QWidget-attribute Qt::WA_ShowWithoutActivating . + const QVariant showWithoutActivating = window->property("_q_showWithoutActivating"); + return showWithoutActivating.isValid() && showWithoutActivating.toBool(); +} + // partially from QWidgetPrivate::show_sys() void QWindowsWindow::show_sys() const { @@ -1180,7 +1187,7 @@ void QWindowsWindow::show_sys() const } // Qt::WindowMaximized } // !Qt::WindowMinimized } - if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool) + if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool || testShowWithoutActivating(w)) sm = SW_SHOWNOACTIVATE; if (w->windowState() & Qt::WindowMaximized) diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index fc3443aba5..dae3a79628 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -910,6 +910,18 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const if (qtKey == baseQtKey || qtKey == 0) continue; + // catch only more specific shortcuts, i.e. Ctrl+Shift+= also generates Ctrl++ and +, + // but Ctrl++ is more specific than +, so we should skip the last one + bool ambiguous = false; + foreach (int shortcut, result) { + if (int(shortcut & ~Qt::KeyboardModifierMask) == qtKey && (shortcut & mods) == mods) { + ambiguous = true; + break; + } + } + if (ambiguous) + continue; + result += (qtKey + mods); } } |